Crates.io | rsip-dns |
lib.rs | rsip-dns |
version | 0.1.4 |
source | src |
created_at | 2021-09-07 20:17:35.670723 |
updated_at | 2022-04-01 08:37:49.800919 |
description | SIP Rust library implementing RFC 3263, implemented on top of rsip |
homepage | |
repository | https://github.com/vasilakisfil/rsip |
max_upload_size | |
id | 448219 |
size | 99,968 |
SIP Rust library implementing RFC 3263, implemented on top of rsip
This library implements all the necessary DNS procedures defined in
RFC3263 that allow a client or a server to
resolve a SIP URI into the (ip, port, transport) tuple. rsip-dns
uses a lazy enumerator
architecture, in a sense of a Stream (but does not implement the Stream trait), which means
any query to the DNS client is performend only when needed.
The first thing you need is to specify a Context
which will act as a guide to the Lookup
.
The Context
, among others, expect anything that implements the DnsClient
trait. Refer to
that for more information. rsip-dns
provides a default implementation of that trait
that you can use under the trust-dns
feature flag.
use rsip_dns::*;
use std::net::{IpAddr, Ipv4Addr};
use rsip::{Transport, Port, Host};
let context = Context {
secure: true,
host: Host::from(IpAddr::V4(Ipv4Addr::new(192, 168, 2, 13))),
transport: Some(Transport::Udp),
port: Some(Port::from(5060)),
dns_client: my_dns_client,
supported_transports: Default::default()
};
Here we created a context rather manually, but you can create a context out of a url as well
using the Context::initialize_from
method:
For example:
use rsip_dns::*;
use rsip::prelude::*;
let uri = rsip::Uri {
scheme: Some(rsip::Scheme::Sip),
host_with_port: ("example.com", 5060).into(),
..Default::default()
};
let context = Context::initialize_from(
uri,
dns_client,
SupportedTransports::any(),
).expect("uri and supported transports don't overlap");
Once you have the Context
, then you need to create a Lookup
out of it.
Basically there is only one (async) method that you are interested to use from Lookup
, the
resolve_next
and this actually comes from ResolvableExt
trait.
let mut lookup = Lookup::from(context);
while let target = lookup.resolve_next().await {
match target {
Some(Target {
ip_addr,
port,
transport,
}) => println!("next tuple: ({:?}, {:?}, {:?})", ip_addr, port, transport),
None => break,
}
}
For each iteration, the Lookup
makes sure it lazily uses the underlying dns client. For
instance, in the case of SRV records, it first resolves the first SRV record for A/AAAA records
and then moves to the next. Usually you will find what you want quite fast (in the first 1-2
iterations), but according to RFC3263, if you don't have port and transport, and NAPTR records
are not responding, you might need 10 or even more DNS queries to resolve the peer (ip, port, transport)
tuple. Probably the dns client could use some kind of caching, but that's left up to you, since
you need to provide a dns client that implements the DnsClient
trait.
RFC 3263 explains in detail how the process of figuring out the (ip, port, transport) tuple depending whether a port and/or a transport exists, but basically there are 4 distinct cases:
In this case an IP address is given, regardless if a port/transport are available.
In this case the target is a domain and also a port is given.
ResolvableExt
traitIf you notice on the section above, there are many reusable components. For instance, (2) reuses (1), while (3) reuses (2) (which reuses (1)) and (4) reuses all the previous.
The structure of the code follows this pattern by defining a ResolvableExt
trait,
Resolvable
type and other types that are built on top of Resolvable
or implement
ResolvableExt
trait.