* generic/udp_tcl.c: An extensive interface rewrite. We now have
authorpatthoyts <patthoyts>
Fri, 13 Feb 2004 21:38:15 +0000 (21:38 +0000)
committerpatthoyts <patthoyts>
Fri, 13 Feb 2004 21:38:15 +0000 (21:38 +0000)
just a udp command and the socket is controlled via the fconfigure
command. This is now a much more similar to the tcl socket
command. For backwards compatability, we define the old functions
in terms of the new interface.
      * * *    INTERFACE INCOMPATABILITY   * * *

ChangeLog
configure
configure.in
generic/udp.tcl [new file with mode: 0644]
generic/udp_tcl.c
generic/udp_tcl.h
tests/udp.test
win/makefile.vc
win/tcludp.dsp
win/tcludp.rc

index df04053f03bfa33196340e42dbba0a0cfb122094..e734115abc796fa5c50aa61e2fe466baae09c034 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
+2004-02-13  Pat Thoyts  <patthoyts@users.sourceforge.net>
+
+       * generic/udp_tcl.c: An extensive interface rewrite. We now have
+       just a udp command and the socket is controlled via the fconfigure
+       command. This is now a much more similar to the tcl socket
+       command. For backwards compatability, we define the old functions
+       in terms of the new interface.
+             * * *    INTERFACE INCOMPATABILITY   * * *
+
+       * all:   Created branch dev-2 to hold udp 2.0 development
+       
 2004-02-09  Pat Thoyts  <patthoyts@users.sourceforge.net>
 
+       * generic/udp_tcl.c: Followed up a suggestion from patch #828180
+       to support address reuse using SO_REUSEADDR. Implemented as an
+       fconfigure option on the channel.
+
        * generic/udp_tcl.c: Followed up a suggestion in patch #794072 to
        support udp broadcast packets. This can be queried/enabled using
        fconfigure $s -broadcast ?1|0?
index db9c7e23795a6c0e031c6d5402a44fd93babc6e8..687e4bdf8972ad4e1d266b7447e4d7ec96a73347 100755 (executable)
--- a/configure
+++ b/configure
@@ -571,9 +571,9 @@ CONFIGDIR=${srcdir}/tclconfig
 
 PACKAGE=udp
 
-MAJOR_VERSION=1
+MAJOR_VERSION=2
 MINOR_VERSION=0
-PATCHLEVEL=6
+PATCHLEVEL=0
 
 VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${PATCHLEVEL}
 NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
index 4355ec6729b35c20b10844902786c8a12f1725a7..fff387de16257c2cc7785f642b4a9ba606a016b0 100644 (file)
@@ -37,9 +37,9 @@ dnl# AC_CONFIG_HEADER(config.h)
 
 PACKAGE=udp
 
-MAJOR_VERSION=1
+MAJOR_VERSION=2
 MINOR_VERSION=0
-PATCHLEVEL=6
+PATCHLEVEL=0
 
 VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${PATCHLEVEL}
 NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
diff --git a/generic/udp.tcl b/generic/udp.tcl
new file mode 100644 (file)
index 0000000..d83a9c3
--- /dev/null
@@ -0,0 +1,52 @@
+
+namespace eval udp {
+    namespace export udp_open udp_conf
+}
+
+proc ::udp::udp_open {{port -1}} {
+    set s [udp]
+    if {$port != -1} {
+        fconfigure $s -sockname [list {} $port]
+    }
+    return $s
+}
+
+# udpConf fileId [-mcastadd] [-mcastdrop] groupaddr
+# udpConf fileId remotehost remoteport
+# udpConf fileId [-myport] [-remote] [-peer]
+proc ::udp::udp_conf {s args} {
+    if {[llength $args] < 1 || [llength $args] > 2} {
+        return -code error "wrong \# args: should be \
+            udp_conf socket ?option ...?"
+    }
+
+    while {[string match -* [set option [lindex $args 0]]]} {
+        switch -exact -- $option {
+            -myport    { return [lindex [fconfigure $s -sockname] 1] }
+            -remote    { return [fconfigure $s -remote] }
+            -peer      { return [fconfigure $s -peer] }
+            -mcastadd  { return [fconfigure $f -mcastadd [Pop args 1]] }
+            -mcastdrop { return [fconfigure $f -mcastdrop [Pop args 1]] }
+            --    { Pop args ; break }
+            default {
+                return -code error "bad option $option: must be one of\
+                    -mcastadd, -mcastdrop, -myport, -remote, or -peer"
+            }
+        }
+        Pop args
+    }
+
+    if {[llength $args] == 2} {
+        return [fconfigure $s -remote $args]
+    } else {
+        return -code error "wrong \# args: should be\
+            udp_conf socket ?option ...?"
+    }
+}
+
+proc ::udp::Pop {varname {nth 0}} {
+    upvar $varname args
+    set r [lindex $args $nth]
+    set args [lreplace $args $nth $nth]
+    return $r
+}
index 1ef237bae9a750c5af5c5dfe1984a3448669831a..187729ae86fb89d8eb2458cbb8174d7bad997d71 100644 (file)
@@ -46,9 +46,9 @@ typedef int socklen_t;
 #endif /* WIN32 */
 
 #ifdef DEBUG
-#define UDPTRACE udpTrace
+#define UDPTRACE UdpTrace
 #else
-#define UDPTRACE 1 ? ((void)0) : udpTrace
+#define UDPTRACE 1 ? ((void)0) : UdpTrace
 #endif
 
 FILE *dbg;
@@ -72,26 +72,31 @@ 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 * []);
+int UdpPeek(ClientData , Tcl_Interp *, int , CONST84 char * []);
+
+Tcl_Channel Tcl_OpenUdpSocket(Tcl_Interp *interp, CONST char *myaddr,
+                             unsigned short myport);
+Tcl_Channel Tcl_MakeUdpChannel(SOCKET sock);
 
 /*
  * internal functions
  */
-static void udpTrace(const char *format, ...);
+static void UdpTrace(const char *format, ...);
+static SOCKET UdpCreateSock(int protocol);
 static int  udpGetService(Tcl_Interp *interp, const char *service,
                           unsigned short *servicePort);
+static int UdpGetProtocolFromObj(Tcl_Interp *interp, 
+                                 Tcl_Obj *objPtr, int *resultPtr);
 
 /*
  * Windows specific functions
  */
 #ifdef WIN32
 
-int  UdpEventProc(Tcl_Event *evPtr, int flags);
+static 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);
+static void UDP_CheckProc(ClientData data, int flags);
+static int  Udp_WinHasSockets(Tcl_Interp *interp);
 
 /* FIX ME - these should be part of a thread/package specific structure */
 static HANDLE waitForSock;
