summaryrefslogblamecommitdiffstats
path: root/pingpong/pingpong.adb
blob: f33814f136082214e6593f12566871959dcf518a (plain) (tree)


























                                                                       
                                                                  
                                                                  

                                                                
























































































































































                                                                       
                                                                  
                                                                  
                                                                






































































































                                                                      
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.
      --
      Ada.Text_IO.Put_Line ("PONG: Get_Host_By_Name" & Host_Name);
      Address.Addr := Addresses (Get_Host_By_Name (Host_Name), 1);
      Ada.Text_IO.Put_Line ("PONG: Back from Get_Host_By_Name");

      --
      --  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.
   --
      Ada.Text_IO.Put_Line ("PING: Get_Host_By_Name" & Host_Name);
      Address.Addr := Addresses (Get_Host_By_Name (Host_Name), 1);
      Ada.Text_IO.Put_Line ("PING: Back from Get_Host_By_Name");
      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;