IBR-DTNSuite  0.8
daemon/src/net/LOWPANConvergenceLayer.cpp
Go to the documentation of this file.
00001 #include "net/LOWPANConvergenceLayer.h"
00002 #include "net/LOWPANConnection.h"
00003 #include "core/BundleCore.h"
00004 #include "core/TimeEvent.h"
00005 #include <ibrcommon/net/lowpanstream.h>
00006 #include <ibrcommon/net/UnicastSocketLowpan.h>
00007 #include <ibrcommon/net/lowpansocket.h>
00008 
00009 #include <ibrcommon/Logger.h>
00010 #include <ibrcommon/thread/MutexLock.h>
00011 #include <ibrcommon/TimeMeasurement.h>
00012 
00013 #include <sys/socket.h>
00014 #include <stdlib.h>
00015 #include <stdio.h>
00016 #include <string.h>
00017 
00018 #include <iostream>
00019 #include <list>
00020 
00021 #define EXTENDED_MASK   0x08
00022 #define SEQ_NUM_MASK    0x07
00023 
00024 using namespace dtn::data;
00025 
00026 namespace dtn
00027 {
00028         namespace net
00029         {
00030                 LOWPANConvergenceLayer::LOWPANConvergenceLayer(ibrcommon::vinterface net, int panid, unsigned int mtu)
00031                         : DiscoveryAgent(dtn::daemon::Configuration::getInstance().getDiscovery()),
00032                           _socket(NULL), _net(net), _panid(panid), _ipnd_buf(new char[BUFF_SIZE+2]), _ipnd_buf_len(0), m_maxmsgsize(mtu), _running(false)
00033                 {
00034                         _socket = new ibrcommon::UnicastSocketLowpan();
00035                 }
00036 
00037                 LOWPANConvergenceLayer::~LOWPANConvergenceLayer()
00038                 {
00039                         componentDown();
00040                         delete _socket;
00041                 }
00042 
00043                 dtn::core::Node::Protocol LOWPANConvergenceLayer::getDiscoveryProtocol() const
00044                 {
00045                         return dtn::core::Node::CONN_LOWPAN;
00046                 }
00047 
00048                 void LOWPANConvergenceLayer::update(const ibrcommon::vinterface &iface, std::string &name, std::string &params) throw(dtn::net::DiscoveryServiceProvider::NoServiceHereException)
00049                 {
00050                         if (iface == _net)
00051                         {
00052                                 name = "lowpancl";
00053                                 stringstream service;
00054 
00055                                 struct sockaddr_ieee802154 address;
00056                                 address.addr.addr_type = IEEE802154_ADDR_SHORT;
00057                                 address.addr.pan_id = _panid;
00058 
00059                                 // Get address via netlink
00060                                 ibrcommon::lowpansocket::getAddress(&address.addr, iface);
00061 
00062                                 //FIXME better naming for address and panid. This will need updates to the service parser.
00063                                 service << "ip=" << address.addr.short_addr << ";port=" << _panid << ";";
00064 
00065                                 params = service.str();
00066                         }
00067                         else
00068                         {
00069                                  throw dtn::net::DiscoveryServiceProvider::NoServiceHereException();
00070                         }
00071                 }
00072 
00073                 void LOWPANConvergenceLayer::send_cb(char *buf, int len, unsigned int address)
00074                 {
00075                         // Add own address at the end
00076                         struct sockaddr_ieee802154 _sockaddr;
00077                         unsigned short local_addr;
00078 
00079                         _socket->getAddress(&_sockaddr.addr, _net);
00080 
00081                         local_addr = _sockaddr.addr.short_addr;
00082 
00083                         // get a lowpan peer
00084                         ibrcommon::lowpansocket::peer p = _socket->getPeer(address, _sockaddr.addr.pan_id);
00085                         if (len > 113)
00086                                 IBRCOMMON_LOGGER(error) << "LOWPANConvergenceLayer::send_cb buffer to big to be transferred (" << len << ")."<< IBRCOMMON_LOGGER_ENDL;
00087 
00088                         // Add own address at the end
00089                         memcpy(&buf[len], &local_addr, 2);
00090 
00091                         // set write lock
00092                         ibrcommon::MutexLock l(m_writelock);
00093 
00094                         // send converted line
00095                         int ret = p.send(buf, len + 2);
00096 
00097                         if (ret == -1)
00098                         {
00099                                 // CL is busy
00100                                 throw(ibrcommon::Exception("Send on socket failed"));
00101                         }
00102                 }
00103 
00104                 void LOWPANConvergenceLayer::queue(const dtn::core::Node &node, const ConvergenceLayer::Job &job)
00105                 {
00106                         const std::list<dtn::core::Node::URI> uri_list = node.get(dtn::core::Node::CONN_LOWPAN);
00107                         if (uri_list.empty()) return;
00108 
00109                         const dtn::core::Node::URI &uri = uri_list.front();
00110 
00111                         std::string address;
00112                         unsigned int pan;
00113 
00114                         uri.decode(address, pan);
00115 
00116                         IBRCOMMON_LOGGER_DEBUG(10) << "LOWPANConvergenceLayer::queue"<< IBRCOMMON_LOGGER_ENDL;
00117 
00118                         ibrcommon::MutexLock lc(_connection_lock);
00119                         getConnection(atoi(address.c_str()))->_sender.queue(job);
00120                 }
00121 
00122                 LOWPANConnection* LOWPANConvergenceLayer::getConnection(unsigned short address)
00123                 {
00124                         // Test if connection for this address already exist
00125                         std::list<LOWPANConnection*>::iterator i;
00126                         for(i = ConnectionList.begin(); i != ConnectionList.end(); ++i)
00127                         {
00128                                 IBRCOMMON_LOGGER_DEBUG(10) << "Connection address: " << hex << (*i)->_address << IBRCOMMON_LOGGER_ENDL;
00129                                 if ((*i)->_address == address)
00130                                         return (*i);
00131                         }
00132 
00133                         // Connection does not exist, create one and put it into the list
00134                         LOWPANConnection *connection = new LOWPANConnection(address, (*this));
00135 
00136                         ConnectionList.push_back(connection);
00137                         IBRCOMMON_LOGGER_DEBUG(10) << "LOWPANConvergenceLayer::getConnection "<< connection->_address << IBRCOMMON_LOGGER_ENDL;
00138                         connection->start();
00139                         return connection;
00140                 }
00141 
00142                 void LOWPANConvergenceLayer::remove(const LOWPANConnection *conn)
00143                 {
00144                         ibrcommon::MutexLock lc(_connection_lock);
00145 
00146                         std::list<LOWPANConnection*>::iterator i;
00147                         for(i = ConnectionList.begin(); i != ConnectionList.end(); ++i)
00148                         {
00149                                 if ((*i) == conn)
00150                                 {
00151                                         ConnectionList.erase(i);
00152                                         return;
00153                                 }
00154                         }
00155                 }
00156 
00157                 void LOWPANConvergenceLayer::componentUp()
00158                 {
00159                         bindEvent(dtn::core::TimeEvent::className);
00160                         try {
00161                                 try {
00162                                         ibrcommon::UnicastSocketLowpan &sock = dynamic_cast<ibrcommon::UnicastSocketLowpan&>(*_socket);
00163                                         sock.bind(_panid, _net);
00164 
00165                                         addService(this);
00166                                 } catch (const std::bad_cast&) {
00167 
00168                                 }
00169                         } catch (const ibrcommon::lowpansocket::SocketException &ex) {
00170                                 IBRCOMMON_LOGGER_DEBUG(10) << "Failed to add LOWPAN ConvergenceLayer on " << _net.toString() << ":" << _panid << IBRCOMMON_LOGGER_ENDL;
00171                                 IBRCOMMON_LOGGER_DEBUG(10) << "Exception: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00172                         }
00173                 }
00174 
00175                 void LOWPANConvergenceLayer::componentDown()
00176                 {
00177                         unbindEvent(dtn::core::TimeEvent::className);
00178                         stop();
00179                         join();
00180                 }
00181 
00182                 void LOWPANConvergenceLayer::sendAnnoucement(const u_int16_t &sn, std::list<dtn::net::DiscoveryService> &services)
00183                 {
00184                         IBRCOMMON_LOGGER_DEBUG(10) << "LOWPAN IPND beacon send started" << IBRCOMMON_LOGGER_ENDL;
00185 
00186                         DiscoveryAnnouncement announcement(DiscoveryAnnouncement::DISCO_VERSION_01, dtn::core::BundleCore::local);
00187 
00188                         // set sequencenumber
00189                         announcement.setSequencenumber(sn);
00190 
00191                         // clear all services
00192                         announcement.clearServices();
00193 
00194                         // add services
00195                         for (std::list<DiscoveryService>::iterator iter = services.begin(); iter != services.end(); iter++)
00196                         {
00197                                 DiscoveryService &service = (*iter);
00198 
00199                                 try {
00200                                         // update service information
00201                                         service.update(_net);
00202 
00203                                         // add service to discovery message
00204                                         announcement.addService(service);
00205                                 } catch (const dtn::net::DiscoveryServiceProvider::NoServiceHereException&) {
00206 
00207                                 }
00208                         }
00209                         // Set extended header bit. Everything else 0
00210                         _ipnd_buf[0] =  0x08;
00211                         // Set discovery bit in extended header
00212                         _ipnd_buf[1] = 0x80;
00213 
00214                         // serialize announcement
00215                         stringstream ss;
00216                         ss << announcement;
00217 
00218                         int len = ss.str().size();
00219                         if (len > 111)
00220                                 IBRCOMMON_LOGGER(error) << "Discovery announcement to big (" << len << ")" << IBRCOMMON_LOGGER_ENDL;
00221 
00222                         memcpy(_ipnd_buf+2, ss.str().c_str(), len);
00223 
00224                         send_cb(_ipnd_buf, len + 2, 0xffff);
00225                 }
00226 
00227                 void LOWPANConvergenceLayer::componentRun()
00228                 {
00229                         _running = true;
00230 
00231                         while (_running)
00232                         {
00233                                 ibrcommon::MutexLock l(m_readlock);
00234 
00235                                 char data[m_maxmsgsize];
00236                                 char header;
00237                                 unsigned short address;
00238 
00239                                 IBRCOMMON_LOGGER_DEBUG(10) << "LOWPANConvergenceLayer::componentRun early" << IBRCOMMON_LOGGER_ENDL;
00240 
00241                                 // Receive full frame from socket
00242                                 int len = _socket->receive(data, m_maxmsgsize);
00243 
00244                                 IBRCOMMON_LOGGER_DEBUG(10) << "LOWPANConvergenceLayer::componentRun" << IBRCOMMON_LOGGER_ENDL;
00245 
00246                                 // We got nothing from the socket, keep reading
00247                                 if (len <= 0)
00248                                         continue;
00249 
00250                                 // Retrieve header of frame
00251                                 header = data[0];
00252 
00253                                 // Retrieve sender address from the end of the frame
00254                                 address = ((char)data[len-1] << 8) | data[len-2];
00255 
00256                                 // Check for extended header and retrieve if available
00257                                 if ((header & EXTENDED_MASK) && (data[1] & 0x80)) {
00258                                         IBRCOMMON_LOGGER_DEBUG(10) << "Received announcement for LoWPAN discovery: ADDRESS " << address << IBRCOMMON_LOGGER_ENDL;
00259                                         DiscoveryAnnouncement announce;
00260                                         stringstream ss;
00261                                         ss.write(data+2, len-4);
00262                                         ss >> announce;
00263                                         DiscoveryAgent::received(announce, 30);
00264                                         continue;
00265                                 }
00266 
00267                                 ibrcommon::MutexLock lc(_connection_lock);
00268 
00269                                 // Connection instance for this address
00270                                 LOWPANConnection* connection = getConnection(address);
00271 
00272                                 // Decide in which queue to write based on the src address
00273                                 connection->getStream().queue(data, len-2); // Cut off address from end
00274 
00275                                 yield();
00276                         }
00277                 }
00278 
00279                 void LOWPANConvergenceLayer::raiseEvent(const Event *evt)
00280                 {
00281                         try {
00282                                 const TimeEvent &time=dynamic_cast<const TimeEvent&>(*evt);
00283                                 if (time.getAction() == TIME_SECOND_TICK)
00284                                         if (time.getTimestamp()%5 == 0)
00285                                                 timeout();
00286                         } catch (const std::bad_cast&)
00287                         {}
00288                 }
00289 
00290                 void LOWPANConvergenceLayer::__cancellation()
00291                 {
00292                         _running = false;
00293                         _socket->shutdown();
00294                 }
00295 
00296                 const std::string LOWPANConvergenceLayer::getName() const
00297                 {
00298                         return "LOWPANConvergenceLayer";
00299                 }
00300         }
00301 }