X-Git-Url: http://nitlanguage.org diff --git a/lib/socket/socket_c.nit b/lib/socket/socket_c.nit index 11bda16..1486752 100644 --- a/lib/socket/socket_c.nit +++ b/lib/socket/socket_c.nit @@ -28,28 +28,24 @@ in "C Header" `{ #include #include #include +`} - 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 + #include `} # 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,90 +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) { - free(c); - return NativeString_to_s_with_length("",0); - } - char* ret = malloc(n + 1); - memcpy(ret, c, n); - ret[n] = '\0'; - free(c); - 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. @@ -169,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; `} @@ -319,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