--- l2_ut_sa.c 2004/04/02 12:27:32 1.24
+++ l2_ut_sa.c 2004/04/21 12:02:12 1.25
@@ -1,8 +1,8 @@
/*
** OSSP sa - Socket Abstraction
-** Copyright (c) 2001-2003 Ralf S. Engelschall <rse@engelschall.com>
-** Copyright (c) 2001-2003 The OSSP Project <http://www.ossp.org/>
-** Copyright (c) 2001-2003 Cable & Wireless Deutschland <http://www.cw.com/de/>
+** Copyright (c) 2001-2004 Ralf S. Engelschall <rse@engelschall.com>
+** Copyright (c) 2001-2004 The OSSP Project <http://www.ossp.org/>
+** Copyright (c) 2001-2004 Cable & Wireless <http://www.cw.com/>
**
** This file is part of OSSP sa, a socket abstraction library which
** can be found at http://www.ossp.org/pkg/lib/sa/.
@@ -1452,6 +1452,7 @@
fd_set rset, wset;
socklen_t len;
sa_rc_t rv;
+ struct timeval *tv;
/* argument sanity check(s) */
if (sa == NULL || raddr == NULL)
@@ -1466,72 +1467,88 @@
if ((rv = sa_socket_init(sa, raddr->nFamily)) != SA_OK)
return SA_RC(rv);
+ /* prepare return code decision */
rv = SA_OK;
- if (SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) {
- /* standard/non-timeout-aware connect operation */
- if (SA_SC_CALL_3(sa, connect, sa->fdSocket, raddr->saBuf, raddr->slBuf) < 0)
- rv = SA_ERR_SYS;
- }
- else {
- /* emulated/timeout-aware connect operation */
- error = 0;
+ error = 0;
- /* temporarily switch underlying socket to non-blocking mode */
+ /* temporarily switch underlying socket to non-blocking mode
+ (necessary under timeout-aware operation only) */
+ flags = 0;
+ if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT])) {
flags = fcntl(sa->fdSocket, F_GETFL, 0);
(void)fcntl(sa->fdSocket, F_SETFL, flags|O_NONBLOCK);
+ }
- /* perform the connect operation */
- if ((n = SA_SC_CALL_3(sa, connect, sa->fdSocket, raddr->saBuf, raddr->slBuf)) < 0) {
- if (errno != EINPROGRESS) {
- error = errno;
- goto done;
- }
- }
-
- /* ok if connect completed immediately */
- if (n == 0)
- goto done;
-
- /* wait for read or write possibility */
- FD_ZERO(&rset);
- FD_ZERO(&wset);
- FD_SET(sa->fdSocket, &rset);
- FD_SET(sa->fdSocket, &wset);
- do {
- n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &rset, &wset, NULL,
- &sa->tvTimeout[SA_TIMEOUT_CONNECT]);
- } while (n == -1 && errno == EINTR);
-
- /* decide on return semantic */
- if (n < 0) {
+ /* perform the connect operation */
+ if ((n = SA_SC_CALL_3(sa, connect, sa->fdSocket, raddr->saBuf, raddr->slBuf)) < 0) {
+ if (errno != EINTR && errno != EINPROGRESS) {
+ /* we have to perform the following post-processing under
+ EINPROGRESS anway, but actually also for EINTR according
+ to Unix Network Programming, volume 1, section 5.9, W.
+ Richard Stevens: "What we are doing [] is restarting
+ the interrupted system call ourself. This is fine for
+ accept, along with the functions such as read, write,
+ select and open. But there is one function that we cannot
+ restart ourself: connect. If this function returns EINTR,
+ we cannot call it again, as doing so will return an
+ immediate error. When connect is interrupted by a caught
+ signal and is not automatically restarted, we must call
+ select to wait for the connection to complete, as we
+ describe in section 15.3." */
error = errno;
goto done;
}
- else if (n == 0) {
- (void)close(sa->fdSocket); /* stop TCP three-way handshake */
- sa->fdSocket = -1;
- rv = SA_ERR_TMT;
- goto done;
- }
-
- /* fetch pending error */
- len = (socklen_t)sizeof(error);
- if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, (void *)&error, &len) < 0)
- error = errno;
-
- done:
+ }
- /* reset socket flags */
+ /* ok if connect completed immediately */
+ if (n == 0)
+ goto done;
+
+ /* wait for read or write possibility */
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_SET(sa->fdSocket, &rset);
+ FD_SET(sa->fdSocket, &wset);
+ if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT]))
+ tv = &sa->tvTimeout[SA_TIMEOUT_CONNECT];
+ else
+ tv = NULL;
+ do {
+ n = SA_SC_CALL_5(sa, select, sa->fdSocket+1, &rset, &wset, NULL, tv);
+ } while (n == -1 && errno == EINTR);
+
+ /* decide on return semantic */
+ if (n < 0) {
+ error = errno;
+ goto done;
+ }
+ else if (n == 0) {
+ (void)close(sa->fdSocket); /* stop TCP three-way handshake */
+ sa->fdSocket = -1;
+ rv = SA_ERR_TMT;
+ goto done;
+ }
+
+ /* fetch pending error */
+ len = (socklen_t)sizeof(error);
+ if (getsockopt(sa->fdSocket, SOL_SOCKET, SO_ERROR, (void *)&error, &len) < 0)
+ error = errno;
+
+ done:
+
+ /* reset socket flags
+ (necessary under timeout-aware operation only) */
+ if (!SA_TVISZERO(sa->tvTimeout[SA_TIMEOUT_CONNECT]))
(void)fcntl(sa->fdSocket, F_SETFL, flags);
- /* optionally set errno */
- if (error != 0) {
- (void)close(sa->fdSocket); /* just in case */
- sa->fdSocket = -1;
- errno = error;
- rv = SA_ERR_SYS;
- }
+ /* optionally set errno */
+ if (error != 0) {
+ (void)close(sa->fdSocket); /* just in case */
+ sa->fdSocket = -1;
+ errno = error;
+ rv = SA_ERR_SYS;
}
+
return SA_RC(rv);
}
|