You must not have my latest. Keep in mind that this function requires a CIDR 
notation or else the IP and subnet mask. Nothing can calculate the subnet with 
only an IP address. 

Bob S

function IPCalc theIPAddress, theSubnetMask
   /* IPCalc yyy
      Syntax:
      IPCalc theIPAddress, [theSubnetMask]
      Examples:
      
      Description:
      Derive Internet values from either CIDR notation in the IPAddress
      or a standard IP and subnet mask
   
      Input: 
      .    theIPAddress -  the IP address in CIDR notation
       or
      .    theIPAddress - a standard IP address and
     .     theSubNetMask - a standard subNetMask
   
      Returns an array of the following values:
      .   bcastaddr
      .   cidraddr
      .   cidrdepth
      .   firstaddr
      .   ipaddress
      .   lastaddr
      .   subnetaddr
      .   subnetmask
      .   usablecount
      Returns a string beginning with ERROR: if the parameters are out of range
      Check that the returned value is an array to see if there was an error
   
   Source:
       Bob Sneidar,  [email protected]
   IPCalc */
   
   set the itemdelimiter to "."
   
   -- check parameters
   -- the IP address must be 4 octets of numbers
   if the number of items of theIPAddress <>4 \
         or the last char of theIPAddress is "." \
         or ".." is in theIPAddress then
      return "ERROR: The IP Address must be in the form:" & cr & \
            "'nnn.nnn.nnn.nnn' or 'nnn.nnn.nnn.nnn/nn'. (ipaddress = '" & 
theIPAddress & "')"
   end if
   
   -- initial setup
   set the numberformat to "00000000"
   
   -- detemine format
   if theIPAddress contains "/" then
      put offset("/", theIPAddress) into theCIDRDelim
      put char theCIDRDelim +1 to -1 of theIPAddress into theCIDRDepth
      
      -- CIDR depth must be a WHOLE number
      put cleanString(theCIDRDepth) into theCIDRDepth
      
      if theCIDRDepth is not a number then
         return "ERROR: The CIDR Depth must be a number between 0 and 32. " & \
               "(CIDRDepth = '" & theCIDRDepth & "')"
      end if
      
      put charx("1", theCIDRDepth) & charx("0", 32-theCIDRDepth) into 
theBinSubnetMask
      put baseconvert(char 1 to 8 of theBinSubnetMask, 2, 10) into item 1 of 
theSubnetMask
      put baseconvert(char 9 to 16 of theBinSubnetMask, 2, 10) into item 2 of 
theSubnetMask
      put baseconvert(char 17 to 24 of theBinSubnetMask, 2, 10) into item 3 of 
theSubnetMask
      put baseconvert(char 25 to 32 of theBinSubnetMask, 2, 10) into item 4 of 
theSubnetMask
      put char 1 to theCIDRDelim -1 of theIPAddress into theIPAddress
   else
      -- subnet mask octets must be 4 numbers between 0 and 255
      -- and all octets after the first octet less than 255 must be 0
      
      if the number of items of theSubnetMask <>4 \
            or the last char of theSubnetMask is "." \
            or ".." is in theSubnetMask then
         return "ERROR: The Subnet Mask must be in the form:" & cr & \
               "'nnn.nnn.nnn.nnn' (subnetmask = '" & theSubnetMask & "')"
      end if
      
      put false into mustBeZero
      repeat for each item theOctet in theSubnetMask
         
         if theOctet <0 or theOctet >255 then
            return "Each octet in the subnet mask must be a number between 0 
and 255. " & \
                  "(subnetmask = '" & theSubnetMask & "')"
         end if
         
         if mustBeZero and theOctet >0 then
            return "ERROR: All octets after an octet less than 255 must be 0. " 
& \
                  "(subnetmask = '" & theSubnetMask & "')"
         end if
         
         if theOctet <255 then
            put true into mustBeZero
         end if
      end repeat
      
      -- convert the subnet mask to binary
      put 0 into whichOctet
      repeat for each item theOctet in theSubnetMask
         add 1 to whichOctet
         
         -- subnet mask must contain only 4 octets
         if whichOctet >4 then
            return "ERROR: The Subnet Mask must contain 4 numbers between 0 and 
