Page 1 of 1

Network Get Address From Host (All OS)

Posted: Sun Jan 01, 2023 12:33 pm
by mk-soft
Returns the IP addresses of the host.

After it ran immediately on Windows and macOS, it did not run on Linux at first.
When I noticed the next day that the structures were minimally different, it also worked. :wink:

update v1.01.2
- Fixed structures

update v1.01.4
- Fixed memory-leak

Update v1.02.0
- Some fixed and optimization

Code: Select all

;-TOP

; *************************************************
; Comment   : Network Get Address From Host (All OS)
; Authors   : mk-soft, infratec
; Version   : v1.02.0
; Create    : 31.12.2022
; Update    : 12.08.2023
; Link      : https://www.purebasic.fr/english/viewtopic.php?t=80387

; Description
;  Family : PF_UNSPEC IPv4 and IPv6
;  Family : PF_INET   IPv4
;  Family : PF_INET6  IPv6

EnableExplicit

;-- Imports

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Import ""
CompilerElse
  ImportC ""
CompilerEndIf
  getaddrinfo(NodeName.p-Ascii, ServiceName.p-Ascii, *pHints, *ppResult)
  freeaddrinfo(*ppResult)
  inet_ntop(Family, *pAddr, pStringBuf, StringBufSize)
EndImport

;-- Contants

#AF_UNSPEC = 0
#AF_INET = 2
CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows
    #AF_INET6 = 23
  CompilerCase #PB_OS_Linux
    #AF_INET6 = 10
  CompilerCase #PB_OS_MacOS
    #AF_INET6 = 30
CompilerEndSelect

#PF_UNSPEC = #AF_UNSPEC
#PF_INET = #AF_INET
#PF_INET6 = #AF_INET6

#AI_CANONNAME = 2

#SOCK_STREAM = 1

;-- Structures

