From: snoopysalive on
Hello!

For some reasons I had to implement a server socket in C++. Now I want
to do the same in Ada and so I read the GNAT.Sockets-library and
implemented a shorter version of the example given in the g-
socket.ads.

The problem is that I want to implement the server in a kind, that
processes written in other languages like the tool telnet or a Java-
programme are able to communicate with it. But my server isn't able to
print a message sent by the telnet-client, so I think that I've
written something wrong in my code.

Here's the code:

with Ada.Text_IO,
Ada.Exceptions,
GNAT.Sockets;
use Ada.Text_IO,
Ada.Exceptions,
GNAT.Sockets;

procedure Server is
Host : String := "localhost";
Port : Port_Type := 7777;
Address : Sock_Addr_Type;
Server : Socket_Type;
Client : Socket_Type;
Channel : Stream_Access;
begin -- Server
Initialize;
Address.Addr := Addresses (Get_Host_By_Name (Host), 1);
Address.Port := Port;

begin
Create_Socket (Server);
Put_Line ("Server socket created");
exception
when E : Socket_Error =>
Put_Line (Standard_Error, "Create_Socket failed");
end;
-- Create server socket

begin
Set_Socket_Option (Server, Socket_Level, (Reuse_Address,
True));
Put_Line ("Socket address reused");
exception
when E : Socket_Error =>
Put_Line (Standard_Error, "Set_Socket_Option failed");
end;
-- Resuse socket address

begin
Bind_Socket (Server, Address);
Put_Line ("Server socket bound");
exception
when E : Socket_Error =>
Put_Line (Standard_Error, "Bind_Socket failed");
end;
-- Bind server

begin
Listen_Socket (Server);
Put ("Server is listening... ");
exception
when E : Socket_Error =>
Put_Line (Standard_Error, "Listen_Socket failed");
end;
-- Listening...

begin
Accept_Socket (Server, Client, Address);
Put_Line ("Got client connection");
delay 0.2;
Channel := Stream (Client);
Put_Line ("Client streamed");

declare
Message : String := String'input (Channel);
begin
Put_Line (Message);
end;
-- Get client message and print it to the screen

exception
when E : Socket_Error =>
Put_Line (Standard_Error, "Accept_Socket failed");
end;
-- Client handling

begin
Close_Socket (Client);
Put_Line ("Client closed");
Close_Socket (Server);
Put_Line ("Server closed");
exception
when E : Socket_Error =>
Put_Line (Standard_Error, "Close_Socket failed");
end;
-- Close client and server sockets

Finalize;
end Server;


The server's output is:

"Server socket created
Socket address reused
Server socket bound
Server is listening... Got client connection
Client streamed

Client closed
Server closed"


The empty line should be the message sent by telnet, but like you can
see, the message is empty.

So, can anybody explain to me, what I have done wrong?

Thank you,
Matthias
From: Jeffrey Creem on
snoopysalive(a)googlemail.com wrote:
> Hello!
>
> For some reasons I had to implement a server socket in C++. Now I want
> to do the same in Ada and so I read the GNAT.Sockets-library and
> implemented a shorter version of the example given in the g-
> socket.ads.
>
> The problem is that I want to implement the server in a kind, that
> processes written in other languages like the tool telnet or a Java-
> programme are able to communicate with it. But my server isn't able to
> print a message sent by the telnet-client, so I think that I've
> written something wrong in my code.
>


You don't show the client code but if you really really mean it is a
telnet client then your problem is that you are using 'input. Look at
the LRM definitions for these. (looking at ada 95 here for a moment,
ARM95-13-13-2)

S'Input reads and returns one value from Stream, using any bounds or
discriminants written by a corresponding S'Output to determine how much
to read.

So, unless your telnet client is Ada aware and is sending strings
formatted per Ada string semantics with bounds, then this can't work.
The example you started from probably had a client and server who had
agreed upon a protocol that used 'input 'output semantics.

Telnet has not agreed to this protocol.

There are plenty of ways to do what you are trying.

You could probably play around with 'read 'write on characters or with

procedure Receive_Socket
(Socket : Socket_Type;
Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);

or with a custom overloaded 'read that you implement with something like
Receive_Socket depending upon what you are trying to accomplish.
From: Alex R. Mosteo on
snoopysalive(a)googlemail.com wrote:

> Hello!
>
> For some reasons I had to implement a server socket in C++. Now I want
> to do the same in Ada and so I read the GNAT.Sockets-library and
> implemented a shorter version of the example given in the g-
> socket.ads.
>
> The problem is that I want to implement the server in a kind, that
> processes written in other languages like the tool telnet or a Java-
> programme are able to communicate with it. But my server isn't able to
> print a message sent by the telnet-client, so I think that I've
> written something wrong in my code.
>
> Here's the code:
>
> with Ada.Text_IO,
> Ada.Exceptions,
> GNAT.Sockets;
> use Ada.Text_IO,
> Ada.Exceptions,
> GNAT.Sockets;
>
> procedure Server is
> Host : String := "localhost";
> Port : Port_Type := 7777;
> Address : Sock_Addr_Type;
> Server : Socket_Type;
> Client : Socket_Type;
> Channel : Stream_Access;
> begin -- Server
> Initialize;
> Address.Addr := Addresses (Get_Host_By_Name (Host), 1);
> Address.Port := Port;
>
> begin
> Create_Socket (Server);
> Put_Line ("Server socket created");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Create_Socket failed");
> end;
> -- Create server socket
>
> begin
> Set_Socket_Option (Server, Socket_Level, (Reuse_Address,
> True));
> Put_Line ("Socket address reused");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Set_Socket_Option failed");
> end;
> -- Resuse socket address
>
> begin
> Bind_Socket (Server, Address);
> Put_Line ("Server socket bound");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Bind_Socket failed");
> end;
> -- Bind server
>
> begin
> Listen_Socket (Server);
> Put ("Server is listening... ");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Listen_Socket failed");
> end;
> -- Listening...
>
> begin
> Accept_Socket (Server, Client, Address);
> Put_Line ("Got client connection");
> delay 0.2;
> Channel := Stream (Client);
> Put_Line ("Client streamed");
>
> declare
> Message : String := String'input (Channel);

