An implementation of the Application Layer Network (ALN).
Project description
Application Layer Network - Python 3
alnmeshpy is a Python implementation of Application Layer Network (ALN),
an amature mesh networking protocol for home lab networking designed for
hacking prototype projects that benefit from the simplicity gained from
completely ignoring security as a concern. Don't use this for production.
Install with --no-deps unless you need Bluetooth support (very experimental) which use bleak and aiofiles.
pip install --no-deps alnmeshpy
The example app demonstrates a 3-node topology
- Node 1 hosts TCP connections and demonstrates mesh networking
- Node 2 connects to Node 1 and provides a 'ping' service
- Node 3 connects to Node 1 and sends packets to 'ping' service
Running example
Node 1
import selectors, signal
from alnmeshpy import TcpHost, Router
def main():
sel = selectors.DefaultSelector() # app event loop
router = Router(sel, "python-host-1") # must be unique
router.start() # Router is a Thread object
def on_connect(tcpChannel, addr): # define TCP host listener
router.add_channel(tcpChannel) # give all new channels to our single router
TcpHost().listen(sel, 'localhost', 8081, on_connect)
def signal_handler(signal, frame): # listen for ^C
router.close()
sel.close()
signal.signal(signal.SIGINT, signal_handler)
signal.pause()
if __name__ == "__main__":
main()
Node 2
import selectors, signal, socket
from alnmeshpy import TcpChannel, Router,Packet
def main():
sel = selectors.DefaultSelector()
router = Router(sel, "python-ping-service-1")
router.start() # router s a Thread object so it must be started
def ping_handler(packet):
print("ping from [{0}]".format(packet.srcAddr))
router.send(Packet(
destAddr=packet.srcAddr, # return to sender
contextID=packet.contextID, # required
data="pong"
))
router.register_service("ping", ping_handler)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 8081)) # hard-coded address for demonstration
router.add_channel(TcpChannel(sock)) # let the router operate on this channel
def signal_handler(signal, frame):
router.close()
sel.close()
signal.signal(signal.SIGINT, signal_handler)
signal.pause()
if __name__ == "__main__":
main()
Node 3
import selectors, signal, socket, time
from alnmeshpy import TcpChannel, Router,Packet
def main():
sel = selectors.DefaultSelector()
router = Router(sel, "python-browser-client-1")
router.start()
def on_pong(packet): # define the ping response handler
print('received:', str(packet.data), 'from:', packet.srcAddr)
time.sleep(1) # wait a second then ping again
router.send(Packet(service="ping", contextID=packet.contextID))
ctxID = router.register_context_handler(on_pong) # set response handler
# send a packet when a 'ping' service is discovered
def on_service_discovery(service, capacity, address):
print("on_service_discovery: {0}:{1}:{2}".format(service, capacity, address))
if service == "ping":
print("sending ping with ctxID {0}".format(ctxID))
router.send(Packet(destAddr=address, service="ping", contextID=ctxID))
router.set_on_service_capacity_changed_handler(on_service_discovery)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 8081)) # hard-coded address for demonstration
router.add_channel(TcpChannel(sock)) # let the router operate on this channel
def signal_handler(signal, frame):
router.close()
sel.close()
signal.signal(signal.SIGINT, signal_handler)
signal.pause()
if __name__ == "__main__":
main()
Integration test
This test is functionally equivalent but uses pipes to connect all 3 routers within a single process. This script serves as a useful integration test when hacking on the protocol.
import os, selectors, signal
from threading import Lock
from alnmeshpy import LocalChannel, Router,Packet
# this is an integration test that configures 3 nodes
# node 1 advertises a ping service that responds with a 'pong'
# node 2 is an intermediate node that demonstrates multi-hop routing
# node 3 listens for the ping service advertisment and sends a pack to it
# finally node 3 prints the content of the ping packet
def main():
r1a, w1a = os.pipe()
r2a, w2a = os.pipe()
ch1a = LocalChannel(r1a, w2a)
ch2a = LocalChannel(r2a, w1a)
sel = selectors.DefaultSelector()
# configure the ping handler on node 1
def ping_handler(packet):
print("ping from [{0}]".format(packet.srcAddr))
router1.send(Packet(
destAddr=packet.srcAddr,
contextID=packet.contextID,
data="pong"
))
router1 = Router(sel, "aln-node-1")
router1.start()
router1.register_service("ping", ping_handler)
# node 2 exists to test mesh networking
router2 = Router(sel, "aln-node-2")
router2.start()
router1.add_channel(ch1a)
router2.add_channel(ch2a)
r1b, w1b = os.pipe()
r2b, w2b = os.pipe()
ch1b = LocalChannel(r1b, w2b)
ch2b = LocalChannel(r2b, w1b)
# node 3 will:
# listen for the ping service advertisment advertisement
# send a 'ping' packet to the advertising node
# print the response to the console
router3 = Router(sel, "aln-node-3")
router3.start()
# set up listener for ping response
def on_packet(packet):
print(packet.toJsonString())
print('unpacked response data:', packet.data)
print('ctrl-C to quit')
ctxID = router3.register_context_handler(on_packet)
# set up a service discovery handler for the "ping" service
def on_service_discovery(service, capacity, address):
print("on_service_discovery at aln-node-3: {0}:{1}:{2}".format(service, capacity, address))
if service == "ping":
print("sending ping with ctxID {0}".format(ctxID))
text = "hello world".encode(encoding="utf-8")
router3.send(Packet(destAddr=address, service="ping", contextID=ctxID, data=text))
router3.set_on_service_capacity_changed_handler(on_service_discovery)
router3.add_channel(ch2b)
router2.add_channel(ch1b)
def signal_handler(signal, frame):
sel.close()
signal.signal(signal.SIGINT, signal_handler)
signal.pause()
if __name__ == "__main__":
main()
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file alnmeshpy-0.1.0.tar.gz.
File metadata
- Download URL: alnmeshpy-0.1.0.tar.gz
- Upload date:
- Size: 28.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec9ce1a39c522d6063a1a985c37821aedf54e8a9d6541ba79e1bdd25e64d0774
|
|
| MD5 |
354a949d35bc22bd97ff2dbc04a3c8aa
|
|
| BLAKE2b-256 |
3099e3d3b1846daff70edafb0f4b725679e9f51d030947a32670f98e0d17dfbd
|
File details
Details for the file alnmeshpy-0.1.0-py3-none-any.whl.
File metadata
- Download URL: alnmeshpy-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2beb50ce32c6811b8fa2adaa6160e83e1c5588d12da5b41e2dd12134dcc89732
|
|
| MD5 |
e901b9865320eeaad712b87939cd2697
|
|
| BLAKE2b-256 |
3bd184f06d2c8ec5aff4dbb0fcdbf17a85dc8f5a671727e699733f15c60a9a7e
|