255 " & \
                  "separated by periods. (subnetmask = '" & theSubnetMask & "')"
         end if
         
         put value(baseconvert(theOctet, 10, 2)) after theBinSubnetMask
      end repeat
      put offset("0", theBinSubnetMask) -1 into theCIDRDepth
   end if
   
   -- CIDR depth must be between 0 and 32
   if theCIDRDepth <0 or theCIDRDepth >32 then
      return "ERROR: The CIDR Depth must be between 0 and 32. " & \
            "(CIDRDepth = '" & theCIDRDepth & "')"
   end if
   
   -- All octets of the IP address must be between 0 and 255
   repeat for each item theOctet in theIPAddress
      if theOctet is empty or theOctet < 0 or theOctet > 255 then
         return "ERROR: Each IP Address octet must be a number between 0 and 
255. " & \
               "(ipaddress = '" & theIPAddress & "')"
      end if
   end repeat
   
   -- convert the ip address to binary
   put 0 into whichOctet
   repeat for each item theOctet in theIPAddress
      add 1 to whichOctet
      put baseconvert(theOctet, 10, 2) into theBinValue
      add 0 to theBinValue
      put theBinValue after theBinIPAddress
   end repeat
   
   -- calculate the binary subnet address
   put char 1 to theCIDRDepth of theBinIPAddress into theBinNetworkAddr
   put char theCIDRDepth +1 to -1 of theBinIPAddress into theBinNodeAddr
   put theBinNodeAddr into theBinSubnetNodeAddr
   set the numberformat to "0"
   replace "1" with "0" in theBinSubnetNodeAddr
   put theBinNetworkAddr & theBinSubnetNodeAddr into theBinSubnetAddr
   
   -- convert the binary subnet address to decimal
   put baseconvert(char 1 to 8 of theBinSubnetAddr, 2, 10)  into item 1 of 
theSubnetAddr
   put baseconvert(char 9 to 16 of theBinSubnetAddr, 2, 10)  into item 2 of 
theSubnetAddr
   put baseconvert(char 17 to 24 of theBinSubnetAddr, 2, 10)  into item 3 of 
theSubnetAddr
   put baseconvert(char 25 to 32 of theBinSubnetAddr, 2, 10)  into item 4 of 
theSubnetAddr
   
   -- calculate the first usable IP address
   put theSubnetAddr into theFirstAddr
   add 1 to item 4 of theFirstAddr
   
   -- calculate the binary broadcast address
   put theBinNodeAddr into theBinBcastNodeAddr
   replace "0" with "1" in theBinBcastNodeAddr
   put theBinNetworkAddr & theBinBcastNodeAddr into theBinBcastAddr
   
   -- convert the binary broadcast address to decimal
   put baseconvert(char 1 to 8 of theBinBcastAddr, 2, 10) into item 1 of 
theBcastAddr
   put baseconvert(char 9 to 16 of theBinBcastAddr, 2, 10) into item 2 of 
theBcastAddr
   put baseconvert(char 17 to 24 of theBinBcastAddr, 2, 10) into item 3 of 
theBcastAddr
   put baseconvert(char 25 to 32 of theBinBcastAddr, 2, 10) into item 4 of 
theBcastAddr
   
   -- calculate the last usable IP address
   put theBcastAddr into theLastAddr
   subtract 1 from item 4 of theLastAddr
   
   -- calculate the number of usable addresses
   -- put item 4 of theLastAddr - item 4 of theFirstAddr +1 into theAddrCount
   put baseconvert(theBinBcastNodeAddr, 2, 10) -1 into theAddrCount
   
   -- calculate the CIDR notation
   put theIPAddress & "/" & theCIDRDepth into theCIDRAddr
   
   -- create array
   put theIPAddress into ipdata ["ipaddress"]
   put theSubnetMask into ipdata ["subnetmask"]
   put theSubnetAddr into ipdata ["subnetaddr"]
   put theFirstAddr into ipdata ["firstaddr"]
   put theBcastAddr into ipdata["bcastaddr"]
   put theLastAddr into ipdata ["lastaddr"]
   put theCIDRDepth into ipdata ["cidrdepth"]
   put theAddrCount into ipdata ["usablecount"]
   put theCIDRAddr into ipdata ["cidraddr"]
   return ipdata
