| 
		
	
	
	
		
	Posts: 7 
	Threads: 2 
	Joined: Oct 2018
	
 Reputation: 
0 Location: Brazil
	 
	
		
		
		11-05-2018, 12:38 AM 
(This post was last modified: 11-07-2018, 10:12 PM by capslock.)
		
	 
		I'm using Indy 10 + fpc + lazarus to build a cross platform app.
 GStack.LocalAddress returns the IP address at Windows, but returns empty at Linux, and GStack.LocalAddresses.Count = 0. The machine has an ip address, checked by ifconfig.
 
 Anybody help me?
 
 Thanks,
 
 Gustavo
 
	
	
	
		
	Posts: 671 
	Threads: 2 
	Joined: Mar 2018
	
 Reputation: 
37 Location: California, USA
	 
	
		
		
		11-05-2018, 06:25 PM 
(This post was last modified: 11-05-2018, 06:40 PM by rlebeau.)
		
	 
		 (11-05-2018, 12:38 AM)capslock Wrote:  I'm using Indy 10 + fpc + lazarus to build a cross platform app.
 GStack.LocalAddress returns the IP address at Windows, but returns empty at Linux, and GStack.LocalAddresses.Count = 0. The machine has an ip address, checked by ifconfig.
 
First, the GStack.LocalAddress  and GStack.LocalAddresses  properties are deprecated, you should be using the GStack.GetLocalAddressList()  method instead.
 
Second, on FPC for Linux, GStack  points to an instance of either the TIdStackLibc  or TIdStackUnix  class (depending on whether KYLIXCOMPAT  is defined).  Both classes should  implement GetLocalAddressList()  using getifaddrs() , but in actuality they only do so when HAS_getifaddrs  is defined in IdCompilerDefines.inc , and that is defined only when LINUX64  is defined by the compiler (in addition to MACOS , IOS , and FREEBSD ).  Which, I believe is defined by Embarcadero only, not FPC.
 
When HAS_getifaddrs()  is not defined, both TIdStackLibc  and TIdStackUnix  implement GetLocalAddressList()  using gethostname()  with gethostbyname()  (Libc) or FPC's own ResolveName/6()  (Unix) instead.  And I guess that is not finding any IP addresses for the local hostname.
 
So, try altering IdCompilerDefines.inc  to define HAS_getifaddrs  for LINUX  instead of LINUX64 .  If that works, I'll check it in.
	 
 
	
	
	
		
	Posts: 7 
	Threads: 2 
	Joined: Oct 2018
	
 Reputation: 
0 Location: Brazil
	 
	
	
		The following patch was applied: Code: Index: Core/IdCompilerDefines.inc===================================================================
 --- Core/IdCompilerDefines.inc    (revision 5478)
 +++ Core/IdCompilerDefines.inc    (working copy)
 @@ -1490,6 +1490,10 @@
 {$DEFINE HAS_getifaddrs}
 {$ENDIF}
 
 +{$IFDEF LINUX}
 +  {$DEFINE HAS_getifaddrs}
 +{$ENDIF}
 +
 {$IFDEF IOS}
 {$DEFINE HAS_getifaddrs}
 {$DEFINE USE_OPENSSL}
 @@ -1866,4 +1870,4 @@
 // indexing for now...
 {$IFDEF HAS_DIRECTIVE_ZEROBASEDSTRINGS}
 {$ZEROBASEDSTRINGS OFF}
 -{$ENDIF}
 \ No newline at end of file
 +{$ENDIF}
 Index: FCL/IdCompilerDefines.inc
 ===================================================================
 --- FCL/IdCompilerDefines.inc    (revision 5478)
 +++ FCL/IdCompilerDefines.inc    (working copy)
 @@ -1490,6 +1490,10 @@
 {$DEFINE HAS_getifaddrs}
 {$ENDIF}
 
 +{$IFDEF LINUX}
 +  {$DEFINE HAS_getifaddrs}
 +{$ENDIF}
 +
 {$IFDEF IOS}
 {$DEFINE HAS_getifaddrs}
 {$DEFINE USE_OPENSSL}
 @@ -1866,4 +1870,4 @@
 // indexing for now...
 {$IFDEF HAS_DIRECTIVE_ZEROBASEDSTRINGS}
 {$ZEROBASEDSTRINGS OFF}
 -{$ENDIF}
 \ No newline at end of file
 +{$ENDIF}
 Index: Protocols/IdCompilerDefines.inc
 ===================================================================
 --- Protocols/IdCompilerDefines.inc    (revision 5478)
 +++ Protocols/IdCompilerDefines.inc    (working copy)
 @@ -1490,6 +1490,10 @@
 {$DEFINE HAS_getifaddrs}
 {$ENDIF}
 
 +{$IFDEF LINUX}
 +  {$DEFINE HAS_getifaddrs}
 +{$ENDIF}
 +
 {$IFDEF IOS}
 {$DEFINE HAS_getifaddrs}
 {$DEFINE USE_OPENSSL}
 @@ -1866,4 +1870,4 @@
 // indexing for now...
 {$IFDEF HAS_DIRECTIVE_ZEROBASEDSTRINGS}
 {$ZEROBASEDSTRINGS OFF}
 -{$ENDIF}
 \ No newline at end of file
 +{$ENDIF}
 Index: System/IdCompilerDefines.inc
 
 ===================================================================
 --- System/IdCompilerDefines.inc    (revision 5478)
 +++ System/IdCompilerDefines.inc    (working copy)
 @@ -1490,6 +1490,10 @@
 {$DEFINE HAS_getifaddrs}
 {$ENDIF}
 
 +{$IFDEF LINUX}
 +  {$DEFINE HAS_getifaddrs}
 +{$ENDIF}
 +
 {$IFDEF IOS}
 {$DEFINE HAS_getifaddrs}
 {$DEFINE USE_OPENSSL}
 @@ -1866,4 +1870,4 @@
 // indexing for now...
 {$IFDEF HAS_DIRECTIVE_ZEROBASEDSTRINGS}
 {$ZEROBASEDSTRINGS OFF}
 -{$ENDIF}
 \ No newline at end of file
 +{$ENDIF}
