IBR-DTN  1.0.0
ManagementConnection.cpp
Go to the documentation of this file.
1 /*
2  * ManagementConnection.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 "DTNTPWorker.h"
25 #include "ManagementConnection.h"
26 #include "storage/BundleResult.h"
27 #include "core/BundleCore.h"
28 #include "core/Node.h"
31 
32 #include "core/EventDispatcher.h"
33 #include "core/GlobalEvent.h"
41 
42 #include <ibrdtn/ibrdtn.h>
43 #ifdef IBRDTN_SUPPORT_BSP
46 #endif
47 
48 #include <ibrdtn/utils/Clock.h>
49 #include <ibrdtn/utils/Utils.h>
50 
51 #include <ibrcommon/Logger.h>
52 #include <ibrcommon/link/LinkManager.h>
53 #include <ibrcommon/link/LinkEvent.h>
54 #include <ibrcommon/thread/RWLock.h>
55 
56 #include <iomanip>
57 
58 namespace dtn
59 {
60  namespace api
61  {
62  ManagementConnection::ManagementConnection(ClientHandler &client, ibrcommon::socketstream &stream)
63  : ProtocolHandler(client, stream)
64  {
65  }
66 
68  {
69  }
70 
72  {
73  std::string buffer = "";
74  _stream << ClientHandler::API_STATUS_OK << " SWITCHED TO MANAGEMENT" << std::endl;
75 
76  // run as long the stream is ok
77  while (_stream.good())
78  {
79  getline(_stream, buffer);
80 
81  if (buffer.length() == 0) continue;
82 
83  // search for '\r\n' and remove the '\r'
84  std::string::reverse_iterator iter = buffer.rbegin();
85  if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
86 
87  std::vector<std::string> cmd = dtn::utils::Utils::tokenize(" ", buffer);
88  if (cmd.empty()) continue;
89 
90  if (cmd[0] == "exit")
91  {
92  // return to previous level
93  break;
94  }
95  else
96  {
97  // forward to standard command set
98  processCommand(cmd);
99  }
100  }
101  }
102 
104  {
105  }
106 
108  {
109  }
110 
112  {
113  }
114 
115  void ManagementConnection::processCommand(const std::vector<std::string> &cmd)
116  {
118  {
119  public:
120  BundleFilter()
121  {};
122 
123  virtual ~BundleFilter() {};
124 
125  virtual dtn::data::Size limit() const throw () { return 0; };
126 
127  virtual bool shouldAdd(const dtn::data::MetaBundle&) const throw (dtn::storage::BundleSelectorException)
128  {
129  return true;
130  }
131  };
132 
133  try {
134  if (cmd[0] == "neighbor")
135  {
136  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
137 
138  if (cmd[1] == "list")
139  {
140  const std::set<dtn::core::Node> nlist = dtn::core::BundleCore::getInstance().getConnectionManager().getNeighbors();
141 
142  _stream << ClientHandler::API_STATUS_OK << " NEIGHBOR LIST" << std::endl;
143  for (std::set<dtn::core::Node>::const_iterator iter = nlist.begin(); iter != nlist.end(); ++iter)
144  {
145  _stream << (*iter).getEID().getString() << std::endl;
146  }
147  _stream << std::endl;
148  }
149  else
150  {
151  _stream << ClientHandler::API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
152  }
153  }
154  else if (cmd[0] == "interface")
155  {
156  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
157 
158  if (cmd[1] == "address")
159  {
160  try {
161  ibrcommon::LinkManager &lm = ibrcommon::LinkManager::getInstance();
162 
163  // the interface is defined as the 3rd parameter
164  ibrcommon::vinterface iface(cmd[3]);
165 
166  // TODO: Throw out the 4th parameter. Previously used to define the
167  // address family.
168 
169  // the new address is defined as 5th parameter
170  ibrcommon::vaddress addr(cmd[5], "");
171 
172  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
173 
174  if (cmd[2] == "add")
175  {
176  ibrcommon::LinkEvent evt(ibrcommon::LinkEvent::ACTION_ADDRESS_ADDED, iface, addr);
177  lm.raiseEvent(evt);
178  _stream << ClientHandler::API_STATUS_OK << " ADDRESS ADDED" << std::endl;
179  }
180  else if (cmd[2] == "del")
181  {
182  ibrcommon::LinkEvent evt(ibrcommon::LinkEvent::ACTION_ADDRESS_REMOVED, iface, addr);
183  lm.raiseEvent(evt);
184  _stream << ClientHandler::API_STATUS_OK << " ADDRESS REMOVED" << std::endl;
185  }
186  else
187  {
188  _stream << ClientHandler::API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
189  }
190  } catch (const std::bad_cast&) {
191  _stream << ClientHandler::API_STATUS_NOT_ALLOWED << " FEATURE NOT AVAILABLE" << std::endl;
192  };
193  }
194  else
195  {
196  _stream << ClientHandler::API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
197  }
198  }
199  else if (cmd[0] == "connection")
200  {
201  if (cmd.size() < 5) throw ibrcommon::Exception("not enough parameters");
202 
203  // need to process the connection arguments
204  // the arguments look like:
205  // <eid> [tcp|udp|file] [add|del] <ip> <port> <global|local>
206  dtn::core::Node n(cmd[1]);
208 
209  if (cmd.size() > 6) {
210  if (cmd[6] == "global") {
212  } else {
214  }
215  }
216 
217  if (cmd[2] == "tcp")
218  {
219  if (cmd.size() < 6) throw ibrcommon::Exception("not enough parameters");
220 
221  if (cmd[3] == "add")
222  {
223  std::string uri = "ip=" + cmd[4] + ";port=" + cmd[5] + ";";
224  n.add(dtn::core::Node::URI(t, dtn::core::Node::CONN_TCPIP, uri, 0, -5));
226 
227  _stream << ClientHandler::API_STATUS_OK << " CONNECTION ADDED" << std::endl;
228  }
229  else if (cmd[3] == "del")
230  {
231  std::string uri = "ip=" + cmd[4] + ";port=" + cmd[5] + ";";
232  n.add(dtn::core::Node::URI(t, dtn::core::Node::CONN_TCPIP, uri, 0, -5));
234 
235  _stream << ClientHandler::API_STATUS_OK << " CONNECTION REMOVED" << std::endl;
236  }
237  }
238  else if (cmd[2] == "udp")
239  {
240  if (cmd.size() < 6) throw ibrcommon::Exception("not enough parameters");
241 
242  if (cmd[3] == "add")
243  {
244  std::string uri = "ip=" + cmd[4] + ";port=" + cmd[5] + ";";
245  n.add(dtn::core::Node::URI(t, dtn::core::Node::CONN_UDPIP, uri, 0, -5));
247 
248  _stream << ClientHandler::API_STATUS_OK << " CONNECTION ADDED" << std::endl;
249  }
250  else if (cmd[3] == "del")
251  {
252  std::string uri = "ip=" + cmd[4] + ";port=" + cmd[5] + ";";
253  n.add(dtn::core::Node::URI(t, dtn::core::Node::CONN_UDPIP, uri, 0, -5));
255 
256  _stream << ClientHandler::API_STATUS_OK << " CONNECTION REMOVED" << std::endl;
257  }
258  }
259  else if (cmd[2] == "file")
260  {
261  if (cmd[3] == "add")
262  {
265 
266  _stream << ClientHandler::API_STATUS_OK << " CONNECTION ADDED" << std::endl;
267  }
268  else if (cmd[3] == "del")
269  {
272 
273  _stream << ClientHandler::API_STATUS_OK << " CONNECTION REMOVED" << std::endl;
274  }
275  }
276  }
277  else if (cmd[0] == "logcat")
278  {
279  ibrcommon::Logger::writeBuffer(_stream);
280  _stream << std::endl;
281  }
282  else if (cmd[0] == "logstream")
283  {
284  ibrcommon::Logger::addStream(_stream, ibrcommon::Logger::LOGGER_ALL, ibrcommon::Logger::LOG_TIMESTAMP | ibrcommon::Logger::LOG_TAG | ibrcommon::Logger::LOG_LEVEL);
285 
286  std::string buffer = "";
287  getline(_stream, buffer);
288 
289  ibrcommon::Logger::removeStream(_stream);
290  _stream << ClientHandler::API_STATUS_OK << " STOPPED STREAMING" << std::endl;
291  }
292  else if (cmd[0] == "core")
293  {
294  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
295 
296  if (cmd[1] == "shutdown")
297  {
298  // send shutdown signal
300  _stream << ClientHandler::API_STATUS_OK << " SHUTDOWN" << std::endl;
301  }
302  else if (cmd[1] == "reload")
303  {
304  // send reload signal
306  _stream << ClientHandler::API_STATUS_OK << " RELOAD" << std::endl;
307  }
308  else if (cmd[1] == "low-energy")
309  {
310  // send low-energy signal
312  _stream << ClientHandler::API_STATUS_OK << " LOW_ENERGY" << std::endl;
313  }
314  else if (cmd[1] == "normal")
315  {
316  // send normal signal to disable LE mode
318  _stream << ClientHandler::API_STATUS_OK << " NORMAL" << std::endl;
319  }
320  else if (cmd[1] == "start_discovery")
321  {
322  // send wakeup signal
324  _stream << ClientHandler::API_STATUS_OK << " DISCOVERY START" << std::endl;
325  }
326  else if (cmd[1] == "stop_discovery")
327  {
328  // send wakeup signal
330  _stream << ClientHandler::API_STATUS_OK << " DISCOVERY STOP" << std::endl;
331  }
332  else if (cmd[1] == "internet_off")
333  {
334  // send internet off signal
336  _stream << ClientHandler::API_STATUS_OK << " INTERNET OFF" << std::endl;
337  }
338  else if (cmd[1] == "internet_on")
339  {
340  // send internet off signal
342  _stream << ClientHandler::API_STATUS_OK << " INTERNET ON" << std::endl;
343  }
344  }
345  else if (cmd[0] == "bundle")
346  {
347  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
348 
349  if (cmd[1] == "list")
350  {
351  // get storage object
353  BundleFilter filter;
354 
355  _stream << ClientHandler::API_STATUS_OK << " BUNDLE LIST" << std::endl;
357 
358  try {
359  bcore.getStorage().get(filter, blist);
360 
361  for (std::list<dtn::data::MetaBundle>::const_iterator iter = blist.begin(); iter != blist.end(); ++iter)
362  {
363  const dtn::data::MetaBundle &b = *iter;
364  _stream << b.toString() << ";" << b.destination.getString() << ";" << std::endl;
365  }
366  } catch (const dtn::storage::NoBundleFoundException&) { }
367 
368  // last line empty
369  _stream << std::endl;
370  }
371  else if (cmd[1] == "clear")
372  {
373  // clear the storage
375  _stream << ClientHandler::API_STATUS_OK << " STORAGE CLEARED" << std::endl;
376  }
377  }
378  else if (cmd[0] == "routing")
379  {
380  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
381 
382  if ( cmd[1] == "prophet" )
383  {
385 
386  // lock the extension list during the processing
387  ibrcommon::MutexLock l(router.getExtensionMutex());
388 
389  const dtn::routing::BaseRouter::extension_list& routingExtensions = router.getExtensions();
390  dtn::routing::BaseRouter::extension_list::const_iterator it;
391 
392  /* find the prophet extension in the BaseRouter */
393 
394  for(it = routingExtensions.begin(); it != routingExtensions.end(); ++it)
395  {
396  try
397  {
398  const dtn::routing::ProphetRoutingExtension& prophet_extension = dynamic_cast<const dtn::routing::ProphetRoutingExtension&>(**it);
399 
400  if ( cmd[2] == "info" ){
401  ibrcommon::ThreadsafeReference<const dtn::routing::DeliveryPredictabilityMap> dp_map = prophet_extension.getDeliveryPredictabilityMap();
402 
403  _stream << ClientHandler::API_STATUS_OK << " ROUTING PROPHET INFO" << std::endl;
404  _stream << *dp_map << std::endl;
405  } else if ( cmd[2] == "acknowledgements" ) {
406  ibrcommon::ThreadsafeReference<const dtn::routing::AcknowledgementSet> ack_set = prophet_extension.getAcknowledgementSet();
407 
408  _stream << ClientHandler::API_STATUS_OK << " ROUTING PROPHET ACKNOWLEDGEMENTS" << std::endl;
409  for (dtn::routing::AcknowledgementSet::const_iterator iter = (*ack_set).begin(); iter != (*ack_set).end(); ++iter)
410  {
411  const dtn::data::MetaBundle &ack = (*iter);
412  _stream << ack.toString() << " | " << ack.expiretime.toString() << std::endl;
413  }
414  _stream << std::endl;
415  } else {
416  throw ibrcommon::Exception("malformed command");
417  }
418 
419  break;
420  } catch (const std::bad_cast&) { }
421  }
422  if(it == routingExtensions.end())
423  {
424  /* no prophet routing extension found */
425  _stream << ClientHandler::API_STATUS_NOT_ACCEPTABLE << " ROUTING PROPHET EXTENSION NOT FOUND" << std::endl;
426  }
427  } else if ( cmd[1] == "static" ) {
428  if (cmd.size() < 5) throw ibrcommon::Exception("not enough parameters");
429 
430  if (cmd[2] == "add")
431  {
433  _stream << ClientHandler::API_STATUS_OK << " ROUTE ADDED FOR " << cmd[3] << " THROUGH " << cmd[4] << std::endl;
434  }
435  else if (cmd[2] == "del")
436  {
438  _stream << ClientHandler::API_STATUS_OK << " ROUTE REMOVED FOR " << cmd[3] << " THROUGH " << cmd[4] << std::endl;
439  }
440  } else {
441  throw ibrcommon::Exception("malformed command");
442  }
443  }
444  else if (cmd[0] == "stats")
445  {
446  if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
447 
448  if ( cmd[1] == "info" ) {
449  _stream << ClientHandler::API_STATUS_OK << " STATS INFO" << std::endl;
450  _stream << "Uptime: " << dtn::utils::Clock::getUptime().get<size_t>() << std::endl;
451  _stream << "Neighbors: " << dtn::core::BundleCore::getInstance().getConnectionManager().getNeighbors().size() << std::endl;
452  _stream << "Storage-size: " << dtn::core::BundleCore::getInstance().getStorage().size() << std::endl;
453  _stream << std::endl;
454  } else if ( cmd[1] == "timesync" ) {
455  _stream << ClientHandler::API_STATUS_OK << " STATS TIMESYNC" << std::endl;
456  _stream << "Timestamp: " << dtn::utils::Clock::getTime().get<size_t>() << std::endl;
457  _stream << "Offset: " << std::setprecision(6) << dtn::utils::Clock::toDouble(dtn::utils::Clock::getOffset()) << std::endl;
458  _stream << "Rating: " << std::setprecision(16) << dtn::utils::Clock::getRating() << std::endl;
460 
462 
463  _stream << "Base: " << std::setprecision(16) << state.base_rating << std::endl;
464  _stream << "Psi: " << std::setprecision(16) << state.psi << std::endl;
465  _stream << "Sigma: " << std::setprecision(16) << state.sigma << std::endl;
466  _stream << "Threshold: " << std::setprecision(6) << state.sync_threshold << std::endl;
467 
468  _stream << std::endl;
469  } else if ( cmd[1] == "bundles" ) {
470  _stream << ClientHandler::API_STATUS_OK << " STATS BUNDLES" << std::endl;
471  _stream << "Stored: " << dtn::core::BundleCore::getInstance().getStorage().count() << std::endl;
478  _stream << std::endl;
479  } else if ( cmd[1] == "convergencelayers" ) {
480  _stream << ClientHandler::API_STATUS_OK << " STATS CONVERGENCELAYERS" << std::endl;
481 
484 
485  for (dtn::net::ConvergenceLayer::stats_data::const_iterator iter = data.begin(); iter != data.end(); ++iter) {
486  const dtn::net::ConvergenceLayer::stats_pair &pair = (*iter);
487  _stream << pair.first << ": " << pair.second << std::endl;
488  }
489  _stream << std::endl;
490  } else if ( cmd[1] == "reset" ) {
497 
498  // reset cl stats
500 
501  _stream << ClientHandler::API_STATUS_ACCEPTED << " STATS RESET" << std::endl;
502  } else {
503  throw ibrcommon::Exception("malformed command");
504  }
505  }
506 #ifdef IBRDTN_SUPPORT_BSP
507  else if (cmd[0] == "key-exchange")
508  {
509  if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
510 
511  const dtn::data::EID peer(cmd[2]);
512 
513  if (cmd[1] == "none")
514  {
517 
518  _stream << ClientHandler::API_STATUS_OK << " KEY-EXCHANGE INITIATED" << std::endl;
519  }
520  else if (cmd[1] == "dh")
521  {
524 
525  _stream << ClientHandler::API_STATUS_OK << " KEY-EXCHANGE INITIATED" << std::endl;
526  }
527  else if (cmd[1] == "jpake")
528  {
529  if (cmd.size() < 4) throw ibrcommon::Exception("password required");
530 
532 
533  // set data
534  kedata.str(cmd[3]);
535 
537 
538  _stream << ClientHandler::API_STATUS_OK << " KEY-EXCHANGE INITIATED" << std::endl;
539  }
540  else if (cmd[1] == "hash")
541  {
544 
545  _stream << ClientHandler::API_STATUS_OK << " KEY-EXCHANGE INITIATED" << std::endl;
546  }
547  else if (cmd[1] == "password")
548  {
549  if (cmd.size() < 4) throw ibrcommon::Exception("password required");
550 
552 
553  // set session id
554  kedata.setSessionId(atoi(cmd[3].c_str()));
555 
556  // set data
557  kedata.str(cmd[4]);
558 
560 
561  _stream << ClientHandler::API_STATUS_OK << " KEY-EXCHANGE INITIATED" << std::endl;
562  }
563  else if (cmd[1] == "hashcompare")
564  {
565  if (cmd.size() < 4) throw ibrcommon::Exception("selection required");
566  if (cmd[4] != "0" && cmd[4] != "1") throw ibrcommon::Exception("wrong value");
567 
569 
570  // set session id
571  kedata.setSessionId(atoi(cmd[3].c_str()));
572 
573  // set step
574  kedata.setStep(atoi(cmd[4].c_str()));
575 
577 
578  _stream << ClientHandler::API_STATUS_OK << " KEY-EXCHANGE INITIATED" << std::endl;
579  }
580  else if (cmd[1] == "newkey")
581  {
582  if (cmd.size() < 4) throw ibrcommon::Exception("selection required");
583  if (cmd[4] != "0" && cmd[4] != "1") throw ibrcommon::Exception("wrong value");
584 
586 
587  // set session id
588  kedata.setSessionId(atoi(cmd[3].c_str()));
589 
590  // set step
591  kedata.setStep(atoi(cmd[4].c_str()));
592 
594 
595  if (kedata.getStep() == 0) {
596  _stream << ClientHandler::API_STATUS_OK << " NEW KEY DISCARDED" << std::endl;
597  } else {
598  _stream << ClientHandler::API_STATUS_OK << " NEW KEY ACCEPTED" << std::endl;
599  }
600  }
601  else
602  {
603  throw ibrcommon::Exception("malformed command");
604  }
605  }
606 #endif
607  else
608  {
609  _stream << ClientHandler::API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
610  }
611  } catch (const std::exception&) {
612  _stream << ClientHandler::API_STATUS_BAD_REQUEST << " ERROR" << std::endl;
613  }
614  }
615  } /* namespace api */
616 } /* namespace dtn */
std::string toString() const
Definition: BundleID.cpp:190
const extension_list & getExtensions() const
Definition: BaseRouter.cpp:90
const std::set< dtn::core::Node > getNeighbors()
dtn::data::Length size() const
ibrcommon::RWMutex & getExtensionMutex()
Definition: BaseRouter.cpp:85
std::set< RoutingExtension * > extension_list
Definition: BaseRouter.h:104
dtn::routing::BaseRouter & getRouter() const
Definition: BundleCore.cpp:227
void setGloballyConnected(bool val)
Definition: BundleCore.cpp:790
std::pair< string, string > stats_pair
void remove(const dtn::core::Node &n)
virtual dtn::data::Size count()
void getStats(dtn::net::ConvergenceLayer::stats_data &data)
void addRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop, const dtn::data::Timeout timeout=0)
Definition: BundleCore.cpp:270
dtn::net::ConnectionManager & getConnectionManager()
Definition: BundleCore.cpp:260
void add(const dtn::core::Node &n)
std::string toString() const
Definition: SDNV.h:414
static void raise(const Action a)
Definition: GlobalEvent.cpp:79
ManagementConnection(ClientHandler &client, ibrcommon::socketstream &stream)
T get() const
Definition: SDNV.h:113
ibrcommon::ThreadsafeReference< const AcknowledgementSet > getAcknowledgementSet() const
static dtn::data::Timestamp getUptime()
Definition: Clock.cpp:284
static double toDouble(const timeval &val)
Definition: Clock.cpp:280
std::map< string, string > stats_data
static dtn::data::Timestamp getTime()
Definition: Clock.cpp:167
dtn::data::EID destination
Definition: MetaBundle.h:60
virtual dtn::data::Bundle get(const dtn::data::BundleID &id)=0
void removeRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop)
Definition: BundleCore.cpp:275
static const struct timeval & getOffset()
Definition: Clock.cpp:182
ibrcommon::ThreadsafeReference< DeliveryPredictabilityMap > getDeliveryPredictabilityMap()
size_t Size
Definition: Number.h:34
static double getRating()
Definition: Clock.cpp:59
std::string getString() const
Definition: EID.cpp:374
dtn::data::BundleList::const_iterator const_iterator
static const TimeSyncState & getState()
dtn::storage::BundleStorage & getStorage()
Definition: BundleCore.cpp:237
ibrcommon::socketstream & _stream
Definition: ClientHandler.h:52
Routing extension for PRoPHET routing.
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
static BundleCore & getInstance()
Definition: BundleCore.cpp:82
static void raise(const dtn::data::EID &eid, const dtn::security::KeyExchangeData &data)