#include <arpa/inet.h>
#include <netdb.h>
#include <sys/poll.h>
+`}
- typedef struct sockaccept_result {
- struct sockaddr_in addr_in;
- int s_desc;
- } S_ACCEPT_RESULT;
+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: 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;
`}
+ redef fun finalize_once
+ do
+ poll_struct.free
+ end
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; `}
+ # 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: FFSocketPollValues) `{
- struct pollfd poll;
- poll.fd = pid;
- poll.events = events;
+ new (pid: Int, events: NativeSocketPollValues) `{
+ struct pollfd *poll = malloc(sizeof(struct pollfd));
+ poll->fd = pid;
+ poll->events = events;
return poll;
`}
-
end
-extern class FFSocket `{ int* `}
+extern class NativeSocket `{ int* `}
- new socket(domain: FFSocketAddressFamilies, socketType: FFSocketTypes, protocol: FFSocketProtocolFamilies) `{
- int *d = malloc(sizeof(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 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): FFSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
+ fun gethostbyname(n: String): NativeSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
- fun connect(addrIn: FFSocketAddrIn): Int `{
- return connect(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn));
+ fun connect(addrIn: NativeSocketAddrIn): Int `{
+ 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));
+ `}
+
+ # 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 `{
- static char c[1024];
- int n = read(*recv, c, 1024);
+ fun read: String import NativeString.to_s_with_length, NativeString `{
+ char *c = new_NativeString(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_length(c, 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));
+ #
+ # 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: FFSocketAddrIn): 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[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
# 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);
+ 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 `{
+ 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: 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(*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
- fun socket: FFSocket `{ return &recv->s_desc; `}
+# Result of a call to `NativeSocket::accept`
+class SocketAcceptResult
- fun addrIn: FFSocketAddrIn `{ return &recv->addr_in; `}
+ # Opened socket
+ var socket: NativeSocket
- fun destroy `{ free(recv); `}
+ # Address of the remote client
+ var addr_in: NativeSocketAddrIn
end
-extern class FFSocketAddrIn `{ struct sockaddr_in* `}
+extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
new `{
struct sockaddr_in *sai = NULL;
sai = malloc(sizeof(struct sockaddr_in));
return sai;
`}
- new with(port: Int, family: FFSocketAddressFamilies) `{
+ new with_port(port: Int, family: NativeSocketAddressFamilies) `{
struct sockaddr_in *sai = NULL;
sai = malloc(sizeof(struct sockaddr_in));
sai->sin_family = family;
return sai;
`}
- new with_hostent(hostent: FFSocketHostent, port: Int) `{
+ new with_hostent(hostent: NativeSocketHostent, port: Int) `{
struct sockaddr_in *sai = NULL;
sai = malloc(sizeof(struct sockaddr_in));
sai->sin_family = hostent->h_addrtype;
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: FFSocketAddressFamilies `{ 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 FFSocketHostent `{ struct hostent* `}
- private fun i_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(recv->h_aliases[i]); `}
+extern class NativeSocketHostent `{ struct hostent* `}
+ private fun native_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(self->h_aliases[i]); `}
- private fun i_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
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(*(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 FFTimeval `{ struct timeval* `}
+extern class NativeTimeval `{ struct timeval* `}
new (seconds: Int, microseconds: Int) `{
struct timeval* tv = NULL;
tv = malloc(sizeof(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 FFSocketSet `{ fd_set* `}
+extern class NativeSocketSet `{ fd_set* `}
new `{
fd_set *f = NULL;
f = malloc(sizeof(fd_set));
return f;
`}
- fun set(s: FFSocket) `{ FD_SET(*s, recv); `}
+ fun set(s: NativeSocket) `{ FD_SET(*s, self); `}
- fun is_set(s: FFSocket): 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: FFSocket) `{ FD_CLR(*s, recv); `}
+ fun clear(s: NativeSocket) `{ FD_CLR(*s, self); `}
- fun destroy `{ free(recv); `}
+ fun destroy `{ free(self); `}
end
-class FFSocketObserver
- fun select(max: FFSocket, reads: nullable FFSocketSet, write: nullable FFSocketSet,
- except: nullable FFSocketSet, timeout: FFTimeval): Int `{
+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;
`}
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; `}
# Unspecified
# 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_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; `}
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;`}
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 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 `}
+extern class NativeSocketPollValues `{ int `}
# Data other than high-priority data may be read without blocking.
new pollin `{ return POLLIN; `}
# This flag is only valid in the revents member; it shall ignored in the events member.
new pollnval `{ return POLLNVAL; `}
- # Combines two FFSocketPollValues
- private fun +(other: FFSocketPollValues): FFSocketPollValues `{
- return recv | other;
+ # Combines two NativeSocketPollValues
+ private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{
+ return self | other;
`}
end