abstract_compiler: remove -lunwind if target is Darwin (macosx)
[nit.git] / lib / socket / socket_c.nit
index 559a844..241422c 100644 (file)
@@ -27,7 +27,7 @@ in "C Header" `{
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <netdb.h>
-       #include <errno.h>
+       #include <sys/poll.h>
 
        typedef int S_DESCRIPTOR;
        typedef struct sockaddr_in S_ADDR_IN;
@@ -40,37 +40,142 @@ in "C Header" `{
        typedef socklen_t S_LEN;
 `}
 
-extern FFSocket `{ S_DESCRIPTOR* `}
+# Wrapper for the data structure PollFD used for polling on a socket
+class PollFD
+
+       # The PollFD object
+       private var poll_struct: FFSocketPollFD
+
+       # A collection of the events to be watched
+       var events: Array[FFSocketPollValues]
+
+       init(pid: Int, events: Array[FFSocketPollValues])
+       do
+               assert events.length >= 1
+               self.events = events
+
+               var events_in_one = events[0]
+
+               for i in [1 .. events.length-1] do
+                       events_in_one += events[i]
+               end
+
+               self.poll_struct = new FFSocketPollFD(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]
+       do
+               var resp_array = new Array[FFSocketPollValues]
+               for i in events do
+                       if c_check_resp(response, i) != 0 then
+                               resp_array.push(i)
+                       end
+               end
+               return resp_array
+       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
+       `{
+               return response & mask;
+       `}
+
+end
+
+# Data structure used by the poll function
+private extern class FFSocketPollFD `{ struct pollfd `}
+       # File descriptor id
+       private fun fd: Int `{ return recv.fd; `}
+       # List of events to be watched
+       private fun events: Int `{ return recv.events; `}
+       # List of events received by the last poll function
+       private fun revents: Int `{  return recv.revents; `}
+
+       new (pid: Int, events: FFSocketPollValues) `{
+               struct pollfd poll;
+               poll.fd = pid;
+               poll.events = events;
+               return poll;
+       `}
+
+end
+
+extern class FFSocket `{ S_DESCRIPTOR* `}
        new socket(domain: FFSocketAddressFamilies, socketType: FFSocketTypes, protocol: FFSocketProtocolFamilies) `{
                S_DESCRIPTOR *d = NULL; d = (S_DESCRIPTOR*) malloc( sizeof(S_DESCRIPTOR) );
                int ds = socket(domain, socketType, protocol);
+               if(ds == -1){
+                       free(d);
+                       return NULL;
+               }
                memcpy(d, &ds, sizeof(ds));
                return d;
        `}
        fun destroy `{ free(recv); `}
        fun close: Int `{ return close( *recv ); `}
        fun descriptor: Int `{ return *recv; `}
-       fun errno: Int `{ return errno; `}
 
-       fun gethostbyname(n: String): FFSocketHostent import String::to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
+       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 `{
-               char c[1024];
-               int n = read(*recv, c, (sizeof(c)-1));
-               if(n < 0) exit(-1);
-               c[n] = '\0';
-               return new_String_from_cstring(c);
+       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);
+       `}
+
+       # 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));
+               if(err != 0){
+                       perror("Error on setsockopts : ");
+                       exit(1);
+               }
        `}
 
        fun bind(addrIn: FFSocketAddrIn): Int `{ return bind(*recv, (S_ADDR*)addrIn, sizeof(*addrIn)); `}
        fun listen(size: Int): Int `{ return listen(*recv, 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]
+       do
+               var result = i_poll(filedesc.poll_struct, timeout)
+               assert result != -1
+               return filedesc.check_response(result)
+       end
+
+       # Call to the poll function of the C socket
+       #
+       # Signature :
+       # int poll(struct pollfd fds[], nfds_t nfds, int timeout);
+       #
+       # 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.
+       # The number of pollfd structures in the fds array is specified by nfds.
+       # The poll() function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.
+       # The fds argument specifies the file descriptors to be examined and the events of interest for each file 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);
+               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 = malloc(sizeof(S_DESCRIPTOR));
                *d = accept(*recv,(S_ADDR*)addrIn, &s);
                return d;
        `}
@@ -82,10 +187,10 @@ extern FFSocket `{ S_DESCRIPTOR* `}
        end
 end
 
-extern FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
+extern class FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
        new (socket: FFSocket, addrIn: FFSocketAddrIn) `{
                S_ACCEPT_RESULT *sar = NULL;
-               sar = malloc( sizeof(S_ACCEPT_RESULT*) );
+               sar = malloc( sizeof(S_ACCEPT_RESULT) );
                sar->s_desc = *socket;
                sar->addr_in = *addrIn;
                return sar;
@@ -95,15 +200,15 @@ extern FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
        fun destroy `{ free(recv); `}
 end
 
-extern FFSocketAddrIn `{ S_ADDR_IN* `}
+extern class FFSocketAddrIn `{ S_ADDR_IN* `}
        new `{
                S_ADDR_IN *sai = NULL;
-               sai = malloc( sizeof(S_ADDR_IN*) );
+               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 = malloc( sizeof(S_ADDR_IN) );
                sai->sin_family = family;
                sai->sin_port = htons(port);
                sai->sin_addr.s_addr = INADDR_ANY;
@@ -111,20 +216,20 @@ extern FFSocketAddrIn `{ S_ADDR_IN* `}
        `}
        new with_hostent(hostent: FFSocketHostent, port: Int) `{
                S_ADDR_IN *sai = NULL;
-               sai = malloc( sizeof(S_ADDR_IN*) );
+               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;
        `}
-       fun address: String `{ return new_String_from_cstring( (char*)inet_ntoa(recv->sin_addr) ); `}
+       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); `}
 end
 
-extern FFSocketHostent `{ S_HOSTENT* `}
-       private fun i_h_aliases(i: Int): String `{ return new_String_from_cstring(recv->h_aliases[i]); `}
+extern class 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); `}
        fun h_aliases: Array[String]
        do
@@ -137,16 +242,16 @@ extern FFSocketHostent `{ S_HOSTENT* `}
                end
                return d
        end
-       fun h_addr: String `{ return new_String_from_cstring( (char*)inet_ntoa(*(S_IN_ADDR*)recv->h_addr) ); `}
+       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 `{ return new_String_from_cstring(recv->h_name); `}
+       fun h_name: String import NativeString.to_s `{ return NativeString_to_s(recv->h_name); `}
 end
 
-extern FFTimeval `{ S_TIMEVAL* `}
+extern class FFTimeval `{ S_TIMEVAL* `}
        new (seconds: Int, microseconds: Int) `{
                S_TIMEVAL* tv = NULL;
-               tv = malloc( sizeof(S_TIMEVAL*) );
+               tv = malloc( sizeof(S_TIMEVAL) );
                tv->tv_sec = seconds;
                tv->tv_usec = microseconds;
                return tv;
@@ -156,10 +261,10 @@ extern FFTimeval `{ S_TIMEVAL* `}
        fun destroy `{ free( recv ); `}
 end
 
-extern FFSocketSet `{ S_FD_SET* `}
+extern class FFSocketSet `{ S_FD_SET* `}
        new `{
                S_FD_SET *f = NULL;
-               f = malloc( sizeof(S_FD_SET*) );
+               f = malloc( sizeof(S_FD_SET) );
                return f;
        `}
        fun set(s: FFSocket) `{ FD_SET( *s, recv ); `}
@@ -182,13 +287,13 @@ class FFSocketObserver
        `}
 end
 
-extern FFSocketTypes `{ int `}
+extern class FFSocketTypes `{ 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 FFSocketAddressFamilies `{ int `}
        new af_null `{ return 0; `}
        new af_unspec `{ return  AF_UNSPEC; `}          # unspecified
        new af_unix `{ return  AF_UNIX; `}              # local to host (pipes)
@@ -202,7 +307,7 @@ extern FFSocketAddressFamilies `{ int `}
        new af_inet6 `{ return  AF_INET6; `}            # IPv6
        new af_max `{ return  AF_MAX; `}
 end
-extern FFSocketProtocolFamilies `{ int `}
+extern class FFSocketProtocolFamilies `{ int `}
        new pf_null `{ return 0; `}
        new pf_unspec `{ return PF_UNSPEC; `}
        new pf_local `{ return PF_LOCAL; `}
@@ -217,4 +322,43 @@ extern FFSocketProtocolFamilies `{ int `}
        new pf_inet6 `{ return PF_INET6; `}
        new pf_max `{ return PF_MAX; `}
 end
+# Level on which to set options
+extern class FFSocketOptLevels `{ 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 class FFSocketOptNames `{ 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; `}
+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 class 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;
+       `}
+end