# chanora_resolver The library accepts the same kind of raw server input a client UI receives and returns a final `host:port` address suitable for `tsclientlib::Connection::build` or Chanora's `ConnectConfig.address`. ## Resolution Flow Use `ChanoraResolver::resolve_client_request` or `resolve_client_address` for app code. The resolver owns the decision tree: 1. Normalize raw client input, including `ts3server://host?port=...`. 2. For dotless names such as `6666` or `wwb`, query the myTeamSpeak server-name endpoint first. If it returns a hostname, restart normal resolution with that hostname. If it returns `ip:port`, use that final address. 3. Start plain A/AAAA DNS as the final fallback address. 4. If the user supplied an explicit port and DNS resolved, return that direct target immediately. 5. Prefer `_ts3._udp.` SRV. Its target host and port override the default port, then the target is resolved to a final IP. 6. Try `_tsdns._tcp.` SRV on candidate parent/full hosts and query the returned TSDNS server over TCP. 7. Try direct TSDNS TCP on candidate parent/full hosts at port `41144`. 8. Fall back to the A/AAAA result with the default TeamSpeak port `9987`. When DNS fallback is already available, TSDNS discovery is capped so missing or filtered TSDNS cannot add multi-second join delays. The older explicit API (`Args { host, service, protocol }`) is still available for diagnostic example use. ## DNS Setup Guide This chart is for choosing DNS records when operating a TeamSpeak 3 server. It is not the client lookup order; the library still implements the client-side resolver behavior above. ```mermaid flowchart TD A["Which DNS type fits your TeamSpeak 3 server?"] A --> X["Don't do this!"] X --> X1["Do not use simple TSDNS
without SRV TSDNS"] A --> B{"How many servers do you have?"} B -->|One virtual server| C{"Does your server use
the default port 9987?"} C -->|Yes| D{"Do all services under this domain
run on the same server
as the TS3 server?"} D -->|Yes| E1["Use A/AAAA or CNAME"] D -->|No| E2["Use SRV TS3"] C -->|No| F{"Are you okay with
entering the port manually?"} F -->|No| E3["Use SRV TS3"] F -->|Yes| G{"Do all services under this domain
run on the same server
as the TS3 server?"} G -->|Yes| E4["Use A/AAAA or CNAME"] G -->|No| E5["Use SRV TSDNS"] B -->|More than one virtual server| H{"Are you okay with port numbers?"} H -->|No| I1["Use subdomains with SRV TS3
for each subdomain"] H -->|Yes| I{"On how many servers
do you run TS3 servers?"} I -->|Only one| J{"Do all services under this domain
run on the same server
as the TS3 server?"} J -->|Yes| K1["Use A/AAAA or CNAME"] J -->|No| K2["Use SRV TSDNS"] I -->|More than one| K3["Use subdomains with A/AAAA
or CNAME for each server"] ``` ## Library Example ```rust use chanora_resolver::ChanoraResolver; let client = ChanoraResolver::new()?; let address = client.resolve_client_address("voice.teamspeak.com").await?; // tsclientlib: // let mut connection = tsclientlib::Connection::build(address).connect()?; // Chanora: // let cfg = chanora_core::ConnectConfig { // address, // nickname, // password, // identity, // ready_timeout, // }; // let snapshot = session.connect(cfg).await?; ``` ## Run ```bash cargo run --example library -- voice.teamspeak.com cargo run --example library -- 6666 cargo run --example library -- wwb cargo run --example library -- kr.teamspeak.app cargo run --example library -- 'ts3server://voice.teamspeak.com?port=9987' cargo run --example cli -- -host voice.teamspeak.com -service ts3 ``` `example_log` contains live sample outputs for TS3 SRV, DNS fallback, server-name lookup, and unsuccessful TSDNS attempts that must remain non-fatal. ## Fail-Safes - Bare numeric names such as `6666` are treated as server names first, avoiding OS DNS coercion into numeric IPv4 addresses. - SRV targets and TSDNS responses are resolved to final IP addresses before handoff, so Chanora can pass a concrete `SocketAddr`-style `host:port` to `tsclientlib`. - TSDNS TCP lookups use short timeouts and are non-fatal; DNS fallback remains available when TSDNS is absent or unreachable. - Android uses an explicit SRV resolver configuration instead of relying on system resolver initialization in a raw binary context. ## Test ```bash cargo fmt --all -- --check cargo test cargo clippy --all-targets --all-features -- -D warnings ```