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>
33 typedef int S_DESCRIPTOR;
34 typedef struct sockaddr_in S_ADDR_IN;
35 typedef struct sockaddr S_ADDR;
36 typedef struct in_addr S_IN_ADDR;
37 typedef struct hostent S_HOSTENT;
38 typedef struct timeval S_TIMEVAL;
39 typedef struct sockaccept_result { S_ADDR_IN addr_in; S_DESCRIPTOR s_desc; } S_ACCEPT_RESULT;
40 typedef fd_set S_FD_SET;
41 typedef socklen_t S_LEN;
44 # Wrapper for the data structure PollFD used for polling on a socket
48 private var poll_struct
: FFSocketPollFD
50 # A collection of the events to be watched
51 var events
: Array[FFSocketPollValues]
53 init(pid
: Int, events
: Array[FFSocketPollValues])
55 assert events
.length
>= 1
58 var events_in_one
= events
[0]
60 for i
in [1 .. events
.length-1
] do
61 events_in_one
+= events
[i
]
64 self.poll_struct
= new FFSocketPollFD(pid
, events_in_one
)
67 # Reads the response and returns an array with the type of events that have been found
68 private fun check_response
(response
: Int): Array[FFSocketPollValues]
70 var resp_array
= new Array[FFSocketPollValues]
72 if c_check_resp
(response
, i
) != 0 then
79 # Checks if the poll call has returned true for a particular type of event
80 private fun c_check_resp
(response
: Int, mask
: FFSocketPollValues): Int
82 return response & mask;
87 # Data structure used by the poll function
88 private extern FFSocketPollFD `{ struct pollfd `}
90 private fun fd: Int `{ return recv.fd; `}
91 # List of events to be watched
92 private fun events
: Int `{ return recv.events; `}
93 # List of events received by the last poll function
94 private fun revents: Int `{ return recv.revents; `}
96 new (pid
: Int, events
: FFSocketPollValues) `{
105 extern FFSocket `{ S_DESCRIPTOR* `}
106 new socket(domain: FFSocketAddressFamilies, socketType: FFSocketTypes, protocol: FFSocketProtocolFamilies) `{
107 S_DESCRIPTOR *d
= NULL; d
= (S_DESCRIPTOR*) malloc
( sizeof
(S_DESCRIPTOR) );
108 int ds
= socket
(domain
, socketType
, protocol
);
113 memcpy
(d
, &ds
, sizeof
(ds
));
116 fun destroy `{ free(recv); `}
117 fun close
: Int `{ return close( *recv ); `}
118 fun descriptor: Int `{ return *recv; `}
119 fun errno
: Int `{ return errno; `}
121 fun gethostbyname(n: String): FFSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
122 fun connect
(addrIn
: FFSocketAddrIn): Int `{ return connect( *recv, (S_ADDR*)addrIn, sizeof(*addrIn) ); `}
123 fun write(buffer: String): Int import String.to_cstring, String.length `{ return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer)); `}
125 fun read
: String import NativeString.to_s
`{
126 char *c = (char*)malloc(1024);
127 int n = read(*recv, c, 1023);
130 return NativeString_to_s(c);
133 fun bind
(addrIn
: FFSocketAddrIn): Int `{ return bind(*recv, (S_ADDR*)addrIn, sizeof(*addrIn)); `}
134 fun listen(size: Int): Int `{ return listen(*recv, size); `}
136 # Checks if the buffer is ready for any event specified when creating the pollfd structure
137 fun socket_poll
(filedesc
: PollFD, timeout
: Int): Array[FFSocketPollValues]
139 var result
= i_poll
(filedesc
.poll_struct
, timeout
)
141 return filedesc
.check_response
(result
)
144 # Call to the poll function of the C socket
147 # int poll(struct pollfd fds[], nfds_t nfds, int timeout);
149 # Official documentation of the poll function :
151 # The poll() function provides applications with a mechanism for multiplexing input/output over a set of file descriptors.
152 # For each member of the array pointed to by fds, poll() shall examine the given file descriptor for the event(s) specified in events.
153 # The number of pollfd structures in the fds array is specified by nfds.
154 # The poll() function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred.
155 # The fds argument specifies the file descriptors to be examined and the events of interest for each file descriptor.
156 # It is a pointer to an array with one member for each open file descriptor of interest.
157 # The array's members are pollfd structures within which fd specifies an open file descriptor and events and revents are bitmasks constructed by
158 # OR'ing a combination of the pollfd flags.
159 private fun i_poll
(filedesc
: FFSocketPollFD, timeout
: Int): Int `{
160 int poll_return = poll(&filedesc, 1, timeout);
164 private fun i_accept
(addrIn
: FFSocketAddrIn): FFSocket `{
165 S_LEN s = sizeof(S_ADDR);
166 S_DESCRIPTOR *d = NULL;
167 d = malloc(sizeof(S_DESCRIPTOR));
168 *d = accept(*recv,(S_ADDR*)addrIn, &s);
171 fun accept
: FFSocketAcceptResult
173 var addrIn
= new FFSocketAddrIn
174 var s
= i_accept
(addrIn
)
175 return new FFSocketAcceptResult(s
, addrIn
)
179 extern FFSocketAcceptResult `{ S_ACCEPT_RESULT* `}
180 new (socket: FFSocket, addrIn: FFSocketAddrIn) `{
181 S_ACCEPT_RESULT *sar
= NULL;
182 sar
= malloc
( sizeof
(S_ACCEPT_RESULT) );
183 sar-
>s_desc
= *socket
;
184 sar-
>addr_in
= *addrIn
;
187 fun socket: FFSocket `{ return &recv->s_desc; `}
188 fun addrIn
: FFSocketAddrIn `{ return &recv->addr_in; `}
189 fun destroy `{ free(recv); `}
192 extern FFSocketAddrIn `{ S_ADDR_IN* `}
194 S_ADDR_IN *sai
= NULL;
195 sai
= malloc
( sizeof
(S_ADDR_IN) );
198 new with(port: Int, family: FFSocketAddressFamilies) `{
199 S_ADDR_IN *sai
= NULL;
200 sai
= malloc
( sizeof
(S_ADDR_IN) );
201 sai-
>sin_family
= family
;
202 sai-
>sin_port
= htons
(port
);
203 sai-
>sin_addr
.s_addr
= INADDR_ANY;
206 new with_hostent(hostent: FFSocketHostent, port: Int) `{
207 S_ADDR_IN *sai
= NULL;
208 sai
= malloc
( sizeof
(S_ADDR_IN) );
209 sai-
>sin_family
= hostent-
>h_addrtype
;
210 sai-
>sin_port
= htons
(port
);
211 memcpy
( (char
*)&sai-
>sin_addr
.s_addr
, (char
*)hostent-
>h_addr
, hostent-
>h_length
);
214 fun address: String import NativeString.to_s `{ return NativeString_to_s( (char*)inet_ntoa(recv->sin_addr) ); `}
215 fun family
: FFSocketAddressFamilies `{ return recv->sin_family; `}
216 fun port: Int `{ return ntohs(recv->sin_port); `}
217 fun destroy
`{ free(recv); `}
220 extern FFSocketHostent `{ S_HOSTENT* `}
221 private fun i_h_aliases
(i
: Int): String import NativeString.to_s
`{ return NativeString_to_s(recv->h_aliases[i]); `}
222 private fun i_h_aliases_reachable(i: Int): Bool `{ return (recv->h_aliases[i] != NULL); `}
223 fun h_aliases
: Array[String]
226 var d
=new Array[String]
228 d
.add
(i_h_aliases
(i
))
229 if i_h_aliases_reachable
(i
+1) == false then break
234 fun h_addr
: String import NativeString.to_s
`{ return NativeString_to_s( (char*)inet_ntoa(*(S_IN_ADDR*)recv->h_addr) ); `}
235 fun h_addrtype: Int `{ return recv->h_addrtype; `}
236 fun h_length
: Int `{ return recv->h_length; `}
237 fun h_name: String import NativeString.to_s `{ return NativeString_to_s(recv->h_name); `}
240 extern FFTimeval `{ S_TIMEVAL* `}
241 new (seconds: Int, microseconds: Int) `{
242 S_TIMEVAL* tv
= NULL;
243 tv
= malloc
( sizeof
(S_TIMEVAL) );
244 tv-
>tv_sec
= seconds
;
245 tv-
>tv_usec
= microseconds
;
248 fun seconds: Int `{ return recv->tv_sec; `}
249 fun microseconds
: Int `{ return recv->tv_usec; `}
250 fun destroy `{ free( recv ); `}
253 extern FFSocketSet `{ S_FD_SET* `}
256 f
= malloc
( sizeof
(S_FD_SET) );
259 fun set(s: FFSocket) `{ FD_SET( *s, recv ); `}
260 fun is_set
(s
: FFSocket): Bool `{ return FD_ISSET( *s, recv ); `}
261 fun zero `{ FD_ZERO( recv ); `}
262 fun clear
(s
: FFSocket) `{ FD_CLR( *s, recv ); `}
263 fun destroy `{ free( recv ); `}
266 class FFSocketObserver
267 fun select
(max
: FFSocket, reads
: nullable FFSocketSet, write
: nullable FFSocketSet,
268 except
: nullable FFSocketSet, timeout
: FFTimeval): Int `{
269 S_FD_SET *rds, *wts, *exs = NULL;
270 S_TIMEVAL *tm = NULL;
271 if(reads != NULL) rds = (S_FD_SET*)reads;
272 if(write != NULL) wts = (S_FD_SET*)write;
273 if(except != NULL) exs = (S_FD_SET*)except;
274 if(timeout != NULL) tm = (S_TIMEVAL*)timeout;
275 return select(*max, rds, wts, exs, tm);
279 extern FFSocketTypes `{ int `}
280 new sock_stream `{ return SOCK_STREAM; `}
281 new sock_dgram
`{ return SOCK_DGRAM; `}
282 new sock_raw `{ return SOCK_RAW; `}
283 new sock_seqpacket
`{ return SOCK_SEQPACKET; `}
285 extern FFSocketAddressFamilies `{ int `}
286 new af_null
`{ return 0; `}
287 new af_unspec `{ return AF_UNSPEC; `} # unspecified
288 new af_unix
`{ return AF_UNIX; `} # local to host (pipes)
289 new af_local `{ return AF_LOCAL; `} # backward compatibility
290 new af_inet
`{ return AF_INET; `} # internetwork: UDP, TCP, etc.
291 new af_sna `{ return AF_SNA; `} # IBM SNA
292 new af_decnet
`{ return AF_DECnet; `} # DECnet
293 new af_route `{ return AF_ROUTE; `} # Internal Routing Protocol
294 new af_ipx
`{ return AF_IPX; `} # Novell Internet Protocol
295 new af_isdn `{ return AF_ISDN; `} # Integrated Services Digital Network
296 new af_inet6
`{ return AF_INET6; `} # IPv6
297 new af_max `{ return AF_MAX; `}
299 extern FFSocketProtocolFamilies `{ int `}
300 new pf_null `{ return 0; `}
301 new pf_unspec
`{ return PF_UNSPEC; `}
302 new pf_local `{ return PF_LOCAL; `}
303 new pf_unix
`{ return PF_UNIX; `}
304 new pf_inet `{ return PF_INET; `}
305 new pf_sna
`{ return PF_SNA; `}
306 new pf_decnet `{ return PF_DECnet; `}
307 new pf_route
`{ return PF_ROUTE; `}
308 new pf_ipx `{ return PF_IPX; `}
309 new pf_isdn
`{ return PF_ISDN; `}
310 new pf_key `{ return PF_KEY; `}
311 new pf_inet6
`{ return PF_INET6; `}
312 new pf_max `{ return PF_MAX; `}
315 # Used for the poll function of a socket, mix several Poll values to check for events on more than one type of event
316 extern FFSocketPollValues `{ int `}
317 new pollin `{ return POLLIN; `} # Data other than high-priority data may be read without blocking.
318 new pollrdnorm
`{ return POLLRDNORM; `} # Normal data may be read without blocking.
319 new pollrdband `{ return POLLRDBAND; `} # Priority data may be read without blocking.
320 new pollpri
`{ return POLLPRI; `} # High-priority data may be read without blocking.
321 new pollout `{ return POLLOUT; `} # Normal data may be written without blocking.
322 new pollwrnorm
`{ return POLLWRNORM; `} # Equivalent to POLLOUT
323 new pollwrband `{ return POLLWRBAND; `} # Priority data may be written.
324 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.
325 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.
326 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.
328 # Combines two FFSocketPollValues
329 private fun +(other: FFSocketPollValues): FFSocketPollValues `{