IBR-DTNSuite  0.12
ClientHandler.cpp
Go to the documentation of this file.
1 /*
2  * ClientHandler.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 "config.h"
23 #include "Configuration.h"
24 #include "api/ClientHandler.h"
25 #include "api/BinaryStreamClient.h"
27 #include "api/EventConnection.h"
28 #include "api/ExtendedApiHandler.h"
31 #include "core/BundleCore.h"
32 #include <ibrcommon/Logger.h>
33 #include <ibrdtn/utils/Utils.h>
35 
36 namespace dtn
37 {
38  namespace api
39  {
41  : _client(client), _stream(stream)
42  {
43  }
44 
46  {}
47 
49  : _srv(srv), _registration(&registration), _stream(conn), _endpoint(dtn::core::BundleCore::local), _handler(NULL)
50  {
51  }
52 
54  {
55  delete _stream;
56  }
57 
59  {
60  return *_registration;
61  }
62 
64  {
65  return _srv;
66  }
67 
69  {
70  _registration->abort();
71 
72  _srv.freeRegistration(*_registration);
73 
74  _registration = &reg;
75  }
76 
77  void ClientHandler::setup() throw ()
78  {
79  }
80 
81  void ClientHandler::run() throw ()
82  {
83  try {
84  // signal the active connection to the server
85  _srv.connectionUp(this);
86 
87  std::string buffer;
88 
89  while (_stream->good())
90  {
91  if (_handler != NULL)
92  {
93  _handler->setup();
94  _handler->run();
95  _handler->finally();
96  delete _handler;
97  _handler = NULL;
98 
99  // end this stream, return to the previous stage
100  (*_stream) << ClientHandler::API_STATUS_OK << " SWITCHED TO LEVEL 0" << std::endl;
101 
102  continue;
103  }
104 
105  getline(*_stream, buffer);
106 
107  // search for '\r\n' and remove the '\r'
108  std::string::reverse_iterator iter = buffer.rbegin();
109  if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
110 
111  std::vector<std::string> cmd = dtn::utils::Utils::tokenize(" ", buffer);
112  if (cmd.empty()) continue;
113 
114  try {
115  if (cmd[0] == "protocol")
116  {
117  if (cmd[1] == "tcpcl")
118  {
119  // switch to binary protocol (old style api)
120  _handler = new BinaryStreamClient(*this, *_stream);
121  continue;
122  }
123  else if (cmd[1] == "management")
124  {
125  // switch to the management protocol
126  _handler = new ManagementConnection(*this, *_stream);
127  continue;
128  }
129  else if (cmd[1] == "event")
130  {
131  // switch to the management protocol
132  _handler = new EventConnection(*this, *_stream);
133  continue;
134  }
135  else if (cmd[1] == "extended")
136  {
137  // switch to the extended api
138  _handler = new ExtendedApiHandler(*this, *_stream);
139  continue;
140  }
141  else if (cmd[1] == "streaming")
142  {
143  // switch to the streaming api
144  _handler = new OrderedStreamHandler(*this, *_stream);
145  continue;
146  }
147  else if (cmd[1] == "p2p_extension")
148  {
149  if (cmd.size() < 3) {
150  error(API_STATUS_NOT_ACCEPTABLE, "P2P TYPE REQUIRED");
151  continue;
152  }
153 
154  if (cmd[2] == "wifi") {
155  // switch to the streaming api
156  _handler = new ApiP2PExtensionHandler(*this, *_stream, dtn::core::Node::CONN_P2P_WIFI);
157  continue;
158  } else if (cmd[2] == "bt") {
159  // switch to the streaming api
160  _handler = new ApiP2PExtensionHandler(*this, *_stream, dtn::core::Node::CONN_P2P_BT);
161  continue;
162  } else {
163  error(API_STATUS_NOT_ACCEPTABLE, "P2P TYPE UNKNOWN");
164  continue;
165  }
166  }
167  else
168  {
169  error(API_STATUS_NOT_ACCEPTABLE, "UNKNOWN PROTOCOL");
170  }
171  }
172  else
173  {
174  // forward to standard command set
175  processCommand(cmd);
176  }
177  } catch (const std::exception&) {
178  error(API_STATUS_BAD_REQUEST, "PROTOCOL ERROR");
179  }
180  }
181  } catch (const ibrcommon::socket_exception &ex) {
182  IBRCOMMON_LOGGER_TAG("ClientHandler", error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
183  }
184  }
185 
186  void ClientHandler::error(STATUS_CODES code, const std::string &msg)
187  {
188  ibrcommon::MutexLock l(_write_lock);
189  (*_stream) << code << " " << msg << std::endl;
190  }
191 
193  {
194  // close the stream
195  (*_stream).close();
196  }
197 
198  void ClientHandler::finally() throw ()
199  {
200  IBRCOMMON_LOGGER_DEBUG_TAG("ClientHandler", 60) << "ApiConnection down" << IBRCOMMON_LOGGER_ENDL;
201 
202  // remove the client from the list in ApiServer
203  _srv.connectionDown(this);
204 
205  _registration->abort();
206  _srv.freeRegistration(*_registration);
207 
208  // close the stream
209  (*_stream).close();
210  }
211 
212  void ClientHandler::processCommand(const std::vector<std::string> &cmd)
213  {
214  class BundleFilter : public dtn::storage::BundleSelector
215  {
216  public:
217  BundleFilter()
218  {};
219 
220  virtual ~BundleFilter() {};
221 
222  virtual dtn::data::Size limit() const throw () { return 0; };
223 
224  virtual bool shouldAdd(const dtn::data::MetaBundle&) const throw (dtn::storage::BundleSelectorException)
225  {
226  return true;
227  }
228  };
229 
230  try {
231  if (cmd[0] == "set")
232  {
233  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
234 
235  if (cmd[1] == "endpoint")
236  {
237  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
238 
239  ibrcommon::MutexLock l(_write_lock);
240  if (cmd[2].length() <= 0) {
241  // send error notification
242  (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID ENDPOINT" << std::endl;
243  } else {
244  // un-subscribe previous registration
245  _registration->unsubscribe(_endpoint);
246 
247  // set new application endpoint
248  _endpoint.setApplication(cmd[2]);
249 
250  // subscribe to new endpoint
251  _registration->subscribe(_endpoint);
252 
253  // send accepted notification
254  (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
255  }
256  }
257  else
258  {
259  ibrcommon::MutexLock l(_write_lock);
260  (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
261  }
262  }
263  else if (cmd[0] == "registration")
264  {
265  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
266 
267  if (cmd[1] == "add")
268  {
269  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
270 
271  ibrcommon::MutexLock l(_write_lock);
272  dtn::data::EID endpoint(cmd[2]);
273 
274  // error checking
275  if (endpoint == dtn::data::EID())
276  {
277  (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID EID" << std::endl;
278  }
279  else
280  {
281  _registration->subscribe(endpoint);
282  (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
283  }
284  }
285  else if (cmd[1] == "del")
286  {
287  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
288 
289  ibrcommon::MutexLock l(_write_lock);
290  dtn::data::EID endpoint(cmd[2]);
291 
292  // error checking
293  if (endpoint == dtn::data::EID())
294  {
295  (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID EID" << std::endl;
296  }
297  else
298  {
299  _registration->unsubscribe(endpoint);
300  (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
301  }
302  }
303  else if (cmd[1] == "list")
304  {
305  ibrcommon::MutexLock l(_write_lock);
306  const std::set<dtn::data::EID> list = _registration->getSubscriptions();
307 
308  (*_stream) << API_STATUS_OK << " REGISTRATION LIST" << std::endl;
309  for (std::set<dtn::data::EID>::const_iterator iter = list.begin(); iter != list.end(); ++iter)
310  {
311  (*_stream) << (*iter).getString() << std::endl;
312  }
313  (*_stream) << std::endl;
314  }
315  else
316  {
317  ibrcommon::MutexLock l(_write_lock);
318  (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
319  }
320  }
321  else
322  {
323  ibrcommon::MutexLock l(_write_lock);
324  (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
325  }
326  } catch (const std::exception&) {
327  ibrcommon::MutexLock l(_write_lock);
328  (*_stream) << API_STATUS_BAD_REQUEST << " ERROR" << std::endl;
329  }
330  }
331  }
332 }