IBR-DTN  1.0.0
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>
34 #include <ibrcommon/link/LinkManager.h>
35 
36 namespace dtn
37 {
38  namespace api
39  {
40  ProtocolHandler::ProtocolHandler(ClientHandler &client, ibrcommon::socketstream &stream)
41  : _client(client), _stream(stream)
42  {
43  }
44 
46  {}
47 
48  ClientHandler::ClientHandler(ApiServerInterface &srv, Registration &registration, ibrcommon::socketstream *conn)
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.size() < 2) throw ibrcommon::Exception("not enough parameters");
118 
119  if (cmd[1] == "tcpcl")
120  {
121  // switch to binary protocol (old style api)
122  _handler = new BinaryStreamClient(*this, *_stream);
123  continue;
124  }
125  else if (cmd[1] == "management")
126  {
127  // switch to the management protocol
128  _handler = new ManagementConnection(*this, *_stream);
129  continue;
130  }
131  else if (cmd[1] == "event")
132  {
133  // switch to the management protocol
134  _handler = new EventConnection(*this, *_stream);
135  continue;
136  }
137  else if (cmd[1] == "extended")
138  {
139  // switch to the extended api
140  _handler = new ExtendedApiHandler(*this, *_stream);
141  continue;
142  }
143  else if (cmd[1] == "streaming")
144  {
145  // switch to the streaming api
146  _handler = new OrderedStreamHandler(*this, *_stream);
147  continue;
148  }
149  else if (cmd[1] == "p2p_extension")
150  {
151  if (cmd.size() < 3) {
152  error(API_STATUS_NOT_ACCEPTABLE, "P2P TYPE REQUIRED");
153  continue;
154  }
155 
156  if (cmd[2] == "wifi") {
157  // switch to the streaming api
158  _handler = new ApiP2PExtensionHandler(*this, *_stream, dtn::core::Node::CONN_P2P_WIFI);
159  continue;
160  } else if (cmd[2] == "bt") {
161  // switch to the streaming api
162  _handler = new ApiP2PExtensionHandler(*this, *_stream, dtn::core::Node::CONN_P2P_BT);
163  continue;
164  } else {
165  error(API_STATUS_NOT_ACCEPTABLE, "P2P TYPE UNKNOWN");
166  continue;
167  }
168  }
169  else
170  {
171  error(API_STATUS_NOT_ACCEPTABLE, "UNKNOWN PROTOCOL");
172  }
173  }
174  else
175  {
176  // forward to standard command set
177  processCommand(cmd);
178  }
179  } catch (const std::exception&) {
180  error(API_STATUS_BAD_REQUEST, "PROTOCOL ERROR");
181  }
182  }
183  } catch (const ibrcommon::socket_exception &ex) {
184  IBRCOMMON_LOGGER_TAG("ClientHandler", error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
185  }
186  }
187 
188  void ClientHandler::error(STATUS_CODES code, const std::string &msg)
189  {
190  ibrcommon::MutexLock l(_write_lock);
191  (*_stream) << code << " " << msg << std::endl;
192  }
193 
195  {
196  // close the stream
197  (*_stream).close();
198  }
199 
200  void ClientHandler::finally() throw ()
201  {
202  IBRCOMMON_LOGGER_DEBUG_TAG("ClientHandler", 60) << "ApiConnection down" << IBRCOMMON_LOGGER_ENDL;
203 
204  // remove the client from the list in ApiServer
205  _srv.connectionDown(this);
206 
207  _registration->abort();
208  _srv.freeRegistration(*_registration);
209 
210  // close the stream
211  (*_stream).close();
212  }
213 
214  void ClientHandler::processCommand(const std::vector<std::string> &cmd)
215  {
217  {
218  public:
219  BundleFilter()
220  {};
221 
222  virtual ~BundleFilter() {};
223 
224  virtual dtn::data::Size limit() const throw () { return 0; };
225 
226  virtual bool shouldAdd(const dtn::data::MetaBundle&) const throw (dtn::storage::BundleSelectorException)
227  {
228  return true;
229  }
230  };
231 
232  try {
233  if (cmd[0] == "set")
234  {
235  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
236 
237  if (cmd[1] == "endpoint")
238  {
239  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
240 
241  ibrcommon::MutexLock l(_write_lock);
242  if (cmd[2].length() <= 0) {
243  // send error notification
244  (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID ENDPOINT" << std::endl;
245  } else {
246  // un-subscribe previous registration
247  _registration->unsubscribe(_endpoint);
248 
249  // set new application endpoint
250  _endpoint.setApplication(cmd[2]);
251 
252  // subscribe to new endpoint
253  _registration->subscribe(_endpoint);
254 
255  // send accepted notification
256  (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
257  }
258  }
259  else
260  {
261  ibrcommon::MutexLock l(_write_lock);
262  (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
263  }
264  }
265  else if (cmd[0] == "registration")
266  {
267  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
268 
269  if (cmd[1] == "add")
270  {
271  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
272 
273  ibrcommon::MutexLock l(_write_lock);
274  dtn::data::EID endpoint(cmd[2]);
275 
276  // error checking
277  if (endpoint == dtn::data::EID())
278  {
279  (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID EID" << std::endl;
280  }
281  else
282  {
283  _registration->subscribe(endpoint);
284  (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
285  }
286  }
287  else if (cmd[1] == "del")
288  {
289  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
290 
291  ibrcommon::MutexLock l(_write_lock);
292  dtn::data::EID endpoint(cmd[2]);
293 
294  // error checking
295  if (endpoint == dtn::data::EID())
296  {
297  (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID EID" << std::endl;
298  }
299  else
300  {
301  _registration->unsubscribe(endpoint);
302  (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
303  }
304  }
305  else if (cmd[1] == "list")
306  {
307  ibrcommon::MutexLock l(_write_lock);
308  const std::set<dtn::data::EID> list = _registration->getSubscriptions();
309 
310  (*_stream) << API_STATUS_OK << " REGISTRATION LIST" << std::endl;
311  for (std::set<dtn::data::EID>::const_iterator iter = list.begin(); iter != list.end(); ++iter)
312  {
313  (*_stream) << (*iter).getString() << std::endl;
314  }
315  (*_stream) << std::endl;
316  }
317  else
318  {
319  ibrcommon::MutexLock l(_write_lock);
320  (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
321  }
322  }
323  else
324  {
325  ibrcommon::MutexLock l(_write_lock);
326  (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
327  }
328  } catch (const std::exception&) {
329  ibrcommon::MutexLock l(_write_lock);
330  (*_stream) << API_STATUS_BAD_REQUEST << " ERROR" << std::endl;
331  }
332  }
333  }
334 }
void subscribe(const dtn::data::EID &endpoint)
void setApplication(const dtn::data::Number &app)
Definition: EID.cpp:403
virtual void freeRegistration(Registration &reg)=0
ApiServerInterface & getAPIServer()
dtn::api::Client * _client
Definition: dtnrecv.cpp:50
Registration & getRegistration()
ProtocolHandler(ClientHandler &client, ibrcommon::socketstream &stream)
void unsubscribe(const dtn::data::EID &endpoint)
virtual void finally()=0
const std::set< dtn::data::EID > getSubscriptions()
void switchRegistration(Registration &reg)
size_t Size
Definition: Number.h:34
virtual void run()=0
virtual void connectionUp(ClientHandler *conn)=0
virtual void connectionDown(ClientHandler *conn)=0
ClientHandler(ApiServerInterface &srv, Registration &registration, ibrcommon::socketstream *conn)
static std::vector< std::string > tokenize(const std::string &token, const std::string &data, const std::string::size_type max=std::string::npos)
Definition: Utils.cpp:60