1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S O C K E T S --
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 Ada
.Streams
; use Ada
.Streams
;
36 with Ada
.Exceptions
; use Ada
.Exceptions
;
37 with Ada
.Unchecked_Deallocation
;
38 with Ada
.Unchecked_Conversion
;
40 with Interfaces
.C
.Strings
;
42 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
43 with GNAT
.Sockets
.Constants
;
44 with GNAT
.Sockets
.Thin
; use GNAT
.Sockets
.Thin
;
47 with GNAT
.Sockets
.Linker_Options
;
48 pragma Warnings
(Off
, GNAT
.Sockets
.Linker_Options
);
49 -- Need to include pragma Linker_Options which is platform dependent.
51 with System
; use System
;
53 package body GNAT
.Sockets
is
55 use type C
.int
, System
.Address
;
57 Finalized
: Boolean := False;
58 Initialized
: Boolean := False;
60 -- Correspondance tables
62 Families
: constant array (Family_Type
) of C
.int
:=
63 (Family_Inet
=> Constants
.AF_INET
,
64 Family_Inet6
=> Constants
.AF_INET6
);
66 Levels
: constant array (Level_Type
) of C
.int
:=
67 (Socket_Level
=> Constants
.SOL_SOCKET
,
68 IP_Protocol_For_IP_Level
=> Constants
.IPPROTO_IP
,
69 IP_Protocol_For_UDP_Level
=> Constants
.IPPROTO_UDP
,
70 IP_Protocol_For_TCP_Level
=> Constants
.IPPROTO_TCP
);
72 Modes
: constant array (Mode_Type
) of C
.int
:=
73 (Socket_Stream
=> Constants
.SOCK_STREAM
,
74 Socket_Datagram
=> Constants
.SOCK_DGRAM
);
76 Shutmodes
: constant array (Shutmode_Type
) of C
.int
:=
77 (Shut_Read
=> Constants
.SHUT_RD
,
78 Shut_Write
=> Constants
.SHUT_WR
,
79 Shut_Read_Write
=> Constants
.SHUT_RDWR
);
81 Requests
: constant array (Request_Name
) of C
.int
:=
82 (Non_Blocking_IO
=> Constants
.FIONBIO
,
83 N_Bytes_To_Read
=> Constants
.FIONREAD
);
85 Options
: constant array (Option_Name
) of C
.int
:=
86 (Keep_Alive
=> Constants
.SO_KEEPALIVE
,
87 Reuse_Address
=> Constants
.SO_REUSEADDR
,
88 Broadcast
=> Constants
.SO_BROADCAST
,
89 Send_Buffer
=> Constants
.SO_SNDBUF
,
90 Receive_Buffer
=> Constants
.SO_RCVBUF
,
91 Linger
=> Constants
.SO_LINGER
,
92 Error
=> Constants
.SO_ERROR
,
93 No_Delay
=> Constants
.TCP_NODELAY
,
94 Add_Membership
=> Constants
.IP_ADD_MEMBERSHIP
,
95 Drop_Membership
=> Constants
.IP_DROP_MEMBERSHIP
,
96 Multicast_TTL
=> Constants
.IP_MULTICAST_TTL
,
97 Multicast_Loop
=> Constants
.IP_MULTICAST_LOOP
);
99 Socket_Error_Id
: constant Exception_Id
:= Socket_Error
'Identity;
100 Host_Error_Id
: constant Exception_Id
:= Host_Error
'Identity;
102 Hex_To_Char
: constant String (1 .. 16) := "0123456789ABCDEF";
103 -- Use to print in hexadecimal format
105 function To_In_Addr
is new Ada
.Unchecked_Conversion
(C
.int
, In_Addr
);
106 function To_Int
is new Ada
.Unchecked_Conversion
(In_Addr
, C
.int
);
108 -----------------------
109 -- Local subprograms --
110 -----------------------
112 function Resolve_Error
113 (Error_Value
: Integer;
114 From_Errno
: Boolean := True)
116 -- Associate an enumeration value (error_type) to en error value
117 -- (errno). From_Errno prevents from mixing h_errno with errno.
119 function To_Host_Name
(N
: String) return Host_Name_Type
;
120 function To_String
(HN
: Host_Name_Type
) return String;
121 -- Conversion functions
123 function Port_To_Network
124 (Port
: C
.unsigned_short
)
125 return C
.unsigned_short
;
126 pragma Inline
(Port_To_Network
);
127 -- Convert a port number into a network port number
129 function Network_To_Port
130 (Net_Port
: C
.unsigned_short
)
131 return C
.unsigned_short
132 renames Port_To_Network
;
133 -- Symetric operation
136 (Val
: Inet_Addr_VN_Type
;
137 Hex
: Boolean := False)
139 -- Output an array of inet address components either in
140 -- hexadecimal or in decimal mode.
142 function To_In_Addr
(Addr
: Inet_Addr_Type
) return Thin
.In_Addr
;
143 function To_Inet_Addr
(Addr
: In_Addr
) return Inet_Addr_Type
;
144 -- Conversion functions
146 function To_Host_Entry
(Host
: Hostent
) return Host_Entry_Type
;
147 -- Conversion function
149 function To_Timeval
(Val
: Duration) return Timeval
;
150 -- Separate Val in seconds and microseconds
152 procedure Raise_Socket_Error
(Error
: Integer);
153 -- Raise Socket_Error with an exception message describing
156 procedure Raise_Host_Error
(Error
: Integer);
157 -- Raise Host_Error exception with message describing error code
158 -- (note hstrerror seems to be obsolete).
160 -- Types needed for Socket_Set_Type
162 type Socket_Set_Record
is new Fd_Set
;
165 new Ada
.Unchecked_Deallocation
(Socket_Set_Record
, Socket_Set_Type
);
167 -- Types needed for Datagram_Socket_Stream_Type
169 type Datagram_Socket_Stream_Type
is new Root_Stream_Type
with record
170 Socket
: Socket_Type
;
172 From
: Sock_Addr_Type
;
175 type Datagram_Socket_Stream_Access
is
176 access all Datagram_Socket_Stream_Type
;
179 (Stream
: in out Datagram_Socket_Stream_Type
;
180 Item
: out Ada
.Streams
.Stream_Element_Array
;
181 Last
: out Ada
.Streams
.Stream_Element_Offset
);
184 (Stream
: in out Datagram_Socket_Stream_Type
;
185 Item
: Ada
.Streams
.Stream_Element_Array
);
187 -- Types needed for Stream_Socket_Stream_Type
189 type Stream_Socket_Stream_Type
is new Root_Stream_Type
with record
190 Socket
: Socket_Type
;
193 type Stream_Socket_Stream_Access
is
194 access all Stream_Socket_Stream_Type
;
197 (Stream
: in out Stream_Socket_Stream_Type
;
198 Item
: out Ada
.Streams
.Stream_Element_Array
;
199 Last
: out Ada
.Streams
.Stream_Element_Offset
);
202 (Stream
: in out Stream_Socket_Stream_Type
;
203 Item
: Ada
.Streams
.Stream_Element_Array
);
209 procedure Abort_Selector
(Selector
: Selector_Type
) is
211 -- Send an empty array to unblock C select system call
213 if Selector
.In_Progress
then
218 Res
:= C_Write
(C
.int
(Selector
.W_Sig_Socket
), Buf
'Address, 0);
227 procedure Accept_Socket
228 (Server
: Socket_Type
;
229 Socket
: out Socket_Type
;
230 Address
: out Sock_Addr_Type
)
233 Sin
: aliased Sockaddr_In
;
234 Len
: aliased C
.int
:= Sin
'Size / 8;
237 Res
:= C_Accept
(C
.int
(Server
), Sin
'Address, Len
'Access);
238 if Res
= Failure
then
239 Raise_Socket_Error
(Socket_Errno
);
242 Socket
:= Socket_Type
(Res
);
244 Address
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
245 Address
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
253 (E
: Host_Entry_Type
;
255 return Inet_Addr_Type
258 return E
.Addresses
(N
);
261 ----------------------
262 -- Addresses_Length --
263 ----------------------
265 function Addresses_Length
(E
: Host_Entry_Type
) return Natural is
267 return E
.Addresses_Length
;
268 end Addresses_Length
;
275 (E
: Host_Entry_Type
;
280 return To_String
(E
.Aliases
(N
));
287 function Aliases_Length
(E
: Host_Entry_Type
) return Natural is
289 return E
.Aliases_Length
;
296 procedure Bind_Socket
297 (Socket
: Socket_Type
;
298 Address
: Sock_Addr_Type
)
301 Sin
: aliased Sockaddr_In
;
302 Len
: aliased C
.int
:= Sin
'Size / 8;
305 if Address
.Family
= Family_Inet6
then
309 Sin
.Sin_Family
:= C
.unsigned_short
(Families
(Address
.Family
));
310 Sin
.Sin_Port
:= Port_To_Network
(C
.unsigned_short
(Address
.Port
));
312 Res
:= C_Bind
(C
.int
(Socket
), Sin
'Address, Len
);
314 if Res
= Failure
then
315 Raise_Socket_Error
(Socket_Errno
);
323 procedure Check_Selector
324 (Selector
: in out Selector_Type
;
325 R_Socket_Set
: in out Socket_Set_Type
;
326 W_Socket_Set
: in out Socket_Set_Type
;
327 Status
: out Selector_Status
;
328 Timeout
: Duration := Forever
)
332 RSet
: aliased Fd_Set
;
333 WSet
: aliased Fd_Set
;
334 TVal
: aliased Timeval
;
335 TPtr
: Timeval_Access
;
340 -- No timeout or Forever is indicated by a null timeval pointer.
342 if Timeout
= Forever
then
345 TVal
:= To_Timeval
(Timeout
);
346 TPtr
:= TVal
'Unchecked_Access;
349 -- Copy R_Socket_Set in RSet and add read signalling socket.
351 if R_Socket_Set
= null then
354 RSet
:= Fd_Set
(R_Socket_Set
.all);
357 Set
(RSet
, C
.int
(Selector
.R_Sig_Socket
));
358 Len
:= Max
(RSet
) + 1;
360 -- Copy W_Socket_Set in WSet.
362 if W_Socket_Set
= null then
365 WSet
:= Fd_Set
(W_Socket_Set
.all);
367 Len
:= C
.int
'Max (Max
(RSet
) + 1, Len
);
369 Selector
.In_Progress
:= True;
373 RSet
'Unchecked_Access,
374 WSet
'Unchecked_Access,
376 Selector
.In_Progress
:= False;
378 -- If Select was resumed because of read signalling socket,
379 -- read this data and remove socket from set.
381 if Is_Set
(RSet
, C
.int
(Selector
.R_Sig_Socket
)) then
382 Clear
(RSet
, C
.int
(Selector
.R_Sig_Socket
));
387 Res
:= C_Read
(C
.int
(Selector
.R_Sig_Socket
), Buf
'Address, 0);
390 -- Select was resumed because of read signalling socket, but
391 -- the call is said aborted only when there is no other read
395 and then Is_Empty
(WSet
)
404 if R_Socket_Set
/= null then
405 R_Socket_Set
.all := Socket_Set_Record
(RSet
);
408 if W_Socket_Set
/= null then
409 W_Socket_Set
.all := Socket_Set_Record
(WSet
);
418 (Item
: in out Socket_Set_Type
;
419 Socket
: Socket_Type
)
423 Item
:= new Socket_Set_Record
;
424 Empty
(Fd_Set
(Item
.all));
427 Clear
(Fd_Set
(Item
.all), C
.int
(Socket
));
434 procedure Close_Selector
(Selector
: in out Selector_Type
) is
437 Close_Socket
(Selector
.R_Sig_Socket
);
438 exception when Socket_Error
=>
443 Close_Socket
(Selector
.W_Sig_Socket
);
444 exception when Socket_Error
=>
453 procedure Close_Socket
(Socket
: Socket_Type
) is
457 Res
:= C_Close
(C
.int
(Socket
));
459 if Res
= Failure
then
460 Raise_Socket_Error
(Socket_Errno
);
468 procedure Connect_Socket
469 (Socket
: Socket_Type
;
470 Server
: in out Sock_Addr_Type
)
473 Sin
: aliased Sockaddr_In
;
474 Len
: aliased C
.int
:= Sin
'Size / 8;
477 if Server
.Family
= Family_Inet6
then
481 Sin
.Sin_Family
:= C
.unsigned_short
(Families
(Server
.Family
));
482 Sin
.Sin_Addr
:= To_In_Addr
(Server
.Addr
);
483 Sin
.Sin_Port
:= Port_To_Network
(C
.unsigned_short
(Server
.Port
));
485 Res
:= C_Connect
(C
.int
(Socket
), Sin
'Address, Len
);
487 if Res
= Failure
then
488 Raise_Socket_Error
(Socket_Errno
);
496 procedure Control_Socket
497 (Socket
: Socket_Type
;
498 Request
: in out Request_Type
)
505 when Non_Blocking_IO
=>
506 Arg
:= C
.int
(Boolean'Pos (Request
.Enabled
));
508 when N_Bytes_To_Read
=>
515 Requests
(Request
.Name
),
516 Arg
'Unchecked_Access);
518 if Res
= Failure
then
519 Raise_Socket_Error
(Socket_Errno
);
523 when Non_Blocking_IO
=>
526 when N_Bytes_To_Read
=>
527 Request
.Size
:= Natural (Arg
);
532 ---------------------
533 -- Create_Selector --
534 ---------------------
536 procedure Create_Selector
(Selector
: out Selector_Type
) is
541 Sin
: aliased Sockaddr_In
;
542 Len
: aliased C
.int
:= Sin
'Size / 8;
546 -- We open two signalling sockets. One socket to send a signal
547 -- to a another socket that always included in a C_Select
548 -- socket set. When received, it resumes the task suspended in
551 -- Create a listening socket
553 S0
:= C_Socket
(Constants
.AF_INET
, Constants
.SOCK_STREAM
, 0);
555 Raise_Socket_Error
(Socket_Errno
);
558 -- Sin is already correctly initialized. Bind the socket to any
561 Res
:= C_Bind
(S0
, Sin
'Address, Len
);
562 if Res
= Failure
then
565 Raise_Socket_Error
(Err
);
568 -- Get the port used by the socket
570 Res
:= C_Getsockname
(S0
, Sin
'Address, Len
'Access);
571 if Res
= Failure
then
574 Raise_Socket_Error
(Err
);
577 Res
:= C_Listen
(S0
, 2);
578 if Res
= Failure
then
581 Raise_Socket_Error
(Err
);
584 S1
:= C_Socket
(Constants
.AF_INET
, Constants
.SOCK_STREAM
, 0);
588 Raise_Socket_Error
(Err
);
591 -- Use INADDR_LOOPBACK
593 Sin
.Sin_Addr
.S_B1
:= 127;
594 Sin
.Sin_Addr
.S_B2
:= 0;
595 Sin
.Sin_Addr
.S_B3
:= 0;
596 Sin
.Sin_Addr
.S_B4
:= 1;
598 -- Do a connect and accept the connection
600 Res
:= C_Connect
(S1
, Sin
'Address, Len
);
601 if Res
= Failure
then
605 Raise_Socket_Error
(Err
);
608 S2
:= C_Accept
(S0
, Sin
'Address, Len
'Access);
613 Raise_Socket_Error
(Err
);
617 if Res
= Failure
then
618 Raise_Socket_Error
(Socket_Errno
);
621 Selector
.R_Sig_Socket
:= Socket_Type
(S1
);
622 Selector
.W_Sig_Socket
:= Socket_Type
(S2
);
629 procedure Create_Socket
630 (Socket
: out Socket_Type
;
631 Family
: Family_Type
:= Family_Inet
;
632 Mode
: Mode_Type
:= Socket_Stream
)
637 Res
:= C_Socket
(Families
(Family
), Modes
(Mode
), 0);
639 if Res
= Failure
then
640 Raise_Socket_Error
(Socket_Errno
);
643 Socket
:= Socket_Type
(Res
);
650 procedure Empty
(Item
: in out Socket_Set_Type
) is
661 procedure Finalize
is
675 function Get_Address
(Stream
: Stream_Access
) return Sock_Addr_Type
is
677 if Stream
= null then
680 elsif Stream
.all in Datagram_Socket_Stream_Type
then
681 return Datagram_Socket_Stream_Type
(Stream
.all).From
;
684 return Get_Peer_Name
(Stream_Socket_Stream_Type
(Stream
.all).Socket
);
688 -------------------------
689 -- Get_Host_By_Address --
690 -------------------------
692 function Get_Host_By_Address
693 (Address
: Inet_Addr_Type
;
694 Family
: Family_Type
:= Family_Inet
)
695 return Host_Entry_Type
697 HA
: aliased In_Addr
:= To_In_Addr
(Address
);
698 Res
: Hostent_Access
;
702 -- This C function is not always thread-safe. Protect against
703 -- concurrent access.
706 Res
:= C_Gethostbyaddr
(HA
'Address, HA
'Size / 8, Constants
.AF_INET
);
711 Raise_Host_Error
(Err
);
714 -- Translate from the C format to the API format
717 HE
: Host_Entry_Type
:= To_Host_Entry
(Res
.all);
723 end Get_Host_By_Address
;
725 ----------------------
726 -- Get_Host_By_Name --
727 ----------------------
729 function Get_Host_By_Name
731 return Host_Entry_Type
733 HN
: C
.char_array
:= C
.To_C
(Name
);
734 Res
: Hostent_Access
;
738 -- This C function is not always thread-safe. Protect against
739 -- concurrent access.
742 Res
:= C_Gethostbyname
(HN
);
747 Raise_Host_Error
(Err
);
750 -- Translate from the C format to the API format
753 HE
: Host_Entry_Type
:= To_Host_Entry
(Res
.all);
759 end Get_Host_By_Name
;
765 function Get_Peer_Name
766 (Socket
: Socket_Type
)
767 return Sock_Addr_Type
769 Sin
: aliased Sockaddr_In
;
770 Len
: aliased C
.int
:= Sin
'Size / 8;
771 Res
: Sock_Addr_Type
(Family_Inet
);
774 if C_Getpeername
(C
.int
(Socket
), Sin
'Address, Len
'Access) = Failure
then
775 Raise_Socket_Error
(Socket_Errno
);
778 Res
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
779 Res
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
784 ---------------------
785 -- Get_Socket_Name --
786 ---------------------
788 function Get_Socket_Name
789 (Socket
: Socket_Type
)
790 return Sock_Addr_Type
792 Sin
: aliased Sockaddr_In
;
793 Len
: aliased C
.int
:= Sin
'Size / 8;
794 Res
: Sock_Addr_Type
(Family_Inet
);
797 if C_Getsockname
(C
.int
(Socket
), Sin
'Address, Len
'Access) = Failure
then
798 Raise_Socket_Error
(Socket_Errno
);
801 Res
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
802 Res
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
807 -----------------------
808 -- Get_Socket_Option --
809 -----------------------
811 function Get_Socket_Option
812 (Socket
: Socket_Type
;
813 Level
: Level_Type
:= Socket_Level
;
817 use type C
.unsigned_char
;
819 V8
: aliased Two_Int
;
821 V1
: aliased C
.unsigned_char
;
823 Add
: System
.Address
;
825 Opt
: Option_Type
(Name
);
829 when Multicast_Loop |
856 Add
, Len
'Unchecked_Access);
858 if Res
= Failure
then
859 Raise_Socket_Error
(Socket_Errno
);
867 Opt
.Enabled
:= (V4
/= 0);
870 Opt
.Enabled
:= (V8
(V8
'First) /= 0);
871 Opt
.Seconds
:= Natural (V8
(V8
'Last));
875 Opt
.Size
:= Natural (V4
);
878 Opt
.Error
:= Resolve_Error
(Integer (V4
));
880 when Add_Membership |
882 Opt
.Multiaddr
:= To_Inet_Addr
(To_In_Addr
(V8
(V8
'First)));
883 Opt
.Interface
:= To_Inet_Addr
(To_In_Addr
(V8
(V8
'Last)));
885 when Multicast_TTL
=>
886 Opt
.Time_To_Live
:= Integer (V1
);
888 when Multicast_Loop
=>
889 Opt
.Enabled
:= (V1
/= 0);
894 end Get_Socket_Option
;
900 function Host_Name
return String is
901 Name
: aliased C
.char_array
(1 .. 64);
905 Res
:= C_Gethostname
(Name
'Address, Name
'Length);
907 if Res
= Failure
then
908 Raise_Socket_Error
(Socket_Errno
);
911 return C
.To_Ada
(Name
);
919 (Val
: Inet_Addr_VN_Type
;
920 Hex
: Boolean := False)
923 -- The largest Inet_Addr_Comp_Type image occurs with IPv4. It
924 -- has at most a length of 3 plus one '.' character.
926 Buffer
: String (1 .. 4 * Val
'Length);
927 Length
: Natural := 1;
928 Separator
: Character;
930 procedure Img10
(V
: Inet_Addr_Comp_Type
);
931 -- Append to Buffer image of V in decimal format
933 procedure Img16
(V
: Inet_Addr_Comp_Type
);
934 -- Append to Buffer image of V in hexadecimal format
936 procedure Img10
(V
: Inet_Addr_Comp_Type
) is
937 Img
: constant String := V
'Img;
938 Len
: Natural := Img
'Length - 1;
941 Buffer
(Length
.. Length
+ Len
- 1) := Img
(2 .. Img
'Last);
942 Length
:= Length
+ Len
;
945 procedure Img16
(V
: Inet_Addr_Comp_Type
) is
947 Buffer
(Length
) := Hex_To_Char
(Natural (V
/ 16) + 1);
948 Buffer
(Length
+ 1) := Hex_To_Char
(Natural (V
mod 16) + 1);
949 Length
:= Length
+ 2;
952 -- Start of processing for Image
961 for J
in Val
'Range loop
968 if J
/= Val
'Last then
969 Buffer
(Length
) := Separator
;
970 Length
:= Length
+ 1;
974 return Buffer
(1 .. Length
- 1);
981 function Image
(Value
: Inet_Addr_Type
) return String is
983 if Value
.Family
= Family_Inet
then
984 return Image
(Inet_Addr_VN_Type
(Value
.Sin_V4
), Hex
=> False);
986 return Image
(Inet_Addr_VN_Type
(Value
.Sin_V6
), Hex
=> True);
994 function Image
(Value
: Sock_Addr_Type
) return String is
995 Port
: constant String := Value
.Port
'Img;
998 return Image
(Value
.Addr
) & ':' & Port
(2 .. Port
'Last);
1005 function Image
(Socket
: Socket_Type
) return String is
1014 function Inet_Addr
(Image
: String) return Inet_Addr_Type
is
1015 use Interfaces
.C
.Strings
;
1017 Img
: chars_ptr
:= New_String
(Image
);
1022 Res
:= C_Inet_Addr
(Img
);
1026 if Res
= Failure
then
1027 Raise_Socket_Error
(Err
);
1030 return To_Inet_Addr
(To_In_Addr
(Res
));
1037 procedure Initialize
(Process_Blocking_IO
: Boolean := False) is
1039 if not Initialized
then
1040 Initialized
:= True;
1041 Thin
.Initialize
(Process_Blocking_IO
);
1049 function Is_Empty
(Item
: Socket_Set_Type
) return Boolean is
1051 return Item
= null or else Is_Empty
(Fd_Set
(Item
.all));
1059 (Item
: Socket_Set_Type
;
1060 Socket
: Socket_Type
) return Boolean
1064 and then Is_Set
(Fd_Set
(Item
.all), C
.int
(Socket
));
1071 procedure Listen_Socket
1072 (Socket
: Socket_Type
;
1073 Length
: Positive := 15)
1078 Res
:= C_Listen
(C
.int
(Socket
), C
.int
(Length
));
1079 if Res
= Failure
then
1080 Raise_Socket_Error
(Socket_Errno
);
1088 function Official_Name
(E
: Host_Entry_Type
) return String is
1090 return To_String
(E
.Official
);
1093 ---------------------
1094 -- Port_To_Network --
1095 ---------------------
1097 function Port_To_Network
1098 (Port
: C
.unsigned_short
)
1099 return C
.unsigned_short
1101 use type C
.unsigned_short
;
1103 if Default_Bit_Order
= High_Order_First
then
1105 -- No conversion needed. On these platforms, htons() defaults
1106 -- to a null procedure.
1111 -- We need to swap the high and low byte on this short to make
1112 -- the port number network compliant.
1114 return (Port
/ 256) + (Port
mod 256) * 256;
1116 end Port_To_Network
;
1118 ----------------------
1119 -- Raise_Host_Error --
1120 ----------------------
1122 procedure Raise_Host_Error
(Error
: Integer) is
1124 function Error_Message
return String;
1125 -- We do not use a C function like strerror because hstrerror
1126 -- that would correspond seems to be obsolete. Return
1127 -- appropriate string for error value.
1129 function Error_Message
return String is
1132 when Constants
.HOST_NOT_FOUND
=> return "Host not found";
1133 when Constants
.TRY_AGAIN
=> return "Try again";
1134 when Constants
.NO_RECOVERY
=> return "No recovery";
1135 when Constants
.NO_ADDRESS
=> return "No address";
1136 when others => return "Unknown error";
1140 -- Start of processing for Raise_Host_Error
1143 Ada
.Exceptions
.Raise_Exception
(Host_Error
'Identity, Error_Message
);
1144 end Raise_Host_Error
;
1146 ------------------------
1147 -- Raise_Socket_Error --
1148 ------------------------
1150 procedure Raise_Socket_Error
(Error
: Integer) is
1151 use type C
.Strings
.chars_ptr
;
1153 function Image
(E
: Integer) return String;
1154 function Image
(E
: Integer) return String is
1155 Msg
: String := E
'Img & "] ";
1157 Msg
(Msg
'First) := '[';
1162 Ada
.Exceptions
.Raise_Exception
1163 (Socket_Error
'Identity, Image
(Error
) & Socket_Error_Message
(Error
));
1164 end Raise_Socket_Error
;
1171 (Stream
: in out Datagram_Socket_Stream_Type
;
1172 Item
: out Ada
.Streams
.Stream_Element_Array
;
1173 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1175 First
: Ada
.Streams
.Stream_Element_Offset
:= Item
'First;
1176 Index
: Ada
.Streams
.Stream_Element_Offset
:= First
- 1;
1177 Max
: constant Ada
.Streams
.Stream_Element_Offset
:= Item
'Last;
1183 Item
(First
.. Max
),
1189 -- Exit when all or zero data received. Zero means that
1190 -- the socket peer is closed.
1192 exit when Index
< First
or else Index
= Max
;
1203 (Stream
: in out Stream_Socket_Stream_Type
;
1204 Item
: out Ada
.Streams
.Stream_Element_Array
;
1205 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1207 First
: Ada
.Streams
.Stream_Element_Offset
:= Item
'First;
1208 Index
: Ada
.Streams
.Stream_Element_Offset
:= First
- 1;
1209 Max
: constant Ada
.Streams
.Stream_Element_Offset
:= Item
'Last;
1213 Receive_Socket
(Stream
.Socket
, Item
(First
.. Max
), Index
);
1216 -- Exit when all or zero data received. Zero means that
1217 -- the socket peer is closed.
1219 exit when Index
< First
or else Index
= Max
;
1229 function Resolve_Error
1230 (Error_Value
: Integer;
1231 From_Errno
: Boolean := True)
1234 use GNAT
.Sockets
.Constants
;
1237 if not From_Errno
then
1239 when HOST_NOT_FOUND
=> return Unknown_Host
;
1240 when TRY_AGAIN
=> return Host_Name_Lookup_Failure
;
1241 when NO_RECOVERY
=> return No_Address_Associated_With_Name
;
1242 when NO_ADDRESS
=> return Unknown_Server_Error
;
1243 when others => return Cannot_Resolve_Error
;
1247 when EACCES
=> return Permission_Denied
;
1248 when EADDRINUSE
=> return Address_Already_In_Use
;
1249 when EADDRNOTAVAIL
=> return Cannot_Assign_Requested_Address
;
1250 when EAFNOSUPPORT
=>
1251 return Address_Family_Not_Supported_By_Protocol
;
1252 when EALREADY
=> return Operation_Already_In_Progress
;
1253 when EBADF
=> return Bad_File_Descriptor
;
1254 when ECONNREFUSED
=> return Connection_Refused
;
1255 when EFAULT
=> return Bad_Address
;
1256 when EINPROGRESS
=> return Operation_Now_In_Progress
;
1257 when EINTR
=> return Interrupted_System_Call
;
1258 when EINVAL
=> return Invalid_Argument
;
1259 when EIO
=> return Input_Output_Error
;
1260 when EISCONN
=> return Transport_Endpoint_Already_Connected
;
1261 when EMSGSIZE
=> return Message_Too_Long
;
1262 when ENETUNREACH
=> return Network_Is_Unreachable
;
1263 when ENOBUFS
=> return No_Buffer_Space_Available
;
1264 when ENOPROTOOPT
=> return Protocol_Not_Available
;
1265 when ENOTCONN
=> return Transport_Endpoint_Not_Connected
;
1266 when EOPNOTSUPP
=> return Operation_Not_Supported
;
1267 when EPROTONOSUPPORT
=> return Protocol_Not_Supported
;
1268 when ESOCKTNOSUPPORT
=> return Socket_Type_Not_Supported
;
1269 when ETIMEDOUT
=> return Connection_Timed_Out
;
1270 when EWOULDBLOCK
=> return Resource_Temporarily_Unavailable
;
1271 when others => return Cannot_Resolve_Error
;
1275 -----------------------
1276 -- Resolve_Exception --
1277 -----------------------
1279 function Resolve_Exception
1280 (Occurrence
: Exception_Occurrence
)
1283 Id
: Exception_Id
:= Exception_Identity
(Occurrence
);
1284 Msg
: constant String := Exception_Message
(Occurrence
);
1285 First
: Natural := Msg
'First;
1290 while First
<= Msg
'Last
1291 and then Msg
(First
) not in '0' .. '9'
1296 if First
> Msg
'Last then
1297 return Cannot_Resolve_Error
;
1302 while Last
< Msg
'Last
1303 and then Msg
(Last
+ 1) in '0' .. '9'
1308 Val
:= Integer'Value (Msg
(First
.. Last
));
1310 if Id
= Socket_Error_Id
then
1311 return Resolve_Error
(Val
);
1313 elsif Id
= Host_Error_Id
then
1314 return Resolve_Error
(Val
, False);
1317 return Cannot_Resolve_Error
;
1319 end Resolve_Exception
;
1321 --------------------
1322 -- Receive_Socket --
1323 --------------------
1325 procedure Receive_Socket
1326 (Socket
: Socket_Type
;
1327 Item
: out Ada
.Streams
.Stream_Element_Array
;
1328 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1330 use type Ada
.Streams
.Stream_Element_Offset
;
1337 Item
(Item
'First)'Address,
1340 if Res
= Failure
then
1341 Raise_Socket_Error
(Socket_Errno
);
1344 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1347 --------------------
1348 -- Receive_Socket --
1349 --------------------
1351 procedure Receive_Socket
1352 (Socket
: Socket_Type
;
1353 Item
: out Ada
.Streams
.Stream_Element_Array
;
1354 Last
: out Ada
.Streams
.Stream_Element_Offset
;
1355 From
: out Sock_Addr_Type
)
1357 use type Ada
.Streams
.Stream_Element_Offset
;
1360 Sin
: aliased Sockaddr_In
;
1361 Len
: aliased C
.int
:= Sin
'Size / 8;
1366 Item
(Item
'First)'Address,
1368 Sin
'Unchecked_Access,
1369 Len
'Unchecked_Access);
1371 if Res
= Failure
then
1372 Raise_Socket_Error
(Socket_Errno
);
1375 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1377 From
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
1378 From
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
1385 procedure Send_Socket
1386 (Socket
: Socket_Type
;
1387 Item
: Ada
.Streams
.Stream_Element_Array
;
1388 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1390 use type Ada
.Streams
.Stream_Element_Offset
;
1397 Item
(Item
'First)'Address,
1400 if Res
= Failure
then
1401 Raise_Socket_Error
(Socket_Errno
);
1404 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1411 procedure Send_Socket
1412 (Socket
: Socket_Type
;
1413 Item
: Ada
.Streams
.Stream_Element_Array
;
1414 Last
: out Ada
.Streams
.Stream_Element_Offset
;
1415 To
: Sock_Addr_Type
)
1417 use type Ada
.Streams
.Stream_Element_Offset
;
1420 Sin
: aliased Sockaddr_In
;
1421 Len
: aliased C
.int
:= Sin
'Size / 8;
1424 Sin
.Sin_Family
:= C
.unsigned_short
(Families
(To
.Family
));
1425 Sin
.Sin_Addr
:= To_In_Addr
(To
.Addr
);
1426 Sin
.Sin_Port
:= Port_To_Network
(C
.unsigned_short
(To
.Port
));
1430 Item
(Item
'First)'Address,
1432 Sin
'Unchecked_Access,
1435 if Res
= Failure
then
1436 Raise_Socket_Error
(Socket_Errno
);
1439 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1446 procedure Set
(Item
: in out Socket_Set_Type
; Socket
: Socket_Type
) is
1449 Item
:= new Socket_Set_Record
'(Socket_Set_Record (Null_Fd_Set));
1452 Set (Fd_Set (Item.all), C.int (Socket));
1455 -----------------------
1456 -- Set_Socket_Option --
1457 -----------------------
1459 procedure Set_Socket_Option
1460 (Socket : Socket_Type;
1461 Level : Level_Type := Socket_Level;
1462 Option : Option_Type)
1464 V8 : aliased Two_Int;
1466 V1 : aliased C.unsigned_char;
1467 Len : aliased C.int;
1468 Add : System.Address := Null_Address;
1477 V4 := C.int (Boolean'Pos (Option.Enabled));
1482 V8 (V8'First) := C.int (Boolean'Pos (Option.Enabled));
1483 V8 (V8'Last) := C.int (Option.Seconds);
1489 V4 := C.int (Option.Size);
1494 V4 := C.int (Boolean'Pos (True));
1498 when Add_Membership |
1500 V8 (V8'First) := To_Int (To_In_Addr (Option.Multiaddr));
1501 V8 (V8'Last) := To_Int (To_In_Addr (Option.Interface));
1505 when Multicast_TTL =>
1506 V1 := C.unsigned_char (Option.Time_To_Live);
1510 when Multicast_Loop =>
1511 V1 := C.unsigned_char (Boolean'Pos (Option.Enabled));
1520 Options (Option.Name),
1523 if Res = Failure then
1524 Raise_Socket_Error (Socket_Errno);
1526 end Set_Socket_Option;
1528 ---------------------
1529 -- Shutdown_Socket --
1530 ---------------------
1532 procedure Shutdown_Socket
1533 (Socket : Socket_Type;
1534 How : Shutmode_Type := Shut_Read_Write)
1539 Res := C_Shutdown (C.int (Socket), Shutmodes (How));
1540 if Res = Failure then
1541 Raise_Socket_Error (Socket_Errno);
1543 end Shutdown_Socket;
1550 (Socket : Socket_Type;
1551 Send_To : Sock_Addr_Type)
1552 return Stream_Access
1554 S : Datagram_Socket_Stream_Access;
1557 S := new Datagram_Socket_Stream_Type;
1560 S.From := Get_Socket_Name (Socket);
1561 return Stream_Access (S);
1569 (Socket : Socket_Type)
1570 return Stream_Access
1572 S : Stream_Socket_Stream_Access;
1575 S := new Stream_Socket_Stream_Type;
1577 return Stream_Access (S);
1584 function To_C (Socket : Socket_Type) return Integer is
1586 return Integer (Socket);
1593 function To_Host_Entry
1595 return Host_Entry_Type
1599 Official : constant String :=
1600 C.Strings.Value (Host.H_Name);
1602 Aliases : constant Chars_Ptr_Array :=
1603 Chars_Ptr_Pointers.Value (Host.H_Aliases);
1604 -- H_Aliases points to a list of name aliases. The list is
1605 -- terminated by a NULL pointer.
1607 Addresses : constant In_Addr_Access_Array :=
1608 In_Addr_Access_Pointers.Value (Host.H_Addr_List);
1609 -- H_Addr_List points to a list of binary addresses (in network
1610 -- byte order). The list is terminated by a NULL pointer.
1612 -- H_Length is not used because it is currently only set to 4.
1613 -- H_Addrtype is always AF_INET
1615 Result : Host_Entry_Type
1616 (Aliases_Length => Aliases'Length - 1,
1617 Addresses_Length => Addresses'Length - 1);
1618 -- The last element is a null pointer.
1624 Result.Official := To_Host_Name (Official);
1626 Source := Aliases'First;
1627 Target := Result.Aliases'First;
1628 while Target <= Result.Aliases_Length loop
1629 Result.Aliases (Target) :=
1630 To_Host_Name (C.Strings.Value (Aliases (Source)));
1631 Source := Source + 1;
1632 Target := Target + 1;
1635 Source := Addresses'First;
1636 Target := Result.Addresses'First;
1637 while Target <= Result.Addresses_Length loop
1638 Result.Addresses (Target) :=
1639 To_Inet_Addr (Addresses (Source).all);
1640 Source := Source + 1;
1641 Target := Target + 1;
1651 function To_Host_Name (N : String) return Host_Name_Type is
1653 return (N'Length, N);
1660 function To_In_Addr (Addr : Inet_Addr_Type) return Thin.In_Addr is
1662 if Addr.Family = Family_Inet then
1663 return (S_B1 => C.unsigned_char (Addr.Sin_V4 (1)),
1664 S_B2 => C.unsigned_char (Addr.Sin_V4 (2)),
1665 S_B3 => C.unsigned_char (Addr.Sin_V4 (3)),
1666 S_B4 => C.unsigned_char (Addr.Sin_V4 (4)));
1676 function To_Inet_Addr
1678 return Inet_Addr_Type
1680 Result : Inet_Addr_Type;
1683 Result.Sin_V4 (1) := Inet_Addr_Comp_Type (Addr.S_B1);
1684 Result.Sin_V4 (2) := Inet_Addr_Comp_Type (Addr.S_B2);
1685 Result.Sin_V4 (3) := Inet_Addr_Comp_Type (Addr.S_B3);
1686 Result.Sin_V4 (4) := Inet_Addr_Comp_Type (Addr.S_B4);
1695 function To_String (HN : Host_Name_Type) return String is
1697 return HN.Name (1 .. HN.Length);
1704 function To_Timeval (Val : Duration) return Timeval is
1705 S : Timeval_Unit := Timeval_Unit (Val);
1706 MS : Timeval_Unit := Timeval_Unit (1_000_000 * (Val - Duration (S)));
1717 (Stream : in out Datagram_Socket_Stream_Type;
1718 Item : Ada.Streams.Stream_Element_Array)
1720 First : Ada.Streams.Stream_Element_Offset := Item'First;
1721 Index : Ada.Streams.Stream_Element_Offset := First - 1;
1722 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1728 Item (First .. Max),
1732 -- Exit when all or zero data sent. Zero means that the
1733 -- socket has been closed by peer.
1735 exit when Index < First or else Index = Max;
1740 if Index /= Max then
1750 (Stream : in out Stream_Socket_Stream_Type;
1751 Item : Ada.Streams.Stream_Element_Array)
1753 First : Ada.Streams.Stream_Element_Offset := Item'First;
1754 Index : Ada.Streams.Stream_Element_Offset := First - 1;
1755 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1759 Send_Socket (Stream.Socket, Item (First .. Max), Index);
1761 -- Exit when all or zero data sent. Zero means that the
1762 -- socket has been closed by peer.
1764 exit when Index < First or else Index = Max;
1769 if Index /= Max then