unit mainfrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient, ExtCtrls,
  StdCtrls, IdUDPServer;

type
  TForm1 = class(TForm)
    Timer: TTimer;
    UDPClient: TIdUDPClient;
    btnStart: TButton;
    btnStop: TButton;
    btnReset: TButton;
    gbStatistics: TGroupBox;
    txtErrors: TLabel;
    txtRecv: TLabel;
    txtSent: TLabel;
    lblSent: TLabel;
    lblRecv: TLabel;
    lblErrors: TLabel;
    gbHost: TGroupBox;
    edHost: TEdit;
    edHostPort: TEdit;
    lblHost: TLabel;
    lblHostPort: TLabel;
    gbLocalClient: TGroupBox;
    edLocalPort: TEdit;
    lblLocalPort: TLabel;
    edInterval: TEdit;
    Label1: TLabel;
    lblInterval: TLabel;
    edMaxPktSize: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    txtBytesSent: TLabel;
    Button1: TButton;
    procedure TimerTimer(Sender: TObject);
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnResetClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FSendEnable : Boolean;

    FCounterSent : Integer;
    FCounterRecv : Integer;
    FCounterErr  : Integer;
    FBytesSent   : Integer;

    FStop        : Boolean;

  public


  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.TimerTimer(Sender: TObject);
const
  cMaxLength = 4000;
var
  Buffer : array[0..cMaxLength] of Byte;
  RecvBuffer : array[0..cMaxLength] of Byte;
  RecvLen : Integer;
  Len    : Integer;
  I      : Integer;

  function MemCompare( Ptr1, Ptr2: PChar; Size: Integer ): Boolean;
  begin
    while (Size > 0) and (Ptr1^ = Ptr2^) do
    begin
      Inc( Ptr1 );
      Inc( Ptr2 );
      Dec( Size );
    end;
    Result := (Size = 0);
  end;


begin
  FStop := False;

  try
    if FSendEnable then
    begin
      Len := Random( StrToInt(edMaxPktSize.Text) ) + 1;
  {   Len := 3;}


      for I := 0 to Len - 1 do
      begin
        Buffer[I] := (Len + I) and 255;
      end;

      Inc( FBytesSent, Len );

      UDPClient.SendBuffer( edHost.Text, StrToInt( edHostPort.Text ), Buffer, Len );

      Inc( FCounterSent );

      txtSent.Caption := IntToStr( FCounterSent );
      txtBytesSent.Caption := IntToStr( FBytesSent );

      RecvLen := UDPClient.ReceiveBuffer( RecvBuffer, SizeOf( RecvBuffer ),  1000);

      if RecvLen > 0 then
      begin
        Inc( FCounterRecv );
        txtRecv.Caption := IntToStr( FCounterRecv );

        if (RecvLen = Len) and MemCompare( @Buffer, @RecvBuffer, Len ) then
        begin
          { OK }
        end
        else begin
          Inc( FCounterErr );
          txtErrors.Caption := IntToStr( FCounterErr );
        end;

      end;

    end;
  except
    btnStopClick(Self);
    raise;
  end;
end;

procedure TForm1.btnStartClick(Sender: TObject);
begin
  try
    UdpClient.Active := False;
    UdpClient.Port := StrToInt( edLocalPort.Text );
    btnStop.Enabled := True;
    btnStart.Enabled := False;
    edLocalPort.Enabled := False;
    edHostPort.Enabled := False;
    edHost.Enabled := False;
    edInterval.Enabled := False;
    FSendEnable := True;
    Timer.Interval := StrToInt( edInterval.Text );
    UdpClient.Active := True;
  except
    btnStopClick(Self);
    raise;
  end;
end;

procedure TForm1.btnStopClick(Sender: TObject);
begin
  btnStart.Enabled := True;
  btnStop.Enabled := False;
  edLocalPort.Enabled := True;
  edHostPort.Enabled := True;
  edHost.Enabled := True;
  edInterval.Enabled := True;
  FSendEnable := False;
  FStop := True;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FSendEnable := False;
  btnResetClick( Self );
end;

procedure TForm1.btnResetClick(Sender: TObject);
begin
  FCounterSent := 0;
  FCounterRecv := 0;
  FCounterErr  := 0;
  FBytesSent   := 0;

  txtSent.Caption := IntToStr( FCounterSent );
  txtRecv.Caption := IntToStr( FCounterRecv );
  txtErrors.Caption := IntToStr( FCounterErr );
  txtBytesSent.Caption := IntToStr( FBytesSent );
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  cMaxLength = 4000;
var
  Buffer : array[0..cMaxLength] of Byte;
  RecvBuffer : array[0..cMaxLength] of Byte;
  RecvLen : Integer;
  Len    : Integer;
  I      : Integer;

  function MemCompare( Ptr1, Ptr2: PChar; Size: Integer ): Boolean;
  begin
    while (Size > 0) and (Ptr1^ = Ptr2^) do
    begin
      Inc( Ptr1 );
      Inc( Ptr2 );
      Dec( Size );
    end;
    Result := (Size = 0);
  end;

begin

  btnStart.Enabled := False;
  btnStop.Enabled := True;

  repeat

     try
       Len := Random( StrToInt(edMaxPktSize.Text) ) + 1;
       for I := 0 to Len - 1 do
        begin
          Buffer[I] := (Len + I) and 255;
        end;

        Inc( FBytesSent, Len );

        UDPClient.SendBuffer( edHost.Text, StrToInt( edHostPort.Text ), Buffer, Len );

        Inc( FCounterSent );

        txtSent.Caption := IntToStr( FCounterSent );
        txtBytesSent.Caption := IntToStr( FBytesSent );

        RecvLen := UDPClient.ReceiveBuffer( RecvBuffer, SizeOf( RecvBuffer ),  1000);

        if RecvLen > 0 then
        begin
          Inc( FCounterRecv );
          txtRecv.Caption := IntToStr( FCounterRecv );

          if (RecvLen = Len) and MemCompare( @Buffer, @RecvBuffer, Len ) then
          begin
            { OK }
          end
          else begin
            Inc( FCounterErr );
            txtErrors.Caption := IntToStr( FCounterErr );
          end;

        end;

      except
        btnStopClick(Self);
        raise;
      end;

      Application.ProcessMessages;

  until fStop;

end;

end.
