X-Git-Url: http://nitlanguage.org diff --git a/lib/socket/socket_c.nit b/lib/socket/socket_c.nit index 5e1db3f..1486752 100644 --- a/lib/socket/socket_c.nit +++ b/lib/socket/socket_c.nit @@ -28,11 +28,16 @@ in "C Header" `{ #include #include #include +`} +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: NativeSocketPollFD @@ -72,27 +77,30 @@ class PollFD return response & mask; `} + redef fun finalize_once + do + poll_struct.free + end end # Data structure used by the poll function -private extern class NativeSocketPollFD `{ struct pollfd `} +private extern class NativeSocketPollFD `{ struct pollfd * `} - # File descriptor id - private fun fd: Int `{ return recv.fd; `} + # 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: NativeSocketPollValues) `{ - struct pollfd poll; - poll.fd = pid; - poll.events = events; + struct pollfd *poll = malloc(sizeof(struct pollfd)); + poll->fd = pid; + poll->events = events; return poll; `} - end extern class NativeSocket `{ int* `} @@ -107,47 +115,46 @@ extern class NativeSocket `{ int* `} return d; `} - fun destroy `{ free(recv); `} + fun destroy `{ free(self); `} - fun close: Int `{ return close(*recv); `} + fun close: Int `{ return close(*self); `} - fun descriptor: Int `{ return *recv; `} - - fun gethostbyname(n: String): NativeSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `} + fun descriptor: Int `{ return *self; `} fun connect(addrIn: NativeSocketAddrIn): Int `{ - return connect(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn)); + return connect(*self, (struct sockaddr*)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)); + # Write `length` bytes from `buffer` + fun write(buffer: CString, length: Int): Int `{ + return write(*self, buffer, length); `} - 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); + # 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: NativeSocketOptLevels, option_name: NativeSocketOptNames, 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: NativeSocketAddrIn): Int `{ return bind(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn)); `} + fun bind(addrIn: NativeSocketAddrIn): Int `{ return bind(*self, (struct sockaddr*)addrIn, sizeof(*addrIn)); `} - fun listen(size: Int): Int `{ return listen(*recv, size); `} + 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[NativeSocketPollValues] @@ -157,6 +164,15 @@ extern class NativeSocket `{ int* `} 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: @@ -173,13 +189,13 @@ extern class NativeSocket `{ int* `} # 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 native_poll(filedesc: NativeSocketPollFD, timeout: Int): Int `{ - int poll_return = poll(&filedesc, 1, timeout); + int poll_return = poll(filedesc, 1, timeout); return poll_return; `} private fun native_accept(addr_in: NativeSocketAddrIn): NativeSocket `{ socklen_t s = sizeof(struct sockaddr); - int socket = accept(*recv, (struct sockaddr*)addr_in, &s); + int socket = accept(*self, (struct sockaddr*)addr_in, &s); if (socket == -1) return NULL; int *ptr = malloc(sizeof(int)); @@ -194,6 +210,37 @@ extern class NativeSocket `{ int* `} if s.address_is_null then return null return new SocketAcceptResult(s, addrIn) end + + # 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)); + `} + + # 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` @@ -206,64 +253,76 @@ class SocketAcceptResult var addr_in: NativeSocketAddrIn end +# 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 `{ struct sockaddr_in *sai = NULL; sai = malloc(sizeof(struct sockaddr_in)); return sai; `} - new with(port: Int, family: NativeSocketAddressFamilies) `{ - struct sockaddr_in *sai = NULL; - sai = malloc(sizeof(struct sockaddr_in)); - sai->sin_family = family; - sai->sin_port = htons(port); - sai->sin_addr.s_addr = INADDR_ANY; - 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); `} - new with_hostent(hostent: NativeSocketHostent, port: Int) `{ - struct sockaddr_in *sai = NULL; - sai = malloc(sizeof(struct sockaddr_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; - `} + # 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; `} - fun address: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(recv->sin_addr)); `} + # Set `address` to `INADDR_BROADCAST` + fun address_broadcast `{ self->sin_addr.s_addr = INADDR_BROADCAST; `} - fun family: NativeSocketAddressFamilies `{ return recv->sin_family; `} + # Address family + fun family: NativeSocketAddressFamilies `{ return self->sin_family; `} - fun port: Int `{ return ntohs(recv->sin_port); `} + # Address family + fun family=(value: NativeSocketAddressFamilies) `{ self->sin_family = value; `} - fun destroy `{ free(recv); `} + # Port + fun port: Int `{ return ntohs(self->sin_port); `} + + # Port + fun port=(value: Int) `{ self->sin_port = htons(value); `} end +# Host entry information, a pointer to a `struct hostent` extern class NativeSocketHostent `{ struct hostent* `} - private fun native_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(recv->h_aliases[i]); `} - - private fun native_h_aliases_reachable(i: Int): Bool `{ return (recv->h_aliases[i] != NULL); `} + 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(native_h_aliases(i)) - if native_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(*(struct in_addr*)recv->h_addr)); `} + fun h_addr: CString `{ + return (char*)inet_ntoa(*(struct in_addr*)self->h_addr); + `} - fun h_addrtype: Int `{ return recv->h_addrtype; `} + fun h_addrtype: Int `{ return self->h_addrtype; `} - fun h_length: Int `{ return recv->h_length; `} + fun h_length: Int `{ return self->h_length; `} - fun h_name: String import NativeString.to_s `{ return NativeString_to_s(recv->h_name); `} + fun h_name: CString `{ return self->h_name; `} end extern class NativeTimeval `{ struct timeval* `} @@ -275,11 +334,11 @@ extern class NativeTimeval `{ struct timeval* `} return tv; `} - fun seconds: Int `{ return recv->tv_sec; `} + fun seconds: Int `{ return self->tv_sec; `} - fun microseconds: Int `{ return recv->tv_usec; `} + fun microseconds: Int `{ return self->tv_usec; `} - fun destroy `{ free(recv); `} + fun destroy `{ free(self); `} end extern class NativeSocketSet `{ fd_set* `} @@ -289,21 +348,25 @@ extern class NativeSocketSet `{ fd_set* `} return f; `} - fun set(s: NativeSocket) `{ FD_SET(*s, recv); `} + fun set(s: NativeSocket) `{ FD_SET(*s, self); `} - fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, recv); `} + fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, self); `} - fun zero `{ FD_ZERO(recv); `} + fun zero `{ FD_ZERO(self); `} - fun clear(s: NativeSocket) `{ FD_CLR(*s, recv); `} + fun clear(s: NativeSocket) `{ FD_CLR(*s, self); `} - fun destroy `{ free(recv); `} + fun destroy `{ free(self); `} end 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, *wts, *exs = NULL; + 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; @@ -347,9 +410,6 @@ extern class NativeSocketAddressFamilies `{ int `} # Novell Internet Protocol new af_ipx `{ return AF_IPX; `} - # Integrated Services Digital Network - new af_isdn `{ return AF_ISDN; `} - # IPv6 new af_inet6 `{ return AF_INET6; `} @@ -366,10 +426,10 @@ extern class NativeSocketProtocolFamilies `{ 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 @@ -402,6 +462,9 @@ extern class NativeSocketOptNames `{ int `} # 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 @@ -449,6 +512,55 @@ extern class NativeSocketPollValues `{ int `} # Combines two NativeSocketPollValues private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{ - return recv | other; + 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