From: mockturtle on
Dear all,
I have a strange problem (which, actually, is a problem only because I
have to use a buggy server) with the following code that sends an HTTP
request to the port 3000 of localhost (server and program run on the
same PC)

-------
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Sockets; use GNAT.Sockets;
with Ada.Streams; use Ada.Streams;
with Ada.Characters.Latin_1;
procedure main is
Sock : Socket_Type;
Server : Sock_Addr_Type := (Family => Family_Inet,
Addr => Inet_Addr("127.0.0.1"),
Port => Port_Type(3000));
Basic_Stream : Stream_Access;

Query : String := "GET /p2p.rb?
stream=pippo&command=join_user&user=127.0.0.1:48946:3 HTTP/1.1";
Crlf : String := Ada.Characters.Latin_1.CR &
Ada.Characters.Latin_1.LF;
Host_name : String := "Host: 127.0.0.1:3000";
begin
Create_Socket (Sock);
Connect_Socket (Sock, Server);

Basic_Stream := Stream (Sock);

String'Write(Basic_Stream, Query);
String'Write(Basic_Stream, Crlf);
String'Write(Basic_Stream, Host_Name);
String'Write(Basic_Stream, Crlf);
String'Write(Basic_Stream, Crlf);
end main;
------

If I compile the code at home and check the traffic with tcpdump, I
can see that each strings is transmited in a packet by itself.

If I compile the code above at work, I see that the strings are
transmitted one char per packet (i.e., first a packet with "G", then a
packet with "E", and so on...) . It seems that the server does not
like this and it closes the connection without replying. However,
sometime (in a random fashion) after sending few single char packets,
it send the remainder of the string in a single packet. In this case
the server replies.

[Yes, the server is buggy since it should not care... Anyway, that is
what I have to use. Before you object, it is just to carry out some
fast-and-dirty tests, so it does not matter much if the system is a
little "brittle".].

We tried several tests. For example, if we use C (I'll have to whash
my keyboard with soap... ;-) or Ruby, each string is sent in a packet
by itself, both at home and at work. I am beginning to think that
this is something in the GNAT library and how it interfaces with BSD
sockets.

Ideas?

My environments:
Work : GPS 4.3.1 and GNAT 4.3.2 (from "About"), Linux 2.6.something
Home: GPS 4.3.1 and GNAT GPL 2009 (20090519), Linux 2.4.26


Thank you in advance.
From: Dmitry A. Kazakov on
On Thu, 12 Nov 2009 11:28:22 -0800 (PST), mockturtle wrote:

> I have a strange problem (which, actually, is a problem only because I
> have to use a buggy server) with the following code that sends an HTTP
> request to the port 3000 of localhost (server and program run on the
> same PC)

[...]

> String'Write(Basic_Stream, Query);
> String'Write(Basic_Stream, Crlf);
> String'Write(Basic_Stream, Host_Name);
> String'Write(Basic_Stream, Crlf);
> String'Write(Basic_Stream, Crlf);
> end main;
> ------
>
> If I compile the code at home and check the traffic with tcpdump, I
> can see that each strings is transmited in a packet by itself.
>
> If I compile the code above at work, I see that the strings are
> transmitted one char per packet (i.e., first a packet with "G", then a
> packet with "E", and so on...)

When you write an array into a stream using the attribute 'Write, the
compiler has right to implement this as individual writings of the array
elements. Newer versions of GNAT coalesce string writing into several
characters at once, the older ones do not.

So the first thing to do is to use Stream operations rather than the
attributes. E.g. Write

procedure Write(
Stream : in out Root_Stream_Type;
Item : in Stream_Element_Array)

Even better would be to use Send from GNAT sockets. With Send you can be
certain that the packet will be split only if the transport layer urgently
will do this.

Another thing is a strange behavior of the socket (TCP stack), which
normally coalesces small packets. There is a TCP_NO_DELAY option which
controls this behavior. By default it is false, i.e. coalescing is on. Make
sure that you don't set it to true when you create the socket. You can also
set it to false explicitly.

> My environments:
> Work : GPS 4.3.1 and GNAT 4.3.2 (from "About"), Linux 2.6.something
> Home: GPS 4.3.1 and GNAT GPL 2009 (20090519), Linux 2.4.26

See, the compilers are indeed different!

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Jacob Sparre Andersen on
mockturtle <framefritti(a)gmail.com> writes:

> String'Write(Basic_Stream, Query);

> If I compile the code at home and check the traffic with tcpdump, I
> can see that each strings is transmited in a packet by itself.
>
> If I compile the code above at work, I see that the strings are
> transmitted one char per packet (i.e., first a packet with "G", then a
> packet with "E", and so on...)

> Ideas?

I think what you see is simply different implementations of the
"Write" attribute for arrays. You can work around the difference by
supplying your own implementation of the "Write" attribute for
strings, which calls "Ada.Streams.Write" with a storage element array
overlayed with the complete string to be written.

Greetings,

Jacob
--
�Verbing weirds language.� -- Calvin