Framework to resolve SIP servers based on RFC 3263.
This is the SIP server resolution framework, which is modelled after RFC 3263 - Locating SIP Servers document. The SIP server resolution framework is asynchronous; callback will be called once the server address has been resolved (successfully or with errors).
Conformance to RFC 3263
The SIP server resolution framework is modelled after RFC 3263 (Locating SIP Servers) document, and it provides a single function (pjsip_resolve()) to resolve a domain into actual IP addresses of the servers, by querying DNS SRV record and DNS A record where necessary.
The pjsip_resolve() function performs the server resolution according to RFC 3263 with some additional fallback mechanisms, as follows:
- if the target name is an IP address, the callback will be called immediately with the IP address. If port number was specified, this port number will be used, otherwise the default port number for the transport will be used (5060 for TCP/UDP, 5061 for TLS) if the transport is specified. If the transport is not specified, UDP with port number 5060 will be used.
- if target name is not an IP address but it contains port number, then the target name is resolved with DNS A (or AAAA, when IPv6 is supported in the future) query, and the port is taken from the port number argument. The callback will be called once the DNS A resolution completes. If the DNS A resolution returns multiple IP addresses, these IP addresses will be returned to the caller.
- if target name is not an IP address and port number is not specified, DNS SRV resolution will be performed for the specified name and transport type (or UDP when transport is not specified), then followed by DNS A (or AAAA, when IPv6 is supported) resolution for each target in the SRV record. If DNS SRV resolution returns error, DNS A (or AAAA) resolution will be performed for the original target (it is assumed that the target domain does not support SRV records). Upon successful completion, application callback will be called with each IP address of the target selected based on the load-balancing and fail-over criteria below.
The above server resolution procedure differs from RFC 3263 in these regards:
- currently pjsip_resolve() doesn't support DNS NAPTR record.
- if transport is not specified, it is assumed to be UDP (the proper behavior is to query the NAPTR record, but we don't support this yet).
Load-Balancing and Fail-Over
When multiple targets are returned in the DNS SRV response, server entries are selected based on the following rule (which is described in RFC 2782):
- targets will be sorted based on the priority first.
- for targets with the same priority, pjsip_resolve() will select only one target according to its weight. To select this one target, the function associates running-sum for all targets, and generates a random number between zero and the total running-sum (inclusive). The target selected is the first target with running-sum greater than or equal to this random number.
The above procedure will select one target for each priority, allowing application to fail-over to the next target when the previous target fails. These targets are returned in the pjsip_server_addresses structure argument of the callback.
SIP SRV Resolver Features
Some features of the SIP resolver:
- DNS SRV entries are returned on sorted order based on priority to allow failover to the next appropriate server.
- The procedure in RFC 2782 is used to select server with the same priority to load-balance the servers load.
- A single function (pjsip_resolve()) performs all server resolution works, from resolving the SRV records to getting the actual IP addresses of the servers with DNS A (or AAAA) resolution.
- When multiple DNS SRV records are returned, parallel DNS A (or AAAA) queries will be issued simultaneously.
- The PJLIB-UTIL DNS resolver provides additional functionality such as response caching, query aggregation, parallel nameservers, fallback nameserver, etc., which will be described below.
- Enable application to provide its own resolver implementation.
DNS Resolver Features
The PJSIP server resolution framework uses PJLIB-UTIL DNS resolver engine for performing the asynchronous DNS request. The PJLIB-UTIL DNS resolver has some useful features, such as:
- queries are asynchronous with configurable timeout,
- query aggregation to combine multiple pending queries to the same DNS target into a single DNS request (to save message round-trip and processing),
- response caching with TTL negotiated between the minimum TTL found in the response and the maximum TTL allowed in the configuration,
- multiple nameservers, with active nameserver is selected from nameserver which provides the best response time,
- fallback nameserver, with periodic detection of which name servers are active or down.
Please consult PJLIB-UTIL DNS resolver documentation for more details.
Using the Resolver
To maintain backward compatibility, the resolver MUST be enabled manually. With the default settings, the resolver WILL NOT perform DNS SRV resolution, as it will just resolve the name with standard pj_gethostbyname() function.
Application can enable the SRV resolver by creating the PJLIB-UTIL DNS resolver with pjsip_endpt_create_resolver(), configure the nameservers of the PJLIB-UTIL DNS resolver object by calling pj_dns_resolver_set_ns() function, and pass the DNS resolver object to pjsip_resolver_set_resolver() function.
Once the resolver is set, it will be used automatically by PJSIP everytime PJSIP needs to send SIP request/response messages.
As an alternative to enabling PJLIB-UTIL DNS resolver, application can provide its own resolver implementation by defining the callback in pjsip_ext_resolver and pass the callback to pjsip_resolver_set_ext_resolver() function. Please note that if the implementation needs feature from PJLIB-UTL DNS resolver, it has to create its own PJLIB-UTL DNS resolver instance.
- RFC 2782: A DNS RR for specifying the location of services (DNS SRV)
- RFC 3263: Locating SIP Servers
The type of callback function to be called when resolver finishes the job.
|status||The status of the operation, which is zero on success. |
|token||The token that was associated with the job when application call the resolve function. |
|addr||The addresses resolved by the operation. |
Create SIP resolver engine. Note that this function is normally called internally by pjsip_endpoint instance.
|pool||Pool to allocate memory from. |
|p_res||Pointer to receive SIP resolver instance.|
- PJ_SUCCESS when resolver can be successfully created.
Set the DNS resolver instance of the SIP resolver engine. Before the DNS resolver is set, the SIP resolver will use standard pj_gethostbyname() to resolve addresses.
Note that application normally will use pjsip_endpt_set_resolver() instead since it does not normally have access to the SIP resolver instance.
|res||The SIP resolver engine. |
|dns_res||The DNS resolver instance to be used by the SIP resolver. This argument can be NULL to reset the internal DNS instance.|
- PJ_SUCCESS on success, or the appropriate error code.
Set the DNS external resolver implementation to use in the SIP resolver engine. Naturally when implementing its own resolver, application would not need the internal resolver, hence this function will also destroy the PJLIB-UTIL DNS resolver if any (e.g: set using pjsip_resolver_set_resolver()). Application that needs it, still be able create its own instance.
Note that application normally will use pjsip_endpt_set_ext_resolver() instead since it does not normally have access to the SIP resolver instance.
|res||The SIP resolver engine. |
|ext_res||The external resolver implementation callback. This argument can be NULL to reset the whole external implementation. However, it is prohibited to reset individual callback.|
- PJ_SUCCESS on success, or the appropriate error code.
Get the DNS resolver instance of the SIP resolver engine.
Note that application normally will use pjsip_endpt_get_resolver() instead since it does not normally have access to the SIP resolver instance.
|res||The SIP resolver engine.|
- The DNS resolver instance (may be NULL)
Destroy resolver engine. Note that this will also destroy the internal DNS resolver inside the engine. If application doesn't want the internal DNS resolver to be destroyed, it should set the internal DNS resolver to NULL before calling this function.
Note that this function will normally called by the SIP endpoint instance when the SIP endpoint instance is destroyed.
Asynchronously resolve a SIP target host or domain according to rule specified in RFC 3263 (Locating SIP Servers). When the resolving operation has completed, the callback will be called.
Note that application normally will use pjsip_endpt_resolve() instead since it does not normally have access to the SIP resolver instance.
|resolver||The resolver engine. |
|pool||The pool to allocate resolver job. |
|target||The target specification to be resolved. |
|token||A user defined token to be passed back to callback function. |
|cb||The callback function. |