1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/*
* tclWinSock.c --
*
* This file contains Windows-specific socket related code.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclWinSock.c,v 1.51 2005/12/13 22:43:18 kennykb Exp $
*/
#include "tclWinInt.h"
/*
* Make sure to remove the redirection defines set in tclWinPort.h that is in
* use in other sections of the core, except for us.
|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/*
* tclWinSock.c --
*
* This file contains Windows-specific socket related code.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclWinSock.c,v 1.52 2006/03/10 17:34:35 vasiljevic Exp $
*/
#include "tclWinInt.h"
/*
* Make sure to remove the redirection defines set in tclWinPort.h that is in
* use in other sections of the core, except for us.
|
| ︙ | | | ︙ | |
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
|
static DWORD WINAPI SocketThread(LPVOID arg);
static void TcpThreadActionProc(ClientData instanceData,
int action);
static Tcl_EventCheckProc SocketCheckProc;
static Tcl_EventProc SocketEventProc;
static Tcl_EventSetupProc SocketSetupProc;
static Tcl_ExitProc SocketThreadExitHandler;
static Tcl_DriverBlockModeProc TcpBlockProc;
static Tcl_DriverCloseProc TcpCloseProc;
static Tcl_DriverSetOptionProc TcpSetOptionProc;
static Tcl_DriverGetOptionProc TcpGetOptionProc;
static Tcl_DriverInputProc TcpInputProc;
static Tcl_DriverOutputProc TcpOutputProc;
static Tcl_DriverWatchProc TcpWatchProc;
|
<
|
245
246
247
248
249
250
251
252
253
254
255
256
257
258
|
static DWORD WINAPI SocketThread(LPVOID arg);
static void TcpThreadActionProc(ClientData instanceData,
int action);
static Tcl_EventCheckProc SocketCheckProc;
static Tcl_EventProc SocketEventProc;
static Tcl_EventSetupProc SocketSetupProc;
static Tcl_DriverBlockModeProc TcpBlockProc;
static Tcl_DriverCloseProc TcpCloseProc;
static Tcl_DriverSetOptionProc TcpSetOptionProc;
static Tcl_DriverGetOptionProc TcpGetOptionProc;
static Tcl_DriverInputProc TcpInputProc;
static Tcl_DriverOutputProc TcpOutputProc;
static Tcl_DriverWatchProc TcpWatchProc;
|
| ︙ | | | ︙ | |
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
*
* InitSockets --
*
* Initialize the socket module. Attempts to load the wsock32.dll library
* and set up the winSock function table. If successful, registers the
* event window for the socket notifier code.
*
* Assumes Mutex is held.
*
* Results:
* None.
*
* Side effects:
* Dynamically loads wsock32.dll, and registers a new window class and
* creates a window for use in asynchronous socket notification.
|
|
|
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
*
* InitSockets --
*
* Initialize the socket module. Attempts to load the wsock32.dll library
* and set up the winSock function table. If successful, registers the
* event window for the socket notifier code.
*
* Assumes socketMutex is held.
*
* Results:
* None.
*
* Side effects:
* Dynamically loads wsock32.dll, and registers a new window class and
* creates a window for use in asynchronous socket notification.
|
| ︙ | | | ︙ | |
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
|
/*
* Check for per-thread initialization.
*/
if (tsdPtr == NULL) {
tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->socketList = NULL;
tsdPtr->hwnd = NULL;
tsdPtr->threadId = Tcl_GetCurrentThread();
tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
tsdPtr, 0, &id);
SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
if (tsdPtr->socketThread == NULL) {
goto unloadLibrary;
}
/*
* Wait for the thread to signal that the window has been created and
* is ready to go. Timeout after twenty seconds.
*/
if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) {
goto unloadLibrary;
}
if (tsdPtr->hwnd == NULL) {
goto unloadLibrary;
}
Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
Tcl_CreateThreadExitHandler(SocketThreadExitHandler, NULL);
}
return;
unloadLibrary:
if (tsdPtr != NULL && tsdPtr->hwnd != NULL) {
SocketThreadExitHandler(0);
}
FreeLibrary(winSock.hModule);
winSock.hModule = NULL;
return;
}
/*
*----------------------------------------------------------------------
|
|
<
|
<
>
>
>
>
>
>
<
<
>
|
|
|
<
|
<
|
<
<
|
<
|
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
|
/*
* Check for per-thread initialization.
*/
if (tsdPtr == NULL) {
tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->socketList = NULL;
tsdPtr->hwnd = NULL;
tsdPtr->threadId = Tcl_GetCurrentThread();
tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (tsdPtr->readyEvent == NULL) {
goto unloadLibrary;
}
tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
if (tsdPtr->socketListLock == NULL) {
goto unloadLibrary;
}
tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
tsdPtr, 0, &id);
if (tsdPtr->socketThread == NULL) {
goto unloadLibrary;
}
SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
/*
* Wait for the thread to signal when the window has
* been created and if it is ready to go.
*/
WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
if (tsdPtr->hwnd == NULL) {
goto unloadLibrary; /* Trouble creating the window */
}
Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
return;
unloadLibrary:
TclpFinalizeSockets();
FreeLibrary(winSock.hModule);
winSock.hModule = NULL;
return;
}
/*
*----------------------------------------------------------------------
|
| ︙ | | | ︙ | |
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
|
/* ARGSUSED */
static void
SocketExitHandler(
ClientData clientData) /* Not used. */
{
Tcl_MutexLock(&socketMutex);
if (winSock.hModule) {
/*
* Make sure the socket event handling window is cleaned-up for, at
* most, this thread.
*/
SocketThreadExitHandler(clientData);
UnregisterClass("TclSocket", TclWinGetTclInstance());
winSock.WSACleanup();
FreeLibrary(winSock.hModule);
winSock.hModule = NULL;
}
initialized = 0;
Tcl_MutexUnlock(&socketMutex);
}
/*
*----------------------------------------------------------------------
*
* SocketThreadExitHandler --
*
* Callback invoked during thread clean up to delete the socket event
* source.
*
* Results:
* None.
*
* Side effects:
* Delete the event source.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static void
SocketThreadExitHandler(
ClientData clientData) /* Not used. */
{
ThreadSpecificData *tsdPtr =
(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr != NULL && tsdPtr->socketThread != NULL) {
DWORD exitCode;
GetExitCodeThread(tsdPtr->socketThread, &exitCode);
if (exitCode == STILL_ACTIVE) {
PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
/*
* Wait for the thread to close. This ensures that we are
* completely cleaned up before we leave this function. If
* Tcl_Finalize was called from DllMain, the thread is in a paused
* state so we need to timeout and continue.
*/
WaitForSingleObject(tsdPtr->socketThread, 100);
}
CloseHandle(tsdPtr->socketThread);
tsdPtr->socketThread = NULL;
CloseHandle(tsdPtr->readyEvent);
CloseHandle(tsdPtr->socketListLock);
Tcl_DeleteThreadExitHandler(SocketThreadExitHandler, NULL);
Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
}
/*
*----------------------------------------------------------------------
*
|
>
|
|
>
>
>
|
<
|
<
|
|
<
|
<
>
|
<
<
|
|
|
<
|
|
|
<
<
|
<
|
>
|
|
|
>
>
|
>
>
>
|
>
|
<
|
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
|
/* ARGSUSED */
static void
SocketExitHandler(
ClientData clientData) /* Not used. */
{
Tcl_MutexLock(&socketMutex);
if (winSock.hModule) {
/*
* Make sure the socket event handling window is cleaned-up for, at
* most, this thread.
*/
TclpFinalizeSockets();
UnregisterClass("TclSocket", TclWinGetTclInstance());
winSock.WSACleanup();
FreeLibrary(winSock.hModule);
winSock.hModule = NULL;
}
initialized = 0;
Tcl_MutexUnlock(&socketMutex);
}
/*
*----------------------------------------------------------------------
*
* TclpFinalizeSockets --
*
* This function is called from Tcl_FinalizeThread to finalize
* the platform specific socket subsystem.
* Also, it may be called from within this module to cleanup
* the state if unable to initialize the sockets subsystem.
*
* Results:
* None.
*
* Side effects:
* Deletes the event source and destroys the socket thread.
*
*----------------------------------------------------------------------
*/
void
TclpFinalizeSockets()
{
ThreadSpecificData *tsdPtr;
tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr != NULL) {
if (tsdPtr->socketThread != NULL) {
if (tsdPtr->hwnd != NULL) {
PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
/*
* Wait for the thread to exit. This ensures that we are
* completely cleaned up before we leave this function.
*/
WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
tsdPtr->hwnd = NULL;
}
CloseHandle(tsdPtr->socketThread);
tsdPtr->socketThread = NULL;
}
if (tsdPtr->readyEvent != NULL) {
CloseHandle(tsdPtr->readyEvent);
tsdPtr->readyEvent = NULL;
}
if (tsdPtr->socketListLock != NULL) {
CloseHandle(tsdPtr->socketListLock);
tsdPtr->socketListLock = NULL;
}
Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | | | ︙ | |
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
|
static DWORD WINAPI
SocketThread(
LPVOID arg)
{
MSG msg;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket",
WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
/*
* Signal the main thread that the window has been created and that the
* socket thread is ready to go.
*/
SetEvent(tsdPtr->readyEvent);
if (tsdPtr->hwnd == NULL) {
return 1;
}
/*
* Process all messages on the socket window until WM_QUIT.
*/
while (GetMessage(&msg, NULL, 0, 0) > 0) {
DispatchMessage(&msg);
}
return msg.wParam;
}
/*
*----------------------------------------------------------------------
*
|
>
>
>
>
<
|
>
>
>
>
>
>
>
>
>
>
>
>
|
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
|
static DWORD WINAPI
SocketThread(
LPVOID arg)
{
MSG msg;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
/*
* Create a dummy window receiving socket events.
*/
tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket",
WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
/*
* Signalize thread creator that we are done creating the window.
*/
SetEvent(tsdPtr->readyEvent);
/*
* If unable to create the window, exit this thread immediately.
*/
if (tsdPtr->hwnd == NULL) {
return 1;
}
/*
* Process all messages on the socket window until WM_QUIT.
* This threads exits only when instructed to do so by the
* call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets().
*/
while (GetMessage(&msg, NULL, 0, 0) > 0) {
DispatchMessage(&msg);
}
/*
* This releases waiters on thread exit in TclpFinalizeSockets()
*/
SetEvent(tsdPtr->readyEvent);
return msg.wParam;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | | | ︙ | |
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
|
SetEvent(tsdPtr->socketListLock);
notifyCmd = SELECT;
} else {
SocketInfo **nextPtrPtr;
int removed = 0;
tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* TIP #218, Bugfix: All access to socketList has to be protected by
* the lock.
*/
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
if ((*nextPtrPtr) == infoPtr) {
(*nextPtrPtr) = infoPtr->nextPtr;
removed = 1;
break;
}
}
SetEvent(tsdPtr->socketListLock);
|
|
|
|
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
|
SetEvent(tsdPtr->socketListLock);
notifyCmd = SELECT;
} else {
SocketInfo **nextPtrPtr;
int removed = 0;
tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* TIP #218, Bugfix: All access to socketList has to be protected by
* the lock.
*/
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
if ((*nextPtrPtr) == infoPtr) {
(*nextPtrPtr) = infoPtr->nextPtr;
removed = 1;
break;
}
}
SetEvent(tsdPtr->socketListLock);
|
| ︙ | | | ︙ | |