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