summaryrefslogtreecommitdiffstats
path: root/src/UdpSocket.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-09-11 22:15:35 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-09-11 22:24:33 +0200
commit9248c1d7976ba1c37e3df147a1eb3115fe72c8d0 (patch)
treee331a2fc4600fe80ca4e2b404d4379989a95d127 /src/UdpSocket.cpp
parent8750493994d574001e466fef21ded86730359640 (diff)
downloaddabmux-9248c1d7976ba1c37e3df147a1eb3115fe72c8d0.tar.gz
dabmux-9248c1d7976ba1c37e3df147a1eb3115fe72c8d0.tar.bz2
dabmux-9248c1d7976ba1c37e3df147a1eb3115fe72c8d0.zip
Drop SLIP, Refactor sockets, improve TCP output
Quite a large refactoring of the sockets, TCP and UDP, in order to improve the ETI-over-TCP output. This can now accept several simultaneous connections, and requires a throttle. The SLIP input is gone. The UDP inputs are currently broken.
Diffstat (limited to 'src/UdpSocket.cpp')
-rw-r--r--src/UdpSocket.cpp504
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
-*/