rename `NativeString` to `CString`
[nit.git] / lib / socket / socket_c.nit
index 1d56bcb..1486752 100644 (file)
@@ -28,28 +28,24 @@ in "C Header" `{
        #include <arpa/inet.h>
        #include <netdb.h>
        #include <sys/poll.h>
+`}
 
-       typedef int S_DESCRIPTOR;
-       typedef struct sockaddr_in S_ADDR_IN;
-       typedef struct sockaddr S_ADDR;
-       typedef struct in_addr S_IN_ADDR;
-       typedef struct hostent S_HOSTENT;
-       typedef struct timeval S_TIMEVAL;
-       typedef struct sockaccept_result { S_ADDR_IN addr_in; S_DESCRIPTOR s_desc; } S_ACCEPT_RESULT;
-       typedef fd_set S_FD_SET;
-       typedef socklen_t S_LEN;
+in "C" `{
+       #include <fcntl.h>
+       #include <netinet/tcp.h>
 `}
 
 # Wrapper for the data structure PollFD used for polling on a socket
 class PollFD
+       super FinalizableOnce
 
        # The PollFD object
-       private var poll_struct: FFSocketPollFD
+       private var poll_struct: NativeSocketPollFD
 
        # A collection of the events to be watched
-       var events: Array[FFSocketPollValues]
+       var events: Array[NativeSocketPollValues]
 
-       init(pid: Int, events: Array[FFSocketPollValues])
+       init(pid: Int, events: Array[NativeSocketPollValues])
        do
                assert events.length >= 1
                self.events = events
@@ -60,13 +56,13 @@ class PollFD
                        events_in_one += events[i]
                end
 
-               self.poll_struct = new FFSocketPollFD(pid, events_in_one)
+               self.poll_struct = new NativeSocketPollFD(pid, events_in_one)
        end
 
        # Reads the response and returns an array with the type of events that have been found
-       private fun check_response(response: Int): Array[FFSocketPollValues]
+       private fun check_response(response: Int): Array[NativeSocketPollValues]
        do
-               var resp_array = new Array[FFSocketPollValues]
+               var resp_array = new Array[NativeSocketPollValues]
                for i in events do
                        if c_check_resp(response, i) != 0 then
                                resp_array.push(i)
@@ -76,88 +72,113 @@ class PollFD
        end
 
        # Checks if the poll call has returned true for a particular type of event
-       private fun c_check_resp(response: Int, mask: FFSocketPollValues): Int
+       private fun c_check_resp(response: Int, mask: NativeSocketPollValues): Int
        `{
                return response & mask;
        `}
 
+       redef fun finalize_once
+       do
+               poll_struct.free
+       end
 end
 
 # Data structure used by the poll function
-private extern FFSocketPollFD `{ struct pollfd `}
-       # File descriptor id
-       private fun fd: Int `{ return recv.fd; `}
+private extern class NativeSocketPollFD `{ struct pollfd * `}
+
+       # File descriptor
+       fun fd: Int `{ return self->fd; `}
+
        # List of events to be watched
-       private fun events: Int `{ return recv.events; `}
+       fun events: Int `{ return self->events; `}
+
        # List of events received by the last poll function
-       private fun revents: Int `{  return recv.revents; `}
+       fun revents: Int `{  return self->revents; `}
 
