diff --git a/hal/inc/hal_socket.h b/hal/inc/hal_socket.h index f4101e17..316058a7 100644 --- a/hal/inc/hal_socket.h +++ b/hal/inc/hal_socket.h @@ -1,7 +1,7 @@ /* * socket_hal.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -87,7 +87,7 @@ PAL_API void Handleset_reset(HandleSet self); /** - * \brief add a soecket to an existing handle set + * \brief add a socket to an existing handle set * * \param self the HandleSet instance * \param sock the socket to add @@ -95,6 +95,12 @@ Handleset_reset(HandleSet self); PAL_API void Handleset_addSocket(HandleSet self, const Socket sock); +/** + * \brief remove a socket from an existing handle set + */ +void +Handleset_removeSocket(HandleSet self, const Socket sock); + /** * \brief wait for a socket to become ready * diff --git a/hal/socket/bsd/socket_bsd.c b/hal/socket/bsd/socket_bsd.c index 84128d1d..d1a6eaa9 100644 --- a/hal/socket/bsd/socket_bsd.c +++ b/hal/socket/bsd/socket_bsd.c @@ -1,7 +1,7 @@ /* * socket_bsd.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * contributions by Michael Clausen (School of engineering Valais). * * This file is part of libIEC61850. @@ -36,6 +36,10 @@ #include // required for TCP keepalive +#include +#include + +#include "linked_list.h" #include "hal_thread.h" #include "lib_memory.h" @@ -54,63 +58,117 @@ struct sServerSocket { }; struct sHandleSet { - fd_set handles; - int maxHandle; + LinkedList sockets; + bool pollfdIsUpdated; + struct pollfd* fds; + int nfds; }; HandleSet Handleset_new(void) { - HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + HandleSet self = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (self) { + self->sockets = LinkedList_create(); + self->pollfdIsUpdated = false; + self->fds = NULL; + self->nfds = 0; + } - if (result != NULL) { - FD_ZERO(&result->handles); - result->maxHandle = -1; - } - return result; + return self; } void Handleset_reset(HandleSet self) { - FD_ZERO(&self->handles); - self->maxHandle = -1; + if (self) { + if (self->sockets) { + LinkedList_destroyStatic(self->sockets); + self->sockets = LinkedList_create(); + self->pollfdIsUpdated = false; + } + } } - void Handleset_addSocket(HandleSet self, const Socket sock) { - if (self != NULL && sock != NULL && sock->fd != -1) { - FD_SET(sock->fd, &self->handles); - if (sock->fd > self->maxHandle) { - self->maxHandle = sock->fd; - } - } + if (self != NULL && sock != NULL && sock->fd != -1) { + LinkedList_add(self->sockets, sock); + self->pollfdIsUpdated = false; + } +} + +void +Handleset_removeSocket(HandleSet self, const Socket sock) +{ + if (self && self->sockets && sock) { + LinkedList_remove(self->sockets, sock); + self->pollfdIsUpdated = false; + } } int Handleset_waitReady(HandleSet self, unsigned int timeoutMs) { - int result; + /* check if pollfd array is updated */ + if (self->pollfdIsUpdated == false) { + if (self->fds) { + GLOBAL_FREEMEM(self->fds); + self->fds = NULL; + } + + self->nfds = LinkedList_size(self->sockets); + + self->fds = GLOBAL_CALLOC(self->nfds, sizeof(struct pollfd)); - if (self != NULL && self->maxHandle >= 0) { - struct timeval timeout; + int i; - timeout.tv_sec = timeoutMs / 1000; - timeout.tv_usec = (timeoutMs % 1000) * 1000; - result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); - } else { - result = -1; - } + for (i = 0; i < self->nfds; i++) { + LinkedList sockElem = LinkedList_get(self->sockets, i); - return result; + if (sockElem) { + Socket sock = (Socket) LinkedList_getData(sockElem); + + if (sock) { + self->fds[i].fd = sock->fd; + self->fds[i].events = POLL_IN; + } + } + } + + self->pollfdIsUpdated = true; + } + + if (self->fds && self->nfds > 0) { + int result = poll(self->fds, self->nfds, timeoutMs); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: poll error (errno: %i)\n", errno); + } + + return result; + } + else { + /* there is no socket to wait for */ + return 0; + } } void Handleset_destroy(HandleSet self) { - GLOBAL_FREEMEM(self); + if (self) { + if (self->sockets) + LinkedList_destroyStatic(self->sockets); + + if (self->fds) + GLOBAL_FREEMEM(self->fds); + + GLOBAL_FREEMEM(self); + } } void diff --git a/hal/socket/linux/socket_linux.c b/hal/socket/linux/socket_linux.c index 350bf2ec..7d04e4ff 100644 --- a/hal/socket/linux/socket_linux.c +++ b/hal/socket/linux/socket_linux.c @@ -1,7 +1,7 @@ /* * socket_linux.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2020 Michael Zillgith * * This file is part of libIEC61850. * @@ -35,6 +35,12 @@ #include /* required for TCP keepalive */ #include +#define _GNU_SOURCE +#include +#include + + +#include "linked_list.h" #include "hal_thread.h" #include "lib_memory.h" @@ -53,62 +59,118 @@ struct sServerSocket { }; struct sHandleSet { - fd_set handles; - int maxHandle; + LinkedList sockets; + bool pollfdIsUpdated; + struct pollfd* fds; + int nfds; }; HandleSet Handleset_new(void) { - HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + HandleSet self = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); - if (result != NULL) { - FD_ZERO(&result->handles); - result->maxHandle = -1; + if (self) { + self->sockets = LinkedList_create(); + self->pollfdIsUpdated = false; + self->fds = NULL; + self->nfds = 0; } - return result; + + return self; } void Handleset_reset(HandleSet self) { - FD_ZERO(&self->handles); - self->maxHandle = -1; + if (self) { + if (self->sockets) { + LinkedList_destroyStatic(self->sockets); + self->sockets = LinkedList_create(); + self->pollfdIsUpdated = false; + } + } } void Handleset_addSocket(HandleSet self, const Socket sock) { if (self != NULL && sock != NULL && sock->fd != -1) { - FD_SET(sock->fd, &self->handles); - if (sock->fd > self->maxHandle) { - self->maxHandle = sock->fd; - } + + LinkedList_add(self->sockets, sock); + self->pollfdIsUpdated = false; } } +void +Handleset_removeSocket(HandleSet self, const Socket sock) +{ + if (self && self->sockets && sock) { + LinkedList_remove(self->sockets, sock); + self->pollfdIsUpdated = false; + } +} + int Handleset_waitReady(HandleSet self, unsigned int timeoutMs) { - int result; + /* check if pollfd array is updated */ + if (self->pollfdIsUpdated == false) { + if (self->fds) { + GLOBAL_FREEMEM(self->fds); + self->fds = NULL; + } - if ((self != NULL) && (self->maxHandle >= 0)) { - struct timeval timeout; + self->nfds = LinkedList_size(self->sockets); - timeout.tv_sec = timeoutMs / 1000; - timeout.tv_usec = (timeoutMs % 1000) * 1000; - result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); - } else { - result = -1; - } + self->fds = GLOBAL_CALLOC(self->nfds, sizeof(struct pollfd)); + + int i; - return result; + for (i = 0; i < self->nfds; i++) { + LinkedList sockElem = LinkedList_get(self->sockets, i); + + if (sockElem) { + Socket sock = (Socket) LinkedList_getData(sockElem); + + if (sock) { + self->fds[i].fd = sock->fd; + self->fds[i].events = POLL_IN; + } + } + } + + self->pollfdIsUpdated = true; + } + + if (self->fds && self->nfds > 0) { + int result = poll(self->fds, self->nfds, timeoutMs); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: poll error (errno: %i)\n", errno); + } + + return result; + } + else { + /* there is no socket to wait for */ + return 0; + } } void Handleset_destroy(HandleSet self) { - GLOBAL_FREEMEM(self); + if (self) { + if (self->sockets) + LinkedList_destroyStatic(self->sockets); + + if (self->fds) + GLOBAL_FREEMEM(self->fds); + + GLOBAL_FREEMEM(self); + } } void @@ -557,10 +619,12 @@ Socket_read(Socket self, uint8_t* buf, int size) case EAGAIN: return 0; - case EBADF: - return -1; default: + + if (DEBUG_SOCKET) + printf("DEBUG_SOCKET: recv returned error (errno=%i)\n", error); + return -1; } } @@ -577,10 +641,17 @@ Socket_write(Socket self, uint8_t* buf, int size) /* MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket */ int retVal = send(self->fd, buf, size, MSG_NOSIGNAL); - if ((retVal == -1) && (errno == EAGAIN)) - return 0; - else - return retVal; + if (retVal == -1) { + if (errno == EAGAIN) { + return 0; + } + else { + if (DEBUG_SOCKET) + printf("DEBUG_SOCKET: send returned error (errno=%i)\n", errno); + } + } + + return retVal; } void diff --git a/hal/socket/win32/socket_win32.c b/hal/socket/win32/socket_win32.c index d99103e3..2d217ade 100644 --- a/hal/socket/win32/socket_win32.c +++ b/hal/socket/win32/socket_win32.c @@ -89,6 +89,14 @@ Handleset_addSocket(HandleSet self, const Socket sock) } } +void +Handleset_removeSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != INVALID_SOCKET) { + FD_CLR(sock->fd, &self->handles); + } +} + int Handleset_waitReady(HandleSet self, unsigned int timeoutMs) { diff --git a/src/mms/inc_private/iso_server_private.h b/src/mms/inc_private/iso_server_private.h index 4e9e45d7..53f34b91 100644 --- a/src/mms/inc_private/iso_server_private.h +++ b/src/mms/inc_private/iso_server_private.h @@ -39,8 +39,11 @@ IsoConnection_destroy(IsoConnection self); LIB61850_INTERNAL void IsoConnection_handleTcpConnection(IsoConnection self); +/** + * \brief Add the connection socket to the given HandleSet instance + */ LIB61850_INTERNAL void -IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles); +IsoConnection_addToHandleSet(const IsoConnection self, HandleSet handles); LIB61850_INTERNAL void private_IsoServer_increaseConnectionCounter(IsoServer self); diff --git a/src/mms/iso_server/iso_connection.c b/src/mms/iso_server/iso_connection.c index cc91823f..03868ca0 100644 --- a/src/mms/iso_server/iso_connection.c +++ b/src/mms/iso_server/iso_connection.c @@ -134,7 +134,7 @@ finalizeIsoConnection(IsoConnection self) } void -IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles) +IsoConnection_addToHandleSet(const IsoConnection self, HandleSet handles) { Handleset_addSocket(handles, self->socket); } diff --git a/src/mms/iso_server/iso_server.c b/src/mms/iso_server/iso_server.c index 194ad542..2549836d 100644 --- a/src/mms/iso_server/iso_server.c +++ b/src/mms/iso_server/iso_server.c @@ -645,10 +645,9 @@ IsoServer_waitReady(IsoServer self, unsigned int timeoutMs) int result; if (getState(self) == ISO_SVR_STATE_RUNNING) { - HandleSet handles; + HandleSet handles = Handleset_new(); - handles = Handleset_new(); - if (handles != NULL) { + if (handles) { #if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED == 0) lockClientConnections(self); @@ -663,7 +662,7 @@ IsoServer_waitReady(IsoServer self, unsigned int timeoutMs) IsoConnection isoConnection = (IsoConnection) openConnection->data; if (IsoConnection_isRunning(isoConnection)) { - IsoConnection_addHandleSet(isoConnection, handles); + IsoConnection_addToHandleSet(isoConnection, handles); openConnection = LinkedList_getNext(openConnection); } else { #if ((CONFIG_MMS_SINGLE_THREADED == 1) || (CONFIG_MMS_THREADLESS_STACK == 1)) @@ -683,7 +682,7 @@ IsoServer_waitReady(IsoServer self, unsigned int timeoutMs) for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { if (self->openClientConnections[i] != NULL) { if (IsoConnection_isRunning(self->openClientConnections[i])) { - IsoConnection_addHandleSet(self->openClientConnections[i], handles); + IsoConnection_addToHandleSet(self->openClientConnections[i], handles); } else { #if ((CONFIG_MMS_SINGLE_THREADED == 1) || (CONFIG_MMS_THREADLESS_STACK == 1))