Changeset 1358 for pjproject/trunk


Ignore:
Timestamp:
Jun 11, 2007 4:54:10 PM (17 years ago)
Author:
bennylp
Message:

Ticket #331: Changed PJSIP DNS SRV resolver to use PJLIB-UTIL DNS SRV resolver

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_resolve.c

    r1326 r1358  
    2121#include <pjsip/sip_errno.h> 
    2222#include <pjlib-util/errno.h> 
     23#include <pjlib-util/srv_resolver.h> 
    2324#include <pj/array.h> 
    2425#include <pj/assert.h> 
     
    3637struct naptr_target 
    3738{ 
    38     pj_str_t                target_name;    /**< NAPTR target name. */ 
     39    pj_str_t                res_type;       /**< e.g. "_sip._udp"   */ 
     40    pj_str_t                name;           /**< Domain name.       */ 
    3941    pjsip_transport_type_e  type;           /**< Transport type.    */ 
    4042    unsigned                order;          /**< Order              */ 
     
    4244}; 
    4345 
    44 struct srv_target 
    45 { 
    46     pjsip_transport_type_e  type; 
    47     pj_str_t                target_name; 
    48     char                    target_buf[PJ_MAX_HOSTNAME]; 
    49     unsigned                port; 
    50     unsigned                priority; 
    51     unsigned                weight; 
    52     unsigned                sum; 
    53     unsigned                addr_cnt; 
    54     pj_in_addr              addr[ADDR_MAX_COUNT]; 
    55 }; 
    56  
    5746struct query 
    5847{ 
    59     char                     objname[PJ_MAX_OBJ_NAME]; 
    60  
    61     pjsip_resolver_t        *resolver;      /**< Resolver SIP instance.     */ 
    62     pj_dns_type              dns_state;     /**< DNS type being resolved.   */ 
     48    char                    *objname; 
     49 
     50    pj_dns_type              query_type; 
    6351    void                    *token; 
    6452    pjsip_resolver_callback *cb; 
     
    6957    struct { 
    7058        pjsip_host_info      target; 
     59        unsigned             def_port; 
    7160    } req; 
    7261 
     
    7463    unsigned                 naptr_cnt; 
    7564    struct naptr_target      naptr[8]; 
    76  
    77     /* SRV records and their resolved IP addresses: */ 
    78     unsigned                 srv_cnt; 
    79     struct srv_target        srv[PJSIP_MAX_RESOLVED_ADDRESSES]; 
    80  
    81     /* Number of hosts in SRV records that the IP address has been resolved */ 
    82     unsigned                 host_resolved; 
    8365}; 
    8466 
     
    8769{ 
    8870    pj_dns_resolver *res; 
    89     unsigned         job_id; 
    9071}; 
    9172 
    92 static void dns_callback(void *user_data, 
    93                          pj_status_t status, 
    94                          pj_dns_parsed_packet *response); 
     73 
     74static void srv_resolver_cb(void *user_data, 
     75                            pj_status_t status, 
     76                            const pj_dns_srv_record *rec); 
     77static void dns_a_callback(void *user_data, 
     78                           pj_status_t status, 
     79                           pj_dns_parsed_packet *response); 
    9580 
    9681 
     
    184169    int is_ip_addr; 
    185170    struct query *query; 
    186     pj_str_t srv_name; 
    187171    pjsip_transport_type_e type = target->type; 
    188172 
     
    280264    /* Build the query state */ 
    281265    query = PJ_POOL_ZALLOC_T(pool, struct query); 
    282     pj_ansi_snprintf(query->objname, sizeof(query->objname), "rsvjob%X", 
    283                      resolver->job_id++); 
    284     query->resolver = resolver; 
     266    query->objname = THIS_FILE; 
    285267    query->token = token; 
    286268    query->cb = cb; 
     
    299281    query->naptr[0].pref = 0; 
    300282    query->naptr[0].type = type; 
    301     query->naptr[0].target_name.ptr = (char*) 
    302         pj_pool_alloc(pool, target->addr.host.slen + 12); 
    303  
    304     if (type == PJSIP_TRANSPORT_TLS) 
    305         pj_strcpy2(&query->naptr[0].target_name, "_sips._tcp."); 
    306     else if (type == PJSIP_TRANSPORT_TCP) 
    307         pj_strcpy2(&query->naptr[0].target_name, "_sip._tcp."); 
    308     else if (type == PJSIP_TRANSPORT_UDP) 
    309         pj_strcpy2(&query->naptr[0].target_name, "_sip._udp."); 
    310     else { 
    311         pj_assert(!"Unknown transport type"); 
    312         pj_strcpy2(&query->naptr[0].target_name, "_sip._udp."); 
    313     } 
    314     pj_strcat(&query->naptr[0].target_name, &target->addr.host); 
     283    pj_strdup(pool, &query->naptr[0].name, &target->addr.host); 
    315284 
    316285 
    317286    /* Start DNS SRV or A resolution, depending on whether port is specified */ 
    318287    if (target->addr.port == 0) { 
    319         query->dns_state = PJ_DNS_TYPE_SRV; 
    320         srv_name = query->naptr[0].target_name; 
     288        query->query_type = PJ_DNS_TYPE_SRV; 
     289 
     290        query->req.def_port = 5060; 
     291 
     292        if (type == PJSIP_TRANSPORT_TLS) { 
     293            query->naptr[0].res_type = pj_str("_sips._tcp."); 
     294            query->req.def_port = 5061; 
     295        } else if (type == PJSIP_TRANSPORT_TCP) 
     296            query->naptr[0].res_type = pj_str("_sip._tcp."); 
     297        else if (type == PJSIP_TRANSPORT_UDP) 
     298            query->naptr[0].res_type = pj_str("_sip._udp."); 
     299        else { 
     300            pj_assert(!"Unknown transport type"); 
     301            query->naptr[0].res_type = pj_str("_sip._udp."); 
     302             
     303        } 
    321304 
    322305    } else { 
     
    324307         * resolution  
    325308         */ 
    326         query->dns_state = PJ_DNS_TYPE_A; 
    327  
    328         /* Since we don't perform SRV resolution, pretend that we'ee already 
    329          * done so by inserting a dummy SRV record. 
    330          */ 
    331  
    332         query->srv_cnt = 1; 
    333         pj_bzero(&query->srv[0], sizeof(query->srv[0])); 
    334         query->srv[0].target_name = query->req.target.addr.host; 
    335         query->srv[0].type = type; 
    336         query->srv[0].port = query->req.target.addr.port; 
    337         query->srv[0].priority = 0; 
    338         query->srv[0].weight = 0; 
    339  
    340         srv_name = query->srv[0].target_name; 
     309        query->query_type = PJ_DNS_TYPE_A; 
     310        query->naptr[0].res_type.slen = 0; 
     311        query->req.def_port = target->addr.port; 
    341312    } 
    342313 
    343314    /* Start the asynchronous query */ 
    344315    PJ_LOG(5, (query->objname,  
    345                "Starting async DNS %s query: target=%.*s, transport=%s, " 
     316               "Starting async DNS %s query: target=%.*s%.*s, transport=%s, " 
    346317               "port=%d", 
    347                pj_dns_get_type_name(query->dns_state), 
    348                (int)srv_name.slen, srv_name.ptr, 
     318               pj_dns_get_type_name(query->query_type), 
     319               (int)query->naptr[0].res_type.slen, 
     320               query->naptr[0].res_type.ptr, 
     321               (int)query->naptr[0].name.slen, query->naptr[0].name.ptr, 
    349322               pjsip_transport_get_type_name(target->type), 
    350323               target->addr.port)); 
    351324 
    352     status = pj_dns_resolver_start_query(resolver->res, &srv_name,  
    353                                          query->dns_state, 0, &dns_callback, 
    354                                          query, &query->object); 
     325    if (query->query_type == PJ_DNS_TYPE_SRV) { 
     326 
     327        status = pj_dns_srv_resolve(&query->naptr[0].name, 
     328                                    &query->naptr[0].res_type, 
     329                                    query->req.def_port, pool, resolver->res, 
     330                                    PJ_TRUE, query, &srv_resolver_cb, NULL); 
     331 
     332    } else if (query->query_type == PJ_DNS_TYPE_A) { 
     333 
     334        status = pj_dns_resolver_start_query(resolver->res,  
     335                                             &query->naptr[0].name, 
     336                                             PJ_DNS_TYPE_A, 0,  
     337                                             &dns_a_callback, 
     338                                             query, &query->object); 
     339 
     340    } else { 
     341        pj_assert(!"Unexpected"); 
     342        status = PJ_EBUG; 
     343    } 
     344 
    355345    if (status != PJ_SUCCESS) 
    356346        goto on_error; 
     
    377367} 
    378368 
    379 /* 
    380  * The rest of the code should only get compiled when resolver is enabled 
    381  */ 
    382369#if PJSIP_HAS_RESOLVER 
    383370 
    384 #define SWAP(type,ptr1,ptr2)    if (ptr1 != ptr2) { \ 
    385                                   type tmp; \ 
    386                                   pj_memcpy(&tmp, ptr1, sizeof(type)); \ 
    387                                   pj_memcpy(ptr1, ptr2, sizeof(type)); \ 
    388                                   (ptr1)->target_name.ptr = (ptr1)->target_buf; \ 
    389                                   pj_memcpy(ptr2, &tmp, sizeof(type)); \ 
    390                                   (ptr2)->target_name.ptr = (ptr2)->target_buf; \ 
    391                                 } else {} 
    392  
    393 /* Build server entries in the query based on received SRV response */ 
    394 static void build_server_entries(struct query *query,  
    395                                  pj_dns_parsed_packet *response) 
    396 { 
     371/*  
     372 * This callback is called when target is resolved with DNS A query. 
     373 */ 
     374static void dns_a_callback(void *user_data, 
     375                           pj_status_t status, 
     376                           pj_dns_parsed_packet *pkt) 
     377{ 
     378    struct query *query = (struct query*) user_data; 
     379    pjsip_server_addresses srv; 
     380    pj_dns_a_record rec; 
    397381    unsigned i; 
    398     unsigned naptr_id; 
    399  
    400     /* Find NAPTR target which corresponds to this SRV target */ 
    401     for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) { 
    402         if (pj_stricmp(&query->naptr[naptr_id].target_name, 
    403                        &response->ans[0].name)==0) 
    404             break; 
    405     } 
    406     if (naptr_id == query->naptr_cnt) { 
    407         PJ_LOG(4,(query->objname,  
    408                   "Unable to find NAPTR record for SRV name %.*s!", 
    409                   (int)response->ans[0].name.slen,  
    410                   response->ans[0].name.ptr)); 
    411         return; 
    412     } 
    413  
    414  
    415     /* Save the Resource Records in DNS answer into SRV targets. */ 
    416     query->srv_cnt = 0; 
    417     for (i=0; i<response->hdr.anscount &&  
    418               query->srv_cnt < PJSIP_MAX_RESOLVED_ADDRESSES; ++i)  
    419     { 
    420         pj_dns_parsed_rr *rr = &response->ans[i]; 
    421         struct srv_target *srv = &query->srv[query->srv_cnt]; 
    422  
    423         if (rr->type != PJ_DNS_TYPE_SRV) { 
    424             PJ_LOG(4,(query->objname,  
    425                       "Received non SRV answer for SRV query!")); 
    426             continue; 
    427         } 
    428  
    429         if (rr->rdata.srv.target.slen > PJ_MAX_HOSTNAME) { 
    430             PJ_LOG(4,(query->objname, "Hostname is too long!")); 
    431             continue; 
    432         } 
    433  
    434         /* Build the SRV entry for RR */ 
    435         pj_bzero(srv, sizeof(*srv)); 
    436         pj_memcpy(srv->target_buf, rr->rdata.srv.target.ptr,  
    437                   rr->rdata.srv.target.slen); 
    438         srv->target_name.ptr = srv->target_buf; 
    439         srv->target_name.slen = rr->rdata.srv.target.slen; 
    440         srv->type = query->naptr[naptr_id].type; 
    441         srv->port = rr->rdata.srv.port; 
    442         srv->priority = rr->rdata.srv.prio; 
    443         srv->weight = rr->rdata.srv.weight; 
    444          
    445         ++query->srv_cnt; 
    446     } 
    447  
    448     /* First pass:  
    449      *  order the entries based on priority. 
    450      */ 
    451     for (i=0; i<query->srv_cnt-1; ++i) { 
    452         unsigned min = i, j; 
    453         for (j=i+1; j<query->srv_cnt; ++j) { 
    454             if (query->srv[j].priority < query->srv[min].priority) 
    455                 min = j; 
    456         } 
    457         SWAP(struct srv_target, &query->srv[i], &query->srv[min]); 
    458     } 
    459  
    460     /* Second pass: 
    461      *  pick one host among hosts with the same priority, according 
    462      *  to its weight. The idea is when one server fails, client should 
    463      *  contact the next server with higher priority rather than contacting 
    464      *  server with the same priority as the failed one. 
    465      * 
    466      *  The algorithm for selecting server among servers with the same 
    467      *  priority is described in RFC 2782. 
    468      */ 
    469     for (i=0; i<query->srv_cnt; ++i) { 
    470         unsigned j, count=1, sum; 
    471  
    472         /* Calculate running sum for servers with the same priority */ 
    473         sum = query->srv[i].sum = query->srv[i].weight; 
    474         for (j=i+1; j<query->srv_cnt &&  
    475                     query->srv[j].priority == query->srv[i].priority; ++j) 
    476         { 
    477             sum += query->srv[j].weight; 
    478             query->srv[j].sum = sum; 
    479             ++count; 
    480         } 
    481  
    482         if (count > 1) { 
    483             unsigned r; 
    484  
    485             /* Elect one random number between zero and the total sum of 
    486              * weight (inclusive). 
    487              */ 
    488             r = pj_rand() % (sum + 1); 
    489  
    490             /* Select the first server which running sum is greater than or 
    491              * equal to the random number. 
    492              */ 
    493             for (j=i; j<i+count; ++j) { 
    494                 if (query->srv[j].sum >= r) 
    495                     break; 
    496             } 
    497  
    498             /* Must have selected one! */ 
    499             pj_assert(j != i+count); 
    500  
    501             /* Put this entry in front (of entries with same priority) */ 
    502             SWAP(struct srv_target, &query->srv[i], &query->srv[j]); 
    503  
    504             /* Remove all other entries (of the same priority) */ 
    505             while (count > 1) { 
    506                 pj_array_erase(query->srv, sizeof(struct srv_target),  
    507                                query->srv_cnt, i+1); 
    508                 --count; 
    509                 --query->srv_cnt; 
    510             } 
    511         } 
    512     } 
    513  
    514     /* Since we've been moving around SRV entries, update the pointers 
    515      * in target_name. 
    516      */ 
    517     for (i=0; i<query->srv_cnt; ++i) { 
    518         query->srv[i].target_name.ptr = query->srv[i].target_buf; 
    519     } 
    520  
    521     /* Check for Additional Info section if A records are available, and 
    522      * fill in the IP address (so that we won't need to resolve the A  
    523      * record with another DNS query).  
    524      */ 
    525     for (i=0; i<response->hdr.arcount; ++i) { 
    526         pj_dns_parsed_rr *rr = &response->arr[i]; 
    527         unsigned j; 
    528  
    529         if (rr->type != PJ_DNS_TYPE_A) 
    530             continue; 
    531  
    532         /* Yippeaiyee!! There is an "A" record!  
    533          * Update the IP address of the corresponding SRV record. 
    534          */ 
    535         for (j=0; j<query->srv_cnt; ++j) { 
    536             if (pj_stricmp(&rr->name, &query->srv[j].target_name)==0) { 
    537                 unsigned cnt = query->srv[j].addr_cnt; 
    538                 query->srv[j].addr[cnt].s_addr = rr->rdata.a.ip_addr.s_addr; 
    539                 ++query->srv[j].addr_cnt; 
    540                 ++query->host_resolved; 
    541                 break; 
    542             } 
    543         } 
    544  
    545         /* Not valid message; SRV entry might have been deleted in 
    546          * server selection process. 
    547          */ 
    548         /* 
    549         if (j == query->srv_cnt) { 
    550             PJ_LOG(4,(query->objname,  
    551                       "Received DNS SRV answer with A record, but " 
    552                       "couldn't find matching name (name=%.*s)", 
    553                       (int)rr->name.slen, 
    554                       rr->name.ptr)); 
    555         } 
    556         */ 
    557     } 
    558  
    559     /* Rescan again the name specified in the SRV record to see if IP 
    560      * address is specified as the target name (unlikely, but well, who  
    561      * knows..). 
    562      */ 
    563     for (i=0; i<query->srv_cnt; ++i) { 
    564         pj_in_addr addr; 
    565  
    566         if (query->srv[i].addr_cnt != 0) { 
    567             /* IP address already resolved */ 
    568             continue; 
    569         } 
    570  
    571         if (pj_inet_aton(&query->srv[i].target_name, &addr) != 0) { 
    572             query->srv[i].addr[query->srv[i].addr_cnt++] = addr; 
    573             ++query->host_resolved; 
    574         } 
    575     } 
    576  
    577     /* Print resolved entries to the log */ 
    578     PJ_LOG(5,(query->objname,  
    579               "SRV query for %.*s completed, " 
    580               "%d of %d total entries selected%c", 
    581               (int)query->naptr[naptr_id].target_name.slen, 
    582               query->naptr[naptr_id].target_name.ptr, 
    583               query->srv_cnt, 
    584               response->hdr.anscount, 
    585               (query->srv_cnt ? ':' : ' '))); 
    586  
    587     for (i=0; i<query->srv_cnt; ++i) { 
    588         const char *addr; 
    589  
    590         if (query->srv[i].addr_cnt != 0) 
    591             addr = pj_inet_ntoa(query->srv[i].addr[0]); 
    592         else 
    593             addr = "-"; 
    594  
    595         PJ_LOG(5,(query->objname,  
    596                   " %d: SRV %d %d %d %.*s (%s)", 
    597                   i, query->srv[i].priority,  
    598                   query->srv[i].weight,  
    599                   query->srv[i].port,  
    600                   (int)query->srv[i].target_name.slen,  
    601                   query->srv[i].target_name.ptr, 
    602                   addr)); 
    603     } 
    604 } 
    605  
    606  
    607 /* Start DNS A record queries for all SRV records in the query structure */ 
    608 static pj_status_t resolve_hostnames(struct query *query) 
    609 { 
    610     unsigned i; 
    611     pj_status_t err=PJ_SUCCESS, status; 
    612  
    613     query->dns_state = PJ_DNS_TYPE_A; 
    614     for (i=0; i<query->srv_cnt; ++i) { 
    615         PJ_LOG(5, (query->objname,  
    616                    "Starting async DNS A query for %.*s", 
    617                    (int)query->srv[i].target_name.slen,  
    618                    query->srv[i].target_name.ptr)); 
    619  
    620         status = pj_dns_resolver_start_query(query->resolver->res, 
    621                                              &query->srv[i].target_name, 
    622                                              PJ_DNS_TYPE_A, 0, 
    623                                              &dns_callback, 
    624                                              query, NULL); 
    625         if (status != PJ_SUCCESS) { 
    626             query->host_resolved++; 
    627             err = status; 
    628         } 
    629     } 
    630      
    631     return (query->host_resolved == query->srv_cnt) ? err : PJ_SUCCESS; 
    632 } 
    633  
    634 /*  
    635  * This callback is called by PJLIB-UTIL DNS resolver when asynchronous 
    636  * query has completed (successfully or with error). 
    637  */ 
    638 static void dns_callback(void *user_data, 
    639                          pj_status_t status, 
    640                          pj_dns_parsed_packet *pkt) 
    641 { 
    642     struct query *query = (struct query*) user_data; 
    643     unsigned i; 
    644  
    645     /* Proceed to next stage */ 
    646  
    647     if (query->dns_state == PJ_DNS_TYPE_SRV) { 
    648  
    649         /* We are getting SRV response */ 
    650  
    651         if (status == PJ_SUCCESS && pkt->hdr.anscount != 0) { 
    652             /* Got SRV response, build server entry. If A records are available 
    653              * in additional records section of the DNS response, save them too. 
    654              */ 
    655             build_server_entries(query, pkt); 
    656  
    657         } else if (status != PJ_SUCCESS) { 
    658             char errmsg[PJ_ERR_MSG_SIZE]; 
    659             unsigned naptr_id; 
    660  
    661             /* Update query last error */ 
    662             query->last_error = status; 
    663  
    664             /* Find which NAPTR target has not got SRV records */ 
    665             for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) { 
    666                 for (i=0; i<query->srv_cnt; ++i) { 
    667                     if (query->srv[i].type == query->naptr[naptr_id].type) 
    668                         break; 
    669                 } 
    670                 if (i == query->srv_cnt) 
    671                     break; 
    672             } 
    673             if (naptr_id == query->naptr_cnt) { 
    674                 /* Strangely all NAPTR records seem to already have SRV 
    675                  * records! This is quite unexpected, by anyway lets set 
    676                  * the naptr_id to zero just in case. 
    677                  */ 
    678                 pj_assert(!"Strange"); 
    679                 naptr_id = 0; 
    680  
    681             } 
    682  
    683             pj_strerror(status, errmsg, sizeof(errmsg)); 
    684             PJ_LOG(4,(query->objname,  
    685                       "DNS SRV resolution failed for %.*s: %s",  
    686                       (int)query->naptr[naptr_id].target_name.slen,  
    687                       query->naptr[naptr_id].target_name.ptr, 
    688                       errmsg)); 
    689         } 
    690  
    691         /* If we can't build SRV record, assume the original target is 
    692          * an A record. 
    693          */ 
    694         if (query->srv_cnt == 0) { 
    695             /* Looks like we aren't getting any SRV responses. 
    696              * Resolve the original target as A record by creating a  
    697              * single "dummy" srv record and start the hostname resolution. 
    698              */ 
    699             unsigned naptr_id; 
    700  
    701             /* Find which NAPTR target has not got SRV records */ 
    702             for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) { 
    703                 for (i=0; i<query->srv_cnt; ++i) { 
    704                     if (query->srv[i].type == query->naptr[naptr_id].type) 
    705                         break; 
    706                 } 
    707                 if (i == query->srv_cnt) 
    708                     break; 
    709             } 
    710             if (naptr_id == query->naptr_cnt) { 
    711                 /* Strangely all NAPTR records seem to already have SRV 
    712                  * records! This is quite unexpected, by anyway lets set 
    713                  * the naptr_id to zero just in case. 
    714                  */ 
    715                 pj_assert(!"Strange"); 
    716                 naptr_id = 0; 
    717  
    718             } 
    719  
    720             PJ_LOG(4, (query->objname,  
    721                        "DNS SRV resolution failed for %.*s, trying " 
    722                        "resolving A record for %.*s", 
    723                        (int)query->naptr[naptr_id].target_name.slen,  
    724                        query->naptr[naptr_id].target_name.ptr, 
    725                        (int)query->req.target.addr.host.slen, 
    726                        query->req.target.addr.host.ptr)); 
    727  
    728             /* Create a "dummy" srv record using the original target */ 
    729             i = query->srv_cnt++; 
    730             pj_bzero(&query->srv[i], sizeof(query->srv[i])); 
    731             query->srv[i].target_name = query->req.target.addr.host; 
    732             query->srv[i].type = query->naptr[naptr_id].type; 
    733             query->srv[i].priority = 0; 
    734             query->srv[i].weight = 0; 
    735  
    736             query->srv[i].port = query->req.target.addr.port; 
    737             if (query->srv[i].port == 0) { 
    738                 query->srv[i].port = (pj_uint16_t) 
    739                  pjsip_transport_get_default_port_for_type(query->srv[i].type); 
    740             } 
    741         }  
    742          
    743  
    744         /* Resolve server hostnames (DNS A record) for hosts which don't have 
    745          * A record yet. 
    746          */ 
    747         if (query->host_resolved != query->srv_cnt) { 
    748             status = resolve_hostnames(query); 
    749             if (status != PJ_SUCCESS) 
    750                 goto on_error; 
    751  
    752             /* Must return now. Callback may have been called and query 
    753              * may have been destroyed. 
    754              */ 
    755             return; 
    756         } 
    757  
    758     } else if (query->dns_state == PJ_DNS_TYPE_A) { 
    759  
    760         /* Check that we really have answer */ 
    761         if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) { 
    762  
    763             unsigned srv_idx; 
    764  
    765             /* Update IP address of the corresponding hostname */ 
    766             for (srv_idx=0; srv_idx<query->srv_cnt; ++srv_idx) { 
    767                 if (pj_stricmp(&pkt->ans[0].name,  
    768                                &query->srv[srv_idx].target_name)==0)  
    769                 { 
    770                     break; 
    771                 } 
    772             } 
    773  
    774             if (srv_idx == query->srv_cnt) { 
    775                 PJ_LOG(4,(query->objname,  
    776                           "Received answer to DNS A request with no matching " 
    777                           "SRV record! The unknown name is %.*s", 
    778                           (int)pkt->ans[0].name.slen, pkt->ans[0].name.ptr)); 
    779             } else { 
    780                 int ans_idx = -1; 
    781                 unsigned k, j; 
    782                 pj_str_t cname = { NULL, 0 }; 
    783  
    784                 /* Find the first DNS A record in the answer while processing 
    785                  * the CNAME info found in the response. 
    786                  */ 
    787                 for (k=0; k < pkt->hdr.anscount; ++k) { 
    788  
    789                     pj_dns_parsed_rr *rr = &pkt->ans[k]; 
    790  
    791                     if (rr->type == PJ_DNS_TYPE_A && 
    792                         (cname.slen == 0 || pj_stricmp(&rr->name, &cname)==0)) 
    793                     { 
    794                         if (ans_idx == -1) 
    795                             ans_idx = k; 
    796  
    797                     } else if (rr->type == PJ_DNS_TYPE_CNAME && 
    798                                pj_stricmp(&query->srv[srv_idx].target_name,  
    799                                           &rr->name)==0)  
    800                     { 
    801                         cname = rr->rdata.cname.name; 
    802                     } 
    803                 } 
    804  
    805                 if (ans_idx == -1) { 
    806                     /* There's no DNS A answer! */ 
    807                     PJ_LOG(5,(query->objname,  
    808                               "No DNS A record in response!")); 
    809                     status = PJLIB_UTIL_EDNSNOANSWERREC; 
    810                     goto on_error; 
    811                 } 
    812  
    813                 query->srv[srv_idx].addr[query->srv[srv_idx].addr_cnt++].s_addr = 
    814                     pkt->ans[ans_idx].rdata.a.ip_addr.s_addr; 
    815  
    816                 PJ_LOG(5,(query->objname,  
    817                           "DNS A for %.*s: %s", 
    818                           (int)query->srv[srv_idx].target_name.slen,  
    819                           query->srv[srv_idx].target_name.ptr, 
    820                           pj_inet_ntoa(pkt->ans[ans_idx].rdata.a.ip_addr))); 
    821  
    822                 /* Check for multiple IP addresses */ 
    823                 for (j=ans_idx+1; j<pkt->hdr.anscount &&  
    824                             query->srv[srv_idx].addr_cnt < ADDR_MAX_COUNT; ++j) 
    825                 { 
    826                     query->srv[srv_idx].addr[query->srv[srv_idx].addr_cnt++].s_addr =  
    827                         pkt->ans[j].rdata.a.ip_addr.s_addr; 
    828  
    829                     PJ_LOG(5,(query->objname,  
    830                               "Additional DNS A for %.*s: %s", 
    831                               (int)query->srv[srv_idx].target_name.slen,  
    832                               query->srv[srv_idx].target_name.ptr, 
    833                               pj_inet_ntoa(pkt->ans[j].rdata.a.ip_addr))); 
    834                 } 
    835             } 
    836  
    837         } else if (status != PJ_SUCCESS) { 
    838             char errmsg[PJ_ERR_MSG_SIZE]; 
    839  
    840             /* Update last error */ 
    841             query->last_error = status; 
    842  
    843             /* Log error */ 
    844             pj_strerror(status, errmsg, sizeof(errmsg)); 
    845             PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",  
    846                       errmsg)); 
    847         } 
    848  
    849         ++query->host_resolved; 
    850  
    851     } else { 
    852         pj_assert(!"Unexpected state!"); 
    853         query->last_error = status = PJ_EINVALIDOP; 
    854         goto on_error; 
    855     } 
    856  
    857     /* Check if all hosts have been resolved */ 
    858     if (query->host_resolved == query->srv_cnt) { 
    859         /* Got all answers, build server addresses */ 
    860         pjsip_server_addresses svr_addr; 
    861  
    862         svr_addr.count = 0; 
    863         for (i=0; i<query->srv_cnt; ++i) { 
    864             unsigned j; 
    865  
    866             /* Do we have IP address for this server? */ 
    867             /* This log is redundant really. 
    868             if (query->srv[i].addr_cnt == 0) { 
    869                 PJ_LOG(5,(query->objname,  
    870                           " SRV target %.*s:%d does not have IP address!", 
    871                           (int)query->srv[i].target_name.slen, 
    872                           query->srv[i].target_name.ptr, 
    873                           query->srv[i].port)); 
    874                 continue; 
    875             } 
    876             */ 
    877  
    878             for (j=0; j<query->srv[i].addr_cnt; ++j) { 
    879                 unsigned idx = svr_addr.count; 
    880                 pj_sockaddr_in *addr; 
    881  
    882                 svr_addr.entry[idx].type = query->srv[i].type; 
    883                 svr_addr.entry[idx].priority = query->srv[i].priority; 
    884                 svr_addr.entry[idx].weight = query->srv[i].weight; 
    885                 svr_addr.entry[idx].addr_len = sizeof(pj_sockaddr_in); 
    886               
    887                 addr = (pj_sockaddr_in*)&svr_addr.entry[idx].addr; 
    888                 pj_bzero(addr, sizeof(pj_sockaddr_in)); 
    889                 addr->sin_family = PJ_AF_INET; 
    890                 addr->sin_addr = query->srv[i].addr[j]; 
    891                 addr->sin_port = pj_htons((pj_uint16_t)query->srv[i].port); 
    892  
    893                 ++svr_addr.count; 
    894             } 
    895         } 
    896  
    897         PJ_LOG(5,(query->objname,  
    898                   "Server resolution complete, %d server entry(s) found", 
    899                   svr_addr.count)); 
    900  
    901  
    902         if (svr_addr.count > 0) 
    903             status = PJ_SUCCESS; 
    904         else { 
    905             status = query->last_error; 
    906             if (status == PJ_SUCCESS) 
    907                 status = PJLIB_UTIL_EDNSNOANSWERREC; 
    908         } 
    909  
    910         /* Call the callback */ 
    911         (*query->cb)(status, query->token, &svr_addr); 
    912     } 
    913  
    914  
    915     return; 
    916  
    917 on_error: 
    918     /* Check for failure */ 
     382 
     383    rec.addr_count = 0; 
     384 
     385    /* Parse the response */ 
     386    if (status == PJ_SUCCESS) { 
     387        status = pj_dns_parse_a_response(pkt, &rec); 
     388    } 
     389 
    919390    if (status != PJ_SUCCESS) { 
    920391        char errmsg[PJ_ERR_MSG_SIZE]; 
    921         PJ_LOG(4,(query->objname,  
    922                   "DNS %s record resolution error for '%.*s'." 
    923                   " Err=%d (%s)", 
    924                   pj_dns_get_type_name(query->dns_state), 
    925                   (int)query->req.target.addr.host.slen, 
    926                   query->req.target.addr.host.ptr, 
    927                   status, 
    928                   pj_strerror(status,errmsg,sizeof(errmsg)).ptr)); 
     392 
     393        /* Log error */ 
     394        pj_strerror(status, errmsg, sizeof(errmsg)); 
     395        PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",  
     396                  errmsg)); 
     397 
     398        /* Call the callback */ 
    929399        (*query->cb)(status, query->token, NULL); 
    930400        return; 
    931401    } 
     402 
     403    /* Build server addresses and call callback */ 
     404    srv.count = 0; 
     405    for (i=0; i<rec.addr_count; ++i) { 
     406        srv.entry[srv.count].type = query->naptr[0].type; 
     407        srv.entry[srv.count].priority = 0; 
     408        srv.entry[srv.count].weight = 0; 
     409        srv.entry[srv.count].addr_len = sizeof(pj_sockaddr_in); 
     410        pj_sockaddr_in_init(&srv.entry[srv.count].addr.ipv4, 
     411                            0, (pj_uint16_t)query->req.def_port); 
     412        srv.entry[srv.count].addr.ipv4.sin_addr.s_addr = 
     413            rec.addr[i].s_addr; 
     414 
     415        ++srv.count; 
     416    } 
     417 
     418    /* Call the callback */ 
     419    (*query->cb)(PJ_SUCCESS, query->token, &srv); 
     420} 
     421 
     422 
     423/* Callback to be called by DNS SRV resolution */ 
     424static void srv_resolver_cb(void *user_data, 
     425                            pj_status_t status, 
     426                            const pj_dns_srv_record *rec) 
     427{ 
     428    struct query *query = (struct query*) user_data; 
     429    pjsip_server_addresses srv; 
     430    unsigned i; 
     431 
     432    if (status != PJ_SUCCESS) { 
     433        char errmsg[PJ_ERR_MSG_SIZE]; 
     434 
     435        /* Log error */ 
     436        pj_strerror(status, errmsg, sizeof(errmsg)); 
     437        PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s",  
     438                  errmsg)); 
     439 
     440        /* Call the callback */ 
     441        (*query->cb)(status, query->token, NULL); 
     442        return; 
     443    } 
     444 
     445    /* Build server addresses and call callback */ 
     446    srv.count = 0; 
     447    for (i=0; i<rec->count; ++i) { 
     448        unsigned j; 
     449 
     450        for (j=0; j<rec->entry[i].server.addr_count; ++j) { 
     451            srv.entry[srv.count].type = query->naptr[0].type; 
     452            srv.entry[srv.count].priority = rec->entry[i].priority; 
     453            srv.entry[srv.count].weight = rec->entry[i].weight; 
     454            srv.entry[srv.count].addr_len = sizeof(pj_sockaddr_in); 
     455            pj_sockaddr_in_init(&srv.entry[srv.count].addr.ipv4, 
     456                                0, (pj_uint16_t)rec->entry[i].port); 
     457            srv.entry[srv.count].addr.ipv4.sin_addr.s_addr = 
     458                rec->entry[i].server.addr[j].s_addr; 
     459 
     460            ++srv.count; 
     461        } 
     462    } 
     463 
     464    /* Call the callback */ 
     465    (*query->cb)(PJ_SUCCESS, query->token, &srv); 
    932466} 
    933467 
    934468#endif  /* PJSIP_HAS_RESOLVER */ 
    935469 
    936  
    937  
Note: See TracChangeset for help on using the changeset viewer.