@@ -106,11 +111,7 @@ static UdpState *sockTail;
  * This structure describes the channel type for accessing UDP.
  */
 static Tcl_ChannelType Udp_ChannelType = {
-#ifdef SIPC_IPV6
-    "udp6",                /* Type name.                                    */
-#else 
     "udp",                 /* Type name.                                    */
-#endif 
     NULL,                  /* Set blocking/nonblocking behaviour. NULL'able */
     udpClose,              /* Close channel, clean instance data            */
     udpInput,              /* Handle read request                           */
@@ -122,6 +123,15 @@ static Tcl_ChannelType Udp_ChannelType = {
     udpGetHandle,          /* Get OS handle from the channel.               */
 };
 
+/*
+ * Package initialization:
+ * tcl_findLibrary basename version patch initScript enVarName varName
+ */
+
+static char initScript[] =
+    "tcl_findLibrary udp " TCLUDP_PACKAGE_VERSION " " TCLUDP_PACKAGE_VERSION
+    " udp.tcl TCLUDP_LIBRARY udp_library";
+
 /*
  * ----------------------------------------------------------------------
  * udpInit
@@ -147,15 +157,15 @@ Udp_Init(Tcl_Interp *interp)
     Tcl_CreateEventSource(UDP_SetupProc, UDP_CheckProc, NULL);
 #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);
+    Tcl_CreateCommand(interp, "udp_peek", UdpPeek , 
+       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
     
-    r = Tcl_PkgProvide(interp, TCLUDP_PACKAGE_NAME, TCLUDP_PACKAGE_VERSION);
-    return r;
+    Tcl_CreateObjCommand(interp, "udp", Udp_CmdProc,
+       (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+    
+    Tcl_PkgProvide(interp, TCLUDP_PACKAGE_NAME, TCLUDP_PACKAGE_VERSION);
+
+    return Tcl_Eval(interp, initScript);
 }
 
 /*
@@ -163,126 +173,366 @@ Udp_Init(Tcl_Interp *interp)
  * Udp_CmdProc --
  *  Provide a user interface similar to the Tcl stock 'socket' command.
  *
- *  udp ?options?
- *  udp ?options? host port
- *  udp -server command ?options? port
+ *  udp ?options? ?port?
  *
+ *  Options (from socket):
+ *    -myaddr addr  which interface to create the socket on.
+ *    -myport port  specify a port to use (0 or omitted means system chooses).
+ *
+ *    -reuseaddr    is specfied, permit address reuse.
  * ----------------------------------------------------------------------
  */
 int
-Udp_CmdProc(ClientData clientData, Tcl_Interp *interp,
-            int objc, Tcl_Obj *CONST objv[])
+Udp_CmdProc(
+    ClientData clientData,     /* Not used */
+    Tcl_Interp *interp,                /* Current interpreter */
+    int objc,                  /* Number of arguments */
+    Tcl_Obj *CONST objv[])     /* Arguments */
 {
-    Tcl_SetResult(interp, "E_NOTIMPL", TCL_STATIC);
-    return TCL_ERROR;
+    static CONST char *options[] = {
+       "-myaddr", "-myport", "-reuseaddr", "-protocol", "--", (char *)NULL
+    };
+    enum {
+       OPT_MYADDR, OPT_MYPORT, OPT_REUSEADDR, OPT_PROTOCOL, OPT_END,
+    };
+    CONST char *myaddr = NULL;
+    uint16_t myport = 0;
+    int protocol = AF_INET;
+    int reuseaddr = 0, index, i, r = TCL_OK;
+
+    for (i = 1; r == TCL_OK && i < objc; i++) {
+       if (Tcl_GetIndexFromObj(interp, objv[i], options,
+           "option", 0, &index) != TCL_OK) {
+           return TCL_ERROR;
+       }
+       
+       switch (index) {
+           case OPT_MYADDR:
+               ++i;
+               if (objc == i) {
+                   Tcl_WrongNumArgs(interp, 1, objv, "-myaddr address");
+                   r = TCL_ERROR;
+               } else {
+                   myaddr = Tcl_GetString(objv[i]);
+               }
+               break;
+
+           case OPT_MYPORT:
+               ++i;
+               if (objc == i) {
+                   Tcl_WrongNumArgs(interp, 1, objv, "-myport port");
+                   r = TCL_ERROR;
+               } else {
+                   r = udpGetService(interp, Tcl_GetString(objv[i]), &myport);
+               }
+               break;
+
+           case OPT_REUSEADDR:
+               ++i;
+               if (objc == i) {
+                   Tcl_WrongNumArgs(interp, 1, objv, "-reuseaddr boolean");
+                   r = TCL_ERROR;
+               } else {
+                   r = Tcl_GetBooleanFromObj(interp, objv[i], &reuseaddr);
+               }
+               break;
+
+            case OPT_PROTOCOL:
+                ++i;
+               if (objc == i) {
+                   Tcl_WrongNumArgs(interp, 1, objv, "-protocol ipv4|ipv6");
+                   r = TCL_ERROR;
+               } else {
+                   r = UdpGetProtocolFromObj(interp, objv[i], &protocol);
+               }
+                break;
+
+           case OPT_END:
+               break;
+
+           default:
+               Tcl_ResetResult(interp);
+               Tcl_AppendResult(interp, "bad option \"", 
+                   Tcl_GetString(objv[i]), "\": must be -myaddr, -myport, "
+                   "-reuseaddr or --", (char *)NULL);
+               r = TCL_ERROR;
+       }
+
+       if (i == OPT_END) {
+           break;
+       }
+    }
+
+    if (r == TCL_OK) {
+       Tcl_Channel channel = NULL;
+       SOCKET sock = UdpCreateSock(protocol);
+       if (sock == INVALID_SOCKET) {
+           r = TCL_ERROR;
+       } else {
+           channel =  Tcl_MakeUdpChannel(sock);
+           if (channel == NULL) {
+               closesocket(sock);
+               r = TCL_ERROR;
+           }
+       }
+
+       if (r == TCL_OK) {
+           Tcl_RegisterChannel(interp, channel);
+           Tcl_SetObjResult(interp, 
+               Tcl_NewStringObj(Tcl_GetChannelName(channel), -1));
+       }
+    }
+    return r;
 }
 
-/*
- * 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
+UdpGetProtocolFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *resultPtr)
+{
+    /* Odd values are AF_INET6 */
+    static const char *protocolStrings[] = {
+        "ipv4", "ipv6", "inet", "inet6", "4", "6", NULL
+    };
+    int af = 0;
+    int r = Tcl_GetIndexFromObj(interp, objPtr, 
+                                protocolStrings, "protocol", 0, &af);
+    if (r == TCL_OK) {
+        if (af & 1) {
+            *resultPtr = AF_INET6;
+        } else {
+            *resultPtr = AF_INET;
+        }
+    }
+    return r;
+}
 
 /*
  * ----------------------------------------------------------------------
- * udpOpen --
+ * UdpCreateSock --
+ *
+ *     Create a UDP socket and optionally specify the local address.
  *
- *  opens a UDP socket and addds the file descriptor to the tcl
- *  interpreter
  * ----------------------------------------------------------------------
  */
