diff tango/tango/net/Socket.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tango/tango/net/Socket.d	Fri Jan 11 17:57:40 2008 +0100
@@ -0,0 +1,2160 @@
+/*
+        Copyright (C) 2004 Christopher E. Miller
+
+        This software is provided 'as-is', without any express or implied
+        warranty.  In no event will the authors be held liable for any damages
+        arising from the use of this software.
+
+        Permission is granted to anyone to use this software for any purpose,
+        including commercial applications, and to alter it and redistribute it
+        freely, subject to the following restrictions:
+
+        1. The origin of this software must not be misrepresented; you must not
+           claim that you wrote the original software. If you use this software
+           in a product, an acknowledgment in the product documentation would be
+           appreciated but is not required.
+
+        2. Altered source versions must be plainly marked as such, and must not be
+           misrepresented as being the original software.
+
+        3. This notice may not be removed or altered from any source distribution.
+
+*/
+
+/*******************************************************************************
+
+        copyright:      Copyright (c) 2004 Kris Bell. All rights reserved
+
+        license:        BSD style: $(LICENSE)
+
+        version:        Initial release: March 2004
+
+        author:         Christopher Miller
+                        Kris Bell
+                        Anders F Bjorklund (Darwin patches)
+
+
+        The original code has been modified in several ways:
+
+        1) It has been altered to fit within the Tango environment, meaning
+           that certain original classes have been reorganized, and/or have
+           subclassed Tango base-classes. For example, the original Socket
+           class has been wrapped with three distinct subclasses, and now
+           derives from class tango.io.Resource.
+
+        2) All exception instances now subclass the Tango IOException.
+
+        3) Construction of new Socket instances via accept() is now
+           overloadable.
+
+        4) Constants and enums have been moved within a class boundary to
+           ensure explicit namespace usage.
+
+        5) changed Socket.select() to loop if it was interrupted.
+
+
+        All changes within the main body of code all marked with "Tango:"
+
+        For a good tutorial on socket-programming I highly recommend going
+        here: http://www.ecst.csuchico.edu/~beej/guide/net/
+
+*******************************************************************************/
+
+module tango.net.Socket;
+
+private import  tango.time.Time;
+
+private import  tango.sys.Common;
+
+private import  tango.core.Exception;
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+version=Tango;
+version (Tango)
+{
+        private char[] toString (char[] tmp, int i)
+        {
+                int j = tmp.length;
+                do {
+                   tmp[--j] = i % 10 + '0';
+                   } while (i /= 10);
+
+                return tmp [j .. $];
+        }
+}
+
+version (linux)
+         version = BsdSockets;
+
+version (darwin)
+         version = BsdSockets;
+
+version (Posix)
+         version = BsdSockets;
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+version (Win32)
+        {
+        pragma(lib, "ws2_32.lib");
+
+        private typedef int socket_t = ~0;
+
+        private const int IOCPARM_MASK =  0x7f;
+        private const int IOC_IN =        cast(int)0x80000000;
+        private const int FIONBIO =       cast(int) (IOC_IN | ((int.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126);
+
+        private const int WSADESCRIPTION_LEN = 256;
+        private const int WSASYS_STATUS_LEN = 128;
+        private const int WSAEWOULDBLOCK =  10035;
+        private const int WSAEINTR =        10004;
+
+
+        struct WSADATA
+        {
+                        WORD wVersion;
+                        WORD wHighVersion;
+                        char szDescription[WSADESCRIPTION_LEN+1];
+                        char szSystemStatus[WSASYS_STATUS_LEN+1];
+                        ushort iMaxSockets;
+                        ushort iMaxUdpDg;
+                        char* lpVendorInfo;
+        }
+        alias WSADATA* LPWSADATA;
+
+        extern  (Windows)
+                {
+                int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
+                int WSACleanup();
+                socket_t socket(int af, int type, int protocol);
+                int ioctlsocket(socket_t s, int cmd, uint* argp);
+                uint inet_addr(char* cp);
+                int bind(socket_t s, sockaddr* name, int namelen);
+                int connect(socket_t s, sockaddr* name, int namelen);
+                int listen(socket_t s, int backlog);
+                socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
+                int closesocket(socket_t s);
+                int shutdown(socket_t s, int how);
+                int getpeername(socket_t s, sockaddr* name, int* namelen);
+                int getsockname(socket_t s, sockaddr* name, int* namelen);
+                int send(socket_t s, void* buf, int len, int flags);
+                int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
+                int recv(socket_t s, void* buf, int len, int flags);
+                int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
+                int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
+                //int __WSAFDIsSet(socket_t s, fd_set* fds);
+                int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
+                int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
+                int gethostname(void* namebuffer, int buflen);
+                char* inet_ntoa(uint ina);
+                hostent* gethostbyname(char* name);
+                hostent* gethostbyaddr(void* addr, int len, int type);
+                int WSAGetLastError();
+                }
+
+        static this()
+        {
+                WSADATA wd;
+                if (WSAStartup (0x0101, &wd))
+                    throw new SocketException("Unable to initialize socket library");
+        }
+
+
+        static ~this()
+        {
+                WSACleanup();
+        }
+
+        }
+
+version (BsdSockets)
+        {
+        private import tango.stdc.errno;
+
+        private typedef int socket_t = -1;
+
+        private const int F_GETFL       = 3;
+        private const int F_SETFL       = 4;
+        version (darwin)
+                 private const int O_NONBLOCK = 0x0004;
+           else
+                 private const int O_NONBLOCK = 04000;  // OCTAL! Thx to volcore
+
+        extern  (C)
+                {
+                socket_t socket(int af, int type, int protocol);
+                int fcntl(socket_t s, int f, ...);
+                uint inet_addr(char* cp);
+                int bind(socket_t s, sockaddr* name, int namelen);
+                int connect(socket_t s, sockaddr* name, int namelen);
+                int listen(socket_t s, int backlog);
+                socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
+                int close(socket_t s);
+                int shutdown(socket_t s, int how);
+                int getpeername(socket_t s, sockaddr* name, int* namelen);
+                int getsockname(socket_t s, sockaddr* name, int* namelen);
+                int send(socket_t s, void* buf, int len, int flags);
+                int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
+                int recv(socket_t s, void* buf, int len, int flags);
+                int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
+                int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
+                int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
+                int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
+                int gethostname(void* namebuffer, int buflen);
+                char* inet_ntoa(uint ina);
+                hostent* gethostbyname(char* name);
+                hostent* gethostbyaddr(void* addr, int len, int type);
+                }
+        }
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+private const socket_t INVALID_SOCKET = socket_t.init;
+private const int SOCKET_ERROR = -1;
+
+
+
+/*******************************************************************************
+
+        Internal structs:
+
+*******************************************************************************/
+
+struct timeval
+{
+        int tv_sec; //seconds
+        int tv_usec; //microseconds
+}
+
+
+//transparent
+struct fd_set
+{
+}
+
+
+struct sockaddr
+{
+        ushort sa_family;
+        char[14] sa_data = [0];
+}
+
+
+struct hostent
+{
+        char* h_name;
+        char** h_aliases;
+        version(Win32)
+        {
+                short h_addrtype;
+                short h_length;
+        }
+        else version(BsdSockets)
+        {
+                int h_addrtype;
+                int h_length;
+        }
+        char** h_addr_list;
+
+
+        char* h_addr()
+        {
+                return h_addr_list[0];
+        }
+}
+
+
+/*******************************************************************************
+
+        conversions for network byte-order
+
+*******************************************************************************/
+
+version(BigEndian)
+{
+        ushort htons(ushort x)
+        {
+                return x;
+        }
+
+
+        uint htonl(uint x)
+        {
+                return x;
+        }
+}
+else version(LittleEndian)
+{
+        import tango.core.BitManip;
+
+
+        ushort htons(ushort x)
+        {
+                return cast(ushort) ((x >> 8) | (x << 8));
+        }
+
+
+        uint htonl(uint x)
+        {
+                return bswap(x);
+        }
+}
+else
+{
+        static assert(0);
+}
+
+
+ushort ntohs(ushort x)
+{
+        return htons(x);
+}
+
+
+uint ntohl(uint x)
+{
+        return htonl(x);
+}
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+private extern (C) int strlen(char*);
+
+private static char[] toString(char* s)
+{
+        return s ? s[0 .. strlen(s)] : cast(char[])null;
+}
+
+private static char* convert2C (char[] input, char[] output)
+{
+        output [0 .. input.length] = input;
+        output [input.length] = 0;
+        return output.ptr;
+}
+
+
+/*******************************************************************************
+
+        Public interface ...
+
+*******************************************************************************/
+
+public:
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+static int lastError ()
+{
+        version (Win32)
+                {
+                return WSAGetLastError();
+                }
+        version (Posix)
+                {
+                return errno;
+                }
+}
+
+
+/***********************************************************************
+
+
+***********************************************************************/
+
+version (Win32)
+{
+        /***************************************************************
+
+
+        ***************************************************************/
+
+        enum SocketOption: int
+        {
+                //consistent
+                SO_DEBUG =         0x1,
+
+                //possibly Winsock-only values
+                SO_BROADCAST =  0x20,
+                SO_REUSEADDR =  0x4,
+                SO_LINGER =     0x80,
+                SO_DONTLINGER = ~(SO_LINGER),
+                SO_OOBINLINE =  0x100,
+                SO_SNDBUF =     0x1001,
+                SO_RCVBUF =     0x1002,
+                SO_ERROR =      0x1007,
+
+                SO_ACCEPTCONN =    0x2, // ?
+                SO_KEEPALIVE =     0x8, // ?
+                SO_DONTROUTE =     0x10, // ?
+                SO_TYPE =          0x1008, // ?
+
+                // OptionLevel.IP settings
+                IP_MULTICAST_TTL = 10,
+                IP_MULTICAST_LOOP = 11,
+                IP_ADD_MEMBERSHIP = 12,
+                IP_DROP_MEMBERSHIP = 13,
+
+                // OptionLevel.TCP settings
+                TCP_NODELAY = 0x0001,
+        }
+
+        /***************************************************************
+
+
+        ***************************************************************/
+
+        union linger
+        {
+                struct {
+                       ushort l_onoff;          // option on/off
+                       ushort l_linger;         // linger time
+                       };
+                ushort[2]       array;          // combined
+        }
+
+        /***************************************************************
+
+
+        ***************************************************************/
+
+        enum SocketOptionLevel
+        {
+                SOCKET =  0xFFFF,
+                IP =      0,
+                TCP =     6,
+                UDP =     17,
+        }
+}
+else version (darwin)
+{
+        enum SocketOption: int
+        {
+                SO_DEBUG        = 0x0001,		/* turn on debugging info recording */
+                SO_BROADCAST    = 0x0020,		/* permit sending of broadcast msgs */
+                SO_REUSEADDR    = 0x0004,		/* allow local address reuse */
+                SO_LINGER       = 0x0080,		/* linger on close if data present */
+                SO_DONTLINGER   = ~(SO_LINGER),
+                SO_OOBINLINE    = 0x0100,		/* leave received OOB data in line */
+                SO_ACCEPTCONN   = 0x0002,		/* socket has had listen() */
+                SO_KEEPALIVE    = 0x0008,		/* keep connections alive */
+                SO_DONTROUTE    = 0x0010,		/* just use interface addresses */
+                SO_TYPE         = 0x1008,               /* get socket type */
+
+                /*
+                 * Additional options, not kept in so_options.
+                 */
+                SO_SNDBUF       = 0x1001,		/* send buffer size */
+                SO_RCVBUF       = 0x1002,		/* receive buffer size */
+                SO_ERROR        = 0x1007,		/* get error status and clear */
+
+                // OptionLevel.IP settings
+                IP_MULTICAST_TTL = 10,
+                IP_MULTICAST_LOOP = 11,
+                IP_ADD_MEMBERSHIP = 12,
+                IP_DROP_MEMBERSHIP = 13,
+
+                // OptionLevel.TCP settings
+                TCP_NODELAY = 0x0001,
+        }
+
+        /***************************************************************
+
+
+        ***************************************************************/
+
+        union linger
+        {
+                struct {
+                       int l_onoff;             // option on/off
+                       int l_linger;            // linger time
+                       };
+                int[2]          array;          // combined
+        }
+
+        /***************************************************************
+
+                Question: are these correct for Darwin?
+
+        ***************************************************************/
+
+        enum SocketOptionLevel
+        {
+                SOCKET =  1,  // correct for linux on x86
+                IP =      0,  // appears to be correct
+                TCP =     6,  // appears to be correct
+                UDP =     17, // appears to be correct
+        }
+}
+else version (linux)
+{
+        /***************************************************************
+
+                these appear to be compatible with x86 platforms,
+                but not others!
+
+        ***************************************************************/
+
+        enum SocketOption: int
+        {
+                //consistent
+                SO_DEBUG        = 1,
+                SO_BROADCAST    = 6,
+                SO_REUSEADDR    = 2,
+                SO_LINGER       = 13,
+                SO_DONTLINGER   = ~(SO_LINGER),
+                SO_OOBINLINE    = 10,
+                SO_SNDBUF       = 7,
+                SO_RCVBUF       = 8,
+                SO_ERROR        = 4,
+
+                SO_ACCEPTCONN   = 30,
+                SO_KEEPALIVE    = 9,
+                SO_DONTROUTE    = 5,
+                SO_TYPE         = 3,
+
+                // OptionLevel.IP settings
+                IP_MULTICAST_TTL = 33,
+                IP_MULTICAST_LOOP = 34,
+                IP_ADD_MEMBERSHIP = 35,
+                IP_DROP_MEMBERSHIP = 36,
+
+                // OptionLevel.TCP settings
+                TCP_NODELAY = 0x0001,
+        }
+
+        /***************************************************************
+
+
+        ***************************************************************/
+
+        union linger
+        {
+                struct {
+                       int l_onoff;             // option on/off
+                       int l_linger;            // linger time
+                       };
+                int[2]          array;          // combined
+        }
+
+        /***************************************************************
+
+
+        ***************************************************************/
+
+        enum SocketOptionLevel
+        {
+                SOCKET =  1,  // correct for linux on x86
+                IP =      0,  // appears to be correct
+                TCP =     6,  // appears to be correct
+                UDP =     17, // appears to be correct
+        }
+} // end versioning
+
+/***********************************************************************
+
+
+***********************************************************************/
+
+enum SocketShutdown: int
+{
+        RECEIVE =  0,
+        SEND =     1,
+        BOTH =     2,
+}
+
+/***********************************************************************
+
+
+***********************************************************************/
+
+enum SocketFlags: int
+{
+        NONE =           0,
+        OOB =            0x1, //out of band
+        PEEK =           0x02, //only for receiving
+        DONTROUTE =      0x04, //only for sending
+}
+
+/***********************************************************************
+
+         Communication semantics
+
+***********************************************************************/
+
+enum SocketType: int
+{
+        STREAM =     1,       /// sequenced, reliable, two-way communication-based byte streams
+        DGRAM =      2,        /// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
+        RAW =        3,          /// raw protocol access
+        RDM =        4,          /// reliably-delivered message datagrams
+        SEQPACKET =  5,    /// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
+}
+
+
+/***********************************************************************
+
+        Protocol
+
+***********************************************************************/
+
+enum ProtocolType: int
+{
+        IP =    0,     /// internet protocol version 4
+        ICMP =  1,   /// internet control message protocol
+        IGMP =  2,   /// internet group management protocol
+        GGP =   3,    /// gateway to gateway protocol
+        TCP =   6,    /// transmission control protocol
+        PUP =   12,    /// PARC universal packet protocol
+        UDP =   17,    /// user datagram protocol
+        IDP =   22,    /// Xerox NS protocol
+}
+
+
+/***********************************************************************
+
+
+***********************************************************************/
+
+version(Win32)
+{
+        enum AddressFamily: int
+        {
+                UNSPEC =     0,
+                UNIX =       1,
+                INET =       2,
+                IPX =        6,
+                APPLETALK =  16,
+                //INET6 =      ? // Need Windows XP ?
+        }
+}
+else version(BsdSockets)
+{
+        version (darwin)
+        {
+                enum AddressFamily: int
+                {
+                        UNSPEC =     0,
+                        UNIX =       1,
+                        INET =       2,
+                        IPX =        23,
+                        APPLETALK =  16,
+                        //INET6 =      10,
+                }
+        }
+        else version (linux)
+        {
+                enum AddressFamily: int
+                {
+                        UNSPEC =     0,
+                        UNIX =       1,
+                        INET =       2,
+                        IPX =        4,
+                        APPLETALK =  5,
+                        //INET6 =      10,
+                }
+        } // end version
+}
+
+
+
+/*******************************************************************************
+
+*******************************************************************************/
+
+class Socket
+{
+        socket_t        sock;
+        SocketType      type;
+        AddressFamily   family;
+        ProtocolType    protocol;
+
+        version(Win32)
+                private bool _blocking = false;
+
+        // For use with accept().
+        package this()
+        {
+        }
+
+
+        /**
+         * Describe a socket flavor. If a single protocol type exists to support
+         * this socket type within the address family, the ProtocolType may be
+         * omitted.
+         */
+        this(AddressFamily family, SocketType type, ProtocolType protocol, bool create=true)
+        {
+                this.type = type;
+                this.family = family;
+                this.protocol = protocol;
+                if (create)
+                    initialize ();
+        }
+
+
+        /**
+         * Create or assign a socket
+         */
+        private void initialize (socket_t sock = sock.init)
+        {
+                if (this.sock)
+                    this.detach;
+
+                if (sock is sock.init)
+                   {
+                   sock = cast(socket_t) socket(family, type, protocol);
+                   if (sock is sock.init)
+                       exception ("Unable to create socket: ");
+                   }
+
+                this.sock = sock;
+        }
+
+        /***********************************************************************
+
+                Return the underlying OS handle of this Conduit
+
+        ***********************************************************************/
+
+        socket_t fileHandle ()
+        {
+                return sock;
+        }
+
+        /***********************************************************************
+
+                Is this socket still alive? A closed socket is considered to
+                be dead, but a shutdown socket is still alive.
+
+        ***********************************************************************/
+
+        bool isAlive()
+        {
+                int type, typesize = type.sizeof;
+                return getsockopt (sock, SocketOptionLevel.SOCKET,
+                                   SocketOption.SO_TYPE, cast(char*) &type,
+                                   &typesize) != SOCKET_ERROR;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        override char[] toString()
+        {
+                return "Socket";
+        }
+
+
+        /***********************************************************************
+
+                getter
+
+        ***********************************************************************/
+
+        bool blocking()
+        {
+                version(Win32)
+                {
+                        return _blocking;
+                }
+                else version(BsdSockets)
+                {
+                        return !(fcntl(sock, F_GETFL, 0) & O_NONBLOCK);
+                }
+        }
+
+
+        /***********************************************************************
+
+                setter
+
+        ***********************************************************************/
+
+        void blocking(bool byes)
+        {
+                version(Win32)
+                {
+                        uint num = !byes;
+                        if(SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
+                                goto err;
+                        _blocking = byes;
+                }
+                else version(BsdSockets)
+                {
+                        int x = fcntl(sock, F_GETFL, 0);
+                        if(byes)
+                                x &= ~O_NONBLOCK;
+                        else
+                                x |= O_NONBLOCK;
+                        if(SOCKET_ERROR == fcntl(sock, F_SETFL, x))
+                                goto err;
+                }
+                return; //success
+
+                err:
+                exception("Unable to set socket blocking: ");
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        AddressFamily addressFamily()
+        {
+                return family;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        Socket bind(Address addr)
+        {
+                if(SOCKET_ERROR == .bind (sock, addr.name(), addr.nameLen()))
+                   exception ("Unable to bind socket: ");
+                return this;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        Socket connect(Address to)
+        {
+                if(SOCKET_ERROR == .connect (sock, to.name(), to.nameLen()))
+                {
+                        if(!blocking)
+                        {
+                                version(Win32)
+                                {
+                                        if(WSAEWOULDBLOCK == WSAGetLastError())
+                                                return this;
+                                }
+                                else version (Posix)
+                                {
+                                        if(EINPROGRESS == errno)
+                                                return this;
+                                }
+                                else
+                                {
+                                        static assert(0);
+                                }
+                        }
+                        exception ("Unable to connect socket: ");
+                }
+                return this;
+        }
+
+
+        /***********************************************************************
+
+                need to bind() first
+
+        ***********************************************************************/
+
+        Socket listen(int backlog)
+        {
+                if(SOCKET_ERROR == .listen (sock, backlog))
+                   exception ("Unable to listen on socket: ");
+                return this;
+        }
+
+        /**
+         * Accept an incoming connection. If the socket is blocking, accept
+         * waits for a connection request. Throws SocketAcceptException if unable
+         * to accept. See accepting for use with derived classes.
+         */
+        Socket accept ()
+        {
+                return accept (new Socket);
+        }
+
+        Socket accept (Socket target)
+        {
+                auto newsock = cast(socket_t).accept(sock, null, null); // DMD 0.101 error: found '(' when expecting ';' following 'statement
+                if (socket_t.init == newsock)
+                   throw new SocketAcceptException("Unable to accept socket connection: " ~ SysError.lookup(lastError));
+
+                target.initialize (newsock);
+                version(Win32)
+                        target._blocking = _blocking;  //inherits blocking mode
+
+                target.protocol = protocol;            //same protocol
+                target.family = family;                //same family
+                target.type = type;                    //same type
+
+                return target;                         //return configured target
+        }
+
+        /***********************************************************************
+
+                The shutdown function shuts down the connection of the socket.
+                Depending on the argument value, it will:
+
+                    -   stop receiving data for this socket. If further data
+                        arrives, it is rejected.
+
+                    -   stop trying to transmit data from this socket. Also
+                        discards any data waiting to be sent. Stop looking for
+                        acknowledgement of data already sent; don't retransmit
+                        if any data is lost.
+
+        ***********************************************************************/
+
+        Socket shutdown(SocketShutdown how)
+        {
+                .shutdown (sock, how);
+                return this;
+        }
+
+
+        /***********************************************************************
+
+                Tango: added
+
+        ***********************************************************************/
+
+        Socket setLingerPeriod (int period)
+        {
+                linger l;
+
+                l.l_onoff = 1;                          //option on/off
+                l.l_linger = cast(ushort) period;       //linger time
+
+                return setOption (SocketOptionLevel.SOCKET, SocketOption.SO_LINGER, l.array);
+        }
+
+
+        /***********************************************************************
+
+
+                Tango: added
+
+        ***********************************************************************/
+
+        Socket setAddressReuse (bool enabled)
+        {
+                int[1] x = enabled;
+                return setOption (SocketOptionLevel.SOCKET, SocketOption.SO_REUSEADDR, x);
+        }
+
+
+        /***********************************************************************
+
+
+                Tango: added
+
+        ***********************************************************************/
+
+        Socket setNoDelay (bool enabled)
+        {
+                int[1] x = enabled;
+                return setOption (SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, x);
+        }
+
+
+        /***********************************************************************
+
+                Helper function to handle the adding and dropping of group
+                membership.
+
+                Tango: Added
+
+        ***********************************************************************/
+
+        void joinGroup (IPv4Address address, bool onOff)
+        {
+                assert (address, "Socket.joinGroup :: invalid null address");
+
+                struct ip_mreq
+                {
+                uint  imr_multiaddr;  /* IP multicast address of group */
+                uint  imr_interface;  /* local IP address of interface */
+                };
+
+                ip_mreq mrq;
+
+                auto option = (onOff) ? SocketOption.IP_ADD_MEMBERSHIP : SocketOption.IP_DROP_MEMBERSHIP;
+                mrq.imr_interface = 0;
+                mrq.imr_multiaddr = address.sin.sin_addr;
+
+                if (.setsockopt(sock, SocketOptionLevel.IP, option, &mrq, mrq.sizeof) == SOCKET_ERROR)
+                    exception ("Unable to perform multicast join: ");
+        }
+
+
+        /***********************************************************************
+
+                calling shutdown() before this is recommended for connection-
+                oriented sockets
+
+        ***********************************************************************/
+
+        void detach ()
+        {
+                if (sock != sock.init)
+                   {
+                   version (TraceLinux)
+                            printf ("closing socket handle ...\n");
+
+                   version(Win32)
+                           .closesocket (sock);
+                   else
+                   version(BsdSockets)
+                           .close (sock);
+
+                   version (TraceLinux)
+                            printf ("socket handle closed\n");
+
+                   sock = sock.init;
+                   }
+        }
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        Address newFamilyObject ()
+        {
+                Address result;
+                switch(family)
+                {
+                        case AddressFamily.INET:
+                                result = new IPv4Address;
+                                break;
+
+                        default:
+                                result = new UnknownAddress;
+                }
+                return result;
+        }
+
+
+        /***********************************************************************
+
+                Tango: added this to return the hostname
+
+        ***********************************************************************/
+
+        static char[] hostName ()
+        {
+                char[64] name;
+
+                if(SOCKET_ERROR == .gethostname (name.ptr, name.length))
+                   exception ("Unable to obtain host name: ");
+                return name [0 .. strlen(name.ptr)].dup;
+        }
+
+
+        /***********************************************************************
+
+                Tango: added this to return the default host address (IPv4)
+
+        ***********************************************************************/
+
+        static uint hostAddress ()
+        {
+                NetHost ih = new NetHost;
+
+                char[] hostname = hostName();
+                ih.getHostByName (hostname);
+                assert (ih.addrList.length);
+                return ih.addrList[0];
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        Address remoteAddress ()
+        {
+                Address addr = newFamilyObject ();
+                int nameLen = addr.nameLen ();
+                if(SOCKET_ERROR == .getpeername (sock, addr.name(), &nameLen))
+                   exception ("Unable to obtain remote socket address: ");
+                assert (addr.addressFamily() == family);
+                return addr;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        Address localAddress ()
+        {
+                Address addr = newFamilyObject ();
+                int nameLen = addr.nameLen();
+                if(SOCKET_ERROR == .getsockname (sock, addr.name(), &nameLen))
+                   exception ("Unable to obtain local socket address: ");
+                assert (addr.addressFamily() == family);
+                return addr;
+        }
+
+        /// Send or receive error code.
+        const int ERROR = SOCKET_ERROR;
+
+
+        /**
+         * Send data on the connection. Returns the number of bytes actually
+         * sent, or ERROR on failure. If the socket is blocking and there is no
+         * buffer space left, send waits.
+         */
+        //returns number of bytes actually sent, or -1 on error
+        int send(void[] buf, SocketFlags flags=SocketFlags.NONE)
+        {
+                return .send(sock, buf.ptr, buf.length, cast(int)flags);
+        }
+
+        /**
+         * Send data to a specific destination Address. If the destination address is not specified, a connection must have been made and that address is used. If the socket is blocking and there is no buffer space left, sendTo waits.
+         */
+        int sendTo(void[] buf, SocketFlags flags, Address to)
+        {
+                return .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name(), to.nameLen());
+        }
+
+        /// ditto
+        int sendTo(void[] buf, Address to)
+        {
+                return sendTo(buf, SocketFlags.NONE, to);
+        }
+
+
+        //assumes you connect()ed
+        /// ditto
+        int sendTo(void[] buf, SocketFlags flags=SocketFlags.NONE)
+        {
+                return .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
+        }
+
+
+        /**
+         * Receive data on the connection. Returns the number of bytes actually
+         * received, 0 if the remote side has closed the connection, or ERROR on
+         * failure. If the socket is blocking, receive waits until there is data
+         * to be received.
+         */
+        //returns number of bytes actually received, 0 on connection closure, or -1 on error
+        int receive(void[] buf, SocketFlags flags=SocketFlags.NONE)
+        {
+                if (!buf.length)
+                     badArg ("Socket.receive :: target buffer has 0 length");
+
+                return .recv(sock, buf.ptr, buf.length, cast(int)flags);
+        }
+
+        /**
+         * Receive data and get the remote endpoint Address. Returns the number of bytes actually received, 0 if the remote side has closed the connection, or ERROR on failure. If the socket is blocking, receiveFrom waits until there is data to be received.
+         */
+        int receiveFrom(void[] buf, SocketFlags flags, Address from)
+        {
+                if (!buf.length)
+                     badArg ("Socket.receiveFrom :: target buffer has 0 length");
+
+                assert(from.addressFamily() == family);
+                int nameLen = from.nameLen();
+                return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
+        }
+
+
+        /// ditto
+        int receiveFrom(void[] buf, Address from)
+        {
+                return receiveFrom(buf, SocketFlags.NONE, from);
+        }
+
+
+        //assumes you connect()ed
+        /// ditto
+        int receiveFrom(void[] buf, SocketFlags flags = SocketFlags.NONE)
+        {
+                if (!buf.length)
+                     badArg ("Socket.receiveFrom :: target buffer has 0 length");
+
+                return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
+        }
+
+
+        /***********************************************************************
+
+                returns the length, in bytes, of the actual result - very
+                different from getsockopt()
+
+        ***********************************************************************/
+
+        int getOption (SocketOptionLevel level, SocketOption option, void[] result)
+        {
+                int len = result.length;
+                if(SOCKET_ERROR == .getsockopt (sock, cast(int)level, cast(int)option, result.ptr, &len))
+                   exception ("Unable to get socket option: ");
+                return len;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        Socket setOption (SocketOptionLevel level, SocketOption option, void[] value)
+        {
+                if(SOCKET_ERROR == .setsockopt (sock, cast(int)level, cast(int)option, value.ptr, value.length))
+                   exception ("Unable to set socket option: ");
+                return this;
+        }
+
+
+        /***********************************************************************
+
+                Tango: added this common function
+
+        ***********************************************************************/
+
+        protected static void exception (char[] msg)
+        {
+                throw new SocketException (msg ~ SysError.lookup(lastError));
+        }
+
+
+        /***********************************************************************
+
+                Tango: added this common function
+
+        ***********************************************************************/
+
+        protected static void badArg (char[] msg)
+        {
+                throw new IllegalArgumentException (msg);
+        }
+
+
+        /***********************************************************************
+
+                SocketSet's are updated to include only those sockets which an
+                event occured.
+
+                Returns the number of events, 0 on timeout, or -1 on error
+
+                for a connect()ing socket, writeability means connected
+                for a listen()ing socket, readability means listening
+
+                Winsock: possibly internally limited to 64 sockets per set
+
+        ***********************************************************************/
+
+        static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, timeval* tv)
+        in
+        {
+                //make sure none of the SocketSet's are the same object
+                if(checkRead)
+                {
+                        assert(checkRead !is checkWrite);
+                        assert(checkRead !is checkError);
+                }
+                if(checkWrite)
+                {
+                        assert(checkWrite !is checkError);
+                }
+        }
+        body
+        {
+                fd_set* fr, fw, fe;
+
+                version(Win32)
+                {
+                        //Windows has a problem with empty fd_set's that aren't null
+                        fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null;
+                        fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null;
+                        fe = (checkError && checkError.count()) ? checkError.toFd_set() : null;
+                }
+                else
+                {
+                        fr = checkRead ? checkRead.toFd_set() : null;
+                        fw = checkWrite ? checkWrite.toFd_set() : null;
+                        fe = checkError ? checkError.toFd_set() : null;
+                }
+
+                int result;
+
+                // Tango: if select() was interrupted, we now try again
+                version(Win32)
+                {
+                        while ((result = .select (socket_t.max - 1, fr, fw, fe, tv)) == -1)
+                        {
+                                if(WSAGetLastError() != WSAEINTR)
+                                   break;
+                        }
+                }
+                else version (Posix)
+                {
+                        socket_t maxfd = 0;
+
+                        if (checkRead)
+                                maxfd = checkRead.maxfd;
+
+                        if (checkWrite && checkWrite.maxfd > maxfd)
+                                maxfd = checkWrite.maxfd;
+
+                        if (checkError && checkError.maxfd > maxfd)
+                                maxfd = checkError.maxfd;
+
+                        while ((result = .select (maxfd + 1, fr, fw, fe, tv)) == -1)
+                        {
+                                if(errno() != EINTR)
+                                   break;
+                        }
+                }
+                else
+                {
+                        static assert(0);
+                }
+                // Tango: don't throw an exception here ... wait until we get
+                // a bit further back along the control path
+                //if(SOCKET_ERROR == result)
+                //   throw new SocketException("Socket select error.");
+
+                return result;
+        }
+
+        /***********************************************************************
+
+                select with specified timeout
+
+        ***********************************************************************/
+
+        static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeSpan time)
+        {
+                auto tv = toTimeval (time);
+                return select (checkRead, checkWrite, checkError, &tv);
+        }
+
+        /***********************************************************************
+
+                select with maximum timeout
+
+        ***********************************************************************/
+
+        static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
+        {
+                return select (checkRead, checkWrite, checkError, null);
+        }
+
+        /***********************************************************************
+
+                Handy utility for converting TimeSpan into timeval
+
+        ***********************************************************************/
+
+        static timeval toTimeval (TimeSpan time)
+        {
+                timeval tv;
+                tv.tv_sec = cast(uint) time.seconds;
+                tv.tv_usec = cast(uint) time.micros % 1_000_000;
+                return tv;
+        }
+}
+
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+abstract class Address
+{
+        protected sockaddr* name();
+        protected int nameLen();
+        AddressFamily addressFamily();
+        char[] toString();
+
+        /***********************************************************************
+
+                Tango: added this common function
+
+        ***********************************************************************/
+
+        static void exception (char[] msg)
+        {
+                throw new AddressException (msg);
+        }
+
+}
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+class UnknownAddress: Address
+{
+        protected:
+        sockaddr sa;
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        sockaddr* name()
+        {
+                return &sa;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        int nameLen()
+        {
+                return sa.sizeof;
+        }
+
+
+        public:
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        AddressFamily addressFamily()
+        {
+                return cast(AddressFamily) sa.sa_family;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        char[] toString()
+        {
+                return "Unknown";
+        }
+}
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+class NetHost
+{
+        char[] name;
+        char[][] aliases;
+        uint[] addrList;
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        protected void validHostent(hostent* he)
+        {
+                if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4)
+                        throw new HostException("Address family mismatch.");
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        void populate(hostent* he)
+        {
+                int i;
+                char* p;
+
+                name = .toString(he.h_name);
+
+                for(i = 0;; i++)
+                {
+                        p = he.h_aliases[i];
+                        if(!p)
+                                break;
+                }
+
+                if(i)
+                {
+                        aliases = new char[][i];
+                        for(i = 0; i != aliases.length; i++)
+                        {
+                                aliases[i] = .toString(he.h_aliases[i]);
+                        }
+                }
+                else
+                {
+                        aliases = null;
+                }
+
+                for(i = 0;; i++)
+                {
+                        p = he.h_addr_list[i];
+                        if(!p)
+                                break;
+                }
+
+                if(i)
+                {
+                        addrList = new uint[i];
+                        for(i = 0; i != addrList.length; i++)
+                        {
+                                addrList[i] = ntohl(*(cast(uint*)he.h_addr_list[i]));
+                        }
+                }
+                else
+                {
+                        addrList = null;
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        synchronized bool getHostByName(char[] name)
+        {
+                char[1024] tmp;
+
+                hostent* he = gethostbyname(convert2C (name, tmp));
+                if(!he)
+                    return false;
+                validHostent(he);
+                populate(he);
+                return true;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        synchronized bool getHostByAddr(uint addr)
+        {
+                uint x = htonl(addr);
+                hostent* he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
+                if(!he)
+                    return false;
+                validHostent(he);
+                populate(he);
+                return true;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        //shortcut
+        synchronized bool getHostByAddr(char[] addr)
+        {
+                char[64] tmp;
+
+                uint x = inet_addr(convert2C (addr, tmp));
+                hostent* he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
+                if(!he)
+                    return false;
+                validHostent(he);
+                populate(he);
+                return true;
+        }
+}
+
+
+debug (UnitText)
+{
+extern (C) int printf(char*, ...);
+unittest
+{
+        try
+        {
+        NetHost ih = new NetHost;
+        ih.getHostByName(Socket.hostName());
+        assert(ih.addrList.length > 0);
+        IPv4Address ia = new IPv4Address(ih.addrList[0], IPv4Address.PORT_ANY);
+        printf("IP address = %.*s\nname = %.*s\n", ia.toAddrString(), ih.name);
+        foreach(int i, char[] s; ih.aliases)
+        {
+                printf("aliases[%d] = %.*s\n", i, s);
+        }
+
+        printf("---\n");
+
+        assert(ih.getHostByAddr(ih.addrList[0]));
+        printf("name = %.*s\n", ih.name);
+        foreach(int i, char[] s; ih.aliases)
+        {
+                printf("aliases[%d] = %.*s\n", i, s);
+                }
+        }
+        catch( Object o )
+        {
+            assert( false );
+        }
+}
+}
+
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+class IPv4Address: Address
+{
+        protected:
+        char[8] _port;
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        struct sockaddr_in
+        {
+                ushort sinfamily = AddressFamily.INET;
+                ushort sin_port;
+                uint sin_addr; //in_addr
+                char[8] sin_zero = [0];
+        }
+
+        sockaddr_in sin;
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        sockaddr* name()
+        {
+                return cast(sockaddr*)&sin;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        int nameLen()
+        {
+                return sin.sizeof;
+        }
+
+
+        public:
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        this()
+        {
+        }
+
+
+        const uint ADDR_ANY = 0;
+        const uint ADDR_NONE = cast(uint)-1;
+        const ushort PORT_ANY = 0;
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        AddressFamily addressFamily()
+        {
+                return AddressFamily.INET;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        ushort port()
+        {
+                return ntohs(sin.sin_port);
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        uint addr()
+        {
+                return ntohl(sin.sin_addr);
+        }
+
+
+        /***********************************************************************
+
+                -port- can be PORT_ANY
+                -addr- is an IP address or host name
+
+        ***********************************************************************/
+
+        this(char[] addr, int port = PORT_ANY)
+        {
+                uint uiaddr = parse(addr);
+                if(ADDR_NONE == uiaddr)
+                {
+                        NetHost ih = new NetHost;
+                        if(!ih.getHostByName(addr))
+                                exception ("Unable to resolve '"~addr~"': ");
+                        uiaddr = ih.addrList[0];
+                }
+                sin.sin_addr = htonl(uiaddr);
+                sin.sin_port = htons(cast(ushort) port);
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        this(uint addr, ushort port)
+        {
+                sin.sin_addr = htonl(addr);
+                sin.sin_port = htons(port);
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        this(ushort port)
+        {
+                sin.sin_addr = 0; //any, "0.0.0.0"
+                sin.sin_port = htons(port);
+        }
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        synchronized char[] toAddrString()
+        {
+                return .toString(inet_ntoa(sin.sin_addr)).dup;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        char[] toPortString()
+        {
+                return .toString (_port, port());
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        char[] toString()
+        {
+                return toAddrString() ~ ":" ~ toPortString();
+        }
+
+
+        /***********************************************************************
+
+                -addr- is an IP address in the format "a.b.c.d"
+                returns ADDR_NONE on failure
+
+        ***********************************************************************/
+
+        static uint parse(char[] addr)
+        {
+                char[64] tmp;
+
+                return ntohl(inet_addr(convert2C (addr, tmp)));
+        }
+}
+
+debug(Unittest)
+{
+unittest
+{
+        IPv4Address ia = new IPv4Address("63.105.9.61", 80);
+        assert(ia.toString() == "63.105.9.61:80");
+}
+}
+
+/*******************************************************************************
+
+
+*******************************************************************************/
+
+//a set of sockets for Socket.select()
+class SocketSet
+{
+//        private:
+        private uint nbytes; //Win32: excludes uint.size "count"
+        private byte* buf;
+
+
+        version(Win32)
+        {
+                uint count()
+                {
+                        return *(cast(uint*)buf);
+                }
+
+
+                void count(int setter)
+                {
+                        *(cast(uint*)buf) = setter;
+                }
+
+
+                socket_t* first()
+                {
+                        return cast(socket_t*)(buf + uint.sizeof);
+                }
+        }
+        else version (Posix)
+        {
+                import tango.core.BitManip;
+
+
+                uint nfdbits;
+                socket_t _maxfd = 0;
+
+                uint fdelt(socket_t s)
+                {
+                        return cast(uint)s / nfdbits;
+                }
+
+
+                uint fdmask(socket_t s)
+                {
+                        return 1 << cast(uint)s % nfdbits;
+                }
+
+
+                uint* first()
+                {
+                        return cast(uint*)buf;
+                }
+
+                public socket_t maxfd()
+                {
+                        return _maxfd;
+                }
+        }
+
+
+        public:
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        this(uint max)
+        {
+                version(Win32)
+                {
+                        nbytes = max * socket_t.sizeof;
+                        buf = (new byte[nbytes + uint.sizeof]).ptr;
+                        count = 0;
+                }
+                else version (Posix)
+                {
+                        if(max <= 32)
+                                nbytes = 32 * uint.sizeof;
+                        else
+                                nbytes = max * uint.sizeof;
+                        buf = (new byte[nbytes]).ptr;
+                        nfdbits = nbytes * 8;
+                        //clear(); //new initializes to 0
+                }
+                else
+                {
+                        static assert(0);
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        this()
+        {
+                version(Win32)
+                {
+                        this(64);
+                }
+                else version (Posix)
+                {
+                        this(32);
+                }
+                else
+                {
+                        static assert(0);
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        void reset()
+        {
+                version(Win32)
+                {
+                        count = 0;
+                }
+                else version (Posix)
+                {
+                        buf[0 .. nbytes] = 0;
+                        _maxfd = 0;
+                }
+                else
+                {
+                        static assert(0);
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        void add(socket_t s)
+        in
+        {
+                version(Win32)
+                {
+                        assert(count < max); //added too many sockets; specify a higher max in the constructor
+                }
+        }
+        body
+        {
+                version(Win32)
+                {
+                        uint c = count;
+                        first[c] = s;
+                        count = c + 1;
+                }
+                else version (Posix)
+                {
+                        if (s > _maxfd)
+                                _maxfd = s;
+
+                        bts(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
+                }
+                else
+                {
+                        static assert(0);
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        void add(Socket s)
+        {
+                add(s.sock);
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        void remove(socket_t s)
+        {
+                version(Win32)
+                {
+                        uint c = count;
+                        socket_t* start = first;
+                        socket_t* stop = start + c;
+
+                        for(; start != stop; start++)
+                        {
+                                if(*start == s)
+                                        goto found;
+                        }
+                        return; //not found
+
+                        found:
+                        for(++start; start != stop; start++)
+                        {
+                                *(start - 1) = *start;
+                        }
+
+                        count = c - 1;
+                }
+                else version (Posix)
+                {
+                        btr(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
+
+                        // If we're removing the biggest file descriptor we've
+                        // entered so far we need to recalculate this value
+                        // for the socket set.
+                        if (s == _maxfd)
+                        {
+                                while (--_maxfd >= 0)
+                                {
+                                        if (isSet(_maxfd))
+                                        {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+                else
+                {
+                        static assert(0);
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        void remove(Socket s)
+        {
+                remove(s.sock);
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        int isSet(socket_t s)
+        {
+                version(Win32)
+                {
+                        socket_t* start = first;
+                        socket_t* stop = start + count;
+
+                        for(; start != stop; start++)
+                        {
+                                if(*start == s)
+                                        return true;
+                        }
+                        return false;
+                }
+                else version (Posix)
+                {
+                        //return bt(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
+                        int index = cast(uint)s % nfdbits;
+                        return (cast(uint*)&first[fdelt(s)])[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)));
+                }
+                else
+                {
+                        static assert(0);
+                }
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        int isSet(Socket s)
+        {
+                return isSet(s.sock);
+        }
+
+
+        /***********************************************************************
+
+                max sockets that can be added, like FD_SETSIZE
+
+        ***********************************************************************/
+
+        uint max()
+        {
+                return nbytes / socket_t.sizeof;
+        }
+
+
+        /***********************************************************************
+
+
+        ***********************************************************************/
+
+        fd_set* toFd_set()
+        {
+                return cast(fd_set*)buf;
+        }
+}
+