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