IBR-DTNSuite  0.8
daemon/src/net/UDPDatagramService.cpp
Go to the documentation of this file.
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 */