| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  | import select | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  | import socket | 
					
						
							|  |  |  | import struct | 
					
						
							| 
									
										
										
										
											2020-07-30 16:12:37 +02:00
										 |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  | import pytest | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | from threading import Event, Thread | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | import dpkt | 
					
						
							|  |  |  | import dpkt.dns | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  | from pytest_embedded import Dut | 
					
						
							|  |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | def get_dns_query_for_esp(esp_host): | 
					
						
							|  |  |  |     dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01') | 
					
						
							|  |  |  |     dns.qd[0].name = esp_host + u'.local' | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |     print('Created query for esp host: {} '.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |     return dns.pack() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_dns_answer_to_mdns(tester_host): | 
					
						
							|  |  |  |     dns = dpkt.dns.DNS(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') | 
					
						
							|  |  |  |     dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA | 
					
						
							|  |  |  |     dns.rcode = dpkt.dns.DNS_RCODE_NOERR | 
					
						
							|  |  |  |     arr = dpkt.dns.DNS.RR() | 
					
						
							|  |  |  |     arr.cls = dpkt.dns.DNS_IN | 
					
						
							|  |  |  |     arr.type = dpkt.dns.DNS_A | 
					
						
							|  |  |  |     arr.name = tester_host | 
					
						
							|  |  |  |     arr.ip = socket.inet_aton('127.0.0.1') | 
					
						
							| 
									
										
										
										
											2021-12-14 18:34:04 +01:00
										 |  |  |     dns.an.append(arr) | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |     print('Created answer to mdns query: {} '.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |     return dns.pack() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_dns_answer_to_mdns_lwip(tester_host, id): | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     dns = dpkt.dns.DNS(b'\x5e\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x0a\x64\x61\x76\x69\x64' | 
					
						
							|  |  |  |                        b'\x2d\x63\x6f\x6d\x70\x05\x6c\x6f\x63\x61\x6c\x00\x00\x01\x00\x01\xc0\x0c' | 
					
						
							|  |  |  |                        b'\x00\x01\x00\x01\x00\x00\x00\x0a\x00\x04\xc0\xa8\x0a\x6c') | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |     dns.qd[0].name = tester_host | 
					
						
							|  |  |  |     dns.an[0].name = tester_host | 
					
						
							|  |  |  |     dns.an[0].ip = socket.inet_aton('127.0.0.1') | 
					
						
							|  |  |  |     dns.an[0].rdata = socket.inet_aton('127.0.0.1') | 
					
						
							|  |  |  |     dns.id = id | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     print('Created answer to mdns (lwip) query: {} '.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |     return dns.pack() | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  | def mdns_server(esp_host, events): | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     UDP_IP = '0.0.0.0' | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  |     UDP_PORT = 5353 | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |     MCAST_GRP = '224.0.0.251' | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |     TESTER_NAME = u'tinytester.local' | 
					
						
							|  |  |  |     TESTER_NAME_LWIP = u'tinytester-lwip.local' | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  |     QUERY_TIMEOUT = 0.2 | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  |     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | 
					
						
							|  |  |  |     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  |     sock.setblocking(False) | 
					
						
							| 
									
										
										
										
											2021-12-14 18:34:04 +01:00
										 |  |  |     sock.bind((UDP_IP, UDP_PORT)) | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |     sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  |     last_query_timepoint = time.time() | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |     while not events['stop'].is_set(): | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  |             current_time = time.time() | 
					
						
							| 
									
										
										
										
											2021-06-30 08:42:09 +02:00
										 |  |  |             if current_time - last_query_timepoint > QUERY_TIMEOUT: | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  |                 last_query_timepoint = current_time | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |                 if not events['esp_answered'].is_set(): | 
					
						
							| 
									
										
										
										
											2021-12-14 18:34:04 +01:00
										 |  |  |                     sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP, UDP_PORT)) | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |                 if not events['esp_delegated_answered'].is_set(): | 
					
						
							| 
									
										
										
										
											2021-12-14 18:34:04 +01:00
										 |  |  |                     sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP, UDP_PORT)) | 
					
						
							| 
									
										
										
										
											2021-05-11 13:47:03 +08:00
										 |  |  |             timeout = max(0, QUERY_TIMEOUT - (current_time - last_query_timepoint)) | 
					
						
							|  |  |  |             read_socks, _, _ = select.select([sock], [], [], timeout) | 
					
						
							|  |  |  |             if not read_socks: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |             data, addr = sock.recvfrom(1024) | 
					
						
							|  |  |  |             dns = dpkt.dns.DNS(data) | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  |             if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A: | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |                 if dns.qd[0].name == TESTER_NAME: | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |                     print('Received query: {} '.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2021-12-14 18:34:04 +01:00
										 |  |  |                     sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP, UDP_PORT)) | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |                 elif dns.qd[0].name == TESTER_NAME_LWIP: | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |                     print('Received query: {} '.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2019-06-19 13:20:58 +02:00
										 |  |  |                     sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr) | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  |             if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A: | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |                 print('Received answer from {}'.format(dns.an[0].name)) | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  |                 if dns.an[0].name == esp_host + u'.local': | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |                     print('Received answer to esp32-mdns query: {}'.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |                     events['esp_answered'].set() | 
					
						
							| 
									
										
										
										
											2021-04-15 20:03:53 +08:00
										 |  |  |                 if dns.an[0].name == esp_host + u'-delegated.local': | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |                     print('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__())) | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |                     events['esp_delegated_answered'].set() | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |         except socket.timeout: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2019-01-25 20:24:30 +01:00
										 |  |  |         except dpkt.UnpackError: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 08:32:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  | def test_examples_protocol_mdns(dut): | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     steps: | | 
					
						
							| 
									
										
										
										
											2022-01-14 14:33:13 +01:00
										 |  |  |       1. obtain IP address + init mdns example | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |       2. get the dut host name (and IP address) | 
					
						
							|  |  |  |       3. check the mdns name is accessible | 
					
						
							|  |  |  |       4. check DUT output if mdns advertized host is resolved | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     specific_host = dut.expect(re.compile(b'mdns hostname set to: \[(.*?)\]')).group(1).decode() | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mdns_server_events = {'stop': Event(), 'esp_answered': Event(), 'esp_delegated_answered': Event()} | 
					
						
							|  |  |  |     mdns_responder = Thread(target=mdns_server, args=(str(specific_host), mdns_server_events)) | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |     ip_address = dut.expect(re.compile(b'IPv4 address:([a-zA-Z0-9]*).*')).group(1).decode() | 
					
						
							|  |  |  |     print('Connected to AP with IP: {}'.format(ip_address)) | 
					
						
							| 
									
										
										
										
											2018-10-12 16:45:52 +02:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |         # 3. check the mdns name is accessible. | 
					
						
							| 
									
										
										
										
											2021-06-30 08:42:09 +02:00
										 |  |  |         mdns_responder.start() | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |         if not mdns_server_events['esp_answered'].wait(timeout=30): | 
					
						
							| 
									
										
										
										
											2020-05-15 10:41:14 +02:00
										 |  |  |             raise ValueError('Test has failed: did not receive mdns answer within timeout') | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |         if not mdns_server_events['esp_delegated_answered'].wait(timeout=30): | 
					
						
							| 
									
										
										
										
											2021-04-15 20:03:53 +08:00
										 |  |  |             raise ValueError('Test has failed: did not receive mdns answer for delegated host within timeout') | 
					
						
							| 
									
										
										
										
											2020-05-15 10:41:14 +02:00
										 |  |  |         # 4. check DUT output if mdns advertized host is resolved | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |         dut.expect(re.compile(b'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30) | 
					
						
							|  |  |  |         dut.expect(re.compile(b'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30) | 
					
						
							|  |  |  |         dut.expect(re.compile(b'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30) | 
					
						
							| 
									
										
										
										
											2020-07-30 16:12:37 +02:00
										 |  |  |         # 5. check the DUT answers to `dig` command | 
					
						
							|  |  |  |         dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251', | 
					
						
							|  |  |  |                                               '{}.local'.format(specific_host)]) | 
					
						
							| 
									
										
										
										
											2022-08-19 13:49:32 +04:00
										 |  |  |         print('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output)) | 
					
						
							| 
									
										
										
										
											2020-07-30 16:12:37 +02:00
										 |  |  |         if not ip_address.encode('utf-8') in dig_output: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |             raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig' | 
					
						
							| 
									
										
										
										
											2020-07-30 16:12:37 +02:00
										 |  |  |                              "Output should've contained DUT's IP address:{}".format(ip_address)) | 
					
						
							| 
									
										
										
										
											2019-01-25 20:24:30 +01:00
										 |  |  |     finally: | 
					
						
							| 
									
										
										
										
											2021-12-15 15:48:59 +01:00
										 |  |  |         mdns_server_events['stop'].set() | 
					
						
							| 
									
										
										
										
											2021-06-30 08:42:09 +02:00
										 |  |  |         mdns_responder.join() |