From 56f1645aa881b8a4d3c2881acf376d0921faf206 Mon Sep 17 00:00:00 2001 From: Mark Rivers Date: Tue, 5 Nov 2024 11:38:24 -0600 Subject: [PATCH] Changes to shorten connect() timeout when connecting to unavailable TCP ports --- asyn/asynDriver/asynDriver.h | 1 + asyn/asynDriver/asynManager.c | 11 +++++++++++ asyn/drvAsynSerial/drvAsynIPPort.c | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/asyn/asynDriver/asynDriver.h b/asyn/asynDriver/asynDriver.h index 446bad350..dd1d1bd62 100644 --- a/asyn/asynDriver/asynDriver.h +++ b/asyn/asynDriver/asynDriver.h @@ -161,6 +161,7 @@ typedef struct asynManager { asynStatus (*isEnabled)(asynUser *pasynUser,int *yesNo); asynStatus (*isAutoConnect)(asynUser *pasynUser,int *yesNo); asynStatus (*setAutoConnectTimeout)(double timeout); + asynStatus (*getAutoConnectTimeout)(double *timeout); asynStatus (*waitConnect)(asynUser *pasynUser, double timeout); /*The following are methods for interrupts*/ asynStatus (*registerInterruptSource)(const char *portName, diff --git a/asyn/asynDriver/asynManager.c b/asyn/asynDriver/asynManager.c index 2061131ed..856a8cc52 100644 --- a/asyn/asynDriver/asynManager.c +++ b/asyn/asynDriver/asynManager.c @@ -313,6 +313,7 @@ static asynStatus isConnected(asynUser *pasynUser,int *yesNo); static asynStatus isEnabled(asynUser *pasynUser,int *yesNo); static asynStatus isAutoConnect(asynUser *pasynUser,int *yesNo); static asynStatus setAutoConnectTimeout(double timeout); +static asynStatus getAutoConnectTimeout(double *timeout); static asynStatus waitConnect(asynUser *pasynUser, double timeout); static asynStatus registerInterruptSource(const char *portName, asynInterface *pasynInterface, void **pasynPvt); @@ -370,6 +371,7 @@ static asynManager manager = { isEnabled, isAutoConnect, setAutoConnectTimeout, + getAutoConnectTimeout, waitConnect, registerInterruptSource, getInterruptPvt, @@ -2222,6 +2224,15 @@ static asynStatus setAutoConnectTimeout(double timeout) return asynSuccess; } +static asynStatus getAutoConnectTimeout(double *timeout) +{ + if(!pasynBase) asynInit(); + epicsMutexMustLock(pasynBase->lock); + *timeout = pasynBase->autoConnectTimeout; + epicsMutexUnlock(pasynBase->lock); + return asynSuccess; +} + static asynStatus setQueueLockPortTimeout(asynUser *pasynUser, double timeout) { userPvt *puserPvt = asynUserToUserPvt(pasynUser); diff --git a/asyn/drvAsynSerial/drvAsynIPPort.c b/asyn/drvAsynSerial/drvAsynIPPort.c index a5fd1415f..da9e849cb 100644 --- a/asyn/drvAsynSerial/drvAsynIPPort.c +++ b/asyn/drvAsynSerial/drvAsynIPPort.c @@ -511,7 +511,22 @@ connectIt(void *drvPvt, asynUser *pasynUser) * problem is just that the device has DHCP'd itself an new number. */ if (tty->socketType != SOCK_DGRAM) { + double connectTimeout; + struct timeval saveTV, connectTV; + socklen_t svlen = sizeof saveTV; + pasynManager->getAutoConnectTimeout(&connectTimeout); + connectTV.tv_sec = (time_t)connectTimeout; + connectTV.tv_usec = (suseconds_t)((connectTimeout - connectTV.tv_sec)*1000000); + asynPrint(pasynUser, ASYN_TRACE_ERROR, "Calling setsockopt SO_SNDTIMEO tv_sec=%d tv_usec=%d\n", connectTV.tv_sec, connectTV.tv_usec); + if (getsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&saveTV, &svlen) < 0) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, error calling getsockopt for SO_RECVTIMEO: %s\n", strerror(SOCKERRNO)); + } + if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&connectTV, sizeof connectTV) < 0) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, error calling setsockopt for SO_RECVTIMEO: %s\n", strerror(SOCKERRNO)); + } + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, calling connect()\n"); if (connect(fd, &tty->farAddr.oa.sa, (int)tty->farAddrSize) < 0) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, connect returned error: %s\n", strerror(SOCKERRNO)); epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't connect to %s: %s", tty->IPDeviceName, strerror(SOCKERRNO)); @@ -520,6 +535,9 @@ connectIt(void *drvPvt, asynUser *pasynUser) tty->flags |= FLAG_NEED_LOOKUP; return asynError; } + if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&saveTV, sizeof saveTV) < 0) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, error calling setsockopt for SO_RECVTIMEO: %s\n", strerror(SOCKERRNO)); + } } } i = 1;