Diff
Not logged in

Differences From Artifact [a5fbbd6b84]:

To Artifact [d91a7fd853]:


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.81 2010/12/14 17:22:55 rmax Exp $
 * RCS: @(#) $Id: tclWinSock.c,v 1.82 2011/01/25 22:33:56 nijtmans Exp $
 *
 * -----------------------------------------------------------------------
 *
 * General information on how this module works.
 *
 * - Each Tcl-thread with its sockets maintains an internal window to receive
 *   socket messages from the OS.
1046
1047
1048
1049
1050
1051
1052
1053

1054
1055
1056
1057
1058

1059
1060

1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
1046
1047
1048
1049
1050
1051
1052

1053
1054
1055
1056
1057

1058
1059

1060
1061
1062
1063

1064
1065
1066
1067
1068
1069
1070
1071







-
+




-
+

-
+



-
+







	TcpFdList *fds = NULL, *newfds;
	for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
	    sock = socket(addrPtr->ai_family, SOCK_STREAM, 0);
	    if (sock == INVALID_SOCKET) {
		TclWinConvertWSAError((DWORD) WSAGetLastError());
		continue;
	    }
	

	    /*
	     * Win-NT has a misfeature that sockets are inherited in child
	     * processes by default. Turn off the inherit bit.
	     */
	    

	    SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
	    

	    /*
	     * Set kernel space buffering
	     */
	    

	    TclSockMinimumBuffers((ClientData)sock, TCP_BUFFER_SIZE);

	    /*
	     * Make sure we use the same port when opening two server sockets
	     * for IPv4 and IPv6.
	     *
	     * As sockaddr_in6 uses the same offset and size for the port
1099
1100
1101
1102
1103
1104
1105
1106

1107
1108
1109
1110
1111
1112

1113
1114
1115
1116
1117
1118

1119
1120
1121
1122
1123

1124
1125
1126

1127
1128
1129
1130

1131
1132
1133

1134
1135
1136
1137
1138
1139
1140
1099
1100
1101
1102
1103
1104
1105

1106
1107
1108
1109
1110
1111

1112
1113
1114
1115
1116
1117

1118
1119
1120
1121
1122

1123
1124
1125

1126
1127
1128
1129

1130
1131
1132

1133
1134
1135
1136
1137
1138
1139
1140







-
+





-
+





-
+




-
+


-
+



-
+


-
+







		 * Synchronize port numbers when binding to port 0 of multiple
		 * addresses.
		 */
		if (getsockname(sock, &sockname.sa, &namelen) >= 0) {
		    chosenport = ntohs(sockname.sa4.sin_port);
		}
	    }
	    

	    /*
	     * Set the maximum number of pending connect requests to the max value
	     * allowed on each platform (Win32 and Win32s may be different, and
	     * there may be differences between TCP/IP stacks).
	     */
	    

	    if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
		TclWinConvertWSAError((DWORD) WSAGetLastError());
		closesocket(sock);
		continue;
	    }
	    

	    if (infoPtr == NULL) {
		/*
		 * Add this socket to the global list of sockets.
		 */
		

		infoPtr = NewSocketInfo(sock);
		fds = infoPtr->sockets;
		

		/*
		 * Set up the select mask for connection request events.
		 */
		

		infoPtr->selectEvents = FD_ACCEPT;
		infoPtr->watchEvents |= FD_ACCEPT;
		

	    } else {
		newfds = (TcpFdList *) ckalloc((unsigned) sizeof(TcpFdList));
		memset(newfds, (int) 0, sizeof(TcpFdList));
		newfds->fd = sock;
		newfds->infoPtr = infoPtr;
		newfds->next = NULL;
		fds->next = newfds;
1155
1156
1157
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
1207

1208
1209
1210
1211
1212
1213
1214
1155
1156
1157
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

1207
1208
1209
1210
1211
1212
1213
1214







-
+










-
+

-
+



-
+




















-
+






-
+







		}

		sock = socket(myaddrPtr->ai_family, SOCK_STREAM, 0);
		if (sock == INVALID_SOCKET) {
		    TclWinConvertWSAError((DWORD) WSAGetLastError());
		    continue;
		}
		

		/*
		 * Win-NT has a misfeature that sockets are inherited in child
		 * processes by default. Turn off the inherit bit.
		 */

		SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);

		/*
		 * Set kernel space buffering
		 */
		

		TclSockMinimumBuffers((ClientData)sock, TCP_BUFFER_SIZE);
		

		/*
		 * Try to bind to a local port.
		 */
		

		if (bind(sock, myaddrPtr->ai_addr, myaddrPtr->ai_addrlen)
		    == SOCKET_ERROR) {
		    TclWinConvertWSAError((DWORD) WSAGetLastError());
		    goto looperror;
		}
		/*
		 * Set the socket into nonblocking mode if the connect should
		 * be done in the background.
		 */
		if (async) {
		    if (ioctlsocket(sock, (long) FIONBIO, &flag)
			== SOCKET_ERROR) {
			TclWinConvertWSAError((DWORD) WSAGetLastError());
			goto looperror;
		    }
		}

		/*
		 * Attempt to connect to the remote socket.
		 */
		

		if (connect(sock, addrPtr->ai_addr, addrPtr->ai_addrlen)
		    == SOCKET_ERROR) {
		    TclWinConvertWSAError((DWORD) WSAGetLastError());
		    if (Tcl_GetErrno() != EWOULDBLOCK) {
			goto looperror;
		    }
		    

		    /*
		     * The connection is progressing in the background.
		     */

		    asyncConnect = 1;
		    goto connected;
		} else {
1223
1224
1225
1226
1227
1228
1229
1230

1231
1232

1233
1234
1235
1236
1237

1238
1239
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
1223
1224
1225
1226
1227
1228
1229

1230
1231

1232
1233
1234
1235
1236

1237
1238
1239
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







-
+

-
+




-
+

















-
+



-
+







	}
	goto error;

    connected:
	/*
	 * Add this socket to the global list of sockets.
	 */
	

	infoPtr = NewSocketInfo(sock);
	

	/*
	 * Set up the select mask for read/write events. If the
	 * connect attempt has not completed, include connect events.
	 */
	    

	infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
	if (asyncConnect) {
	    infoPtr->flags |= SOCKET_ASYNC_CONNECT;
	    infoPtr->selectEvents |= FD_CONNECT;
	}
    }

  error:
    if (addrlist == NULL)
	freeaddrinfo(addrlist);
    if (myaddrlist == NULL)
	freeaddrinfo(myaddrlist);

    /*
     * Register for interest in events in the select mask. Note that this
     * automatically places the socket into non-blocking mode.
     */
    

    if (infoPtr != NULL) {
	ioctlsocket(sock, (long) FIONBIO, &flag);
	SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr);
	

	return infoPtr;
    }

    if (interp != NULL) {
	Tcl_AppendResult(interp, "couldn't open socket: ",
		Tcl_PosixError(interp), NULL);
    }
