Diff
Not logged in

Differences From Artifact [621f50a8c0]:

To Artifact [2b65464f73]:


601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
601
602
603
604
605
606
607



608
609
610
611
612
613
614







-
-
-








static int
WaitForConnect(
    TcpState *statePtr,		/* State of the socket. */
    int *errorCodePtr)		/* Where to store errors? A passed
				 * null-pointer activates background mode. */
{
    int result;
    int oldMode;

    /*
     * Check if an async connect failed already and error reporting is
     * demanded, return the error ENOTCONN.
     */

    if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
	*errorCodePtr = ENOTCONN;
641
642
643
644
645
646
647
648

649
650
651
652
653
654
655
638
639
640
641
642
643
644

645
646
647
648
649
650
651
652







-
+







	return -1;
    }

    /*
     * Be sure to disable event servicing so we are truly modal.
     */

    oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
    int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);

    /*
     * Loop in the blocking case until the connect signal is present
     */

    while (1) {
	/*
688
689
690
691
692
693
694
695

696
697
698
699
700
701
702
685
686
687
688
689
690
691

692
693
694
695
696
697
698
699







-
+







	    SetEvent(tsdPtr->socketListLock);

	    /*
	     * Continue connect. If switched to synchronous connect, the
	     * connect is terminated.
	     */

	    result = TcpConnect(NULL, statePtr);
	    int result = TcpConnect(NULL, statePtr);

	    /*
	     * Restore event service mode.
	     */

	    (void) Tcl_SetServiceMode(oldMode);

787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
784
785
786
787
788
789
790


791
792
793
794
795
796
797







-
-







    void *instanceData,		/* Socket state. */
    char *buf,			/* Where to store data read. */
    int bufSize,		/* How much space is available in the
				 * buffer? */
    int *errorCodePtr)		/* Where to store error code. */
{
    TcpState *statePtr = (TcpState *)instanceData;
    int bytesRead;
    DWORD error;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    *errorCodePtr = 0;

    /*
     * First check to see if EOF was already detected, to prevent calling the
821
822
823
824
825
826
827

828
829
830
831
832
833
834
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830







+







     * No EOF, and it is connected, so try to read more from the socket. Note
     * that we clear the FD_READ bit because read events are level triggered
     * so a new event will be generated if there is still data available to be
     * read. We have to simulate blocking behavior here since we are always
     * using non-blocking sockets.
     */

    int bytesRead;
    while (1) {
	SendSelectMessage(tsdPtr, UNSELECT, statePtr);

	/*
	 * Single fd operation: this proc is only called for a connected
	 * socket.
	 */
854
855
856
857
858
859
860
861

862
863
864
865
866
867
868
850
851
852
853
854
855
856

857
858
859
860
861
862
863
864







-
+








	if (GOT_BITS(statePtr->readyEvents, FD_CLOSE)) {
	    SET_BITS(statePtr->flags, SOCKET_EOF);
	    bytesRead = 0;
	    break;
	}

	error = WSAGetLastError();
	DWORD error = WSAGetLastError();

	/*
	 * If an RST comes, then ignore the error and report an EOF just like
	 * on Unix.
	 */

	if (error == WSAECONNRESET) {
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
916
917
918
919
920
921
922


923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945







-
-















+







TcpOutputProc(
    void *instanceData,		/* Socket state. */
    const char *buf,		/* The data buffer. */
    int toWrite,		/* How many bytes to write? */
    int *errorCodePtr)		/* Where to store error code. */
{
    TcpState *statePtr = (TcpState *)instanceData;
    int written;
    DWORD error;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    *errorCodePtr = 0;

    /*
     * Check if there is an async connect running.
     * For blocking sockets terminate connect, otherwise do one step.
     * For a non blocking socket return EWOULDBLOCK if connect not terminated
     */

    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }

    int written;
    while (1) {
	SendSelectMessage(tsdPtr, UNSELECT, statePtr);

	/*
	 * Single fd operation: this proc is only called for a connected
	 * socket.
	 */
968
969
970
971
972
973
974
975

976
977
978
979
980
981
982
963
964
965
966
967
968
969

970
971
972
973
974
975
976
977







-
+







	/*
	 * Check for error condition or overflow. In the event of overflow, we
	 * need to clear the FD_WRITE flag so we can detect the next writable
	 * event. Note that Windows only sends a new writable event after a
	 * send fails with WSAEWOULDBLOCK.
	 */

	error = WSAGetLastError();
	DWORD error = WSAGetLastError();
	if (error == WSAEWOULDBLOCK) {
	    CLEAR_BITS(statePtr->readyEvents, FD_WRITE);
	    if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
		*errorCodePtr = EWOULDBLOCK;
		written = -1;
		break;
	    }
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207

1208
1209
1210
1211
1212
1213
1214
1158
1159
1160
1161
1162
1163
1164

1165
1166
1167
1168
1169
1170

1171
1172
1173
1174
1175

1176
1177
1178
1179

1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194

1195
1196
1197
1198

1199
1200
1201
1202
1203
1204
1205
1206







-






-
+




-




-
+














-




-
+







TcpSetOptionProc(
    void *instanceData,		/* Socket state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Name of the option to set. */
    const char *value)		/* New value for option. */
{
    TcpState *statePtr = (TcpState *)instanceData;
    SOCKET sock;
    size_t len = 0;

    if (optionName != NULL) {
	len = strlen(optionName);
    }

    sock = statePtr->sockets->fd;
    SOCKET sock = statePtr->sockets->fd;

    if ((len > 1) && (optionName[1] == 'k') &&
	    (strncmp(optionName, "-keepalive", len) == 0)) {
	BOOL boolVar;
	int rtn;

	if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
	    return TCL_ERROR;
	}
	rtn = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
	int rtn = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
		(const char *) &boolVar, sizeof(boolVar));
	if (rtn != 0) {
	    Tcl_WinConvertError(WSAGetLastError());
	    if (interp) {
		TclPrintfResult(interp, "couldn't set socket option: %s",
			Tcl_PosixError(interp));
	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }
    if ((len > 1) && (optionName[1] == 'n') &&
	    (strncmp(optionName, "-nodelay", len) == 0)) {
	BOOL boolVar;
	int rtn;

	if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
	    return TCL_ERROR;
	}
	rtn = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
	int rtn = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
		(const char *) &boolVar, sizeof(boolVar));
	if (rtn != 0) {
	    Tcl_WinConvertError(WSAGetLastError());
	    if (interp) {
		TclPrintfResult(interp, "couldn't set socket option: %s",
			Tcl_PosixError(interp));
	    }
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274

1275
1276
1277
1278
1279
1280
1281
1240
1241
1242
1243
1244
1245
1246

1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264

1265
1266
1267
1268
1269
1270
1271
1272







-


















-
+







				 * for, or NULL to get all options and their
				 * values. */
    Tcl_DString *dsPtr)		/* Where to store the computed value;
				 * initialized by caller. */
{
    TcpState *statePtr = (TcpState *)instanceData;
    char host[NI_MAXHOST], port[NI_MAXSERV];
    SOCKET sock;
    size_t len = 0;
    int reverseDNS = 0;
#define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS"
#define HAVE_OPTION(option) \
	((len > 1) && (optionName[1] == option[1]) && \
	    (strncmp(optionName, option, len) == 0))

    /*
     * Go one step in async connect
     *
     * If any error is thrown save it as background error to report eventually
     * below.
     */

    if (!GOT_BITS(statePtr->flags, TCP_ASYNC_TEST_MODE)) {
	WaitForConnect(statePtr, NULL);
    }

    sock = statePtr->sockets->fd;
    SOCKET sock = statePtr->sockets->fd;
    if (optionName != NULL) {
	len = strlen(optionName);
    }

    if (HAVE_OPTION("-error")) {
	/*
	 * Do not return any errors if async connect is running.
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312


1313
1314
1315
1316
1317
1318
1319
1287
1288
1289
1290
1291
1292
1293


1294
1295
1296
1297
1298
1299


1300
1301
1302
1303
1304
1305
1306
1307
1308







-
-






-
-
+
+







		    statePtr->connectError = 0;
		}
	    } else {
		/*
		 * Report an eventual last error of the socket system.
		 */

		int optlen;
		int ret;
		DWORD err;

		/*
		 * Populate the err variable with a POSIX error
		 */

		optlen = sizeof(int);
		ret = getsockopt(sock, SOL_SOCKET, SO_ERROR,
		int optlen = sizeof(int);
		int ret = getsockopt(sock, SOL_SOCKET, SO_ERROR,
			(char *)&err, &optlen);

		/*
		 * The error was not returned directly but should be taken
		 * from WSA.
		 */

1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426




1427
1428
1429
1430
1431
1432
1433
1390
1391
1392
1393
1394
1395
1396



1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409



1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420







-
-
-













-
-
-
+
+
+
+







		}
		return TCL_ERROR;
	    }
	}
    }

    if ((len == 0) || HAVE_OPTION("-sockname")) {
	TcpFdList *fds;
	address sockname;
	socklen_t size;
	int found = 0;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
	    /*
	     * In async connect output an empty string
	     */

	    found = 1;
	} else {
	    for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
		sock = fds->fd;
		size = sizeof(sockname);
	    for (TcpFdList *fds = statePtr->sockets; fds; fds = fds->next) {
		address sockname;
		socklen_t size = sizeof(sockname);
		sock = fds->fd;
		if (getsockname(sock, &(sockname.sa), &size) >= 0) {
		    int flags = reverseDNS;

		    found = 1;
		    getnameinfo(&sockname.sa, size, host, sizeof(host),
			    NULL, 0, NI_NUMERICHOST);
		    Tcl_DStringAppendElement(dsPtr, host);
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503

1504
1505
1506
1507
1508
1509
1510
1460
1461
1462
1463
1464
1465
1466

1467
1468
1469
1470
1471
1472

1473
1474
1475
1476
1477
1478
1479
1480
1481

1482
1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
1495







-






-
+








-






-
+







			Tcl_PosixError(interp));
	    }
	    return TCL_ERROR;
	}
    }

    if ((len == 0) || HAVE_OPTION("-keepalive")) {
	int optlen;
	BOOL opt = FALSE;

	if (len == 0) {
	    sock = statePtr->sockets->fd;
	    Tcl_DStringAppendElement(dsPtr, "-keepalive");
	}
	optlen = sizeof(BOOL);
	int optlen = sizeof(BOOL);
	getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, &optlen);
	Tcl_DStringAppendElement(dsPtr, opt ? "1" : "0");
	if (len > 0) {
	    return TCL_OK;
	}
    }

    if ((len == 0) || HAVE_OPTION("-nodelay")) {
	int optlen;
	BOOL opt = FALSE;

	if (len == 0) {
	    sock = statePtr->sockets->fd;
	    Tcl_DStringAppendElement(dsPtr, "-nodelay");
	}
	optlen = sizeof(BOOL);
	int optlen = sizeof(BOOL);
	getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, &optlen);
	Tcl_DStringAppendElement(dsPtr, opt ? "1" : "0");
	if (len > 0) {
	    return TCL_OK;
	}
    }

