From fcd4dc7e0cb88cead31a32ee1591802d21660336 Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Tue, 14 May 2013 14:22:39 -0400 Subject: [PATCH] Sockets : Added a function to check if the socket is ready to be read A timeout is available to wait for x milliseconds before continuing. Signed-off-by: Lucas Bajolet --- ffsocket.nit | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ socket.nit | 8 +++++++ 2 files changed, 70 insertions(+) diff --git a/ffsocket.nit b/ffsocket.nit index 33cd0b8..843f598 100644 --- a/ffsocket.nit +++ b/ffsocket.nit @@ -10,6 +10,7 @@ in "C Header" `{ #include #include #include + #include #include typedef int S_DESCRIPTOR; @@ -23,6 +24,24 @@ in "C Header" `{ typedef socklen_t S_LEN; `} +# Data structure used by the poll function +extern PollFD `{ struct pollfd `} + # File descriptor id + fun fd: Int `{ return recv.fd; `} + # List of events to be watched + fun events: Int `{ return recv.events; `} + # List of events received by the last poll function + 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) `{ @@ -60,6 +79,34 @@ extern FFSocket `{ S_DESCRIPTOR* `} private fun i_listen(size: Int):Int `{ return listen(*recv, size); `} fun listen(size: Int):Int do return i_listen(size) + # Checks if the buffer is ready for any event specified when creating the pollfd structure + fun socket_poll(filedesc: PollFD, timeout: Int): Bool + do + var result = i_poll(filedesc, timeout) + assert result != -1 + if result == 0 then return false + return true + 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: PollFD, timeout: Int): Int `{ + return poll(&filedesc, 1, timeout); + `} + private fun i_accept(addrIn: FFSocketAddrIn):FFSocket `{ S_LEN s = sizeof(S_ADDR); S_DESCRIPTOR *d = NULL; @@ -209,4 +256,19 @@ extern FFSocketProtocolFamilies `{ int `} new pf_inet6 `{ return PF_INET6; `} new pf_max `{ return PF_MAX; `} end +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. + fun +(other: FFSocketPollValues): FFSocketPollValues `{ + return recv | other; + `} +end diff --git a/socket.nit b/socket.nit index 7a5c2aa..6dc2ee2 100644 --- a/socket.nit +++ b/socket.nit @@ -8,10 +8,13 @@ class Socket var port: Int private var socket: FFSocket private var addrin: FFSocketAddrIn + # PollFD object, used for the ready_to_read function + private var read_pollFD: PollFD init streamWithHost(thost: String, tport: Int) do socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null ) + self.read_pollFD = new PollFD(socket.descriptor, new FFSocketPollValues.pollin) var hostname = socket.gethostbyname(thost) addrin = new FFSocketAddrIn.withHostent(hostname, tport) address = addrin.address @@ -22,6 +25,7 @@ class Socket init streamWithPort(tport: Int) do socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null ) + self.read_pollFD = new PollFD(socket.descriptor, new FFSocketPollValues.pollin) addrin = new FFSocketAddrIn.with(tport, new FFSocketAddressFamilies.af_inet) address = addrin.address port = addrin.port @@ -31,6 +35,7 @@ class Socket init primitiveInit(h: FFSocketAcceptResult) do socket = h.socket + self.read_pollFD = new PollFD(socket.descriptor, new FFSocketPollValues.pollin) addrin = h.addrIn address = addrin.address port = addrin.port @@ -44,6 +49,9 @@ class Socket fun bind:Bool do return socket.bind(addrin) >= 0 fun listen(size: Int):Bool do return socket.listen(size) >= 0 fun accept:Socket do return new Socket.primitiveInit(socket.accept) + # Checks if the socket is ready to be read with the read() function without blocking + fun ready_to_read: Bool do return socket.socket_poll(self.read_pollFD, 0) + fun timeout_rdy_to_read(timeout: Int): Bool do return socket.socket_poll(self.read_pollFD, timeout) fun errno:Int do return socket.errno end