1451
1452
1453
1454
1455
1456
1457
1458

1459
1460
1461
1462
1463
1464
1465
1451
1452
1453
1454
1455
1456
1457

1458
1459
1460
1461
1462
1463
1464
1465







-
+







     */

    infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
    if (infoPtr == NULL) {
	return NULL;
    }

    wsprintfA(channelName, "sock%d", infoPtr->sockets->fd);
    sprintf(channelName, "sock%Id", (size_t) infoPtr->sockets->fd);

    infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    infoPtr, (TCL_READABLE | TCL_WRITABLE));
    if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
	return (Tcl_Channel) NULL;
1516
1517
1518
1519
1520
1521
1522
1523

1524
1525
1526
1527
1528
1529
1530
1516
1517
1518
1519
1520
1521
1522

1523
1524
1525
1526
1527
1528
1529
1530







-
+







     * Start watching for read/write events on the socket.
     */

    infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
	    (WPARAM) SELECT, (LPARAM) infoPtr);

    wsprintfA(channelName, "sock%d", infoPtr->sockets->fd);
    sprintf(channelName, "sock%Id", (size_t) infoPtr->sockets->fd);
    infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    infoPtr, (TCL_READABLE | TCL_WRITABLE));
    Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
    return infoPtr->channel;
}

/*
1569
1570
1571
1572
1573
1574
1575
1576

1577
1578
1579
1580
1581
1582
1583
1569
1570
1571
1572
1573
1574
1575

1576
1577
1578
1579
1580
1581
1582
1583







-
+







    if (infoPtr == NULL) {
	return NULL;
    }

    infoPtr->acceptProc = acceptProc;
    infoPtr->acceptProcData = acceptProcData;

    wsprintfA(channelName, "sock%d", infoPtr->sockets->fd);
    sprintf(channelName, "sock%Id", (size_t) infoPtr->sockets->fd);

    infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    infoPtr, 0);
    if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")
	    == TCL_ERROR) {
	Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
	return (Tcl_Channel) NULL;
1675
1676
1677
1678
1679
1680
1681
1682

1683
1684
1685
1686
1687
1688
1689
1675
1676
1677
1678
1679
1680
1681

1682
1683
1684
1685
1686
1687
1688
1689







-
+







     * Select on read/write events and create the channel.
     */

    newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
	    (WPARAM) SELECT, (LPARAM) newInfoPtr);

    wsprintfA(channelName, "sock%d", newInfoPtr->sockets->fd);
    sprintf(channelName, "sock%Id", (size_t) newInfoPtr->sockets->fd);
    newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
    if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
	return;
    }
2167
2168
2169
2170
2171
2172
2173
2174

2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185

2186
2187
2188
2189

2190
2191
2192
2193
2194
2195
2196
2167
2168
2169
2170
2171
2172
2173

2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184

2185
2186
2187
2188

2189
2190
2191
2192
2193
2194
2195
2196







-
+










-
+



-
+







    if ((len == 0) || ((len > 1) && (optionName[1] == 's') &&
	    (strncmp(optionName, "-sockname", len) == 0))) {

	TcpFdList *fds;
        address sockname;
        socklen_t size;
	int found = 0;
	

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) {
	    sock = fds->fd;
	    size = sizeof(sockname);
	    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);
	    

		/*
		 * We don't want to resolve INADDR_ANY and sin6addr_any; they
		 * can sometimes cause problems (and never have a name).
		 */
		flags |= NI_NUMERICSERV;
		if (sockname.sa.sa_family == AF_INET) {
		    if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) {
2224
2225
2226
2227
2228
2229
2230
2231

2232
2233
2234
2235
2236
2237
2238
2224
2225
2226
2227
2228
2229
2230

2231
2232
2233
2234
2235
2236
2237
2238







-
+







		TclWinConvertWSAError((DWORD) WSAGetLastError());
		Tcl_AppendResult(interp, "can't get sockname: ",
				 Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
    }
	

#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
    if (len == 0 || !strncmp(optionName, "-keepalive", len)) {
	int optlen;
	BOOL opt = FALSE;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-keepalive");