program UdpSpd;

uses
  Crt,
  NumToStr,
  CoBase,
  CoIPv4,
  CoEth01,
  CoUdp,
  CoINET;


const

{$IFDEF VERMC}
  IoBase        = $2300;
{$ENDIF}
{$IFDEF VERPC}
  IoBase        = $300;
{$ENDIF}

  MaxBuffSize   = 1500;

type

  TTestProcedure = function ( ADev: PCoDevice ): Boolean;



  procedure RunTest( ATestProc: TTestProcedure );
  var
    Status    : TCoStatus;
    Dev       : PCoDevice;
    StartTime : TCoTime;
    StopTime  : TCoTime;
  begin
    Status := NetOpenSocket( 'UDP', 'LPORT=5000', '', Dev );

    if Status = CST_SUCCESS then
    begin

      Status := Dev^.CoBind( nil, COF_PROPAGATE, nil );

      if Status = CST_SUCCESS then
      begin
        StartTime := CoGetTime;

        WriteLn( 'Test running...' );

        if Assigned( ATestProc ) then ATestProc( Dev );

        StopTime  := CoGetTime;

        Write( 'Test stopped after ' );

        WriteLn( CoTimeDistMs(StopTime,  StartTime), 'ms' );

        Status := Dev^.CoUnbind( 0, nil );

        if Status <> CST_SUCCESS then
        begin
          WriteLn( 'CoUnbind() failed: ', Dev^.CoStatusToStr( Status ) );
        end;

        CoReleaseDevicePtr( Dev );
      end
      else begin
        WriteLn( 'CoBind() failed: ', Dev^.CoStatusToStr( Status ) );
        CoReleaseDevicePtr( Dev );
      end;

    end
    else begin
      WriteLn( 'NetOpenSocket() failed: ', CoStatusToStr( Status ) );
    end;

  end;



  function  SendTestProc( ADev: PCoDevice ): Boolean; far;
  const
    MaxPasses = 1024;

  var
    Address : TUdpAddress;
    Buffer  : array[0..MaxBuffSize - 1] of Byte;
    Status  : TCoStatus;
    Cnt     : Word;
  begin
    WriteLn( 'Sending ', MaxPasses, ' x ', MaxBuffSize, ' bytes');

    Address.Size := SizeOf( TUdpAddress );
    Address.Address := MakeIpAddr( 192, 168, 1, 8 );
    Address.Port := 5000;


    for Cnt := 1 to MaxPasses do
    begin

      Status := ADev^.CoSendBufferTo( @Buffer, SizeOf( Buffer ), 0,
                                      @Address, nil );


      if Status <> CST_SUCCESS then
      begin
        WriteLn( 'CoSendBufferTo() failed: ', ADev^.CoStatusToStr( Status ) );
        Exit;
      end;

    end;

  end;



  function  SendTestProcOvlp( ADev: PCoDevice ): Boolean; far;
  const


    MaxPasses = 1024;

  var
    Address : TUdpAddress;

    Buffer  : array[0..MaxBuffSize - 1] of Byte;
    Status  : TCoStatus;
    Cnt     : Word;

    Ovlp1   : TOverlapped;
    Ovlp2   : TOverlapped;
    Ovlp3   : TOverlapped;
  begin
    WriteLn( 'Sending 2 x', MaxPasses, ' x ', MaxBuffSize, ' bytes -- Overlapped');

    Address.Size := SizeOf( TUdpAddress );
    Address.Address := MakeIpAddr( 192, 168, 1, 8 );
    Address.Port := 5000;


    FillChar( Ovlp1, SizeOf( Ovlp1 ), 0 );
    FillChar( Ovlp2, SizeOf( Ovlp2 ), 0 );
    FillChar( Ovlp3, SizeOf( Ovlp2 ), 0 );


    for Cnt := 1 to MaxPasses do
    begin


      Status := ADev^.CoGetIOResult( @Ovlp3, COF_WAIT );


      Status := ADev^.CoSendBufferTo( @Buffer, SizeOf( Buffer ), 0,
                                      @Address, @Ovlp3 );


      Status := ADev^.CoGetIOResult( @Ovlp1, COF_WAIT );

      if Status <> CST_SUCCESS then
      begin
        WriteLn( 'CoSendBufferTo() failed: ', ADev^.CoStatusToStr( Status ) );
        Exit;
      end;

      Status := ADev^.CoSendBufferTo( @Buffer, SizeOf( Buffer ), 0,
                                      @Address, @Ovlp1 );


      Status := ADev^.CoGetIOResult( @Ovlp2, COF_WAIT );

      if Status <> CST_SUCCESS then
      begin
        WriteLn( 'CoSendBufferTo() failed: ', ADev^.CoStatusToStr( Status ) );
        Exit;
      end;


      Status := ADev^.CoSendBufferTo( @Buffer, SizeOf( Buffer ), 0,
                                      @Address, @Ovlp2 );




    end;

  end;


var

  OldExitProc : Pointer;

  procedure MyExitProc; far;
  begin
    if ExitCode <> 0 then
    begin
      WriteLn( 'ExitCode: ', ExitCode, ' Address: ', PtrToStr( ErrorAddr ) );
      repeat until False;
    end;
    ExitProc := OldExitProc;
  end;

var
  Status : TCoStatus;

begin

  OldExitProc := ExitProc;
  ExitProc := @MyExitProc;

  {$IFDEF VERPC}
  Status := NetOpenStack( 'ETH01', 'IOBASE=$300', 'IPADDR="192.168.1.210"', '' );
  {$ELSE}
  Status := NetOpenStack( 'ETH01', 'IOBASE=$2300', 'IPADDR="192.168.1.210"', '' );
  {$ENDIF}


  if Status = CST_SUCCESS then
  begin

    RunTest( SendTestProcOvlp );

    NetCloseStack( '' );
  end
  else begin
    WriteLn( 'NetOpenStack() failed: ', CoStatusToStr( Status ) );
  end;

{$IFDEF VERMC}
  repeat until False;
{$ENDIF}
end.