-
+ B7560776B05822024C15F66648C6EA0777A6EF23B817DF4418A8C52D1319F62F3348DB65E4EE905D4730ECBC2BCA800628F3FEC21D5E9AC62FDD5B293D1E9973
udp/udp_tester/udp_tester.adb
(0 . 0)(1 . 310)
282 -- UDP transmissions tester for the libUDP
283 -- S.MG, 2018
284
285 with Ada.Text_IO; use Ada.Text_IO;
286 with Ada.Calendar; use Ada.Calendar; -- for local time
287 with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones; -- UTC_Time_Offset
288 with Ada.Calendar.Formatting; use Ada.Calendar.Formatting; -- for unix-like
289 with Ada.Directories; use Ada.Directories; -- for log files checks
290 with Interfaces; use Interfaces; --Unsigned_8 for payload
291
292 with UDP;
293 with MT;
294
295 package body UDP_Tester is
296
297 procedure Create_If_Not_Exists( Filename: in String; Header: in String) is
298 F : File_Type;
299 begin
300 begin
301 Open(File => F, Mode => Append_File, Name => Filename);
302 Close(File => F);
303 exception
304 when Ada.Text_IO.Name_Error =>
305 Create( File => F, Mode => Out_File, Name => Filename);
306 Put_Line(F, Header);
307 Close(F);
308 Put_Line("Created file " & Filename);
309 end;
310 end Create_If_Not_Exists;
311
312 procedure Sender( Receiver_IP: in String;
313 Receiver_Port: in Unsigned_16;
314 Sender_Port: in Unsigned_16 ) is
315
316 -- payload sizes to choose from
317 Sizes : array(1..Max_Len-Header_Len+1) of Natural;
318 Len_Sizes : Natural := Sizes'Length;
319 Packet_Size : Positive;
320 Pos : Natural;
321
322 -- log file for sender
323 OutFile : File_Type;
324 OutFileName : constant String := "sender_udp_log.txt";
325 HeaderOutFile : constant String :=
326 "SizeSent" &
327 ",TimeSent" &
328 ",DestinationIP" &
329 ",DestinationPort" &
330 ",Seed";
331
332 -- seed for initialising the MT PRNG
333 Seed : constant MT.U32 := MT.U32(Ada.Calendar.Clock - Epoch);
334 begin
335 -- create log file and add header to it if it doesn't exist already
336 Create_If_Not_Exists( OutFileName, HeaderOutFile);
337
338 -- initialize MT rpng
339 MT.Init_Genrand(Seed);
340
341 -- initialize payload sizes to choose from
342 for I in Sizes'Range loop
343 Sizes(I) := I - 1;
344 end loop;
345
346 -- send packages in a loop
347 Sending_Loop:
348 while Len_Sizes > 0 loop
349
350 --a delay of 1 sec to avoid saturating the link with burst-mode
351 delay 1.0;
352
353 -- pick randomly one of the available sizes for payload
354 Pos := Natural(MT.Gen_U32 mod MT.U32(Len_Sizes)) + 1;
355 Packet_Size := Sizes( Pos ) + Header_Len;
356
357 -- shift available sizes to exclude the latest pick
358 if Pos<Len_Sizes and Len_Sizes>Sizes'First then
359 Sizes(Pos..Len_Sizes-1) := Sizes(Pos+1..Len_Sizes);
360 end if;
361 -- decrease length of available sizes
362 Len_Sizes := Len_Sizes - 1;
363
364 -- instantiate UDP sender of picked size and send packet
365 declare
366 K : constant Positive := Packet_Size;
367 -- sender will have *current* size of UDP packet
368 package UDP_Sdr is new UDP( Payload_Size => K );
369
370 -- socket, addr, port
371 Socket : UDP_Sdr.Socket;
372
373 Local_Endpoint : UDP_Sdr.Endpoint :=
374 (Address => UDP_Sdr.INADDR_ANY,
375 Port => Sender_Port);
376
377 Remote_Endpoint : UDP_Sdr.Endpoint :=
378 (Address => UDP_Sdr.IP_From_String(Receiver_IP),
379 Port => Receiver_Port);
380
381 Sent_Payload : UDP_Sdr.Payload;
382
383 TimeUTC : Ada.Calendar.Time;
384 TimeUnix : Interfaces.Unsigned_32;
385
386 begin
387 -- message to console
388 Put_Line("Sending packet Len_Sizes= " & Integer'Image(Len_Sizes) &
389 " with length " & Positive'Image(Sent_Payload'Length));
390
391 -- fill the payload, so starting after header octets
392 for I in (Sent_Payload'First + Header_Len) .. Sent_Payload'Last loop
393 Sent_Payload(I) := Interfaces.Unsigned_8(I mod 256);
394 end loop;
395
396 -- fill the header part
397 -- time (UTC): year, month, day, seconds since midnight (2 octets)
398 TimeUTC := Ada.Calendar.Clock;
399 TimeUnix := Interfaces.Unsigned_32(TimeUTC - Epoch);
400
401 Sent_Payload(Sent_Payload'First+3) := Interfaces.Unsigned_8(
402 TimeUnix mod 256 );
403 TimeUnix := Shift_Right(TimeUnix, 8);
404
405 Sent_Payload(Sent_Payload'First+2) := Interfaces.Unsigned_8(
406 TimeUnix mod 256 );
407 TimeUnix := Shift_Right(TimeUnix, 8);
408
409 Sent_Payload(Sent_Payload'First+1) := Interfaces.Unsigned_8(
410 TimeUnix mod 256 );
411 TimeUnix := Shift_Right(TimeUnix, 8);
412 Sent_Payload(Sent_Payload'First) := Interfaces.Unsigned_8(
413 TimeUnix mod 256 );
414
415
416 -- size of message (full, payload+header)
417 Sent_Payload(Sent_Payload'First + 4) := Interfaces.Unsigned_8(
418 Sent_Payload'Length / 256);
419
420 Sent_Payload(Sent_Payload'First + 5) := Interfaces.Unsigned_8(
421 Sent_Payload'Length mod 256);
422
423 -- send packet
424 UDP_Sdr.Open_Socket(Socket, Local_Endpoint);
425 UDP_Sdr.Transmit(Socket, Remote_Endpoint, Sent_Payload);
426 UDP_Sdr.Close_Socket(Socket);
427
428 -- log the packet
429 TimeUnix := Interfaces.Unsigned_32(TimeUTC - Epoch);
430
431 Open(File => OutFile,
432 Mode => Append_File,
433 Name => OutFileName);
434 Put(OutFile, Integer'Image(Sent_Payload'Length));
435 Put(OutFile, "," & Unsigned_32'Image(TimeUnix));
436 Put(OutFile, "," & Receiver_IP);
437 Put(OutFile, "," & Unsigned_16'Image(Receiver_Port));
438 Put_Line(OutFile, "," & MT.U32'Image(Seed));
439
440 Close(File => OutFile);
441 end;
442 end loop Sending_Loop;
443 end Sender;
444
445 procedure Receiver( Receiver_Port: in Unsigned_16 ) is
446 -- receiver HAS to have max len for UDP size; it doesn't know it in advance
447 package UDP_Rcv is new UDP( Payload_Size => Max_Len );
448
449 -- socket and local endpoint to receive on
450 Socket : UDP_Rcv.Socket;
451 Local_Endpoint : UDP_Rcv.Endpoint := (Address => UDP_Rcv.INADDR_ANY,
452 Port => Receiver_Port);
453
454 -- received payload and source information
455 Received_Payload : UDP_Rcv.Payload;
456 Received_Origin : UDP_Rcv.Endpoint;
457 Received_Len : Unsigned_32;
458
459 -- for logging
460 TimeUTC : Ada.Calendar.Time;
461 TimeUnix : Interfaces.Unsigned_32;
462 TimeSent : Interfaces.Unsigned_32;
463 SizeSent : Interfaces.Unsigned_32;
464 Expected : Interfaces.Unsigned_8; --one octet of payload
465 ErrCount : Natural;
466
467 -- log file
468 OutFile : File_Type;
469 ErrFile : File_Type;
470 OutFileName : constant String := "receiver_udp_log.txt";
471 ErrFileName : constant String := "receiver_udp_err_log.txt";
472 HeaderOutFile : constant String :=
473 "SizeSent" &
474 ",TimeSent" &
475 ",SourceIP" &
476 ",SourcePort" &
477 ",SizeReceived" &
478 ",TimeReceived" &
479 ",ErrorOctetsCount";
480 HeaderErrFile : constant String :=
481 "SizeSent" &
482 ",TimeSent" &
483 ",SourceIP" &
484 ",SourcePort" &
485 ",SizeReceived" &
486 ",TimeReceived" &
487 "(,Position" & --position in payload of err octet
488 ",ValueReceived" &
489 ",ValueExpected)*";
490
491 begin
492 -- create log files and add headers to them if they don't exist already
493 Create_If_Not_Exists( OutFileName, HeaderOutFile);
494 Create_If_Not_Exists( ErrFileName, HeaderErrFile);
495
496 Put_Line("Opening socket on local endpoint " &
497 UDP_Rcv.IP_To_String(Local_Endpoint.Address) &
498 " :" & UDP_Rcv.IP_Port'Image(Local_Endpoint.Port) & "...");
499
500 UDP_Rcv.Open_Socket(Socket, Local_Endpoint);
501
502 Put_Line("Waiting for payloads...");
503
504 -- endless, receiving loop
505 Receiving_Loop:
506 loop
507 -- receive a payload
508 UDP_Rcv.Receive(Socket, Received_Origin, Received_Payload, Received_Len);
509
510 -- log the received payload
511 -- -- get local, arrival time
512 TimeUTC := Ada.Calendar.Clock;
513 TimeUnix := Unsigned_32(TimeUTC - Epoch); -- local, arrival time
514
515 -- -- append to log file(s)
516 Open(File => OutFile, -- main log
517 Mode => Append_File,
518 Name => OutFileName);
519
520 Open(File => ErrFile, -- error log
521 Mode => Append_File,
522 Name => ErrFileName);
523
524 -- -- info from the received package itself
525 TimeSent := 0;
526 for I in 1..4 loop
527 TimeSent := Shift_Left(TimeSent, 8);
528 TimeSent := TimeSent + Unsigned_32(Received_Payload(I));
529 end loop;
530
531 SizeSent := Shift_Left(Unsigned_32(Received_Payload(5)), 8) +
532 Unsigned_32(Received_Payload(6));
533
534 Put(OutFile, Unsigned_32'Image(SizeSent));
535 Put(OutFile, "," & Unsigned_32'Image(TimeSent));
536
537 -- -- info from receiver end
538 Put(OutFile, "," & UDP_Rcv.IP_To_String(Received_Origin.Address));
539 Put(OutFile, "," & UDP_Rcv.IP_Port'Image(Received_Origin.Port));
540 Put(OutFile, "," & Unsigned_32'Image(Received_Len));
541 Put(OutFile, "," & Unsigned_32'Image(TimeUnix));
542
543 -- any octets that are different from expected (i.e. errors)
544 ErrCount := 0;
545 for I in Header_Len+1 .. Natural(Received_Len) loop
546 Expected := Unsigned_8(I mod 256);
547 if Received_Payload(I) /= Expected then
548 ErrCount := ErrCount + 1;
549
550 -- first time *only*, add all the package info as well
551 if ErrCount = 1 then
552 Put(ErrFile, Unsigned_32'Image(SizeSent));
553 Put(ErrFile, "," & Unsigned_32'Image(TimeSent));
554 Put(ErrFile, "," & UDP_Rcv.IP_To_String(Received_Origin.Address));
555 Put(ErrFile, "," & UDP_Rcv.IP_Port'Image(Received_Origin.Port));
556 Put(ErrFile, "," & Unsigned_32'Image(Received_Len));
557 Put(ErrFile, "," & Unsigned_32'Image(TimeUnix));
558 end if;
559
560 -- at all times: add the error details - position, received, expected
561 Put(ErrFile, "," & Natural'Image(I) & "," &
562 Unsigned_8'Image( Received_Payload(I) ) & "," &
563 Unsigned_8'Image( Expected )
564 );
565 end if;
566 end loop;
567 -- if there was at least an error, move to next line in error log
568 if ErrCount > 0 then
569 New_Line(File => ErrFile);
570 end if;
571
572 -- in all cases, record ErrCount in main log file too
573 Put_Line(OutFile, "," & Natural'Image(ErrCount));
574
575 -- logging done for this entry, close the log files
576 Close(File => OutFile);
577 Close(File => ErrFile);
578
579 Put_Line("Received payload from " &
580 UDP_Rcv.IP_To_String(Received_Origin.Address) &
581 " :" & UDP_Rcv.IP_Port'Image(Received_Origin.Port) &
582 " with length " & Unsigned_32'Image(Received_Len));
583
584 end loop Receiving_Loop; -- infinite, receiving loop
585
586 -- close the socket and tidy up
587 UDP_Rcv.Close_Socket(Socket);
588
589 end Receiver;
590
591 end UDP_Tester;