+
+SOCKET
+UdpCreateSock(int protocol)
+{
+    SOCKET sock;
+    unsigned long nonblocking = 1;
+
+    sock = socket(protocol, SOCK_DGRAM, 0);
+
+    /* Make this a non-blocking socket */
+    ioctlsocket(sock, FIONBIO, &nonblocking);
+    return sock;
+}
+
+/*
+ * UdpGetAddressFromObj --
+ * Convert a Tcl object into a sockaddr_in socket name.
+ * The Tcl object may be just a hostname, or a list
+ * made up of {hostname port} where port can be the
+ * service name or the port number.
+ * Returns:
+ * A standard tcl result.
+ */
+
 int
-udpOpen(ClientData clientData, Tcl_Interp *interp,
-        int argc, CONST84 char * argv[]) 
+UdpGetAddressFromObj(
+    Tcl_Interp *interp,
+    Tcl_Obj *objPtr,
+    struct sockaddr *saddr)
 {
-    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;
-    
-    if (argc >= 2) {
-        if (udpGetService(interp, argv[1], &localport) != TCL_OK)
-            return TCL_ERROR;
+    int len, r = TCL_OK;
+    unsigned short port = 0;
+    CONST char *hostname = NULL;
+    struct hostent *hostent;
+
+    r = Tcl_ListObjLength(interp, objPtr, &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, objPtr, 0, &hostPtr);
+            hostname = Tcl_GetString(hostPtr);
+            
+            if (len == 2) {
+                Tcl_ListObjIndex(interp, objPtr, 1, &portPtr);            
+                r = udpGetService(interp, Tcl_GetString(portPtr), &port);
+            }
+        }
     }
-    
-    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;
+    if (r == TCL_OK) {
+
+        if (saddr->sa_family == AF_INET6) {
+
+            struct sockaddr_in6 * addr = (struct sockaddr_in6 *)saddr;
+
+#if HAVE_GETADDRINFO
+            char service[TCL_INTEGER_SPACE];
+            struct addrinfo ai;
+            struct addrinfo *pai = 0;
+
+            sprintf(service, "%u", ntohs(port));
+            memset(&ai, 0, sizeof(ai));
+            ai.ai_family = PF_INET6;
+            ai.ai_socktype = SOCK_DGRAM;
+            if (getaddrinfo(hostname, service, &ai, &pai) == 0)
+                memcpy(&addr->sin6_addr, pai->ai_addr, pai->ai_addrlen);
+            freeaddrinfo(pai);
+            
+#elif HAVE_INET_PTON
+            int n, errnum;
+            n = inet_pton(AF_INET6, hostname, &addr->sin6_addr);
+            if (n <= 0) {
+                name = getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &errnum);
+            }
 #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;
+           addr->sin6_family = AF_INET6;
+           addr->sin6_port = port;
+
+        } else {
+
+            struct sockaddr_in *addr = (struct sockaddr_in *)saddr;
+           addr->sin_family = AF_INET;
+           addr->sin_port = port;
+           if (hostname == NULL) {
+               addr->sin_addr.s_addr = INADDR_ANY;
+           } else {
+               addr->sin_addr.s_addr = inet_addr(hostname);
+               if (addr->sin_addr.s_addr == INADDR_NONE) {
+                   hostent = gethostbyname(hostname);
+                   if (hostent != NULL) {
+                       memcpy(&addr->sin_addr, hostent->h_addr, 
+                           (size_t)hostent->h_length);
+                   } else {
+                       Tcl_SetResult(interp, "host not found", TCL_STATIC);
+                       return TCL_ERROR;
+                   }
+                }
+           }
+       }
     }
 
-    ioctlsocket(sock, FIONBIO, &status);
+    return r;
+};
 
