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 of 9 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 * 11 * RCS: @(#) $Id: tclWinSock.c,v 1.62.2.3 2010/01/31 23:51:37 nijtmans Exp $ 12 */ 13 14#include "tclWinInt.h" 15 16#ifdef _MSC_VER 17# pragma comment (lib, "ws2_32") 18#endif 19 20/* 21 * Support for control over sockets' KEEPALIVE and NODELAY behavior is 22 * currently disabled. 23 */ 24 25#undef TCL_FEATURE_KEEPALIVE_NAGLE 26 27/* 28 * Make sure to remove the redirection defines set in tclWinPort.h that is in 29 * use in other sections of the core, except for us. 30 */ 31 32#undef getservbyname 33#undef getsockopt 34#undef ntohs 35#undef setsockopt 36 37/* 38 * The following variable is used to tell whether this module has been 39 * initialized. If 1, initialization of sockets was successful, if -1 then 40 * socket initialization failed (WSAStartup failed). 41 */ 42 43static int initialized = 0; 44TCL_DECLARE_MUTEX(socketMutex) 45 46/* 47 * The following variable holds the network name of this host. 48 */ 49 50static TclInitProcessGlobalValueProc InitializeHostName; 51static ProcessGlobalValue hostName = { 52 0, 0, NULL, NULL, InitializeHostName, NULL, NULL 53}; 54 55/* 56 * The following defines declare the messages used on socket windows. 57 */ 58 59#define SOCKET_MESSAGE WM_USER+1 60#define SOCKET_SELECT WM_USER+2 61#define SOCKET_TERMINATE WM_USER+3 62#define SELECT TRUE 63#define UNSELECT FALSE 64 65/* 66 * The following structure is used to store the data associated with each 67 * socket. 68 */ 69 70typedef struct SocketInfo { 71 Tcl_Channel channel; /* Channel associated with this socket. */ 72 SOCKET socket; /* Windows SOCKET handle. */ 73 int flags; /* Bit field comprised of the flags described 74 * below. */ 75 int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE, 76 * FD_CLOSE, FD_ACCEPT and FD_CONNECT that 77 * indicate which events are interesting. */ 78 int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE, 79 * FD_CLOSE, FD_ACCEPT and FD_CONNECT that 80 * indicate which events have occurred. */ 81 int selectEvents; /* OR'ed combination of FD_READ, FD_WRITE, 82 * FD_CLOSE, FD_ACCEPT and FD_CONNECT that 83 * indicate which events are currently being 84 * selected. */ 85 int acceptEventCount; /* Count of the current number of FD_ACCEPTs 86 * that have arrived and not yet processed. */ 87 Tcl_TcpAcceptProc *acceptProc; 88 /* Proc to call on accept. */ 89 ClientData acceptProcData; /* The data for the accept proc. */ 90 int lastError; /* Error code from last message. */ 91 struct SocketInfo *nextPtr; /* The next socket on the per-thread socket 92 * list. */ 93} SocketInfo; 94 95/* 96 * The following structure is what is added to the Tcl event queue when a 97 * socket event occurs. 98 */ 99 100typedef struct SocketEvent { 101 Tcl_Event header; /* Information that is standard for all 102 * events. */ 103 SOCKET socket; /* Socket descriptor that is ready. Used to 104 * find the SocketInfo structure for the file 105 * (can't point directly to the SocketInfo 106 * structure because it could go away while 107 * the event is queued). */ 108} SocketEvent; 109 110/* 111 * This defines the minimum buffersize maintained by the kernel. 112 */ 113 114#define TCP_BUFFER_SIZE 4096 115 116/* 117 * The following macros may be used to set the flags field of a SocketInfo 118 * structure. 119 */ 120 121#define SOCKET_ASYNC (1<<0) /* The socket is in blocking mode. */ 122#define SOCKET_EOF (1<<1) /* A zero read happened on the 123 * socket. */ 124#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async connect. */ 125#define SOCKET_PENDING (1<<3) /* A message has been sent for this 126 * socket */ 127 128typedef struct ThreadSpecificData { 129 HWND hwnd; /* Handle to window for socket messages. */ 130 HANDLE socketThread; /* Thread handling the window */ 131 Tcl_ThreadId threadId; /* Parent thread. */ 132 HANDLE readyEvent; /* Event indicating that a socket event is 133 * ready. Also used to indicate that the 134 * socketThread has been initialized and has 135 * started. */ 136 HANDLE socketListLock; /* Win32 Event to lock the socketList */ 137 SocketInfo *socketList; /* Every open socket in this thread has an 138 * entry on this list. */ 139} ThreadSpecificData; 140 141static Tcl_ThreadDataKey dataKey; 142static WNDCLASS windowClass; 143 144/* 145 * Static functions defined in this file. 146 */ 147 148static SocketInfo * CreateSocket(Tcl_Interp *interp, int port, 149 const char *host, int server, const char *myaddr, 150 int myport, int async); 151static int CreateSocketAddress(LPSOCKADDR_IN sockaddrPtr, 152 const char *host, int port); 153static void InitSockets(void); 154static SocketInfo * NewSocketInfo(SOCKET socket); 155static void SocketExitHandler(ClientData clientData); 156static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam, 157 LPARAM lParam); 158static int SocketsEnabled(void); 159static void TcpAccept(SocketInfo *infoPtr); 160static int WaitForSocketEvent(SocketInfo *infoPtr, int events, 161 int *errorCodePtr); 162static DWORD WINAPI SocketThread(LPVOID arg); 163static void TcpThreadActionProc(ClientData instanceData, 164 int action); 165 166static Tcl_EventCheckProc SocketCheckProc; 167static Tcl_EventProc SocketEventProc; 168static Tcl_EventSetupProc SocketSetupProc; 169static Tcl_DriverBlockModeProc TcpBlockProc; 170static Tcl_DriverCloseProc TcpCloseProc; 171static Tcl_DriverSetOptionProc TcpSetOptionProc; 172static Tcl_DriverGetOptionProc TcpGetOptionProc; 173static Tcl_DriverInputProc TcpInputProc; 174static Tcl_DriverOutputProc TcpOutputProc; 175static Tcl_DriverWatchProc TcpWatchProc; 176static Tcl_DriverGetHandleProc TcpGetHandleProc; 177 178/* 179 * This structure describes the channel type structure for TCP socket 180 * based IO. 181 */ 182 183static Tcl_ChannelType tcpChannelType = { 184 "tcp", /* Type name. */ 185 TCL_CHANNEL_VERSION_5, /* v5 channel */ 186 TcpCloseProc, /* Close proc. */ 187 TcpInputProc, /* Input proc. */ 188 TcpOutputProc, /* Output proc. */ 189 NULL, /* Seek proc. */ 190 TcpSetOptionProc, /* Set option proc. */ 191 TcpGetOptionProc, /* Get option proc. */ 192 TcpWatchProc, /* Set up notifier to watch this channel. */ 193 TcpGetHandleProc, /* Get an OS handle from channel. */ 194 NULL, /* close2proc. */ 195 TcpBlockProc, /* Set socket into (non-)blocking mode. */ 196 NULL, /* flush proc. */ 197 NULL, /* handler proc. */ 198 NULL, /* wide seek proc */ 199 TcpThreadActionProc, /* thread action proc */ 200 NULL, /* truncate */ 201}; 202 203/* 204 *---------------------------------------------------------------------- 205 * 206 * InitSockets -- 207 * 208 * Initialize the socket module. If winsock startup is successful, 209 * registers the event window for the socket notifier code. 210 * 211 * Assumes socketMutex is held. 212 * 213 * Results: 214 * None. 215 * 216 * Side effects: 217 * Initializes winsock, registers a new window class and creates a 218 * window for use in asynchronous socket notification. 219 * 220 *---------------------------------------------------------------------- 221 */ 222 223static void 224InitSockets(void) 225{ 226 DWORD id; 227 WSADATA wsaData; 228 DWORD err; 229 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 230 TclThreadDataKeyGet(&dataKey); 231 232 if (!initialized) { 233 initialized = 1; 234 TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL); 235 236 /* 237 * Create the async notification window with a new class. We must 238 * create a new class to avoid a Windows 95 bug that causes us to get 239 * the wrong message number for socket events if the message window is 240 * a subclass of a static control. 241 */ 242 243 windowClass.style = 0; 244 windowClass.cbClsExtra = 0; 245 windowClass.cbWndExtra = 0; 246 windowClass.hInstance = TclWinGetTclInstance(); 247 windowClass.hbrBackground = NULL; 248 windowClass.lpszMenuName = NULL; 249 windowClass.lpszClassName = "TclSocket"; 250 windowClass.lpfnWndProc = SocketProc; 251 windowClass.hIcon = NULL; 252 windowClass.hCursor = NULL; 253 254 if (!RegisterClassA(&windowClass)) { 255 TclWinConvertError(GetLastError()); 256 goto initFailure; 257 } 258 259 /* 260 * Initialize the winsock library and check the interface version 261 * actually loaded. We only ask for the 1.1 interface and do require 262 * that it not be less than 1.1. 263 */ 264 265#define WSA_VERSION_MAJOR 1 266#define WSA_VERSION_MINOR 1 267#define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR) 268 269 err = WSAStartup((WORD)WSA_VERSION_REQD, &wsaData); 270 if (err != 0) { 271 TclWinConvertWSAError(err); 272 goto initFailure; 273 } 274 275 /* 276 * Note the byte positions are swapped for the comparison, so that 277 * 0x0002 (2.0, MAKEWORD(2,0)) doesn't look less than 0x0101 (1.1). 278 * We want the comparison to be 0x0200 < 0x0101. 279 */ 280 281 if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion)) 282 < MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) { 283 TclWinConvertWSAError(WSAVERNOTSUPPORTED); 284 WSACleanup(); 285 goto initFailure; 286 } 287 288#undef WSA_VERSION_REQD 289#undef WSA_VERSION_MAJOR 290#undef WSA_VERSION_MINOR 291 } 292 293 /* 294 * Check for per-thread initialization. 295 */ 296 297 if (tsdPtr == NULL) { 298 tsdPtr = TCL_TSD_INIT(&dataKey); 299 tsdPtr->socketList = NULL; 300 tsdPtr->hwnd = NULL; 301 tsdPtr->threadId = Tcl_GetCurrentThread(); 302 tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 303 if (tsdPtr->readyEvent == NULL) { 304 goto initFailure; 305 } 306 tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL); 307 if (tsdPtr->socketListLock == NULL) { 308 goto initFailure; 309 } 310 tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 311 0, &id); 312 if (tsdPtr->socketThread == NULL) { 313 goto initFailure; 314 } 315 316 SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); 317 318 /* 319 * Wait for the thread to signal when the window has been created and 320 * if it is ready to go. 321 */ 322 323 WaitForSingleObject(tsdPtr->readyEvent, INFINITE); 324 325 if (tsdPtr->hwnd == NULL) { 326 goto initFailure; /* Trouble creating the window */ 327 } 328 329 Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); 330 } 331 return; 332 333 initFailure: 334 TclpFinalizeSockets(); 335 initialized = -1; 336 return; 337} 338 339/* 340 *---------------------------------------------------------------------- 341 * 342 * SocketsEnabled -- 343 * 344 * Check that the WinSock was successfully initialized. 345 * 346 * Results: 347 * 1 if it is. 348 * 349 * Side effects: 350 * None. 351 * 352 *---------------------------------------------------------------------- 353 */ 354 355 /* ARGSUSED */ 356static int 357SocketsEnabled(void) 358{ 359 int enabled; 360 Tcl_MutexLock(&socketMutex); 361 enabled = (initialized == 1); 362 Tcl_MutexUnlock(&socketMutex); 363 return enabled; 364} 365 366 367/* 368 *---------------------------------------------------------------------- 369 * 370 * SocketExitHandler -- 371 * 372 * Callback invoked during exit clean up to delete the socket 373 * communication window and to release the WinSock DLL. 374 * 375 * Results: 376 * None. 377 * 378 * Side effects: 379 * None. 380 * 381 *---------------------------------------------------------------------- 382 */ 383 384 /* ARGSUSED */ 385static void 386SocketExitHandler( 387 ClientData clientData) /* Not used. */ 388{ 389 Tcl_MutexLock(&socketMutex); 390 /* 391 * Make sure the socket event handling window is cleaned-up for, at 392 * most, this thread. 393 */ 394 395 TclpFinalizeSockets(); 396 UnregisterClass("TclSocket", TclWinGetTclInstance()); 397 WSACleanup(); 398 initialized = 0; 399 Tcl_MutexUnlock(&socketMutex); 400} 401 402/* 403 *---------------------------------------------------------------------- 404 * 405 * TclpFinalizeSockets -- 406 * 407 * This function is called from Tcl_FinalizeThread to finalize the 408 * platform specific socket subsystem. Also, it may be called from within 409 * this module to cleanup the state if unable to initialize the sockets 410 * subsystem. 411 * 412 * Results: 413 * None. 414 * 415 * Side effects: 416 * Deletes the event source and destroys the socket thread. 417 * 418 *---------------------------------------------------------------------- 419 */ 420 421void 422TclpFinalizeSockets(void) 423{ 424 ThreadSpecificData *tsdPtr; 425 426 tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); 427 if (tsdPtr != NULL) { 428 if (tsdPtr->socketThread != NULL) { 429 if (tsdPtr->hwnd != NULL) { 430 PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0); 431 432 /* 433 * Wait for the thread to exit. This ensures that we are 434 * completely cleaned up before we leave this function. 435 */ 436 437 WaitForSingleObject(tsdPtr->readyEvent, INFINITE); 438 tsdPtr->hwnd = NULL; 439 } 440 CloseHandle(tsdPtr->socketThread); 441 tsdPtr->socketThread = NULL; 442 } 443 if (tsdPtr->readyEvent != NULL) { 444 CloseHandle(tsdPtr->readyEvent); 445 tsdPtr->readyEvent = NULL; 446 } 447 if (tsdPtr->socketListLock != NULL) { 448 CloseHandle(tsdPtr->socketListLock); 449 tsdPtr->socketListLock = NULL; 450 } 451 Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); 452 } 453} 454 455/* 456 *---------------------------------------------------------------------- 457 * 458 * TclpHasSockets -- 459 * 460 * This function determines whether sockets are available on the current 461 * system and returns an error in interp if they are not. Note that 462 * interp may be NULL. 463 * 464 * Results: 465 * Returns TCL_OK if the system supports sockets, or TCL_ERROR with an 466 * error in interp (if non-NULL). 467 * 468 * Side effects: 469 * If not already prepared, initializes the TSD structure and socket 470 * message handling thread associated to the calling thread for the 471 * subsystem of the driver. 472 * 473 *---------------------------------------------------------------------- 474 */ 475 476int 477TclpHasSockets( 478 Tcl_Interp *interp) /* Where to write an error message if sockets 479 * are not present, or NULL if no such message 480 * is to be written. */ 481{ 482 Tcl_MutexLock(&socketMutex); 483 InitSockets(); 484 Tcl_MutexUnlock(&socketMutex); 485 486 if (SocketsEnabled()) { 487 return TCL_OK; 488 } 489 if (interp != NULL) { 490 Tcl_AppendResult(interp, "sockets are not available on this system", 491 NULL); 492 } 493 return TCL_ERROR; 494} 495 496/* 497 *---------------------------------------------------------------------- 498 * 499 * SocketSetupProc -- 500 * 501 * This function is invoked before Tcl_DoOneEvent blocks waiting for an 502 * event. 503 * 504 * Results: 505 * None. 506 * 507 * Side effects: 508 * Adjusts the block time if needed. 509 * 510 *---------------------------------------------------------------------- 511 */ 512 513void 514SocketSetupProc( 515 ClientData data, /* Not used. */ 516 int flags) /* Event flags as passed to Tcl_DoOneEvent. */ 517{ 518 SocketInfo *infoPtr; 519 Tcl_Time blockTime = { 0, 0 }; 520 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 521 522 if (!(flags & TCL_FILE_EVENTS)) { 523 return; 524 } 525 526 /* 527 * Check to see if there is a ready socket. If so, poll. 528 */ 529 530 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 531 for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 532 infoPtr = infoPtr->nextPtr) { 533 if (infoPtr->readyEvents & infoPtr->watchEvents) { 534 Tcl_SetMaxBlockTime(&blockTime); 535 break; 536 } 537 } 538 SetEvent(tsdPtr->socketListLock); 539} 540 541/* 542 *---------------------------------------------------------------------- 543 * 544 * SocketCheckProc -- 545 * 546 * This function is called by Tcl_DoOneEvent to check the socket event 547 * source for events. 548 * 549 * Results: 550 * None. 551 * 552 * Side effects: 553 * May queue an event. 554 * 555 *---------------------------------------------------------------------- 556 */ 557 558static void 559SocketCheckProc( 560 ClientData data, /* Not used. */ 561 int flags) /* Event flags as passed to Tcl_DoOneEvent. */ 562{ 563 SocketInfo *infoPtr; 564 SocketEvent *evPtr; 565 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 566 567 if (!(flags & TCL_FILE_EVENTS)) { 568 return; 569 } 570 571 /* 572 * Queue events for any ready sockets that don't already have events 573 * queued (caused by persistent states that won't generate WinSock 574 * events). 575 */ 576 577 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 578 for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 579 infoPtr = infoPtr->nextPtr) { 580 if ((infoPtr->readyEvents & infoPtr->watchEvents) 581 && !(infoPtr->flags & SOCKET_PENDING)) { 582 infoPtr->flags |= SOCKET_PENDING; 583 evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent)); 584 evPtr->header.proc = SocketEventProc; 585 evPtr->socket = infoPtr->socket; 586 Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); 587 } 588 } 589 SetEvent(tsdPtr->socketListLock); 590} 591 592/* 593 *---------------------------------------------------------------------- 594 * 595 * SocketEventProc -- 596 * 597 * This function is called by Tcl_ServiceEvent when a socket event 598 * reaches the front of the event queue. This function is responsible for 599 * notifying the generic channel code. 600 * 601 * Results: 602 * Returns 1 if the event was handled, meaning it should be removed from 603 * the queue. Returns 0 if the event was not handled, meaning it should 604 * stay on the queue. The only time the event isn't handled is if the 605 * TCL_FILE_EVENTS flag bit isn't set. 606 * 607 * Side effects: 608 * Whatever the channel callback functions do. 609 * 610 *---------------------------------------------------------------------- 611 */ 612 613static int 614SocketEventProc( 615 Tcl_Event *evPtr, /* Event to service. */ 616 int flags) /* Flags that indicate what events to handle, 617 * such as TCL_FILE_EVENTS. */ 618{ 619 SocketInfo *infoPtr; 620 SocketEvent *eventPtr = (SocketEvent *) evPtr; 621 int mask = 0; 622 int events; 623 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 624 625 if (!(flags & TCL_FILE_EVENTS)) { 626 return 0; 627 } 628 629 /* 630 * Find the specified socket on the socket list. 631 */ 632 633 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 634 for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 635 infoPtr = infoPtr->nextPtr) { 636 if (infoPtr->socket == eventPtr->socket) { 637 break; 638 } 639 } 640 SetEvent(tsdPtr->socketListLock); 641 642 /* 643 * Discard events that have gone stale. 644 */ 645 646 if (!infoPtr) { 647 return 1; 648 } 649 650 infoPtr->flags &= ~SOCKET_PENDING; 651 652 /* 653 * Handle connection requests directly. 654 */ 655 656 if (infoPtr->readyEvents & FD_ACCEPT) { 657 TcpAccept(infoPtr); 658 return 1; 659 } 660 661 /* 662 * Mask off unwanted events and compute the read/write mask so we can 663 * notify the channel. 664 */ 665 666 events = infoPtr->readyEvents & infoPtr->watchEvents; 667 668 if (events & FD_CLOSE) { 669 /* 670 * If the socket was closed and the channel is still interested in 671 * read events, then we need to ensure that we keep polling for this 672 * event until someone does something with the channel. Note that we 673 * do this before calling Tcl_NotifyChannel so we don't have to watch 674 * out for the channel being deleted out from under us. This may cause 675 * a redundant trip through the event loop, but it's simpler than 676 * trying to do unwind protection. 677 */ 678 679 Tcl_Time blockTime = { 0, 0 }; 680 Tcl_SetMaxBlockTime(&blockTime); 681 mask |= TCL_READABLE|TCL_WRITABLE; 682 } else if (events & FD_READ) { 683 fd_set readFds; 684 struct timeval timeout; 685 686 /* 687 * We must check to see if data is really available, since someone 688 * could have consumed the data in the meantime. Turn off async 689 * notification so select will work correctly. If the socket is still 690 * readable, notify the channel driver, otherwise reset the async 691 * select handler and keep waiting. 692 */ 693 694 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 695 (WPARAM) UNSELECT, (LPARAM) infoPtr); 696 697 FD_ZERO(&readFds); 698 FD_SET(infoPtr->socket, &readFds); 699 timeout.tv_usec = 0; 700 timeout.tv_sec = 0; 701 702 if (select(0, &readFds, NULL, NULL, &timeout) != 0) { 703 mask |= TCL_READABLE; 704 } else { 705 infoPtr->readyEvents &= ~(FD_READ); 706 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 707 (WPARAM) SELECT, (LPARAM) infoPtr); 708 } 709 } 710 if (events & (FD_WRITE | FD_CONNECT)) { 711 mask |= TCL_WRITABLE; 712 if (events & FD_CONNECT && infoPtr->lastError != NO_ERROR) { 713 /* 714 * Connect errors should also fire the readable handler. 715 */ 716 717 mask |= TCL_READABLE; 718 } 719 } 720 721 if (mask) { 722 Tcl_NotifyChannel(infoPtr->channel, mask); 723 } 724 return 1; 725} 726 727/* 728 *---------------------------------------------------------------------- 729 * 730 * TcpBlockProc -- 731 * 732 * Sets a socket into blocking or non-blocking mode. 733 * 734 * Results: 735 * 0 if successful, errno if there was an error. 736 * 737 * Side effects: 738 * None. 739 * 740 *---------------------------------------------------------------------- 741 */ 742 743static int 744TcpBlockProc( 745 ClientData instanceData, /* The socket to block/un-block. */ 746 int mode) /* TCL_MODE_BLOCKING or 747 * TCL_MODE_NONBLOCKING. */ 748{ 749 SocketInfo *infoPtr = (SocketInfo *) instanceData; 750 751 if (mode == TCL_MODE_NONBLOCKING) { 752 infoPtr->flags |= SOCKET_ASYNC; 753 } else { 754 infoPtr->flags &= ~(SOCKET_ASYNC); 755 } 756 return 0; 757} 758 759/* 760 *---------------------------------------------------------------------- 761 * 762 * TcpCloseProc -- 763 * 764 * This function is called by the generic IO level to perform channel 765 * type specific cleanup on a socket based channel when the channel is 766 * closed. 767 * 768 * Results: 769 * 0 if successful, the value of errno if failed. 770 * 771 * Side effects: 772 * Closes the socket. 773 * 774 *---------------------------------------------------------------------- 775 */ 776 777 /* ARGSUSED */ 778static int 779TcpCloseProc( 780 ClientData instanceData, /* The socket to close. */ 781 Tcl_Interp *interp) /* Unused. */ 782{ 783 SocketInfo *infoPtr = (SocketInfo *) instanceData; 784 /* TIP #218 */ 785 int errorCode = 0; 786 /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */ 787 788 /* 789 * Check that WinSock is initialized; do not call it if not, to prevent 790 * system crashes. This can happen at exit time if the exit handler for 791 * WinSock ran before other exit handlers that want to use sockets. 792 */ 793 794 if (SocketsEnabled()) { 795 /* 796 * Clean up the OS socket handle. The default Windows setting for a 797 * socket is SO_DONTLINGER, which does a graceful shutdown in the 798 * background. 799 */ 800 801 if (closesocket(infoPtr->socket) == SOCKET_ERROR) { 802 TclWinConvertWSAError((DWORD) WSAGetLastError()); 803 errorCode = Tcl_GetErrno(); 804 } 805 } 806 807 /* 808 * TIP #218. Removed the code removing the structure from the global 809 * socket list. This is now done by the thread action callbacks, and only 810 * there. This happens before this code is called. We can free without 811 * fear of damaging the list. 812 */ 813 814 ckfree((char *) infoPtr); 815 return errorCode; 816} 817 818/* 819 *---------------------------------------------------------------------- 820 * 821 * NewSocketInfo -- 822 * 823 * This function allocates and initializes a new SocketInfo structure. 824 * 825 * Results: 826 * Returns a newly allocated SocketInfo. 827 * 828 * Side effects: 829 * None, except for allocation of memory. 830 * 831 *---------------------------------------------------------------------- 832 */ 833 834static SocketInfo * 835NewSocketInfo( 836 SOCKET socket) 837{ 838 SocketInfo *infoPtr; 839 /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */ 840 841 infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo)); 842 infoPtr->channel = 0; 843 infoPtr->socket = socket; 844 infoPtr->flags = 0; 845 infoPtr->watchEvents = 0; 846 infoPtr->readyEvents = 0; 847 infoPtr->selectEvents = 0; 848 infoPtr->acceptEventCount = 0; 849 infoPtr->acceptProc = NULL; 850 infoPtr->acceptProcData = NULL; 851 infoPtr->lastError = 0; 852 853 /* 854 * TIP #218. Removed the code inserting the new structure into the global 855 * list. This is now handled in the thread action callbacks, and only 856 * there. 857 */ 858 859 infoPtr->nextPtr = NULL; 860 861 return infoPtr; 862} 863 864/* 865 *---------------------------------------------------------------------- 866 * 867 * CreateSocket -- 868 * 869 * This function opens a new socket and initializes the SocketInfo 870 * structure. 871 * 872 * Results: 873 * Returns a new SocketInfo, or NULL with an error in interp. 874 * 875 * Side effects: 876 * None, except for allocation of memory. 877 * 878 *---------------------------------------------------------------------- 879 */ 880 881static SocketInfo * 882CreateSocket( 883 Tcl_Interp *interp, /* For error reporting; can be NULL. */ 884 int port, /* Port number to open. */ 885 const char *host, /* Name of host on which to open port. */ 886 int server, /* 1 if socket should be a server socket, else 887 * 0 for a client socket. */ 888 const char *myaddr, /* Optional client-side address */ 889 int myport, /* Optional client-side port */ 890 int async) /* If nonzero, connect client socket 891 * asynchronously. */ 892{ 893 u_long flag = 1; /* Indicates nonblocking mode. */ 894 int asyncConnect = 0; /* Will be 1 if async connect is in 895 * progress. */ 896 SOCKADDR_IN sockaddr; /* Socket address */ 897 SOCKADDR_IN mysockaddr; /* Socket address for client */ 898 SOCKET sock = INVALID_SOCKET; 899 SocketInfo *infoPtr; /* The returned value. */ 900 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 901 TclThreadDataKeyGet(&dataKey); 902 903 /* 904 * Check that WinSock is initialized; do not call it if not, to prevent 905 * system crashes. This can happen at exit time if the exit handler for 906 * WinSock ran before other exit handlers that want to use sockets. 907 */ 908 909 if (!SocketsEnabled()) { 910 return NULL; 911 } 912 913 if (!CreateSocketAddress(&sockaddr, host, port)) { 914 goto error; 915 } 916 if ((myaddr != NULL || myport != 0) && 917 !CreateSocketAddress(&mysockaddr, myaddr, myport)) { 918 goto error; 919 } 920 921 sock = socket(AF_INET, SOCK_STREAM, 0); 922 if (sock == INVALID_SOCKET) { 923 goto error; 924 } 925 926 /* 927 * Win-NT has a misfeature that sockets are inherited in child processes 928 * by default. Turn off the inherit bit. 929 */ 930 931 SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); 932 933 /* 934 * Set kernel space buffering 935 */ 936 937 TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE); 938 939 if (server) { 940 /* 941 * Bind to the specified port. Note that we must not call setsockopt 942 * with SO_REUSEADDR because Microsoft allows addresses to be reused 943 * even if they are still in use. 944 * 945 * Bind should not be affected by the socket having already been set 946 * into nonblocking mode. If there is trouble, this is one place to 947 * look for bugs. 948 */ 949 950 if (bind(sock, (SOCKADDR *) &sockaddr, sizeof(SOCKADDR_IN)) 951 == SOCKET_ERROR) { 952 goto error; 953 } 954 955 /* 956 * Set the maximum number of pending connect requests to the max value 957 * allowed on each platform (Win32 and Win32s may be different, and 958 * there may be differences between TCP/IP stacks). 959 */ 960 961 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { 962 goto error; 963 } 964 965 /* 966 * Add this socket to the global list of sockets. 967 */ 968 969 infoPtr = NewSocketInfo(sock); 970 971 /* 972 * Set up the select mask for connection request events. 973 */ 974 975 infoPtr->selectEvents = FD_ACCEPT; 976 infoPtr->watchEvents |= FD_ACCEPT; 977 978 } else { 979 /* 980 * Try to bind to a local port, if specified. 981 */ 982 983 if (myaddr != NULL || myport != 0) { 984 if (bind(sock, (SOCKADDR *) &mysockaddr, sizeof(SOCKADDR_IN)) 985 == SOCKET_ERROR) { 986 goto error; 987 } 988 } 989 990 /* 991 * Set the socket into nonblocking mode if the connect should be done 992 * in the background. 993 */ 994 995 if (async) { 996 if (ioctlsocket(sock, (long) FIONBIO, &flag) == SOCKET_ERROR) { 997 goto error; 998 } 999 } 1000 1001 /* 1002 * Attempt to connect to the remote socket. 1003 */ 1004 1005 if (connect(sock, (SOCKADDR *) &sockaddr, 1006 sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { 1007 TclWinConvertWSAError((DWORD) WSAGetLastError()); 1008 if (Tcl_GetErrno() != EWOULDBLOCK) { 1009 goto error; 1010 } 1011 1012 /* 1013 * The connection is progressing in the background. 1014 */ 1015 1016 asyncConnect = 1; 1017 } 1018 1019 /* 1020 * Add this socket to the global list of sockets. 1021 */ 1022 1023 infoPtr = NewSocketInfo(sock); 1024 1025 /* 1026 * Set up the select mask for read/write events. If the connect 1027 * attempt has not completed, include connect events. 1028 */ 1029 1030 infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE; 1031 if (asyncConnect) { 1032 infoPtr->flags |= SOCKET_ASYNC_CONNECT; 1033 infoPtr->selectEvents |= FD_CONNECT; 1034 } 1035 } 1036 1037 /* 1038 * Register for interest in events in the select mask. Note that this 1039 * automatically places the socket into non-blocking mode. 1040 */ 1041 1042 ioctlsocket(sock, (long) FIONBIO, &flag); 1043 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); 1044 1045 return infoPtr; 1046 1047 error: 1048 TclWinConvertWSAError((DWORD) WSAGetLastError()); 1049 if (interp != NULL) { 1050 Tcl_AppendResult(interp, "couldn't open socket: ", 1051 Tcl_PosixError(interp), NULL); 1052 } 1053 if (sock != INVALID_SOCKET) { 1054 closesocket(sock); 1055 } 1056 return NULL; 1057} 1058 1059/* 1060 *---------------------------------------------------------------------- 1061 * 1062 * CreateSocketAddress -- 1063 * 1064 * This function initializes a sockaddr structure for a host and port. 1065 * 1066 * Results: 1067 * 1 if the host was valid, 0 if the host could not be converted to an IP 1068 * address. 1069 * 1070 * Side effects: 1071 * Fills in the *sockaddrPtr structure. 1072 * 1073 *---------------------------------------------------------------------- 1074 */ 1075 1076static int 1077CreateSocketAddress( 1078 LPSOCKADDR_IN sockaddrPtr, /* Socket address */ 1079 const char *host, /* Host. NULL implies INADDR_ANY */ 1080 int port) /* Port number */ 1081{ 1082 struct hostent *hostent; /* Host database entry */ 1083 struct in_addr addr; /* For 64/32 bit madness */ 1084 1085 /* 1086 * Check that WinSock is initialized; do not call it if not, to prevent 1087 * system crashes. This can happen at exit time if the exit handler for 1088 * WinSock ran before other exit handlers that want to use sockets. 1089 */ 1090 1091 if (!SocketsEnabled()) { 1092 Tcl_SetErrno(EFAULT); 1093 return 0; 1094 } 1095 1096 ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN)); 1097 sockaddrPtr->sin_family = AF_INET; 1098 sockaddrPtr->sin_port = htons((u_short) (port & 0xFFFF)); 1099 if (host == NULL) { 1100 addr.s_addr = INADDR_ANY; 1101 } else { 1102 addr.s_addr = inet_addr(host); 1103 if (addr.s_addr == INADDR_NONE) { 1104 hostent = gethostbyname(host); 1105 if (hostent != NULL) { 1106 memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length); 1107 } else { 1108#ifdef EHOSTUNREACH 1109 Tcl_SetErrno(EHOSTUNREACH); 1110#else 1111#ifdef ENXIO 1112 Tcl_SetErrno(ENXIO); 1113#endif 1114#endif 1115 return 0; /* Error. */ 1116 } 1117 } 1118 } 1119 1120 /* 1121 * NOTE: On 64 bit machines the assignment below is rumored to not do the 1122 * right thing. Please report errors related to this if you observe 1123 * incorrect behavior on 64 bit machines such as DEC Alphas. Should we 1124 * modify this code to do an explicit memcpy? 1125 */ 1126 1127 sockaddrPtr->sin_addr.s_addr = addr.s_addr; 1128 return 1; /* Success. */ 1129} 1130 1131/* 1132 *---------------------------------------------------------------------- 1133 * 1134 * WaitForSocketEvent -- 1135 * 1136 * Waits until one of the specified events occurs on a socket. 1137 * 1138 * Results: 1139 * Returns 1 on success or 0 on failure, with an error code in 1140 * errorCodePtr. 1141 * 1142 * Side effects: 1143 * Processes socket events off the system queue. 1144 * 1145 *---------------------------------------------------------------------- 1146 */ 1147 1148static int 1149WaitForSocketEvent( 1150 SocketInfo *infoPtr, /* Information about this socket. */ 1151 int events, /* Events to look for. */ 1152 int *errorCodePtr) /* Where to store errors? */ 1153{ 1154 int result = 1; 1155 int oldMode; 1156 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1157 TclThreadDataKeyGet(&dataKey); 1158 1159 /* 1160 * Be sure to disable event servicing so we are truly modal. 1161 */ 1162 1163 oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); 1164 1165 /* 1166 * Reset WSAAsyncSelect so we have a fresh set of events pending. 1167 */ 1168 1169 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, 1170 (LPARAM) infoPtr); 1171 1172 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, 1173 (LPARAM) infoPtr); 1174 1175 while (1) { 1176 if (infoPtr->lastError) { 1177 *errorCodePtr = infoPtr->lastError; 1178 result = 0; 1179 break; 1180 } else if (infoPtr->readyEvents & events) { 1181 break; 1182 } else if (infoPtr->flags & SOCKET_ASYNC) { 1183 *errorCodePtr = EWOULDBLOCK; 1184 result = 0; 1185 break; 1186 } 1187 1188 /* 1189 * Wait until something happens. 1190 */ 1191 1192 WaitForSingleObject(tsdPtr->readyEvent, INFINITE); 1193 } 1194 1195 (void) Tcl_SetServiceMode(oldMode); 1196 return result; 1197} 1198 1199/* 1200 *---------------------------------------------------------------------- 1201 * 1202 * Tcl_OpenTcpClient -- 1203 * 1204 * Opens a TCP client socket and creates a channel around it. 1205 * 1206 * Results: 1207 * The channel or NULL if failed. An error message is returned in the 1208 * interpreter on failure. 1209 * 1210 * Side effects: 1211 * Opens a client socket and creates a new channel. 1212 * 1213 *---------------------------------------------------------------------- 1214 */ 1215 1216Tcl_Channel 1217Tcl_OpenTcpClient( 1218 Tcl_Interp *interp, /* For error reporting; can be NULL. */ 1219 int port, /* Port number to open. */ 1220 const char *host, /* Host on which to open port. */ 1221 const char *myaddr, /* Client-side address */ 1222 int myport, /* Client-side port */ 1223 int async) /* If nonzero, should connect client socket 1224 * asynchronously. */ 1225{ 1226 SocketInfo *infoPtr; 1227 char channelName[16 + TCL_INTEGER_SPACE]; 1228 1229 if (TclpHasSockets(interp) != TCL_OK) { 1230 return NULL; 1231 } 1232 1233 /* 1234 * Create a new client socket and wrap it in a channel. 1235 */ 1236 1237 infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); 1238 if (infoPtr == NULL) { 1239 return NULL; 1240 } 1241 1242 wsprintfA(channelName, "sock%d", infoPtr->socket); 1243 1244 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 1245 (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); 1246 if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation", 1247 "auto crlf") == TCL_ERROR) { 1248 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); 1249 return (Tcl_Channel) NULL; 1250 } 1251 if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "") 1252 == TCL_ERROR) { 1253 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); 1254 return (Tcl_Channel) NULL; 1255 } 1256 return infoPtr->channel; 1257} 1258 1259/* 1260 *---------------------------------------------------------------------- 1261 * 1262 * Tcl_MakeTcpClientChannel -- 1263 * 1264 * Creates a Tcl_Channel from an existing client TCP socket. 1265 * 1266 * Results: 1267 * The Tcl_Channel wrapped around the preexisting TCP socket. 1268 * 1269 * Side effects: 1270 * None. 1271 * 1272 * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com) 1273 * 1274 *---------------------------------------------------------------------- 1275 */ 1276 1277Tcl_Channel 1278Tcl_MakeTcpClientChannel( 1279 ClientData sock) /* The socket to wrap up into a channel. */ 1280{ 1281 SocketInfo *infoPtr; 1282 char channelName[16 + TCL_INTEGER_SPACE]; 1283 ThreadSpecificData *tsdPtr; 1284 1285 if (TclpHasSockets(NULL) != TCL_OK) { 1286 return NULL; 1287 } 1288 1289 tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 1290 1291 /* 1292 * Set kernel space buffering and non-blocking. 1293 */ 1294 1295 TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE); 1296 1297 infoPtr = NewSocketInfo((SOCKET) sock); 1298 1299 /* 1300 * Start watching for read/write events on the socket. 1301 */ 1302 1303 infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; 1304 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1305 (WPARAM) SELECT, (LPARAM) infoPtr); 1306 1307 wsprintfA(channelName, "sock%d", infoPtr->socket); 1308 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 1309 (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); 1310 Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf"); 1311 return infoPtr->channel; 1312} 1313 1314/* 1315 *---------------------------------------------------------------------- 1316 * 1317 * Tcl_OpenTcpServer -- 1318 * 1319 * Opens a TCP server socket and creates a channel around it. 1320 * 1321 * Results: 1322 * The channel or NULL if failed. An error message is returned in the 1323 * interpreter on failure. 1324 * 1325 * Side effects: 1326 * Opens a server socket and creates a new channel. 1327 * 1328 *---------------------------------------------------------------------- 1329 */ 1330 1331Tcl_Channel 1332Tcl_OpenTcpServer( 1333 Tcl_Interp *interp, /* For error reporting - may be NULL. */ 1334 int port, /* Port number to open. */ 1335 const char *host, /* Name of local host. */ 1336 Tcl_TcpAcceptProc *acceptProc, 1337 /* Callback for accepting connections from new 1338 * clients. */ 1339 ClientData acceptProcData) /* Data for the callback. */ 1340{ 1341 SocketInfo *infoPtr; 1342 char channelName[16 + TCL_INTEGER_SPACE]; 1343 1344 if (TclpHasSockets(interp) != TCL_OK) { 1345 return NULL; 1346 } 1347 1348 /* 1349 * Create a new client socket and wrap it in a channel. 1350 */ 1351 1352 infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0); 1353 if (infoPtr == NULL) { 1354 return NULL; 1355 } 1356 1357 infoPtr->acceptProc = acceptProc; 1358 infoPtr->acceptProcData = acceptProcData; 1359 1360 wsprintfA(channelName, "sock%d", infoPtr->socket); 1361 1362 infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 1363 (ClientData) infoPtr, 0); 1364 if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") 1365 == TCL_ERROR) { 1366 Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); 1367 return (Tcl_Channel) NULL; 1368 } 1369 1370 return infoPtr->channel; 1371} 1372 1373/* 1374 *---------------------------------------------------------------------- 1375 * 1376 * TcpAccept -- 1377 * 1378 * Accept a TCP socket connection. This is called by SocketEventProc and 1379 * it in turns calls the registered accept function. 1380 * 1381 * Results: 1382 * None. 1383 * 1384 * Side effects: 1385 * Invokes the accept proc which may invoke arbitrary Tcl code. 1386 * 1387 *---------------------------------------------------------------------- 1388 */ 1389 1390static void 1391TcpAccept( 1392 SocketInfo *infoPtr) /* Socket to accept. */ 1393{ 1394 SOCKET newSocket; 1395 SocketInfo *newInfoPtr; 1396 SOCKADDR_IN addr; 1397 int len; 1398 char channelName[16 + TCL_INTEGER_SPACE]; 1399 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1400 TclThreadDataKeyGet(&dataKey); 1401 1402 /* 1403 * Accept the incoming connection request. 1404 */ 1405 1406 len = sizeof(SOCKADDR_IN); 1407 1408 newSocket = accept(infoPtr->socket, (SOCKADDR *)&addr, 1409 &len); 1410 1411 /* 1412 * Clear the ready mask so we can detect the next connection request. Note 1413 * that connection requests are level triggered, so if there is a request 1414 * already pending, a new event will be generated. 1415 */ 1416 1417 if (newSocket == INVALID_SOCKET) { 1418 infoPtr->acceptEventCount = 0; 1419 infoPtr->readyEvents &= ~(FD_ACCEPT); 1420 return; 1421 } 1422 1423 /* 1424 * It is possible that more than one FD_ACCEPT has been sent, so an extra 1425 * count must be kept. Decrement the count, and reset the readyEvent bit 1426 * if the count is no longer > 0. 1427 */ 1428 1429 infoPtr->acceptEventCount--; 1430 1431 if (infoPtr->acceptEventCount <= 0) { 1432 infoPtr->readyEvents &= ~(FD_ACCEPT); 1433 } 1434 1435 /* 1436 * Win-NT has a misfeature that sockets are inherited in child processes 1437 * by default. Turn off the inherit bit. 1438 */ 1439 1440 SetHandleInformation((HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0); 1441 1442 /* 1443 * Add this socket to the global list of sockets. 1444 */ 1445 1446 newInfoPtr = NewSocketInfo(newSocket); 1447 1448 /* 1449 * Select on read/write events and create the channel. 1450 */ 1451 1452 newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); 1453 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1454 (WPARAM) SELECT, (LPARAM) newInfoPtr); 1455 1456 wsprintfA(channelName, "sock%d", newInfoPtr->socket); 1457 newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 1458 (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); 1459 if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation", 1460 "auto crlf") == TCL_ERROR) { 1461 Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); 1462 return; 1463 } 1464 if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "") 1465 == TCL_ERROR) { 1466 Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); 1467 return; 1468 } 1469 1470 /* 1471 * Invoke the accept callback function. 1472 */ 1473 1474 if (infoPtr->acceptProc != NULL) { 1475 (infoPtr->acceptProc) (infoPtr->acceptProcData, newInfoPtr->channel, 1476 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 1477 } 1478} 1479 1480/* 1481 *---------------------------------------------------------------------- 1482 * 1483 * TcpInputProc -- 1484 * 1485 * This function is called by the generic IO level to read data from a 1486 * socket based channel. 1487 * 1488 * Results: 1489 * The number of bytes read or -1 on error. 1490 * 1491 * Side effects: 1492 * Consumes input from the socket. 1493 * 1494 *---------------------------------------------------------------------- 1495 */ 1496 1497static int 1498TcpInputProc( 1499 ClientData instanceData, /* The socket state. */ 1500 char *buf, /* Where to store data. */ 1501 int toRead, /* Maximum number of bytes to read. */ 1502 int *errorCodePtr) /* Where to store error codes. */ 1503{ 1504 SocketInfo *infoPtr = (SocketInfo *) instanceData; 1505 int bytesRead; 1506 DWORD error; 1507 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1508 TclThreadDataKeyGet(&dataKey); 1509 1510 *errorCodePtr = 0; 1511 1512 /* 1513 * Check that WinSock is initialized; do not call it if not, to prevent 1514 * system crashes. This can happen at exit time if the exit handler for 1515 * WinSock ran before other exit handlers that want to use sockets. 1516 */ 1517 1518 if (!SocketsEnabled()) { 1519 *errorCodePtr = EFAULT; 1520 return -1; 1521 } 1522 1523 /* 1524 * First check to see if EOF was already detected, to prevent calling the 1525 * socket stack after the first time EOF is detected. 1526 */ 1527 1528 if (infoPtr->flags & SOCKET_EOF) { 1529 return 0; 1530 } 1531 1532 /* 1533 * Check to see if the socket is connected before trying to read. 1534 */ 1535 1536 if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) 1537 && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { 1538 return -1; 1539 } 1540 1541 /* 1542 * No EOF, and it is connected, so try to read more from the socket. Note 1543 * that we clear the FD_READ bit because read events are level triggered 1544 * so a new event will be generated if there is still data available to be 1545 * read. We have to simulate blocking behavior here since we are always 1546 * using non-blocking sockets. 1547 */ 1548 1549 while (1) { 1550 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1551 (WPARAM) UNSELECT, (LPARAM) infoPtr); 1552 bytesRead = recv(infoPtr->socket, buf, toRead, 0); 1553 infoPtr->readyEvents &= ~(FD_READ); 1554 1555 /* 1556 * Check for end-of-file condition or successful read. 1557 */ 1558 1559 if (bytesRead == 0) { 1560 infoPtr->flags |= SOCKET_EOF; 1561 } 1562 if (bytesRead != SOCKET_ERROR) { 1563 break; 1564 } 1565 1566 /* 1567 * If an error occurs after the FD_CLOSE has arrived, then ignore the 1568 * error and report an EOF. 1569 */ 1570 1571 if (infoPtr->readyEvents & FD_CLOSE) { 1572 infoPtr->flags |= SOCKET_EOF; 1573 bytesRead = 0; 1574 break; 1575 } 1576 1577 error = WSAGetLastError(); 1578 1579 /* 1580 * If an RST comes, then ignore the error and report an EOF just like 1581 * on unix. 1582 */ 1583 1584 if (error == WSAECONNRESET) { 1585 infoPtr->flags |= SOCKET_EOF; 1586 bytesRead = 0; 1587 break; 1588 } 1589 1590 /* 1591 * Check for error condition or underflow in non-blocking case. 1592 */ 1593 1594 if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { 1595 TclWinConvertWSAError(error); 1596 *errorCodePtr = Tcl_GetErrno(); 1597 bytesRead = -1; 1598 break; 1599 } 1600 1601 /* 1602 * In the blocking case, wait until the file becomes readable or 1603 * closed and try again. 1604 */ 1605 1606 if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) { 1607 bytesRead = -1; 1608 break; 1609 } 1610 } 1611 1612 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1613 (WPARAM) SELECT, (LPARAM) infoPtr); 1614 1615 return bytesRead; 1616} 1617 1618/* 1619 *---------------------------------------------------------------------- 1620 * 1621 * TcpOutputProc -- 1622 * 1623 * This function is called by the generic IO level to write data to a 1624 * socket based channel. 1625 * 1626 * Results: 1627 * The number of bytes written or -1 on failure. 1628 * 1629 * Side effects: 1630 * Produces output on the socket. 1631 * 1632 *---------------------------------------------------------------------- 1633 */ 1634 1635static int 1636TcpOutputProc( 1637 ClientData instanceData, /* The socket state. */ 1638 const char *buf, /* Where to get data. */ 1639 int toWrite, /* Maximum number of bytes to write. */ 1640 int *errorCodePtr) /* Where to store error codes. */ 1641{ 1642 SocketInfo *infoPtr = (SocketInfo *) instanceData; 1643 int bytesWritten; 1644 DWORD error; 1645 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1646 TclThreadDataKeyGet(&dataKey); 1647 1648 *errorCodePtr = 0; 1649 1650 /* 1651 * Check that WinSock is initialized; do not call it if not, to prevent 1652 * system crashes. This can happen at exit time if the exit handler for 1653 * WinSock ran before other exit handlers that want to use sockets. 1654 */ 1655 1656 if (!SocketsEnabled()) { 1657 *errorCodePtr = EFAULT; 1658 return -1; 1659 } 1660 1661 /* 1662 * Check to see if the socket is connected before trying to write. 1663 */ 1664 1665 if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) 1666 && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { 1667 return -1; 1668 } 1669 1670 while (1) { 1671 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1672 (WPARAM) UNSELECT, (LPARAM) infoPtr); 1673 1674 bytesWritten = send(infoPtr->socket, buf, toWrite, 0); 1675 if (bytesWritten != SOCKET_ERROR) { 1676 /* 1677 * Since Windows won't generate a new write event until we hit an 1678 * overflow condition, we need to force the event loop to poll 1679 * until the condition changes. 1680 */ 1681 1682 if (infoPtr->watchEvents & FD_WRITE) { 1683 Tcl_Time blockTime = { 0, 0 }; 1684 Tcl_SetMaxBlockTime(&blockTime); 1685 } 1686 break; 1687 } 1688 1689 /* 1690 * Check for error condition or overflow. In the event of overflow, we 1691 * need to clear the FD_WRITE flag so we can detect the next writable 1692 * event. Note that Windows only sends a new writable event after a 1693 * send fails with WSAEWOULDBLOCK. 1694 */ 1695 1696 error = WSAGetLastError(); 1697 if (error == WSAEWOULDBLOCK) { 1698 infoPtr->readyEvents &= ~(FD_WRITE); 1699 if (infoPtr->flags & SOCKET_ASYNC) { 1700 *errorCodePtr = EWOULDBLOCK; 1701 bytesWritten = -1; 1702 break; 1703 } 1704 } else { 1705 TclWinConvertWSAError(error); 1706 *errorCodePtr = Tcl_GetErrno(); 1707 bytesWritten = -1; 1708 break; 1709 } 1710 1711 /* 1712 * In the blocking case, wait until the file becomes writable or 1713 * closed and try again. 1714 */ 1715 1716 if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) { 1717 bytesWritten = -1; 1718 break; 1719 } 1720 } 1721 1722 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 1723 (WPARAM) SELECT, (LPARAM) infoPtr); 1724 1725 return bytesWritten; 1726} 1727 1728/* 1729 *---------------------------------------------------------------------- 1730 * 1731 * TcpSetOptionProc -- 1732 * 1733 * Sets Tcp channel specific options. 1734 * 1735 * Results: 1736 * None, unless an error happens. 1737 * 1738 * Side effects: 1739 * Changes attributes of the socket at the system level. 1740 * 1741 *---------------------------------------------------------------------- 1742 */ 1743 1744static int 1745TcpSetOptionProc( 1746 ClientData instanceData, /* Socket state. */ 1747 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 1748 const char *optionName, /* Name of the option to set. */ 1749 const char *value) /* New value for option. */ 1750{ 1751 SocketInfo *infoPtr; 1752 SOCKET sock; 1753 1754 /* 1755 * Check that WinSock is initialized; do not call it if not, to prevent 1756 * system crashes. This can happen at exit time if the exit handler for 1757 * WinSock ran before other exit handlers that want to use sockets. 1758 */ 1759 1760 if (!SocketsEnabled()) { 1761 if (interp) { 1762 Tcl_AppendResult(interp, "winsock is not initialized", NULL); 1763 } 1764 return TCL_ERROR; 1765 } 1766 1767 infoPtr = (SocketInfo *) instanceData; 1768 sock = infoPtr->socket; 1769 1770#ifdef TCL_FEATURE_KEEPALIVE_NAGLE 1771 if (!strcasecmp(optionName, "-keepalive")) { 1772 BOOL val = FALSE; 1773 int boolVar, rtn; 1774 1775 if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { 1776 return TCL_ERROR; 1777 } 1778 if (boolVar) { 1779 val = TRUE; 1780 } 1781 rtn = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, 1782 (const char *) &val, sizeof(BOOL)); 1783 if (rtn != 0) { 1784 TclWinConvertWSAError(WSAGetLastError()); 1785 if (interp) { 1786 Tcl_AppendResult(interp, "couldn't set socket option: ", 1787 Tcl_PosixError(interp), NULL); 1788 } 1789 return TCL_ERROR; 1790 } 1791 return TCL_OK; 1792 } else if (!strcasecmp(optionName, "-nagle")) { 1793 BOOL val = FALSE; 1794 int boolVar, rtn; 1795 1796 if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { 1797 return TCL_ERROR; 1798 } 1799 if (!boolVar) { 1800 val = TRUE; 1801 } 1802 rtn = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 1803 (const char *) &val, sizeof(BOOL)); 1804 if (rtn != 0) { 1805 TclWinConvertWSAError(WSAGetLastError()); 1806 if (interp) { 1807 Tcl_AppendResult(interp, "couldn't set socket option: ", 1808 Tcl_PosixError(interp), NULL); 1809 } 1810 return TCL_ERROR; 1811 } 1812 return TCL_OK; 1813 } 1814 1815 return Tcl_BadChannelOption(interp, optionName, "keepalive nagle"); 1816#else 1817 return Tcl_BadChannelOption(interp, optionName, ""); 1818#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ 1819} 1820 1821/* 1822 *---------------------------------------------------------------------- 1823 * 1824 * TcpGetOptionProc -- 1825 * 1826 * Computes an option value for a TCP socket based channel, or a list of 1827 * all options and their values. 1828 * 1829 * Note: This code is based on code contributed by John Haxby. 1830 * 1831 * Results: 1832 * A standard Tcl result. The value of the specified option or a list of 1833 * all options and their values is returned in the supplied DString. 1834 * 1835 * Side effects: 1836 * None. 1837 * 1838 *---------------------------------------------------------------------- 1839 */ 1840 1841static int 1842TcpGetOptionProc( 1843 ClientData instanceData, /* Socket state. */ 1844 Tcl_Interp *interp, /* For error reporting - can be NULL */ 1845 const char *optionName, /* Name of the option to retrieve the value 1846 * for, or NULL to get all options and their 1847 * values. */ 1848 Tcl_DString *dsPtr) /* Where to store the computed value; 1849 * initialized by caller. */ 1850{ 1851 SocketInfo *infoPtr; 1852 SOCKADDR_IN sockname; 1853 SOCKADDR_IN peername; 1854 struct hostent *hostEntPtr; 1855 SOCKET sock; 1856 int size = sizeof(SOCKADDR_IN); 1857 size_t len = 0; 1858 char buf[TCL_INTEGER_SPACE]; 1859 1860 /* 1861 * Check that WinSock is initialized; do not call it if not, to prevent 1862 * system crashes. This can happen at exit time if the exit handler for 1863 * WinSock ran before other exit handlers that want to use sockets. 1864 */ 1865 1866 if (!SocketsEnabled()) { 1867 if (interp) { 1868 Tcl_AppendResult(interp, "winsock is not initialized", NULL); 1869 } 1870 return TCL_ERROR; 1871 } 1872 1873 infoPtr = (SocketInfo *) instanceData; 1874 sock = (int) infoPtr->socket; 1875 if (optionName != NULL) { 1876 len = strlen(optionName); 1877 } 1878 1879 if ((len > 1) && (optionName[1] == 'e') && 1880 (strncmp(optionName, "-error", len) == 0)) { 1881 int optlen; 1882 DWORD err; 1883 int ret; 1884 1885 optlen = sizeof(int); 1886 ret = TclWinGetSockOpt((int)sock, SOL_SOCKET, SO_ERROR, 1887 (char *)&err, &optlen); 1888 if (ret == SOCKET_ERROR) { 1889 err = WSAGetLastError(); 1890 } 1891 if (err) { 1892 TclWinConvertWSAError(err); 1893 Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); 1894 } 1895 return TCL_OK; 1896 } 1897 1898 if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && 1899 (strncmp(optionName, "-peername", len) == 0))) { 1900 if (getpeername(sock, (LPSOCKADDR) &peername, &size) == 0) { 1901 if (len == 0) { 1902 Tcl_DStringAppendElement(dsPtr, "-peername"); 1903 Tcl_DStringStartSublist(dsPtr); 1904 } 1905 Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); 1906 1907 if (peername.sin_addr.s_addr == 0) { 1908 hostEntPtr = NULL; 1909 } else { 1910 hostEntPtr = gethostbyaddr((char *) &(peername.sin_addr), 1911 sizeof(peername.sin_addr), AF_INET); 1912 } 1913 if (hostEntPtr != NULL) { 1914 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); 1915 } else { 1916 Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); 1917 } 1918 TclFormatInt(buf, ntohs(peername.sin_port)); 1919 Tcl_DStringAppendElement(dsPtr, buf); 1920 if (len == 0) { 1921 Tcl_DStringEndSublist(dsPtr); 1922 } else { 1923 return TCL_OK; 1924 } 1925 } else { 1926 /* 1927 * getpeername failed - but if we were asked for all the options 1928 * (len==0), don't flag an error at that point because it could be 1929 * an fconfigure request on a server socket (such sockets have no 1930 * peer). {Copied from unix/tclUnixChan.c} 1931 */ 1932 1933 if (len) { 1934 TclWinConvertWSAError((DWORD) WSAGetLastError()); 1935 if (interp) { 1936 Tcl_AppendResult(interp, "can't get peername: ", 1937 Tcl_PosixError(interp), NULL); 1938 } 1939 return TCL_ERROR; 1940 } 1941 } 1942 } 1943 1944 if ((len == 0) || ((len > 1) && (optionName[1] == 's') && 1945 (strncmp(optionName, "-sockname", len) == 0))) { 1946 if (getsockname(sock, (LPSOCKADDR) &sockname, &size) == 0) { 1947 if (len == 0) { 1948 Tcl_DStringAppendElement(dsPtr, "-sockname"); 1949 Tcl_DStringStartSublist(dsPtr); 1950 } 1951 Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); 1952 if (sockname.sin_addr.s_addr == 0) { 1953 hostEntPtr = NULL; 1954 } else { 1955 hostEntPtr = gethostbyaddr((char *) &(sockname.sin_addr), 1956 sizeof(peername.sin_addr), AF_INET); 1957 } 1958 if (hostEntPtr != NULL) { 1959 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); 1960 } else { 1961 Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); 1962 } 1963 TclFormatInt(buf, ntohs(sockname.sin_port)); 1964 Tcl_DStringAppendElement(dsPtr, buf); 1965 if (len == 0) { 1966 Tcl_DStringEndSublist(dsPtr); 1967 } else { 1968 return TCL_OK; 1969 } 1970 } else { 1971 if (interp) { 1972 TclWinConvertWSAError((DWORD) WSAGetLastError()); 1973 Tcl_AppendResult(interp, "can't get sockname: ", 1974 Tcl_PosixError(interp), NULL); 1975 } 1976 return TCL_ERROR; 1977 } 1978 } 1979 1980#ifdef TCL_FEATURE_KEEPALIVE_NAGLE 1981 if (len == 0 || !strncmp(optionName, "-keepalive", len)) { 1982 int optlen; 1983 BOOL opt = FALSE; 1984 1985 if (len == 0) { 1986 Tcl_DStringAppendElement(dsPtr, "-keepalive"); 1987 } 1988 optlen = sizeof(BOOL); 1989 getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, &optlen); 1990 if (opt) { 1991 Tcl_DStringAppendElement(dsPtr, "1"); 1992 } else { 1993 Tcl_DStringAppendElement(dsPtr, "0"); 1994 } 1995 if (len > 0) { 1996 return TCL_OK; 1997 } 1998 } 1999 2000 if (len == 0 || !strncmp(optionName, "-nagle", len)) { 2001 int optlen; 2002 BOOL opt = FALSE; 2003 2004 if (len == 0) { 2005 Tcl_DStringAppendElement(dsPtr, "-nagle"); 2006 } 2007 optlen = sizeof(BOOL); 2008 getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, 2009 &optlen); 2010 if (opt) { 2011 Tcl_DStringAppendElement(dsPtr, "0"); 2012 } else { 2013 Tcl_DStringAppendElement(dsPtr, "1"); 2014 } 2015 if (len > 0) { 2016 return TCL_OK; 2017 } 2018 } 2019#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ 2020 2021 if (len > 0) { 2022#ifdef TCL_FEATURE_KEEPALIVE_NAGLE 2023 return Tcl_BadChannelOption(interp, optionName, 2024 "peername sockname keepalive nagle"); 2025#else 2026 return Tcl_BadChannelOption(interp, optionName, "peername sockname"); 2027#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ 2028 } 2029 2030 return TCL_OK; 2031} 2032 2033/* 2034 *---------------------------------------------------------------------- 2035 * 2036 * TcpWatchProc -- 2037 * 2038 * Informs the channel driver of the events that the generic channel code 2039 * wishes to receive on this socket. 2040 * 2041 * Results: 2042 * None. 2043 * 2044 * Side effects: 2045 * May cause the notifier to poll if any of the specified conditions are 2046 * already true. 2047 * 2048 *---------------------------------------------------------------------- 2049 */ 2050 2051static void 2052TcpWatchProc( 2053 ClientData instanceData, /* The socket state. */ 2054 int mask) /* Events of interest; an OR-ed combination of 2055 * TCL_READABLE, TCL_WRITABLE and 2056 * TCL_EXCEPTION. */ 2057{ 2058 SocketInfo *infoPtr = (SocketInfo *) instanceData; 2059 2060 /* 2061 * Update the watch events mask. Only if the socket is not a server 2062 * socket. Fix for SF Tcl Bug #557878. 2063 */ 2064 2065 if (!infoPtr->acceptProc) { 2066 infoPtr->watchEvents = 0; 2067 if (mask & TCL_READABLE) { 2068 infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT); 2069 } 2070 if (mask & TCL_WRITABLE) { 2071 infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT); 2072 } 2073 2074 /* 2075 * If there are any conditions already set, then tell the notifier to 2076 * poll rather than block. 2077 */ 2078 2079 if (infoPtr->readyEvents & infoPtr->watchEvents) { 2080 Tcl_Time blockTime = { 0, 0 }; 2081 Tcl_SetMaxBlockTime(&blockTime); 2082 } 2083 } 2084} 2085 2086/* 2087 *---------------------------------------------------------------------- 2088 * 2089 * TcpGetProc -- 2090 * 2091 * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside 2092 * a TCP socket based channel. 2093 * 2094 * Results: 2095 * Returns TCL_OK with the socket in handlePtr. 2096 * 2097 * Side effects: 2098 * None. 2099 * 2100 *---------------------------------------------------------------------- 2101 */ 2102 2103static int 2104TcpGetHandleProc( 2105 ClientData instanceData, /* The socket state. */ 2106 int direction, /* Not used. */ 2107 ClientData *handlePtr) /* Where to store the handle. */ 2108{ 2109 SocketInfo *statePtr = (SocketInfo *) instanceData; 2110 2111 *handlePtr = (ClientData) statePtr->socket; 2112 return TCL_OK; 2113} 2114 2115/* 2116 *---------------------------------------------------------------------- 2117 * 2118 * SocketThread -- 2119 * 2120 * Helper thread used to manage the socket event handling window. 2121 * 2122 * Results: 2123 * 1 if unable to create socket event window, 0 otherwise. 2124 * 2125 * Side effects: 2126 * None. 2127 * 2128 *---------------------------------------------------------------------- 2129 */ 2130 2131static DWORD WINAPI 2132SocketThread( 2133 LPVOID arg) 2134{ 2135 MSG msg; 2136 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg); 2137 2138 /* 2139 * Create a dummy window receiving socket events. 2140 */ 2141 2142 tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket", 2143 WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg); 2144 2145 /* 2146 * Signalize thread creator that we are done creating the window. 2147 */ 2148 2149 SetEvent(tsdPtr->readyEvent); 2150 2151 /* 2152 * If unable to create the window, exit this thread immediately. 2153 */ 2154 2155 if (tsdPtr->hwnd == NULL) { 2156 return 1; 2157 } 2158 2159 /* 2160 * Process all messages on the socket window until WM_QUIT. This threads 2161 * exits only when instructed to do so by the call to 2162 * PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets(). 2163 */ 2164 2165 while (GetMessage(&msg, NULL, 0, 0) > 0) { 2166 DispatchMessage(&msg); 2167 } 2168 2169 /* 2170 * This releases waiters on thread exit in TclpFinalizeSockets() 2171 */ 2172 2173 SetEvent(tsdPtr->readyEvent); 2174 2175 return msg.wParam; 2176} 2177 2178 2179/* 2180 *---------------------------------------------------------------------- 2181 * 2182 * SocketProc -- 2183 * 2184 * This function is called when WSAAsyncSelect has been used to register 2185 * interest in a socket event, and the event has occurred. 2186 * 2187 * Results: 2188 * 0 on success. 2189 * 2190 * Side effects: 2191 * The flags for the given socket are updated to reflect the event that 2192 * occured. 2193 * 2194 *---------------------------------------------------------------------- 2195 */ 2196 2197static LRESULT CALLBACK 2198SocketProc( 2199 HWND hwnd, 2200 UINT message, 2201 WPARAM wParam, 2202 LPARAM lParam) 2203{ 2204 int event, error; 2205 SOCKET socket; 2206 SocketInfo *infoPtr; 2207 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 2208#ifdef _WIN64 2209 GetWindowLongPtr(hwnd, GWLP_USERDATA); 2210#else 2211 GetWindowLong(hwnd, GWL_USERDATA); 2212#endif 2213 2214 switch (message) { 2215 default: 2216 return DefWindowProc(hwnd, message, wParam, lParam); 2217 break; 2218 2219 case WM_CREATE: 2220 /* 2221 * Store the initial tsdPtr, it's from a different thread, so it's not 2222 * directly accessible, but needed. 2223 */ 2224 2225#ifdef _WIN64 2226 SetWindowLongPtr(hwnd, GWLP_USERDATA, 2227 (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams); 2228#else 2229 SetWindowLong(hwnd, GWL_USERDATA, 2230 (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams); 2231#endif 2232 break; 2233 2234 case WM_DESTROY: 2235 PostQuitMessage(0); 2236 break; 2237 2238 case SOCKET_MESSAGE: 2239 event = WSAGETSELECTEVENT(lParam); 2240 error = WSAGETSELECTERROR(lParam); 2241 socket = (SOCKET) wParam; 2242 2243 /* 2244 * Find the specified socket on the socket list and update its 2245 * eventState flag. 2246 */ 2247 2248 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 2249 for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 2250 infoPtr = infoPtr->nextPtr) { 2251 if (infoPtr->socket == socket) { 2252 /* 2253 * Update the socket state. 2254 * 2255 * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event 2256 * happens, then clear the FD_ACCEPT count. Otherwise, 2257 * increment the count if the current event is an FD_ACCEPT. 2258 */ 2259 2260 if (event & FD_CLOSE) { 2261 infoPtr->acceptEventCount = 0; 2262 infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); 2263 } else if (event & FD_ACCEPT) { 2264 infoPtr->acceptEventCount++; 2265 } 2266 2267 if (event & FD_CONNECT) { 2268 /* 2269 * The socket is now connected, clear the async connect 2270 * flag. 2271 */ 2272 2273 infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); 2274 2275 /* 2276 * Remember any error that occurred so we can report 2277 * connection failures. 2278 */ 2279 2280 if (error != ERROR_SUCCESS) { 2281 TclWinConvertWSAError((DWORD) error); 2282 infoPtr->lastError = Tcl_GetErrno(); 2283 } 2284 } 2285 2286 if (infoPtr->flags & SOCKET_ASYNC_CONNECT) { 2287 infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); 2288 if (error != ERROR_SUCCESS) { 2289 TclWinConvertWSAError((DWORD) error); 2290 infoPtr->lastError = Tcl_GetErrno(); 2291 } 2292 infoPtr->readyEvents |= FD_WRITE; 2293 } 2294 infoPtr->readyEvents |= event; 2295 2296 /* 2297 * Wake up the Main Thread. 2298 */ 2299 2300 SetEvent(tsdPtr->readyEvent); 2301 Tcl_ThreadAlert(tsdPtr->threadId); 2302 break; 2303 } 2304 } 2305 SetEvent(tsdPtr->socketListLock); 2306 break; 2307 2308 case SOCKET_SELECT: 2309 infoPtr = (SocketInfo *) lParam; 2310 if (wParam == SELECT) { 2311 WSAAsyncSelect(infoPtr->socket, hwnd, 2312 SOCKET_MESSAGE, infoPtr->selectEvents); 2313 } else { 2314 /* 2315 * Clear the selection mask 2316 */ 2317 2318 WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0); 2319 } 2320 break; 2321 2322 case SOCKET_TERMINATE: 2323 DestroyWindow(hwnd); 2324 break; 2325 } 2326 2327 return 0; 2328} 2329 2330/* 2331 *---------------------------------------------------------------------- 2332 * 2333 * Tcl_GetHostName -- 2334 * 2335 * Returns the name of the local host. 2336 * 2337 * Results: 2338 * A string containing the network name for this machine. The caller must 2339 * not modify or free this string. 2340 * 2341 * Side effects: 2342 * Caches the name to return for future calls. 2343 * 2344 *---------------------------------------------------------------------- 2345 */ 2346 2347const char * 2348Tcl_GetHostName(void) 2349{ 2350 return Tcl_GetString(TclGetProcessGlobalValue(&hostName)); 2351} 2352 2353/* 2354 *---------------------------------------------------------------------- 2355 * 2356 * InitializeHostName -- 2357 * 2358 * This routine sets the process global value of the name of the local 2359 * host on which the process is running. 2360 * 2361 * Results: 2362 * None. 2363 * 2364 *---------------------------------------------------------------------- 2365 */ 2366 2367void 2368InitializeHostName( 2369 char **valuePtr, 2370 int *lengthPtr, 2371 Tcl_Encoding *encodingPtr) 2372{ 2373 WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1]; 2374 DWORD length = sizeof(wbuf) / sizeof(WCHAR); 2375 Tcl_DString ds; 2376 2377 if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) { 2378 /* 2379 * Convert string from native to UTF then change to lowercase. 2380 */ 2381 2382 Tcl_UtfToLower(Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds)); 2383 2384 } else { 2385 Tcl_DStringInit(&ds); 2386 if (TclpHasSockets(NULL) == TCL_OK) { 2387 /* 2388 * Buffer length of 255 copied slavishly from previous version of 2389 * this routine. Presumably there's a more "correct" macro value 2390 * for a properly sized buffer for a gethostname() call. 2391 * Maintainers are welcome to supply it. 2392 */ 2393 2394 Tcl_DString inDs; 2395 2396 Tcl_DStringInit(&inDs); 2397 Tcl_DStringSetLength(&inDs, 255); 2398 if (gethostname(Tcl_DStringValue(&inDs), 2399 Tcl_DStringLength(&inDs)) == 0) { 2400 Tcl_DStringSetLength(&ds, 0); 2401 } else { 2402 Tcl_ExternalToUtfDString(NULL, 2403 Tcl_DStringValue(&inDs), -1, &ds); 2404 } 2405 Tcl_DStringFree(&inDs); 2406 } 2407 } 2408 2409 *encodingPtr = Tcl_GetEncoding(NULL, "utf-8"); 2410 *lengthPtr = Tcl_DStringLength(&ds); 2411 *valuePtr = ckalloc((unsigned int) (*lengthPtr)+1); 2412 memcpy(*valuePtr, Tcl_DStringValue(&ds), (size_t)(*lengthPtr)+1); 2413 Tcl_DStringFree(&ds); 2414} 2415 2416/* 2417 *---------------------------------------------------------------------- 2418 * 2419 * TclWinGetSockOpt, et al. -- 2420 * 2421 * These functions are wrappers that let us bind the WinSock API 2422 * dynamically so we can run on systems that don't have the wsock32.dll. 2423 * We need wrappers for these interfaces because they are called from the 2424 * generic Tcl code. 2425 * 2426 * Results: 2427 * As defined for each function. 2428 * 2429 * Side effects: 2430 * As defined for each function. 2431 * 2432 *---------------------------------------------------------------------- 2433 */ 2434 2435int 2436TclWinGetSockOpt( 2437 int s, 2438 int level, 2439 int optname, 2440 char * optval, 2441 int FAR *optlen) 2442{ 2443 /* 2444 * Check that WinSock is initialized; do not call it if not, to prevent 2445 * system crashes. This can happen at exit time if the exit handler for 2446 * WinSock ran before other exit handlers that want to use sockets. 2447 */ 2448 2449 if (!SocketsEnabled()) { 2450 return SOCKET_ERROR; 2451 } 2452 2453 return getsockopt((SOCKET)s, level, optname, optval, optlen); 2454} 2455 2456int 2457TclWinSetSockOpt( 2458 int s, 2459 int level, 2460 int optname, 2461 const char * optval, 2462 int optlen) 2463{ 2464 /* 2465 * Check that WinSock is initialized; do not call it if not, to prevent 2466 * system crashes. This can happen at exit time if the exit handler for 2467 * WinSock ran before other exit handlers that want to use sockets. 2468 */ 2469 2470 if (!SocketsEnabled()) { 2471 return SOCKET_ERROR; 2472 } 2473 2474 return setsockopt((SOCKET)s, level, optname, optval, optlen); 2475} 2476 2477u_short 2478TclWinNToHS( 2479 u_short netshort) 2480{ 2481 /* 2482 * Check that WinSock is initialized; do not call it if not, to prevent 2483 * system crashes. This can happen at exit time if the exit handler for 2484 * WinSock ran before other exit handlers that want to use sockets. 2485 */ 2486 2487 if (!SocketsEnabled()) { 2488 return (u_short) -1; 2489 } 2490 2491 return ntohs(netshort); 2492} 2493 2494struct servent * 2495TclWinGetServByName( 2496 const char *name, 2497 const char *proto) 2498{ 2499 /* 2500 * Check that WinSock is initialized; do not call it if not, to prevent 2501 * system crashes. This can happen at exit time if the exit handler for 2502 * WinSock ran before other exit handlers that want to use sockets. 2503 */ 2504 2505 if (!SocketsEnabled()) { 2506 return NULL; 2507 } 2508 2509 return getservbyname(name, proto); 2510} 2511 2512/* 2513 *---------------------------------------------------------------------- 2514 * 2515 * TcpThreadActionProc -- 2516 * 2517 * Insert or remove any thread local refs to this channel. 2518 * 2519 * Results: 2520 * None. 2521 * 2522 * Side effects: 2523 * Changes thread local list of valid channels. 2524 * 2525 *---------------------------------------------------------------------- 2526 */ 2527 2528static void 2529TcpThreadActionProc( 2530 ClientData instanceData, 2531 int action) 2532{ 2533 ThreadSpecificData *tsdPtr; 2534 SocketInfo *infoPtr = (SocketInfo *) instanceData; 2535 int notifyCmd; 2536 2537 if (action == TCL_CHANNEL_THREAD_INSERT) { 2538 /* 2539 * Ensure that socket subsystem is initialized in this thread, or else 2540 * sockets will not work. 2541 */ 2542 2543 Tcl_MutexLock(&socketMutex); 2544 InitSockets(); 2545 Tcl_MutexUnlock(&socketMutex); 2546 2547 tsdPtr = TCL_TSD_INIT(&dataKey); 2548 2549 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 2550 infoPtr->nextPtr = tsdPtr->socketList; 2551 tsdPtr->socketList = infoPtr; 2552 SetEvent(tsdPtr->socketListLock); 2553 2554 notifyCmd = SELECT; 2555 } else { 2556 SocketInfo **nextPtrPtr; 2557 int removed = 0; 2558 2559 tsdPtr = TCL_TSD_INIT(&dataKey); 2560 2561 /* 2562 * TIP #218, Bugfix: All access to socketList has to be protected by 2563 * the lock. 2564 */ 2565 2566 WaitForSingleObject(tsdPtr->socketListLock, INFINITE); 2567 for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL; 2568 nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { 2569 if ((*nextPtrPtr) == infoPtr) { 2570 (*nextPtrPtr) = infoPtr->nextPtr; 2571 removed = 1; 2572 break; 2573 } 2574 } 2575 SetEvent(tsdPtr->socketListLock); 2576 2577 /* 2578 * This could happen if the channel was created in one thread and then 2579 * moved to another without updating the thread local data in each 2580 * thread. 2581 */ 2582 2583 if (!removed) { 2584 Tcl_Panic("file info ptr not on thread channel list"); 2585 } 2586 2587 notifyCmd = UNSELECT; 2588 } 2589 2590 /* 2591 * Ensure that, or stop, notifications for the socket occur in this 2592 * thread. 2593 */ 2594 2595 SendMessage(tsdPtr->hwnd, SOCKET_SELECT, 2596 (WPARAM) notifyCmd, (LPARAM) infoPtr); 2597} 2598 2599/* 2600 * Local Variables: 2601 * mode: c 2602 * c-basic-offset: 4 2603 * fill-column: 78 2604 * End: 2605 */ 2606