IBR-DTNSuite  0.8
ibrcommon/ibrcommon/net/udpsocket.cpp
Go to the documentation of this file.
00001 /*
00002  * udpsocket.cpp
00003  *
00004  *  Created on: 02.03.2010
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/config.h"
00009 #include "ibrcommon/net/udpsocket.h"
00010 #include "ibrcommon/Logger.h"
00011 #include <sys/socket.h>
00012 #include <errno.h>
00013 #include <sys/types.h>
00014 #include <netinet/in.h>
00015 #include <arpa/inet.h>
00016 #include <string.h>
00017 
00018 #ifndef HAVE_BZERO
00019 #define bzero(s,n) (memset((s), '\0', (n)), (void) 0)
00020 #endif
00021 
00022 namespace ibrcommon
00023 {
00024         udpsocket::udpsocket() throw (SocketException)
00025         {
00026         }
00027 
00028         udpsocket::~udpsocket()
00029         {
00030                 _socket.close();
00031         }
00032 
00033         void udpsocket::shutdown()
00034         {
00035                 _socket.close();
00036         }
00037 
00038         int udpsocket::receive(char* data, size_t maxbuffer)
00039         {
00040                 struct sockaddr_in clientAddress;
00041                 socklen_t clientAddressLength = sizeof(clientAddress);
00042 
00043                 std::list<int> fds;
00044                 _socket.select(fds, NULL);
00045                 int fd = fds.front();
00046 
00047                 // data waiting
00048                 return recvfrom(fd, data, maxbuffer, MSG_WAITALL, (struct sockaddr *) &clientAddress, &clientAddressLength);
00049         }
00050 
00051         int udpsocket::receive(char* data, size_t maxbuffer, std::string &address, unsigned int &port)
00052         {
00053                 struct sockaddr_storage addr;
00054                 socklen_t fromlen = sizeof(addr);
00055                 char ipstr[INET6_ADDRSTRLEN];
00056 
00057                 std::list<int> fds;
00058                 _socket.select(fds, NULL);
00059                 int fd = fds.front();
00060 
00061                 // data waiting
00062                 int ret = recvfrom(fd, data, maxbuffer, MSG_WAITALL, (struct sockaddr *) &addr, &fromlen);
00063 
00064                 if ( addr.ss_family == AF_INET )
00065                 {
00066                         // IPv4
00067                         inet_ntop(addr.ss_family, &((struct sockaddr_in *)&addr)->sin_addr, ipstr, sizeof ipstr);
00068                         address = std::string(ipstr);
00069                         port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
00070                 }
00071                 else if ( addr.ss_family == AF_INET6 )
00072                 {
00073                         // IPv6
00074                         inet_ntop(addr.ss_family, &((struct sockaddr_in6 *)&addr)->sin6_addr, ipstr, sizeof ipstr);
00075                         address = std::string(ipstr);
00076                         port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
00077                 }
00078                 else
00079                 {
00080                         address = "unknown";
00081                         port = 0;
00082                 }
00083 
00084                 return ret;
00085         }
00086 
00087         int udpsocket::send(const ibrcommon::vaddress &addr, const unsigned int port, const char *data, const size_t length)
00088         {
00089                 int stat = -1;
00090 
00091                 // iterate over all sockets
00092                 std::list<int> fds = _socket.get();
00093 
00094                 for (std::list<int>::const_iterator iter = fds.begin(); iter != fds.end(); iter++)
00095                 {
00096                         try {
00097                                 ssize_t ret = 0;
00098                                 int flags = 0;
00099 
00100                                 struct addrinfo hints, *ainfo;
00101                                 memset(&hints, 0, sizeof hints);
00102 
00103                                 hints.ai_socktype = SOCK_DGRAM;
00104                                 ainfo = addr.addrinfo(&hints, port);
00105 
00106                                 ret = ::sendto(*iter, data, length, flags, ainfo->ai_addr, ainfo->ai_addrlen);
00107 
00108                                 freeaddrinfo(ainfo);
00109 
00110                                 // if the send was successful, set the correct return value
00111                                 if (ret != -1)
00112                                 {
00113                                         stat = ret;
00114 
00115                                         if ((!addr.isBroadcast()) && (!addr.isMulticast()))
00116                                         {
00117                                                 // stop here
00118                                                 break;
00119                                         }
00120                                 }
00121                         } catch (const ibrcommon::vsocket_exception&) {
00122                                 IBRCOMMON_LOGGER_DEBUG(5) << "can not send message to " << addr.toString() << IBRCOMMON_LOGGER_ENDL;
00123                         }
00124                 }
00125 
00126                 return stat;
00127         }
00128 }