diff --git a/asyn/asynDriver/asynDriver.h b/asyn/asynDriver/asynDriver.h index 6157f1b9f..d37eeeaa8 100644 --- a/asyn/asynDriver/asynDriver.h +++ b/asyn/asynDriver/asynDriver.h @@ -164,6 +164,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 dc2882685..fe848cea9 100644 --- a/asyn/asynDriver/asynManager.c +++ b/asyn/asynDriver/asynManager.c @@ -316,6 +316,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); @@ -374,6 +375,7 @@ static asynManager manager = { isEnabled, isAutoConnect, setAutoConnectTimeout, + getAutoConnectTimeout, waitConnect, registerInterruptSource, getInterruptPvt, @@ -2376,6 +2378,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..0c8b8c07c 100644 --- a/asyn/drvAsynSerial/drvAsynIPPort.c +++ b/asyn/drvAsynSerial/drvAsynIPPort.c @@ -85,6 +85,13 @@ # endif #endif +/* Linux after version 2.3.31 (2001) supports SO_SNDTIMEO for connect() calls. It uses a timeval argument. + * Windows supports SO_SNDTIMEO but it takes a DWORD argument and does not appear to apply to connect() calls. + * Darwin supports SO_SNDTIMEO but the documentation is not clear whether it applies to connect() calls. */ +#if defined(linux) || defined(darwin) +# define USE_CONNECTTIMEOUT +#endif + /* If SO_REUSEPORT is not defined then use SO_REUSEADDR instead. It is not defined on RTEMS, Windows and older Linux versions. */ #ifndef SO_REUSEPORT @@ -511,6 +518,20 @@ 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 = (long)connectTimeout; + connectTV.tv_usec = (long)((connectTimeout - connectTV.tv_sec)*1000000); +#ifdef USE_CONNECTTIMEOUT + if (getsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&saveTV, &svlen) < 0) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, error calling getsockopt for SO_SNDTIMEO: %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_SNDTIMEO: %s\n", strerror(SOCKERRNO)); + } +#endif if (connect(fd, &tty->farAddr.oa.sa, (int)tty->farAddrSize) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't connect to %s: %s", @@ -520,6 +541,11 @@ connectIt(void *drvPvt, asynUser *pasynUser) tty->flags |= FLAG_NEED_LOOKUP; return asynError; } +#ifdef USE_CONNECTTIMEOUT + if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&saveTV, sizeof saveTV) < 0) { + asynPrint(pasynUser, ASYN_TRACE_ERROR, "connectIt, error calling setsockopt for SO_SNDTIMEO: %s\n", strerror(SOCKERRNO)); + } +#endif } } i = 1;