libsocket : Updated sockets to add poll function, also added wrappers for external use
authorLucas Bajolet <lucas.bajolet@hotmail.com>
Tue, 25 Jun 2013 16:06:13 +0000 (12:06 -0400)
committerLucas Bajolet <lucas.bajolet@hotmail.com>
Tue, 25 Jun 2013 16:06:13 +0000 (12:06 -0400)
Signed-off-by: Lucas Bajolet <lucas.bajolet@hotmail.com>

lib/socket/socket.nit
lib/socket/socket_c.nit

index d5f203a..b6c7740 100644 (file)
@@ -54,6 +54,38 @@ class Socket
                host = null
        end
 
+       # Returns an array containing an enum of the events ready to be read
+       #
+       # event_types : Combination of several event types to watch
+       #
+       # timeout : Time in milliseconds before stopping listening for events on this socket
+       #
+       private fun poll_in(event_types: Array[FFSocketPollValues], timeout: Int): Array[FFSocketPollValues] do return socket.socket_poll(new PollFD(socket.descriptor, event_types), timeout)
+
+       # Easier use of poll_in to check for something to read on all channels of any priority
+       #
+       # timeout : Time in milliseconds before stopping to wait for events
+       #
+       fun ready_to_read(timeout: Int): Bool
+       do
+               var events = new Array[FFSocketPollValues]
+               events.push(new FFSocketPollValues.pollin)
+               events.push(new FFSocketPollValues.pollrdnorm)
+               events.push(new FFSocketPollValues.pollpri)
+               events.push(new FFSocketPollValues.pollrdband)
+               return poll_in(events, timeout).length != 0
+       end
+
+       # Checks if the socket still is connected
+       #
+       fun connected: Bool
+       do
+               var events = new Array[FFSocketPollValues]
+               events.push(new FFSocketPollValues.pollhup)
+               events.push(new FFSocketPollValues.pollerr)
+               return poll_in(events, 0).length == 0
+       end
+
        fun connect: Bool do return socket.connect(addrin) >= 0
        fun write(msg: String): Bool do return socket.write(msg) >= 0
        fun read: String do return socket.read
index 559a844..4843354 100644 (file)
@@ -27,6 +27,7 @@ in "C Header" `{
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <netdb.h>
+       #include <sys/poll.h>
        #include <errno.h>
 
        typedef int S_DESCRIPTOR;
@@ -40,6 +41,67 @@ in "C Header" `{
        typedef socklen_t S_LEN;
 `}
 
+# 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 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 FFSocket `{ S_DESCRIPTOR* `}
        new socket(domain: FFSocketAddressFamilies, socketType: FFSocketTypes, protocol: FFSocketProtocolFamilies) `{
                S_DESCRIPTOR *d = NULL; d = (S_DESCRIPTOR*) malloc( sizeof(S_DESCRIPTOR) );
@@ -67,6 +129,34 @@ extern FFSocket `{ S_DESCRIPTOR* `}
        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;
@@ -218,3 +308,21 @@ extern FFSocketProtocolFamilies `{ int `}
        new pf_max `{ return PF_MAX; `}
 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;
+       `}
+end