📄 sip_resolve.c
字号:
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]); /* 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; } } } /* 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; } /* 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)); } */ } /* 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)); }}/* 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){ struct query *query = user_data; 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) { /* Update IP address of the corresponding hostname */ for (i=0; i<query->srv_cnt; ++i) { if (pj_stricmp(&pkt->ans[0].name, &query->srv[i].target_name)==0) { break; } } if (i == 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 { unsigned j; query->srv[i].addr[query->srv[i].addr_cnt++].s_addr = pkt->ans[0].rdata.a.ip_addr.s_addr; PJ_LOG(5,(query->objname, "DNS A for %.*s: %s", (int)query->srv[i].target_name.slen, query->srv[i].target_name.ptr, pj_inet_ntoa(pkt->ans[0].rdata.a.ip_addr))); /* Check for multiple IP addresses */ for (j=1; j<pkt->hdr.anscount && query->srv[i].addr_cnt < ADDR_MAX_COUNT; ++j) { query->srv[i].addr[query->srv[i].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[i].target_name.slen, query->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->last_error = status; /* Log error */ pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s", errmsg)); } ++query->host_resolved; } else { pj_assert(!"Unexpected state!"); query->last_error = status = PJ_EINVALIDOP; goto on_error; } /* 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)); if (svr_addr.count > 0) status = PJ_SUCCESS; else { status = query->last_error; if (status == PJ_SUCCESS) status = PJLIB_UTIL_EDNSNOANSWERREC; } /* 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; }}#endif /* PJSIP_HAS_RESOLVER */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -