{ $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.38 1/15/05 2:14:58 PM RLebeau Removed virtual specifier from SetConnectTimeout() and SetReadTimeout(), not being used by any descendants. Rev 1.37 11/29/2004 11:49:24 PM JPMugaas Fixes for compiler errors. Rev 1.36 11/29/04 10:38:58 AM RLebeau Updated Connect() to release the IOHandler on error if implicitally created. Rev 1.35 11/28/04 2:28:22 PM RLebeau Added 'const' to various property setter parameters. Removed redundant getter methods. Rev 1.34 11/27/2004 8:27:44 PM JPMugaas Fix for compiler errors. Rev 1.33 11/26/04 3:46:10 PM RLebeau Added support for BoundIP and BoundPort properties Rev 1.32 2004.11.05 10:58:34 PM czhower Changed connect overloads for C#. Rev 1.31 8/8/04 12:32:08 AM RLebeau Redeclared ReadTimeout and ConnectTimeout properties as public instead of protected in TIdTCPClientCustom Rev 1.30 8/4/2004 5:37:34 AM DSiders Changed camel-casing on ReadTimeout to be consistent with ConnectTimeout. Rev 1.29 8/3/04 11:17:30 AM RLebeau Added support for ReadTimeout property Rev 1.28 8/2/04 5:50:58 PM RLebeau Added support for ConnectTimeout property Rev 1.27 2004.03.06 10:40:28 PM czhower Changed IOHandler management to fix bug in server shutdowns. Rev 1.26 2004.02.03 4:16:54 PM czhower For unit name changes. Rev 1.25 1/8/2004 8:22:54 PM JPMugaas SetIPVersion now virtual so I can override in TIdFTP. Other stuff may need the override as well. Rev 1.24 1/2/2004 12:02:18 AM BGooijen added OnBeforeBind/OnAfterBind Rev 1.23 12/31/2003 9:52:04 PM BGooijen Added IPv6 support Rev 1.20 2003.10.14 1:27:00 PM czhower Uupdates + Intercept support Rev 1.19 2003.10.01 9:11:26 PM czhower .Net Rev 1.18 2003.10.01 2:30:42 PM czhower .Net Rev 1.17 2003.10.01 11:16:36 AM czhower .Net Rev 1.16 2003.09.30 1:23:06 PM czhower Stack split for DotNet Rev 1.15 2003.09.18 2:59:46 PM czhower Modified port and host overrides to only override if values exist. Rev 1.14 6/3/2003 11:48:32 PM BGooijen Undid change from version 1.12, is now fixed in iohandlersocket Rev 1.13 2003.06.03 7:27:56 PM czhower Added overloaded Connect method Rev 1.12 5/23/2003 6:45:32 PM BGooijen ClosedGracefully is now set if Connect failes. Rev 1.11 2003.04.10 8:05:34 PM czhower removed unneeded self. reference Rev 1.10 4/7/2003 06:58:32 AM JPMugaas Implicit IOHandler now created in virtual method function TIdTCPClientCustom.MakeImplicitClientHandler: TIdIOHandler; Rev 1.9 3/17/2003 9:40:16 PM BGooijen Host and Port were not properly synchronised with the IOHandler, fixed that Rev 1.8 3/5/2003 11:05:24 PM BGooijen Intercept Rev 1.7 2003.02.25 1:36:16 AM czhower Rev 1.6 12-14-2002 22:52:34 BGooijen now also saves host and port settings when an explicit iohandler is used. the host and port settings are copied to the iohandler if the iohandler doesn't have them specified. Rev 1.5 12-14-2002 22:38:26 BGooijen The host and port settings were lost when the implicit iohandler was created in .Connect, fixed that. Rev 1.4 2002.12.07 12:26:12 AM czhower Rev 1.2 12/6/2002 02:11:42 PM JPMugaas Protected Port and Host properties added to TCPClient because those are needed by protocol implementations. Socket property added to TCPConnection. Rev 1.1 6/12/2002 4:08:34 PM SGrobety Rev 1.0 11/13/2002 09:00:26 AM JPMugaas } unit IdTCPClient; {$i IdCompilerDefines.inc} interface uses Classes, IdGlobal, IdExceptionCore, IdIOHandler, IdTCPConnection; (*$HPPEMIT '#if defined(_VCL_ALIAS_RECORDS)' *) (*$HPPEMIT '#if !defined(UNICODE)' *) (*$HPPEMIT '#pragma alias "@Idtcpclient@TIdTCPClientCustom@SetPortA$qqrxus"="@Idtcpclient@TIdTCPClientCustom@SetPort$qqrxus"' *) (*$HPPEMIT '#else' *) (*$HPPEMIT '#pragma alias "@Idtcpclient@TIdTCPClientCustom@SetPortW$qqrxus"="@Idtcpclient@TIdTCPClientCustom@SetPort$qqrxus"' *) (*$HPPEMIT '#endif' *) (*$HPPEMIT '#endif' *) type TIdTCPClientCustom = class(TIdTCPConnection) protected FBoundIP: String; FBoundPort: TIdPort; FBoundPortMax: TIdPort; FBoundPortMin: TIdPort; FConnectTimeout: Integer; FDestination: string; FHost: string; FIPVersion: TIdIPVersion; FOnConnected: TNotifyEvent; FPassword: string; FPort: TIdPort; FReadTimeout: Integer; FUsername: string; FReuseSocket: TIdReuseSocket; FUseNagle: Boolean; // FOnBeforeBind: TNotifyEvent; FOnAfterBind: TNotifyEvent; FOnSocketAllocated: TNotifyEvent; // procedure DoOnConnected; virtual; function MakeImplicitClientHandler: TIdIOHandler; virtual; // procedure SetConnectTimeout(const AValue: Integer); procedure SetReadTimeout(const AValue: Integer); procedure SetReuseSocket(const AValue: TIdReuseSocket); procedure SetUseNagle(const AValue: Boolean); procedure SetBoundIP(const AValue: String); procedure SetBoundPort(const AValue: TIdPort); procedure SetBoundPortMax(const AValue: TIdPort); procedure SetBoundPortMin(const AValue: TIdPort); procedure SetHost(const AValue: string); virtual; procedure SetPort(const AValue: TIdPort); virtual; procedure SetIPVersion(const AValue: TIdIPVersion); virtual; // procedure SetOnBeforeBind(const AValue: TNotifyEvent); procedure SetOnAfterBind(const AValue: TNotifyEvent); procedure SetOnSocketAllocated(const AValue: TNotifyEvent); // procedure SetIOHandler(AValue: TIdIOHandler); override; procedure InitComponent; override; // function GetReadTimeout: Integer; function GetReuseSocket: TIdReuseSocket; function GetUseNagle: Boolean; // property Host: string read FHost write SetHost; property IPVersion: TIdIPVersion read FIPVersion write SetIPVersion; property Password: string read FPassword write FPassword; property Port: TIdPort read FPort write SetPort; property Username: string read FUsername write FUsername; public procedure Connect; overload; virtual; // This is overridden and not as default params so that descendants // do not have to worry about the arguments. // Also has been split further to allow usage from C# as it does not have optional // params procedure Connect(const AHost: string); overload; procedure Connect(const AHost: string; const APort: TIdPort); overload; function ConnectAndGetAll: string; virtual; // property BoundIP: string read FBoundIP write SetBoundIP; property BoundPort: TIdPort read FBoundPort write SetBoundPort default DEF_PORT_ANY; property BoundPortMax: TIdPort read FBoundPortMax write SetBoundPortMax default DEF_PORT_ANY; property BoundPortMin: TIdPort read FBoundPortMin write SetBoundPortMin default DEF_PORT_ANY; // property ConnectTimeout: Integer read FConnectTimeout write SetConnectTimeout; property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout; property ReuseSocket: TIdReuseSocket read GetReuseSocket write SetReuseSocket default rsOSDependent; property UseNagle: Boolean read GetUseNagle write SetUseNagle default True; // property OnBeforeBind: TNotifyEvent read FOnBeforeBind write SetOnBeforeBind; property OnAfterBind: TNotifyEvent read FOnAfterBind write SetOnAfterBind; property OnSocketAllocated: TNotifyEvent read FOnSocketAllocated write SetOnSocketAllocated; // published property OnConnected: TNotifyEvent read FOnConnected write FOnConnected; end; TIdTCPClient = class(TIdTCPClientCustom) published property BoundIP; property BoundPort; property ConnectTimeout; property Host; property IPVersion; property Port; property ReadTimeout; property ReuseSocket; property UseNagle; property OnBeforeBind; property OnAfterBind; property OnSocketAllocated; end; //Temp IFDEF till we change aliaser // Temp - reversed it for code freeze - will rereverse later. implementation uses IdComponent, IdResourceStringsCore, IdIOHandlerSocket; { TIdTCPClientCustom } procedure TIdTCPClientCustom.InitComponent; begin inherited InitComponent; FReadTimeOut := IdTimeoutDefault; FBoundPort := DEF_PORT_ANY; FBoundPortMin := DEF_PORT_ANY; FBoundPortMax := DEF_PORT_ANY; FUseNagle := True; end; procedure TIdTCPClientCustom.Connect; begin if Connected then begin raise EIdAlreadyConnected.Create(RSAlreadyConnected); end; if Host = '' then begin raise EIdHostRequired.Create('A Host is required'); {do not localize} end; if Port = 0 then begin raise EIdPortRequired.Create('A Port is required'); {do not localize} end; if IOHandler = nil then begin IOHandler := MakeImplicitClientHandler; // TODO: always assign the OnStatus event even if the IOHandler is not implicit? IOHandler.OnStatus := OnStatus; ManagedIOHandler := True; end; try // Bypass GetDestination if FDestination <> '' then begin IOHandler.Destination := FDestination; end; {BGO: not any more, TIdTCPClientCustom has precedence now (for port protocols, and things like that) // We retain the settings that are in here (filled in by the user) // we only do this when the iohandler has no settings, // because the iohandler has precedence if (IOHandler.Port = 0) and (IOHandler.Host = '') then begin IOHandler.Port := FPort; IOHandler.Host := FHost; end; } IOHandler.Port := FPort; //BGO: just to make sure IOHandler.Host := FHost; IOHandler.ConnectTimeout := FConnectTimeout; IOHandler.ReadTimeout := FReadTimeout; if Socket <> nil then begin Socket.BoundIP := FBoundIP; Socket.BoundPort := FBoundPort; Socket.BoundPortMin := FBoundPortMin; Socket.BoundPortMax := FBoundPortMax; Socket.IPVersion := FIPVersion; Socket.ReuseSocket := FReuseSocket; Socket.UseNagle := FUseNagle; Socket.OnBeforeBind := FOnBeforeBind; Socket.OnAfterBind := FOnAfterBind; Socket.OnSocketAllocated := FOnSocketAllocated; end; IOHandler.Open; if IOHandler.Intercept <> nil then begin IOHandler.Intercept.Connect(Self); end; DoStatus(hsConnected, [Host]); DoOnConnected; except if IOHandler <> nil then begin IOHandler.Close; if ManagedIOHandler then begin IOHandler := nil; // RLebeau - SetIOHandler() will free the IOHandler end; end; raise; end; end; function TIdTCPClientCustom.ConnectAndGetAll: string; begin Connect; try Result := IOHandler.AllData; finally Disconnect; end; end; procedure TIdTCPClientCustom.DoOnConnected; begin if Assigned(OnConnected) then begin OnConnected(Self); end; end; procedure TIdTCPClientCustom.SetConnectTimeout(const AValue: Integer); begin FConnectTimeout := AValue; if IOHandler <> nil then begin IOHandler.ConnectTimeout := AValue; end; end; procedure TIdTCPClientCustom.SetReadTimeout(const AValue: Integer); begin FReadTimeout := AValue; if IOHandler <> nil then begin IOHandler.ReadTimeout := AValue; end; end; procedure TIdTCPClientCustom.SetReuseSocket(const AValue: TIdReuseSocket); begin FReuseSocket := AValue; if Socket <> nil then begin Socket.ReuseSocket := AValue; end; end; procedure TIdTCPClientCustom.SetUseNagle(const AValue: Boolean); begin FUseNagle := AValue; if Socket <> nil then begin Socket.UseNagle := AValue; end; end; procedure TIdTCPClientCustom.SetBoundIP(const AValue: String); begin FBoundIP := AValue; if Socket <> nil then begin Socket.BoundIP := AValue; end; end; procedure TIdTCPClientCustom.SetBoundPort(const AValue: TIdPort); begin FBoundPort := AValue; if Socket <> nil then begin Socket.BoundPort := AValue; end; end; procedure TIdTCPClientCustom.SetBoundPortMax(const AValue: TIdPort); begin FBoundPortMax := AValue; if Socket <> nil then begin Socket.BoundPortMax := AValue; end; end; procedure TIdTCPClientCustom.SetBoundPortMin(const AValue: TIdPort); begin FBoundPortMin := AValue; if Socket <> nil then begin Socket.BoundPortMin := AValue; end; end; procedure TIdTCPClientCustom.SetHost(const AValue: string); begin FHost := AValue; if IOHandler <> nil then begin IOHandler.Host := AValue; end; end; procedure TIdTCPClientCustom.SetPort(const AValue: TIdPort); begin FPort := AValue; if IOHandler <> nil then begin IOHandler.Port := AValue; end; end; procedure TIdTCPClientCustom.SetIPVersion(const AValue: TIdIPVersion); begin FIPVersion := AValue; if Socket <> nil then begin Socket.IPVersion := AValue; end; end; procedure TIdTCPClientCustom.SetOnBeforeBind(const AValue: TNotifyEvent); begin FOnBeforeBind := AValue; if Socket <> nil then begin Socket.OnBeforeBind := AValue; end; end; procedure TIdTCPClientCustom.SetOnAfterBind(const AValue: TNotifyEvent); begin FOnAfterBind := AValue; if Socket <> nil then begin Socket.OnAfterBind := AValue; end; end; procedure TIdTCPClientCustom.SetOnSocketAllocated(const AValue: TNotifyEvent); begin FOnSocketAllocated := AValue; if Socket <> nil then begin Socket.OnSocketAllocated := AValue; end; end; procedure TIdTCPClientCustom.SetIOHandler(AValue: TIdIOHandler); begin inherited SetIOHandler(AValue); // TIdTCPClientCustom overrides settings in iohandler to initialize // protocol defaults. if IOHandler <> nil then begin IOHandler.Port := FPort; IOHandler.Host := FHost; IOHandler.ConnectTimeout := FConnectTimeout; IOHandler.ReadTimeout := FReadTimeout; end; if Socket <> nil then begin Socket.BoundIP := FBoundIP; Socket.BoundPort := FBoundPort; Socket.BoundPortMin := FBoundPortMin; Socket.BoundPortMax := FBoundPortMax; Socket.IPVersion := FIPVersion; Socket.ReuseSocket := FReuseSocket; Socket.UseNagle := FUseNagle; // TODO: use local event handlers that then trigger the user event handler if assigned Socket.OnBeforeBind := FOnBeforeBind; Socket.OnAfterBind := FOnAfterBind; Socket.OnSocketAllocated := FOnSocketAllocated; end; end; function TIdTCPClientCustom.MakeImplicitClientHandler: TIdIOHandler; begin Result := TIdIOHandler.MakeDefaultIOHandler(Self); end; procedure TIdTCPClientCustom.Connect(const AHost: string); begin Host := AHost; Connect; end; procedure TIdTCPClientCustom.Connect(const AHost: string; const APort: TIdPort); begin Host := AHost; Port := APort; Connect; end; function TIdTCPClientCustom.GetReadTimeout: Integer; begin if IOHandler <> nil then begin Result := IOHandler.ReadTimeout; end else begin Result := FReadTimeout; end; end; function TIdTCPClientCustom.GetReuseSocket: TIdReuseSocket; begin if Socket <> nil then begin Result := Socket.ReuseSocket; end else begin Result := FReuseSocket; end; end; function TIdTCPClientCustom.GetUseNagle: Boolean; begin if Socket <> nil then begin Result := Socket.UseNagle; end else begin Result := FUseNagle; end; end; end.