-    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
+int
+UdpGetObjFromAddress(
+    Tcl_Interp *interp,
+    struct sockaddr *saddr,
+    Tcl_Obj **objPtrPtr)
+{
+    struct sockaddr_in *addr = (struct sockaddr_in *)saddr;
+    Tcl_Obj *parts[2];
+
+    if (addr->sin_addr.s_addr == INADDR_NONE) {
+        parts[0] = Tcl_NewStringObj(NULL, 0);
+    } else {
+        parts[0] = Tcl_NewStringObj(inet_ntoa(addr->sin_addr), -1);
     }
-    
-    UDPTRACE("Open socket %d. Bind socket to port %d\n", 
-             sock, ntohs(localport));
+    parts[1] = Tcl_NewIntObj(ntohs(addr->sin_port));
+
+    *objPtrPtr = Tcl_NewListObj(2, parts);
+    return TCL_OK;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Tcl_OpenUdpSocket --
+ *
+ *     Opens a UDP socket and wraps it in a Tcl channel. There is no
+ *     difference between client and server UDP sockets except for the
+ *     port number. If the port is 0 then the system will select a port
+ *     for us, otherwise we use the specified port.
+ *
+ * Results:
+ *     The newly created channel is returned, or NULL. The interpreters
+ *     error message will be set in the event of failure.
+ *
+ * Side effects:
+ *     Opens a socket and registers a new channel in interp.
+ *
+ * ----------------------------------------------------------------------
+ */
+
+Tcl_Channel
+Tcl_OpenUdpSocket(
+    Tcl_Interp *interp,                /* May be NULL - used for returning errors */
+    CONST char *myaddr,                /* Client-side address */
+    unsigned short myport)     /* Client-side port in network byte order */
+{
+    /* FIX ME: can probably tell from the address info what protocol */
+    Tcl_Channel chan = NULL;
+    SOCKET sock = UdpCreateSock(AF_INET);
+    if (sock != INVALID_SOCKET) {
+       chan = Tcl_MakeUdpChannel(sock);
+    }
+    return chan;
+}
+\f
+/*
+ * ----------------------------------------------------------------------
+ * 
+ * Tcl_MakeUdpChannel --
+ *
+ *     Creates a Tcl_Channel from an existing UDP socket.
+ *
+ * Results:
+ *     Wraps a system socket in a Tcl_Channel structure.
+ *
+ * Side effects:
+ *     Under Win32, the channel instance data is appended to the list
+ *     of available listeners. For all platforms, a new channel is 
+ *     registered.
+ *
+ * ----------------------------------------------------------------------
+ */
 
+Tcl_Channel
+Tcl_MakeUdpChannel(SOCKET sock)
+{
+    UdpState *statePtr;
+    char channelName[TCL_INTEGER_SPACE + 5];
+    sockaddr_t name;
+    int len = sizeof(sockaddr_t);
+    
     statePtr = (UdpState *) ckalloc((unsigned) sizeof(UdpState));
     memset(statePtr, 0, sizeof(UdpState));
     statePtr->sock = sock;
+
+    getsockname(sock, (struct sockaddr *)&name, &len);
+    if (name.ss_family == AF_INET) {
+        statePtr->saddr_local.ipv4.sin_addr.s_addr = INADDR_NONE;
+        statePtr->saddr_remote.ipv4.sin_addr.s_addr = INADDR_NONE;
+        statePtr->saddr_peer.ipv4.sin_addr.s_addr = INADDR_NONE;
+    }
+
     sprintf(channelName, "sock%d", statePtr->sock);
-    statePtr->channel = Tcl_CreateChannel(&Udp_ChannelType, channelName,
-                                          (ClientData) statePtr,
-                                          (TCL_READABLE | TCL_WRITABLE | TCL_MODE_NONBLOCKING));
+    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);
+
+    len = sizeof(sockaddr_t);
+    getsockname(sock, (struct sockaddr *)&statePtr->saddr_local, &len);
+
 #ifdef WIN32
     statePtr->threadId = Tcl_GetCurrentThread();    
     statePtr->packetNum = 0;
     statePtr->next = NULL;
     statePtr->packets = NULL;
     statePtr->packetsTail = 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;
+        sockList = sockTail = statePtr;
     } else {
         sockTail->next = statePtr;
         sockTail = statePtr;
@@ -292,160 +542,18 @@ udpOpen(ClientData clientData, Tcl_Interp *interp,
     SetEvent(sockListLock);
     SetEvent(waitForSock);
 #endif
-    return TCL_OK;
-}
 
-/*
- * ----------------------------------------------------------------------
- * udpConf --
- * ----------------------------------------------------------------------
- */
-int
-udpConf(ClientData clientData, Tcl_Interp *interp,
-        int argc, CONST84 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;
-    
-    if (argc != 4 && argc != 3) {
-        result = "udpConf fileId [-mcastadd] [-mcastdrop] groupaddr | udpConf fileId remotehost remoteport | udpConf fileId [-myport] [-remote] [-peer] [-broadcast]";
-        Tcl_SetResult (interp, result, NULL);
-        return TCL_ERROR;
-    }
-    chan = Tcl_GetChannel(interp, (char *)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", ntohs(statePtr->localport));
-            Tcl_AppendResult(interp, buf, (char *)NULL);
-        } else if (!strcmp(argv[2], "-remote")) {
-            if (statePtr->remotehost && *statePtr->remotehost) {
-                sprintf(buf, "%s", statePtr->remotehost);
-                Tcl_AppendResult(interp, buf, (char *)NULL);
-                sprintf(buf, "%d", ntohs(statePtr->remoteport));
-                Tcl_AppendElement(interp, buf);
-            }
-        } else if (!strcmp(argv[2], "-peer")) {
-            if (statePtr->peerhost && *statePtr->peerhost) {
-                sprintf(buf, "%s", statePtr->peerhost);
-                Tcl_AppendResult(interp, buf, (char *)NULL);
-                sprintf(buf, "%d", statePtr->peerport);
-                Tcl_AppendElement(interp, buf);
-            }
-        } else if (!strcmp(argv[2], "-broadcast")) {
-            int tmp = 1;
-            socklen_t optlen = sizeof(int);
-            if (getsockopt(statePtr->sock, SOL_SOCKET, SO_BROADCAST, 
-                           (char *)&tmp, &optlen)) {
-                sprintf(errBuf, "%s", "udp - setsockopt");
-                UDPTRACE("UDP error - setsockopt\n");
-                Tcl_AppendResult(interp, errBuf, (char *)NULL);
-                return TCL_ERROR;
-            } else {
-                Tcl_SetObjResult(interp, Tcl_NewIntObj(tmp));
-                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;
-        }
-        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) {
-                    UDPTRACE("UDP error - gethostbyname");
-                    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, (const char*)&mreq, sizeof(mreq)) < 0) {
-                UDPTRACE("UDP error - setsockopt - IP_ADD_MEMBERSHIP");
-                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) {
-                    UDPTRACE("UDP error - gethostbyname");
-                    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, (const char*)&mreq, sizeof(mreq)) < 0) {
-                UDPTRACE("UDP error - setsockopt - IP_DROP_MEMBERSHIP");
-                return TCL_ERROR;
-            }
-            return TCL_OK;
-        } else if (!strcmp(argv[2], "-broadcast")) {
-            socklen_t optlen = sizeof(int);
-            int tmp = 0;
-            int r = Tcl_GetInt(interp, argv[3], &tmp);
-            if (r == TCL_OK) {
-                if (setsockopt(statePtr->sock, SOL_SOCKET, SO_BROADCAST, 
-                               (const char *)&tmp, optlen)) {
-                    sprintf(errBuf, "%s", "udp - setsockopt");
-                    UDPTRACE("UDP error - setsockopt\n");
-                    Tcl_AppendResult(interp, errBuf, (char *)NULL);
-                    r = TCL_ERROR;
-                } else {
-                    Tcl_SetObjResult(interp, Tcl_NewIntObj(tmp));
-                }
-            }
-            return r;
-        } 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]);
-            return udpGetService(interp, argv[3], &(statePtr->remoteport));
-        }
-    } 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 statePtr->channel;
 }
 
 /*
  * ----------------------------------------------------------------------
- * udpPeek --
+ * UdpPeek --
  *  peek some data and set the peer information
  * ----------------------------------------------------------------------
  */
 int
