df556386893b588c4b01e46439c0c77b443605df
[nit.git] / lib / socket / socket_c.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Low-level socket functionalities
18 module socket_c
19
20 in "C Header" `{
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <netdb.h>
30 #include <sys/poll.h>
31
32 `}
33
34 # Wrapper for the data structure PollFD used for polling on a socket
35 class PollFD
36
37 # The PollFD object
38 private var poll_struct: NativeSocketPollFD
39
40 # A collection of the events to be watched
41 var events: Array[NativeSocketPollValues]
42
43 init(pid: Int, events: Array[NativeSocketPollValues])
44 do
45 assert events.length >= 1
46 self.events = events
47
48 var events_in_one = events[0]
49
50 for i in [1 .. events.length-1] do
51 events_in_one += events[i]
52 end
53
54 self.poll_struct = new NativeSocketPollFD(pid, events_in_one)
55 end
56
57 # Reads the response and returns an array with the type of events that have been found
58 private fun check_response(response: Int): Array[NativeSocketPollValues]
59 do
60 var resp_array = new Array[NativeSocketPollValues]
61 for i in events do
62 if c_check_resp(response, i) != 0 then
63 resp_array.push(i)
64 end
65 end
66 return resp_array
67 end
68
69 # Checks if the poll call has returned true for a particular type of event
70 private fun c_check_resp(response: Int, mask: NativeSocketPollValues): Int
71 `{
72 return response & mask;
73 `}
74
75 end
76
77 # Data structure used by the poll function
78 private extern class NativeSocketPollFD `{ struct pollfd `}
79
80 # File descriptor id
81 private fun fd: Int `{ return recv.fd; `}
82
83 # List of events to be watched
84 private fun events: Int `{ return recv.events; `}
85
86 # List of events received by the last poll function
87 private fun revents: Int `{ return recv.revents; `}
88
89 new (pid: Int, events: NativeSocketPollValues) `{
90 struct pollfd poll;
91 poll.fd = pid;
92 poll.events = events;
93 return poll;
94 `}
95
96 end
97
98 extern class NativeSocket `{ int* `}
99
100 new socket(domain: NativeSocketAddressFamilies, socketType: NativeSocketTypes, protocol: NativeSocketProtocolFamilies) `{
101 int ds = socket(domain, socketType, protocol);
102 if(ds == -1){
103 return NULL;
104 }
105 int *d = malloc(sizeof(int));
106 memcpy(d, &ds, sizeof(ds));
107 return d;
108 `}
109
110 fun destroy `{ free(recv); `}
111
112 fun close: Int `{ return close(*recv); `}
113
114 fun descriptor: Int `{ return *recv; `}
115
116 fun gethostbyname(n: String): NativeSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
117
118 fun connect(addrIn: NativeSocketAddrIn): Int `{
119 return connect(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn));
120 `}
121
122 fun write(buffer: String): Int
123 import String.to_cstring, String.length `{
124 return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer));
125 `}
126
127 fun read: String import NativeString.to_s_with_length `{
128 static char c[1024];
129 int n = read(*recv, c, 1024);
130 if(n < 0) {
131 return NativeString_to_s_with_length("",0);
132 }
133 char* ret = malloc(n + 1);
134 memcpy(ret, c, n);
135 ret[n] = '\0';
136 return NativeString_to_s_with_length(ret, n);
137 `}
138
139 # Sets an option for the socket
140 fun setsockopt(level: NativeSocketOptLevels, option_name: NativeSocketOptNames, option_value: Int) `{
141 int err = setsockopt(*recv, level, option_name, &option_value, sizeof(int));
142 if(err != 0){
143 perror("Error on setsockopts: ");
144 exit(1);
145 }
146 `}
147
148 fun bind(addrIn: NativeSocketAddrIn): Int `{ return bind(*recv, (struct sockaddr*)addrIn, sizeof(*addrIn)); `}
149
150 fun listen(size: Int): Int `{ return listen(*recv, size); `}
151
152 # Checks if the buffer is ready for any event specified when creating the pollfd structure
153 fun socket_poll(filedesc: PollFD, timeout: Int): Array[NativeSocketPollValues]
154 do
155 var result = native_poll(filedesc.poll_struct, timeout)
156 assert result != -1
157 return filedesc.check_response(result)
158 end
159
160 # Call to the poll function of the C socket
161 #
162 # Signature:
163 # int poll(struct pollfd fds[], nfds_t nfds, int timeout);
164 #
165 # Official documentation of the poll function:
166 #
167 # The poll() function provides applications with a mechanism for multiplexing input/output over a set of file descriptors.
168 # For each member of the array pointed to by fds, poll() shall examine the given file descriptor for the event(s) specified in events.
169 # The number of pollfd structures in the fds array is specified by nfds.
170 # The poll() function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.
171 # The fds argument specifies the file descriptors to be examined and the events of interest for each file descriptor.
172 # It is a pointer to an array with one member for each open file descriptor of interest.
173 # The array's members are pollfd structures within which fd specifies an open file descriptor and events and revents are bitmasks constructed by
174 # OR'ing a combination of the pollfd flags.
175 private fun native_poll(filedesc: NativeSocketPollFD, timeout: Int): Int `{
176 int poll_return = poll(&filedesc, 1, timeout);
177 return poll_return;
178 `}
179
180 private fun native_accept(addrIn: NativeSocketAddrIn): NativeSocket `{
181 socklen_t s = sizeof(struct sockaddr);
182 int *d = NULL;
183 d = malloc(sizeof(int));
184 *d = accept(*recv,(struct sockaddr*)addrIn, &s);
185 return d;
186 `}
187
188 fun accept: nullable SocketAcceptResult
189 do
190 var addrIn = new NativeSocketAddrIn
191 var s = native_accept(addrIn)
192 return new SocketAcceptResult(s, addrIn)
193 end
194 end
195
196 # Result of a call to `NativeSocket::accept`
197 class SocketAcceptResult
198
199 # Opened socket
200 var socket: NativeSocket
201
202 # Address of the remote client
203 var addr_in: NativeSocketAddrIn
204 end
205
206 extern class NativeSocketAddrIn `{ struct sockaddr_in* `}
207 new `{
208 struct sockaddr_in *sai = NULL;
209 sai = malloc(sizeof(struct sockaddr_in));
210 return sai;
211 `}
212
213 new with(port: Int, family: NativeSocketAddressFamilies) `{
214 struct sockaddr_in *sai = NULL;
215 sai = malloc(sizeof(struct sockaddr_in));
216 sai->sin_family = family;
217 sai->sin_port = htons(port);
218 sai->sin_addr.s_addr = INADDR_ANY;
219 return sai;
220 `}
221
222 new with_hostent(hostent: NativeSocketHostent, port: Int) `{
223 struct sockaddr_in *sai = NULL;
224 sai = malloc(sizeof(struct sockaddr_in));
225 sai->sin_family = hostent->h_addrtype;
226 sai->sin_port = htons(port);
227 memcpy((char*)&sai->sin_addr.s_addr, (char*)hostent->h_addr, hostent->h_length);
228 return sai;
229 `}
230
231 fun address: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(recv->sin_addr)); `}
232
233 fun family: NativeSocketAddressFamilies `{ return recv->sin_family; `}
234
235 fun port: Int `{ return ntohs(recv->sin_port); `}
236
237 fun destroy `{ free(recv); `}
238 end
239
240 extern class NativeSocketHostent `{ struct hostent* `}
241 private fun native_h_aliases(i: Int): String import NativeString.to_s `{ return NativeString_to_s(recv->h_aliases[i]); `}
242
243 private fun native_h_aliases_reachable(i: Int): Bool `{ return (recv->h_aliases[i] != NULL); `}
244
245 fun h_aliases: Array[String]
246 do
247 var i=0
248 var d=new Array[String]
249 loop
250 d.add(native_h_aliases(i))
251 if native_h_aliases_reachable(i+1) == false then break
252 i += 1
253 end
254 return d
255 end
256
257 fun h_addr: String import NativeString.to_s `{ return NativeString_to_s((char*)inet_ntoa(*(struct in_addr*)recv->h_addr)); `}
258
259 fun h_addrtype: Int `{ return recv->h_addrtype; `}
260
261 fun h_length: Int `{ return recv->h_length; `}
262
263 fun h_name: String import NativeString.to_s `{ return NativeString_to_s(recv->h_name); `}
264 end
265
266 extern class NativeTimeval `{ struct timeval* `}
267 new (seconds: Int, microseconds: Int) `{
268 struct timeval* tv = NULL;
269 tv = malloc(sizeof(struct timeval));
270 tv->tv_sec = seconds;
271 tv->tv_usec = microseconds;
272 return tv;
273 `}
274
275 fun seconds: Int `{ return recv->tv_sec; `}
276
277 fun microseconds: Int `{ return recv->tv_usec; `}
278
279 fun destroy `{ free(recv); `}
280 end
281
282 extern class NativeSocketSet `{ fd_set* `}
283 new `{
284 fd_set *f = NULL;
285 f = malloc(sizeof(fd_set));
286 return f;
287 `}
288
289 fun set(s: NativeSocket) `{ FD_SET(*s, recv); `}
290
291 fun is_set(s: NativeSocket): Bool `{ return FD_ISSET(*s, recv); `}
292
293 fun zero `{ FD_ZERO(recv); `}
294
295 fun clear(s: NativeSocket) `{ FD_CLR(*s, recv); `}
296
297 fun destroy `{ free(recv); `}
298 end
299
300 class NativeSocketObserver
301 fun select(max: NativeSocket, reads: nullable NativeSocketSet, write: nullable NativeSocketSet,
302 except: nullable NativeSocketSet, timeout: NativeTimeval): Int `{
303 fd_set *rds, *wts, *exs = NULL;
304 struct timeval *tm = NULL;
305 if (reads != NULL) rds = (fd_set*)reads;
306 if (write != NULL) wts = (fd_set*)write;
307 if (except != NULL) exs = (fd_set*)except;
308 if (timeout != NULL) tm = (struct timeval*)timeout;
309 return select(*max, rds, wts, exs, tm);
310 `}
311 end
312
313 extern class NativeSocketTypes `{ int `}
314 new sock_stream `{ return SOCK_STREAM; `}
315 new sock_dgram `{ return SOCK_DGRAM; `}
316 new sock_raw `{ return SOCK_RAW; `}
317 new sock_seqpacket `{ return SOCK_SEQPACKET; `}
318 end
319
320 extern class NativeSocketAddressFamilies `{ int `}
321 new af_null `{ return 0; `}
322
323 # Unspecified
324 new af_unspec `{ return AF_UNSPEC; `}
325
326 # Local to host (pipes)
327 new af_unix `{ return AF_UNIX; `}
328
329 # For backward compatibility
330 new af_local `{ return AF_LOCAL; `}
331
332 # Internetwork: UDP, TCP, etc.
333 new af_inet `{ return AF_INET; `}
334
335 # IBM SNA
336 new af_sna `{ return AF_SNA; `}
337
338 # DECnet
339 new af_decnet `{ return AF_DECnet; `}
340
341 # Internal Routing Protocol
342 new af_route `{ return AF_ROUTE; `}
343
344 # Novell Internet Protocol
345 new af_ipx `{ return AF_IPX; `}
346
347 # Integrated Services Digital Network
348 new af_isdn `{ return AF_ISDN; `}
349
350 # IPv6
351 new af_inet6 `{ return AF_INET6; `}
352
353 new af_max `{ return AF_MAX; `}
354 end
355
356 extern class NativeSocketProtocolFamilies `{ int `}
357 new pf_null `{ return 0; `}
358 new pf_unspec `{ return PF_UNSPEC; `}
359 new pf_local `{ return PF_LOCAL; `}
360 new pf_unix `{ return PF_UNIX; `}
361 new pf_inet `{ return PF_INET; `}
362 new pf_sna `{ return PF_SNA; `}
363 new pf_decnet `{ return PF_DECnet; `}
364 new pf_route `{ return PF_ROUTE; `}
365 new pf_ipx `{ return PF_IPX; `}
366 new pf_isdn `{ return PF_ISDN; `}
367 new pf_key `{ return PF_KEY; `}
368 new pf_inet6 `{ return PF_INET6; `}
369 new pf_max `{ return PF_MAX; `}
370 end
371
372 # Level on which to set options
373 extern class NativeSocketOptLevels `{ int `}
374
375 # Dummy for IP (As defined in C)
376 new ip `{ return IPPROTO_IP;`}
377
378 # Control message protocol
379 new icmp `{ return IPPROTO_ICMP;`}
380
381 # Use TCP
382 new tcp `{ return IPPROTO_TCP; `}
383
384 # Socket level options
385 new socket `{ return SOL_SOCKET; `}
386 end
387
388 # Options for socket, use with setsockopt
389 extern class NativeSocketOptNames `{ int `}
390
391 # Enables debugging information
392 new debug `{ return SO_DEBUG; `}
393
394 # Authorizes the broadcasting of messages
395 new broadcast `{ return SO_BROADCAST; `}
396
397 # Authorizes the reuse of the local address
398 new reuseaddr `{ return SO_REUSEADDR; `}
399
400 # Authorizes the use of keep-alive packets in a connection
401 new keepalive `{ return SO_KEEPALIVE; `}
402 end
403
404 # Used for the poll function of a socket, mix several Poll values to check for events on more than one type of event
405 extern class NativeSocketPollValues `{ int `}
406
407 # Data other than high-priority data may be read without blocking.
408 new pollin `{ return POLLIN; `}
409
410 # Normal data may be read without blocking.
411 new pollrdnorm `{ return POLLRDNORM; `}
412
413 # Priority data may be read without blocking.
414 new pollrdband `{ return POLLRDBAND; `}
415
416 # High-priority data may be read without blocking.
417 new pollpri `{ return POLLPRI; `}
418
419 # Normal data may be written without blocking.
420 new pollout `{ return POLLOUT; `}
421
422 # Equivalent to POLLOUT
423 new pollwrnorm `{ return POLLWRNORM; `}
424
425 # Priority data may be written.
426 new pollwrband `{ return POLLWRBAND; `}
427
428 # An error has occurred on the device or stream.
429 #
430 # This flag is only valid in the revents bitmask; it shall be ignored in the events member.
431 new pollerr `{ return POLLERR; `}
432
433 # The device has been disconnected.
434 #
435 # This event and POLLOUT are mutually-exclusive; a stream can never be
436 # writable if a hangup has occurred. However, this event and POLLIN,
437 # POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive.
438 #
439 # This flag is only valid in the revents bitmask; it shall be ignored in the events member.
440 new pollhup `{ return POLLHUP; `}
441
442 # The specified fd value is invalid.
443 #
444 # This flag is only valid in the revents member; it shall ignored in the events member.
445 new pollnval `{ return POLLNVAL; `}
446
447 # Combines two NativeSocketPollValues
448 private fun +(other: NativeSocketPollValues): NativeSocketPollValues `{
449 return recv | other;
450 `}
451 end