Thanks Michael and Andrew. Michael Van Canneyt wrote: > I plan a set of socket options in TSocketServer; > I have the same problem as you, I just need a free moment to > implement it :-)
Great, then I'll wait for your implementation. I've done some changes in my local copy to get things working until better implementation is ready. In case you are interested I'm attaching a diff of these changes (sorry, they got mixed with my earlier patch for #20370) > Configurable seems like the best option. In the attached diff there is boolean ReuseAddress property for TCustomHTTPApplication. The drawback of this approach is that it's not uniform with TCustomFCgiApplication.ProtocolOptions (serving the same purpose for FCGI application). The advantage is that it does not declare new data structures and thus does not force us to add more lower-level units into main program's uses clause.
Index: src/base/custhttpapp.pp =================================================================== --- src/base/custhttpapp.pp (revision 19236) +++ src/base/custhttpapp.pp (working copy) @@ -43,10 +43,12 @@ function GetAllowConnect: TConnectQuery; function GetPort: Word; function GetQueueSize: Word; + function GetReuseAddress: Boolean; function GetThreaded: Boolean; procedure SetOnAllowConnect(const AValue: TConnectQuery); procedure SetPort(const AValue: Word); procedure SetQueueSize(const AValue: Word); + procedure SetReuseAddress(AValue: Boolean); procedure SetThreaded(const AValue: Boolean); protected function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; override; @@ -64,6 +66,8 @@ Property OnAllowConnect : TConnectQuery Read GetAllowConnect Write SetOnAllowConnect; // Use a thread to handle a connection ? property Threaded : Boolean read GetThreaded Write SetThreaded; + // Reuse socket address on Unix platforms (enables SO_REUSEADDR socket option) + property ReuseAddress : Boolean Read GetReuseAddress Write SetReuseAddress; end; { TCustomHTTPApplication } @@ -73,10 +77,12 @@ function GetAllowConnect: TConnectQuery; function GetPort: Word; function GetQueueSize: Word; + function GetReuseAddress: Boolean; function GetThreaded: Boolean; procedure SetOnAllowConnect(const AValue: TConnectQuery); procedure SetPort(const AValue: Word); procedure SetQueueSize(const AValue: Word); + procedure SetReuseAddress(const AValue: Boolean); procedure SetThreaded(const AValue: Boolean); protected function InitializeWebHandler: TWebHandler; override; @@ -89,6 +95,8 @@ Property OnAllowConnect : TConnectQuery Read GetAllowConnect Write SetOnAllowConnect; // Use a thread to handle a connection ? property Threaded : Boolean read GetThreaded Write SetThreaded; + // Reuse socket address on Unix platforms (enables SO_REUSEADDR socket option) + property ReuseAddress : Boolean Read GetReuseAddress Write SetReuseAddress; end; ResourceString @@ -124,6 +132,11 @@ Result:=HTTPHandler.QueueSize; end; +function TCustomHTTPApplication.GetReuseAddress: Boolean; +begin + Result:=HTTPHandler.ReuseAddress; +end; + function TCustomHTTPApplication.GetThreaded: Boolean; begin Result:=HTTPHandler.Threaded; @@ -144,6 +157,11 @@ HTTPHandler.QueueSize:=Avalue; end; +procedure TCustomHTTPApplication.SetReuseAddress(const AValue: Boolean); +begin + HTTPHandler.ReuseAddress := AValue; +end; + procedure TCustomHTTPApplication.SetThreaded(const AValue: Boolean); begin HTTPHandler.Threaded:=Avalue; @@ -190,6 +208,11 @@ Result:=FServer.QueueSize; end; +function TFPHTTPServerHandler.GetReuseAddress: Boolean; +begin + Result:=FServer.ReuseAddress; +end; + function TFPHTTPServerHandler.GetThreaded: Boolean; begin Result:=FServer.Threaded; @@ -210,6 +233,11 @@ FServer.QueueSize:=Avalue end; +procedure TFPHTTPServerHandler.SetReuseAddress(AValue: Boolean); +begin + FServer.ReuseAddress:=AValue; +end; + procedure TFPHTTPServerHandler.SetThreaded(const AValue: Boolean); begin FServer.Threaded:=AValue; Index: src/base/fphttpserver.pp =================================================================== --- src/base/fphttpserver.pp (revision 19236) +++ src/base/fphttpserver.pp (working copy) @@ -20,7 +20,7 @@ interface uses - Classes, SysUtils, ssockets, httpdefs; + Classes, SysUtils, sockets, ssockets, resolve, httpdefs; Const ReadBufLen = 4096; @@ -35,8 +35,12 @@ TFPHTTPConnectionRequest = Class(TRequest) private FConnection: TFPHTTPConnection; + FRemoteAddress: String; + FServerPort: String; protected + function GetFieldValue(AIndex : Integer) : String; override; procedure SetContent(AValue : String); + procedure SetFieldValue(Index : Integer; Value : String); override; published Property Connection : TFPHTTPConnection Read FConnection; end; @@ -100,6 +104,7 @@ FOnRequest: THTTPServerRequestHandler; FPort: Word; FQueueSize: Word; + FReuseAddress: Boolean; FServer : TInetServer; FLoadActivate : Boolean; FServerBanner: string; @@ -109,6 +114,7 @@ procedure SetOnAllowConnect(const AValue: TConnectQuery); procedure SetPort(const AValue: Word); procedure SetQueueSize(const AValue: Word); + procedure SetReuseAddress(AValue: Boolean); procedure SetThreaded(const AValue: Boolean); Protected // Create a connection handling object. @@ -140,6 +146,8 @@ Property OnAllowConnect : TConnectQuery Read FOnAllowConnect Write SetOnAllowConnect; // Use a thread to handle a connection ? property Threaded : Boolean read FThreaded Write SetThreaded; + // Reuse socket address on Unix platforms (enables SO_REUSEADDR socket option) + property ReuseAddress : Boolean read FReuseAddress Write SetReuseAddress; // Called to handle the request. If Threaded=True, it is called in a the connection thread. Property OnRequest : THTTPServerRequestHandler Read FOnRequest Write FOnRequest; @@ -221,6 +229,41 @@ end; end; +Function SocketAddrToString(ASocketAddr: TSockAddr): String; +begin + if ASocketAddr.sa_family = AF_INET then + Result := NetAddrToStr(ASocketAddr.sin_addr) + else // no ipv6 support yet + Result := ''; +end; + +Function GetHostNameByAddress(const AnAddress: String): String; +var + Resolver: THostResolver; +begin + Result := ''; + if AnAddress = '' then exit; + + Resolver := THostResolver.Create(nil); + try + if Resolver.AddressLookup(AnAddress) then + Result := Resolver.ResolvedName + finally + FreeAndNil(Resolver); + end; +end; + +function TFPHTTPConnectionRequest.GetFieldValue(AIndex: Integer): String; +begin + case AIndex of + 27 : Result := FRemoteAddress; + 28 : Result := GetHostNameByAddress(FRemoteAddress); // Remote Host + 30 : Result := FServerPort; + else + Result := inherited GetFieldValue(AIndex); + end; +end; + procedure TFPHTTPConnectionRequest.SetContent(AValue : String); begin @@ -228,6 +271,17 @@ FContentRead:=true; InitRequestVars; end; + +procedure TFPHTTPConnectionRequest.SetFieldValue(Index: Integer; Value: String); +begin + case Index of + 27 : FRemoteAddress := Value; + 30 : FServerPort := Value; + else + inherited SetFieldValue(Index, Value); + end; +end; + (* Procedure TFPHTTPConnectionRequest.SetFieldValue(Index : Integer; Value : String); @@ -437,6 +491,9 @@ if (S<>'') then InterPretHeader(Result,S); Until (S=''); + + Result.RemoteAddress := SocketAddrToString(FSocket.RemoteAddress); + Result.ServerPort := FServer.Port; end; constructor TFPHTTPConnection.Create(AServer: TFPCustomHttpServer; ASocket: TSocketStream); @@ -550,6 +607,13 @@ FQueueSize:=AValue; end; +procedure TFPCustomHttpServer.SetReuseAddress(AValue: Boolean); +begin + if FReuseAddress=AValue then exit; + CheckInactive; + FReuseAddress:=AValue; +end; + procedure TFPCustomHttpServer.SetThreaded(const AValue: Boolean); begin if FThreaded=AValue then exit; @@ -596,8 +660,18 @@ end; procedure TFPCustomHttpServer.CreateServerSocket; +var + TrueValue: Integer; begin FServer:=TInetServer.Create(FPort); + {$IFDEF Unix} + if ReuseAddress then + begin + // remedy socket port locking on Posix platforms + TrueValue := 1; + fpSetSockOpt(FServer.Socket, SOL_SOCKET, SO_REUSEADDR, @TrueValue, SizeOf(TrueValue)); + end; + {$ENDIF} FServer.MaxConnections:=-1; FServer.OnConnectQuery:=OnAllowConnect; FServer.OnConnect:=@DOConnect;
_______________________________________________ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel