www.pudn.com > indyprelim.zip > IdSimpleServer.pas


{
  $Project$
  $Workfile$
  $Revision$
  $DateUTC$
  $Id$

  This file is part of the Indy (Internet Direct) project, and is offered
  under the dual-licensing agreement described on the Indy website.
  (http://www.indyproject.org/)

  Copyright:
   (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
  $Log$
}
{
   Rev 1.17    7/13/04 6:46:36 PM  RLebeau
 Added support for BoundPortMin/Max propeties
}
{
   Rev 1.16    6/6/2004 12:49:40 PM  JPMugaas
 Removed old todo's for things that have already been done.
}
{
   Rev 1.15    5/6/2004 6:04:44 PM  JPMugaas
 Attempt to reenable TransparentProxy.Bind.
}
{
   Rev 1.14    5/5/2004 2:08:40 PM  JPMugaas
 Reenabled Socks Listen for TIdSimpleServer.
}
{
   Rev 1.13    2004.02.03 4:16:52 PM  czhower
 For unit name changes.
}
{
   Rev 1.12    2004.01.20 10:03:34 PM  czhower
 InitComponent
}
{
   Rev 1.11    1/2/2004 12:02:16 AM  BGooijen
 added OnBeforeBind/OnAfterBind
}
{
   Rev 1.10    1/1/2004 10:57:58 PM  BGooijen
 Added IPv6 support
}
{
   Rev 1.9    10/26/2003 10:08:44 PM  BGooijen
 Compiles in DotNet
}
{
   Rev 1.8    10/20/2003 03:04:56 PM  JPMugaas
 Should now work without Transparant Proxy.  That still needs to be enabled.
}
{
   Rev 1.7    2003.10.14 9:57:42 PM  czhower
 Compile todos
}
{
   Rev 1.6    2003.10.11 5:50:12 PM  czhower
 -VCL fixes for servers
 -Chain suport for servers (Super core)
 -Scheduler upgrades
 -Full yarn support
}
{
   Rev 1.5    2003.09.30 1:23:02 PM  czhower
 Stack split for DotNet
}
{
    Rev 1.4    5/16/2003 9:25:36 AM  BGooijen
  TransparentProxy support
}
{
    Rev 1.3    3/29/2003 5:55:04 PM  BGooijen
  now calls AfterAccept
}
{
    Rev 1.2    3/23/2003 11:24:46 PM  BGooijen
  changed cast from TIdIOHandlerStack to TIdIOHandlerSocket
}
{ 
   Rev 1.1    1-6-2003 21:39:00  BGooijen
 The handle to the listening socket was not closed when accepting a
 connection. This is fixed by merging the responsible code from 9.00.11

  Rev 1.0    11/13/2002 08:58:40 AM  JPMugaas
}
unit IdSimpleServer;

interface
{$i IdCompilerDefines.inc}
uses
  IdException,
  IdGlobal,
  IdSocketHandle,
  IdTCPConnection,
  IdObjs,
  IdStackConsts,
  IdIOHandler;

const
  ID_ACCEPT_WAIT = 1000;

type
  TIdSimpleServer = class(TIdTCPConnection)
  protected
    FAbortedRequested: Boolean;
    FAcceptWait: Integer;
    FBoundIP: String;
    FBoundPort: Integer;
    FBoundPortMin: Integer;
    FBoundPortMax: Integer;
    FIPVersion: TIdIPVersion;
    FListenHandle: TIdStackSocketHandle;
    FListening: Boolean;
    FOnBeforeBind: TIdNotifyEvent;
    FOnAfterBind: TIdNotifyEvent;
    //
    procedure Bind;
    procedure DoBeforeBind; virtual;
    procedure DoAfterBind; virtual;
    function GetIPVersion: TIdIPVersion;
    function GetBinding: TIdSocketHandle;
    procedure InitComponent; override;
    procedure SetIPVersion(const AValue: TIdIPVersion);
  public
    procedure Abort; virtual;
    procedure BeginListen; virtual;
    procedure CreateBinding;
    procedure EndListen; virtual;
    function Listen: Boolean; virtual;
    //
    property AcceptWait: Integer read FAcceptWait write FAcceptWait default ID_ACCEPT_WAIT;
  published
    property BoundIP: string read FBoundIP write FBoundIP;
    property BoundPort: Integer read FBoundPort write FBoundPort;
    property BoundPortMin: Integer read FBoundPortMin write FBoundPortMin;
    property BoundPortMax: Integer read FBoundPortMax write FBoundPortMax;
    property Binding: TIdSocketHandle read GetBinding;
    property IPVersion: TIdIPVersion read GetIPVersion write SetIPVersion;

    property OnBeforeBind:TIdNotifyEvent read FOnBeforeBind write FOnBeforeBind;
    property OnAfterBind:TIdNotifyEvent read FOnAfterBind write FOnAfterBind;
  end;

  EIdCannotUseNonSocketIOHandler = class(EIdException);

implementation

uses
  IdIOHandlerStack, IdIOHandlerSocket, IdStack;

{ TIdSimpleServer }

procedure TIdSimpleServer.Abort;
begin
  FAbortedRequested := True;
end;

procedure TIdSimpleServer.BeginListen;
begin
  if TIdIOHandlerSocket(IOHandler).TransparentProxy.Enabled then begin
    if Assigned(Binding) then
    begin
      TIdIOHandlerSocket(IOHandler).Binding.IP := BoundIP;
      TIdIOHandlerSocket(IOHandler).TransparentProxy.Bind(FIOHandler, BoundPort);
      TIdIOHandlerSocket(IOHandler).TransparentProxy.Listen(FIOHandler,15);
    end;
  end else begin
   // Must be before IOHandler as it resets it
   if not Assigned(Binding) then begin
      EndListen;
      CreateBinding;
    end;
    Bind;
    Binding.Listen(15);
  end;
  FListening := True;
end;

procedure TIdSimpleServer.Bind;
begin
  with Binding do begin
    try
      DoBeforeBind;
      IPVersion := FIPVersion;  // needs to be before AllocateSocket, because AllocateSocket uses this
      AllocateSocket;
      FListenHandle := Handle;
      IP := BoundIP;
      Port := BoundPort;
      ClientPortMin := BoundPortMin;
      ClientPortMax := BoundPortMax;
      Bind;
      DoAfterBind;
    except
      FListenHandle := Id_INVALID_SOCKET;
      raise;
    end;
  end;
end;

procedure TIdSimpleServer.CreateBinding;
begin
  if not assigned(IOHandler) then begin
    CreateIOHandler();
  end;
  IOHandler.Open;
end;

procedure TIdSimpleServer.DoBeforeBind;
begin
  if Assigned(FOnBeforeBind) then begin
    FOnBeforeBind(self);
  end;
end;

procedure TIdSimpleServer.DoAfterBind;
begin
  if Assigned(FOnAfterBind) then begin
    FOnAfterBind(self);
  end;
end;

procedure TIdSimpleServer.EndListen;
begin
  FAbortedRequested := False;
  FListening := False;
end;

function TIdSimpleServer.GetBinding: TIdSocketHandle;
begin
  Result := nil;
  if Assigned(IOHandler) then begin
    if IOHandler is TIdIOHandlerSocket then begin
      Result := TIdIOHandlerSocket(IOHandler).Binding;
    end;
  end;
end;

procedure TIdSimpleServer.SetIPVersion(const AValue: TIdIPVersion);
begin
  FIPVersion := AValue;
  if Assigned(IOHandler) then begin
    if IOHandler is TIdIOHandlerSocket then begin
      TIdIOHandlerSocket(IOHandler).IPVersion := AValue;
    end;
  end;
end;

function TIdSimpleServer.GetIPVersion: TIdIPVersion;
begin
  result := FIPVersion;
end;

function TIdSimpleServer.Listen: Boolean;
begin
  Assert(IOHandler<>nil);
  Result := False;
  if TIdIOHandlerSocket(IOHandler).TransparentProxy.Enabled then begin
    if not FListening then begin
      BeginListen;
    end;
    with Binding do begin
      if FAbortedRequested = False then begin
        while (FAbortedRequested = False) and (Result = False) do begin
          Result := TIdIOHandlerSocket(IOHandler).TransparentProxy.Listen(IOHandler,AcceptWait);
        end;
      end;
    end;
  end else begin
    if not FListening then begin
      BeginListen;
    end;
    with Binding do begin
      if FAbortedRequested = False then begin
        while (FAbortedRequested = False) and (Result = False) do begin
          Result := Select(AcceptWait);
        end;
      end;
      if Result then begin
        Binding.Listen(1);
        Binding.Accept(Binding.Handle);
        IOHandler.AfterAccept;
      end;

// This is now proteced. Disconnect replaces it - but it also calls shutdown.
// Im not sure we want to call shutdown here? Need to investigate before fixing
// this.
      GStack.Disconnect(FListenHandle);
      FListenHandle := Id_INVALID_SOCKET;
    end;
  end;
end;


procedure TIdSimpleServer.InitComponent;
begin
  inherited InitComponent;
  FAcceptWait := ID_ACCEPT_WAIT;
  FListenHandle := Id_INVALID_SOCKET;
end;

end.