1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S O C K E T S --
10 -- Copyright (C) 2001-2002 Ada Core Technologies, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
30 -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). --
32 ------------------------------------------------------------------------------
34 with Ada
.Streams
; use Ada
.Streams
;
35 with Ada
.Exceptions
; use Ada
.Exceptions
;
36 with Ada
.Unchecked_Deallocation
;
37 with Ada
.Unchecked_Conversion
;
39 with Interfaces
.C
.Strings
;
41 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
42 with GNAT
.Sockets
.Constants
;
43 with GNAT
.Sockets
.Thin
; use GNAT
.Sockets
.Thin
;
46 with GNAT
.Sockets
.Linker_Options
;
47 pragma Warnings
(Off
, GNAT
.Sockets
.Linker_Options
);
48 -- Need to include pragma Linker_Options which is platform dependent.
50 with System
; use System
;
52 package body GNAT
.Sockets
is
54 use type C
.int
, System
.Address
;
56 Finalized
: Boolean := False;
57 Initialized
: Boolean := False;
59 -- Correspondance tables
61 Families
: constant array (Family_Type
) of C
.int
:=
62 (Family_Inet
=> Constants
.AF_INET
,
63 Family_Inet6
=> Constants
.AF_INET6
);
65 Levels
: constant array (Level_Type
) of C
.int
:=
66 (Socket_Level
=> Constants
.SOL_SOCKET
,
67 IP_Protocol_For_IP_Level
=> Constants
.IPPROTO_IP
,
68 IP_Protocol_For_UDP_Level
=> Constants
.IPPROTO_UDP
,
69 IP_Protocol_For_TCP_Level
=> Constants
.IPPROTO_TCP
);
71 Modes
: constant array (Mode_Type
) of C
.int
:=
72 (Socket_Stream
=> Constants
.SOCK_STREAM
,
73 Socket_Datagram
=> Constants
.SOCK_DGRAM
);
75 Shutmodes
: constant array (Shutmode_Type
) of C
.int
:=
76 (Shut_Read
=> Constants
.SHUT_RD
,
77 Shut_Write
=> Constants
.SHUT_WR
,
78 Shut_Read_Write
=> Constants
.SHUT_RDWR
);
80 Requests
: constant array (Request_Name
) of C
.int
:=
81 (Non_Blocking_IO
=> Constants
.FIONBIO
,
82 N_Bytes_To_Read
=> Constants
.FIONREAD
);
84 Options
: constant array (Option_Name
) of C
.int
:=
85 (Keep_Alive
=> Constants
.SO_KEEPALIVE
,
86 Reuse_Address
=> Constants
.SO_REUSEADDR
,
87 Broadcast
=> Constants
.SO_BROADCAST
,
88 Send_Buffer
=> Constants
.SO_SNDBUF
,
89 Receive_Buffer
=> Constants
.SO_RCVBUF
,
90 Linger
=> Constants
.SO_LINGER
,
91 Error
=> Constants
.SO_ERROR
,
92 No_Delay
=> Constants
.TCP_NODELAY
,
93 Add_Membership
=> Constants
.IP_ADD_MEMBERSHIP
,
94 Drop_Membership
=> Constants
.IP_DROP_MEMBERSHIP
,
95 Multicast_TTL
=> Constants
.IP_MULTICAST_TTL
,
96 Multicast_Loop
=> Constants
.IP_MULTICAST_LOOP
);
98 Socket_Error_Id
: constant Exception_Id
:= Socket_Error
'Identity;
99 Host_Error_Id
: constant Exception_Id
:= Host_Error
'Identity;
101 Hex_To_Char
: constant String (1 .. 16) := "0123456789ABCDEF";
102 -- Use to print in hexadecimal format
104 function To_In_Addr
is new Ada
.Unchecked_Conversion
(C
.int
, In_Addr
);
105 function To_Int
is new Ada
.Unchecked_Conversion
(In_Addr
, C
.int
);
107 -----------------------
108 -- Local subprograms --
109 -----------------------
111 function Resolve_Error
112 (Error_Value
: Integer;
113 From_Errno
: Boolean := True)
115 -- Associate an enumeration value (error_type) to en error value
116 -- (errno). From_Errno prevents from mixing h_errno with errno.
118 function To_Host_Name
(N
: String) return Host_Name_Type
;
119 function To_String
(HN
: Host_Name_Type
) return String;
120 -- Conversion functions
122 function Port_To_Network
123 (Port
: C
.unsigned_short
)
124 return C
.unsigned_short
;
125 pragma Inline
(Port_To_Network
);
126 -- Convert a port number into a network port number
128 function Network_To_Port
129 (Net_Port
: C
.unsigned_short
)
130 return C
.unsigned_short
131 renames Port_To_Network
;
132 -- Symetric operation
135 (Val
: Inet_Addr_VN_Type
;
136 Hex
: Boolean := False)
138 -- Output an array of inet address components either in
139 -- hexadecimal or in decimal mode.
141 function To_In_Addr
(Addr
: Inet_Addr_Type
) return Thin
.In_Addr
;
142 function To_Inet_Addr
(Addr
: In_Addr
) return Inet_Addr_Type
;
143 -- Conversion functions
145 function To_Host_Entry
(Host
: Hostent
) return Host_Entry_Type
;
146 -- Conversion function
148 function To_Timeval
(Val
: Duration) return Timeval
;
149 -- Separate Val in seconds and microseconds
151 procedure Raise_Socket_Error
(Error
: Integer);
152 -- Raise Socket_Error with an exception message describing
155 procedure Raise_Host_Error
(Error
: Integer);
156 -- Raise Host_Error exception with message describing error code
157 -- (note hstrerror seems to be obsolete).
159 -- Types needed for Socket_Set_Type
161 type Socket_Set_Record
is new Fd_Set
;
164 new Ada
.Unchecked_Deallocation
(Socket_Set_Record
, Socket_Set_Type
);
166 -- Types needed for Datagram_Socket_Stream_Type
168 type Datagram_Socket_Stream_Type
is new Root_Stream_Type
with record
169 Socket
: Socket_Type
;
171 From
: Sock_Addr_Type
;
174 type Datagram_Socket_Stream_Access
is
175 access all Datagram_Socket_Stream_Type
;
178 (Stream
: in out Datagram_Socket_Stream_Type
;
179 Item
: out Ada
.Streams
.Stream_Element_Array
;
180 Last
: out Ada
.Streams
.Stream_Element_Offset
);
183 (Stream
: in out Datagram_Socket_Stream_Type
;
184 Item
: Ada
.Streams
.Stream_Element_Array
);
186 -- Types needed for Stream_Socket_Stream_Type
188 type Stream_Socket_Stream_Type
is new Root_Stream_Type
with record
189 Socket
: Socket_Type
;
192 type Stream_Socket_Stream_Access
is
193 access all Stream_Socket_Stream_Type
;
196 (Stream
: in out Stream_Socket_Stream_Type
;
197 Item
: out Ada
.Streams
.Stream_Element_Array
;
198 Last
: out Ada
.Streams
.Stream_Element_Offset
);
201 (Stream
: in out Stream_Socket_Stream_Type
;
202 Item
: Ada
.Streams
.Stream_Element_Array
);
208 procedure Abort_Selector
(Selector
: Selector_Type
) is
213 -- Send an empty array to unblock C select system call
215 if Selector
.In_Progress
then
216 Res
:= C_Write
(C
.int
(Selector
.W_Sig_Socket
), Buf
'Address, 1);
224 procedure Accept_Socket
225 (Server
: Socket_Type
;
226 Socket
: out Socket_Type
;
227 Address
: out Sock_Addr_Type
)
230 Sin
: aliased Sockaddr_In
;
231 Len
: aliased C
.int
:= Sin
'Size / 8;
234 Res
:= C_Accept
(C
.int
(Server
), Sin
'Address, Len
'Access);
236 if Res
= Failure
then
237 Raise_Socket_Error
(Socket_Errno
);
240 Socket
:= Socket_Type
(Res
);
242 Address
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
243 Address
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
251 (E
: Host_Entry_Type
;
253 return Inet_Addr_Type
256 return E
.Addresses
(N
);
259 ----------------------
260 -- Addresses_Length --
261 ----------------------
263 function Addresses_Length
(E
: Host_Entry_Type
) return Natural is
265 return E
.Addresses_Length
;
266 end Addresses_Length
;
273 (E
: Host_Entry_Type
;
278 return To_String
(E
.Aliases
(N
));
285 function Aliases_Length
(E
: Host_Entry_Type
) return Natural is
287 return E
.Aliases_Length
;
294 procedure Bind_Socket
295 (Socket
: Socket_Type
;
296 Address
: Sock_Addr_Type
)
299 Sin
: aliased Sockaddr_In
;
300 Len
: aliased C
.int
:= Sin
'Size / 8;
303 if Address
.Family
= Family_Inet6
then
307 Sin
.Sin_Family
:= C
.unsigned_short
(Families
(Address
.Family
));
308 Sin
.Sin_Port
:= Port_To_Network
(C
.unsigned_short
(Address
.Port
));
310 Res
:= C_Bind
(C
.int
(Socket
), Sin
'Address, Len
);
312 if Res
= Failure
then
313 Raise_Socket_Error
(Socket_Errno
);
321 procedure Check_Selector
322 (Selector
: in out Selector_Type
;
323 R_Socket_Set
: in out Socket_Set_Type
;
324 W_Socket_Set
: in out Socket_Set_Type
;
325 Status
: out Selector_Status
;
326 Timeout
: Duration := Forever
)
330 RSet
: aliased Fd_Set
;
331 WSet
: aliased Fd_Set
;
332 TVal
: aliased Timeval
;
333 TPtr
: Timeval_Access
;
338 -- No timeout or Forever is indicated by a null timeval pointer.
340 if Timeout
= Forever
then
343 TVal
:= To_Timeval
(Timeout
);
344 TPtr
:= TVal
'Unchecked_Access;
347 -- Copy R_Socket_Set in RSet and add read signalling socket.
349 if R_Socket_Set
= null then
352 RSet
:= Fd_Set
(R_Socket_Set
.all);
355 Set
(RSet
, C
.int
(Selector
.R_Sig_Socket
));
356 Len
:= Max
(RSet
) + 1;
358 -- Copy W_Socket_Set in WSet.
360 if W_Socket_Set
= null then
363 WSet
:= Fd_Set
(W_Socket_Set
.all);
366 Len
:= C
.int
'Max (Max
(RSet
) + 1, Len
);
368 Selector
.In_Progress
:= True;
372 RSet
'Unchecked_Access,
373 WSet
'Unchecked_Access,
375 Selector
.In_Progress
:= False;
377 -- If Select was resumed because of read signalling socket,
378 -- read this data and remove socket from set.
380 if Is_Set
(RSet
, C
.int
(Selector
.R_Sig_Socket
)) then
381 Clear
(RSet
, C
.int
(Selector
.R_Sig_Socket
));
386 Res
:= C_Read
(C
.int
(Selector
.R_Sig_Socket
), Buf
'Address, 1);
389 -- Select was resumed because of read signalling socket, but
390 -- the call is said aborted only when there is no other read
394 and then Is_Empty
(WSet
)
403 if R_Socket_Set
/= null then
404 R_Socket_Set
.all := Socket_Set_Record
(RSet
);
407 if W_Socket_Set
/= null then
408 W_Socket_Set
.all := Socket_Set_Record
(WSet
);
417 (Item
: in out Socket_Set_Type
;
418 Socket
: Socket_Type
)
422 Item
:= new Socket_Set_Record
;
423 Empty
(Fd_Set
(Item
.all));
426 Clear
(Fd_Set
(Item
.all), C
.int
(Socket
));
433 procedure Close_Selector
(Selector
: in out Selector_Type
) is
436 Close_Socket
(Selector
.R_Sig_Socket
);
437 exception when Socket_Error
=>
442 Close_Socket
(Selector
.W_Sig_Socket
);
443 exception when Socket_Error
=>
452 procedure Close_Socket
(Socket
: Socket_Type
) is
456 Res
:= C_Close
(C
.int
(Socket
));
458 if Res
= Failure
then
459 Raise_Socket_Error
(Socket_Errno
);
467 procedure Connect_Socket
468 (Socket
: Socket_Type
;
469 Server
: in out Sock_Addr_Type
)
472 Sin
: aliased Sockaddr_In
;
473 Len
: aliased C
.int
:= Sin
'Size / 8;
476 if Server
.Family
= Family_Inet6
then
480 Sin
.Sin_Family
:= C
.unsigned_short
(Families
(Server
.Family
));
481 Sin
.Sin_Addr
:= To_In_Addr
(Server
.Addr
);
482 Sin
.Sin_Port
:= Port_To_Network
(C
.unsigned_short
(Server
.Port
));
484 Res
:= C_Connect
(C
.int
(Socket
), Sin
'Address, Len
);
486 if Res
= Failure
then
487 Raise_Socket_Error
(Socket_Errno
);
495 procedure Control_Socket
496 (Socket
: Socket_Type
;
497 Request
: in out Request_Type
)
504 when Non_Blocking_IO
=>
505 Arg
:= C
.int
(Boolean'Pos (Request
.Enabled
));
507 when N_Bytes_To_Read
=>
514 Requests
(Request
.Name
),
515 Arg
'Unchecked_Access);
517 if Res
= Failure
then
518 Raise_Socket_Error
(Socket_Errno
);
522 when Non_Blocking_IO
=>
525 when N_Bytes_To_Read
=>
526 Request
.Size
:= Natural (Arg
);
531 ---------------------
532 -- Create_Selector --
533 ---------------------
535 procedure Create_Selector
(Selector
: out Selector_Type
) is
540 Sin
: aliased Sockaddr_In
;
541 Len
: aliased C
.int
:= Sin
'Size / 8;
545 -- We open two signalling sockets. One socket to send a signal
546 -- to a another socket that always included in a C_Select
547 -- socket set. When received, it resumes the task suspended in
550 -- Create a listening socket
552 S0
:= C_Socket
(Constants
.AF_INET
, Constants
.SOCK_STREAM
, 0);
554 Raise_Socket_Error
(Socket_Errno
);
557 -- Sin is already correctly initialized. Bind the socket to any
560 Res
:= C_Bind
(S0
, Sin
'Address, Len
);
561 if Res
= Failure
then
564 Raise_Socket_Error
(Err
);
567 -- Get the port used by the socket
569 Res
:= C_Getsockname
(S0
, Sin
'Address, Len
'Access);
571 if Res
= Failure
then
574 Raise_Socket_Error
(Err
);
577 Res
:= C_Listen
(S0
, 2);
579 if Res
= Failure
then
582 Raise_Socket_Error
(Err
);
585 S1
:= C_Socket
(Constants
.AF_INET
, Constants
.SOCK_STREAM
, 0);
590 Raise_Socket_Error
(Err
);
593 -- Use INADDR_LOOPBACK
595 Sin
.Sin_Addr
.S_B1
:= 127;
596 Sin
.Sin_Addr
.S_B2
:= 0;
597 Sin
.Sin_Addr
.S_B3
:= 0;
598 Sin
.Sin_Addr
.S_B4
:= 1;
600 -- Do a connect and accept the connection
602 Res
:= C_Connect
(S1
, Sin
'Address, Len
);
604 if Res
= Failure
then
608 Raise_Socket_Error
(Err
);
611 S2
:= C_Accept
(S0
, Sin
'Address, Len
'Access);
617 Raise_Socket_Error
(Err
);
622 if Res
= Failure
then
623 Raise_Socket_Error
(Socket_Errno
);
626 Selector
.R_Sig_Socket
:= Socket_Type
(S1
);
627 Selector
.W_Sig_Socket
:= Socket_Type
(S2
);
634 procedure Create_Socket
635 (Socket
: out Socket_Type
;
636 Family
: Family_Type
:= Family_Inet
;
637 Mode
: Mode_Type
:= Socket_Stream
)
642 Res
:= C_Socket
(Families
(Family
), Modes
(Mode
), 0);
644 if Res
= Failure
then
645 Raise_Socket_Error
(Socket_Errno
);
648 Socket
:= Socket_Type
(Res
);
655 procedure Empty
(Item
: in out Socket_Set_Type
) is
666 procedure Finalize
is
680 function Get_Address
(Stream
: Stream_Access
) return Sock_Addr_Type
is
682 if Stream
= null then
685 elsif Stream
.all in Datagram_Socket_Stream_Type
then
686 return Datagram_Socket_Stream_Type
(Stream
.all).From
;
689 return Get_Peer_Name
(Stream_Socket_Stream_Type
(Stream
.all).Socket
);
693 -------------------------
694 -- Get_Host_By_Address --
695 -------------------------
697 function Get_Host_By_Address
698 (Address
: Inet_Addr_Type
;
699 Family
: Family_Type
:= Family_Inet
)
700 return Host_Entry_Type
702 pragma Unreferenced
(Family
);
704 HA
: aliased In_Addr
:= To_In_Addr
(Address
);
705 Res
: Hostent_Access
;
709 -- This C function is not always thread-safe. Protect against
710 -- concurrent access.
713 Res
:= C_Gethostbyaddr
(HA
'Address, HA
'Size / 8, Constants
.AF_INET
);
718 Raise_Host_Error
(Err
);
721 -- Translate from the C format to the API format
724 HE
: Host_Entry_Type
:= To_Host_Entry
(Res
.all);
730 end Get_Host_By_Address
;
732 ----------------------
733 -- Get_Host_By_Name --
734 ----------------------
736 function Get_Host_By_Name
738 return Host_Entry_Type
740 HN
: C
.char_array
:= C
.To_C
(Name
);
741 Res
: Hostent_Access
;
745 -- This C function is not always thread-safe. Protect against
746 -- concurrent access.
749 Res
:= C_Gethostbyname
(HN
);
754 Raise_Host_Error
(Err
);
757 -- Translate from the C format to the API format
760 HE
: Host_Entry_Type
:= To_Host_Entry
(Res
.all);
766 end Get_Host_By_Name
;
772 function Get_Peer_Name
773 (Socket
: Socket_Type
)
774 return Sock_Addr_Type
776 Sin
: aliased Sockaddr_In
;
777 Len
: aliased C
.int
:= Sin
'Size / 8;
778 Res
: Sock_Addr_Type
(Family_Inet
);
781 if C_Getpeername
(C
.int
(Socket
), Sin
'Address, Len
'Access) = Failure
then
782 Raise_Socket_Error
(Socket_Errno
);
785 Res
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
786 Res
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
791 ---------------------
792 -- Get_Socket_Name --
793 ---------------------
795 function Get_Socket_Name
796 (Socket
: Socket_Type
)
797 return Sock_Addr_Type
799 Sin
: aliased Sockaddr_In
;
800 Len
: aliased C
.int
:= Sin
'Size / 8;
801 Res
: Sock_Addr_Type
(Family_Inet
);
804 if C_Getsockname
(C
.int
(Socket
), Sin
'Address, Len
'Access) = Failure
then
805 Raise_Socket_Error
(Socket_Errno
);
808 Res
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
809 Res
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
814 -----------------------
815 -- Get_Socket_Option --
816 -----------------------
818 function Get_Socket_Option
819 (Socket
: Socket_Type
;
820 Level
: Level_Type
:= Socket_Level
;
824 use type C
.unsigned_char
;
826 V8
: aliased Two_Int
;
828 V1
: aliased C
.unsigned_char
;
830 Add
: System
.Address
;
832 Opt
: Option_Type
(Name
);
836 when Multicast_Loop |
864 Add
, Len
'Unchecked_Access);
866 if Res
= Failure
then
867 Raise_Socket_Error
(Socket_Errno
);
875 Opt
.Enabled
:= (V4
/= 0);
878 Opt
.Enabled
:= (V8
(V8
'First) /= 0);
879 Opt
.Seconds
:= Natural (V8
(V8
'Last));
883 Opt
.Size
:= Natural (V4
);
886 Opt
.Error
:= Resolve_Error
(Integer (V4
));
888 when Add_Membership |
890 Opt
.Multiaddr
:= To_Inet_Addr
(To_In_Addr
(V8
(V8
'First)));
891 Opt
.Interface
:= To_Inet_Addr
(To_In_Addr
(V8
(V8
'Last)));
893 when Multicast_TTL
=>
894 Opt
.Time_To_Live
:= Integer (V1
);
896 when Multicast_Loop
=>
897 Opt
.Enabled
:= (V1
/= 0);
902 end Get_Socket_Option
;
908 function Host_Name
return String is
909 Name
: aliased C
.char_array
(1 .. 64);
913 Res
:= C_Gethostname
(Name
'Address, Name
'Length);
915 if Res
= Failure
then
916 Raise_Socket_Error
(Socket_Errno
);
919 return C
.To_Ada
(Name
);
927 (Val
: Inet_Addr_VN_Type
;
928 Hex
: Boolean := False)
931 -- The largest Inet_Addr_Comp_Type image occurs with IPv4. It
932 -- has at most a length of 3 plus one '.' character.
934 Buffer
: String (1 .. 4 * Val
'Length);
935 Length
: Natural := 1;
936 Separator
: Character;
938 procedure Img10
(V
: Inet_Addr_Comp_Type
);
939 -- Append to Buffer image of V in decimal format
941 procedure Img16
(V
: Inet_Addr_Comp_Type
);
942 -- Append to Buffer image of V in hexadecimal format
944 procedure Img10
(V
: Inet_Addr_Comp_Type
) is
945 Img
: constant String := V
'Img;
946 Len
: Natural := Img
'Length - 1;
949 Buffer
(Length
.. Length
+ Len
- 1) := Img
(2 .. Img
'Last);
950 Length
:= Length
+ Len
;
953 procedure Img16
(V
: Inet_Addr_Comp_Type
) is
955 Buffer
(Length
) := Hex_To_Char
(Natural (V
/ 16) + 1);
956 Buffer
(Length
+ 1) := Hex_To_Char
(Natural (V
mod 16) + 1);
957 Length
:= Length
+ 2;
960 -- Start of processing for Image
969 for J
in Val
'Range loop
976 if J
/= Val
'Last then
977 Buffer
(Length
) := Separator
;
978 Length
:= Length
+ 1;
982 return Buffer
(1 .. Length
- 1);
989 function Image
(Value
: Inet_Addr_Type
) return String is
991 if Value
.Family
= Family_Inet
then
992 return Image
(Inet_Addr_VN_Type
(Value
.Sin_V4
), Hex
=> False);
994 return Image
(Inet_Addr_VN_Type
(Value
.Sin_V6
), Hex
=> True);
1002 function Image
(Value
: Sock_Addr_Type
) return String is
1003 Port
: constant String := Value
.Port
'Img;
1006 return Image
(Value
.Addr
) & ':' & Port
(2 .. Port
'Last);
1013 function Image
(Socket
: Socket_Type
) return String is
1022 function Inet_Addr
(Image
: String) return Inet_Addr_Type
is
1023 use Interfaces
.C
.Strings
;
1025 Img
: chars_ptr
:= New_String
(Image
);
1030 Res
:= C_Inet_Addr
(Img
);
1034 if Res
= Failure
then
1035 Raise_Socket_Error
(Err
);
1038 return To_Inet_Addr
(To_In_Addr
(Res
));
1045 procedure Initialize
(Process_Blocking_IO
: Boolean := False) is
1047 if not Initialized
then
1048 Initialized
:= True;
1049 Thin
.Initialize
(Process_Blocking_IO
);
1057 function Is_Empty
(Item
: Socket_Set_Type
) return Boolean is
1059 return Item
= null or else Is_Empty
(Fd_Set
(Item
.all));
1067 (Item
: Socket_Set_Type
;
1068 Socket
: Socket_Type
) return Boolean
1072 and then Is_Set
(Fd_Set
(Item
.all), C
.int
(Socket
));
1079 procedure Listen_Socket
1080 (Socket
: Socket_Type
;
1081 Length
: Positive := 15)
1086 Res
:= C_Listen
(C
.int
(Socket
), C
.int
(Length
));
1087 if Res
= Failure
then
1088 Raise_Socket_Error
(Socket_Errno
);
1096 function Official_Name
(E
: Host_Entry_Type
) return String is
1098 return To_String
(E
.Official
);
1101 ---------------------
1102 -- Port_To_Network --
1103 ---------------------
1105 function Port_To_Network
1106 (Port
: C
.unsigned_short
)
1107 return C
.unsigned_short
1109 use type C
.unsigned_short
;
1111 if Default_Bit_Order
= High_Order_First
then
1113 -- No conversion needed. On these platforms, htons() defaults
1114 -- to a null procedure.
1119 -- We need to swap the high and low byte on this short to make
1120 -- the port number network compliant.
1122 return (Port
/ 256) + (Port
mod 256) * 256;
1124 end Port_To_Network
;
1126 ----------------------
1127 -- Raise_Host_Error --
1128 ----------------------
1130 procedure Raise_Host_Error
(Error
: Integer) is
1132 function Error_Message
return String;
1133 -- We do not use a C function like strerror because hstrerror
1134 -- that would correspond seems to be obsolete. Return
1135 -- appropriate string for error value.
1137 function Error_Message
return String is
1140 when Constants
.HOST_NOT_FOUND
=> return "Host not found";
1141 when Constants
.TRY_AGAIN
=> return "Try again";
1142 when Constants
.NO_RECOVERY
=> return "No recovery";
1143 when Constants
.NO_ADDRESS
=> return "No address";
1144 when others => return "Unknown error";
1148 -- Start of processing for Raise_Host_Error
1151 Ada
.Exceptions
.Raise_Exception
(Host_Error
'Identity, Error_Message
);
1152 end Raise_Host_Error
;
1154 ------------------------
1155 -- Raise_Socket_Error --
1156 ------------------------
1158 procedure Raise_Socket_Error
(Error
: Integer) is
1159 use type C
.Strings
.chars_ptr
;
1161 function Image
(E
: Integer) return String;
1162 function Image
(E
: Integer) return String is
1163 Msg
: String := E
'Img & "] ";
1165 Msg
(Msg
'First) := '[';
1170 Ada
.Exceptions
.Raise_Exception
1171 (Socket_Error
'Identity, Image
(Error
) & Socket_Error_Message
(Error
));
1172 end Raise_Socket_Error
;
1179 (Stream
: in out Datagram_Socket_Stream_Type
;
1180 Item
: out Ada
.Streams
.Stream_Element_Array
;
1181 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1183 First
: Ada
.Streams
.Stream_Element_Offset
:= Item
'First;
1184 Index
: Ada
.Streams
.Stream_Element_Offset
:= First
- 1;
1185 Max
: constant Ada
.Streams
.Stream_Element_Offset
:= Item
'Last;
1191 Item
(First
.. Max
),
1197 -- Exit when all or zero data received. Zero means that
1198 -- the socket peer is closed.
1200 exit when Index
< First
or else Index
= Max
;
1211 (Stream
: in out Stream_Socket_Stream_Type
;
1212 Item
: out Ada
.Streams
.Stream_Element_Array
;
1213 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1215 First
: Ada
.Streams
.Stream_Element_Offset
:= Item
'First;
1216 Index
: Ada
.Streams
.Stream_Element_Offset
:= First
- 1;
1217 Max
: constant Ada
.Streams
.Stream_Element_Offset
:= Item
'Last;
1221 Receive_Socket
(Stream
.Socket
, Item
(First
.. Max
), Index
);
1224 -- Exit when all or zero data received. Zero means that
1225 -- the socket peer is closed.
1227 exit when Index
< First
or else Index
= Max
;
1237 function Resolve_Error
1238 (Error_Value
: Integer;
1239 From_Errno
: Boolean := True)
1242 use GNAT
.Sockets
.Constants
;
1245 if not From_Errno
then
1247 when HOST_NOT_FOUND
=> return Unknown_Host
;
1248 when TRY_AGAIN
=> return Host_Name_Lookup_Failure
;
1249 when NO_RECOVERY
=> return No_Address_Associated_With_Name
;
1250 when NO_ADDRESS
=> return Unknown_Server_Error
;
1251 when others => return Cannot_Resolve_Error
;
1256 when EACCES
=> return Permission_Denied
;
1257 when EADDRINUSE
=> return Address_Already_In_Use
;
1258 when EADDRNOTAVAIL
=> return Cannot_Assign_Requested_Address
;
1259 when EAFNOSUPPORT
=>
1260 return Address_Family_Not_Supported_By_Protocol
;
1261 when EALREADY
=> return Operation_Already_In_Progress
;
1262 when EBADF
=> return Bad_File_Descriptor
;
1263 when ECONNREFUSED
=> return Connection_Refused
;
1264 when EFAULT
=> return Bad_Address
;
1265 when EINPROGRESS
=> return Operation_Now_In_Progress
;
1266 when EINTR
=> return Interrupted_System_Call
;
1267 when EINVAL
=> return Invalid_Argument
;
1268 when EIO
=> return Input_Output_Error
;
1269 when EISCONN
=> return Transport_Endpoint_Already_Connected
;
1270 when EMSGSIZE
=> return Message_Too_Long
;
1271 when ENETUNREACH
=> return Network_Is_Unreachable
;
1272 when ENOBUFS
=> return No_Buffer_Space_Available
;
1273 when ENOPROTOOPT
=> return Protocol_Not_Available
;
1274 when ENOTCONN
=> return Transport_Endpoint_Not_Connected
;
1275 when EOPNOTSUPP
=> return Operation_Not_Supported
;
1276 when EPROTONOSUPPORT
=> return Protocol_Not_Supported
;
1277 when ESOCKTNOSUPPORT
=> return Socket_Type_Not_Supported
;
1278 when ETIMEDOUT
=> return Connection_Timed_Out
;
1279 when EWOULDBLOCK
=> return Resource_Temporarily_Unavailable
;
1280 when others => return Cannot_Resolve_Error
;
1284 -----------------------
1285 -- Resolve_Exception --
1286 -----------------------
1288 function Resolve_Exception
1289 (Occurrence
: Exception_Occurrence
)
1292 Id
: Exception_Id
:= Exception_Identity
(Occurrence
);
1293 Msg
: constant String := Exception_Message
(Occurrence
);
1294 First
: Natural := Msg
'First;
1299 while First
<= Msg
'Last
1300 and then Msg
(First
) not in '0' .. '9'
1305 if First
> Msg
'Last then
1306 return Cannot_Resolve_Error
;
1311 while Last
< Msg
'Last
1312 and then Msg
(Last
+ 1) in '0' .. '9'
1317 Val
:= Integer'Value (Msg
(First
.. Last
));
1319 if Id
= Socket_Error_Id
then
1320 return Resolve_Error
(Val
);
1322 elsif Id
= Host_Error_Id
then
1323 return Resolve_Error
(Val
, False);
1326 return Cannot_Resolve_Error
;
1328 end Resolve_Exception
;
1330 --------------------
1331 -- Receive_Socket --
1332 --------------------
1334 procedure Receive_Socket
1335 (Socket
: Socket_Type
;
1336 Item
: out Ada
.Streams
.Stream_Element_Array
;
1337 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1339 use type Ada
.Streams
.Stream_Element_Offset
;
1346 Item
(Item
'First)'Address,
1349 if Res
= Failure
then
1350 Raise_Socket_Error
(Socket_Errno
);
1353 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1356 --------------------
1357 -- Receive_Socket --
1358 --------------------
1360 procedure Receive_Socket
1361 (Socket
: Socket_Type
;
1362 Item
: out Ada
.Streams
.Stream_Element_Array
;
1363 Last
: out Ada
.Streams
.Stream_Element_Offset
;
1364 From
: out Sock_Addr_Type
)
1366 use type Ada
.Streams
.Stream_Element_Offset
;
1369 Sin
: aliased Sockaddr_In
;
1370 Len
: aliased C
.int
:= Sin
'Size / 8;
1375 Item
(Item
'First)'Address,
1377 Sin
'Unchecked_Access,
1378 Len
'Unchecked_Access);
1380 if Res
= Failure
then
1381 Raise_Socket_Error
(Socket_Errno
);
1384 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1386 From
.Addr
:= To_Inet_Addr
(Sin
.Sin_Addr
);
1387 From
.Port
:= Port_Type
(Network_To_Port
(Sin
.Sin_Port
));
1394 procedure Send_Socket
1395 (Socket
: Socket_Type
;
1396 Item
: Ada
.Streams
.Stream_Element_Array
;
1397 Last
: out Ada
.Streams
.Stream_Element_Offset
)
1399 use type Ada
.Streams
.Stream_Element_Offset
;
1406 Item
(Item
'First)'Address,
1409 if Res
= Failure
then
1410 Raise_Socket_Error
(Socket_Errno
);
1413 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1420 procedure Send_Socket
1421 (Socket
: Socket_Type
;
1422 Item
: Ada
.Streams
.Stream_Element_Array
;
1423 Last
: out Ada
.Streams
.Stream_Element_Offset
;
1424 To
: Sock_Addr_Type
)
1426 use type Ada
.Streams
.Stream_Element_Offset
;
1429 Sin
: aliased Sockaddr_In
;
1430 Len
: aliased C
.int
:= Sin
'Size / 8;
1433 Sin
.Sin_Family
:= C
.unsigned_short
(Families
(To
.Family
));
1434 Sin
.Sin_Addr
:= To_In_Addr
(To
.Addr
);
1435 Sin
.Sin_Port
:= Port_To_Network
(C
.unsigned_short
(To
.Port
));
1439 Item
(Item
'First)'Address,
1441 Sin
'Unchecked_Access,
1444 if Res
= Failure
then
1445 Raise_Socket_Error
(Socket_Errno
);
1448 Last
:= Item
'First + Ada
.Streams
.Stream_Element_Offset
(Res
- 1);
1455 procedure Set
(Item
: in out Socket_Set_Type
; Socket
: Socket_Type
) is
1458 Item
:= new Socket_Set_Record
'(Socket_Set_Record (Null_Fd_Set));
1461 Set (Fd_Set (Item.all), C.int (Socket));
1464 -----------------------
1465 -- Set_Socket_Option --
1466 -----------------------
1468 procedure Set_Socket_Option
1469 (Socket : Socket_Type;
1470 Level : Level_Type := Socket_Level;
1471 Option : Option_Type)
1473 V8 : aliased Two_Int;
1475 V1 : aliased C.unsigned_char;
1476 Len : aliased C.int;
1477 Add : System.Address := Null_Address;
1486 V4 := C.int (Boolean'Pos (Option.Enabled));
1491 V8 (V8'First) := C.int (Boolean'Pos (Option.Enabled));
1492 V8 (V8'Last) := C.int (Option.Seconds);
1498 V4 := C.int (Option.Size);
1503 V4 := C.int (Boolean'Pos (True));
1507 when Add_Membership |
1509 V8 (V8'First) := To_Int (To_In_Addr (Option.Multiaddr));
1510 V8 (V8'Last) := To_Int (To_In_Addr (Option.Interface));
1514 when Multicast_TTL =>
1515 V1 := C.unsigned_char (Option.Time_To_Live);
1519 when Multicast_Loop =>
1520 V1 := C.unsigned_char (Boolean'Pos (Option.Enabled));
1529 Options (Option.Name),
1532 if Res = Failure then
1533 Raise_Socket_Error (Socket_Errno);
1535 end Set_Socket_Option;
1537 ---------------------
1538 -- Shutdown_Socket --
1539 ---------------------
1541 procedure Shutdown_Socket
1542 (Socket : Socket_Type;
1543 How : Shutmode_Type := Shut_Read_Write)
1548 Res := C_Shutdown (C.int (Socket), Shutmodes (How));
1550 if Res = Failure then
1551 Raise_Socket_Error (Socket_Errno);
1553 end Shutdown_Socket;
1560 (Socket : Socket_Type;
1561 Send_To : Sock_Addr_Type)
1562 return Stream_Access
1564 S : Datagram_Socket_Stream_Access;
1567 S := new Datagram_Socket_Stream_Type;
1570 S.From := Get_Socket_Name (Socket);
1571 return Stream_Access (S);
1579 (Socket : Socket_Type)
1580 return Stream_Access
1582 S : Stream_Socket_Stream_Access;
1585 S := new Stream_Socket_Stream_Type;
1587 return Stream_Access (S);
1594 function To_C (Socket : Socket_Type) return Integer is
1596 return Integer (Socket);
1603 function To_Host_Entry
1605 return Host_Entry_Type
1609 Official : constant String :=
1610 C.Strings.Value (Host.H_Name);
1612 Aliases : constant Chars_Ptr_Array :=
1613 Chars_Ptr_Pointers.Value (Host.H_Aliases);
1614 -- H_Aliases points to a list of name aliases. The list is
1615 -- terminated by a NULL pointer.
1617 Addresses : constant In_Addr_Access_Array :=
1618 In_Addr_Access_Pointers.Value (Host.H_Addr_List);
1619 -- H_Addr_List points to a list of binary addresses (in network
1620 -- byte order). The list is terminated by a NULL pointer.
1622 -- H_Length is not used because it is currently only set to 4.
1623 -- H_Addrtype is always AF_INET
1625 Result : Host_Entry_Type
1626 (Aliases_Length => Aliases'Length - 1,
1627 Addresses_Length => Addresses'Length - 1);
1628 -- The last element is a null pointer.
1634 Result.Official := To_Host_Name (Official);
1636 Source := Aliases'First;
1637 Target := Result.Aliases'First;
1638 while Target <= Result.Aliases_Length loop
1639 Result.Aliases (Target) :=
1640 To_Host_Name (C.Strings.Value (Aliases (Source)));
1641 Source := Source + 1;
1642 Target := Target + 1;
1645 Source := Addresses'First;
1646 Target := Result.Addresses'First;
1647 while Target <= Result.Addresses_Length loop
1648 Result.Addresses (Target) :=
1649 To_Inet_Addr (Addresses (Source).all);
1650 Source := Source + 1;
1651 Target := Target + 1;
1661 function To_Host_Name (N : String) return Host_Name_Type is
1663 return (N'Length, N);
1670 function To_In_Addr (Addr : Inet_Addr_Type) return Thin.In_Addr is
1672 if Addr.Family = Family_Inet then
1673 return (S_B1 => C.unsigned_char (Addr.Sin_V4 (1)),
1674 S_B2 => C.unsigned_char (Addr.Sin_V4 (2)),
1675 S_B3 => C.unsigned_char (Addr.Sin_V4 (3)),
1676 S_B4 => C.unsigned_char (Addr.Sin_V4 (4)));
1686 function To_Inet_Addr
1688 return Inet_Addr_Type
1690 Result : Inet_Addr_Type;
1693 Result.Sin_V4 (1) := Inet_Addr_Comp_Type (Addr.S_B1);
1694 Result.Sin_V4 (2) := Inet_Addr_Comp_Type (Addr.S_B2);
1695 Result.Sin_V4 (3) := Inet_Addr_Comp_Type (Addr.S_B3);
1696 Result.Sin_V4 (4) := Inet_Addr_Comp_Type (Addr.S_B4);
1705 function To_String (HN : Host_Name_Type) return String is
1707 return HN.Name (1 .. HN.Length);
1714 function To_Timeval (Val : Duration) return Timeval is
1715 S : Timeval_Unit := Timeval_Unit (Val);
1716 MS : Timeval_Unit := Timeval_Unit (1_000_000 * (Val - Duration (S)));
1727 (Stream : in out Datagram_Socket_Stream_Type;
1728 Item : Ada.Streams.Stream_Element_Array)
1730 First : Ada.Streams.Stream_Element_Offset := Item'First;
1731 Index : Ada.Streams.Stream_Element_Offset := First - 1;
1732 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1738 Item (First .. Max),
1742 -- Exit when all or zero data sent. Zero means that the
1743 -- socket has been closed by peer.
1745 exit when Index < First or else Index = Max;
1750 if Index /= Max then
1760 (Stream : in out Stream_Socket_Stream_Type;
1761 Item : Ada.Streams.Stream_Element_Array)
1763 First : Ada.Streams.Stream_Element_Offset := Item'First;
1764 Index : Ada.Streams.Stream_Element_Offset := First - 1;
1765 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1769 Send_Socket (Stream.Socket, Item (First .. Max), Index);
1771 -- Exit when all or zero data sent. Zero means that the
1772 -- socket has been closed by peer.
1774 exit when Index < First or else Index = Max;
1779 if Index /= Max then