1/* 2 * tclWinSock.c -- 3 * 4 * This file contains Windows-specific socket related code. 5 * 6 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 7 * 8 * See the file "license.terms" for information on usage and redistribution 9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 * 11 * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.8 2007/11/29 00:31:51 hobbs Exp $ 12 */ 13 14#include "tclWinInt.h" 15 16/* 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. 19 */ 20#undef getservbyname 21#undef getsockopt 22#undef ntohs 23#undef setsockopt 24 25/* 26 * The following variable is used to tell whether this module has been 27 * initialized. 28 */ 29 30static int initialized = 0; 31 32static int hostnameInitialized = 0; 33static char hostname[255]; /* This buffer should be big enough for 34 * hostname plus domain name. */ 35 36TCL_DECLARE_MUTEX(socketMutex) 37 38 39/* 40 * Mingw and Cygwin may not have LPFN_* typedefs. 41 */ 42 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, 56 int namelen); 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) 69 (struct in_addr in); 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, 75 int len, int flags); 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, 84 int optlen); 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, 92 LPWSADATA lpWSAData); 93#endif 94 95 96/* 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. 101 */ 102 103static struct { 104 HMODULE hModule; /* Handle to WinSock library. */ 105 106 /* Winsock 1.1 functions */ 107 LPFN_ACCEPT accept; 108 LPFN_BIND bind; 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; 118 LPFN_HTONS htons; 119 LPFN_INET_ADDR inet_addr; 120 LPFN_INET_NTOA inet_ntoa; 121 LPFN_IOCTLSOCKET ioctlsocket; 122 LPFN_LISTEN listen; 123 LPFN_NTOHS ntohs; 124 LPFN_RECV recv; 125 LPFN_SELECT select; 126 LPFN_SEND send; 127 LPFN_SETSOCKOPT setsockopt; 128 LPFN_SOCKET socket; 129 LPFN_WSAASYNCSELECT WSAAsyncSelect; 130 LPFN_WSACLEANUP WSACleanup; 131 LPFN_WSAGETLASTERROR WSAGetLastError; 132 LPFN_WSASTARTUP WSAStartup; 133 134} winSock; 135 136/* 137 * The following defines declare the messages used on socket windows. 138 */ 139 140#define SOCKET_MESSAGE WM_USER+1 141#define SOCKET_SELECT WM_USER+2 142#define SOCKET_TERMINATE WM_USER+3 143#define SELECT TRUE 144#define UNSELECT FALSE 145 146/* 147 * The following structure is used to store the data associated with 148 * each socket. 149 */ 150 151typedef struct SocketInfo { 152 Tcl_Channel channel; /* Channel associated with this 153 * socket. */ 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 169 * selected. */ 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 177 * socket list. */ 178} SocketInfo; 179 180/* 181 * The following structure is what is added to the Tcl event queue when 182 * a socket event occurs. 183 */ 184 185typedef struct SocketEvent { 186 Tcl_Event header; /* Information that is standard for 187 * all events. */ 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). */ 193} SocketEvent; 194 195/* 196 * This defines the minimum buffersize maintained by the kernel. 197 */ 198 199#define TCP_BUFFER_SIZE 4096 200 201/* 202 * The following macros may be used to set the flags field of 203 * a SocketInfo structure. 204 */ 205 206#define SOCKET_ASYNC (1<<0) /* The socket is in blocking 207 * mode. */ 208#define SOCKET_EOF (1<<1) /* A zero read happened on 209 * the socket. */ 210#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async 211 * connect. */ 212#define SOCKET_PENDING (1<<3) /* A message has been sent 213 * for this socket */ 214 215typedef 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 222 * started. */ 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; 227 228static Tcl_ThreadDataKey dataKey; 229static WNDCLASS windowClass; 230 231/* 232 * Static functions defined in this file. 233 */ 234 235static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, 236 int port, CONST char *host, 237 int server, CONST char *myaddr, 238 int myport, int async)); 239static int CreateSocketAddress _ANSI_ARGS_( 240 (LPSOCKADDR_IN sockaddrPtr, 241 CONST char *host, int port)); 242static void InitSockets _ANSI_ARGS_((void)); 243static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket)); 244static Tcl_EventCheckProc SocketCheckProc; 245static Tcl_EventProc SocketEventProc; 246static void SocketExitHandler _ANSI_ARGS_(( 247 ClientData clientData)); 248static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, 249 UINT message, WPARAM wParam, 250 LPARAM lParam)); 251static Tcl_EventSetupProc SocketSetupProc; 252static int SocketsEnabled _ANSI_ARGS_((void)); 253static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr)); 254static Tcl_DriverBlockModeProc TcpBlockProc; 255static Tcl_DriverCloseProc TcpCloseProc; 256static Tcl_DriverSetOptionProc TcpSetOptionProc; 257static Tcl_DriverGetOptionProc TcpGetOptionProc; 258static Tcl_DriverInputProc TcpInputProc; 259static Tcl_DriverOutputProc TcpOutputProc; 260static Tcl_DriverWatchProc TcpWatchProc; 261static Tcl_DriverGetHandleProc TcpGetHandleProc; 262static int WaitForSocketEvent _ANSI_ARGS_(( 263 SocketInfo *infoPtr, int events, 264 int *errorCodePtr)); 265static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg)); 266 267static void TcpThreadActionProc _ANSI_ARGS_ (( 268 ClientData instanceData, int action)); 269 270 271/* 272 * This structure describes the channel type structure for TCP socket 273 * based IO. 274 */ 275 276static 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 */ 293}; 294 295 296/* 297 *---------------------------------------------------------------------- 298 * 299 * InitSockets -- 300 * 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. 304 * 305 * Assumes socketMutex is held. 306 * 307 * Results: 308 * None. 309 * 310 * Side effects: 311 * Dynamically loads wsock32.dll, and registers a new window 312 * class and creates a window for use in asynchronous socket 313 * notification. 314 * 315 *---------------------------------------------------------------------- 316 */ 317 318static void 319InitSockets() 320{ 321 DWORD id; 322 WSADATA wsaData; 323 DWORD err; 324 ThreadSpecificData *tsdPtr = 325 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 326 327 if (!initialized) { 328 initialized = 1; 329 TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL); 330 331 winSock.hModule = LoadLibraryA("wsock32.dll"); 332 333 if (winSock.hModule == NULL) { 334 return; 335 } 336 337 /* 338 * Initialize the function table. 339 */ 340 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"); 393 394 /* 395 * Now check that all fields are properly initialized. If not, 396 * return zero to indicate that we failed to initialize 397 * properly. 398 */ 399 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)) 426 { 427 goto unloadLibrary; 428 } 429 430 /* 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. 435 */ 436 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; 447 448 if (!RegisterClassA(&windowClass)) { 449 TclWinConvertError(GetLastError()); 450 goto unloadLibrary; 451 } 452 453 /* 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. 457 */ 458 459#define WSA_VERSION_MAJOR 1 460#define WSA_VERSION_MINOR 1 461#define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR) 462 463 if ((err = winSock.WSAStartup(WSA_VERSION_REQD, &wsaData)) != 0) { 464 TclWinConvertWSAError(err); 465 goto unloadLibrary; 466 } 467 468 /* 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. 472 */ 473 474 if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion)) 475 < MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) { 476 TclWinConvertWSAError(WSAVERNOTSUPPORTED); 477 winSock.WSACleanup(); 478 goto unloadLibrary; 479 } 480 481#undef WSA_VERSION_REQD 482#undef WSA_VERSION_MAJOR 483#undef WSA_VERSION_MINOR 484 } 485 486 /* 487 * Check for per-thread initialization. 488 */ 489 490 if (tsdPtr == NULL) { 491 tsdPtr = TCL_TSD_INIT(&dataKey); 492 tsdPtr->socketList = NULL; 493 tsdPtr->hwnd = NULL; 494 tsdPtr->threadId = Tcl_GetCurrentThread(); 495 tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 496 if (tsdPtr->readyEvent == NULL) { 497 goto unloadLibrary; 498 } 499 tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL); 500 if (tsdPtr->socketListLock == NULL) { 501 goto unloadLibrary; 502 } 503 tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, 504 tsdPtr, 0, &id); 505 if (tsdPtr->socketThread == NULL) { 506 goto unloadLibrary; 507 } 508 509 SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); 510 511 /* 512 * Wait for the thread to signal when the window has 513 * been created and if it is ready to go. 514 */ 515 516 WaitForSingleObject(tsdPtr->readyEvent, INFINITE); 517 518 if (tsdPtr->hwnd == NULL) { 519 goto unloadLibrary; /* Trouble creating the window */ 520 } 521 522 Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); 523 } 524 return; 525 526unloadLibrary: 527 TclpFinalizeSockets(); 528 FreeLibrary(winSock.hModule); 529 winSock.hModule = NULL; 530 return; 531} 532 533/* 534 *---------------------------------------------------------------------- 535 * 536 * SocketsEnabled -- 537 * 538 * Check that the WinSock DLL is loaded and ready. 539 * 540 * Results: 541 * 1 if it is. 542 * 543 * Side effects: 544 * None. 545 * 546 *---------------------------------------------------------------------- 547 */ 548 549 /* ARGSUSED */ 550static int 551SocketsEnabled() 552{ 553 int enabled; 554 Tcl_MutexLock(&socketMutex); 555 enabled = (winSock.hModule != NULL); 556 Tcl_MutexUnlock(&socketMutex); 557 return enabled; 558} 559 560 561/* 562 *---------------------------------------------------------------------- 563 * 564 * SocketExitHandler -- 565 * 566 * Callback invoked during app exit clean up to delete the socket 567 * communication window and to release the WinSock DLL. 568 * 569 * Results: 570 * None. 571 * 572 * Side effects: 573 * None. 574 * 575 *---------------------------------------------------------------------- 576 */ 577 578 /* ARGSUSED */ 579static void 580SocketExitHandler(clientData) 581 ClientData clientData; /* Not used. */ 582{ 583 Tcl_MutexLock(&socketMutex); 584 if (winSock.hModule) { 585 /* 586 * Make sure the socket event handling window is cleaned-up 587 * for, at most, this thread. 588 */ 589 TclpFinalizeSockets(); 590 UnregisterClass("TclSocket", TclWinGetTclInstance()); 591 winSock.WSACleanup(); 592 FreeLibrary(winSock.hModule); 593 winSock.hModule = NULL; 594 } 595 initialized = 0; 596 hostnameInitialized = 0; 597 Tcl_MutexUnlock(&socketMutex); 598} 599 600/* 601 *---------------------------------------------------------------------- 602 * 603 * TclpFinalizeSockets -- 604 * 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. 609 * 610 * Results: 611 * None. 612 * 613 * Side effects: 614 * Deletes the event source and destroys the socket thread. 615 * 616 *---------------------------------------------------------------------- 617 */ 618 619void 620TclpFinalizeSockets() 621{ 622 ThreadSpecificData *tsdPtr; 623 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); 629 /* 630 * Wait for the thread to exit. This ensures that we are 631 * completely cleaned up before we leave this function. 632 */ 633 WaitForSingleObject(tsdPtr->readyEvent, INFINITE); 634 tsdPtr->hwnd = NULL; 635 } 636 CloseHandle(tsdPtr->socketThread); 637 tsdPtr->socketThread = NULL; 638 } 639 if (tsdPtr->readyEvent != NULL) { 640 CloseHandle(tsdPtr->readyEvent); 641 tsdPtr->readyEvent = NULL; 642 } 643 if (tsdPtr->socketListLock != NULL) { 644 CloseHandle(tsdPtr->socketListLock); 645 tsdPtr->socketListLock = NULL; 646 } 647 Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); 648 } 649} 650 651/* 652 *---------------------------------------------------------------------- 653 * 654 * TclpHasSockets -- 655 * 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. 659 * 660 * Results: 661 * Returns TCL_OK if the system supports sockets, or TCL_ERROR with 662 * an error in interp. 663 * 664 * Side effects: 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. 668 * 669 *---------------------------------------------------------------------- 670 */ 671 672int 673TclpHasSockets(interp) 674 Tcl_Interp *interp; 675{ 676 Tcl_MutexLock(&socketMutex); 677 InitSockets(); 678 Tcl_MutexUnlock(&socketMutex); 679 680 if (SocketsEnabled()) { 681 return TCL_OK; 682 } 683 if (interp != NULL) { 684 Tcl_AppendResult(interp, "sockets are not available on this system", 685 NULL); 686 } 687 return TCL_ERROR; 688} 689 690/* 691 *---------------------------------------------------------------------- 692 * 693 * SocketSetupProc -- 694 * 695 * This procedure is invoked before Tcl_DoOneEvent blocks waiting 696 * for an event. 697 * 698 * Results: 699 * None. 700 * 701 * Side effects: 702 * Adjusts the block time if needed. 703 * 704 *---------------------------------------------------------------------- 705 */ 706 707void 708SocketSetupProc(data, flags) 709 ClientData data; /* Not used. */ 710 int flags; /* Event flags as passed to Tcl_DoOneEvent. */ 711{ 712 SocketInfo *infoPtr; 713 Tcl_Time blockTime = { 0, 0 }; 714 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 715 716 if (!(flags & TCL_FILE_EVENTS)) { 717 return; 718 } 719 720 /* 721 * Check to see if there is a ready socket. If so, poll. 722 */ 723 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); 729 break; 730 } 731 } 732 SetEvent(tsdPtr->socketListLock); 733} 734 735/* 736 *---------------------------------------------------------------------- 737 * 738 * SocketCheckProc -- 739 * 740 * This procedure is called by Tcl_DoOneEvent to check the socket 741 * event source for events. 742 * 743 * Results: 744 * None. 745 * 746 * Side effects: 747 * May queue an event. 748 * 749 *---------------------------------------------------------------------- 750 */ 751 752static void 753SocketCheckProc(data, flags) 754 ClientData data; /* Not used. */ 755 int flags; /* Event flags as passed to Tcl_DoOneEvent. */ 756{ 757 SocketInfo *infoPtr; 758 SocketEvent *evPtr; 759 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 760 761 if (!(flags & TCL_FILE_EVENTS)) { 762 return; 763 } 764 765 /* 766 * Queue events for any ready sockets that don't already have events 767 * queued (caused by persistent states that won't generate WinSock 768 * events). 769 */ 770 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); 781 } 782 } 783 SetEvent(tsdPtr->socketListLock); 784} 785 786/* 787 *---------------------------------------------------------------------- 788 * 789 * SocketEventProc -- 790 * 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. 794 * 795 * Results: 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. 800 * 801 * Side effects: 802 * Whatever the channel callback procedures do. 803 * 804 *---------------------------------------------------------------------- 805 */ 806 807static int 808SocketEventProc(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. */ 812{ 813 SocketInfo *infoPtr; 814 SocketEvent *eventPtr = (SocketEvent *) evPtr; 815 int mask = 0; 816 int events; 817 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 818 819 if (!(flags & TCL_FILE_EVENTS)) { 820 return 0; 821 } 822 823 /* 824 * Find the specified socket on the socket list. 825 */ 826 827 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 828 for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 829 infoPtr = infoPtr->nextPtr) { 830 if (infoPtr->socket == eventPtr->socket) { 831 break; 832 } 833 } 834 SetEvent(tsdPtr->socketListLock); 835 836 /* 837 * Discard events that have gone stale. 838 */ 839 840 if (!infoPtr) { 841 return 1; 842 } 843 844 infoPtr->flags &= ~SOCKET_PENDING; 845 846 /* 847 * Handle connection requests directly. 848 */ 849 850 if (infoPtr->readyEvents & FD_ACCEPT) { 851 TcpAccept(infoPtr); 852 return 1; 853 } 854 855 /* 856 * Mask off unwanted events and compute the read/write mask so 857 * we can notify the channel. 858 */ 859 860 events = infoPtr->readyEvents & infoPtr->watchEvents; 861 862 if (events & FD_CLOSE) { 863 /* 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. 871 */ 872 873 Tcl_Time blockTime = { 0, 0 }; 874 Tcl_SetMaxBlockTime(&blockTime); 875 mask |= TCL_READABLE|TCL_WRITABLE; 876 } else if (events & FD_READ) { 877 fd_set readFds; 878 struct timeval timeout; 879 880 /* 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. 886 */ 887 888 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 889 (WPARAM) UNSELECT, (LPARAM) infoPtr); 890 891 FD_ZERO(&readFds); 892 FD_SET(infoPtr->socket, &readFds); 893 timeout.tv_usec = 0; 894 timeout.tv_sec = 0; 895 896 if (winSock.select(0, &readFds, NULL, NULL, &timeout) != 0) { 897 mask |= TCL_READABLE; 898 } else { 899 infoPtr->readyEvents &= ~(FD_READ); 900 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 901 (WPARAM) SELECT, (LPARAM) infoPtr); 902 } 903 } 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; 909 } 910 } 911 912 if (mask) { 913 Tcl_NotifyChannel(infoPtr->channel, mask); 914 } 915 return 1; 916} 917 918/* 919 *---------------------------------------------------------------------- 920 * 921 * TcpBlockProc -- 922 * 923 * Sets a socket into blocking or non-blocking mode. 924 * 925 * Results: 926 * 0 if successful, errno if there was an error. 927 * 928 * Side effects: 929 * None. 930 * 931 *---------------------------------------------------------------------- 932 */ 933 934static int 935TcpBlockProc(instanceData, mode) 936 ClientData instanceData; /* The socket to block/un-block. */ 937 int mode; /* TCL_MODE_BLOCKING or 938 * TCL_MODE_NONBLOCKING. */ 939{ 940 SocketInfo *infoPtr = (SocketInfo *) instanceData; 941 942 if (mode == TCL_MODE_NONBLOCKING) { 943 infoPtr->flags |= SOCKET_ASYNC; 944 } else { 945 infoPtr->flags &= ~(SOCKET_ASYNC); 946 } 947 return 0; 948} 949 950/* 951 *---------------------------------------------------------------------- 952 * 953 * TcpCloseProc -- 954 * 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. 958 * 959 * Results: 960 * 0 if successful, the value of errno if failed. 961 * 962 * Side effects: 963 * Closes the socket. 964 * 965 *---------------------------------------------------------------------- 966 */ 967 968 /* ARGSUSED */ 969static int 970TcpCloseProc(instanceData, interp) 971 ClientData instanceData; /* The socket to close. */ 972 Tcl_Interp *interp; /* Unused. */ 973{ 974 SocketInfo *infoPtr = (SocketInfo *) instanceData; 975 /* TIP #218 */ 976 int errorCode = 0; 977 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 978 979 /* 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 983 * use sockets. 984 */ 985 986 if (SocketsEnabled()) { 987 988 /* 989 * Clean up the OS socket handle. The default Windows setting 990 * for a socket is SO_DONTLINGER, which does a graceful shutdown 991 * in the background. 992 */ 993 994 if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) { 995 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); 996 errorCode = Tcl_GetErrno(); 997 } 998 } 999 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. 1005 */ 1006 ckfree((char *) infoPtr); 1007 return errorCode; 1008} 1009 1010/* 1011 *---------------------------------------------------------------------- 1012 * 1013 * NewSocketInfo -- 1014 * 1015 * This function allocates and initializes a new SocketInfo 1016 * structure. 1017 * 1018 * Results: 1019 * Returns a newly allocated SocketInfo. 1020 * 1021 * Side effects: 1022 * None, except for allocation of memory. 1023 * 1024 *---------------------------------------------------------------------- 1025 */ 1026 1027static SocketInfo * 1028NewSocketInfo(socket) 1029 SOCKET socket; 1030{ 1031 SocketInfo *infoPtr; 1032 1033 infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo)); 1034 infoPtr->socket = socket; 1035 infoPtr->flags = 0; 1036 infoPtr->watchEvents = 0; 1037 infoPtr->readyEvents = 0; 1038 infoPtr->selectEvents = 0; 1039 infoPtr->acceptEventCount = 0; 1040 infoPtr->acceptProc = NULL; 1041 infoPtr->lastError = 0; 1042 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. 1046 */ 1047 infoPtr->nextPtr = NULL; 1048 1049 return infoPtr; 1050} 1051 1052/* 1053 *---------------------------------------------------------------------- 1054 * 1055 * CreateSocket -- 1056 * 1057 * This function opens a new socket and initializes the 1058 * SocketInfo structure. 1059 * 1060 * Results: 1061 * Returns a new SocketInfo, or NULL with an error in interp. 1062 * 1063 * Side effects: 1064 * None, except for allocation of memory. 1065 * 1066 *---------------------------------------------------------------------- 1067 */ 1068 1069static SocketInfo * 1070CreateSocket(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. */ 1080{ 1081 u_long flag = 1; /* Indicates nonblocking mode. */ 1082 int asyncConnect = 0; /* Will be 1 if async connect is 1083 * in progress. */ 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); 1090 1091 /* 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 1095 * use sockets. 1096 */ 1097 1098 if (!SocketsEnabled()) { 1099 return NULL; 1100 } 1101 1102 if (! CreateSocketAddress(&sockaddr, host, port)) { 1103 goto error; 1104 } 1105 if ((myaddr != NULL || myport != 0) && 1106 ! CreateSocketAddress(&mysockaddr, myaddr, myport)) { 1107 goto error; 1108 } 1109 1110 sock = winSock.socket(AF_INET, SOCK_STREAM, 0); 1111 if (sock == INVALID_SOCKET) { 1112 goto error; 1113 } 1114 1115 /* 1116 * Win-NT has a misfeature that sockets are inherited in child 1117 * processes by default. Turn off the inherit bit. 1118 */ 1119 1120 SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0 ); 1121 1122 /* 1123 * Set kernel space buffering 1124 */ 1125 1126 TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE); 1127 1128 if (server) { 1129 /* 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. 1133 * 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 1136 * to look for bugs. 1137 */ 1138 1139 if (winSock.bind(sock, (SOCKADDR *) &sockaddr, 1140 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { 1141 goto error; 1142 } 1143 1144 /* 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). 1148 */ 1149 1150 if (winSock.listen(sock, SOMAXCONN) == SOCKET_ERROR) { 1151 goto error; 1152 } 1153 1154 /* 1155 * Add this socket to the global list of sockets. 1156 */ 1157 1158 infoPtr = NewSocketInfo(sock); 1159 1160 /* 1161 * Set up the select mask for connection request events. 1162 */ 1163 1164 infoPtr->selectEvents = FD_ACCEPT; 1165 infoPtr->watchEvents |= FD_ACCEPT; 1166 1167 } else { 1168 1169 /* 1170 * Try to bind to a local port, if specified. 1171 */ 1172 1173 if (myaddr != NULL || myport != 0) { 1174 if (winSock.bind(sock, (SOCKADDR *) &mysockaddr, 1175 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { 1176 goto error; 1177 } 1178 } 1179 1180 /* 1181 * Set the socket into nonblocking mode if the connect should be 1182 * done in the background. 1183 */ 1184 1185 if (async) { 1186 if (winSock.ioctlsocket(sock, (long) FIONBIO, &flag) == SOCKET_ERROR) { 1187 goto error; 1188 } 1189 } 1190 1191 /* 1192 * Attempt to connect to the remote socket. 1193 */ 1194 1195 if (winSock.connect(sock, (SOCKADDR *) &sockaddr, 1196 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { 1197 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); 1198 if (Tcl_GetErrno() != EWOULDBLOCK) { 1199 goto error; 1200 } 1201 1202 /* 1203 * The connection is progressing in the background. 1204 */ 1205 1206 asyncConnect = 1; 1207 } 1208 1209 /* 1210 * Add this socket to the global list of sockets. 1211 */ 1212 1213 infoPtr = NewSocketInfo(sock); 1214 1215 /* 1216 * Set up the select mask for read/write events. If the connect 1217 * attempt has not completed, include connect events. 1218 */ 1219 1220 infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE; 1221 if (asyncConnect) { 1222 infoPtr->flags |= SOCKET_ASYNC_CONNECT; 1223 infoPtr->selectEvents |= FD_CONNECT; 1224 } 1225 } 1226 1227 /* 1228 * Register for interest in events in the select mask. Note that this 1229 * automatically places the socket into non-blocking mode. 1230 */ 1231 1232 winSock.ioctlsocket(sock, (long) FIONBIO, &flag); 1233 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1234 (WPARAM) SELECT, (LPARAM) infoPtr); 1235 1236 return infoPtr; 1237 1238error: 1239 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); 1240 if (interp != NULL) { 1241 Tcl_AppendResult(interp, "couldn't open socket: ", 1242 Tcl_PosixError(interp), (char *) NULL); 1243 } 1244 if (sock != INVALID_SOCKET) { 1245 winSock.closesocket(sock); 1246 } 1247 return NULL; 1248} 1249 1250/* 1251 *---------------------------------------------------------------------- 1252 * 1253 * CreateSocketAddress -- 1254 * 1255 * This function initializes a sockaddr structure for a host and port. 1256 * 1257 * Results: 1258 * 1 if the host was valid, 0 if the host could not be converted to 1259 * an IP address. 1260 * 1261 * Side effects: 1262 * Fills in the *sockaddrPtr structure. 1263 * 1264 *---------------------------------------------------------------------- 1265 */ 1266 1267static int 1268CreateSocketAddress(sockaddrPtr, host, port) 1269 LPSOCKADDR_IN sockaddrPtr; /* Socket address */ 1270 CONST char *host; /* Host. NULL implies INADDR_ANY */ 1271 int port; /* Port number */ 1272{ 1273 struct hostent *hostent; /* Host database entry */ 1274 struct in_addr addr; /* For 64/32 bit madness */ 1275 1276 /* 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 1280 * use sockets. 1281 */ 1282 1283 if (!SocketsEnabled()) { 1284 Tcl_SetErrno(EFAULT); 1285 return 0; 1286 } 1287 1288 ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN)); 1289 sockaddrPtr->sin_family = AF_INET; 1290 sockaddrPtr->sin_port = winSock.htons((u_short) (port & 0xFFFF)); 1291 if (host == NULL) { 1292 addr.s_addr = INADDR_ANY; 1293 } else { 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); 1299 } else { 1300#ifdef EHOSTUNREACH 1301 Tcl_SetErrno(EHOSTUNREACH); 1302#else 1303#ifdef ENXIO 1304 Tcl_SetErrno(ENXIO); 1305#endif 1306#endif 1307 return 0; /* Error. */ 1308 } 1309 } 1310 } 1311 1312 /* 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? 1317 */ 1318 1319 sockaddrPtr->sin_addr.s_addr = addr.s_addr; 1320 return 1; /* Success. */ 1321} 1322 1323/* 1324 *---------------------------------------------------------------------- 1325 * 1326 * WaitForSocketEvent -- 1327 * 1328 * Waits until one of the specified events occurs on a socket. 1329 * 1330 * Results: 1331 * Returns 1 on success or 0 on failure, with an error code in 1332 * errorCodePtr. 1333 * 1334 * Side effects: 1335 * Processes socket events off the system queue. 1336 * 1337 *---------------------------------------------------------------------- 1338 */ 1339 1340static int 1341WaitForSocketEvent(infoPtr, events, errorCodePtr) 1342 SocketInfo *infoPtr; /* Information about this socket. */ 1343 int events; /* Events to look for. */ 1344 int *errorCodePtr; /* Where to store errors? */ 1345{ 1346 int result = 1; 1347 int oldMode; 1348 ThreadSpecificData *tsdPtr = 1349 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 1350 1351 /* 1352 * Be sure to disable event servicing so we are truly modal. 1353 */ 1354 1355 oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); 1356 1357 /* 1358 * Reset WSAAsyncSelect so we have a fresh set of events pending. 1359 */ 1360 1361 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1362 (WPARAM) UNSELECT, (LPARAM) infoPtr); 1363 1364 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1365 (WPARAM) SELECT, (LPARAM) infoPtr); 1366 1367 while (1) { 1368 1369 if (infoPtr->lastError) { 1370 *errorCodePtr = infoPtr->lastError; 1371 result = 0; 1372 break; 1373 } else if (infoPtr->readyEvents & events) { 1374 break; 1375 } else if (infoPtr->flags & SOCKET_ASYNC) { 1376 *errorCodePtr = EWOULDBLOCK; 1377 result = 0; 1378 break; 1379 } 1380 1381 /* 1382 * Wait until something happens. 1383 */ 1384 WaitForSingleObject(tsdPtr->readyEvent, INFINITE); 1385 } 1386 1387 (void) Tcl_SetServiceMode(oldMode); 1388 return result; 1389} 1390 1391/* 1392 *---------------------------------------------------------------------- 1393 * 1394 * Tcl_OpenTcpClient -- 1395 * 1396 * Opens a TCP client socket and creates a channel around it. 1397 * 1398 * Results: 1399 * The channel or NULL if failed. An error message is returned 1400 * in the interpreter on failure. 1401 * 1402 * Side effects: 1403 * Opens a client socket and creates a new channel. 1404 * 1405 *---------------------------------------------------------------------- 1406 */ 1407 1408Tcl_Channel 1409Tcl_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. */ 1417{ 1418 SocketInfo *infoPtr; 1419 char channelName[16 + TCL_INTEGER_SPACE]; 1420 1421 if (TclpHasSockets(interp) != TCL_OK) { 1422 return NULL; 1423 } 1424 1425 /* 1426 * Create a new client socket and wrap it in a channel. 1427 */ 1428 1429 infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); 1430 if (infoPtr == NULL) { 1431 return NULL; 1432 } 1433 1434 wsprintfA(channelName, "sock%d", infoPtr->socket); 1435 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; 1442 } 1443 if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "") 1444 == TCL_ERROR) { 1445 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); 1446 return (Tcl_Channel) NULL; 1447 } 1448 return infoPtr->channel; 1449} 1450 1451/* 1452 *---------------------------------------------------------------------- 1453 * 1454 * Tcl_MakeTcpClientChannel -- 1455 * 1456 * Creates a Tcl_Channel from an existing client TCP socket. 1457 * 1458 * Results: 1459 * The Tcl_Channel wrapped around the preexisting TCP socket. 1460 * 1461 * Side effects: 1462 * None. 1463 * 1464 * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com) 1465 * 1466 *---------------------------------------------------------------------- 1467 */ 1468 1469Tcl_Channel 1470Tcl_MakeTcpClientChannel(sock) 1471 ClientData sock; /* The socket to wrap up into a channel. */ 1472{ 1473 SocketInfo *infoPtr; 1474 char channelName[16 + TCL_INTEGER_SPACE]; 1475 ThreadSpecificData *tsdPtr; 1476 1477 if (TclpHasSockets(NULL) != TCL_OK) { 1478 return NULL; 1479 } 1480 1481 tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 1482 1483 /* 1484 * Set kernel space buffering and non-blocking. 1485 */ 1486 1487 TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE); 1488 1489 infoPtr = NewSocketInfo((SOCKET) sock); 1490 1491 /* 1492 * Start watching for read/write events on the socket. 1493 */ 1494 1495 infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; 1496 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1497 (WPARAM) SELECT, (LPARAM) infoPtr); 1498 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; 1504} 1505 1506/* 1507 *---------------------------------------------------------------------- 1508 * 1509 * Tcl_OpenTcpServer -- 1510 * 1511 * Opens a TCP server socket and creates a channel around it. 1512 * 1513 * Results: 1514 * The channel or NULL if failed. An error message is returned 1515 * in the interpreter on failure. 1516 * 1517 * Side effects: 1518 * Opens a server socket and creates a new channel. 1519 * 1520 *---------------------------------------------------------------------- 1521 */ 1522 1523Tcl_Channel 1524Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) 1525 Tcl_Interp *interp; /* For error reporting - may be 1526 * NULL. */ 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. */ 1532{ 1533 SocketInfo *infoPtr; 1534 char channelName[16 + TCL_INTEGER_SPACE]; 1535 1536 if (TclpHasSockets(interp) != TCL_OK) { 1537 return NULL; 1538 } 1539 1540 /* 1541 * Create a new client socket and wrap it in a channel. 1542 */ 1543 1544 infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0); 1545 if (infoPtr == NULL) { 1546 return NULL; 1547 } 1548 1549 infoPtr->acceptProc = acceptProc; 1550 infoPtr->acceptProcData = acceptProcData; 1551 1552 wsprintfA(channelName, "sock%d", infoPtr->socket); 1553 1554 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 1555 (ClientData) infoPtr, 0); 1556 if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") 1557 == TCL_ERROR) { 1558 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); 1559 return (Tcl_Channel) NULL; 1560 } 1561 1562 return infoPtr->channel; 1563} 1564 1565/* 1566 *---------------------------------------------------------------------- 1567 * 1568 * TcpAccept -- 1569 * Accept a TCP socket connection. This is called by 1570 * SocketEventProc and it in turns calls the registered accept 1571 * procedure. 1572 * 1573 * Results: 1574 * None. 1575 * 1576 * Side effects: 1577 * Invokes the accept proc which may invoke arbitrary Tcl code. 1578 * 1579 *---------------------------------------------------------------------- 1580 */ 1581 1582static void 1583TcpAccept(infoPtr) 1584 SocketInfo *infoPtr; /* Socket to accept. */ 1585{ 1586 SOCKET newSocket; 1587 SocketInfo *newInfoPtr; 1588 SOCKADDR_IN addr; 1589 int len; 1590 char channelName[16 + TCL_INTEGER_SPACE]; 1591 ThreadSpecificData *tsdPtr = 1592 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 1593 1594 /* 1595 * Accept the incoming connection request. 1596 */ 1597 1598 len = sizeof(SOCKADDR_IN); 1599 1600 newSocket = winSock.accept(infoPtr->socket, (SOCKADDR *)&addr, 1601 &len); 1602 1603 /* 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. 1607 */ 1608 1609 if (newSocket == INVALID_SOCKET) { 1610 infoPtr->acceptEventCount = 0; 1611 infoPtr->readyEvents &= ~(FD_ACCEPT); 1612 return; 1613 } 1614 1615 /* 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. 1619 */ 1620 1621 infoPtr->acceptEventCount--; 1622 1623 if (infoPtr->acceptEventCount <= 0) { 1624 infoPtr->readyEvents &= ~(FD_ACCEPT); 1625 } 1626 1627 /* 1628 * Win-NT has a misfeature that sockets are inherited in child 1629 * processes by default. Turn off the inherit bit. 1630 */ 1631 1632 SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 ); 1633 1634 /* 1635 * Add this socket to the global list of sockets. 1636 */ 1637 1638 newInfoPtr = NewSocketInfo(newSocket); 1639 1640 /* 1641 * Select on read/write events and create the channel. 1642 */ 1643 1644 newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); 1645 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1646 (WPARAM) SELECT, (LPARAM) newInfoPtr); 1647 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); 1654 return; 1655 } 1656 if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "") 1657 == TCL_ERROR) { 1658 Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); 1659 return; 1660 } 1661 1662 /* 1663 * Invoke the accept callback procedure. 1664 */ 1665 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)); 1671 } 1672} 1673 1674/* 1675 *---------------------------------------------------------------------- 1676 * 1677 * TcpInputProc -- 1678 * 1679 * This procedure is called by the generic IO level to read data from 1680 * a socket based channel. 1681 * 1682 * Results: 1683 * The number of bytes read or -1 on error. 1684 * 1685 * Side effects: 1686 * Consumes input from the socket. 1687 * 1688 *---------------------------------------------------------------------- 1689 */ 1690 1691static int 1692TcpInputProc(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. */ 1697{ 1698 SocketInfo *infoPtr = (SocketInfo *) instanceData; 1699 int bytesRead; 1700 DWORD error; 1701 ThreadSpecificData *tsdPtr = 1702 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 1703 1704 *errorCodePtr = 0; 1705 1706 /* 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 1710 * use sockets. 1711 */ 1712 1713 if (!SocketsEnabled()) { 1714 *errorCodePtr = EFAULT; 1715 return -1; 1716 } 1717 1718 /* 1719 * First check to see if EOF was already detected, to prevent 1720 * calling the socket stack after the first time EOF is detected. 1721 */ 1722 1723 if (infoPtr->flags & SOCKET_EOF) { 1724 return 0; 1725 } 1726 1727 /* 1728 * Check to see if the socket is connected before trying to read. 1729 */ 1730 1731 if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) 1732 && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { 1733 return -1; 1734 } 1735 1736 /* 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. 1742 */ 1743 1744 while (1) { 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); 1749 1750 /* 1751 * Check for end-of-file condition or successful read. 1752 */ 1753 1754 if (bytesRead == 0) { 1755 infoPtr->flags |= SOCKET_EOF; 1756 } 1757 if (bytesRead != SOCKET_ERROR) { 1758 break; 1759 } 1760 1761 /* 1762 * If an error occurs after the FD_CLOSE has arrived, 1763 * then ignore the error and report an EOF. 1764 */ 1765 1766 if (infoPtr->readyEvents & FD_CLOSE) { 1767 infoPtr->flags |= SOCKET_EOF; 1768 bytesRead = 0; 1769 break; 1770 } 1771 1772 error = winSock.WSAGetLastError(); 1773 1774 /* 1775 * If an RST comes, then ignore the error and report an EOF just like 1776 * on unix. 1777 */ 1778 1779 if (error == WSAECONNRESET) { 1780 infoPtr->flags |= SOCKET_EOF; 1781 bytesRead = 0; 1782 break; 1783 } 1784 1785 /* 1786 * Check for error condition or underflow in non-blocking case. 1787 */ 1788 1789 if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { 1790 TclWinConvertWSAError(error); 1791 *errorCodePtr = Tcl_GetErrno(); 1792 bytesRead = -1; 1793 break; 1794 } 1795 1796 /* 1797 * In the blocking case, wait until the file becomes readable 1798 * or closed and try again. 1799 */ 1800 1801 if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) { 1802 bytesRead = -1; 1803 break; 1804 } 1805 } 1806 1807 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1808 (WPARAM) SELECT, (LPARAM) infoPtr); 1809 1810 return bytesRead; 1811} 1812 1813/* 1814 *---------------------------------------------------------------------- 1815 * 1816 * TcpOutputProc -- 1817 * 1818 * This procedure is called by the generic IO level to write data 1819 * to a socket based channel. 1820 * 1821 * Results: 1822 * The number of bytes written or -1 on failure. 1823 * 1824 * Side effects: 1825 * Produces output on the socket. 1826 * 1827 *---------------------------------------------------------------------- 1828 */ 1829 1830static int 1831TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) 1832 ClientData instanceData; /* The socket state. */ 1833 CONST char *buf; /* Where to get data. */ 1834 int toWrite; /* Maximum number of bytes to write. */ 1835 int *errorCodePtr; /* Where to store error codes. */ 1836{ 1837 SocketInfo *infoPtr = (SocketInfo *) instanceData; 1838 int bytesWritten; 1839 DWORD error; 1840 ThreadSpecificData *tsdPtr = 1841 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 1842 1843 *errorCodePtr = 0; 1844 1845 /* 1846 * Check that WinSock is initialized; do not call it if not, to 1847 * prevent system crashes. This can happen at exit time if the exit 1848 * handler for WinSock ran before other exit handlers that want to 1849 * use sockets. 1850 */ 1851 1852 if (!SocketsEnabled()) { 1853 *errorCodePtr = EFAULT; 1854 return -1; 1855 } 1856 1857 /* 1858 * Check to see if the socket is connected before trying to write. 1859 */ 1860 1861 if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) 1862 && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { 1863 return -1; 1864 } 1865 1866 while (1) { 1867 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1868 (WPARAM) UNSELECT, (LPARAM) infoPtr); 1869 1870 bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0); 1871 if (bytesWritten != SOCKET_ERROR) { 1872 /* 1873 * Since Windows won't generate a new write event until we hit 1874 * an overflow condition, we need to force the event loop to 1875 * poll until the condition changes. 1876 */ 1877 1878 if (infoPtr->watchEvents & FD_WRITE) { 1879 Tcl_Time blockTime = { 0, 0 }; 1880 Tcl_SetMaxBlockTime(&blockTime); 1881 } 1882 break; 1883 } 1884 1885 /* 1886 * Check for error condition or overflow. In the event of overflow, we 1887 * need to clear the FD_WRITE flag so we can detect the next writable 1888 * event. Note that Windows only sends a new writable event after a 1889 * send fails with WSAEWOULDBLOCK. 1890 */ 1891 1892 error = winSock.WSAGetLastError(); 1893 if (error == WSAEWOULDBLOCK) { 1894 infoPtr->readyEvents &= ~(FD_WRITE); 1895 if (infoPtr->flags & SOCKET_ASYNC) { 1896 *errorCodePtr = EWOULDBLOCK; 1897 bytesWritten = -1; 1898 break; 1899 } 1900 } else { 1901 TclWinConvertWSAError(error); 1902 *errorCodePtr = Tcl_GetErrno(); 1903 bytesWritten = -1; 1904 break; 1905 } 1906 1907 /* 1908 * In the blocking case, wait until the file becomes writable 1909 * or closed and try again. 1910 */ 1911 1912 if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) { 1913 bytesWritten = -1; 1914 break; 1915 } 1916 } 1917 1918 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1919 (WPARAM) SELECT, (LPARAM) infoPtr); 1920 1921 return bytesWritten; 1922} 1923 1924/* 1925 *---------------------------------------------------------------------- 1926 * 1927 * TcpSetOptionProc -- 1928 * 1929 * Sets Tcp channel specific options. 1930 * 1931 * Results: 1932 * None, unless an error happens. 1933 * 1934 * Side effects: 1935 * Changes attributes of the socket at the system level. 1936 * 1937 *---------------------------------------------------------------------- 1938 */ 1939 1940static int 1941TcpSetOptionProc ( 1942 ClientData instanceData, /* Socket state. */ 1943 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 1944 CONST char *optionName, /* Name of the option to set. */ 1945 CONST char *value) /* New value for option. */ 1946{ 1947 SocketInfo *infoPtr; 1948 SOCKET sock; 1949/* 1950 BOOL val = FALSE; 1951 int boolVar, rtn; 1952*/ 1953 /* 1954 * Check that WinSock is initialized; do not call it if not, to 1955 * prevent system crashes. This can happen at exit time if the exit 1956 * handler for WinSock ran before other exit handlers that want to 1957 * use sockets. 1958 */ 1959 1960 if (!SocketsEnabled()) { 1961 if (interp) { 1962 Tcl_AppendResult(interp, "winsock is not initialized", NULL); 1963 } 1964 return TCL_ERROR; 1965 } 1966 1967 infoPtr = (SocketInfo *) instanceData; 1968 sock = infoPtr->socket; 1969 1970/* 1971 if (!stricmp(optionName, "-keepalive")) { 1972 if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { 1973 return TCL_ERROR; 1974 } 1975 if (boolVar) val = TRUE; 1976 rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, 1977 (const char *) &val, sizeof(BOOL)); 1978 if (rtn != 0) { 1979 TclWinConvertWSAError(winSock.WSAGetLastError()); 1980 if (interp) { 1981 Tcl_AppendResult(interp, "couldn't set socket option: ", 1982 Tcl_PosixError(interp), NULL); 1983 } 1984 return TCL_ERROR; 1985 } 1986 return TCL_OK; 1987 1988 } else if (!stricmp(optionName, "-nagle")) { 1989 if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { 1990 return TCL_ERROR; 1991 } 1992 if (!boolVar) val = TRUE; 1993 rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 1994 (const char *) &val, sizeof(BOOL)); 1995 if (rtn != 0) { 1996 TclWinConvertWSAError(winSock.WSAGetLastError()); 1997 if (interp) { 1998 Tcl_AppendResult(interp, "couldn't set socket option: ", 1999 Tcl_PosixError(interp), NULL); 2000 } 2001 return TCL_ERROR; 2002 } 2003 return TCL_OK; 2004 } 2005 2006 return Tcl_BadChannelOption(interp, optionName, "keepalive nagle"); 2007*/ 2008 return Tcl_BadChannelOption(interp, optionName, ""); 2009} 2010 2011/* 2012 *---------------------------------------------------------------------- 2013 * 2014 * TcpGetOptionProc -- 2015 * 2016 * Computes an option value for a TCP socket based channel, or a 2017 * list of all options and their values. 2018 * 2019 * Note: This code is based on code contributed by John Haxby. 2020 * 2021 * Results: 2022 * A standard Tcl result. The value of the specified option or a 2023 * list of all options and their values is returned in the 2024 * supplied DString. 2025 * 2026 * Side effects: 2027 * None. 2028 * 2029 *---------------------------------------------------------------------- 2030 */ 2031 2032static int 2033TcpGetOptionProc(instanceData, interp, optionName, dsPtr) 2034 ClientData instanceData; /* Socket state. */ 2035 Tcl_Interp *interp; /* For error reporting - can be NULL */ 2036 CONST char *optionName; /* Name of the option to 2037 * retrieve the value for, or 2038 * NULL to get all options and 2039 * their values. */ 2040 Tcl_DString *dsPtr; /* Where to store the computed 2041 * value; initialized by caller. */ 2042{ 2043 SocketInfo *infoPtr; 2044 SOCKADDR_IN sockname; 2045 SOCKADDR_IN peername; 2046 struct hostent *hostEntPtr; 2047 SOCKET sock; 2048 int size = sizeof(SOCKADDR_IN); 2049 size_t len = 0; 2050 char buf[TCL_INTEGER_SPACE]; 2051 2052 /* 2053 * Check that WinSock is initialized; do not call it if not, to 2054 * prevent system crashes. This can happen at exit time if the exit 2055 * handler for WinSock ran before other exit handlers that want to 2056 * use sockets. 2057 */ 2058 2059 if (!SocketsEnabled()) { 2060 if (interp) { 2061 Tcl_AppendResult(interp, "winsock is not initialized", NULL); 2062 } 2063 return TCL_ERROR; 2064 } 2065 2066 infoPtr = (SocketInfo *) instanceData; 2067 sock = (int) infoPtr->socket; 2068 if (optionName != (char *) NULL) { 2069 len = strlen(optionName); 2070 } 2071 2072 if ((len > 1) && (optionName[1] == 'e') && 2073 (strncmp(optionName, "-error", len) == 0)) { 2074 int optlen; 2075 DWORD err; 2076 int ret; 2077 2078 optlen = sizeof(int); 2079 ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, 2080 (char *)&err, &optlen); 2081 if (ret == SOCKET_ERROR) { 2082 err = winSock.WSAGetLastError(); 2083 } 2084 if (err) { 2085 TclWinConvertWSAError(err); 2086 Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); 2087 } 2088 return TCL_OK; 2089 } 2090 2091 if ((len == 0) || 2092 ((len > 1) && (optionName[1] == 'p') && 2093 (strncmp(optionName, "-peername", len) == 0))) { 2094 if (winSock.getpeername(sock, (LPSOCKADDR) &peername, &size) 2095 == 0) { 2096 if (len == 0) { 2097 Tcl_DStringAppendElement(dsPtr, "-peername"); 2098 Tcl_DStringStartSublist(dsPtr); 2099 } 2100 Tcl_DStringAppendElement(dsPtr, 2101 winSock.inet_ntoa(peername.sin_addr)); 2102 2103 if (peername.sin_addr.s_addr == 0) { 2104 hostEntPtr = (struct hostent *) NULL; 2105 } else { 2106 hostEntPtr = winSock.gethostbyaddr( 2107 (char *) &(peername.sin_addr), sizeof(peername.sin_addr), 2108 AF_INET); 2109 } 2110 if (hostEntPtr != (struct hostent *) NULL) { 2111 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); 2112 } else { 2113 Tcl_DStringAppendElement(dsPtr, 2114 winSock.inet_ntoa(peername.sin_addr)); 2115 } 2116 TclFormatInt(buf, winSock.ntohs(peername.sin_port)); 2117 Tcl_DStringAppendElement(dsPtr, buf); 2118 if (len == 0) { 2119 Tcl_DStringEndSublist(dsPtr); 2120 } else { 2121 return TCL_OK; 2122 } 2123 } else { 2124 /* 2125 * getpeername failed - but if we were asked for all the options 2126 * (len==0), don't flag an error at that point because it could 2127 * be an fconfigure request on a server socket. (which have 2128 * no peer). {copied from unix/tclUnixChan.c} 2129 */ 2130 if (len) { 2131 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); 2132 if (interp) { 2133 Tcl_AppendResult(interp, "can't get peername: ", 2134 Tcl_PosixError(interp), 2135 (char *) NULL); 2136 } 2137 return TCL_ERROR; 2138 } 2139 } 2140 } 2141 2142 if ((len == 0) || 2143 ((len > 1) && (optionName[1] == 's') && 2144 (strncmp(optionName, "-sockname", len) == 0))) { 2145 if (winSock.getsockname(sock, (LPSOCKADDR) &sockname, &size) 2146 == 0) { 2147 if (len == 0) { 2148 Tcl_DStringAppendElement(dsPtr, "-sockname"); 2149 Tcl_DStringStartSublist(dsPtr); 2150 } 2151 Tcl_DStringAppendElement(dsPtr, 2152 winSock.inet_ntoa(sockname.sin_addr)); 2153 if (sockname.sin_addr.s_addr == 0) { 2154 hostEntPtr = (struct hostent *) NULL; 2155 } else { 2156 hostEntPtr = winSock.gethostbyaddr( 2157 (char *) &(sockname.sin_addr), sizeof(peername.sin_addr), 2158 AF_INET); 2159 } 2160 if (hostEntPtr != (struct hostent *) NULL) { 2161 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); 2162 } else { 2163 Tcl_DStringAppendElement(dsPtr, 2164 winSock.inet_ntoa(sockname.sin_addr)); 2165 } 2166 TclFormatInt(buf, winSock.ntohs(sockname.sin_port)); 2167 Tcl_DStringAppendElement(dsPtr, buf); 2168 if (len == 0) { 2169 Tcl_DStringEndSublist(dsPtr); 2170 } else { 2171 return TCL_OK; 2172 } 2173 } else { 2174 if (interp) { 2175 TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); 2176 Tcl_AppendResult(interp, "can't get sockname: ", 2177 Tcl_PosixError(interp), 2178 (char *) NULL); 2179 } 2180 return TCL_ERROR; 2181 } 2182 } 2183 2184/* 2185 if (len == 0 || !strncmp(optionName, "-keepalive", len)) { 2186 int optlen; 2187 BOOL opt = FALSE; 2188 2189 if (len == 0) { 2190 Tcl_DStringAppendElement(dsPtr, "-keepalive"); 2191 } 2192 optlen = sizeof(BOOL); 2193 winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, 2194 &optlen); 2195 if (opt) { 2196 Tcl_DStringAppendElement(dsPtr, "1"); 2197 } else { 2198 Tcl_DStringAppendElement(dsPtr, "0"); 2199 } 2200 if (len > 0) return TCL_OK; 2201 } 2202 2203 if (len == 0 || !strncmp(optionName, "-nagle", len)) { 2204 int optlen; 2205 BOOL opt = FALSE; 2206 2207 if (len == 0) { 2208 Tcl_DStringAppendElement(dsPtr, "-nagle"); 2209 } 2210 optlen = sizeof(BOOL); 2211 winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, 2212 &optlen); 2213 if (opt) { 2214 Tcl_DStringAppendElement(dsPtr, "0"); 2215 } else { 2216 Tcl_DStringAppendElement(dsPtr, "1"); 2217 } 2218 if (len > 0) return TCL_OK; 2219 } 2220*/ 2221 2222 if (len > 0) { 2223 /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/ 2224 return Tcl_BadChannelOption(interp, optionName, "peername sockname"); 2225 } 2226 2227 return TCL_OK; 2228} 2229 2230/* 2231 *---------------------------------------------------------------------- 2232 * 2233 * TcpWatchProc -- 2234 * 2235 * Informs the channel driver of the events that the generic 2236 * channel code wishes to receive on this socket. 2237 * 2238 * Results: 2239 * None. 2240 * 2241 * Side effects: 2242 * May cause the notifier to poll if any of the specified 2243 * conditions are already true. 2244 * 2245 *---------------------------------------------------------------------- 2246 */ 2247 2248static void 2249TcpWatchProc(instanceData, mask) 2250 ClientData instanceData; /* The socket state. */ 2251 int mask; /* Events of interest; an OR-ed 2252 * combination of TCL_READABLE, 2253 * TCL_WRITABLE and TCL_EXCEPTION. */ 2254{ 2255 SocketInfo *infoPtr = (SocketInfo *) instanceData; 2256 2257 /* 2258 * Update the watch events mask. Only if the socket is not a 2259 * server socket. Fix for SF Tcl Bug #557878. 2260 */ 2261 2262 if (!infoPtr->acceptProc) { 2263 infoPtr->watchEvents = 0; 2264 if (mask & TCL_READABLE) { 2265 infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT); 2266 } 2267 if (mask & TCL_WRITABLE) { 2268 infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT); 2269 } 2270 2271 /* 2272 * If there are any conditions already set, then tell the notifier to poll 2273 * rather than block. 2274 */ 2275 2276 if (infoPtr->readyEvents & infoPtr->watchEvents) { 2277 Tcl_Time blockTime = { 0, 0 }; 2278 Tcl_SetMaxBlockTime(&blockTime); 2279 } 2280 } 2281} 2282 2283/* 2284 *---------------------------------------------------------------------- 2285 * 2286 * TcpGetProc -- 2287 * 2288 * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside 2289 * a TCP socket based channel. 2290 * 2291 * Results: 2292 * Returns TCL_OK with the socket in handlePtr. 2293 * 2294 * Side effects: 2295 * None. 2296 * 2297 *---------------------------------------------------------------------- 2298 */ 2299 2300static int 2301TcpGetHandleProc(instanceData, direction, handlePtr) 2302 ClientData instanceData; /* The socket state. */ 2303 int direction; /* Not used. */ 2304 ClientData *handlePtr; /* Where to store the handle. */ 2305{ 2306 SocketInfo *statePtr = (SocketInfo *) instanceData; 2307 2308 *handlePtr = (ClientData) statePtr->socket; 2309 return TCL_OK; 2310} 2311 2312/* 2313 *---------------------------------------------------------------------- 2314 * 2315 * SocketThread -- 2316 * 2317 * Helper thread used to manage the socket event handling window. 2318 * 2319 * Results: 2320 * 1 if unable to create socket event window, 0 otherwise. 2321 * 2322 * Side effects: 2323 * None. 2324 * 2325 *---------------------------------------------------------------------- 2326 */ 2327 2328static DWORD WINAPI 2329SocketThread(LPVOID arg) 2330{ 2331 MSG msg; 2332 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg); 2333 2334 /* 2335 * Create a dummy window receiving socket events. 2336 */ 2337 2338 tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket", 2339 WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg); 2340 2341 /* 2342 * Signalize thread creator that we are done creating the window. 2343 */ 2344 2345 SetEvent(tsdPtr->readyEvent); 2346 2347 /* 2348 * If unable to create the window, exit this thread immediately. 2349 */ 2350 2351 if (tsdPtr->hwnd == NULL) { 2352 return 1; 2353 } 2354 2355 /* 2356 * Process all messages on the socket window until WM_QUIT. 2357 * This threads exits only when instructed to do so by the 2358 * call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets(). 2359 */ 2360 2361 while (GetMessage(&msg, NULL, 0, 0) > 0) { 2362 DispatchMessage(&msg); 2363 } 2364 2365 /* 2366 * This releases waiters on thread exit in TclpFinalizeSockets() 2367 */ 2368 2369 SetEvent(tsdPtr->readyEvent); 2370 2371 return (DWORD)msg.wParam; 2372} 2373 2374 2375/* 2376 *---------------------------------------------------------------------- 2377 * 2378 * SocketProc -- 2379 * 2380 * This function is called when WSAAsyncSelect has been used 2381 * to register interest in a socket event, and the event has 2382 * occurred. 2383 * 2384 * Results: 2385 * 0 on success. 2386 * 2387 * Side effects: 2388 * The flags for the given socket are updated to reflect the 2389 * event that occured. 2390 * 2391 *---------------------------------------------------------------------- 2392 */ 2393 2394static LRESULT CALLBACK 2395SocketProc(hwnd, message, wParam, lParam) 2396 HWND hwnd; 2397 UINT message; 2398 WPARAM wParam; 2399 LPARAM lParam; 2400{ 2401 int event, error; 2402 SOCKET socket; 2403 SocketInfo *infoPtr; 2404 ThreadSpecificData *tsdPtr = 2405#ifdef _WIN64 2406 (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); 2407#else 2408 (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA); 2409#endif 2410 2411 switch (message) { 2412 2413 default: 2414 return DefWindowProc(hwnd, message, wParam, lParam); 2415 break; 2416 2417 case WM_CREATE: 2418 /* 2419 * store the initial tsdPtr, it's from a different thread, so it's 2420 * not directly accessible, but needed. 2421 */ 2422 2423#ifdef _WIN64 2424 SetWindowLongPtr(hwnd, GWLP_USERDATA, 2425 (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams); 2426#else 2427 SetWindowLong(hwnd, GWL_USERDATA, 2428 (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams); 2429#endif 2430 break; 2431 2432 case WM_DESTROY: 2433 PostQuitMessage(0); 2434 break; 2435 2436 case SOCKET_MESSAGE: 2437 event = WSAGETSELECTEVENT(lParam); 2438 error = WSAGETSELECTERROR(lParam); 2439 socket = (SOCKET) wParam; 2440 2441 /* 2442 * Find the specified socket on the socket list and update its 2443 * eventState flag. 2444 */ 2445 2446 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 2447 for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 2448 infoPtr = infoPtr->nextPtr) { 2449 if (infoPtr->socket == socket) { 2450 /* 2451 * Update the socket state. 2452 */ 2453 2454 /* 2455 * A count of FD_ACCEPTS is stored, so if an FD_CLOSE 2456 * event happens, then clear the FD_ACCEPT count. 2457 * Otherwise, increment the count if the current 2458 * event is an FD_ACCEPT. 2459 */ 2460 2461 if (event & FD_CLOSE) { 2462 infoPtr->acceptEventCount = 0; 2463 infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); 2464 } else if (event & FD_ACCEPT) { 2465 infoPtr->acceptEventCount++; 2466 } 2467 2468 if (event & FD_CONNECT) { 2469 /* 2470 * The socket is now connected, 2471 * clear the async connect flag. 2472 */ 2473 2474 infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); 2475 2476 /* 2477 * Remember any error that occurred so we can report 2478 * connection failures. 2479 */ 2480 2481 if (error != ERROR_SUCCESS) { 2482 TclWinConvertWSAError((DWORD) error); 2483 infoPtr->lastError = Tcl_GetErrno(); 2484 } 2485 2486 } 2487 if(infoPtr->flags & SOCKET_ASYNC_CONNECT) { 2488 infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); 2489 if (error != ERROR_SUCCESS) { 2490 TclWinConvertWSAError((DWORD) error); 2491 infoPtr->lastError = Tcl_GetErrno(); 2492 } 2493 infoPtr->readyEvents |= FD_WRITE; 2494 } 2495 infoPtr->readyEvents |= event; 2496 2497 /* 2498 * Wake up the Main Thread. 2499 */ 2500 SetEvent(tsdPtr->readyEvent); 2501 Tcl_ThreadAlert(tsdPtr->threadId); 2502 break; 2503 } 2504 } 2505 SetEvent(tsdPtr->socketListLock); 2506 break; 2507 2508 case SOCKET_SELECT: 2509 infoPtr = (SocketInfo *) lParam; 2510 if (wParam == SELECT) { 2511 2512 winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 2513 SOCKET_MESSAGE, infoPtr->selectEvents); 2514 } else { 2515 /* 2516 * Clear the selection mask 2517 */ 2518 2519 winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0); 2520 } 2521 break; 2522 2523 case SOCKET_TERMINATE: 2524 DestroyWindow(hwnd); 2525 break; 2526 } 2527 2528 return 0; 2529} 2530 2531/* 2532 *---------------------------------------------------------------------- 2533 * 2534 * Tcl_GetHostName -- 2535 * 2536 * Returns the name of the local host. 2537 * 2538 * Results: 2539 * A string containing the network name for this machine, or 2540 * an empty string if we can't figure out the name. The caller 2541 * must not modify or free this string. 2542 * 2543 * Side effects: 2544 * None. 2545 * 2546 *---------------------------------------------------------------------- 2547 */ 2548 2549CONST char * 2550Tcl_GetHostName() 2551{ 2552 DWORD length; 2553 WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1]; 2554 2555 Tcl_MutexLock(&socketMutex); 2556 InitSockets(); 2557 2558 if (!hostnameInitialized) { 2559 /* 2560 * Convert hostname from native to UTF then change to lowercase. 2561 */ 2562 Tcl_DString ds; 2563 2564 length = sizeof(hostname); 2565 /* same as SocketsEnabled without the socketMutex lock */ 2566 if ((winSock.hModule != NULL) 2567 && (winSock.gethostname(hostname, length) == 0)) { 2568 Tcl_ExternalToUtfDString(NULL, hostname, -1, &ds); 2569 } else if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) { 2570 Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds); 2571 } else { 2572 Tcl_DStringInit(&ds); 2573 Tcl_DStringSetLength(&ds, 0); 2574 } 2575 lstrcpynA(hostname, Tcl_DStringValue(&ds), sizeof(hostname)); 2576 Tcl_DStringFree(&ds); 2577 Tcl_UtfToLower(hostname); 2578 hostnameInitialized = 1; 2579 } 2580 Tcl_MutexUnlock(&socketMutex); 2581 return hostname; 2582} 2583 2584/* 2585 *---------------------------------------------------------------------- 2586 * 2587 * TclWinGetSockOpt, et al. -- 2588 * 2589 * These functions are wrappers that let us bind the WinSock 2590 * API dynamically so we can run on systems that don't have 2591 * the wsock32.dll. We need wrappers for these interfaces 2592 * because they are called from the generic Tcl code. 2593 * 2594 * Results: 2595 * As defined for each function. 2596 * 2597 * Side effects: 2598 * As defined for each function. 2599 * 2600 *---------------------------------------------------------------------- 2601 */ 2602 2603int 2604TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval, 2605 int FAR *optlen) 2606{ 2607 /* 2608 * Check that WinSock is initialized; do not call it if not, to 2609 * prevent system crashes. This can happen at exit time if the exit 2610 * handler for WinSock ran before other exit handlers that want to 2611 * use sockets. 2612 */ 2613 2614 if (!SocketsEnabled()) { 2615 return SOCKET_ERROR; 2616 } 2617 2618 return winSock.getsockopt(s, level, optname, optval, optlen); 2619} 2620 2621int 2622TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval, 2623 int optlen) 2624{ 2625 /* 2626 * Check that WinSock is initialized; do not call it if not, to 2627 * prevent system crashes. This can happen at exit time if the exit 2628 * handler for WinSock ran before other exit handlers that want to 2629 * use sockets. 2630 */ 2631 if (!SocketsEnabled()) { 2632 return SOCKET_ERROR; 2633 } 2634 2635 return winSock.setsockopt(s, level, optname, optval, optlen); 2636} 2637 2638u_short 2639TclWinNToHS(u_short netshort) 2640{ 2641 /* 2642 * Check that WinSock is initialized; do not call it if not, to 2643 * prevent system crashes. This can happen at exit time if the exit 2644 * handler for WinSock ran before other exit handlers that want to 2645 * use sockets. 2646 */ 2647 2648 if (!SocketsEnabled()) { 2649 return (u_short) -1; 2650 } 2651 2652 return winSock.ntohs(netshort); 2653} 2654 2655struct servent * 2656TclWinGetServByName(const char * name, const char * proto) 2657{ 2658 /* 2659 * Check that WinSock is initialized; do not call it if not, to 2660 * prevent system crashes. This can happen at exit time if the exit 2661 * handler for WinSock ran before other exit handlers that want to 2662 * use sockets. 2663 */ 2664 if (!SocketsEnabled()) { 2665 return (struct servent *) NULL; 2666 } 2667 2668 return winSock.getservbyname(name, proto); 2669} 2670 2671/* 2672 *---------------------------------------------------------------------- 2673 * 2674 * TcpThreadActionProc -- 2675 * 2676 * Insert or remove any thread local refs to this channel. 2677 * 2678 * Results: 2679 * None. 2680 * 2681 * Side effects: 2682 * Changes thread local list of valid channels. 2683 * 2684 *---------------------------------------------------------------------- 2685 */ 2686 2687static void 2688TcpThreadActionProc (instanceData, action) 2689 ClientData instanceData; 2690 int action; 2691{ 2692 ThreadSpecificData *tsdPtr; 2693 SocketInfo *infoPtr = (SocketInfo *) instanceData; 2694 int notifyCmd; 2695 2696 if (action == TCL_CHANNEL_THREAD_INSERT) { 2697 /* 2698 * Ensure that socket subsystem is initialized in this thread, or 2699 * else sockets will not work. 2700 */ 2701 2702 Tcl_MutexLock(&socketMutex); 2703 InitSockets(); 2704 Tcl_MutexUnlock(&socketMutex); 2705 2706 tsdPtr = TCL_TSD_INIT(&dataKey); 2707 2708 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 2709 infoPtr->nextPtr = tsdPtr->socketList; 2710 tsdPtr->socketList = infoPtr; 2711 SetEvent(tsdPtr->socketListLock); 2712 2713 notifyCmd = SELECT; 2714 } else { 2715 SocketInfo **nextPtrPtr; 2716 int removed = 0; 2717 2718 tsdPtr = TCL_TSD_INIT(&dataKey); 2719 2720 /* TIP #218, Bugfix: All access to socketList has to be protected by the lock */ 2721 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 2722 for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL; 2723 nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { 2724 if ((*nextPtrPtr) == infoPtr) { 2725 (*nextPtrPtr) = infoPtr->nextPtr; 2726 removed = 1; 2727 break; 2728 } 2729 } 2730 SetEvent(tsdPtr->socketListLock); 2731 2732 /* 2733 * This could happen if the channel was created in one thread 2734 * and then moved to another without updating the thread 2735 * local data in each thread. 2736 */ 2737 2738 if (!removed) { 2739 Tcl_Panic("file info ptr not on thread channel list"); 2740 } 2741 2742 notifyCmd = UNSELECT; 2743 } 2744 2745 /* 2746 * Ensure that, or stop, notifications for the socket occur in this thread. 2747 */ 2748 2749 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 2750 (WPARAM) notifyCmd, (LPARAM) infoPtr); 2751} 2752