📄 srv_resolver.c
字号:
response->hdr.anscount,
(query_job->srv_cnt ? ':' : ' ')));
for (i=0; i<query_job->srv_cnt; ++i) {
const char *addr;
if (query_job->srv[i].addr_cnt != 0)
addr = pj_inet_ntoa(query_job->srv[i].addr[0]);
else
addr = "-";
PJ_LOG(5,(query_job->objname,
" %d: SRV %d %d %d %.*s (%s)",
i, query_job->srv[i].priority,
query_job->srv[i].weight,
query_job->srv[i].port,
(int)query_job->srv[i].target_name.slen,
query_job->srv[i].target_name.ptr,
addr));
}
}
/* Start DNS A record queries for all SRV records in the query_job structure */
static pj_status_t resolve_hostnames(pj_dns_srv_resolver_job *query_job)
{
unsigned i;
pj_status_t err=PJ_SUCCESS, status;
query_job->dns_state = PJ_DNS_TYPE_A;
for (i=0; i<query_job->srv_cnt; ++i) {
PJ_LOG(5, (query_job->objname,
"Starting async DNS A query_job for %.*s",
(int)query_job->srv[i].target_name.slen,
query_job->srv[i].target_name.ptr));
status = pj_dns_resolver_start_query(query_job->resolver,
&query_job->srv[i].target_name,
PJ_DNS_TYPE_A, 0,
&dns_callback,
query_job, NULL);
if (status != PJ_SUCCESS) {
query_job->host_resolved++;
err = status;
}
}
return (query_job->host_resolved == query_job->srv_cnt) ? err : PJ_SUCCESS;
}
/*
* This callback is called by PJLIB-UTIL DNS resolver when asynchronous
* query_job has completed (successfully or with error).
*/
static void dns_callback(void *user_data,
pj_status_t status,
pj_dns_parsed_packet *pkt)
{
pj_dns_srv_resolver_job *query_job = (pj_dns_srv_resolver_job*) user_data;
unsigned i;
/* Proceed to next stage */
if (query_job->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_job, pkt);
} else if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
/* Update query_job last error */
query_job->last_error = status;
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(query_job->objname,
"DNS SRV resolution failed for %.*s: %s",
(int)query_job->full_name.slen,
query_job->full_name.ptr,
errmsg));
/* Trigger error when fallback is disabled */
if (query_job->fallback_a == PJ_FALSE) {
goto on_error;
}
}
/* If we can't build SRV record, assume the original target is
* an A record and resolve with DNS A resolution.
*/
if (query_job->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.
*/
PJ_LOG(4, (query_job->objname,
"DNS SRV resolution failed for %.*s, trying "
"resolving A record for %.*s",
(int)query_job->full_name.slen,
query_job->full_name.ptr,
(int)query_job->domain_part.slen,
query_job->domain_part.ptr));
/* Create a "dummy" srv record using the original target */
i = query_job->srv_cnt++;
pj_bzero(&query_job->srv[i], sizeof(query_job->srv[i]));
query_job->srv[i].target_name = query_job->domain_part;
query_job->srv[i].priority = 0;
query_job->srv[i].weight = 0;
query_job->srv[i].port = query_job->def_port;
}
/* Resolve server hostnames (DNS A record) for hosts which don't have
* A record yet.
*/
if (query_job->host_resolved != query_job->srv_cnt) {
status = resolve_hostnames(query_job);
if (status != PJ_SUCCESS)
goto on_error;
/* Must return now. Callback may have been called and query_job
* may have been destroyed.
*/
return;
}
} else if (query_job->dns_state == PJ_DNS_TYPE_A) {
/* Check that we really have answer */
if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) {
int ans_idx = -1;
/* Find the first DNS A record in the answer while processing
* the CNAME info found in the response.
*/
for (i=0; i < pkt->hdr.anscount; ++i) {
pj_dns_parsed_rr *rr = &pkt->ans[i];
if (rr->type == PJ_DNS_TYPE_A) {
if (ans_idx == -1)
ans_idx = i;
} else if (rr->type == PJ_DNS_TYPE_CNAME) {
/* Find which server entry to be updated with
* the CNAME information.
*/
unsigned j;
pj_str_t cname = rr->rdata.cname.name;
for (j=0; j<query_job->srv_cnt; ++j)
{
struct srv_target *srv = &query_job->srv[j];
if (pj_stricmp(&rr->name, &srv->target_name)==0)
{
/* Update CNAME info for this server entry */
srv->cname.ptr = srv->cname_buf;
pj_strncpy(&srv->cname, &cname,
sizeof(srv->cname_buf));
break;
}
}
}
}
if (ans_idx == -1) {
/* There's no DNS A answer! */
PJ_LOG(5,(query_job->objname,
"No DNS A record in response!"));
status = PJLIB_UTIL_EDNSNOANSWERREC;
goto on_error;
}
/* Update IP address of the corresponding hostname or CNAME */
for (i=0; i<query_job->srv_cnt; ++i) {
pj_dns_parsed_rr *rr = &pkt->ans[ans_idx];
struct srv_target *srv = &query_job->srv[i];
if (pj_stricmp(&rr->name, &srv->target_name)==0 ||
pj_stricmp(&rr->name, &srv->cname)==0)
{
break;
}
}
if (i == query_job->srv_cnt) {
PJ_LOG(4,(query_job->objname,
"Received answer to DNS A request with no matching "
"SRV record! The unknown name is %.*s",
(int)pkt->ans[ans_idx].name.slen,
pkt->ans[ans_idx].name.ptr));
} else {
unsigned j;
query_job->srv[i].addr[query_job->srv[i].addr_cnt++].s_addr =
pkt->ans[ans_idx].rdata.a.ip_addr.s_addr;
PJ_LOG(5,(query_job->objname,
"DNS A for %.*s: %s",
(int)query_job->srv[i].target_name.slen,
query_job->srv[i].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_job->srv[i].addr_cnt < ADDR_MAX_COUNT; ++j)
{
query_job->srv[i].addr[query_job->srv[i].addr_cnt++].s_addr =
pkt->ans[j].rdata.a.ip_addr.s_addr;
PJ_LOG(5,(query_job->objname,
"Additional DNS A for %.*s: %s",
(int)query_job->srv[i].target_name.slen,
query_job->srv[i].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_job->last_error = status;
/* Log error */
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(query_job->objname, "DNS A record resolution failed: %s",
errmsg));
}
++query_job->host_resolved;
} else {
pj_assert(!"Unexpected state!");
query_job->last_error = status = PJ_EINVALIDOP;
goto on_error;
}
/* Check if all hosts have been resolved */
if (query_job->host_resolved == query_job->srv_cnt) {
/* Got all answers, build server addresses */
pj_dns_srv_record svr_addr;
svr_addr.count = 0;
for (i=0; i<query_job->srv_cnt; ++i) {
unsigned j;
/* Do we have IP address for this server? */
/* This log is redundant really.
if (query_job->srv[i].addr_cnt == 0) {
PJ_LOG(5,(query_job->objname,
" SRV target %.*s:%d does not have IP address!",
(int)query_job->srv[i].target_name.slen,
query_job->srv[i].target_name.ptr,
query_job->srv[i].port));
continue;
}
*/
for (j=0; j<query_job->srv[i].addr_cnt; ++j) {
unsigned idx = svr_addr.count;
pj_sockaddr_in *addr;
svr_addr.entry[idx].priority = query_job->srv[i].priority;
svr_addr.entry[idx].weight = query_job->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_job->srv[i].addr[j];
addr->sin_port = pj_htons((pj_uint16_t)query_job->srv[i].port);
++svr_addr.count;
}
}
PJ_LOG(5,(query_job->objname,
"Server resolution complete, %d server entry(s) found",
svr_addr.count));
if (svr_addr.count > 0)
status = PJ_SUCCESS;
else {
status = query_job->last_error;
if (status == PJ_SUCCESS)
status = PJLIB_UTIL_EDNSNOANSWERREC;
}
/* Call the callback */
(*query_job->cb)(query_job->token, status, &svr_addr);
}
return;
on_error:
/* Check for failure */
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
PJ_UNUSED_ARG(errmsg);
PJ_LOG(4,(query_job->objname,
"DNS %s record resolution error for '%.*s'."
" Err=%d (%s)",
pj_dns_get_type_name(query_job->dns_state),
(int)query_job->domain_part.slen,
query_job->domain_part.ptr,
status,
pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
(*query_job->cb)(query_job->token, status, NULL);
return;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -