diff --git a/src/libCom/osi/os/WIN32/osdSock.c b/src/libCom/osi/os/WIN32/osdSock.c index 19b542494..d18f49ebe 100644 --- a/src/libCom/osi/os/WIN32/osdSock.c +++ b/src/libCom/osi/os/WIN32/osdSock.c @@ -212,3 +212,16 @@ epicsShareFunc const char * epicsShareAPI convertSocketErrorToString (int errnoI #endif } +/* + * WINSOCK II shutdown() function does not wake up threads blocking in TCP recv() + */ +epicsShareFunc enum osiSockShutdownReturn epicsShareAPI osiSocketShutdown ( SOCKET sock ) +{ + int status = socket_close ( sock ); + if ( status ) { + errlogPrintf ("TCP WIN32 socket close (for shutdown purposes) error was %s\n", + SOCKERRSTR (SOCKERRNO) ); + return ossrSocketNoChange; + } + return ossrSocketClosed; +} \ No newline at end of file diff --git a/src/libCom/osi/os/default/osdSock.c b/src/libCom/osi/os/default/osdSock.c index 9b614496b..70cc90615 100644 --- a/src/libCom/osi/os/default/osdSock.c +++ b/src/libCom/osi/os/default/osdSock.c @@ -128,3 +128,28 @@ epicsShareFunc int epicsShareAPI hostToIPAddr unlockInfo (); return ret; } + +/* + * typically the shutdown() function will wake up threads blocking in TCP recv() + * and this is a more graceful way to shutdown + */ +epicsShareFunc enum osiSockShutdownReturn epicsShareAPI osiSocketShutdown ( SOCKET sock ) +{ + status = shutdown ( this->sock, SD_BOTH ); + if ( status ) { + errlogPrintf ( "TCP socket shutdown error (for shutdown purposes) was %s\n", + SOCKERRSTR (SOCKERRNO) ); + status = socket_close ( this->sock ); + if ( status ) { + errlogPrintf ("TCP socket close error (for shutdown purposes) was %s\n", + SOCKERRSTR (SOCKERRNO) ); + return ossrSocketNoChange; + } + else { + return ossrSocketClosed; + } + } + else { + return ossrSocketShutdown; + } +} \ No newline at end of file diff --git a/src/libCom/osi/os/vxWorks/osdSock.c b/src/libCom/osi/os/vxWorks/osdSock.c index c88eee15c..4fe34c499 100644 --- a/src/libCom/osi/os/vxWorks/osdSock.c +++ b/src/libCom/osi/os/vxWorks/osdSock.c @@ -86,3 +86,28 @@ epicsShareFunc int epicsShareAPI hostToIPAddr */ return 0; } + +/* + * typically the shutdown() function will wake up threads blocking in TCP recv() + * and this is a more graceful way to shutdown + */ +epicsShareFunc enum osiSockShutdownReturn epicsShareAPI osiSocketShutdown ( SOCKET sock ) +{ + status = shutdown ( this->sock, SD_BOTH ); + if ( status ) { + errlogPrintf ( "TCP socket shutdown error (for shutdown purposes) was %s\n", + SOCKERRSTR (SOCKERRNO) ); + status = socket_close ( this->sock ); + if ( status ) { + errlogPrintf ("TCP socket close error (for shutdown purposes) was %s\n", + SOCKERRSTR (SOCKERRNO) ); + return ossrSocketNoChange; + } + else { + return ossrSocketClosed; + } + } + else { + return ossrSocketShutdown; + } +} \ No newline at end of file diff --git a/src/libCom/osi/osiSock.h b/src/libCom/osi/osiSock.h index 6d76e4da5..f517874fb 100644 --- a/src/libCom/osi/osiSock.h +++ b/src/libCom/osi/osiSock.h @@ -175,6 +175,13 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses */ epicsShareFunc osiSockAddr epicsShareAPI osiLocalAddr (SOCKET socket); +/* + * WINSOCK shutdown() function does not wake up threads blocking + * in TCP recv() + */ +enum osiSockShutdownReturn { ossrSocketClosed, ossrSocketShutdown, ossrSocketNoChange }; +epicsShareFunc enum osiSockShutdownReturn epicsShareAPI osiSocketShutdown ( SOCKET sock ); + #ifdef __cplusplus } #endif