GStack.GetLocalAddressList returned empty anyway, before and after patch applied. But the deprecated method GStack.LocalAddresses returned the right IPv4 address after patch. Tested with two network interfaces, GStack.LocalAddresses returned the right two IPv4 addresses.  
 
And about IPv6 addresses, how to get them?
	 
	
	
	
		
	Posts: 671 
	Threads: 2 
	Joined: Mar 2018
	
 Reputation: 
37 Location: California, USA
	 
	
		
		
		11-06-2018, 05:36 PM 
(This post was last modified: 11-06-2018, 06:16 PM by rlebeau.)
		
	 
		 (11-06-2018, 04:58 AM)capslock Wrote:  GStack.GetLocalAddressList returned empty anyway, before and after patch applied. But the deprecated method GStack.LocalAddresses returned the right IPv4 address after patch. 
The GStack.LocalAddress(es)  properties call GStack.GetLocalAddressList()  internally, so if the local address list is returned empty, the properties must also return empty.  Likewise, if the GStack.LocalAddress(es)  properties are not returning empty, then GStack.GetLocalAddressList()  must not be returning an empty list.
 Code:    property LocalAddress: string read GetLocalAddress; // {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'use GetLocalAddressList()'{$ENDIF};{$ENDIF}property LocalAddresses: TStrings read GetLocalAddresses; // {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'use GetLocalAddressList()'{$ENDIF};{$ENDIF}
 
 ...
 
 function TIdStack.GetLocalAddresses: TStrings;
 var
 LList: TIdStackLocalAddressList;
 I: Integer;
 begin
 if FLocalAddresses = nil then begin
 FLocalAddresses := TStringList.Create;
 end;
 FLocalAddresses.BeginUpdate;
 try
 FLocalAddresses.Clear;
 LList := TIdStackLocalAddressList.Create;
 try
 // for backwards compatibility, return only IPv4 addresses
 GetLocalAddressList(LList);
 for I := 0 to LList.Count-1 do begin
 if LList[I].IPVersion = Id_IPv4 then begin
 FLocalAddresses.Add(LList[I].IPAddress);
 end;
 end;
 finally
 LList.Free;
 end;
 finally
 FLocalAddresses.EndUpdate;
 end;
 Result := FLocalAddresses;
 end;
 
 function TIdStack.GetLocalAddress: string;
 var
 LList: TIdStackLocalAddressList;
 I: Integer;
 begin
 // RLebeau: using a local list instead of the LocalAddresses
 // property so this method can be thread-safe...
 //
 // old code:
 // Result := LocalAddresses[0];
 
 Result := '';
 LList := TIdStackLocalAddressList.Create;
 try
 // for backwards compatibility, return only IPv4 addresses
 GetLocalAddressList(LList);
 for I := 0 to LList.Count-1 do begin
 if LList[I].IPVersion = Id_IPv4 then begin
 Result := LList[I].IPAddress;
 Exit;
 end;
 end;
 finally
 LList.Free;
 end;
 end;
 (11-06-2018, 04:58 AM)capslock Wrote:  Tested with two network interfaces, GStack.LocalAddresses returned the right two IPv4 addresses.   
Then GStack.GetLocalAddressList()  must be succeeding now.
  (11-06-2018, 04:58 AM)capslock Wrote:  And about IPv6 addresses, how to get them? 