1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763

1764

1765
1766
1767
1768
1769
1770
1771
1722
1723
1724
1725
1726
1727
1728



1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746

1747
1748
1749
1750
1751
1752
1753
1754







-
-
-

















+
-
+








	    /*
	     * For asynchronous connect set the socket in nonblocking mode
	     * and activate connect notification
	     */

	    if (async_connect) {
		TcpState *statePtr2;
		int in_socket_list = 0;

		/*
		 * Get statePtr lock.
		 */

		WaitForSingleObject(tsdPtr->socketListLock, INFINITE);

		/*
		 * Bugfig for 336441ed59 to not ignore notifications until the
		 * infoPtr is in the list.
		 * Check if my statePtr is already in the tsdPtr->socketList
		 * It is set after this call by TcpThreadActionProc and is set
		 * on a second round.
		 *
		 * If not, we buffer my statePtr in the tsd memory so it is
		 * not lost by the event procedure
		 */

		int in_socket_list = 0;
		for (statePtr2 = tsdPtr->socketList; statePtr2 != NULL;
		for (TcpState *statePtr2 = tsdPtr->socketList; statePtr2;
			statePtr2 = statePtr2->nextPtr) {
		    if (statePtr2 == statePtr) {
			in_socket_list = 1;
			break;
		    }
		}
		if (!in_socket_list) {
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2087
2088
2089
2090
2091
2092
2093

2094
2095
2096
2097
2098
2099
2100







-







				/* Callback for accepting connections from new
				 * clients. */
    void *acceptProcData)	/* Data for the callback. */
{
    SOCKET sock = INVALID_SOCKET;
    unsigned short chosenport = 0;
    struct addrinfo *addrlist = NULL;
    struct addrinfo *addrPtr;	/* Socket address to listen on. */
    TcpState *statePtr = NULL;	/* The returned value. */
    char channelName[SOCK_CHAN_LENGTH];
    u_long flag = 1;		/* Indicates nonblocking mode. */
    const char *errorMsg = NULL;
    int optvalue, port;

    TclInitSockets();
2127
2128
2129
2130
2131
2132
2133

2134

2135
2136
2137
2138
2139
2140
2141
2109
2110
2111
2112
2113
2114
2115
2116

2117
2118
2119
2120
2121
2122
2123
2124







+
-
+







    }

    if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1,
	    &errorMsg)) {
	goto error;
    }

    for (struct addrinfo *addrPtr = addrlist; addrPtr != NULL;
    for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
	    addrPtr = addrPtr->ai_next) {
	sock = socket(addrPtr->ai_family, addrPtr->ai_socktype,
		addrPtr->ai_protocol);
	if (sock == INVALID_SOCKET) {
	    Tcl_WinConvertError((DWORD) WSAGetLastError());
	    continue;
	}

2465
2466
2467
2468
2469
2470
2471
2472
2473

2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484

2485
2486
2487
2488
2489
2490
2491
2448
2449
2450
2451
2452
2453
2454


2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465

2466
2467
2468
2469
2470
2471
2472
2473







-
-
+










-
+







 */

void
SocketSetupProc(
    TCL_UNUSED(void *),
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    TcpState *statePtr;
    Tcl_Time blockTime = { 0, 0 };
    const Tcl_Time blockTime = { 0, 0 };
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
	return;
    }

    /*
     * Check to see if there is a ready socket.	 If so, poll.
     */
    WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
    for (statePtr = tsdPtr->socketList; statePtr != NULL;
    for (TcpState *statePtr = tsdPtr->socketList; statePtr != NULL;
	    statePtr = statePtr->nextPtr) {
	if (GOT_BITS(statePtr->readyEvents,
		statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) {
	    Tcl_SetMaxBlockTime(&blockTime);
	    break;
	}
    }
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532

2533
2534
2535
2536
2537

2538

2539
2540
2541
2542
2543
2544
2545
2492
2493
2494
2495
2496
2497
2498


2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511

2512
2513
2514
2515
2516
2517
2518

2519
2520
2521
2522
2523
2524
2525
2526







-
-













-
+





+
-
+







 */

static void
SocketCheckProc(
    TCL_UNUSED(void *),
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    TcpState *statePtr;
    SocketEvent *evPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
	return;
    }

    /*
     * Queue events for any ready sockets that don't already have events
     * queued (caused by persistent states that won't generate WinSock
     * events).
     */

    WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
    for (statePtr = tsdPtr->socketList; statePtr != NULL;
    for (TcpState *statePtr = tsdPtr->socketList; statePtr != NULL;
	    statePtr = statePtr->nextPtr) {
	if (GOT_BITS(statePtr->readyEvents,
		statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)
		&& !GOT_BITS(statePtr->flags, SOCKET_PENDING)) {
	    SET_BITS(statePtr->flags, SOCKET_PENDING);

	    evPtr = (SocketEvent *)Tcl_Alloc(sizeof(SocketEvent));
	    SocketEvent *evPtr = (SocketEvent *)Tcl_Alloc(sizeof(SocketEvent));
	    evPtr->header.proc = SocketEventProc;
	    evPtr->socket = statePtr->sockets->fd;
	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
	}
    }
    SetEvent(tsdPtr->socketListLock);
}
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2552
2553
2554
2555
2556
2557
2558

2559
2560
2561
2562
2563
2564
2565







-







    int flags)			/* Flags that indicate what events to handle,
				 * such as TCL_FILE_EVENTS. */
{
    TcpState *statePtr;
    SocketEvent *eventPtr = (SocketEvent *) evPtr;
    int mask = 0, events;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
    TcpFdList *fds;
    SOCKET newSocket;
    address addr;
    int len;

    if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
	return 0;
    }
2635
2636
2637
2638
2639
2640
2641
2642

2643
2644
2645
2646
2647
2648
2649
2615
2616
2617
2618
2619
2620
2621

2622
2623
2624
2625
2626
2627
2628
2629







-
+







    }

    /*
     * Handle connection requests directly.
     */

    if (GOT_BITS(statePtr->readyEvents, FD_ACCEPT)) {
	for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
	for (TcpFdList *fds = statePtr->sockets; fds != NULL; fds = fds->next) {
	    /*
	     * Accept the incoming connection request.
	     */

	    len = sizeof(address);
	    newSocket = accept(fds->fd, &(addr.sa), &len);

3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3030
3031
3032
3033
3034
3035
3036

3037
3038
3039
3040
3041
3042
3043







-







    WPARAM wParam,
    LPARAM lParam)
{
    int event, error;
    SOCKET socket;
    TcpState *statePtr;
    int info_found = 0;
    TcpFdList *fds = NULL;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
#ifdef _WIN64
	    GetWindowLongPtrW(hwnd, GWLP_USERDATA);
#else
	    GetWindowLongW(hwnd, GWL_USERDATA);
#endif

3157
3158
3159
3160
3161
3162
3163
3164

3165
3166
3167
3168
3169
3170
3171
3136
3137
3138
3139
3140
3141
3142

3143
3144
3145
3146
3147
3148
3149
3150







-
+







	    Tcl_ThreadAlert(tsdPtr->threadId);
	}
	SetEvent(tsdPtr->socketListLock);
	break;

    case SOCKET_SELECT:
	statePtr = (TcpState *) lParam;
	for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
	for (TcpFdList *fds = statePtr->sockets; fds != NULL; fds = fds->next) {
	    if (wParam == SELECT) {
		WSAAsyncSelect(fds->fd, hwnd,
			SOCKET_MESSAGE, statePtr->selectEvents);
	    } else {
		/*
		 * Clear the selection mask
		 */
3200
3201
3202
3203
3204
3205
3206
3207
3208

3209
3210
3211
3212
3213
3214
3215
3179
3180
3181
3182
3183
3184
3185


3186
3187
3188
3189
3190
3191
3192
3193







-
-
+







 */

static int
FindFDInList(
    TcpState *statePtr,
    SOCKET socket)
{
    TcpFdList *fds;
    for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
    for (TcpFdList *fds = statePtr->sockets; fds != NULL; fds = fds->next) {
	if (fds->fd == socket) {
	    return 1;
	}
    }
    return 0;
}

3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249




3250

3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277




3278
3279
3280
3281
3282
3283
3284
3208
3209
3210
3211
3212
3213
3214




3215
3216
3217
3218
3219
3220
3221


3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239

3240
3241


3242
3243
3244
3245
3246
3247




3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258







-
-
-
-







-
-
+
+
+
+

+












-


-
-






-
-
-
-
+
+
+
+







 */

static void
TcpThreadActionProc(
    void *instanceData,
    int action)
{
    ThreadSpecificData *tsdPtr;
    TcpState *statePtr = (TcpState *)instanceData;
    int notifyCmd;

    if (action == TCL_CHANNEL_THREAD_INSERT) {
	/*
	 * Ensure that socket subsystem is initialized in this thread, or else
	 * sockets will not work.
	 */

	TclInitSockets();

	tsdPtr = TCL_TSD_INIT(&dataKey);
    }
    TcpState *statePtr = (TcpState *)instanceData;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
    int notifyCmd;

    if (action == TCL_CHANNEL_THREAD_INSERT) {
	WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
	statePtr->nextPtr = tsdPtr->socketList;
	tsdPtr->socketList = statePtr;

	if (statePtr == tsdPtr->pendingTcpState) {
	    tsdPtr->pendingTcpState = NULL;
	}

	SetEvent(tsdPtr->socketListLock);

	notifyCmd = SELECT;
    } else {
	TcpState **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) == statePtr) {
		(*nextPtrPtr) = statePtr->nextPtr;
	for (TcpState **nextPtrPtr = &tsdPtr->socketList; *nextPtrPtr != NULL;
		nextPtrPtr = &(*nextPtrPtr)->nextPtr) {
	    if (*nextPtrPtr == statePtr) {
		*nextPtrPtr = statePtr->nextPtr;
		removed = 1;
		break;
	    }
	}
	SetEvent(tsdPtr->socketListLock);

	/*