# Socket services
module socket
-import socket_c
+private import socket_c
intrude import standard::stream
-# Portal for communication between two machines
-class Socket
- super BufferedIStream
- super OStream
- super PollableIStream
+# A general TCP socket, either a `TCPStream` or a `TCPServer`
+abstract class Socket
+
+ # Underlying C socket
+ private var socket: NativeSocket is noinit
- # IPv4 address the socket is connected to
- # Formatted as xxx.xxx.xxx.xxx
+ # Port used by the socket
+ var port: Int
+
+ # IPv4 address to which `self` is connected
+ #
+ # Formatted as xxx.xxx.xxx.xxx.
var address: String is noinit
- # Hostname of the socket connected to self
- # In C : The real canonical host name (e.g. example.org)
- var host: nullable String = null
+ # Is this socket closed?
+ var closed = false
+end
- # Port open for the socket
- var port: Int is noinit
+# Simple communication stream with a remote socket
+class TCPStream
+ super Socket
+ super BufferedIStream
+ super OStream
+ super PollableIStream
- # Underlying C socket
- private var socket: FFSocket is noinit
+ # Real canonical name of the host to which `self` is connected
+ var host: String
- # Underlying C socket
- private var addrin: FFSocketAddrIn is noinit
+ private var addrin: NativeSocketAddrIn is noinit
redef var end_reached = false
- # Creates a socket connection to host `thost` on port `port`
- init client(thost: String, tport: Int)
- do
- _buffer = new FlatBuffer
- _buffer_pos = 0
- socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null )
- if socket.address_is_null then
- end_reached = true
- return
- end
- socket.setsockopt(new FFSocketOptLevels.socket, new FFSocketOptNames.reuseaddr, 1)
- var hostname = socket.gethostbyname(thost)
- addrin = new FFSocketAddrIn.with_hostent(hostname, tport)
- address = addrin.address
- host = hostname.h_name
- port = addrin.port
- if not end_reached then end_reached = not connect
- end
+ # TODO make init private
- # Creates a server socket on port `tport`, with a connection queue of size `max`
- init server(tport: Int, max: Int)
+ # Creates a socket connection to host `host` on port `port`
+ init connect(host: String, port: Int)
do
_buffer = new FlatBuffer
_buffer_pos = 0
- socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null )
+ socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
+ new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
if socket.address_is_null then
end_reached = true
+ closed = true
return
end
- socket.setsockopt(new FFSocketOptLevels.socket, new FFSocketOptNames.reuseaddr, 1)
- addrin = new FFSocketAddrIn.with(tport, new FFSocketAddressFamilies.af_inet)
+ socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1)
+ var hostname = socket.gethostbyname(host)
+ addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
+
address = addrin.address
- port = addrin.port
- host = null
- bind
- listen(max)
+ init(addrin.port, hostname.h_name)
+
+ closed = not internal_connect
+ end_reached = closed
end
# Creates a client socket, this is meant to be used by accept only
- private init primitive_init(h: FFSocketAcceptResult)
+ private init server_side(h: SocketAcceptResult)
do
_buffer = new FlatBuffer
_buffer_pos = 0
socket = h.socket
- addrin = h.addrIn
+ addrin = h.addr_in
address = addrin.address
- port = addrin.port
- host = null
+
+ init(addrin.port, address)
end
redef fun poll_in do return ready_to_read(0)
# event_types : Combination of several event types to watch
#
# timeout : Time in milliseconds before stopping listening for events on this socket
- #
- private fun pollin(event_types: Array[FFSocketPollValues], timeout: Int): Array[FFSocketPollValues] do
- if end_reached then return new Array[FFSocketPollValues]
+ private fun pollin(event_types: Array[NativeSocketPollValues], timeout: Int): Array[NativeSocketPollValues] do
+ if end_reached then return new Array[NativeSocketPollValues]
return socket.socket_poll(new PollFD(socket.descriptor, event_types), timeout)
end
# Easier use of pollin 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
if _buffer_pos < _buffer.length then return true
if eof then return false
- var events = new Array[FFSocketPollValues]
- events.push(new FFSocketPollValues.pollin)
+ var events = [new NativeSocketPollValues.pollin]
return pollin(events, timeout).length != 0
end
# Checks if the socket still is connected
- #
fun connected: Bool
do
- if eof then return false
- var events = new Array[FFSocketPollValues]
- events.push(new FFSocketPollValues.pollhup)
- events.push(new FFSocketPollValues.pollerr)
+ if closed then return false
+ var events = [new NativeSocketPollValues.pollhup, new NativeSocketPollValues.pollerr]
if pollin(events, 0).length == 0 then
return true
else
- end_reached = true
+ closed = true
return false
end
end
# Establishes a connection to socket addrin
#
# REQUIRES : not self.end_reached
- private fun connect: Bool
+ private fun internal_connect: Bool
do
- assert not end_reached
+ assert not closed
return socket.connect(addrin) >= 0
end
# If socket.end_reached, nothing will happen
redef fun write(msg: Text)
do
- if end_reached then return
+ if closed then return
socket.write(msg.to_s)
end
_buffer.append(read)
end
- redef fun close do
- if end_reached then return
+ redef fun close
+ do
+ if closed then return
if socket.close >= 0 then
- end_reached = true
+ closed = true
end
end
+ # Send the data present in the socket buffer
+ fun flush
+ do
+ socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 1)
+ socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 0)
+ end
+end
+
+# A socket listening on a given `port` for incomming connections
+#
+# Create streams to communicate with clients using `accept`.
+class TCPServer
+ super Socket
+
+ private var addrin: NativeSocketAddrIn is noinit
+
+ # Create and bind a listening server socket on port `port`
+ init
+ do
+ socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
+ new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
+ assert not socket.address_is_null
+ socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1)
+ addrin = new NativeSocketAddrIn.with(port, new NativeSocketAddressFamilies.af_inet)
+ address = addrin.address
+
+ # Bind it
+ closed = not bind
+ end
+
# Associates the socket to a local address and port
#
- # Returns : `true` if the socket could be bound, `false` otherwise
+ # Returns whether the socket has been be bound.
private fun bind: Bool do
- if end_reached then return false
return socket.bind(addrin) >= 0
end
# Sets the socket as ready to accept incoming connections, `size` is the maximum number of queued clients
#
- # Returns : `true` if the socket could be set, `false` otherwise
- private fun listen(size: Int): Bool do
- if end_reached then return false
+ # Returns `true` if the socket could be set, `false` otherwise
+ fun listen(size: Int): Bool do
return socket.listen(size) >= 0
end
# Accepts an incoming connection from a client
- # This creates a new socket that represents the connection to a client
#
- # Returns : the socket for communication with the client
+ # Create and return a new socket to the client. May return null if not
+ # `blocking` and there's no waiting clients, or upon an interruption
+ # (whether `blocking` or not).
#
- # REQUIRES : not self.end_reached
- fun accept: Socket do
- assert not end_reached
- return new Socket.primitive_init(socket.accept)
+ # Require: not closed
+ fun accept: nullable TCPStream
+ do
+ assert not closed
+ var native = socket.accept
+ if native == null then return null
+ return new TCPStream.server_side(native)
end
+ # Set whether calls to `accept` are blocking
+ fun blocking=(value: Bool)
+ do
+ # We use the opposite from the native version as the native API
+ # is closer to the C API. In the Nity API, we use a positive version
+ # of the name.
+ socket.non_blocking = not value
+ end
+
+ # Close this socket
+ fun close
+ do
+ # FIXME unify with `SocketStream::close` when we can use qualified names
+
+ if closed then return
+ if socket.close >= 0 then
+ closed = true
+ end
+ end
end
+# A simple set of sockets used by `SocketObserver`
class SocketSet
- var sset = new FFSocketSet
- fun set(s: Socket) do sset.set(s.socket) end
- fun is_set(s: Socket): Bool do return sset.is_set(s.socket) end
- fun zero do sset.zero end
- fun clear(s: Socket) do sset.clear(s.socket) end
+ private var native = new NativeSocketSet
+
+ init do clear
+
+ # Add `socket` to this set
+ fun add(socket: Socket) do native.set(socket.socket)
+
+ # Remove `socket` from this set
+ fun remove(socket: Socket) do native.clear(socket.socket)
+
+ # Does this set has `socket`?
+ fun has(socket: Socket): Bool do return native.is_set(socket.socket)
+
+ # Clear all sockets from this set
+ fun clear do native.zero
end
+# Service class to manage calls to `select`
class SocketObserver
- private var observer: FFSocketObserver
- var readset: nullable SocketSet = null
- var writeset: nullable SocketSet = null
- var exceptset: nullable SocketSet = null
- init(read :Bool, write :Bool, except: Bool)
- do
- if read then readset = new SocketSet
- if write then writeset = new SocketSet
- if except then exceptset = new SocketSet
- observer = new FFSocketObserver
- end
- fun select(max: Socket,seconds: Int, microseconds: Int): Bool
+ private var native = new NativeSocketObserver
+
+ var read_set: nullable SocketSet = null
+
+ var write_set: nullable SocketSet = null
+
+ var except_set: nullable SocketSet = null
+
+ init(read: Bool, write: Bool, except: Bool)
+ is old_style_init do
+ if read then read_set = new SocketSet
+ if write then write_set = new SocketSet
+ if except then except_set = new SocketSet
+ end
+
+ fun select(max: Socket, seconds: Int, microseconds: Int): Bool
do
- var timeval = new FFTimeval(seconds, microseconds)
- return observer.select(max.socket, readset.sset, writeset.sset, readset.sset, timeval) > 0
+ # FIXME this implementation (see the call to nullable attributes below) and
+ # `NativeSockectObserver::select` is not stable.
+
+ var timeval = new NativeTimeval(seconds, microseconds)
+ return native.select(max.socket, read_set.native, write_set.native, except_set.native, timeval) > 0
end
end
-
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/poll.h>
+`}
- typedef int S_DESCRIPTOR;
- typedef struct sockaddr_in S_ADDR_IN;
- typedef struct sockaddr S_ADDR;
- typedef struct in_addr S_IN_ADDR;
- typedef struct hostent S_HOSTENT;
- typedef struct timeval S_TIMEVAL;
- typedef struct sockaccept_result { S_ADDR_IN addr_in; S_DESCRIPTOR s_desc; } S_ACCEPT_RESULT;
- typedef fd_set S_FD_SET;
- typedef socklen_t S_LEN;
+in "C" `{
+ #include <fcntl.h>
+ #include <netinet/tcp.h>
`}
# Wrapper for the data structure PollFD used for polling on a socket
class PollFD
# The PollFD object
- private var poll_struct: FFSocketPollFD
+ private var poll_struct: NativeSocketPollFD
# A collection of the events to be watched
- var events: Array[FFSocketPollValues]
+ var events: Array[NativeSocketPollValues]
- init(pid: Int, events: Array[FFSocketPollValues])
+ init(pid: Int, events: Array[NativeSocketPollValues])
do
assert events.length >= 1
self.events = events
events_in_one += events[i]
end
- self.poll_struct = new FFSocketPollFD(pid, events_in_one)
+ self.poll_struct = new NativeSocketPollFD(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]
+ private fun check_response(response: Int): Array[NativeSocketPollValues]
do
- var resp_array = new Array[FFSocketPollValues]
+ var resp_array = new Array[NativeSocketPollValues]
for i in events do
if c_check_resp(response, i) != 0 then
resp_array.push(i)
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
+ private fun c_check_resp(response: Int, mask: NativeSocketPollValues): Int
`{
return response & mask;
`}
end
# Data structure used by the poll function
-private extern class FFSocketPollFD `{ struct pollfd `}
+private extern class NativeSocketPollFD `{ 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) `{
+ new (pid: Int, events: NativeSocketPollValues) `{
struct pollfd poll;
poll.fd = pid;
poll.events = events;
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) );
+extern class NativeSocket `{ int* `}
+
+ new socket(domain: NativeSocketAddressFamilies, socketType: NativeSocketTypes, protocol: NativeSocketProtocolFamilies) `{
int ds = socket(domain, socketType, protocol);
if(ds == -1){
- free(d);
return NULL;
}
+ int *d = malloc(sizeof(int));
memcpy(d, &ds, sizeof(ds));
return d;
`}
+
fun destroy `{ free(recv); `}
- fun close: Int `{ return close( *recv ); `}
+
+ fun close: Int `{ return close(*recv); `}
+
fun descriptor: Int `{ return *recv; `}
- 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 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));
+ `}
+
+ 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];
`}
# Sets an option for the socket
- fun setsockopt(level: FFSocketOptLevels, option_name: FFSocketOptNames, option_value: Int) `{
+ fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int) `{
int err = setsockopt(*recv, level, option_name, &option_value, sizeof(int));
if(err != 0){
- perror("Error on setsockopts : ");
+ perror("Error on setsockopts: ");
exit(1);
}
`}
- fun bind(addrIn: FFSocketAddrIn): Int `{ return bind(*recv, (S_ADDR*)addrIn, sizeof(*addrIn)); `}
+ fun bind(addrIn: NativeSocketAddrIn): Int `{ return bind(*recv, (struct sockaddr*)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]
+ fun socket_poll(filedesc: PollFD, timeout: Int): Array[NativeSocketPollValues]
do
- var result = i_poll(filedesc.poll_struct, timeout)
+ var result = native_poll(filedesc.poll_struct, timeout)
assert result != -1
return filedesc.check_response(result)
end
# Call to the poll function of the C socket
#
- # Signature :
+ # Signature:
# int poll(struct pollfd fds[], nfds_t nfds, int timeout);
#
- # Official documentation of the poll function :
+ # 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.
# 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 `{
+ private fun native_poll(filedesc: NativeSocketPollFD, 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 = accept(*recv,(S_ADDR*)addrIn, &s);
- return d;
+ private fun native_accept(addr_in: NativeSocketAddrIn): NativeSocket `{
+ socklen_t s = sizeof(struct sockaddr);
+ int socket = accept(*recv, (struct sockaddr*)addr_in, &s);
+ if (socket == -1) return NULL;
+
+ int *ptr = malloc(sizeof(int));
+ *ptr = socket;
+ return ptr;
`}
- fun accept: FFSocketAcceptResult
+
+ fun accept: nullable SocketAcceptResult
do
- var addrIn = new FFSocketAddrIn
- var s = i_accept(addrIn)
- return new FFSocketAcceptResult(s, addrIn)
+ var addrIn = new NativeSocketAddrIn
+ var s = native_accept(addrIn)
+ if s.address_is_null then return null
+ return new SocketAcceptResult(s, addrIn)
end
-end
-extern class FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
- new (socket: FFSocket, addrIn: FFSocketAddrIn) `{
- S_ACCEPT_RESULT *sar = NULL;
- sar = malloc( sizeof(S_ACCEPT_RESULT) );
- sar->s_desc = *socket;
- sar->addr_in = *addrIn;
- return sar;
+ # Set wether this socket is non blocking
+ fun non_blocking=(value: Bool) `{
+ int flags = fcntl(*recv, 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(*recv, F_SETFL, flags);
`}
- fun socket: FFSocket `{ return &recv->s_desc; `}
- fun addrIn: FFSocketAddrIn `{ return &recv->addr_in; `}
- fun destroy `{ free(recv); `}
end
-extern class FFSocketAddrIn `{ S_ADDR_IN* `}
+# Result of a call to `NativeSocket::accept`
+class SocketAcceptResult
+
+ # Opened socket
+ var socket: NativeSocket
+
+ # Address of the remote client
+ var addr_in: NativeSocketAddrIn
+end
+
+extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
new `{
- S_ADDR_IN *sai = NULL;
- sai = malloc( sizeof(S_ADDR_IN) );
+ struct sockaddr_in *sai = NULL;
+ sai = malloc(sizeof(struct sockaddr_in));
return sai;
`}
- new with(port: Int, family: FFSocketAddressFamilies) `{
- S_ADDR_IN *sai = NULL;
- sai = malloc( sizeof(S_ADDR_IN) );
+
+ 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;
`}
- new with_hostent(hostent: FFSocketHostent, port: Int) `{
- S_ADDR_IN *sai = NULL;
- sai = malloc( sizeof(S_ADDR_IN) );
+
+ 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 );
+ memcpy((char*)&sai->sin_addr.s_addr, (char*)hostent->h_addr, hostent->h_length);
return sai;
`}
- 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 address: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(recv->sin_addr)); `}
+
+ fun family: NativeSocketAddressFamilies `{ return recv->sin_family; `}
+
fun port: Int `{ return ntohs(recv->sin_port); `}
+
fun destroy `{ free(recv); `}
end
-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); `}
+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); `}
+
fun h_aliases: Array[String]
do
var i=0
var d=new Array[String]
loop
- d.add(i_h_aliases(i))
- if i_h_aliases_reachable(i+1) == false then break
+ d.add(native_h_aliases(i))
+ if native_h_aliases_reachable(i+1) == false then break
i += 1
end
return d
end
- fun h_addr: String import NativeString.to_s `{ return NativeString_to_s( (char*)inet_ntoa(*(S_IN_ADDR*)recv->h_addr) ); `}
+
+ fun h_addr: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(*(struct 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 import NativeString.to_s `{ return NativeString_to_s(recv->h_name); `}
end
-extern class FFTimeval `{ S_TIMEVAL* `}
+extern class NativeTimeval `{ struct timeval* `}
new (seconds: Int, microseconds: Int) `{
- S_TIMEVAL* tv = NULL;
- tv = malloc( sizeof(S_TIMEVAL) );
+ struct timeval* tv = NULL;
+ tv = malloc(sizeof(struct timeval));
tv->tv_sec = seconds;
tv->tv_usec = microseconds;
return tv;
`}
+
fun seconds: Int `{ return recv->tv_sec; `}
+
fun microseconds: Int `{ return recv->tv_usec; `}
- fun destroy `{ free( recv ); `}
+
+ fun destroy `{ free(recv); `}
end
-extern class FFSocketSet `{ S_FD_SET* `}
+extern class NativeSocketSet `{ fd_set* `}
new `{
- S_FD_SET *f = NULL;
- f = malloc( sizeof(S_FD_SET) );
+ fd_set *f = NULL;
+ f = malloc(sizeof(fd_set));
return f;
`}
- fun set(s: FFSocket) `{ FD_SET( *s, recv ); `}
- fun is_set(s: FFSocket): Bool `{ return FD_ISSET( *s, recv ); `}
- fun zero `{ FD_ZERO( recv ); `}
- fun clear(s: FFSocket) `{ FD_CLR( *s, recv ); `}
- fun destroy `{ free( recv ); `}
+
+ fun set(s: NativeSocket) `{ FD_SET(*s, recv); `}
+
+ fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, recv); `}
+
+ fun zero `{ FD_ZERO(recv); `}
+
+ fun clear(s: NativeSocket) `{ FD_CLR(*s, recv); `}
+
+ fun destroy `{ free(recv); `}
end
-class FFSocketObserver
- fun select(max: FFSocket, reads: nullable FFSocketSet, write: nullable FFSocketSet,
- except: nullable FFSocketSet, timeout: FFTimeval): Int `{
- S_FD_SET *rds, *wts, *exs = NULL;
- S_TIMEVAL *tm = NULL;
- if(reads != NULL) rds = (S_FD_SET*)reads;
- if(write != NULL) wts = (S_FD_SET*)write;
- if(except != NULL) exs = (S_FD_SET*)except;
- if(timeout != NULL) tm = (S_TIMEVAL*)timeout;
+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;
+ struct timeval *tm = NULL;
+ if (reads != NULL) rds = (fd_set*)reads;
+ if (write != NULL) wts = (fd_set*)write;
+ if (except != NULL) exs = (fd_set*)except;
+ if (timeout != NULL) tm = (struct timeval*)timeout;
return select(*max, rds, wts, exs, tm);
`}
end
-extern class FFSocketTypes `{ int `}
+extern class NativeSocketTypes `{ 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 class FFSocketAddressFamilies `{ int `}
+
+extern class NativeSocketAddressFamilies `{ int `}
new af_null `{ return 0; `}
- new af_unspec `{ return AF_UNSPEC; `} # unspecified
- new af_unix `{ return AF_UNIX; `} # local to host (pipes)
- new af_local `{ return AF_LOCAL; `} # backward compatibility
- new af_inet `{ return AF_INET; `} # internetwork: UDP, TCP, etc.
- new af_sna `{ return AF_SNA; `} # IBM SNA
- new af_decnet `{ return AF_DECnet; `} # DECnet
- new af_route `{ return AF_ROUTE; `} # Internal Routing Protocol
- new af_ipx `{ return AF_IPX; `} # Novell Internet Protocol
- new af_isdn `{ return AF_ISDN; `} # Integrated Services Digital Network
- new af_inet6 `{ return AF_INET6; `} # IPv6
- new af_max `{ return AF_MAX; `}
+
+ # Unspecified
+ new af_unspec `{ return AF_UNSPEC; `}
+
+ # Local to host (pipes)
+ new af_unix `{ return AF_UNIX; `}
+
+ # For backward compatibility
+ new af_local `{ return AF_LOCAL; `}
+
+ # Internetwork: UDP, TCP, etc.
+ new af_inet `{ return AF_INET; `}
+
+ # IBM SNA
+ new af_sna `{ return AF_SNA; `}
+
+ # DECnet
+ new af_decnet `{ return AF_DECnet; `}
+
+ # Internal Routing Protocol
+ new af_route `{ return AF_ROUTE; `}
+
+ # 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; `}
+
+ new af_max `{ return AF_MAX; `}
end
-extern class FFSocketProtocolFamilies `{ int `}
+
+extern class NativeSocketProtocolFamilies `{ int `}
new pf_null `{ return 0; `}
new pf_unspec `{ return PF_UNSPEC; `}
new pf_local `{ return PF_LOCAL; `}
new pf_inet6 `{ return PF_INET6; `}
new pf_max `{ return PF_MAX; `}
end
+
# Level on which to set options
-extern class FFSocketOptLevels `{ int `}
+extern class NativeSocketOptLevels `{ 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 `}
+extern class NativeSocketOptNames `{ 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; `}
+
+ # 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
-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 `{
+extern class NativeSocketPollValues `{ int `}
+
+ # Data other than high-priority data may be read without blocking.
+ new pollin `{ return POLLIN; `}
+
+ # Normal data may be read without blocking.
+ new pollrdnorm `{ return POLLRDNORM; `}
+
+ # Priority data may be read without blocking.
+ new pollrdband `{ return POLLRDBAND; `}
+
+ # High-priority data may be read without blocking.
+ new pollpri `{ return POLLPRI; `}
+
+ # Normal data may be written without blocking.
+ new pollout `{ return POLLOUT; `}
+
+ # Equivalent to POLLOUT
+ new pollwrnorm `{ return POLLWRNORM; `}
+
+ # Priority data may be written.
+ new pollwrband `{ return POLLWRBAND; `}
+
+ # 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 pollerr `{ return POLLERR; `}
+
+ # 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 pollhup `{ return POLLHUP; `}
+
+ # The specified fd value is invalid.
+ #
+ # This flag is only valid in the revents member; it shall ignored in the events member.
+ new pollnval `{ return POLLNVAL; `}
+
+ # Combines two NativeSocketPollValues
+ private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{
return recv | other;
`}
end