As you can see above, the GStack.LocalAddress(es)  properties are restricted to IPv4 only for backwards compatibility.  To get the IPv6 addresses, you must call GStack.GetLocalAddressList()  directly.  The returned list will include all local IPv4 and IPv6 addresses that getifaddrs()  reports:
 Code: procedure TIdStackUnix.GetLocalAddressList(AAddresses: TIdStackLocalAddressList);var
 {$IFDEF HAS_getifaddrs}
 LAddrList, LAddrInfo: pifaddrs;
 LSubNetStr: String;
 {$ELSE}
 ...
 {$ENDIF}
 begin
 ...
 
 {$IFDEF HAS_getifaddrs}
 
 if getifaddrs(LAddrList) = 0 then // TODO: raise an exception if it fails
 try
 AAddresses.BeginUpdate;
 try
 LAddrInfo := LAddrList;
 repeat
 if (LAddrInfo^.ifa_addr <> nil) and ((LAddrInfo^.ifa_flags and IFF_LOOPBACK) = 0) then
 begin
 case LAddrInfo^.ifa_addr^.sa_family of
 Id_PF_INET4: begin
 if LAddrInfo^.ifa_netmask <> nil then begin
 LSubNetStr := TranslateTInAddrToString( PSockAddr_In(LAddrInfo^.ifa_netmask)^.sin_addr, Id_IPv4);
 end else begin
 LSubNetStr := '';
 end;
 TIdStackLocalAddressIPv4.Create(AAddresses, TranslateTInAddrToString( PSockAddr_In(LAddrInfo^.ifa_addr)^.sin_addr, Id_IPv4), LSubNetStr);
 end;
 Id_PF_INET6: begin
 TIdStackLocalAddressIPv6.Create(AAddresses, TranslateTInAddrToString( PSockAddr_In6(LAddrInfo^.ifa_addr)^.sin6_addr, Id_IPv6));
 end;
 end;
 end;
 LAddrInfo := LAddrInfo^.ifa_next;
 until LAddrInfo = nil;
 finally
 AAddresses.EndUpdate;
 end;
 finally
 freeifaddrs(LAddrList);
 end;
 
 {$ELSE}
 
 ...
 
 {$ENDIF}
 end;
Code: procedure TIdStackLibc.GetLocalAddressList(AAddresses: TIdStackLocalAddressList);{$IFNDEF HAS_getifaddrs}
 ...
 {$ENDIF}
 var
 {$IFDEF HAS_getifaddrs}
 LAddrList, LAddrInfo: pifaddrs;
 LSubNetStr: string;
 {$ELSE}
 ...
 {$ENDIF}
 begin
 ...
 
 {$IFDEF HAS_getifaddrs}
 
 if getifaddrs(@LAddrList) = 0 then // TODO: raise an exception if it fails
 try
 AAddresses.BeginUpdate;
 try
 LAddrInfo := LAddrList;
 repeat
 if (LAddrInfo^.ifa_addr <> nil) and ((LAddrInfo^.ifa_flags and IFF_LOOPBACK) = 0) then
 begin
 case LAddrInfo^.ifa_addr^.sa_family of
 Id_PF_INET4: begin
 if LAddrInfo^.ifa_netmask <> nil then begin
 LSubNetStr := TranslateTInAddrToString(PSockAddr_In(LAddrInfo^.ifa_netmask)^.sin_addr, Id_IPv4);
 end else begin
 LSubNetStr := '';
 end;
 TIdStackLocalAddressIPv4.Create(AAddresses, TranslateTInAddrToString(PSockAddr_In(LAddrInfo^.ifa_addr)^.sin_addr, Id_IPv4), LSubNetStr);
 end;
 Id_PF_INET6: begin
 TIdStackLocalAddressIPv6.Create(AAddresses, TranslateTInAddrToString(PSockAddr_In6(LAddrInfo^.ifa_addr)^.sin6_addr, Id_IPv6));
 end;
 end;
 end;
 LAddrInfo := LAddrInfo^.ifa_next;
 until LAddrInfo = nil;
 finally
 AAddresses.EndUpdate;
 end;
 finally
 freeifaddrs(LAddrList);
 end;
 
 {$ELSE}
 
 ...
 
 {$ENDIF}
 end;
 
I have now checked in a patch to IdCompilerDefines.inc  to define HAS_getifaddrs()  when LINUX  is defined, not just LINUX64 .
	 
 
	
	
	
		
	Posts: 7 
	Threads: 2 
	Joined: Oct 2018
	
 Reputation: 
0 Location: Brazil
	 
	
		
		
		11-07-2018, 10:11 PM 
(This post was last modified: 11-07-2018, 11:15 PM by rlebeau.)
		
	 
		I tested again. You right, I'm wrong... Works like a charm, both IPv4 and IPv6. 
 Thanks.
 |