CompilerIf Not Defined(in_addr, #PB_Structure)
  Structure in_addr Align #PB_Structure_AlignC
    StructureUnion
      s_b.a[4]
      s_w.u[2]
      s_addr.l
    EndStructureUnion
  EndStructure
CompilerEndIf

CompilerIf Not Defined(in6_addr, #PB_Structure)
  Structure in6_addr Align #PB_Structure_AlignC
    s6_addr.a[16]
  EndStructure
CompilerEndIf

CompilerIf Not Defined(SOCKADDR, #PB_Structure)
  Structure SOCKADDR Align #PB_Structure_AlignC
    sa_family.u
    sa_data.a[14]
  EndStructure
CompilerEndIf

CompilerIf Not Defined(SOCKADDR_IN4, #PB_Structure)
  Structure SOCKADDR_IN4 Align #PB_Structure_AlignC
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      sin_len.a
      sin_family.a
    CompilerElse
      sin_family.u
    CompilerEndIf
    sin_port.u
    sin_addr.in_addr
    sin_zero.a[8]
  EndStructure
CompilerEndIf

CompilerIf Not Defined(SOCKADDR_IN6, #PB_Structure)
  Structure SOCKADDR_IN6 Align #PB_Structure_AlignC
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      sin6_len.a
      sin6_family.a
    CompilerElse
      sin6_family.u
    CompilerEndIf
    sin6_port.u
    sin6_flowinfo.l
    sin6_addr.in6_addr
    sin6_scope_id.l
  EndStructure
CompilerEndIf

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  
  Structure addrinfo Align #PB_Structure_AlignC
    ai_flags.l
    ai_family.l
    ai_socktype.l
    ai_protocol.l
    ai_addrlen.l
    StructureUnion
      *ai_addr.SOCKADDR
      *ai_addr_in.SOCKADDR_IN4
      *ai_addr_in6.SOCKADDR_IN6
    EndStructureUnion
    *ai_canonname
    *ai_next.addrinfo
  EndStructure
  
CompilerElse
  
  Structure addrinfo Align #PB_Structure_AlignC
    ai_flags.l
    ai_family.l
    ai_socktype.l
    ai_protocol.l
    ai_addrlen.l
    *ai_canonname
    StructureUnion
      *ai_addr.SOCKADDR
      *ai_addr_in.SOCKADDR_IN4
      *ai_addr_in6.SOCKADDR_IN6
    EndStructureUnion
    *ai_next.addrinfo
  EndStructure
  
CompilerEndIf

;-- Functions

Procedure.s GetAddrString(HostName.s, Family = #AF_UNSPEC, CanonName = #False)
  Protected r1.s
  Protected hints.addrinfo, *res.addrinfo, *result.addrinfo
  Protected errcode.l
  Protected *addrstr
  Protected *ptr4.in_addr, *ptr6.in6_addr
  Protected name.s
  
  
  hints\ai_family = Family
  hints\ai_socktype = #SOCK_STREAM
  If CanonName
    hints\ai_flags = #AI_CANONNAME
  Else
    hints\ai_flags = 0
  EndIf
  
  errcode = getaddrinfo(Hostname, #Empty$, hints, @*result)
  If errcode = 0
    *addrstr = AllocateMemory(258)
    *res = *result
    While *res
      Select (*res\ai_family)
        Case #AF_INET
          If *res\ai_addr
            *ptr4 = @*res\ai_addr_in\sin_addr
            If inet_ntop(*res\ai_family, *ptr4, *addrstr, 256)
              r1 + PeekS(*addrstr, -1, #PB_Ascii)
            EndIf
          EndIf
        Case #AF_INET6
          If *res\ai_addr
            *ptr6 = @*res\ai_addr_in6\sin6_addr
            If inet_ntop(*res\ai_family, *ptr6, *addrstr, 256)
              r1 + PeekS(*addrstr, -1, #PB_Ascii)
            EndIf
          EndIf
      EndSelect
      
      If CanonName And *res\ai_canonname
        name = PeekS(*res\ai_canonname, -1, #PB_Ascii)
      EndIf
      *res = *res\ai_next
      If *res
        r1 + ";"
      EndIf
    Wend
    
    If CanonName
      r1 + ";" + name
    EndIf
    FreeMemory(*addrstr)
    freeaddrinfo(*result)
  Else
    ; Error
  EndIf
  
  ProcedureReturn r1
EndProcedure

; ****

CompilerIf #PB_Compiler_IsMainFile
  
  ;- Example
  Define r1.s, host.s
  
  host = "localhost" ; local network
  r1.s = GetAddrString(host, #PF_INET6, #True)
  Debug host + "/ " + r1
  
  host = "raspberrypi" ; local network
  r1.s = GetAddrString(host, #PF_UNSPEC, #True)
  Debug host + "/ " + r1
  
  host = "michaels-mini-2" ; local network
  r1.s = GetAddrString(host, #PF_INET, #True)
  Debug host + "/ " + r1
  
  host = "www.purebasic.fr"
  r1.s = GetAddrString(host, #PF_UNSPEC, #True)
  Debug host + "/ " + r1
  
  host = "raspberry.com" ; internet
  r1.s = GetAddrString(host, #PF_UNSPEC, #True)
  Debug host + "/ " + r1
  
CompilerEndIf

Re: Network Get Address From Host (All OS)

Posted: Sun Jan 01, 2023 11:03 pm
by idle
I tested it on windows 11, there's was a leak freeing resources but if an address is unresolvable or doesn't exist, the errors not clearing even calling wsacleanup_() Not sure what the issue is.

Code: Select all

Procedure.s GetAddrString(HostName.s, Family = #AF_UNSPEC, CanonName = #False)
  Protected r1.s, *host
  Protected hints.addrinfo, *res.addrinfo, *result.addrinfo
  Protected errcode.l
  Protected *addrstr
  Protected *ptr4.in_addr, *ptr6.in6_addr
  Protected name.s
  
  *host = Ascii(Hostname)
  *addrstr = AllocateMemory(258)
  
  hints\ai_family = Family
  hints\ai_socktype = #SOCK_STREAM
  If CanonName
    hints\ai_flags = #AI_CANONNAME
  Else
    hints\ai_flags = 0
  EndIf
  
  errcode = getaddrinfo(*host, #Empty$, hints, @*result)
  If errcode <> 0
     Goto ERROR: 
   EndIf
  
  *res = *result
  While *res
    Select (*res\ai_family)
      Case #AF_INET
        If *res\ai_addr
          *ptr4 = @*res\ai_addr_in\sin_addr
          If inet_ntop(*res\ai_family, *ptr4, *addrstr, 256)
            r1 + PeekS(*addrstr, -1, #PB_Ascii)
          EndIf
        EndIf
      Case #AF_INET6
        If *res\ai_addr
          *ptr6 = @*res\ai_addr_in6\sin6_addr
          If inet_ntop(*res\ai_family, *ptr6, *addrstr, 256)
            r1 + PeekS(*addrstr, -1, #PB_Ascii)
          EndIf
        EndIf
    EndSelect
    
    If CanonName And *res\ai_canonname
      name = PeekS(*res\ai_canonname, -1, #PB_Ascii)
    EndIf
    *res = *res\ai_next
    If *res
      r1 + ";"
    EndIf
  Wend
  
  If CanonName
    r1 + ";" + name
  EndIf
  
  freeaddrinfo(*result);
  Error: 
  FreeMemory(*addrstr)
  FreeMemory(*host)
  
  ProcedureReturn r1
EndProcedure
but if an address is unresolved the error isn't cleared and I don't know why.

Code: Select all

host = "raspberrypi"
  r1.s = GetAddrString(host, #AF_INET, #True)
  Debug host + ": " + r1
  
  host = "www.purebasic.fr"
  r1.s = GetAddrString(host, #AF_INET, #True)
  Debug host + ": " + r1

; second run 
 host = "raspberrypi.com"
  r1.s = GetAddrString(host, #AF_INET, #True)
  Debug host + ": " + r1
  
  host = "www.purebasic.fr"
  r1.s = GetAddrString(host, #AF_INET, #True)
  Debug host + ": " + r1

Result as

raspberrypi:
www.purebasic.fr:

;second run
raspberrypi.com: 93.93.130.37;raspberrypi.com
www.purebasic.fr: 163.172.93.88;www.purebasic.fr

Re: Network Get Address From Host (All OS)

Posted: Sun Jan 01, 2023 11:30 pm
by mk-soft
update v1.01.4
- Fixed memory-leak

I overlooked the memory leak. Thanks for reporting it.
If an error like the address could not be resolved, no result memory is created.

The query with "raspberrypi" without a result is correct for you. I have a Raspberry in my network for testing and therefore also the IPv6 address.

It also seems that the timeout time is very short.
raspberrypi/ 2003:e1:bf3f:5a00:XXXX:XXXX:XXXX:XXXX;192.168.XXX.XXX;raspberrypi.fritz.box
www.purebasic.fr/ 163.172.93.88;purebasic.fr
raspberry.com/ 178.62.51.113;raspberry.com

Re: Network Get Address From Host (All OS)

Posted: Mon Jan 02, 2023 1:01 am
by idle
windows timeout is at least 3 seconds, it can be a very slow function.

I'm still not sure why the error isn't clearing, the call to "raspberrypi" doesn.t resolve to an address on my network which is correct and returns the error #WSAHOST_NOT_FOUND = 11001
but the next call to purebasic.fr also fails when it shouldn't so somethings not quite right.
I think it a windows bug.

Re: Network Get Address From Host (All OS)

Posted: Mon Jan 02, 2023 10:08 am
by mk-soft
ah,

You also have a Raspberry PI on the net.
It works for me under Windows 10, macOS Ventura and Linux Mint.
My router is a Fritzbox 5590.

Try the programme with the Raspberry.

Re: Network Get Address From Host (All OS)

Posted: Mon Jan 16, 2023 12:50 pm
by Kwai chang caine
Hello TsSoft

Thanks for sharing 8)
I try your nice code, but i have an IMA in line 164 with W10 and v6 beta9

Code: Select all

  Select (*res\ai_family)

Re: Network Get Address From Host (All OS)

Posted: Mon Jan 16, 2023 7:25 pm
by mk-soft
No Problem with PB v6.0 Release ... ( why beta 9)

Re: Network Get Address From Host (All OS)

Posted: Sat Aug 12, 2023 10:51 am
by mk-soft
Update v1.02.0
- Some fixed and optimization

Thanks to infratec

Testing with:
- Windows 10 PB x86 and x64
- Linux Debian 9 x86, Debian 11 x64
- macOS 13.5 x64, m1

Re: Network Get Address From Host (All OS)

Posted: Sat Aug 12, 2023 11:32 am
by infratec
Unfortunately it does not always return what I want (macOS)

If I try to get the IPs (v4 and v6) and LAN is connected to IPv4 and WLAN is connected to IPv4/v6 I get no IPv6 address.
If I disconnect LAN it works.
To specify AF_INET6 makes no difference.

nslookup works always at least if I use -type=AAAA

So it is not a problem of the DNS.

Re: Network Get Address From Host (All OS)

Posted: Sat Aug 12, 2023 12:02 pm
by mk-soft
I don't get an IP6 result even with only WLAN. Even if I switch off IPv4.
Even if I make the query from the Raspberry.
Is it possibly due to macOS?

Re: Network Get Address From Host (All OS)

Posted: Sat Aug 12, 2023 12:19 pm
by infratec
If I'm only in an IPv4/v6 network I get for mit.edu one IPv4 address and 2 IPv6 addresses (macOS)

Re: Network Get Address From Host (All OS)

Posted: Sat Aug 12, 2023 2:24 pm
by mk-soft
infratec wrote: Sat Aug 12, 2023 12:19 pm If I'm only in an IPv4/v6 network I get for mit.edu one IPv4 address and 2 IPv6 addresses (macOS)
Same here ...