Skip to main content

UserAgent

Struct UserAgent 

Source
pub struct UserAgent { /* private fields */ }
Expand description

A user agent bound to a transport endpoint.

Implementations§

Source§

impl UserAgent

Source

pub fn new(endpoint: Handle, config: Config) -> Self

A user agent that will send through endpoint.

Source

pub fn path(&self) -> &PathSet

The path the registrar recorded for this binding (RFC 3327).

Empty until a registration succeeds, and empty afterwards if no proxy on the way put itself on the path. This is reported rather than routed on: §5.1 says “the general operation of the UA is to ignore the Path header field in the response”, because the vector exists so that requests arriving at the registrar can be steered back toward a UA behind a NAT. What §5.1 does offer it for is inspection — seeing a proxy that has “inappropriately added” itself — and that is only possible if the value survives.

Source

pub fn service_route(&self) -> &ServiceRoute

The route the registrar dictated for requests this UA sends (RFC 3608).

The opposite direction from UserAgent::path, and the one a UA is meant to act on: §6.1 has it used “as a preloaded Route header field in outgoing initial requests”. sipx does not preload it behind the caller’s back — a Route set silently attached to every request is the kind of thing that is impossible to debug from the outside — so this is handed to whoever builds the request, via DialOptions::with_service_route for a call.

Empty until a registration succeeds, and empty again after any 2xx that carries no Service-Route.

Source

pub const fn registration_observation(&self) -> &RegistrationObservation

What the registrar’s top response Via reported for the last successful registration.

RegistrationObservation::NotRegistered means no registration has succeeded yet; RegistrationObservation::Absent is different: a success carried a valid top Via but no observation parameters.

This does not authorize rewriting Contact, routing, GRUU, Outbound, push, SDP or media addresses. RegistrationObservation::Invalid still accompanies a successful lease.

Source

pub const fn observed_registration_address(&self) -> Option<SocketAddr>

The registrar-observed address, when one was reported unambiguously.

This convenience accessor deliberately returns no fallback for absent or invalid data. Use Self::registration_observation when the distinction matters.

Source

pub fn flow_accepted(&self) -> bool

Whether the registrar reported performing an Outbound registration (RFC 5626 §6).

False until a registration succeeds, and false afterwards if the registrar did not put the option tag in Require — which is the case for every registrar that does not implement RFC 5626 at all. Asking for Outbound and not getting it is not an error: the binding is an ordinary one, and the only thing that changes is that there is no flow to keep alive.

Source

pub fn keepalive_after(&self, power: Power) -> Option<Duration>

How long to wait before the next keep-alive on this flow, if it is one (RFC 5626 §4.4).

None when the registrar did not perform an Outbound registration — there is no flow, so pinging would be traffic with nothing at the far end that cares. Re-drawn on every call, because §4.4.1 requires a fresh random interval for each ping: a fleet on a fixed period synchronises after any shared outage and arrives back as one spike.

Source

pub async fn keepalive(&mut self) -> Result<()>

Send one keep-alive on this flow and judge the answer (RFC 5626 §4.4).

Three ways this reports a failed flow, and §4.4 makes each of them one:

  • no answer within outbound::PONG_TIMEOUT (§4.4.1),
  • a STUN Binding Error Response (§4.4.2),
  • a reflexive address different from the last one (§4.4.2).

The third is the one that is easy to leave out and the reason STUN is the UDP technique at all. The socket still works; what has changed is that the NAT rebound, so the mapping the registrar holds for this flow no longer reaches it. A keep-alive that only asked “did anything come back” would call that flow healthy right up until a call failed to arrive.

Ok(()) on a flow the registrar did not accept: there is no flow, so there is nothing to keep alive and nothing has failed.

Source

pub fn reflexive_address(&self) -> Option<SocketAddr>

The reflexive address the last keep-alive reported, if one did (RFC 5626 §4.4.2).

Source

pub fn gruus(&self) -> &Gruus

The GRUUs the registrar issued for this instance (RFC 5627 §4.2).

Empty until a registration succeeds, empty afterwards if GRUU was not asked for, and empty again if it was and the registrar issued nothing — §4.2 requires a UA to be ready for one, both or neither, and a registrar that does not implement RFC 5627 answers a REGISTER perfectly well and attaches none.

