From f13e70e40d4e7518a91647fb502b9ad8b1e1c4bf Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Wed, 20 Dec 2023 23:34:18 +0000 Subject: [PATCH 1/5] Invalid socket, but still prone to race conditions --- asyn/drvAsynSerial/drvAsynIPServerPort.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.c b/asyn/drvAsynSerial/drvAsynIPServerPort.c index 7a7f27bdd..7cc5f6c79 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.c +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.c @@ -305,7 +305,7 @@ static void connectionListener(void *drvPvt) asynPrint(pasynUser, ASYN_TRACE_FLOW, "drvAsynIPServerPort: %s started listening for connections on %s\n", tty->portName, tty->serverInfo); - while (1) { + while (tty->fd != INVALID_SOCKET) { if (tty->socketType == SOCK_DGRAM) { if ((tty->UDPbufferPos == 0) && (tty->UDPbufferSize == 0)) { tty->UDPbufferSize = recvfrom(tty->fd, tty->UDPbuffer, THEORETICAL_UDP_MAX_SIZE , 0, NULL, NULL); @@ -498,6 +498,7 @@ static void ttyCleanup(void *pPvt) if (tty->fd >= 0) { asynPrint(tty->pasynUser, ASYN_TRACE_FLOW, "drvAsynIPServerPort:ttyCleanup %s: shutdown socket %d\n", tty->portName, tty->fd); epicsSocketDestroy(tty->fd); + tty->fd = INVALID_SOCKET; } free(tty->portName); free(tty->serverInfo); From 0138904cdd245275aa24f12ea97c787edb921cf5 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Wed, 20 Dec 2023 23:37:24 +0000 Subject: [PATCH 2/5] Add sleeep --- asyn/drvAsynSerial/drvAsynIPServerPort.c | 1 + 1 file changed, 1 insertion(+) diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.c b/asyn/drvAsynSerial/drvAsynIPServerPort.c index 7cc5f6c79..7b12f35e9 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.c +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.c @@ -499,6 +499,7 @@ static void ttyCleanup(void *pPvt) asynPrint(tty->pasynUser, ASYN_TRACE_FLOW, "drvAsynIPServerPort:ttyCleanup %s: shutdown socket %d\n", tty->portName, tty->fd); epicsSocketDestroy(tty->fd); tty->fd = INVALID_SOCKET; + epicsThreadSleep(0.1); /* wait for accept thread to terminate */ } free(tty->portName); free(tty->serverInfo); From 12566042bd52d223362a1295a701f5c87bce0c86 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Thu, 21 Dec 2023 14:25:55 +0000 Subject: [PATCH 3/5] Add select() call --- asyn/drvAsynSerial/drvAsynIPServerPort.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.c b/asyn/drvAsynSerial/drvAsynIPServerPort.c index 7b12f35e9..8aeef3df1 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.c +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.c @@ -295,6 +295,8 @@ static void connectionListener(void *drvPvt) int i; portList_t *pl, *p; int connected; + fd_set read_set; + struct timeval select_timeout; /* * Sanity check @@ -306,6 +308,13 @@ static void connectionListener(void *drvPvt) "drvAsynIPServerPort: %s started listening for connections on %s\n", tty->portName, tty->serverInfo); while (tty->fd != INVALID_SOCKET) { + FD_ZERO(&read_set); + FD_SET(tty->fd, &read_set); + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 50000; /* 0.05 seconds, needs to be less than delay in ttyCleanup */ + if (select(tty->fd + 1, &read_set, NULL, NULL, &select_timeout) < 1 || !FD_ISSET(tty->fd, &read_set)) { + continue; + } if (tty->socketType == SOCK_DGRAM) { if ((tty->UDPbufferPos == 0) && (tty->UDPbufferSize == 0)) { tty->UDPbufferSize = recvfrom(tty->fd, tty->UDPbuffer, THEORETICAL_UDP_MAX_SIZE , 0, NULL, NULL); From 7f89753ea29f2b3716109c54c7224a9e8d4564dc Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Fri, 22 Dec 2023 14:48:44 +0000 Subject: [PATCH 4/5] shutdown socket prior to close --- asyn/drvAsynSerial/drvAsynIPServerPort.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.c b/asyn/drvAsynSerial/drvAsynIPServerPort.c index 8aeef3df1..0fb0ea87a 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.c +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.c @@ -295,8 +295,6 @@ static void connectionListener(void *drvPvt) int i; portList_t *pl, *p; int connected; - fd_set read_set; - struct timeval select_timeout; /* * Sanity check @@ -308,13 +306,6 @@ static void connectionListener(void *drvPvt) "drvAsynIPServerPort: %s started listening for connections on %s\n", tty->portName, tty->serverInfo); while (tty->fd != INVALID_SOCKET) { - FD_ZERO(&read_set); - FD_SET(tty->fd, &read_set); - select_timeout.tv_sec = 0; - select_timeout.tv_usec = 50000; /* 0.05 seconds, needs to be less than delay in ttyCleanup */ - if (select(tty->fd + 1, &read_set, NULL, NULL, &select_timeout) < 1 || !FD_ISSET(tty->fd, &read_set)) { - continue; - } if (tty->socketType == SOCK_DGRAM) { if ((tty->UDPbufferPos == 0) && (tty->UDPbufferSize == 0)) { tty->UDPbufferSize = recvfrom(tty->fd, tty->UDPbuffer, THEORETICAL_UDP_MAX_SIZE , 0, NULL, NULL); @@ -506,9 +497,13 @@ static void ttyCleanup(void *pPvt) if (!tty) return; if (tty->fd >= 0) { asynPrint(tty->pasynUser, ASYN_TRACE_FLOW, "drvAsynIPServerPort:ttyCleanup %s: shutdown socket %d\n", tty->portName, tty->fd); - epicsSocketDestroy(tty->fd); + SOCKET fd_save = tty->fd; tty->fd = INVALID_SOCKET; - epicsThreadSleep(0.1); /* wait for accept thread to terminate */ + /* shutdown then close the socket so accept thread will terminate */ + shutdown(fd_save, SHUT_RDWR); + epicsThreadSleep(0.01); /* give time for shutdown to be noticed prior to close */ + epicsSocketDestroy(fd_save); + epicsThreadSleep(0.1); } free(tty->portName); free(tty->serverInfo); From 19db7d33e5576393f99feeb196f88b7d321e5a95 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sun, 24 Dec 2023 00:33:49 +0000 Subject: [PATCH 5/5] Do not print accept error on connection close --- asyn/drvAsynSerial/drvAsynIPServerPort.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/asyn/drvAsynSerial/drvAsynIPServerPort.c b/asyn/drvAsynSerial/drvAsynIPServerPort.c index 0fb0ea87a..84980c90a 100644 --- a/asyn/drvAsynSerial/drvAsynIPServerPort.c +++ b/asyn/drvAsynSerial/drvAsynIPServerPort.c @@ -324,6 +324,12 @@ static void connectionListener(void *drvPvt) } else { clientFd = epicsSocketAccept(tty->fd, (struct sockaddr *) &clientAddr, &clientLen); + if (tty->fd == INVALID_SOCKET) { + asynPrint(pasynUser, ASYN_TRACE_FLOW, + "drvAsynIPServerPort: terminating connection thread for %s\n", + tty->serverInfo); + break; /* we must be in ioc shutdown and ttyCleanup has been called */ + } asynPrint(pasynUser, ASYN_TRACE_FLOW, "drvAsynIPServerPort: new connection, socket=%d on %s\n", clientFd, tty->serverInfo);