/tango/net/device/Berkeley.d
D | 2412 lines | 1396 code | 377 blank | 639 comment | 135 complexity | 8f0d84adfdab271ae6dbaa0bcc941d1b MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- module tango.net.device.Berkeley;
- private import tango.sys.Common;
- private import tango.core.Exception;
- import consts=tango.sys.consts.socket;
- private import tango.stdc.string : strlen;
- private import tango.stdc.stringz;
- /*******************************************************************************
- *******************************************************************************/
- enum {SOCKET_ERROR = consts.SOCKET_ERROR}
- /*******************************************************************************
- *******************************************************************************/
- enum SocketOption
- {
- DEBUG = consts.SO_DEBUG , /* turn on debugging info recording */
- BROADCAST = consts.SO_BROADCAST , /* permit sending of broadcast msgs */
- REUSEADDR = consts.SO_REUSEADDR , /* allow local address reuse */
- LINGER = consts.SO_LINGER , /* linger on close if data present */
- DONTLINGER = ~(consts.SO_LINGER),
- OOBINLINE = consts.SO_OOBINLINE , /* leave received OOB data in line */
- ACCEPTCONN = consts.SO_ACCEPTCONN, /* socket has had listen() */
- KEEPALIVE = consts.SO_KEEPALIVE , /* keep connections alive */
- DONTROUTE = consts.SO_DONTROUTE , /* just use interface addresses */
- TYPE = consts.SO_TYPE , /* get socket type */
- /*
- * Additional options, not kept in so_options.
- */
- SNDBUF = consts.SO_SNDBUF, /* send buffer size */
- RCVBUF = consts.SO_RCVBUF, /* receive buffer size */
- ERROR = consts.SO_ERROR , /* get error status and clear */
- // OptionLevel.IP settings
- MULTICAST_TTL = consts.IP_MULTICAST_TTL ,
- MULTICAST_LOOP = consts.IP_MULTICAST_LOOP ,
- ADD_MEMBERSHIP = consts.IP_ADD_MEMBERSHIP ,
- DROP_MEMBERSHIP = consts.IP_DROP_MEMBERSHIP,
- // OptionLevel.TCP settings
- TCP_NODELAY = consts.TCP_NODELAY ,
- // Windows specifics
- WIN_UPDATE_ACCEPT_CONTEXT = 0x700B,
- WIN_CONNECT_TIME = 0x700C,
- WIN_UPDATE_CONNECT_CONTEXT = 0x7010,
- }
- /*******************************************************************************
- *******************************************************************************/
- enum SocketOptionLevel
- {
- SOCKET = consts.SOL_SOCKET ,
- IP = consts.IPPROTO_IP ,
- TCP = consts.IPPROTO_TCP ,
- UDP = consts.IPPROTO_UDP ,
- }
- /*******************************************************************************
- *******************************************************************************/
- enum SocketType
- {
- STREAM = consts.SOCK_STREAM , /++ sequential, reliable +/
- DGRAM = consts.SOCK_DGRAM , /++ connectionless unreliable, max length +/
- SEQPACKET = consts.SOCK_SEQPACKET, /++ sequential, reliable, max length +/
- }
- /*******************************************************************************
- *******************************************************************************/
- enum ProtocolType
- {
- IP = consts.IPPROTO_IP , /// default internet protocol (probably 4 for compatibility)
- IPV4 = consts.IPPROTO_IP , /// internet protocol version 4
- IPV6 = consts.IPPROTO_IPV6 , /// internet protocol version 6
- ICMP = consts.IPPROTO_ICMP , /// internet control message protocol
- IGMP = consts.IPPROTO_IGMP , /// internet group management protocol
- TCP = consts.IPPROTO_TCP , /// transmission control protocol
- PUP = consts.IPPROTO_PUP , /// PARC universal packet protocol
- UDP = consts.IPPROTO_UDP , /// user datagram protocol
- IDP = consts.IPPROTO_IDP , /// Xerox NS protocol
- }
- /*******************************************************************************
- *******************************************************************************/
- enum AddressFamily
- {
- UNSPEC = consts.AF_UNSPEC ,
- UNIX = consts.AF_UNIX ,
- INET = consts.AF_INET ,
- IPX = consts.AF_IPX ,
- APPLETALK = consts.AF_APPLETALK,
- INET6 = consts.AF_INET6 ,
- }
- /*******************************************************************************
- *******************************************************************************/
- enum SocketShutdown
- {
- RECEIVE = consts.SHUT_RD,
- SEND = consts.SHUT_WR,
- BOTH = consts.SHUT_RDWR,
- }
- /*******************************************************************************
- *******************************************************************************/
- enum SocketFlags
- {
- NONE = 0,
- OOB = consts.MSG_OOB, /// out of band
- PEEK = consts.MSG_PEEK, /// only for receiving
- DONTROUTE = consts.MSG_DONTROUTE, /// only for sending
- NOSIGNAL = 0x4000, /// inhibit signals
- }
- enum AIFlags: int
- {
- PASSIVE = consts.AI_PASSIVE, /// get address to use bind()
- CANONNAME = consts.AI_CANONNAME, /// fill ai_canonname
- NUMERICHOST = consts.AI_NUMERICHOST, /// prevent host name resolution
- NUMERICSERV = consts.AI_NUMERICSERV, /// prevent service name resolution valid
- /// flags for addrinfo (not a standard def,
- /// apps should not use it)
- ALL = consts.AI_ALL, /// IPv6 and IPv4-mapped (with AI_V4MAPPED)
- ADDRCONFIG = consts.AI_ADDRCONFIG, /// only if any address is assigned
- V4MAPPED = consts.AI_V4MAPPED, /// accept IPv4-mapped IPv6 address special
- /// recommended flags for getipnodebyname
- MASK = consts.AI_MASK,
- DEFAULT = consts.AI_DEFAULT,
- }
- enum AIError
- {
- BADFLAGS = consts.EAI_BADFLAGS, /// Invalid value for `ai_flags' field.
- NONAME = consts.EAI_NONAME, /// NAME or SERVICE is unknown.
- AGAIN = consts.EAI_AGAIN, /// Temporary failure in name resolution.
- FAIL = consts.EAI_FAIL, /// Non-recoverable failure in name res.
- NODATA = consts.EAI_NODATA, /// No address associated with NAME.
- FAMILY = consts.EAI_FAMILY, /// `ai_family' not supported.
- SOCKTYPE = consts.EAI_SOCKTYPE, /// `ai_socktype' not supported.
- SERVICE = consts.EAI_SERVICE, /// SERVICE not supported for `ai_socktype'.
- MEMORY = consts.EAI_MEMORY, /// Memory allocation failure.
- }
- enum NIFlags: int
- {
- MAXHOST = consts.NI_MAXHOST,
- MAXSERV = consts.NI_MAXSERV,
- NUMERICHOST = consts.NI_NUMERICHOST, /// Don't try to look up hostname.
- NUMERICSERV = consts.NI_NUMERICSERV, /// Don't convert port number to name.
- NOFQDN = consts.NI_NOFQDN, /// Only return nodename portion.
- NAMEREQD = consts.NI_NAMEREQD, /// Don't return numeric addresses.
- DGRAM = consts.NI_DGRAM, /// Look up UDP service rather than TCP.
- }
- /*******************************************************************************
- conversions for network byte-order
- *******************************************************************************/
- version(BigEndian)
- {
- private ushort htons (ushort x)
- {
- return x;
- }
- private uint htonl (uint x)
- {
- return x;
- }
- }
- else
- {
- private import tango.core.BitManip;
- private ushort htons (ushort x)
- {
- return cast(ushort) ((x >> 8) | (x << 8));
- }
- private uint htonl (uint x)
- {
- return bswap(x);
- }
- }
- /*******************************************************************************
- *******************************************************************************/
- version (Win32)
- {
- pragma (lib, "ws2_32.lib");
-
- private import tango.sys.win32.WsaSock;
- enum socket_t: int
- {
- init = ~0
- }
- package extern (Windows)
- {
- alias closesocket close;
- socket_t socket(int af, int type, int protocol);
- int ioctlsocket(socket_t s, int cmd, uint* argp);
- uint inet_addr(const(char)* cp);
- int bind(socket_t s, Address.sockaddr* name, int namelen);
- int connect(socket_t s, Address.sockaddr* name, int namelen);
- int listen(socket_t s, int backlog);
- socket_t accept(socket_t s, Address.sockaddr* addr, int* addrlen);
- int closesocket(socket_t s);
- int shutdown(socket_t s, int how);
- int getpeername(socket_t s, Address.sockaddr* name, int* namelen);
- int getsockname(socket_t s, Address.sockaddr* name, int* namelen);
- int send(socket_t s, const(void)* buf, int len, int flags);
- int sendto(socket_t s, const(void)* buf, int len, int flags, Address.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, Address.sockaddr* from, int* fromlen);
- int select(int nfds, SocketSet.fd* readfds, SocketSet.fd* writefds, SocketSet.fd* errorfds, SocketSet.timeval* timeout);
- int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
- int setsockopt(socket_t s, int level, int optname, const(void)* optval, int optlen);
- int gethostname(void* namebuffer, int buflen);
- char* inet_ntoa(uint ina);
- NetHost.hostent* gethostbyname(const(char)* name);
- NetHost.hostent* gethostbyaddr(const(void)* addr, int len, int type);
- /**
- The gai_strerror function translates error codes of getaddrinfo,
- freeaddrinfo and getnameinfo to a human readable string, suitable
- for error reporting. (C) MAN
- */
- //char* gai_strerror(int errcode);
- /**
- Given node and service, which identify an Internet host and a service,
- getaddrinfo() returns one or more addrinfo structures, each of which
- contains an Internet address that can be specified in a call to bind
- or connect. The getaddrinfo() function combines the functionality
- provided by the getservbyname and getservbyport functions into a single
- interface, but unlike the latter functions, getaddrinfo() is reentrant
- and allows programs to eliminate IPv4-versus-IPv6 dependencies.(C) MAN
- */
- int function(const(char)* node, const(char)* service, Address.addrinfo* hints, Address.addrinfo** res) getaddrinfo;
- /**
- The freeaddrinfo() function frees the memory that was allocated for the
- dynamically allocated linked list res. (C) MAN
- */
- void function(Address.addrinfo *res) freeaddrinfo;
- /**
- The getnameinfo() function is the inverse of getaddrinfo: it converts
- a socket address to a corresponding host and service, in a protocol-
- independent manner. It combines the functionality of gethostbyaddr and
- getservbyport, but unlike those functions, getaddrinfo is reentrant and
- allows programs to eliminate IPv4-versus-IPv6 dependencies. (C) MAN
- */
- int function(Address.sockaddr* sa, int salen, char* host, int hostlen, char* serv, int servlen, int flags) getnameinfo;
- bool function (socket_t, uint, void*, DWORD, DWORD, DWORD, DWORD*, OVERLAPPED*) AcceptEx;
- bool function (socket_t, HANDLE, DWORD, DWORD, OVERLAPPED*, void*, DWORD) TransmitFile;
- bool function (socket_t, void*, int, void*, DWORD, DWORD*, OVERLAPPED*) ConnectEx;
- //char* inet_ntop(int af, void *src, char *dst, int len);
- }
- private __gshared HMODULE lib;
- shared static this()
- {
- lib = LoadLibraryA ("Ws2_32.dll");
- getnameinfo = cast(typeof(getnameinfo)) GetProcAddress(lib, "getnameinfo");
- if (!getnameinfo)
- {
- FreeLibrary (lib);
- lib = LoadLibraryA ("Wship6.dll");
- }
- getnameinfo = cast(typeof(getnameinfo)) GetProcAddress(lib, "getnameinfo");
- getaddrinfo = cast(typeof(getaddrinfo)) GetProcAddress(lib, "getaddrinfo");
- freeaddrinfo = cast(typeof(freeaddrinfo)) GetProcAddress(lib, "freeaddrinfo");
- if (!getnameinfo)
- {
- FreeLibrary (lib);
- lib = null;
- }
- WSADATA wd = void;
- if (WSAStartup (0x0202, &wd))
- throw new SocketException("version of socket library is too old");
- DWORD result;
- Guid acceptG = {0xb5367df1, 0xcbac, 0x11cf, [0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
- Guid connectG = {0x25a207b9, 0xddf3, 0x4660, [0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e]};
- Guid transmitG = {0xb5367df0, 0xcbac, 0x11cf, [0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
- auto s = cast(HANDLE) socket (AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
- assert (s != cast(HANDLE) -1);
- WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
- &connectG, connectG.sizeof, &ConnectEx,
- ConnectEx.sizeof, &result, null, null);
- WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
- &acceptG, acceptG.sizeof, &AcceptEx,
- AcceptEx.sizeof, &result, null, null);
- WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
- &transmitG, transmitG.sizeof, &TransmitFile,
- TransmitFile.sizeof, &result, null, null);
- closesocket (cast(socket_t)(cast(int)s));
- }
- shared static ~this()
- {
- if (lib)
- FreeLibrary (lib);
- WSACleanup();
- }
- }
- else
- {
- private import tango.stdc.errno;
- //private alias int socket_t = -1;
- enum socket_t: int
- {
- init = -1
- }
- package extern (C)
- {
- socket_t socket(int af, int type, int protocol);
- int fcntl(socket_t s, int f, ...);
- uint inet_addr(const(char)* cp);
- int bind(socket_t s, const(Address.sockaddr)* name, int namelen);
- int connect(socket_t s, const(Address.sockaddr)* name, int namelen);
- int listen(socket_t s, int backlog);
- socket_t accept(socket_t s, Address.sockaddr* addr, int* addrlen);
- int close(socket_t s);
- int shutdown(socket_t s, int how);
- int getpeername(socket_t s, Address.sockaddr* name, int* namelen);
- int getsockname(socket_t s, Address.sockaddr* name, int* namelen);
- int send(socket_t s, const(void)* buf, size_t len, int flags);
- int sendto(socket_t s, const(void)* buf, size_t len, int flags, Address.sockaddr* to, int tolen);
- int recv(socket_t s, void* buf, size_t len, int flags);
- int recvfrom(socket_t s, void* buf, size_t len, int flags, Address.sockaddr* from, int* fromlen);
- int select(int nfds, SocketSet.fd* readfds, SocketSet.fd* writefds, SocketSet.fd* errorfds, SocketSet.timeval* timeout);
- int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
- int setsockopt(socket_t s, int level, int optname, const(void)* optval, int optlen);
- int gethostname(void* namebuffer, int buflen);
- char* inet_ntoa(uint ina);
- NetHost.hostent* gethostbyname(const(char)* name);
- NetHost.hostent* gethostbyaddr(const(void)* addr, int len, int type);
- /**
- Given node and service, which identify an Internet host and a service,
- getaddrinfo() returns one or more addrinfo structures, each of which
- contains an Internet address that can be specified in a call to bind or
- connect. The getaddrinfo() function combines the functionality provided
- by the getservbyname and getservbyport functions into a single interface,
- but unlike the latter functions, getaddrinfo() is reentrant and allows
- programs to eliminate IPv4-versus-IPv6 dependencies. (C) MAN
- */
- int getaddrinfo(const(char)* node, const(char)* service, Address.addrinfo* hints, Address.addrinfo** res);
- /**
- The freeaddrinfo() function frees the memory that was allocated for the
- dynamically allocated linked list res. (C) MAN
- */
- void freeaddrinfo(Address.addrinfo *res);
- /**
- The getnameinfo() function is the inverse of getaddrinfo: it converts a socket
- address to a corresponding host and service, in a protocol-independent manner.
- It combines the functionality of gethostbyaddr and getservbyport, but unlike
- those functions, getaddrinfo is reentrant and allows programs to eliminate
- IPv4-versus-IPv6 dependencies. (C) MAN
- */
- int getnameinfo(Address.sockaddr* sa, int salen, char* host, int hostlen, char* serv, int servlen, int flags);
- /**
- The gai_strerror function translates error codes of getaddrinfo, freeaddrinfo
- and getnameinfo to a human readable string, suitable for error reporting. (C) MAN
- */
- const(char)* gai_strerror(int errcode);
- const(char)* inet_ntop(int af, const(void) *src, char *dst, int len);
- }
- }
- /*******************************************************************************
- *******************************************************************************/
- public struct Berkeley
- {
- socket_t sock;
- SocketType type;
- AddressFamily family;
- ProtocolType protocol;
- version (Windows)
- bool synchronous;
- enum INVALID_SOCKET = socket_t.init;
- enum
- {
- Error = -1
- }
- alias Error ERROR; // backward compatibility
- alias noDelay setNoDelay; // backward compatibility
- alias addressReuse setAddressReuse; // backward compatibility
- /***********************************************************************
- Configure this instance
- ***********************************************************************/
- void open (AddressFamily family, SocketType type, ProtocolType protocol, bool create=true)
- {
- this.type = type;
- this.family = family;
- this.protocol = protocol;
- if (create)
- reopen();
- }
- /***********************************************************************
- Open/reopen a native socket for this instance
- ***********************************************************************/
- void reopen (socket_t sock = sock.init)
- {
- if (this.sock != sock.init)
- 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;
- }
- /***********************************************************************
- calling shutdown() before this is recommended for connection-
- oriented sockets
- ***********************************************************************/
- void detach ()
- {
- if (sock != sock.init)
- .close (sock);
- sock = sock.init;
- }
- /***********************************************************************
- Return the underlying OS handle of this Conduit
- ***********************************************************************/
- @property const socket_t handle ()
- {
- return sock;
- }
- /***********************************************************************
- Return socket error status
- ***********************************************************************/
- @property const int error ()
- {
- int errcode;
- getOption (SocketOptionLevel.SOCKET, SocketOption.ERROR, (&errcode)[0..1]);
- return errcode;
- }
- /***********************************************************************
- Return the last error
- ***********************************************************************/
- @property static int lastError ()
- {
- version (Win32)
- return WSAGetLastError();
- else
- return errno;
- }
- /***********************************************************************
- Is this socket still alive? A closed socket is considered to
- be dead, but a shutdown socket is still alive.
- ***********************************************************************/
- @property const bool isAlive ()
- {
- int type, typesize = type.sizeof;
- return getsockopt (sock, SocketOptionLevel.SOCKET,
- SocketOption.TYPE, cast(char*) &type,
- &typesize) != Error;
- }
- /***********************************************************************
- ***********************************************************************/
- @property AddressFamily addressFamily ()
- {
- return family;
- }
- /***********************************************************************
- ***********************************************************************/
- Berkeley* bind (Address addr)
- {
- if(Error == .bind (sock, addr.name, addr.nameLen))
- exception ("Unable to bind socket: ");
- return &this;
- }
- /***********************************************************************
- ***********************************************************************/
- Berkeley* connect (Address to)
- {
- if (Error == .connect (sock, to.name, to.nameLen))
- {
- if (! blocking)
- {
- auto err = lastError;
- version (Windows)
- {
- if (err is WSAEWOULDBLOCK)
- return &this;
- }
- else
- {
- if (err is EINPROGRESS)
- return &this;
- }
- }
- exception ("Unable to connect socket: ");
- }
- return &this;
- }
- /***********************************************************************
- need to bind() first
- ***********************************************************************/
- Berkeley* listen (int backlog)
- {
- if (Error == .listen (sock, backlog))
- exception ("Unable to listen on socket: ");
- return &this;
- }
- /***********************************************************************
- need to bind() first
- ***********************************************************************/
- void accept (ref Berkeley target)
- {
- auto newsock = .accept (sock, null, null);
- if (socket_t.init is newsock)
- exception ("Unable to accept socket connection: ");
- target.reopen (newsock);
- target.protocol = protocol; //same protocol
- target.family = family; //same family
- target.type = type; //same type
- }
- /***********************************************************************
- 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.
- ***********************************************************************/
- Berkeley* shutdown (SocketShutdown how)
- {
- .shutdown (sock, how);
- return &this;
- }
- /***********************************************************************
- set linger timeout
- ***********************************************************************/
- @property Berkeley* linger (int period)
- {
- version (Win32)
- alias ushort attr;
- else
- alias uint attr;
- union linger
- {
- struct {
- attr l_onoff; // option on/off
- attr l_linger; // linger time
- };
- attr[2] array; // combined
- }
- linger l;
- l.l_onoff = 1; // option on/off
- l.l_linger = cast(ushort) period; // linger time
- return setOption (SocketOptionLevel.SOCKET, SocketOption.LINGER, l.array);
- }
- /***********************************************************************
- enable/disable address reuse
- ***********************************************************************/
- @property Berkeley* addressReuse (bool enabled)
- {
- int[1] x = enabled;
- return setOption (SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, x);
- }
- /***********************************************************************
- enable/disable noDelay option (nagle)
- ***********************************************************************/
- @property Berkeley* noDelay (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.
- ***********************************************************************/
- 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.ADD_MEMBERSHIP : SocketOption.DROP_MEMBERSHIP;
- mrq.imr_interface = 0;
- mrq.imr_multiaddr = address.sin.sin_addr;
- if (.setsockopt(sock, SocketOptionLevel.IP, option, &mrq, mrq.sizeof) == Error)
- exception ("Unable to perform multicast join: ");
- }
- /***********************************************************************
- ***********************************************************************/
- const Address newFamilyObject ()
- {
- if (family is AddressFamily.INET)
- return new IPv4Address;
- if (family is AddressFamily.INET6)
- return new IPv6Address;
- return new UnknownAddress;
- }
- /***********************************************************************
- return the hostname
- ***********************************************************************/
- @property static char[] hostName ()
- {
- char[64] name;
- if(Error == .gethostname (name.ptr, name.length))
- exception ("Unable to obtain host name: ");
- return name [0 .. strlen(name.ptr)].dup;
- }
- /***********************************************************************
- return the default host address (IPv4)
- ***********************************************************************/
- @property static uint hostAddress ()
- {
- auto ih = new NetHost;
- ih.getHostByName (hostName);
- assert (ih.addrList.length);
- return ih.addrList[0];
- }
- /***********************************************************************
- return the remote address of the current connection (IPv4)
- ***********************************************************************/
- @property const Address remoteAddress ()
- {
- auto addr = newFamilyObject();
- auto nameLen = addr.nameLen;
- if(Error == .getpeername (sock, addr.name, &nameLen))
- exception ("Unable to obtain remote socket address: ");
- assert (addr.addressFamily is family);
- return addr;
- }
- /***********************************************************************
- return the local address of the current connection (IPv4)
- ***********************************************************************/
- @property const Address localAddress ()
- {
- auto addr = newFamilyObject();
- auto nameLen = addr.nameLen;
- if(Error == .getsockname (sock, addr.name, &nameLen))
- exception ("Unable to obtain local socket address: ");
- assert (addr.addressFamily is family);
- return addr;
- }
- /***********************************************************************
- 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
- ***********************************************************************/
- const int send (const(void)[] buf, SocketFlags flags=SocketFlags.NONE)
- {
- if (buf.length is 0)
- return 0;
- version (Posix)
- {
- auto ret = .send (sock, buf.ptr, buf.length,
- SocketFlags.NOSIGNAL + cast(int) flags);
- if (errno is EPIPE)
- ret = -1;
- return ret;
- }
- else
- 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.
- ***********************************************************************/
- const int sendTo (const(void)[] buf, SocketFlags flags, Address to)
- {
- return sendTo (buf, cast(int) flags, to.name, to.nameLen);
- }
- /***********************************************************************
- ditto
- ***********************************************************************/
- const int sendTo (const(void)[] buf, Address to)
- {
- return sendTo (buf, SocketFlags.NONE, to);
- }
- /***********************************************************************
- ditto - assumes you connect()ed
- ***********************************************************************/
- const int sendTo (const(void)[] buf, SocketFlags flags=SocketFlags.NONE)
- {
- return sendTo (buf, cast(int) flags, null, 0);
- }
- /***********************************************************************
- 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.
- ***********************************************************************/
- private const int sendTo (const(void)[] buf, int flags, Address.sockaddr* to, int len)
- {
- if (buf.length is 0)
- return 0;
- version (Posix)
- {
- auto ret = .sendto (sock, buf.ptr, buf.length,
- flags | SocketFlags.NOSIGNAL, to, len);
- if (errno is EPIPE)
- ret = -1;
- return ret;
- }
- else
- return .sendto (sock, buf.ptr, buf.length, flags, to, len);
- }
- /***********************************************************************
- 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
- ***********************************************************************/
- const 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.
- ***********************************************************************/
- const 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
- ***********************************************************************/
- const int receiveFrom (void[] buf, Address from)
- {
- return receiveFrom(buf, SocketFlags.NONE, from);
- }
- /***********************************************************************
- ditto - assumes you connect()ed
- ***********************************************************************/
- const 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()
- ***********************************************************************/
- const int getOption (SocketOptionLevel level, SocketOption option, void[] result)
- {
- int len = cast(int) result.length;
- if(Error == .getsockopt (sock, cast(int)level, cast(int)option, result.ptr, &len))
- exception ("Unable to get socket option: ");
- return len;
- }
- /***********************************************************************
- ***********************************************************************/
- Berkeley* setOption (SocketOptionLevel level, SocketOption option, const(void)[] value)
- {
- if(Error == .setsockopt (sock, cast(int)level, cast(int)option, value.ptr, cast(int) value.length))
- exception ("Unable to set socket option: ");
- return &this;
- }
- /***********************************************************************
- getter
- ***********************************************************************/
- @property const bool blocking()
- {
- version (Windows)
- return synchronous;
- else
- return !(fcntl(sock, F_GETFL, 0) & O_NONBLOCK);
- }
- /***********************************************************************
- setter
- ***********************************************************************/
- @property void blocking(bool yes)
- {
- version (Windows)
- {
- uint num = !yes;
- if(ioctlsocket(sock, consts.FIONBIO, &num) is ERROR)
- exception("Unable to set socket blocking: ");
- synchronous = yes;
- }
- else
- {
- int x = fcntl(sock, F_GETFL, 0);
- if(yes)
- x &= ~O_NONBLOCK;
- else
- x |= O_NONBLOCK;
- if(fcntl(sock, F_SETFL, x) is ERROR)
- exception("Unable to set socket blocking: ");
- }
- return;
- }
- /***********************************************************************
- ***********************************************************************/
- static void exception (immutable(char)[] msg)
- {
- throw new SocketException (msg ~ SysError.lookup(lastError).idup);
- }
- /***********************************************************************
- ***********************************************************************/
- protected static void badArg (immutable(char)[] msg)
- {
- throw new IllegalArgumentException (msg);
- }
- }
- /*******************************************************************************
- *******************************************************************************/
- public abstract class Address
- {
- public struct sockaddr
- {
- ushort sa_family;
- char[14] sa_data = 0;
- }
- struct addrinfo
- {
- int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- uint ai_addrlen;
- version (FreeBSD)
- {
- char* ai_canonname;
- sockaddr* ai_addr;
- }
- else
- {
- sockaddr* ai_addr;
- char* ai_canonname;
- }
- addrinfo* ai_next;
- }
- @property abstract sockaddr* name();
- @property abstract const int nameLen();
- /***********************************************************************
- Internal usage
- ***********************************************************************/
- private static ushort ntohs (ushort x)
- {
- return htons(x);
- }
- /***********************************************************************
- Internal usage
- ***********************************************************************/
- private static uint ntohl (uint x)
- {
- return htonl(x);
- }
- /***********************************************************************
- Internal usage
- ***********************************************************************/
- private static char[] fromInt (char[] tmp, int i)
- {
- size_t j = tmp.length;
- do {
- tmp[--j] = cast(char)(i % 10 + '0');
- } while (i /= 10);
- return tmp [j .. $];
- }
- /***********************************************************************
- Internal usage
- ***********************************************************************/
- private static int toInt (const(char)[] s)
- {
- uint value;
- foreach (c; s)
- if (c >= '0' && c <= '9')
- value = value * 10 + (c - '0');
- else
- break;
- return value;
- }
- /***********************************************************************
- Tango: added this common function
- ***********************************************************************/
- static void exception (immutable(char)[] msg)
- {
- throw new SocketException (msg);
- }
- /***********************************************************************
- Address factory
- ***********************************************************************/
- static Address create (sockaddr* sa)
- {
- switch (sa.sa_family)
- {
- case AddressFamily.INET:
- return new IPv4Address(sa);
- case AddressFamily.INET6:
- return new IPv6Address(sa);
- default:
- return null;
- }
- }
- /***********************************************************************
- ***********************************************************************/
- static Address resolve (const(char)[] host, const(char)[] service = null,
- AddressFamily af = AddressFamily.UNSPEC,
- AIFlags flags = cast(AIFlags)0)
- {
- return resolveAll (host, service, af, flags)[0];
- }
- /***********************************************************************
- ***********************************************************************/
- static Address resolve (const(char)[] host, ushort port,
- AddressFamily af = AddressFamily.UNSPEC,
- AIFlags flags = cast(AIFlags)0)
- {
- return resolveAll (host, port, af, flags)[0];
- }
- /***********************************************************************
- ***********************************************************************/
- static Address[] resolveAll (const(char)[] host, const(char)[] service = null,
- AddressFamily af = AddressFamily.UNSPEC,
- AIFlags flags = cast(AIFlags)0)
- {
- Address[] retVal;
- version (Win32)
- {
- if (!getaddrinfo)
- { // *old* windows, let's fall back to NetHost
- uint port = toInt(service);
- if (flags & AIFlags.PASSIVE && host is null)
- return [new IPv4Address(0, cast(ushort)port)];
- auto nh = new NetHost;
- if (!nh.getHostByName(host))
- throw new AddressException("couldn't resolve " ~ host.idup);
- retVal.length = nh.addrList.length;
- foreach (i, addr; nh.addrList)
- retVal[i] = new IPv4Address(addr, cast(ushort)port);
- return retVal;
- }
- }
- addrinfo* info;
- addrinfo hints;
- hints.ai_flags = flags;
- hints.ai_family = (flags & AIFlags.PASSIVE && af == AddressFamily.UNSPEC) ? AddressFamily.INET6 : af;
- hints.ai_socktype = SocketType.STREAM;
- int error = getaddrinfo(toStringz(host), service.length == 0 ? null : toStringz(service), &hints, &info);
- if (error != 0)
- throw new AddressException("couldn't resolve " ~ host.idup);
- retVal.length = 16;
- retVal.length = 0;
- while (info)
- {
- if (auto addr = create(info.ai_addr))
- retVal ~= addr;
- info = info.ai_next;
- }
- freeaddrinfo (info);
- return retVal;
- }
- /***********************************************************************
- ***********************************************************************/
- static Address[] resolveAll (const(char)[] host, ushort port,
- AddressFamily af = AddressFamily.UNSPEC,
- AIFlags flags = cast(AIFlags)0)
- {
- char[16] buf;
- return resolveAll (host, fromInt(buf, port), af, flags);
- }
- /***********************************************************************
- ***********************************************************************/
- static Address passive (const(char)[] service,
- AddressFamily af = AddressFamily.UNSPEC,
- AIFlags flags = cast(AIFlags)0)
- {
- return resolve (null, service, af, flags | AIFlags.PASSIVE);
- }
- /***********************************************************************
- ***********************************************************************/
- static Address passive (ushort port, AddressFamily af = AddressFamily.UNSPEC,
- AIFlags flags = cast(AIFlags)0)
- {
- return resolve (null, port, af, flags | AIFlags.PASSIVE);
- }
- /***********************************************************************
- ***********************************************************************/
- @property char[] toAddrString()
- {
- char[1025] host = void;
- // Getting name info. Don't look up hostname, returns
- // numeric name. (NIFlags.NUMERICHOST)
- getnameinfo (name, nameLen, host.ptr, host.length, null, 0, NIFlags.NUMERICHOST);
- return fromStringz (host.ptr).dup;
- }
- /***********************************************************************
- ***********************************************************************/
- @property char[] toPortString()
- …
Large files files are truncated, but you can click here to view the full file