Commit aed6fda8 by Thomas Quinot Committed by Arnaud Charlet

re PR ada/35953 (Socket stream subprograms incorrectly handling null arrays)

2009-04-17  Thomas Quinot  <quinot@adacore.com>

	PR ada/35953

	* g-socthi-vms.adb, g-socthi-vms.ads, g-socthi-vxworks.adb,
	g-socthi-vxworks.ads, g-socthi-mingw.adb, g-socthi-mingw.ads,
	g-socthi.adb, g-stsifd-sockets.adb, g-socthi.ads, g-socket.adb,
	g-socket.ads (GNAT.Sockets.Thin.C_Send,
	GNAT.Sockets.Thin.Syscall_Send): Remove unused subprograms.
	Replace calls to send(2) with equivalent sendto(2) calls.
	(GNAT.Sockets.Send_Socket): Factor common code in inlined subprogram.
	(GNAT.Sockets.Write): Account for the case of hyper-empty arrays, do not
	report an error in that case. Factor code common to the two versions
	(datagram and stream) in common routine Stream_Write.

From-SVN: r146267
parent c5d91669
2009-04-17 Thomas Quinot <quinot@adacore.com>
PR ada/35953
* g-socthi-vms.adb, g-socthi-vms.ads, g-socthi-vxworks.adb,
g-socthi-vxworks.ads, g-socthi-mingw.adb, g-socthi-mingw.ads,
g-socthi.adb, g-stsifd-sockets.adb, g-socthi.ads, g-socket.adb,
g-socket.ads (GNAT.Sockets.Thin.C_Send,
GNAT.Sockets.Thin.Syscall_Send): Remove unused subprograms.
Replace calls to send(2) with equivalent sendto(2) calls.
(GNAT.Sockets.Send_Socket): Factor common code in inlined subprogram.
(GNAT.Sockets.Write): Account for the case of hyper-empty arrays, do not
report an error in that case. Factor code common to the two versions
(datagram and stream) in common routine Stream_Write.
2009-04-17 Robert Dewar <dewar@adacore.com> 2009-04-17 Robert Dewar <dewar@adacore.com>
* exp_disp.adb: Minor reformatting * exp_disp.adb: Minor reformatting
...@@ -228,6 +228,13 @@ package body GNAT.Sockets is ...@@ -228,6 +228,13 @@ package body GNAT.Sockets is
(Stream : in out Stream_Socket_Stream_Type; (Stream : in out Stream_Socket_Stream_Type;
Item : Ada.Streams.Stream_Element_Array); 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 procedure Wait_On_Socket
(Socket : Socket_Type; (Socket : Socket_Type;
For_Read : Boolean; For_Read : Boolean;
...@@ -1801,21 +1808,24 @@ package body GNAT.Sockets is ...@@ -1801,21 +1808,24 @@ package body GNAT.Sockets is
Last : out Ada.Streams.Stream_Element_Offset; Last : out Ada.Streams.Stream_Element_Offset;
Flags : Request_Flag_Type := No_Request_Flag) Flags : Request_Flag_Type := No_Request_Flag)
is is
Res : C.int;
begin begin
Res := Send_Socket (Socket, Item, Last, To => null, Flags => Flags);
C_Send end Send_Socket;
(C.int (Socket),
Item'Address,
Item'Length,
Set_Forced_Flags (To_Int (Flags)));
if Res = Failure then -----------------
Raise_Socket_Error (Socket_Errno); -- Send_Socket --
end if; -----------------
Last := Item'First + Ada.Streams.Stream_Element_Offset (Res - 1); 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; end Send_Socket;
----------------- -----------------
...@@ -1826,26 +1836,36 @@ package body GNAT.Sockets is ...@@ -1826,26 +1836,36 @@ package body GNAT.Sockets is
(Socket : Socket_Type; (Socket : Socket_Type;
Item : Ada.Streams.Stream_Element_Array; Item : Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset; Last : out Ada.Streams.Stream_Element_Offset;
To : Sock_Addr_Type; To : access Sock_Addr_Type;
Flags : Request_Flag_Type := No_Request_Flag) Flags : Request_Flag_Type := No_Request_Flag)
is is
Res : C.int; Res : C.int;
Sin : aliased Sockaddr_In;
Len : constant C.int := Sin'Size / 8; Sin : aliased Sockaddr_In;
C_To : Sockaddr_In_Access;
Len : C.int;
begin begin
Set_Family (Sin.Sin_Family, To.Family); if To /= null then
Set_Address (Sin'Unchecked_Access, To_In_Addr (To.Addr)); Set_Family (Sin.Sin_Family, To.Family);
Set_Port Set_Address (Sin'Unchecked_Access, To_In_Addr (To.Addr));
(Sin'Unchecked_Access, Set_Port
Short_To_Network (C.unsigned_short (To.Port))); (Sin'Unchecked_Access,
Short_To_Network (C.unsigned_short (To.Port)));
C_To := Sin'Unchecked_Access;
Len := Sin'Size / 8;
else
C_To := null;
Len := 0;
end if;
Res := C_Sendto Res := C_Sendto
(C.int (Socket), (C.int (Socket),
Item'Address, Item'Address,
Item'Length, Item'Length,
Set_Forced_Flags (To_Int (Flags)), Set_Forced_Flags (To_Int (Flags)),
Sin'Unchecked_Access, C_To,
Len); Len);
if Res = Failure then if Res = Failure then
...@@ -2094,6 +2114,43 @@ package body GNAT.Sockets is ...@@ -2094,6 +2114,43 @@ package body GNAT.Sockets is
return Stream_Access (S); return Stream_Access (S);
end Stream; 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 succesful 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 -- -- To_C --
---------- ----------
...@@ -2315,31 +2372,8 @@ package body GNAT.Sockets is ...@@ -2315,31 +2372,8 @@ package body GNAT.Sockets is
(Stream : in out Datagram_Socket_Stream_Type; (Stream : in out Datagram_Socket_Stream_Type;
Item : Ada.Streams.Stream_Element_Array) Item : Ada.Streams.Stream_Element_Array)
is 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 begin
loop Stream_Write (Stream.Socket, Item, To => Stream.To'Unrestricted_Access);
Send_Socket
(Stream.Socket,
Item (First .. Max),
Index,
Stream.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;
if Index /= Max then
raise Socket_Error;
end if;
end Write; end Write;
----------- -----------
...@@ -2350,27 +2384,8 @@ package body GNAT.Sockets is ...@@ -2350,27 +2384,8 @@ package body GNAT.Sockets is
(Stream : in out Stream_Socket_Stream_Type; (Stream : in out Stream_Socket_Stream_Type;
Item : Ada.Streams.Stream_Element_Array) Item : Ada.Streams.Stream_Element_Array)
is 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 begin
loop Stream_Write (Stream.Socket, Item, To => null);
Send_Socket (Stream.Socket, Item (First .. Max), Index);
-- 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;
if Index /= Max then
raise Socket_Error;
end if;
end Write; end Write;
Sockets_Library_Controller_Object : Sockets_Library_Controller; Sockets_Library_Controller_Object : Sockets_Library_Controller;
......
...@@ -917,8 +917,21 @@ package GNAT.Sockets is ...@@ -917,8 +917,21 @@ package GNAT.Sockets is
(Socket : Socket_Type; (Socket : Socket_Type;
Item : Ada.Streams.Stream_Element_Array; Item : Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset; Last : out Ada.Streams.Stream_Element_Offset;
To : access Sock_Addr_Type;
Flags : Request_Flag_Type := No_Request_Flag); Flags : Request_Flag_Type := No_Request_Flag);
-- Transmit a message to another socket. Note that Last is set to pragma Inline (Send_Socket);
-- Transmit a message over a socket. For a datagram socket, the address is
-- given by To.all. For a stream socket, To must be null. Flags
-- allows to control the transmission. Raises Socket_Error on error.
-- Note: this subprogram is inlined because it is also used to implement
-- the two variants below.
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);
-- Transmit a message over a socket. Note that Last is set to
-- Item'First-1 when socket has been closed by peer. This is not -- Item'First-1 when socket has been closed by peer. This is not
-- considered an error and no exception is raised. Flags allows to control -- considered an error and no exception is raised. Flags allows to control
-- the transmission. Raises Socket_Error on any other error condition. -- the transmission. Raises Socket_Error on any other error condition.
...@@ -929,8 +942,9 @@ package GNAT.Sockets is ...@@ -929,8 +942,9 @@ package GNAT.Sockets is
Last : out Ada.Streams.Stream_Element_Offset; Last : out Ada.Streams.Stream_Element_Offset;
To : Sock_Addr_Type; To : Sock_Addr_Type;
Flags : Request_Flag_Type := No_Request_Flag); Flags : Request_Flag_Type := No_Request_Flag);
-- Transmit a message to another socket. The address is given by To. Flags -- Transmit a message over a datagram socket. The destination address is
-- allows to control the transmission. Raises Socket_Error on error. -- To. Flags allows to control the transmission. Raises Socket_Error on
-- error.
procedure Send_Vector procedure Send_Vector
(Socket : Socket_Type; (Socket : Socket_Type;
......
...@@ -390,11 +390,13 @@ package body GNAT.Sockets.Thin is ...@@ -390,11 +390,13 @@ package body GNAT.Sockets.Thin is
begin begin
for J in Iovec'Range loop for J in Iovec'Range loop
Res := C_Send Res := C_Sendto
(Fd, (Fd,
Iovec (J).Base.all'Address, Iovec (J).Base.all'Address,
C.int (Iovec (J).Length), C.int (Iovec (J).Length),
0); Flags => 0,
To => null,
Tolen => 0);
if Res < 0 then if Res < 0 then
return Res; return Res;
......
...@@ -153,12 +153,6 @@ package GNAT.Sockets.Thin is ...@@ -153,12 +153,6 @@ package GNAT.Sockets.Thin is
Exceptfds : access Fd_Set; Exceptfds : access Fd_Set;
Timeout : Timeval_Access) return C.int; Timeout : Timeval_Access) return C.int;
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
function C_Sendto function C_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
...@@ -243,7 +237,6 @@ private ...@@ -243,7 +237,6 @@ private
pragma Import (Stdcall, C_Listen, "listen"); pragma Import (Stdcall, C_Listen, "listen");
pragma Import (Stdcall, C_Recv, "recv"); pragma Import (Stdcall, C_Recv, "recv");
pragma Import (Stdcall, C_Recvfrom, "recvfrom"); pragma Import (Stdcall, C_Recvfrom, "recvfrom");
pragma Import (Stdcall, C_Send, "send");
pragma Import (Stdcall, C_Sendto, "sendto"); pragma Import (Stdcall, C_Sendto, "sendto");
pragma Import (Stdcall, C_Setsockopt, "setsockopt"); pragma Import (Stdcall, C_Setsockopt, "setsockopt");
pragma Import (Stdcall, C_Shutdown, "shutdown"); pragma Import (Stdcall, C_Shutdown, "shutdown");
......
...@@ -92,13 +92,6 @@ package body GNAT.Sockets.Thin is ...@@ -92,13 +92,6 @@ package body GNAT.Sockets.Thin is
Fromlen : not null access C.int) return C.int; Fromlen : not null access C.int) return C.int;
pragma Import (C, Syscall_Recvfrom, "recvfrom"); pragma Import (C, Syscall_Recvfrom, "recvfrom");
function Syscall_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
pragma Import (C, Syscall_Send, "send");
function Syscall_Sendto function Syscall_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
...@@ -285,31 +278,6 @@ package body GNAT.Sockets.Thin is ...@@ -285,31 +278,6 @@ package body GNAT.Sockets.Thin is
return Res; return Res;
end C_Recvfrom; end C_Recvfrom;
------------
-- C_Send --
------------
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int
is
Res : C.int;
begin
loop
Res := Syscall_Send (S, Msg, Len, Flags);
exit when SOSC.Thread_Blocking_IO
or else Res /= Failure
or else Non_Blocking_Socket (S)
or else Errno /= SOSC.EWOULDBLOCK;
delay Quantum;
end loop;
return Res;
end C_Send;
-------------- --------------
-- C_Sendto -- -- C_Sendto --
-------------- --------------
...@@ -500,11 +468,13 @@ package body GNAT.Sockets.Thin is ...@@ -500,11 +468,13 @@ package body GNAT.Sockets.Thin is
begin begin
for J in Iovec'Range loop for J in Iovec'Range loop
Res := C_Send Res := C_Sendto
(Fd, (Fd,
Iovec (J).Base.all'Address, Iovec (J).Base.all'Address,
Interfaces.C.int (Iovec (J).Length), Interfaces.C.int (Iovec (J).Length),
SOSC.MSG_Forced_Flags); SOSC.MSG_Forced_Flags,
To => null,
Tolen => 0);
if Res < 0 then if Res < 0 then
return Res; return Res;
......
...@@ -156,12 +156,6 @@ package GNAT.Sockets.Thin is ...@@ -156,12 +156,6 @@ package GNAT.Sockets.Thin is
Exceptfds : access Fd_Set; Exceptfds : access Fd_Set;
Timeout : Timeval_Access) return C.int; Timeout : Timeval_Access) return C.int;
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
function C_Sendto function C_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
......
...@@ -102,13 +102,6 @@ package body GNAT.Sockets.Thin is ...@@ -102,13 +102,6 @@ package body GNAT.Sockets.Thin is
Fromlen : not null access C.int) return C.int; Fromlen : not null access C.int) return C.int;
pragma Import (C, Syscall_Recvfrom, "recvfrom"); pragma Import (C, Syscall_Recvfrom, "recvfrom");
function Syscall_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
pragma Import (C, Syscall_Send, "send");
function Syscall_Sendto function Syscall_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
...@@ -298,31 +291,6 @@ package body GNAT.Sockets.Thin is ...@@ -298,31 +291,6 @@ package body GNAT.Sockets.Thin is
return Res; return Res;
end C_Recvfrom; end C_Recvfrom;
------------
-- C_Send --
------------
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int
is
Res : C.int;
begin
loop
Res := Syscall_Send (S, Msg, Len, Flags);
exit when SOSC.Thread_Blocking_IO
or else Res /= Failure
or else Non_Blocking_Socket (S)
or else Errno /= SOSC.EWOULDBLOCK;
delay Quantum;
end loop;
return Res;
end C_Send;
-------------- --------------
-- C_Sendto -- -- C_Sendto --
-------------- --------------
......
...@@ -154,12 +154,6 @@ package GNAT.Sockets.Thin is ...@@ -154,12 +154,6 @@ package GNAT.Sockets.Thin is
Exceptfds : access Fd_Set; Exceptfds : access Fd_Set;
Timeout : Timeval_Access) return C.int; Timeout : Timeval_Access) return C.int;
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
function C_Sendto function C_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
......
...@@ -98,13 +98,6 @@ package body GNAT.Sockets.Thin is ...@@ -98,13 +98,6 @@ package body GNAT.Sockets.Thin is
Fromlen : not null access C.int) return C.int; Fromlen : not null access C.int) return C.int;
pragma Import (C, Syscall_Recvfrom, "recvfrom"); pragma Import (C, Syscall_Recvfrom, "recvfrom");
function Syscall_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
pragma Import (C, Syscall_Send, "send");
function Syscall_Sendto function Syscall_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
...@@ -303,31 +296,6 @@ package body GNAT.Sockets.Thin is ...@@ -303,31 +296,6 @@ package body GNAT.Sockets.Thin is
return Res; return Res;
end C_Recvfrom; end C_Recvfrom;
------------
-- C_Send --
------------
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int
is
Res : C.int;
begin
loop
Res := Syscall_Send (S, Msg, Len, Flags);
exit when SOSC.Thread_Blocking_IO
or else Res /= Failure
or else Non_Blocking_Socket (S)
or else Errno /= SOSC.EWOULDBLOCK;
delay Quantum;
end loop;
return Res;
end C_Send;
-------------- --------------
-- C_Sendto -- -- C_Sendto --
-------------- --------------
......
...@@ -155,12 +155,6 @@ package GNAT.Sockets.Thin is ...@@ -155,12 +155,6 @@ package GNAT.Sockets.Thin is
Exceptfds : access Fd_Set; Exceptfds : access Fd_Set;
Timeout : Timeval_Access) return C.int; Timeout : Timeval_Access) return C.int;
function C_Send
(S : C.int;
Msg : System.Address;
Len : C.int;
Flags : C.int) return C.int;
function C_Sendto function C_Sendto
(S : C.int; (S : C.int;
Msg : System.Address; Msg : System.Address;
......
...@@ -226,7 +226,11 @@ package body Signalling_Fds is ...@@ -226,7 +226,11 @@ package body Signalling_Fds is
function Write (Wsig : C.int) return C.int is function Write (Wsig : C.int) return C.int is
Buf : aliased Character := ASCII.NUL; Buf : aliased Character := ASCII.NUL;
begin begin
return C_Send (Wsig, Buf'Address, 1, SOSC.MSG_Forced_Flags); return C_Sendto
(Wsig, Buf'Address, 1,
Flags => SOSC.MSG_Forced_Flags,
To => null,
Tolen => 0);
end Write; end Write;
end Signalling_Fds; end Signalling_Fds;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment