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..4090f633e 100644 --- a/asyn/drvAsynSerial/drvAsynIPPort.c +++ b/asyn/drvAsynSerial/drvAsynIPPort.c @@ -505,13 +505,56 @@ connectIt(void *drvPvt, asynUser *pasynUser) } } + } + +#ifdef USE_POLL + if (setNonBlock(fd, 1) < 0) { + epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, + "Can't set %s O_NONBLOCK option: %s", + tty->IPDeviceName, strerror(SOCKERRNO)); + epicsSocketDestroy(fd); + return asynError; + } +#endif + + if (pasynUser->reason <= 0) { + /* * Connect to the remote host * If the connect fails, arrange for another DNS lookup in case the * problem is just that the device has DHCP'd itself an new number. */ if (tty->socketType != SOCK_DGRAM) { - if (connect(fd, &tty->farAddr.oa.sa, (int)tty->farAddrSize) < 0) { + int connectResult = connect(fd, &tty->farAddr.oa.sa, (int)tty->farAddrSize); + #ifdef USE_POLL + if (connectResult < 0 && ((SOCKERRNO == EWOULDBLOCK) || (SOCKERRNO == EINPROGRESS))) { + double connectTimeout; + int msConnectTimeout; + struct pollfd pollfd; + + pasynManager->getAutoConnectTimeout(&connectTimeout); + msConnectTimeout = 1000 * connectTimeout; + pollfd.fd = fd; + pollfd.events = POLLOUT; + + /* + * poll() returning 1 is the only case where connect might have been successful. + * Otherwise connectResult will remain -1. + */ + if (poll(&pollfd, 1, msConnectTimeout) == 1) { + int so_error; + socklen_t len = sizeof so_error; + + /* + * We must verify SO_ERROR to make sure the connection was successful. + */ + getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len); + if (so_error == 0) + connectResult = 0; + } + } + #endif + if (connectResult < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't connect to %s: %s", tty->IPDeviceName, strerror(SOCKERRNO)); @@ -532,15 +575,6 @@ connectIt(void *drvPvt, asynUser *pasynUser) epicsSocketDestroy(fd); return asynError; } -#ifdef USE_POLL - if (setNonBlock(fd, 1) < 0) { - epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, - "Can't set %s O_NONBLOCK option: %s", - tty->IPDeviceName, strerror(SOCKERRNO)); - epicsSocketDestroy(fd); - return asynError; - } -#endif asynPrint(pasynUser, ASYN_TRACE_FLOW, "Opened connection OK to %s\n", tty->IPDeviceName);