diff options
author | stanton <stanton> | 1998-09-24 23:58:14 (GMT) |
---|---|---|
committer | stanton <stanton> | 1998-09-24 23:58:14 (GMT) |
commit | 9995355714bc90faf7c2e345b3d6a1d041447097 (patch) | |
tree | 2ad97c5b1994495118cef4df947cf16b55e326f2 /win/tclWinSock.c | |
parent | e13392595faf8e8d0d1c3c514ce160cfadc3d372 (diff) | |
download | tcl-9995355714bc90faf7c2e345b3d6a1d041447097.zip tcl-9995355714bc90faf7c2e345b3d6a1d041447097.tar.gz tcl-9995355714bc90faf7c2e345b3d6a1d041447097.tar.bz2 |
merging changes from 8.0.3 into 8.1a2
Diffstat (limited to 'win/tclWinSock.c')
-rw-r--r-- | win/tclWinSock.c | 211 |
1 files changed, 109 insertions, 102 deletions
diff --git a/win/tclWinSock.c b/win/tclWinSock.c index c6e6273..3b0ba15 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tclWinSock.c 1.93 98/02/19 15:21:32 + * RCS: @(#) $Id: tclWinSock.c,v 1.1.2.2 1998/09/24 23:59:53 stanton Exp $ */ #include "tclWinInt.h" @@ -51,6 +51,9 @@ static struct { int (PASCAL FAR *listen)(SOCKET s, int backlog); u_short (PASCAL FAR *ntohs)(u_short netshort); int (PASCAL FAR *recv)(SOCKET s, char FAR * buf, int len, int flags); + int (PASCAL FAR *select)(int nfds, fd_set FAR * readfds, + fd_set FAR * writefds, fd_set FAR * exceptfds, + const struct timeval FAR * tiemout); int (PASCAL FAR *send)(SOCKET s, const char FAR * buf, int len, int flags); int (PASCAL FAR *setsockopt)(SOCKET s, int level, int optname, const char FAR * optval, int optlen); @@ -292,7 +295,8 @@ InitSockets() const struct sockaddr FAR *name, int namelen)) GetProcAddress(winSock.hInstance, "connect"); winSock.ioctlsocket = (int (PASCAL FAR *)(SOCKET s, long cmd, - u_long FAR *argp)) GetProcAddress(winSock.hInstance, "ioctlsocket"); + u_long FAR *argp)) + GetProcAddress(winSock.hInstance, "ioctlsocket"); winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s, int level, int optname, char FAR * optval, int FAR *optlen)) GetProcAddress(winSock.hInstance, "getsockopt"); @@ -308,6 +312,10 @@ InitSockets() GetProcAddress(winSock.hInstance, "ntohs"); winSock.recv = (int (PASCAL FAR *)(SOCKET s, char FAR * buf, int len, int flags)) GetProcAddress(winSock.hInstance, "recv"); + winSock.select = (int (PASCAL FAR *)(int nfds, fd_set FAR * readfds, + fd_set FAR * writefds, fd_set FAR * exceptfds, + const struct timeval FAR * tiemout)) + GetProcAddress(winSock.hInstance, "select"); winSock.send = (int (PASCAL FAR *)(SOCKET s, const char FAR * buf, int len, int flags)) GetProcAddress(winSock.hInstance, "send"); winSock.setsockopt = (int (PASCAL FAR *)(SOCKET s, int level, @@ -362,6 +370,7 @@ InitSockets() (winSock.listen == NULL) || (winSock.ntohs == NULL) || (winSock.recv == NULL) || + (winSock.select == NULL) || (winSock.send == NULL) || (winSock.setsockopt == NULL) || (winSock.socket == NULL) || @@ -686,8 +695,7 @@ SocketEventProc(evPtr, flags) SocketInfo *infoPtr; SocketEvent *eventPtr = (SocketEvent *) evPtr; int mask = 0; - u_long nBytes; - int status, events; + int events; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { @@ -747,33 +755,30 @@ SocketEventProc(evPtr, flags) Tcl_SetMaxBlockTime(&blockTime); mask |= TCL_READABLE; } else if (events & FD_READ) { + fd_set readFds; + struct timeval timeout; + /* * We must check to see if data is really available, since someone - * could have consumed the data in the meantime. + * could have consumed the data in the meantime. Turn off async + * notification so select will work correctly. If the socket is + * still readable, notify the channel driver, otherwise reset the + * async select handler and keep waiting. */ - nBytes = 0; - status = (*winSock.ioctlsocket)(infoPtr->socket, FIONREAD, - &nBytes); - if ((status != SOCKET_ERROR) && (nBytes > 0)) { + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, 0, 0); + + FD_ZERO(&readFds); + FD_SET(infoPtr->socket, &readFds); + timeout.tv_usec = 0; + timeout.tv_sec = 0; + + if ((*winSock.select)(0, &readFds, NULL, NULL, &timeout) != 0) { mask |= TCL_READABLE; } else { - /* - * We are in a strange state, probably because someone - * besides Tcl is reading from this socket. Try to - * recover by clearing the read event. - */ - + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + SOCKET_MESSAGE, infoPtr->selectEvents); infoPtr->readyEvents &= ~(FD_READ); - - /* - * Re-issue WSAAsyncSelect() since we are gobbling up an - * event, without letting the reader do any I/O to re-enable - * the notification. - */ - - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, - SOCKET_MESSAGE, infoPtr->selectEvents); } } if (events & FD_WRITE) { @@ -1094,6 +1099,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) * automatically places the socket into non-blocking mode. */ + (*winSock.ioctlsocket)(sock, FIONBIO, &flag); (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); @@ -1219,51 +1225,42 @@ WaitForSocketEvent(infoPtr, events, errorCodePtr) oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); - while (!(infoPtr->readyEvents & events)) { - if (infoPtr->flags & SOCKET_ASYNC) { - if (!PeekMessage(&msg, winSock.hwnd, SOCKET_MESSAGE, - SOCKET_MESSAGE, PM_REMOVE)) { - *errorCodePtr = EWOULDBLOCK; - result = 0; - break; - } - } else { - /* - * Look for a socket event. Note that we will be getting - * events for all of Tcl's sockets, not just the one we wanted. - */ - - result = GetMessage(&msg, winSock.hwnd, SOCKET_MESSAGE, - SOCKET_MESSAGE); - if (result == -1) { - TclWinConvertError(GetLastError()); - *errorCodePtr = Tcl_GetErrno(); - result = 0; - break; - } - - /* - * I don't think we can get a WM_QUIT during a tight modal - * loop, but just in case... - */ + /* + * Reset WSAAsyncSelect so we have a fresh set of events pending. + */ - if (result == 0) { - panic("WaitForSocketEvent: Got WM_QUIT during modal loop!"); - } - } + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, 0, 0); + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + SOCKET_MESSAGE, infoPtr->selectEvents); + while (1) { /* - * Dispatch the message and then check for an error on the socket. + * Process all outstanding messages on the socket window. */ - infoPtr->lastError = 0; - DispatchMessage(&msg); + while (PeekMessage(&msg, winSock.hwnd, 0, 0, PM_REMOVE)) { + DispatchMessage(&msg); + } + if (infoPtr->lastError) { *errorCodePtr = infoPtr->lastError; result = 0; break; + } else if (infoPtr->readyEvents & events) { + break; + } else if (infoPtr->flags & SOCKET_ASYNC) { + *errorCodePtr = EWOULDBLOCK; + result = 0; + break; } + + /* + * Wait until something happens. + */ + + WaitMessage(); } + (void) Tcl_SetServiceMode(oldMode); return result; @@ -1595,45 +1592,43 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) */ while (1) { - if (infoPtr->readyEvents & (FD_CLOSE|FD_READ)) { - bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0); - infoPtr->readyEvents &= ~(FD_READ); - - /* - * Check for end-of-file condition or successful read. - */ - - if (bytesRead == 0) { - infoPtr->flags |= SOCKET_EOF; - } - if (bytesRead != SOCKET_ERROR) { - return bytesRead; - } - - /* - * If an error occurs after the FD_CLOSE has arrived, - * then ignore the error and report an EOF. - */ - - if (infoPtr->readyEvents & FD_CLOSE) { - infoPtr->flags |= SOCKET_EOF; - return 0; - } - - /* - * Check for error condition or underflow in non-blocking case. - */ - - error = (*winSock.WSAGetLastError)(); - if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { - TclWinConvertWSAError(error); - *errorCodePtr = Tcl_GetErrno(); - return -1; - } - - } else if (infoPtr->flags & SOCKET_ASYNC) { - *errorCodePtr = EWOULDBLOCK; - return -1; + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + 0, 0); + bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0); + infoPtr->readyEvents &= ~(FD_READ); + + /* + * Check for end-of-file condition or successful read. + */ + + if (bytesRead == 0) { + infoPtr->flags |= SOCKET_EOF; + } + if (bytesRead != SOCKET_ERROR) { + break; + } + + /* + * If an error occurs after the FD_CLOSE has arrived, + * then ignore the error and report an EOF. + */ + + if (infoPtr->readyEvents & FD_CLOSE) { + infoPtr->flags |= SOCKET_EOF; + bytesRead = 0; + break; + } + + /* + * Check for error condition or underflow in non-blocking case. + */ + + error = (*winSock.WSAGetLastError)(); + if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { + TclWinConvertWSAError(error); + *errorCodePtr = Tcl_GetErrno(); + bytesRead = -1; + break; } /* @@ -1642,9 +1637,14 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) */ if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) { - return -1; - } + bytesRead = -1; + break; + } } + + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + SOCKET_MESSAGE, infoPtr->selectEvents); + return bytesRead; } /* @@ -1699,6 +1699,8 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) } while (1) { + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + 0, 0); bytesWritten = (*winSock.send)(infoPtr->socket, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { /* @@ -1726,12 +1728,14 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) infoPtr->readyEvents &= ~(FD_WRITE); if (infoPtr->flags & SOCKET_ASYNC) { *errorCodePtr = EWOULDBLOCK; - return -1; + bytesWritten = -1; + break; } } else { TclWinConvertWSAError(error); *errorCodePtr = Tcl_GetErrno(); - return -1; + bytesWritten = -1; + break; } /* @@ -1740,10 +1744,13 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) */ if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) { - return -1; + bytesWritten = -1; + break; } } + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + SOCKET_MESSAGE, infoPtr->selectEvents); return bytesWritten; } |