Autodiscovery of LAN devices
Bob Sneidar
bobsneidar at iotecdigital.com
Mon Oct 31 10:55:08 EDT 2016
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, slylabs13 at icloud.com
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 <ambassador at fourthworld.com> 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
> use-livecode at lists.runrev.com
> Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
> http://lists.runrev.com/mailman/listinfo/use-livecode
More information about the use-livecode
mailing list