-       new (pid: Int, events: FFSocketPollValues) `{
-               struct pollfd poll;
-               poll.fd = pid;
-               poll.events = events;
+       new (pid: Int, events: NativeSocketPollValues) `{
+               struct pollfd *poll = malloc(sizeof(struct pollfd));
+               poll->fd = pid;
+               poll->events = events;
                return poll;
        `}
-
 end
 
-extern FFSocket `{ S_DESCRIPTOR* `}
-       new socket(domain: FFSocketAddressFamilies, socketType: FFSocketTypes, protocol: FFSocketProtocolFamilies) `{
-               S_DESCRIPTOR *d = NULL; d = (S_DESCRIPTOR*) malloc( sizeof(S_DESCRIPTOR) );
+extern class NativeSocket `{ int* `}
+
+       new socket(domain: NativeSocketAddressFamilies, socketType: NativeSocketTypes, protocol: NativeSocketProtocolFamilies) `{
                int ds = socket(domain, socketType, protocol);
                if(ds == -1){
-                       free(d);
                        return NULL;
                }
+               int *d = malloc(sizeof(int));
                memcpy(d, &ds, sizeof(ds));
                return d;
        `}
-       fun destroy `{ free(recv); `}
-       fun close: Int `{ return close( *recv ); `}
-       fun descriptor: Int `{ return *recv; `}
-
-       fun gethostbyname(n: String): FFSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
-       fun connect(addrIn: FFSocketAddrIn): Int `{ return connect( *recv, (S_ADDR*)addrIn, sizeof(*addrIn) ); `}
-       fun write(buffer: String): Int import String.to_cstring, String.length `{ return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer)); `}
-
-       fun read: String import NativeString.to_s_with_length `{
-               static char c[1024];
-               int n = read(*recv, c, 1024);
-               if(n < 0) {
-                       return NativeString_to_s_with_length("",0);
-               }
-               char* ret = malloc(n + 1);
-               memcpy(ret, c, n);
-               ret[n] = '\0';
-               return NativeString_to_s_with_length(ret, n);
+
+       fun destroy `{ free(self); `}
+
+       fun close: Int `{ return close(*self); `}
+
+       fun descriptor: Int `{ return *self; `}
+
+       fun connect(addrIn: NativeSocketAddrIn): Int `{
+               return connect(*self, (struct sockaddr*)addrIn, sizeof(*addrIn));
+       `}
+
+       # Write `length` bytes from `buffer`
+       fun write(buffer: CString, length: Int): Int `{
+               return write(*self, buffer, length);
+       `}
+
+       # Write `value` as a single byte
+       fun write_byte(value: Byte): Int `{
+               unsigned char byt = (unsigned char)value;
+               return write(*self, &byt, 1);
+       `}
+
+       # Read `length` bytes into `buffer`, returns the number of bytes read
+       fun read(buffer: CString, length: Int): Int `{
+               return read(*self, buffer, length);
        `}
 
        # Sets an option for the socket
-       fun setsockopt(level: FFSocketOptLevels, option_name: FFSocketOptNames, option_value: Int) `{
-               int err = setsockopt(*recv, level, option_name, &option_value, sizeof(int));
+       #
+       # Returns `true` on success.
+       fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int): Bool `{
+               int err = setsockopt(*self, level, option_name, &option_value, sizeof(int));
                if(err != 0){
-                       perror("Error on setsockopts : ");
-                       exit(1);
+                       return 0;
                }
+               return 1;
        `}
 
-       fun bind(addrIn: FFSocketAddrIn): Int `{ return bind(*recv, (S_ADDR*)addrIn, sizeof(*addrIn)); `}
-       fun listen(size: Int): Int `{ return listen(*recv, size); `}
+       fun bind(addrIn: NativeSocketAddrIn): Int `{ return bind(*self, (struct sockaddr*)addrIn, sizeof(*addrIn)); `}
+
+       fun listen(size: Int): Int `{ return listen(*self, size); `}
 
        # Checks if the buffer is ready for any event specified when creating the pollfd structure
-       fun socket_poll(filedesc: PollFD, timeout: Int): Array[FFSocketPollValues]
+       fun socket_poll(filedesc: PollFD, timeout: Int): Array[NativeSocketPollValues]
        do
-               var result = i_poll(filedesc.poll_struct, timeout)
+               var result = native_poll(filedesc.poll_struct, timeout)
                assert result != -1
                return filedesc.check_response(result)
        end
 
+       # Poll this socket with `POLLHUP|POLLERR`
+       #
+       # A return value of 0 means there is no errors.
+       fun poll_hup_err: Int `{
+               struct pollfd fd = {*self, POLLHUP|POLLERR, 0};
+               int res = poll(&fd, 1, 0);
+               return res;
+       `}
+
        # Call to the poll function of the C socket
        #
-       # Signature :
+       # Signature:
        # int poll(struct pollfd fds[], nfds_t nfds, int timeout);
        #
-       # Official documentation of the poll function :
+       # Official documentation of the poll function:
        #
        # The poll() function provides applications with a mechanism for multiplexing input/output over a set of file descriptors.
        # For each member of the array pointed to by fds, poll() shall examine the given file descriptor for the event(s) specified in events.
@@ -167,147 +188,235 @@ extern FFSocket `{ S_DESCRIPTOR* `}
        # It is a pointer to an array with one member for each open file descriptor of interest.
        # The array's members are pollfd structures within which fd specifies an open file descriptor and events and revents are bitmasks constructed by
        # OR'ing a combination of the pollfd flags.
