summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavygrvy <davygrvy@pobox.com>2008-12-10 02:12:16 (GMT)
committerdavygrvy <davygrvy@pobox.com>2008-12-10 02:12:16 (GMT)
commit8817f6b6137d1d30d4745d71573f962f19562eb8 (patch)
tree00981ca67fd3fda5e461941a57fc0c78790ec535
parent53ae9f94958573bbd8df85390fdf7ea4b2902737 (diff)
downloadtcl-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.c4
-rw-r--r--win/tclWinsockCore.c56
-rw-r--r--win/tclWinsockCore.h3
-rw-r--r--win/tclWinsockTCP.c4
-rw-r--r--win/tclWinsockUDP.c236
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;
}