IBR-DTNSuite
0.8
|
00001 /* 00002 * UDPDatagramService.cpp 00003 * 00004 * Created on: 22.11.2011 00005 * Author: morgenro 00006 */ 00007 00008 #include "net/UDPDatagramService.h" 00009 #include <ibrdtn/utils/Utils.h> 00010 #include <ibrcommon/Logger.h> 00011 #include <vector> 00012 #include <string.h> 00013 00014 namespace dtn 00015 { 00016 namespace net 00017 { 00018 UDPDatagramService::UDPDatagramService(const ibrcommon::vinterface &iface, int port, size_t mtu) 00019 : _iface(iface), _bind_port(port) 00020 { 00021 // set connection parameters 00022 _params.max_msg_length = mtu - 2; // minus 2 bytes because we encode seqno and flags into 2 bytes 00023 _params.max_seq_numbers = 8; // seqno 0..7 00024 _params.flowcontrol = DatagramConnectionParameter::FLOW_STOPNWAIT; 00025 } 00026 00027 UDPDatagramService::~UDPDatagramService() 00028 { 00029 } 00030 00035 void UDPDatagramService::bind() throw (DatagramException) 00036 { 00037 try { 00038 // bind socket to interface 00039 _socket.bind(_iface, _bind_port, SOCK_DGRAM); 00040 } catch (const ibrcommon::Exception&) { 00041 throw DatagramException("bind failed"); 00042 } 00043 } 00044 00048 void UDPDatagramService::shutdown() 00049 { 00050 // abort socket operations 00051 udpsocket::shutdown(); 00052 } 00053 00060 void UDPDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const std::string &identifier, const char *buf, size_t length) throw (DatagramException) 00061 { 00062 try { 00063 char tmp[length + 2]; 00064 00065 // add a 2-byte header - type of frame first 00066 tmp[0] = type; 00067 00068 // flags (4-bit) + seqno (4-bit) 00069 tmp[1] = (0xf0 & (flags << 4)) | (0x0f & seqno); 00070 00071 // copy payload to the new buffer 00072 ::memcpy(&tmp[2], buf, length); 00073 00074 unsigned int port = 0; 00075 std::string address; 00076 00077 // decode address 00078 UDPDatagramService::decode(identifier, address, port); 00079 00080 IBRCOMMON_LOGGER_DEBUG(20) << "UDPDatagramService::send() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: [" << address << "]:" << std::dec << port << IBRCOMMON_LOGGER_ENDL; 00081 00082 // create vaddress 00083 const ibrcommon::vaddress destination(address); 00084 udpsocket::send(destination, port, tmp, length + 2); 00085 } catch (const ibrcommon::Exception&) { 00086 throw DatagramException("send failed"); 00087 } 00088 } 00089 00095 void UDPDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const char *buf, size_t length) throw (DatagramException) 00096 { 00097 try { 00098 char tmp[length]; 00099 00100 // add a 2-byte header - type of frame first 00101 tmp[0] = type; 00102 00103 // flags (4-bit) + seqno (4-bit) 00104 tmp[1] = (0xf0 & (flags << 4)) | (0x0f & seqno); 00105 00106 // copy payload to the new buffer 00107 ::memcpy(&tmp[2], buf, length); 00108 00109 IBRCOMMON_LOGGER_DEBUG(20) << "UDPDatagramService::send() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << std::dec << seqno << IBRCOMMON_LOGGER_ENDL; 00110 00111 // create broadcast address 00112 const ibrcommon::vaddress broadcast(ibrcommon::vaddress::VADDRESS_INET6, "ff02::1", true); 00113 udpsocket::send(broadcast, BROADCAST_PORT, tmp, length + 2); 00114 } catch (const ibrcommon::Exception&) { 00115 throw DatagramException("send failed"); 00116 } 00117 } 00118 00127 size_t UDPDatagramService::recvfrom(char *buf, size_t length, char &type, char &flags, unsigned int &seqno, std::string &address) throw (DatagramException) 00128 { 00129 try { 00130 char tmp[length + 2]; 00131 std::string from; 00132 unsigned int port; 00133 size_t ret = receive(tmp, length + 2, from, port); 00134 00135 // first byte if the type 00136 type = tmp[0]; 00137 00138 // second byte if flags (4-bit) + seqno (4-bit) 00139 flags = 0x0f & (tmp[1] >> 4); 00140 seqno = 0x0f & tmp[1]; 00141 00142 address = UDPDatagramService::encode(from, port); 00143 00144 // copy payload to the destination buffer 00145 ::memcpy(buf, &tmp[2], ret - 2); 00146 00147 IBRCOMMON_LOGGER_DEBUG(20) << "UDPDatagramService::recvfrom() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: [" << from << "]:" << std::dec << port << IBRCOMMON_LOGGER_ENDL; 00148 00149 return ret - 2; 00150 } catch (const ibrcommon::Exception&) { 00151 throw DatagramException("receive failed"); 00152 } 00153 } 00154 00159 const std::string UDPDatagramService::getServiceTag() const 00160 { 00161 return "dgram:udp"; 00162 } 00163 00169 const std::string UDPDatagramService::getServiceDescription() const 00170 { 00171 std::string address; 00172 00173 // first try IPv6 addresses 00174 std::list<ibrcommon::vaddress> addrs = _iface.getAddresses(ibrcommon::vaddress::VADDRESS_INET6); 00175 00176 // fallback to IPv4 if IPv6 is not available 00177 if (addrs.size() == 0) 00178 { 00179 addrs = _iface.getAddresses(ibrcommon::vaddress::VADDRESS_INET); 00180 } 00181 00182 // no addresses available, return empty string 00183 if (addrs.size() == 0) return ""; 00184 00185 const ibrcommon::vaddress &addr = addrs.front(); 00186 00187 return UDPDatagramService::encode(addr, _bind_port); 00188 } 00189 00194 const ibrcommon::vinterface& UDPDatagramService::getInterface() const 00195 { 00196 return _iface; 00197 } 00198 00203 dtn::core::Node::Protocol UDPDatagramService::getProtocol() const 00204 { 00205 return dtn::core::Node::CONN_DGRAM_UDP; 00206 } 00207 00208 const DatagramConnectionParameter& UDPDatagramService::getParameter() const 00209 { 00210 return _params; 00211 } 00212 00213 const std::string UDPDatagramService::encode(const ibrcommon::vaddress &address, const unsigned int &port) 00214 { 00215 std::stringstream ss; 00216 ss << "ip=" << address.toString() << ";port=" << port << ";"; 00217 return ss.str(); 00218 } 00219 00220 void UDPDatagramService::decode(const std::string &identifier, std::string &address, unsigned int &port) 00221 { 00222 // parse parameters 00223 std::vector<string> parameters = dtn::utils::Utils::tokenize(";", identifier); 00224 std::vector<string>::const_iterator param_iter = parameters.begin(); 00225 00226 while (param_iter != parameters.end()) 00227 { 00228 std::vector<string> p = dtn::utils::Utils::tokenize("=", (*param_iter)); 00229 00230 if (p[0].compare("ip") == 0) 00231 { 00232 address = p[1]; 00233 } 00234 00235 if (p[0].compare("port") == 0) 00236 { 00237 std::stringstream port_stream; 00238 port_stream << p[1]; 00239 port_stream >> port; 00240 } 00241 00242 param_iter++; 00243 } 00244 } 00245 } /* namespace net */ 00246 } /* namespace dtn */