| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- {
- $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 11/10/2004 8:25:54 AM JPMugaas
- Fix for AV caused by short-circut boolean evaluation.
- Rev 1.37 27.08.2004 21:58:20 Andreas Hausladen
- Speed optimization ("const" for string parameters)
- Rev 1.36 8/2/04 5:44:40 PM RLebeau
- Moved ConnectTimeout over from TIdIOHandlerStack
- Rev 1.35 7/21/2004 12:22:32 PM BGooijen
- Fix to .connected
- Rev 1.34 6/30/2004 12:31:34 PM BGooijen
- Added OnSocketAllocated
- Rev 1.33 4/24/04 12:52:52 PM RLebeau
- Added setter method to UseNagle property
- Rev 1.32 2004.04.18 12:52:02 AM czhower
- Big bug fix with server disconnect and several other bug fixed that I found
- along the way.
- Rev 1.31 2004.02.03 4:16:46 PM czhower
- For unit name changes.
- Rev 1.30 2/2/2004 11:46:46 AM BGooijen
- Dotnet and TransparentProxy
- Rev 1.29 2/1/2004 9:44:00 PM JPMugaas
- Start on reenabling Transparant proxy.
- Rev 1.28 2004.01.20 10:03:28 PM czhower
- InitComponent
- Rev 1.27 1/2/2004 12:02:16 AM BGooijen
- added OnBeforeBind/OnAfterBind
- Rev 1.26 12/31/2003 9:51:56 PM BGooijen
- Added IPv6 support
- Rev 1.25 11/4/2003 10:37:40 PM BGooijen
- JP's patch to fix the bound port
- Rev 1.24 10/19/2003 5:21:26 PM BGooijen
- SetSocketOption
- Rev 1.23 10/18/2003 1:44:06 PM BGooijen
- Added include
- Rev 1.22 2003.10.14 1:26:54 PM czhower
- Uupdates + Intercept support
- Rev 1.21 10/9/2003 8:09:06 PM SPerry
- bug fixes
- Rev 1.20 8/10/2003 2:05:50 PM SGrobety
- Dotnet
- Rev 1.19 2003.10.07 10:18:26 PM czhower
- Uncommneted todo code that is now non dotnet.
- Rev 1.18 2003.10.02 8:23:42 PM czhower
- DotNet Excludes
- Rev 1.17 2003.10.01 9:11:18 PM czhower
- .Net
- Rev 1.16 2003.10.01 5:05:12 PM czhower
- .Net
- Rev 1.15 2003.10.01 2:46:38 PM czhower
- .Net
- Rev 1.14 2003.10.01 11:16:32 AM czhower
- .Net
- Rev 1.13 2003.09.30 1:22:58 PM czhower
- Stack split for DotNet
- Rev 1.12 7/4/2003 08:26:44 AM JPMugaas
- Optimizations.
- Rev 1.11 7/1/2003 03:39:44 PM JPMugaas
- Started numeric IP function API calls for more efficiency.
- Rev 1.10 2003.06.30 5:41:56 PM czhower
- -Fixed AV that occurred sometimes when sockets were closed with chains
- -Consolidated code that was marked by a todo for merging as it no longer
- needed to be separate
- -Removed some older code that was no longer necessary
- Passes bubble tests.
- Rev 1.9 6/3/2003 11:45:58 PM BGooijen
- Added .Connected
- Rev 1.8 2003.04.22 7:45:34 PM czhower
- Rev 1.7 4/2/2003 3:24:56 PM BGooijen
- Moved transparantproxy from ..stack to ..socket
- Rev 1.6 2/28/2003 9:51:56 PM BGooijen
- removed the field: FReadTimeout: Integer, it hided the one in TIdIOHandler
- Rev 1.5 2/26/2003 1:15:38 PM BGooijen
- FBinding is now freed in IdIOHandlerSocket, instead of in IdIOHandlerStack
- Rev 1.4 2003.02.25 1:36:08 AM czhower
- Rev 1.3 2002.12.07 12:26:26 AM czhower
- Rev 1.2 12-6-2002 20:09:14 BGooijen
- Changed SetDestination to search for the last ':', instead of the first
- Rev 1.1 12-6-2002 18:54:14 BGooijen
- Added IPv6-support
- Rev 1.0 11/13/2002 08:45:08 AM JPMugaas
- }
- unit IdIOHandlerSocket;
- interface
- {$I IdCompilerDefines.inc}
- uses
- Classes,
- IdCustomTransparentProxy,
- IdBaseComponent,
- IdGlobal,
- IdIOHandler,
- IdSocketHandle;
- const
- IdDefTimeout = 0;
- IdBoundPortDefault = 0;
- type
- {
- TIdIOHandlerSocket is the base class for socket IOHandlers that implement a
- binding.
- Descendants
- -TIdIOHandlerStack
- -TIdIOHandlerChain
- }
- TIdIOHandlerSocket = class(TIdIOHandler)
- protected
- FBinding: TIdSocketHandle;
- FBoundIP: string;
- FBoundPort: TIdPort;
- FBoundPortMax: TIdPort;
- FBoundPortMin: TIdPort;
- FDefaultPort: TIdPort;
- FOnBeforeBind: TNotifyEvent;
- FOnAfterBind: TNotifyEvent;
- FOnSocketAllocated: TNotifyEvent;
- {$IFDEF USE_OBJECT_ARC}[Weak]{$ENDIF} FTransparentProxy: TIdCustomTransparentProxy;
- FImplicitTransparentProxy: Boolean;
- FUseNagle: Boolean;
- FReuseSocket: TIdReuseSocket;
- FIPVersion: TIdIPVersion;
- //
- procedure ConnectClient; virtual;
- procedure DoBeforeBind; virtual;
- procedure DoAfterBind; virtual;
- procedure DoSocketAllocated; virtual;
- procedure InitComponent; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- function GetDestination: string; override;
- procedure SetDestination(const AValue: string); override;
- function GetReuseSocket: TIdReuseSocket;
- procedure SetReuseSocket(AValue: TIdReuseSocket);
- function GetTransparentProxy: TIdCustomTransparentProxy; virtual;
- procedure SetTransparentProxy(AProxy: TIdCustomTransparentProxy); virtual;
- function GetUseNagle: Boolean;
- procedure SetUseNagle(AValue: Boolean);
- //
- function SourceIsAvailable: Boolean; override;
- function CheckForError(ALastResult: Integer): Integer; override;
- procedure RaiseError(AError: Integer); override;
- public
- procedure AfterAccept; override;
- destructor Destroy; override;
- function BindingAllocated: Boolean;
- procedure Close; override;
- function Connected: Boolean; override;
- procedure Open; override;
- function WriteFile(const AFile: String; AEnableTransferFile: Boolean = False): Int64; override;
- //
- property Binding: TIdSocketHandle read FBinding;
- property BoundPortMax: TIdPort read FBoundPortMax write FBoundPortMax;
- property BoundPortMin: TIdPort read FBoundPortMin write FBoundPortMin;
- // events
- property OnBeforeBind: TNotifyEvent read FOnBeforeBind write FOnBeforeBind;
- property OnAfterBind: TNotifyEvent read FOnAfterBind write FOnAfterBind;
- property OnSocketAllocated: TNotifyEvent read FOnSocketAllocated write FOnSocketAllocated;
- published
- property BoundIP: string read FBoundIP write FBoundIP;
- property BoundPort: TIdPort read FBoundPort write FBoundPort default IdBoundPortDefault;
- property DefaultPort: TIdPort read FDefaultPort write FDefaultPort;
- property IPVersion: TIdIPVersion read FIPVersion write FIPVersion default ID_DEFAULT_IP_VERSION;
- property ReuseSocket: TIdReuseSocket read GetReuseSocket write SetReuseSocket default rsOSDependent;
- property TransparentProxy: TIdCustomTransparentProxy read GetTransparentProxy write SetTransparentProxy;
- property UseNagle: boolean read GetUseNagle write SetUseNagle default True;
- end;
- implementation
- uses
- //facilitate inlining only.
- {$IFDEF DOTNET}
- {$IFDEF USE_INLINE}
- System.IO,
- {$ENDIF}
- {$ENDIF}
- {$IFDEF WIN32_OR_WIN64 }
- Windows,
- {$ENDIF}
- SysUtils,
- IdStack,
- IdStackConsts,
- IdSocks;
- { TIdIOHandlerSocket }
- procedure TIdIOHandlerSocket.AfterAccept;
- begin
- inherited AfterAccept;
- FIPVersion := FBinding.IPVersion;
- end;
- procedure TIdIOHandlerSocket.Close;
- begin
- if FBinding <> nil then begin
- FBinding.CloseSocket;
- end;
- inherited Close;
- end;
- procedure TIdIOHandlerSocket.ConnectClient;
- var
- LBinding: TIdSocketHandle;
- begin
- LBinding := Binding;
- DoBeforeBind;
- // Allocate the socket
- LBinding.IPVersion := FIPVersion;
- LBinding.AllocateSocket;
- DoSocketAllocated;
- // Bind the socket
- if BoundIP <> '' then begin
- LBinding.IP := BoundIP;
- end;
- LBinding.Port := BoundPort;
- LBinding.ClientPortMin := BoundPortMin;
- LBinding.ClientPortMax := BoundPortMax;
- LBinding.ReuseSocket := FReuseSocket;
- // RLebeau 11/15/2014: Using the socket bind() function in a Mac OSX sandbox
- // causes the Apple store to reject an app with the following error if it
- // uses Indy client(s) and no Indy server(s):
- //
- // "This app uses one or more entitlements which do not have matching
- // functionality within the app. Apps should have only the minimum set of
- // entitlements necessary for the app to function properly. Please remove
- // all entitlements that are not needed by your app and submit an updated
- // binary for review, including the following:
- //
- // com.apple.security.network.server"
- //
- // Ideally, TIdSocketHandle.Bind() should not call TryBind() if the IP is
- // blank and the Port, ClientPortMin, and ClientPortMax are all 0. However,
- // TIdSocketHandle.Bind() is used for both clients and servers, and sometimes
- // a server needs to bind to port 0 to get a random ephemeral port, which it
- // can then report to clients. So lets do the check here instead, as this
- // method is only used for clients...
- {$IFDEF DARWIN}
- // TODO: remove the DARWIN check and just skip the Bind() on all platforms?
- if (LBinding.IP <> '') or (LBinding.Port <> 0) or
- ((LBinding.ClientPortMin <> 0) and (LBinding.ClientPortMax <> 0)) then
- begin
- LBinding.Bind;
- end;
- {$ELSE}
- LBinding.Bind;
- {$ENDIF}
- // Turn off Nagle if specified
- LBinding.UseNagle := FUseNagle;
- DoAfterBind;
- end;
- function TIdIOHandlerSocket.Connected: Boolean;
- begin
- Result := (BindingAllocated and inherited Connected) or (not InputBufferIsEmpty);
- end;
- destructor TIdIOHandlerSocket.Destroy;
- begin
- SetTransparentProxy(nil);
- FreeAndNil(FBinding);
- inherited Destroy;
- end;
- procedure TIdIOHandlerSocket.DoBeforeBind;
- begin
- if Assigned(FOnBeforeBind) then begin
- FOnBeforeBind(self);
- end;
- end;
- procedure TIdIOHandlerSocket.DoAfterBind;
- begin
- if Assigned(FOnAfterBind) then begin
- FOnAfterBind(self);
- end;
- end;
- procedure TIdIOHandlerSocket.DoSocketAllocated;
- begin
- if Assigned(FOnSocketAllocated) then begin
- FOnSocketAllocated(self);
- end;
- end;
- function TIdIOHandlerSocket.GetDestination: string;
- begin
- Result := Host;
- if (Port <> DefaultPort) and (Port > 0) then begin
- Result := Host + ':' + IntToStr(Port);
- end;
- end;
- procedure TIdIOHandlerSocket.Open;
- begin
- inherited Open;
- if not Assigned(FBinding) then begin
- FBinding := TIdSocketHandle.Create(nil);
- end else begin
- FBinding.Reset(True);
- end;
- FBinding.ClientPortMin := BoundPortMin;
- FBinding.ClientPortMax := BoundPortMax;
- //if the IOHandler is used to accept connections then port+host will be empty
- if (Host <> '') and (Port > 0) then begin
- ConnectClient;
- end;
- end;
- procedure TIdIOHandlerSocket.SetDestination(const AValue: string);
- var
- LPortStart: integer;
- begin
- // Bas Gooijen 06-Dec-2002: Changed to search the last ':', instead of the first:
- LPortStart := LastDelimiter(':', AValue);
- if LPortStart > 0 then begin
- Host := Copy(AValue, 1, LPortStart-1);
- Port := IndyStrToInt(Trim(Copy(AValue, LPortStart + 1, $FF)), DefaultPort);
- end;
- end;
- function TIdIOHandlerSocket.BindingAllocated: Boolean;
- begin
- Result := FBinding <> nil;
- if Result then begin
- Result := FBinding.HandleAllocated;
- end;
- end;
- function TIdIOHandlerSocket.WriteFile(const AFile: String;
- AEnableTransferFile: Boolean): Int64;
- //TODO: There is a way in linux to dump a file to a socket as well. use it.
- {$IFDEF WIN32_OR_WIN64}
- var
- LOldErrorMode : Integer;
- {$ENDIF}
- begin
- Result := 0;
- {$IFDEF WIN32_OR_WIN64}
- LOldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
- try
- {$ENDIF}
- if FileExists(AFile) then begin
- if Assigned(GServeFileProc) and (not WriteBufferingActive)
- {and (Intercept = nil)} and AEnableTransferFile
- then begin
- Result := GServeFileProc(Binding.Handle, AFile);
- Exit;
- end
- else
- begin
- Result := inherited WriteFile(AFile, AEnableTransferFile);
- end;
- end;
- {$IFDEF WIN32_OR_WIN64}
- finally
- SetErrorMode(LOldErrorMode)
- end;
- {$ENDIF}
- end;
- function TIdIOHandlerSocket.GetReuseSocket: TIdReuseSocket;
- begin
- if FBinding <> nil then begin
- Result := FBinding.ReuseSocket;
- end else begin
- Result := FReuseSocket;
- end;
- end;
- procedure TIdIOHandlerSocket.SetReuseSocket(AValue: TIdReuseSocket);
- begin
- FReuseSocket := AValue;
- if FBinding <> nil then begin
- FBinding.ReuseSocket := AValue;
- end;
- end;
- procedure TIdIOHandlerSocket.SetTransparentProxy(AProxy : TIdCustomTransparentProxy);
- var
- LClass: TIdCustomTransparentProxyClass;
- // under ARC, convert a weak reference to a strong reference before working with it
- LTransparentProxy: TIdCustomTransparentProxy;
- begin
- LTransparentProxy := FTransparentProxy;
- if LTransparentProxy <> AProxy then
- begin
- // All this is to preserve the compatibility with old version
- // In the case when we have SocksInfo as object created in runtime without owner form it is treated as temporary object
- // In the case when the ASocks points to an object with owner it is treated as component on form.
- // under ARC, all weak references to a freed object get nil'ed automatically
- if Assigned(AProxy) then begin
- if not Assigned(AProxy.Owner) then begin
- if Assigned(LTransparentProxy) and (not FImplicitTransparentProxy) then begin
- FTransparentProxy := nil;
- {$IFNDEF USE_OBJECT_ARC}
- LTransparentProxy.RemoveFreeNotification(Self);
- {$ENDIF}
- end;
- LClass := TIdCustomTransparentProxyClass(AProxy.ClassType);
- if Assigned(LTransparentProxy) and (LTransparentProxy.ClassType <> LClass) then begin
- FTransparentProxy := nil;
- FImplicitTransparentProxy := False;
- IdDisposeAndNil(LTransparentProxy);
- end;
- if not Assigned(LTransparentProxy) then begin
- LTransparentProxy := LClass.Create(Self);
- FTransparentProxy := LTransparentProxy;
- FImplicitTransparentProxy := True;
- end;
- LTransparentProxy.Assign(AProxy);
- end else begin
- if Assigned(LTransparentProxy) then begin
- if FImplicitTransparentProxy then begin
- FTransparentProxy := nil;
- FImplicitTransparentProxy := False;
- IdDisposeAndNil(LTransparentProxy);
- end else begin
- {$IFNDEF USE_OBJECT_ARC}
- LTransparentProxy.RemoveFreeNotification(Self);
- {$ENDIF}
- end;
- end;
- FTransparentProxy := AProxy;
- {$IFNDEF USE_OBJECT_ARC}
- AProxy.FreeNotification(Self);
- {$ENDIF}
- end;
- end
- else if Assigned(LTransparentProxy) then begin
- if FImplicitTransparentProxy then begin
- FTransparentProxy := nil;
- FImplicitTransparentProxy := False;
- IdDisposeAndNil(LTransparentProxy);
- end else begin
- FTransparentProxy := nil;
- {$IFNDEF USE_OBJECT_ARC}
- LTransparentProxy.RemoveFreeNotification(Self);
- {$ENDIF}
- end;
- end;
- end;
- end;
- function TIdIOHandlerSocket.GetTransparentProxy: TIdCustomTransparentProxy;
- var
- // under ARC, convert a weak reference to a strong reference before working with it
- LTransparentProxy: TIdCustomTransparentProxy;
- begin
- LTransparentProxy := FTransparentProxy;
- // Necessary at design time for Borland SOAP support
- if LTransparentProxy = nil then begin
- LTransparentProxy := TIdSocksInfo.Create(Self); //default
- FTransparentProxy := LTransparentProxy;
- FImplicitTransparentProxy := True;
- end;
- Result := LTransparentProxy;
- end;
- function TIdIOHandlerSocket.GetUseNagle: Boolean;
- begin
- if FBinding <> nil then begin
- Result := FBinding.UseNagle;
- end else begin
- Result := FUseNagle;
- end;
- end;
- procedure TIdIOHandlerSocket.SetUseNagle(AValue: Boolean);
- begin
- FUseNagle := AValue;
- if FBinding <> nil then begin
- FBinding.UseNagle := AValue;
- end;
- end;
- // under ARC, all weak references to a freed object get nil'ed automatically
- // so this is mostly redundant
- procedure TIdIOHandlerSocket.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FTransparentProxy) then begin
- FTransparentProxy := nil;
- FImplicitTransparentProxy := False;
- end;
- inherited Notification(AComponent, Operation);
- end;
- procedure TIdIOHandlerSocket.InitComponent;
- begin
- inherited InitComponent;
- FUseNagle := True;
- FIPVersion := ID_DEFAULT_IP_VERSION;
- end;
- function TIdIOHandlerSocket.SourceIsAvailable: Boolean;
- begin
- Result := BindingAllocated;
- end;
- function TIdIOHandlerSocket.CheckForError(ALastResult: Integer): Integer;
- begin
- Result := GStack.CheckForSocketError(ALastResult, [Id_WSAESHUTDOWN, Id_WSAECONNABORTED, Id_WSAECONNRESET, Id_WSAETIMEDOUT]);
- end;
- procedure TIdIOHandlerSocket.RaiseError(AError: Integer);
- begin
- GStack.RaiseSocketError(AError);
- end;
- end.
|