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 struct sockaccept_result {
33 struct sockaddr_in addr_in;
38 # Wrapper for the data structure PollFD used for polling on a socket
42 private var poll_struct
: NativeSocketPollFD
44 # A collection of the events to be watched
45 var events
: Array[NativeSocketPollValues]
47 init(pid
: Int, events
: Array[NativeSocketPollValues])
49 assert events
.length
>= 1
52 var events_in_one
= events
[0]
54 for i
in [1 .. events
.length-1
] do
55 events_in_one
+= events
[i
]
58 self.poll_struct
= new NativeSocketPollFD(pid
, events_in_one
)
61 # Reads the response and returns an array with the type of events that have been found
62 private fun check_response
(response
: Int): Array[NativeSocketPollValues]
64 var resp_array
= new Array[NativeSocketPollValues]
66 if c_check_resp
(response
, i
) != 0 then
73 # Checks if the poll call has returned true for a particular type of event
74 private fun c_check_resp
(response
: Int, mask
: NativeSocketPollValues): Int
76 return response & mask;
81 # Data structure used by the poll function
82 private extern class NativeSocketPollFD `{ struct pollfd `}
85 private fun fd: Int `{ return recv.fd; `}
87 # List of events to be watched
88 private fun events
: Int `{ return recv.events; `}
90 # List of events received by the last poll function
91 private fun revents: Int `{ return recv.revents; `}
93 new (pid
: Int, events
: NativeSocketPollValues) `{
102 extern class NativeSocket `{ int* `}
104 new socket(domain: NativeSocketAddressFamilies, socketType: NativeSocketTypes, protocol: NativeSocketProtocolFamilies) `{
105 int ds
= socket
(domain
, socketType
, protocol
);
109 int
*d
= malloc
(sizeof
(int
));
110 memcpy
(d
, &ds
, sizeof
(ds
));
114 fun destroy `{ free(recv); `}
116 fun close
: Int `{ return close(*recv); `}
118 fun descriptor: Int `{ return *recv; `}
120 fun gethostbyname
(n
: String): NativeSocketHostent import String.to_cstring
`{ return gethostbyname(String_to_cstring(n)); `}
122 fun connect(addrIn: NativeSocketAddrIn): Int `{
123 return connect
(*recv
, (struct sockaddr
*)addrIn
, sizeof
(*addrIn
));
126 fun write(buffer: String): Int
127 import String.to_cstring, String.length `{
128 return write
(*recv
, (char
*)String_to_cstring(buffer
), String_length(buffer
));
131 fun read: String import NativeString.to_s_with_length `{
133 int n
= read
(*recv
, c
, 1024);
135 return NativeString_to_s_with_length("",0);
137 char
* ret
= malloc
(n
+ 1);
140 return NativeString_to_s_with_length(ret
, n
);
143 # Sets an option for the socket
144 fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int) `{
145 int err
= setsockopt
(*recv
, level
, option_name
, &option_value
, sizeof
(int
));
147 perror
("Error on setsockopts: ");
152 fun bind(addrIn: NativeSocketAddrIn): Int `{ return bind(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn)); `}
154 fun listen
(size
: Int): Int `{ return listen(*recv, size); `}
156 # Checks if the buffer is ready for any event specified when creating the pollfd structure
157 fun socket_poll(filedesc: PollFD, timeout: Int): Array[NativeSocketPollValues]
159 var result = native_poll(filedesc.poll_struct, timeout)
161 return filedesc.check_response(result)
164 # Call to the poll function of the C socket
167 # int poll(struct pollfd fds[], nfds_t nfds, int timeout);
169 # Official documentation of the poll function:
171 # The poll() function provides applications with a mechanism for multiplexing input/output over a set of file descriptors.
172 # For each member of the array pointed to by fds, poll() shall examine the given file descriptor for the event(s) specified in events.
173 # The number of pollfd structures in the fds array is specified by nfds.
174 # The poll() function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.
175 # The fds argument specifies the file descriptors to be examined and the events of interest for each file descriptor.
176 # It is a pointer to an array with one member for each open file descriptor of interest.
177 # The array's members are pollfd structures within which fd specifies an open file descriptor and events and revents are bitmasks constructed by
178 # OR'ing a combination of the pollfd flags.
179 private fun native_poll(filedesc: NativeSocketPollFD, timeout: Int): Int `{
180 int poll_return
= poll
(&filedesc
, 1, timeout
);
184 private fun native_accept(addrIn: NativeSocketAddrIn): NativeSocket `{
185 socklen_t s
= sizeof
(struct sockaddr
);
187 d
= malloc
(sizeof
(int
));
188 *d
= accept
(*recv
,(struct sockaddr
*)addrIn
, &s
);
192 fun accept: NativeSocketAcceptResult
194 var addrIn = new NativeSocketAddrIn
195 var s = native_accept(addrIn)
196 return new NativeSocketAcceptResult(s, addrIn)
200 extern class NativeSocketAcceptResult `{ S_ACCEPT_RESULT* `}
201 new (socket
: NativeSocket, addrIn
: NativeSocketAddrIn) `{
202 S_ACCEPT_RESULT *sar = NULL;
203 sar = malloc(sizeof(S_ACCEPT_RESULT));
204 sar->s_desc = *socket;
205 sar->addr_in = *addrIn;
209 fun socket
: NativeSocket `{ return &recv->s_desc; `}
211 fun addrIn: NativeSocketAddrIn `{ return &recv->addr_in; `}
213 fun destroy
`{ free(recv); `}
216 extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
218 struct sockaddr_in *sai = NULL;
219 sai = malloc(sizeof(struct sockaddr_in));
223 new with
(port
: Int, family
: NativeSocketAddressFamilies) `{
224 struct sockaddr_in *sai = NULL;
225 sai = malloc(sizeof(struct sockaddr_in));
226 sai->sin_family = family;
227 sai->sin_port = htons(port);
228 sai->sin_addr.s_addr = INADDR_ANY;
232 new with_hostent
(hostent
: NativeSocketHostent, port
: Int) `{
233 struct sockaddr_in *sai = NULL;
234 sai = malloc(sizeof(struct sockaddr_in));
235 sai->sin_family = hostent->h_addrtype;
236 sai->sin_port = htons(port);
237 memcpy((char*)&sai->sin_addr.s_addr, (char*)hostent->h_addr, hostent->h_length);
241 fun address
: String import NativeString.to_s
`{ return NativeString_to_s((char*)inet_ntoa(recv->sin_addr)); `}
243 fun family: NativeSocketAddressFamilies `{ return recv->sin_family; `}
245 fun port
: Int `{ return ntohs(recv->sin_port); `}
247 fun destroy `{ free(recv); `}
250 extern class NativeSocketHostent `{ struct hostent* `}
251 private fun native_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(recv->h_aliases[i]); `}
253 private fun native_h_aliases_reachable
(i
: Int): Bool `{ return (recv->h_aliases[i] != NULL); `}
255 fun h_aliases: Array[String]
258 var d=new Array[String]
260 d.add(native_h_aliases(i))
261 if native_h_aliases_reachable(i+1) == false then break
267 fun h_addr: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(*(struct in_addr*)recv->h_addr)); `}
269 fun h_addrtype
: Int `{ return recv->h_addrtype; `}
271 fun h_length: Int `{ return recv->h_length; `}
273 fun h_name
: String import NativeString.to_s
`{ return NativeString_to_s(recv->h_name); `}
276 extern class NativeTimeval `{ struct timeval* `}
277 new (seconds
: Int, microseconds
: Int) `{
278 struct timeval* tv = NULL;
279 tv = malloc(sizeof(struct timeval));
280 tv->tv_sec = seconds;
281 tv->tv_usec = microseconds;
285 fun seconds
: Int `{ return recv->tv_sec; `}
287 fun microseconds: Int `{ return recv->tv_usec; `}
289 fun destroy
`{ free(recv); `}
292 extern class NativeSocketSet `{ fd_set* `}
295 f = malloc(sizeof(fd_set));
299 fun set
(s
: NativeSocket) `{ FD_SET(*s, recv); `}
301 fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, recv); `}
303 fun zero
`{ FD_ZERO(recv); `}
305 fun clear(s: NativeSocket) `{ FD_CLR(*s, recv); `}
307 fun destroy
`{ free(recv); `}
310 class NativeSocketObserver
311 fun select(max: NativeSocket, reads: nullable NativeSocketSet, write: nullable NativeSocketSet,
312 except: nullable NativeSocketSet, timeout: NativeTimeval): Int `{
313 fd_set
*rds
, *wts
, *exs
= NULL;
314 struct timeval
*tm
= NULL;
315 if (reads
!= NULL) rds
= (fd_set
*)reads
;
316 if (write
!= NULL) wts
= (fd_set
*)write
;
317 if (except
!= NULL) exs
= (fd_set
*)except
;
318 if (timeout
!= NULL) tm
= (struct timeval
*)timeout
;
319 return select
(*max
, rds
, wts
, exs
, tm
);
323 extern class NativeSocketTypes `{ int `}
324 new sock_stream
`{ return SOCK_STREAM; `}
325 new sock_dgram `{ return SOCK_DGRAM; `}
326 new sock_raw
`{ return SOCK_RAW; `}
327 new sock_seqpacket `{ return SOCK_SEQPACKET; `}
330 extern class NativeSocketAddressFamilies `{ int `}
331 new af_null `{ return 0; `}
334 new af_unspec
`{ return AF_UNSPEC; `}
336 # Local to host (pipes)
337 new af_unix `{ return AF_UNIX; `}
339 # For backward compatibility
340 new af_local
`{ return AF_LOCAL; `}
342 # Internetwork: UDP, TCP, etc.
343 new af_inet `{ return AF_INET; `}
346 new af_sna
`{ return AF_SNA; `}
349 new af_decnet `{ return AF_DECnet; `}
351 # Internal Routing Protocol
352 new af_route
`{ return AF_ROUTE; `}
354 # Novell Internet Protocol
355 new af_ipx `{ return AF_IPX; `}
357 # Integrated Services Digital Network
358 new af_isdn
`{ return AF_ISDN; `}
361 new af_inet6 `{ return AF_INET6; `}
363 new af_max
`{ return AF_MAX; `}
366 extern class NativeSocketProtocolFamilies `{ int `}
367 new pf_null
`{ return 0; `}
368 new pf_unspec `{ return PF_UNSPEC; `}
369 new pf_local
`{ return PF_LOCAL; `}
370 new pf_unix `{ return PF_UNIX; `}
371 new pf_inet
`{ return PF_INET; `}
372 new pf_sna `{ return PF_SNA; `}
373 new pf_decnet
`{ return PF_DECnet; `}
374 new pf_route `{ return PF_ROUTE; `}
375 new pf_ipx
`{ return PF_IPX; `}
376 new pf_isdn `{ return PF_ISDN; `}
377 new pf_key
`{ return PF_KEY; `}
378 new pf_inet6 `{ return PF_INET6; `}
379 new pf_max
`{ return PF_MAX; `}
382 # Level on which to set options
383 extern class NativeSocketOptLevels `{ int `}
385 # Dummy for IP (As defined in C)
386 new ip
`{ return IPPROTO_IP;`}
388 # Control message protocol
389 new icmp `{ return IPPROTO_ICMP;`}
392 new tcp
`{ return IPPROTO_TCP; `}
394 # Socket level options
395 new socket `{ return SOL_SOCKET; `}
398 # Options for socket, use with setsockopt
399 extern class NativeSocketOptNames `{ int `}
401 # Enables debugging information
402 new debug `{ return SO_DEBUG; `}
404 # Authorizes the broadcasting of messages
405 new broadcast
`{ return SO_BROADCAST; `}
407 # Authorizes the reuse of the local address
408 new reuseaddr `{ return SO_REUSEADDR; `}
410 # Authorizes the use of keep-alive packets in a connection
411 new keepalive
`{ return SO_KEEPALIVE; `}
414 # Used for the poll function of a socket, mix several Poll values to check for events on more than one type of event
415 extern class NativeSocketPollValues `{ int `}
417 # Data other than high-priority data may be read without blocking.
418 new pollin
`{ return POLLIN; `}
420 # Normal data may be read without blocking.
421 new pollrdnorm `{ return POLLRDNORM; `}
423 # Priority data may be read without blocking.
424 new pollrdband
`{ return POLLRDBAND; `}
426 # High-priority data may be read without blocking.
427 new pollpri `{ return POLLPRI; `}
429 # Normal data may be written without blocking.
430 new pollout
`{ return POLLOUT; `}
432 # Equivalent to POLLOUT
433 new pollwrnorm `{ return POLLWRNORM; `}
435 # Priority data may be written.
436 new pollwrband
`{ return POLLWRBAND; `}
438 # An error has occurred on the device or stream.
440 # This flag is only valid in the revents bitmask; it shall be ignored in the events member.
441 new pollerr `{ return POLLERR; `}
443 # The device has been disconnected.
445 # This event and POLLOUT are mutually-exclusive; a stream can never be
446 # writable if a hangup has occurred. However, this event and POLLIN,
447 # POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive.
449 # This flag is only valid in the revents bitmask; it shall be ignored in the events member.
450 new pollhup
`{ return POLLHUP; `}
452 # The specified fd value is invalid.
454 # This flag is only valid in the revents member; it shall ignored in the events member.
455 new pollnval `{ return POLLNVAL; `}
457 # Combines two NativeSocketPollValues
458 private fun +(other
: NativeSocketPollValues): NativeSocketPollValues `{