Merge: Use self in the FFI
[nit.git] / lib / socket / socket_c.nit
index df55638..ee6173e 100644 (file)
@@ -28,11 +28,16 @@ in "C Header" `{
        #include <arpa/inet.h>
        #include <netdb.h>
        #include <sys/poll.h>
+`}
 
+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: 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,53 @@ 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 descriptor: Int `{ return *self; `}
 
        fun gethostbyname(n: String): NativeSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
 
        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));
+               return write(*self, (char*)String_to_cstring(buffer), String_length(buffer));
        `}
 
-       fun read: String import NativeString.to_s_with_length `{
+       # Write `value` as a single byte
+       fun write_byte(value: Int): Int `{
+               unsigned char byt = (unsigned char)value;
+               return write(*self, &byt, 1);
+       `}
+
+       fun read: String import NativeString.to_s_with_length, NativeString.to_s_with_copy `{
                static char c[1024];
-               int n = read(*recv, c, 1024);
+               int n = read(*self, c, 1023);
                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);
+               c[n] = 0;
+               return NativeString_to_s_with_copy(c);
        `}
 
        # 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]
@@ -173,24 +187,42 @@ 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(addrIn: NativeSocketAddrIn): NativeSocket `{
+       private fun native_accept(addr_in: NativeSocketAddrIn): NativeSocket `{
                socklen_t s = sizeof(struct sockaddr);
-               int *d = NULL;
-               d = malloc(sizeof(int));
-               *d = accept(*recv,(struct sockaddr*)addrIn, &s);
-               return d;
+               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: nullable SocketAcceptResult
        do
                var addrIn = new NativeSocketAddrIn
                var s = native_accept(addrIn)
+               if s.address_is_null then return null
                return new SocketAcceptResult(s, addrIn)
        end
+
+       # Set wether 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);
+       `}
 end
 
 # Result of a call to `NativeSocket::accept`
@@ -210,7 +242,7 @@ extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
                return sai;
        `}
 
-       new with(port: Int, family: NativeSocketAddressFamilies) `{
+       new with_port(port: Int, family: NativeSocketAddressFamilies) `{
                struct sockaddr_in *sai = NULL;
                sai = malloc(sizeof(struct sockaddr_in));
                sai->sin_family = family;
@@ -228,19 +260,19 @@ extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
                return sai;
        `}
 
-       fun address: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(recv->sin_addr)); `}
+       fun address: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(self->sin_addr)); `}
 
-       fun family: NativeSocketAddressFamilies `{ return recv->sin_family; `}
+       fun family: NativeSocketAddressFamilies `{ return self->sin_family; `}
 
-       fun port: Int `{ return ntohs(recv->sin_port); `}
+       fun port: Int `{ return ntohs(self->sin_port); `}
 
-       fun destroy `{ free(recv); `}
+       fun destroy `{ free(self); `}
 end
 
 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(i: Int): String import NativeString.to_s `{ return NativeString_to_s(self->h_aliases[i]); `}
 
-       private fun native_h_aliases_reachable(i: Int): Bool `{ return (recv->h_aliases[i] != NULL); `}
+       private fun native_h_aliases_reachable(i: Int): Bool `{ return (self->h_aliases[i] != NULL); `}
 
        fun h_aliases: Array[String]
        do
@@ -254,13 +286,13 @@ extern class NativeSocketHostent `{ struct hostent* `}
                return d
        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: String import NativeString.to_s `{ return NativeString_to_s((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: String import NativeString.to_s `{ return NativeString_to_s(self->h_name); `}
 end
 
 extern class NativeTimeval `{ struct timeval* `}
@@ -272,11 +304,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* `}
@@ -286,18 +318,20 @@ 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;
@@ -344,9 +378,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; `}
 
@@ -363,7 +394,6 @@ 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; `}
@@ -399,6 +429,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
@@ -446,6 +479,6 @@ extern class NativeSocketPollValues `{ int `}
 
        # Combines two NativeSocketPollValues
        private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{
-               return recv | other;
+               return self | other;
        `}
 end