os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinSock.c
Update contrib.
4 * This file contains Windows-specific socket related code.
6 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.6 2006/09/26 21:40:37 patthoyts Exp $
14 #include "tclWinInt.h"
17 * Make sure to remove the redirection defines set in tclWinPort.h
18 * that is in use in other sections of the core, except for us.
26 * The following variable is used to tell whether this module has been
30 static int initialized = 0;
32 static int hostnameInitialized = 0;
33 static char hostname[255]; /* This buffer should be big enough for
34 * hostname plus domain name. */
36 TCL_DECLARE_MUTEX(socketMutex)
40 * Mingw and Cygwin may not have LPFN_* typedefs.
43 #ifdef HAVE_NO_LPFN_DECLS
44 typedef SOCKET (PASCAL FAR *LPFN_ACCEPT)(SOCKET s,
45 struct sockaddr FAR * addr, int FAR * addrlen);
46 typedef int (PASCAL FAR *LPFN_BIND)(SOCKET s,
47 const struct sockaddr FAR *addr, int namelen);
48 typedef int (PASCAL FAR *LPFN_CLOSESOCKET)(SOCKET s);
49 typedef int (PASCAL FAR *LPFN_CONNECT)(SOCKET s,
50 const struct sockaddr FAR *name, int namelen);
51 typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYADDR)
52 (const char FAR *addr, int addrlen, int addrtype);
53 typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYNAME)
54 (const char FAR * name);
55 typedef int (PASCAL FAR *LPFN_GETHOSTNAME)(char FAR * name,
57 typedef int (PASCAL FAR *LPFN_GETPEERNAME)(SOCKET sock,
58 struct sockaddr FAR *name, int FAR *namelen);
59 typedef struct servent FAR * (PASCAL FAR *LPFN_GETSERVBYNAME)
60 (const char FAR * name, const char FAR * proto);
61 typedef int (PASCAL FAR *LPFN_GETSOCKNAME)(SOCKET sock,
62 struct sockaddr FAR *name, int FAR *namelen);
63 typedef int (PASCAL FAR *LPFN_GETSOCKOPT)(SOCKET s, int level,
64 int optname, char FAR * optval, int FAR *optlen);
65 typedef u_short (PASCAL FAR *LPFN_HTONS)(u_short hostshort);
66 typedef unsigned long (PASCAL FAR *LPFN_INET_ADDR)
67 (const char FAR * cp);
68 typedef char FAR * (PASCAL FAR *LPFN_INET_NTOA)
70 typedef int (PASCAL FAR *LPFN_IOCTLSOCKET)(SOCKET s,
71 long cmd, u_long FAR *argp);
72 typedef int (PASCAL FAR *LPFN_LISTEN)(SOCKET s, int backlog);
73 typedef u_short (PASCAL FAR *LPFN_NTOHS)(u_short netshort);
74 typedef int (PASCAL FAR *LPFN_RECV)(SOCKET s, char FAR * buf,
76 typedef int (PASCAL FAR *LPFN_SELECT)(int nfds,
77 fd_set FAR * readfds, fd_set FAR * writefds,
78 fd_set FAR * exceptfds,
79 const struct timeval FAR * timeout);
80 typedef int (PASCAL FAR *LPFN_SEND)(SOCKET s,
81 const char FAR * buf, int len, int flags);
82 typedef int (PASCAL FAR *LPFN_SETSOCKOPT)(SOCKET s,
83 int level, int optname, const char FAR * optval,
85 typedef SOCKET (PASCAL FAR *LPFN_SOCKET)(int af,
86 int type, int protocol);
87 typedef int (PASCAL FAR *LPFN_WSAASYNCSELECT)(SOCKET s,
88 HWND hWnd, u_int wMsg, long lEvent);
89 typedef int (PASCAL FAR *LPFN_WSACLEANUP)(void);
90 typedef int (PASCAL FAR *LPFN_WSAGETLASTERROR)(void);
91 typedef int (PASCAL FAR *LPFN_WSASTARTUP)(WORD wVersionRequired,
97 * The following structure contains pointers to all of the WinSock API
98 * entry points used by Tcl. It is initialized by InitSockets. Since
99 * we dynamically load the Winsock DLL on demand, we must use this
100 * function table to refer to functions in the winsock API.
104 HMODULE hModule; /* Handle to WinSock library. */
106 /* Winsock 1.1 functions */
109 LPFN_CLOSESOCKET closesocket;
110 LPFN_CONNECT connect;
111 LPFN_GETHOSTBYADDR gethostbyaddr;
112 LPFN_GETHOSTBYNAME gethostbyname;
113 LPFN_GETHOSTNAME gethostname;
114 LPFN_GETPEERNAME getpeername;
115 LPFN_GETSERVBYNAME getservbyname;
116 LPFN_GETSOCKNAME getsockname;
117 LPFN_GETSOCKOPT getsockopt;
119 LPFN_INET_ADDR inet_addr;
120 LPFN_INET_NTOA inet_ntoa;
121 LPFN_IOCTLSOCKET ioctlsocket;
127 LPFN_SETSOCKOPT setsockopt;
129 LPFN_WSAASYNCSELECT WSAAsyncSelect;
130 LPFN_WSACLEANUP WSACleanup;
131 LPFN_WSAGETLASTERROR WSAGetLastError;
132 LPFN_WSASTARTUP WSAStartup;
137 * The following defines declare the messages used on socket windows.
140 #define SOCKET_MESSAGE WM_USER+1
141 #define SOCKET_SELECT WM_USER+2
142 #define SOCKET_TERMINATE WM_USER+3
144 #define UNSELECT FALSE
147 * The following structure is used to store the data associated with
151 typedef struct SocketInfo {
152 Tcl_Channel channel; /* Channel associated with this
154 SOCKET socket; /* Windows SOCKET handle. */
155 int flags; /* Bit field comprised of the flags
156 * described below. */
157 int watchEvents; /* OR'ed combination of FD_READ,
158 * FD_WRITE, FD_CLOSE, FD_ACCEPT and
159 * FD_CONNECT that indicate which
160 * events are interesting. */
161 int readyEvents; /* OR'ed combination of FD_READ,
162 * FD_WRITE, FD_CLOSE, FD_ACCEPT and
163 * FD_CONNECT that indicate which
164 * events have occurred. */
165 int selectEvents; /* OR'ed combination of FD_READ,
166 * FD_WRITE, FD_CLOSE, FD_ACCEPT and
167 * FD_CONNECT that indicate which
168 * events are currently being
170 int acceptEventCount; /* Count of the current number of
171 * FD_ACCEPTs that have arrived and
172 * not yet processed. */
173 Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */
174 ClientData acceptProcData; /* The data for the accept proc. */
175 int lastError; /* Error code from last message. */
176 struct SocketInfo *nextPtr; /* The next socket on the per-thread
181 * The following structure is what is added to the Tcl event queue when
182 * a socket event occurs.
185 typedef struct SocketEvent {
186 Tcl_Event header; /* Information that is standard for
188 SOCKET socket; /* Socket descriptor that is ready. Used
189 * to find the SocketInfo structure for
190 * the file (can't point directly to the
191 * SocketInfo structure because it could
192 * go away while the event is queued). */
196 * This defines the minimum buffersize maintained by the kernel.
199 #define TCP_BUFFER_SIZE 4096
202 * The following macros may be used to set the flags field of
203 * a SocketInfo structure.
206 #define SOCKET_ASYNC (1<<0) /* The socket is in blocking
208 #define SOCKET_EOF (1<<1) /* A zero read happened on
210 #define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async
212 #define SOCKET_PENDING (1<<3) /* A message has been sent
215 typedef struct ThreadSpecificData {
216 HWND hwnd; /* Handle to window for socket messages. */
217 HANDLE socketThread; /* Thread handling the window */
218 Tcl_ThreadId threadId; /* Parent thread. */
219 HANDLE readyEvent; /* Event indicating that a socket event is
220 * ready. Also used to indicate that the
221 * socketThread has been initialized and has
223 HANDLE socketListLock; /* Win32 Event to lock the socketList */
224 SocketInfo *socketList; /* Every open socket in this thread has an
225 * entry on this list. */
226 } ThreadSpecificData;
228 static Tcl_ThreadDataKey dataKey;
229 static WNDCLASS windowClass;
232 * Static functions defined in this file.
235 static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,
236 int port, CONST char *host,
237 int server, CONST char *myaddr,
238 int myport, int async));
239 static int CreateSocketAddress _ANSI_ARGS_(
240 (LPSOCKADDR_IN sockaddrPtr,
241 CONST char *host, int port));
242 static void InitSockets _ANSI_ARGS_((void));
243 static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket));
244 static Tcl_EventCheckProc SocketCheckProc;
245 static Tcl_EventProc SocketEventProc;
246 static void SocketExitHandler _ANSI_ARGS_((
247 ClientData clientData));
248 static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd,
249 UINT message, WPARAM wParam,
251 static Tcl_EventSetupProc SocketSetupProc;
252 static int SocketsEnabled _ANSI_ARGS_((void));
253 static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr));
254 static Tcl_DriverBlockModeProc TcpBlockProc;
255 static Tcl_DriverCloseProc TcpCloseProc;
256 static Tcl_DriverSetOptionProc TcpSetOptionProc;
257 static Tcl_DriverGetOptionProc TcpGetOptionProc;
258 static Tcl_DriverInputProc TcpInputProc;
259 static Tcl_DriverOutputProc TcpOutputProc;
260 static Tcl_DriverWatchProc TcpWatchProc;
261 static Tcl_DriverGetHandleProc TcpGetHandleProc;
262 static int WaitForSocketEvent _ANSI_ARGS_((
263 SocketInfo *infoPtr, int events,
265 static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
267 static void TcpThreadActionProc _ANSI_ARGS_ ((
268 ClientData instanceData, int action));
272 * This structure describes the channel type structure for TCP socket
276 static Tcl_ChannelType tcpChannelType = {
277 "tcp", /* Type name. */
278 TCL_CHANNEL_VERSION_4, /* v4 channel */
279 TcpCloseProc, /* Close proc. */
280 TcpInputProc, /* Input proc. */
281 TcpOutputProc, /* Output proc. */
282 NULL, /* Seek proc. */
283 TcpSetOptionProc, /* Set option proc. */
284 TcpGetOptionProc, /* Get option proc. */
285 TcpWatchProc, /* Set up notifier to watch this channel. */
286 TcpGetHandleProc, /* Get an OS handle from channel. */
287 NULL, /* close2proc. */
288 TcpBlockProc, /* Set socket into (non-)blocking mode. */
289 NULL, /* flush proc. */
290 NULL, /* handler proc. */
291 NULL, /* wide seek proc */
292 TcpThreadActionProc, /* thread action proc */
297 *----------------------------------------------------------------------
301 * Initialize the socket module. Attempts to load the wsock32.dll
302 * library and set up the winSock function table. If successful,
303 * registers the event window for the socket notifier code.
305 * Assumes socketMutex is held.
311 * Dynamically loads wsock32.dll, and registers a new window
312 * class and creates a window for use in asynchronous socket
315 *----------------------------------------------------------------------
324 ThreadSpecificData *tsdPtr =
325 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
329 Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL);
331 winSock.hModule = LoadLibraryA("wsock32.dll");
333 if (winSock.hModule == NULL) {
338 * Initialize the function table.
341 winSock.accept = (LPFN_ACCEPT)
342 GetProcAddress(winSock.hModule, "accept");
343 winSock.bind = (LPFN_BIND)
344 GetProcAddress(winSock.hModule, "bind");
345 winSock.closesocket = (LPFN_CLOSESOCKET)
346 GetProcAddress(winSock.hModule, "closesocket");
347 winSock.connect = (LPFN_CONNECT)
348 GetProcAddress(winSock.hModule, "connect");
349 winSock.gethostbyaddr = (LPFN_GETHOSTBYADDR)
350 GetProcAddress(winSock.hModule, "gethostbyaddr");
351 winSock.gethostbyname = (LPFN_GETHOSTBYNAME)
352 GetProcAddress(winSock.hModule, "gethostbyname");
353 winSock.gethostname = (LPFN_GETHOSTNAME)
354 GetProcAddress(winSock.hModule, "gethostname");
355 winSock.getpeername = (LPFN_GETPEERNAME)
356 GetProcAddress(winSock.hModule, "getpeername");
357 winSock.getservbyname = (LPFN_GETSERVBYNAME)
358 GetProcAddress(winSock.hModule, "getservbyname");
359 winSock.getsockname = (LPFN_GETSOCKNAME)
360 GetProcAddress(winSock.hModule, "getsockname");
361 winSock.getsockopt = (LPFN_GETSOCKOPT)
362 GetProcAddress(winSock.hModule, "getsockopt");
363 winSock.htons = (LPFN_HTONS)
364 GetProcAddress(winSock.hModule, "htons");
365 winSock.inet_addr = (LPFN_INET_ADDR)
366 GetProcAddress(winSock.hModule, "inet_addr");
367 winSock.inet_ntoa = (LPFN_INET_NTOA)
368 GetProcAddress(winSock.hModule, "inet_ntoa");
369 winSock.ioctlsocket = (LPFN_IOCTLSOCKET)
370 GetProcAddress(winSock.hModule, "ioctlsocket");
371 winSock.listen = (LPFN_LISTEN)
372 GetProcAddress(winSock.hModule, "listen");
373 winSock.ntohs = (LPFN_NTOHS)
374 GetProcAddress(winSock.hModule, "ntohs");
375 winSock.recv = (LPFN_RECV)
376 GetProcAddress(winSock.hModule, "recv");
377 winSock.select = (LPFN_SELECT)
378 GetProcAddress(winSock.hModule, "select");
379 winSock.send = (LPFN_SEND)
380 GetProcAddress(winSock.hModule, "send");
381 winSock.setsockopt = (LPFN_SETSOCKOPT)
382 GetProcAddress(winSock.hModule, "setsockopt");
383 winSock.socket = (LPFN_SOCKET)
384 GetProcAddress(winSock.hModule, "socket");
385 winSock.WSAAsyncSelect = (LPFN_WSAASYNCSELECT)
386 GetProcAddress(winSock.hModule, "WSAAsyncSelect");
387 winSock.WSACleanup = (LPFN_WSACLEANUP)
388 GetProcAddress(winSock.hModule, "WSACleanup");
389 winSock.WSAGetLastError = (LPFN_WSAGETLASTERROR)
390 GetProcAddress(winSock.hModule, "WSAGetLastError");
391 winSock.WSAStartup = (LPFN_WSASTARTUP)
392 GetProcAddress(winSock.hModule, "WSAStartup");
395 * Now check that all fields are properly initialized. If not,
396 * return zero to indicate that we failed to initialize
400 if ((winSock.accept == NULL) ||
401 (winSock.bind == NULL) ||
402 (winSock.closesocket == NULL) ||
403 (winSock.connect == NULL) ||
404 (winSock.gethostbyname == NULL) ||
405 (winSock.gethostbyaddr == NULL) ||
406 (winSock.gethostname == NULL) ||
407 (winSock.getpeername == NULL) ||
408 (winSock.getservbyname == NULL) ||
409 (winSock.getsockname == NULL) ||
410 (winSock.getsockopt == NULL) ||
411 (winSock.htons == NULL) ||
412 (winSock.inet_addr == NULL) ||
413 (winSock.inet_ntoa == NULL) ||
414 (winSock.ioctlsocket == NULL) ||
415 (winSock.listen == NULL) ||
416 (winSock.ntohs == NULL) ||
417 (winSock.recv == NULL) ||
418 (winSock.select == NULL) ||
419 (winSock.send == NULL) ||
420 (winSock.setsockopt == NULL) ||
421 (winSock.socket == NULL) ||
422 (winSock.WSAAsyncSelect == NULL) ||
423 (winSock.WSACleanup == NULL) ||
424 (winSock.WSAGetLastError == NULL) ||
425 (winSock.WSAStartup == NULL))
431 * Create the async notification window with a new class. We
432 * must create a new class to avoid a Windows 95 bug that causes
433 * us to get the wrong message number for socket events if the
434 * message window is a subclass of a static control.
437 windowClass.style = 0;
438 windowClass.cbClsExtra = 0;
439 windowClass.cbWndExtra = 0;
440 windowClass.hInstance = TclWinGetTclInstance();
441 windowClass.hbrBackground = NULL;
442 windowClass.lpszMenuName = NULL;
443 windowClass.lpszClassName = "TclSocket";
444 windowClass.lpfnWndProc = SocketProc;
445 windowClass.hIcon = NULL;
446 windowClass.hCursor = NULL;
448 if (!RegisterClassA(&windowClass)) {
449 TclWinConvertError(GetLastError());
454 * Initialize the winsock library and check the interface
455 * version actually loaded. We only ask for the 1.1 interface
456 * and do require that it not be less than 1.1.
459 #define WSA_VERSION_MAJOR 1
460 #define WSA_VERSION_MINOR 1
461 #define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR)
463 if ((err = winSock.WSAStartup(WSA_VERSION_REQD, &wsaData)) != 0) {
464 TclWinConvertWSAError(err);
469 * Note the byte positions are swapped for the comparison, so
470 * that 0x0002 (2.0, MAKEWORD(2,0)) doesn't look less than 0x0101
471 * (1.1). We want the comparison to be 0x0200 < 0x0101.
474 if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion))
475 < MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) {
476 TclWinConvertWSAError(WSAVERNOTSUPPORTED);
477 winSock.WSACleanup();
481 #undef WSA_VERSION_REQD
482 #undef WSA_VERSION_MAJOR
483 #undef WSA_VERSION_MINOR
487 * Check for per-thread initialization.
490 if (tsdPtr == NULL) {
491 tsdPtr = TCL_TSD_INIT(&dataKey);
492 tsdPtr->socketList = NULL;
494 tsdPtr->threadId = Tcl_GetCurrentThread();
495 tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
496 if (tsdPtr->readyEvent == NULL) {
499 tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
500 if (tsdPtr->socketListLock == NULL) {
503 tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
505 if (tsdPtr->socketThread == NULL) {
509 SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
512 * Wait for the thread to signal when the window has
513 * been created and if it is ready to go.
516 WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
518 if (tsdPtr->hwnd == NULL) {
519 goto unloadLibrary; /* Trouble creating the window */
522 Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
527 TclpFinalizeSockets();
528 FreeLibrary(winSock.hModule);
529 winSock.hModule = NULL;
534 *----------------------------------------------------------------------
538 * Check that the WinSock DLL is loaded and ready.
546 *----------------------------------------------------------------------
554 Tcl_MutexLock(&socketMutex);
555 enabled = (winSock.hModule != NULL);
556 Tcl_MutexUnlock(&socketMutex);
562 *----------------------------------------------------------------------
564 * SocketExitHandler --
566 * Callback invoked during app exit clean up to delete the socket
567 * communication window and to release the WinSock DLL.
575 *----------------------------------------------------------------------
580 SocketExitHandler(clientData)
581 ClientData clientData; /* Not used. */
583 Tcl_MutexLock(&socketMutex);
584 if (winSock.hModule) {
586 * Make sure the socket event handling window is cleaned-up
587 * for, at most, this thread.
589 TclpFinalizeSockets();
590 UnregisterClass("TclSocket", TclWinGetTclInstance());
591 winSock.WSACleanup();
592 FreeLibrary(winSock.hModule);
593 winSock.hModule = NULL;
596 hostnameInitialized = 0;
597 Tcl_MutexUnlock(&socketMutex);
601 *----------------------------------------------------------------------
603 * TclpFinalizeSockets --
605 * This function is called from Tcl_FinalizeThread to finalize
606 * the platform specific socket subsystem.
607 * Also, it may be called from within this module to cleanup
608 * the state if unable to initialize the sockets subsystem.
614 * Deletes the event source and destroys the socket thread.
616 *----------------------------------------------------------------------
620 TclpFinalizeSockets()
622 ThreadSpecificData *tsdPtr;
624 tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
625 if (tsdPtr != NULL) {
626 if (tsdPtr->socketThread != NULL) {
627 if (tsdPtr->hwnd != NULL) {
628 PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
630 * Wait for the thread to exit. This ensures that we are
631 * completely cleaned up before we leave this function.
633 WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
636 CloseHandle(tsdPtr->socketThread);
637 tsdPtr->socketThread = NULL;
639 if (tsdPtr->readyEvent != NULL) {
640 CloseHandle(tsdPtr->readyEvent);
641 tsdPtr->readyEvent = NULL;
643 if (tsdPtr->socketListLock != NULL) {
644 CloseHandle(tsdPtr->socketListLock);
645 tsdPtr->socketListLock = NULL;
647 Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
652 *----------------------------------------------------------------------
656 * This function determines whether sockets are available on the
657 * current system and returns an error in interp if they are not.
658 * Note that interp may be NULL.
661 * Returns TCL_OK if the system supports sockets, or TCL_ERROR with
662 * an error in interp.
665 * If not already prepared, initializes the TSD structure and
666 * socket message handling thread associated to the calling thread
667 * for the subsystem of the driver.
669 *----------------------------------------------------------------------
673 TclpHasSockets(interp)
676 Tcl_MutexLock(&socketMutex);
678 Tcl_MutexUnlock(&socketMutex);
680 if (SocketsEnabled()) {
683 if (interp != NULL) {
684 Tcl_AppendResult(interp, "sockets are not available on this system",
691 *----------------------------------------------------------------------
695 * This procedure is invoked before Tcl_DoOneEvent blocks waiting
702 * Adjusts the block time if needed.
704 *----------------------------------------------------------------------
708 SocketSetupProc(data, flags)
709 ClientData data; /* Not used. */
710 int flags; /* Event flags as passed to Tcl_DoOneEvent. */
713 Tcl_Time blockTime = { 0, 0 };
714 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
716 if (!(flags & TCL_FILE_EVENTS)) {
721 * Check to see if there is a ready socket. If so, poll.
724 WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
725 for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
726 infoPtr = infoPtr->nextPtr) {
727 if (infoPtr->readyEvents & infoPtr->watchEvents) {
728 Tcl_SetMaxBlockTime(&blockTime);
732 SetEvent(tsdPtr->socketListLock);
736 *----------------------------------------------------------------------
740 * This procedure is called by Tcl_DoOneEvent to check the socket
741 * event source for events.
747 * May queue an event.
749 *----------------------------------------------------------------------
753 SocketCheckProc(data, flags)
754 ClientData data; /* Not used. */
755 int flags; /* Event flags as passed to Tcl_DoOneEvent. */
759 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
761 if (!(flags & TCL_FILE_EVENTS)) {
766 * Queue events for any ready sockets that don't already have events
767 * queued (caused by persistent states that won't generate WinSock
771 WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
772 for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
773 infoPtr = infoPtr->nextPtr) {
774 if ((infoPtr->readyEvents & infoPtr->watchEvents)
775 && !(infoPtr->flags & SOCKET_PENDING)) {
776 infoPtr->flags |= SOCKET_PENDING;
777 evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));
778 evPtr->header.proc = SocketEventProc;
779 evPtr->socket = infoPtr->socket;
780 Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
783 SetEvent(tsdPtr->socketListLock);
787 *----------------------------------------------------------------------
791 * This procedure is called by Tcl_ServiceEvent when a socket event
792 * reaches the front of the event queue. This procedure is
793 * responsible for notifying the generic channel code.
796 * Returns 1 if the event was handled, meaning it should be removed
797 * from the queue. Returns 0 if the event was not handled, meaning
798 * it should stay on the queue. The only time the event isn't
799 * handled is if the TCL_FILE_EVENTS flag bit isn't set.
802 * Whatever the channel callback procedures do.
804 *----------------------------------------------------------------------
808 SocketEventProc(evPtr, flags)
809 Tcl_Event *evPtr; /* Event to service. */
810 int flags; /* Flags that indicate what events to
811 * handle, such as TCL_FILE_EVENTS. */
814 SocketEvent *eventPtr = (SocketEvent *) evPtr;
817 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
819 if (!(flags & TCL_FILE_EVENTS)) {
824 * Find the specified socket on the socket list.
827 WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
828 for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
829 infoPtr = infoPtr->nextPtr) {
830 if (infoPtr->socket == eventPtr->socket) {
834 SetEvent(tsdPtr->socketListLock);
837 * Discard events that have gone stale.
844 infoPtr->flags &= ~SOCKET_PENDING;
847 * Handle connection requests directly.
850 if (infoPtr->readyEvents & FD_ACCEPT) {
856 * Mask off unwanted events and compute the read/write mask so
857 * we can notify the channel.
860 events = infoPtr->readyEvents & infoPtr->watchEvents;
862 if (events & FD_CLOSE) {
864 * If the socket was closed and the channel is still interested
865 * in read events, then we need to ensure that we keep polling
866 * for this event until someone does something with the channel.
867 * Note that we do this before calling Tcl_NotifyChannel so we don't
868 * have to watch out for the channel being deleted out from under
869 * us. This may cause a redundant trip through the event loop, but
870 * it's simpler than trying to do unwind protection.
873 Tcl_Time blockTime = { 0, 0 };
874 Tcl_SetMaxBlockTime(&blockTime);
875 mask |= TCL_READABLE|TCL_WRITABLE;
876 } else if (events & FD_READ) {
878 struct timeval timeout;
881 * We must check to see if data is really available, since someone
882 * could have consumed the data in the meantime. Turn off async
883 * notification so select will work correctly. If the socket is
884 * still readable, notify the channel driver, otherwise reset the
885 * async select handler and keep waiting.
888 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
889 (WPARAM) UNSELECT, (LPARAM) infoPtr);
892 FD_SET(infoPtr->socket, &readFds);
896 if (winSock.select(0, &readFds, NULL, NULL, &timeout) != 0) {
897 mask |= TCL_READABLE;
899 infoPtr->readyEvents &= ~(FD_READ);
900 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
901 (WPARAM) SELECT, (LPARAM) infoPtr);
904 if (events & (FD_WRITE | FD_CONNECT)) {
905 mask |= TCL_WRITABLE;
906 if (events & FD_CONNECT && infoPtr->lastError != NO_ERROR) {
907 /* connect errors should also fire the readable handler. */
908 mask |= TCL_READABLE;
913 Tcl_NotifyChannel(infoPtr->channel, mask);
919 *----------------------------------------------------------------------
923 * Sets a socket into blocking or non-blocking mode.
926 * 0 if successful, errno if there was an error.
931 *----------------------------------------------------------------------
935 TcpBlockProc(instanceData, mode)
936 ClientData instanceData; /* The socket to block/un-block. */
937 int mode; /* TCL_MODE_BLOCKING or
938 * TCL_MODE_NONBLOCKING. */
940 SocketInfo *infoPtr = (SocketInfo *) instanceData;
942 if (mode == TCL_MODE_NONBLOCKING) {
943 infoPtr->flags |= SOCKET_ASYNC;
945 infoPtr->flags &= ~(SOCKET_ASYNC);
951 *----------------------------------------------------------------------
955 * This procedure is called by the generic IO level to perform
956 * channel type specific cleanup on a socket based channel
957 * when the channel is closed.
960 * 0 if successful, the value of errno if failed.
965 *----------------------------------------------------------------------
970 TcpCloseProc(instanceData, interp)
971 ClientData instanceData; /* The socket to close. */
972 Tcl_Interp *interp; /* Unused. */
974 SocketInfo *infoPtr = (SocketInfo *) instanceData;
977 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
980 * Check that WinSock is initialized; do not call it if not, to
981 * prevent system crashes. This can happen at exit time if the exit
982 * handler for WinSock ran before other exit handlers that want to
986 if (SocketsEnabled()) {
989 * Clean up the OS socket handle. The default Windows setting
990 * for a socket is SO_DONTLINGER, which does a graceful shutdown
994 if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) {
995 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
996 errorCode = Tcl_GetErrno();
1000 /* TIP #218. Removed the code removing the structure
1001 * from the global socket list. This is now done by
1002 * the thread action callbacks, and only there. This
1003 * happens before this code is called. We can free
1004 * without fear of damanging the list.
1006 ckfree((char *) infoPtr);
1011 *----------------------------------------------------------------------
1015 * This function allocates and initializes a new SocketInfo
1019 * Returns a newly allocated SocketInfo.
1022 * None, except for allocation of memory.
1024 *----------------------------------------------------------------------
1028 NewSocketInfo(socket)
1031 SocketInfo *infoPtr;
1033 infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
1034 infoPtr->socket = socket;
1036 infoPtr->watchEvents = 0;
1037 infoPtr->readyEvents = 0;
1038 infoPtr->selectEvents = 0;
1039 infoPtr->acceptEventCount = 0;
1040 infoPtr->acceptProc = NULL;
1041 infoPtr->lastError = 0;
1043 /* TIP #218. Removed the code inserting the new structure
1044 * into the global list. This is now handled in the thread
1045 * action callbacks, and only there.
1047 infoPtr->nextPtr = NULL;
1053 *----------------------------------------------------------------------
1057 * This function opens a new socket and initializes the
1058 * SocketInfo structure.
1061 * Returns a new SocketInfo, or NULL with an error in interp.
1064 * None, except for allocation of memory.
1066 *----------------------------------------------------------------------
1070 CreateSocket(interp, port, host, server, myaddr, myport, async)
1071 Tcl_Interp *interp; /* For error reporting; can be NULL. */
1072 int port; /* Port number to open. */
1073 CONST char *host; /* Name of host on which to open port. */
1074 int server; /* 1 if socket should be a server socket,
1075 * else 0 for a client socket. */
1076 CONST char *myaddr; /* Optional client-side address */
1077 int myport; /* Optional client-side port */
1078 int async; /* If nonzero, connect client socket
1079 * asynchronously. */
1081 u_long flag = 1; /* Indicates nonblocking mode. */
1082 int asyncConnect = 0; /* Will be 1 if async connect is
1084 SOCKADDR_IN sockaddr; /* Socket address */
1085 SOCKADDR_IN mysockaddr; /* Socket address for client */
1086 SOCKET sock = INVALID_SOCKET;
1087 SocketInfo *infoPtr; /* The returned value. */
1088 ThreadSpecificData *tsdPtr =
1089 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1092 * Check that WinSock is initialized; do not call it if not, to
1093 * prevent system crashes. This can happen at exit time if the exit
1094 * handler for WinSock ran before other exit handlers that want to
1098 if (!SocketsEnabled()) {
1102 if (! CreateSocketAddress(&sockaddr, host, port)) {
1105 if ((myaddr != NULL || myport != 0) &&
1106 ! CreateSocketAddress(&mysockaddr, myaddr, myport)) {
1110 sock = winSock.socket(AF_INET, SOCK_STREAM, 0);
1111 if (sock == INVALID_SOCKET) {
1116 * Win-NT has a misfeature that sockets are inherited in child
1117 * processes by default. Turn off the inherit bit.
1120 SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0 );
1123 * Set kernel space buffering
1126 TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE);
1130 * Bind to the specified port. Note that we must not call setsockopt
1131 * with SO_REUSEADDR because Microsoft allows addresses to be reused
1132 * even if they are still in use.
1134 * Bind should not be affected by the socket having already been
1135 * set into nonblocking mode. If there is trouble, this is one place
1139 if (winSock.bind(sock, (SOCKADDR *) &sockaddr,
1140 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
1145 * Set the maximum number of pending connect requests to the
1146 * max value allowed on each platform (Win32 and Win32s may be
1147 * different, and there may be differences between TCP/IP stacks).
1150 if (winSock.listen(sock, SOMAXCONN) == SOCKET_ERROR) {
1155 * Add this socket to the global list of sockets.
1158 infoPtr = NewSocketInfo(sock);
1161 * Set up the select mask for connection request events.
1164 infoPtr->selectEvents = FD_ACCEPT;
1165 infoPtr->watchEvents |= FD_ACCEPT;
1170 * Try to bind to a local port, if specified.
1173 if (myaddr != NULL || myport != 0) {
1174 if (winSock.bind(sock, (SOCKADDR *) &mysockaddr,
1175 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
1181 * Set the socket into nonblocking mode if the connect should be
1182 * done in the background.
1186 if (winSock.ioctlsocket(sock, (long) FIONBIO, &flag) == SOCKET_ERROR) {
1192 * Attempt to connect to the remote socket.
1195 if (winSock.connect(sock, (SOCKADDR *) &sockaddr,
1196 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
1197 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
1198 if (Tcl_GetErrno() != EWOULDBLOCK) {
1203 * The connection is progressing in the background.
1210 * Add this socket to the global list of sockets.
1213 infoPtr = NewSocketInfo(sock);
1216 * Set up the select mask for read/write events. If the connect
1217 * attempt has not completed, include connect events.
1220 infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
1222 infoPtr->flags |= SOCKET_ASYNC_CONNECT;
1223 infoPtr->selectEvents |= FD_CONNECT;
1228 * Register for interest in events in the select mask. Note that this
1229 * automatically places the socket into non-blocking mode.
1232 winSock.ioctlsocket(sock, (long) FIONBIO, &flag);
1233 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1234 (WPARAM) SELECT, (LPARAM) infoPtr);
1239 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
1240 if (interp != NULL) {
1241 Tcl_AppendResult(interp, "couldn't open socket: ",
1242 Tcl_PosixError(interp), (char *) NULL);
1244 if (sock != INVALID_SOCKET) {
1245 winSock.closesocket(sock);
1251 *----------------------------------------------------------------------
1253 * CreateSocketAddress --
1255 * This function initializes a sockaddr structure for a host and port.
1258 * 1 if the host was valid, 0 if the host could not be converted to
1262 * Fills in the *sockaddrPtr structure.
1264 *----------------------------------------------------------------------
1268 CreateSocketAddress(sockaddrPtr, host, port)
1269 LPSOCKADDR_IN sockaddrPtr; /* Socket address */
1270 CONST char *host; /* Host. NULL implies INADDR_ANY */
1271 int port; /* Port number */
1273 struct hostent *hostent; /* Host database entry */
1274 struct in_addr addr; /* For 64/32 bit madness */
1277 * Check that WinSock is initialized; do not call it if not, to
1278 * prevent system crashes. This can happen at exit time if the exit
1279 * handler for WinSock ran before other exit handlers that want to
1283 if (!SocketsEnabled()) {
1284 Tcl_SetErrno(EFAULT);
1288 ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN));
1289 sockaddrPtr->sin_family = AF_INET;
1290 sockaddrPtr->sin_port = winSock.htons((u_short) (port & 0xFFFF));
1292 addr.s_addr = INADDR_ANY;
1294 addr.s_addr = winSock.inet_addr(host);
1295 if (addr.s_addr == INADDR_NONE) {
1296 hostent = winSock.gethostbyname(host);
1297 if (hostent != NULL) {
1298 memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length);
1301 Tcl_SetErrno(EHOSTUNREACH);
1304 Tcl_SetErrno(ENXIO);
1307 return 0; /* Error. */
1313 * NOTE: On 64 bit machines the assignment below is rumored to not
1314 * do the right thing. Please report errors related to this if you
1315 * observe incorrect behavior on 64 bit machines such as DEC Alphas.
1316 * Should we modify this code to do an explicit memcpy?
1319 sockaddrPtr->sin_addr.s_addr = addr.s_addr;
1320 return 1; /* Success. */
1324 *----------------------------------------------------------------------
1326 * WaitForSocketEvent --
1328 * Waits until one of the specified events occurs on a socket.
1331 * Returns 1 on success or 0 on failure, with an error code in
1335 * Processes socket events off the system queue.
1337 *----------------------------------------------------------------------
1341 WaitForSocketEvent(infoPtr, events, errorCodePtr)
1342 SocketInfo *infoPtr; /* Information about this socket. */
1343 int events; /* Events to look for. */
1344 int *errorCodePtr; /* Where to store errors? */
1348 ThreadSpecificData *tsdPtr =
1349 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1352 * Be sure to disable event servicing so we are truly modal.
1355 oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
1358 * Reset WSAAsyncSelect so we have a fresh set of events pending.
1361 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1362 (WPARAM) UNSELECT, (LPARAM) infoPtr);
1364 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1365 (WPARAM) SELECT, (LPARAM) infoPtr);
1369 if (infoPtr->lastError) {
1370 *errorCodePtr = infoPtr->lastError;
1373 } else if (infoPtr->readyEvents & events) {
1375 } else if (infoPtr->flags & SOCKET_ASYNC) {
1376 *errorCodePtr = EWOULDBLOCK;
1382 * Wait until something happens.
1384 WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
1387 (void) Tcl_SetServiceMode(oldMode);
1392 *----------------------------------------------------------------------
1394 * Tcl_OpenTcpClient --
1396 * Opens a TCP client socket and creates a channel around it.
1399 * The channel or NULL if failed. An error message is returned
1400 * in the interpreter on failure.
1403 * Opens a client socket and creates a new channel.
1405 *----------------------------------------------------------------------
1409 Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async)
1410 Tcl_Interp *interp; /* For error reporting; can be NULL. */
1411 int port; /* Port number to open. */
1412 CONST char *host; /* Host on which to open port. */
1413 CONST char *myaddr; /* Client-side address */
1414 int myport; /* Client-side port */
1415 int async; /* If nonzero, should connect
1416 * client socket asynchronously. */
1418 SocketInfo *infoPtr;
1419 char channelName[16 + TCL_INTEGER_SPACE];
1421 if (TclpHasSockets(interp) != TCL_OK) {
1426 * Create a new client socket and wrap it in a channel.
1429 infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
1430 if (infoPtr == NULL) {
1434 wsprintfA(channelName, "sock%d", infoPtr->socket);
1436 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1437 (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
1438 if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",
1439 "auto crlf") == TCL_ERROR) {
1440 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
1441 return (Tcl_Channel) NULL;
1443 if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "")
1445 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
1446 return (Tcl_Channel) NULL;
1448 return infoPtr->channel;
1452 *----------------------------------------------------------------------
1454 * Tcl_MakeTcpClientChannel --
1456 * Creates a Tcl_Channel from an existing client TCP socket.
1459 * The Tcl_Channel wrapped around the preexisting TCP socket.
1464 * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com)
1466 *----------------------------------------------------------------------
1470 Tcl_MakeTcpClientChannel(sock)
1471 ClientData sock; /* The socket to wrap up into a channel. */
1473 SocketInfo *infoPtr;
1474 char channelName[16 + TCL_INTEGER_SPACE];
1475 ThreadSpecificData *tsdPtr;
1477 if (TclpHasSockets(NULL) != TCL_OK) {
1481 tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1484 * Set kernel space buffering and non-blocking.
1487 TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE);
1489 infoPtr = NewSocketInfo((SOCKET) sock);
1492 * Start watching for read/write events on the socket.
1495 infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
1496 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1497 (WPARAM) SELECT, (LPARAM) infoPtr);
1499 wsprintfA(channelName, "sock%d", infoPtr->socket);
1500 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1501 (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
1502 Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
1503 return infoPtr->channel;
1507 *----------------------------------------------------------------------
1509 * Tcl_OpenTcpServer --
1511 * Opens a TCP server socket and creates a channel around it.
1514 * The channel or NULL if failed. An error message is returned
1515 * in the interpreter on failure.
1518 * Opens a server socket and creates a new channel.
1520 *----------------------------------------------------------------------
1524 Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)
1525 Tcl_Interp *interp; /* For error reporting - may be
1527 int port; /* Port number to open. */
1528 CONST char *host; /* Name of local host. */
1529 Tcl_TcpAcceptProc *acceptProc; /* Callback for accepting connections
1530 * from new clients. */
1531 ClientData acceptProcData; /* Data for the callback. */
1533 SocketInfo *infoPtr;
1534 char channelName[16 + TCL_INTEGER_SPACE];
1536 if (TclpHasSockets(interp) != TCL_OK) {
1541 * Create a new client socket and wrap it in a channel.
1544 infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0);
1545 if (infoPtr == NULL) {
1549 infoPtr->acceptProc = acceptProc;
1550 infoPtr->acceptProcData = acceptProcData;
1552 wsprintfA(channelName, "sock%d", infoPtr->socket);
1554 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1555 (ClientData) infoPtr, 0);
1556 if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")
1558 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
1559 return (Tcl_Channel) NULL;
1562 return infoPtr->channel;
1566 *----------------------------------------------------------------------
1569 * Accept a TCP socket connection. This is called by
1570 * SocketEventProc and it in turns calls the registered accept
1577 * Invokes the accept proc which may invoke arbitrary Tcl code.
1579 *----------------------------------------------------------------------
1584 SocketInfo *infoPtr; /* Socket to accept. */
1587 SocketInfo *newInfoPtr;
1590 char channelName[16 + TCL_INTEGER_SPACE];
1591 ThreadSpecificData *tsdPtr =
1592 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1595 * Accept the incoming connection request.
1598 len = sizeof(SOCKADDR_IN);
1600 newSocket = winSock.accept(infoPtr->socket, (SOCKADDR *)&addr,
1604 * Clear the ready mask so we can detect the next connection request.
1605 * Note that connection requests are level triggered, so if there is
1606 * a request already pending, a new event will be generated.
1609 if (newSocket == INVALID_SOCKET) {
1610 infoPtr->acceptEventCount = 0;
1611 infoPtr->readyEvents &= ~(FD_ACCEPT);
1616 * It is possible that more than one FD_ACCEPT has been sent, so an extra
1617 * count must be kept. Decrement the count, and reset the readyEvent bit
1618 * if the count is no longer > 0.
1621 infoPtr->acceptEventCount--;
1623 if (infoPtr->acceptEventCount <= 0) {
1624 infoPtr->readyEvents &= ~(FD_ACCEPT);
1628 * Win-NT has a misfeature that sockets are inherited in child
1629 * processes by default. Turn off the inherit bit.
1632 SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 );
1635 * Add this socket to the global list of sockets.
1638 newInfoPtr = NewSocketInfo(newSocket);
1641 * Select on read/write events and create the channel.
1644 newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
1645 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1646 (WPARAM) SELECT, (LPARAM) newInfoPtr);
1648 wsprintfA(channelName, "sock%d", newInfoPtr->socket);
1649 newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1650 (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
1651 if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
1652 "auto crlf") == TCL_ERROR) {
1653 Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
1656 if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "")
1658 Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
1663 * Invoke the accept callback procedure.
1666 if (infoPtr->acceptProc != NULL) {
1667 (infoPtr->acceptProc) (infoPtr->acceptProcData,
1668 newInfoPtr->channel,
1669 winSock.inet_ntoa(addr.sin_addr),
1670 winSock.ntohs(addr.sin_port));
1675 *----------------------------------------------------------------------
1679 * This procedure is called by the generic IO level to read data from
1680 * a socket based channel.
1683 * The number of bytes read or -1 on error.
1686 * Consumes input from the socket.
1688 *----------------------------------------------------------------------
1692 TcpInputProc(instanceData, buf, toRead, errorCodePtr)
1693 ClientData instanceData; /* The socket state. */
1694 char *buf; /* Where to store data. */
1695 int toRead; /* Maximum number of bytes to read. */
1696 int *errorCodePtr; /* Where to store error codes. */
1698 SocketInfo *infoPtr = (SocketInfo *) instanceData;
1701 ThreadSpecificData *tsdPtr =
1702 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1707 * Check that WinSock is initialized; do not call it if not, to
1708 * prevent system crashes. This can happen at exit time if the exit
1709 * handler for WinSock ran before other exit handlers that want to
1713 if (!SocketsEnabled()) {
1714 *errorCodePtr = EFAULT;
1719 * First check to see if EOF was already detected, to prevent
1720 * calling the socket stack after the first time EOF is detected.
1723 if (infoPtr->flags & SOCKET_EOF) {
1728 * Check to see if the socket is connected before trying to read.
1731 if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
1732 && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) {
1737 * No EOF, and it is connected, so try to read more from the socket.
1738 * Note that we clear the FD_READ bit because read events are level
1739 * triggered so a new event will be generated if there is still data
1740 * available to be read. We have to simulate blocking behavior here
1741 * since we are always using non-blocking sockets.
1745 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1746 (WPARAM) UNSELECT, (LPARAM) infoPtr);
1747 bytesRead = winSock.recv(infoPtr->socket, buf, toRead, 0);
1748 infoPtr->readyEvents &= ~(FD_READ);
1751 * Check for end-of-file condition or successful read.
1754 if (bytesRead == 0) {
1755 infoPtr->flags |= SOCKET_EOF;
1757 if (bytesRead != SOCKET_ERROR) {
1762 * If an error occurs after the FD_CLOSE has arrived,
1763 * then ignore the error and report an EOF.
1766 if (infoPtr->readyEvents & FD_CLOSE) {
1767 infoPtr->flags |= SOCKET_EOF;
1773 * Check for error condition or underflow in non-blocking case.
1776 error = winSock.WSAGetLastError();
1777 if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {
1778 TclWinConvertWSAError(error);
1779 *errorCodePtr = Tcl_GetErrno();
1785 * In the blocking case, wait until the file becomes readable
1786 * or closed and try again.
1789 if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) {
1795 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1796 (WPARAM) SELECT, (LPARAM) infoPtr);
1802 *----------------------------------------------------------------------
1806 * This procedure is called by the generic IO level to write data
1807 * to a socket based channel.
1810 * The number of bytes written or -1 on failure.
1813 * Produces output on the socket.
1815 *----------------------------------------------------------------------
1819 TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)
1820 ClientData instanceData; /* The socket state. */
1821 CONST char *buf; /* Where to get data. */
1822 int toWrite; /* Maximum number of bytes to write. */
1823 int *errorCodePtr; /* Where to store error codes. */
1825 SocketInfo *infoPtr = (SocketInfo *) instanceData;
1828 ThreadSpecificData *tsdPtr =
1829 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1834 * Check that WinSock is initialized; do not call it if not, to
1835 * prevent system crashes. This can happen at exit time if the exit
1836 * handler for WinSock ran before other exit handlers that want to
1840 if (!SocketsEnabled()) {
1841 *errorCodePtr = EFAULT;
1846 * Check to see if the socket is connected before trying to write.
1849 if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
1850 && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) {
1855 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1856 (WPARAM) UNSELECT, (LPARAM) infoPtr);
1858 bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0);
1859 if (bytesWritten != SOCKET_ERROR) {
1861 * Since Windows won't generate a new write event until we hit
1862 * an overflow condition, we need to force the event loop to
1863 * poll until the condition changes.
1866 if (infoPtr->watchEvents & FD_WRITE) {
1867 Tcl_Time blockTime = { 0, 0 };
1868 Tcl_SetMaxBlockTime(&blockTime);
1874 * Check for error condition or overflow. In the event of overflow, we
1875 * need to clear the FD_WRITE flag so we can detect the next writable
1876 * event. Note that Windows only sends a new writable event after a
1877 * send fails with WSAEWOULDBLOCK.
1880 error = winSock.WSAGetLastError();
1881 if (error == WSAEWOULDBLOCK) {
1882 infoPtr->readyEvents &= ~(FD_WRITE);
1883 if (infoPtr->flags & SOCKET_ASYNC) {
1884 *errorCodePtr = EWOULDBLOCK;
1889 TclWinConvertWSAError(error);
1890 *errorCodePtr = Tcl_GetErrno();
1896 * In the blocking case, wait until the file becomes writable
1897 * or closed and try again.
1900 if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {
1906 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1907 (WPARAM) SELECT, (LPARAM) infoPtr);
1909 return bytesWritten;
1913 *----------------------------------------------------------------------
1915 * TcpSetOptionProc --
1917 * Sets Tcp channel specific options.
1920 * None, unless an error happens.
1923 * Changes attributes of the socket at the system level.
1925 *----------------------------------------------------------------------
1930 ClientData instanceData, /* Socket state. */
1931 Tcl_Interp *interp, /* For error reporting - can be NULL. */
1932 CONST char *optionName, /* Name of the option to set. */
1933 CONST char *value) /* New value for option. */
1935 SocketInfo *infoPtr;
1942 * Check that WinSock is initialized; do not call it if not, to
1943 * prevent system crashes. This can happen at exit time if the exit
1944 * handler for WinSock ran before other exit handlers that want to
1948 if (!SocketsEnabled()) {
1950 Tcl_AppendResult(interp, "winsock is not initialized", NULL);
1955 infoPtr = (SocketInfo *) instanceData;
1956 sock = infoPtr->socket;
1959 if (!stricmp(optionName, "-keepalive")) {
1960 if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
1963 if (boolVar) val = TRUE;
1964 rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
1965 (const char *) &val, sizeof(BOOL));
1967 TclWinConvertWSAError(winSock.WSAGetLastError());
1969 Tcl_AppendResult(interp, "couldn't set socket option: ",
1970 Tcl_PosixError(interp), NULL);
1976 } else if (!stricmp(optionName, "-nagle")) {
1977 if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
1980 if (!boolVar) val = TRUE;
1981 rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
1982 (const char *) &val, sizeof(BOOL));
1984 TclWinConvertWSAError(winSock.WSAGetLastError());
1986 Tcl_AppendResult(interp, "couldn't set socket option: ",
1987 Tcl_PosixError(interp), NULL);
1994 return Tcl_BadChannelOption(interp, optionName, "keepalive nagle");
1996 return Tcl_BadChannelOption(interp, optionName, "");
2000 *----------------------------------------------------------------------
2002 * TcpGetOptionProc --
2004 * Computes an option value for a TCP socket based channel, or a
2005 * list of all options and their values.
2007 * Note: This code is based on code contributed by John Haxby.
2010 * A standard Tcl result. The value of the specified option or a
2011 * list of all options and their values is returned in the
2017 *----------------------------------------------------------------------
2021 TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
2022 ClientData instanceData; /* Socket state. */
2023 Tcl_Interp *interp; /* For error reporting - can be NULL */
2024 CONST char *optionName; /* Name of the option to
2025 * retrieve the value for, or
2026 * NULL to get all options and
2028 Tcl_DString *dsPtr; /* Where to store the computed
2029 * value; initialized by caller. */
2031 SocketInfo *infoPtr;
2032 SOCKADDR_IN sockname;
2033 SOCKADDR_IN peername;
2034 struct hostent *hostEntPtr;
2036 int size = sizeof(SOCKADDR_IN);
2038 char buf[TCL_INTEGER_SPACE];
2041 * Check that WinSock is initialized; do not call it if not, to
2042 * prevent system crashes. This can happen at exit time if the exit
2043 * handler for WinSock ran before other exit handlers that want to
2047 if (!SocketsEnabled()) {
2049 Tcl_AppendResult(interp, "winsock is not initialized", NULL);
2054 infoPtr = (SocketInfo *) instanceData;
2055 sock = (int) infoPtr->socket;
2056 if (optionName != (char *) NULL) {
2057 len = strlen(optionName);
2060 if ((len > 1) && (optionName[1] == 'e') &&
2061 (strncmp(optionName, "-error", len) == 0)) {
2066 optlen = sizeof(int);
2067 ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR,
2068 (char *)&err, &optlen);
2069 if (ret == SOCKET_ERROR) {
2070 err = winSock.WSAGetLastError();
2073 TclWinConvertWSAError(err);
2074 Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
2080 ((len > 1) && (optionName[1] == 'p') &&
2081 (strncmp(optionName, "-peername", len) == 0))) {
2082 if (winSock.getpeername(sock, (LPSOCKADDR) &peername, &size)
2085 Tcl_DStringAppendElement(dsPtr, "-peername");
2086 Tcl_DStringStartSublist(dsPtr);
2088 Tcl_DStringAppendElement(dsPtr,
2089 winSock.inet_ntoa(peername.sin_addr));
2091 if (peername.sin_addr.s_addr == 0) {
2092 hostEntPtr = (struct hostent *) NULL;
2094 hostEntPtr = winSock.gethostbyaddr(
2095 (char *) &(peername.sin_addr), sizeof(peername.sin_addr),
2098 if (hostEntPtr != (struct hostent *) NULL) {
2099 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
2101 Tcl_DStringAppendElement(dsPtr,
2102 winSock.inet_ntoa(peername.sin_addr));
2104 TclFormatInt(buf, winSock.ntohs(peername.sin_port));
2105 Tcl_DStringAppendElement(dsPtr, buf);
2107 Tcl_DStringEndSublist(dsPtr);
2113 * getpeername failed - but if we were asked for all the options
2114 * (len==0), don't flag an error at that point because it could
2115 * be an fconfigure request on a server socket. (which have
2116 * no peer). {copied from unix/tclUnixChan.c}
2119 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
2121 Tcl_AppendResult(interp, "can't get peername: ",
2122 Tcl_PosixError(interp),
2131 ((len > 1) && (optionName[1] == 's') &&
2132 (strncmp(optionName, "-sockname", len) == 0))) {
2133 if (winSock.getsockname(sock, (LPSOCKADDR) &sockname, &size)
2136 Tcl_DStringAppendElement(dsPtr, "-sockname");
2137 Tcl_DStringStartSublist(dsPtr);
2139 Tcl_DStringAppendElement(dsPtr,
2140 winSock.inet_ntoa(sockname.sin_addr));
2141 if (sockname.sin_addr.s_addr == 0) {
2142 hostEntPtr = (struct hostent *) NULL;
2144 hostEntPtr = winSock.gethostbyaddr(
2145 (char *) &(sockname.sin_addr), sizeof(peername.sin_addr),
2148 if (hostEntPtr != (struct hostent *) NULL) {
2149 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
2151 Tcl_DStringAppendElement(dsPtr,
2152 winSock.inet_ntoa(sockname.sin_addr));
2154 TclFormatInt(buf, winSock.ntohs(sockname.sin_port));
2155 Tcl_DStringAppendElement(dsPtr, buf);
2157 Tcl_DStringEndSublist(dsPtr);
2163 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
2164 Tcl_AppendResult(interp, "can't get sockname: ",
2165 Tcl_PosixError(interp),
2173 if (len == 0 || !strncmp(optionName, "-keepalive", len)) {
2178 Tcl_DStringAppendElement(dsPtr, "-keepalive");
2180 optlen = sizeof(BOOL);
2181 winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt,
2184 Tcl_DStringAppendElement(dsPtr, "1");
2186 Tcl_DStringAppendElement(dsPtr, "0");
2188 if (len > 0) return TCL_OK;
2191 if (len == 0 || !strncmp(optionName, "-nagle", len)) {
2196 Tcl_DStringAppendElement(dsPtr, "-nagle");
2198 optlen = sizeof(BOOL);
2199 winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt,
2202 Tcl_DStringAppendElement(dsPtr, "0");
2204 Tcl_DStringAppendElement(dsPtr, "1");
2206 if (len > 0) return TCL_OK;
2211 /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/
2212 return Tcl_BadChannelOption(interp, optionName, "peername sockname");
2219 *----------------------------------------------------------------------
2223 * Informs the channel driver of the events that the generic
2224 * channel code wishes to receive on this socket.
2230 * May cause the notifier to poll if any of the specified
2231 * conditions are already true.
2233 *----------------------------------------------------------------------
2237 TcpWatchProc(instanceData, mask)
2238 ClientData instanceData; /* The socket state. */
2239 int mask; /* Events of interest; an OR-ed
2240 * combination of TCL_READABLE,
2241 * TCL_WRITABLE and TCL_EXCEPTION. */
2243 SocketInfo *infoPtr = (SocketInfo *) instanceData;
2246 * Update the watch events mask. Only if the socket is not a
2247 * server socket. Fix for SF Tcl Bug #557878.
2250 if (!infoPtr->acceptProc) {
2251 infoPtr->watchEvents = 0;
2252 if (mask & TCL_READABLE) {
2253 infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);
2255 if (mask & TCL_WRITABLE) {
2256 infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT);
2260 * If there are any conditions already set, then tell the notifier to poll
2261 * rather than block.
2264 if (infoPtr->readyEvents & infoPtr->watchEvents) {
2265 Tcl_Time blockTime = { 0, 0 };
2266 Tcl_SetMaxBlockTime(&blockTime);
2272 *----------------------------------------------------------------------
2276 * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside
2277 * a TCP socket based channel.
2280 * Returns TCL_OK with the socket in handlePtr.
2285 *----------------------------------------------------------------------
2289 TcpGetHandleProc(instanceData, direction, handlePtr)
2290 ClientData instanceData; /* The socket state. */
2291 int direction; /* Not used. */
2292 ClientData *handlePtr; /* Where to store the handle. */
2294 SocketInfo *statePtr = (SocketInfo *) instanceData;
2296 *handlePtr = (ClientData) statePtr->socket;
2301 *----------------------------------------------------------------------
2305 * Helper thread used to manage the socket event handling window.
2308 * 1 if unable to create socket event window, 0 otherwise.
2313 *----------------------------------------------------------------------
2317 SocketThread(LPVOID arg)
2320 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
2323 * Create a dummy window receiving socket events.
2326 tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket",
2327 WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
2330 * Signalize thread creator that we are done creating the window.
2333 SetEvent(tsdPtr->readyEvent);
2336 * If unable to create the window, exit this thread immediately.
2339 if (tsdPtr->hwnd == NULL) {
2344 * Process all messages on the socket window until WM_QUIT.
2345 * This threads exits only when instructed to do so by the
2346 * call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets().
2349 while (GetMessage(&msg, NULL, 0, 0) > 0) {
2350 DispatchMessage(&msg);
2354 * This releases waiters on thread exit in TclpFinalizeSockets()
2357 SetEvent(tsdPtr->readyEvent);
2359 return (DWORD)msg.wParam;
2364 *----------------------------------------------------------------------
2368 * This function is called when WSAAsyncSelect has been used
2369 * to register interest in a socket event, and the event has
2376 * The flags for the given socket are updated to reflect the
2377 * event that occured.
2379 *----------------------------------------------------------------------
2382 static LRESULT CALLBACK
2383 SocketProc(hwnd, message, wParam, lParam)
2391 SocketInfo *infoPtr;
2392 ThreadSpecificData *tsdPtr =
2394 (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
2396 (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA);
2402 return DefWindowProc(hwnd, message, wParam, lParam);
2407 * store the initial tsdPtr, it's from a different thread, so it's
2408 * not directly accessible, but needed.
2412 SetWindowLongPtr(hwnd, GWLP_USERDATA,
2413 (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams);
2415 SetWindowLong(hwnd, GWL_USERDATA,
2416 (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams);
2424 case SOCKET_MESSAGE:
2425 event = WSAGETSELECTEVENT(lParam);
2426 error = WSAGETSELECTERROR(lParam);
2427 socket = (SOCKET) wParam;
2430 * Find the specified socket on the socket list and update its
2434 WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
2435 for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
2436 infoPtr = infoPtr->nextPtr) {
2437 if (infoPtr->socket == socket) {
2439 * Update the socket state.
2443 * A count of FD_ACCEPTS is stored, so if an FD_CLOSE
2444 * event happens, then clear the FD_ACCEPT count.
2445 * Otherwise, increment the count if the current
2446 * event is an FD_ACCEPT.
2449 if (event & FD_CLOSE) {
2450 infoPtr->acceptEventCount = 0;
2451 infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
2452 } else if (event & FD_ACCEPT) {
2453 infoPtr->acceptEventCount++;
2456 if (event & FD_CONNECT) {
2458 * The socket is now connected,
2459 * clear the async connect flag.
2462 infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
2465 * Remember any error that occurred so we can report
2466 * connection failures.
2469 if (error != ERROR_SUCCESS) {
2470 TclWinConvertWSAError((DWORD) error);
2471 infoPtr->lastError = Tcl_GetErrno();
2475 if(infoPtr->flags & SOCKET_ASYNC_CONNECT) {
2476 infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
2477 if (error != ERROR_SUCCESS) {
2478 TclWinConvertWSAError((DWORD) error);
2479 infoPtr->lastError = Tcl_GetErrno();
2481 infoPtr->readyEvents |= FD_WRITE;
2483 infoPtr->readyEvents |= event;
2486 * Wake up the Main Thread.
2488 SetEvent(tsdPtr->readyEvent);
2489 Tcl_ThreadAlert(tsdPtr->threadId);
2493 SetEvent(tsdPtr->socketListLock);
2497 infoPtr = (SocketInfo *) lParam;
2498 if (wParam == SELECT) {
2500 winSock.WSAAsyncSelect(infoPtr->socket, hwnd,
2501 SOCKET_MESSAGE, infoPtr->selectEvents);
2504 * Clear the selection mask
2507 winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0);
2511 case SOCKET_TERMINATE:
2512 DestroyWindow(hwnd);
2520 *----------------------------------------------------------------------
2522 * Tcl_GetHostName --
2524 * Returns the name of the local host.
2527 * A string containing the network name for this machine, or
2528 * an empty string if we can't figure out the name. The caller
2529 * must not modify or free this string.
2534 *----------------------------------------------------------------------
2541 WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1];
2543 Tcl_MutexLock(&socketMutex);
2546 if (hostnameInitialized) {
2547 Tcl_MutexUnlock(&socketMutex);
2550 Tcl_MutexUnlock(&socketMutex);
2552 if (TclpHasSockets(NULL) == TCL_OK) {
2557 if (winSock.gethostname(hostname, sizeof(hostname)) == 0) {
2558 Tcl_MutexLock(&socketMutex);
2559 hostnameInitialized = 1;
2560 Tcl_MutexUnlock(&socketMutex);
2564 Tcl_MutexLock(&socketMutex);
2565 length = sizeof(hostname);
2566 if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) {
2568 * Convert string from native to UTF then change to lowercase.
2573 lstrcpynA(hostname, Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds),
2575 Tcl_DStringFree(&ds);
2576 Tcl_UtfToLower(hostname);
2580 hostnameInitialized = 1;
2581 Tcl_MutexUnlock(&socketMutex);
2586 *----------------------------------------------------------------------
2588 * TclWinGetSockOpt, et al. --
2590 * These functions are wrappers that let us bind the WinSock
2591 * API dynamically so we can run on systems that don't have
2592 * the wsock32.dll. We need wrappers for these interfaces
2593 * because they are called from the generic Tcl code.
2596 * As defined for each function.
2599 * As defined for each function.
2601 *----------------------------------------------------------------------
2605 TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval,
2609 * Check that WinSock is initialized; do not call it if not, to
2610 * prevent system crashes. This can happen at exit time if the exit
2611 * handler for WinSock ran before other exit handlers that want to
2615 if (!SocketsEnabled()) {
2616 return SOCKET_ERROR;
2619 return winSock.getsockopt(s, level, optname, optval, optlen);
2623 TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval,
2627 * Check that WinSock is initialized; do not call it if not, to
2628 * prevent system crashes. This can happen at exit time if the exit
2629 * handler for WinSock ran before other exit handlers that want to
2632 if (!SocketsEnabled()) {
2633 return SOCKET_ERROR;
2636 return winSock.setsockopt(s, level, optname, optval, optlen);
2640 TclWinNToHS(u_short netshort)
2643 * Check that WinSock is initialized; do not call it if not, to
2644 * prevent system crashes. This can happen at exit time if the exit
2645 * handler for WinSock ran before other exit handlers that want to
2649 if (!SocketsEnabled()) {
2650 return (u_short) -1;
2653 return winSock.ntohs(netshort);
2657 TclWinGetServByName(const char * name, const char * proto)
2660 * Check that WinSock is initialized; do not call it if not, to
2661 * prevent system crashes. This can happen at exit time if the exit
2662 * handler for WinSock ran before other exit handlers that want to
2665 if (!SocketsEnabled()) {
2666 return (struct servent *) NULL;
2669 return winSock.getservbyname(name, proto);
2673 *----------------------------------------------------------------------
2675 * TcpThreadActionProc --
2677 * Insert or remove any thread local refs to this channel.
2683 * Changes thread local list of valid channels.
2685 *----------------------------------------------------------------------
2689 TcpThreadActionProc (instanceData, action)
2690 ClientData instanceData;
2693 ThreadSpecificData *tsdPtr;
2694 SocketInfo *infoPtr = (SocketInfo *) instanceData;
2697 if (action == TCL_CHANNEL_THREAD_INSERT) {
2699 * Ensure that socket subsystem is initialized in this thread, or
2700 * else sockets will not work.
2703 Tcl_MutexLock(&socketMutex);
2705 Tcl_MutexUnlock(&socketMutex);
2707 tsdPtr = TCL_TSD_INIT(&dataKey);
2709 WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
2710 infoPtr->nextPtr = tsdPtr->socketList;
2711 tsdPtr->socketList = infoPtr;
2712 SetEvent(tsdPtr->socketListLock);
2716 SocketInfo **nextPtrPtr;
2719 tsdPtr = TCL_TSD_INIT(&dataKey);
2721 /* TIP #218, Bugfix: All access to socketList has to be protected by the lock */
2722 WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
2723 for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
2724 nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
2725 if ((*nextPtrPtr) == infoPtr) {
2726 (*nextPtrPtr) = infoPtr->nextPtr;
2731 SetEvent(tsdPtr->socketListLock);
2734 * This could happen if the channel was created in one thread
2735 * and then moved to another without updating the thread
2736 * local data in each thread.
2740 Tcl_Panic("file info ptr not on thread channel list");
2743 notifyCmd = UNSELECT;
2747 * Ensure that, or stop, notifications for the socket occur in this thread.
2750 SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
2751 (WPARAM) notifyCmd, (LPARAM) infoPtr);