{"name":"nat.nu","source":"// examples/nat.nu — gather this host's connection candidates and probe the\n// NAT mapping type (TODO §7.4 Phase 1). On one UDP socket we discover:\n//   • host candidate  — our routable local IP + the socket's port\n//   • srflx candidate — the public endpoint a STUN server observed\n// then query a SECOND STUN server and compare the reflexive endpoints to\n// classify the NAT (cone → hole-punchable, symmetric → must relay).\n//\n//   ./nurl.sh examples/nat.nu\n//\n// Needs outbound UDP + DNS. Uses public STUN servers.\n\n$ `stdlib/core/string.nu`\n$ `stdlib/core/vec.nu`\n$ `stdlib/std/udp.nu`\n$ `stdlib/net/stun.nu`\n$ `stdlib/net/nat.nu`\n\n@ kind_name i k → s { ^ ? == k 0 `host ` ? == k 1 `srflx` `relay` }\n\n// Build \"<host>:<port>\" without nurl_print_int (which forces a newline).\n@ endpoint_str String host i port → String {\n    : String s ( string_with_cap 48 )\n    ( string_push_str s ( string_data host ) )\n    ( string_push_char s 58 )\n    ( string_push_int s port )\n    ^ s\n}\n\n@ show_candidates ( Vec s ) cs → v {\n    : i n ( vec_len [s] cs )\n    ( nurl_print `candidates:\\n` )\n    : ~ i k 0\n    ~ < k n {\n        : s pp ?? ( vec_get [s] cs k ) { T x → x F → # s 0 }\n        ? != # i pp 0 {\n            : *Candidate c # *Candidate pp\n            : String ep ( endpoint_str . c host . c port )\n            ( nurl_print `  [` ) ( nurl_print ( kind_name . c kind ) ) ( nurl_print `] ` )\n            ( nurl_print ( string_data ep ) )\n            ( nurl_print ? == . c family 2 `  (IPv6)\\n` `  (IPv4)\\n` )\n            ( string_free ep )\n        } {}\n        = k + k 1\n    }\n}\n\n@ type_name i t → s { ^ ? == t 1 `endpoint-independent (cone) — hole punch can work` ? == t 2 `symmetric / CGNAT — go straight to a relay` `unknown (STUN unreachable)` }\n\n@ main → i {\n    : !UdpSocket NetErr sr ( udp_bind_any )\n    ?? sr {\n        T sock → {\n            // ── candidates ───────────────────────────────────────\n            : ( Vec s ) cs ( nat_gather sock `stun.l.google.com` 19302 3000 )\n            ( show_candidates cs )\n            ( nat_candidates_free cs )\n\n            // ── NAT-type probe (two distinct servers) ─────────────\n            ( nurl_print `\\nprobing NAT type …\\n` )\n            : i t ( nat_probe sock `stun.l.google.com` 19302 `stun.cloudflare.com` 3478 3000 )\n            ( nurl_print `NAT type: ` ) ( nurl_print ( type_name t ) ) ( nurl_print `\\n` )\n            ( nurl_print ? ( nat_punchable t ) `→ attempt direct UDP hole punch\\n` `→ relay path\\n` )\n\n            ( udp_close sock )\n        }\n        F e → ( nurl_print `bind failed\\n` )\n    }\n    ^ 0\n}\n","bytes":2725}