Files
chanora/crates/chanora_resolver

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.<host> SRV. Its target host and port override the default port, then the target is resolved to a final IP.
  6. Try _tsdns._tcp.<candidate> 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.

flowchart TD
    A["Which DNS type fits your TeamSpeak 3 server?"]

    A --> X["Don't do this!"]
    X --> X1["Do not use simple TSDNS<br/>without SRV TSDNS"]

    A --> B{"How many servers do you have?"}

    B -->|One virtual server| C{"Does your server use<br/>the default port 9987?"}

    C -->|Yes| D{"Do all services under this domain<br/>run on the same server<br/>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<br/>entering the port manually?"}
    F -->|No| E3["Use SRV TS3"]
    F -->|Yes| G{"Do all services under this domain<br/>run on the same server<br/>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<br/>for each subdomain"]

    H -->|Yes| I{"On how many servers<br/>do you run TS3 servers?"}
    I -->|Only one| J{"Do all services under this domain<br/>run on the same server<br/>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<br/>or CNAME for each server"]

Library Example

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

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

cargo fmt --all -- --check
cargo test
cargo clippy --all-targets --all-features -- -D warnings