IBR-DTNSuite
0.8
|
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 */