{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence                                   }
{ Team Coherence is Copyright 2002 by Quality Software Components      }
{                                                                      }
{ For further information / comments, visit our WEB site at            }
{ http://www.TeamCoherence.com                                         }
{**********************************************************************}
{}
{ $Log:  18311: TCPServer.pas }
{
{   Rev 1.18    2004.01.19 8:51:06 PM  czhower
{ No comment
}
{
{   Rev 1.17    2003.07.17 4:48:16 PM  czhower
{ Removed IdChainEngineStack
}
{
    Rev 1.16    7/14/2003 10:13:06 PM  BGooijen
  Added tcpserver test with IOCP
}
{
{   Rev 1.15    2003.07.11 4:07:46 PM  czhower
{ Removed deprecated BXBoxster reference.
}
{
{   Rev 1.14    2003.07.11 3:56:28 PM  czhower
{ Fixed to match changes in Indy.
}
{
{   Rev 1.13    6/24/2003 01:13:40 PM  JPMugaas
{ Updates for minor API change.
}
{
    Rev 1.12    6/4/2003 11:53:52 PM  BGooijen
  Removed tcpserver test with IOCP
}
{
    Rev 1.11    6/4/2003 9:40:28 PM  BGooijen
  Added tcpserver test with IOCP
}
{
    Rev 1.10    4/22/2003 11:50:52 PM  BGooijen
  Added Connect disconnect test
}
{
{   Rev 1.9    2003.04.22 4:12:04 PM  czhower
}
{
{   Rev 1.8    2003.04.16 8:20:14 PM  czhower
}
{
    Rev 1.7    4/16/2003 5:13:02 PM  BGooijen
}
{
{   Rev 1.6    2003.04.16 1:32:30 PM  czhower
}
{
{   Rev 1.5    2003.04.16 1:26:48 PM  czhower
}
{
    Rev 1.4    4/15/2003 8:28:50 PM  BGooijen
}
{
    Rev 1.3    4/15/2003 8:18:52 PM  BGooijen
}
{
    Rev 1.2    4/15/2003 8:12:54 PM  BGooijen
}
unit TCPServer;

interface

uses
  SysUtils, Classes, BXBubble, Forms, IdContext, IdServerIOHandler, IdScheduler,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

type
  TdmodTCPServer = class(TDataModule)
    TCPServer: TBXBubble;
    TCPServerPool: TBXBubble;
    TCPClient: TIdTCPClient;
    TCPServerFibersIOCP: TBXBubble;
    procedure TCPServerTest(Sender: TBXBubble);
    procedure TCPServerPoolTest(Sender: TBXBubble);
    procedure TCPServerFibersIOCPTest(Sender: TBXBubble);
  protected
    FBubble: TBXBubble;
    procedure DoClient(const APort: integer);
    procedure DoServer(const AIOHandler: TIdServerIOHandler; const AScheduler:TIdScheduler);
    procedure ServerExecute(AContext:TIdContext);
  public
  end;

var
  dmodTCPServer: TdmodTCPServer;

implementation
{$R *.dfm}

{ TdmodTCPServer }
uses
  IdCoreGlobal, IdTCPServer, IdServerIOHandlerChain, IdSchedulerOfFiber,
  IdSchedulerOfThreadPool, IdIOHandlerChain,
  BXGlobal;

procedure TdmodTCPServer.DoClient(const APort: integer);
var
  i, j: integer;
  LStream: TMemoryStream;
  LTime: LongWord;
begin
  FBubble.Check((APort = 6000) or (APort = 7000), 'Port mismatch.');
  with TCPClient do begin
    Port := APort;
    FBubble.Status('Connect and text test.');
    for i := 1 to 10 do begin
      FBubble.Status('  Test #' + IntToStr(i));
      Connect; try
        for j := 1 to 10 do begin
          SendCmd('Text ' + IntToStr(j), 200);
          FBubble.Check(StrToInt(IOHandler.ReadLn) = j * 2
           , 'Response string does not match.');
        end;
        SendCmd('Quit', 200);
      finally Disconnect; end;
    end;
    FBubble.Status('');
    FBubble.Status('Sized stream test.');
    Connect; try
      SendCmd('Stream', 200);
      LStream := TMemoryStream.Create; try
        LTime := Ticks;
todo;
//        IOHandler.ReadStream(LStream);
        LTime := Ticks - LTime;
        FBubble.Status(IntToStr(LStream.Size) + ' bytes read in ' + IntToStr(LTime));
      finally FreeAndNil(LStream); end;
      SendCmd('Quit', 200);
    finally Disconnect; end;
    FBubble.Status('Sized stream test complete.');
    FBubble.Status('');
    FBubble.Status('Unsized stream test.');
    Connect; try
      SendCmd('Stream Disconnect', 200);
      LStream := TMemoryStream.Create; try
        LTime := Ticks;
        IOHandler.ReadCardinal; // Throw away length byte
todo;
//        IOHandler.ReadStream(LStream, -1, True);
        LTime := Ticks - LTime;
        FBubble.Status(IntToStr(LStream.Size) + ' bytes read in ' + IntToStr(LTime));
      finally FreeAndNil(LStream); end;
    finally Disconnect; end;
    FBubble.Status('Unsized stream test complete.');
    FBubble.Status('');
    FBubble.Status('Connect disconnect test.');
    Connect;
    Disconnect;
    FBubble.Status('Connect disconnect test complete.');
  end;
end;

procedure TdmodTCPServer.ServerExecute(AContext:TIdContext);
var
  i: integer;
  s: string;
  LCmd: string;
  LParams: string;
  LStream: TMemoryStream;
begin
  with AContext.Connection do begin
    LParams := IOHandler.ReadLn;
    LCmd := Fetch(LParams);
    if AnsiSameText(LCmd, 'Text') then begin
      IOHandler.WriteLn('200 Ok');
      IOHandler.WriteLn(IntToStr(StrToInt(LParams) * 2));
    end else if AnsiSameText(LCmd, 'Stream') then begin
      IOHandler.WriteLn('200 Stream follows');
      SetLength(s, 256);
      for i := 0 to Length(s) - 1 do begin
        s[i + 1] := Chr(i and 255);
      end;
      LStream := TMemoryStream.Create; try
        LStream.SetSize(Length(s) * 4096); // 1MB
        for i := 1 to LStream.Size div Length(s) do begin
          LStream.WriteBuffer(s[1], Length(s));
        end;
todo;
//        AContext.Connection.IOHandler.WriteStream(LStream, 0, True);
      finally FreeAndNil(LStream); end;
      if AnsiSameText(LParams, 'Disconnect') then begin
        Disconnect;
      end;
    end else if AnsiSameText(LCmd, 'Quit') then begin
      IOHandler.WriteLn('200 Goodbye');
      Disconnect;
    end;
  end;
end;

procedure TdmodTCPServer.DoServer(const AIOHandler: TIdServerIOHandler; const AScheduler:TIdScheduler);
begin
  with TIdTCPServer.Create(nil) do try
    IOHandler := AIOHandler;
    Scheduler := AScheduler;
    DefaultPort := 6000;
    OnExecute := ServerExecute;
    Active := True;
    DoClient(Bindings[0].Port);

    FBubble.Status('Testing server reset.');
    Active := False;
    Active := True;
    DoClient(Bindings[0].Port);

    FBubble.Status('Testing multiple bindings.');
    Active := False;
    Bindings.Add.Port := 7000;
    Active := True;
    DoClient(7000);
  finally Free; end;
end;

procedure TdmodTCPServer.TCPServerTest(Sender: TBXBubble);
begin
  FBubble := Sender;
  DoServer(nil, nil);
end;

procedure TdmodTCPServer.TCPServerPoolTest(Sender: TBXBubble);
var
 LScheduler:TIdScheduler;
begin
  FBubble := Sender;
  LScheduler:=TIdSchedulerOfThreadPool.Create(nil);
  try
    DoServer(nil,LScheduler);
  finally
    FreeAndNil(LScheduler);
  end;
end;

procedure TdmodTCPServer.TCPServerFibersIOCPTest(Sender: TBXBubble);
var
 LIOHandler: TIdServerIOHandler;
 LScheduler:TIdScheduler;
begin
  FBubble := Sender;
  LIOHandler := TIdServerIOHandlerChain.Create(nil); try
    TIdServerIOHandlerChain(LIOHandler).ChainEngine
     := TIdChainEngine.Create(nil); try
      LScheduler:=TIdSchedulerOfFiber.Create(nil); try
        DoServer(LIOHandler,LScheduler);
      finally FreeAndNil(LScheduler); end;
    finally
      TIdServerIOHandlerChain(LIOHandler).ChainEngine.Free;
      TIdServerIOHandlerChain(LIOHandler).ChainEngine := nil;
    end;
  finally FreeAndNil(LIOHandler); end;
end;

end.
