#ifdef WIN32
#include <stdlib.h>
-#include <tcl.h>
-#include <winsock.h>
-#include <stdio.h>
#include <malloc.h>
#else
#if defined(HAVE_SYS_IOCTL_H)
static char errBuf[256];
+/*
+ * Channel handling procedures
+ */
+static Tcl_DriverOutputProc udpOutput;
+static Tcl_DriverInputProc udpInput;
+static Tcl_DriverCloseProc udpClose;
+static Tcl_DriverWatchProc udpWatch;
+static Tcl_DriverGetHandleProc udpGetHandle;
+static Tcl_DriverSetOptionProc udpSetOption;
+static Tcl_DriverGetOptionProc udpGetOption;
+
+/*
+ * Tcl command procedures
+ */
+int Udp_CmdProc(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
int udpOpen(ClientData , Tcl_Interp *, int , CONST84 char * []);
int udpConf(ClientData , Tcl_Interp *, int , CONST84 char * []);
int udpPeek(ClientData , Tcl_Interp *, int , CONST84 char * []);
-static int udpGet(ClientData instanceData,int direction,ClientData *handlePtr);
-static void udpWatch(ClientData instanceData, int mask);
-static int udpOutput(ClientData instanceData, CONST84 char *buf, int toWrite, int *errorCode);
-static int udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode);
-static int udpClose(ClientData instanceData, Tcl_Interp *interp);
+/*
+ * internal functions
+ */
static void udpTrace(const char *format, ...);
-static int udpGetService(Tcl_Interp *interp, const char *service,
- unsigned short *servicePort);
+static int udpGetService(Tcl_Interp *interp, const char *service,
+ unsigned short *servicePort);
+/*
+ * Windows specific functions
+ */
#ifdef WIN32
+
+int UdpEventProc(Tcl_Event *evPtr, int flags);
+static void UDP_SetupProc(ClientData data, int flags);
+void UDP_CheckProc(ClientData data, int flags);
+int Udp_WinHasSockets(Tcl_Interp *interp);
+
+/* FIX ME - these should be part of a thread/package specific structure */
static HANDLE waitForSock;
static HANDLE waitSockRead;
static HANDLE sockListLock;
static UdpState *sockList;
static UdpState *sockTail;
-#endif
+
+#endif /* ! WIN32 */
/*
- * udpClose
+ * ----------------------------------------------------------------------
+ * udpInit
+ * ----------------------------------------------------------------------
*/
-int
-udpClose(ClientData instanceData, Tcl_Interp *interp)
+int
+Udp_Init(Tcl_Interp *interp)
{
- int sock;
- int errorCode = 0;
- UdpState *statePtr = (UdpState *) instanceData;
-#ifdef WIN32
- UdpState *statePre;
-
- WaitForSingleObject(sockListLock, INFINITE);
-#endif /* ! WIN32 */
-
- sock = statePtr->sock;
-
-#ifdef WIN32
- /* remove the statePtr from the list */
- for (statePtr = sockList, statePre = sockList;
- statePtr != NULL;
- statePre=statePtr, statePtr=statePtr->next) {
- if (statePtr->sock == sock) {
- UDPTRACE("Remove %d from the list\n", sock);
- if (statePtr == sockList) {
- sockList = statePtr->next;
- } else {
- statePre->next = statePtr->next;
- if (sockTail == statePtr)
- sockTail = statePre;
- }
- }
- }
-#endif /* ! WIN32 */
-
- ckfree((char *) statePtr);
- if (closesocket(sock) < 0) {
- errorCode = errno;
- }
- if (errorCode != 0) {
-#ifndef WIN32
- sprintf(errBuf, "udpClose: %d, error: %d\n", sock, errorCode);
-#else
- sprintf(errBuf, "udpClose: %d, error: %d\n", sock, WSAGetLastError());
+ int r = TCL_OK;
+#if defined(DEBUG) && !defined(WIN32)
+ dbg = fopen("udp.dbg", "wt");
#endif
- UDPTRACE("UDP error - close %d", sock);
- } else {
- UDPTRACE("Close socket %d\n", sock);
- }
-
+
+#ifdef USE_TCL_STUBS
+ Tcl_InitStubs(interp, "8.1", 0);
+#endif
+
#ifdef WIN32
- SetEvent(sockListLock);
+ if (Udp_WinHasSockets(interp) != TCL_OK) {
+ return TCL_ERROR;
+ }
#endif
+
+ Tcl_CreateCommand(interp, "udp_open", udpOpen ,
+ (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
+ Tcl_CreateCommand(interp, "udp_conf", udpConf ,
+ (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
+ Tcl_CreateCommand(interp, "udp_peek", udpPeek ,
+ (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
- return errorCode;
+ r = Tcl_PkgProvide(interp, TCLUDP_PACKAGE_NAME, TCLUDP_PACKAGE_VERSION);
+ return r;
}
-
+
/*
- * udpWatch
+ * ----------------------------------------------------------------------
+ * Udp_CmdProc --
+ * Provide a user interface similar to the Tcl stock 'socket' command.
+ *
+ * udp ?options?
+ * udp ?options? host port
+ * udp -server command ?options? port
+ *
+ * ----------------------------------------------------------------------
*/
-static void
-udpWatch(ClientData instanceData, int mask)
+int
+Udp_CmdProc(ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[])
{
-#ifndef WIN32
- UdpState *fsPtr = (UdpState *) instanceData;
- if (mask) {
- UDPTRACE("Tcl_CreateFileHandler\n");
- Tcl_CreateFileHandler(fsPtr->sock, mask,
- (Tcl_FileProc *) Tcl_NotifyChannel,
- (ClientData) fsPtr->channel);
- } else {
- UDPTRACE("Tcl_DeleteFileHandler\n");
- Tcl_DeleteFileHandler(fsPtr->sock);
- }
-#endif
+ Tcl_SetResult(interp, "E_NOTIMPL", TCL_STATIC);
+ return TCL_ERROR;
}
/*
- * udpGet
+ * Probably we should provide an equivalent to the C API for TCP.
+ *
+ * Tcl_Channel Tcl_OpenUdpClient(interp, port, host, myaddr, myport, async);
+ * Tcl_Channel Tcl_OpenUdpServer(interp, port, myaddr, proc, clientData);
+ * Tcl_Channel Tcl_MakeUdpClientChannel(sock);
*/
-static int
-udpGet(ClientData instanceData,int direction,ClientData *handlePtr)
-{
- UdpState *statePtr = (UdpState *) instanceData;
- UDPTRACE("UDP_get %d\n", statePtr->sock);
- return statePtr->sock;
-}
/*
- * udpPeek - peek some data and set the peer information
+ * ----------------------------------------------------------------------
+ * udpOpen --
+ *
+ * opens a UDP socket and addds the file descriptor to the tcl
+ * interpreter
+ * ----------------------------------------------------------------------
*/
int
-udpPeek(ClientData clientData, Tcl_Interp *interp,
- int argc, CONST84 char * argv[])
+udpOpen(ClientData clientData, Tcl_Interp *interp,
+ int argc, CONST84 char * argv[])
{
-#ifndef WIN32
- int buffer_size = 16;
- int actual_size, socksize, port;
int sock;
- char message[17];
- char *remotehost;
- struct hostent *name;
+ char channelName[20];
+ UdpState *statePtr;
+ uint16_t localport = 0;
#ifdef SIPC_IPV6
- struct sockaddr_in6 recvaddr;
+ struct sockaddr_in6 addr, sockaddr;
#else
- struct sockaddr_in recvaddr;
+ struct sockaddr_in addr, sockaddr;
#endif
- Tcl_Channel chan;
- UdpState *statePtr;
+ unsigned long status = 1;
+ int len;
- chan = Tcl_GetChannel(interp, (char *)argv[1], NULL);
- if (chan == (Tcl_Channel) NULL) {
- return TCL_ERROR;
- }
- statePtr = (UdpState *) Tcl_GetChannelInstanceData(chan);
- sock = Tcl_GetChannelHandle (chan, (TCL_READABLE | TCL_WRITABLE), NULL);
+ Tcl_ChannelType *Udp_ChannelType;
+ Udp_ChannelType = (Tcl_ChannelType *) ckalloc((unsigned) sizeof(Tcl_ChannelType));
+ memset(Udp_ChannelType, 0, sizeof(Tcl_ChannelType));
+#ifdef SIPC_IPV6
+ Udp_ChannelType->typeName = strdup("udp6");
+#else
+ Udp_ChannelType->typeName = strdup("udp");
+#endif
+ Udp_ChannelType->blockModeProc = NULL;
+ Udp_ChannelType->closeProc = udpClose;
+ Udp_ChannelType->inputProc = udpInput;
+ Udp_ChannelType->outputProc = udpOutput;
+ Udp_ChannelType->seekProc = NULL;
+ Udp_ChannelType->setOptionProc = udpSetOption;
+ Udp_ChannelType->getOptionProc = udpGetOption;
+ Udp_ChannelType->watchProc = udpWatch;
+ Udp_ChannelType->getHandleProc = udpGetHandle;
+ Udp_ChannelType->close2Proc = NULL;
- if (argc > 2) {
- buffer_size = atoi(argv[2]);
- if (buffer_size > 16) buffer_size = 16;
+ if (argc >= 2) {
+ if (udpGetService(interp, argv[1], &localport) != TCL_OK)
+ return TCL_ERROR;
}
- actual_size = recvfrom(sock, message, buffer_size, MSG_PEEK,
- (struct sockaddr *)&recvaddr, &socksize);
- if (actual_size < 0) {
- sprintf(errBuf, "udppeek error");
+ memset(channelName, 0, sizeof(channelName));
+
+#ifdef SIPC_IPV6
+ sock = socket(AF_INET6, SOCK_DGRAM, 0);
+#else
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
+ if (sock < 0) {
+ sprintf(errBuf,"%s","udp - socket");
+ UDPTRACE("UDP error - socket\n");
Tcl_AppendResult(interp, errBuf, (char *)NULL);
return TCL_ERROR;
}
+ memset(&addr, 0, sizeof(addr));
#ifdef SIPC_IPV6
- remotehost = (char *)inet_ntop(AF_INET6, &recvaddr.sin_addr, statePtr->peerhost, sizeof(statePtr->peerhost) );
- statePtr->peerport = ntohs(recvaddr.sin_port);
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = localport;
#else
- strcpy(statePtr->peerhost, (char *)inet_ntoa(recvaddr.sin_addr));
- statePtr->peerport = ntohs(recvaddr.sin_port);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = 0;
+ addr.sin_port = localport;
#endif
- message[16]='\0';
+ if (bind(sock,(struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ sprintf(errBuf,"%s","udp - bind");
+ UDPTRACE("UDP error - bind\n");
+ Tcl_AppendResult(interp, errBuf, (char *)NULL);
+ return TCL_ERROR;
+ }
+#ifdef WIN32
+ ioctlsocket(sock, FIONBIO, &status);
+#else
+ ioctl(sock, (int) FIONBIO, &status);
+#endif
+ if (localport == 0) {
+ len = sizeof(sockaddr);
+ getsockname(sock, (struct sockaddr *)&sockaddr, &len);
+#ifdef SIPC_IPV6
+ localport = sockaddr.sin6_port;
+#else
+ localport = sockaddr.sin_port;
+#endif
+ }
- Tcl_AppendResult(interp, message, (char *)NULL);
+ UDPTRACE("Open socket %d. Bind socket to port %d\n",
+ sock, ntohs(localport));
+
+ statePtr = (UdpState *) ckalloc((unsigned) sizeof(UdpState));
+ memset(statePtr, 0, sizeof(UdpState));
+ statePtr->sock = sock;
+ sprintf(channelName, "sock%d", statePtr->sock);
+ statePtr->channel = Tcl_CreateChannel(Udp_ChannelType, channelName,
+ (ClientData) statePtr,
+ (TCL_READABLE | TCL_WRITABLE | TCL_MODE_NONBLOCKING));
+ statePtr->doread = 1;
+ statePtr->localport = localport;
+ Tcl_RegisterChannel(interp, statePtr->channel);
+#ifdef WIN32
+ statePtr->threadId = Tcl_GetCurrentThread();
+ statePtr->packetNum = 0;
+ statePtr->next = NULL;
+ statePtr->packets = NULL;
+ statePtr->packetsTail = NULL;
+ Tcl_CreateEventSource(UDP_SetupProc, UDP_CheckProc, NULL);
+#endif
+ /* Tcl_SetChannelOption(interp, statePtr->channel, "-blocking", "0"); */
+ Tcl_AppendResult(interp, channelName, (char *)NULL);
+#ifdef WIN32
+ WaitForSingleObject(sockListLock, INFINITE);
+ if (sockList == NULL) {
+ sockList = statePtr;
+ sockTail = statePtr;
+ } else {
+ sockTail->next = statePtr;
+ sockTail = statePtr;
+ }
+
+ UDPTRACE("Append %d to sockList\n", statePtr->sock);
+ SetEvent(sockListLock);
+ SetEvent(waitForSock);
+#endif
return TCL_OK;
-#else /* WIN32 */
- Tcl_SetResult(interp, "udp_peek not implemented for this platform",
- TCL_STATIC);
- return TCL_ERROR;
-#endif /* ! WIN32 */
}
/*
- * udpConf
+ * ----------------------------------------------------------------------
+ * udpConf --
+ * ----------------------------------------------------------------------
*/
int
udpConf(ClientData clientData, Tcl_Interp *interp,
}
}
+/*
+ * ----------------------------------------------------------------------
+ * udpPeek --
+ * peek some data and set the peer information
+ * ----------------------------------------------------------------------
+ */
+int
+udpPeek(ClientData clientData, Tcl_Interp *interp,
+ int argc, CONST84 char * argv[])
+{
+#ifndef WIN32
+ int buffer_size = 16;
+ int actual_size, socksize, port;
+ int sock;
+ char message[17];
+ char *remotehost;
+ struct hostent *name;
+#ifdef SIPC_IPV6
+ struct sockaddr_in6 recvaddr;
+#else
+ struct sockaddr_in recvaddr;
+#endif
+ Tcl_Channel chan;
+ UdpState *statePtr;
+
+ chan = Tcl_GetChannel(interp, (char *)argv[1], NULL);
+ if (chan == (Tcl_Channel) NULL) {
+ return TCL_ERROR;
+ }
+ statePtr = (UdpState *) Tcl_GetChannelInstanceData(chan);
+ sock = Tcl_GetChannelHandle (chan, (TCL_READABLE | TCL_WRITABLE), NULL);
+
+ if (argc > 2) {
+ buffer_size = atoi(argv[2]);
+ if (buffer_size > 16) buffer_size = 16;
+ }
+ actual_size = recvfrom(sock, message, buffer_size, MSG_PEEK,
+ (struct sockaddr *)&recvaddr, &socksize);
+
+ if (actual_size < 0) {
+ sprintf(errBuf, "udppeek error");
+ Tcl_AppendResult(interp, errBuf, (char *)NULL);
+ return TCL_ERROR;
+ }
+#ifdef SIPC_IPV6
+ remotehost = (char *)inet_ntop(AF_INET6, &recvaddr.sin_addr, statePtr->peerhost, sizeof(statePtr->peerhost) );
+ statePtr->peerport = ntohs(recvaddr.sin_port);
+#else
+ strcpy(statePtr->peerhost, (char *)inet_ntoa(recvaddr.sin_addr));
+ statePtr->peerport = ntohs(recvaddr.sin_port);
+#endif
+ message[16]='\0';
+
+ Tcl_AppendResult(interp, message, (char *)NULL);
+ return TCL_OK;
+#else /* WIN32 */
+ Tcl_SetResult(interp, "udp_peek not implemented for this platform",
+ TCL_STATIC);
+ return TCL_ERROR;
+#endif /* ! WIN32 */
+}
+
#ifdef WIN32
/*
+ * ----------------------------------------------------------------------
* UdpEventProc --
+ *
+ * Raise an event from the UDP read thread to notify the Tcl interpreter
+ * that something has happened.
+ *
+ * ----------------------------------------------------------------------
*/
int
UdpEventProc(Tcl_Event *evPtr, int flags)
}
/*
+ * ----------------------------------------------------------------------
* UDP_SetupProc - called in Tcl_SetEventSource to do the setup step
+ * ----------------------------------------------------------------------
*/
static void
UDP_SetupProc(ClientData data, int flags)
}
/*
+ * ----------------------------------------------------------------------
* UDP_CheckProc --
+ * ----------------------------------------------------------------------
*/
void
UDP_CheckProc(ClientData data, int flags)
p->message = message;
p->actual_size = actual_size;
#ifdef SIPC_IPV6
- remotehost = (char *)inet_ntoa(AF_INET6, &recvaddr.sin6_addr, p->r_host, sizeof(p->r_host));
- p->r_port = ntohs(recvaddr.sin6_port);
-#else
- strcpy(p->r_host, (char *)inet_ntoa(recvaddr.sin_addr));
- p->r_port = ntohs(recvaddr.sin_port);
-#endif
- p->next = NULL;
-
-#ifdef SIPC_IPV6
- remotehost = (char *)inet_ntoa(AF_INET6, &recvaddr.sin6_addr, statePtr->peerhost, sizeof(statePtr->peerhost) );
- statePtr->peerport = ntohs(recvaddr.sin6_port);
-#else
- strcpy(statePtr->peerhost, (char *)inet_ntoa(recvaddr.sin_addr));
- statePtr->peerport = ntohs(recvaddr.sin_port);
-#endif
-
- if (statePtr->packets == NULL) {
- statePtr->packets = p;
- statePtr->packetsTail = p;
- } else {
- statePtr->packetsTail->next = p;
- statePtr->packetsTail = p;
- }
-
- UDPTRACE("Received %d bytes from %s:%d through %d\n",
- p->actual_size, p->r_host, p->r_port, statePtr->sock);
- UDPTRACE("%s\n", p->message);
- }
-
- statePtr->packetNum--;
- statePtr->doread = 1;
- UDPTRACE("packetNum is %d\n", statePtr->packetNum);
-
- if (actual_size >= 0) {
- evPtr = (UdpEvent *) ckalloc(sizeof(UdpEvent));
- evPtr->header.proc = UdpEventProc;
- evPtr->chan = statePtr->channel;
- Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
- UDPTRACE("socket %d has data\n", statePtr->sock);
- }
- }
- }
-
- SetEvent(sockListLock);
-}
-#endif /* ! WIN32 */
-
-/*
- *----------------------------------------------------------------------
- * udpOpen - opens a UDP socket and addds the file descriptor to the
- * tcl interpreter
- *----------------------------------------------------------------------
- */
-int
-udpOpen(ClientData clientData, Tcl_Interp *interp,
- int argc, CONST84 char * argv[])
-{
- int sock;
- char channelName[20];
- UdpState *statePtr;
- uint16_t localport = 0;
-#ifdef SIPC_IPV6
- struct sockaddr_in6 addr, sockaddr;
-#else
- struct sockaddr_in addr, sockaddr;
-#endif
- unsigned long status = 1;
- int len;
-
- Tcl_ChannelType *Udp_ChannelType;
- Udp_ChannelType = (Tcl_ChannelType *) ckalloc((unsigned) sizeof(Tcl_ChannelType));
- memset(Udp_ChannelType, 0, sizeof(Tcl_ChannelType));
-#ifdef SIPC_IPV6
- Udp_ChannelType->typeName = strdup("udp6");
-#else
- Udp_ChannelType->typeName = strdup("udp");
-#endif
- Udp_ChannelType->blockModeProc = NULL;
- Udp_ChannelType->closeProc = udpClose;
- Udp_ChannelType->inputProc = udpInput;
- Udp_ChannelType->outputProc = udpOutput;
- Udp_ChannelType->seekProc = NULL;
- Udp_ChannelType->setOptionProc = NULL;
- Udp_ChannelType->getOptionProc = NULL;
- Udp_ChannelType->watchProc = udpWatch;
- Udp_ChannelType->getHandleProc = udpGet;
- Udp_ChannelType->close2Proc = NULL;
-
- if (argc >= 2) {
- if (udpGetService(interp, argv[1], &localport) != TCL_OK)
- return TCL_ERROR;
- }
-
- memset(channelName, 0, sizeof(channelName));
-
-#ifdef SIPC_IPV6
- sock = socket(AF_INET6, SOCK_DGRAM, 0);
-#else
- sock = socket(AF_INET, SOCK_DGRAM, 0);
-#endif
- if (sock < 0) {
- sprintf(errBuf,"%s","udp - socket");
- UDPTRACE("UDP error - socket\n");
- Tcl_AppendResult(interp, errBuf, (char *)NULL);
- return TCL_ERROR;
- }
- memset(&addr, 0, sizeof(addr));
-#ifdef SIPC_IPV6
- addr.sin6_family = AF_INET6;
- addr.sin6_port = localport;
-#else
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = 0;
- addr.sin_port = localport;
-#endif
- if (bind(sock,(struct sockaddr *)&addr, sizeof(addr)) < 0) {
- sprintf(errBuf,"%s","udp - bind");
- UDPTRACE("UDP error - bind\n");
- Tcl_AppendResult(interp, errBuf, (char *)NULL);
- return TCL_ERROR;
- }
-#ifdef WIN32
- ioctlsocket(sock, FIONBIO, &status);
+ remotehost = (char *)inet_ntoa(AF_INET6, &recvaddr.sin6_addr, p->r_host, sizeof(p->r_host));
+ p->r_port = ntohs(recvaddr.sin6_port);
#else
- ioctl(sock, (int) FIONBIO, &status);
+ strcpy(p->r_host, (char *)inet_ntoa(recvaddr.sin_addr));
+ p->r_port = ntohs(recvaddr.sin_port);
#endif
- if (localport == 0) {
- len = sizeof(sockaddr);
- getsockname(sock, (struct sockaddr *)&sockaddr, &len);
+ p->next = NULL;
+
#ifdef SIPC_IPV6
- localport = sockaddr.sin6_port;
+ remotehost = (char *)inet_ntoa(AF_INET6, &recvaddr.sin6_addr, statePtr->peerhost, sizeof(statePtr->peerhost) );
+ statePtr->peerport = ntohs(recvaddr.sin6_port);
#else
- localport = sockaddr.sin_port;
+ strcpy(statePtr->peerhost, (char *)inet_ntoa(recvaddr.sin_addr));
+ statePtr->peerport = ntohs(recvaddr.sin_port);
#endif
+
+ if (statePtr->packets == NULL) {
+ statePtr->packets = p;
+ statePtr->packetsTail = p;
+ } else {
+ statePtr->packetsTail->next = p;
+ statePtr->packetsTail = p;
+ }
+
+ UDPTRACE("Received %d bytes from %s:%d through %d\n",
+ p->actual_size, p->r_host, p->r_port, statePtr->sock);
+ UDPTRACE("%s\n", p->message);
+ }
+
+ statePtr->packetNum--;
+ statePtr->doread = 1;
+ UDPTRACE("packetNum is %d\n", statePtr->packetNum);
+
+ if (actual_size >= 0) {
+ evPtr = (UdpEvent *) ckalloc(sizeof(UdpEvent));
+ evPtr->header.proc = UdpEventProc;
+ evPtr->chan = statePtr->channel;
+ Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
+ UDPTRACE("socket %d has data\n", statePtr->sock);
+ }
+ }
}
- UDPTRACE("Open socket %d. Bind socket to port %d\n",
- sock, ntohs(localport));
-
- statePtr = (UdpState *) ckalloc((unsigned) sizeof(UdpState));
- memset(statePtr, 0, sizeof(UdpState));
- statePtr->sock = sock;
- sprintf(channelName, "sock%d", statePtr->sock);
- statePtr->channel = Tcl_CreateChannel(Udp_ChannelType, channelName,
- (ClientData) statePtr,
- (TCL_READABLE | TCL_WRITABLE | TCL_MODE_NONBLOCKING));
- statePtr->doread = 1;
- statePtr->localport = localport;
- Tcl_RegisterChannel(interp, statePtr->channel);
-#ifdef WIN32
- statePtr->threadId = Tcl_GetCurrentThread();
- statePtr->packetNum = 0;
- statePtr->next = NULL;
- statePtr->packets = NULL;
- statePtr->packetsTail = NULL;
- Tcl_CreateEventSource(UDP_SetupProc, UDP_CheckProc, NULL);
-#endif
- /* Tcl_SetChannelOption(interp, statePtr->channel, "-blocking", "0"); */
- Tcl_AppendResult(interp, channelName, (char *)NULL);
-#ifdef WIN32
- WaitForSingleObject(sockListLock, INFINITE);
- if (sockList == NULL) {
- sockList = statePtr;
- sockTail = statePtr;
- } else {
- sockTail->next = statePtr;
- sockTail = statePtr;
- }
-
- UDPTRACE("Append %d to sockList\n", statePtr->sock);
SetEvent(sockListLock);
- SetEvent(waitForSock);
-#endif
- return TCL_OK;
}
-#ifdef WIN32
-
/*
+ * ----------------------------------------------------------------------
* InitSockets
+ * ----------------------------------------------------------------------
*/
static int
InitSockets()
}
/*
+ * ----------------------------------------------------------------------
* SocketThread
+ * ----------------------------------------------------------------------
*/
static DWORD WINAPI
SocketThread(LPVOID arg)
}
/*
+ * ----------------------------------------------------------------------
* Udp_WinHasSockets --
+ * ----------------------------------------------------------------------
*/
int
Udp_WinHasSockets(Tcl_Interp *interp)
}
/*
- * Start the socketThread windows and set the thread priority of the
+ * Start the socketThread window and set the thread priority of the
* socketThread as highest
*/
#endif /* ! WIN32 */
/*
- * udpInit
+ * ----------------------------------------------------------------------
+ * udpClose --
+ * Called from the channel driver code to cleanup and close
+ * the socket.
+ *
+ * Results:
+ * 0 if successful, the value of errno if failed.
+ *
+ * Side effects:
+ * The socket is closed.
+ *
+ * ----------------------------------------------------------------------
*/
-int
-Udp_Init(Tcl_Interp *interp)
+static int
+udpClose(ClientData instanceData, Tcl_Interp *interp)
{
- int r = TCL_OK;
-#if defined(DEBUG) && !defined(WIN32)
- dbg = fopen("udp.dbg", "wt");
-#endif
-
-#ifdef USE_TCL_STUBS
- Tcl_InitStubs(interp, "8.3", 0);
+ int sock;
+ int errorCode = 0;
+ UdpState *statePtr = (UdpState *) instanceData;
+#ifdef WIN32
+ UdpState *statePre;
+
+ WaitForSingleObject(sockListLock, INFINITE);
+#endif /* ! WIN32 */
+
+ sock = statePtr->sock;
+
+#ifdef WIN32
+ /* remove the statePtr from the list */
+ for (statePtr = sockList, statePre = sockList;
+ statePtr != NULL;
+ statePre=statePtr, statePtr=statePtr->next) {
+ if (statePtr->sock == sock) {
+ UDPTRACE("Remove %d from the list\n", sock);
+ if (statePtr == sockList) {
+ sockList = statePtr->next;
+ } else {
+ statePre->next = statePtr->next;
+ if (sockTail == statePtr)
+ sockTail = statePre;
+ }
+ }
+ }
+#endif /* ! WIN32 */
+
+ ckfree((char *) statePtr);
+ if (closesocket(sock) < 0) {
+ errorCode = errno;
+ }
+ if (errorCode != 0) {
+#ifndef WIN32
+ sprintf(errBuf, "udpClose: %d, error: %d\n", sock, errorCode);
+#else
+ sprintf(errBuf, "udpClose: %d, error: %d\n", sock, WSAGetLastError());
#endif
-
+ UDPTRACE("UDP error - close %d", sock);
+ } else {
+ UDPTRACE("Close socket %d\n", sock);
+ }
+
#ifdef WIN32
- if (Udp_WinHasSockets(interp) != TCL_OK) {
- return TCL_ERROR;
+ SetEvent(sockListLock);
+#endif
+
+ return errorCode;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * udpWatch --
+ * ----------------------------------------------------------------------
+ */
+static void
+udpWatch(ClientData instanceData, int mask)
+{
+#ifndef WIN32
+ UdpState *fsPtr = (UdpState *) instanceData;
+ if (mask) {
+ UDPTRACE("Tcl_CreateFileHandler\n");
+ Tcl_CreateFileHandler(fsPtr->sock, mask,
+ (Tcl_FileProc *) Tcl_NotifyChannel,
+ (ClientData) fsPtr->channel);
+ } else {
+ UDPTRACE("Tcl_DeleteFileHandler\n");
+ Tcl_DeleteFileHandler(fsPtr->sock);
}
#endif
+}
- Tcl_CreateCommand(interp, "udp_open", udpOpen ,
- (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
- Tcl_CreateCommand(interp, "udp_conf", udpConf ,
- (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
- Tcl_CreateCommand(interp, "udp_peek", udpPeek ,
- (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
-
- r = Tcl_PkgProvide(interp, TCLUDP_PACKAGE_NAME, TCLUDP_PACKAGE_VERSION);
- return r;
+/*
+ * ----------------------------------------------------------------------
+ * udpGetHandle --
+ * Called from the channel driver to get a handle to the socket.
+ *
+ * Results:
+ * Puts the socket into handlePtr and returns TCL_OK;
+ *
+ * Side Effects:
+ * None
+ * ----------------------------------------------------------------------
+ */
+static int
+udpGetHandle(ClientData instanceData, int direction, ClientData *handlePtr)
+{
+ UdpState *statePtr = (UdpState *) instanceData;
+ UDPTRACE("udpGetHandle %ld\n", (long)statePtr->sock);
+ *handlePtr = (ClientData) statePtr->sock;
+ return TCL_OK;
}
/*
+ * ----------------------------------------------------------------------
* udpOutput--
+ * ----------------------------------------------------------------------
*/
static int
udpOutput(ClientData instanceData, CONST84 char *buf, int toWrite, int *errorCode)
}
/*
+ * ----------------------------------------------------------------------
* udpInput
+ * ----------------------------------------------------------------------
*/
static int
udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode)
return -1;
}
+/*
+ * ----------------------------------------------------------------------
+ * udpGetOption --
+ * ----------------------------------------------------------------------
+ */
+static int
+udpGetOption(ClientData instanceData, Tcl_Interp *interp,
+ CONST84 char *optionName, Tcl_DString *optionValue)
+{
+ UdpState *statePtr = (UdpState *)instanceData;
+ const char * options = "myport remote peer mcastadd mcastdrop";
+ int r = TCL_OK;
+
+ if (optionName == NULL) {
+
+ Tcl_DStringAppend(optionValue, " -myport ", -1);
+ udpGetOption(instanceData, interp, "-myport", optionValue);
+ Tcl_DStringAppend(optionValue, " -remote ", -1);
+ udpGetOption(instanceData, interp, "-remote", optionValue);
+ Tcl_DStringAppend(optionValue, " -peer ", -1);
+ udpGetOption(instanceData, interp, "-peer", optionValue);
+ Tcl_DStringAppend(optionValue, " -mcastadd ", -1);
+ udpGetOption(instanceData, interp, "-mcastadd", optionValue);
+ Tcl_DStringAppend(optionValue, " -mcastdrop ", -1);
+ udpGetOption(instanceData, interp, "-mcastdrop", optionValue);
+
+ } else {
+
+ Tcl_DString ds, dsInt;
+ Tcl_DStringInit(&ds);
+ Tcl_DStringInit(&dsInt);
+
+ if (!strcmp("-myport", optionName)) {
+
+ Tcl_DStringSetLength(&ds, TCL_INTEGER_SPACE);
+ sprintf(Tcl_DStringValue(&ds), "%u", ntohs(statePtr->localport));
+
+ } else if (!strcmp("-remote", optionName)) {
+
+ Tcl_DStringSetLength(&dsInt, TCL_INTEGER_SPACE);
+ sprintf(Tcl_DStringValue(&dsInt), "%u",
+ ntohs(statePtr->remoteport));
+ Tcl_DStringAppendElement(&ds, statePtr->remotehost);
+ Tcl_DStringAppendElement(&ds, Tcl_DStringValue(&dsInt));
+
+ } else if (!strcmp("-peer", optionName)) {
+
+ Tcl_DStringSetLength(&dsInt, TCL_INTEGER_SPACE);
+ sprintf(Tcl_DStringValue(&dsInt), "%u", statePtr->peerport);
+ Tcl_DStringAppendElement(&ds, statePtr->peerhost);
+ Tcl_DStringAppendElement(&ds, Tcl_DStringValue(&dsInt));
+
+ } else if (!strcmp("-mcastadd", optionName)) {
+ ;
+ } else if (!strcmp("-mcastdrop", optionName)) {
+ ;
+ } else {
+ r = Tcl_BadChannelOption(interp, optionName, options);
+ }
+
+ Tcl_DStringAppendElement(optionValue, Tcl_DStringValue(&ds));
+ Tcl_DStringFree(&dsInt);
+ Tcl_DStringFree(&ds);
+ }
+
+ return r;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * udpSetOption --
+ *
+ * Handle channel configuration requests from the generic layer.
+ *
+ * ----------------------------------------------------------------------
+ */
+static int
+udpSetOption(ClientData instanceData, Tcl_Interp *interp,
+ CONST char *optionName, CONST char *newValue)
+{
+ UdpState *statePtr = (UdpState *)instanceData;
+ const char * options = "remote mcastadd mcastdrop";
+ int r = TCL_OK;
+
+ if (!strcmp("-remote", optionName)) {
+
+ Tcl_Obj *valPtr;
+ int len;
+
+ valPtr = Tcl_NewStringObj(newValue, -1);
+ r = Tcl_ListObjLength(interp, valPtr, &len);
+ if (r == TCL_OK) {
+ if (len < 1 || len > 2) {
+ Tcl_SetResult(interp, "wrong # args", TCL_STATIC);
+ r = TCL_ERROR;
+ } else {
+ Tcl_Obj *hostPtr, *portPtr;
+
+ Tcl_ListObjIndex(interp, valPtr, 0, &hostPtr);
+ strcpy(statePtr->remotehost, Tcl_GetString(hostPtr));
+
+ if (len == 2) {
+ Tcl_ListObjIndex(interp, valPtr, 1, &portPtr);
+ r = udpGetService(interp, Tcl_GetString(portPtr),
+ &(statePtr->remoteport));
+ }
+ }
+ }
+
+ } else if (!strcmp("-mcastadd", optionName)) {
+
+ Tcl_SetResult(interp, "E_NOTIMPL", TCL_STATIC);
+ r = TCL_ERROR;
+
+ } else if (!strcmp("-mcastdrop", optionName)) {
+
+ Tcl_SetResult(interp, "E_NOTIMPL", TCL_STATIC);
+ r = TCL_ERROR;
+
+ } else {
+
+ r = Tcl_BadChannelOption(interp, optionName, options);
+
+ }
+
+ return r;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * udpTrace --
+ * ----------------------------------------------------------------------
+ */
static void
udpTrace(const char *format, ...)
{
}
/*
- * Return the service port number in network byte order from either a string
- * representation of the port number or the service name. If the service
- * string cannot be converted (ie: a name not present in the services
- * database) then set a Tcl error.
+ * ----------------------------------------------------------------------
+ * udpGetSetvice --
+ *
+ * Return the service port number in network byte order from either a string
+ * representation of the port number or the service name. If the service
+ * string cannot be converted (ie: a name not present in the services
+ * database) then set a Tcl error.
+ * ----------------------------------------------------------------------
*/
static int
udpGetService(Tcl_Interp *interp, const char *service,
}
return r;
}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: nil
+ * End:
+ */
-# Microsoft Developer Studio Project File - Name="tcludp" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
-\r
-CFG=tcludp - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "tcludp.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "tcludp.mak" CFG="tcludp - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "tcludp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE "tcludp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-MTL=midl.exe\r
-RSC=rc.exe\r
-\r
-!IF "$(CFG)" == "tcludp - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "Release"\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCLUDP_EXPORTS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D VERSION=\"1.0.4\" /D "USE_TCL_STUBS" /D "TCLUDP_EXPORTS" /D "BUILD_udp" /YX /FD /c\r
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-# ADD BASE RSC /l 0x809 /d "NDEBUG"\r
-# ADD RSC /l 0x809 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
-# ADD LINK32 tclstub84.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/udp104.dll"\r
-\r
-!ELSEIF "$(CFG)" == "tcludp - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "Debug"\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCLUDP_EXPORTS" /YX /FD /GZ /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D VERSION=\"1.0.4\" /D "USE_TCL_STUBS" /D "TCLUDP_EXPORTS" /D "BUILD_udp" /YX /FD /GZ /c\r
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-# ADD BASE RSC /l 0x809 /d "_DEBUG"\r
-# ADD RSC /l 0x809 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 tclstub84.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/udp104d.dll" /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "tcludp - Win32 Release"\r
-# Name "tcludp - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\generic\udp_tcl.c\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\generic\udp_tcl.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# Begin Source File\r
-\r
-SOURCE=.\tcludp.rc\r
-# End Source File\r
-# End Group\r
-# End Target\r
-# End Project\r
+# Microsoft Developer Studio Project File - Name="tcludp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=tcludp - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "tcludp.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "tcludp.mak" CFG="tcludp - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "tcludp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "tcludp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "tcludp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCLUDP_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D VERSION=\"1.0.5\" /D "USE_TCL_STUBS" /D "TCLUDP_EXPORTS" /D "BUILD_udp" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 tclstub84.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/udp105.dll"
+
+!ELSEIF "$(CFG)" == "tcludp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCLUDP_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D VERSION=\"1.0.5\" /D "USE_TCL_STUBS" /D "TCLUDP_EXPORTS" /D "BUILD_udp" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 tclstub84.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/udp105d.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "tcludp - Win32 Release"
+# Name "tcludp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\generic\udp_tcl.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\generic\udp_tcl.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\tcludp.rc
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\tests\udp.test
+# End Source File
+# End Target
+# End Project