Recent

Author Topic: Get external IP address without error if there is no internet  (Read 716 times)

Libra07

  • New Member
  • *
  • Posts: 17
Get external IP address without error if there is no internet
« on: December 03, 2022, 02:51:44 pm »
I wrote a function that returns the IP address. It works fine, if I have internet. But if I have no internet, it stops with error message 217 .
My functions use FpHttpClient unit.

Code: Pascal  [Select][+][-]
  1. Function Get_Public_IP:String;       // #1
  2. Var   IdGetIP  : TFPHTTPClient;
  3.       Temp_IP  : String;
  4.       I:Longint;
  5. Const URL_List : Array[1..2] Of String
  6.                = ('http://dynupdate.no-ip.com/ip.php',
  7.                   'http://ipinfo.io/ip');
  8. Begin
  9.   Temp_IP:='0.0.0.0';
  10.  
  11.   IdGetIP := TFPHTTPClient.Create(nil);
  12.   Temp_IP := IdGetIP.Get(URL_List[1]);
  13.   IdGetIP.Free;
  14.  
  15.   Get_Public_IP:=Temp_IP;
  16. End;
  17.  

I read about it and tried another code, with TRY and EXCEPT, but it also works fine when i have is internet, but stops with an error 217 when there is no internet.

Code: Pascal  [Select][+][-]
  1. Function Get_Public_IP:String;       // #2
  2. Var
  3.   IdGetIP : TFPHTTPClient;
  4.   Html    : String;
  5. Const
  6.   gUrlIpA = 'http://dynupdate.no-ip.com/ip.php';
  7.   gUrlIpB = 'http://ipinfo.io/ip';
  8. Begin
  9.   Try
  10.     IdGetIP:=TFPHTTPClient.Create(nil);
  11.     Result := '';
  12.     Try
  13.       Html := IdGetIP.Get(gUrlIpA);
  14.     Except
  15.       Html := IdGetIP.Get(gUrlIpB);
  16.     End;
  17.     Result := Html;
  18.   Finally
  19.     IdGetIP.Free;
  20.   End;
  21. End;
  22.  

How can I extend my code to handle this error and not stop when there is no internet?
It's good for me if the functions return with '0.0.0.0' ip address, if I have no internet.

Libra07

  • New Member
  • *
  • Posts: 17
Re: Get external IP address without error if there is no internet
« Reply #1 on: December 03, 2022, 03:13:35 pm »
When I entered the two source codes here, I found the solution. :D
I edited the second source code:

Code: Pascal  [Select][+][-]
  1. Function Get_Public_IP:String;       // #2
  2. Var
  3.   IdGetIP : TFPHTTPClient;
  4.   Html    : String;
  5. Const
  6.   gUrlIpA = 'http://dynupdate.no-ip.com/ip.php';
  7.   gUrlIpB = 'http://ipinfo.io/ip';
  8. Begin
  9.   Try
  10.     IdGetIP:=TFPHTTPClient.Create(nil);
  11.     Result := '';
  12.     Try
  13.       Html := IdGetIP.Get(gUrlIpA);
  14.     Except
  15.       Html := '0.0.0.0';
  16.     End;
  17.     Result := Html;
  18.   Finally
  19.     IdGetIP.Free;
  20.   End;
  21. End;
  22.  

MarkMLl

  • Hero Member
  • *****
  • Posts: 5864
Re: Get external IP address without error if there is no internet
« Reply #2 on: December 03, 2022, 05:44:52 pm »
So the basic problem would appear to be that your computer or site is relying on an external name server (DNS etc.) to resolve e.g. http://ipinfo.io/ip to a dotted-quad address.

This whole area is rather fraught, since there is a vast number of possibilities relating to nameserver fallback etc. In fact your problems will really start when you try to work out whether you currently have a live route to the Internet at large.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Dzandaa

  • Jr. Member
  • **
  • Posts: 89
  • From C# to Lazarus
Re: Get external IP address without error if there is no internet
« Reply #3 on: December 03, 2022, 06:49:51 pm »
Hi,

You can try a validate function on the URL:

Code: Pascal  [Select][+][-]
  1. function CheckValidUrl(URL: String): integer;
  2. var
  3.  HTTPSender: THTTPSend;
  4. begin
  5.   HTTPSender := THTTPSend.Create;
  6.   HTTPSender.Timeout := 50;
  7.  try
  8.    HTTPSender.HTTPMethod('GET', URL);
  9.    if (HTTPSender.ResultCode >= 100) and (HTTPSender.ResultCode<=302) then Result := 0
  10.    else Result := HTTPSender.ResultCode;
  11.  finally
  12.    HTTPSender.Free;
  13.  end;
  14. end;  
  15.  