-udpPeek(ClientData clientData, Tcl_Interp *interp,
+UdpPeek(ClientData clientData, Tcl_Interp *interp,
         int argc, CONST84 char * argv[])
 {
 #ifndef WIN32
@@ -483,11 +591,9 @@ udpPeek(ClientData clientData, Tcl_Interp *interp,
         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);
+    memcpy(&statePtr->saddr6_peer, &recvaddr, sizeof(recvaddr));
 #else
-    strcpy(statePtr->peerhost, (char *)inet_ntoa(recvaddr.sin_addr));
-    statePtr->peerport = ntohs(recvaddr.sin_port);
+    memcpy(&statePtr->saddr_peer, &recvaddr, sizeof(recvaddr));
 #endif
     message[16]='\0';
     
@@ -533,7 +639,7 @@ UDP_SetupProc(ClientData data, int flags)
     UdpState *statePtr;
     Tcl_Time blockTime = { 0, 0 };
     
-    UDPTRACE("setupProc\n");
+    /* UDPTRACE("setupProc\n"); */
     
     if (!(flags & TCL_FILE_EVENTS)) {
         return;
@@ -563,17 +669,9 @@ UDP_CheckProc(ClientData data, int flags)
     int actual_size, socksize;
     int buffer_size = MAXBUFFERSIZE;
     char *message;
-#ifdef SIPC_IPV6
-    char number[128], *remotehost;
-    struct sockaddr_in6 recvaddr;
-#else
-    char number[32];
-    struct sockaddr_in recvaddr;
-#endif
+    sockaddr_t recvaddr;
     PacketList *p;
     
-    UDPTRACE("checkProc\n");
-    
     /* synchronized */
     WaitForSingleObject(sockListLock, INFINITE);
     
@@ -582,13 +680,8 @@ UDP_CheckProc(ClientData data, int flags)
             UDPTRACE("UDP_CheckProc\n");
             /* 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) {
                 UDPTRACE("calloc error\n");
@@ -601,28 +694,14 @@ UDP_CheckProc(ClientData data, int flags)
             
             if (actual_size < 0) {
                 UDPTRACE("UDP error - recvfrom %d\n", statePtr->sock);
-                ckfree(message);
+                free(message);
             } 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
+                memcpy(&p->peer, &recvaddr, sizeof(recvaddr));
                 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;
@@ -631,9 +710,9 @@ UDP_CheckProc(ClientData data, int flags)
                     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);
+                UDPTRACE("Received %d bytes from through %d\n",
+                         p->actual_size, statePtr->sock);
+                //UDPTRACE("%s\n", p->message);
             }
             
             statePtr->packetNum--;
@@ -667,7 +746,7 @@ InitSockets()
      * Load the socket DLL and initialize the function table.
      */
     
-    if (WSAStartup(0x0101, &wsaData))
+    if (WSAStartup(0x0002, &wsaData))
         return 0;
     
     return 1;
@@ -709,15 +788,15 @@ SocketThread(LPVOID arg)
         
         /* set each socket for select */
         for (statePtr = sockList; statePtr != NULL; statePtr=statePtr->next) {
-            FD_SET(statePtr->sock, &readfds);
-            UDPTRACE("SET sock %d\n", statePtr->sock);
+            FD_SET((SOCKET)statePtr->sock, &readfds);
+            /* UDPTRACE("SET sock %d\n", statePtr->sock); */
         }
         
         SetEvent(sockListLock);
-        UDPTRACE("Wait for select\n");
+        /* UDPTRACE("Wait for select\n"); */
         /* block here */
         found = select(0, &readfds, NULL, NULL, &timeout);
-        UDPTRACE("select end\n");
+        /* UDPTRACE("select end\n"); */
         
         if (found <= 0) {
             /* We closed the socket during select or time out */
@@ -794,7 +873,7 @@ Udp_WinHasSockets(Tcl_Interp *interp)
         
         sockList = NULL;
         sockTail = NULL;
-        waitForSock = CreateEvent(NULL, FALSE, FALSE, NULL);
+        waitForSock  = CreateEvent(NULL, FALSE, FALSE, NULL);
         waitSockRead = CreateEvent(NULL, FALSE, FALSE, NULL);
         sockListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
         
@@ -840,32 +919,32 @@ udpClose(ClientData instanceData, Tcl_Interp *interp)
     int errorCode = 0;
     UdpState *statePtr = (UdpState *) instanceData;
 #ifdef WIN32
-    UdpState *statePre, *searchPtr;
-    
-    WaitForSingleObject(sockListLock, INFINITE);
+    UdpState *p, *q;
 #endif /* ! WIN32 */
     
     sock = statePtr->sock;
 
 #ifdef WIN32
     /* remove the statePtr from the list */
-    for (searchPtr = sockList, statePre = sockList;
-         searchPtr != NULL;
-         statePre=statePtr, searchPtr=searchPtr->next) {
-        if (searchPtr->sock == sock) {
-            UDPTRACE("Remove %d from the list\n", sock);
-            if (searchPtr == sockList) {
-                sockList = sockList->next;
-            } else {
-                statePre->next = searchPtr->next;
-                if (sockTail == searchPtr)
-                    sockTail = statePre;
-            }
-        }
+    WaitForSingleObject(sockListLock, INFINITE);
+
+    for (p = q = sockList; p != NULL; q = p, p = p->next) {
+       if (p->sock == sock) {
+           UDPTRACE("Remove sock%d from list\n", sock);
+           if (p == sockList) {
+               sockList = q = p->next;
+           } else {
+               q->next = p->next;
+           }
+           if (p == sockTail) {
+               sockTail = q;
+           }
+           break;
+       }
     }
+
 #endif /* ! WIN32 */
     
-    Tcl_UnregisterChannel(interp, statePtr->channel);
     if (closesocket(sock) < 0) {
         errorCode = errno;
     }
@@ -941,14 +1020,8 @@ udpOutput(ClientData instanceData, CONST84 char *buf, int toWrite, int *errorCod
 {
     UdpState *statePtr = (UdpState *) instanceData;
     int written;
-    int socksize;
-    struct hostent *name;
-#ifdef SIPC_IPV6
-    struct sockaddr_in6 sendaddr;
-    int n, errnum;
-#else
-    struct sockaddr_in sendaddr;
-#endif
+    int socksize = sizeof(sockaddr_t);
+    sockaddr_t name;
     
     *errorCode = 0;
     errno = 0;
@@ -957,43 +1030,29 @@ udpOutput(ClientData instanceData, CONST84 char *buf, int toWrite, int *errorCod
         UDPTRACE("UDP error - MAXBUFFERSIZE");
         return -1;
     }
-    socksize = sizeof(sendaddr);
-    memset(&sendaddr, 0, socksize);
-    
+
+    getsockname(statePtr->sock, (struct sockaddr *)&name, &socksize);
+
+    if ((name.ss_family == AF_INET
+       && statePtr->saddr_remote.ipv4.sin_addr.s_addr == INADDR_NONE)
 #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);
+       || (name.ss_family == AF_INET6 
+            && IN6_IS_ADDR_UNSPECIFIED(&statePtr->saddr_remote.ipv6.sin6_addr))
 #endif
-            if (name == NULL) {
-                UDPTRACE("UDP error - gethostbyname");
-                return -1;
-            }
-#ifdef SIPC_IPV6
-            memcpy(&sendaddr.sin6_addr, name->h_addr, sizeof(sendaddr.sin6_addr));
-        }
-        sendaddr.sin6_family = AF_INET6;
-        sendaddr.sin6_port = statePtr->remoteport;
-#else
-        memcpy(&sendaddr.sin_addr, name->h_addr, sizeof(sendaddr.sin_addr));
+       ) {
+        UDPTRACE("UDP error - no host set");
+        return -1;
     }
-    sendaddr.sin_family = AF_INET;
-    sendaddr.sin_port = statePtr->remoteport;
-#endif
+
+    socksize = sizeof(statePtr->saddr_remote);
     written = sendto(statePtr->sock, buf, toWrite, 0,
-                     (struct sockaddr *)&sendaddr, socksize);
+                     (const struct sockaddr *)&statePtr->saddr_remote, socksize);
     if (written < 0) {
         UDPTRACE("UDP error - sendto");
         return -1;
     }
-    
-    UDPTRACE("Send %d to %s:%d through %d\n", written, statePtr->remotehost,
-             ntohs(statePtr->remoteport), statePtr->sock);
+
+    UDPTRACE("Send %d through socket %u\n", written, statePtr->sock);
     
     return written;
 }
@@ -1017,13 +1076,8 @@ udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode)
     int buffer_size = MAXBUFFERSIZE;
     char *remotehost;
     int sock = statePtr->sock;
-#ifdef SIPC_IPV6
     char number[128];
-    struct sockaddr_in6 recvaddr;
-#else /* ! SIPC_IPV6 */
-    char number[32];
-    struct sockaddr_in recvaddr;
-#endif /* ! SIPC_IPV6 */
+    sockaddr_t recvaddr;
 #endif /* ! WIN32 */
     
     UDPTRACE("In udpInput\n");
@@ -1062,18 +1116,13 @@ udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode)
     free((char *) packets->message);
     UDPTRACE("udp_recv message\n%s", buf);
     bufSize = packets->actual_size;
-    strcpy(statePtr->peerhost, packets->r_host);
-    statePtr->peerport = packets->r_port;
+    memcpy(&statePtr->saddr_peer, &packets->peer, sizeof(packets->peer));
     statePtr->packets = packets->next;
     free((char *) packets);
     bytesRead = bufSize;
 #else /* ! WIN32 */
     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,
@@ -1083,20 +1132,18 @@ udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode)
         *errorCode = errno;
         return -1;
     }
