diff options
author | davygrvy <davygrvy@pobox.com> | 2008-12-10 02:12:16 (GMT) |
---|---|---|
committer | davygrvy <davygrvy@pobox.com> | 2008-12-10 02:12:16 (GMT) |
commit | 8817f6b6137d1d30d4745d71573f962f19562eb8 (patch) | |
tree | 00981ca67fd3fda5e461941a57fc0c78790ec535 | |
parent | 53ae9f94958573bbd8df85390fdf7ea4b2902737 (diff) | |
download | tcl-8817f6b6137d1d30d4745d71573f962f19562eb8.zip tcl-8817f6b6137d1d30d4745d71573f962f19562eb8.tar.gz tcl-8817f6b6137d1d30d4745d71573f962f19562eb8.tar.bz2 |
Can almost open UDP sockets.. WSARecv bails with 10014 (WSAEFAULT), researching..
-rw-r--r-- | win/tclWinsockBTH.c | 4 | ||||
-rw-r--r-- | win/tclWinsockCore.c | 56 | ||||
-rw-r--r-- | win/tclWinsockCore.h | 3 | ||||
-rw-r--r-- | win/tclWinsockTCP.c | 4 | ||||
-rw-r--r-- | win/tclWinsockUDP.c | 236 |
5 files changed, 293 insertions, 10 deletions
diff --git a/win/tclWinsockBTH.c b/win/tclWinsockBTH.c index 0253c53..b4435f2 100644 --- a/win/tclWinsockBTH.c +++ b/win/tclWinsockBTH.c @@ -4,8 +4,8 @@ #include "tclWinsockCore.h" #include <ws2bth.h> -#include <Bthsdpdef.h> -#include <BluetoothAPIs.h> +//#include <Bthsdpdef.h> +//#include <BluetoothAPIs.h> static Tcl_NetCreateClientProc OpenBthClientChannel; static Tcl_NetCreateServerProc OpenBthServerChannel; diff --git a/win/tclWinsockCore.c b/win/tclWinsockCore.c index 8ec5059..10aac73 100644 --- a/win/tclWinsockCore.c +++ b/win/tclWinsockCore.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinsockCore.c,v 1.1.2.7 2008/12/09 19:52:05 davygrvy Exp $ + * RCS: @(#) $Id: tclWinsockCore.c,v 1.1.2.8 2008/12/10 02:12:16 davygrvy Exp $ */ #include "tclWinInt.h" @@ -86,7 +86,9 @@ static Tcl_EventDeleteProc IocpRemoveAllPendingEvents; static Tcl_DriverCloseProc IocpCloseProc; static Tcl_DriverInputProc IocpInputProc; +static Tcl_DriverInputProc IocpInputNotSupProc; static Tcl_DriverOutputProc IocpOutputProc; +static Tcl_DriverOutputProc IocpOutputNotSupProc; static Tcl_DriverSetOptionProc IocpSetOptionProc; static Tcl_DriverGetOptionProc IocpGetOptionProc; static Tcl_DriverWatchProc IocpWatchProc; @@ -141,8 +143,8 @@ static BOOL PASCAL OurDisconnectEx(SOCKET hSocket, * in kernel-mode. */ -Tcl_ChannelType IocpChannelType = { - "sock", /* Type name. */ +Tcl_ChannelType IocpStreamChannelType = { + "iocp_stream", /* Type name. */ TCL_CHANNEL_VERSION_5, IocpCloseProc, /* Close proc. */ IocpInputProc, /* Input proc. */ @@ -161,6 +163,26 @@ Tcl_ChannelType IocpChannelType = { NULL /* truncate */ }; +Tcl_ChannelType IocpPacketChannelType = { + "iocp_packet", /* Type name. */ + TCL_CHANNEL_VERSION_5, + IocpCloseProc, /* Close proc. */ + IocpInputNotSupProc, /* Input proc. */ + IocpOutputNotSupProc, /* Output proc. */ + NULL, /* Seek proc. */ + IocpSetOptionProc, /* Set option proc. */ + IocpGetOptionProc, /* Get option proc. */ + IocpWatchProc, /* Set up notifier to watch this channel. */ + IocpGetHandleProc, /* Get an OS handle from channel. */ + NULL, /* close2proc. */ + IocpBlockProc, /* Set socket into (non-)blocking mode. */ + NULL, /* flush proc. */ + NULL, /* handler proc. */ + NULL, /* wide seek */ + IocpThreadActionProc, /* TIP #218. */ + NULL /* truncate */ +}; + typedef struct SocketEvent { Tcl_Event header; /* Information that is standard for @@ -596,7 +618,7 @@ Tcl_MakeSocketClientChannel ( } snprintf(channelName, 4 + TCL_INTEGER_SPACE, "sock%lu", infoPtr->socket); - infoPtr->channel = Tcl_CreateChannel(&IocpChannelType, channelName, + infoPtr->channel = Tcl_CreateChannel(&IocpStreamChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf"); SetLastError(ERROR_SUCCESS); @@ -988,7 +1010,7 @@ IocpAcceptOne (SocketInfo *infoPtr) } snprintf(channelName, 4 + TCL_INTEGER_SPACE, "sock%lu", acptInfo->clientInfo->socket); - acptInfo->clientInfo->channel = Tcl_CreateChannel(&IocpChannelType, channelName, + acptInfo->clientInfo->channel = Tcl_CreateChannel(&IocpStreamChannelType, channelName, (ClientData) acptInfo->clientInfo, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(NULL, acptInfo->clientInfo->channel, "-translation", "auto crlf") == TCL_ERROR) { @@ -1190,6 +1212,18 @@ error: } static int +IocpInputNotSupProc ( + ClientData instanceData, /* The socket state. */ + char *buf, /* Where to store data. */ + int toRead, /* Maximum number of bytes to read. */ + int *errorCodePtr) /* Where to store error codes. */ +{ + Tcl_SetErrno(EOPNOTSUPP); + *errorCodePtr = Tcl_GetErrno(); + return -1; +} + +static int FilterPartialRecvBufMerge ( SocketInfo *infoPtr, BufferInfo *bufPtr, @@ -1415,6 +1449,18 @@ error: } static int +IocpOutputNotSupProc ( + ClientData instanceData, /* The socket state. */ + CONST char *buf, /* Where to get data. */ + int toWrite, /* Maximum number of bytes to write. */ + int *errorCodePtr) /* Where to store error codes. */ +{ + Tcl_SetErrno(EOPNOTSUPP); + *errorCodePtr = Tcl_GetErrno(); + return -1; +} + +static int IocpSetOptionProc ( ClientData instanceData, /* Socket state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ diff --git a/win/tclWinsockCore.h b/win/tclWinsockCore.h index 78692ba..a4ecfae 100644 --- a/win/tclWinsockCore.h +++ b/win/tclWinsockCore.h @@ -281,7 +281,8 @@ typedef struct CompletionPortInfo { #define IOCP_SEND_CAP 20 -extern Tcl_ChannelType IocpChannelType; +extern Tcl_ChannelType IocpStreamChannelType; +extern Tcl_ChannelType IocpPacketChannelType; extern CompletionPortInfo IocpSubSystem; extern void IocpInitProtocolData (SOCKET sock, WS2ProtocolData *pdata); diff --git a/win/tclWinsockTCP.c b/win/tclWinsockTCP.c index 026b077..d3512a0 100644 --- a/win/tclWinsockTCP.c +++ b/win/tclWinsockTCP.c @@ -190,7 +190,7 @@ OpenTcpClientChannel( return NULL; } snprintf(channelName, 4 + TCL_INTEGER_SPACE, "sock%lu", infoPtr->socket); - infoPtr->channel = Tcl_CreateChannel(&IocpChannelType, channelName, + infoPtr->channel = Tcl_CreateChannel(&IocpStreamChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation", "auto crlf") == TCL_ERROR) { @@ -232,7 +232,7 @@ OpenTcpServerChannel( infoPtr->acceptProc = acceptProc; infoPtr->acceptProcData = acceptProcData; snprintf(channelName, 4 + TCL_INTEGER_SPACE, "sock%lu", infoPtr->socket); - infoPtr->channel = Tcl_CreateChannel(&IocpChannelType, channelName, + infoPtr->channel = Tcl_CreateChannel(&IocpStreamChannelType, channelName, (ClientData) infoPtr, 0); if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") == TCL_ERROR) { diff --git a/win/tclWinsockUDP.c b/win/tclWinsockUDP.c index 1f54198..2e5ef51 100644 --- a/win/tclWinsockUDP.c +++ b/win/tclWinsockUDP.c @@ -2,6 +2,11 @@ #include "tclWinInt.h" #include "tclWinsockCore.h" +/* ISO hack for dumb VC++ */ +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + static Tcl_NetCreateClientProc OpenUdpClientChannel; WS2ProtocolData udpAnyProtoData = { @@ -59,6 +64,11 @@ WS2ProtocolData udp6ProtoData = { NULL }; +static SocketInfo * CreateUdpSocket(Tcl_Interp *interp, + const char *port, const char *host, + const char *myaddr, + const char *myport, int afhint); + Tcl_Channel OpenUdpClientChannel( @@ -71,5 +81,231 @@ OpenUdpClientChannel( * client socket asynchronously. */ int afhint) { + SocketInfo *infoPtr; + char channelName[4 + TCL_INTEGER_SPACE]; + + + /* + * Create a new client socket and wrap it in a channel. + */ + + infoPtr = CreateUdpSocket(interp, port, host, myaddr, myport, afhint); + if (infoPtr == NULL) { + return NULL; + } + snprintf(channelName, 4 + TCL_INTEGER_SPACE, "sock%lu", infoPtr->socket); + infoPtr->channel = Tcl_CreateChannel(&IocpPacketChannelType, channelName, + (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); + if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation", + "binary") == TCL_ERROR) { + Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); + return (Tcl_Channel) NULL; + } + if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "") + == TCL_ERROR) { + Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); + return (Tcl_Channel) NULL; + } + + return infoPtr->channel; +} + +SocketInfo * +CreateUdpSocket( + Tcl_Interp *interp, + const char *port, + const char *host, + const char *myaddr, + const char *myport, + int afhint) +{ + u_long flag = 1; /* Indicates nonblocking mode. */ + int asyncConnect = 0; /* Will be 1 if async connect is + * in progress. */ + LPADDRINFO hostaddr; /* Socket address for peer */ + LPADDRINFO mysockaddr; /* Socket address for client */ + SOCKET sock = INVALID_SOCKET; + SocketInfo *infoPtr = NULL; /* The returned value. */ + BufferInfo *bufPtr; /* The returned value. */ + //DWORD bytes; + BOOL code; + int i; + WS2ProtocolData *pdata; + ADDRINFO hints; + LPADDRINFO addr; + WSAPROTOCOL_INFO wpi; + ThreadSpecificData *tsdPtr = InitSockets(); + + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = afhint; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (host == NULL && !strcmp(port, "0")) { + /* Win2K hack. Ask for port 1, then set to 0 so getaddrinfo() doesn't bomb. */ + if (! CreateSocketAddress(host, "1", &hints, &hostaddr)) { + goto error1; + } + addr = hostaddr; + while (addr) { + if (addr->ai_family == AF_INET) { + ((LPSOCKADDR_IN)addr->ai_addr)->sin_port = INADDR_ANY; + } else { + IN6ADDR_SETANY((LPSOCKADDR_IN6) addr->ai_addr); + } + addr = addr->ai_next; + } + } else { + if (! CreateSocketAddress(host, port, &hints, &hostaddr)) { + goto error1; + } + } + addr = hostaddr; + + if (myaddr != NULL || myport != NULL) { + if (!CreateSocketAddress(myaddr, myport, addr, &mysockaddr)) { + goto error2; + } + } else if (1) { + /* Win2K hack. Ask for port 1, then set to 0 so getaddrinfo() doesn't bomb. */ + if (!CreateSocketAddress(NULL, "1", addr, &mysockaddr)) { + goto error2; + } + if (mysockaddr->ai_family == AF_INET) { + ((LPSOCKADDR_IN)mysockaddr->ai_addr)->sin_port = INADDR_ANY; + } else { + IN6ADDR_SETANY((LPSOCKADDR_IN6) mysockaddr->ai_addr); + } + } + + + switch (addr->ai_family) { + case AF_INET: + pdata = &udp4ProtoData; break; + case AF_INET6: + pdata = &udp6ProtoData; break; + default: + Tcl_Panic("very bad protocol family returned from getaddrinfo()"); + } + + code = FindProtocolInfo(pdata->af, pdata->type, pdata->protocol, + 0 /*XP1_QOS_SUPPORTED*/, &wpi); + if (code == FALSE) { + goto error2; + } + + sock = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, &wpi, 0, WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + goto error2; + } + + IocpInitProtocolData(sock, pdata); + + /* + * 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); + + /* + * Turn off the internal send buffing. We get more speed and are + * more efficient by reducing memcpy calls as the stack will use + * our overlapped buffers directly. + */ + + i = 0; + if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, + (const char *) &i, sizeof(int)) == SOCKET_ERROR) { + goto error2; + } + + infoPtr = NewSocketInfo(sock); + infoPtr->proto = pdata; + + /* Info needed to get back to this thread. */ + infoPtr->tsdHome = tsdPtr; + + /* + * bind to a local address. ConnectEx needs this. + */ + + if (bind(sock, mysockaddr->ai_addr, + mysockaddr->ai_addrlen) == SOCKET_ERROR) { + FreeSocketAddress(mysockaddr); + goto error2; + } + FreeSocketAddress(mysockaddr); + +#if 0 + /* + * Associate remote for filtering. + */ + + code = connect(sock, addr->ai_addr, addr->ai_addrlen); + FreeSocketAddress(hostaddr); + if (code == SOCKET_ERROR) { + goto error1; + } +#endif + + /* + * Associate the socket and its SocketInfo struct to the + * completion port. This implies an automatic set to + * non-blocking. We emulate blocking to the Tcl side. + */ + if (CreateIoCompletionPort((HANDLE)sock, IocpSubSystem.port, + (ULONG_PTR)infoPtr, 0) == NULL) { + WSASetLastError(GetLastError()); + goto error1; + } + + infoPtr->llPendingRecv = IocpLLCreate(); + + /* post IOCP_INITIAL_RECV_COUNT recvs. */ + for(i=0; i < IOCP_INITIAL_RECV_COUNT ;i++) { + bufPtr = GetBufferObj(infoPtr, + (infoPtr->recvMode == IOCP_RECVMODE_ZERO_BYTE ? 0 : IOCP_RECV_BUFSIZE)); + if (PostOverlappedRecv(infoPtr, bufPtr, 0, 0)) { + FreeBufferObj(bufPtr); + goto error1; + } + } +#if 0 + { + int ret; + QOS clientQos; + DWORD dwBytes; + + ZeroMemory(&clientQos, sizeof(QOS)); + clientQos.SendingFlowspec = flowspec_g711; + clientQos.ReceivingFlowspec = flowspec_notraffic; + clientQos.ProviderSpecific.buf = NULL; + clientQos.ProviderSpecific.len = 0; + + /*clientQos.SendingFlowspec.ServiceType |= + SERVICE_NO_QOS_SIGNALING; + clientQos.ReceivingFlowspec.ServiceType |= + SERVICE_NO_QOS_SIGNALING;*/ + + ret = WSAIoctl(sock, SIO_SET_QOS, &clientQos, + sizeof(clientQos), NULL, 0, &dwBytes, NULL, NULL); + } + bufPtr = GetBufferObj(infoPtr, QOS_BUFFER_SZ); + PostOverlappedQOS(infoPtr, bufPtr); +#endif + + return infoPtr; + +error2: + FreeSocketAddress(hostaddr); +error1: + TclWinConvertWSAError(WSAGetLastError()); + if (interp != NULL) { + Tcl_AppendResult(interp, "couldn't open socket: ", + Tcl_PosixError(interp), NULL); + } + FreeSocketInfo(infoPtr); return NULL; } |