IBR-DTNSuite  0.8
daemon/src/net/LOWPANDatagramService.cpp
Go to the documentation of this file.
00001 /*
00002  * LOWPANDatagramService.cpp
00003  *
00004  *  Created on: 24.11.2011
00005  *      Author: morgenro
00006  */
00007 
00008 #include "net/LOWPANDatagramService.h"
00009 #include <ibrdtn/utils/Utils.h>
00010 
00011 #include <ibrcommon/net/lowpanstream.h>
00012 #include <ibrcommon/net/UnicastSocketLowpan.h>
00013 
00014 #include <ibrcommon/Logger.h>
00015 
00016 #include <string.h>
00017 
00018 #define EXTENDED_MASK   0x40
00019 #define SEQ_NUM_MASK    0x07
00020 
00021 namespace dtn
00022 {
00023         namespace net
00024         {
00025                 LOWPANDatagramService::LOWPANDatagramService(const ibrcommon::vinterface &iface, int panid)
00026                  : _panid(panid), _iface(iface)
00027                 {
00028                         // set connection parameters
00029                         _params.max_msg_length = 111;
00030                         _params.max_seq_numbers = 8;
00031                         _params.flowcontrol = DatagramConnectionParameter::FLOW_NONE;
00032 
00033                         _socket = new ibrcommon::UnicastSocketLowpan();
00034                 }
00035 
00036                 LOWPANDatagramService::~LOWPANDatagramService()
00037                 {
00038                         delete _socket;
00039                 }
00040 
00045                 void LOWPANDatagramService::bind() throw (DatagramException)
00046                 {
00047                         try {
00048                                 // bind socket to interface
00049                                 ibrcommon::UnicastSocketLowpan &sock = dynamic_cast<ibrcommon::UnicastSocketLowpan&>(*_socket);
00050                                 sock.bind(_panid, _iface);
00051                         } catch (const std::bad_cast&) {
00052                                 throw DatagramException("bind failed");
00053                         } catch (const ibrcommon::Exception&) {
00054                                 throw DatagramException("bind failed");
00055                         }
00056                 }
00057 
00061                 void LOWPANDatagramService::shutdown()
00062                 {
00063                         // abort socket operations
00064                         _socket->shutdown();
00065                 }
00066 
00073                 void LOWPANDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const std::string &identifier, const char *buf, size_t length) throw (DatagramException)
00074                 {
00075                         try {
00076                                 // Add own address at the end
00077                                 struct sockaddr_ieee802154 sockaddr;
00078                                 unsigned short local_addr;
00079 
00080                                 if (length > _params.max_msg_length)
00081                                 {
00082                                         IBRCOMMON_LOGGER(error) << "LOWPANConvergenceLayer::send buffer to big to be transferred (" << length << ")."<< IBRCOMMON_LOGGER_ENDL;
00083                                         throw DatagramException("send failed - buffer to big to be transferred");
00084                                 }
00085 
00086                                 // get the local address
00087                                 _socket->getAddress(&sockaddr.addr, _iface);
00088                                 local_addr = sockaddr.addr.short_addr;
00089 
00090                                 // decode destination address
00091                                 uint16_t addr = 0;
00092                                 int panid = 0;
00093                                 size_t end_of_payload = length + 1;
00094                                 LOWPANDatagramService::decode(identifier, addr, panid);
00095 
00096                                 // get a lowpan peer
00097                                 ibrcommon::lowpansocket::peer p = _socket->getPeer(addr, panid);
00098 
00099                                 // buffer for the datagram plus local address
00100                                 char tmp[length + 4];
00101 
00102                                 // encode the flags (4-bit) + seqno (4-bit)
00103                                 tmp[0] = (0x30 & (flags << 4)) | (0x0f & seqno);
00104 
00105                                 // Need to encode flags, type and seqno into the message
00106                                 if (type == DatagramConvergenceLayer::HEADER_SEGMENT)
00107                                 {
00108                                         // copy payload to the new buffer
00109                                         ::memcpy(&tmp[1], buf, length);
00110                                 }
00111                                 else
00112                                 {
00113                                         // set datagram to extended
00114                                         tmp[0] |= EXTENDED_MASK;
00115 
00116                                         // encode the type into the second byte
00117                                         tmp[1] = type;
00118 
00119                                         // copy payload to the new buffer
00120                                         ::memcpy(&tmp[2], buf, length);
00121 
00122                                         // payload will be one byte longer with extended header
00123                                         end_of_payload++;
00124                                 }
00125 
00126                                 // Add own address at the end
00127                                 memcpy(&tmp[end_of_payload], &local_addr, 2);
00128 
00129                                 // send converted line
00130                                 if (p.send(buf, end_of_payload + 2) == -1)
00131                                 {
00132                                         // CL is busy
00133                                         throw DatagramException("send on socket failed");
00134                                 }
00135                         } catch (const ibrcommon::Exception&) {
00136                                 throw DatagramException("send failed");
00137                         }
00138                 }
00139 
00145                 void LOWPANDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const char *buf, size_t length) throw (DatagramException)
00146                 {
00147                         try {
00148                                 // Add own address at the end
00149                                 struct sockaddr_ieee802154 sockaddr;
00150                                 unsigned short local_addr;
00151 
00152                                 if (length > _params.max_msg_length)
00153                                 {
00154                                         IBRCOMMON_LOGGER(error) << "LOWPANConvergenceLayer::send buffer to big to be transferred (" << length << ")."<< IBRCOMMON_LOGGER_ENDL;
00155                                         throw DatagramException("send failed - buffer to big to be transferred");
00156                                 }
00157 
00158                                 // get the local address
00159                                 _socket->getAddress(&sockaddr.addr, _iface);
00160                                 local_addr = sockaddr.addr.short_addr;
00161 
00162                                 // get a lowpan peer
00163                                 ibrcommon::lowpansocket::peer p = _socket->getPeer(BROADCAST_ADDR, _panid);
00164 
00165                                 // extend the buffer if the len is zero (ACKs)
00166                                 if (length == 0) length++;
00167 
00168                                 // buffer for the datagram plus local address
00169                                 char tmp[length + 4];
00170 
00171                                 // encode header: 2-bit unused, flags (2-bit) + seqno (4-bit)
00172                                 tmp[0] = (0x30 & (flags << 4)) | (0x0f & seqno);
00173 
00174                                 // set datagram to extended
00175                                 tmp[0] |= EXTENDED_MASK;
00176 
00177                                 // encode the type into the second byte
00178                                 tmp[1] = type;
00179 
00180                                 // copy payload to the new buffer
00181                                 ::memcpy(&tmp[2], buf, length);
00182 
00183                                 // Add own address at the end
00184                                 memcpy(&tmp[length+2], &local_addr, 2);
00185 
00186                                 // send converted line
00187                                 if (p.send(buf, length + 4) == -1)
00188                                 {
00189                                         // CL is busy
00190                                         throw DatagramException("send on socket failed");
00191                                 }
00192                         } catch (const ibrcommon::Exception&) {
00193                                 throw DatagramException("send failed");
00194                         }
00195                 }
00196 
00205                 size_t LOWPANDatagramService::recvfrom(char *buf, size_t length, char &type, char &flags, unsigned int &seqno, std::string &address) throw (DatagramException)
00206                 {
00207                         try {
00208                                 char tmp[length + 4];
00209 
00210                                 // Receive full frame from socket
00211                                 size_t ret = _socket->receive(tmp, length + 4);
00212 
00213                                 // decode type, flags and seqno
00214                                 // extended mask are discovery and ACK datagrams
00215                                 if (tmp[0] & EXTENDED_MASK)
00216                                 {
00217                                         // in extended frames the second byte
00218                                         // contains the real type
00219                                         type = tmp[1];
00220 
00221                                         // copy payload to the destination buffer
00222                                         ::memcpy(buf, &tmp[2], ret - 4);
00223                                 }
00224                                 else
00225                                 {
00226                                         // no extended mask means "segment"
00227                                         type = DatagramConvergenceLayer::HEADER_SEGMENT;
00228 
00229                                         // copy payload to the destination buffer
00230                                         ::memcpy(buf, &tmp[1], ret - 3);
00231                                 }
00232 
00233                                 // first byte contains flags (4-bit) + seqno (4-bit)
00234                                 flags = 0x0f & (tmp[0] >> 4);
00235                                 seqno = 0x0f & tmp[0];
00236 
00237                                 // Retrieve sender address from the end of the frame
00238                                 uint16_t from = ((char)tmp[length-1] << 8) | tmp[length-2];
00239 
00240                                 address = LOWPANDatagramService::encode(from, _panid);
00241 
00242                                 IBRCOMMON_LOGGER_DEBUG(20) << "LOWPANDatagramService::recvfrom() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: " << address << IBRCOMMON_LOGGER_ENDL;
00243 
00244                                 return ret - 2;
00245                         } catch (const ibrcommon::Exception&) {
00246                                 throw DatagramException("receive failed");
00247                         }
00248                 }
00249 
00254                 const std::string LOWPANDatagramService::getServiceTag() const
00255                 {
00256                         return "dgram:lowpan";
00257                 }
00258 
00264                 const std::string LOWPANDatagramService::getServiceDescription() const
00265                 {
00266                         struct sockaddr_ieee802154 address;
00267                         address.addr.addr_type = IEEE802154_ADDR_SHORT;
00268                         address.addr.pan_id = _panid;
00269 
00270                         // Get address via netlink
00271                         ibrcommon::lowpansocket::getAddress(&address.addr, _iface);
00272 
00273                         return LOWPANDatagramService::encode(address.addr.short_addr, _panid);
00274                 }
00275 
00280                 const ibrcommon::vinterface& LOWPANDatagramService::getInterface() const
00281                 {
00282                         return _iface;
00283                 }
00284 
00289                 dtn::core::Node::Protocol LOWPANDatagramService::getProtocol() const
00290                 {
00291                         return dtn::core::Node::CONN_DGRAM_LOWPAN;
00292                 }
00293 
00294                 const DatagramConnectionParameter& LOWPANDatagramService::getParameter() const
00295                 {
00296                         return _params;
00297                 }
00298 
00299                 const std::string LOWPANDatagramService::encode(const uint16_t &addr, const int &panid)
00300                 {
00301                         std::stringstream ss;
00302                         ss << "addr=" << addr << ";pan=" << panid << ";";
00303                         return ss.str();
00304                 }
00305 
00306                 void LOWPANDatagramService::decode(const std::string &identifier, uint16_t &addr, int &panid)
00307                 {
00308                         // parse parameters
00309                         std::vector<string> parameters = dtn::utils::Utils::tokenize(";", identifier);
00310                         std::vector<string>::const_iterator param_iter = parameters.begin();
00311 
00312                         while (param_iter != parameters.end())
00313                         {
00314                                 std::vector<string> p = dtn::utils::Utils::tokenize("=", (*param_iter));
00315 
00316                                 if (p[0].compare("addr") == 0)
00317                                 {
00318                                         std::stringstream port_stream;
00319                                         port_stream << p[1];
00320                                         port_stream >> addr;
00321                                 }
00322 
00323                                 if (p[0].compare("pan") == 0)
00324                                 {
00325                                         std::stringstream port_stream;
00326                                         port_stream << p[1];
00327                                         port_stream >> panid;
00328                                 }
00329 
00330                                 param_iter++;
00331                         }
00332                 }
00333         } /* namespace net */
00334 } /* namespace dtn */