diff options
Diffstat (limited to 'src/UdpSocket.cpp')
-rw-r--r-- | src/UdpSocket.cpp | 504 |
1 files changed, 120 insertions, 384 deletions
diff --git a/src/UdpSocket.cpp b/src/UdpSocket.cpp index 8ac3706..020e3f5 100644 --- a/src/UdpSocket.cpp +++ b/src/UdpSocket.cpp @@ -2,7 +2,9 @@ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2015 Matthias P. Braendli + Copyright (C) 2016 + Matthias P. Braendli, matthias.braendli@mpb.li + http://www.opendigitalradio.org */ /* @@ -30,228 +32,126 @@ #include <fcntl.h> #include <string.h> -#ifdef TRACE_ON -# ifndef TRACE_CLASS -# define TRACE_CLASS(class, func) cout <<"-" <<(class) <<"\t(" <<this <<")::" <<(func) <<endl -# define TRACE_STATIC(class, func) cout <<"-" <<(class) <<"\t(static)::" <<(func) <<endl -# endif -#else -# ifndef TRACE_CLASS -# define TRACE_CLASS(class, func) -# define TRACE_STATIC(class, func) -# endif -#endif - - -/// Must be call once before doing any operation on sockets -int UdpSocket::init() -{ -#ifdef _WIN32 - WSADATA wsaData; - WORD wVersionRequested = wVersionRequested = MAKEWORD( 2, 2 ); - - int res = WSAStartup( wVersionRequested, &wsaData ); - if (res) { - setInetError("Can't initialize winsock"); - return -1; - } -#endif - return 0; -} - +using namespace std; -/// Must be call once before leaving application -int UdpSocket::clean() +UdpSocket::UdpSocket() : + listenSocket(INVALID_SOCKET) { -#ifdef _WIN32 - int res = WSACleanup(); - if (res) { - setInetError("Can't initialize winsock"); - return -1; - } -#endif - return 0; + init_sock(0, ""); } - -/** - * Two step constructor. Create must be called prior to use this - * socket. - */ -UdpSocket::UdpSocket() : - listenSocket(INVALID_SOCKET) +UdpSocket::UdpSocket(int port) : + listenSocket(INVALID_SOCKET) { - TRACE_CLASS("UdpSocket", "UdpSocket()"); + init_sock(port, ""); } - -/** - * One step constructor. - * @param port The port number on which the socket will be bind - * @param name The IP address on which the socket will be bind. - * It is used to bind the socket on a specific interface if - * the computer have many NICs. - */ -UdpSocket::UdpSocket(int port, char *name) : - listenSocket(INVALID_SOCKET) +UdpSocket::UdpSocket(int port, const std::string& name) : + listenSocket(INVALID_SOCKET) { - TRACE_CLASS("UdpSocket", "UdpSocket(int, char*)"); - create(port, name); + init_sock(port, name); } -/** - * This functin set blocking mode. The socket can be blocking or not, - * depending of the parametre. By default, the socket is blocking. - * @param block If true, set the socket blocking, otherwise set non-blocking - * @return 0 if ok - * -1 if error - */ int UdpSocket::setBlocking(bool block) { -#ifdef _WIN32 - unsigned long res = block ? 0 : 1; - if (ioctlsocket(listenSocket, FIONBIO, &res) != 0) { + int res; + if (block) + res = fcntl(listenSocket, F_SETFL, 0); + else + res = fcntl(listenSocket, F_SETFL, O_NONBLOCK); + if (res == SOCKET_ERROR) { setInetError("Can't change blocking state of socket"); return -1; - } + } return 0; -#else - int res; - if (block) - res = fcntl(listenSocket, F_SETFL, 0); - else - res = fcntl(listenSocket, F_SETFL, O_NONBLOCK); - if (res == SOCKET_ERROR) { - setInetError("Can't change blocking state of socket"); - return -1; - } - return 0; -#endif } - -/** - * Two step initializer. This function must be called after the constructor - * without argument as been called. - * @param port The port number on which the socket will be bind - * @param name The IP address on which the socket will be bind. - * It is used to bind the socket on a specific interface if - * the computer have many NICs. - * @return 0 if ok - * -1 if error - */ -int UdpSocket::create(int port, char *name) +int UdpSocket::init_sock(int port, const std::string& name) { - TRACE_CLASS("UdpSocket", "create(int, char*)"); - if (listenSocket != INVALID_SOCKET) - closesocket(listenSocket); - address.setAddress(name); - address.setPort(port); - if ((listenSocket = socket(PF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { - setInetError("Can't create socket"); - return -1; - } - reuseopt_t reuse = 1; - if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) - == SOCKET_ERROR) { - setInetError("Can't reuse address"); - return -1; - } - - if (bind(listenSocket, address.getAddress(), sizeof(sockaddr_in)) == SOCKET_ERROR) { - setInetError("Can't bind socket"); - closesocket(listenSocket); - listenSocket = INVALID_SOCKET; - return -1; - } - return 0; + if (listenSocket != INVALID_SOCKET) { + ::close(listenSocket); + } + + if ((listenSocket = socket(PF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { + setInetError("Can't create socket"); + return -1; + } + reuseopt_t reuse = 1; + if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) + == SOCKET_ERROR) { + setInetError("Can't reuse address"); + return -1; + } + + if (port) { + address.setAddress(name); + address.setPort(port); + + if (bind(listenSocket, address.getAddress(), sizeof(sockaddr_in)) == SOCKET_ERROR) { + setInetError("Can't bind socket"); + ::close(listenSocket); + listenSocket = INVALID_SOCKET; + return -1; + } + } + return 0; } -/// Destructor -UdpSocket::~UdpSocket() { - TRACE_CLASS("UdpSocket", "~UdpSocket()"); - if (listenSocket != INVALID_SOCKET) - closesocket(listenSocket); +UdpSocket::~UdpSocket() +{ + if (listenSocket != INVALID_SOCKET) { + ::close(listenSocket); + } } -/** - * Receive an UDP packet. - * @param packet The packet that will receive data. The address will be set - * to the source address. - * @return 0 if ok, -1 if error - */ -int UdpSocket::receive(UdpPacket &packet) +int UdpSocket::receive(UdpPacket& packet) { - TRACE_CLASS("UdpSocket", "receive(UdpPacket)"); - socklen_t addrSize; - addrSize = sizeof(*packet.getAddress().getAddress()); - int ret = recvfrom(listenSocket, packet.getData(), packet.getSize() - packet.getOffset(), 0, - packet.getAddress().getAddress(), &addrSize); - if (ret == SOCKET_ERROR) { - packet.setLength(0); -#ifndef _WIN32 - if (errno == EAGAIN) + socklen_t addrSize; + addrSize = sizeof(*packet.getAddress().getAddress()); + ssize_t ret = recvfrom(listenSocket, + packet.getData(), + packet.getSize(), + 0, + packet.getAddress().getAddress(), + &addrSize); + + if (ret == SOCKET_ERROR) { + packet.setSize(0); + if (errno == EAGAIN) { + return 0; + } + setInetError("Can't receive UDP packet"); + return -1; + } + + packet.setSize(ret); return 0; -#endif - setInetError("Can't receive UDP packet"); - return -1; - } - packet.setLength(ret); - if (ret == (long)packet.getSize()) { - packet.setSize(packet.getSize() << 1); - } - return 0; } -/** - * Send an UDP packet. - * @param packet The UDP packet to be sent. It includes the data and the - * destination address - * return 0 if ok, -1 if error - */ -int UdpSocket::send(UdpPacket &packet) +int UdpSocket::send(UdpPacket& packet) { -#ifdef DUMP - TRACE_CLASS("UdpSocket", "send(UdpPacket)"); -#endif - int ret = sendto(listenSocket, packet.getData(), packet.getLength(), 0, - packet.getAddress().getAddress(), sizeof(*packet.getAddress().getAddress())); - if (ret == SOCKET_ERROR -#ifndef _WIN32 - && errno != ECONNREFUSED -#endif - ) { - setInetError("Can't send UDP packet"); - return -1; - } - return 0; + int ret = sendto(listenSocket, packet.getData(), packet.getSize(), 0, + packet.getAddress().getAddress(), sizeof(*packet.getAddress().getAddress())); + if (ret == SOCKET_ERROR && errno != ECONNREFUSED) { + setInetError("Can't send UDP packet"); + return -1; + } + return 0; } -/** - * Send an UDP packet - * - * return 0 if ok, -1 if error - */ -int UdpSocket::send(std::vector<uint8_t> data, InetAddress destination) +int UdpSocket::send(const std::vector<uint8_t>& data, InetAddress destination) { -#ifdef DUMP - TRACE_CLASS("UdpSocket", "send(vector<uint8_t>)"); -#endif - int ret = sendto(listenSocket, &data[0], data.size(), 0, - destination.getAddress(), sizeof(*destination.getAddress())); - if (ret == SOCKET_ERROR -#ifndef _WIN32 - && errno != ECONNREFUSED -#endif - ) { - setInetError("Can't send UDP packet"); - return -1; - } - return 0; + int ret = sendto(listenSocket, &data[0], data.size(), 0, + destination.getAddress(), sizeof(*destination.getAddress())); + if (ret == SOCKET_ERROR && errno != ECONNREFUSED) { + setInetError("Can't send UDP packet"); + return -1; + } + return 0; } @@ -263,36 +163,22 @@ st address to join. */ int UdpSocket::joinGroup(char* groupname) { - TRACE_CLASS("UdpSocket", "joinGroup(char*)"); -#ifdef _WIN32 - ip_mreq group; -#else - ip_mreqn group; -#endif - if ((group.imr_multiaddr.s_addr = inet_addr(groupname)) == INADDR_NONE) { - setInetError(groupname); - return -1; - } - if (!IN_MULTICAST(ntohl(group.imr_multiaddr.s_addr))) { - setInetError("Not a multicast address"); - return -1; - } -#ifdef _WIN32 - group.imr_interface.s_addr = 0; - if (setsockopt(listenSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&group, sizeof(group)) - == SOCKET_ERROR) { - setInetError("Can't join multicast group"); - return -1; - } -#else - group.imr_address.s_addr = htons(INADDR_ANY);; - group.imr_ifindex = 0; - if (setsockopt(listenSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group)) - == SOCKET_ERROR) { - setInetError("Can't join multicast group"); - } -#endif - return 0; + ip_mreqn group; + if ((group.imr_multiaddr.s_addr = inet_addr(groupname)) == INADDR_NONE) { + setInetError(groupname); + return -1; + } + if (!IN_MULTICAST(ntohl(group.imr_multiaddr.s_addr))) { + setInetError("Not a multicast address"); + return -1; + } + group.imr_address.s_addr = htons(INADDR_ANY);; + group.imr_ifindex = 0; + if (setsockopt(listenSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group)) + == SOCKET_ERROR) { + setInetError("Can't join multicast group"); + } + return 0; } int UdpSocket::setMulticastTTL(int ttl) @@ -323,188 +209,38 @@ int UdpSocket::setMulticastSource(const char* source_addr) return 0; } +UdpPacket::UdpPacket() { } -/** - * Constructs an UDP packet. - * @param initSize The initial size of the data buffer - */ -UdpPacket::UdpPacket(unsigned int initSize) : - dataBuf(new char[initSize]), - length(0), - size(initSize), - offset(0) -{ - TRACE_CLASS("UdpPacket", "UdpPacket(unsigned int)"); - if (dataBuf == NULL) - size = 0; -} +UdpPacket::UdpPacket(size_t initSize) : + m_buffer(initSize) +{ } -/// Destructor -UdpPacket::~UdpPacket() +void UdpPacket::setSize(size_t newSize) { - TRACE_CLASS("UdpPacket", "~UdpPacket()"); - if (dataBuf != NULL) { - delete []dataBuf; - dataBuf = NULL; - } + m_buffer.resize(newSize); } - -/** - * Changes size of the data buffer size. \a Length + \a offset data will be copied - * in the new buffer. - * @warning The pointer to data will be changed - * @param newSize The new data buffer size - */ -void UdpPacket::setSize(unsigned newSize) -{ - TRACE_CLASS("UdpPacket", "setSize(unsigned)"); - char *tmp = new char[newSize]; - if (length > newSize) - length = newSize; - if (tmp) { - memcpy(tmp, dataBuf, length); - delete []dataBuf; - dataBuf = tmp; - size = newSize; - } -} - -/** - * Give the pointer to data. It is ajusted with the \a offset. - * @warning This pointer change. when the \a size of the buffer and the \a offset change. - * @return The pointer - */ -char *UdpPacket::getData() +uint8_t* UdpPacket::getData() { - return dataBuf + offset; + return &m_buffer[0]; } -/** - * Add some data at the end of data buffer and adjust size. - * @param data Pointer to the data to add - * @param size Size in bytes of new data - */ -void UdpPacket::addData(const void *data, unsigned size) +void UdpPacket::addData(const void *data, size_t size) { - if (length + size > this->size) { - setSize(this->size << 1); - } - memcpy(dataBuf + length, data, size); - length += size; + uint8_t *d = (uint8_t*)data; + std::copy(d, d + size, std::back_inserter(m_buffer)); } - -/** - * Returns the length of useful data. Data before the \a offset are ignored. - * @return The data length - */ -unsigned long UdpPacket::getLength() +size_t UdpPacket::getSize() { - return length - offset; + return m_buffer.size(); } - -/** - * Returns the size of the data buffer. - * @return The data buffer size - */ -unsigned long UdpPacket::getSize() +InetAddress UdpPacket::getAddress() { - return size; + return address; } - -/** - * Returns the offset value. - * @return The offset value - */ -unsigned long UdpPacket::getOffset() -{ - return offset; -} - - -/** - * Sets the data length value. Data before the \a offset are ignored. - * @param len The new length of data - */ -void UdpPacket::setLength(unsigned long len) -{ - length = len + offset; -} - - -/** - * Sets the data offset. Data length is ajusted to ignore data before the \a offset. - * @param val The new data offset. - */ -void UdpPacket::setOffset(unsigned long val) -{ - offset = val; - if (offset > length) - length = offset; -} - - -/** - * Returns the UDP address of the data. - * @return The UDP address - */ -InetAddress &UdpPacket::getAddress() -{ - return address; -} - -/* -WSAEINTR -WSAEBADF -WSAEACCES -WSAEFAULT -WSAEINVAL -WSAEMFILE -WSAEWOULDBLOCK -WSAEINPROGRESS -WSAEALREADY -WSAENOTSOCK -WSAEDESTADDRREQ -WSAEMSGSIZE -WSAEPROTOTYPE -WSAENOPROTOOPT -WSAEPROTONOSUPPORT -WSAESOCKTNOSUPPORT -WSAEOPNOTSUPP -WSAEPFNOSUPPORT -WSAEAFNOSUPPORT -WSAEADDRINUSE -WSAEADDRNOTAVAIL -WSAENETDOWN -WSAENETUNREACH -WSAENETRESET -WSAECONNABORTED -WSAECONNRESET -WSAENOBUFS -WSAEISCONN -WSAENOTCONN -WSAESHUTDOWN -WSAETOOMANYREFS -WSAETIMEDOUT -WSAECONNREFUSED -WSAELOOP -WSAENAMETOOLONG -WSAEHOSTDOWN -WSAEHOSTUNREACH -WSAENOTEMPTY -WSAEPROCLIM -WSAEUSERS -WSAEDQUOT -WSAESTALE -WSAEREMOTE -WSAEDISCON -WSASYSNOTREADY -WSAVERNOTSUPPORTED -WSANOTINITIALISED -*/ |