IBR-DTNSuite  0.10
Client.cpp
Go to the documentation of this file.
1 /*
2  * Client.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrdtn/api/Client.h"
23 #include "ibrdtn/data/SDNV.h"
24 #include "ibrdtn/data/Exceptions.h"
27 
29 #include <ibrcommon/Logger.h>
30 
31 #include <iostream>
32 #include <string>
33 
34 namespace dtn
35 {
36  namespace api
37  {
38  Client::AsyncReceiver::AsyncReceiver(Client &client)
39  : _client(client), _running(true)
40  {
41  }
42 
43  Client::AsyncReceiver::~AsyncReceiver()
44  {
45  }
46 
47  void Client::AsyncReceiver::__cancellation() throw ()
48  {
49  _running = false;
50  }
51 
52  void Client::AsyncReceiver::run() throw ()
53  {
54  try {
55  while (!_client.eof() && _running)
56  {
58 
59  // To receive a bundle, we construct a default deserializer. Such a deserializer
60  // convert a byte stream into a bundle object. If this deserialization fails
61  // an exception will be thrown.
63 
64  _client.received(b);
65  yield();
66  }
67  } catch (const dtn::api::ConnectionException &ex) {
68  IBRCOMMON_LOGGER_TAG("Client::AsyncReceiver", error) << "ConnectionException: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
69  _client.shutdown(CONNECTION_SHUTDOWN_ERROR);
71  IBRCOMMON_LOGGER_TAG("Client::AsyncReceiver", error) << "StreamErrorException: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
72  _client.shutdown(CONNECTION_SHUTDOWN_ERROR);
73  } catch (const ibrcommon::IOException &ex) {
74  IBRCOMMON_LOGGER_TAG("Client::AsyncReceiver", error) << "IOException: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
75  _client.shutdown(CONNECTION_SHUTDOWN_ERROR);
76  } catch (const dtn::InvalidDataException &ex) {
77  if (_running) {
78  IBRCOMMON_LOGGER_TAG("Client::AsyncReceiver", error) << "InvalidDataException: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
79  _client.shutdown(CONNECTION_SHUTDOWN_ERROR);
80  }
81  } catch (const std::exception &ex) {
82  IBRCOMMON_LOGGER_TAG("Client::AsyncReceiver", error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
83  _client.shutdown(CONNECTION_SHUTDOWN_ERROR);
84  }
85  }
86 
87  Client::Client(const std::string &app, const dtn::data::EID &group, ibrcommon::socketstream &stream, const COMMUNICATION_MODE mode)
88  : StreamConnection(*this, stream), lastack(0), _stream(stream), _mode(mode), _app(app), _group(group), _receiver(*this)
89  {
90  }
91 
92  Client::Client(const std::string &app, ibrcommon::socketstream &stream, const COMMUNICATION_MODE mode)
93  : StreamConnection(*this, stream), lastack(0), _stream(stream), _mode(mode), _app(app), _group(), _receiver(*this)
94  {
95  }
96 
98  {
99  try {
100  // stop the receiver
101  _receiver.stop();
102  } catch (const ibrcommon::ThreadException &ex) {
103  IBRCOMMON_LOGGER_DEBUG_TAG("Client", 20) << "ThreadException in Client destructor: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
104  }
105 
106  // Close the stream. This releases all reading or writing threads.
107  _stream.close();
108 
109  // wait until the async thread has been finished
110  _receiver.join();
111  }
112 
114  {
115  // do a handshake
116  EID localeid;
117  if (_app.length() > 0) localeid = EID("api:" + _app);
118 
119  // connection flags
121 
122  // request acknowledgements
124 
125  // set comm. mode
127 
128  // receive API banner
129  std::string buffer;
130  std::getline(_stream, buffer);
131 
132  // if requested...
133  if (!_group.isNone())
134  {
135  // join the group
136  _stream << "registration add " << _group.getString() << std::endl;
137 
138  // read the reply
139  std::getline(_stream, buffer);
140  }
141 
142  // switch to API tcpcl mode
143  _stream << "protocol tcpcl" << std::endl;
144 
145  // do the handshake (no timeout, no keepalive)
146  handshake(localeid, 0, flags);
147 
148  try {
149  // run the receiver
150  _receiver.start();
151  } catch (const ibrcommon::ThreadException &ex) {
152  IBRCOMMON_LOGGER_TAG("Client", error) << "failed to start Client::Receiver\n" << ex.what() << IBRCOMMON_LOGGER_ENDL;
153  }
154  }
155 
157  {
158  // shutdown the bundle stream connection
159  shutdown(StreamConnection::CONNECTION_SHUTDOWN_SIMPLE_SHUTDOWN);
160  }
161 
163  {
164  _inqueue.abort();
165 
166  // shutdown the bundle stream connection
167  shutdown(StreamConnection::CONNECTION_SHUTDOWN_ERROR);
168  }
169 
171  {
172  _inqueue.abort();
173 
174  try {
175  _receiver.stop();
176  } catch (const ibrcommon::ThreadException &ex) {
178  }
179  }
180 
181  void Client::eventBundleAck(const dtn::data::Length &ack) throw ()
182  {
183  lastack = ack;
184  }
185 
187  {
188  // if we are in send only mode...
189  if (_mode != dtn::api::Client::MODE_SENDONLY)
190  {
191  _inqueue.push(b);
192  }
193 
194  // ... then discard the received bundle
195  }
196 
198  {
199  // To send a bundle, we construct a default serializer. Such a serializer convert
200  // the bundle data to the standardized form as byte stream.
201  dtn::data::DefaultSerializer(*this) << b;
202 
203  // Since this method is used to serialize bundles into an StreamConnection, we need to call
204  // a flush on the StreamConnection. This signals the stream to set the bundle end flag on
205  // the last segment of streaming.
206  flush();
207  }
208 
210  {
211  try {
212  return _inqueue.getnpop(true, timeout * 1000);
213  } catch (const ibrcommon::QueueUnblockedException &ex) {
215  {
217  }
219  {
220  throw ConnectionAbortedException(ex.what());
221  }
222 
223  throw ConnectionException(ex.what());
224  } catch (const std::exception &ex) {
225  throw ConnectionException(ex.what());
226  }
227 
228  throw ConnectionException();
229  }
230  }
231 }