summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavygrvy <davygrvy@pobox.com>2009-01-06 22:17:35 (GMT)
committerdavygrvy <davygrvy@pobox.com>2009-01-06 22:17:35 (GMT)
commit74f1d70da56d9db2c2c3d66aa4482283f52ef725 (patch)
treee383a673c621d4278944dc58e1421616a47ab7d4
parent94fd2665a59d45f3535b7a66a8ff9205541f85ce (diff)
downloadtcl-tip_162_branch.zip
tcl-tip_162_branch.tar.gz
tcl-tip_162_branch.tar.bz2
read() errors or EOF shall not prevent write(). This allows for proper graceful closing. Prevent the threadActionProc from doing anything if we are exiting as the TclpFinailize order problem still exists. tip_162_branch
-rw-r--r--win/tclWinsockCore.c122
1 files changed, 84 insertions, 38 deletions
diff --git a/win/tclWinsockCore.c b/win/tclWinsockCore.c
index c8872b8..62beaa9 100644
--- a/win/tclWinsockCore.c
+++ b/win/tclWinsockCore.c
@@ -12,7 +12,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinsockCore.c,v 1.1.2.13 2008/12/13 21:30:52 davygrvy Exp $
+ * RCS: @(#) $Id: tclWinsockCore.c,v 1.1.2.14 2009/01/06 22:17:35 davygrvy Exp $
*/
#include "tclWinInt.h"
@@ -78,6 +78,7 @@ static Tcl_EventDeleteProc IocpRemovePendingEvents;
static Tcl_EventDeleteProc IocpRemoveAllPendingEvents;
static Tcl_DriverCloseProc IocpCloseProc;
+static Tcl_DriverClose2Proc IocpClose2Proc;
static Tcl_DriverInputProc IocpInputProc;
static Tcl_DriverInputProc IocpInputNotSupProc;
static Tcl_DriverOutputProc IocpOutputProc;
@@ -147,7 +148,7 @@ Tcl_ChannelType IocpStreamChannelType = {
IocpGetOptionProc, /* Get option proc. */
IocpWatchProc, /* Set up notifier to watch this channel. */
IocpGetHandleProc, /* Get an OS handle from channel. */
- NULL, /* close2proc. */
+ IocpClose2Proc, /* close2proc. */
IocpBlockProc, /* Set socket into (non-)blocking mode. */
NULL, /* flush proc. */
NULL, /* handler proc. */
@@ -561,7 +562,7 @@ Tcl_MakeSocketClientChannel (
if (getsockopt(sock, SOL_SOCKET, SO_PROTOCOL_INFO,
(char *)&protocolInfo, &protocolInfoSize) == SOCKET_ERROR)
{
- /* Bail if we can't get the internal LSP data */
+ /* Bail if we can't get the LSP data. */
SetLastError(WSAGetLastError());
return NULL;
}
@@ -630,16 +631,15 @@ FindProtocolMatch(LPWSAPROTOCOL_INFO pinfo, WS2ProtocolData **pdata)
) {
psdata = Tcl_GetHashValue(entryPtr);
if (
- pinfo->iAddressFamily == psdata->af &&
- pinfo->iSocketType == psdata->type &&
- pinfo->iProtocol == psdata->protocol
- ){
+ pinfo->iAddressFamily == psdata->af &&
+ pinfo->iSocketType == psdata->type &&
+ pinfo->iProtocol == psdata->protocol
+ ) {
/* found */
*pdata = psdata;
return TCL_OK;
}
}
-
return TCL_ERROR;
}
@@ -1144,6 +1144,66 @@ IocpCloseProc (
return errorCode;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * IocpClose2Proc --
+ *
+ * This function is called by the generic IO level to perform the channel
+ * type specific part of a half-close: namely, a shutdown() on a socket.
+ *
+ * Results:
+ * 0 if successful, the value of errno if failed.
+ *
+ * Side effects:
+ * Shuts down one side of the socket.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+IocpClose2Proc(
+ ClientData instanceData, /* The socket to close. */
+ Tcl_Interp *interp, /* For error reporting. */
+ int flags) /* Flags that indicate which side to close. */
+{
+ /*
+ * Shutdown the OS socket handle.
+ */
+ switch(flags) {
+ case TCL_CLOSE_READ:
+ sd=SD_RECEIVE;
+ break;
+ case TCL_CLOSE_WRITE:
+ if (!infoPtr->acceptProc) {
+ bufPtr = GetBufferObj(infoPtr, 0);
+ PostOverlappedDisconnect(infoPtr, bufPtr);
+ }
+ break;
+ default:
+ if (interp) {
+ Tcl_AppendResult(interp, "Socket close2proc called bidirectionally", NULL);
+ }
+ return TCL_ERROR;
+ }
+
+ if (!infoPtr->acceptProc) {
+ bufPtr = GetBufferObj(infoPtr, 0);
+ PostOverlappedDisconnect(infoPtr, bufPtr);
+ } else {
+ SOCKET temp;
+ /* Close this listening socket directly. */
+ infoPtr->flags |= IOCP_CLOSABLE;
+ InterlockedDecrement(&infoPtr->outstandingOps);
+ temp = infoPtr->socket;
+ infoPtr->socket = INVALID_SOCKET;
+ /* Cause all pending AcceptEx calls to return with WSA_OPERATION_ABORTED */
+ closesocket(temp);
+ }
+
+ return errorCode;
+}
+
static int
IocpInputProc (
ClientData instanceData, /* The socket state. */
@@ -1161,11 +1221,6 @@ IocpInputProc (
*errorCodePtr = 0;
- if (infoPtr->flags & IOCP_EOF) {
- *errorCodePtr = ENOTCONN;
- return -1;
- }
-
/* If we are async, don't block on the queue. */
timeout = (infoPtr->flags & IOCP_ASYNC ? 0 : INFINITE);
@@ -1408,21 +1463,11 @@ IocpOutputProc (
*errorCodePtr = 0;
- if (TclInExit() || infoPtr->flags & IOCP_EOF
- || infoPtr->flags & IOCP_CLOSING) {
+ if (TclInExit() || infoPtr->flags & IOCP_CLOSING) {
*errorCodePtr = ENOTCONN;
return -1;
}
- /*
- * Check for a background error on the last operations.
- */
-
- if (infoPtr->lastError) {
- WSASetLastError(infoPtr->lastError);
- goto error;
- }
-
bufPtr = GetBufferObj(infoPtr, toWrite);
memcpy(bufPtr->buf, buf, toWrite);
result = PostOverlappedSend(infoPtr, bufPtr);
@@ -1433,7 +1478,6 @@ IocpOutputProc (
return -1;
} else if (result != NO_ERROR) {
/* Don't FreeBufferObj(), as it is already queued to the cp, too */
- infoPtr->lastError = result;
WSASetLastError(result);
goto error;
}
@@ -1961,20 +2005,22 @@ IocpThreadActionProc (ClientData instanceData, int action)
{
SocketInfo *infoPtr = (SocketInfo *) instanceData;
- /* This lock is to prevent IocpZapTclNotifier() from accessing
- * infoPtr->tsdHome */
- EnterCriticalSection(&infoPtr->tsdLock);
- switch (action) {
- case TCL_CHANNEL_THREAD_INSERT:
- infoPtr->tsdHome = InitSockets();
- break;
- case TCL_CHANNEL_THREAD_REMOVE:
- /* Unable to turn off reading, therefore don't notify
- * anyone during the move. */
- infoPtr->tsdHome = NULL;
- break;
+ if (initialized) {
+ /* This lock is to prevent IocpZapTclNotifier() from accessing
+ * infoPtr->tsdHome */
+ EnterCriticalSection(&infoPtr->tsdLock);
+ switch (action) {
+ case TCL_CHANNEL_THREAD_INSERT:
+ infoPtr->tsdHome = InitSockets();
+ break;
+ case TCL_CHANNEL_THREAD_REMOVE:
+ /* Unable to turn off reading, therefore don't notify
+ * anyone during the move. */
+ infoPtr->tsdHome = NULL;
+ break;
+ }
+ LeaveCriticalSection(&infoPtr->tsdLock);
}
- LeaveCriticalSection(&infoPtr->tsdLock);
}
/* =================================================================== */