with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
with Ada.Strings.Bounded; use Ada.Strings.Bounded;
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Command_Line; use GNAT.Command_Line;
with GNAT.Sockets; use GNAT.Sockets;
with Neat_Sockets; use Neat_Sockets;
procedure Ring_Node is
type Command_Line_Options is record
This_Addr : Inet_Addr_Type := Addresses (Get_Host_By_Name (Host_Name), 1);
This_Port : Port_Type := 45042;
Next_Addr : Inet_Addr_Type := Addresses (Get_Host_By_Name (Host_Name), 1);
Next_Port : Port_Type := 45042;
end record;
CLP : Command_Line_Options;
Float_Generator : Generator;
procedure Print_Options is
begin
New_Line; Put ("accepted options:");
New_Line; Put (" [-a {IP address of this node : String }] -> "); Put (Image (CLP.This_Addr));
New_Line; Put (" [-n {IP address of next node : String }] -> "); Put (Image (CLP.Next_Addr));
New_Line; Put (" [-p {This node's port : Port_Type }] ->"); Put (Port_Type'Image (CLP.This_Port));
New_Line; Put (" [-q {Next node's port : Port_Type }] ->"); Put (Port_Type'Image (CLP.Next_Port));
New_Line;
New_Line;
end Print_Options;
begin
Initialize_Option_Scan;
loop
declare
Option : constant Character := Getopt ("a: n: p: q:");
begin
case Option is
when ASCII.NUL => exit;
when 'a' => CLP.This_Addr := Inet_Addr (Parameter);
when 'n' => CLP.Next_Addr := Inet_Addr (Parameter);
when 'p' => CLP.This_Port := Port_Type'Value (Parameter);
when 'q' => CLP.Next_Port := Port_Type'Value (Parameter);
when others => raise Program_Error;
end case;
exception
when others => raise Program_Error with ("---> Error in option -" & Option);
end;
end loop;
Print_Options;
Put_Line ("This is ring node at IP: " & Image (Addresses (Get_Host_By_Name (Host_Name))) & " serving port: " & Port_Type'Image (CLP.This_Port));
Reset (Float_Generator);
declare
package String_80 is new Generic_Bounded_Length (80);
use String_80;
type Election_Message is record
Random_Id : Uniformly_Distributed := Random (Float_Generator);
IP_Addr : Bounded_String := To_Bounded_String (Image (Addresses (Get_Host_By_Name (Host_Name), 1)));
end record;
function "<" (M1, M2 : Election_Message) return Boolean is
(M1.Random_Id < M2.Random_Id or else
(M1.Random_Id = M2.Random_Id and then M1.IP_Addr < M2.IP_Addr));
Server_Socket : constant Socket_Type := Open_Server_Port (Port => CLP.This_Port);
Incoming_Connection_Socket,
Outgoing_Connection_Socket : Socket_Type;
Incoming_Connection_Address : Sock_Addr_Type;
Incoming_Channel,
Outgoing_Channel : Stream_Access;
Election_Bid, Message : Election_Message;
begin
Put_Line ("Sending out election bid");
Election_Message'Write (Outgoing_Channel, Election_Bid);
loop
begin
Election_Message'Read (Incoming_Channel, Message);
Put ("Incoming message .. ");
exception
when End_Error =>
Put_Line ("No more messages --> End of election");
exit;
end;
if Message = Election_Bid then
Put_Line ("--> Found own message -> I win!");
exit;
elsif Election_Bid < Message then
Put_Line ("--> Forward");
Election_Message'Write (Outgoing_Channel, Message);
else
Put_Line ("--> Drop");
end if;
end loop;
Close_Connection (Outgoing_Connection_Socket);
Close_Connection (Incoming_Connection_Socket);
Close_Socket (Server_Socket);
end;
end Ring_Node;