From 7d41626b1c8f343b5b59a35ea3bce6570b996213 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 19 Oct 2026 02:48:58 +0100 Subject: 140's 1, DNS messages (RFC 1035), written in aup with no new opcode (aup's examples/dns.aup: a message read by a handler into its header and records, names uncompressed in their wire form, those in NS, CNAME, PTR, MX, SOA and SRV data too, each pointer pointing before the last; written back by the view wire, the owners compressed): 400 messages dnspython made (148,582 bytes, 3,466 records: A, AAAA, NS, CNAME, PTR, MX, SOA, TXT, SRV, EDNS, shared suffixes, 63-byte labels, bytes above 0x7f, 245-byte names) read on the three paths as dnspython reads them (each section's records as a set) and written back to bytes dnspython reads as the same message, the paths' outputs the same bytes; 300 damaged messages as dns_message.py (the Python reference) reads them, 185 refused by both and 115 the same records and bytes; module_specs in make check: 200 of those messages (tests/specs/dns, no dnspython at check time) read on the three paths, written back and read again to the same state and bytes, 23 cut ones failing; dnspython shuffles a set's records unless want_shuffle is off, and merges a set's differing TTLs to the least; bars: written, two workarounds both the core's (bytes have no ==: TEXT_COMPARE takes text alone; a view calls no block fn: CALL is in handlers and functions alone), 115 lines against Python's 72, 244 ns a message byte read and written against the same algorithm in C 3.65 (67x), glibc's resolver reading alone 4.4, pure Python 131 (Pure 1.9x slower), 218 compiled; 63.6 instructions a byte, reading 42%, writing 58%; CHECKPOINT's direction row --- tests/check.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'tests/check.py') diff --git a/tests/check.py b/tests/check.py index 4f2fb98..b78b184 100644 --- a/tests/check.py +++ b/tests/check.py @@ -1731,7 +1731,9 @@ def module_specs(aup, pure, work): every y_ case taken, every n_ case refused (a refusal: valid false, or the event failing as encoding on bytes that are not UTF-8); JSON read into a tree (its examples/json_tree.aup); raw deflate streams zlib made inflated - by its examples/inflate.aup to the original's bytes, cut ones refused.""" + by its examples/inflate.aup to the original's bytes, cut ones refused; DNS + messages dnspython made (tests/specs/dns) read by its examples/dns.aup and + written back by its view to the same records, cut ones refused.""" import hashlib import os import random @@ -1864,6 +1866,36 @@ def module_specs(aup, pure, work): for state in shown[len(streams):]: assert state['fault'] != 'none' and state['states']['inflated'][-1]['data'] == streams[-1][0].hex(), ('inflate cut', state['fault']) runs['inflate'] = {'streams': len(streams), 'bytes': sum(len(d) for d, _ in streams), 'cut': len(cut)} + # DNS messages (RFC 1035, its examples/dns.aup): messages dnspython made (tests/specs/dns), each read without fault on + # the three paths, what its view wire writes back read to the same records and written again to the same bytes; a + # message cut short fails its event. + program = work / 'dns.pmod' + compile_module(aup, EXAMPLES / 'dns.aup', program) + given, wires = (pure / 'tests/specs/dns/messages.bin').read_bytes(), [] + while given: + wires.append(given[2:2 + int.from_bytes(given[:2], 'big')]) + given = given[2 + len(wires[-1]):] + + def read(messages, env): + lines = '' + for n, wire in enumerate(messages): + (work / f'{n}.dns').write_bytes(wire) + lines += f'message read @{work / f"{n}.dns"}\n' + return subprocess.run([str(pure / 'build/pure-run'), str(program)], input=lines, capture_output=True, text=True, + timeout=600, env=dict(os.environ, **env)).stdout + + outputs = {name: read(wires, env) for name, env in + (('batches', {'PURE_JIT': '0'}), ('rounds', {'PURE_JIT': '0', 'PURE_BATCH': '0'}), ('all', {'PURE_JIT': 'all'}))} + for name in ('rounds', 'all'): + assert outputs[name] == outputs['batches'], ('dns', name) + first = [json.loads(line) for line in outputs['batches'].splitlines()] + assert len(first) == len(wires) and all(state['fault'] == 'none' for state in first), 'dns' + written = [bytes.fromhex(state['views']['wire']) for state in first] + again = [json.loads(line) for line in read(written, {}).splitlines()] + assert [(a['states'], a['views']) for a in again] == [(f['states'], f['views']) for f in first], 'dns written back' + cut = [wire[:len(wire) // 2] for wire in wires[::9]] + assert all(json.loads(line)['fault'] != 'none' for line in read(cut, {}).splitlines()), 'dns cut' + runs['dns'] = {'messages': len(wires), 'records': sum(len(state['states']['records']) for state in first), 'cut': len(cut)} return runs -- cgit v1.2.3