mdns_example_test.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import os
  2. import re
  3. import socket
  4. import struct
  5. import subprocess
  6. import time
  7. from threading import Event, Thread
  8. import dpkt
  9. import dpkt.dns
  10. import ttfw_idf
  11. from tiny_test_fw import DUT
  12. stop_mdns_server = Event()
  13. esp_answered = Event()
  14. def get_dns_query_for_esp(esp_host):
  15. dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
  16. dns.qd[0].name = esp_host + u'.local'
  17. print('Created query for esp host: {} '.format(dns.__repr__()))
  18. return dns.pack()
  19. def get_dns_answer_to_mdns(tester_host):
  20. dns = dpkt.dns.DNS(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
  21. dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA
  22. dns.rcode = dpkt.dns.DNS_RCODE_NOERR
  23. arr = dpkt.dns.DNS.RR()
  24. arr.cls = dpkt.dns.DNS_IN
  25. arr.type = dpkt.dns.DNS_A
  26. arr.name = tester_host
  27. arr.ip = socket.inet_aton('127.0.0.1')
  28. dns. an.append(arr)
  29. print('Created answer to mdns query: {} '.format(dns.__repr__()))
  30. return dns.pack()
  31. def get_dns_answer_to_mdns_lwip(tester_host, id):
  32. dns = dpkt.dns.DNS(b'\x5e\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x0a\x64\x61\x76\x69\x64'
  33. b'\x2d\x63\x6f\x6d\x70\x05\x6c\x6f\x63\x61\x6c\x00\x00\x01\x00\x01\xc0\x0c'
  34. b'\x00\x01\x00\x01\x00\x00\x00\x0a\x00\x04\xc0\xa8\x0a\x6c')
  35. dns.qd[0].name = tester_host
  36. dns.an[0].name = tester_host
  37. dns.an[0].ip = socket.inet_aton('127.0.0.1')
  38. dns.an[0].rdata = socket.inet_aton('127.0.0.1')
  39. dns.id = id
  40. print('Created answer to mdns (lwip) query: {} '.format(dns.__repr__()))
  41. return dns.pack()
  42. def mdns_server(esp_host):
  43. global esp_answered
  44. UDP_IP = '0.0.0.0'
  45. UDP_PORT = 5353
  46. MCAST_GRP = '224.0.0.251'
  47. TESTER_NAME = u'tinytester.local'
  48. TESTER_NAME_LWIP = u'tinytester-lwip.local'
  49. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  50. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  51. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  52. sock.bind((UDP_IP,UDP_PORT))
  53. mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
  54. sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
  55. sock.settimeout(30)
  56. while not stop_mdns_server.is_set():
  57. try:
  58. if not esp_answered.is_set():
  59. sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT))
  60. time.sleep(0.2)
  61. data, addr = sock.recvfrom(1024)
  62. dns = dpkt.dns.DNS(data)
  63. if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
  64. if dns.qd[0].name == TESTER_NAME:
  65. print('Received query: {} '.format(dns.__repr__()))
  66. sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP,UDP_PORT))
  67. elif dns.qd[0].name == TESTER_NAME_LWIP:
  68. print('Received query: {} '.format(dns.__repr__()))
  69. sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr)
  70. if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A:
  71. if dns.an[0].name == esp_host + u'.local':
  72. print('Received answer to esp32-mdns query: {}'.format(dns.__repr__()))
  73. esp_answered.set()
  74. except socket.timeout:
  75. break
  76. except dpkt.UnpackError:
  77. continue
  78. @ttfw_idf.idf_example_test(env_tag='Example_WIFI')
  79. def test_examples_protocol_mdns(env, extra_data):
  80. global stop_mdns_server
  81. """
  82. steps: |
  83. 1. join AP + init mdns example
  84. 2. get the dut host name (and IP address)
  85. 3. check the mdns name is accessible
  86. 4. check DUT output if mdns advertized host is resolved
  87. """
  88. dut1 = env.get_dut('mdns-test', 'examples/protocols/mdns', dut_class=ttfw_idf.ESP32DUT)
  89. # check and log bin size
  90. binary_file = os.path.join(dut1.app.binary_path, 'mdns-test.bin')
  91. bin_size = os.path.getsize(binary_file)
  92. ttfw_idf.log_performance('mdns-test_bin_size', '{}KB'.format(bin_size // 1024))
  93. # 1. start mdns application
  94. dut1.start_app()
  95. # 2. get the dut host name (and IP address)
  96. specific_host = dut1.expect(re.compile(r'mdns hostname set to: \[([^\]]+)\]'), timeout=30)
  97. specific_host = str(specific_host[0])
  98. thread1 = Thread(target=mdns_server, args=(specific_host,))
  99. thread1.start()
  100. try:
  101. ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30)[0]
  102. print('Connected to AP with IP: {}'.format(ip_address))
  103. except DUT.ExpectTimeout:
  104. stop_mdns_server.set()
  105. thread1.join()
  106. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
  107. try:
  108. # 3. check the mdns name is accessible
  109. if not esp_answered.wait(timeout=30):
  110. raise ValueError('Test has failed: did not receive mdns answer within timeout')
  111. # 4. check DUT output if mdns advertized host is resolved
  112. dut1.expect(re.compile(r'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30)
  113. dut1.expect(re.compile(r'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
  114. dut1.expect(re.compile(r'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
  115. # 5. check the DUT answers to `dig` command
  116. dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251',
  117. '{}.local'.format(specific_host)])
  118. print('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output))
  119. if not ip_address.encode('utf-8') in dig_output:
  120. raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig'
  121. "Output should've contained DUT's IP address:{}".format(ip_address))
  122. finally:
  123. stop_mdns_server.set()
  124. thread1.join()
  125. if __name__ == '__main__':
  126. test_examples_protocol_mdns()