Diff
Not logged in

Differences From Artifact [29834ca735]:

To Artifact [081d7dece3]:


1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
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.37.2.10 2006/01/25 18:39:59 dgp Exp $
 * RCS: @(#) $Id: tclWinSock.c,v 1.37.2.11 2006/04/28 16:10:51 dgp 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
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
245
246
247
248
249
250
251

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302







-
















-
+














+











-
+







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;
static Tcl_DriverGetHandleProc	TcpGetHandleProc;

/*
 * This structure describes the channel type structure for TCP socket
 * based IO.
 */

static Tcl_ChannelType tcpChannelType = {
    "tcp",		    /* Type name. */
    TCL_CHANNEL_VERSION_4,  /* v4 channel */
    TCL_CHANNEL_VERSION_5,  /* v5 channel */
    TcpCloseProc,	    /* Close proc. */
    TcpInputProc,	    /* Input proc. */
    TcpOutputProc,	    /* Output proc. */
    NULL,		    /* Seek proc. */
    TcpSetOptionProc,	    /* Set option proc. */
    TcpGetOptionProc,	    /* Get option proc. */
    TcpWatchProc,	    /* Set up notifier to watch this channel. */
    TcpGetHandleProc,	    /* Get an OS handle from channel. */
    NULL,		    /* close2proc. */
    TcpBlockProc,	    /* Set socket into (non-)blocking mode. */
    NULL,		    /* flush proc. */
    NULL,		    /* handler proc. */
    NULL,		    /* wide seek proc */
    TcpThreadActionProc,    /* thread action proc */
    NULL,                   /* truncate */
};

/*
 *----------------------------------------------------------------------
 *
 * 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.
 *	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
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







-
+
-
-
+
-

+
+
+

+
+
+


-
-




+


-
-
+
+


-
+
-
-
+
-

-
+



-




-
-
+
-







    /*
     * Check for per-thread initialization.
     */

    if (tsdPtr == NULL) {
	tsdPtr = TCL_TSD_INIT(&dataKey);
	tsdPtr->socketList = NULL;
	tsdPtr->hwnd = NULL;
	tsdPtr->hwnd       = NULL;

	tsdPtr->threadId = Tcl_GetCurrentThread();
	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);
	SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);

	if (tsdPtr->socketThread == NULL) {
	    goto unloadLibrary;
	}

	SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);

	/*
	 * Wait for the thread to signal that the window has been created and
	 * is ready to go. Timeout after twenty seconds.
	 * Wait for the thread to signal when the window has
	 * been created and if it is ready to go.
	 */

	if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) {
	WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
	    goto unloadLibrary;
	}


	if (tsdPtr->hwnd == NULL) {
	    goto unloadLibrary;
	    goto unloadLibrary; /* Trouble creating the window */
	}

	Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
	Tcl_CreateThreadExitHandler(SocketThreadExitHandler, NULL);
    }
    return;

  unloadLibrary:
    if (tsdPtr != NULL && tsdPtr->hwnd != NULL) {
	SocketThreadExitHandler(0);
    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
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
641







+





-
+












-
+

+
+
+
-
+
-





-
+




-
-
-
+
+
-

-
+
-

+
-
+
-
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-







    /* 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);
	TclpFinalizeSockets();
	UnregisterClass("TclSocket", TclWinGetTclInstance());
	winSock.WSACleanup();
	FreeLibrary(winSock.hModule);
	winSock.hModule = NULL;
    }
    initialized = 0;
    Tcl_MutexUnlock(&socketMutex);
}

/*
 *----------------------------------------------------------------------
 *
 * SocketThreadExitHandler --
 * 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
 *	Callback invoked during thread clean up to delete the socket event
 *	the state if unable to initialize the sockets subsystem.
 *	source.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Delete the event source.
 *	Deletes the event source and destroys the socket thread.
 *
 *----------------------------------------------------------------------
 */

    /* ARGSUSED */
static void
SocketThreadExitHandler(
void
TclpFinalizeSockets()
    ClientData clientData)	/* Not used. */
{
    ThreadSpecificData *tsdPtr =
    ThreadSpecificData *tsdPtr;
	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);

    tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
    if (tsdPtr != NULL && tsdPtr->socketThread != NULL) {
    if (tsdPtr != NULL) {
	DWORD exitCode;

	GetExitCodeThread(tsdPtr->socketThread, &exitCode);
	if (exitCode == STILL_ACTIVE) {
	    PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
	if (tsdPtr->socketThread != NULL) {
	    if (tsdPtr->hwnd != NULL) {
		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
		/*
		 * Wait for the thread to exit. This ensures that we are
		 * completely cleaned up before we leave this function.
	     * 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);

		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_DeleteThreadExitHandler(SocketThreadExitHandler, 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
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
2350







+
+
+
+




-
-
+




+
+
+
+






+
+






+
+
+
+
+
+







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);

    /*
     * Signal the main thread that the window has been created and that the
     * socket thread is ready to go.
     * 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;
}


/*
 *----------------------------------------------------------------------
 *
2546
2547
2548
2549
2550
2551
2552


2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575







+
+







	 */

	Tcl_DStringInit(&ds);
	Tcl_DStringSetLength(&ds, 255);
	if (winSock.gethostname(Tcl_DStringValue(&ds),
		Tcl_DStringLength(&ds)) == 0) {
	    Tcl_DStringSetLength(&ds, 0);
	} else {
	    Tcl_DStringSetLength(&ds, strlen(Tcl_DStringValue(&ds)));
	}
    }

    *encodingPtr = Tcl_GetEncoding(NULL, "utf-8");
    *lengthPtr = Tcl_DStringLength(&ds);
    *valuePtr = ckalloc((unsigned int) (*lengthPtr)+1);
    memcpy((VOID *) *valuePtr, (VOID *) Tcl_DStringValue(&ds),
2700
2701
2702
2703
2704
2705
2706
2707

2708
2709
2710
2711
2712
2713
2714
2715
2716

2717
2718
2719
2720
2721
2722
2723
2716
2717
2718
2719
2720
2721
2722

2723
2724
2725
2726
2727
2728
2729
2730
2731

2732
2733
2734
2735
2736
2737
2738
2739







-
+








-
+







	SetEvent(tsdPtr->socketListLock);

	notifyCmd = SELECT;
    } else {
	SocketInfo **nextPtrPtr;
	int removed = 0;

	tsdPtr	= TCL_TSD_INIT(&dataKey);
	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)) {
		nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
	    if ((*nextPtrPtr) == infoPtr) {
		(*nextPtrPtr) = infoPtr->nextPtr;
		removed = 1;
		break;
	    }
	}
	SetEvent(tsdPtr->socketListLock);