My bet is the problem is here above: by using String'Input, you're first trying
to read the bounds of the array. A foreign telnet client won't send
Ada-compliant arrays, but characters one by one.

You can't either use String'Read because you don't know in advance the line
length. So I'd change this to manually read one character at a time until end
of line is detected.

> begin
> Put_Line (Message);
> end;
> -- Get client message and print it to the screen
>
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Accept_Socket failed");
> end;
> -- Client handling
>
> begin
> Close_Socket (Client);
> Put_Line ("Client closed");
> Close_Socket (Server);
> Put_Line ("Server closed");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Close_Socket failed");
> end;
> -- Close client and server sockets
>
> Finalize;
> end Server;
>
>
> The server's output is:
>
> "Server socket created
> Socket address reused
> Server socket bound
> Server is listening... Got client connection
> Client streamed
>
> Client closed
> Server closed"
>
>
> The empty line should be the message sent by telnet, but like you can
> see, the message is empty.
>
> So, can anybody explain to me, what I have done wrong?
>
> Thank you,
> Matthias

From: anon on
If your doing a direct conversion from C to Ada using sockets then you might
need to use the lower-level socket package, "GNAT.Sockets.Thin". This
package has direct library links to the sockets library routines, bypassing the
extra layer of code in "GNAT.Sockets".

Also, in "GNAT.Sockets.Thin", the "Bind" function is called "C_Bind" and is
still a function unlike "sockets where the sockets routines are mostly
procedures and are based on "Ada.Streams", in "GNAT.Sockets".

In <ca7b2304-6726-479b-89a0-67486c3dc06f(a)f63g2000hsf.googlegroups.com>, "snoopysalive(a)googlemail.com" <snoopysalive(a)googlemail.com> writes:
>Hello!
>
>For some reasons I had to implement a server socket in C++. Now I want
>to do the same in Ada and so I read the GNAT.Sockets-library and
>implemented a shorter version of the example given in the g-
>socket.ads.
>
>The problem is that I want to implement the server in a kind, that
>processes written in other languages like the tool telnet or a Java-
>programme are able to communicate with it. But my server isn't able to
>print a message sent by the telnet-client, so I think that I've
>written something wrong in my code.
>
>Here's the code:
>
>with Ada.Text_IO,
> Ada.Exceptions,
> GNAT.Sockets;
>use Ada.Text_IO,
> Ada.Exceptions,
> GNAT.Sockets;
>
>procedure Server is
> Host : String := "localhost";
> Port : Port_Type := 7777;
> Address : Sock_Addr_Type;
> Server : Socket_Type;
> Client : Socket_Type;
> Channel : Stream_Access;
>begin -- Server
> Initialize;
> Address.Addr := Addresses (Get_Host_By_Name (Host), 1);
> Address.Port := Port;
>
> begin
> Create_Socket (Server);
> Put_Line ("Server socket created");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Create_Socket failed");
> end;
> -- Create server socket
>
> begin
> Set_Socket_Option (Server, Socket_Level, (Reuse_Address,
>True));
> Put_Line ("Socket address reused");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Set_Socket_Option failed");
> end;
> -- Resuse socket address
>
> begin
> Bind_Socket (Server, Address);
> Put_Line ("Server socket bound");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Bind_Socket failed");
> end;
> -- Bind server
>
> begin
> Listen_Socket (Server);
> Put ("Server is listening... ");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Listen_Socket failed");
> end;
> -- Listening...
>
> begin
> Accept_Socket (Server, Client, Address);
> Put_Line ("Got client connection");
> delay 0.2;
> Channel := Stream (Client);
> Put_Line ("Client streamed");
>
> declare
> Message : String := String'input (Channel);
> begin
> Put_Line (Message);
> end;
> -- Get client message and print it to the screen
>
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Accept_Socket failed");
> end;
> -- Client handling
>
> begin
> Close_Socket (Client);
> Put_Line ("Client closed");
> Close_Socket (Server);
> Put_Line ("Server closed");
> exception
> when E : Socket_Error =>
> Put_Line (Standard_Error, "Close_Socket failed");
> end;
> -- Close client and server sockets
>
> Finalize;
>end Server;
>
>
>The server's output is:
>
>"Server socket created
>Socket address reused
>Server socket bound
>Server is listening... Got client connection
>Client streamed
>
>Client closed
>Server closed"
>
>
>The empty line should be the message sent by telnet, but like you can
>see, the message is empty.
>
>So, can anybody explain to me, what I have done wrong?
>
>Thank you,
>Matthias

From: snoopysalive on
Thanks to all the answers of you three. Actually, I also suspected
that the problem could have something to do sort of incompatibility of
programmes written in C and those written in Ada. So, I'll try out
your solution hints. Thank you!