If the function return 0, it's O.K.

B->
Dzandaa

KodeZwerg

  • Hero Member
  • *****
  • Posts: 954
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Get external IP address without error if there is no internet
« Reply #4 on: December 03, 2022, 07:21:32 pm »
I am using mostly same code (specific for Windows) that user Remy Lebeau posted here.
(Just to mention it, since I do not know about anything what the target platform is.)
« Last Edit: Tomorrow at 31:76:97 by KodeZwerg »

Dzandaa

  • Jr. Member
  • **
  • Posts: 89
  • From C# to Lazarus
Re: Get external IP address without error if there is no internet
« Reply #5 on: December 03, 2022, 07:33:13 pm »
Hi,

Work for Windows and Linux.

B->
Dzandaa

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1169
    • Lebeau Software
Re: Get external IP address without error if there is no internet
« Reply #6 on: December 04, 2022, 03:21:09 am »
I wrote a function that returns the IP address. It works fine, if I have internet. But if I have no internet, it stops with error message 217 .
My functions use FpHttpClient unit.

You need a try..except around EVERY call to TFPHTTPClient.Get().  In your first attempt, you aren't catching any errors at all.  In your second attempt, you are catching errors only on the 1st call but not the 2nd call.  In your third attempt, you are only querying 1 URL, but at least you are catching errors for it.

Try something more like this:

Code: Pascal  [Select][+][-]
  1. function Get_Public_IP: String;
  2. var
  3.   IdGetIP : TFPHTTPClient;
  4.   I : LongInt;
  5. cconst
  6.   URL_List : array[1..2] of string = (
  7.     'http://dynupdate.no-ip.com/ip.php',
  8.     'http://ipinfo.io/ip'
  9.   );
  10. begin
  11.   Result := '0.0.0.0';
  12.   IdGetIP := TFPHTTPClient.Create(nil);
  13.   try
  14.     for I := Low(URL_List) to High(URL_List) do
  15.     try
  16.       Result := IdGetIP.Get(URL_List[I]);
  17.       Break;
  18.     except
  19.     end;
  20.   finally
  21.     IdGetIP.Free;
  22.   end;
  23. end;
  24.  
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Libra07

  • New Member
  • *
  • Posts: 17
Re: Get external IP address without error if there is no internet
« Reply #7 on: December 05, 2022, 12:13:47 pm »
Remy Lebeau, thank you! Your idea is very good and works fine, but speed is important to me, so I would like to query an external URL. If this doesn't work for some reason in the future, I'll replace the URL with the other one.
I couldn't try Remy's other code, the myIPAddress() function, because I couldn't find the UNIT that contains the HINTERNET type. Which UNIT is this?

I'm sure that you can't query the external IP address without an external DNS URL, right? This can't be solved with internal resources, can it?

GetMem

  • Hero Member
  • *****
  • Posts: 3953
Re: Get external IP address without error if there is no internet
« Reply #8 on: December 05, 2022, 12:25:37 pm »
@Libra07

Quote
I couldn't try Remy's other code, the myIPAddress() function, because I couldn't find the UNIT that contains the HINTERNET type. Which UNIT is this?
uses WinINet

Libra07

  • New Member
  • *
  • Posts: 17
Re: Get external IP address without error if there is no internet
« Reply #9 on: December 05, 2022, 12:47:22 pm »
@GetMem

Thank you GetMem! Now I can compile the code but I have an error message in 2 rows: "Error: Operator is not overloaded: Pointer = ShortInt".

11.  :  if pSession = 0 then Exit;
14.  :  if hFile = 0 then Exit;

After I edited this rows to this, I can compile the source code.
11.  :  if pSession = nil then Exit;
14.  :  if hFile = nil then Exit;

But finally the function returned an empty value.
I relpaced the DNS URL too this:
'http://ip.thaddy.com/' -> 'http://dynupdate.no-ip.com/ip.php'

Now it's working fine! Thank you!

If I can help anyone with this, this is the second source code that works well:

