11bda16aca52bdb3f97816adc7b6fda640a952e5
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Low-level socket functionalities
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
32 typedef int S_DESCRIPTOR;
33 typedef struct sockaddr_in S_ADDR_IN;
34 typedef struct sockaddr S_ADDR;
35 typedef struct in_addr S_IN_ADDR;
36 typedef struct hostent S_HOSTENT;
37 typedef struct timeval S_TIMEVAL;
38 typedef struct sockaccept_result { S_ADDR_IN addr_in; S_DESCRIPTOR s_desc; } S_ACCEPT_RESULT;
39 typedef fd_set S_FD_SET;
40 typedef socklen_t S_LEN;
43 # Wrapper for the data structure PollFD used for polling on a socket
47 private var poll_struct
: FFSocketPollFD
49 # A collection of the events to be watched
50 var events
: Array[FFSocketPollValues]
52 init(pid
: Int, events
: Array[FFSocketPollValues])
54 assert events
.length
>= 1
57 var events_in_one
= events
[0]
59 for i
in [1 .. events
.length-1
] do
60 events_in_one
+= events
[i
]
63 self.poll_struct
= new FFSocketPollFD(pid
, events_in_one
)
66 # Reads the response and returns an array with the type of events that have been found
67 private fun check_response
(response
: Int): Array[FFSocketPollValues]
69 var resp_array
= new Array[FFSocketPollValues]
71 if c_check_resp
(response
, i
) != 0 then
78 # Checks if the poll call has returned true for a particular type of event
79 private fun c_check_resp
(response
: Int, mask
: FFSocketPollValues): Int
81 return response & mask;
86 # Data structure used by the poll function
87 private extern FFSocketPollFD `{ struct pollfd `}
89 private fun fd: Int `{ return recv.fd; `}
90 # List of events to be watched
91 private fun events
: Int `{ return recv.events; `}
92 # List of events received by the last poll function
93 private fun revents: Int `{ return recv.revents; `}
95 new (pid
: Int, events
: FFSocketPollValues) `{
104 extern FFSocket `{ S_DESCRIPTOR* `}
105 new socket(domain: FFSocketAddressFamilies, socketType: FFSocketTypes, protocol: FFSocketProtocolFamilies) `{
106 S_DESCRIPTOR *d
= NULL; d
= (S_DESCRIPTOR*) malloc
( sizeof
(S_DESCRIPTOR) );
107 int ds
= socket
(domain
, socketType
, protocol
);
112 memcpy
(d
, &ds
, sizeof
(ds
));
115 fun destroy `{ free(recv); `}
116 fun close
: Int `{ return close( *recv ); `}
117 fun descriptor: Int `{ return *recv; `}
119 fun gethostbyname
(n
: String): FFSocketHostent import String.to_cstring
`{ return gethostbyname(String_to_cstring(n)); `}
120 fun connect(addrIn: FFSocketAddrIn): Int `{ return connect( *recv, (S_ADDR*)addrIn, sizeof(*addrIn) ); `}
121 fun write
(buffer
: String): Int import String.to_cstring
, String.length
`{ return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer)); `}
123 fun read: String import NativeString.to_s_with_length `{
125 int n
= read
(*recv
, c
, 1024);
128 return NativeString_to_s_with_length("",0);
130 char
* ret
= malloc
(n
+ 1);
134 return NativeString_to_s_with_length(ret
, n
);
137 # Sets an option for the socket
138 fun setsockopt(level: FFSocketOptLevels, option_name: FFSocketOptNames, option_value: Int) `{
139 int err
= setsockopt
(*recv
, level
, option_name
, &option_value
, sizeof
(int
));
141 perror
("Error on setsockopts : ");
146 fun bind(addrIn: FFSocketAddrIn): Int `{ return bind(*recv, (S_ADDR*)addrIn, sizeof(*addrIn)); `}
147 fun listen
(size
: Int): Int `{ return listen(*recv, size); `}
149 # Checks if the buffer is ready for any event specified when creating the pollfd structure
150 fun socket_poll(filedesc: PollFD, timeout: Int): Array[FFSocketPollValues]
152 var result = i_poll(filedesc.poll_struct, timeout)
154 return filedesc.check_response(result)
157 # Call to the poll function of the C socket
160 # int poll(struct pollfd fds[], nfds_t nfds, int timeout);
162 # Official documentation of the poll function :
164 # The poll() function provides applications with a mechanism for multiplexing input/output over a set of file descriptors.
165 # For each member of the array pointed to by fds, poll() shall examine the given file descriptor for the event(s) specified in events.
166 # The number of pollfd structures in the fds array is specified by nfds.
167 # The poll() function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.
168 # The fds argument specifies the file descriptors to be examined and the events of interest for each file descriptor.
169 # It is a pointer to an array with one member for each open file descriptor of interest.
170 # The array's members are pollfd structures within which fd specifies an open file descriptor and events and revents are bitmasks constructed by
171 # OR'ing a combination of the pollfd flags.
172 private fun i_poll(filedesc: FFSocketPollFD, timeout: Int): Int `{
173 int poll_return
= poll
(&filedesc
, 1, timeout
);
177 private fun i_accept(addrIn: FFSocketAddrIn): FFSocket `{
178 S_LEN s
= sizeof
(S_ADDR);
179 S_DESCRIPTOR *d
= NULL;
180 d
= malloc
(sizeof
(S_DESCRIPTOR));
181 *d
= accept
(*recv
,(S_ADDR*)addrIn
, &s
);
184 fun accept: FFSocketAcceptResult
186 var addrIn = new FFSocketAddrIn
187 var s = i_accept(addrIn)
188 return new FFSocketAcceptResult(s, addrIn)
192 extern FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
193 new (socket
: FFSocket, addrIn
: FFSocketAddrIn) `{
194 S_ACCEPT_RESULT *sar = NULL;
195 sar = malloc( sizeof(S_ACCEPT_RESULT) );
196 sar->s_desc = *socket;
197 sar->addr_in = *addrIn;
200 fun socket
: FFSocket `{ return &recv->s_desc; `}
201 fun addrIn: FFSocketAddrIn `{ return &recv->addr_in; `}
202 fun destroy
`{ free(recv); `}
205 extern FFSocketAddrIn `{ S_ADDR_IN* `}
207 S_ADDR_IN *sai = NULL;
208 sai = malloc( sizeof(S_ADDR_IN) );
211 new with
(port
: Int, family
: FFSocketAddressFamilies) `{
212 S_ADDR_IN *sai = NULL;
213 sai = malloc( sizeof(S_ADDR_IN) );
214 sai->sin_family = family;
215 sai->sin_port = htons(port);
216 sai->sin_addr.s_addr = INADDR_ANY;
219 new with_hostent
(hostent
: FFSocketHostent, port
: Int) `{
220 S_ADDR_IN *sai = NULL;
221 sai = malloc( sizeof(S_ADDR_IN) );
222 sai->sin_family = hostent->h_addrtype;
223 sai->sin_port = htons(port);
224 memcpy( (char*)&sai->sin_addr.s_addr, (char*)hostent->h_addr, hostent->h_length );
227 fun address
: String import NativeString.to_s
`{ return NativeString_to_s( (char*)inet_ntoa(recv->sin_addr) ); `}
228 fun family: FFSocketAddressFamilies `{ return recv->sin_family; `}
229 fun port
: Int `{ return ntohs(recv->sin_port); `}
230 fun destroy `{ free(recv); `}
233 extern FFSocketHostent `{ S_HOSTENT* `}
234 private fun i_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(recv->h_aliases[i]); `}
235 private fun i_h_aliases_reachable
(i
: Int): Bool `{ return (recv->h_aliases[i] != NULL); `}
236 fun h_aliases: Array[String]
239 var d=new Array[String]
241 d.add(i_h_aliases(i))
242 if i_h_aliases_reachable(i+1) == false then break
247 fun h_addr: String import NativeString.to_s `{ return NativeString_to_s( (char*)inet_ntoa(*(S_IN_ADDR*)recv->h_addr) ); `}
248 fun h_addrtype
: Int `{ return recv->h_addrtype; `}
249 fun h_length: Int `{ return recv->h_length; `}
250 fun h_name
: String import NativeString.to_s
`{ return NativeString_to_s(recv->h_name); `}
253 extern FFTimeval `{ S_TIMEVAL* `}
254 new (seconds
: Int, microseconds
: Int) `{
255 S_TIMEVAL* tv = NULL;
256 tv = malloc( sizeof(S_TIMEVAL) );
257 tv->tv_sec = seconds;
258 tv->tv_usec = microseconds;
261 fun seconds
: Int `{ return recv->tv_sec; `}
262 fun microseconds: Int `{ return recv->tv_usec; `}
263 fun destroy
`{ free( recv ); `}
266 extern FFSocketSet `{ S_FD_SET* `}
269 f = malloc( sizeof(S_FD_SET) );
272 fun set
(s
: FFSocket) `{ FD_SET( *s, recv ); `}
273 fun is_set(s: FFSocket): Bool `{ return FD_ISSET( *s, recv ); `}
274 fun zero
`{ FD_ZERO( recv ); `}
275 fun clear(s: FFSocket) `{ FD_CLR( *s, recv ); `}
276 fun destroy
`{ free( recv ); `}
279 class FFSocketObserver
280 fun select(max: FFSocket, reads: nullable FFSocketSet, write: nullable FFSocketSet,
281 except: nullable FFSocketSet, timeout: FFTimeval): Int `{
282 S_FD_SET *rds
, *wts
, *exs
= NULL;
283 S_TIMEVAL *tm
= NULL;
284 if(reads
!= NULL) rds
= (S_FD_SET*)reads
;
285 if(write
!= NULL) wts
= (S_FD_SET*)write
;
286 if(except
!= NULL) exs
= (S_FD_SET*)except
;
287 if(timeout
!= NULL) tm
= (S_TIMEVAL*)timeout
;
288 return select
(*max
, rds
, wts
, exs
, tm
);
292 extern FFSocketTypes `{ int `}
293 new sock_stream
`{ return SOCK_STREAM; `}
294 new sock_dgram `{ return SOCK_DGRAM; `}
295 new sock_raw
`{ return SOCK_RAW; `}
296 new sock_seqpacket `{ return SOCK_SEQPACKET; `}
298 extern FFSocketAddressFamilies `{ int `}
299 new af_null `{ return 0; `}
300 new af_unspec
`{ return AF_UNSPEC; `} # unspecified
301 new af_unix `{ return AF_UNIX; `} # local to host (pipes)
302 new af_local
`{ return AF_LOCAL; `} # backward compatibility
303 new af_inet `{ return AF_INET; `} # internetwork: UDP, TCP, etc.
304 new af_sna
`{ return AF_SNA; `} # IBM SNA
305 new af_decnet `{ return AF_DECnet; `} # DECnet
306 new af_route
`{ return AF_ROUTE; `} # Internal Routing Protocol
307 new af_ipx `{ return AF_IPX; `} # Novell Internet Protocol
308 new af_isdn
`{ return AF_ISDN; `} # Integrated Services Digital Network
309 new af_inet6 `{ return AF_INET6; `} # IPv6
310 new af_max
`{ return AF_MAX; `}
312 extern FFSocketProtocolFamilies `{ int `}
313 new pf_null
`{ return 0; `}
314 new pf_unspec `{ return PF_UNSPEC; `}
315 new pf_local
`{ return PF_LOCAL; `}
316 new pf_unix `{ return PF_UNIX; `}
317 new pf_inet
`{ return PF_INET; `}
318 new pf_sna `{ return PF_SNA; `}
319 new pf_decnet
`{ return PF_DECnet; `}
320 new pf_route `{ return PF_ROUTE; `}
321 new pf_ipx
`{ return PF_IPX; `}
322 new pf_isdn `{ return PF_ISDN; `}
323 new pf_key
`{ return PF_KEY; `}
324 new pf_inet6 `{ return PF_INET6; `}
325 new pf_max
`{ return PF_MAX; `}
327 # Level on which to set options
328 extern FFSocketOptLevels `{ int `}
329 # Dummy for IP (As defined in C)
330 new ip
`{ return IPPROTO_IP;`}
331 # Control message protocol
332 new icmp `{ return IPPROTO_ICMP;`}
334 new tcp
`{ return IPPROTO_TCP; `}
335 # Socket level options
336 new socket `{ return SOL_SOCKET; `}
338 # Options for socket, use with setsockopt
339 extern FFSocketOptNames `{ int `}
340 # Enables debugging information
341 new debug `{ return SO_DEBUG; `}
342 # Authorizes the broadcasting of messages
343 new broadcast
`{ return SO_BROADCAST; `}
344 # Authorizes the reuse of the local address
345 new reuseaddr `{ return SO_REUSEADDR; `}
346 # Authorizes the use of keep-alive packets in a connection
347 new keepalive
`{ return SO_KEEPALIVE; `}
349 # Used for the poll function of a socket, mix several Poll values to check for events on more than one type of event
350 extern FFSocketPollValues `{ int `}
351 new pollin
`{ return POLLIN; `} # Data other than high-priority data may be read without blocking.
352 new pollrdnorm `{ return POLLRDNORM; `} # Normal data may be read without blocking.
353 new pollrdband
`{ return POLLRDBAND; `} # Priority data may be read without blocking.
354 new pollpri `{ return POLLPRI; `} # High-priority data may be read without blocking.
355 new pollout
`{ return POLLOUT; `} # Normal data may be written without blocking.
356 new pollwrnorm `{ return POLLWRNORM; `} # Equivalent to POLLOUT
357 new pollwrband
`{ return POLLWRBAND; `} # Priority data may be written.
358 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.
359 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.
360 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.
362 # Combines two FFSocketPollValues
363 private fun +(other
: FFSocketPollValues): FFSocketPollValues `{