+    memcpy(&statePtr->saddr_peer, &recvaddr, sizeof(recvaddr));
     
 #ifdef SIPC_IPV6
-    remotehost = (char *)inet_ntop(AF_INET6,
-                                   &recvaddr.sin6_addr, statePtr->peerhost,
-                                   sizeof(statePtr->peerhost));
-    port = ntohs(recvaddr.sin6_port);
+    inet_ntop(recvaddr.sin_family, &statePtr->saddr_peer.sin_addr, 
+        number, 128);
 #else
-    remotehost = (char *)inet_ntoa(recvaddr.sin_addr);
-    port = ntohs(recvaddr.sin_port);
-    strcpy(statePtr->peerhost, remotehost);
+    inet_ntop(statePtr->saddr_peer.sin_family, &statePtr->saddr_peer.sin_addr, 
+        number, 128);
 #endif
-    
-    UDPTRACE("remotehost: %s:%d\n", remotehost, port);
-    statePtr->peerport = port;
+
+    UDPTRACE("remotehost: %s:%d\n", number, ntohs(recvaddr.sin6_port));
+
 #endif /* ! WIN32 */
     
     /* we don't want to return anything next time */
@@ -1115,6 +1162,42 @@ udpInput(ClientData instanceData, char *buf, int bufSize, int *errorCode)
     return -1;
 }
 
