IBR-DTNSuite  0.8
daemon/src/net/DiscoveryAnnouncement.cpp
Go to the documentation of this file.
00001 /*
00002  * DiscoveryAnnouncement.cpp
00003  *
00004  *  Created on: 11.09.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "net/DiscoveryAnnouncement.h"
00009 #include <ibrdtn/data/Exceptions.h>
00010 #include <ibrdtn/data/SDNV.h>
00011 #include <ibrcommon/Logger.h>
00012 #include <netinet/in.h>
00013 #include <typeinfo>
00014 #include <iostream>
00015 
00016 using namespace dtn::data;
00017 
00018 namespace dtn
00019 {
00020         namespace net
00021         {
00022                 DiscoveryAnnouncement::DiscoveryAnnouncement(const DiscoveryVersion version, dtn::data::EID eid)
00023                  : _version(version), _flags(BEACON_NO_FLAGS), _canonical_eid(eid)
00024                 {
00025                 }
00026 
00027                 DiscoveryAnnouncement::~DiscoveryAnnouncement()
00028                 {
00029                 }
00030 
00031                 bool DiscoveryAnnouncement::isShort()
00032                 {
00033                         switch (_version)
00034                         {
00035                         case DISCO_VERSION_00:
00036                                 return (_flags & DiscoveryAnnouncement::BEACON_SHORT);
00037 
00038                         case DISCO_VERSION_01:
00039                                 return !(_flags & DiscoveryAnnouncement::BEACON_SERVICE_BLOCK);
00040                         };
00041 
00042                         return false;
00043                 }
00044 
00045                 dtn::data::EID DiscoveryAnnouncement::getEID() const
00046                 {
00047                         return _canonical_eid;
00048                 }
00049 
00050                 const list<DiscoveryService> DiscoveryAnnouncement::getServices() const
00051                 {
00052                         return _services;
00053                 }
00054 
00055                 void DiscoveryAnnouncement::clearServices()
00056                 {
00057                         _services.clear();
00058                 }
00059 
00060                 const DiscoveryService& DiscoveryAnnouncement::getService(string name) const
00061                 {
00062                         for (std::list<DiscoveryService>::const_iterator iter = _services.begin(); iter != _services.end(); iter++)
00063                         {
00064                                 if ((*iter).getName() == name)
00065                                 {
00066                                         return (*iter);
00067                                 }
00068                         }
00069 
00070                         throw dtn::MissingObjectException("No service found with tag " + name);
00071                 }
00072 
00073                 void DiscoveryAnnouncement::addService(DiscoveryService service)
00074                 {
00075                         _services.push_back(service);
00076                 }
00077 
00078                 void DiscoveryAnnouncement::setSequencenumber(u_int16_t sequence)
00079                 {
00080                         _sn = sequence;
00081                 }
00082 
00083                 std::ostream &operator<<(std::ostream &stream, const DiscoveryAnnouncement &announcement)
00084                 {
00085                         const list<DiscoveryService> &services = announcement._services;
00086 
00087                         switch (announcement._version)
00088                         {
00089                                 case DiscoveryAnnouncement::DISCO_VERSION_00:
00090                                 {
00091                                         if (services.empty())
00092                                         {
00093                                                 unsigned char flags = DiscoveryAnnouncement::BEACON_SHORT | announcement._flags;
00094                                                 stream << (unsigned char)DiscoveryAnnouncement::DISCO_VERSION_00 << flags;
00095                                                 return stream;
00096                                         }
00097 
00098                                         dtn::data::BundleString eid(announcement._canonical_eid.getString());
00099                                         dtn::data::SDNV beacon_len;
00100 
00101                                         // determine the beacon length
00102                                         beacon_len += eid.getLength();
00103 
00104                                         // add service block length
00105                                         for (list<DiscoveryService>::const_iterator iter = services.begin(); iter != services.end(); iter++)
00106                                         {
00107                                                 beacon_len += (*iter).getLength();
00108                                         }
00109 
00110                                         stream << (unsigned char)DiscoveryAnnouncement::DISCO_VERSION_00 << announcement._flags << beacon_len << eid;
00111 
00112                                         for (list<DiscoveryService>::const_iterator iter = services.begin(); iter != services.end(); iter++)
00113                                         {
00114                                                 stream << (*iter);
00115                                         }
00116 
00117                                         break;
00118                                 }
00119 
00120                                 case DiscoveryAnnouncement::DISCO_VERSION_01:
00121                                 {
00122                                         unsigned char flags = 0;
00123 
00124                                         stream << (unsigned char)DiscoveryAnnouncement::DISCO_VERSION_01;
00125 
00126                                         if (announcement._canonical_eid != EID())
00127                                         {
00128                                                 flags |= DiscoveryAnnouncement::BEACON_CONTAINS_EID;
00129                                         }
00130 
00131                                         if (!services.empty())
00132                                         {
00133                                                 flags |= DiscoveryAnnouncement::BEACON_SERVICE_BLOCK;
00134                                         }
00135 
00136                                         stream << flags;
00137 
00138                                         // sequencenumber
00139                                         u_int16_t sn = htons(announcement._sn);
00140                                         stream.write( (char*)&sn, 2 );
00141 
00142                                         if ( flags && DiscoveryAnnouncement::BEACON_CONTAINS_EID )
00143                                         {
00144                                                 dtn::data::BundleString eid(announcement._canonical_eid.getString());
00145                                                 stream << eid;
00146                                         }
00147 
00148                                         if ( flags && DiscoveryAnnouncement::BEACON_SERVICE_BLOCK )
00149                                         {
00150                                                 stream << dtn::data::SDNV(services.size());
00151 
00152                                                 for (list<DiscoveryService>::const_iterator iter = services.begin(); iter != services.end(); iter++)
00153                                                 {
00154                                                         stream << (*iter);
00155                                                 }
00156                                         }
00157 
00158                                         break;
00159                                 }
00160 
00161                                 case DiscoveryAnnouncement::DTND_IPDISCOVERY:
00162                                 {
00163                                         u_int8_t cl_type = 1;
00164                                         char zero = '\0';
00165                                         u_int8_t interval = 10;
00166                                         // u_int32_t inet_addr;
00167                                         u_int16_t inet_port = htons(4556);
00168                                         std::string eid = announcement._canonical_eid.getString();
00169                                         u_int16_t eid_len = htons(eid.length());
00170                                         unsigned int add_zeros = (4 - (eid.length() % 4)) % 4;
00171                                         u_int16_t length = htons(12 + eid.length() + add_zeros);
00172 
00173 
00174                                         stream << (unsigned char)cl_type;
00175                                         stream.write((char*)&interval, 1);
00176                                         stream.write((char*)&length, 2);
00177 
00178 //                                      std::list<dtn::daemon::Configuration::NetConfig> interfaces = dtn::daemon::Configuration::getInstance().getInterfaces();
00179 //                                      dtn::daemon::Configuration::NetConfig &i = interfaces.front();
00180 
00181 //                                      struct sockaddr_in sock_address;
00182 //
00183 //                                      // set the local interface address
00184 //                                      i.interface.getAddress(&sock_address.sin_addr);
00185 //
00186 //                                      stream.write((char*)&sock_address.sin_addr, 4);
00187                                         stream.write(&zero, 1);
00188                                         stream.write(&zero, 1);
00189                                         stream.write(&zero, 1);
00190                                         stream.write(&zero, 1);
00191 
00192                                         stream.write((char*)&inet_port, 2);
00193                                         stream.write((char*)&eid_len, 2);
00194                                         stream << eid;
00195 
00196                                         for (unsigned int i = 0; i < add_zeros; i++)
00197                                         {
00198                                                 stream.write((char*)&zero, 1);
00199                                         }
00200 
00201                                         break;
00202                                 }
00203                         }
00204 
00205                         return stream;
00206                 }
00207 
00208                 std::istream &operator>>(std::istream &stream, DiscoveryAnnouncement &announcement)
00209                 {
00210                         unsigned char version = 0;
00211 
00212                         // do we running DTN2 compatibility mode?
00213                         if (announcement._version == DiscoveryAnnouncement::DTND_IPDISCOVERY)
00214                         {
00215                                 // set version to IPDiscovery (DTN2)
00216                                 version = DiscoveryAnnouncement::DTND_IPDISCOVERY;
00217                         }
00218                         else
00219                         {
00220                                 // read IPND version of the frame
00221                                 version = stream.get();
00222                         }
00223 
00224                         switch (version)
00225                         {
00226                         case DiscoveryAnnouncement::DISCO_VERSION_00:
00227                         {
00228                                 IBRCOMMON_LOGGER_DEBUG(15) << "beacon version 1 received" << IBRCOMMON_LOGGER_ENDL;
00229 
00230                                 dtn::data::SDNV beacon_len;
00231                                 dtn::data::SDNV eid_len;
00232 
00233                                 stream.get((char&)announcement._flags);
00234 
00235                                 // catch a short beacon
00236                                 if (DiscoveryAnnouncement::BEACON_SHORT == announcement._flags)
00237                                 {
00238                                         announcement._canonical_eid = dtn::data::EID();
00239                                         return stream;
00240                                 }
00241 
00242                                 stream >> beacon_len; int remain = beacon_len.getValue();
00243 
00244                                 dtn::data::BundleString eid;
00245                                 stream >> eid; remain -= eid.getLength();
00246                                 announcement._canonical_eid = dtn::data::EID((std::string)eid);
00247 
00248                                 // get the services
00249                                 list<DiscoveryService> &services = announcement._services;
00250 
00251                                 // clear the services
00252                                 services.clear();
00253 
00254                                 while (remain > 0)
00255                                 {
00256                                         // decode the service blocks
00257                                         DiscoveryService service;
00258                                         stream >> service;
00259                                         services.push_back(service);
00260                                         remain -= service.getLength();
00261                                 }
00262                                 break;
00263                         }
00264 
00265                         case DiscoveryAnnouncement::DISCO_VERSION_01:
00266                         {
00267                                 IBRCOMMON_LOGGER_DEBUG(15) << "beacon version 2 received" << IBRCOMMON_LOGGER_ENDL;
00268 
00269                                 stream.get((char&)announcement._flags);
00270 
00271                                 IBRCOMMON_LOGGER_DEBUG(25) << "beacon flags: " << hex << (int)announcement._flags << IBRCOMMON_LOGGER_ENDL;
00272 
00273                                 u_int16_t sn = 0;
00274                                 stream.read((char*)&sn, 2);
00275 
00276                                 // convert from network byte order
00277                                 u_int16_t sequencenumber = ntohs(sn);
00278 
00279                                 IBRCOMMON_LOGGER_DEBUG(25) << "beacon sequence number: " << sequencenumber << IBRCOMMON_LOGGER_ENDL;
00280 
00281                                 if (announcement._flags & DiscoveryAnnouncement::BEACON_CONTAINS_EID)
00282                                 {
00283                                         dtn::data::BundleString eid;
00284                                         stream >> eid;
00285 
00286                                         announcement._canonical_eid = dtn::data::EID((std::string)eid);
00287 
00288                                         IBRCOMMON_LOGGER_DEBUG(25) << "beacon eid: " << (std::string)eid << IBRCOMMON_LOGGER_ENDL;
00289                                 }
00290 
00291                                 if (announcement._flags & DiscoveryAnnouncement::BEACON_SERVICE_BLOCK)
00292                                 {
00293                                         // get the services
00294                                         list<DiscoveryService> &services = announcement._services;
00295 
00296                                         // read the number of services
00297                                         dtn::data::SDNV num_services;
00298                                         stream >> num_services;
00299 
00300                                         IBRCOMMON_LOGGER_DEBUG(25) << "beacon services (" << num_services.getValue() << "): " << IBRCOMMON_LOGGER_ENDL;
00301 
00302                                         // clear the services
00303                                         services.clear();
00304 
00305                                         for (unsigned int i = 0; i < num_services.getValue(); i++)
00306                                         {
00307                                                 // decode the service blocks
00308                                                 DiscoveryService service;
00309                                                 stream >> service;
00310                                                 services.push_back(service);
00311 
00312                                                 IBRCOMMON_LOGGER_DEBUG(25) << "\t " << service.getName() << " [" << service.getParameters() << "]" << IBRCOMMON_LOGGER_ENDL;
00313                                         }
00314                                 }
00315 
00316                                 if (announcement._flags & DiscoveryAnnouncement::BEACON_BLOOMFILTER)
00317                                 {
00318                                         // TODO: read the bloomfilter
00319                                 }
00320 
00321                                 break;
00322                         }
00323 
00324                         case DiscoveryAnnouncement::DTND_IPDISCOVERY:
00325                         {
00326                                 u_int8_t cl_type;
00327                                 u_int8_t interval;
00328                                 u_int16_t length;
00329                                 u_int32_t inet_addr;
00330                                 u_int16_t inet_port;
00331                                 u_int16_t eid_len;
00332 
00333                                 IBRCOMMON_LOGGER_DEBUG(15) << "beacon IPDiscovery (DTN2) frame received" << IBRCOMMON_LOGGER_ENDL;
00334 
00335                                 stream.read((char*)&cl_type, 1);
00336                                 stream.read((char*)&interval, 1);
00337                                 stream.read((char*)&length, 2);
00338                                 stream.read((char*)&inet_addr, 4);
00339                                 stream.read((char*)&inet_port, 2);
00340                                 stream.read((char*)&eid_len, 2);
00341 
00342                                 char eid[eid_len];
00343                                 stream.read((char*)&eid, eid_len);
00344 
00345                                 announcement._version = DiscoveryAnnouncement::DTND_IPDISCOVERY;
00346                                 announcement._canonical_eid = EID(std::string(eid));
00347 
00348                                 break;
00349                         }
00350 
00351                         default:
00352                                 IBRCOMMON_LOGGER_DEBUG(20) << "unknown beacon received" << IBRCOMMON_LOGGER_ENDL;
00353 
00354                                 // Error, throw Exception!
00355                                 throw InvalidProtocolException("The received data does not match the discovery protocol.");
00356 
00357                                 break;
00358                         }
00359 
00360                         return stream;
00361                 }
00362 
00363                 string DiscoveryAnnouncement::toString() const
00364                 {
00365                         stringstream ss;
00366                         ss << "ANNOUNCE: " << _canonical_eid.getString();
00367                         return ss.str();
00368                 }
00369         }
00370 }