+++ /dev/null
-/******************************************************************************
- * UDP Extension for Tcl 8.4
- *
- * Copyright 1999-2000 by Columbia University; all rights reserved
- *
- * Written by Xiaotao Wu
- * Last modified: 11/03/2000
- ******************************************************************************/
-#include "udp_tcl.h"
-
-#ifdef WIN32
-#include <stdlib.h>
-#include <tcl.h>
-#include <winsock.h>
-#include <stdio.h>
-#else
-#ifdef LINUX
-#include <sys/ioctl.h>
-#else
-#include <sys/filio.h>
-#endif
-#endif
-
-#ifdef DEBUG
-FILE *dbg;
-#endif
-
-#define MAXBUFFERSIZE 4096
-
-static char errBuf[256];
-
-EXTERN int Udp_Init(Tcl_Interp *);
-
-int udpOpen(ClientData , Tcl_Interp *, int , char *[]);
-int udpConf(ClientData , Tcl_Interp *, int , char *[]);
-int udpPeek(ClientData , Tcl_Interp *, int , char *[]);
-
-static int udpGet(ClientData instanceData,int direction,ClientData *handlePtr);
-static void udpWatch(ClientData instanceData, int mask);
-static int udpOutput(ClientData instanceData, 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);
-
-#ifdef WIN32
-static HANDLE waitForSock;
-static HANDLE waitSockRead;
-static HANDLE sockListLock;
-static UdpState *sockList;
-static UdpState *sockTail;
-#endif
-
-/*
- * udpClose
- */
-int udpClose(ClientData instanceData, Tcl_Interp *interp) {
- int sock;
- int errorCode = 0;
- UdpState *statePtr = (UdpState *) instanceData;
-#ifdef WIN32
- UdpState *statePre;
-
- WaitForSingleObject(sockListLock, INFINITE);
-#endif
-
- 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) {
-#ifdef DEBUG
- fprintf(dbg, "Remove %d from the list\n", sock);
- fflush(dbg);
-#endif
- if (statePtr == sockList) {
- sockList = statePtr->next;
- } else {
- statePre->next = statePtr->next;
- if (sockTail == statePtr)
- sockTail = statePre;
- }
- }
- }
-#endif
-
- ckfree((char *) statePtr);
-#ifndef WIN32
- if (close(sock) < 0) {
-#else
- if (closesocket(sock) < 0) {
-#endif
- 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
-#ifdef DEBUG
- fprintf(dbg, "UDP error - close %d", sock);
- fflush(dbg);
-#endif
- } else {
-#ifdef DEBUG
- fprintf(dbg, "Close socket %d\n", sock);
- fflush(dbg);
-#endif
- }
-
-#ifdef WIN32
- SetEvent(sockListLock);
-#endif
-
- return errorCode;
-}
-
-/*
- * udpWatch
- */
-static void udpWatch(ClientData instanceData, int mask) {
-#ifndef WIN32
- UdpState *fsPtr = (UdpState *) instanceData;
- if (mask) {
-#ifdef DEBUG
- fprintf(dbg, "Tcl_CreateFileHandler\n");
- fflush(dbg);
-#endif
- Tcl_CreateFileHandler(fsPtr->sock, mask,
- (Tcl_FileProc *) Tcl_NotifyChannel,
- (ClientData) fsPtr->channel);
- } else {
-#ifdef DEBUG
- fprintf(dbg, "Tcl_DeleteFileHandler\n");
- fflush(dbg);
-#endif
- Tcl_DeleteFileHandler(fsPtr->sock);
- }
-#endif
-}
-
-/*
- * udpGet
- */
-static int udpGet(ClientData instanceData,int direction,ClientData *handlePtr) {
- UdpState *statePtr = (UdpState *) instanceData;
-#ifdef DEBUG
- fprintf(dbg, "UDP_get %d\n", statePtr->sock);
- fflush(dbg);
-#endif
- return statePtr->sock;
-}
-
-/*
- * udpPeek - peek some data and set the peer information
- */
-int udpPeek(ClientData clientData, Tcl_Interp *interp, int argc, 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, 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);
-#endif
- return TCL_OK;
-}
-
-/*
- * udpConf
- */
-int udpConf(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) {
- Tcl_Channel chan;
- UdpState *statePtr;
- char *result;
- char buf[128];
- struct hostent *name;
- struct ip_mreq mreq;
- struct sockaddr_in maddr;
- int sock, ret;
-
- if (argc != 4 && argc != 3) {
- result = "udpConf fileId [-mcastadd] [-mcastdrop] groupaddr | udpConf fileId remotehost remoteport | udpConf fileId [-myport] [-remote] [-peer]";
- Tcl_SetResult (interp, result, NULL);
- return TCL_ERROR;
- }
- chan = Tcl_GetChannel(interp, argv[1], NULL);
- if (chan == (Tcl_Channel) NULL) {
- return TCL_ERROR;
- }
- statePtr = (UdpState *) Tcl_GetChannelInstanceData(chan);
- sock = statePtr->sock;
-
- if (argc == 3) {
- if (!strcmp(argv[2], "-myport")) {
- sprintf(buf, "%d", statePtr->localport);
- Tcl_AppendResult(interp, buf, (char *)NULL);
- } else if (!strcmp(argv[2], "-remote")) {
- sprintf(buf, "%s", statePtr->remotehost);
- Tcl_AppendResult(interp, buf, (char *)NULL);
- sprintf(buf, "%d", statePtr->remoteport);
- Tcl_AppendElement(interp, buf);
- } else if (!strcmp(argv[2], "-peer")) {
- sprintf(buf, "%s", statePtr->peerhost);
- Tcl_AppendResult(interp, buf, (char *)NULL);
- sprintf(buf, "%d", statePtr->peerport);
- Tcl_AppendElement(interp, buf);
- } else {
- result = "udpConf fileId [-mcastadd] [-mcastdrop] groupaddr | udpConf fileId remotehost remoteport | udpConf fileId [-myport] [-remote] [-peer]";
- Tcl_SetResult (interp, result, NULL);
- return TCL_ERROR;
- }
- return TCL_OK;
- } else if (argc == 4) {
- if (!strcmp(argv[2], "-mcastadd")) {
- if (strlen(argv[3]) >= sizeof(statePtr->remotehost)) {
- result = "hostname too long";
- Tcl_SetResult (interp, result, NULL);
- return TCL_ERROR;
- }
- mreq.imr_multiaddr.s_addr = inet_addr(argv[3]);
- if (mreq.imr_multiaddr.s_addr == -1) {
- name = gethostbyname(argv[3]);
- if (name == NULL) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - gethostbyname");
- fflush(dbg);
-#endif
- return TCL_ERROR;
- }
- memcpy(&mreq.imr_multiaddr.s_addr, name->h_addr, sizeof(mreq.imr_multiaddr.s_addr));
- }
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - setsockopt - IP_ADD_MEMBERSHIP");
- fflush(dbg);
-#endif
- return TCL_ERROR;
- }
- maddr.sin_addr.s_addr = htonl(INADDR_ANY);
- return TCL_OK;
- } else if (!strcmp(argv[2], "-mcastdrop")) {
- if (strlen(argv[3]) >= sizeof(statePtr->remotehost)) {
- result = "hostname too long";
- Tcl_SetResult (interp, result, NULL);
- return TCL_ERROR;
- }
- mreq.imr_multiaddr.s_addr = inet_addr(argv[3]);
- if (mreq.imr_multiaddr.s_addr == -1) {
- name = gethostbyname(argv[3]);
- if (name == NULL) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - gethostbyname");
- fflush(dbg);
-#endif
- return TCL_ERROR;
- }
- memcpy(&mreq.imr_multiaddr.s_addr, name->h_addr, sizeof(mreq.imr_multiaddr.s_addr));
- }
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - setsockopt - IP_DROP_MEMBERSHIP");
- fflush(dbg);
-#endif
- return TCL_ERROR;
- }
- return TCL_OK;
- } else {
- if (strlen(argv[2]) >= sizeof(statePtr->remotehost)) {
- result = "hostname too long";
- Tcl_SetResult (interp, result, NULL);
- return TCL_ERROR;
- }
- strcpy(statePtr->remotehost, argv[2]);
- statePtr->remoteport = atoi(argv[3]);
- return TCL_OK;
- }
- } else {
- result = "udpConf fileId [-mcastadd] [-mcastdrop] groupaddr | udpConf fileId remotehost remoteport | udpConf fileId [-myport] [-remote] [-peer]";
- Tcl_SetResult (interp, result, NULL);
- return TCL_ERROR;
- }
-}
-
-#ifdef WIN32
-/*
- * UdpEventProc --
- */
-int UdpEventProc(Tcl_Event *evPtr, int flags) {
- UdpEvent *eventPtr = (UdpEvent *) evPtr;
- int mask = 0;
-
- mask |= TCL_READABLE;
-#ifdef DEBUG
- fprintf(dbg, "UdpEventProc\n");
- fflush(dbg);
-#endif
- Tcl_NotifyChannel(eventPtr->chan, mask);
- return 1;
-}
-
-/*
- * UDP_SetupProc - called in Tcl_SetEventSource to do the setup step
- */
-static void UDP_SetupProc(ClientData data, int flags) {
- UdpState *statePtr;
- Tcl_Time blockTime = { 0, 0 };
-
-#ifdef DEBUG
- fprintf(dbg, "setupProc\n");
- fflush(dbg);
-#endif
-
- if (!(flags & TCL_FILE_EVENTS)) {
- return;
- }
-
- WaitForSingleObject(sockListLock, INFINITE);
- for (statePtr = sockList; statePtr != NULL; statePtr=statePtr->next) {
- if (statePtr->packetNum > 0) {
-#ifdef DEBUG
- fprintf(dbg, "UDP_SetupProc\n");
- fflush(dbg);
-#endif
- Tcl_SetMaxBlockTime(&blockTime);
- break;
- }
- }
- SetEvent(sockListLock);
-}
-
-/*
- * UDP_CheckProc --
- */
-void UDP_CheckProc(ClientData data, int flags) {
- UdpState *statePtr;
- UdpEvent *evPtr;
- int actual_size, socksize, reply;
- int buffer_size = MAXBUFFERSIZE;
- int port;
- struct hostent *name;
- char *remotehost, *message;
-#ifdef SIPC_IPV6
- char number[128];
- struct sockaddr_in6 recvaddr;
-#else
- char number[32];
- struct sockaddr_in recvaddr;
-#endif
- PacketList *p;
-
-#ifdef DEBUG
- fprintf(dbg, "checkProc\n");
- fflush(dbg);
-#endif
-
- //synchronized
- WaitForSingleObject(sockListLock, INFINITE);
-
- for (statePtr = sockList; statePtr != NULL; statePtr=statePtr->next) {
- if (statePtr->packetNum > 0) {
-
-#ifdef DEBUG
- fprintf(dbg, "UDP_CheckProc\n");
- fflush(dbg);
-#endif
- //Read the data from socket and put it into statePtr
- socksize = sizeof(recvaddr);
-#ifdef SIPC_IPV6
- memset(number, 0, 128);
-#else
- memset(number, 0, 32);
-#endif
- memset(&recvaddr, 0, socksize);
-
- message = (char *)calloc(1, MAXBUFFERSIZE);
- if (message == NULL) {
-#ifdef DEBUG
- fprintf(dbg, "calloc error\n");
- fflush(dbg);
-#endif
- exit(1);
- }
-
- actual_size = recvfrom(statePtr->sock, message, buffer_size, 0,
- (struct sockaddr *)&recvaddr, &socksize);
- SetEvent(waitSockRead);
-
- if (actual_size < 0) {
- if (WSAGetLastError() == WSAEMSGSIZE) {
- actual_size = buffer_size;
- }
- }
-
- if (actual_size < 0) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - recvfrom %d\n", statePtr->sock);
- fflush(dbg);
-#endif
- } else {
- p = (PacketList *)calloc(1, sizeof(struct PacketList));
- 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;
- }
-
-#ifdef DEBUG
- fprintf(dbg, "Received %d bytes from %s:%d through %d\n", p->actual_size, p->r_host, p->r_port, statePtr->sock);
- fwrite(p->message, 1, p->actual_size, dbg);
- fflush(dbg);
-#endif
- }
-
- statePtr->packetNum--;
- statePtr->doread = 1;
-#ifdef DEBUG
- fprintf(dbg, "packetNum is %d\n", statePtr->packetNum);
- fflush(dbg);
-#endif
- 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);
-#ifdef DEBUG
- fprintf(dbg, "socket %d has data\n", statePtr->sock);
- fflush(dbg);
-#endif
- }
- }
- }
-
- SetEvent(sockListLock);
-}
-#endif
-
-/*
- *----------------------------------------------------------------------
- * udpOpen - opens a UDP socket and addds the file descriptor to the
- * tcl interpreter
- *----------------------------------------------------------------------
- */
-int udpOpen(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) {
- int sock;
- char channelName[20];
- UdpState *statePtr;
- char * result;
- 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;
-#ifdef WIN32
- UdpState *tmp;
- static initd = 0;
-#endif
-
- Tcl_ChannelType *Udp_ChannelType;
- Udp_ChannelType = (Tcl_ChannelType *) ckalloc((unsigned) 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) {
- localport = atoi(argv[1]);
- }
-
- memset(channelName, 0, sizeof(channelName));
-
-#ifdef SIPC_IPV6
- if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
-#else
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-#endif
- sprintf(errBuf,"%s","udp - socket");
-#ifdef DEBUG
- fprintf(dbg, "UDP error - socket\n");
- fflush(dbg);
-#endif
- 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 = htons(localport);
-#else
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = 0;
- addr.sin_port = htons(localport);
-#endif
- if (bind(sock,(struct sockaddr *)&addr, sizeof(addr)) < 0) {
- sprintf(errBuf,"%s","udp - bind");
-#ifdef DEBUG
- fprintf(dbg, "UDP error - bind\n");
- fflush(dbg);
-#endif
- 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 = ntohs(sockaddr.sin6_port);
-#else
- localport = ntohs(sockaddr.sin_port);
-#endif
- }
-#ifdef DEBUG
- fprintf(dbg, "Open socket %d. Bind socket to port %d\n", sock, localport);
- fflush(dbg);
-#endif
-
- statePtr = (UdpState *) ckalloc((unsigned) 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;
- }
-#ifdef DEBUG
- fprintf(dbg, "Append %d to sockList\n", statePtr->sock);
- fflush(dbg);
- for (tmp = sockList; tmp != NULL; tmp = tmp->next) {
- fprintf(dbg, "%d --> ", tmp->sock);
- fflush(dbg);
- }
- fprintf(dbg, "NULL\n");
- fflush(dbg);
-#endif
- SetEvent(sockListLock);
- SetEvent(waitForSock);
-#endif
- return TCL_OK;
-}
-
-#ifdef WIN32
-
-/*
- * InitSockets
- */
-static int InitSockets() {
- WSADATA wsaData;
- WNDCLASS class;
- HINSTANCE handle;
-
- /*
- * Load the socket DLL and initialize the function table.
- */
-
- if (WSAStartup(0x0101, &wsaData))
- return 0;
-
- return 1;
-}
-
-/*
- * SocketThread
- */
-static DWORD WINAPI SocketThread(LPVOID arg) {
- fd_set readfds; //variable used for select
- struct timeval timeout;
- UdpState *statePtr;
- int found;
- int sockset;
-
- FD_ZERO(&readfds);
-
-#ifdef DEBUG
- fprintf(dbg, "In socket thread\n");
- fflush(dbg);
-#endif
- while (1) {
- FD_ZERO(&readfds);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- //synchronized
- WaitForSingleObject(sockListLock, INFINITE);
-
- //no socket, just wait, use event
- if (sockList == NULL) {
- SetEvent(sockListLock);
-#ifdef DEBUG
- fprintf(dbg, "Wait for adding socket\n");
- fflush(dbg);
-#endif
- WaitForSingleObject(waitForSock, INFINITE);
- //synchronized
- WaitForSingleObject(sockListLock, INFINITE);
- }
-
- //set each socket for select
- for (statePtr = sockList; statePtr != NULL; statePtr=statePtr->next) {
- FD_SET(statePtr->sock, &readfds);
-#ifdef DEBUG
- fprintf(dbg, "SET sock %d\n", statePtr->sock);
- fflush(dbg);
-#endif
- }
-
- SetEvent(sockListLock);
-
-#ifdef DEBUG
- fprintf(dbg, "Wait for select\n");
- fflush(dbg);
-#endif
- //block here
- found = select(0, &readfds, NULL, NULL, &timeout);
-#ifdef DEBUG
- fprintf(dbg, "select end\n");
- fflush(dbg);
-#endif
-
- if (found <= 0) {
- //We closed the socket during select or time out
- continue;
- }
-
-#ifdef DEBUG
- fprintf(dbg, "Packet comes in\n");
- fflush(dbg);
-#endif
-
- WaitForSingleObject(sockListLock, INFINITE);
- sockset = 0;
- for (statePtr = sockList; statePtr != NULL; statePtr=statePtr->next) {
- if (FD_ISSET(statePtr->sock, &readfds)) {
- statePtr->packetNum++;
- sockset++;
-#ifdef DEBUG
- fprintf(dbg, "sock %d is set\n", statePtr->sock);
- fflush(dbg);
-#endif
- break;
- }
- }
- SetEvent(sockListLock);
-
- //wait for the socket data was read
- if (sockset > 0) {
-#ifdef DEBUG
- fprintf(dbg, "Wait sock read\n");
- fflush(dbg);
-#endif
- //alert the thread to do event checking
- Tcl_ThreadAlert(statePtr->threadId);
- WaitForSingleObject(waitSockRead, INFINITE);
-#ifdef DEBUG
- fprintf(dbg, "Sock read finished\n");
- fflush(dbg);
-#endif
- }
- }
-}
-
-/*
- * Udp_WinHasSockets --
- */
-int Udp_WinHasSockets(Tcl_Interp *interp) {
- static int initialized = 0; /* 1 if the socket sys has been initialized. */
- static int hasSockets = 0; /* 1 if the system supports sockets. */
- HANDLE socketThread;
- DWORD id;
-
- if (!initialized) {
- OSVERSIONINFO info;
-
- initialized = 1;
-
- /*
- * Find out if we're running on Win32s.
- */
-
- info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&info);
-
- /*
- * Check to see if Sockets are supported on this system. Since
- * win32s panics if we call WSAStartup on a system that doesn't
- * have winsock.dll, we need to look for it on the system first.
- * If we find winsock, then load the library and initialize the
- * stub table.
- */
-
- if ((info.dwPlatformId != VER_PLATFORM_WIN32s)
- || (SearchPath(NULL, "WINSOCK", ".DLL", 0, NULL, NULL) != 0)) {
- hasSockets = InitSockets();
- }
-
- /*
- * Start the socketThread windows and set the thread priority of the
- * socketThread as highest
- */
-
- sockList = NULL;
- sockTail = NULL;
- waitForSock = CreateEvent(NULL, FALSE, FALSE, NULL);
- waitSockRead = CreateEvent(NULL, FALSE, FALSE, NULL);
- sockListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
-
- socketThread = CreateThread(NULL, 8000, SocketThread, NULL, 0, &id);
- SetThreadPriority(socketThread, THREAD_PRIORITY_HIGHEST);
-
-#ifdef DEBUG
- fprintf(dbg, "Initialize socket thread\n");
- fflush(dbg);
-#endif
-
- if (socketThread == NULL) {
-#ifdef DEBUG
- fprintf(dbg, "Failed to create thread\n");
- fflush(dbg);
-#endif
- }
- }
- if (hasSockets) {
- return TCL_OK;
- }
- if (interp != NULL) {
- Tcl_AppendResult(interp, "sockets are not available on this system",
- NULL);
- }
- return TCL_ERROR;
-}
-
-#endif
-
-/*
- * udpInit
- */
-int Udp_Init(Tcl_Interp *interp) {
-#ifdef DEBUG
- dbg = fopen("udp.dbg", "wb");
-#endif
-
-#ifdef WIN32
- 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 TCL_OK;
-}
-
-/*
- * udpOutput--
- */
-static int udpOutput(ClientData instanceData, char *buf, int toWrite, int *errorCode) {
- UdpState *statePtr = (UdpState *) instanceData;
- int written;
- int socksize;
- struct hostent *name;
-#ifdef SIPC_IPV6
- struct sockaddr_in6 sendaddr;
- struct in6_addr inp;
- int n, errnum;
-#else
- struct sockaddr_in sendaddr;
- struct in_addr inp;
-#endif
-
- *errorCode = 0;
- errno = 0;
-
- if (toWrite > MAXBUFFERSIZE) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - MAXBUFFERSIZE");
- fflush(dbg);
-#endif
- return -1;
- }
- socksize = sizeof(sendaddr);
- memset(&sendaddr, 0, socksize);
-
-#ifdef SIPC_IPV6
- n = inet_pton(AF_INET6, statePtr->remotehost, &sendaddr.sin6_addr);
- if (n <= 0) {
- name = getipnodebyname(statePtr->remotehost, AF_INET6, AI_DEFAULT, &errnum);
-#else
- sendaddr.sin_addr.s_addr = inet_addr(statePtr->remotehost);
- if (sendaddr.sin_addr.s_addr == -1) {
- name = gethostbyname(statePtr->remotehost);
-#endif
- if (name == NULL) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - gethostbyname");
- fflush(dbg);
-#endif
- return -1;
- }
-#ifdef SIPC_IPV6
- memcpy(&sendaddr.sin6_addr, name->h_addr, sizeof(sendaddr.sin6_addr));
- }
- sendaddr.sin6_family = AF_INET6;
- sendaddr.sin6_port = htons(statePtr->remoteport);
-#else
- memcpy(&sendaddr.sin_addr, name->h_addr, sizeof(sendaddr.sin_addr));
- }
- sendaddr.sin_family = AF_INET;
- sendaddr.sin_port = htons(statePtr->remoteport);
-#endif
- written = sendto(statePtr->sock, buf, toWrite, 0, (struct sockaddr *)&sendaddr, socksize);
- if (written < 0) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - sendto");
- fflush(dbg);
-#endif
- return -1;
- }
-
-#ifdef DEBUG
- fprintf(dbg, "Send %d to %s:%d through %d\n", written, statePtr->remotehost, statePtr->remoteport, statePtr->sock);
- fflush(dbg);
-#endif
-
- return written;
-}
-
-/*
- * udpInput
- */
-static int udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode) {
- UdpState *statePtr = (UdpState *) instanceData;
- int bytesRead;
- int actual_size, socksize, reply;
- int buffer_size = MAXBUFFERSIZE;
- int port;
- char *remotehost;
- struct hostent *name;
-#ifdef SIPC_IPV6
- char number[128];
- struct sockaddr_in6 recvaddr;
-#else
- char number[32];
- struct sockaddr_in recvaddr;
-#endif
- int sock = statePtr->sock;
- int i;
-#ifdef WIN32
- PacketList *packets;
-#endif
-
-#ifdef DEBUG
- fprintf(dbg, "In udpInput\n");
- fflush(dbg);
-#endif
-
- /*
- * The caller of this function is looking for a stream oriented
- * system, so it keeps calling the function until no bytes are
- * returned, and then appends all the characters together. This
- * is not what we want from UDP, so we fake it by returning a
- * blank every other call. whenever the doread variable is 1 do
- * a normal read, otherwise just return 0.
- */
- if (statePtr->doread == 0) {
- statePtr->doread = 1; /* next time we want to behave normally */
- *errorCode = EAGAIN; /* pretend that we would block */
-#ifdef DEBUG
- fprintf(dbg, "Pretend we would block\n");
- fflush(dbg);
-#endif
- return 0;
- }
-
- *errorCode = 0;
- errno = 0;
-
- if (bufSize == 0) {
- return 0;
- }
-
-#ifdef WIN32
- packets = statePtr->packets;
-#ifdef DEBUG
- fprintf(dbg, "udp_recv\n");
- fflush(dbg);
-#endif
- if (packets == NULL) {
-#ifdef DEBUG
- fprintf(dbg, "packets is NULL\n");
- fflush(dbg);
-#endif
- return 0;
- }
- memcpy(buf, packets->message, packets->actual_size);
- free((char *) packets->message);
-#ifdef DEBUG
- fprintf(dbg, "udp_recv message\n");
- fwrite(buf, 1, packets->actual_size, dbg);
- fflush(dbg);
-#endif
- bufSize = packets->actual_size;
- strcpy(statePtr->peerhost, packets->r_host);
- statePtr->peerport = packets->r_port;
- statePtr->packets = packets->next;
- free((char *) packets);
- bytesRead = bufSize;
-#else
- // else for Unix/Linux
- socksize = sizeof(recvaddr);
-#ifdef SIPC_IPV6
- memset(number, 0, 128);
-#else
- memset(number, 0, 32);
-#endif
- memset(&recvaddr, 0, socksize);
-
- bytesRead = recvfrom(sock, buf, buffer_size, 0, (struct sockaddr *)&recvaddr, &socksize);
- if (bytesRead < 0) {
-#ifdef DEBUG
- fprintf(dbg, "UDP error - recvfrom %d\n", sock);
- fflush(dbg);
-#endif
- *errorCode = errno;
- return -1;
- }
-
-#ifdef SIPC_IPV6
- remotehost = (char *)inet_ntop(AF_INET6, &recvaddr.sin6_addr, statePtr->peerhost, sizeof(statePtr->peerhost));
- port = ntohs(recvaddr.sin6_port);
-#else
- remotehost = (char *)inet_ntoa(recvaddr.sin_addr);
- port = ntohs(recvaddr.sin_port);
- strcpy(statePtr->peerhost, remotehost);
-#endif
-
-#ifdef DEBUG
- fprintf(dbg, "remotehost: %s\n", remotehost);
- fflush(dbg);
-#endif
- statePtr->peerport = port;
-#endif
-
- /* we don't want to return anything next time */
- if (bytesRead > 0) { buf[bytesRead] = '\0'; statePtr->doread = 0; }
-
-#ifdef DEBUG
- fprintf(dbg, "udpInput end: %d, %s\n", bytesRead, buf);
- fflush(dbg);
-#endif
-
- if (bytesRead > -1) {
- return bytesRead;
- }
-
- *errorCode = errno;
- return -1;
-}
-