+/*
+ * ----------------------------------------------------------------------
+ *
+ * UdpMulticast --
+ *
+ * Action should be IP_ADD_MEMBERSHIP | IP_DROP_MEMBERSHIP 
+ *
+ */
+int
+UdpMulticast(Tcl_Interp *interp,
+    SOCKET sock, CONST84 char *grp, int action)
+{
+    struct ip_mreq mreq;
+    struct hostent *name;
+
+    memset(&mreq, 0, sizeof(mreq));
+
+    mreq.imr_multiaddr.s_addr = inet_addr(grp);
+    if (mreq.imr_multiaddr.s_addr == -1) {
+        name = gethostbyname(grp);
+        if (name == NULL) {
+            Tcl_SetResult(interp, "invalid hostname", TCL_STATIC);
+            return TCL_ERROR;
+        }
+        memcpy(&mreq.imr_multiaddr.s_addr, name->h_addr, 
+               sizeof(mreq.imr_multiaddr));
+    }
+    mreq.imr_interface.s_addr = INADDR_ANY;
+    if (setsockopt(sock, IPPROTO_IP, action,
+                   (const char*)&mreq, sizeof(mreq)) < 0) {
+       Tcl_SetResult(interp, "error changind multicast group", TCL_STATIC);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
 /*
  * ----------------------------------------------------------------------
  * udpGetOption --
@@ -1125,23 +1208,22 @@ udpGetOption(ClientData instanceData, Tcl_Interp *interp,
              CONST84 char *optionName, Tcl_DString *optionValue)
 {
     UdpState *statePtr = (UdpState *)instanceData;
-    CONST84 char * options = "myport remote peer mcastadd mcastdrop";
+    CONST84 char * options = 
+        "sockname remote peer broadcast reuseaddr";
     int r = TCL_OK;
 
     if (optionName == NULL) {
 
-        Tcl_DStringAppend(optionValue, " -myport ", -1);
-        udpGetOption(instanceData, interp, "-myport", optionValue);
+        Tcl_DStringAppend(optionValue, " -sockname ", -1);
+        udpGetOption(instanceData, interp, "-sockname", 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);
         Tcl_DStringAppend(optionValue, " -broadcast ", -1);
         udpGetOption(instanceData, interp, "-broadcast", optionValue);
+        Tcl_DStringAppend(optionValue, " -reuseaddr ", -1);
+        udpGetOption(instanceData, interp, "-reuseaddr", optionValue);
 
     } else {
 
@@ -1149,38 +1231,44 @@ udpGetOption(ClientData instanceData, Tcl_Interp *interp,
         Tcl_DStringInit(&ds);
         Tcl_DStringInit(&dsInt);
 
-        if (!strcmp("-myport", optionName)) {
+        if (!strcmp("-sockname", optionName)) {
 
-            Tcl_DStringSetLength(&ds, TCL_INTEGER_SPACE);
-            sprintf(Tcl_DStringValue(&ds), "%u", ntohs(statePtr->localport));
+            Tcl_Obj *nameObj;
+            UdpGetObjFromAddress(interp, (struct sockaddr *)&statePtr->saddr_local, &nameObj);
+            Tcl_DStringAppend(&ds, Tcl_GetString(nameObj), -1);
 
         } 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));
+            Tcl_Obj *nameObj;
+            UdpGetObjFromAddress(interp, (struct sockaddr *)&statePtr->saddr_remote, &nameObj);
+            Tcl_DStringAppend(&ds, Tcl_GetString(nameObj), -1);
 
         } 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));
+            Tcl_Obj *nameObj;
+            UdpGetObjFromAddress(interp, (struct sockaddr *)&statePtr->saddr_peer, &nameObj);
+            Tcl_DStringAppend(&ds, Tcl_GetString(nameObj), -1);
 
-        } else if (!strcmp("-mcastadd", optionName)) {
-            ;
-        } else if (!strcmp("-mcastdrop", optionName)) {
-            ;
         } else if (!strcmp("-broadcast", optionName)) {
 
             int tmp = 1;
             socklen_t optlen = sizeof(int);
             if (getsockopt(statePtr->sock, SOL_SOCKET, SO_BROADCAST, 
                            (char *)&tmp, &optlen)) {
-                UDPTRACE("UDP error - setsockopt\n");
-                Tcl_SetResult(interp, "error in setsockopt", TCL_STATIC);
+                Tcl_SetResult(interp, "error in setsockopt SO_BROADCAST", TCL_STATIC);
+                r = TCL_ERROR;
+            } else {
+                Tcl_DStringSetLength(&ds, TCL_INTEGER_SPACE);
+                sprintf(Tcl_DStringValue(&ds), "%d", tmp);
+            }
+
+        } else if (!strcmp("-reuseaddr", optionName)) {
+
+            int tmp = 1;
+            socklen_t optlen = sizeof(int);
+            if (getsockopt(statePtr->sock, SOL_SOCKET, SO_REUSEADDR, 
+                           (char *)&tmp, &optlen)) {
+                Tcl_SetResult(interp, "error in setsockopt SO_REUSEADDR", TCL_STATIC);
                 r = TCL_ERROR;
             } else {
                 Tcl_DStringSetLength(&ds, TCL_INTEGER_SPACE);
@@ -1214,43 +1302,47 @@ udpSetOption(ClientData instanceData, Tcl_Interp *interp,
              CONST84 char *optionName, CONST84 char *newValue)
 {
     UdpState *statePtr = (UdpState *)instanceData;
-    CONST84 char * options = "remote mcastadd mcastdrop broadcast";
+    CONST84 char * options = "sockname remote mcastadd mcastdrop broadcast reuseaddr";
     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));
-                }
-            }
-        }
+    if (!strcmp("-sockname", optionName)) {
+       
+       struct sockaddr_in addr;
+       memset(&addr, 0, sizeof(struct sockaddr_in));
+
+       r = UdpGetAddressFromObj(interp, Tcl_NewStringObj(newValue, -1),
+           (struct sockaddr *)&addr);
+       if (r == TCL_OK) {
+           int e = bind(statePtr->sock, (struct sockaddr *)&addr,
+               sizeof(struct sockaddr_in));
+           if (e < 0) {
+               Tcl_SetErrno(e);
+                Tcl_SetResult(interp, "bind error", TCL_STATIC);
+               r = TCL_ERROR;
+           } else {
+               int len = sizeof(statePtr->saddr_local);
+                getsockname(statePtr->sock, (struct sockaddr *)&statePtr->saddr_local, &len);
+           }
+       }
+
+    } else if (!strcmp("-remote", optionName)) {
+
+       struct sockaddr_in addr;
+       memset(&addr, 0, sizeof(struct sockaddr_in));
+
+       r = UdpGetAddressFromObj(interp, Tcl_NewStringObj(newValue, -1),
+           (struct sockaddr *)&addr);
+       if (r == TCL_OK) {
+           memcpy(&statePtr->saddr_remote, &addr, sizeof(addr));
+       }
 
     } else if (!strcmp("-mcastadd", optionName)) {
 
-        Tcl_SetResult(interp, "E_NOTIMPL", TCL_STATIC);
-        r = TCL_ERROR;
+        r = UdpMulticast(interp, statePtr->sock, newValue, IP_ADD_MEMBERSHIP);
 
     } else if (!strcmp("-mcastdrop", optionName)) {
 
-        Tcl_SetResult(interp, "E_NOTIMPL", TCL_STATIC);
-        r = TCL_ERROR;
+        r = UdpMulticast(interp, statePtr->sock, newValue, IP_DROP_MEMBERSHIP);
 
     } else if (!strcmp("-broadcast", optionName)) {
 
@@ -1259,9 +1351,28 @@ udpSetOption(ClientData instanceData, Tcl_Interp *interp,
         if (r == TCL_OK) {
             if (setsockopt(statePtr->sock, SOL_SOCKET, SO_BROADCAST, 
                            (const char *)&tmp, sizeof(int))) {
-                sprintf(errBuf, "%s", "udp - setsockopt");
                 UDPTRACE("UDP error - setsockopt\n");
-                Tcl_SetObjResult(interp, Tcl_NewStringObj(errBuf, -1));
+                Tcl_SetResult(interp, "udp - setsockopt SO_BROADCAST", TCL_STATIC);
+                r = TCL_ERROR;
+            } else {
+                Tcl_SetObjResult(interp, Tcl_NewIntObj(tmp));
+            }
+        }
+
+    } else if (!strcmp("-reuseaddr", optionName)) {
+        /*
+         * FIX ME: this doesn't work here.
+         * what we want is a udp command and to be able to specify this to that
+         * command. This will only work if re-attaching a client socket.
+         * (if we can do that)
+         */
+        int tmp = 1;
+        r = Tcl_GetInt(interp, newValue, &tmp);
+        if (r == TCL_OK) {
+            if (setsockopt(statePtr->sock, SOL_SOCKET, SO_REUSEADDR, 
+                           (const char *)&tmp, sizeof(int))) {
+                UDPTRACE("UDP error - setsockopt\n");
+                Tcl_SetResult(interp, "udp - setsockopt SO_REUSEADDR", TCL_STATIC);
                 r = TCL_ERROR;
             } else {
                 Tcl_SetObjResult(interp, Tcl_NewIntObj(tmp));
@@ -1279,11 +1390,11 @@ udpSetOption(ClientData instanceData, Tcl_Interp *interp,
 
 /*
  * ----------------------------------------------------------------------
- * udpTrace --
+ * UdpTrace --
  * ----------------------------------------------------------------------
  */
 static void
-udpTrace(const char *format, ...)
+UdpTrace(const char *format, ...)
 {
     va_list args;
     
index fdcf8998c7c4e295814b628a146fe6242253ede3..0eec82e005f0bbb0fb923cb1d0bff0a5d154cf78 100644 (file)
@@ -5,7 +5,9 @@
  * Copyright 1999-2000 by Columbia University; all rights reserved
  *
  * Written by Xiaotao Wu
- * Last modified: 11/03/2000
+ * Modifications by Pat Thoyts
+ *
+ * $Id$
  *----------------------------------------------------------------------
  */
 
@@ -25,7 +27,8 @@
 #endif
 
 #ifdef WIN32
-#  include <winsock.h>
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
 #else
 #  if HAVE_UNISTD_H
 #    include <unistd.h>
 #define TCL_STORAGE_CLASS DLLEXPORT
 #endif /* BUILD_udp */
 
+typedef union {
+    short  ss_family;
+    /*struct sockaddr_storage stg;*/
+    struct sockaddr_in      ipv4;
+    struct sockaddr_in6     ipv6;
+} sockaddr_t;
+
 #ifdef WIN32
 
 typedef u_short uint16_t;
 
 typedef struct {
-  Tcl_Event         header;     /* Information that is standard for */
-  Tcl_Channel       chan;       /* Socket descriptor that is ready  */
+    Tcl_Event         header;  /* Information that is standard for */
+    Tcl_Channel       chan;    /* Socket descriptor that is ready  */
 } UdpEvent;
 
 typedef struct PacketList {
-  char              *message;
-  int               actual_size;
-  char              r_host[256];
-  int               r_port;
-  struct PacketList *next;
+    char              *message;
+    int               actual_size;
+    sockaddr_t        peer;
+    struct PacketList *next;
 } PacketList;
 
 #endif /* WIN32 */
 
 typedef struct UdpState {
-  Tcl_Channel       channel;
-  int               sock;
-  char              remotehost[256]; /* send packets to */
-  uint16_t          remoteport;
-  char              peerhost[256];   /* receive packets from */
-  uint16_t          peerport;
-  uint16_t          localport;
-  int               doread;
+    Tcl_Channel       channel;
+    int               sock;
+    int               doread;
+    sockaddr_t        saddr_local;
+    sockaddr_t        saddr_remote;
+    sockaddr_t        saddr_peer;
 #ifdef WIN32
-  HWND              hwnd;
-  PacketList        *packets;
-  PacketList        *packetsTail;
-  int               packetNum;
-  struct UdpState   *next;
-  Tcl_ThreadId      threadId;        /* for Tcl_ThreadAlert */
+    HWND              hwnd;
+    PacketList        *packets;
+    PacketList        *packetsTail;
+    int               packetNum;
+    struct UdpState   *next;
+    Tcl_ThreadId      threadId;        /* for Tcl_ThreadAlert */
 #endif
 } UdpState;
 
index 14318b42acecfc40ad4e96a2e835d552e8368233..6d18876710f5869407d2e4c8aae4e1524c7e8828 100644 (file)
@@ -19,6 +19,7 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
 package require udp
 
 # -------------------------------------------------------------------------
+# Original tcludp < 1.0.4 user interface
 
 test udp-1.0 {udp_open with any port} {
     global _udp
index e909bd9888c33973e32f298c6d4972d274a6fdb8..65eb0ae6b300c1ea85ca61d82c3adff89ae1ad5c 100644 (file)
@@ -156,7 +156,7 @@ Please `cd` to its location first.
 PROJECT = udp
 !include "rules.vc"
 
-DOTVERSION      = 1.0.6
+DOTVERSION      = 2.0.0
 VERSION         = $(DOTVERSION:.=)
 STUBPREFIX      = $(PROJECT)stub
 
@@ -278,7 +278,7 @@ lflags      = $(lflags) -ws:aggressive
 dlllflags = $(lflags) -dll
 conlflags = $(lflags) -subsystem:console
 guilflags = $(lflags) -subsystem:windows
-baselibs   = $(TCLSTUBLIB) wsock32.lib
+baselibs   = $(TCLSTUBLIB) ws2_32.lib #wsock32.lib
 
 #---------------------------------------------------------------------
 # TclTest flags
index 1d7ae3be1a2335e8eff752032672f61d30eb5d89..1d3f328d877a78ba26747019989f2cfe5cc22840 100644 (file)
@@ -105,5 +105,17 @@ SOURCE=..\generic\udp_tcl.h
 SOURCE=.\tcludp.rc
 # End Source File
 # End Group
+# Begin Source File
+
+SOURCE=.\bcastdemo.tcl
+# End Source File
+# Begin Source File
+
+SOURCE=.\demo.tcl
+# End Source File
+# Begin Source File
+
+SOURCE=..\generic\udp.tcl
+# End Source File
 # End Target
 # End Project
index fb16bf5b2c0cfb2740f5afc7abdfdb0ac838aff1..821a500410d9918016a29d28d97d697f408b8b1c 100644 (file)
@@ -8,8 +8,8 @@
 LANGUAGE 0x9, 0x1      /* LANG_ENGLISH, SUBLANG_DEFAULT */
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION    1,0,6,0
- PRODUCTVERSION 1,0,6,0
+ FILEVERSION    2,0,0,0
+ PRODUCTVERSION 2,0,0,0
  FILEFLAGSMASK         0x3fL
 #ifdef DEBUG
  FILEFLAGS     VS_FF_DEBUG
@@ -25,11 +25,11 @@ BEGIN
         BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
         BEGIN
             VALUE "FileDescription", "Tcl UDP extension\0"
-            VALUE "OriginalFilename", "udp106.dll\0"
-            VALUE "FileVersion", "1.0.6.0\0"
+            VALUE "OriginalFilename", "udp200.dll\0"
+            VALUE "FileVersion", "2.0.0.0\0"
             VALUE "LegalCopyright", "Copyright \251 1999-2000 Columbia University; all rights reserved\0"
             VALUE "ProductName", "TclUDP\0"
-            VALUE "ProductVersion", "1.0.6.0\0"
+            VALUE "ProductVersion", "2.0.0.0\0"
         END                
     END
     BLOCK "VarFileInfo"