Advertisement
Guest User

std.socket.Socket compatible class with a constructor that accepts a socket_t and other stuff

a guest
Aug 22nd, 2010
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 24.02 KB | None | 0 0
  1. import std.socket;
  2. import std.c.unix.unix; // sockaddr
  3. import std.c.string; // strlen, memset
  4. import std.c.stdlib; // getError() and maybe other stuff for LLSocket
  5. import std.stdint; // int32_t
  6. import std.string; // toStrinz
  7. static import std.gc; // malloc() is used once..
  8.  
  9. // some C functions we need that are not contained in std.c.* or are implemented by me in mischelper.c
  10. extern(C) {
  11.     /* ****************************************************************************************
  12.      * The following two functions are implemented in C, because std.c.linux.socket currently *
  13.      * lacks sendmsg(), recvmsg() and related structs and macros/functions                    *
  14.      * (the cmsg-stuff like struct msghdr, struct iovec, struct cmsghdr and all those         *
  15.      * macros to modify those structs like CMSG_LEN, CMSG_FIRSTHDR, CMSG_DATA etc)            *
  16.      * These functions however are crucial to pass file descriptors between processes.        *
  17.      * ****************************************************************************************/
  18.    
  19.     /**
  20.      * Sends file/socket-descriptor fd_to_send to other process via socket.
  21.      * The Socket must be of AddressFamily UNIX (AF_UNIX)!
  22.      *
  23.      * Returns: The amount of bytes written, -1 on error
  24.      */
  25.     // this is not a standard function - you have to compile the C-code and link it yourself
  26.     int send_fd(int socket, int fd_to_send);
  27.    
  28.     /**
  29.      * Receives a file/socket-descriptor from another process via socket.
  30.      * The Socket must be of AddressFamily UNIX (AF_UNIX)!
  31.      *
  32.      * Returns: The received file/socket-descriptor, -1 on error
  33.      */
  34.     // this is not a standard function - you have to compile the C-code and link it yourself
  35.     int recv_fd(int socket);
  36.    
  37.     /**
  38.      * creates a pair of locally connected sockets
  39.      *
  40.      * domain: must be AF_UNIX
  41.      * type: STREAM, DGRAM or something like that (I use SOCK_STREAM)
  42.      * protocol: optional (0 should work)
  43.      * sv[2]: sv[0] will contain first socket-fd, sv[1] the second
  44.      */
  45.     // this is a standard POSIX function that isn't represented in std.c.*
  46.     int socketpair(int domain, int type, int protocol, int sv[2]);
  47. }
  48.  
  49. /* ********************
  50.  *    Socket-Stuff    *
  51.  * ********************/
  52.  
  53. // this struct normally resides in <sys/un.h> (for C)
  54. /// a sockaddr for local connections (AF_UNIX)
  55. struct sockaddr_un {
  56.     ushort sun_family = AF_UNIX; // addr family
  57.     char sun_path[108]; // pathname
  58. };
  59.  
  60. /// an Address (derived from std.socket.Address) with public getters...
  61. abstract class PubAddress : Address {
  62.     // add public accessors for name and namelen
  63.     public sockaddr* getName() { return name(); }
  64.     public int getNameLen() { return nameLen(); }
  65. }
  66.  
  67. /// an Address (derived from std.socket.Address) with public getters for local addresses (AF_UNIX)
  68. class LocalAddress : PubAddress {
  69.     sockaddr_un addr;
  70.    
  71.     this() {
  72.         addr.sun_family = AF_UNIX;
  73.     }
  74.    
  75.     this(char[] path) {
  76.         // see man 7 unix for further information about the path/address types
  77.         if(path && path.length>0) {
  78.             // unnamed type
  79.             if(path[0] == '\0' && path[1] == '\0')
  80.                 return;
  81.             // abstract type
  82.             if(path[0] == '\0'){
  83.                 if(path.length > 108)
  84.                     throw new Exception("path to long - must be at most 108 chars");
  85.                 addr.sun_path[0..path.length] = path[];
  86.             }
  87.             // pathname type
  88.             path ~= '\0'; // just to be sure
  89.             int len = cast(int)strlen(cast(char*)addr.sun_path);
  90.             if(len > 107) // nullterminated path doesn't fit into sun_path
  91.                 throw new Exception("path to long - must be at most 108 chars");
  92.             addr.sun_path[0..len] = path[0..len];
  93.         }
  94.     }
  95.    
  96.     this(sockaddr_un *sadr){
  97.         if(sadr.sun_family != AF_UNIX) {
  98.             throw new Exception("this was not a AF_UNIX socketaddr");
  99.         }
  100.         addr = *sadr;
  101.     }
  102.    
  103.     protected sockaddr* name() { return cast(sockaddr*) &addr; }
  104.     protected int nameLen() {
  105.         // if the address is the unnamed type
  106.         if(addr.sun_path[0] == '\0' && addr.sun_path[1] == '\0')
  107.             return cast(int)ushort.sizeof;
  108.        
  109.         // if the address is the abstract type
  110.         if(addr.sun_path[0] == '\0')
  111.             return cast(int)addr.sizeof;
  112.        
  113.         // at this point it has to be the pathname type
  114.         assert(addr.sun_path[107] == '\0');
  115.         int len = cast(int)strlen(cast(char*)addr.sun_path) + 1; // + terminating \0
  116.         return cast(int)(ushort.sizeof + len);
  117.     }
  118.    
  119.     AddressFamily addressFamily() { return AddressFamily.UNIX; }
  120.    
  121.     string toString() { return "local:"~getPath(); }
  122.    
  123.     char[] getPath() {
  124.         // if the address is the unnamed type
  125.         if(addr.sun_path[0] == '\0' && addr.sun_path[1] == '\0')
  126.             return "\0\0";
  127.        
  128.         // if the address is the abstract type
  129.         if(addr.sun_path[0] == '\0')
  130.             return addr.sun_path;
  131.        
  132.         // at this point it has to be the pathname type
  133.         assert(addr.sun_path[107] == '\0');
  134.         int len = cast(int)strlen(cast(char*)addr.sun_path)+1; // + terminating \0
  135.         return addr.sun_path[0..len];
  136.     }
  137. }
  138.  
  139.  
  140. version = BsdSockets;
  141. /**
  142.  * "Low Level Socket" - Like an ordinary std.socket.Socket, but contains 1000% more hatred and also
  143.  * a constructor that accepts an existing socket_t (like one might get from c functions, e.g. socketpair()).
  144.  */
  145. class LLSocket : Socket
  146. {
  147.     /*
  148.      * yeah, this mess is basically copied&pasted from the original std.socket.Socket,
  149.      * a constructor accepting a socket_t was added and then hacks were added to work around
  150.      * package protection and such in std.socket
  151.      */
  152.     protected: // don't make the same mistake (making this private) again ...
  153.     socket_t sock;
  154.     AddressFamily _family;
  155.     // to be used with the constructor getting a socket_t
  156.     bool closeOnExit=true;
  157.    
  158.     // ####################################################################################
  159.     // ########## workarounds all this private crap in std.socket #########################
  160.    
  161.     // this might be specific for BsdSockets, i.e. doesn't work in windows - see std.socket
  162.     private const int _SOCKET_ERROR = -1;
  163.    
  164.     static private int _lasterr()
  165.     {
  166.             return getErrno();
  167.     }
  168.    
  169.     /**
  170.      * wraps an Address into a PubAddress - currently only works for InternetAddress and PubAddress
  171.      * (because, apart from UnknownAddress, no other Addresses are currently specified by std.socket)
  172.      */
  173.     class WrapAddress : PubAddress {
  174.         Address _addr;
  175.         AddressFamily fam;
  176.         sockaddr *sad;
  177.         int len;
  178.        
  179.         this(Address addr) {
  180.             _addr = addr;
  181.             fam = addr.addressFamily();
  182.             // addr is an InternetAddress
  183.             if( is(addr : InternetAddress) ) {
  184.                 InternetAddress iad = cast(InternetAddress)addr;
  185.                 sockaddr_in *tmp = cast(sockaddr_in *)std.gc.malloc(sockaddr_in.sizeof);
  186.                 memset(tmp, 0, sockaddr_in.sizeof); // should be nulled
  187.                 tmp.sin_family = AF_INET;
  188.                 // set address
  189.                 tmp.sin_addr.s_addr = htonl(iad.addr());
  190.                 // set port
  191.                 tmp.sin_port = htons(iad.port());
  192.                 sad = cast(sockaddr *)tmp;
  193.             } else if( is(addr : PubAddress) ) {
  194.                 PubAddress pad = cast(PubAddress) addr;
  195.                 sad = pad.getName();
  196.                 len = pad.getNameLen();
  197.             }
  198.            
  199.         }
  200.        
  201.         protected sockaddr* name() {
  202.             return sad;
  203.         }
  204.        
  205.         protected int nameLen() {
  206.             return len;
  207.         }
  208.        
  209.         AddressFamily addressFamily() { return fam; }
  210.         string toString() { return _addr.toString(); } 
  211.     }
  212.    
  213.     // ################ end of sucky workarounds ##########################################
  214.     // ####################################################################################
  215.    
  216.     version(Win32)
  217.         bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking.
  218.    
  219.    
  220.     // For use with accepting().
  221.     protected this()
  222.     {
  223.     }
  224.    
  225.    
  226.     public:
  227.     /**
  228.      * Create a Socket from a given socket handle (which might have been obtained
  229.      * from a C-function like socketpair() or might even have been passed from
  230.      * another process via ancillary messages - see man cmsg or man 7 unix).
  231.      * The AddressFamily has to be specified.
  232.      * Per default the socket will be closed when this Socket object is
  233.      * destructed - set closeOnExit=false to prevent this.
  234.      */
  235.     this(socket_t socket, AddressFamily fam, bool closeOnExit=true) {
  236.         this.sock = socket;
  237.         this._family = fam;
  238.         this.closeOnExit = closeOnExit;
  239.     }
  240.  
  241.     /**
  242.      * Create a blocking socket. If a single protocol type exists to support
  243.      * this socket type within the address family, the ProtocolType may be
  244.      * omitted.
  245.      */
  246.     this(AddressFamily af, SocketType type, ProtocolType protocol)
  247.     {
  248.         sock = cast(socket_t)socket(af, type, protocol);
  249.         if(sock == socket_t.init)
  250.             throw new SocketException("Unable to create socket", _lasterr());
  251.         _family = af;
  252.     }
  253.    
  254.    
  255.     // A single protocol exists to support this socket type within the
  256.     // protocol family, so the ProtocolType is assumed.
  257.     /// ditto
  258.     this(AddressFamily af, SocketType type)
  259.     {
  260.         this(af, type, cast(ProtocolType)0); // Pseudo protocol number.
  261.     }
  262.    
  263.    
  264.     /// ditto
  265.     this(AddressFamily af, SocketType type, string protocolName)
  266.     {
  267.         protoent* proto;
  268.         proto = getprotobyname(toStringz(protocolName));
  269.         if(!proto)
  270.             throw new SocketException("Unable to find the protocol", _lasterr());
  271.         this(af, type, cast(ProtocolType)proto.p_proto);
  272.     }
  273.    
  274.    
  275.     ~this()
  276.     {
  277.         if(closeOnExit)
  278.             close();
  279.     }
  280.    
  281.    
  282.     /// Get underlying socket handle.
  283.     socket_t handle()
  284.     {
  285.         return sock;
  286.     }
  287.  
  288.     /**
  289.      * Get/set socket's blocking flag.
  290.      *
  291.      * When a socket is blocking, calls to receive(), accept(), and send()
  292.      * will block and wait for data/action.
  293.      * A non-blocking socket will immediately return instead of blocking.
  294.      */
  295.     bool blocking()
  296.     {
  297.         version(Win32)
  298.         {
  299.             return _blocking;
  300.         }
  301.         else version(BsdSockets)
  302.         {
  303.             return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK);
  304.         }
  305.     }
  306.    
  307.     /// ditto
  308.     void blocking(bool byes)
  309.     {
  310.         version(Win32)
  311.         {
  312.             uint num = !byes;
  313.             if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
  314.                 goto err;
  315.             _blocking = byes;
  316.         }
  317.         else version(BsdSockets)
  318.         {
  319.             int x = fcntl(sock, F_GETFL, 0);
  320.             if(-1 == x)
  321.                 goto err;
  322.             if(byes)
  323.                 x &= ~O_NONBLOCK;
  324.             else
  325.                 x |= O_NONBLOCK;
  326.             if(-1 == fcntl(sock, F_SETFL, x))
  327.                 goto err;
  328.         }
  329.         return; // Success.
  330.        
  331.         err:
  332.         throw new SocketException("Unable to set socket blocking", _lasterr());
  333.     }
  334.    
  335.  
  336.     /// Get the socket's address family.   
  337.     AddressFamily addressFamily() // getter
  338.     {
  339.         return _family;
  340.     }
  341.    
  342.     /// Property that indicates if this is a valid, alive socket.
  343.     bool isAlive() // getter
  344.     {
  345.         int type, typesize = type.sizeof;
  346.         return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
  347.     }
  348.    
  349.     /// Associate a local address with this socket.
  350.     void bind(Address addr)
  351.     {
  352.         PubAddress wad;
  353.         if(is(addr : PubAddress))
  354.             wad = cast(PubAddress)addr;
  355.         else
  356.             wad = new WrapAddress(addr);
  357.         if(_SOCKET_ERROR == .bind(sock, wad.getName(), wad.getNameLen()))
  358.             throw new SocketException("Unable to bind socket", _lasterr());
  359.     }
  360.    
  361.     /**
  362.      * Establish a connection. If the socket is blocking, connect waits for
  363.      * the connection to be made. If the socket is nonblocking, connect
  364.      * returns immediately and the connection attempt is still in progress.
  365.      */
  366.     void connect(Address to)
  367.     {
  368.         PubAddress wad;
  369.         if(is(to : PubAddress))
  370.             wad = cast(PubAddress)to;
  371.         else
  372.             wad = new WrapAddress(to);
  373.         if(_SOCKET_ERROR == .connect(sock, wad.getName(), wad.getNameLen()))
  374.         {
  375.             int err;
  376.             err = _lasterr();
  377.            
  378.             if(!blocking)
  379.             {
  380.                 version(Win32)
  381.                 {
  382.                     if(WSAEWOULDBLOCK == err)
  383.                         return;
  384.                 }
  385.                 else version(Unix)
  386.                 {
  387.                     if(EINPROGRESS == err)
  388.                         return;
  389.                 }
  390.                 else
  391.                 {
  392.                     static assert(0);
  393.                 }
  394.             }
  395.             throw new SocketException("Unable to connect socket", err);
  396.         }
  397.     }
  398.    
  399.     /**
  400.      * Listen for an incoming connection. bind must be called before you can
  401.      * listen. The backlog is a request of how many pending incoming
  402.      * connections are queued until accept'ed.
  403.      */
  404.     void listen(int backlog)
  405.     {
  406.         if(_SOCKET_ERROR == .listen(sock, backlog))
  407.             throw new SocketException("Unable to listen on socket", _lasterr());
  408.     }
  409.    
  410.     /**
  411.      * Called by accept when a new Socket must be created for a new
  412.      * connection. To use a derived class, override this method and return an
  413.      * instance of your class. The returned Socket's handle must not be set;
  414.      * Socket has a protected constructor this() to use in this situation.
  415.      */
  416.     // Override to use a derived class.
  417.     // The returned socket's handle must not be set.
  418.     protected Socket accepting()
  419.     {
  420.         return new LLSocket;
  421.     }
  422.    
  423.    
  424.     /**
  425.      * Accept an incoming connection. If the socket is blocking, accept
  426.      * waits for a connection request. Throws SocketAcceptException if unable
  427.      * to accept. See accepting for use with derived classes.
  428.      */
  429.     Socket accept()
  430.     {
  431.         socket_t newsock;
  432.         //newsock = cast(socket_t).accept(sock, null, null); // DMD 0.101 error: found '(' when expecting ';' following 'statement
  433.         alias .accept topaccept;
  434.         newsock = cast(socket_t)topaccept(sock, null, null);
  435.         if(socket_t.init == newsock)
  436.             throw new SocketAcceptException("Unable to accept socket connection", _lasterr());
  437.        
  438.         LLSocket newSocket;
  439.         try
  440.         {
  441.             // this cast shouldn't do any harm - accepting returns an LLSocket and any derived class
  442.             // will also be castable to LLSocket
  443.             newSocket = cast(LLSocket)accepting();
  444.             assert(newSocket.sock == socket_t.init);
  445.            
  446.             newSocket.sock = newsock;
  447.             version(Win32)
  448.                 newSocket._blocking = _blocking; //inherits blocking mode
  449.             newSocket._family = _family; //same family
  450.         }
  451.         catch(Object o)
  452.         {
  453.             _close(newsock);
  454.             throw o;
  455.         }
  456.        
  457.         return newSocket;
  458.     }
  459.    
  460.     /// Disables sends and/or receives.
  461.     void shutdown(SocketShutdown how)
  462.     {
  463.         .shutdown(sock, cast(int)how);
  464.     }
  465.    
  466.    
  467.     private static void _close(socket_t sock)
  468.     {
  469.         version(Win32)
  470.         {
  471.             .closesocket(sock);
  472.         }
  473.         else version(BsdSockets)
  474.         {
  475.             .close(sock);
  476.         }
  477.     }
  478.    
  479.  
  480.     /**
  481.      * Immediately drop any connections and release socket resources.
  482.      * Calling shutdown before close is recommended for connection-oriented
  483.      * sockets. The Socket object is no longer usable after close.
  484.      */
  485.     //calling shutdown() before this is recommended
  486.     //for connection-oriented sockets
  487.     void close()
  488.     {
  489.         _close(sock);
  490.         sock = socket_t.init;
  491.     }
  492.    
  493.    
  494.     private Address newFamilyObject()
  495.     {
  496.         Address result;
  497.         switch(_family)
  498.         {
  499.             case cast(AddressFamily)AddressFamily.INET:
  500.                 // port 0 seems to be default so this shouldn't do any harm
  501.                 result = new InternetAddress(cast(ushort)0);
  502.                 break;
  503.            
  504.             default:
  505.                 result = new UnknownAddress;
  506.         }
  507.         return result;
  508.     }
  509.    
  510.    
  511.     /// Returns the local machine's host name. Idea from mango.
  512.     static string hostName() // getter
  513.     {
  514.         char[256] result; // Host names are limited to 255 chars.
  515.         if(_SOCKET_ERROR == .gethostname(result.ptr, result.length))
  516.             throw new SocketException("Unable to obtain host name", _lasterr());
  517.         return std.string.toString(cast(char*)result).dup;
  518.     }
  519.    
  520.     /// Remote endpoint Address.
  521.     Address remoteAddress()
  522.     {
  523.         Address addr = newFamilyObject();
  524.         PubAddress wad;
  525.         if(is(addr : PubAddress))
  526.             wad = cast(PubAddress)addr;
  527.         else
  528.             wad = new WrapAddress(addr);
  529.         int nameLen = wad.getNameLen();
  530.         if(_SOCKET_ERROR == .getpeername(sock, wad.getName(), &nameLen))
  531.             throw new SocketException("Unable to obtain remote socket address", _lasterr());
  532.         assert(addr.addressFamily() == _family);
  533.         return addr;
  534.     }
  535.    
  536.     /// Local endpoint Address.
  537.     Address localAddress()
  538.     {
  539.         Address addr = newFamilyObject();
  540.         PubAddress wad;
  541.         if(is(addr : PubAddress))
  542.             wad = cast(PubAddress)addr;
  543.         else
  544.             wad = new WrapAddress(addr);
  545.         int nameLen = wad.getNameLen();
  546.         if(_SOCKET_ERROR == .getsockname(sock, wad.getName(), &nameLen))
  547.             throw new SocketException("Unable to obtain local socket address", _lasterr());
  548.         assert(addr.addressFamily() == _family);
  549.         return addr;
  550.     }
  551.    
  552.     /// Send or receive error code.
  553.     const int ERROR = _SOCKET_ERROR;
  554.    
  555.     /**
  556.      * Send data on the connection. Returns the number of bytes actually
  557.      * sent, or ERROR on failure. If the socket is blocking and there is no
  558.      * buffer space left, send waits.
  559.      */
  560.     //returns number of bytes actually sent, or -1 on error
  561.     int send(void[] buf, SocketFlags flags)
  562.     {
  563.                 flags |= SocketFlags.NOSIGNAL;
  564.         int sent = .send(sock, buf.ptr, buf.length, cast(int)flags);
  565.         return sent;
  566.     }
  567.    
  568.     /// ditto
  569.     int send(void[] buf)
  570.     {
  571.         return send(buf, SocketFlags.NOSIGNAL);
  572.     }
  573.    
  574.     /**
  575.      * 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.
  576.      */
  577.     int sendTo(void[] buf, SocketFlags flags, Address to)
  578.     {
  579.                 flags |= SocketFlags.NOSIGNAL;
  580.         PubAddress wad;
  581.         if(is(to : PubAddress))
  582.             wad = cast(PubAddress)to;
  583.         else
  584.             wad = new WrapAddress(to);
  585.         int sent = .sendto(sock, buf.ptr, buf.length, cast(int)flags, wad.getName(), wad.getNameLen());
  586.         return sent;
  587.     }
  588.    
  589.     /// ditto
  590.     int sendTo(void[] buf, Address to)
  591.     {
  592.         return sendTo(buf, SocketFlags.NONE, to);
  593.     }
  594.    
  595.    
  596.     //assumes you connect()ed
  597.     /// ditto
  598.     int sendTo(void[] buf, SocketFlags flags)
  599.     {
  600.                 flags |= SocketFlags.NOSIGNAL;
  601.         int sent = .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
  602.         return sent;
  603.     }
  604.    
  605.    
  606.     //assumes you connect()ed
  607.     /// ditto
  608.     int sendTo(void[] buf)
  609.     {
  610.         return sendTo(buf, SocketFlags.NONE);
  611.     }
  612.    
  613.  
  614.     /**
  615.      * Receive data on the connection. Returns the number of bytes actually
  616.      * received, 0 if the remote side has closed the connection, or ERROR on
  617.      * failure. If the socket is blocking, receive waits until there is data
  618.      * to be received.
  619.      */
  620.     //returns number of bytes actually received, 0 on connection closure, or -1 on error
  621.     int receive(void[] buf, SocketFlags flags)
  622.     {
  623.         if(!buf.length) //return 0 and don't think the connection closed
  624.             return 0;
  625.         int read = .recv(sock, buf.ptr, buf.length, cast(int)flags);
  626.         // if(!read) //connection closed
  627.         return read;
  628.     }
  629.    
  630.     /// ditto
  631.     int receive(void[] buf)
  632.     {
  633.         return receive(buf, SocketFlags.NONE);
  634.     }
  635.    
  636.     /**
  637.      * Receive data and get the remote endpoint Address.
  638.      * If the socket is blocking, receiveFrom waits until there is data to
  639.      * be received.
  640.      * Returns: the number of bytes actually received,
  641.      * 0 if the remote side has closed the connection, or ERROR on failure.
  642.      */
  643.     int receiveFrom(void[] buf, SocketFlags flags, out Address from)
  644.     {
  645.         if(!buf.length) //return 0 and don't think the connection closed
  646.             return 0;
  647.         from = newFamilyObject();
  648.         PubAddress wad;
  649.         if(is(from : PubAddress))
  650.             wad = cast(PubAddress)from;
  651.         else
  652.             wad = new WrapAddress(from);
  653.         int nameLen = wad.getNameLen();
  654.         int read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, wad.getName(), &nameLen);
  655.         assert(from.addressFamily() == _family);
  656.         // if(!read) //connection closed
  657.         return read;
  658.     }
  659.    
  660.    
  661.     /// ditto
  662.     int receiveFrom(void[] buf, out Address from)
  663.     {
  664.         return receiveFrom(buf, SocketFlags.NONE, from);
  665.     }
  666.    
  667.    
  668.     //assumes you connect()ed
  669.     /// ditto
  670.     int receiveFrom(void[] buf, SocketFlags flags)
  671.     {
  672.         if(!buf.length) //return 0 and don't think the connection closed
  673.             return 0;
  674.         int read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
  675.         // if(!read) //connection closed
  676.         return read;
  677.     }
  678.    
  679.    
  680.     //assumes you connect()ed
  681.     /// ditto
  682.     int receiveFrom(void[] buf)
  683.     {
  684.         return receiveFrom(buf, SocketFlags.NONE);
  685.     }
  686.    
  687.  
  688.     /// Get a socket option. Returns the number of bytes written to result.
  689.     //returns the length, in bytes, of the actual result - very different from getsockopt()
  690.     int getOption(SocketOptionLevel level, SocketOption option, void[] result)
  691.     {
  692.         int len = result.length;
  693.         if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result.ptr, &len))
  694.             throw new SocketException("Unable to get socket option", _lasterr());
  695.         return len;
  696.     }
  697.    
  698.  
  699.     /// Common case of getting integer and boolean options.
  700.     int getOption(SocketOptionLevel level, SocketOption option, out int32_t result)
  701.     {
  702.         return getOption(level, option, (&result)[0 .. 1]);
  703.     }
  704.  
  705.  
  706.     /// Get the linger option. 
  707.     int getOption(SocketOptionLevel level, SocketOption option, out std.socket.linger result)
  708.     {
  709.         //return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
  710.         return getOption(level, option, (&result)[0 .. 1]);
  711.     }
  712.    
  713.     // Set a socket option.
  714.     void setOption(SocketOptionLevel level, SocketOption option, void[] value)
  715.     {
  716.         if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level, cast(int)option, value.ptr, value.length))
  717.             throw new SocketException("Unable to set socket option", _lasterr());
  718.     }
  719.    
  720.    
  721.     /// Common case for setting integer and boolean options.
  722.     void setOption(SocketOptionLevel level, SocketOption option, int32_t value)
  723.     {
  724.         setOption(level, option, (&value)[0 .. 1]);
  725.     }
  726.  
  727.  
  728.     /// Set the linger option.
  729.     void setOption(SocketOptionLevel level, SocketOption option, std.socket.linger value)
  730.     {
  731.         //setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
  732.         setOption(level, option, (&value)[0 .. 1]);
  733.     }
  734.    
  735.  
  736.     /**
  737.      * Wait for a socket to change status. A wait timeout timeval or int microseconds may be specified; if a timeout is not specified or the timeval is null, the maximum timeout is used. The timeval timeout has an unspecified value when select returns. Returns the number of sockets with status changes, 0 on timeout, or -1 on interruption. If the return value is greater than 0, the SocketSets are updated to only contain the sockets having status changes. For a connecting socket, a write status change means the connection is established and it's able to send. For a listening socket, a read status change means there is an incoming connection request and it's able to accept.
  738.      */
  739.     //SocketSet's updated to include only those sockets which an event occured
  740.     //returns the number of events, 0 on timeout, or -1 on interruption
  741.     //for a connect()ing socket, writeability means connected
  742.     //for a listen()ing socket, readability means listening
  743.     //Winsock: possibly internally limited to 64 sockets per set
  744.     static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, std.socket.timeval* tv)
  745.     in
  746.     {
  747.         //make sure none of the SocketSet's are the same object
  748.         if(checkRead)
  749.         {
  750.             assert(checkRead !is checkWrite);
  751.             assert(checkRead !is checkError);
  752.         }
  753.         if(checkWrite)
  754.         {
  755.             assert(checkWrite !is checkError);
  756.         }
  757.     }
  758.     body
  759.     {
  760.         fd_set* fr, fw, fe;
  761.         int n = 0;
  762.        
  763.         version(Win32)
  764.         {
  765.             // Windows has a problem with empty fd_set`s that aren't null.
  766.             fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null;
  767.             fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null;
  768.             fe = (checkError && checkError.count()) ? checkError.toFd_set() : null;
  769.         }
  770.         else
  771.         {
  772.             if(checkRead)
  773.             {
  774.                 fr = checkRead.toFd_set();
  775.                 n = checkRead.selectn();
  776.             }
  777.             else
  778.             {
  779.                 fr = null;
  780.             }
  781.            
  782.             if(checkWrite)
  783.             {
  784.                 fw = checkWrite.toFd_set();
  785.                 int _n;
  786.                 _n = checkWrite.selectn();
  787.                 if(_n > n)
  788.                     n = _n;
  789.             }
  790.             else
  791.             {
  792.                 fw = null;
  793.             }
  794.            
  795.             if(checkError)
  796.             {
  797.                 fe = checkError.toFd_set();
  798.                 int _n;
  799.                 _n = checkError.selectn();
  800.                 if(_n > n)
  801.                     n = _n;
  802.             }
  803.             else
  804.             {
  805.                 fe = null;
  806.             }
  807.         }
  808.        
  809.         int result = .select(n, fr, fw, fe, cast(_ctimeval*)tv);
  810.        
  811.         version(Win32)
  812.         {
  813.             if(_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR)
  814.                 return -1;
  815.         }
  816.         else version(Unix)
  817.         {
  818.             if(_SOCKET_ERROR == result && getErrno() == EINTR)
  819.                 return -1;
  820.         }
  821.         else
  822.         {
  823.             static assert(0);
  824.         }
  825.        
  826.         if(_SOCKET_ERROR == result)
  827.             throw new SocketException("Socket select error", _lasterr());
  828.        
  829.         return result;
  830.     }
  831.  
  832.  
  833.     /// ditto
  834.     static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, int microseconds)
  835.     {
  836.         std.socket.timeval tv;
  837.         tv.seconds = 0;
  838.         tv.microseconds = microseconds;
  839.         return select(checkRead, checkWrite, checkError, &tv);
  840.     }
  841.    
  842.    
  843.     /// ditto
  844.     //maximum timeout
  845.     static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
  846.     {
  847.         return select(checkRead, checkWrite, checkError, null);
  848.     }
  849. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement