This change implements a suggested improvement to the behaviour of
stream primitives for streams backed by datagram sockets: a Read or
Write call now corresponds to exactly one Receive_Socket or Send_Socket call.
Test case:
$ gnatmake -q udp_stream
$ ./udp_stream
Got 5 characters: <<hello>>
with Ada.Streams; use Ada.Streams;
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Sockets; use GNAT.Sockets;
procedure UDP_Stream is
A : Sock_Addr_Type;
S1, S2 : Socket_Type;
begin
Create_Socket (S1, Family_Inet, Socket_Datagram);
A.Addr := Loopback_Inet_Addr;
A.Port := Any_Port;
Bind_Socket (S1, A);
A := Get_Socket_Name (S1);
Create_Socket (S2, Family_Inet, Socket_Datagram);
Connect_Socket (S2, A);
String'Write (Stream (S2, A), "hello");
declare
SEA : Stream_Element_Array (1 .. 16);
Last : Stream_Element_Offset;
Str : String (1 .. 16);
for Str'Address use SEA'Address;
pragma Import (Ada, Str);
begin
Read (Stream (S1, A).all, SEA, Last);
Put_Line
("Got" & Last'Img & " characters: <<"
& Str (1 .. Integer (Last)) & ">>");
end;
end UDP_Stream;
Tested on x86_64-pc-linux-gnu, committed on trunk
2014-05-21 Thomas Quinot <[email protected]>
* g-socket.adb (Read and Write for Datagram_Socket_Stream_Type):
Provide a behaviour more consistent with underlying datagram
socket: do not attempt to loop over Send_Socket/Receive_Socket
iterating along the buffer.
Index: g-socket.adb
===================================================================
--- g-socket.adb (revision 210687)
+++ g-socket.adb (working copy)
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2001-2013, AdaCore --
+-- Copyright (C) 2001-2014, 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- --
@@ -244,13 +244,6 @@
(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;
@@ -1732,27 +1725,12 @@
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;
+ Receive_Socket
+ (Stream.Socket,
+ Item,
+ Last,
+ Stream.From);
end Read;
----------
@@ -2419,43 +2397,6 @@
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 --
----------
@@ -2695,8 +2636,20 @@
(Stream : in out Datagram_Socket_Stream_Type;
Item : Ada.Streams.Stream_Element_Array)
is
+ Last : Stream_Element_Offset;
+
begin
- Stream_Write (Stream.Socket, Item, To => Stream.To'Unrestricted_Access);
+ Send_Socket
+ (Stream.Socket,
+ Item,
+ Last,
+ Stream.To);
+
+ -- It is an error if not all of the data has been sent
+
+ if Last /= Item'Last then
+ Raise_Socket_Error (Socket_Errno);
+ end if;
end Write;
-----------
@@ -2707,8 +2660,32 @@
(Stream : in out Stream_Socket_Stream_Type;
Item : Ada.Streams.Stream_Element_Array)
is
+ First : Ada.Streams.Stream_Element_Offset;
+ Index : Ada.Streams.Stream_Element_Offset;
+ Max : constant Ada.Streams.Stream_Element_Offset := Item'Last;
+
begin
- Stream_Write (Stream.Socket, Item, To => null);
+ First := Item'First;
+ Index := First - 1;
+ while First <= Max loop
+ Send_Socket (Stream.Socket, Item (First .. Max), Index, null);
+
+ -- 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 Write;
Sockets_Library_Controller_Object : Sockets_Library_Controller;