Interaction with the Transaction
A new Transaction creates a DnsResult object.
DnsResult is the brain/pump for DNS work - it drives queries and captures asyncronous DNS query results. This is the object that knows 3263 - it knows to make NAPTR queries and SRV queries based on the results. Ultimately, it makes the decision about which Tuples actually get tried.
DnsResult makes a query to DnsStub (through a Fifo using the command pattern), which exists to abstract the Dns subsystem (allowing something other than ares to be plugged under the stack). (Note - in the current code, this happens in a passthrough through DnsInterface. Work is in progress to take that object out of this call sequence).
(Further note - DnsInterface is owned by the TransportSelector, the DnsResult asks TransportSelector for the DnsInterface to use).
DnsStub looks in its RRCache (intended to be a singleton so all DnsStubs share a cache) for a hit. RRCache implements a normal DNS caching server with an extra interface for early cache flush. (Note: the RRVIP is in the path of this call, and may transform the results from the cache - see below for more discussion of the RRVIP)
If there's no hit in the cache, the query is forwarded to ExternalDns (an interface realized by ares in the stack by default).
ExternalDns will asyncronously cram results back into the DnsStub through a callback. DnsStub plops those results into the RRCache, then drops it into its CommandFifo.
The next time process runs across the queue between DnsStub and DnsResult, the results are taken from that queue and pushed through the onDnsResult callback in DnsResult.
The process of making queries to DnsStub repeats until the 3263 logic has a result it wants to try.
Once the tuples are ordered, the TransactionState starts working through them, calling getNext on DnsResult. For each tuple, TransactionState asks the TransportSelector to transmit to that destination.
Suppose the transmit succeded - we get a SipMessage back to TransactionState. TransactionState will note the success in an object named RRVIP (Very Important Proxy?). RRVIP is where resip captures the white/blacklist behavior implied in 3263 and specified in nit-future.
RRVIP keeps a directed graph of RR results, changing weights or priorities as appropriate to move a successful path to the top. On Expiry, ExternalDns gets requeried. If the successful path is still in the results, it stays at the highest point in the order (as opposed to resetting to what the new DNS query says to do - This will be the topic of a future design session).
When a transmit fails, we get a failMessage back at the TransactionState. TransactionState tells DnsResult to blacklist. DnsResult tells DnsStub to blacklist. It will also check to see if all its siblings have been blacklisted - if so, it will blacklist the parent (recursively).
Once the entire digraph is blacklisted, the digraph is flushed and the process starts over. This is how the system will recover after a network failure. (This is another area for design review, especially for proxy behavior - it doesn't match the conversation at IETF61 - this should probably be a transform instead that just pushed "bad" things to the back of the list).
RRCache is configurable to cache only particular RRs RRCache can be flushed Need to teach RRCache to cap ttls