summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-06-11 16:54:10 +0000
committerBenny Prijono <bennylp@teluu.com>2007-06-11 16:54:10 +0000
commit612be11df187ea3186c0c16c1c245b4f6c9b22b9 (patch)
treea97a877358f47d29a1390576a30dcbc09da00a54 /pjsip
parent3f873c23f1ba23394203a2083e0f76f47266492b (diff)
Ticket #331: Changed PJSIP DNS SRV resolver to use PJLIB-UTIL DNS SRV resolver
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1358 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/src/pjsip/sip_resolve.c722
1 files changed, 127 insertions, 595 deletions
diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c
index 98c3650d..367d3fc4 100644
--- a/pjsip/src/pjsip/sip_resolve.c
+++ b/pjsip/src/pjsip/sip_resolve.c
@@ -20,6 +20,7 @@
#include <pjsip/sip_transport.h>
#include <pjsip/sip_errno.h>
#include <pjlib-util/errno.h>
+#include <pjlib-util/srv_resolver.h>
#include <pj/array.h>
#include <pj/assert.h>
#include <pj/ctype.h>
@@ -35,31 +36,18 @@
struct naptr_target
{
- pj_str_t target_name; /**< NAPTR target name. */
+ pj_str_t res_type; /**< e.g. "_sip._udp" */
+ pj_str_t name; /**< Domain name. */
pjsip_transport_type_e type; /**< Transport type. */
unsigned order; /**< Order */
unsigned pref; /**< Preference. */
};
-struct srv_target
-{
- pjsip_transport_type_e type;
- pj_str_t target_name;
- char target_buf[PJ_MAX_HOSTNAME];
- unsigned port;
- unsigned priority;
- unsigned weight;
- unsigned sum;
- unsigned addr_cnt;
- pj_in_addr addr[ADDR_MAX_COUNT];
-};
-
struct query
{
- char objname[PJ_MAX_OBJ_NAME];
+ char *objname;
- pjsip_resolver_t *resolver; /**< Resolver SIP instance. */
- pj_dns_type dns_state; /**< DNS type being resolved. */
+ pj_dns_type query_type;
void *token;
pjsip_resolver_callback *cb;
pj_dns_async_query *object;
@@ -68,30 +56,27 @@ struct query
/* Original request: */
struct {
pjsip_host_info target;
+ unsigned def_port;
} req;
/* NAPTR records: */
unsigned naptr_cnt;
struct naptr_target naptr[8];
-
- /* SRV records and their resolved IP addresses: */
- unsigned srv_cnt;
- struct srv_target srv[PJSIP_MAX_RESOLVED_ADDRESSES];
-
- /* Number of hosts in SRV records that the IP address has been resolved */
- unsigned host_resolved;
};
struct pjsip_resolver_t
{
pj_dns_resolver *res;
- unsigned job_id;
};
-static void dns_callback(void *user_data,
- pj_status_t status,
- pj_dns_parsed_packet *response);
+
+static void srv_resolver_cb(void *user_data,
+ pj_status_t status,
+ const pj_dns_srv_record *rec);
+static void dns_a_callback(void *user_data,
+ pj_status_t status,
+ pj_dns_parsed_packet *response);
/*
@@ -183,7 +168,6 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
pj_status_t status = PJ_SUCCESS;
int is_ip_addr;
struct query *query;
- pj_str_t srv_name;
pjsip_transport_type_e type = target->type;
/* Is it IP address or hostname?. */
@@ -279,9 +263,7 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
/* Build the query state */
query = PJ_POOL_ZALLOC_T(pool, struct query);
- pj_ansi_snprintf(query->objname, sizeof(query->objname), "rsvjob%X",
- resolver->job_id++);
- query->resolver = resolver;
+ query->objname = THIS_FILE;
query->token = token;
query->cb = cb;
query->req.target = *target;
@@ -298,60 +280,68 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
query->naptr[0].order = 0;
query->naptr[0].pref = 0;
query->naptr[0].type = type;
- query->naptr[0].target_name.ptr = (char*)
- pj_pool_alloc(pool, target->addr.host.slen + 12);
-
- if (type == PJSIP_TRANSPORT_TLS)
- pj_strcpy2(&query->naptr[0].target_name, "_sips._tcp.");
- else if (type == PJSIP_TRANSPORT_TCP)
- pj_strcpy2(&query->naptr[0].target_name, "_sip._tcp.");
- else if (type == PJSIP_TRANSPORT_UDP)
- pj_strcpy2(&query->naptr[0].target_name, "_sip._udp.");
- else {
- pj_assert(!"Unknown transport type");
- pj_strcpy2(&query->naptr[0].target_name, "_sip._udp.");
- }
- pj_strcat(&query->naptr[0].target_name, &target->addr.host);
+ pj_strdup(pool, &query->naptr[0].name, &target->addr.host);
/* Start DNS SRV or A resolution, depending on whether port is specified */
if (target->addr.port == 0) {
- query->dns_state = PJ_DNS_TYPE_SRV;
- srv_name = query->naptr[0].target_name;
+ query->query_type = PJ_DNS_TYPE_SRV;
+
+ query->req.def_port = 5060;
+
+ if (type == PJSIP_TRANSPORT_TLS) {
+ query->naptr[0].res_type = pj_str("_sips._tcp.");
+ query->req.def_port = 5061;
+ } else if (type == PJSIP_TRANSPORT_TCP)
+ query->naptr[0].res_type = pj_str("_sip._tcp.");
+ else if (type == PJSIP_TRANSPORT_UDP)
+ query->naptr[0].res_type = pj_str("_sip._udp.");
+ else {
+ pj_assert(!"Unknown transport type");
+ query->naptr[0].res_type = pj_str("_sip._udp.");
+
+ }
} else {
/* Otherwise if port is specified, start with A (or AAAA) host
* resolution
*/
- query->dns_state = PJ_DNS_TYPE_A;
-
- /* Since we don't perform SRV resolution, pretend that we'ee already
- * done so by inserting a dummy SRV record.
- */
-
- query->srv_cnt = 1;
- pj_bzero(&query->srv[0], sizeof(query->srv[0]));
- query->srv[0].target_name = query->req.target.addr.host;
- query->srv[0].type = type;
- query->srv[0].port = query->req.target.addr.port;
- query->srv[0].priority = 0;
- query->srv[0].weight = 0;
-
- srv_name = query->srv[0].target_name;
+ query->query_type = PJ_DNS_TYPE_A;
+ query->naptr[0].res_type.slen = 0;
+ query->req.def_port = target->addr.port;
}
/* Start the asynchronous query */
PJ_LOG(5, (query->objname,
- "Starting async DNS %s query: target=%.*s, transport=%s, "
+ "Starting async DNS %s query: target=%.*s%.*s, transport=%s, "
"port=%d",
- pj_dns_get_type_name(query->dns_state),
- (int)srv_name.slen, srv_name.ptr,
+ pj_dns_get_type_name(query->query_type),
+ (int)query->naptr[0].res_type.slen,
+ query->naptr[0].res_type.ptr,
+ (int)query->naptr[0].name.slen, query->naptr[0].name.ptr,
pjsip_transport_get_type_name(target->type),
target->addr.port));
- status = pj_dns_resolver_start_query(resolver->res, &srv_name,
- query->dns_state, 0, &dns_callback,
- query, &query->object);
+ if (query->query_type == PJ_DNS_TYPE_SRV) {
+
+ status = pj_dns_srv_resolve(&query->naptr[0].name,
+ &query->naptr[0].res_type,
+ query->req.def_port, pool, resolver->res,
+ PJ_TRUE, query, &srv_resolver_cb, NULL);
+
+ } else if (query->query_type == PJ_DNS_TYPE_A) {
+
+ status = pj_dns_resolver_start_query(resolver->res,
+ &query->naptr[0].name,
+ PJ_DNS_TYPE_A, 0,
+ &dns_a_callback,
+ query, &query->object);
+
+ } else {
+ pj_assert(!"Unexpected");
+ status = PJ_EBUG;
+ }
+
if (status != PJ_SUCCESS)
goto on_error;
@@ -376,562 +366,104 @@ on_error:
}
}
-/*
- * The rest of the code should only get compiled when resolver is enabled
- */
#if PJSIP_HAS_RESOLVER
-#define SWAP(type,ptr1,ptr2) if (ptr1 != ptr2) { \
- type tmp; \
- pj_memcpy(&tmp, ptr1, sizeof(type)); \
- pj_memcpy(ptr1, ptr2, sizeof(type)); \
- (ptr1)->target_name.ptr = (ptr1)->target_buf; \
- pj_memcpy(ptr2, &tmp, sizeof(type)); \
- (ptr2)->target_name.ptr = (ptr2)->target_buf; \
- } else {}
-
-/* Build server entries in the query based on received SRV response */
-static void build_server_entries(struct query *query,
- pj_dns_parsed_packet *response)
+/*
+ * This callback is called when target is resolved with DNS A query.
+ */
+static void dns_a_callback(void *user_data,
+ pj_status_t status,
+ pj_dns_parsed_packet *pkt)
{
+ struct query *query = (struct query*) user_data;
+ pjsip_server_addresses srv;
+ pj_dns_a_record rec;
unsigned i;
- unsigned naptr_id;
-
- /* Find NAPTR target which corresponds to this SRV target */
- for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
- if (pj_stricmp(&query->naptr[naptr_id].target_name,
- &response->ans[0].name)==0)
- break;
- }
- if (naptr_id == query->naptr_cnt) {
- PJ_LOG(4,(query->objname,
- "Unable to find NAPTR record for SRV name %.*s!",
- (int)response->ans[0].name.slen,
- response->ans[0].name.ptr));
- return;
- }
+ rec.addr_count = 0;
- /* Save the Resource Records in DNS answer into SRV targets. */
- query->srv_cnt = 0;
- for (i=0; i<response->hdr.anscount &&
- query->srv_cnt < PJSIP_MAX_RESOLVED_ADDRESSES; ++i)
- {
- pj_dns_parsed_rr *rr = &response->ans[i];
- struct srv_target *srv = &query->srv[query->srv_cnt];
-
- if (rr->type != PJ_DNS_TYPE_SRV) {
- PJ_LOG(4,(query->objname,
- "Received non SRV answer for SRV query!"));
- continue;
- }
-
- if (rr->rdata.srv.target.slen > PJ_MAX_HOSTNAME) {
- PJ_LOG(4,(query->objname, "Hostname is too long!"));
- continue;
- }
-
- /* Build the SRV entry for RR */
- pj_bzero(srv, sizeof(*srv));
- pj_memcpy(srv->target_buf, rr->rdata.srv.target.ptr,
- rr->rdata.srv.target.slen);
- srv->target_name.ptr = srv->target_buf;
- srv->target_name.slen = rr->rdata.srv.target.slen;
- srv->type = query->naptr[naptr_id].type;
- srv->port = rr->rdata.srv.port;
- srv->priority = rr->rdata.srv.prio;
- srv->weight = rr->rdata.srv.weight;
-
- ++query->srv_cnt;
+ /* Parse the response */
+ if (status == PJ_SUCCESS) {
+ status = pj_dns_parse_a_response(pkt, &rec);
}
- /* First pass:
- * order the entries based on priority.
- */
- for (i=0; i<query->srv_cnt-1; ++i) {
- unsigned min = i, j;
- for (j=i+1; j<query->srv_cnt; ++j) {
- if (query->srv[j].priority < query->srv[min].priority)
- min = j;
- }
- SWAP(struct srv_target, &query->srv[i], &query->srv[min]);
- }
-
- /* Second pass:
- * pick one host among hosts with the same priority, according
- * to its weight. The idea is when one server fails, client should
- * contact the next server with higher priority rather than contacting
- * server with the same priority as the failed one.
- *
- * The algorithm for selecting server among servers with the same
- * priority is described in RFC 2782.
- */
- for (i=0; i<query->srv_cnt; ++i) {
- unsigned j, count=1, sum;
-
- /* Calculate running sum for servers with the same priority */
- sum = query->srv[i].sum = query->srv[i].weight;
- for (j=i+1; j<query->srv_cnt &&
- query->srv[j].priority == query->srv[i].priority; ++j)
- {
- sum += query->srv[j].weight;
- query->srv[j].sum = sum;
- ++count;
- }
-
- if (count > 1) {
- unsigned r;
-
- /* Elect one random number between zero and the total sum of
- * weight (inclusive).
- */
- r = pj_rand() % (sum + 1);
-
- /* Select the first server which running sum is greater than or
- * equal to the random number.
- */
- for (j=i; j<i+count; ++j) {
- if (query->srv[j].sum >= r)
- break;
- }
-
- /* Must have selected one! */
- pj_assert(j != i+count);
-
- /* Put this entry in front (of entries with same priority) */
- SWAP(struct srv_target, &query->srv[i], &query->srv[j]);
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
- /* Remove all other entries (of the same priority) */
- while (count > 1) {
- pj_array_erase(query->srv, sizeof(struct srv_target),
- query->srv_cnt, i+1);
- --count;
- --query->srv_cnt;
- }
- }
- }
+ /* Log error */
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",
+ errmsg));
- /* Since we've been moving around SRV entries, update the pointers
- * in target_name.
- */
- for (i=0; i<query->srv_cnt; ++i) {
- query->srv[i].target_name.ptr = query->srv[i].target_buf;
+ /* Call the callback */
+ (*query->cb)(status, query->token, NULL);
+ return;
}
- /* Check for Additional Info section if A records are available, and
- * fill in the IP address (so that we won't need to resolve the A
- * record with another DNS query).
- */
- for (i=0; i<response->hdr.arcount; ++i) {
- pj_dns_parsed_rr *rr = &response->arr[i];
- unsigned j;
-
- if (rr->type != PJ_DNS_TYPE_A)
- continue;
-
- /* Yippeaiyee!! There is an "A" record!
- * Update the IP address of the corresponding SRV record.
- */
- for (j=0; j<query->srv_cnt; ++j) {
- if (pj_stricmp(&rr->name, &query->srv[j].target_name)==0) {
- unsigned cnt = query->srv[j].addr_cnt;
- query->srv[j].addr[cnt].s_addr = rr->rdata.a.ip_addr.s_addr;
- ++query->srv[j].addr_cnt;
- ++query->host_resolved;
- break;
- }
- }
-
- /* Not valid message; SRV entry might have been deleted in
- * server selection process.
- */
- /*
- if (j == query->srv_cnt) {
- PJ_LOG(4,(query->objname,
- "Received DNS SRV answer with A record, but "
- "couldn't find matching name (name=%.*s)",
- (int)rr->name.slen,
- rr->name.ptr));
- }
- */
+ /* Build server addresses and call callback */
+ srv.count = 0;
+ for (i=0; i<rec.addr_count; ++i) {
+ srv.entry[srv.count].type = query->naptr[0].type;
+ srv.entry[srv.count].priority = 0;
+ srv.entry[srv.count].weight = 0;
+ srv.entry[srv.count].addr_len = sizeof(pj_sockaddr_in);
+ pj_sockaddr_in_init(&srv.entry[srv.count].addr.ipv4,
+ 0, (pj_uint16_t)query->req.def_port);
+ srv.entry[srv.count].addr.ipv4.sin_addr.s_addr =
+ rec.addr[i].s_addr;
+
+ ++srv.count;
}
- /* Rescan again the name specified in the SRV record to see if IP
- * address is specified as the target name (unlikely, but well, who
- * knows..).
- */
- for (i=0; i<query->srv_cnt; ++i) {
- pj_in_addr addr;
-
- if (query->srv[i].addr_cnt != 0) {
- /* IP address already resolved */
- continue;
- }
-
- if (pj_inet_aton(&query->srv[i].target_name, &addr) != 0) {
- query->srv[i].addr[query->srv[i].addr_cnt++] = addr;
- ++query->host_resolved;
- }
- }
-
- /* Print resolved entries to the log */
- PJ_LOG(5,(query->objname,
- "SRV query for %.*s completed, "
- "%d of %d total entries selected%c",
- (int)query->naptr[naptr_id].target_name.slen,
- query->naptr[naptr_id].target_name.ptr,
- query->srv_cnt,
- response->hdr.anscount,
- (query->srv_cnt ? ':' : ' ')));
-
- for (i=0; i<query->srv_cnt; ++i) {
- const char *addr;
-
- if (query->srv[i].addr_cnt != 0)
- addr = pj_inet_ntoa(query->srv[i].addr[0]);
- else
- addr = "-";
-
- PJ_LOG(5,(query->objname,
- " %d: SRV %d %d %d %.*s (%s)",
- i, query->srv[i].priority,
- query->srv[i].weight,
- query->srv[i].port,
- (int)query->srv[i].target_name.slen,
- query->srv[i].target_name.ptr,
- addr));
- }
+ /* Call the callback */
+ (*query->cb)(PJ_SUCCESS, query->token, &srv);
}
-/* Start DNS A record queries for all SRV records in the query structure */
-static pj_status_t resolve_hostnames(struct query *query)
-{
- unsigned i;
- pj_status_t err=PJ_SUCCESS, status;
-
- query->dns_state = PJ_DNS_TYPE_A;
- for (i=0; i<query->srv_cnt; ++i) {
- PJ_LOG(5, (query->objname,
- "Starting async DNS A query for %.*s",
- (int)query->srv[i].target_name.slen,
- query->srv[i].target_name.ptr));
-
- status = pj_dns_resolver_start_query(query->resolver->res,
- &query->srv[i].target_name,
- PJ_DNS_TYPE_A, 0,
- &dns_callback,
- query, NULL);
- if (status != PJ_SUCCESS) {
- query->host_resolved++;
- err = status;
- }
- }
-
- return (query->host_resolved == query->srv_cnt) ? err : PJ_SUCCESS;
-}
-
-/*
- * This callback is called by PJLIB-UTIL DNS resolver when asynchronous
- * query has completed (successfully or with error).
- */
-static void dns_callback(void *user_data,
- pj_status_t status,
- pj_dns_parsed_packet *pkt)
+/* Callback to be called by DNS SRV resolution */
+static void srv_resolver_cb(void *user_data,
+ pj_status_t status,
+ const pj_dns_srv_record *rec)
{
struct query *query = (struct query*) user_data;
+ pjsip_server_addresses srv;
unsigned i;
- /* Proceed to next stage */
-
- if (query->dns_state == PJ_DNS_TYPE_SRV) {
-
- /* We are getting SRV response */
-
- if (status == PJ_SUCCESS && pkt->hdr.anscount != 0) {
- /* Got SRV response, build server entry. If A records are available
- * in additional records section of the DNS response, save them too.
- */
- build_server_entries(query, pkt);
-
- } else if (status != PJ_SUCCESS) {
- char errmsg[PJ_ERR_MSG_SIZE];
- unsigned naptr_id;
-
- /* Update query last error */
- query->last_error = status;
-
- /* Find which NAPTR target has not got SRV records */
- for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
- for (i=0; i<query->srv_cnt; ++i) {
- if (query->srv[i].type == query->naptr[naptr_id].type)
- break;
- }
- if (i == query->srv_cnt)
- break;
- }
- if (naptr_id == query->naptr_cnt) {
- /* Strangely all NAPTR records seem to already have SRV
- * records! This is quite unexpected, by anyway lets set
- * the naptr_id to zero just in case.
- */
- pj_assert(!"Strange");
- naptr_id = 0;
-
- }
-
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(4,(query->objname,
- "DNS SRV resolution failed for %.*s: %s",
- (int)query->naptr[naptr_id].target_name.slen,
- query->naptr[naptr_id].target_name.ptr,
- errmsg));
- }
-
- /* If we can't build SRV record, assume the original target is
- * an A record.
- */
- if (query->srv_cnt == 0) {
- /* Looks like we aren't getting any SRV responses.
- * Resolve the original target as A record by creating a
- * single "dummy" srv record and start the hostname resolution.
- */
- unsigned naptr_id;
-
- /* Find which NAPTR target has not got SRV records */
- for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
- for (i=0; i<query->srv_cnt; ++i) {
- if (query->srv[i].type == query->naptr[naptr_id].type)
- break;
- }
- if (i == query->srv_cnt)
- break;
- }
- if (naptr_id == query->naptr_cnt) {
- /* Strangely all NAPTR records seem to already have SRV
- * records! This is quite unexpected, by anyway lets set
- * the naptr_id to zero just in case.
- */
- pj_assert(!"Strange");
- naptr_id = 0;
-
- }
-
- PJ_LOG(4, (query->objname,
- "DNS SRV resolution failed for %.*s, trying "
- "resolving A record for %.*s",
- (int)query->naptr[naptr_id].target_name.slen,
- query->naptr[naptr_id].target_name.ptr,
- (int)query->req.target.addr.host.slen,
- query->req.target.addr.host.ptr));
-
- /* Create a "dummy" srv record using the original target */
- i = query->srv_cnt++;
- pj_bzero(&query->srv[i], sizeof(query->srv[i]));
- query->srv[i].target_name = query->req.target.addr.host;
- query->srv[i].type = query->naptr[naptr_id].type;
- query->srv[i].priority = 0;
- query->srv[i].weight = 0;
-
- query->srv[i].port = query->req.target.addr.port;
- if (query->srv[i].port == 0) {
- query->srv[i].port = (pj_uint16_t)
- pjsip_transport_get_default_port_for_type(query->srv[i].type);
- }
- }
-
-
- /* Resolve server hostnames (DNS A record) for hosts which don't have
- * A record yet.
- */
- if (query->host_resolved != query->srv_cnt) {
- status = resolve_hostnames(query);
- if (status != PJ_SUCCESS)
- goto on_error;
-
- /* Must return now. Callback may have been called and query
- * may have been destroyed.
- */
- return;
- }
-
- } else if (query->dns_state == PJ_DNS_TYPE_A) {
-
- /* Check that we really have answer */
- if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) {
-
- unsigned srv_idx;
-
- /* Update IP address of the corresponding hostname */
- for (srv_idx=0; srv_idx<query->srv_cnt; ++srv_idx) {
- if (pj_stricmp(&pkt->ans[0].name,
- &query->srv[srv_idx].target_name)==0)
- {
- break;
- }
- }
-
- if (srv_idx == query->srv_cnt) {
- PJ_LOG(4,(query->objname,
- "Received answer to DNS A request with no matching "
- "SRV record! The unknown name is %.*s",
- (int)pkt->ans[0].name.slen, pkt->ans[0].name.ptr));
- } else {
- int ans_idx = -1;
- unsigned k, j;
- pj_str_t cname = { NULL, 0 };
-
- /* Find the first DNS A record in the answer while processing
- * the CNAME info found in the response.
- */
- for (k=0; k < pkt->hdr.anscount; ++k) {
-
- pj_dns_parsed_rr *rr = &pkt->ans[k];
-
- if (rr->type == PJ_DNS_TYPE_A &&
- (cname.slen == 0 || pj_stricmp(&rr->name, &cname)==0))
- {
- if (ans_idx == -1)
- ans_idx = k;
-
- } else if (rr->type == PJ_DNS_TYPE_CNAME &&
- pj_stricmp(&query->srv[srv_idx].target_name,
- &rr->name)==0)
- {
- cname = rr->rdata.cname.name;
- }
- }
-
- if (ans_idx == -1) {
- /* There's no DNS A answer! */
- PJ_LOG(5,(query->objname,
- "No DNS A record in response!"));
- status = PJLIB_UTIL_EDNSNOANSWERREC;
- goto on_error;
- }
-
- query->srv[srv_idx].addr[query->srv[srv_idx].addr_cnt++].s_addr =
- pkt->ans[ans_idx].rdata.a.ip_addr.s_addr;
-
- PJ_LOG(5,(query->objname,
- "DNS A for %.*s: %s",
- (int)query->srv[srv_idx].target_name.slen,
- query->srv[srv_idx].target_name.ptr,
- pj_inet_ntoa(pkt->ans[ans_idx].rdata.a.ip_addr)));
-
- /* Check for multiple IP addresses */
- for (j=ans_idx+1; j<pkt->hdr.anscount &&
- query->srv[srv_idx].addr_cnt < ADDR_MAX_COUNT; ++j)
- {
- query->srv[srv_idx].addr[query->srv[srv_idx].addr_cnt++].s_addr =
- pkt->ans[j].rdata.a.ip_addr.s_addr;
-
- PJ_LOG(5,(query->objname,
- "Additional DNS A for %.*s: %s",
- (int)query->srv[srv_idx].target_name.slen,
- query->srv[srv_idx].target_name.ptr,
- pj_inet_ntoa(pkt->ans[j].rdata.a.ip_addr)));
- }
- }
-
- } else if (status != PJ_SUCCESS) {
- char errmsg[PJ_ERR_MSG_SIZE];
-
- /* Update last error */
- query->last_error = status;
-
- /* Log error */
- pj_strerror(status, errmsg, sizeof(errmsg));
- PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",
- errmsg));
- }
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
- ++query->host_resolved;
+ /* Log error */
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",
+ errmsg));
- } else {
- pj_assert(!"Unexpected state!");
- query->last_error = status = PJ_EINVALIDOP;
- goto on_error;
+ /* Call the callback */
+ (*query->cb)(status, query->token, NULL);
+ return;
}
- /* Check if all hosts have been resolved */
- if (query->host_resolved == query->srv_cnt) {
- /* Got all answers, build server addresses */
- pjsip_server_addresses svr_addr;
-
- svr_addr.count = 0;
- for (i=0; i<query->srv_cnt; ++i) {
- unsigned j;
-
- /* Do we have IP address for this server? */
- /* This log is redundant really.
- if (query->srv[i].addr_cnt == 0) {
- PJ_LOG(5,(query->objname,
- " SRV target %.*s:%d does not have IP address!",
- (int)query->srv[i].target_name.slen,
- query->srv[i].target_name.ptr,
- query->srv[i].port));
- continue;
- }
- */
-
- for (j=0; j<query->srv[i].addr_cnt; ++j) {
- unsigned idx = svr_addr.count;
- pj_sockaddr_in *addr;
-
- svr_addr.entry[idx].type = query->srv[i].type;
- svr_addr.entry[idx].priority = query->srv[i].priority;
- svr_addr.entry[idx].weight = query->srv[i].weight;
- svr_addr.entry[idx].addr_len = sizeof(pj_sockaddr_in);
-
- addr = (pj_sockaddr_in*)&svr_addr.entry[idx].addr;
- pj_bzero(addr, sizeof(pj_sockaddr_in));
- addr->sin_family = PJ_AF_INET;
- addr->sin_addr = query->srv[i].addr[j];
- addr->sin_port = pj_htons((pj_uint16_t)query->srv[i].port);
-
- ++svr_addr.count;
- }
- }
-
- PJ_LOG(5,(query->objname,
- "Server resolution complete, %d server entry(s) found",
- svr_addr.count));
-
+ /* Build server addresses and call callback */
+ srv.count = 0;
+ for (i=0; i<rec->count; ++i) {
+ unsigned j;
- if (svr_addr.count > 0)
- status = PJ_SUCCESS;
- else {
- status = query->last_error;
- if (status == PJ_SUCCESS)
- status = PJLIB_UTIL_EDNSNOANSWERREC;
+ for (j=0; j<rec->entry[i].server.addr_count; ++j) {
+ srv.entry[srv.count].type = query->naptr[0].type;
+ srv.entry[srv.count].priority = rec->entry[i].priority;
+ srv.entry[srv.count].weight = rec->entry[i].weight;
+ srv.entry[srv.count].addr_len = sizeof(pj_sockaddr_in);
+ pj_sockaddr_in_init(&srv.entry[srv.count].addr.ipv4,
+ 0, (pj_uint16_t)rec->entry[i].port);
+ srv.entry[srv.count].addr.ipv4.sin_addr.s_addr =
+ rec->entry[i].server.addr[j].s_addr;
+
+ ++srv.count;
}
-
- /* Call the callback */
- (*query->cb)(status, query->token, &svr_addr);
}
-
- return;
-
-on_error:
- /* Check for failure */
- if (status != PJ_SUCCESS) {
- char errmsg[PJ_ERR_MSG_SIZE];
- PJ_LOG(4,(query->objname,
- "DNS %s record resolution error for '%.*s'."
- " Err=%d (%s)",
- pj_dns_get_type_name(query->dns_state),
- (int)query->req.target.addr.host.slen,
- query->req.target.addr.host.ptr,
- status,
- pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
- (*query->cb)(status, query->token, NULL);
- return;
- }
+ /* Call the callback */
+ (*query->cb)(PJ_SUCCESS, query->token, &srv);
}
#endif /* PJSIP_HAS_RESOLVER */
-
-