Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

101 行
2.5 KiB

  1. import asyncio
  2. import random
  3. import socket
  4. import struct
  5. import unittest
  6. from util import *
  7. # This function based upon code from:
  8. # https://gist.github.com/petrdvor/e802bec72e78ace061ab9d4469418fae#file-async-multicast-receiver-server-py-L54-L72
  9. def make_multisock(maddr):
  10. # family, type, proto, ??, addr)
  11. addrinfo = socket.getaddrinfo(*maddr, type=socket.SOCK_DGRAM)[0]
  12. sock = socket.socket(*addrinfo[:2])
  13. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  14. sock.bind(maddr)
  15. group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
  16. mreq = group_bin + struct.pack('=I', socket.INADDR_ANY)
  17. sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
  18. return sock
  19. class StupidProtocol(object):
  20. def __init__(self):
  21. self.transport = None
  22. def close(self):
  23. return self.transport.close()
  24. def connection_lost(self, exc):
  25. self.transport = None
  26. def connection_made(self, transport):
  27. # Note: the connection_made call seems to be sync. This
  28. # isn't documented, and I don't know how to force a test
  29. # if it isn't.
  30. self.transport = transport
  31. class ReceiverProtocol(StupidProtocol):
  32. def __init__(self):
  33. super().__init__()
  34. self._q = asyncio.Queue()
  35. def datagram_received(self, data, addr):
  36. self._q.put_nowait((data, addr))
  37. async def recv(self):
  38. return await self._q.get()
  39. async def create_multicast_receiver(maddr):
  40. sock = make_multisock(maddr)
  41. loop = asyncio.get_running_loop()
  42. transport, protocol = await loop.create_datagram_endpoint(
  43. lambda: ReceiverProtocol(),
  44. sock=sock)
  45. return protocol
  46. class TransmitterProtocol(StupidProtocol):
  47. async def send(self, msg):
  48. self.transport.sendto(msg)
  49. async def create_multicast_transmitter(maddr):
  50. loop = asyncio.get_running_loop()
  51. transport, protocol = await loop.create_datagram_endpoint(
  52. lambda: TransmitterProtocol(),
  53. remote_addr=maddr)
  54. return protocol
  55. class TestMulticast(unittest.IsolatedAsyncioTestCase):
  56. @timeout(2)
  57. async def test_multicast(self):
  58. # see: https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml#multicast-addresses-1
  59. maddr = ('224.0.0.199', 3485)
  60. l1 = await create_multicast_receiver(maddr)
  61. l2 = await create_multicast_receiver(maddr)
  62. t1 = await create_multicast_transmitter(maddr)
  63. msg = b'test message'
  64. await t1.send(msg)
  65. await t1.send(msg)
  66. self.assertEqual((await l1.recv())[0], msg)
  67. self.assertEqual((await l2.recv())[0], msg)
  68. self.assertEqual((await l1.recv())[0], msg)
  69. self.assertEqual((await l2.recv())[0], msg)
  70. t1.close()
  71. l1.close()
  72. l2.close()