Announcement

Collapse
No announcement yet.

IP number string (dotted) to LONG Discussion

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • IP number string (dotted) to LONG Discussion

    IMPORTANT NOTE:

    PB's LONG "IP number" is NOT the actual IP address number. It is just a PB internal representation of the IP address and can't be used as an IP number outside of PB's HOST, TCP etc functions..

    PB's ADDR is a little endian LONG. Internet protocol (IP) uses 'network byte order' (big-endian) positive integers..

    PB's stores "192.168.7.254" as the number &HFE07A8C0 i.e the LONG -33052480

    The actual Internet Protocal number represented by the dotted string "192.168.7.254" is the DWORD &HC0A807FE or 3232237566
    One particular situation where this can byte () you is in testing IP address ranges. To do that, you need the real IP address numbers.
    See https://forum.powerbasic.com/forum/u...471#post807471

    Here's a couple of relevant functions:

    Code:
    FUNCTION IPStringToDec(IPString AS STRING) AS DWORD
      'Converts a "dotted" IP address string to its decimal value
      FUNCTION = VAL(PARSE$(IPString, ".", 1)) * 16777216 + _
       VAL(PARSE$(IPString, ".", 2)) *  65536 + _
       VAL(PARSE$(IPString, ".", 3)) * 256  + _
       VAL(PARSE$(IPString, ".", 4))
    END FUNCTION
    
    FUNCTION IPToDecimal(IP AS LONG) AS DWORD
        'Converts a PB IP Long to its Decimal IP Number
        LOCAL p1,p2 AS BYTE PTR
        LOCAL d AS DWORD
        p1 = VARPTR(IP)
        p2 = VARPTR(d)
        @p2 = @p1[3]
        @p2[1] = @p1[2]
        @p2[2] = @p1[1]
        @p2[3] = @p1
        FUNCTION = d
    END FUNCTION




  • #2
    Okay it wasn't bold enough for you.
    'Needed (at times) for HOST NAME, TCP OPEN SERVER and UDP SEND.
    He is correct. where PB uses IP& in syntax definition it is little endian.
    It is REAL, but with byte order reversed. The Internet uses big endian, Windows little endian.
    Use the right one in right place, but no need to get that excited.

    Cheers,
    Dale

    Comment


    • #3
      Oh, it was quite bold enough for me.

      I was just clarifying for those who may not appreciate (as I didn't until I worked on the application in my link) that the PB value is not the IP address and is not sequential.

      This is contrary to what is stated in Help under HOST ADDR:
      "ip& receives the IP address of the specified host name."
      and Help -HOST NAME:
      "ip& is the IP address you want to look up"
      and Help -UDP SEND
      "at the IP address specified in ip&"

      '
      Code:
        Dotted = "192.168.7.253"
        IP_Num = DotIP4_Bin(STRPTR(Dotted), 0)
        Dotted = "192.168.7.254"
        IP_Num2 = DotIP4_Bin(STRPTR(Dotted), 0)
        ? "The IP addresses 192.168.7.253 and 192.168.7.254 differ by 1" & $LF & _
         "but PB's IP numbers for these addresses differ by "  & STR$(ABS(IP_Num2 - IP_Num))
        '
      ---------------------------
      PowerBASIC
      ---------------------------
      The IP addresses 192.168.7.253 and 192.168.7.254 differ by 1
      but PB's IP numbers for these addresses differ by 16777216
      ---------------------------
      OK
      ---------------------------



      Comment


      • #4
        The 32 bits of a LONG hold EXACTLY the IP number. It is the little endian assuming decimal conversion that gives mucked up numbers. And the to hex conversion that also assumes little endian that shows bytes in backwards order.

        The negative appearing numbers would not happen if Bob Z. had used a DWORD to store IPs. (IPs aren't signed anyway)

        Again, the bit pattern is exactly as networking uses. The REAL IP.

        The little code I posted puts 4 decimal values of the 4 bytes of IP (IP version 4) into the 4 bytes of a long "in spite" of the endianness of windows. Converting to decimal then complaining that wrongly converted sequential IPs are no longer sequential is nonsense.

        Your code (at link) and Help wording not considered. The code in Help mentioned to do reverse conversion without endianness assumptions making a mess.
        Dale

        Comment


        • #5
          Originally posted by Dale Yarker View Post
          The 32 bits of a LONG hold EXACTLY the IP number..
          The PB IP number, but NOT the internet IP address! The IP address is by definition a 32 bit stream (which can be treated as 4 bytes in BigEndian order).

          Click image for larger version  Name:	IPbits.jpg Views:	0 Size:	38.4 KB ID:	808115


          The 32 bits of a PB LONG are not in the same order. You cannot subnet a PB Long IP number by simple bit masking. (Try applying a /22 bit mask to a PB IP number and see if it works)

          Again, the bit pattern is exactly as networking uses. The REAL IP.
          Clearly, they are not.

          Which of these two bit patterns is "exactly as networking uses" (see image above)
          ---------------------------
          PowerBASIC
          ---------------------------
          172.16.254.1
          PB IP Long bit pattern: 00000001111111100001000010101100
          IP address bit pattern: 10101100000100001111111000000001
          ---------------------------
          OK
          ---------------------------



          '
          Code:
          #COMPILE EXE
          #DIM ALL
          FASTPROC DotIP4_Bin(BYVAL pDotted AS LONG, BYVAL Tmp AS LONG) AS LONG
            Tmp = VAL(PARSE$(PEEK$(pDotted, 15), ".", 4))
            SHIFT LEFT Tmp, 8
            Tmp OR= VAL(PARSE$(PEEK$(pDotted, 15), ".", 3))
            SHIFT LEFT Tmp, 8
            Tmp OR= VAL(PARSE$(PEEK$(pDotted, 15), ".", 2))
            SHIFT LEFT Tmp, 8
            Tmp OR= VAL(PARSE$(PEEK$(pDotted, 15), ".", 1))
          END FASTPROC = Tmp
          
          FUNCTION IPStringToDec(IPString AS STRING) AS DWORD
            'Converts a "dotted" IP address string to its decimal value
            FUNCTION = VAL(PARSE$(IPString, ".", 1)) * 16777216 + _
             VAL(PARSE$(IPString, ".", 2)) *  65536 + _
             VAL(PARSE$(IPString, ".", 3)) * 256  + _
             VAL(PARSE$(IPString, ".", 4))
          END FUNCTION
          
          FUNCTION PBMAIN() AS LONG
           LOCAL dotted AS STRING
           LOCAL IPNum AS LONG
           LOCAL IPaddr AS DWORD
           Dotted = "172.16.254.1"
           IPNum = DotIP4_Bin(STRPTR(Dotted), 0)
           IPAddr = IPStringToDec(dotted)
             ? Dotted & $LF &  _
             "PB IP Long bit pattern: " & BIN$(IPNum,32) & $LF & _
            "IP address bit pattern:  " & BIN$(IPAddr,32)
          END FUNCTION
          '
          Last edited by Stuart McLachlan; 1 Jun 2021, 11:49 PM.

          Comment


          • #6
            'Correct binary showing PB IP in long is little endian of
            'IP address
            '
            Code:
            172.16.254.1
            PB IP long bit pattern:
            00000001111111100001000010101100
            IP address bit pattern:
            10101100000100001111111000000001
            
            'Changed code lines in your PBMAIN
              ? bin$(IPNum, 32)   '<<<====== added comma thirtytwo
              '
              ? bin$(IPAddr, 32)  '<<<====== added comma thirtytwo
            '
            You were losing zeros!
            Dale

            Comment


            • #7
              My current theory is that it is double reverse.

              PB endian swaps before sending to NIC or Wifi. So we must endian swap before passing to make up for that swap. That really gives screwy number if assumed to be signed little endian.

              Alternate code for endian swap could use 2 PB SWAPs or one asm BSWAP. (after/before string/binary conversion)
              Dale

              Comment


              • #8
                Originally posted by Dale Yarker View Post
                '? bin$(IPNum, 32) '<<<====== added comma thirtytwo

                You were losing zeros!
                Doh! Should have noticed that

                I've edited post #6 to make the correction.

                Comment


                • #9
                  Originally posted by Dale Yarker View Post
                  My current theory is that it is double reverse.

                  PB endian swaps before sending to NIC or Wifi. So we must endian swap before passing to make up for that swap. That really gives screwy number if assumed to be signed little endian.

                  Alternate code for endian swap could use 2 PB SWAPs or one asm BSWAP. (after/before string/binary conversion)
                  That's essentially what IPToDecimal in Post #2 does
                  (Although it's not optimised and does four separate byte copies)

                  Comment

                  Working...
                  X