end IPCalc


> On Oct 27, 2016, at 17:58 , Richard Gaskin <[email protected]> wrote:
> 
> Thanks, Alex.  I may need something more refined later on, but for now my 
> modest needs appear to be well met through simple brute force:
> 
> At the moment this is for some network tools for students to use in a 
> classroom.  Ideally there would be no Internet connection, just a local 
> network of a small number of devices all using a single wifi router.
> 
> I had experimented briefly with a UDP broadcast, but ran into an issue in 
> which it seemed the server wasn't receiving the message.
> 
> Before spending more time on that I tried a different tack with TCP.
> 
> With Bob's IPCalc function I'm able to get the first and last addresses of 
> the local subnet.  His function needs the local IP and subnet mask, which can 
> be obtained on Mac and Linux with a shell call to ifconfig, and on Win with 
> ipconfig.
> 
> Armed with that I just attempt a TCP connection to each device in turn, 
> looking for a specific reply.  When I get what I expect, I know I've reached 
> my app on the other machine.  Takes less than a second to scan the network.
> 
> Done in a few minutes' work.
> 
> Of course this won't do much for mobile devices (how do I get the local 
> address on iOS and Android without shell?), but since UDP is off the table 
> there anyway I'm no worse off, and can at least get started with laptops and 
> Raspberry Pis happily talking to one another...
> 
> --
> Richard Gaskin
> Fourth World Systems
> 
> 
> Alex Tweedly wrote:
> 
>> it might help if you were to more precisely describe the problem you are
>> seeking to solve.
>> 
>> If you need to discover all/any/arbitrary listeners - then "what Bob said".
>> 
>> If you need to discover listeners for a specific port/service provided
>> by some other apps/servers in a standard way - then "what Monte said".
>> 
>> If you need to discover instances of "your own" server on the LAN, then
>> there may be an other solution..... depending on how well defined "my
>> LAN" is.
>> 
>> Basically,
>> 
>> - every server listens for UDP packet on some port
>> 
>>  - client sends a broadcast UDP request to that port
>> 
>>  - servers respond.
>> 
>> This assumes that you can *reliably* depend on your LAN being a single
>> subnet, that your LAN is not too huge :-), that all servers are within
>> your control and you can add such a listener to them, etc.
>> 
>> NB - this is only a solution for desktops (only they can send broadcasts).
>> 
>> For ios you can use mergSomething :-)
>> 
>> For Android, afaik there isn't anything to allow broadcast transmission,
>> so I think your only solution for now is to move to a
>> broadcast/advertisement approach - servers (currently desktop only, you
>> said) must advertise their service, and Android clients can listen for
>> such adverts and thus learn where the service is available. This is only
>> feasible if you know of limits on the number of servers & services - or
>> (for-android as-client) if you are willing to add significant complexity
>> and have proxy-servers handle it for you; you can do that in an
>> automatic way (i.e. no configuration needed) but it is complex.
>> 
>> Don't even start down that road unless you need this for Android before
>> the timeframe for either bonjour or sockets on android.
>> 
>> (But if you do want to go down that road, get in touch I'd be happy to
>> collaborate)
>> 
>> -- Alex.
>> 
>> 
>> On 27/10/2016 22:12, Richard Gaskin wrote:
>>> I'd like to have an app automatically discover and attempt connection
>>> to other devices on my LAN.
>>> 
>>> Looking through the list archives I can find a few half-solutions, but
>>> not one which works well across the platforms LC supports (Mac, Win,
>>> Linux, iOS, Android).
>>> 
>>> At this time the only things listening on a port will be desktop
>>> computers, but I still need to be able to connect with them from any
>>> other device on the local network, and down the road I may want to
>>> allow even handheld devices to take on an accept role.
>>> 
>>> Any robust, tested solutions available?
>>> 
> 
> 
> _______________________________________________
> use-livecode mailing list
> [email protected]
> Please visit this url to subscribe, unsubscribe and manage your subscription 
> preferences:
> http://lists.runrev.com/mailman/listinfo/use-livecode


_______________________________________________
use-livecode mailing list
[email protected]
Please visit this url to subscribe, unsubscribe and manage your subscription 
preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode

Reply via email to