diff options
Diffstat (limited to 'gcc-4.7/gcc/ada/g-socket.adb')
-rw-r--r-- | gcc-4.7/gcc/ada/g-socket.adb | 2614 |
1 files changed, 0 insertions, 2614 deletions
diff --git a/gcc-4.7/gcc/ada/g-socket.adb b/gcc-4.7/gcc/ada/g-socket.adb deleted file mode 100644 index d48065a23..000000000 --- a/gcc-4.7/gcc/ada/g-socket.adb +++ /dev/null @@ -1,2614 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT COMPILER COMPONENTS -- --- -- --- G N A T . S O C K E T S -- --- -- --- B o d y -- --- -- --- Copyright (C) 2001-2011, AdaCore -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - -with Ada.Streams; use Ada.Streams; -with Ada.Exceptions; use Ada.Exceptions; -with Ada.Finalization; -with Ada.Unchecked_Conversion; - -with Interfaces.C.Strings; - -with GNAT.Sockets.Thin_Common; use GNAT.Sockets.Thin_Common; -with GNAT.Sockets.Thin; use GNAT.Sockets.Thin; - -with GNAT.Sockets.Linker_Options; -pragma Warnings (Off, GNAT.Sockets.Linker_Options); --- Need to include pragma Linker_Options which is platform dependent - -with System; use System; -with System.Communication; use System.Communication; -with System.CRTL; use System.CRTL; -with System.Task_Lock; - -package body GNAT.Sockets is - - package C renames Interfaces.C; - - use type C.int; - - ENOERROR : constant := 0; - - Netdb_Buffer_Size : constant := SOSC.Need_Netdb_Buffer * 1024; - Need_Netdb_Lock : constant Boolean := SOSC.Need_Netdb_Lock /= 0; - -- The network database functions gethostbyname, gethostbyaddr, - -- getservbyname and getservbyport can either be guaranteed task safe by - -- the operating system, or else return data through a user-provided buffer - -- to ensure concurrent uses do not interfere. - - -- Correspondence tables - - Levels : constant array (Level_Type) of C.int := - (Socket_Level => SOSC.SOL_SOCKET, - IP_Protocol_For_IP_Level => SOSC.IPPROTO_IP, - IP_Protocol_For_UDP_Level => SOSC.IPPROTO_UDP, - IP_Protocol_For_TCP_Level => SOSC.IPPROTO_TCP); - - Modes : constant array (Mode_Type) of C.int := - (Socket_Stream => SOSC.SOCK_STREAM, - Socket_Datagram => SOSC.SOCK_DGRAM); - - Shutmodes : constant array (Shutmode_Type) of C.int := - (Shut_Read => SOSC.SHUT_RD, - Shut_Write => SOSC.SHUT_WR, - Shut_Read_Write => SOSC.SHUT_RDWR); - - Requests : constant array (Request_Name) of C.int := - (Non_Blocking_IO => SOSC.FIONBIO, - N_Bytes_To_Read => SOSC.FIONREAD); - - Options : constant array (Option_Name) of C.int := - (Keep_Alive => SOSC.SO_KEEPALIVE, - Reuse_Address => SOSC.SO_REUSEADDR, - Broadcast => SOSC.SO_BROADCAST, - Send_Buffer => SOSC.SO_SNDBUF, - Receive_Buffer => SOSC.SO_RCVBUF, - Linger => SOSC.SO_LINGER, - Error => SOSC.SO_ERROR, - No_Delay => SOSC.TCP_NODELAY, - Add_Membership => SOSC.IP_ADD_MEMBERSHIP, - Drop_Membership => SOSC.IP_DROP_MEMBERSHIP, - Multicast_If => SOSC.IP_MULTICAST_IF, - Multicast_TTL => SOSC.IP_MULTICAST_TTL, - Multicast_Loop => SOSC.IP_MULTICAST_LOOP, - Receive_Packet_Info => SOSC.IP_PKTINFO, - Send_Timeout => SOSC.SO_SNDTIMEO, - Receive_Timeout => SOSC.SO_RCVTIMEO); - -- ??? Note: for OpenSolaris, Receive_Packet_Info should be IP_RECVPKTINFO, - -- but for Linux compatibility this constant is the same as IP_PKTINFO. - - Flags : constant array (0 .. 3) of C.int := - (0 => SOSC.MSG_OOB, -- Process_Out_Of_Band_Data - 1 => SOSC.MSG_PEEK, -- Peek_At_Incoming_Data - 2 => SOSC.MSG_WAITALL, -- Wait_For_A_Full_Reception - 3 => SOSC.MSG_EOR); -- Send_End_Of_Record - - Socket_Error_Id : constant Exception_Id := Socket_Error'Identity; - Host_Error_Id : constant Exception_Id := Host_Error'Identity; - - Hex_To_Char : constant String (1 .. 16) := "0123456789ABCDEF"; - -- Use to print in hexadecimal format - - ----------------------- - -- Local subprograms -- - ----------------------- - - function Resolve_Error - (Error_Value : Integer; - From_Errno : Boolean := True) return Error_Type; - -- Associate an enumeration value (error_type) to en error value (errno). - -- From_Errno prevents from mixing h_errno with errno. - - function To_Name (N : String) return Name_Type; - function To_String (HN : Name_Type) return String; - -- Conversion functions - - function To_Int (F : Request_Flag_Type) return C.int; - -- Return the int value corresponding to the specified flags combination - - function Set_Forced_Flags (F : C.int) return C.int; - -- Return F with the bits from SOSC.MSG_Forced_Flags forced set - - function Short_To_Network - (S : C.unsigned_short) return C.unsigned_short; - pragma Inline (Short_To_Network); - -- Convert a port number into a network port number - - function Network_To_Short - (S : C.unsigned_short) return C.unsigned_short - renames Short_To_Network; - -- Symmetric operation - - function Image - (Val : Inet_Addr_VN_Type; - Hex : Boolean := False) return String; - -- Output an array of inet address components in hex or decimal mode - - function Is_IP_Address (Name : String) return Boolean; - -- Return true when Name is an IP address in standard dot notation - - procedure Netdb_Lock; - pragma Inline (Netdb_Lock); - procedure Netdb_Unlock; - pragma Inline (Netdb_Unlock); - -- Lock/unlock operation used to protect netdb access for platforms that - -- require such protection. - - function To_In_Addr (Addr : Inet_Addr_Type) return In_Addr; - procedure To_Inet_Addr - (Addr : In_Addr; - Result : out Inet_Addr_Type); - -- Conversion functions - - function To_Host_Entry (E : Hostent_Access) return Host_Entry_Type; - -- Conversion function - - function To_Service_Entry (E : Servent_Access) return Service_Entry_Type; - -- Conversion function - - function Value (S : System.Address) return String; - -- Same as Interfaces.C.Strings.Value but taking a System.Address (on VMS, - -- chars_ptr is a 32-bit pointer, and here we need a 64-bit version). - - function To_Timeval (Val : Timeval_Duration) return Timeval; - -- Separate Val in seconds and microseconds - - function To_Duration (Val : Timeval) return Timeval_Duration; - -- Reconstruct a Duration value from a Timeval record (seconds and - -- microseconds). - - procedure Raise_Socket_Error (Error : Integer); - -- Raise Socket_Error with an exception message describing the error code - -- from errno. - - procedure Raise_Host_Error (H_Error : Integer); - -- Raise Host_Error exception with message describing error code (note - -- hstrerror seems to be obsolete) from h_errno. - - procedure Narrow (Item : in out Socket_Set_Type); - -- Update Last as it may be greater than the real last socket - - procedure Check_For_Fd_Set (Fd : Socket_Type); - pragma Inline (Check_For_Fd_Set); - -- Raise Constraint_Error if Fd is less than 0 or greater than or equal to - -- FD_SETSIZE, on platforms where fd_set is a bitmap. - - -- Types needed for Datagram_Socket_Stream_Type - - type Datagram_Socket_Stream_Type is new Root_Stream_Type with record - Socket : Socket_Type; - To : Sock_Addr_Type; - From : Sock_Addr_Type; - end record; - - type Datagram_Socket_Stream_Access is - access all Datagram_Socket_Stream_Type; - - procedure Read - (Stream : in out Datagram_Socket_Stream_Type; - Item : out Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset); - - procedure Write - (Stream : in out Datagram_Socket_Stream_Type; - Item : Ada.Streams.Stream_Element_Array); - - -- Types needed for Stream_Socket_Stream_Type - - type Stream_Socket_Stream_Type is new Root_Stream_Type with record - Socket : Socket_Type; - end record; - - type Stream_Socket_Stream_Access is - access all Stream_Socket_Stream_Type; - - procedure Read - (Stream : in out Stream_Socket_Stream_Type; - Item : out Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset); - - procedure Write - (Stream : in out Stream_Socket_Stream_Type; - Item : Ada.Streams.Stream_Element_Array); - - procedure Stream_Write - (Socket : Socket_Type; - Item : Ada.Streams.Stream_Element_Array; - To : access Sock_Addr_Type); - -- Common implementation for the Write operation of Datagram_Socket_Stream_ - -- Type and Stream_Socket_Stream_Type. - - procedure Wait_On_Socket - (Socket : Socket_Type; - For_Read : Boolean; - Timeout : Selector_Duration; - Selector : access Selector_Type := null; - Status : out Selector_Status); - -- Common code for variants of socket operations supporting a timeout: - -- block in Check_Selector on Socket for at most the indicated timeout. - -- If For_Read is True, Socket is added to the read set for this call, else - -- it is added to the write set. If no selector is provided, a local one is - -- created for this call and destroyed prior to returning. - - type Sockets_Library_Controller is new Ada.Finalization.Limited_Controlled - with null record; - -- This type is used to generate automatic calls to Initialize and Finalize - -- during the elaboration and finalization of this package. A single object - -- of this type must exist at library level. - - function Err_Code_Image (E : Integer) return String; - -- Return the value of E surrounded with brackets - - procedure Initialize (X : in out Sockets_Library_Controller); - procedure Finalize (X : in out Sockets_Library_Controller); - - procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type); - -- If S is the empty set (detected by Last = No_Socket), make sure its - -- fd_set component is actually cleared. Note that the case where it is - -- not can occur for an uninitialized Socket_Set_Type object. - - function Is_Open (S : Selector_Type) return Boolean; - -- Return True for an "open" Selector_Type object, i.e. one for which - -- Create_Selector has been called and Close_Selector has not been called, - -- or the null selector. - - --------- - -- "+" -- - --------- - - function "+" (L, R : Request_Flag_Type) return Request_Flag_Type is - begin - return L or R; - end "+"; - - -------------------- - -- Abort_Selector -- - -------------------- - - procedure Abort_Selector (Selector : Selector_Type) is - Res : C.int; - - begin - if not Is_Open (Selector) then - raise Program_Error with "closed selector"; - - elsif Selector.Is_Null then - raise Program_Error with "null selector"; - - end if; - - -- Send one byte to unblock select system call - - Res := Signalling_Fds.Write (C.int (Selector.W_Sig_Socket)); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Abort_Selector; - - ------------------- - -- Accept_Socket -- - ------------------- - - procedure Accept_Socket - (Server : Socket_Type; - Socket : out Socket_Type; - Address : out Sock_Addr_Type) - is - Res : C.int; - Sin : aliased Sockaddr_In; - Len : aliased C.int := Sin'Size / 8; - - begin - Res := C_Accept (C.int (Server), Sin'Address, Len'Access); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Socket := Socket_Type (Res); - - To_Inet_Addr (Sin.Sin_Addr, Address.Addr); - Address.Port := Port_Type (Network_To_Short (Sin.Sin_Port)); - end Accept_Socket; - - ------------------- - -- Accept_Socket -- - ------------------- - - procedure Accept_Socket - (Server : Socket_Type; - Socket : out Socket_Type; - Address : out Sock_Addr_Type; - Timeout : Selector_Duration; - Selector : access Selector_Type := null; - Status : out Selector_Status) - is - begin - if Selector /= null and then not Is_Open (Selector.all) then - raise Program_Error with "closed selector"; - end if; - - -- Wait for socket to become available for reading - - Wait_On_Socket - (Socket => Server, - For_Read => True, - Timeout => Timeout, - Selector => Selector, - Status => Status); - - -- Accept connection if available - - if Status = Completed then - Accept_Socket (Server, Socket, Address); - else - Socket := No_Socket; - end if; - end Accept_Socket; - - --------------- - -- Addresses -- - --------------- - - function Addresses - (E : Host_Entry_Type; - N : Positive := 1) return Inet_Addr_Type - is - begin - return E.Addresses (N); - end Addresses; - - ---------------------- - -- Addresses_Length -- - ---------------------- - - function Addresses_Length (E : Host_Entry_Type) return Natural is - begin - return E.Addresses_Length; - end Addresses_Length; - - ------------- - -- Aliases -- - ------------- - - function Aliases - (E : Host_Entry_Type; - N : Positive := 1) return String - is - begin - return To_String (E.Aliases (N)); - end Aliases; - - ------------- - -- Aliases -- - ------------- - - function Aliases - (S : Service_Entry_Type; - N : Positive := 1) return String - is - begin - return To_String (S.Aliases (N)); - end Aliases; - - -------------------- - -- Aliases_Length -- - -------------------- - - function Aliases_Length (E : Host_Entry_Type) return Natural is - begin - return E.Aliases_Length; - end Aliases_Length; - - -------------------- - -- Aliases_Length -- - -------------------- - - function Aliases_Length (S : Service_Entry_Type) return Natural is - begin - return S.Aliases_Length; - end Aliases_Length; - - ----------------- - -- Bind_Socket -- - ----------------- - - procedure Bind_Socket - (Socket : Socket_Type; - Address : Sock_Addr_Type) - is - Res : C.int; - Sin : aliased Sockaddr_In; - Len : constant C.int := Sin'Size / 8; - -- This assumes that Address.Family = Family_Inet??? - - begin - if Address.Family = Family_Inet6 then - raise Socket_Error with "IPv6 not supported"; - end if; - - Set_Family (Sin.Sin_Family, Address.Family); - Set_Address (Sin'Unchecked_Access, To_In_Addr (Address.Addr)); - Set_Port - (Sin'Unchecked_Access, - Short_To_Network (C.unsigned_short (Address.Port))); - - Res := C_Bind (C.int (Socket), Sin'Address, Len); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Bind_Socket; - - ---------------------- - -- Check_For_Fd_Set -- - ---------------------- - - procedure Check_For_Fd_Set (Fd : Socket_Type) is - use SOSC; - - begin - -- On Windows, fd_set is a FD_SETSIZE array of socket ids: - -- no check required. Warnings suppressed because condition - -- is known at compile time. - - pragma Warnings (Off); - if Target_OS = Windows then - pragma Warnings (On); - - return; - - -- On other platforms, fd_set is an FD_SETSIZE bitmap: check - -- that Fd is within range (otherwise behaviour is undefined). - - elsif Fd < 0 or else Fd >= SOSC.FD_SETSIZE then - raise Constraint_Error - with "invalid value for socket set: " & Image (Fd); - end if; - end Check_For_Fd_Set; - - -------------------- - -- Check_Selector -- - -------------------- - - procedure Check_Selector - (Selector : Selector_Type; - R_Socket_Set : in out Socket_Set_Type; - W_Socket_Set : in out Socket_Set_Type; - Status : out Selector_Status; - Timeout : Selector_Duration := Forever) - is - E_Socket_Set : Socket_Set_Type; - begin - Check_Selector - (Selector, R_Socket_Set, W_Socket_Set, E_Socket_Set, Status, Timeout); - end Check_Selector; - - -------------------- - -- Check_Selector -- - -------------------- - - procedure Check_Selector - (Selector : Selector_Type; - R_Socket_Set : in out Socket_Set_Type; - W_Socket_Set : in out Socket_Set_Type; - E_Socket_Set : in out Socket_Set_Type; - Status : out Selector_Status; - Timeout : Selector_Duration := Forever) - is - Res : C.int; - Last : C.int; - RSig : Socket_Type := No_Socket; - TVal : aliased Timeval; - TPtr : Timeval_Access; - - begin - if not Is_Open (Selector) then - raise Program_Error with "closed selector"; - end if; - - Status := Completed; - - -- No timeout or Forever is indicated by a null timeval pointer - - if Timeout = Forever then - TPtr := null; - else - TVal := To_Timeval (Timeout); - TPtr := TVal'Unchecked_Access; - end if; - - -- Add read signalling socket, if present - - if not Selector.Is_Null then - RSig := Selector.R_Sig_Socket; - Set (R_Socket_Set, RSig); - end if; - - Last := C.int'Max (C.int'Max (C.int (R_Socket_Set.Last), - C.int (W_Socket_Set.Last)), - C.int (E_Socket_Set.Last)); - - -- Zero out fd_set for empty Socket_Set_Type objects - - Normalize_Empty_Socket_Set (R_Socket_Set); - Normalize_Empty_Socket_Set (W_Socket_Set); - Normalize_Empty_Socket_Set (E_Socket_Set); - - Res := - C_Select - (Last + 1, - R_Socket_Set.Set'Access, - W_Socket_Set.Set'Access, - E_Socket_Set.Set'Access, - TPtr); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - -- If Select was resumed because of read signalling socket, read this - -- data and remove socket from set. - - if RSig /= No_Socket and then Is_Set (R_Socket_Set, RSig) then - Clear (R_Socket_Set, RSig); - - Res := Signalling_Fds.Read (C.int (RSig)); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Status := Aborted; - - elsif Res = 0 then - Status := Expired; - end if; - - -- Update socket sets in regard to their new contents - - Narrow (R_Socket_Set); - Narrow (W_Socket_Set); - Narrow (E_Socket_Set); - end Check_Selector; - - ----------- - -- Clear -- - ----------- - - procedure Clear - (Item : in out Socket_Set_Type; - Socket : Socket_Type) - is - Last : aliased C.int := C.int (Item.Last); - - begin - Check_For_Fd_Set (Socket); - - if Item.Last /= No_Socket then - Remove_Socket_From_Set (Item.Set'Access, C.int (Socket)); - Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access); - Item.Last := Socket_Type (Last); - end if; - end Clear; - - -------------------- - -- Close_Selector -- - -------------------- - - procedure Close_Selector (Selector : in out Selector_Type) is - begin - -- Nothing to do if selector already in closed state - - if Selector.Is_Null or else not Is_Open (Selector) then - return; - end if; - - -- Close the signalling file descriptors used internally for the - -- implementation of Abort_Selector. - - Signalling_Fds.Close (C.int (Selector.R_Sig_Socket)); - Signalling_Fds.Close (C.int (Selector.W_Sig_Socket)); - - -- Reset R_Sig_Socket and W_Sig_Socket to No_Socket to ensure that any - -- (erroneous) subsequent attempt to use this selector properly fails. - - Selector.R_Sig_Socket := No_Socket; - Selector.W_Sig_Socket := No_Socket; - end Close_Selector; - - ------------------ - -- Close_Socket -- - ------------------ - - procedure Close_Socket (Socket : Socket_Type) is - Res : C.int; - - begin - Res := C_Close (C.int (Socket)); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Close_Socket; - - -------------------- - -- Connect_Socket -- - -------------------- - - procedure Connect_Socket - (Socket : Socket_Type; - Server : Sock_Addr_Type) - is - Res : C.int; - Sin : aliased Sockaddr_In; - Len : constant C.int := Sin'Size / 8; - - begin - if Server.Family = Family_Inet6 then - raise Socket_Error with "IPv6 not supported"; - end if; - - Set_Family (Sin.Sin_Family, Server.Family); - Set_Address (Sin'Unchecked_Access, To_In_Addr (Server.Addr)); - Set_Port - (Sin'Unchecked_Access, - Short_To_Network (C.unsigned_short (Server.Port))); - - Res := C_Connect (C.int (Socket), Sin'Address, Len); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Connect_Socket; - - -------------------- - -- Connect_Socket -- - -------------------- - - procedure Connect_Socket - (Socket : Socket_Type; - Server : Sock_Addr_Type; - Timeout : Selector_Duration; - Selector : access Selector_Type := null; - Status : out Selector_Status) - is - Req : Request_Type; - -- Used to set Socket to non-blocking I/O - - begin - if Selector /= null and then not Is_Open (Selector.all) then - raise Program_Error with "closed selector"; - end if; - - -- Set the socket to non-blocking I/O - - Req := (Name => Non_Blocking_IO, Enabled => True); - Control_Socket (Socket, Request => Req); - - -- Start operation (non-blocking), will raise Socket_Error with - -- EINPROGRESS. - - begin - Connect_Socket (Socket, Server); - exception - when E : Socket_Error => - if Resolve_Exception (E) = Operation_Now_In_Progress then - null; - else - raise; - end if; - end; - - -- Wait for socket to become available for writing - - Wait_On_Socket - (Socket => Socket, - For_Read => False, - Timeout => Timeout, - Selector => Selector, - Status => Status); - - -- Reset the socket to blocking I/O - - Req := (Name => Non_Blocking_IO, Enabled => False); - Control_Socket (Socket, Request => Req); - end Connect_Socket; - - -------------------- - -- Control_Socket -- - -------------------- - - procedure Control_Socket - (Socket : Socket_Type; - Request : in out Request_Type) - is - Arg : aliased C.int; - Res : C.int; - - begin - case Request.Name is - when Non_Blocking_IO => - Arg := C.int (Boolean'Pos (Request.Enabled)); - - when N_Bytes_To_Read => - null; - end case; - - Res := Socket_Ioctl - (C.int (Socket), Requests (Request.Name), Arg'Unchecked_Access); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - case Request.Name is - when Non_Blocking_IO => - null; - - when N_Bytes_To_Read => - Request.Size := Natural (Arg); - end case; - end Control_Socket; - - ---------- - -- Copy -- - ---------- - - procedure Copy - (Source : Socket_Set_Type; - Target : out Socket_Set_Type) - is - begin - Target := Source; - end Copy; - - --------------------- - -- Create_Selector -- - --------------------- - - procedure Create_Selector (Selector : out Selector_Type) is - Two_Fds : aliased Fd_Pair; - Res : C.int; - - begin - if Is_Open (Selector) then - -- Raise exception to prevent socket descriptor leak - - raise Program_Error with "selector already open"; - end if; - - -- We open two signalling file descriptors. One of them is used to send - -- data to the other, which is included in a C_Select socket set. The - -- communication is used to force a call to C_Select to complete, and - -- the waiting task to resume its execution. - - Res := Signalling_Fds.Create (Two_Fds'Access); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Selector.R_Sig_Socket := Socket_Type (Two_Fds (Read_End)); - Selector.W_Sig_Socket := Socket_Type (Two_Fds (Write_End)); - end Create_Selector; - - ------------------- - -- Create_Socket -- - ------------------- - - procedure Create_Socket - (Socket : out Socket_Type; - Family : Family_Type := Family_Inet; - Mode : Mode_Type := Socket_Stream) - is - Res : C.int; - - begin - Res := C_Socket (Families (Family), Modes (Mode), 0); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Socket := Socket_Type (Res); - end Create_Socket; - - ----------- - -- Empty -- - ----------- - - procedure Empty (Item : out Socket_Set_Type) is - begin - Reset_Socket_Set (Item.Set'Access); - Item.Last := No_Socket; - end Empty; - - -------------------- - -- Err_Code_Image -- - -------------------- - - function Err_Code_Image (E : Integer) return String is - Msg : String := E'Img & "] "; - begin - Msg (Msg'First) := '['; - return Msg; - end Err_Code_Image; - - -------------- - -- Finalize -- - -------------- - - procedure Finalize (X : in out Sockets_Library_Controller) is - pragma Unreferenced (X); - - begin - -- Finalization operation for the GNAT.Sockets package - - Thin.Finalize; - end Finalize; - - -------------- - -- Finalize -- - -------------- - - procedure Finalize is - begin - -- This is a dummy placeholder for an obsolete API. - -- The real finalization actions are in Initialize primitive operation - -- of Sockets_Library_Controller. - - null; - end Finalize; - - --------- - -- Get -- - --------- - - procedure Get - (Item : in out Socket_Set_Type; - Socket : out Socket_Type) - is - S : aliased C.int; - L : aliased C.int := C.int (Item.Last); - - begin - if Item.Last /= No_Socket then - Get_Socket_From_Set - (Item.Set'Access, Last => L'Access, Socket => S'Access); - Item.Last := Socket_Type (L); - Socket := Socket_Type (S); - else - Socket := No_Socket; - end if; - end Get; - - ----------------- - -- Get_Address -- - ----------------- - - function Get_Address - (Stream : not null Stream_Access) return Sock_Addr_Type - is - begin - if Stream.all in Datagram_Socket_Stream_Type then - return Datagram_Socket_Stream_Type (Stream.all).From; - else - return Get_Peer_Name (Stream_Socket_Stream_Type (Stream.all).Socket); - end if; - end Get_Address; - - ------------------------- - -- Get_Host_By_Address -- - ------------------------- - - function Get_Host_By_Address - (Address : Inet_Addr_Type; - Family : Family_Type := Family_Inet) return Host_Entry_Type - is - pragma Unreferenced (Family); - - HA : aliased In_Addr := To_In_Addr (Address); - Buflen : constant C.int := Netdb_Buffer_Size; - Buf : aliased C.char_array (1 .. Netdb_Buffer_Size); - Res : aliased Hostent; - Err : aliased C.int; - - begin - Netdb_Lock; - - if C_Gethostbyaddr (HA'Address, HA'Size / 8, SOSC.AF_INET, - Res'Access, Buf'Address, Buflen, Err'Access) /= 0 - then - Netdb_Unlock; - Raise_Host_Error (Integer (Err)); - end if; - - return H : constant Host_Entry_Type := - To_Host_Entry (Res'Unchecked_Access) - do - Netdb_Unlock; - end return; - end Get_Host_By_Address; - - ---------------------- - -- Get_Host_By_Name -- - ---------------------- - - function Get_Host_By_Name (Name : String) return Host_Entry_Type is - begin - -- Detect IP address name and redirect to Inet_Addr - - if Is_IP_Address (Name) then - return Get_Host_By_Address (Inet_Addr (Name)); - end if; - - declare - HN : constant C.char_array := C.To_C (Name); - Buflen : constant C.int := Netdb_Buffer_Size; - Buf : aliased C.char_array (1 .. Netdb_Buffer_Size); - Res : aliased Hostent; - Err : aliased C.int; - - begin - Netdb_Lock; - - if C_Gethostbyname - (HN, Res'Access, Buf'Address, Buflen, Err'Access) /= 0 - then - Netdb_Unlock; - Raise_Host_Error (Integer (Err)); - end if; - - return H : constant Host_Entry_Type := - To_Host_Entry (Res'Unchecked_Access) - do - Netdb_Unlock; - end return; - end; - end Get_Host_By_Name; - - ------------------- - -- Get_Peer_Name -- - ------------------- - - function Get_Peer_Name (Socket : Socket_Type) return Sock_Addr_Type is - Sin : aliased Sockaddr_In; - Len : aliased C.int := Sin'Size / 8; - Res : Sock_Addr_Type (Family_Inet); - - begin - if C_Getpeername (C.int (Socket), Sin'Address, Len'Access) = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - To_Inet_Addr (Sin.Sin_Addr, Res.Addr); - Res.Port := Port_Type (Network_To_Short (Sin.Sin_Port)); - - return Res; - end Get_Peer_Name; - - ------------------------- - -- Get_Service_By_Name -- - ------------------------- - - function Get_Service_By_Name - (Name : String; - Protocol : String) return Service_Entry_Type - is - SN : constant C.char_array := C.To_C (Name); - SP : constant C.char_array := C.To_C (Protocol); - Buflen : constant C.int := Netdb_Buffer_Size; - Buf : aliased C.char_array (1 .. Netdb_Buffer_Size); - Res : aliased Servent; - - begin - Netdb_Lock; - - if C_Getservbyname (SN, SP, Res'Access, Buf'Address, Buflen) /= 0 then - Netdb_Unlock; - raise Service_Error with "Service not found"; - end if; - - -- Translate from the C format to the API format - - return S : constant Service_Entry_Type := - To_Service_Entry (Res'Unchecked_Access) - do - Netdb_Unlock; - end return; - end Get_Service_By_Name; - - ------------------------- - -- Get_Service_By_Port -- - ------------------------- - - function Get_Service_By_Port - (Port : Port_Type; - Protocol : String) return Service_Entry_Type - is - SP : constant C.char_array := C.To_C (Protocol); - Buflen : constant C.int := Netdb_Buffer_Size; - Buf : aliased C.char_array (1 .. Netdb_Buffer_Size); - Res : aliased Servent; - - begin - Netdb_Lock; - - if C_Getservbyport - (C.int (Short_To_Network (C.unsigned_short (Port))), SP, - Res'Access, Buf'Address, Buflen) /= 0 - then - Netdb_Unlock; - raise Service_Error with "Service not found"; - end if; - - -- Translate from the C format to the API format - - return S : constant Service_Entry_Type := - To_Service_Entry (Res'Unchecked_Access) - do - Netdb_Unlock; - end return; - end Get_Service_By_Port; - - --------------------- - -- Get_Socket_Name -- - --------------------- - - function Get_Socket_Name - (Socket : Socket_Type) return Sock_Addr_Type - is - Sin : aliased Sockaddr_In; - Len : aliased C.int := Sin'Size / 8; - Res : C.int; - Addr : Sock_Addr_Type := No_Sock_Addr; - - begin - Res := C_Getsockname (C.int (Socket), Sin'Address, Len'Access); - - if Res /= Failure then - To_Inet_Addr (Sin.Sin_Addr, Addr.Addr); - Addr.Port := Port_Type (Network_To_Short (Sin.Sin_Port)); - end if; - - return Addr; - end Get_Socket_Name; - - ----------------------- - -- Get_Socket_Option -- - ----------------------- - - function Get_Socket_Option - (Socket : Socket_Type; - Level : Level_Type := Socket_Level; - Name : Option_Name) return Option_Type - is - use type C.unsigned_char; - - V8 : aliased Two_Ints; - V4 : aliased C.int; - V1 : aliased C.unsigned_char; - VT : aliased Timeval; - Len : aliased C.int; - Add : System.Address; - Res : C.int; - Opt : Option_Type (Name); - - begin - case Name is - when Multicast_Loop | - Multicast_TTL | - Receive_Packet_Info => - Len := V1'Size / 8; - Add := V1'Address; - - when Keep_Alive | - Reuse_Address | - Broadcast | - No_Delay | - Send_Buffer | - Receive_Buffer | - Multicast_If | - Error => - Len := V4'Size / 8; - Add := V4'Address; - - when Send_Timeout | - Receive_Timeout => - Len := VT'Size / 8; - Add := VT'Address; - - when Linger | - Add_Membership | - Drop_Membership => - Len := V8'Size / 8; - Add := V8'Address; - - end case; - - Res := - C_Getsockopt - (C.int (Socket), - Levels (Level), - Options (Name), - Add, Len'Access); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - case Name is - when Keep_Alive | - Reuse_Address | - Broadcast | - No_Delay => - Opt.Enabled := (V4 /= 0); - - when Linger => - Opt.Enabled := (V8 (V8'First) /= 0); - Opt.Seconds := Natural (V8 (V8'Last)); - - when Send_Buffer | - Receive_Buffer => - Opt.Size := Natural (V4); - - when Error => - Opt.Error := Resolve_Error (Integer (V4)); - - when Add_Membership | - Drop_Membership => - To_Inet_Addr (To_In_Addr (V8 (V8'First)), Opt.Multicast_Address); - To_Inet_Addr (To_In_Addr (V8 (V8'Last)), Opt.Local_Interface); - - when Multicast_If => - To_Inet_Addr (To_In_Addr (V4), Opt.Outgoing_If); - - when Multicast_TTL => - Opt.Time_To_Live := Integer (V1); - - when Multicast_Loop | - Receive_Packet_Info => - Opt.Enabled := (V1 /= 0); - - when Send_Timeout | - Receive_Timeout => - Opt.Timeout := To_Duration (VT); - end case; - - return Opt; - end Get_Socket_Option; - - --------------- - -- Host_Name -- - --------------- - - function Host_Name return String is - Name : aliased C.char_array (1 .. 64); - Res : C.int; - - begin - Res := C_Gethostname (Name'Address, Name'Length); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - return C.To_Ada (Name); - end Host_Name; - - ----------- - -- Image -- - ----------- - - function Image - (Val : Inet_Addr_VN_Type; - Hex : Boolean := False) return String - is - -- The largest Inet_Addr_Comp_Type image occurs with IPv4. It - -- has at most a length of 3 plus one '.' character. - - Buffer : String (1 .. 4 * Val'Length); - Length : Natural := 1; - Separator : Character; - - procedure Img10 (V : Inet_Addr_Comp_Type); - -- Append to Buffer image of V in decimal format - - procedure Img16 (V : Inet_Addr_Comp_Type); - -- Append to Buffer image of V in hexadecimal format - - ----------- - -- Img10 -- - ----------- - - procedure Img10 (V : Inet_Addr_Comp_Type) is - Img : constant String := V'Img; - Len : constant Natural := Img'Length - 1; - begin - Buffer (Length .. Length + Len - 1) := Img (2 .. Img'Last); - Length := Length + Len; - end Img10; - - ----------- - -- Img16 -- - ----------- - - procedure Img16 (V : Inet_Addr_Comp_Type) is - begin - Buffer (Length) := Hex_To_Char (Natural (V / 16) + 1); - Buffer (Length + 1) := Hex_To_Char (Natural (V mod 16) + 1); - Length := Length + 2; - end Img16; - - -- Start of processing for Image - - begin - Separator := (if Hex then ':' else '.'); - - for J in Val'Range loop - if Hex then - Img16 (Val (J)); - else - Img10 (Val (J)); - end if; - - if J /= Val'Last then - Buffer (Length) := Separator; - Length := Length + 1; - end if; - end loop; - - return Buffer (1 .. Length - 1); - end Image; - - ----------- - -- Image -- - ----------- - - function Image (Value : Inet_Addr_Type) return String is - begin - if Value.Family = Family_Inet then - return Image (Inet_Addr_VN_Type (Value.Sin_V4), Hex => False); - else - return Image (Inet_Addr_VN_Type (Value.Sin_V6), Hex => True); - end if; - end Image; - - ----------- - -- Image -- - ----------- - - function Image (Value : Sock_Addr_Type) return String is - Port : constant String := Value.Port'Img; - begin - return Image (Value.Addr) & ':' & Port (2 .. Port'Last); - end Image; - - ----------- - -- Image -- - ----------- - - function Image (Socket : Socket_Type) return String is - begin - return Socket'Img; - end Image; - - ----------- - -- Image -- - ----------- - - function Image (Item : Socket_Set_Type) return String is - Socket_Set : Socket_Set_Type := Item; - - begin - declare - Last_Img : constant String := Socket_Set.Last'Img; - Buffer : String - (1 .. (Integer (Socket_Set.Last) + 1) * Last_Img'Length); - Index : Positive := 1; - Socket : Socket_Type; - - begin - while not Is_Empty (Socket_Set) loop - Get (Socket_Set, Socket); - - declare - Socket_Img : constant String := Socket'Img; - begin - Buffer (Index .. Index + Socket_Img'Length - 1) := Socket_Img; - Index := Index + Socket_Img'Length; - end; - end loop; - - return "[" & Last_Img & "]" & Buffer (1 .. Index - 1); - end; - end Image; - - --------------- - -- Inet_Addr -- - --------------- - - function Inet_Addr (Image : String) return Inet_Addr_Type is - use Interfaces.C; - use Interfaces.C.Strings; - - Img : aliased char_array := To_C (Image); - Addr : aliased C.int; - Res : C.int; - Result : Inet_Addr_Type; - - begin - -- Special case for an empty Image as on some platforms (e.g. Windows) - -- calling Inet_Addr("") will not return an error. - - if Image = "" then - Raise_Socket_Error (SOSC.EINVAL); - end if; - - Res := Inet_Pton (SOSC.AF_INET, Img'Address, Addr'Address); - - if Res < 0 then - Raise_Socket_Error (Socket_Errno); - - elsif Res = 0 then - Raise_Socket_Error (SOSC.EINVAL); - end if; - - To_Inet_Addr (To_In_Addr (Addr), Result); - return Result; - end Inet_Addr; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize (X : in out Sockets_Library_Controller) is - pragma Unreferenced (X); - - begin - Thin.Initialize; - end Initialize; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize (Process_Blocking_IO : Boolean) is - Expected : constant Boolean := not SOSC.Thread_Blocking_IO; - - begin - if Process_Blocking_IO /= Expected then - raise Socket_Error with - "incorrect Process_Blocking_IO setting, expected " & Expected'Img; - end if; - - -- This is a dummy placeholder for an obsolete API - - -- Real initialization actions are in Initialize primitive operation - -- of Sockets_Library_Controller. - - null; - end Initialize; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize is - begin - -- This is a dummy placeholder for an obsolete API - - -- Real initialization actions are in Initialize primitive operation - -- of Sockets_Library_Controller. - - null; - end Initialize; - - -------------- - -- Is_Empty -- - -------------- - - function Is_Empty (Item : Socket_Set_Type) return Boolean is - begin - return Item.Last = No_Socket; - end Is_Empty; - - ------------------- - -- Is_IP_Address -- - ------------------- - - function Is_IP_Address (Name : String) return Boolean is - begin - for J in Name'Range loop - if Name (J) /= '.' - and then Name (J) not in '0' .. '9' - then - return False; - end if; - end loop; - - return True; - end Is_IP_Address; - - ------------- - -- Is_Open -- - ------------- - - function Is_Open (S : Selector_Type) return Boolean is - begin - if S.Is_Null then - return True; - - else - -- Either both controlling socket descriptors are valid (case of an - -- open selector) or neither (case of a closed selector). - - pragma Assert ((S.R_Sig_Socket /= No_Socket) - = - (S.W_Sig_Socket /= No_Socket)); - - return S.R_Sig_Socket /= No_Socket; - end if; - end Is_Open; - - ------------ - -- Is_Set -- - ------------ - - function Is_Set - (Item : Socket_Set_Type; - Socket : Socket_Type) return Boolean - is - begin - Check_For_Fd_Set (Socket); - - return Item.Last /= No_Socket - and then Socket <= Item.Last - and then Is_Socket_In_Set (Item.Set'Access, C.int (Socket)) /= 0; - end Is_Set; - - ------------------- - -- Listen_Socket -- - ------------------- - - procedure Listen_Socket - (Socket : Socket_Type; - Length : Natural := 15) - is - Res : constant C.int := C_Listen (C.int (Socket), C.int (Length)); - begin - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Listen_Socket; - - ------------ - -- Narrow -- - ------------ - - procedure Narrow (Item : in out Socket_Set_Type) is - Last : aliased C.int := C.int (Item.Last); - begin - if Item.Last /= No_Socket then - Last_Socket_In_Set (Item.Set'Access, Last'Unchecked_Access); - Item.Last := Socket_Type (Last); - end if; - end Narrow; - - ---------------- - -- Netdb_Lock -- - ---------------- - - procedure Netdb_Lock is - begin - if Need_Netdb_Lock then - System.Task_Lock.Lock; - end if; - end Netdb_Lock; - - ------------------ - -- Netdb_Unlock -- - ------------------ - - procedure Netdb_Unlock is - begin - if Need_Netdb_Lock then - System.Task_Lock.Unlock; - end if; - end Netdb_Unlock; - - -------------------------------- - -- Normalize_Empty_Socket_Set -- - -------------------------------- - - procedure Normalize_Empty_Socket_Set (S : in out Socket_Set_Type) is - begin - if S.Last = No_Socket then - Reset_Socket_Set (S.Set'Access); - end if; - end Normalize_Empty_Socket_Set; - - ------------------- - -- Official_Name -- - ------------------- - - function Official_Name (E : Host_Entry_Type) return String is - begin - return To_String (E.Official); - end Official_Name; - - ------------------- - -- Official_Name -- - ------------------- - - function Official_Name (S : Service_Entry_Type) return String is - begin - return To_String (S.Official); - end Official_Name; - - -------------------- - -- Wait_On_Socket -- - -------------------- - - procedure Wait_On_Socket - (Socket : Socket_Type; - For_Read : Boolean; - Timeout : Selector_Duration; - Selector : access Selector_Type := null; - Status : out Selector_Status) - is - type Local_Selector_Access is access Selector_Type; - for Local_Selector_Access'Storage_Size use Selector_Type'Size; - - S : Selector_Access; - -- Selector to use for waiting - - R_Fd_Set : Socket_Set_Type; - W_Fd_Set : Socket_Set_Type; - - begin - -- Create selector if not provided by the user - - if Selector = null then - declare - Local_S : constant Local_Selector_Access := new Selector_Type; - begin - S := Local_S.all'Unchecked_Access; - Create_Selector (S.all); - end; - - else - S := Selector.all'Access; - end if; - - if For_Read then - Set (R_Fd_Set, Socket); - else - Set (W_Fd_Set, Socket); - end if; - - Check_Selector (S.all, R_Fd_Set, W_Fd_Set, Status, Timeout); - - if Selector = null then - Close_Selector (S.all); - end if; - end Wait_On_Socket; - - ----------------- - -- Port_Number -- - ----------------- - - function Port_Number (S : Service_Entry_Type) return Port_Type is - begin - return S.Port; - end Port_Number; - - ------------------- - -- Protocol_Name -- - ------------------- - - function Protocol_Name (S : Service_Entry_Type) return String is - begin - return To_String (S.Protocol); - end Protocol_Name; - - ---------------------- - -- Raise_Host_Error -- - ---------------------- - - procedure Raise_Host_Error (H_Error : Integer) is - begin - raise Host_Error with - Err_Code_Image (H_Error) - & C.Strings.Value (Host_Error_Messages.Host_Error_Message (H_Error)); - end Raise_Host_Error; - - ------------------------ - -- Raise_Socket_Error -- - ------------------------ - - procedure Raise_Socket_Error (Error : Integer) is - use type C.Strings.chars_ptr; - begin - raise Socket_Error with - Err_Code_Image (Error) - & C.Strings.Value (Socket_Error_Message (Error)); - end Raise_Socket_Error; - - ---------- - -- Read -- - ---------- - - procedure Read - (Stream : in out Datagram_Socket_Stream_Type; - Item : out Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset) - is - First : Ada.Streams.Stream_Element_Offset := Item'First; - Index : Ada.Streams.Stream_Element_Offset := First - 1; - Max : constant Ada.Streams.Stream_Element_Offset := Item'Last; - - begin - loop - Receive_Socket - (Stream.Socket, - Item (First .. Max), - Index, - Stream.From); - - Last := Index; - - -- Exit when all or zero data received. Zero means that the socket - -- peer is closed. - - exit when Index < First or else Index = Max; - - First := Index + 1; - end loop; - end Read; - - ---------- - -- Read -- - ---------- - - procedure Read - (Stream : in out Stream_Socket_Stream_Type; - Item : out Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset) - is - pragma Warnings (Off, Stream); - - First : Ada.Streams.Stream_Element_Offset := Item'First; - Index : Ada.Streams.Stream_Element_Offset := First - 1; - Max : constant Ada.Streams.Stream_Element_Offset := Item'Last; - - begin - loop - Receive_Socket (Stream.Socket, Item (First .. Max), Index); - Last := Index; - - -- Exit when all or zero data received. Zero means that the socket - -- peer is closed. - - exit when Index < First or else Index = Max; - - First := Index + 1; - end loop; - end Read; - - -------------------- - -- Receive_Socket -- - -------------------- - - procedure Receive_Socket - (Socket : Socket_Type; - Item : out Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset; - Flags : Request_Flag_Type := No_Request_Flag) - is - Res : C.int; - - begin - Res := - C_Recv (C.int (Socket), Item'Address, Item'Length, To_Int (Flags)); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Last := Last_Index (First => Item'First, Count => size_t (Res)); - end Receive_Socket; - - -------------------- - -- Receive_Socket -- - -------------------- - - procedure Receive_Socket - (Socket : Socket_Type; - Item : out Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset; - From : out Sock_Addr_Type; - Flags : Request_Flag_Type := No_Request_Flag) - is - Res : C.int; - Sin : aliased Sockaddr_In; - Len : aliased C.int := Sin'Size / 8; - - begin - Res := - C_Recvfrom - (C.int (Socket), - Item'Address, - Item'Length, - To_Int (Flags), - Sin'Address, - Len'Access); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Last := Last_Index (First => Item'First, Count => size_t (Res)); - - To_Inet_Addr (Sin.Sin_Addr, From.Addr); - From.Port := Port_Type (Network_To_Short (Sin.Sin_Port)); - end Receive_Socket; - - -------------------- - -- Receive_Vector -- - -------------------- - - procedure Receive_Vector - (Socket : Socket_Type; - Vector : Vector_Type; - Count : out Ada.Streams.Stream_Element_Count; - Flags : Request_Flag_Type := No_Request_Flag) - is - Res : ssize_t; - - Msg : Msghdr := - (Msg_Name => System.Null_Address, - Msg_Namelen => 0, - Msg_Iov => Vector'Address, - - -- recvmsg(2) returns EMSGSIZE on Linux (and probably on other - -- platforms) when the supplied vector is longer than IOV_MAX, - -- so use minimum of the two lengths. - - Msg_Iovlen => SOSC.Msg_Iovlen_T'Min - (Vector'Length, SOSC.IOV_MAX), - - Msg_Control => System.Null_Address, - Msg_Controllen => 0, - Msg_Flags => 0); - - begin - Res := - C_Recvmsg - (C.int (Socket), - Msg'Address, - To_Int (Flags)); - - if Res = ssize_t (Failure) then - Raise_Socket_Error (Socket_Errno); - end if; - - Count := Ada.Streams.Stream_Element_Count (Res); - end Receive_Vector; - - ------------------- - -- Resolve_Error -- - ------------------- - - function Resolve_Error - (Error_Value : Integer; - From_Errno : Boolean := True) return Error_Type - is - use GNAT.Sockets.SOSC; - - begin - if not From_Errno then - case Error_Value is - when SOSC.HOST_NOT_FOUND => return Unknown_Host; - when SOSC.TRY_AGAIN => return Host_Name_Lookup_Failure; - when SOSC.NO_RECOVERY => return Non_Recoverable_Error; - when SOSC.NO_DATA => return Unknown_Server_Error; - when others => return Cannot_Resolve_Error; - end case; - end if; - - -- Special case: EAGAIN may be the same value as EWOULDBLOCK, so we - -- can't include it in the case statement below. - - pragma Warnings (Off); - -- Condition "EAGAIN /= EWOULDBLOCK" is known at compile time - - if EAGAIN /= EWOULDBLOCK and then Error_Value = EAGAIN then - return Resource_Temporarily_Unavailable; - end if; - - -- This is not a case statement because if a particular error - -- number constant is not defined, s-oscons-tmplt.c defines - -- it to -1. If multiple constants are not defined, they - -- would each be -1 and result in a "duplicate value in case" error. - -- - -- But we have to leave warnings off because the compiler is also - -- smart enough to note that when two errnos have the same value, - -- the second if condition is useless. - if Error_Value = ENOERROR then - return Success; - elsif Error_Value = EACCES then - return Permission_Denied; - elsif Error_Value = EADDRINUSE then - return Address_Already_In_Use; - elsif Error_Value = EADDRNOTAVAIL then - return Cannot_Assign_Requested_Address; - elsif Error_Value = EAFNOSUPPORT then - return Address_Family_Not_Supported_By_Protocol; - elsif Error_Value = EALREADY then - return Operation_Already_In_Progress; - elsif Error_Value = EBADF then - return Bad_File_Descriptor; - elsif Error_Value = ECONNABORTED then - return Software_Caused_Connection_Abort; - elsif Error_Value = ECONNREFUSED then - return Connection_Refused; - elsif Error_Value = ECONNRESET then - return Connection_Reset_By_Peer; - elsif Error_Value = EDESTADDRREQ then - return Destination_Address_Required; - elsif Error_Value = EFAULT then - return Bad_Address; - elsif Error_Value = EHOSTDOWN then - return Host_Is_Down; - elsif Error_Value = EHOSTUNREACH then - return No_Route_To_Host; - elsif Error_Value = EINPROGRESS then - return Operation_Now_In_Progress; - elsif Error_Value = EINTR then - return Interrupted_System_Call; - elsif Error_Value = EINVAL then - return Invalid_Argument; - elsif Error_Value = EIO then - return Input_Output_Error; - elsif Error_Value = EISCONN then - return Transport_Endpoint_Already_Connected; - elsif Error_Value = ELOOP then - return Too_Many_Symbolic_Links; - elsif Error_Value = EMFILE then - return Too_Many_Open_Files; - elsif Error_Value = EMSGSIZE then - return Message_Too_Long; - elsif Error_Value = ENAMETOOLONG then - return File_Name_Too_Long; - elsif Error_Value = ENETDOWN then - return Network_Is_Down; - elsif Error_Value = ENETRESET then - return Network_Dropped_Connection_Because_Of_Reset; - elsif Error_Value = ENETUNREACH then - return Network_Is_Unreachable; - elsif Error_Value = ENOBUFS then - return No_Buffer_Space_Available; - elsif Error_Value = ENOPROTOOPT then - return Protocol_Not_Available; - elsif Error_Value = ENOTCONN then - return Transport_Endpoint_Not_Connected; - elsif Error_Value = ENOTSOCK then - return Socket_Operation_On_Non_Socket; - elsif Error_Value = EOPNOTSUPP then - return Operation_Not_Supported; - elsif Error_Value = EPFNOSUPPORT then - return Protocol_Family_Not_Supported; - elsif Error_Value = EPIPE then - return Broken_Pipe; - elsif Error_Value = EPROTONOSUPPORT then - return Protocol_Not_Supported; - elsif Error_Value = EPROTOTYPE then - return Protocol_Wrong_Type_For_Socket; - elsif Error_Value = ESHUTDOWN then - return Cannot_Send_After_Transport_Endpoint_Shutdown; - elsif Error_Value = ESOCKTNOSUPPORT then - return Socket_Type_Not_Supported; - elsif Error_Value = ETIMEDOUT then - return Connection_Timed_Out; - elsif Error_Value = ETOOMANYREFS then - return Too_Many_References; - elsif Error_Value = EWOULDBLOCK then - return Resource_Temporarily_Unavailable; - else - return Cannot_Resolve_Error; - end if; - pragma Warnings (On); - - end Resolve_Error; - - ----------------------- - -- Resolve_Exception -- - ----------------------- - - function Resolve_Exception - (Occurrence : Exception_Occurrence) return Error_Type - is - Id : constant Exception_Id := Exception_Identity (Occurrence); - Msg : constant String := Exception_Message (Occurrence); - First : Natural; - Last : Natural; - Val : Integer; - - begin - First := Msg'First; - while First <= Msg'Last - and then Msg (First) not in '0' .. '9' - loop - First := First + 1; - end loop; - - if First > Msg'Last then - return Cannot_Resolve_Error; - end if; - - Last := First; - while Last < Msg'Last - and then Msg (Last + 1) in '0' .. '9' - loop - Last := Last + 1; - end loop; - - Val := Integer'Value (Msg (First .. Last)); - - if Id = Socket_Error_Id then - return Resolve_Error (Val); - - elsif Id = Host_Error_Id then - return Resolve_Error (Val, False); - - else - return Cannot_Resolve_Error; - end if; - end Resolve_Exception; - - ----------------- - -- Send_Socket -- - ----------------- - - procedure Send_Socket - (Socket : Socket_Type; - Item : Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset; - Flags : Request_Flag_Type := No_Request_Flag) - is - begin - Send_Socket (Socket, Item, Last, To => null, Flags => Flags); - end Send_Socket; - - ----------------- - -- Send_Socket -- - ----------------- - - procedure Send_Socket - (Socket : Socket_Type; - Item : Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset; - To : Sock_Addr_Type; - Flags : Request_Flag_Type := No_Request_Flag) - is - begin - Send_Socket - (Socket, Item, Last, To => To'Unrestricted_Access, Flags => Flags); - end Send_Socket; - - ----------------- - -- Send_Socket -- - ----------------- - - procedure Send_Socket - (Socket : Socket_Type; - Item : Ada.Streams.Stream_Element_Array; - Last : out Ada.Streams.Stream_Element_Offset; - To : access Sock_Addr_Type; - Flags : Request_Flag_Type := No_Request_Flag) - is - Res : C.int; - - Sin : aliased Sockaddr_In; - C_To : System.Address; - Len : C.int; - - begin - if To /= null then - Set_Family (Sin.Sin_Family, To.Family); - Set_Address (Sin'Unchecked_Access, To_In_Addr (To.Addr)); - Set_Port - (Sin'Unchecked_Access, - Short_To_Network (C.unsigned_short (To.Port))); - C_To := Sin'Address; - Len := Sin'Size / 8; - - else - C_To := System.Null_Address; - Len := 0; - end if; - - Res := C_Sendto - (C.int (Socket), - Item'Address, - Item'Length, - Set_Forced_Flags (To_Int (Flags)), - C_To, - Len); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - - Last := Last_Index (First => Item'First, Count => size_t (Res)); - end Send_Socket; - - ----------------- - -- Send_Vector -- - ----------------- - - procedure Send_Vector - (Socket : Socket_Type; - Vector : Vector_Type; - Count : out Ada.Streams.Stream_Element_Count; - Flags : Request_Flag_Type := No_Request_Flag) - is - use SOSC; - use Interfaces.C; - - Res : ssize_t; - Iov_Count : SOSC.Msg_Iovlen_T; - This_Iov_Count : SOSC.Msg_Iovlen_T; - Msg : Msghdr; - - begin - Count := 0; - Iov_Count := 0; - while Iov_Count < Vector'Length loop - - pragma Warnings (Off); - -- Following test may be compile time known on some targets - - This_Iov_Count := - (if Vector'Length - Iov_Count > SOSC.IOV_MAX - then SOSC.IOV_MAX - else Vector'Length - Iov_Count); - - pragma Warnings (On); - - Msg := - (Msg_Name => System.Null_Address, - Msg_Namelen => 0, - Msg_Iov => Vector - (Vector'First + Integer (Iov_Count))'Address, - Msg_Iovlen => This_Iov_Count, - Msg_Control => System.Null_Address, - Msg_Controllen => 0, - Msg_Flags => 0); - - Res := - C_Sendmsg - (C.int (Socket), - Msg'Address, - Set_Forced_Flags (To_Int (Flags))); - - if Res = ssize_t (Failure) then - Raise_Socket_Error (Socket_Errno); - end if; - - Count := Count + Ada.Streams.Stream_Element_Count (Res); - Iov_Count := Iov_Count + This_Iov_Count; - end loop; - end Send_Vector; - - --------- - -- Set -- - --------- - - procedure Set (Item : in out Socket_Set_Type; Socket : Socket_Type) is - begin - Check_For_Fd_Set (Socket); - - if Item.Last = No_Socket then - - -- Uninitialized socket set, make sure it is properly zeroed out - - Reset_Socket_Set (Item.Set'Access); - Item.Last := Socket; - - elsif Item.Last < Socket then - Item.Last := Socket; - end if; - - Insert_Socket_In_Set (Item.Set'Access, C.int (Socket)); - end Set; - - ---------------------- - -- Set_Forced_Flags -- - ---------------------- - - function Set_Forced_Flags (F : C.int) return C.int is - use type C.unsigned; - function To_unsigned is - new Ada.Unchecked_Conversion (C.int, C.unsigned); - function To_int is - new Ada.Unchecked_Conversion (C.unsigned, C.int); - begin - return To_int (To_unsigned (F) or SOSC.MSG_Forced_Flags); - end Set_Forced_Flags; - - ----------------------- - -- Set_Socket_Option -- - ----------------------- - - procedure Set_Socket_Option - (Socket : Socket_Type; - Level : Level_Type := Socket_Level; - Option : Option_Type) - is - V8 : aliased Two_Ints; - V4 : aliased C.int; - V1 : aliased C.unsigned_char; - VT : aliased Timeval; - Len : C.int; - Add : System.Address := Null_Address; - Res : C.int; - - begin - case Option.Name is - when Keep_Alive | - Reuse_Address | - Broadcast | - No_Delay => - V4 := C.int (Boolean'Pos (Option.Enabled)); - Len := V4'Size / 8; - Add := V4'Address; - - when Linger => - V8 (V8'First) := C.int (Boolean'Pos (Option.Enabled)); - V8 (V8'Last) := C.int (Option.Seconds); - Len := V8'Size / 8; - Add := V8'Address; - - when Send_Buffer | - Receive_Buffer => - V4 := C.int (Option.Size); - Len := V4'Size / 8; - Add := V4'Address; - - when Error => - V4 := C.int (Boolean'Pos (True)); - Len := V4'Size / 8; - Add := V4'Address; - - when Add_Membership | - Drop_Membership => - V8 (V8'First) := To_Int (To_In_Addr (Option.Multicast_Address)); - V8 (V8'Last) := To_Int (To_In_Addr (Option.Local_Interface)); - Len := V8'Size / 8; - Add := V8'Address; - - when Multicast_If => - V4 := To_Int (To_In_Addr (Option.Outgoing_If)); - Len := V4'Size / 8; - Add := V4'Address; - - when Multicast_TTL => - V1 := C.unsigned_char (Option.Time_To_Live); - Len := V1'Size / 8; - Add := V1'Address; - - when Multicast_Loop | - Receive_Packet_Info => - V1 := C.unsigned_char (Boolean'Pos (Option.Enabled)); - Len := V1'Size / 8; - Add := V1'Address; - - when Send_Timeout | - Receive_Timeout => - VT := To_Timeval (Option.Timeout); - Len := VT'Size / 8; - Add := VT'Address; - - end case; - - Res := C_Setsockopt - (C.int (Socket), - Levels (Level), - Options (Option.Name), - Add, Len); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Set_Socket_Option; - - ---------------------- - -- Short_To_Network -- - ---------------------- - - function Short_To_Network (S : C.unsigned_short) return C.unsigned_short is - use type C.unsigned_short; - - begin - -- Big-endian case. No conversion needed. On these platforms, - -- htons() defaults to a null procedure. - - pragma Warnings (Off); - -- Since the test can generate "always True/False" warning - - if Default_Bit_Order = High_Order_First then - return S; - - pragma Warnings (On); - - -- Little-endian case. We must swap the high and low bytes of this - -- short to make the port number network compliant. - - else - return (S / 256) + (S mod 256) * 256; - end if; - end Short_To_Network; - - --------------------- - -- Shutdown_Socket -- - --------------------- - - procedure Shutdown_Socket - (Socket : Socket_Type; - How : Shutmode_Type := Shut_Read_Write) - is - Res : C.int; - - begin - Res := C_Shutdown (C.int (Socket), Shutmodes (How)); - - if Res = Failure then - Raise_Socket_Error (Socket_Errno); - end if; - end Shutdown_Socket; - - ------------ - -- Stream -- - ------------ - - function Stream - (Socket : Socket_Type; - Send_To : Sock_Addr_Type) return Stream_Access - is - S : Datagram_Socket_Stream_Access; - - begin - S := new Datagram_Socket_Stream_Type; - S.Socket := Socket; - S.To := Send_To; - S.From := Get_Socket_Name (Socket); - return Stream_Access (S); - end Stream; - - ------------ - -- Stream -- - ------------ - - function Stream (Socket : Socket_Type) return Stream_Access is - S : Stream_Socket_Stream_Access; - begin - S := new Stream_Socket_Stream_Type; - S.Socket := Socket; - return Stream_Access (S); - end Stream; - - ------------------ - -- Stream_Write -- - ------------------ - - procedure Stream_Write - (Socket : Socket_Type; - Item : Ada.Streams.Stream_Element_Array; - To : access Sock_Addr_Type) - is - First : Ada.Streams.Stream_Element_Offset; - Index : Ada.Streams.Stream_Element_Offset; - Max : constant Ada.Streams.Stream_Element_Offset := Item'Last; - - begin - First := Item'First; - Index := First - 1; - while First <= Max loop - Send_Socket (Socket, Item (First .. Max), Index, To); - - -- Exit when all or zero data sent. Zero means that the socket has - -- been closed by peer. - - exit when Index < First or else Index = Max; - - First := Index + 1; - end loop; - - -- For an empty array, we have First > Max, and hence Index >= Max (no - -- error, the loop above is never executed). After a successful send, - -- Index = Max. The only remaining case, Index < Max, is therefore - -- always an actual send failure. - - if Index < Max then - Raise_Socket_Error (Socket_Errno); - end if; - end Stream_Write; - - ---------- - -- To_C -- - ---------- - - function To_C (Socket : Socket_Type) return Integer is - begin - return Integer (Socket); - end To_C; - - ----------------- - -- To_Duration -- - ----------------- - - function To_Duration (Val : Timeval) return Timeval_Duration is - begin - return Natural (Val.Tv_Sec) * 1.0 + Natural (Val.Tv_Usec) * 1.0E-6; - end To_Duration; - - ------------------- - -- To_Host_Entry -- - ------------------- - - function To_Host_Entry (E : Hostent_Access) return Host_Entry_Type is - use type C.size_t; - use C.Strings; - - Aliases_Count, Addresses_Count : Natural; - - -- H_Length is not used because it is currently only set to 4 - -- H_Addrtype is always AF_INET - - begin - Aliases_Count := 0; - while Hostent_H_Alias (E, C.int (Aliases_Count)) /= Null_Address loop - Aliases_Count := Aliases_Count + 1; - end loop; - - Addresses_Count := 0; - while Hostent_H_Addr (E, C.int (Addresses_Count)) /= Null_Address loop - Addresses_Count := Addresses_Count + 1; - end loop; - - return Result : Host_Entry_Type - (Aliases_Length => Aliases_Count, - Addresses_Length => Addresses_Count) - do - Result.Official := To_Name (Value (Hostent_H_Name (E))); - - for J in Result.Aliases'Range loop - Result.Aliases (J) := - To_Name (Value (Hostent_H_Alias - (E, C.int (J - Result.Aliases'First)))); - end loop; - - for J in Result.Addresses'Range loop - declare - Addr : In_Addr; - for Addr'Address use - Hostent_H_Addr (E, C.int (J - Result.Addresses'First)); - pragma Import (Ada, Addr); - begin - To_Inet_Addr (Addr, Result.Addresses (J)); - end; - end loop; - end return; - end To_Host_Entry; - - ---------------- - -- To_In_Addr -- - ---------------- - - function To_In_Addr (Addr : Inet_Addr_Type) return In_Addr is - begin - if Addr.Family = Family_Inet then - return (S_B1 => C.unsigned_char (Addr.Sin_V4 (1)), - S_B2 => C.unsigned_char (Addr.Sin_V4 (2)), - S_B3 => C.unsigned_char (Addr.Sin_V4 (3)), - S_B4 => C.unsigned_char (Addr.Sin_V4 (4))); - end if; - - raise Socket_Error with "IPv6 not supported"; - end To_In_Addr; - - ------------------ - -- To_Inet_Addr -- - ------------------ - - procedure To_Inet_Addr - (Addr : In_Addr; - Result : out Inet_Addr_Type) is - begin - Result.Sin_V4 (1) := Inet_Addr_Comp_Type (Addr.S_B1); - Result.Sin_V4 (2) := Inet_Addr_Comp_Type (Addr.S_B2); - Result.Sin_V4 (3) := Inet_Addr_Comp_Type (Addr.S_B3); - Result.Sin_V4 (4) := Inet_Addr_Comp_Type (Addr.S_B4); - end To_Inet_Addr; - - ------------ - -- To_Int -- - ------------ - - function To_Int (F : Request_Flag_Type) return C.int - is - Current : Request_Flag_Type := F; - Result : C.int := 0; - - begin - for J in Flags'Range loop - exit when Current = 0; - - if Current mod 2 /= 0 then - if Flags (J) = -1 then - Raise_Socket_Error (SOSC.EOPNOTSUPP); - end if; - - Result := Result + Flags (J); - end if; - - Current := Current / 2; - end loop; - - return Result; - end To_Int; - - ------------- - -- To_Name -- - ------------- - - function To_Name (N : String) return Name_Type is - begin - return Name_Type'(N'Length, N); - end To_Name; - - ---------------------- - -- To_Service_Entry -- - ---------------------- - - function To_Service_Entry (E : Servent_Access) return Service_Entry_Type is - use C.Strings; - use type C.size_t; - - Aliases_Count : Natural; - - begin - Aliases_Count := 0; - while Servent_S_Alias (E, C.int (Aliases_Count)) /= Null_Address loop - Aliases_Count := Aliases_Count + 1; - end loop; - - return Result : Service_Entry_Type (Aliases_Length => Aliases_Count) do - Result.Official := To_Name (Value (Servent_S_Name (E))); - - for J in Result.Aliases'Range loop - Result.Aliases (J) := - To_Name (Value (Servent_S_Alias - (E, C.int (J - Result.Aliases'First)))); - end loop; - - Result.Protocol := To_Name (Value (Servent_S_Proto (E))); - Result.Port := - Port_Type (Network_To_Short (Servent_S_Port (E))); - end return; - end To_Service_Entry; - - --------------- - -- To_String -- - --------------- - - function To_String (HN : Name_Type) return String is - begin - return HN.Name (1 .. HN.Length); - end To_String; - - ---------------- - -- To_Timeval -- - ---------------- - - function To_Timeval (Val : Timeval_Duration) return Timeval is - S : time_t; - uS : suseconds_t; - - begin - -- If zero, set result as zero (otherwise it gets rounded down to -1) - - if Val = 0.0 then - S := 0; - uS := 0; - - -- Normal case where we do round down - - else - S := time_t (Val - 0.5); - uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S))); - end if; - - return (S, uS); - end To_Timeval; - - ----------- - -- Value -- - ----------- - - function Value (S : System.Address) return String is - Str : String (1 .. Positive'Last); - for Str'Address use S; - pragma Import (Ada, Str); - - Terminator : Positive := Str'First; - - begin - while Str (Terminator) /= ASCII.NUL loop - Terminator := Terminator + 1; - end loop; - - return Str (1 .. Terminator - 1); - end Value; - - ----------- - -- Write -- - ----------- - - procedure Write - (Stream : in out Datagram_Socket_Stream_Type; - Item : Ada.Streams.Stream_Element_Array) - is - begin - Stream_Write (Stream.Socket, Item, To => Stream.To'Unrestricted_Access); - end Write; - - ----------- - -- Write -- - ----------- - - procedure Write - (Stream : in out Stream_Socket_Stream_Type; - Item : Ada.Streams.Stream_Element_Array) - is - begin - Stream_Write (Stream.Socket, Item, To => null); - end Write; - - Sockets_Library_Controller_Object : Sockets_Library_Controller; - pragma Unreferenced (Sockets_Library_Controller_Object); - -- The elaboration and finalization of this object perform the required - -- initialization and cleanup actions for the sockets library. - -end GNAT.Sockets; |