1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S O C K E T S . T H I N --
11 -- Copyright (C) 2001 Ada Core Technologies, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
31 -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 ------------------------------------------------------------------------------
35 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
37 with Interfaces
.C
; use Interfaces
.C
;
39 package body GNAT
.Sockets
.Thin
is
41 -- When this package is initialized with Process_Blocking_IO set
42 -- to True, sockets are set in non-blocking mode to avoid blocking
43 -- the whole process when a thread wants to perform a blocking IO
44 -- operation. But the user can set a socket in non-blocking mode
45 -- by purpose. We track the socket in such a mode by redefining
46 -- C_Ioctl. In blocking IO operations, we exit normally when the
47 -- non-blocking flag is set by user, we poll and try later when
48 -- this flag is set automatically by this package.
50 type Socket_Info
is record
51 Non_Blocking
: Boolean := False;
54 Table
: array (C
.int
range 0 .. 31) of Socket_Info
;
55 -- Get info on blocking flag. This array is limited to 32 sockets
56 -- because the select operation allows socket set of less then 32
59 Quantum
: constant Duration := 0.2;
62 Thread_Blocking_IO
: Boolean := True;
64 function Syscall_Accept
66 Addr
: System
.Address
;
67 Addrlen
: access C
.int
)
69 pragma Import
(C
, Syscall_Accept
, "accept");
71 function Syscall_Connect
73 Name
: System
.Address
;
76 pragma Import
(C
, Syscall_Connect
, "connect");
78 function Syscall_Ioctl
83 pragma Import
(C
, Syscall_Ioctl
, "ioctl");
91 pragma Import
(C
, Syscall_Recv
, "recv");
93 function Syscall_Recvfrom
98 From
: Sockaddr_In_Access
;
99 Fromlen
: access C
.int
)
101 pragma Import
(C
, Syscall_Recvfrom
, "recvfrom");
103 function Syscall_Send
105 Msg
: System
.Address
;
109 pragma Import
(C
, Syscall_Send
, "send");
111 function Syscall_Sendto
113 Msg
: System
.Address
;
116 To
: Sockaddr_In_Access
;
119 pragma Import
(C
, Syscall_Sendto
, "sendto");
121 function Syscall_Socket
122 (Domain
, Typ
, Protocol
: C
.int
)
124 pragma Import
(C
, Syscall_Socket
, "socket");
126 procedure Set_Non_Blocking
(S
: C
.int
);
134 Addr
: System
.Address
;
135 Addrlen
: access C
.int
)
142 Res
:= Syscall_Accept
(S
, Addr
, Addrlen
);
143 exit when Thread_Blocking_IO
144 or else Res
/= Failure
145 or else Table
(S
).Non_Blocking
146 or else Errno
/= Constants
.EWOULDBLOCK
;
150 if not Thread_Blocking_IO
151 and then Res
/= Failure
153 -- A socket inherits the properties ot its server especially
156 Table
(Res
).Non_Blocking
:= Table
(S
).Non_Blocking
;
157 Set_Non_Blocking
(Res
);
169 Name
: System
.Address
;
176 Res
:= Syscall_Connect
(S
, Name
, Namelen
);
178 if Thread_Blocking_IO
179 or else Res
/= Failure
180 or else Table
(S
).Non_Blocking
181 or else Errno
/= Constants
.EINPROGRESS
187 Set
: aliased Fd_Set
;
188 Now
: aliased Timeval
;
192 Set
:= 2 ** Natural (S
);
196 null, Set
'Unchecked_Access,
197 null, Now
'Unchecked_Access);
201 if Res
= Failure
then
209 Res
:= Syscall_Connect
(S
, Name
, Namelen
);
212 and then Errno
= Constants
.EISCONN
231 if not Thread_Blocking_IO
232 and then Req
= Constants
.FIONBIO
234 Table
(S
).Non_Blocking
:= (Arg
.all /= 0);
237 return Syscall_Ioctl
(S
, Req
, Arg
);
246 Msg
: System
.Address
;
255 Res
:= Syscall_Recv
(S
, Msg
, Len
, Flags
);
256 exit when Thread_Blocking_IO
257 or else Res
/= Failure
258 or else Table
(S
).Non_Blocking
259 or else Errno
/= Constants
.EWOULDBLOCK
;
272 Msg
: System
.Address
;
275 From
: Sockaddr_In_Access
;
276 Fromlen
: access C
.int
)
283 Res
:= Syscall_Recvfrom
(S
, Msg
, Len
, Flags
, From
, Fromlen
);
284 exit when Thread_Blocking_IO
285 or else Res
/= Failure
286 or else Table
(S
).Non_Blocking
287 or else Errno
/= Constants
.EWOULDBLOCK
;
300 Msg
: System
.Address
;
309 Res
:= Syscall_Send
(S
, Msg
, Len
, Flags
);
310 exit when Thread_Blocking_IO
311 or else Res
/= Failure
312 or else Table
(S
).Non_Blocking
313 or else Errno
/= Constants
.EWOULDBLOCK
;
326 Msg
: System
.Address
;
329 To
: Sockaddr_In_Access
;
337 Res
:= Syscall_Sendto
(S
, Msg
, Len
, Flags
, To
, Tolen
);
338 exit when Thread_Blocking_IO
339 or else Res
/= Failure
340 or else Table
(S
).Non_Blocking
341 or else Errno
/= Constants
.EWOULDBLOCK
;
361 Res
:= Syscall_Socket
(Domain
, Typ
, Protocol
);
363 if not Thread_Blocking_IO
364 and then Res
/= Failure
366 Set_Non_Blocking
(Res
);
377 (Item
: in out Fd_Set
;
380 Mask
: constant Fd_Set
:= 2 ** Natural (Socket
);
383 if (Item
and Mask
) /= 0 then
384 Item
:= Item
xor Mask
;
392 procedure Empty
(Item
: in out Fd_Set
) is
401 procedure Finalize
is
410 procedure Initialize
(Process_Blocking_IO
: Boolean) is
412 Thread_Blocking_IO
:= not Process_Blocking_IO
;
419 function Is_Empty
(Item
: Fd_Set
) return Boolean is
428 function Is_Set
(Item
: Fd_Set
; Socket
: C
.int
) return Boolean is
430 return (Item
and 2 ** Natural (Socket
)) /= 0;
437 function Max
(Item
: Fd_Set
) return C
.int
454 procedure Set
(Item
: in out Fd_Set
; Socket
: in C
.int
) is
456 Item
:= Item
or 2 ** Natural (Socket
);
459 ----------------------
460 -- Set_Non_Blocking --
461 ----------------------
463 procedure Set_Non_Blocking
(S
: C
.int
) is
465 Val
: aliased C
.int
:= 1;
469 -- Do not use C_Fcntl because this subprogram tracks the
470 -- sockets set by user in non-blocking mode.
472 Res
:= Syscall_Ioctl
(S
, Constants
.FIONBIO
, Val
'Unchecked_Access);
473 end Set_Non_Blocking
;
475 --------------------------
476 -- Socket_Error_Message --
477 --------------------------
479 function Socket_Error_Message
(Errno
: Integer) return String is
480 use type Interfaces
.C
.Strings
.chars_ptr
;
482 C_Msg
: C
.Strings
.chars_ptr
;
485 C_Msg
:= C_Strerror
(C
.int
(Errno
));
487 if C_Msg
= C
.Strings
.Null_Ptr
then
488 return "Unknown system error";
491 return C
.Strings
.Value
(C_Msg
);
493 end Socket_Error_Message
;
495 end GNAT
.Sockets
.Thin
;