summaryrefslogtreecommitdiff
path: root/gcc/ada/g-socket.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/g-socket.adb')
-rw-r--r--gcc/ada/g-socket.adb289
1 files changed, 176 insertions, 113 deletions
diff --git a/gcc/ada/g-socket.adb b/gcc/ada/g-socket.adb
index a7af20b87d2..163dd2d0710 100644
--- a/gcc/ada/g-socket.adb
+++ b/gcc/ada/g-socket.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2001-2005 Ada Core Technologies, Inc. --
+-- Copyright (C) 2001-2005, 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- --
@@ -92,8 +92,11 @@ package body GNAT.Sockets is
No_Delay => Constants.TCP_NODELAY,
Add_Membership => Constants.IP_ADD_MEMBERSHIP,
Drop_Membership => Constants.IP_DROP_MEMBERSHIP,
+ Multicast_If => Constants.IP_MULTICAST_IF,
Multicast_TTL => Constants.IP_MULTICAST_TTL,
- Multicast_Loop => Constants.IP_MULTICAST_LOOP);
+ Multicast_Loop => Constants.IP_MULTICAST_LOOP,
+ Send_Timeout => Constants.SO_SNDTIMEO,
+ Receive_Timeout => Constants.SO_RCVTIMEO);
Flags : constant array (0 .. 3) of C.int :=
(0 => Constants.MSG_OOB, -- Process_Out_Of_Band_Data
@@ -110,6 +113,9 @@ package body GNAT.Sockets is
function To_In_Addr is new Ada.Unchecked_Conversion (C.int, In_Addr);
function To_Int is new Ada.Unchecked_Conversion (In_Addr, C.int);
+ function Err_Code_Image (E : Integer) return String;
+ -- Return the value of E surrounded with brackets
+
-----------------------
-- Local subprograms --
-----------------------
@@ -160,15 +166,20 @@ package body GNAT.Sockets is
function To_Service_Entry (E : Servent) return Service_Entry_Type;
-- Conversion function
- function To_Timeval (Val : Selector_Duration) return Timeval;
+ 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 (Error : Integer);
+ procedure Raise_Host_Error (H_Error : Integer);
-- Raise Host_Error exception with message describing error code (note
- -- hstrerror seems to be obsolete).
+ -- 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
@@ -384,6 +395,7 @@ package body GNAT.Sockets is
is
Res : C.int;
Last : C.int;
+ RSig : Socket_Type renames Selector.R_Sig_Socket;
RSet : Socket_Set_Type;
WSet : Socket_Set_Type;
ESet : Socket_Set_Type;
@@ -391,102 +403,116 @@ package body GNAT.Sockets is
TPtr : Timeval_Access;
begin
- Status := Completed;
+ begin
+ Status := Completed;
- -- No timeout or Forever is indicated by a null timeval pointer
+ -- 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;
+ if Timeout = Forever then
+ TPtr := null;
+ else
+ TVal := To_Timeval (Timeout);
+ TPtr := TVal'Unchecked_Access;
+ end if;
- -- Copy R_Socket_Set in RSet and add read signalling socket
+ -- Copy R_Socket_Set in RSet and add read signalling socket
- RSet := (Set => New_Socket_Set (R_Socket_Set.Set),
- Last => R_Socket_Set.Last);
- Set (RSet, Selector.R_Sig_Socket);
+ RSet := (Set => New_Socket_Set (R_Socket_Set.Set),
+ Last => R_Socket_Set.Last);
+ Set (RSet, RSig);
- -- Copy W_Socket_Set in WSet
+ -- Copy W_Socket_Set in WSet
- WSet := (Set => New_Socket_Set (W_Socket_Set.Set),
- Last => W_Socket_Set.Last);
+ WSet := (Set => New_Socket_Set (W_Socket_Set.Set),
+ Last => W_Socket_Set.Last);
- -- Copy E_Socket_Set in ESet
+ -- Copy E_Socket_Set in ESet
- ESet := (Set => New_Socket_Set (E_Socket_Set.Set),
- Last => E_Socket_Set.Last);
+ ESet := (Set => New_Socket_Set (E_Socket_Set.Set),
+ Last => E_Socket_Set.Last);
- Last := C.int'Max (C.int'Max (C.int (RSet.Last),
- C.int (WSet.Last)),
- C.int (ESet.Last));
+ Last := C.int'Max (C.int'Max (C.int (RSet.Last),
+ C.int (WSet.Last)),
+ C.int (ESet.Last));
- Res :=
- C_Select
- (Last + 1,
- RSet.Set,
- WSet.Set,
- ESet.Set,
- TPtr);
+ Res :=
+ C_Select
+ (Last + 1,
+ RSet.Set,
+ WSet.Set,
+ ESet.Set,
+ TPtr);
- if Res = Failure then
- Raise_Socket_Error (Socket_Errno);
- end if;
+ 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 Select was resumed because of read signalling socket, read this
+ -- data and remove socket from set.
- if Is_Set (RSet, Selector.R_Sig_Socket) then
- Clear (RSet, Selector.R_Sig_Socket);
+ if Is_Set (RSet, RSig) then
+ Clear (RSet, RSig);
- declare
- Buf : Character;
+ declare
+ Buf : Character;
- begin
- Res := C_Recv (C.int (Selector.R_Sig_Socket), Buf'Address, 1, 0);
+ begin
+ Res := C_Recv (C.int (RSig), Buf'Address, 1, 0);
- if Res = Failure then
- Raise_Socket_Error (Socket_Errno);
- end if;
- end;
+ if Res = Failure then
+ Raise_Socket_Error (Socket_Errno);
+ end if;
+ end;
- Status := Aborted;
+ Status := Aborted;
- elsif Res = 0 then
- Status := Expired;
- end if;
+ elsif Res = 0 then
+ Status := Expired;
+ end if;
- -- Update RSet, WSet and ESet in regard to their new socket sets
+ -- Update RSet, WSet and ESet in regard to their new socket sets
- Narrow (RSet);
- Narrow (WSet);
- Narrow (ESet);
+ Narrow (RSet);
+ Narrow (WSet);
+ Narrow (ESet);
- -- Reset RSet as it should be if R_Sig_Socket was not added
+ -- Reset RSet as it should be if R_Sig_Socket was not added
- if Is_Empty (RSet) then
- Empty (RSet);
- end if;
+ if Is_Empty (RSet) then
+ Empty (RSet);
+ end if;
- if Is_Empty (WSet) then
- Empty (WSet);
- end if;
+ if Is_Empty (WSet) then
+ Empty (WSet);
+ end if;
- if Is_Empty (ESet) then
- Empty (ESet);
- end if;
+ if Is_Empty (ESet) then
+ Empty (ESet);
+ end if;
- -- Deliver RSet, WSet and ESet
+ -- Deliver RSet, WSet and ESet
- Empty (R_Socket_Set);
- R_Socket_Set := RSet;
+ Empty (R_Socket_Set);
+ R_Socket_Set := RSet;
- Empty (W_Socket_Set);
- W_Socket_Set := WSet;
+ Empty (W_Socket_Set);
+ W_Socket_Set := WSet;
- Empty (E_Socket_Set);
- E_Socket_Set := ESet;
+ Empty (E_Socket_Set);
+ E_Socket_Set := ESet;
+
+ exception
+
+ when Socket_Error =>
+
+ -- The local socket sets must be emptied before propagating
+ -- Socket_Error so the associated storage is freed.
+
+ Empty (RSet);
+ Empty (WSet);
+ Empty (ESet);
+ raise;
+ end;
end Check_Selector;
-----------
@@ -510,11 +536,16 @@ package body GNAT.Sockets is
-- Close_Selector --
--------------------
- -- Comments needed below ???
- -- Why are exceptions ignored ???
-
procedure Close_Selector (Selector : in out Selector_Type) is
begin
+
+ -- Close the signalling sockets used internally for the implementation
+ -- of Abort_Selector. Exceptions are ignored because these sockets
+ -- are implementation artefacts of no interest to the user, and
+ -- there is little that can be done if either Close_Socket call fails
+ -- (which theoretically should not happen anyway). We also want to try
+ -- to perform the second Close_Socket even if the first one failed.
+
begin
Close_Socket (Selector.R_Sig_Socket);
exception
@@ -772,6 +803,17 @@ package body GNAT.Sockets is
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 --
--------------
@@ -845,7 +887,7 @@ package body GNAT.Sockets is
Res := C_Gethostbyaddr (HA'Address, HA'Size / 8, Constants.AF_INET);
if Res = null then
- Err := Socket_Errno;
+ Err := Host_Errno;
Task_Lock.Unlock;
Raise_Host_Error (Err);
end if;
@@ -884,7 +926,7 @@ package body GNAT.Sockets is
Res := C_Gethostbyname (HN);
if Res = null then
- Err := Socket_Errno;
+ Err := Host_Errno;
Task_Lock.Unlock;
Raise_Host_Error (Err);
end if;
@@ -1027,6 +1069,7 @@ package body GNAT.Sockets is
V8 : aliased Two_Int;
V4 : aliased C.int;
V1 : aliased C.unsigned_char;
+ VT : aliased Timeval;
Len : aliased C.int;
Add : System.Address;
Res : C.int;
@@ -1045,10 +1088,16 @@ package body GNAT.Sockets is
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 =>
@@ -1091,12 +1140,19 @@ package body GNAT.Sockets is
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 =>
Opt.Enabled := (V1 /= 0);
+ when Send_Timeout |
+ Receive_Timeout =>
+ Opt.Timeout := To_Duration (VT);
+
end case;
return Opt;
@@ -1379,12 +1435,11 @@ package body GNAT.Sockets is
-- Raise_Host_Error --
----------------------
- procedure Raise_Host_Error (Error : Integer) is
+ procedure Raise_Host_Error (H_Error : Integer) is
function Host_Error_Message return String;
- -- We do not use a C function like strerror because hstrerror
- -- that would correspond seems to be obsolete. Return
- -- appropriate string for error value.
+ -- We do not use a C function like strerror because hstrerror that would
+ -- correspond is obsolete. Return appropriate string for error value.
------------------------
-- Host_Error_Message --
@@ -1392,7 +1447,7 @@ package body GNAT.Sockets is
function Host_Error_Message return String is
begin
- case Error is
+ case H_Error is
when Constants.HOST_NOT_FOUND => return "Host not found";
when Constants.TRY_AGAIN => return "Try again";
when Constants.NO_RECOVERY => return "No recovery";
@@ -1404,7 +1459,9 @@ package body GNAT.Sockets is
-- Start of processing for Raise_Host_Error
begin
- Ada.Exceptions.Raise_Exception (Host_Error'Identity, Host_Error_Message);
+ Ada.Exceptions.Raise_Exception (Host_Error'Identity,
+ Err_Code_Image (H_Error)
+ & Host_Error_Message);
end Raise_Host_Error;
------------------------
@@ -1413,26 +1470,10 @@ package body GNAT.Sockets is
procedure Raise_Socket_Error (Error : Integer) is
use type C.Strings.chars_ptr;
-
- function Image (E : Integer) return String;
-
- -----------
- -- Image --
- -----------
-
- function Image (E : Integer) return String is
- Msg : String := E'Img & "] ";
- begin
- Msg (Msg'First) := '[';
- return Msg;
- end Image;
-
- -- Start of processing for Raise_Socket_Error
-
begin
- Ada.Exceptions.Raise_Exception
- (Socket_Error'Identity,
- Image (Error) & C.Strings.Value (Socket_Error_Message (Error)));
+ Ada.Exceptions.Raise_Exception (Socket_Error'Identity,
+ Err_Code_Image (Error)
+ & C.Strings.Value (Socket_Error_Message (Error)));
end Raise_Socket_Error;
----------
@@ -1639,11 +1680,12 @@ package body GNAT.Sockets is
is
Id : constant Exception_Id := Exception_Identity (Occurrence);
Msg : constant String := Exception_Message (Occurrence);
- First : Natural := Msg'First;
+ First : Natural;
Last : Natural;
Val : Integer;
begin
+ First := Msg'First;
while First <= Msg'Last
and then Msg (First) not in '0' .. '9'
loop
@@ -1655,7 +1697,6 @@ package body GNAT.Sockets is
end if;
Last := First;
-
while Last < Msg'Last
and then Msg (Last + 1) in '0' .. '9'
loop
@@ -1854,7 +1895,8 @@ package body GNAT.Sockets is
V8 : aliased Two_Int;
V4 : aliased C.int;
V1 : aliased C.unsigned_char;
- Len : aliased C.int;
+ VT : aliased Timeval;
+ Len : C.int;
Add : System.Address := Null_Address;
Res : C.int;
@@ -1892,6 +1934,11 @@ package body GNAT.Sockets is
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;
@@ -1902,6 +1949,12 @@ package body GNAT.Sockets is
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
@@ -1999,6 +2052,15 @@ package body GNAT.Sockets is
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 --
-------------------
@@ -2100,6 +2162,7 @@ package body GNAT.Sockets is
if Flags (J) = -1 then
Raise_Socket_Error (Constants.EOPNOTSUPP);
end if;
+
Result := Result + Flags (J);
end if;
@@ -2176,25 +2239,25 @@ package body GNAT.Sockets is
-- To_Timeval --
----------------
- function To_Timeval (Val : Selector_Duration) return Timeval is
- S : Timeval_Unit;
- MS : Timeval_Unit;
+ 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;
- MS := 0;
+ uS := 0;
-- Normal case where we do round down
else
- S := Timeval_Unit (Val - 0.5);
- MS := Timeval_Unit (1_000_000 * (Val - Selector_Duration (S)));
+ S := time_t (Val - 0.5);
+ uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)));
end if;
- return (S, MS);
+ return (S, uS);
end To_Timeval;
-----------