summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--win/tclWinPort.h10
-rw-r--r--win/tclWinSock.c982
3 files changed, 608 insertions, 403 deletions
diff --git a/ChangeLog b/ChangeLog
index 57a3b20..16e5fc4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
2002-11-26 David Gravereaux <davygrvy@pobox.com>
+ * win/tclWinPort.h:
+ * win/tclWinSock.c: This patch does two things:
+
+ 1) Cleans-up the winsock typedefs by using the typedefs
+ provided by winsock2.h. This has no effect on how winsock
+ is initialized; just makes the source code easier to read.
+ [Patch 561305]
+
+ 2) Revamps how the socket message handler thread is brough up
+ and down to allows for cleaner exits without the use of
+ TerminateThread(). TerminateThread is evil. No attempt has
+ been made to resolve [Bug 593810] which may need a new
+ channel driver version for adding a registering function
+ whithin the transfered thread to init the handler thread.
+ IOW, initialization of the TSD structure was getting bypassed
+ through the thread extension's [thread::transfer] command.
+
+2002-11-26 David Gravereaux <davygrvy@pobox.com>
+
* win/tclWinConsole.c:
* win/tclWinPipe.c:
* win/tclWinSerial.c:
diff --git a/win/tclWinPort.h b/win/tclWinPort.h
index 011a061..f0ba460 100644
--- a/win/tclWinPort.h
+++ b/win/tclWinPort.h
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinPort.h,v 1.34 2002/09/27 00:50:10 hobbs Exp $
+ * RCS: @(#) $Id: tclWinPort.h,v 1.35 2002/11/27 00:58:01 davygrvy Exp $
*/
#ifndef _TCLWINPORT
@@ -69,6 +69,14 @@
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
+/*
+ * Ask for the winsock function typedefs, only. wspiapi.h may be
+ * included, 1) isn't used, and 2) can't cope with typedefs only.
+ * This appears to be a bug in wspiapi.h, so make sure it is excluded.
+ */
+#define _WSPIAPI_H_
+#define INCL_WINSOCK_API_PROTOTYPES 0
+#define INCL_WINSOCK_API_TYPEDEFS 1
#include <winsock2.h>
#ifdef BUILD_tcl
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index a520380..160ed14 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -8,12 +8,21 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinSock.c,v 1.27 2002/11/26 22:35:20 davygrvy Exp $
+ * RCS: @(#) $Id: tclWinSock.c,v 1.28 2002/11/27 00:58:01 davygrvy Exp $
*/
#include "tclWinInt.h"
/*
+ * Make sure to remove the redirection defines set in tclWinPort.h
+ * that is in use in other sections of the core, except for us.
+ */
+#undef getservbyname
+#undef getsockopt
+#undef ntohs
+#undef setsockopt
+
+/*
* The following variable is used to tell whether this module has been
* initialized.
*/
@@ -27,64 +36,66 @@ static char hostname[255]; /* This buffer should be big enough for
TCL_DECLARE_MUTEX(socketMutex)
/*
- * The following structure contains pointers to all of the WinSock API entry
- * points used by Tcl. It is initialized by InitSockets. Since we
- * dynamically load Winsock.dll on demand, we must use this function table
- * to refer to functions in the socket API.
+ * The following structure contains pointers to all of the WinSock API
+ * entry points used by Tcl. It is initialized by InitSockets. Since
+ * we dynamically load the Winsock DLL on demand, we must use this
+ * function table to refer to functions in the winsock API.
*/
static struct {
- HINSTANCE hInstance; /* Handle to WinSock library. */
- SOCKET (PASCAL FAR *accept)(SOCKET s, struct sockaddr FAR *addr,
- int FAR *addrlen);
- int (PASCAL FAR *bind)(SOCKET s, const struct sockaddr FAR *addr,
- int namelen);
- int (PASCAL FAR *closesocket)(SOCKET s);
- int (PASCAL FAR *connect)(SOCKET s, const struct sockaddr FAR *name,
- int namelen);
- int (PASCAL FAR *ioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
- int (PASCAL FAR *getsockopt)(SOCKET s, int level, int optname,
- char FAR * optval, int FAR *optlen);
- u_short (PASCAL FAR *htons)(u_short hostshort);
- unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp);
- char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in);
- 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);
- int (PASCAL FAR *shutdown)(SOCKET s, int how);
- SOCKET (PASCAL FAR *socket)(int af, int type, int protocol);
- struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name);
- struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR *addr,
- int addrlen, int addrtype);
- int (PASCAL FAR *gethostname)(char FAR * name, int namelen);
- int (PASCAL FAR *getpeername)(SOCKET sock, struct sockaddr FAR *name,
- int FAR *namelen);
- struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name,
- const char FAR * proto);
- int (PASCAL FAR *getsockname)(SOCKET sock, struct sockaddr FAR *name,
- int FAR *namelen);
- int (PASCAL FAR *WSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
- int (PASCAL FAR *WSACleanup)(void);
- int (PASCAL FAR *WSAGetLastError)(void);
- int (PASCAL FAR *WSAAsyncSelect)(SOCKET s, HWND hWnd, u_int wMsg,
- long lEvent);
+ HMODULE hModule; /* Handle to WinSock library. */
+
+ /* Winsock 1.1 functions */
+ LPFN_ACCEPT accept;
+ LPFN_BIND bind;
+ LPFN_CLOSESOCKET closesocket;
+ LPFN_CONNECT connect;
+ LPFN_GETHOSTBYADDR gethostbyaddr;
+ LPFN_GETHOSTBYNAME gethostbyname;
+ LPFN_GETHOSTNAME gethostname;
+ LPFN_GETPEERNAME getpeername;
+ LPFN_GETSERVBYNAME getservbyname;
+ LPFN_GETSOCKNAME getsockname;
+ LPFN_GETSOCKOPT getsockopt;
+ LPFN_HTONS htons;
+ LPFN_INET_ADDR inet_addr;
+ LPFN_INET_NTOA inet_ntoa;
+ LPFN_IOCTLSOCKET ioctlsocket;
+ LPFN_LISTEN listen;
+ LPFN_NTOHS ntohs;
+ LPFN_RECV recv;
+ LPFN_SELECT select;
+ LPFN_SEND send;
+ LPFN_SETSOCKOPT setsockopt;
+ LPFN_SHUTDOWN shutdown;
+ LPFN_SOCKET socket;
+ LPFN_WSAASYNCSELECT WSAAsyncSelect;
+ LPFN_WSACLEANUP WSACleanup;
+ LPFN_WSAGETLASTERROR WSAGetLastError;
+ LPFN_WSASTARTUP WSAStartup;
+
} winSock;
/*
* The following defines declare the messages used on socket windows.
*/
-#define SOCKET_MESSAGE WM_USER+1
-#define SOCKET_SELECT WM_USER+2
-#define SOCKET_TERMINATE WM_USER+3
-#define SELECT TRUE
-#define UNSELECT FALSE
+#define SOCKET_MESSAGE WM_USER+1
+#define SOCKET_SELECT WM_USER+2
+#define SOCKET_TERMINATE WM_USER+3
+#define SELECT TRUE
+#define UNSELECT FALSE
+
+/*
+ * Accepted sockets done in the message handling thread are stored here
+ * and appended to the listen sockets SocketInfo struct until they are
+ * processed.
+ */
+
+typedef struct SocketAcceptInfo {
+ SOCKET newSock;
+ SOCKADDR_IN newAddr;
+} SocketAcceptInfo;
/*
* The following structure is used to store the data associated with
@@ -92,27 +103,37 @@ static struct {
*/
typedef struct SocketInfo {
- Tcl_Channel channel; /* Channel associated with this socket. */
+ Tcl_Channel channel; /* Channel associated with this
+ * socket. */
SOCKET socket; /* Windows SOCKET handle. */
int flags; /* Bit field comprised of the flags
* described below. */
- int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE,
- * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
- * indicate which events are interesting. */
- int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE,
- * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
- * indicate which events have occurred. */
- int selectEvents; /* OR'ed combination of FD_READ, FD_WRITE,
- * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
- * indicate which events are currently
- * being selected. */
- int acceptEventCount; /* Count of the current number of FD_ACCEPTs
- * that have arrived and not processed. */
+ int watchEvents; /* OR'ed combination of FD_READ,
+ * FD_WRITE, FD_CLOSE, FD_ACCEPT and
+ * FD_CONNECT that indicate which
+ * events are interesting. */
+ int readyEvents; /* OR'ed combination of FD_READ,
+ * FD_WRITE, FD_CLOSE, FD_ACCEPT and
+ * FD_CONNECT that indicate which
+ * events have occurred. */
+ int selectEvents; /* OR'ed combination of FD_READ,
+ * FD_WRITE, FD_CLOSE, FD_ACCEPT and
+ * FD_CONNECT that indicate which
+ * events are currently being
+ * selected. */
+ int acceptedSocketsCount; /* Count of the current number of
+ * accepted connections ready and
+ * not yet processed. */
+ SocketAcceptInfo **acceptedSockets; /* The array of accepted
+ * connections on this listening
+ * socket. */
+ int acceptedSocketsSize; /* The size of the acceptedSockets
+ * array. */
Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */
ClientData acceptProcData; /* The data for the accept proc. */
int lastError; /* Error code from last message. */
- struct SocketInfo *nextPtr; /* The next socket on the global socket
- * list. */
+ struct SocketInfo *nextPtr; /* The next socket on the per-thread
+ * socket list. */
} SocketInfo;
/*
@@ -141,73 +162,68 @@ typedef struct SocketEvent {
* a SocketInfo structure.
*/
-#define SOCKET_ASYNC (1<<0) /* The socket is in blocking mode. */
+#define SOCKET_ASYNC (1<<0) /* The socket is in blocking
+ * mode. */
#define SOCKET_EOF (1<<1) /* A zero read happened on
* the socket. */
-#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async connect. */
+#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async
+ * connect. */
#define SOCKET_PENDING (1<<3) /* A message has been sent
* for this socket */
typedef struct ThreadSpecificData {
- /*
- * Every open socket has an entry on the following list.
- */
-
HWND hwnd; /* Handle to window for socket messages. */
HANDLE socketThread; /* Thread handling the window */
Tcl_ThreadId threadId; /* Parent thread. */
- HANDLE readyEvent; /* Event indicating that a socket event is ready.
- * Also used to indicate that the socketThread has
- * been initialized and has started. */
+ HANDLE readyEvent; /* Event indicating that a socket event is
+ * ready. Also used to indicate that the
+ * socketThread has been initialized and has
+ * started. */
HANDLE socketListLock; /* Win32 Event to lock the socketList */
- SocketInfo *socketList;
+ SocketInfo *socketList; /* Every open socket has an entry on this
+ * list. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
-static WNDCLASSA windowClass;
+static WNDCLASS windowClass;
/*
* Static functions defined in this file.
*/
-static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,
- int port, CONST char *host, int server,
- CONST char *myaddr, int myport, int async));
-static int CreateSocketAddress _ANSI_ARGS_(
- (struct sockaddr_in *sockaddrPtr,
- CONST char *host, int port));
-static void InitSockets _ANSI_ARGS_((void));
-static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket));
-static void SocketCheckProc _ANSI_ARGS_((ClientData clientData,
- int flags));
-static int SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
- int flags));
-static void SocketExitHandler _ANSI_ARGS_((ClientData clientData));
-static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam));
-static void SocketSetupProc _ANSI_ARGS_((ClientData clientData,
- int flags));
-static void SocketThreadExitHandler _ANSI_ARGS_((ClientData clientData));
-static int SocketsEnabled _ANSI_ARGS_((void));
-static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr));
-static int TcpBlockProc _ANSI_ARGS_((ClientData instanceData,
- int mode));
-static int TcpCloseProc _ANSI_ARGS_((ClientData instanceData,
- Tcl_Interp *interp));
-static int TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData,
- Tcl_Interp *interp, CONST char *optionName,
- Tcl_DString *optionValue));
-static int TcpInputProc _ANSI_ARGS_((ClientData instanceData,
- char *buf, int toRead, int *errorCode));
-static int TcpOutputProc _ANSI_ARGS_((ClientData instanceData,
- CONST char *buf, int toWrite, int *errorCode));
-static void TcpWatchProc _ANSI_ARGS_((ClientData instanceData,
- int mask));
-static int TcpGetHandleProc _ANSI_ARGS_((ClientData instanceData,
- int direction, ClientData *handlePtr));
-static int WaitForSocketEvent _ANSI_ARGS_((SocketInfo *infoPtr,
- int events, int *errorCodePtr));
-static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
+static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,
+ int port, CONST char *host,
+ int server, CONST char *myaddr,
+ int myport, int async));
+static int CreateSocketAddress _ANSI_ARGS_(
+ (LPSOCKADDR_IN sockaddrPtr,
+ CONST char *host, int port));
+static void InitSockets _ANSI_ARGS_((void));
+static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket));
+static Tcl_EventCheckProc SocketCheckProc;
+static Tcl_EventProc SocketEventProc;
+static void SocketExitHandler _ANSI_ARGS_((
+ ClientData clientData));
+static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd,
+ UINT message, WPARAM wParam,
+ LPARAM lParam));
+static Tcl_EventSetupProc SocketSetupProc;
+static Tcl_ExitProc SocketThreadExitHandler;
+static int SocketsEnabled _ANSI_ARGS_((void));
+static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr,
+ SocketAcceptInfo *saiPtr));
+static Tcl_DriverBlockModeProc TcpBlockProc;
+static Tcl_DriverCloseProc TcpCloseProc;
+static Tcl_DriverSetOptionProc TcpSetOptionProc;
+static Tcl_DriverGetOptionProc TcpGetOptionProc;
+static Tcl_DriverInputProc TcpInputProc;
+static Tcl_DriverOutputProc TcpOutputProc;
+static Tcl_DriverWatchProc TcpWatchProc;
+static Tcl_DriverGetHandleProc TcpGetHandleProc;
+static int WaitForSocketEvent _ANSI_ARGS_((
+ SocketInfo *infoPtr, int events,
+ int *errorCodePtr));
+static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
/*
* This structure describes the channel type structure for TCP socket
@@ -215,27 +231,22 @@ static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
*/
static Tcl_ChannelType tcpChannelType = {
- "tcp", /* Type name. */
- TCL_CHANNEL_VERSION_2, /* v2 channel */
- TcpCloseProc, /* Close proc. */
- TcpInputProc, /* Input proc. */
- TcpOutputProc, /* Output proc. */
- NULL, /* Seek proc. */
- NULL, /* Set option proc. */
- TcpGetOptionProc, /* Get option proc. */
- TcpWatchProc, /* Set up notifier to watch this channel. */
- TcpGetHandleProc, /* Get an OS handle from channel. */
- NULL, /* close2proc. */
- TcpBlockProc, /* Set socket into (non-)blocking mode. */
- NULL, /* flush proc. */
- NULL, /* handler proc. */
+ "tcp", /* Type name. */
+ TCL_CHANNEL_VERSION_2, /* v2 channel */
+ TcpCloseProc, /* Close proc. */
+ TcpInputProc, /* Input proc. */
+ TcpOutputProc, /* Output proc. */
+ NULL, /* Seek proc. */
+ TcpSetOptionProc, /* Set option proc. */
+ TcpGetOptionProc, /* Get option proc. */
+ TcpWatchProc, /* Set up notifier to watch this channel. */
+ TcpGetHandleProc, /* Get an OS handle from channel. */
+ NULL, /* close2proc. */
+ TcpBlockProc, /* Set socket into (non-)blocking mode. */
+ NULL, /* flush proc. */
+ NULL, /* handler proc. */
};
-/*
- * Define version of Winsock required by Tcl.
- */
-
-#define WSA_VERSION_REQD MAKEWORD(1,1)
/*
*----------------------------------------------------------------------
@@ -267,104 +278,97 @@ InitSockets()
ThreadSpecificData *tsdPtr =
(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
- if (! initialized) {
+ if (!initialized) {
initialized = 1;
Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL);
- winSock.hInstance = LoadLibraryA("wsock32.dll");
+ /* Try loading the win32 winsock library. */
+ winSock.hModule = LoadLibraryA("wsock32.dll");
/*
* Initialize the function table.
*/
- if (!SocketsEnabled()) {
+ if (winSock.hModule == NULL) {
return;
}
- winSock.accept = (SOCKET (PASCAL FAR *)(SOCKET s,
- struct sockaddr FAR *addr, int FAR *addrlen))
- GetProcAddress(winSock.hInstance, "accept");
- winSock.bind = (int (PASCAL FAR *)(SOCKET s,
- const struct sockaddr FAR *addr, int namelen))
- GetProcAddress(winSock.hInstance, "bind");
- winSock.closesocket = (int (PASCAL FAR *)(SOCKET s))
- GetProcAddress(winSock.hInstance, "closesocket");
- winSock.connect = (int (PASCAL FAR *)(SOCKET s,
- 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");
- winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s,
- int level, int optname, char FAR * optval, int FAR *optlen))
- GetProcAddress(winSock.hInstance, "getsockopt");
- winSock.htons = (u_short (PASCAL FAR *)(u_short hostshort))
- GetProcAddress(winSock.hInstance, "htons");
- winSock.inet_addr = (unsigned long (PASCAL FAR *)(const char FAR *cp))
- GetProcAddress(winSock.hInstance, "inet_addr");
- winSock.inet_ntoa = (char FAR * (PASCAL FAR *)(struct in_addr in))
- GetProcAddress(winSock.hInstance, "inet_ntoa");
- winSock.listen = (int (PASCAL FAR *)(SOCKET s, int backlog))
- GetProcAddress(winSock.hInstance, "listen");
- winSock.ntohs = (u_short (PASCAL FAR *)(u_short netshort))
- 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,
- int optname, const char FAR * optval, int optlen))
- GetProcAddress(winSock.hInstance, "setsockopt");
- winSock.shutdown = (int (PASCAL FAR *)(SOCKET s, int how))
- GetProcAddress(winSock.hInstance, "shutdown");
- winSock.socket = (SOCKET (PASCAL FAR *)(int af, int type,
- int protocol)) GetProcAddress(winSock.hInstance, "socket");
- winSock.gethostbyaddr = (struct hostent FAR * (PASCAL FAR *)
- (const char FAR *addr, int addrlen, int addrtype))
- GetProcAddress(winSock.hInstance, "gethostbyaddr");
- winSock.gethostbyname = (struct hostent FAR * (PASCAL FAR *)
- (const char FAR *name))
- GetProcAddress(winSock.hInstance, "gethostbyname");
- winSock.gethostname = (int (PASCAL FAR *)(char FAR * name,
- int namelen)) GetProcAddress(winSock.hInstance, "gethostname");
- winSock.getpeername = (int (PASCAL FAR *)(SOCKET sock,
- struct sockaddr FAR *name, int FAR *namelen))
- GetProcAddress(winSock.hInstance, "getpeername");
- winSock.getservbyname = (struct servent FAR * (PASCAL FAR *)
- (const char FAR * name, const char FAR * proto))
- GetProcAddress(winSock.hInstance, "getservbyname");
- winSock.getsockname = (int (PASCAL FAR *)(SOCKET sock,
- struct sockaddr FAR *name, int FAR *namelen))
- GetProcAddress(winSock.hInstance, "getsockname");
- winSock.WSAStartup = (int (PASCAL FAR *)(WORD wVersionRequired,
- LPWSADATA lpWSAData)) GetProcAddress(winSock.hInstance, "WSAStartup");
- winSock.WSACleanup = (int (PASCAL FAR *)(void))
- GetProcAddress(winSock.hInstance, "WSACleanup");
- winSock.WSAGetLastError = (int (PASCAL FAR *)(void))
- GetProcAddress(winSock.hInstance, "WSAGetLastError");
- winSock.WSAAsyncSelect = (int (PASCAL FAR *)(SOCKET s, HWND hWnd,
- u_int wMsg, long lEvent))
- GetProcAddress(winSock.hInstance, "WSAAsyncSelect");
+ winSock.accept = (LPFN_ACCEPT)
+ GetProcAddress(winSock.hModule, "accept");
+ winSock.bind = (LPFN_BIND)
+ GetProcAddress(winSock.hModule, "bind");
+ winSock.closesocket = (LPFN_CLOSESOCKET)
+ GetProcAddress(winSock.hModule, "closesocket");
+ winSock.connect = (LPFN_CONNECT)
+ GetProcAddress(winSock.hModule, "connect");
+ winSock.gethostbyaddr = (LPFN_GETHOSTBYADDR)
+ GetProcAddress(winSock.hModule, "gethostbyaddr");
+ winSock.gethostbyname = (LPFN_GETHOSTBYNAME)
+ GetProcAddress(winSock.hModule, "gethostbyname");
+ winSock.gethostname = (LPFN_GETHOSTNAME)
+ GetProcAddress(winSock.hModule, "gethostname");
+ winSock.getpeername = (LPFN_GETPEERNAME)
+ GetProcAddress(winSock.hModule, "getpeername");
+ winSock.getservbyname = (LPFN_GETSERVBYNAME)
+ GetProcAddress(winSock.hModule, "getservbyname");
+ winSock.getsockname = (LPFN_GETSOCKNAME)
+ GetProcAddress(winSock.hModule, "getsockname");
+ winSock.getsockopt = (LPFN_GETSOCKOPT)
+ GetProcAddress(winSock.hModule, "getsockopt");
+ winSock.htons = (LPFN_HTONS)
+ GetProcAddress(winSock.hModule, "htons");
+ winSock.inet_addr = (LPFN_INET_ADDR)
+ GetProcAddress(winSock.hModule, "inet_addr");
+ winSock.inet_ntoa = (LPFN_INET_NTOA)
+ GetProcAddress(winSock.hModule, "inet_ntoa");
+ winSock.ioctlsocket = (LPFN_IOCTLSOCKET)
+ GetProcAddress(winSock.hModule, "ioctlsocket");
+ winSock.listen = (LPFN_LISTEN)
+ GetProcAddress(winSock.hModule, "listen");
+ winSock.ntohs = (LPFN_NTOHS)
+ GetProcAddress(winSock.hModule, "ntohs");
+ winSock.recv = (LPFN_RECV)
+ GetProcAddress(winSock.hModule, "recv");
+ winSock.select = (LPFN_SELECT)
+ GetProcAddress(winSock.hModule, "select");
+ winSock.send = (LPFN_SEND)
+ GetProcAddress(winSock.hModule, "send");
+ winSock.setsockopt = (LPFN_SETSOCKOPT)
+ GetProcAddress(winSock.hModule, "setsockopt");
+ winSock.shutdown = (LPFN_SHUTDOWN)
+ GetProcAddress(winSock.hModule, "shutdown");
+ winSock.socket = (LPFN_SOCKET)
+ GetProcAddress(winSock.hModule, "socket");
+ winSock.WSAAsyncSelect = (LPFN_WSAASYNCSELECT)
+ GetProcAddress(winSock.hModule, "WSAAsyncSelect");
+ winSock.WSACleanup = (LPFN_WSACLEANUP)
+ GetProcAddress(winSock.hModule, "WSACleanup");
+ winSock.WSAGetLastError = (LPFN_WSAGETLASTERROR)
+ GetProcAddress(winSock.hModule, "WSAGetLastError");
+ winSock.WSAStartup = (LPFN_WSASTARTUP)
+ GetProcAddress(winSock.hModule, "WSAStartup");
/*
- * Now check that all fields are properly initialized. If not, return
- * zero to indicate that we failed to initialize properly.
+ * Now check that all fields are properly initialized. If not,
+ * return zero to indicate that we failed to initialize
+ * properly.
*/
- if ((winSock.hInstance == NULL) ||
- (winSock.accept == NULL) ||
+ if ((winSock.accept == NULL) ||
(winSock.bind == NULL) ||
(winSock.closesocket == NULL) ||
(winSock.connect == NULL) ||
- (winSock.ioctlsocket == NULL) ||
+ (winSock.gethostbyname == NULL) ||
+ (winSock.gethostbyaddr == NULL) ||
+ (winSock.gethostname == NULL) ||
+ (winSock.getpeername == NULL) ||
+ (winSock.getservbyname == NULL) ||
+ (winSock.getsockname == NULL) ||
(winSock.getsockopt == NULL) ||
(winSock.htons == NULL) ||
(winSock.inet_addr == NULL) ||
(winSock.inet_ntoa == NULL) ||
+ (winSock.ioctlsocket == NULL) ||
(winSock.listen == NULL) ||
(winSock.ntohs == NULL) ||
(winSock.recv == NULL) ||
@@ -372,16 +376,11 @@ InitSockets()
(winSock.send == NULL) ||
(winSock.setsockopt == NULL) ||
(winSock.socket == NULL) ||
- (winSock.gethostbyname == NULL) ||
- (winSock.gethostbyaddr == NULL) ||
- (winSock.gethostname == NULL) ||
- (winSock.getpeername == NULL) ||
- (winSock.getservbyname == NULL) ||
- (winSock.getsockname == NULL) ||
- (winSock.WSAStartup == NULL) ||
+ (winSock.WSAAsyncSelect == NULL) ||
(winSock.WSACleanup == NULL) ||
(winSock.WSAGetLastError == NULL) ||
- (winSock.WSAAsyncSelect == NULL)) {
+ (winSock.WSAStartup == NULL))
+ {
goto unloadLibrary;
}
@@ -405,19 +404,19 @@ InitSockets()
if (!RegisterClassA(&windowClass)) {
TclWinConvertError(GetLastError());
- (*winSock.WSACleanup)();
goto unloadLibrary;
}
/*
* Initialize the winsock library and check the version number.
+ * We only ask for the 1.1 interface.
*/
- if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) {
+ if (winSock.WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
goto unloadLibrary;
}
- if (wsaData.wVersion != WSA_VERSION_REQD) {
- (*winSock.WSACleanup)();
+ if (wsaData.wVersion < MAKEWORD(1,1)) {
+ winSock.WSACleanup();
goto unloadLibrary;
}
}
@@ -437,7 +436,7 @@ InitSockets()
tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
tsdPtr, 0, &id);
- SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
+ SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
if (tsdPtr->socketThread == NULL) {
goto unloadLibrary;
@@ -450,7 +449,8 @@ InitSockets()
* seconds.
*/
- if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) {
+ if (WaitForSingleObject(tsdPtr->readyEvent, 20000)
+ == WAIT_TIMEOUT) {
goto unloadLibrary;
}
@@ -464,19 +464,11 @@ InitSockets()
return;
unloadLibrary:
- if (tsdPtr != NULL) {
- if (tsdPtr->hwnd != NULL) {
- DestroyWindow(tsdPtr->hwnd);
- }
- if (tsdPtr->socketThread != NULL) {
- TerminateThread(tsdPtr->socketThread, 0);
- tsdPtr->socketThread = NULL;
- }
- CloseHandle(tsdPtr->readyEvent);
- CloseHandle(tsdPtr->socketListLock);
+ if (tsdPtr != NULL && tsdPtr->hwnd != NULL) {
+ SocketThreadExitHandler(0);
}
- FreeLibrary(winSock.hInstance);
- winSock.hInstance = NULL;
+ FreeLibrary(winSock.hModule);
+ winSock.hModule = NULL;
return;
}
@@ -502,7 +494,7 @@ SocketsEnabled()
{
int enabled;
Tcl_MutexLock(&socketMutex);
- enabled = (winSock.hInstance != NULL);
+ enabled = (winSock.hModule != NULL);
Tcl_MutexUnlock(&socketMutex);
return enabled;
}
@@ -531,11 +523,16 @@ SocketExitHandler(clientData)
ClientData clientData; /* Not used. */
{
Tcl_MutexLock(&socketMutex);
- if (winSock.hInstance) {
- UnregisterClassA("TclSocket", TclWinGetTclInstance());
- (*winSock.WSACleanup)();
- FreeLibrary(winSock.hInstance);
- winSock.hInstance = NULL;
+ if (winSock.hModule) {
+ /*
+ * Make sure the socket event handling window is cleaned-up
+ * for, at most, this thread.
+ */
+ SocketThreadExitHandler(clientData);
+ UnregisterClass("TclSocket", TclWinGetTclInstance());
+ winSock.WSACleanup();
+ FreeLibrary(winSock.hModule);
+ winSock.hModule = NULL;
}
initialized = 0;
hostnameInitialized = 0;
@@ -568,24 +565,26 @@ SocketThreadExitHandler(clientData)
(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr->socketThread != NULL) {
+ DWORD exitCode;
- PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
+ GetExitCodeThread(tsdPtr->socketThread, &exitCode);
+ if (exitCode == STILL_ACTIVE) {
+ PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
- /*
- * Wait for the thread to terminate. This ensures that we are
- * completely cleaned up before we leave this function.
- */
+ /*
+ * Wait for the thread to close. This ensures that we are
+ * completely cleaned up before we leave this function.
+ */
- WaitForSingleObject(tsdPtr->socketThread, INFINITE);
+ WaitForSingleObject(tsdPtr->socketThread, INFINITE);
+ }
CloseHandle(tsdPtr->socketThread);
+ tsdPtr->socketThread = NULL;
CloseHandle(tsdPtr->readyEvent);
CloseHandle(tsdPtr->socketListLock);
-
- }
- if (tsdPtr->hwnd != NULL) {
- DestroyWindow(tsdPtr->hwnd);
}
-
+
+ Tcl_DeleteThreadExitHandler(SocketThreadExitHandler, NULL);
Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
@@ -770,27 +769,50 @@ SocketEventProc(evPtr, flags)
break;
}
}
- SetEvent(tsdPtr->socketListLock);
/*
* Discard events that have gone stale.
*/
if (!infoPtr) {
+ SetEvent(tsdPtr->socketListLock);
return 1;
}
infoPtr->flags &= ~SOCKET_PENDING;
/*
- * Handle connection requests directly.
+ * Handle all accepted connections directly.
*/
if (infoPtr->readyEvents & FD_ACCEPT) {
- TcpAccept(infoPtr);
+ int todo, count;
+ SocketAcceptInfo **saiPtr;
+
+ /*
+ * First copy and reset the list, so we can remove the lock.
+ */
+
+ count = infoPtr->acceptedSocketsCount;
+ infoPtr->acceptedSocketsCount = 0;
+ saiPtr = (SocketAcceptInfo **) ckalloc(sizeof(SocketAcceptInfo *) * count);
+ memcpy(saiPtr, infoPtr->acceptedSockets, sizeof(SocketAcceptInfo *) * count);
+ infoPtr->readyEvents &= ~(FD_ACCEPT);
+ SetEvent(tsdPtr->socketListLock);
+
+ for (todo = 0; count > todo; todo++) {
+ TcpAccept(infoPtr, saiPtr[todo]);
+ ckfree((char *) saiPtr[todo]);
+ }
+ ckfree((char *) saiPtr);
return 1;
}
+ /*
+ * Release the lock here as FD_ACCEPTs are a special case.
+ */
+
+ SetEvent(tsdPtr->socketListLock);
/*
* Mask off unwanted events and compute the read/write mask so
@@ -833,7 +855,7 @@ SocketEventProc(evPtr, flags)
timeout.tv_usec = 0;
timeout.tv_sec = 0;
- if ((*winSock.select)(0, &readFds, NULL, NULL, &timeout) != 0) {
+ if (winSock.select(0, &readFds, NULL, NULL, &timeout) != 0) {
mask |= TCL_READABLE;
} else {
infoPtr->readyEvents &= ~(FD_READ);
@@ -927,8 +949,8 @@ TcpCloseProc(instanceData, interp)
* in the background.
*/
- if ((*winSock.closesocket)(infoPtr->socket) == SOCKET_ERROR) {
- TclWinConvertWSAError((*winSock.WSAGetLastError)());
+ if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) {
+ TclWinConvertWSAError(winSock.WSAGetLastError());
errorCode = Tcl_GetErrno();
}
}
@@ -945,8 +967,21 @@ TcpCloseProc(instanceData, interp)
break;
}
}
- SetEvent(tsdPtr->socketListLock);
+ /*
+ * In case any accepted sockets had been queued, close them.
+ */
+ if (infoPtr->acceptedSocketsCount) {
+ int ready;
+
+ for (ready = 0; infoPtr->acceptedSocketsCount > ready; ready++) {
+ winSock.closesocket(infoPtr->acceptedSockets[ready]->newSock);
+ ckfree((char *)infoPtr->acceptedSockets[ready]);
+ }
+ }
+
+ SetEvent(tsdPtr->socketListLock);
+ ckfree((char *) infoPtr->acceptedSockets);
ckfree((char *) infoPtr);
return errorCode;
}
@@ -981,7 +1016,10 @@ NewSocketInfo(socket)
infoPtr->watchEvents = 0;
infoPtr->readyEvents = 0;
infoPtr->selectEvents = 0;
- infoPtr->acceptEventCount = 0;
+ infoPtr->acceptedSocketsCount = 0;
+ infoPtr->acceptedSocketsSize = 1; /* start with 1. */
+ infoPtr->acceptedSockets = (SocketAcceptInfo **)
+ ckalloc(sizeof(SocketAcceptInfo *) * infoPtr->acceptedSocketsSize);
infoPtr->acceptProc = NULL;
infoPtr->lastError = 0;
@@ -1022,13 +1060,13 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
int async; /* If nonzero, connect client socket
* asynchronously. */
{
- u_long flag = 1; /* Indicates nonblocking mode. */
- int asyncConnect = 0; /* Will be 1 if async connect is
- * in progress. */
- struct sockaddr_in sockaddr; /* Socket address */
- struct sockaddr_in mysockaddr; /* Socket address for client */
+ u_long flag = 1; /* Indicates nonblocking mode. */
+ int asyncConnect = 0; /* Will be 1 if async connect is
+ * in progress. */
+ SOCKADDR_IN sockaddr; /* Socket address */
+ SOCKADDR_IN mysockaddr; /* Socket address for client */
SOCKET sock;
- SocketInfo *infoPtr; /* The returned value. */
+ SocketInfo *infoPtr; /* The returned value. */
ThreadSpecificData *tsdPtr =
(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
@@ -1051,7 +1089,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
goto error;
}
- sock = (*winSock.socket)(AF_INET, SOCK_STREAM, 0);
+ sock = winSock.socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
goto error;
}
@@ -1080,8 +1118,8 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
* to look for bugs.
*/
- if ((*winSock.bind)(sock, (struct sockaddr *) &sockaddr,
- sizeof(sockaddr)) == SOCKET_ERROR) {
+ if (winSock.bind(sock, (SOCKADDR *) &sockaddr,
+ sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
goto error;
}
@@ -1091,7 +1129,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
* different, and there may be differences between TCP/IP stacks).
*/
- if ((*winSock.listen)(sock, SOMAXCONN) == SOCKET_ERROR) {
+ if (winSock.listen(sock, SOMAXCONN) == SOCKET_ERROR) {
goto error;
}
@@ -1115,8 +1153,8 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
*/
if (myaddr != NULL || myport != 0) {
- if ((*winSock.bind)(sock, (struct sockaddr *) &mysockaddr,
- sizeof(struct sockaddr)) == SOCKET_ERROR) {
+ if (winSock.bind(sock, (SOCKADDR *) &mysockaddr,
+ sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
goto error;
}
}
@@ -1127,7 +1165,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
*/
if (async) {
- if ((*winSock.ioctlsocket)(sock, FIONBIO, &flag) == SOCKET_ERROR) {
+ if (winSock.ioctlsocket(sock, FIONBIO, &flag) == SOCKET_ERROR) {
goto error;
}
}
@@ -1136,9 +1174,9 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
* Attempt to connect to the remote socket.
*/
- if ((*winSock.connect)(sock, (struct sockaddr *) &sockaddr,
- sizeof(sockaddr)) == SOCKET_ERROR) {
- TclWinConvertWSAError((*winSock.WSAGetLastError)());
+ if (winSock.connect(sock, (SOCKADDR *) &sockaddr,
+ sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
+ TclWinConvertWSAError(winSock.WSAGetLastError());
if (Tcl_GetErrno() != EWOULDBLOCK) {
goto error;
}
@@ -1173,20 +1211,20 @@ CreateSocket(interp, port, host, server, myaddr, myport, async)
* automatically places the socket into non-blocking mode.
*/
- (*winSock.ioctlsocket)(sock, FIONBIO, &flag);
+ winSock.ioctlsocket(sock, FIONBIO, &flag);
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) SELECT, (LPARAM) infoPtr);
return infoPtr;
error:
- TclWinConvertWSAError((*winSock.WSAGetLastError)());
+ TclWinConvertWSAError(winSock.WSAGetLastError());
if (interp != NULL) {
Tcl_AppendResult(interp, "couldn't open socket: ",
Tcl_PosixError(interp), (char *) NULL);
}
if (sock != INVALID_SOCKET) {
- (*winSock.closesocket)(sock);
+ winSock.closesocket(sock);
}
return NULL;
}
@@ -1210,7 +1248,7 @@ error:
static int
CreateSocketAddress(sockaddrPtr, host, port)
- struct sockaddr_in *sockaddrPtr; /* Socket address */
+ LPSOCKADDR_IN sockaddrPtr; /* Socket address */
CONST char *host; /* Host. NULL implies INADDR_ANY */
int port; /* Port number */
{
@@ -1231,13 +1269,13 @@ CreateSocketAddress(sockaddrPtr, host, port)
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
sockaddrPtr->sin_family = AF_INET;
- sockaddrPtr->sin_port = (*winSock.htons)((short) (port & 0xFFFF));
+ sockaddrPtr->sin_port = winSock.htons((u_short) (port & 0xFFFF));
if (host == NULL) {
addr.s_addr = INADDR_ANY;
} else {
- addr.s_addr = (*winSock.inet_addr)(host);
+ addr.s_addr = winSock.inet_addr(host);
if (addr.s_addr == INADDR_NONE) {
- hostent = (*winSock.gethostbyname)(host);
+ hostent = winSock.gethostbyname(host);
if (hostent != NULL) {
memcpy((char *) &addr,
(char *) hostent->h_addr_list[0],
@@ -1377,7 +1415,7 @@ Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async)
return NULL;
}
- wsprintfA(channelName, "sock%d", infoPtr->socket);
+ wsprintf(channelName, "sock%d", infoPtr->socket);
infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
@@ -1442,7 +1480,7 @@ Tcl_MakeTcpClientChannel(sock)
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) SELECT, (LPARAM) infoPtr);
- wsprintfA(channelName, "sock%d", infoPtr->socket);
+ wsprintf(channelName, "sock%d", infoPtr->socket);
infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
@@ -1495,7 +1533,7 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)
infoPtr->acceptProc = acceptProc;
infoPtr->acceptProcData = acceptProcData;
- wsprintfA(channelName, "sock%d", infoPtr->socket);
+ wsprintf(channelName, "sock%d", infoPtr->socket);
infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) infoPtr, 0);
@@ -1512,9 +1550,8 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)
*----------------------------------------------------------------------
*
* TcpAccept --
- * Accept a TCP socket connection. This is called by
- * SocketEventProc and it in turns calls the registered accept
- * procedure.
+ * Turns the already accepted socket into a channel and calls
+ * the registered accept procedure.
*
* Results:
* None.
@@ -1526,73 +1563,30 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)
*/
static void
-TcpAccept(infoPtr)
- SocketInfo *infoPtr; /* Socket to accept. */
+TcpAccept(infoPtr, saiPtr)
+ SocketInfo *infoPtr; /* Listening socket accepted from. */
+ SocketAcceptInfo *saiPtr; /* Accept info pointer. */
{
- SOCKET newSocket;
SocketInfo *newInfoPtr;
- struct sockaddr_in addr;
- int len;
char channelName[16 + TCL_INTEGER_SPACE];
ThreadSpecificData *tsdPtr =
(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
/*
- * Accept the incoming connection request.
+ * Add this socket to the global list of sockets.
*/
- len = sizeof(struct sockaddr_in);
+ newInfoPtr = NewSocketInfo(saiPtr->newSock);
- newSocket = (*winSock.accept)(infoPtr->socket,
- (struct sockaddr *)&addr,
- &len);
-
/*
- * Clear the ready mask so we can detect the next connection request.
- * Note that connection requests are level triggered, so if there is
- * a request already pending, a new event will be generated.
+ * Select on read/write/close events and create the channel.
*/
-
- if (newSocket == INVALID_SOCKET) {
- infoPtr->acceptEventCount = 0;
- infoPtr->readyEvents &= ~(FD_ACCEPT);
- return;
- }
- /*
- * It is possible that more than one FD_ACCEPT has been sent, so an extra
- * count must be kept. Decrement the count, and reset the readyEvent bit
- * if the count is no longer > 0.
- */
-
- infoPtr->acceptEventCount--;
-
- if (infoPtr->acceptEventCount <= 0) {
- infoPtr->readyEvents &= ~(FD_ACCEPT);
- }
-
- /*
- * Win-NT has a misfeature that sockets are inherited in child
- * processes by default. Turn off the inherit bit.
- */
-
- SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 );
-
- /*
- * Add this socket to the global list of sockets.
- */
-
- newInfoPtr = NewSocketInfo(newSocket);
-
- /*
- * Select on read/write events and create the channel.
- */
-
newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) SELECT, (LPARAM) newInfoPtr);
-
- wsprintfA(channelName, "sock%d", newInfoPtr->socket);
+
+ wsprintf(channelName, "sock%d", newInfoPtr->socket);
newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
@@ -1605,16 +1599,16 @@ TcpAccept(infoPtr)
Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
return;
}
-
+
/*
* Invoke the accept callback procedure.
*/
-
+
if (infoPtr->acceptProc != NULL) {
(infoPtr->acceptProc) (infoPtr->acceptProcData,
newInfoPtr->channel,
- (*winSock.inet_ntoa)(addr.sin_addr),
- (*winSock.ntohs)(addr.sin_port));
+ winSock.inet_ntoa(saiPtr->newAddr.sin_addr),
+ winSock.ntohs(saiPtr->newAddr.sin_port));
}
}
@@ -1691,7 +1685,7 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr)
while (1) {
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) UNSELECT, (LPARAM) infoPtr);
- bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0);
+ bytesRead = winSock.recv(infoPtr->socket, buf, toRead, 0);
infoPtr->readyEvents &= ~(FD_READ);
/*
@@ -1720,7 +1714,7 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr)
* Check for error condition or underflow in non-blocking case.
*/
- error = (*winSock.WSAGetLastError)();
+ error = winSock.WSAGetLastError();
if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {
TclWinConvertWSAError(error);
*errorCodePtr = Tcl_GetErrno();
@@ -1802,7 +1796,7 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) UNSELECT, (LPARAM) infoPtr);
- bytesWritten = (*winSock.send)(infoPtr->socket, buf, toWrite, 0);
+ bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0);
if (bytesWritten != SOCKET_ERROR) {
/*
* Since Windows won't generate a new write event until we hit
@@ -1824,7 +1818,7 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)
* send fails with WSAEWOULDBLOCK.
*/
- error = (*winSock.WSAGetLastError)();
+ error = winSock.WSAGetLastError();
if (error == WSAEWOULDBLOCK) {
infoPtr->readyEvents &= ~(FD_WRITE);
if (infoPtr->flags & SOCKET_ASYNC) {
@@ -1859,6 +1853,92 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)
/*
*----------------------------------------------------------------------
*
+ * TcpSetOptionProc --
+ *
+ * Sets Tcp channel specific options.
+ *
+ * Results:
+ * ...
+ *
+ * Side effects:
+ * ...
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+TcpSetOptionProc (
+ ClientData instanceData, /* Socket state. */
+ Tcl_Interp *interp, /* For error reporting - can be NULL. */
+ CONST char *optionName, /* Name of the option to set. */
+ CONST char *value) /* New value for option. */
+{
+ SocketInfo *infoPtr;
+ SOCKET sock;
+ BOOL val = FALSE;
+/* int boolVar, rtn;
+*/
+ /*
+ * Check that WinSock is initialized; do not call it if not, to
+ * prevent system crashes. This can happen at exit time if the exit
+ * handler for WinSock ran before other exit handlers that want to
+ * use sockets.
+ */
+
+ if (!SocketsEnabled()) {
+ if (interp) {
+ Tcl_AppendResult(interp, "winsock is not initialized", NULL);
+ }
+ return TCL_ERROR;
+ }
+
+ infoPtr = (SocketInfo *) instanceData;
+ sock = infoPtr->socket;
+
+/*
+ if (!stricmp(optionName, "-keepalive")) {
+ if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (boolVar) val = TRUE;
+ rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *) &val, sizeof(BOOL));
+ if (rtn != 0) {
+ TclWinConvertWSAError(winSock.WSAGetLastError());
+ if (interp) {
+ Tcl_AppendResult(interp, "couldn't set socket option: ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+
+ } else if (!stricmp(optionName, "-nagle")) {
+ if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (!boolVar) val = TRUE;
+ rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (const char *) &val, sizeof(BOOL));
+ if (rtn != 0) {
+ TclWinConvertWSAError(winSock.WSAGetLastError());
+ if (interp) {
+ Tcl_AppendResult(interp, "couldn't set socket option: ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ }
+
+ return Tcl_BadChannelOption(interp, optionName, "keepalive nagle");
+*/
+ return Tcl_BadChannelOption(interp, optionName, "");
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TcpGetOptionProc --
*
* Computes an option value for a TCP socket based channel, or a
@@ -1889,11 +1969,11 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
* value; initialized by caller. */
{
SocketInfo *infoPtr;
- struct sockaddr_in sockname;
- struct sockaddr_in peername;
+ SOCKADDR_IN sockname;
+ SOCKADDR_IN peername;
struct hostent *hostEntPtr;
SOCKET sock;
- int size = sizeof(struct sockaddr_in);
+ int size = sizeof(SOCKADDR_IN);
size_t len = 0;
char buf[TCL_INTEGER_SPACE];
@@ -1926,7 +2006,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR,
(char *)&err, &optlen);
if (ret == SOCKET_ERROR) {
- err = (*winSock.WSAGetLastError)();
+ err = winSock.WSAGetLastError();
}
if (err) {
TclWinConvertWSAError(err);
@@ -1938,19 +2018,19 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
if ((len == 0) ||
((len > 1) && (optionName[1] == 'p') &&
(strncmp(optionName, "-peername", len) == 0))) {
- if ((*winSock.getpeername)(sock, (struct sockaddr *) &peername, &size)
+ if (winSock.getpeername(sock, (LPSOCKADDR) &peername, &size)
== 0) {
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-peername");
Tcl_DStringStartSublist(dsPtr);
}
Tcl_DStringAppendElement(dsPtr,
- (*winSock.inet_ntoa)(peername.sin_addr));
+ winSock.inet_ntoa(peername.sin_addr));
if (peername.sin_addr.s_addr == 0) {
hostEntPtr = (struct hostent *) NULL;
} else {
- hostEntPtr = (*winSock.gethostbyaddr)(
+ hostEntPtr = winSock.gethostbyaddr(
(char *) &(peername.sin_addr), sizeof(peername.sin_addr),
AF_INET);
}
@@ -1958,9 +2038,9 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
} else {
Tcl_DStringAppendElement(dsPtr,
- (*winSock.inet_ntoa)(peername.sin_addr));
+ winSock.inet_ntoa(peername.sin_addr));
}
- TclFormatInt(buf, (*winSock.ntohs)(peername.sin_port));
+ TclFormatInt(buf, winSock.ntohs(peername.sin_port));
Tcl_DStringAppendElement(dsPtr, buf);
if (len == 0) {
Tcl_DStringEndSublist(dsPtr);
@@ -1975,7 +2055,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
* no peer). {copied from unix/tclUnixChan.c}
*/
if (len) {
- TclWinConvertWSAError((*winSock.WSAGetLastError)());
+ TclWinConvertWSAError(winSock.WSAGetLastError());
if (interp) {
Tcl_AppendResult(interp, "can't get peername: ",
Tcl_PosixError(interp),
@@ -1989,18 +2069,18 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
if ((len == 0) ||
((len > 1) && (optionName[1] == 's') &&
(strncmp(optionName, "-sockname", len) == 0))) {
- if ((*winSock.getsockname)(sock, (struct sockaddr *) &sockname, &size)
+ if (winSock.getsockname(sock, (LPSOCKADDR) &sockname, &size)
== 0) {
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-sockname");
Tcl_DStringStartSublist(dsPtr);
}
Tcl_DStringAppendElement(dsPtr,
- (*winSock.inet_ntoa)(sockname.sin_addr));
+ winSock.inet_ntoa(sockname.sin_addr));
if (sockname.sin_addr.s_addr == 0) {
hostEntPtr = (struct hostent *) NULL;
} else {
- hostEntPtr = (*winSock.gethostbyaddr)(
+ hostEntPtr = winSock.gethostbyaddr(
(char *) &(sockname.sin_addr), sizeof(peername.sin_addr),
AF_INET);
}
@@ -2008,9 +2088,9 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
} else {
Tcl_DStringAppendElement(dsPtr,
- (*winSock.inet_ntoa)(sockname.sin_addr));
+ winSock.inet_ntoa(sockname.sin_addr));
}
- TclFormatInt(buf, (*winSock.ntohs)(sockname.sin_port));
+ TclFormatInt(buf, winSock.ntohs(sockname.sin_port));
Tcl_DStringAppendElement(dsPtr, buf);
if (len == 0) {
Tcl_DStringEndSublist(dsPtr);
@@ -2019,7 +2099,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
}
} else {
if (interp) {
- TclWinConvertWSAError((*winSock.WSAGetLastError)());
+ TclWinConvertWSAError(winSock.WSAGetLastError());
Tcl_AppendResult(interp, "can't get sockname: ",
Tcl_PosixError(interp),
(char *) NULL);
@@ -2028,7 +2108,46 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
}
}
+/*
+ if (len == 0 || !strncmp(optionName, "-keepalive", len)) {
+ int optlen;
+ BOOL opt = FALSE;
+
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-keepalive");
+ }
+ optlen = sizeof(BOOL);
+ winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt,
+ &optlen);
+ if (opt) {
+ Tcl_DStringAppendElement(dsPtr, "1");
+ } else {
+ Tcl_DStringAppendElement(dsPtr, "0");
+ }
+ if (len > 0) return TCL_OK;
+ }
+
+ if (len == 0 || !strncmp(optionName, "-nagle", len)) {
+ int optlen;
+ BOOL opt = FALSE;
+
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-nagle");
+ }
+ optlen = sizeof(BOOL);
+ winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt,
+ &optlen);
+ if (opt) {
+ Tcl_DStringAppendElement(dsPtr, "0");
+ } else {
+ Tcl_DStringAppendElement(dsPtr, "1");
+ }
+ if (len > 0) return TCL_OK;
+ }
+*/
+
if (len > 0) {
+ /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/
return Tcl_BadChannelOption(interp, optionName, "peername sockname");
}
@@ -2139,8 +2258,8 @@ SocketThread(LPVOID arg)
MSG msg;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
- tsdPtr->hwnd = CreateWindowA("TclSocket", "TclSocket",
- WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, NULL);
+ tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket",
+ WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
/*
* Signal the main thread that the window has been created
@@ -2151,29 +2270,17 @@ SocketThread(LPVOID arg)
if (tsdPtr->hwnd == NULL) {
return 1;
- } else {
- /*
- * store the tsdPtr, it's from a different thread, so it's
- * not directly accessible, but needed.
- */
-
-#ifdef _WIN64
- SetWindowLongPtr(tsdPtr->hwnd, GWLP_USERDATA, (LONG_PTR) tsdPtr);
-#else
- SetWindowLong(tsdPtr->hwnd, GWL_USERDATA, (LONG) tsdPtr);
-#endif
}
- while (1) {
- /*
- * Process all outstanding messages on the socket window.
- */
+ /*
+ * Process all messages on the socket window.
+ */
- while (PeekMessage(&msg, tsdPtr->hwnd, 0, 0, PM_REMOVE)) {
- DispatchMessage(&msg);
- }
- WaitMessage();
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ DispatchMessage(&msg);
}
+
+ return msg.wParam;
}
@@ -2218,7 +2325,26 @@ SocketProc(hwnd, message, wParam, lParam)
default:
return DefWindowProc(hwnd, message, wParam, lParam);
break;
-
+
+ case WM_CREATE:
+ /*
+ * store the initial tsdPtr, it's from a different thread, so it's
+ * not directly accessible, but needed.
+ */
+
+#ifdef _WIN64
+ SetWindowLongPtr(hwnd, GWLP_USERDATA,
+ (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams);
+#else
+ SetWindowLong(hwnd, GWL_USERDATA,
+ (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams);
+#endif
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
case SOCKET_MESSAGE:
event = WSAGETSELECTEVENT(lParam);
error = WSAGETSELECTERROR(lParam);
@@ -2243,12 +2369,62 @@ SocketProc(hwnd, message, wParam, lParam)
* increment the count if the current event is and
* FD_ACCEPT.
*/
-
+
if (event & FD_CLOSE) {
- infoPtr->acceptEventCount = 0;
infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
} else if (event & FD_ACCEPT) {
- infoPtr->acceptEventCount++;
+ SocketAcceptInfo *saiPtr;
+ int len = sizeof(SOCKADDR_IN);
+
+ /*
+ * Accept the incoming connection request now,
+ * instead of later. This helps avoid time delays
+ * and possible threading issues related to the
+ * underlying TCP/IP stack by keeping the accept()
+ * in the same thread context as the notification
+ * for it.
+ */
+
+ saiPtr = (SocketAcceptInfo *)
+ ckalloc(sizeof(SocketAcceptInfo));
+ saiPtr->newSock = winSock.accept(infoPtr->socket,
+ (LPSOCKADDR)&saiPtr->newAddr, &len);
+
+ /*
+ * Clear the event notification mask, due to
+ * inheritence from the parent listening socket.
+ */
+
+ winSock.WSAAsyncSelect(saiPtr->newSock, hwnd, 0,
+ 0);
+
+ /*
+ * Win-NT has a misfeature that sockets are
+ * inherited in child processes by default.
+ * Turn off the inherit bit.
+ */
+
+ SetHandleInformation((HANDLE)saiPtr->newSock,
+ HANDLE_FLAG_INHERIT, 0);
+ /*
+ * If the array isn't large enough, make it
+ * bigger.
+ */
+
+ if ((infoPtr->acceptedSocketsCount + 1) >
+ infoPtr->acceptedSocketsSize) {
+ /* double the size. */
+ infoPtr->acceptedSocketsSize *= 2;
+ infoPtr->acceptedSockets =
+ (SocketAcceptInfo **)
+ ckrealloc((char *)
+ infoPtr->acceptedSockets,
+ sizeof(SocketAcceptInfo *) *
+ infoPtr->acceptedSocketsSize);
+ }
+
+ infoPtr->acceptedSockets[
+ infoPtr->acceptedSocketsCount++] = saiPtr;
}
if (event & FD_CONNECT) {
@@ -2256,19 +2432,19 @@ SocketProc(hwnd, message, wParam, lParam)
* The socket is now connected,
* clear the async connect flag.
*/
-
+
infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
-
+
/*
* Remember any error that occurred so we can report
* connection failures.
*/
-
+
if (error != ERROR_SUCCESS) {
TclWinConvertWSAError(error);
infoPtr->lastError = Tcl_GetErrno();
}
-
+
}
if(infoPtr->flags & SOCKET_ASYNC_CONNECT) {
infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
@@ -2290,22 +2466,24 @@ SocketProc(hwnd, message, wParam, lParam)
}
SetEvent(tsdPtr->socketListLock);
break;
+
case SOCKET_SELECT:
infoPtr = (SocketInfo *) lParam;
if (wParam == SELECT) {
- (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd,
+ winSock.WSAAsyncSelect(infoPtr->socket, hwnd,
SOCKET_MESSAGE, infoPtr->selectEvents);
} else {
/*
* Clear the selection mask
*/
-
- (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd, 0, 0);
+
+ winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0);
}
break;
+
case SOCKET_TERMINATE:
- ExitThread(0);
+ DestroyWindow(hwnd);
break;
}
@@ -2350,7 +2528,7 @@ Tcl_GetHostName()
* INTL: bug
*/
- if ((*winSock.gethostname)(hostname, sizeof(hostname)) == 0) {
+ if (winSock.gethostname(hostname, sizeof(hostname)) == 0) {
Tcl_MutexLock(&socketMutex);
hostnameInitialized = 1;
Tcl_MutexUnlock(&socketMutex);
@@ -2412,7 +2590,7 @@ TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval,
return SOCKET_ERROR;
}
- return (*winSock.getsockopt)(s, level, optname, optval, optlen);
+ return winSock.getsockopt(s, level, optname, optval, optlen);
}
int
@@ -2429,7 +2607,7 @@ TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval,
return SOCKET_ERROR;
}
- return (*winSock.setsockopt)(s, level, optname, optval, optlen);
+ return winSock.setsockopt(s, level, optname, optval, optlen);
}
u_short
@@ -2446,7 +2624,7 @@ TclWinNToHS(u_short netshort)
return (u_short) -1;
}
- return (*winSock.ntohs)(netshort);
+ return winSock.ntohs(netshort);
}
struct servent *
@@ -2462,7 +2640,7 @@ TclWinGetServByName(const char * name, const char * proto)
return (struct servent *) NULL;
}
- return (*winSock.getservbyname)(name, proto);
+ return winSock.getservbyname(name, proto);
}