summaryrefslogtreecommitdiffstats
path: root/pingpong/pingpong.adb
diff options
context:
space:
mode:
Diffstat (limited to 'pingpong/pingpong.adb')
-rw-r--r--pingpong/pingpong.adb285
1 files changed, 285 insertions, 0 deletions
diff --git a/pingpong/pingpong.adb b/pingpong/pingpong.adb
new file mode 100644
index 0000000..549e2e6
--- /dev/null
+++ b/pingpong/pingpong.adb
@@ -0,0 +1,285 @@
+with Ada.Text_IO;
+with Ada.Exceptions; use Ada.Exceptions;
+with GNAT.Sockets; use GNAT.Sockets;
+
+procedure PingPong is
+
+ Group : constant String := "239.255.128.128";
+ -- Multicast groupe: administratively scoped IP address
+ --
+ task Pong is
+ entry Start;
+ entry Stop;
+ end Pong;
+
+ task body Pong is
+ Address : Sock_Addr_Type;
+ Server : Socket_Type;
+ Socket : Socket_Type;
+ Channel : Stream_Access;
+
+ begin
+ accept Start;
+ --
+ -- Get an Internet address of a host (here the local host name).
+ -- Note that a host can have several addresses. Here we get
+ -- the first one which is supposed to be the official one.
+ --
+ Address.Addr := Addresses (Get_Host_By_Name (Host_Name), 1);
+ --
+ -- Get a socket address that is an Internet address and a port
+ --
+ Address.Port := 5432;
+ --
+ -- The first step is to create a socket. Once created, this
+ -- socket must be associated to with an address. Usually only
+ -- a server (Pong here) needs to bind an address explicitly.
+ -- Most of the time clients can skip this step because the
+ -- socket routines will bind an arbitrary address to an unbound
+ -- socket.
+ --
+ Create_Socket (Server);
+ --
+ -- Allow reuse of local addresses.
+ --
+ Set_Socket_Option
+ (Server,
+ Socket_Level,
+ (Reuse_Address, True));
+
+ Bind_Socket (Server, Address);
+ --
+ -- A server marks a socket as willing to receive connect events.
+ --
+ Listen_Socket (Server);
+ --
+ -- Once a server calls Listen_Socket, incoming connects events
+ -- can be accepted. The returned Socket is a new socket that
+ -- represents the server side of the connection. Server remains
+ -- available to receive further connections.
+ --
+ Accept_Socket (Server, Socket, Address);
+ --
+ -- Return a stream associated to the connected socket.
+ --
+ Channel := Stream (Socket);
+ --
+ -- Force Pong to block
+ --
+ delay 0.2;
+ --
+ -- Receive and print message from client Ping.
+ --
+ declare
+ Message : String := String'Input (Channel);
+ begin
+ Ada.Text_IO.Put_Line (Message);
+ --
+ -- Send same message to server Pong.
+ --
+ String'Output (Channel, Message);
+ end;
+
+ Close_Socket (Server);
+ Close_Socket (Socket);
+ --
+ -- Part of the multicast example
+ --
+ -- Create a datagram socket to send connectionless, unreliable
+ -- messages of a fixed maximum length.
+ --
+ Create_Socket (Socket, Family_Inet, Socket_Datagram);
+ --
+ -- Allow reuse of local addresses.
+ --
+ Set_Socket_Option
+ (Socket,
+ Socket_Level,
+ (Reuse_Address, True));
+ --
+ -- Join a multicast group.
+ --
+ Set_Socket_Option
+ (Socket,
+ IP_Protocol_For_IP_Level,
+ (Add_Membership, Inet_Addr (Group), Any_Inet_Addr));
+ --
+ -- Controls the live time of the datagram to avoid it being
+ -- looped forever due to routing errors. Routers decrement
+ -- the TTL of every datagram as it traverses from one network
+ -- to another and when its value reaches 0 the packet is
+ -- dropped. Default is 1.
+ --
+ Set_Socket_Option
+ (Socket,
+ IP_Protocol_For_IP_Level,
+ (Multicast_TTL, 1));
+ --
+ -- Want the data you send to be looped back to your host.
+ --
+ Set_Socket_Option
+ (Socket,
+ IP_Protocol_For_IP_Level,
+ (Multicast_Loop, True));
+ --
+ -- If this socket is intended to receive messages, bind it to a
+ -- given socket address.
+ --
+ Address.Addr := Any_Inet_Addr;
+ Address.Port := 55505;
+
+ Bind_Socket (Socket, Address);
+ --
+ -- If this socket is intended to send messages, provide the
+ -- receiver socket address.
+ --
+ Address.Addr := Inet_Addr (Group);
+ Address.Port := 55506;
+
+ Channel := Stream (Socket, Address);
+ --
+ -- Receive and print message from client Ping.
+ --
+ declare
+ Message : String := String'Input (Channel);
+
+ begin
+ --
+ -- Get the address of the sender.
+ --
+ Address := Get_Address (Channel);
+ Ada.Text_IO.Put_Line (Message & " from " & Image (Address));
+ --
+ -- Send same message to server Pong.
+ --
+ String'Output (Channel, Message);
+ end;
+
+ Close_Socket (Socket);
+
+ accept Stop;
+
+ exception when E : others =>
+ Ada.Text_IO.Put_Line
+ (Exception_Name (E) & ": " & Exception_Message (E));
+ end Pong;
+
+ task Ping is
+ entry Start;
+ entry Stop;
+ end Ping;
+
+ task body Ping is
+ Address : Sock_Addr_Type;
+ Socket : Socket_Type;
+ Channel : Stream_Access;
+
+ begin
+ accept Start;
+ --
+ -- See comments in Ping section for the first steps.
+ --
+ Address.Addr := Addresses (Get_Host_By_Name (Host_Name), 1);
+ Address.Port := 5432;
+ Create_Socket (Socket);
+
+ Set_Socket_Option
+ (Socket,
+ Socket_Level,
+ (Reuse_Address, True));
+ --
+ -- Force Pong to block
+ --
+ delay 0.2;
+ --
+ -- If the client's socket is not bound, Connect_Socket will
+ -- bind to an unused address. The client uses Connect_Socket to
+ -- create a logical connection between the client's socket and
+ -- a server's socket returned by Accept_Socket.
+ --
+ Connect_Socket (Socket, Address);
+
+ Channel := Stream (Socket);
+ --
+ -- Send message to server Pong.
+ --
+ String'Output (Channel, "Hello world");
+ --
+ -- Force Ping to block
+ --
+ delay 0.2;
+ --
+ -- Receive and print message from server Pong.
+ --
+ Ada.Text_IO.Put_Line (String'Input (Channel));
+ Close_Socket (Socket);
+ --
+ -- Part of multicast example. Code similar to Pong's one.
+ --
+ Create_Socket (Socket, Family_Inet, Socket_Datagram);
+
+ Set_Socket_Option
+ (Socket,
+ Socket_Level,
+ (Reuse_Address, True));
+
+ Set_Socket_Option
+ (Socket,
+ IP_Protocol_For_IP_Level,
+ (Add_Membership, Inet_Addr (Group), Any_Inet_Addr));
+
+ Set_Socket_Option
+ (Socket,
+ IP_Protocol_For_IP_Level,
+ (Multicast_TTL, 1));
+
+ Set_Socket_Option
+ (Socket,
+ IP_Protocol_For_IP_Level,
+ (Multicast_Loop, True));
+
+ Address.Addr := Any_Inet_Addr;
+ Address.Port := 55506;
+
+ Bind_Socket (Socket, Address);
+
+ Address.Addr := Inet_Addr (Group);
+ Address.Port := 55505;
+
+ Channel := Stream (Socket, Address);
+ --
+ -- Send message to server Pong.
+ --
+ String'Output (Channel, "Hello world");
+ --
+ -- Receive and print message from server Pong.
+ --
+ declare
+ Message : String := String'Input (Channel);
+
+ begin
+ Address := Get_Address (Channel);
+ Ada.Text_IO.Put_Line (Message & " from " & Image (Address));
+ end;
+
+ Close_Socket (Socket);
+
+ accept Stop;
+
+ exception when E : others =>
+ Ada.Text_IO.Put_Line
+ (Exception_Name (E) & ": " & Exception_Message (E));
+ end Ping;
+
+begin
+ -- Indicate whether the thread library provides process
+ -- blocking IO. Basically, if you are not using FSU threads
+ -- the default is ok.
+ --
+ Initialize (Process_Blocking_IO => False);
+ Ping.Start;
+ Pong.Start;
+ Ping.Stop;
+ Pong.Stop;
+ Finalize;
+end PingPong;