On Android both in terminal and GUI apps, TFPHTTPClient fails to connect when ConnectTimeout property has a value bigger than zero.
The following project shows the problem:
program test_fphttpclient;
{$define UseCThreads}
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes,SysUtils,fphttpclient,opensslsockets,openssl,netdb
{ you can add units after this };
var
c:TFPHTTPClient;
r:RawByteString='';
begin
WriteLn('GetDNSServers: '+GetDNSServers.ToString);
WriteLn('InitSSLInterface: '+InitSSLInterface.ToString(TUseBoolStrs.True));
WriteLn('IsSSLloaded: '+IsSSLloaded.ToString(TUseBoolStrs.True));
c:=TFPHTTPClient.Create(nil);
try
c.AllowRedirect:=True;
c.ConnectTimeout:=0;//<--- Passes
//c.ConnectTimeout:=3000;//<---- Fails
try
r:=c.Get('https://www.google.com');
WriteLn('Response Length: ',Length(r));
except
on e:exception do WriteLn(e.ClassName+': '+e.Message);
end;
finally
c.Free;
end;
end.
Run it using:
adb push "$Project()" "/data/local/tmp"
adb shell chmod 755 /data/local/tmp/$ProjFile()
adb shell /data/local/tmp/$ProjFile()
OR
adb push "$Project()" "/data/local/tmp" && adb shell chmod 755 /data/local/tmp/$ProjFile() && adb shell /data/local/tmp/$ProjFile()
When ConnectTimeout>0, it fails with:
GetDNSServers: 2
InitSSLInterface: True
IsSSLloaded: True
ESocketError: Connect to www.google.com:443 failed.
Tracking the code:
procedure TInetSocket.Connect;
...
{$ifdef unix}
Err:=ESysEINTR;
While IsError and (Err in [ESysEINTR, ESysEAGAIN]) do
{$endif}
begin
IsError:=fpConnect(Handle, @addr, sizeof(addr))<>0;
if IsError then
Err:=Socketerror;
end;
{$IFDEF HAVENONBLOCKING}
if (ConnectTimeOut>0) then
begin
if IsError and (Err=ErrWouldBlock) then
begin
TimeOutResult:=CheckSocketConnectTimeout(Handle, @FDS, @TimeV);
IsError:=(TimeOutResult<>ctrOK);
end;
SetSocketBlockingMode(Handle, bmBlocking, @FDS);
end;
{$ENDIF}
If Not IsError then
begin
IsError:=Not FHandler.Connect;
if IsError then
CloseSocket(Handle);
end;
If IsError then
if TimeoutResult=ctrTimeout then
Raise ESocketError.Create(seConnectTimeOut, [Format('%s:%d',[FHost, FPort])])
else
Raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort])]);
end;
It fails in the call to fpConnect, but the Err is 0!!!
I don't know what that means.
Is it a bug in the way TInetSocket.Connect handles ConnectTimeout?
As a nice outcome, Android is providing openssl libraries for both the GUI and the terminal apps.
The above test using Laz2.0.10/FPC3.2.0 to cross compile to Android/ArmV7a