Code: Pascal  [Select][+][-]
  1. Program Get_External_IP_Address_2;
  2.  
  3. Uses WinINet;
  4.  
  5. function myIPAddress(): string;
  6. var
  7.   pSession: HINTERNET;
  8.   hFile: HINTERNET;
  9.   buffer: array[0..45] of AnsiChar;
  10.   bytesRead: DWORD;
  11.   myIP: AnsiString;
  12. begin
  13.   Result := 'error';
  14.   pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  15.   if pSession = nil then Exit;    // Old value: 0
  16.   try
  17.     hFile := InternetOpenUrlA(pSession, 'http://dynupdate.no-ip.com/ip.php', nil, 0, INTERNET_FLAG_RELOAD, 0);
  18.     if hFile = nil then Exit;    // Old value: 0
  19.     try
  20.       if InternetReadFile(hFile, @buffer, SizeOf(buffer), bytesRead) then
  21.       begin
  22.         SetString(myIP, buffer, bytesRead);
  23.         Result := string(myIP);
  24.       end;
  25.     finally
  26.       InternetCloseHandle(hFile);
  27.     end;
  28.   finally
  29.     InternetCloseHandle(pSession);
  30.   end;
  31. end;
  32.  
  33. Begin
  34.   Write('IP: ');
  35.   WriteLn(myIPAddress);
  36.   ReadLn;
  37. End.
  38.  

Warfley

  • Hero Member
  • *****
  • Posts: 992
Re: Get external IP address without error if there is no internet
« Reply #10 on: December 05, 2022, 02:24:00 pm »
Just on a conceptual level, if you are not connected to the Internet, you don't have a internet accessible IP address, so the question is what does your function retrun. You can return the empty string, but in the socket API the NULL string (which is equivalent to the empty string in Pascal) is resolved to the loopback address (127.0.0.1 in IPv4 or ::1 in IPv6). An alternative is that you could return the 0 address (0.0.0.0 in IPv4 or ::0 in IPv6), but this address has other special purposes, e.g. it binds any address. Also there is the question, when you return a dummy address like the 0 address, if you should return an IPv4 or IPv6 address.

Therefore I would suggest that the usage of exceptions to signal that there is no internet connection (and therefore no meaningful external IP address), is actually a good solution for the issue at hand. When calling your function, it either returns a valid IP address, or it raises an exception. Then you avoid the problem with adding a bottom element to a type which is not intended to have a bottom element

BobDog

  • Sr. Member
  • ****
  • Posts: 366
Re: Get external IP address without error if there is no internet
« Reply #11 on: December 05, 2022, 02:24:09 pm »
Here is a winsock way for www
Code: Pascal  [Select][+][-]
  1.  
  2.  
  3. {$mode objfpc}
  4. {$apptype console}
  5.  
  6. uses
  7. winsock;
  8.  
  9. function GetSiteAddress(Site:pchar='www.freepascal.org'):ansistring;
  10. type
  11. lwp=^longword;
  12. var
  13. answer:ansistring='';
  14.    _wsDAT:WSADATA;
  15.    addr:in_addr;
  16.    res:^hostent;
  17.    i:integer=0;
  18.  
  19.    begin
  20.    _wsDAT.wversion:=0;
  21.    _wsDAT.wHighVersion:=0;;
  22.     WSAStartup(514,twsadata(_wsDAT));
  23.    res := gethostbyname(Site);
  24.    answer:=answer+site+chr(10);
  25.    if (res=nil) then
  26.    begin
  27.     WSACleanup();
  28.     answer:=answer+'Error - Site not found'+chr(10);
  29.     exit(answer);
  30.    end
  31.    else
  32.    begin
  33.    while ((res^.h_addr_list[i]) <> nil) do
  34.    begin
  35.    addr.s_addr:= lwp((res^).h_addr_list[i])^;
  36.    answer:=answer+inet_ntoa(addr)+chr(10);
  37.       i:=i+1;
  38.    end;
  39.    WSACleanup();
  40.    end;
  41.    exit(answer);
  42. end;  
  43.  
  44.  
  45. begin
  46. writeln(GetSiteAddress());;
  47. writeln(GetSiteAddress('www.google.com'));
  48. writeln(GetSiteAddress('www.nosuchsiteexists.com'));
  49. writeln(GetSiteAddress('www.Youtube.com'));
  50. writeln(GetSiteAddress('www.Wikipedia.org'));
  51. writeln(GetSiteAddress('www.Yahoo.com'));
  52. writeln('Press return to end . . .');
  53. readln;
  54. end.
  55.  

Libra07

  • New Member
  • *
  • Posts: 17
Re: Get external IP address without error if there is no internet
« Reply #12 on: December 05, 2022, 03:00:47 pm »
BobDog, this is very nice solution to identify the IP address of a site! Thank you!

 

TinyPortal © 2005-2018