Source

pub fn sent_to_our_gruu(&self, request: &Request) -> bool

Whether a request that arrived was sent to one of this instance’s GRUUs (RFC 5627 §4.5).

This is the question the mechanism exists to make answerable, and it is not the question “is this request for me”: an address of record reaches every device the user registered, and RFC 5627 §5.4 notes that a public GRUU “will always be equivalent to the AOR based on URI equality rules”. A true here means the sender addressed this instance and nothing else — which is what a transfer target or a callback is relying on.

Source

pub fn dialog_contact(&self) -> String

The Contact to put on a dialog-forming or target-refresh request (RFC 5627 §4.4, RFC 5626 §4.3).

Three answers, in the order the RFCs put them:

  • The GRUU, when one is known. §4.4: “A UA SHOULD use a GRUU when populating the Contact header field of dialog-forming and target refresh requests and responses.” It is an address that survives this flow, this NAT mapping and this registration, which is more than either of the others can say.
  • The contact with ob, when this is an accepted flow and no GRUU is known. RFC 5626 §4.3 makes that a MUST in the absence of a GRUU, and it tells the far end that mid-dialog requests belong on this flow rather than at the address in the URI — behind a NAT, the difference between a re-INVITE arriving and vanishing.
  • The plain contact, when neither applies.

A caller that asked for a temporary GRUU and did not get one lands in the second or third case, never the first: the public GRUU is not a substitute for an unlinkable address, and quietly publishing the device’s permanent name to a peer that was promised otherwise is a worse outcome than publishing the contact. It is logged, because the caller asked for something it did not get.

Source

pub fn push_support(&self) -> &Support

What the registrar said about push notifications (RFC 8599 §8.2).

Empty until a registration succeeds, and empty afterwards when the registrar implements nothing of RFC 8599 — which is not a refusal, just silence. The question to ask it is Support::supports with the provider this side registered: a registrar that answered 200 while naming a different push service has recorded a binding nothing will ever wake, and this is the only place that says so.

Source

pub async fn woken(&mut self) -> Result<Pending>

A push notification arrived: refresh the binding, and only then expect the request (RFC 8599 §4.1.3).

§4.1.3: “When a UA receives a push notification, the UA MUST send a binding-refresh REGISTER request.” The push is not the call — it is permission to go and get a flow, and the request the push was sent for arrives down the flow this REGISTER creates. A client that skips this and waits for the INVITE is waiting on a path that does not exist yet, which is why the Pending that licenses the wait comes from here and nowhere else.

sipx neither sends nor receives the push itself: the service is behind crate::push::PushService, and when to call this is the application’s — it is whatever “the notification fired” means on its platform.

Source

pub async fn register(&mut self) -> Result<Lease>

Register, answering a challenge if one comes.

One retry, not a loop. A second challenge after credentials were supplied means the credentials are wrong — unless the server says the nonce was merely stale, which is a different thing and is retried. Looping on a genuine rejection is how a client locks out the account it is trying to use.

Source

pub async fn keep_registered(&mut self) -> Result<Infallible>

Register and keep registering, refreshing before each lease expires.

A failed refresh is retried once inside the margin left by the last granted lease. The registrar’s grant defines both deadlines: the first attempt starts at refresh_after, and the retry divides what remains before granted. A second failure returns rather than creating an unbounded retry loop.

Source

pub async fn answer(&self, incoming: &Incoming) -> Result<bool>

Answer a request that arrived, when the user-agent layer owns the decision.

Handles what a user agent must answer to be a good citizen on the network, and refuses an initial INVITE addressed to a GRUU this registered instance does not own. Anything else is left to the caller, which is why this returns whether it acted.

The GRUU guard applies only after this agent has learned at least one GRUU. An unregistered agent cannot prove that an unfamiliar value belongs to somebody else, while one holding its registrar-issued values can. RFC 5627 §4.5 says gr identifies an instance-specific URI; §6.1 gives an unresolved GRUU the ordinary 404 Not Found response. Applying that response at the last hop keeps a proxy’s accidental misrouting from turning an instance address back into an address-of-record fan-out.

Source

pub fn endpoint(&self) -> &Handle

The transport handle this agent sends through.

Trait Implementations§

Source§

impl Debug for UserAgent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,