Ignore:
Timestamp:
Jun 11, 2007 4:51:18 PM (14 years ago)
Author:
bennylp
Message:

Ticket #330: Changed DNS SRV resolver to use the new DNS A response parser

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/src/pjlib-util/srv_resolver.c

    r1346 r1357  
    2929#define THIS_FILE   "srv_resolver.c" 
    3030 
    31 #define ADDR_MAX_COUNT      8 
     31#define ADDR_MAX_COUNT      PJ_DNS_MAX_IP_IN_A_REC 
    3232 
    3333struct srv_target 
     
    5353    void                    *token; 
    5454    pj_dns_srv_resolver_cb  *cb; 
    55     pj_dns_async_query      *qobject; 
    5655    pj_status_t              last_error; 
    5756 
     
    8988                                        pj_bool_t fallback_a, 
    9089                                        void *token, 
    91                                         pj_dns_srv_resolver_cb *cb) 
     90                                        pj_dns_srv_resolver_cb *cb, 
     91                                        pj_dns_async_query **p_query) 
    9292{ 
    9393    int len; 
     
    128128 
    129129    PJ_LOG(5, (query_job->objname,  
    130                "Starting async DNS %s query_job: target=%.*s", 
     130               "Starting async DNS %s query_job: target=%.*s:%d", 
    131131               pj_dns_get_type_name(query_job->dns_state), 
    132                (int)target_name.slen, target_name.ptr)); 
     132               (int)target_name.slen, target_name.ptr, 
     133               def_port)); 
    133134 
    134135    status = pj_dns_resolver_start_query(resolver, &target_name,  
    135136                                         query_job->dns_state, 0,  
    136137                                         &dns_callback, 
    137                                          query_job, &query_job->qobject); 
     138                                         query_job, p_query); 
    138139    return status; 
    139140} 
     
    466467        /* Check that we really have answer */ 
    467468        if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) { 
    468             int ans_idx = -1; 
    469  
    470             /* Find the first DNS A record in the answer while processing 
    471              * the CNAME info found in the response. 
    472              */ 
    473             for (i=0; i < pkt->hdr.anscount; ++i) { 
    474  
    475                 pj_dns_parsed_rr *rr = &pkt->ans[i]; 
    476  
    477                 if (rr->type == PJ_DNS_TYPE_A) { 
    478  
    479                     if (ans_idx == -1) 
    480                         ans_idx = i; 
    481  
    482                 } else if (rr->type == PJ_DNS_TYPE_CNAME) { 
    483                     /* Find which server entry to be updated with 
    484                      * the CNAME information. 
    485                      */ 
    486                     unsigned j; 
    487                     pj_str_t cname = rr->rdata.cname.name; 
    488  
    489                     for (j=0; j<query_job->srv_cnt; ++j)  
    490                     { 
    491                         struct srv_target *srv = &query_job->srv[j]; 
    492                         if (pj_stricmp(&rr->name, &srv->target_name)==0) 
    493                         { 
    494                             /* Update CNAME info for this server entry */ 
    495                             srv->cname.ptr = srv->cname_buf; 
    496                             pj_strncpy(&srv->cname, &cname,  
    497                                        sizeof(srv->cname_buf)); 
    498                             break; 
    499                         } 
    500                     } 
    501                 } 
    502             } 
    503  
    504             if (ans_idx == -1) { 
    505                 /* There's no DNS A answer! */ 
    506                 PJ_LOG(5,(query_job->objname,  
    507                           "No DNS A record in response!")); 
    508                 status = PJLIB_UTIL_EDNSNOANSWERREC; 
     469            unsigned srv_idx; 
     470            struct srv_target *srv = NULL; 
     471            pj_dns_a_record rec; 
     472 
     473            /* Parse response */ 
     474            status = pj_dns_parse_a_response(pkt, &rec); 
     475            if (status != PJ_SUCCESS) 
    509476                goto on_error; 
    510             } 
    511  
    512             /* Update IP address of the corresponding hostname or CNAME */ 
    513             for (i=0; i<query_job->srv_cnt; ++i) { 
    514                 pj_dns_parsed_rr *rr = &pkt->ans[ans_idx]; 
    515                 struct srv_target *srv = &query_job->srv[i]; 
    516  
    517                 if (pj_stricmp(&rr->name, &srv->target_name)==0 || 
    518                     pj_stricmp(&rr->name, &srv->cname)==0)  
    519                 { 
     477 
     478            pj_assert(rec.addr_count != 0); 
     479 
     480            /* Find which server entry to be updated. */ 
     481            for (srv_idx=0; srv_idx<query_job->srv_cnt; ++srv_idx) { 
     482                srv = &query_job->srv[srv_idx]; 
     483                if (pj_stricmp(&rec.name, &srv->target_name)==0) { 
    520484                    break; 
    521485                } 
    522486            } 
    523487 
    524             if (i == query_job->srv_cnt) { 
    525                 PJ_LOG(4,(query_job->objname,  
    526                           "Received answer to DNS A request with no matching " 
    527                           "SRV record! The unknown name is %.*s", 
    528                           (int)pkt->ans[ans_idx].name.slen,  
    529                           pkt->ans[ans_idx].name.ptr)); 
     488            if (srv_idx==query_job->srv_cnt) { 
     489                /* The DNS A response doesn't match any server names 
     490                 * we're querying! 
     491                 */ 
     492                status = PJLIB_UTIL_EDNSINANSWER; 
     493                goto on_error; 
     494            } 
     495 
     496            srv = &query_job->srv[srv_idx]; 
     497 
     498            /* Update CNAME alias, if present. */ 
     499            if (rec.alias.slen) { 
     500                pj_assert(rec.alias.slen <= sizeof(srv->cname_buf)); 
     501                srv->cname.ptr = srv->cname_buf; 
     502                pj_strcpy(&srv->cname, &rec.alias); 
    530503            } else { 
    531                 unsigned j; 
    532  
    533                 query_job->srv[i].addr[query_job->srv[i].addr_cnt++].s_addr = 
    534                     pkt->ans[ans_idx].rdata.a.ip_addr.s_addr; 
     504                srv->cname.slen = 0; 
     505            } 
     506 
     507            /* Update IP address of the corresponding hostname or CNAME */ 
     508            if (srv->addr_cnt < ADDR_MAX_COUNT) { 
     509                srv->addr[srv->addr_cnt++].s_addr = rec.addr[0].s_addr; 
    535510 
    536511                PJ_LOG(5,(query_job->objname,  
    537512                          "DNS A for %.*s: %s", 
    538                           (int)query_job->srv[i].target_name.slen,  
    539                           query_job->srv[i].target_name.ptr, 
    540                           pj_inet_ntoa(pkt->ans[ans_idx].rdata.a.ip_addr))); 
    541  
    542                 /* Check for multiple IP addresses */ 
    543                 for (j=ans_idx+1; j<pkt->hdr.anscount &&  
    544                             query_job->srv[i].addr_cnt < ADDR_MAX_COUNT; ++j) 
    545                 { 
    546                     query_job->srv[i].addr[query_job->srv[i].addr_cnt++].s_addr =  
    547                         pkt->ans[j].rdata.a.ip_addr.s_addr; 
    548  
    549                     PJ_LOG(5,(query_job->objname,  
    550                               "Additional DNS A for %.*s: %s", 
    551                               (int)query_job->srv[i].target_name.slen,  
    552                               query_job->srv[i].target_name.ptr, 
    553                               pj_inet_ntoa(pkt->ans[j].rdata.a.ip_addr))); 
    554                 } 
     513                          (int)srv->target_name.slen,  
     514                          srv->target_name.ptr, 
     515                          pj_inet_ntoa(rec.addr[0]))); 
     516            } 
     517 
     518            /* Check for multiple IP addresses */ 
     519            for (i=1; i<rec.addr_count && srv->addr_cnt < ADDR_MAX_COUNT; ++i) 
     520            { 
     521                srv->addr[srv->addr_cnt++].s_addr = rec.addr[i].s_addr; 
     522 
     523                PJ_LOG(5,(query_job->objname,  
     524                          "Additional DNS A for %.*s: %s", 
     525                          (int)srv->target_name.slen,  
     526                          srv->target_name.ptr, 
     527                          pj_inet_ntoa(rec.addr[i]))); 
    555528            } 
    556529 
     
    578551    if (query_job->host_resolved == query_job->srv_cnt) { 
    579552        /* Got all answers, build server addresses */ 
    580         pj_dns_srv_record svr_addr; 
    581  
    582         svr_addr.count = 0; 
     553        pj_dns_srv_record srv_rec; 
     554 
     555        srv_rec.count = 0; 
    583556        for (i=0; i<query_job->srv_cnt; ++i) { 
    584557            unsigned j; 
    585  
    586             /* Do we have IP address for this server? */ 
    587             /* This log is redundant really. 
    588             if (query_job->srv[i].addr_cnt == 0) { 
    589                 PJ_LOG(5,(query_job->objname,  
    590                           " SRV target %.*s:%d does not have IP address!", 
    591                           (int)query_job->srv[i].target_name.slen, 
    592                           query_job->srv[i].target_name.ptr, 
    593                           query_job->srv[i].port)); 
    594                 continue; 
    595             } 
    596             */ 
    597  
    598             for (j=0; j<query_job->srv[i].addr_cnt; ++j) { 
    599                 unsigned idx = svr_addr.count; 
    600                 pj_sockaddr_in *addr; 
    601  
    602                 svr_addr.entry[idx].priority = query_job->srv[i].priority; 
    603                 svr_addr.entry[idx].weight = query_job->srv[i].weight; 
    604                 svr_addr.entry[idx].addr_len = sizeof(pj_sockaddr_in); 
    605               
    606                 addr = (pj_sockaddr_in*)&svr_addr.entry[idx].addr; 
    607                 pj_bzero(addr, sizeof(pj_sockaddr_in)); 
    608                 addr->sin_family = PJ_AF_INET; 
    609                 addr->sin_addr = query_job->srv[i].addr[j]; 
    610                 addr->sin_port = pj_htons((pj_uint16_t)query_job->srv[i].port); 
    611  
    612                 ++svr_addr.count; 
     558            struct srv_target *srv = &query_job->srv[i]; 
     559 
     560            srv_rec.entry[srv_rec.count].priority = srv->priority; 
     561            srv_rec.entry[srv_rec.count].weight = srv->weight; 
     562            srv_rec.entry[srv_rec.count].port = (pj_uint16_t)srv->port ; 
     563 
     564            srv_rec.entry[srv_rec.count].server.name = srv->target_name; 
     565            srv_rec.entry[srv_rec.count].server.alias = srv->cname; 
     566            srv_rec.entry[srv_rec.count].server.addr_count = 0; 
     567 
     568            pj_assert(srv->addr_cnt <= PJ_DNS_MAX_IP_IN_A_REC); 
     569 
     570            for (j=0; j<srv->addr_cnt; ++j) { 
     571                srv_rec.entry[srv_rec.count].server.addr[j].s_addr =  
     572                    srv->addr[j].s_addr; 
     573                ++srv_rec.entry[srv_rec.count].server.addr_count; 
     574            } 
     575 
     576            if (srv->addr_cnt > 0) { 
     577                ++srv_rec.count; 
     578                if (srv_rec.count == PJ_DNS_SRV_MAX_ADDR) 
     579                    break; 
    613580            } 
    614581        } 
     
    616583        PJ_LOG(5,(query_job->objname,  
    617584                  "Server resolution complete, %d server entry(s) found", 
    618                   svr_addr.count)); 
    619  
    620  
    621         if (svr_addr.count > 0) 
     585                  srv_rec.count)); 
     586 
     587 
     588        if (srv_rec.count > 0) 
    622589            status = PJ_SUCCESS; 
    623590        else { 
     
    628595 
    629596        /* Call the callback */ 
    630         (*query_job->cb)(query_job->token, status, &svr_addr); 
     597        (*query_job->cb)(query_job->token, status, &srv_rec); 
    631598    } 
    632599 
Note: See TracChangeset for help on using the changeset viewer.