raw
udp_tester              1   -- UDP transmissions tester for the libUDP
udp_tester 2 -- S.MG, 2018
udp_tester 3
udp_tester 4 with Ada.Text_IO; use Ada.Text_IO;
udp_tester 5 with Ada.Calendar; use Ada.Calendar; -- for local time
udp_tester 6 with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones; -- UTC_Time_Offset
udp_tester 7 with Ada.Calendar.Formatting; use Ada.Calendar.Formatting; -- for unix-like
udp_tester 8 with Ada.Directories; use Ada.Directories; -- for log files checks
udp_tester 9 with Interfaces; use Interfaces; --Unsigned_8 for payload
udp_tester 10
udp_tester 11 with UDP;
udp_tester 12 with MT;
udp_tester 13
udp_tester 14 package body UDP_Tester is
udp_tester 15
udp_tester 16 procedure Create_If_Not_Exists( Filename: in String; Header: in String) is
udp_tester 17 F : File_Type;
udp_tester 18 begin
udp_tester 19 begin
udp_tester 20 Open(File => F, Mode => Append_File, Name => Filename);
udp_tester 21 Close(File => F);
udp_tester 22 exception
udp_tester 23 when Ada.Text_IO.Name_Error =>
udp_tester 24 Create( File => F, Mode => Out_File, Name => Filename);
udp_tester 25 Put_Line(F, Header);
udp_tester 26 Close(F);
udp_tester 27 Put_Line("Created file " & Filename);
udp_tester 28 end;
udp_tester 29 end Create_If_Not_Exists;
udp_tester 30
udp_tester 31 procedure Sender( Receiver_IP: in String;
udp_tester 32 Receiver_Port: in Unsigned_16;
udp_tester 33 Sender_Port: in Unsigned_16 ) is
udp_tester 34
udp_tester 35 -- payload sizes to choose from
udp_tester 36 Sizes : array(1..Max_Len-Header_Len+1) of Natural;
udp_tester 37 Len_Sizes : Natural := Sizes'Length;
udp_tester 38 Packet_Size : Positive;
udp_tester 39 Pos : Natural;
udp_tester 40
udp_tester 41 -- log file for sender
udp_tester 42 OutFile : File_Type;
udp_tester 43 OutFileName : constant String := "sender_udp_log.txt";
udp_tester 44 HeaderOutFile : constant String :=
udp_tester 45 "SizeSent" &
udp_tester 46 ",TimeSent" &
udp_tester 47 ",DestinationIP" &
udp_tester 48 ",DestinationPort" &
udp_tester 49 ",Seed";
udp_tester 50
udp_tester 51 -- seed for initialising the MT PRNG
udp_tester 52 Seed : constant MT.U32 := MT.U32(Ada.Calendar.Clock - Epoch);
udp_tester 53 begin
udp_tester 54 -- create log file and add header to it if it doesn't exist already
udp_tester 55 Create_If_Not_Exists( OutFileName, HeaderOutFile);
udp_tester 56
udp_tester 57 -- initialize MT rpng
udp_tester 58 MT.Init_Genrand(Seed);
udp_tester 59
udp_tester 60 -- initialize payload sizes to choose from
udp_tester 61 for I in Sizes'Range loop
udp_tester 62 Sizes(I) := I - 1;
udp_tester 63 end loop;
udp_tester 64
udp_tester 65 -- send packages in a loop
udp_tester 66 Sending_Loop:
udp_tester 67 while Len_Sizes > 0 loop
udp_tester 68
udp_tester 69 --a delay of 1 sec to avoid saturating the link with burst-mode
udp_tester 70 delay 1.0;
udp_tester 71
udp_tester 72 -- pick randomly one of the available sizes for payload
udp_tester 73 Pos := Natural(MT.Gen_U32 mod MT.U32(Len_Sizes)) + 1;
udp_tester 74 Packet_Size := Sizes( Pos ) + Header_Len;
udp_tester 75
udp_tester 76 -- shift available sizes to exclude the latest pick
udp_tester 77 if Pos<Len_Sizes and Len_Sizes>Sizes'First then
udp_tester 78 Sizes(Pos..Len_Sizes-1) := Sizes(Pos+1..Len_Sizes);
udp_tester 79 end if;
udp_tester 80 -- decrease length of available sizes
udp_tester 81 Len_Sizes := Len_Sizes - 1;
udp_tester 82
udp_tester 83 -- instantiate UDP sender of picked size and send packet
udp_tester 84 declare
udp_tester 85 K : constant Positive := Packet_Size;
udp_tester 86 -- sender will have *current* size of UDP packet
udp_tester 87 package UDP_Sdr is new UDP( Payload_Size => K );
udp_tester 88
udp_tester 89 -- socket, addr, port
udp_tester 90 Socket : UDP_Sdr.Socket;
udp_tester 91
udp_tester 92 Local_Endpoint : UDP_Sdr.Endpoint :=
udp_tester 93 (Address => UDP_Sdr.INADDR_ANY,
udp_tester 94 Port => Sender_Port);
udp_tester 95
udp_tester 96 Remote_Endpoint : UDP_Sdr.Endpoint :=
udp_tester 97 (Address => UDP_Sdr.IP_From_String(Receiver_IP),
udp_tester 98 Port => Receiver_Port);
udp_tester 99
udp_tester 100 Sent_Payload : UDP_Sdr.Payload;
udp_tester 101
udp_tester 102 TimeUTC : Ada.Calendar.Time;
udp_tester 103 TimeUnix : Interfaces.Unsigned_32;
udp_tester 104
udp_tester 105 begin
udp_tester 106 -- message to console
udp_tester 107 Put_Line("Sending packet Len_Sizes= " & Integer'Image(Len_Sizes) &
udp_tester 108 " with length " & Positive'Image(Sent_Payload'Length));
udp_tester 109
udp_tester 110 -- fill the payload, so starting after header octets
udp_tester 111 for I in (Sent_Payload'First + Header_Len) .. Sent_Payload'Last loop
udp_tester 112 Sent_Payload(I) := Interfaces.Unsigned_8(I mod 256);
udp_tester 113 end loop;
udp_tester 114
udp_tester 115 -- fill the header part
udp_tester 116 -- time (UTC): year, month, day, seconds since midnight (2 octets)
udp_tester 117 TimeUTC := Ada.Calendar.Clock;
udp_tester 118 TimeUnix := Interfaces.Unsigned_32(TimeUTC - Epoch);
udp_tester 119
udp_tester 120 Sent_Payload(Sent_Payload'First+3) := Interfaces.Unsigned_8(
udp_tester 121 TimeUnix mod 256 );
udp_tester 122 TimeUnix := Shift_Right(TimeUnix, 8);
udp_tester 123
udp_tester 124 Sent_Payload(Sent_Payload'First+2) := Interfaces.Unsigned_8(
udp_tester 125 TimeUnix mod 256 );
udp_tester 126 TimeUnix := Shift_Right(TimeUnix, 8);
udp_tester 127
udp_tester 128 Sent_Payload(Sent_Payload'First+1) := Interfaces.Unsigned_8(
udp_tester 129 TimeUnix mod 256 );
udp_tester 130 TimeUnix := Shift_Right(TimeUnix, 8);
udp_tester 131 Sent_Payload(Sent_Payload'First) := Interfaces.Unsigned_8(
udp_tester 132 TimeUnix mod 256 );
udp_tester 133
udp_tester 134
udp_tester 135 -- size of message (full, payload+header)
udp_tester 136 Sent_Payload(Sent_Payload'First + 4) := Interfaces.Unsigned_8(
udp_tester 137 Sent_Payload'Length / 256);
udp_tester 138
udp_tester 139 Sent_Payload(Sent_Payload'First + 5) := Interfaces.Unsigned_8(
udp_tester 140 Sent_Payload'Length mod 256);
udp_tester 141
udp_tester 142 -- send packet
udp_tester 143 UDP_Sdr.Open_Socket(Socket, Local_Endpoint);
udp_tester 144 UDP_Sdr.Transmit(Socket, Remote_Endpoint, Sent_Payload);
udp_tester 145 UDP_Sdr.Close_Socket(Socket);
udp_tester 146
udp_tester 147 -- log the packet
udp_tester 148 TimeUnix := Interfaces.Unsigned_32(TimeUTC - Epoch);
udp_tester 149
udp_tester 150 Open(File => OutFile,
udp_tester 151 Mode => Append_File,
udp_tester 152 Name => OutFileName);
udp_tester 153 Put(OutFile, Integer'Image(Sent_Payload'Length));
udp_tester 154 Put(OutFile, "," & Unsigned_32'Image(TimeUnix));
udp_tester 155 Put(OutFile, "," & Receiver_IP);
udp_tester 156 Put(OutFile, "," & Unsigned_16'Image(Receiver_Port));
udp_tester 157 Put_Line(OutFile, "," & MT.U32'Image(Seed));
udp_tester 158
udp_tester 159 Close(File => OutFile);
udp_tester 160 end;
udp_tester 161 end loop Sending_Loop;
udp_tester 162 end Sender;
udp_tester 163
udp_tester 164 procedure Receiver( Receiver_Port: in Unsigned_16 ) is
udp_tester 165 -- receiver HAS to have max len for UDP size; it doesn't know it in advance
udp_tester 166 package UDP_Rcv is new UDP( Payload_Size => Max_Len );
udp_tester 167
udp_tester 168 -- socket and local endpoint to receive on
udp_tester 169 Socket : UDP_Rcv.Socket;
udp_tester 170 Local_Endpoint : UDP_Rcv.Endpoint := (Address => UDP_Rcv.INADDR_ANY,
udp_tester 171 Port => Receiver_Port);
udp_tester 172
udp_tester 173 -- received payload and source information
udp_tester 174 Received_Payload : UDP_Rcv.Payload;
udp_tester 175 Received_Origin : UDP_Rcv.Endpoint;
udp_tester 176 Received_Len : Unsigned_32;
udp_tester 177
udp_tester 178 -- for logging
udp_tester 179 TimeUTC : Ada.Calendar.Time;
udp_tester 180 TimeUnix : Interfaces.Unsigned_32;
udp_tester 181 TimeSent : Interfaces.Unsigned_32;
udp_tester 182 SizeSent : Interfaces.Unsigned_32;
udp_tester 183 Expected : Interfaces.Unsigned_8; --one octet of payload
udp_tester 184 ErrCount : Natural;
udp_tester 185
udp_tester 186 -- log file
udp_tester 187 OutFile : File_Type;
udp_tester 188 ErrFile : File_Type;
udp_tester 189 OutFileName : constant String := "receiver_udp_log.txt";
udp_tester 190 ErrFileName : constant String := "receiver_udp_err_log.txt";
udp_tester 191 HeaderOutFile : constant String :=
udp_tester 192 "SizeSent" &
udp_tester 193 ",TimeSent" &
udp_tester 194 ",SourceIP" &
udp_tester 195 ",SourcePort" &
udp_tester 196 ",SizeReceived" &
udp_tester 197 ",TimeReceived" &
udp_tester 198 ",ErrorOctetsCount";
udp_tester 199 HeaderErrFile : constant String :=
udp_tester 200 "SizeSent" &
udp_tester 201 ",TimeSent" &
udp_tester 202 ",SourceIP" &
udp_tester 203 ",SourcePort" &
udp_tester 204 ",SizeReceived" &
udp_tester 205 ",TimeReceived" &
udp_tester 206 "(,Position" & --position in payload of err octet
udp_tester 207 ",ValueReceived" &
udp_tester 208 ",ValueExpected)*";
udp_tester 209
udp_tester 210 begin
udp_tester 211 -- create log files and add headers to them if they don't exist already
udp_tester 212 Create_If_Not_Exists( OutFileName, HeaderOutFile);
udp_tester 213 Create_If_Not_Exists( ErrFileName, HeaderErrFile);
udp_tester 214
udp_tester 215 Put_Line("Opening socket on local endpoint " &
udp_tester 216 UDP_Rcv.IP_To_String(Local_Endpoint.Address) &
udp_tester 217 " :" & UDP_Rcv.IP_Port'Image(Local_Endpoint.Port) & "...");
udp_tester 218
udp_tester 219 UDP_Rcv.Open_Socket(Socket, Local_Endpoint);
udp_tester 220
udp_tester 221 Put_Line("Waiting for payloads...");
udp_tester 222
udp_tester 223 -- endless, receiving loop
udp_tester 224 Receiving_Loop:
udp_tester 225 loop
udp_tester 226 -- receive a payload
udp_tester 227 UDP_Rcv.Receive(Socket, Received_Origin, Received_Payload, Received_Len);
udp_tester 228
udp_tester 229 -- log the received payload
udp_tester 230 -- -- get local, arrival time
udp_tester 231 TimeUTC := Ada.Calendar.Clock;
udp_tester 232 TimeUnix := Unsigned_32(TimeUTC - Epoch); -- local, arrival time
udp_tester 233
udp_tester 234 -- -- append to log file(s)
udp_tester 235 Open(File => OutFile, -- main log
udp_tester 236 Mode => Append_File,
udp_tester 237 Name => OutFileName);
udp_tester 238
udp_tester 239 Open(File => ErrFile, -- error log
udp_tester 240 Mode => Append_File,
udp_tester 241 Name => ErrFileName);
udp_tester 242
udp_tester 243 -- -- info from the received package itself
udp_tester 244 TimeSent := 0;
udp_tester 245 for I in 1..4 loop
udp_tester 246 TimeSent := Shift_Left(TimeSent, 8);
udp_tester 247 TimeSent := TimeSent + Unsigned_32(Received_Payload(I));
udp_tester 248 end loop;
udp_tester 249
udp_tester 250 SizeSent := Shift_Left(Unsigned_32(Received_Payload(5)), 8) +
udp_tester 251 Unsigned_32(Received_Payload(6));
udp_tester 252
udp_tester 253 Put(OutFile, Unsigned_32'Image(SizeSent));
udp_tester 254 Put(OutFile, "," & Unsigned_32'Image(TimeSent));
udp_tester 255
udp_tester 256 -- -- info from receiver end
udp_tester 257 Put(OutFile, "," & UDP_Rcv.IP_To_String(Received_Origin.Address));
udp_tester 258 Put(OutFile, "," & UDP_Rcv.IP_Port'Image(Received_Origin.Port));
udp_tester 259 Put(OutFile, "," & Unsigned_32'Image(Received_Len));
udp_tester 260 Put(OutFile, "," & Unsigned_32'Image(TimeUnix));
udp_tester 261
udp_tester 262 -- any octets that are different from expected (i.e. errors)
udp_tester 263 ErrCount := 0;
udp_tester 264 for I in Header_Len+1 .. Natural(Received_Len) loop
udp_tester 265 Expected := Unsigned_8(I mod 256);
udp_tester 266 if Received_Payload(I) /= Expected then
udp_tester 267 ErrCount := ErrCount + 1;
udp_tester 268
udp_tester 269 -- first time *only*, add all the package info as well
udp_tester 270 if ErrCount = 1 then
udp_tester 271 Put(ErrFile, Unsigned_32'Image(SizeSent));
udp_tester 272 Put(ErrFile, "," & Unsigned_32'Image(TimeSent));
udp_tester 273 Put(ErrFile, "," & UDP_Rcv.IP_To_String(Received_Origin.Address));
udp_tester 274 Put(ErrFile, "," & UDP_Rcv.IP_Port'Image(Received_Origin.Port));
udp_tester 275 Put(ErrFile, "," & Unsigned_32'Image(Received_Len));
udp_tester 276 Put(ErrFile, "," & Unsigned_32'Image(TimeUnix));
udp_tester 277 end if;
udp_tester 278
udp_tester 279 -- at all times: add the error details - position, received, expected
udp_tester 280 Put(ErrFile, "," & Natural'Image(I) & "," &
udp_tester 281 Unsigned_8'Image( Received_Payload(I) ) & "," &
udp_tester 282 Unsigned_8'Image( Expected )
udp_tester 283 );
udp_tester 284 end if;
udp_tester 285 end loop;
udp_tester 286 -- if there was at least an error, move to next line in error log
udp_tester 287 if ErrCount > 0 then
udp_tester 288 New_Line(File => ErrFile);
udp_tester 289 end if;
udp_tester 290
udp_tester 291 -- in all cases, record ErrCount in main log file too
udp_tester 292 Put_Line(OutFile, "," & Natural'Image(ErrCount));
udp_tester 293
udp_tester 294 -- logging done for this entry, close the log files
udp_tester 295 Close(File => OutFile);
udp_tester 296 Close(File => ErrFile);
udp_tester 297
udp_tester 298 Put_Line("Received payload from " &
udp_tester 299 UDP_Rcv.IP_To_String(Received_Origin.Address) &
udp_tester 300 " :" & UDP_Rcv.IP_Port'Image(Received_Origin.Port) &
udp_tester 301 " with length " & Unsigned_32'Image(Received_Len));
udp_tester 302
udp_tester 303 end loop Receiving_Loop; -- infinite, receiving loop
udp_tester 304
udp_tester 305 -- close the socket and tidy up
udp_tester 306 UDP_Rcv.Close_Socket(Socket);
udp_tester 307
udp_tester 308 end Receiver;
udp_tester 309
udp_tester 310 end UDP_Tester;