restemplate/indy/Protocols/IdMappedPortTCP.pas

440 lines
13 KiB
Plaintext
Raw Permalink Normal View History

{
$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.28 12/2/2004 4:23:54 PM JPMugaas
Adjusted for changes in Core.
Rev 1.27 11/15/04 11:32:22 AM RLebeau
Changed OutboundConnect() to assign the TIdTcpClient.ConnectTimeout property
instead of the IOHandler.ConnectTimeout property.
Rev 1.26 10/6/2004 10:22:12 PM BGooijen
Removed PEVerify errors in this unit
Rev 1.25 8/2/04 5:55:00 PM RLebeau
Updated TIdMappedPortContext.OutboundConnect() with ConnectTimeout property
change.
Rev 1.24 3/1/04 7:17:02 PM RLebeau
Minor correction to previous change
Rev 1.23 3/1/04 7:14:34 PM RLebeau
Updated TIdMappedPortContext.OutboundConnect() to call CreateIOHandler()
before attempting to use the outbound client's IOHandler property.
Rev 1.22 2004.02.03 5:43:58 PM czhower
Name changes
Rev 1.21 2/1/2004 4:23:32 AM JPMugaas
Should now compile in DotNET.
Rev 1.20 1/21/2004 3:11:30 PM JPMugaas
InitComponent
Rev 1.19 12/14/03 7:16:20 PM RLebeau
Typo fixes when accessing OutboudClient.IOHandler
Rev 1.18 2003.11.29 10:19:04 AM czhower
Updated for core change to InputBuffer.
Rev 1.17 2003.10.21 9:13:10 PM czhower
Now compiles.
Rev 1.16 10/19/2003 5:25:10 PM DSiders
Added localization comments.
Rev 1.15 2003.10.18 9:42:10 PM czhower
Boatload of bug fixes to command handlers.
Rev 1.14 2003.10.12 4:04:00 PM czhower
compile todos
Rev 1.13 9/19/2003 03:30:06 PM JPMugaas
Now should compile again.
Rev 1.12 04.06.2003 14:09:28 ARybin
updated for new IoHandler behavior
Rev 1.11 3/6/2003 5:08:46 PM SGrobety
Updated the read buffer methodes to fit the new core (InputBuffer ->
InputBufferAsString + call to CheckForDataOnSource)
Rev 1.10 28.05.2003 17:35:34 ARybin
right bug fix
Rev 1.9 28.05.2003 16:55:30 ARybin
bug fix
Rev 1.8 5/26/2003 12:23:46 PM JPMugaas
Rev 1.7 4/3/2003 7:26:10 PM BGooijen
Re-enabled .ConnectTimeout and .Connect
Rev 1.6 3/21/2003 11:45:36 AM JPMugaas
Added OnBeforeConnect method so the TIdMappedPort component is more flexible.
Rev 1.5 2/24/2003 09:14:38 PM JPMugaas
Rev 1.4 1/20/2003 1:15:32 PM BGooijen
Changed to TIdTCPServer / TIdCmdTCPServer classes
Rev 1.3 1/17/2003 06:45:12 PM JPMugaas
Now compiles with new framework.
Rev 1.2 1-8-2003 22:20:40 BGooijen
these compile (TIdContext)
Rev 1.1 12/7/2002 06:43:10 PM JPMugaas
These should now compile except for Socks server. IPVersion has to be a
property someplace for that.
Rev 1.0 11/13/2002 07:56:42 AM JPMugaas
2001-12-xx - Andrew P.Rybin
-new architecture
2002-02-02 - Andrew P.Rybin
-DoDisconnect fix
}
unit IdMappedPortTCP;
interface
{$i IdCompilerDefines.inc}
uses
Classes,
IdAssignedNumbers,
IdContext,
IdCustomTCPServer,
IdGlobal, IdStack, IdTCPConnection, IdTCPServer, IdYarn, SysUtils;
type
TIdMappedPortTCP = class;
TIdMappedPortContext = class(TIdServerContext)
protected
FOutboundClient: TIdTCPConnection;//was TIdTCPClient
FReadList: TIdSocketList;
FDataAvailList: TIdSocketList;
FConnectTimeOut: Integer;
FNetData: TIdBytes;
FServer : TIdMappedPortTCP;
//
procedure CheckForData(DoRead: Boolean); virtual;
procedure HandleLocalClientData; virtual;
procedure HandleOutboundClientData; virtual;
procedure OutboundConnect; virtual;
public
constructor Create(
AConnection: TIdTCPConnection;
AYarn: TIdYarn;
AList: TIdContextThreadList = nil
); override;
destructor Destroy; override;
//
property Server : TIdMappedPortTCP Read FServer write FServer;
property ConnectTimeOut: Integer read FConnectTimeOut write FConnectTimeOut default IdTimeoutDefault;
property NetData: TIdBytes read FNetData write FNetData;
property OutboundClient: TIdTCPConnection read FOutboundClient write FOutboundClient;
end;//TIdMappedPortContext
TIdMappedPortTCP = class(TIdCustomTCPServer)
protected
FMappedHost: string;
FMappedPort: TIdPort;
FOnBeforeConnect: TIdServerThreadEvent;
//AThread.Connection.Server & AThread.OutboundClient
FOnOutboundConnect: TIdServerThreadEvent;
FOnOutboundData: TIdServerThreadEvent;
FOnOutboundDisConnect: TIdServerThreadEvent;
//
procedure ContextCreated(AContext:TIdContext); override;
procedure DoBeforeConnect(AContext: TIdContext); virtual;
procedure DoConnect(AContext: TIdContext); override;
function DoExecute(AContext: TIdContext): boolean; override;
procedure DoDisconnect(AContext: TIdContext); override; //DoLocalClientDisconnect
procedure DoLocalClientConnect(AContext: TIdContext); virtual;
procedure DoLocalClientData(AContext: TIdContext); virtual;//APR: bServer
procedure DoOutboundClientConnect(AContext: TIdContext); virtual;
procedure DoOutboundClientData(AContext: TIdContext); virtual;
procedure DoOutboundDisconnect(AContext: TIdContext); virtual;
function GetOnConnect: TIdServerThreadEvent;
function GetOnExecute: TIdServerThreadEvent;
procedure SetOnConnect(const Value: TIdServerThreadEvent);
procedure SetOnExecute(const Value: TIdServerThreadEvent);
function GetOnDisconnect: TIdServerThreadEvent;
procedure SetOnDisconnect(const Value: TIdServerThreadEvent);
procedure InitComponent; override;
published
property OnBeforeConnect: TIdServerThreadEvent read FOnBeforeConnect write FOnBeforeConnect;
property MappedHost: String read FMappedHost write FMappedHost;
property MappedPort: TIdPort read FMappedPort write FMappedPort;
//
property OnConnect: TIdServerThreadEvent read GetOnConnect write SetOnConnect; //OnLocalClientConnect
property OnOutboundConnect: TIdServerThreadEvent read FOnOutboundConnect write FOnOutboundConnect;
property OnExecute: TIdServerThreadEvent read GetOnExecute write SetOnExecute;//OnLocalClientData
property OnOutboundData: TIdServerThreadEvent read FOnOutboundData write FOnOutboundData;
property OnDisconnect: TIdServerThreadEvent read GetOnDisconnect write SetOnDisconnect;//OnLocalClientDisconnect
property OnOutboundDisconnect: TIdServerThreadEvent read FOnOutboundDisconnect write FOnOutboundDisconnect;
End;//TIdMappedPortTCP
Implementation
uses
IdException,
IdIOHandler, IdIOHandlerSocket, IdResourceStrings,IdStackConsts, IdTCPClient;
procedure TIdMappedPortTCP.InitComponent;
begin
inherited InitComponent;
FContextClass := TIdMappedPortContext;
end;
procedure TIdMappedPortTCP.ContextCreated(AContext: TIdContext);
begin
TIdMappedPortContext(AContext).Server := Self;
end;
procedure TIdMappedPortTCP.DoBeforeConnect(AContext: TIdContext);
begin
if Assigned(FOnBeforeConnect) then begin
FOnBeforeConnect(AContext);
end;
end;
procedure TIdMappedPortTCP.DoLocalClientConnect(AContext: TIdContext);
begin
if Assigned(FOnConnect) then begin
FOnConnect(AContext);
end;
end;
procedure TIdMappedPortTCP.DoOutboundClientConnect(AContext: TIdContext);
begin
if Assigned(FOnOutboundConnect) then begin
FOnOutboundConnect(AContext);
end;
end;
procedure TIdMappedPortTCP.DoLocalClientData(AContext: TIdContext);
begin
if Assigned(FOnExecute) then begin
FOnExecute(AContext);
end;
end;
procedure TIdMappedPortTCP.DoOutboundClientData(AContext: TIdContext);
begin
if Assigned(FOnOutboundData) then begin
FOnOutboundData(AContext);
end;
end;
procedure TIdMappedPortTCP.DoDisconnect(AContext: TIdContext);
begin
inherited DoDisconnect(AContext);
//check for loop
if Assigned(TIdMappedPortContext(AContext).FOutboundClient) and
TIdMappedPortContext(AContext).FOutboundClient.Connected then
begin
TIdMappedPortContext(AContext).FOutboundClient.Disconnect;
end;
end;
procedure TIdMappedPortTCP.DoOutboundDisconnect(AContext: TIdContext);
begin
if Assigned(FOnOutboundDisconnect) then begin
FOnOutboundDisconnect(AContext);
end;
AContext.Connection.Disconnect; //disconnect local
end;
procedure TIdMappedPortTCP.DoConnect(AContext: TIdContext);
var
LContext: TIdMappedPortContext;
begin
DoBeforeConnect(AContext);
LContext := TIdMappedPortContext(AContext);
//WARNING: Check TIdTCPServer.DoConnect and synchronize code. Don't call inherited!=> OnConnect in OutboundConnect {Do not Localize}
LContext.OutboundConnect;
//cache
LContext.FReadList.Clear;
LContext.FReadList.Add(AContext.Connection.Socket.Binding.Handle);
LContext.FReadList.Add(LContext.FOutboundClient.Socket.Binding.Handle);
end;
function TIdMappedPortTCP.DoExecute(AContext: TIdContext): Boolean;
var
LContext: TIdMappedPortContext;
begin
LContext := TIdMappedPortContext(AContext);
try
LContext.CheckForData(True);
finally
if not LContext.FOutboundClient.Connected then begin
Result := False;
DoOutboundDisconnect(AContext); //&Connection.Disconnect
end else begin;
Result := AContext.Connection.Connected;
end;
end;
end;
function TIdMappedPortTCP.GetOnConnect: TIdServerThreadEvent;
begin
Result := FOnConnect;
end;
function TIdMappedPortTCP.GetOnExecute: TIdServerThreadEvent;
begin
Result := FOnExecute;
end;
function TIdMappedPortTCP.GetOnDisconnect: TIdServerThreadEvent;
begin
Result := FOnDisconnect;
end;
procedure TIdMappedPortTCP.SetOnConnect(const Value: TIdServerThreadEvent);
begin
FOnConnect := Value;
end;
procedure TIdMappedPortTCP.SetOnExecute(const Value: TIdServerThreadEvent);
begin
FOnExecute := Value;
end;
procedure TIdMappedPortTCP.SetOnDisconnect(const Value: TIdServerThreadEvent);
begin
FOnDisconnect := Value;
end;
{ TIdMappedPortContext }
constructor TIdMappedPortContext.Create(
AConnection: TIdTCPConnection;
AYarn: TIdYarn;
AList: TIdContextThreadList = nil
);
begin
inherited Create(AConnection, AYarn, AList);
FReadList := TIdSocketList.CreateSocketList;
FDataAvailList := TIdSocketList.CreateSocketList;
FConnectTimeOut := IdTimeoutDefault;
end;
destructor TIdMappedPortContext.Destroy;
begin
FreeAndNil(FOutboundClient);
FreeAndNIL(FReadList);
FreeAndNIL(FDataAvailList);
inherited Destroy;
end;
procedure TIdMappedPortContext.CheckForData(DoRead: Boolean);
begin
if DoRead and Connection.IOHandler.InputBufferIsEmpty and FOutboundClient.IOHandler.InputBufferIsEmpty then
begin
if FReadList.SelectReadList(FDataAvailList, IdTimeoutInfinite) then
begin
//1.LConnectionHandle
if FDataAvailList.ContainsSocket(Connection.Socket.Binding.Handle) then
begin
// TODO: WSAECONNRESET (Exception [EIdSocketError] Socket Error # 10054 Connection reset by peer)
Connection.IOHandler.CheckForDataOnSource(0);
end;
//2.LOutBoundHandle
if FDataAvailList.ContainsSocket(FOutboundClient.Socket.Binding.Handle) then
begin
FOutboundClient.IOHandler.CheckForDataOnSource(0);
end;
end;
end;
if not Connection.IOHandler.InputBufferIsEmpty then
begin
HandleLocalClientData;
end;
if not FOutboundClient.IOHandler.InputBufferIsEmpty then
begin
HandleOutboundClientData;
end;
Connection.IOHandler.CheckForDisconnect;
FOutboundClient.IOHandler.CheckForDisconnect;
end;
procedure TIdMappedPortContext.HandleLocalClientData;
begin
SetLength(FNetData, 0);
Connection.IOHandler.InputBuffer.ExtractToBytes(FNetData);
Server.DoLocalClientData(Self);
FOutboundClient.IOHandler.Write(FNetData);
end;
procedure TIdMappedPortContext.HandleOutboundClientData;
begin
SetLength(FNetData, 0);
FOutboundClient.IOHandler.InputBuffer.ExtractToBytes(FNetData);
Server.DoOutboundClientData(Self);
Connection.IOHandler.Write(FNetData);
end;
procedure TIdMappedPortContext.OutboundConnect;
var
LServer: TIdMappedPortTCP;
LClient: TIdTCPClient;
begin
FOutboundClient := TIdTCPClient.Create(nil);
LServer := TIdMappedPortTCP(Server);
try
LClient := TIdTCPClient(FOutboundClient);
LClient.Port := LServer.MappedPort;
LClient.Host := LServer.MappedHost;
LServer.DoLocalClientConnect(Self);
LClient.ConnectTimeout := FConnectTimeOut;
LClient.Connect;
LServer.DoOutboundClientConnect(Self);
//APR: buffer can contain data from prev (users) read op.
CheckForData(False);
except
on E: Exception do
begin
DoException(E);// DONE: Handle connect failures
Connection.Disconnect; //req IdTcpServer with "Stop this thread if we were disconnected"
raise;
end;
end;
end;
end.