1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S O C K E T S --
9 -- Copyright (C) 2001-2009, AdaCore --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 with Ada.Streams; use Ada.Streams;
35 with Ada.Exceptions; use Ada.Exceptions;
36 with Ada.Finalization;
37 with Ada.Unchecked_Conversion;
39 with Interfaces.C.Strings;
41 with GNAT.Sockets.Thin_Common; use GNAT.Sockets.Thin_Common;
42 with GNAT.Sockets.Thin; use GNAT.Sockets.Thin;
43 with GNAT.Sockets.Thin.Task_Safe_NetDB; use GNAT.Sockets.Thin.Task_Safe_NetDB;
45 with GNAT.Sockets.Linker_Options;
46 pragma Warnings (Off, GNAT.Sockets.Linker_Options);
47 -- Need to include pragma Linker_Options which is platform dependent
49 with System; use System;
50 with System.Communication; use System.Communication;
52 package body GNAT.Sockets is
54 package C renames Interfaces.C;
58 ENOERROR : constant := 0;
60 Netdb_Buffer_Size : constant := SOSC.Need_Netdb_Buffer * 1024;
61 -- The network database functions gethostbyname, gethostbyaddr,
62 -- getservbyname and getservbyport can either be guaranteed task safe by
63 -- the operating system, or else return data through a user-provided buffer
64 -- to ensure concurrent uses do not interfere.
66 -- Correspondence tables
68 Levels : constant array (Level_Type) of C.int :=
69 (Socket_Level => SOSC.SOL_SOCKET,
70 IP_Protocol_For_IP_Level => SOSC.IPPROTO_IP,
71 IP_Protocol_For_UDP_Level => SOSC.IPPROTO_UDP,
72 IP_Protocol_For_TCP_Level => SOSC.IPPROTO_TCP);
74 Modes : constant array (Mode_Type) of C.int :=
75 (Socket_Stream => SOSC.SOCK_STREAM,
76 Socket_Datagram => SOSC.SOCK_DGRAM);
78 Shutmodes : constant array (Shutmode_Type) of C.int :=
79 (Shut_Read => SOSC.SHUT_RD,
80 Shut_Write => SOSC.SHUT_WR,
81 Shut_Read_Write => SOSC.SHUT_RDWR);
83 Requests : constant array (Request_Name) of C.int :=
84 (Non_Blocking_IO => SOSC.FIONBIO,
85 N_Bytes_To_Read => SOSC.FIONREAD);
87 Options : constant array (Option_Name) of C.int :=
88 (Keep_Alive => SOSC.SO_KEEPALIVE,
89 Reuse_Address => SOSC.SO_REUSEADDR,
90 Broadcast => SOSC.SO_BROADCAST,
91 Send_Buffer => SOSC.SO_SNDBUF,
92 Receive_Buffer => SOSC.SO_RCVBUF,
93 Linger => SOSC.SO_LINGER,
94 Error => SOSC.SO_ERROR,
95 No_Delay => SOSC.TCP_NODELAY,
96 Add_Membership => SOSC.IP_ADD_MEMBERSHIP,
97 Drop_Membership => SOSC.IP_DROP_MEMBERSHIP,
98 Multicast_If => SOSC.IP_MULTICAST_IF,
99 Multicast_TTL => SOSC.IP_MULTICAST_TTL,
100 Multicast_Loop => SOSC.IP_MULTICAST_LOOP,
101 Receive_Packet_Info => SOSC.IP_PKTINFO,
102 Send_Timeout => SOSC.SO_SNDTIMEO,
103 Receive_Timeout => SOSC.SO_RCVTIMEO);
104 -- ??? Note: for OpenSolaris, Receive_Packet_Info should be IP_RECVPKTINFO,
105 -- but for Linux compatibility this constant is the same as IP_PKTINFO.
107 Flags : constant array (0 .. 3) of C.int :=
108 (0 => SOSC.MSG_OOB, -- Process_Out_Of_Band_Data
109 1 => SOSC.MSG_PEEK, -- Peek_At_Incoming_Data
110 2 => SOSC.MSG_WAITALL, -- Wait_For_A_Full_Reception
111 3 => SOSC.MSG_EOR); -- Send_End_Of_Record
113 Socket_Error_Id : constant Exception_Id := Socket_Error'Identity;
114 Host_Error_Id : constant Exception_Id := Host_Error'Identity;
116 Hex_To_Char : constant String (1 .. 16) := "0123456789ABCDEF";
117 -- Use to print in hexadecimal format
119 -----------------------
120 -- Local subprograms --
121 -----------------------
123 function Resolve_Error
124 (Error_Value : Integer;
125 From_Errno : Boolean := True) return Error_Type;
126 -- Associate an enumeration value (error_type) to en error value (errno).
127 -- From_Errno prevents from mixing h_errno with errno.
129 function To_Name (N : String) return Name_Type;
130 function To_String (HN : Name_Type) return String;
131 -- Conversion functions
133 function To_Int (F : Request_Flag_Type) return C.int;
134 -- Return the int value corresponding to the specified flags combination
136 function Set_Forced_Flags (F : C.int) return C.int;
137 -- Return F with the bits from SOSC.MSG_Forced_Flags forced set
139 function Short_To_Network
140 (S : C.unsigned_short) return C.unsigned_short;
141 pragma Inline (Short_To_Network);
142 -- Convert a port number into a network port number
144 function Network_To_Short
145 (S : C.unsigned_short) return C.unsigned_short
146 renames Short_To_Network;
147 -- Symmetric operation
150 (Val : Inet_Addr_VN_Type;
151 Hex : Boolean := False) return String;
152 -- Output an array of inet address components in hex or decimal mode
154 function Is_IP_Address (Name : String) return Boolean;
155 -- Return true when Name is an IP address in standard dot notation
157 function To_In_Addr (Addr : Inet_Addr_Type) return In_Addr;
158 procedure To_Inet_Addr
160 Result : out Inet_Addr_Type);
161 -- Conversion functions
163 function To_Host_Entry (E : Hostent) return Host_Entry_Type;
164 -- Conversion function
166 function To_Service_Entry (E : Servent) return Service_Entry_Type;
167 -- Conversion function
169 function To_Timeval (Val : Timeval_Duration) return Timeval;
170 -- Separate Val in seconds and microseconds
172 function To_Duration (Val : Timeval) return Timeval_Duration;
173 -- Reconstruct a Duration value from a Timeval record (seconds and
176 procedure Raise_Socket_Error (Error : Integer);
177 -- Raise Socket_Error with an exception message describing the error code
180 procedure Raise_Host_Error (H_Error : Integer);
181 -- Raise Host_Error exception with message describing error code (note
182 -- hstrerror seems to be obsolete) from h_errno.
184 procedure Narrow (Item : in out Socket_Set_Type);
185 -- Update Last as it may be greater than the real last socket
187 -- Types needed for Datagram_Socket_Stream_Type
189 type Datagram_Socket_Stream_Type is new Root_Stream_Type with record
190 Socket : Socket_Type;
192 From : Sock_Addr_Type;
195 type Datagram_Socket_Stream_Access is
196 access all Datagram_Socket_Stream_Type;
199 (Stream : in out Datagram_Socket_Stream_Type;
200 Item : out Ada.Streams.Stream_Element_Array;
201 Last : out Ada.Streams.Stream_Element_Offset);
204 (Stream : in out Datagram_Socket_Stream_Type;
205 Item : Ada.Streams.Stream_Element_Array);
207 -- Types needed for Stream_Socket_Stream_Type
209 type Stream_Socket_Stream_Type is new Root_Stream_Type with record
210 Socket : Socket_Type;
213 type Stream_Socket_Stream_Access is
214 access all Stream_Socket_Stream_Type;
217 (Stream : in out Stream_Socket_Stream_Type;
218 Item : out Ada.Streams.Stream_Element_Array;
219 Last : out Ada.Streams.Stream_Element_Offset);
222 (Stream : in out Stream_Socket_Stream_Type;
223 Item : Ada.Streams.Stream_Element_Array);
225 procedure Stream_Write
226 (Socket : Socket_Type;
227 Item : Ada.Streams.Stream_Element_Array;
228 To : access Sock_Addr_Type);
229 -- Common implementation for the Write operation of Datagram_Socket_Stream_
230 -- Type and Stream_Socket_Stream_Type.
232 procedure Wait_On_Socket
233 (Socket : Socket_Type;
235 Timeout : Selector_Duration;
236 Selector : access Selector_Type := null;
237 Status : out Selector_Status);
238 -- Common code for variants of socket operations supporting a timeout:
239 -- block in Check_Selector on Socket for at most the indicated timeout.
240 -- If For_Read is True, Socket is added to the read set for this call, else
241 -- it is added to the write set. If no selector is provided, a local one is
242 -- created for this call and destroyed prior to returning.
244 type Sockets_Library_Controller is new Ada.Finalization.Limited_Controlled
246 -- This type is used to generate automatic calls to Initialize and Finalize
247 -- during the elaboration and finalization of this package. A single object
248 -- of this type must exist at library level.
250 function Err_Code_Image (E : Integer) return String;
251 -- Return the value of E surrounded with brackets
253 procedure Initialize (X : in out Sockets_Library_Controller);
254 procedure Finalize (X : in out Sockets_Library_Controller);
256 procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type);
257 -- If S is the empty set (detected by Last = No_Socket), make sure its
258 -- fd_set component is actually cleared. Note that the case where it is
259 -- not can occur for an uninitialized Socket_Set_Type object.
261 function Is_Open (S : Selector_Type) return Boolean;
262 -- Return True for an "open" Selector_Type object, i.e. one for which
263 -- Create_Selector has been called and Close_Selector has not been called.
269 function "+" (L, R : Request_Flag_Type) return Request_Flag_Type is
278 procedure Abort_Selector (Selector : Selector_Type) is
282 if not Is_Open (Selector) then
283 raise Program_Error with "closed selector";
286 -- Send one byte to unblock select system call
288 Res := Signalling_Fds.Write (C.int (Selector.W_Sig_Socket));
290 if Res = Failure then
291 Raise_Socket_Error (Socket_Errno);
299 procedure Accept_Socket
300 (Server : Socket_Type;
301 Socket : out Socket_Type;
302 Address : out Sock_Addr_Type)
305 Sin : aliased Sockaddr_In;
306 Len : aliased C.int := Sin'Size / 8;
309 Res := C_Accept (C.int (Server), Sin'Address, Len'Access);
311 if Res = Failure then
312 Raise_Socket_Error (Socket_Errno);
315 Socket := Socket_Type (Res);
317 To_Inet_Addr (Sin.Sin_Addr, Address.Addr);
318 Address.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
325 procedure Accept_Socket
326 (Server : Socket_Type;
327 Socket : out Socket_Type;
328 Address : out Sock_Addr_Type;
329 Timeout : Selector_Duration;
330 Selector : access Selector_Type := null;
331 Status : out Selector_Status)
334 if Selector /= null and then not Is_Open (Selector.all) then
335 raise Program_Error with "closed selector";
338 -- Wait for socket to become available for reading
344 Selector => Selector,
347 -- Accept connection if available
349 if Status = Completed then
350 Accept_Socket (Server, Socket, Address);
361 (E : Host_Entry_Type;
362 N : Positive := 1) return Inet_Addr_Type
365 return E.Addresses (N);
368 ----------------------
369 -- Addresses_Length --
370 ----------------------
372 function Addresses_Length (E : Host_Entry_Type) return Natural is
374 return E.Addresses_Length;
375 end Addresses_Length;
382 (E : Host_Entry_Type;
383 N : Positive := 1) return String
386 return To_String (E.Aliases (N));
394 (S : Service_Entry_Type;
395 N : Positive := 1) return String
398 return To_String (S.Aliases (N));
405 function Aliases_Length (E : Host_Entry_Type) return Natural is
407 return E.Aliases_Length;
414 function Aliases_Length (S : Service_Entry_Type) return Natural is
416 return S.Aliases_Length;
423 procedure Bind_Socket
424 (Socket : Socket_Type;
425 Address : Sock_Addr_Type)
428 Sin : aliased Sockaddr_In;
429 Len : constant C.int := Sin'Size / 8;
430 -- This assumes that Address.Family = Family_Inet???
433 if Address.Family = Family_Inet6 then
434 raise Socket_Error with "IPv6 not supported";
437 Set_Family (Sin.Sin_Family, Address.Family);
438 Set_Address (Sin'Unchecked_Access, To_In_Addr (Address.Addr));
440 (Sin'Unchecked_Access,
441 Short_To_Network (C.unsigned_short (Address.Port)));
443 Res := C_Bind (C.int (Socket), Sin'Address, Len);
445 if Res = Failure then
446 Raise_Socket_Error (Socket_Errno);
454 procedure Check_Selector
455 (Selector : in out Selector_Type;
456 R_Socket_Set : in out Socket_Set_Type;
457 W_Socket_Set : in out Socket_Set_Type;
458 Status : out Selector_Status;
459 Timeout : Selector_Duration := Forever)
461 E_Socket_Set : Socket_Set_Type;
464 (Selector, R_Socket_Set, W_Socket_Set, E_Socket_Set, Status, Timeout);
471 procedure Check_Selector
472 (Selector : in out Selector_Type;
473 R_Socket_Set : in out Socket_Set_Type;
474 W_Socket_Set : in out Socket_Set_Type;
475 E_Socket_Set : in out Socket_Set_Type;
476 Status : out Selector_Status;
477 Timeout : Selector_Duration := Forever)
481 RSig : constant Socket_Type := Selector.R_Sig_Socket;
482 TVal : aliased Timeval;
483 TPtr : Timeval_Access;
486 if not Is_Open (Selector) then
487 raise Program_Error with "closed selector";
492 -- No timeout or Forever is indicated by a null timeval pointer
494 if Timeout = Forever then
497 TVal := To_Timeval (Timeout);
498 TPtr := TVal'Unchecked_Access;
501 -- Add read signalling socket
503 Set (R_Socket_Set, RSig);
505 Last := C.int'Max (C.int'Max (C.int (R_Socket_Set.Last),
506 C.int (W_Socket_Set.Last)),
507 C.int (E_Socket_Set.Last));
509 -- Zero out fd_set for empty Socket_Set_Type objects
511 Normalize_Empty_Socket_Set (R_Socket_Set);
512 Normalize_Empty_Socket_Set (W_Socket_Set);
513 Normalize_Empty_Socket_Set (E_Socket_Set);
518 R_Socket_Set.Set'Access,
519 W_Socket_Set.Set'Access,
520 E_Socket_Set.Set'Access,
523 if Res = Failure then
524 Raise_Socket_Error (Socket_Errno);
527 -- If Select was resumed because of read signalling socket, read this
528 -- data and remove socket from set.
530 if Is_Set (R_Socket_Set, RSig) then
531 Clear (R_Socket_Set, RSig);
533 Res := Signalling_Fds.Read (C.int (RSig));
535 if Res = Failure then
536 Raise_Socket_Error (Socket_Errno);
545 -- Update socket sets in regard to their new contents
547 Narrow (R_Socket_Set);
548 Narrow (W_Socket_Set);
549 Narrow (E_Socket_Set);
557 (Item : in out Socket_Set_Type;
558 Socket : Socket_Type)
560 Last : aliased C.int := C.int (Item.Last);
562 if Item.Last /= No_Socket then
563 Remove_Socket_From_Set (Item.Set'Access, C.int (Socket));
564 Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access);
565 Item.Last := Socket_Type (Last);
573 procedure Close_Selector (Selector : in out Selector_Type) is
575 if not Is_Open (Selector) then
577 -- Selector already in closed state: nothing to do
582 -- Close the signalling file descriptors used internally for the
583 -- implementation of Abort_Selector.
585 Signalling_Fds.Close (C.int (Selector.R_Sig_Socket));
586 Signalling_Fds.Close (C.int (Selector.W_Sig_Socket));
588 -- Reset R_Sig_Socket and W_Sig_Socket to No_Socket to ensure that any
589 -- (erroneous) subsequent attempt to use this selector properly fails.
591 Selector.R_Sig_Socket := No_Socket;
592 Selector.W_Sig_Socket := No_Socket;
599 procedure Close_Socket (Socket : Socket_Type) is
603 Res := C_Close (C.int (Socket));
605 if Res = Failure then
606 Raise_Socket_Error (Socket_Errno);
614 procedure Connect_Socket
615 (Socket : Socket_Type;
616 Server : Sock_Addr_Type)
619 Sin : aliased Sockaddr_In;
620 Len : constant C.int := Sin'Size / 8;
623 if Server.Family = Family_Inet6 then
624 raise Socket_Error with "IPv6 not supported";
627 Set_Family (Sin.Sin_Family, Server.Family);
628 Set_Address (Sin'Unchecked_Access, To_In_Addr (Server.Addr));
630 (Sin'Unchecked_Access,
631 Short_To_Network (C.unsigned_short (Server.Port)));
633 Res := C_Connect (C.int (Socket), Sin'Address, Len);
635 if Res = Failure then
636 Raise_Socket_Error (Socket_Errno);
644 procedure Connect_Socket
645 (Socket : Socket_Type;
646 Server : Sock_Addr_Type;
647 Timeout : Selector_Duration;
648 Selector : access Selector_Type := null;
649 Status : out Selector_Status)
652 -- Used to set Socket to non-blocking I/O
655 if Selector /= null and then not Is_Open (Selector.all) then
656 raise Program_Error with "closed selector";
659 -- Set the socket to non-blocking I/O
661 Req := (Name => Non_Blocking_IO, Enabled => True);
662 Control_Socket (Socket, Request => Req);
664 -- Start operation (non-blocking), will raise Socket_Error with
668 Connect_Socket (Socket, Server);
670 when E : Socket_Error =>
671 if Resolve_Exception (E) = Operation_Now_In_Progress then
678 -- Wait for socket to become available for writing
684 Selector => Selector,
687 -- Reset the socket to blocking I/O
689 Req := (Name => Non_Blocking_IO, Enabled => False);
690 Control_Socket (Socket, Request => Req);
697 procedure Control_Socket
698 (Socket : Socket_Type;
699 Request : in out Request_Type)
706 when Non_Blocking_IO =>
707 Arg := C.int (Boolean'Pos (Request.Enabled));
709 when N_Bytes_To_Read =>
714 (C.int (Socket), Requests (Request.Name), Arg'Unchecked_Access);
716 if Res = Failure then
717 Raise_Socket_Error (Socket_Errno);
721 when Non_Blocking_IO =>
724 when N_Bytes_To_Read =>
725 Request.Size := Natural (Arg);
734 (Source : Socket_Set_Type;
735 Target : out Socket_Set_Type)
741 ---------------------
742 -- Create_Selector --
743 ---------------------
745 procedure Create_Selector (Selector : out Selector_Type) is
746 Two_Fds : aliased Fd_Pair;
750 if Is_Open (Selector) then
751 -- Raise exception to prevent socket descriptor leak
753 raise Program_Error with "selector already open";
756 -- We open two signalling file descriptors. One of them is used to send
757 -- data to the other, which is included in a C_Select socket set. The
758 -- communication is used to force a call to C_Select to complete, and
759 -- the waiting task to resume its execution.
761 Res := Signalling_Fds.Create (Two_Fds'Access);
763 if Res = Failure then
764 Raise_Socket_Error (Socket_Errno);
767 Selector.R_Sig_Socket := Socket_Type (Two_Fds (Read_End));
768 Selector.W_Sig_Socket := Socket_Type (Two_Fds (Write_End));
775 procedure Create_Socket
776 (Socket : out Socket_Type;
777 Family : Family_Type := Family_Inet;
778 Mode : Mode_Type := Socket_Stream)
783 Res := C_Socket (Families (Family), Modes (Mode), 0);
785 if Res = Failure then
786 Raise_Socket_Error (Socket_Errno);
789 Socket := Socket_Type (Res);
796 procedure Empty (Item : out Socket_Set_Type) is
798 Reset_Socket_Set (Item.Set'Access);
799 Item.Last := No_Socket;
806 function Err_Code_Image (E : Integer) return String is
807 Msg : String := E'Img & "] ";
809 Msg (Msg'First) := '[';
817 procedure Finalize (X : in out Sockets_Library_Controller) is
818 pragma Unreferenced (X);
821 -- Finalization operation for the GNAT.Sockets package
830 procedure Finalize is
832 -- This is a dummy placeholder for an obsolete API.
833 -- The real finalization actions are in Initialize primitive operation
834 -- of Sockets_Library_Controller.
844 (Item : in out Socket_Set_Type;
845 Socket : out Socket_Type)
848 L : aliased C.int := C.int (Item.Last);
851 if Item.Last /= No_Socket then
853 (Item.Set'Access, Last => L'Access, Socket => S'Access);
854 Item.Last := Socket_Type (L);
855 Socket := Socket_Type (S);
866 (Stream : not null Stream_Access) return Sock_Addr_Type
869 if Stream.all in Datagram_Socket_Stream_Type then
870 return Datagram_Socket_Stream_Type (Stream.all).From;
872 return Get_Peer_Name (Stream_Socket_Stream_Type (Stream.all).Socket);
876 -------------------------
877 -- Get_Host_By_Address --
878 -------------------------
880 function Get_Host_By_Address
881 (Address : Inet_Addr_Type;
882 Family : Family_Type := Family_Inet) return Host_Entry_Type
884 pragma Unreferenced (Family);
886 HA : aliased In_Addr := To_In_Addr (Address);
887 Buflen : constant C.int := Netdb_Buffer_Size;
888 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
889 Res : aliased Hostent;
893 if Safe_Gethostbyaddr (HA'Address, HA'Size / 8, SOSC.AF_INET,
894 Res'Access, Buf'Address, Buflen, Err'Access) /= 0
896 Raise_Host_Error (Integer (Err));
899 return To_Host_Entry (Res);
900 end Get_Host_By_Address;
902 ----------------------
903 -- Get_Host_By_Name --
904 ----------------------
906 function Get_Host_By_Name (Name : String) return Host_Entry_Type is
908 -- Detect IP address name and redirect to Inet_Addr
910 if Is_IP_Address (Name) then
911 return Get_Host_By_Address (Inet_Addr (Name));
915 HN : constant C.char_array := C.To_C (Name);
916 Buflen : constant C.int := Netdb_Buffer_Size;
917 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
918 Res : aliased Hostent;
922 if Safe_Gethostbyname
923 (HN, Res'Access, Buf'Address, Buflen, Err'Access) /= 0
925 Raise_Host_Error (Integer (Err));
928 return To_Host_Entry (Res);
930 end Get_Host_By_Name;
936 function Get_Peer_Name (Socket : Socket_Type) return Sock_Addr_Type is
937 Sin : aliased Sockaddr_In;
938 Len : aliased C.int := Sin'Size / 8;
939 Res : Sock_Addr_Type (Family_Inet);
942 if C_Getpeername (C.int (Socket), Sin'Address, Len'Access) = Failure then
943 Raise_Socket_Error (Socket_Errno);
946 To_Inet_Addr (Sin.Sin_Addr, Res.Addr);
947 Res.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
952 -------------------------
953 -- Get_Service_By_Name --
954 -------------------------
956 function Get_Service_By_Name
958 Protocol : String) return Service_Entry_Type
960 SN : constant C.char_array := C.To_C (Name);
961 SP : constant C.char_array := C.To_C (Protocol);
962 Buflen : constant C.int := Netdb_Buffer_Size;
963 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
964 Res : aliased Servent;
967 if Safe_Getservbyname (SN, SP, Res'Access, Buf'Address, Buflen) /= 0 then
968 raise Service_Error with "Service not found";
971 -- Translate from the C format to the API format
973 return To_Service_Entry (Res);
974 end Get_Service_By_Name;
976 -------------------------
977 -- Get_Service_By_Port --
978 -------------------------
980 function Get_Service_By_Port
982 Protocol : String) return Service_Entry_Type
984 SP : constant C.char_array := C.To_C (Protocol);
985 Buflen : constant C.int := Netdb_Buffer_Size;
986 Buf : aliased C.char_array (1 .. Netdb_Buffer_Size);
987 Res : aliased Servent;
990 if Safe_Getservbyport
991 (C.int (Short_To_Network (C.unsigned_short (Port))), SP,
992 Res'Access, Buf'Address, Buflen) /= 0
994 raise Service_Error with "Service not found";
997 -- Translate from the C format to the API format
999 return To_Service_Entry (Res);
1000 end Get_Service_By_Port;
1002 ---------------------
1003 -- Get_Socket_Name --
1004 ---------------------
1006 function Get_Socket_Name
1007 (Socket : Socket_Type) return Sock_Addr_Type
1009 Sin : aliased Sockaddr_In;
1010 Len : aliased C.int := Sin'Size / 8;
1012 Addr : Sock_Addr_Type := No_Sock_Addr;
1015 Res := C_Getsockname (C.int (Socket), Sin'Address, Len'Access);
1017 if Res /= Failure then
1018 To_Inet_Addr (Sin.Sin_Addr, Addr.Addr);
1019 Addr.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
1023 end Get_Socket_Name;
1025 -----------------------
1026 -- Get_Socket_Option --
1027 -----------------------
1029 function Get_Socket_Option
1030 (Socket : Socket_Type;
1031 Level : Level_Type := Socket_Level;
1032 Name : Option_Name) return Option_Type
1034 use type C.unsigned_char;
1036 V8 : aliased Two_Ints;
1038 V1 : aliased C.unsigned_char;
1039 VT : aliased Timeval;
1040 Len : aliased C.int;
1041 Add : System.Address;
1043 Opt : Option_Type (Name);
1047 when Multicast_Loop |
1049 Receive_Packet_Info =>
1084 if Res = Failure then
1085 Raise_Socket_Error (Socket_Errno);
1093 Opt.Enabled := (V4 /= 0);
1096 Opt.Enabled := (V8 (V8'First) /= 0);
1097 Opt.Seconds := Natural (V8 (V8'Last));
1101 Opt.Size := Natural (V4);
1104 Opt.Error := Resolve_Error (Integer (V4));
1106 when Add_Membership |
1108 To_Inet_Addr (To_In_Addr (V8 (V8'First)), Opt.Multicast_Address);
1109 To_Inet_Addr (To_In_Addr (V8 (V8'Last)), Opt.Local_Interface);
1111 when Multicast_If =>
1112 To_Inet_Addr (To_In_Addr (V4), Opt.Outgoing_If);
1114 when Multicast_TTL =>
1115 Opt.Time_To_Live := Integer (V1);
1117 when Multicast_Loop |
1118 Receive_Packet_Info =>
1119 Opt.Enabled := (V1 /= 0);
1123 Opt.Timeout := To_Duration (VT);
1127 end Get_Socket_Option;
1133 function Host_Name return String is
1134 Name : aliased C.char_array (1 .. 64);
1138 Res := C_Gethostname (Name'Address, Name'Length);
1140 if Res = Failure then
1141 Raise_Socket_Error (Socket_Errno);
1144 return C.To_Ada (Name);
1152 (Val : Inet_Addr_VN_Type;
1153 Hex : Boolean := False) return String
1155 -- The largest Inet_Addr_Comp_Type image occurs with IPv4. It
1156 -- has at most a length of 3 plus one '.' character.
1158 Buffer : String (1 .. 4 * Val'Length);
1159 Length : Natural := 1;
1160 Separator : Character;
1162 procedure Img10 (V : Inet_Addr_Comp_Type);
1163 -- Append to Buffer image of V in decimal format
1165 procedure Img16 (V : Inet_Addr_Comp_Type);
1166 -- Append to Buffer image of V in hexadecimal format
1172 procedure Img10 (V : Inet_Addr_Comp_Type) is
1173 Img : constant String := V'Img;
1174 Len : constant Natural := Img'Length - 1;
1176 Buffer (Length .. Length + Len - 1) := Img (2 .. Img'Last);
1177 Length := Length + Len;
1184 procedure Img16 (V : Inet_Addr_Comp_Type) is
1186 Buffer (Length) := Hex_To_Char (Natural (V / 16) + 1);
1187 Buffer (Length + 1) := Hex_To_Char (Natural (V mod 16) + 1);
1188 Length := Length + 2;
1191 -- Start of processing for Image
1194 Separator := (if Hex then ':' else '.');
1196 for J in Val'Range loop
1203 if J /= Val'Last then
1204 Buffer (Length) := Separator;
1205 Length := Length + 1;
1209 return Buffer (1 .. Length - 1);
1216 function Image (Value : Inet_Addr_Type) return String is
1218 if Value.Family = Family_Inet then
1219 return Image (Inet_Addr_VN_Type (Value.Sin_V4), Hex => False);
1221 return Image (Inet_Addr_VN_Type (Value.Sin_V6), Hex => True);
1229 function Image (Value : Sock_Addr_Type) return String is
1230 Port : constant String := Value.Port'Img;
1232 return Image (Value.Addr) & ':' & Port (2 .. Port'Last);
1239 function Image (Socket : Socket_Type) return String is
1248 function Image (Item : Socket_Set_Type) return String is
1249 Socket_Set : Socket_Set_Type := Item;
1253 Last_Img : constant String := Socket_Set.Last'Img;
1255 (1 .. (Integer (Socket_Set.Last) + 1) * Last_Img'Length);
1256 Index : Positive := 1;
1257 Socket : Socket_Type;
1260 while not Is_Empty (Socket_Set) loop
1261 Get (Socket_Set, Socket);
1264 Socket_Img : constant String := Socket'Img;
1266 Buffer (Index .. Index + Socket_Img'Length - 1) := Socket_Img;
1267 Index := Index + Socket_Img'Length;
1271 return "[" & Last_Img & "]" & Buffer (1 .. Index - 1);
1279 function Inet_Addr (Image : String) return Inet_Addr_Type is
1281 use Interfaces.C.Strings;
1283 Img : aliased char_array := To_C (Image);
1284 Cp : constant chars_ptr := To_Chars_Ptr (Img'Unchecked_Access);
1285 Addr : aliased C.int;
1287 Result : Inet_Addr_Type;
1290 -- Special case for an empty Image as on some platforms (e.g. Windows)
1291 -- calling Inet_Addr("") will not return an error.
1294 Raise_Socket_Error (SOSC.EINVAL);
1297 Res := Inet_Pton (SOSC.AF_INET, Cp, Addr'Address);
1300 Raise_Socket_Error (Socket_Errno);
1303 Raise_Socket_Error (SOSC.EINVAL);
1306 To_Inet_Addr (To_In_Addr (Addr), Result);
1314 procedure Initialize (X : in out Sockets_Library_Controller) is
1315 pragma Unreferenced (X);
1325 procedure Initialize (Process_Blocking_IO : Boolean) is
1326 Expected : constant Boolean := not SOSC.Thread_Blocking_IO;
1329 if Process_Blocking_IO /= Expected then
1330 raise Socket_Error with
1331 "incorrect Process_Blocking_IO setting, expected " & Expected'Img;
1334 -- This is a dummy placeholder for an obsolete API
1336 -- Real initialization actions are in Initialize primitive operation
1337 -- of Sockets_Library_Controller.
1346 procedure Initialize is
1348 -- This is a dummy placeholder for an obsolete API
1350 -- Real initialization actions are in Initialize primitive operation
1351 -- of Sockets_Library_Controller.
1360 function Is_Empty (Item : Socket_Set_Type) return Boolean is
1362 return Item.Last = No_Socket;
1369 function Is_IP_Address (Name : String) return Boolean is
1371 for J in Name'Range loop
1373 and then Name (J) not in '0' .. '9'
1386 function Is_Open (S : Selector_Type) return Boolean is
1388 -- Either both controlling socket descriptors are valid (case of an
1389 -- open selector) or neither (case of a closed selector).
1391 pragma Assert ((S.R_Sig_Socket /= No_Socket)
1393 (S.W_Sig_Socket /= No_Socket));
1395 return S.R_Sig_Socket /= No_Socket;
1403 (Item : Socket_Set_Type;
1404 Socket : Socket_Type) return Boolean
1407 return Item.Last /= No_Socket
1408 and then Socket <= Item.Last
1409 and then Is_Socket_In_Set (Item.Set'Access, C.int (Socket)) /= 0;
1416 procedure Listen_Socket
1417 (Socket : Socket_Type;
1418 Length : Natural := 15)
1420 Res : constant C.int := C_Listen (C.int (Socket), C.int (Length));
1422 if Res = Failure then
1423 Raise_Socket_Error (Socket_Errno);
1431 procedure Narrow (Item : in out Socket_Set_Type) is
1432 Last : aliased C.int := C.int (Item.Last);
1434 if Item.Last /= No_Socket then
1435 Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access);
1436 Item.Last := Socket_Type (Last);
1440 --------------------------------
1441 -- Normalize_Empty_Socket_Set --
1442 --------------------------------
1444 procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type) is
1446 if S.Last = No_Socket then
1447 Reset_Socket_Set (S.Set'Access);
1449 end Normalize_Empty_Socket_Set;
1455 function Official_Name (E : Host_Entry_Type) return String is
1457 return To_String (E.Official);
1464 function Official_Name (S : Service_Entry_Type) return String is
1466 return To_String (S.Official);
1469 --------------------
1470 -- Wait_On_Socket --
1471 --------------------
1473 procedure Wait_On_Socket
1474 (Socket : Socket_Type;
1476 Timeout : Selector_Duration;
1477 Selector : access Selector_Type := null;
1478 Status : out Selector_Status)
1480 type Local_Selector_Access is access Selector_Type;
1481 for Local_Selector_Access'Storage_Size use Selector_Type'Size;
1483 S : Selector_Access;
1484 -- Selector to use for waiting
1486 R_Fd_Set : Socket_Set_Type;
1487 W_Fd_Set : Socket_Set_Type;
1490 -- Create selector if not provided by the user
1492 if Selector = null then
1494 Local_S : constant Local_Selector_Access := new Selector_Type;
1496 S := Local_S.all'Unchecked_Access;
1497 Create_Selector (S.all);
1501 S := Selector.all'Access;
1505 Set (R_Fd_Set, Socket);
1507 Set (W_Fd_Set, Socket);
1510 Check_Selector (S.all, R_Fd_Set, W_Fd_Set, Status, Timeout);
1512 if Selector = null then
1513 Close_Selector (S.all);
1521 function Port_Number (S : Service_Entry_Type) return Port_Type is
1530 function Protocol_Name (S : Service_Entry_Type) return String is
1532 return To_String (S.Protocol);
1535 ----------------------
1536 -- Raise_Host_Error --
1537 ----------------------
1539 procedure Raise_Host_Error (H_Error : Integer) is
1541 raise Host_Error with
1542 Err_Code_Image (H_Error)
1543 & C.Strings.Value (Host_Error_Messages.Host_Error_Message (H_Error));
1544 end Raise_Host_Error;
1546 ------------------------
1547 -- Raise_Socket_Error --
1548 ------------------------
1550 procedure Raise_Socket_Error (Error : Integer) is
1551 use type C.Strings.chars_ptr;
1553 raise Socket_Error with
1554 Err_Code_Image (Error)
1555 & C.Strings.Value (Socket_Error_Message (Error));
1556 end Raise_Socket_Error;
1563 (Stream : in out Datagram_Socket_Stream_Type;
1564 Item : out Ada.Streams.Stream_Element_Array;
1565 Last : out Ada.Streams.Stream_Element_Offset)
1567 First : Ada.Streams.Stream_Element_Offset := Item'First;
1568 Index : Ada.Streams.Stream_Element_Offset := First - 1;
1569 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1575 Item (First .. Max),
1581 -- Exit when all or zero data received. Zero means that the socket
1584 exit when Index < First or else Index = Max;
1595 (Stream : in out Stream_Socket_Stream_Type;
1596 Item : out Ada.Streams.Stream_Element_Array;
1597 Last : out Ada.Streams.Stream_Element_Offset)
1599 pragma Warnings (Off, Stream);
1601 First : Ada.Streams.Stream_Element_Offset := Item'First;
1602 Index : Ada.Streams.Stream_Element_Offset := First - 1;
1603 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
1607 Receive_Socket (Stream.Socket, Item (First .. Max), Index);
1610 -- Exit when all or zero data received. Zero means that the socket
1613 exit when Index < First or else Index = Max;
1619 --------------------
1620 -- Receive_Socket --
1621 --------------------
1623 procedure Receive_Socket
1624 (Socket : Socket_Type;
1625 Item : out Ada.Streams.Stream_Element_Array;
1626 Last : out Ada.Streams.Stream_Element_Offset;
1627 Flags : Request_Flag_Type := No_Request_Flag)
1633 C_Recv (C.int (Socket), Item'Address, Item'Length, To_Int (Flags));
1635 if Res = Failure then
1636 Raise_Socket_Error (Socket_Errno);
1639 Last := Last_Index (First => Item'First, Count => Res);
1642 --------------------
1643 -- Receive_Socket --
1644 --------------------
1646 procedure Receive_Socket
1647 (Socket : Socket_Type;
1648 Item : out Ada.Streams.Stream_Element_Array;
1649 Last : out Ada.Streams.Stream_Element_Offset;
1650 From : out Sock_Addr_Type;
1651 Flags : Request_Flag_Type := No_Request_Flag)
1654 Sin : aliased Sockaddr_In;
1655 Len : aliased C.int := Sin'Size / 8;
1667 if Res = Failure then
1668 Raise_Socket_Error (Socket_Errno);
1671 Last := Last_Index (First => Item'First, Count => Res);
1673 To_Inet_Addr (Sin.Sin_Addr, From.Addr);
1674 From.Port := Port_Type (Network_To_Short (Sin.Sin_Port));
1677 --------------------
1678 -- Receive_Vector --
1679 --------------------
1681 procedure Receive_Vector
1682 (Socket : Socket_Type;
1683 Vector : Vector_Type;
1684 Count : out Ada.Streams.Stream_Element_Count;
1685 Flags : Request_Flag_Type := No_Request_Flag)
1690 (Msg_Name => System.Null_Address,
1692 Msg_Iov => Vector'Address,
1694 -- recvmsg(2) returns EMSGSIZE on Linux (and probably on other
1695 -- platforms) when the supplied vector is longer than IOV_MAX,
1696 -- so use minimum of the two lengths.
1698 Msg_Iovlen => SOSC.Msg_Iovlen_T'Min
1699 (Vector'Length, SOSC.IOV_MAX),
1701 Msg_Control => System.Null_Address,
1702 Msg_Controllen => 0,
1712 if Res = ssize_t (Failure) then
1713 Raise_Socket_Error (Socket_Errno);
1716 Count := Ada.Streams.Stream_Element_Count (Res);
1723 function Resolve_Error
1724 (Error_Value : Integer;
1725 From_Errno : Boolean := True) return Error_Type
1727 use GNAT.Sockets.SOSC;
1730 if not From_Errno then
1732 when SOSC.HOST_NOT_FOUND => return Unknown_Host;
1733 when SOSC.TRY_AGAIN => return Host_Name_Lookup_Failure;
1734 when SOSC.NO_RECOVERY => return Non_Recoverable_Error;
1735 when SOSC.NO_DATA => return Unknown_Server_Error;
1736 when others => return Cannot_Resolve_Error;
1740 -- Special case: EAGAIN may be the same value as EWOULDBLOCK, so we
1741 -- can't include it in the case statement below.
1743 pragma Warnings (Off);
1744 -- Condition "EAGAIN /= EWOULDBLOCK" is known at compile time
1746 if EAGAIN /= EWOULDBLOCK and then Error_Value = EAGAIN then
1747 return Resource_Temporarily_Unavailable;
1750 pragma Warnings (On);
1753 when ENOERROR => return Success;
1754 when EACCES => return Permission_Denied;
1755 when EADDRINUSE => return Address_Already_In_Use;
1756 when EADDRNOTAVAIL => return Cannot_Assign_Requested_Address;
1757 when EAFNOSUPPORT => return
1758 Address_Family_Not_Supported_By_Protocol;
1759 when EALREADY => return Operation_Already_In_Progress;
1760 when EBADF => return Bad_File_Descriptor;
1761 when ECONNABORTED => return Software_Caused_Connection_Abort;
1762 when ECONNREFUSED => return Connection_Refused;
1763 when ECONNRESET => return Connection_Reset_By_Peer;
1764 when EDESTADDRREQ => return Destination_Address_Required;
1765 when EFAULT => return Bad_Address;
1766 when EHOSTDOWN => return Host_Is_Down;
1767 when EHOSTUNREACH => return No_Route_To_Host;
1768 when EINPROGRESS => return Operation_Now_In_Progress;
1769 when EINTR => return Interrupted_System_Call;
1770 when EINVAL => return Invalid_Argument;
1771 when EIO => return Input_Output_Error;
1772 when EISCONN => return Transport_Endpoint_Already_Connected;
1773 when ELOOP => return Too_Many_Symbolic_Links;
1774 when EMFILE => return Too_Many_Open_Files;
1775 when EMSGSIZE => return Message_Too_Long;
1776 when ENAMETOOLONG => return File_Name_Too_Long;
1777 when ENETDOWN => return Network_Is_Down;
1778 when ENETRESET => return
1779 Network_Dropped_Connection_Because_Of_Reset;
1780 when ENETUNREACH => return Network_Is_Unreachable;
1781 when ENOBUFS => return No_Buffer_Space_Available;
1782 when ENOPROTOOPT => return Protocol_Not_Available;
1783 when ENOTCONN => return Transport_Endpoint_Not_Connected;
1784 when ENOTSOCK => return Socket_Operation_On_Non_Socket;
1785 when EOPNOTSUPP => return Operation_Not_Supported;
1786 when EPFNOSUPPORT => return Protocol_Family_Not_Supported;
1787 when EPIPE => return Broken_Pipe;
1788 when EPROTONOSUPPORT => return Protocol_Not_Supported;
1789 when EPROTOTYPE => return Protocol_Wrong_Type_For_Socket;
1790 when ESHUTDOWN => return
1791 Cannot_Send_After_Transport_Endpoint_Shutdown;
1792 when ESOCKTNOSUPPORT => return Socket_Type_Not_Supported;
1793 when ETIMEDOUT => return Connection_Timed_Out;
1794 when ETOOMANYREFS => return Too_Many_References;
1795 when EWOULDBLOCK => return Resource_Temporarily_Unavailable;
1797 when others => return Cannot_Resolve_Error;
1801 -----------------------
1802 -- Resolve_Exception --
1803 -----------------------
1805 function Resolve_Exception
1806 (Occurrence : Exception_Occurrence) return Error_Type
1808 Id : constant Exception_Id := Exception_Identity (Occurrence);
1809 Msg : constant String := Exception_Message (Occurrence);
1816 while First <= Msg'Last
1817 and then Msg (First) not in '0' .. '9'
1822 if First > Msg'Last then
1823 return Cannot_Resolve_Error;
1827 while Last < Msg'Last
1828 and then Msg (Last + 1) in '0' .. '9'
1833 Val := Integer'Value (Msg (First .. Last));
1835 if Id = Socket_Error_Id then
1836 return Resolve_Error (Val);
1838 elsif Id = Host_Error_Id then
1839 return Resolve_Error (Val, False);
1842 return Cannot_Resolve_Error;
1844 end Resolve_Exception;
1850 procedure Send_Socket
1851 (Socket : Socket_Type;
1852 Item : Ada.Streams.Stream_Element_Array;
1853 Last : out Ada.Streams.Stream_Element_Offset;
1854 Flags : Request_Flag_Type := No_Request_Flag)
1857 Send_Socket (Socket, Item, Last, To => null, Flags => Flags);
1864 procedure Send_Socket
1865 (Socket : Socket_Type;
1866 Item : Ada.Streams.Stream_Element_Array;
1867 Last : out Ada.Streams.Stream_Element_Offset;
1868 To : Sock_Addr_Type;
1869 Flags : Request_Flag_Type := No_Request_Flag)
1873 (Socket, Item, Last, To => To'Unrestricted_Access, Flags => Flags);
1880 procedure Send_Socket
1881 (Socket : Socket_Type;
1882 Item : Ada.Streams.Stream_Element_Array;
1883 Last : out Ada.Streams.Stream_Element_Offset;
1884 To : access Sock_Addr_Type;
1885 Flags : Request_Flag_Type := No_Request_Flag)
1889 Sin : aliased Sockaddr_In;
1890 C_To : System.Address;
1895 Set_Family (Sin.Sin_Family, To.Family);
1896 Set_Address (Sin'Unchecked_Access, To_In_Addr (To.Addr));
1898 (Sin'Unchecked_Access,
1899 Short_To_Network (C.unsigned_short (To.Port)));
1900 C_To := Sin'Address;
1901 Len := Sin'Size / 8;
1904 C_To := System.Null_Address;
1912 Set_Forced_Flags (To_Int (Flags)),
1916 if Res = Failure then
1917 Raise_Socket_Error (Socket_Errno);
1920 Last := Last_Index (First => Item'First, Count => Res);
1927 procedure Send_Vector
1928 (Socket : Socket_Type;
1929 Vector : Vector_Type;
1930 Count : out Ada.Streams.Stream_Element_Count;
1931 Flags : Request_Flag_Type := No_Request_Flag)
1937 Iov_Count : SOSC.Msg_Iovlen_T;
1938 This_Iov_Count : SOSC.Msg_Iovlen_T;
1944 while Iov_Count < Vector'Length loop
1946 pragma Warnings (Off);
1947 -- Following test may be compile time known on some targets
1950 (if Vector'Length - Iov_Count > SOSC.IOV_MAX
1952 else Vector'Length - Iov_Count);
1954 pragma Warnings (On);
1957 (Msg_Name => System.Null_Address,
1960 (Vector'First + Integer (Iov_Count))'Address,
1961 Msg_Iovlen => This_Iov_Count,
1962 Msg_Control => System.Null_Address,
1963 Msg_Controllen => 0,
1970 Set_Forced_Flags (To_Int (Flags)));
1972 if Res = ssize_t (Failure) then
1973 Raise_Socket_Error (Socket_Errno);
1976 Count := Count + Ada.Streams.Stream_Element_Count (Res);
1977 Iov_Count := Iov_Count + This_Iov_Count;
1985 procedure Set (Item : in out Socket_Set_Type; Socket : Socket_Type) is
1987 if Item.Last = No_Socket then
1989 -- Uninitialized socket set, make sure it is properly zeroed out
1991 Reset_Socket_Set (Item.Set'Access);
1992 Item.Last := Socket;
1994 elsif Item.Last < Socket then
1995 Item.Last := Socket;
1998 Insert_Socket_In_Set (Item.Set'Access, C.int (Socket));
2001 ----------------------
2002 -- Set_Forced_Flags --
2003 ----------------------
2005 function Set_Forced_Flags (F : C.int) return C.int is
2006 use type C.unsigned;
2007 function To_unsigned is
2008 new Ada.Unchecked_Conversion (C.int, C.unsigned);
2010 new Ada.Unchecked_Conversion (C.unsigned, C.int);
2012 return To_int (To_unsigned (F) or SOSC.MSG_Forced_Flags);
2013 end Set_Forced_Flags;
2015 -----------------------
2016 -- Set_Socket_Option --
2017 -----------------------
2019 procedure Set_Socket_Option
2020 (Socket : Socket_Type;
2021 Level : Level_Type := Socket_Level;
2022 Option : Option_Type)
2024 V8 : aliased Two_Ints;
2026 V1 : aliased C.unsigned_char;
2027 VT : aliased Timeval;
2029 Add : System.Address := Null_Address;
2038 V4 := C.int (Boolean'Pos (Option.Enabled));
2043 V8 (V8'First) := C.int (Boolean'Pos (Option.Enabled));
2044 V8 (V8'Last) := C.int (Option.Seconds);
2050 V4 := C.int (Option.Size);
2055 V4 := C.int (Boolean'Pos (True));
2059 when Add_Membership |
2061 V8 (V8'First) := To_Int (To_In_Addr (Option.Multicast_Address));
2062 V8 (V8'Last) := To_Int (To_In_Addr (Option.Local_Interface));
2066 when Multicast_If =>
2067 V4 := To_Int (To_In_Addr (Option.Outgoing_If));
2071 when Multicast_TTL =>
2072 V1 := C.unsigned_char (Option.Time_To_Live);
2076 when Multicast_Loop |
2077 Receive_Packet_Info =>
2078 V1 := C.unsigned_char (Boolean'Pos (Option.Enabled));
2084 VT := To_Timeval (Option.Timeout);
2093 Options (Option.Name),
2096 if Res = Failure then
2097 Raise_Socket_Error (Socket_Errno);
2099 end Set_Socket_Option;
2101 ----------------------
2102 -- Short_To_Network --
2103 ----------------------
2105 function Short_To_Network (S : C.unsigned_short) return C.unsigned_short is
2106 use type C.unsigned_short;
2109 -- Big-endian case. No conversion needed. On these platforms,
2110 -- htons() defaults to a null procedure.
2112 pragma Warnings (Off);
2113 -- Since the test can generate "always True/False" warning
2115 if Default_Bit_Order = High_Order_First then
2118 pragma Warnings (On);
2120 -- Little-endian case. We must swap the high and low bytes of this
2121 -- short to make the port number network compliant.
2124 return (S / 256) + (S mod 256) * 256;
2126 end Short_To_Network;
2128 ---------------------
2129 -- Shutdown_Socket --
2130 ---------------------
2132 procedure Shutdown_Socket
2133 (Socket : Socket_Type;
2134 How : Shutmode_Type := Shut_Read_Write)
2139 Res := C_Shutdown (C.int (Socket), Shutmodes (How));
2141 if Res = Failure then
2142 Raise_Socket_Error (Socket_Errno);
2144 end Shutdown_Socket;
2151 (Socket : Socket_Type;
2152 Send_To : Sock_Addr_Type) return Stream_Access
2154 S : Datagram_Socket_Stream_Access;
2157 S := new Datagram_Socket_Stream_Type;
2160 S.From := Get_Socket_Name (Socket);
2161 return Stream_Access (S);
2168 function Stream (Socket : Socket_Type) return Stream_Access is
2169 S : Stream_Socket_Stream_Access;
2171 S := new Stream_Socket_Stream_Type;
2173 return Stream_Access (S);
2180 procedure Stream_Write
2181 (Socket : Socket_Type;
2182 Item : Ada.Streams.Stream_Element_Array;
2183 To : access Sock_Addr_Type)
2185 First : Ada.Streams.Stream_Element_Offset;
2186 Index : Ada.Streams.Stream_Element_Offset;
2187 Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
2190 First := Item'First;
2192 while First <= Max loop
2193 Send_Socket (Socket, Item (First .. Max), Index, To);
2195 -- Exit when all or zero data sent. Zero means that the socket has
2196 -- been closed by peer.
2198 exit when Index < First or else Index = Max;
2203 -- For an empty array, we have First > Max, and hence Index >= Max (no
2204 -- error, the loop above is never executed). After a succesful send,
2205 -- Index = Max. The only remaining case, Index < Max, is therefore
2206 -- always an actual send failure.
2209 Raise_Socket_Error (Socket_Errno);
2217 function To_C (Socket : Socket_Type) return Integer is
2219 return Integer (Socket);
2226 function To_Duration (Val : Timeval) return Timeval_Duration is
2228 return Natural (Val.Tv_Sec) * 1.0 + Natural (Val.Tv_Usec) * 1.0E-6;
2235 function To_Host_Entry (E : Hostent) return Host_Entry_Type is
2238 Official : constant String :=
2239 C.Strings.Value (E.H_Name);
2241 Aliases : constant Chars_Ptr_Array :=
2242 Chars_Ptr_Pointers.Value (E.H_Aliases);
2243 -- H_Aliases points to a list of name aliases. The list is terminated by
2246 Addresses : constant In_Addr_Access_Array :=
2247 In_Addr_Access_Pointers.Value (E.H_Addr_List);
2248 -- H_Addr_List points to a list of binary addresses (in network byte
2249 -- order). The list is terminated by a NULL pointer.
2251 -- H_Length is not used because it is currently only set to 4.
2252 -- H_Addrtype is always AF_INET
2254 Result : Host_Entry_Type
2255 (Aliases_Length => Aliases'Length - 1,
2256 Addresses_Length => Addresses'Length - 1);
2257 -- The last element is a null pointer
2263 Result.Official := To_Name (Official);
2265 Source := Aliases'First;
2266 Target := Result.Aliases'First;
2267 while Target <= Result.Aliases_Length loop
2268 Result.Aliases (Target) :=
2269 To_Name (C.Strings.Value (Aliases (Source)));
2270 Source := Source + 1;
2271 Target := Target + 1;
2274 Source := Addresses'First;
2275 Target := Result.Addresses'First;
2276 while Target <= Result.Addresses_Length loop
2277 To_Inet_Addr (Addresses (Source).all, Result.Addresses (Target));
2278 Source := Source + 1;
2279 Target := Target + 1;
2289 function To_In_Addr (Addr : Inet_Addr_Type) return In_Addr is
2291 if Addr.Family = Family_Inet then
2292 return (S_B1 => C.unsigned_char (Addr.Sin_V4 (1)),
2293 S_B2 => C.unsigned_char (Addr.Sin_V4 (2)),
2294 S_B3 => C.unsigned_char (Addr.Sin_V4 (3)),
2295 S_B4 => C.unsigned_char (Addr.Sin_V4 (4)));
2298 raise Socket_Error with "IPv6 not supported";
2305 procedure To_Inet_Addr
2307 Result : out Inet_Addr_Type) is
2309 Result.Sin_V4 (1) := Inet_Addr_Comp_Type (Addr.S_B1);
2310 Result.Sin_V4 (2) := Inet_Addr_Comp_Type (Addr.S_B2);
2311 Result.Sin_V4 (3) := Inet_Addr_Comp_Type (Addr.S_B3);
2312 Result.Sin_V4 (4) := Inet_Addr_Comp_Type (Addr.S_B4);
2319 function To_Int (F : Request_Flag_Type) return C.int
2321 Current : Request_Flag_Type := F;
2322 Result : C.int := 0;
2325 for J in Flags'Range loop
2326 exit when Current = 0;
2328 if Current mod 2 /= 0 then
2329 if Flags (J) = -1 then
2330 Raise_Socket_Error (SOSC.EOPNOTSUPP);
2333 Result := Result + Flags (J);
2336 Current := Current / 2;
2346 function To_Name (N : String) return Name_Type is
2348 return Name_Type'(N'Length, N);
2351 ----------------------
2352 -- To_Service_Entry --
2353 ----------------------
2355 function To_Service_Entry (E : Servent) return Service_Entry_Type is
2358 Official : constant String := C.Strings.Value (E.S_Name);
2360 Aliases : constant Chars_Ptr_Array :=
2361 Chars_Ptr_Pointers.Value (E.S_Aliases);
2362 -- S_Aliases points to a list of name aliases. The list is
2363 -- terminated by a NULL pointer.
2365 Protocol : constant String := C.Strings.Value (E.S_Proto);
2367 Result : Service_Entry_Type (Aliases_Length => Aliases'Length - 1);
2368 -- The last element is a null pointer
2374 Result.Official := To_Name (Official);
2376 Source := Aliases'First;
2377 Target := Result.Aliases'First;
2378 while Target <= Result.Aliases_Length loop
2379 Result.Aliases (Target) :=
2380 To_Name (C.Strings.Value (Aliases (Source)));
2381 Source := Source + 1;
2382 Target := Target + 1;
2386 Port_Type (Network_To_Short (C.unsigned_short (E.S_Port)));
2388 Result.Protocol := To_Name (Protocol);
2390 end To_Service_Entry;
2396 function To_String (HN : Name_Type) return String is
2398 return HN.Name (1 .. HN.Length);
2405 function To_Timeval (Val : Timeval_Duration) return Timeval is
2410 -- If zero, set result as zero (otherwise it gets rounded down to -1)
2416 -- Normal case where we do round down
2419 S := time_t (Val - 0.5);
2420 uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)));
2431 (Stream : in out Datagram_Socket_Stream_Type;
2432 Item : Ada.Streams.Stream_Element_Array)
2435 Stream_Write (Stream.Socket, Item, To => Stream.To'Unrestricted_Access);
2443 (Stream : in out Stream_Socket_Stream_Type;
2444 Item : Ada.Streams.Stream_Element_Array)
2447 Stream_Write (Stream.Socket, Item, To => null);
2450 Sockets_Library_Controller_Object : Sockets_Library_Controller;
2451 pragma Unreferenced (Sockets_Library_Controller_Object);
2452 -- The elaboration and finalization of this object perform the required
2453 -- initialization and cleanup actions for the sockets library.