summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormax <max@tclers.tk>2014-04-04 10:02:47 (GMT)
committermax <max@tclers.tk>2014-04-04 10:02:47 (GMT)
commit053685ad2952fe7a83cf63ff28ec273862c903b3 (patch)
treee28f08521e12f9fde833f2d4762ff83db2b77f9b
parent8978760b1a95d061dff0d9c3f0c8a997aa56998d (diff)
downloadtcl-053685ad2952fe7a83cf63ff28ec273862c903b3.zip
tcl-053685ad2952fe7a83cf63ff28ec273862c903b3.tar.gz
tcl-053685ad2952fe7a83cf63ff28ec273862c903b3.tar.bz2
* Rework WaitForConnect() to fix synchronous completion of asynchronous connections.
* Let TcpInputProc() and TcpOutputProc() fail before calling any I/O syscalls when an asynchronous connection has failed. * Adjust the tests accordingly.
-rw-r--r--tests/socket.test13
-rw-r--r--unix/tclUnixSock.c54
2 files changed, 32 insertions, 35 deletions
diff --git a/tests/socket.test b/tests/socket.test
index 61660cd..4fba2c3 100644
--- a/tests/socket.test
+++ b/tests/socket.test
@@ -1993,7 +1993,7 @@ test socket-14.7.2 {pending [socket -async] and blocking [gets], no listener} \
list $x [fconfigure $sock -error]
} -cleanup {
close $sock
- } -match glob -result {{error reading "sock*": socket is not connected} {connection refused}}
+ } -match glob -result {{error reading "sock*": connection refused} {}}
test socket-14.8.0 {pending [socket -async] and nonblocking [gets], server is IPv4} \
-constraints {socket supported_inet supported_inet6} \
-setup {
@@ -2055,10 +2055,10 @@ test socket-14.8.2 {pending [socket -async] and nonblocking [gets], no listener}
if {[catch {gets $sock} x] || $x ne "" || ![fblocked $sock]} break
after 200
}
- fconfigure $sock -error
+ list $x [fconfigure $sock -error]
} -cleanup {
close $sock
- } -match glob -result {connection refused}
+ } -match glob -result {{error reading "sock*": connection refused} {}}
test socket-14.9.0 {pending [socket -async] and blocking [puts], server is IPv4} \
-constraints {socket supported_inet supported_inet6} \
-setup {
@@ -2171,7 +2171,9 @@ test socket-14.11.0 {pending [socket -async] and blocking [puts], no listener, n
vwait x
close $sock
} -cleanup {
- } -result {broken pipe} -returnCodes 1
+ catch {close $sock}
+ unset x
+ } -result {connection refused} -returnCodes 1
test socket-14.11.1 {pending [socket -async] and blocking [puts], no listener, flush} \
-constraints {socket supported_inet supported_inet6} \
-body {
@@ -2183,8 +2185,9 @@ test socket-14.11.1 {pending [socket -async] and blocking [puts], no listener, f
vwait x
close $sock
} -cleanup {
+ catch {close $sock}
unset x
- } -result {broken pipe} -returnCodes 1
+ } -result {connection refused} -returnCodes 1
test socket-14.12 {[socket -async] background progress triggered by [fconfigure -error]} \
-constraints {socket supported_inet supported_inet6} \
-body {
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index 466b231..d4b7b62 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -128,8 +128,7 @@ static int TcpInputProc(ClientData instanceData, char *buf,
static int TcpOutputProc(ClientData instanceData,
const char *buf, int toWrite, int *errorCode);
static void TcpWatchProc(ClientData instanceData, int mask);
-static int WaitForConnect(TcpState *statePtr, int *errorCodePtr,
- int noblock);
+static int WaitForConnect(TcpState *statePtr, int noblock);
/*
* This structure describes the channel type structure for TCP socket
@@ -399,41 +398,33 @@ TcpBlockModeProc(
static int
WaitForConnect(
TcpState *statePtr, /* State of the socket. */
- int *errorCodePtr, /* Where to store errors? */
int noblock) /* Don't wait, even for sockets in blocking mode */
{
- int timeOut; /* How long to wait. */
- int state; /* Of calling TclWaitForFile. */
-
/*
* If an asynchronous connect is in progress, attempt to wait for it to
* complete before reading.
*/
if (statePtr->flags & TCP_ASYNC_CONNECT) {
- if (noblock || statePtr->flags & TCP_ASYNC_SOCKET) {
- timeOut = 0;
+ if (noblock || (statePtr->flags & TCP_ASYNC_SOCKET)) {
+ if (TclUnixWaitForFile(statePtr->fds.fd,
+ TCL_WRITABLE | TCL_EXCEPTION, 0) != 0) {
+ CreateClientSocket(NULL, statePtr);
+ }
} else {
- timeOut = -1;
- CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
- }
- errno = 0;
- state = TclUnixWaitForFile(statePtr->fds.fd,
- TCL_WRITABLE | TCL_EXCEPTION, timeOut);
- if (state != 0) {
- CreateClientSocket(NULL, statePtr);
- }
- if (statePtr->flags & TCP_ASYNC_CONNECT) {
- /* We are still in progress, so ignore the result of the last
- * attempt */
- *errorCodePtr = errno = EWOULDBLOCK;
- return -1;
+ while (statePtr->flags & TCP_ASYNC_CONNECT) {
+ if (TclUnixWaitForFile(statePtr->fds.fd,
+ TCL_WRITABLE | TCL_EXCEPTION, -1) != 0) {
+ CreateClientSocket(NULL, statePtr);
+ }
+ }
}
- if (state & TCL_EXCEPTION) {
- return -1;
- }
}
- return 0;
+ if (statePtr->error != 0) {
+ return -1;
+ } else {
+ return 0;
+ }
}
/*
@@ -471,7 +462,9 @@ TcpInputProc(
int bytesRead;
*errorCodePtr = 0;
- if (WaitForConnect(statePtr, errorCodePtr, 0) != 0) {
+ if (WaitForConnect(statePtr, 0) != 0) {
+ *errorCodePtr = statePtr->error;
+ statePtr->error = 0;
return -1;
}
bytesRead = recv(statePtr->fds.fd, buf, (size_t) bufSize, 0);
@@ -521,7 +514,9 @@ TcpOutputProc(
int written;
*errorCodePtr = 0;
- if (WaitForConnect(statePtr, errorCodePtr, 0) != 0) {
+ if (WaitForConnect(statePtr, 0) != 0) {
+ *errorCodePtr = statePtr->error;
+ statePtr->error = 0;
return -1;
}
written = send(statePtr->fds.fd, buf, (size_t) toWrite, 0);
@@ -748,9 +743,8 @@ TcpGetOptionProc(
{
TcpState *statePtr = instanceData;
size_t len = 0;
- int errorCode;
- WaitForConnect(statePtr, &errorCode, 1);
+ WaitForConnect(statePtr, 1);
if (optionName != NULL) {
len = strlen(optionName);