IBR-DTNSuite  0.8
daemon/src/api/ClientHandler.cpp
Go to the documentation of this file.
00001 /*
00002  * ClientHandler.cpp
00003  *
00004  *  Created on: 24.06.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "config.h"
00009 #include "Configuration.h"
00010 #include "api/ClientHandler.h"
00011 #include "api/BinaryStreamClient.h"
00012 #include "api/ManagementConnection.h"
00013 #include "api/EventConnection.h"
00014 #include "api/ExtendedApiHandler.h"
00015 #include "api/OrderedStreamHandler.h"
00016 #include "core/BundleCore.h"
00017 #include <ibrcommon/Logger.h>
00018 #include <ibrdtn/utils/Utils.h>
00019 #include <ibrcommon/net/LinkManager.h>
00020 
00021 namespace dtn
00022 {
00023         namespace api
00024         {
00025                 ProtocolHandler::ProtocolHandler(ClientHandler &client, ibrcommon::tcpstream &stream)
00026                  : _client(client), _stream(stream)
00027                 {
00028                 }
00029 
00030                 ProtocolHandler::~ProtocolHandler()
00031                 {}
00032 
00033                 ClientHandler::ClientHandler(ApiServerInterface &srv, Registration &registration, ibrcommon::tcpstream *conn)
00034                  : _srv(srv), _registration(&registration), _stream(conn), _endpoint(dtn::core::BundleCore::local), _handler(NULL)
00035                 {
00036                         if ( dtn::daemon::Configuration::getInstance().getNetwork().getTCPOptionNoDelay() )
00037                         {
00038                                 _stream->enableNoDelay();
00039                         }
00040                 }
00041 
00042                 ClientHandler::~ClientHandler()
00043                 {
00044                         delete _stream;
00045                 }
00046 
00047                 Registration& ClientHandler::getRegistration()
00048                 {
00049                         return *_registration;
00050                 }
00051 
00052                 ApiServerInterface& ClientHandler::getAPIServer()
00053                 {
00054                         return _srv;
00055                 }
00056 
00057                 void ClientHandler::switchRegistration(Registration &reg)
00058                 {
00059                         _registration->abort();
00060 
00061                         _srv.freeRegistration(*_registration);
00062 
00063                         _registration = &reg;
00064                 }
00065 
00066                 void ClientHandler::setup()
00067                 {
00068                 }
00069 
00070                 void ClientHandler::run()
00071                 {
00072                         // signal the active connection to the server
00073                         _srv.connectionUp(this);
00074 
00075                         std::string buffer;
00076 
00077                         while (_stream->good())
00078                         {
00079                                 if (_handler != NULL)
00080                                 {
00081                                         _handler->setup();
00082                                         _handler->run();
00083                                         _handler->finally();
00084                                         delete _handler;
00085                                         _handler = NULL;
00086 
00087                                         // end this stream, return to the previous stage
00088                                         (*_stream) << ClientHandler::API_STATUS_OK << " SWITCHED TO LEVEL 0" << std::endl;
00089 
00090                                         continue;
00091                                 }
00092 
00093                                 getline(*_stream, buffer);
00094 
00095                                 // search for '\r\n' and remove the '\r'
00096                                 std::string::reverse_iterator iter = buffer.rbegin();
00097                                 if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
00098 
00099                                 std::vector<std::string> cmd = dtn::utils::Utils::tokenize(" ", buffer);
00100                                 if (cmd.size() == 0) continue;
00101 
00102                                 try {
00103                                         if (cmd[0] == "protocol")
00104                                         {
00105                                                 if (cmd[1] == "tcpcl")
00106                                                 {
00107                                                         // switch to binary protocol (old style api)
00108                                                         _handler = new BinaryStreamClient(*this, *_stream);
00109                                                         continue;
00110                                                 }
00111                                                 else if (cmd[1] == "management")
00112                                                 {
00113                                                         // switch to the management protocol
00114                                                         _handler = new ManagementConnection(*this, *_stream);
00115                                                         continue;
00116                                                 }
00117                                                 else if (cmd[1] == "event")
00118                                                 {
00119                                                         // switch to the management protocol
00120                                                         _handler = new EventConnection(*this, *_stream);
00121                                                         continue;
00122                                                 }
00123                                                 else if (cmd[1] == "extended")
00124                                                 {
00125                                                         // switch to the extended api
00126                                                         _handler = new ExtendedApiHandler(*this, *_stream);
00127                                                         continue;
00128                                                 }
00129                                                 else if (cmd[1] == "streaming")
00130                                                 {
00131                                                         // switch to the streaming api
00132                                                         _handler = new OrderedStreamHandler(*this, *_stream);
00133                                                         continue;
00134                                                 }
00135                                                 else
00136                                                 {
00137                                                         error(API_STATUS_NOT_ACCEPTABLE, "UNKNOWN PROTOCOL");
00138                                                 }
00139                                         }
00140                                         else
00141                                         {
00142                                                 // forward to standard command set
00143                                                 processCommand(cmd);
00144                                         }
00145                                 } catch (const std::exception&) {
00146                                         error(API_STATUS_BAD_REQUEST, "PROTOCOL ERROR");
00147                                 }
00148                         }
00149                 }
00150 
00151                 void ClientHandler::error(STATUS_CODES code, const std::string &msg)
00152                 {
00153                         ibrcommon::MutexLock l(_write_lock);
00154                         (*_stream) << code << " " << msg << std::endl;
00155                 }
00156 
00157                 void ClientHandler::__cancellation()
00158                 {
00159                         // close the stream
00160                         (*_stream).close();
00161                 }
00162 
00163                 void ClientHandler::finally()
00164                 {
00165                         IBRCOMMON_LOGGER_DEBUG(60) << "ApiConnection down" << IBRCOMMON_LOGGER_ENDL;
00166 
00167                         // remove the client from the list in ApiServer
00168                         _srv.connectionDown(this);
00169 
00170                         _registration->abort();
00171                         _srv.freeRegistration(*_registration);
00172 
00173                         // close the stream
00174                         try {
00175                                 (*_stream).close();
00176                         } catch (const ibrcommon::ConnectionClosedException&) { };
00177                 }
00178 
00179                 void ClientHandler::eventNodeAvailable(const dtn::core::Node &node)
00180                 {
00181                 }
00182 
00183                 void ClientHandler::eventNodeUnavailable(const dtn::core::Node &node)
00184                 {
00185                 }
00186 
00187                 void ClientHandler::processCommand(const std::vector<std::string> &cmd)
00188                 {
00189                         class BundleFilter : public dtn::storage::BundleStorage::BundleFilterCallback
00190                         {
00191                         public:
00192                                 BundleFilter()
00193                                 {};
00194 
00195                                 virtual ~BundleFilter() {};
00196 
00197                                 virtual size_t limit() const { return 0; };
00198 
00199                                 virtual bool shouldAdd(const dtn::data::MetaBundle &meta) const
00200                                 {
00201                                         return true;
00202                                 }
00203                         };
00204 
00205                         try {
00206                                 if (cmd[0] == "set")
00207                                 {
00208                                         if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
00209 
00210                                         if (cmd[1] == "endpoint")
00211                                         {
00212                                                 if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
00213 
00214                                                 ibrcommon::MutexLock l(_write_lock);
00215                                                 _endpoint = dtn::core::BundleCore::local + "/" + cmd[2];
00216 
00217                                                 // error checking
00218                                                 if (_endpoint == dtn::data::EID())
00219                                                 {
00220                                                         (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID ENDPOINT" << std::endl;
00221                                                         _endpoint = dtn::core::BundleCore::local;
00222                                                 }
00223                                                 else
00224                                                 {
00225                                                         _registration->subscribe(_endpoint);
00226                                                         (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
00227                                                 }
00228                                         }
00229                                         else
00230                                         {
00231                                                 ibrcommon::MutexLock l(_write_lock);
00232                                                 (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
00233                                         }
00234                                 }
00235                                 else if (cmd[0] == "registration")
00236                                 {
00237                                         if (cmd.size() < 2) throw ibrcommon::Exception("not enough parameters");
00238 
00239                                         if (cmd[1] == "add")
00240                                         {
00241                                                 if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
00242 
00243                                                 ibrcommon::MutexLock l(_write_lock);
00244                                                 dtn::data::EID endpoint(cmd[2]);
00245 
00246                                                 // error checking
00247                                                 if (endpoint == dtn::data::EID())
00248                                                 {
00249                                                         (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID EID" << std::endl;
00250                                                 }
00251                                                 else
00252                                                 {
00253                                                         _registration->subscribe(endpoint);
00254                                                         (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
00255                                                 }
00256                                         }
00257                                         else if (cmd[1] == "del")
00258                                         {
00259                                                 if (cmd.size() < 3) throw ibrcommon::Exception("not enough parameters");
00260 
00261                                                 ibrcommon::MutexLock l(_write_lock);
00262                                                 dtn::data::EID endpoint(cmd[2]);
00263 
00264                                                 // error checking
00265                                                 if (endpoint == dtn::data::EID())
00266                                                 {
00267                                                         (*_stream) << API_STATUS_NOT_ACCEPTABLE << " INVALID EID" << std::endl;
00268                                                 }
00269                                                 else
00270                                                 {
00271                                                         _registration->unsubscribe(endpoint);
00272                                                         (*_stream) << API_STATUS_ACCEPTED << " OK" << std::endl;
00273                                                 }
00274                                         }
00275                                         else if (cmd[1] == "list")
00276                                         {
00277                                                 ibrcommon::MutexLock l(_write_lock);
00278                                                 const std::set<dtn::data::EID> list = _registration->getSubscriptions();
00279 
00280                                                 (*_stream) << API_STATUS_OK << " REGISTRATION LIST" << std::endl;
00281                                                 for (std::set<dtn::data::EID>::const_iterator iter = list.begin(); iter != list.end(); iter++)
00282                                                 {
00283                                                         (*_stream) << (*iter).getString() << std::endl;
00284                                                 }
00285                                                 (*_stream) << std::endl;
00286                                         }
00287                                         else
00288                                         {
00289                                                 ibrcommon::MutexLock l(_write_lock);
00290                                                 (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
00291                                         }
00292                                 }
00293                                 else
00294                                 {
00295                                         ibrcommon::MutexLock l(_write_lock);
00296                                         (*_stream) << API_STATUS_BAD_REQUEST << " UNKNOWN COMMAND" << std::endl;
00297                                 }
00298                         } catch (const std::exception&) {
00299                                 ibrcommon::MutexLock l(_write_lock);
00300                                 (*_stream) << API_STATUS_BAD_REQUEST << " ERROR" << std::endl;
00301                         }
00302                 }
00303         }
00304 }