-       private fun i_poll(filedesc: FFSocketPollFD, timeout: Int): Int `{
-               int poll_return = poll(&filedesc, 1, timeout);
+       private fun native_poll(filedesc: NativeSocketPollFD, timeout: Int): Int `{
+               int poll_return = poll(filedesc, 1, timeout);
                return poll_return;
        `}
 
-       private fun i_accept(addrIn: FFSocketAddrIn): FFSocket `{
-               S_LEN s = sizeof(S_ADDR);
-               S_DESCRIPTOR *d = NULL;
-               d = malloc(sizeof(S_DESCRIPTOR));
-               *d = accept(*recv,(S_ADDR*)addrIn, &s);
-               return d;
+       private fun native_accept(addr_in: NativeSocketAddrIn): NativeSocket `{
+               socklen_t s = sizeof(struct sockaddr);
+               int socket = accept(*self, (struct sockaddr*)addr_in, &s);
+               if (socket == -1) return NULL;
+
+               int *ptr = malloc(sizeof(int));
+               *ptr = socket;
+               return ptr;
        `}
-       fun accept: FFSocketAcceptResult
+
+       fun accept: nullable SocketAcceptResult
        do
-               var addrIn = new FFSocketAddrIn
-               var s = i_accept(addrIn)
-               return new FFSocketAcceptResult(s, addrIn)
+               var addrIn = new NativeSocketAddrIn
+               var s = native_accept(addrIn)
+               if s.address_is_null then return null
+               return new SocketAcceptResult(s, addrIn)
        end
-end
 
-extern FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
-       new (socket: FFSocket, addrIn: FFSocketAddrIn) `{
-               S_ACCEPT_RESULT *sar = NULL;
-               sar = malloc( sizeof(S_ACCEPT_RESULT) );
-               sar->s_desc = *socket;
-               sar->addr_in = *addrIn;
-               return sar;
+       # Set whether this socket is non blocking
+       fun non_blocking=(value: Bool) `{
+               int flags = fcntl(*self, F_GETFL, 0);
+               if (flags == -1) flags = 0;
+
+               if (value) {
+                       flags = flags | O_NONBLOCK;
+               } else if (flags & O_NONBLOCK) {
+                       flags = flags - O_NONBLOCK;
+               } else {
+                       return;
+               }
+               fcntl(*self, F_SETFL, flags);
+       `}
+
+       # Send `len` bytes from `buf` to `dest_addr`
+       fun sendto(buf: CString, len: Int, flags: Int, dest_addr: NativeSocketAddrIn): Int `{
+               return sendto(*self, buf, len, flags, (struct sockaddr*)dest_addr, sizeof(struct sockaddr_in));
        `}
-       fun socket: FFSocket `{ return &recv->s_desc; `}
-       fun addrIn: FFSocketAddrIn `{ return &recv->addr_in; `}
-       fun destroy `{ free(recv); `}
+
+       # Receive a message into `buf` of maximum `len` bytes
+       fun recv(buf: CString, len: Int, flags: Int): Int `{
+               return recv(*self, buf, len, flags);
+       `}
+
+       # Receive a message into `buf` of maximum `len` bytes and store sender info into `src_addr`
+       fun recvfrom(buf: CString, len: Int, flags: Int, src_addr: NativeSocketAddrIn): Int `{
+               socklen_t srclen = sizeof(struct sockaddr_in);
+               return recvfrom(*self, buf, len, flags, (struct sockaddr*)src_addr, &srclen);
+       `}
+end
+
+# Result of a call to `NativeSocket::accept`
+class SocketAcceptResult
+
+       # Opened socket
+       var socket: NativeSocket
+
+       # Address of the remote client
+       var addr_in: NativeSocketAddrIn
 end
 
-extern FFSocketAddrIn `{ S_ADDR_IN* `}
+# Socket address in the Internet namespace, pointer to a `struct sockaddr_in`
+extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
+
+       # `NULL` pointer
+       new nul `{ return NULL; `}
+
+       # `malloc` a new instance
        new `{
-               S_ADDR_IN *sai = NULL;
-               sai = malloc( sizeof(S_ADDR_IN) );
-               return sai;
-       `}
-       new with(port: Int, family: FFSocketAddressFamilies) `{
-               S_ADDR_IN *sai = NULL;
-               sai = malloc( sizeof(S_ADDR_IN) );
-               sai->sin_family = family;
-               sai->sin_port = htons(port);
-               sai->sin_addr.s_addr = INADDR_ANY;
+               struct sockaddr_in *sai = NULL;
+               sai = malloc(sizeof(struct sockaddr_in));
                return sai;
        `}
-       new with_hostent(hostent: FFSocketHostent, port: Int) `{
-               S_ADDR_IN *sai = NULL;
-               sai = malloc( sizeof(S_ADDR_IN) );
-               sai->sin_family = hostent->h_addrtype;
-               sai->sin_port = htons(port);
-               memcpy( (char*)&sai->sin_addr.s_addr, (char*)hostent->h_addr, hostent->h_length );
-               return sai;
+
+       # Set `address` and `family` from `hostent` (to use with `Sys::gethostbyname`)
+       fun fill_from_hostent(hostent: NativeSocketHostent) `{
+               self->sin_family = hostent->h_addrtype;
+               memcpy((char*)&self->sin_addr.s_addr,
+                      (char*)hostent->h_addr,
+                          hostent->h_length);
        `}
-       fun address: String import NativeString.to_s `{ return NativeString_to_s( (char*)inet_ntoa(recv->sin_addr) ); `}
-       fun family: FFSocketAddressFamilies `{ return recv->sin_family; `}
-       fun port: Int `{ return ntohs(recv->sin_port); `}
-       fun destroy `{ free(recv); `}
+
+       # Internet address as then IPV4 numbers-and-dots notation
+       fun address: CString `{ return (char*)inet_ntoa(self->sin_addr); `}
+
+       # Set `address` to `INADDR_ANY`
+       fun address_any `{ self->sin_addr.s_addr = INADDR_ANY; `}
+
+       # Set `address` to `INADDR_BROADCAST`
+       fun address_broadcast `{ self->sin_addr.s_addr = INADDR_BROADCAST; `}
+
+       # Address family
+       fun family: NativeSocketAddressFamilies `{ return self->sin_family; `}
+
+       # Address family
+       fun family=(value: NativeSocketAddressFamilies) `{ self->sin_family = value; `}
+
+       # Port
+       fun port: Int `{ return ntohs(self->sin_port); `}
+
+       # Port
+       fun port=(value: Int) `{ self->sin_port = htons(value); `}
 end
 
-extern FFSocketHostent `{ S_HOSTENT* `}
-       private fun i_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(recv->h_aliases[i]); `}
-       private fun i_h_aliases_reachable(i: Int): Bool `{ return (recv->h_aliases[i] != NULL); `}
+# Host entry information, a pointer to a `struct hostent`
+extern class NativeSocketHostent `{ struct hostent* `}
+       private fun native_h_aliases(i: Int): CString `{
+               return self->h_aliases[i];
+       `}
+
+       # Alternative names for the host
        fun h_aliases: Array[String]
        do
-               var i=0
-               var d=new Array[String]
+               var res = new Array[String]
                loop
-                       d.add(i_h_aliases(i))
-                       if i_h_aliases_reachable(i+1) == false then break
-                       i += 1
+                       var ha = native_h_aliases(res.length)
+                       if ha.address_is_null then break
+                       res.add ha.to_s
                end
-               return d
+               return res
        end
-       fun h_addr: String import NativeString.to_s `{ return NativeString_to_s( (char*)inet_ntoa(*(S_IN_ADDR*)recv->h_addr) ); `}
-       fun h_addrtype: Int `{ return recv->h_addrtype; `}
-       fun h_length: Int `{ return recv->h_length; `}
-       fun h_name: String import NativeString.to_s `{ return NativeString_to_s(recv->h_name); `}
+
+       fun h_addr: CString `{
+               return (char*)inet_ntoa(*(struct in_addr*)self->h_addr);
+       `}
+
+       fun h_addrtype: Int `{ return self->h_addrtype; `}
+
+       fun h_length: Int `{ return self->h_length; `}
+
+       fun h_name: CString `{ return self->h_name; `}
 end
 
-extern FFTimeval `{ S_TIMEVAL* `}
+extern class NativeTimeval `{ struct timeval* `}
        new (seconds: Int, microseconds: Int) `{
-               S_TIMEVAL* tv = NULL;
-               tv = malloc( sizeof(S_TIMEVAL) );
+               struct timeval* tv = NULL;
+               tv = malloc(sizeof(struct timeval));
                tv->tv_sec = seconds;
                tv->tv_usec = microseconds;
                return tv;
        `}
-       fun seconds: Int `{ return recv->tv_sec; `}
-       fun microseconds: Int `{ return recv->tv_usec; `}
-       fun destroy `{ free( recv ); `}
+
+       fun seconds: Int `{ return self->tv_sec; `}
+
+       fun microseconds: Int `{ return self->tv_usec; `}
+
+       fun destroy `{ free(self); `}
 end
 
-extern FFSocketSet `{ S_FD_SET* `}
+extern class NativeSocketSet `{ fd_set* `}
        new `{
-               S_FD_SET *f = NULL;
-               f = malloc( sizeof(S_FD_SET) );
+               fd_set *f = NULL;
+               f = malloc(sizeof(fd_set));
                return f;
        `}
-       fun set(s: FFSocket) `{ FD_SET( *s, recv ); `}
-       fun is_set(s: FFSocket): Bool `{ return FD_ISSET( *s, recv ); `}
-       fun zero `{ FD_ZERO( recv ); `}
-       fun clear(s: FFSocket) `{ FD_CLR( *s, recv ); `}
-       fun destroy `{ free( recv ); `}
+
+       fun set(s: NativeSocket) `{ FD_SET(*s, self); `}
+
+       fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, self); `}
+
+       fun zero `{ FD_ZERO(self); `}
+
+       fun clear(s: NativeSocket) `{ FD_CLR(*s, self); `}
+
+       fun destroy `{ free(self); `}
 end
 
-class FFSocketObserver
-       fun select(max: FFSocket, reads: nullable FFSocketSet, write: nullable FFSocketSet,
-             except: nullable FFSocketSet, timeout: FFTimeval): Int `{
-               S_FD_SET *rds, *wts, *exs = NULL;
-               S_TIMEVAL *tm = NULL;
-               if(reads != NULL) rds = (S_FD_SET*)reads;
-               if(write != NULL) wts = (S_FD_SET*)write;
-               if(except != NULL) exs = (S_FD_SET*)except;
-               if(timeout != NULL) tm = (S_TIMEVAL*)timeout;
+class NativeSocketObserver
+       # FIXME this implementation is broken. `reads`, `write` and `except`
+       # are boxed objects, passing them to a C function is illegal.
+       fun select(max: NativeSocket, reads: nullable NativeSocketSet, write: nullable NativeSocketSet,
+                        except: nullable NativeSocketSet, timeout: NativeTimeval): Int `{
+               fd_set *rds = NULL,
+                      *wts = NULL,
+                      *exs = NULL;
+               struct timeval *tm = NULL;
+               if (reads != NULL) rds = (fd_set*)reads;
+               if (write != NULL) wts = (fd_set*)write;
+               if (except != NULL) exs = (fd_set*)except;
+               if (timeout != NULL) tm = (struct timeval*)timeout;
                return select(*max, rds, wts, exs, tm);
        `}
 end
 
-extern FFSocketTypes `{ int `}
+extern class NativeSocketTypes `{ int `}
        new sock_stream `{ return SOCK_STREAM; `}
        new sock_dgram `{ return SOCK_DGRAM; `}
        new sock_raw `{ return SOCK_RAW; `}
        new sock_seqpacket `{ return SOCK_SEQPACKET; `}
 end
-extern FFSocketAddressFamilies `{ int `}
+
+extern class NativeSocketAddressFamilies `{ int `}
        new af_null `{ return 0; `}
-       new af_unspec `{ return  AF_UNSPEC; `}          # unspecified
-       new af_unix `{ return  AF_UNIX; `}              # local to host (pipes)
-       new af_local `{ return  AF_LOCAL; `}            # backward compatibility
-       new af_inet `{ return  AF_INET; `}              # internetwork: UDP, TCP, etc.
-       new af_sna `{ return  AF_SNA; `}                # IBM SNA
-       new af_decnet `{ return  AF_DECnet; `}          # DECnet
-       new af_route `{ return  AF_ROUTE; `}            # Internal Routing Protocol
-       new af_ipx `{ return  AF_IPX; `}                # Novell Internet Protocol
-       new af_isdn `{ return  AF_ISDN; `}              # Integrated Services Digital Network
-       new af_inet6 `{ return  AF_INET6; `}            # IPv6
-       new af_max `{ return  AF_MAX; `}
+
+       # Unspecified
+       new af_unspec `{ return AF_UNSPEC; `}
+
+       # Local to host (pipes)
+       new af_unix `{ return AF_UNIX; `}
+
+       # For backward compatibility
+       new af_local `{ return AF_LOCAL; `}
+
+       # Internetwork: UDP, TCP, etc.
+       new af_inet `{ return AF_INET; `}
+
+       # IBM SNA
+       new af_sna `{ return AF_SNA; `}
+
+       # DECnet
+       new af_decnet `{ return AF_DECnet; `}
+
+       # Internal Routing Protocol
+       new af_route `{ return AF_ROUTE; `}
+
+       # Novell Internet Protocol
+       new af_ipx `{ return AF_IPX; `}
+
+       # IPv6
+       new af_inet6 `{ return AF_INET6; `}
+
+       new af_max `{ return AF_MAX; `}
 end
-extern FFSocketProtocolFamilies `{ int `}
+
+extern class NativeSocketProtocolFamilies `{ int `}
        new pf_null `{ return 0; `}
        new pf_unspec `{ return PF_UNSPEC; `}
        new pf_local `{ return PF_LOCAL; `}
@@ -317,48 +426,141 @@ extern FFSocketProtocolFamilies `{ int `}
        new pf_decnet `{ return PF_DECnet; `}
        new pf_route `{ return PF_ROUTE; `}
        new pf_ipx `{ return PF_IPX; `}
-       new pf_isdn `{ return PF_ISDN; `}
        new pf_key `{ return PF_KEY; `}
        new pf_inet6 `{ return PF_INET6; `}
        new pf_max `{ return PF_MAX; `}
+       new ipproto_udp `{ return IPPROTO_UDP; `}
 end
+
 # Level on which to set options
-extern FFSocketOptLevels `{ int `}
+extern class NativeSocketOptLevels `{ int `}
+
        # Dummy for IP (As defined in C)
        new ip `{ return IPPROTO_IP;`}
+
        # Control message protocol
        new icmp `{ return IPPROTO_ICMP;`}
+
        # Use TCP
        new tcp `{ return IPPROTO_TCP; `}
+
        # Socket level options
        new socket `{ return SOL_SOCKET; `}
 end
+
 # Options for socket, use with setsockopt
-extern FFSocketOptNames `{ int `}
+extern class NativeSocketOptNames `{ int `}
+
        # Enables debugging information
        new debug `{ return SO_DEBUG; `}
+
        # Authorizes the broadcasting of messages
        new broadcast `{ return SO_BROADCAST; `}
+
        # Authorizes the reuse of the local address
        new reuseaddr `{ return SO_REUSEADDR; `}
+
        # Authorizes the use of keep-alive packets in a connection
        new keepalive `{ return SO_KEEPALIVE; `}
+
+       # Disable the Nagle algorithm and send data as soon as possible, in smaller packets
+       new tcp_nodelay `{ return TCP_NODELAY; `}
 end
+
 # Used for the poll function of a socket, mix several Poll values to check for events on more than one type of event
-extern FFSocketPollValues `{ int `}
-       new pollin `{ return POLLIN; `}           # Data other than high-priority data may be read without blocking.
-       new pollrdnorm `{ return POLLRDNORM; `}   # Normal data may be read without blocking.
-       new pollrdband `{ return POLLRDBAND; `}   # Priority data may be read without blocking.
-       new pollpri `{ return POLLPRI; `}         # High-priority data may be read without blocking.
-       new pollout `{ return POLLOUT; `}         # Normal data may be written without blocking.
-       new pollwrnorm `{ return POLLWRNORM; `}   # Equivalent to POLLOUT
-       new pollwrband `{ return POLLWRBAND; `}   # Priority data may be written.
-       new pollerr `{ return POLLERR; `}         # An error has occurred on the device or stream. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
-       new pollhup `{ return POLLHUP; `}         # The device has been disconnected. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
-       new pollnval `{ return POLLNVAL; `}       # The specified fd value is invalid. This flag is only valid in the revents member; it shall ignored in the events member.
-
-       # Combines two FFSocketPollValues
-       private fun +(other: FFSocketPollValues): FFSocketPollValues `{
-               return recv | other;
+extern class NativeSocketPollValues `{ int `}
+
+       # Data other than high-priority data may be read without blocking.
+       new pollin `{ return POLLIN; `}
+
+       # Normal data may be read without blocking.
+       new pollrdnorm `{ return POLLRDNORM; `}
+
+       # Priority data may be read without blocking.
+       new pollrdband `{ return POLLRDBAND; `}
+
+       # High-priority data may be read without blocking.
+       new pollpri `{ return POLLPRI; `}
+
+       # Normal data may be written without blocking.
+       new pollout `{ return POLLOUT; `}
+
+       # Equivalent to POLLOUT
+       new pollwrnorm `{ return POLLWRNORM; `}
+
+       # Priority data may be written.
+       new pollwrband `{ return POLLWRBAND; `}
+
+       # An error has occurred on the device or stream.
+       #
+       # This flag is only valid in the revents bitmask; it shall be ignored in the events member.
+       new pollerr `{ return POLLERR; `}
+
+       # The device has been disconnected.
+       #
+       # This event and POLLOUT are mutually-exclusive; a stream can never be
+       # writable if a hangup has occurred. However, this event and POLLIN,
+       # POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive.
+       #
+       # This flag is only valid in the revents bitmask; it shall be ignored in the events member.
+       new pollhup `{ return POLLHUP; `}
+
+       # The specified fd value is invalid.
+       #
+       # This flag is only valid in the revents member; it shall ignored in the events member.
+       new pollnval `{ return POLLNVAL; `}
+
+       # Combines two NativeSocketPollValues
+       private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{
+               return self | other;
+       `}
+end
+
+redef class Sys
+       # Get network host entry
+       fun gethostbyname(name: CString): NativeSocketHostent `{
+               return gethostbyname(name);
        `}
+
+       # Last error raised by `gethostbyname`
+       fun h_errno: HErrno `{ return h_errno; `}
+end
+
+# Error code of `Sys::h_errno`
+extern class HErrno `{ int `}
+       # The specified host is unknown
+       fun host_not_found: Bool `{ return self == HOST_NOT_FOUND; `}
+
+       # The requested name is valid but does not have an IP address
+       #
+       # Same as `no_data`.
+       fun no_address: Bool `{ return self == NO_ADDRESS; `}
+
+       # The requested name is valid byt does not have an IP address
+       #
+       # Same as `no_address`.
+       fun no_data: Bool `{ return self == NO_DATA; `}
+
+       # A nonrecoverable name server error occurred
+       fun no_recovery: Bool `{ return self == NO_RECOVERY; `}
+
+       # A temporary error occurred on an authoritative name server, try again later
+       fun try_again: Bool `{ return self == TRY_AGAIN; `}
+
+       redef fun to_s
+       do
+               if host_not_found then
+                       return "The specified host is unknown"
+               else if no_address then
+                       return "The requested name is valid but does not have an IP address"
+               else if no_recovery then
+                       return "A nonrecoverable name server error occurred"
+               else if try_again then
+                       return "A temporary error occurred on an authoritative name server, try again later"
+               else
+                       # This may happen if another call was made to `gethostbyname`
+                       # before we fetch the error code.
+                       return "Unknown error on `gethostbyname`"
+               end
+       end
 end