X-Git-Url: http://nitlanguage.org diff --git a/lib/socket/socket_c.nit b/lib/socket/socket_c.nit index 9930dc6..fbf2923 100644 --- a/lib/socket/socket_c.nit +++ b/lib/socket/socket_c.nit @@ -28,23 +28,24 @@ in "C Header" `{ #include #include #include +`} - typedef struct sockaccept_result { - struct sockaddr_in addr_in; - int s_desc; - } S_ACCEPT_RESULT; +in "C" `{ + #include + #include `} # 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 @@ -55,13 +56,13 @@ class PollFD 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) @@ -71,43 +72,45 @@ class PollFD 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 recv->fd; `} # List of events to be watched - private fun events: Int `{ return recv.events; `} + fun events: Int `{ return recv->events; `} # List of events received by the last poll function - private fun revents: Int `{ return recv.revents; `} + fun revents: Int `{ return recv->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; `} @@ -118,9 +121,9 @@ extern class FFSocket `{ int* `} fun descriptor: Int `{ return *recv; `} - 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 `{ + fun connect(addrIn: NativeSocketAddrIn): Int `{ return connect(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn)); `} @@ -129,35 +132,41 @@ extern class FFSocket `{ int* `} return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer)); `} - fun read: String import NativeString.to_s_with_length `{ + # Write `value` as a single byte + fun write_byte(value: Int): Int `{ + unsigned char byt = (unsigned char)value; + return write(*recv, &byt, 1); + `} + + fun read: String import NativeString.to_s_with_length, NativeString.to_s_with_copy `{ static char c[1024]; - int n = read(*recv, c, 1024); + int n = read(*recv, 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_copy(c); `} # Sets an option for the socket - fun setsockopt(level: FFSocketOptLevels, option_name: FFSocketOptNames, option_value: Int) `{ + # + # Returns `true` on success. + fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int): Bool `{ int err = setsockopt(*recv, 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(*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 @@ -177,51 +186,63 @@ extern class FFSocket `{ int* `} # 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(*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); `} +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; @@ -230,7 +251,7 @@ extern class FFSocketAddrIn `{ struct sockaddr_in* `} 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; @@ -241,25 +262,25 @@ extern class FFSocketAddrIn `{ struct sockaddr_in* `} 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 family: NativeSocketAddressFamilies `{ return recv->sin_family; `} fun port: Int `{ return ntohs(recv->sin_port); `} fun destroy `{ free(recv); `} 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(recv->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 (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 @@ -274,7 +295,7 @@ extern class FFSocketHostent `{ struct hostent* `} fun h_name: String import NativeString.to_s `{ return NativeString_to_s(recv->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)); @@ -290,27 +311,29 @@ extern class FFTimeval `{ struct timeval* `} fun destroy `{ free(recv); `} 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, recv); `} - fun is_set(s: FFSocket): Bool `{ return FD_ISSET(*s, recv); `} + fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, recv); `} fun zero `{ FD_ZERO(recv); `} - fun clear(s: FFSocket) `{ FD_CLR(*s, 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 `{ +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; @@ -321,14 +344,14 @@ class FFSocketObserver `} 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 @@ -355,16 +378,13 @@ extern class FFSocketAddressFamilies `{ int `} # 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; `} @@ -374,14 +394,13 @@ extern class FFSocketProtocolFamilies `{ int `} 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;`} @@ -397,7 +416,7 @@ extern class FFSocketOptLevels `{ int `} end # Options for socket, use with setsockopt -extern class FFSocketOptNames `{ int `} +extern class NativeSocketOptNames `{ int `} # Enables debugging information new debug `{ return SO_DEBUG; `} @@ -410,10 +429,13 @@ extern class FFSocketOptNames `{ int `} # 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; `} @@ -455,8 +477,8 @@ extern class FFSocketPollValues `{ int `} # 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 `{ + # Combines two NativeSocketPollValues + private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{ return recv | other; `} end