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 $
*
* -----------------------------------------------------------------------
*
* General information on how this module works.
*
* - Each Tcl-thread with its sockets maintains an internal window to receive
* socket messages from the OS.
|
|
|
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.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
|
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
|
|
|
|
|
|
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
|
* 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;
|
|
|
|
|
|
|
|
|
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
|
}
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 {
|
|
|
|
|
|
|
|
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
|
}
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);
}
|
|
|
|
|
|
|
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
|
*/
infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
if (infoPtr == NULL) {
return NULL;
}
wsprintfA(channelName, "sock%d", 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;
|
|
|
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;
}
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
|
* 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);
infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
infoPtr, (TCL_READABLE | TCL_WRITABLE));
Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
return infoPtr->channel;
}
/*
|
|
|
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);
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
|
if (infoPtr == NULL) {
return NULL;
}
infoPtr->acceptProc = acceptProc;
infoPtr->acceptProcData = acceptProcData;
wsprintfA(channelName, "sock%d", 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;
|
|
|
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;
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
|
* 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);
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;
}
|
|
|
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);
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
|
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) {
|
|
|
|
|
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
|
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");
|
|
|
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");
|
| ︙ | | | ︙ | |