Ignore:
Timestamp:
Oct 8, 2006 12:39:34 PM (18 years ago)
Author:
bennylp
Message:

Major addition to support DNS SRV resolution in PJSIP:

  • added DNS asynchronous/caching resolver engine in PJLIB-UTIL (resolver.[hc])
  • modified SIP resolver (sip_resolve.c) to properly perform DNS SRV/A resolution when DNS resolution is enabled.
  • added dns_test.c in PJSIP-TEST for testing the SIP resolver.
  • added nameserver configuration in PJSUA-LIB
  • added "--nameserver" option in PJSUA.
  • updated project/Makefiles and doxygen documentation.
File:
1 edited

Legend:

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

    r745 r753  
    2626 
    2727 
     28PJ_DEF(const char *) pj_dns_get_type_name(int type) 
     29{ 
     30    switch (type) { 
     31    case PJ_DNS_TYPE_A:     return "A"; 
     32    case PJ_DNS_TYPE_SRV:   return "SRV"; 
     33    case PJ_DNS_TYPE_NS:    return "NS"; 
     34    case PJ_DNS_TYPE_CNAME: return "CNAME"; 
     35    case PJ_DNS_TYPE_PTR:   return "PTR"; 
     36    case PJ_DNS_TYPE_MX:    return "MX"; 
     37    case PJ_DNS_TYPE_TXT:   return "TXT"; 
     38    case PJ_DNS_TYPE_NAPTR: return "NAPTR"; 
     39    } 
     40    return "(Unknown)"; 
     41} 
     42 
     43 
    2844/** 
    2945 * Initialize a DNS query transaction. 
     
    3248                                       unsigned *size, 
    3349                                       pj_uint16_t id, 
    34                                        pj_dns_type qtype, 
     50                                       int qtype, 
    3551                                       const pj_str_t *name) 
    3652{ 
     
    225241 
    226242/* Skip query records. */ 
    227 static pj_status_t skip_query(const char *pkt, const char *start,  
    228                               const char *max, int *skip_len) 
    229 { 
    230     int name_len = 0; 
     243static pj_status_t parse_query(pj_dns_parsed_query *q, pj_pool_t *pool, 
     244                               const char *pkt, const char *start,  
     245                               const char *max, int *parsed_len) 
     246{ 
     247    const char *p = start; 
     248    int name_len, name_part_len; 
    231249    pj_status_t status; 
    232250 
    233     status = get_name_len(0, pkt, start, max, skip_len, &name_len); 
     251    /* Get the length of the name */ 
     252    status = get_name_len(0, pkt, start, max, &name_part_len, &name_len); 
    234253    if (status != PJ_SUCCESS) 
    235254        return status; 
    236255 
    237     (*skip_len) += 4; 
     256    /* Allocate memory for the name */ 
     257    q->name.ptr = pj_pool_alloc(pool, name_len+4); 
     258    q->name.slen = 0; 
     259 
     260    /* Get the name */ 
     261    status = get_name(0, pkt, start, max, &q->name); 
     262    if (status != PJ_SUCCESS) 
     263        return status; 
     264 
     265    p = (start + name_part_len); 
     266 
     267    /* Get the type */ 
     268    pj_memcpy(&q->type, p, 2); 
     269    q->type = pj_ntohs(q->type); 
     270    p += 2; 
     271 
     272    /* Get the class */ 
     273    pj_memcpy(&q->dnsclass, p, 2); 
     274    q->dnsclass = pj_ntohs(q->dnsclass); 
     275    p += 2; 
     276 
     277    *parsed_len = (int)(p - start); 
     278 
    238279    return PJ_SUCCESS; 
    239280} 
     
    276317     
    277318    /* Get the class */ 
    278     pj_memcpy(&rr->class_, p, 2); 
    279     rr->class_ = pj_ntohs(rr->class_); 
     319    pj_memcpy(&rr->dnsclass, p, 2); 
     320    rr->dnsclass = pj_ntohs(rr->dnsclass); 
    280321    p += 2; 
    281322 
    282323    /* Class MUST be IN */ 
    283     if (rr->class_ != 1) 
     324    if (rr->dnsclass != 1) 
    284325        return PJLIB_UTIL_EDNSINCLASS; 
    285326 
     
    297338    if (p + rr->rdlength > max) 
    298339        return PJLIB_UTIL_EDNSINSIZE; 
    299  
    300     /* Copy the raw data */ 
    301     rr->data = pj_pool_alloc(pool, rr->rdlength); 
    302     pj_memcpy(rr->data, p, rr->rdlength); 
    303340 
    304341    /* Parse some well known records */ 
     
    365402 
    366403    } else { 
     404        /* Copy the raw data */ 
     405        rr->data = pj_pool_alloc(pool, rr->rdlength); 
     406        pj_memcpy(rr->data, p, rr->rdlength); 
     407 
    367408        p += rr->rdlength; 
    368409    } 
     
    374415 
    375416/* 
    376  * Parse raw DNS response packet into DNS response structure. 
     417 * Parse raw DNS packet into DNS packet structure. 
    377418 */ 
    378 PJ_DEF(pj_status_t) pj_dns_parse_response( pj_pool_t *pool, 
    379                                           const void *packet, 
    380                                            unsigned size, 
    381                                            pj_dns_parsed_response **p_res) 
    382 { 
    383     pj_dns_parsed_response *res; 
     419PJ_DEF(pj_status_t) pj_dns_parse_packet( pj_pool_t *pool, 
     420                                        const void *packet, 
     421                                         unsigned size, 
     422                                         pj_dns_parsed_packet **p_res) 
     423{ 
     424    pj_dns_parsed_packet *res; 
    384425    char *start, *end; 
    385426    pj_status_t status; 
     
    393434        return PJLIB_UTIL_EDNSINSIZE; 
    394435 
    395     /* Create the response */ 
    396     res = pj_pool_zalloc(pool, sizeof(pj_dns_parsed_response)); 
     436    /* Create the structure */ 
     437    res = pj_pool_zalloc(pool, sizeof(pj_dns_parsed_packet)); 
    397438 
    398439    /* Copy the DNS header, and convert endianness to host byte order */ 
     
    409450    end = ((char*)packet) + size; 
    410451 
    411     /* If we have query records (some DNS servers do send them), skip 
    412      * the records. 
     452    /* Parse query records (if any). 
    413453     */ 
    414     for (i=0; i<res->hdr.qdcount; ++i) { 
    415         int skip_len; 
    416  
    417         status = skip_query(packet, start, end, &skip_len); 
    418         if (status != PJ_SUCCESS) 
    419             return status; 
    420  
    421         start += skip_len; 
     454    if (res->hdr.qdcount) { 
     455        res->q = pj_pool_zalloc(pool, res->hdr.qdcount * 
     456                                      sizeof(pj_dns_parsed_query)); 
     457        for (i=0; i<res->hdr.qdcount; ++i) { 
     458            int parsed_len; 
     459             
     460            status = parse_query(&res->q[i], pool, packet, start, end, 
     461                                 &parsed_len); 
     462            if (status != PJ_SUCCESS) 
     463                return status; 
     464 
     465            start += parsed_len; 
     466        } 
    422467    } 
    423468 
     
    478523    return PJ_SUCCESS; 
    479524} 
     525 
     526 
     527/* Perform name compression scheme. 
     528 * If a name is already in the nametable, when no need to duplicate 
     529 * the string with the pool, but rather just use the pointer there. 
     530 */ 
     531static void apply_name_table( unsigned *count, 
     532                              pj_str_t nametable[], 
     533                              const pj_str_t *src, 
     534                              pj_pool_t *pool, 
     535                              pj_str_t *dst) 
     536{ 
     537    unsigned i; 
     538 
     539    /* Scan strings in nametable */ 
     540    for (i=0; i<*count; ++i) { 
     541        if (pj_stricmp(&nametable[i], src) == 0) 
     542            break; 
     543    } 
     544 
     545    /* If name is found in nametable, use the pointer in the nametable */ 
     546    if (i != *count) { 
     547        dst->ptr = nametable[i].ptr; 
     548        dst->slen = nametable[i].slen; 
     549        return; 
     550    } 
     551 
     552    /* Otherwise duplicate the string, and insert new name in nametable */ 
     553    pj_strdup(pool, dst, src); 
     554 
     555    if (*count < PJ_DNS_MAX_NAMES_IN_NAMETABLE) { 
     556        nametable[*count].ptr = dst->ptr; 
     557        nametable[*count].slen = dst->slen; 
     558 
     559        ++(*count); 
     560    } 
     561} 
     562 
     563static void copy_query(pj_pool_t *pool, pj_dns_parsed_query *dst, 
     564                       const pj_dns_parsed_query *src, 
     565                       unsigned *nametable_count, 
     566                       pj_str_t nametable[]) 
     567{ 
     568    pj_memcpy(dst, src, sizeof(*src)); 
     569    apply_name_table(nametable_count, nametable, &src->name, pool, &dst->name); 
     570} 
     571 
     572 
     573static void copy_rr(pj_pool_t *pool, pj_dns_parsed_rr *dst, 
     574                    const pj_dns_parsed_rr *src, 
     575                    unsigned *nametable_count, 
     576                    pj_str_t nametable[]) 
     577{ 
     578    pj_memcpy(dst, src, sizeof(*src)); 
     579    apply_name_table(nametable_count, nametable, &src->name, pool, &dst->name); 
     580 
     581    if (src->data) { 
     582        dst->data = pj_pool_alloc(pool, src->rdlength); 
     583        pj_memcpy(dst->data, src->data, src->rdlength); 
     584    } 
     585 
     586    if (src->type == PJ_DNS_TYPE_SRV) { 
     587        apply_name_table(nametable_count, nametable, &src->rdata.srv.target,  
     588                         pool, &dst->rdata.srv.target); 
     589    } else if (src->type == PJ_DNS_TYPE_A) { 
     590        pj_strdup(pool, &dst->rdata.a.ip_addr, &src->rdata.a.ip_addr); 
     591    } else if (src->type == PJ_DNS_TYPE_CNAME) { 
     592        pj_strdup(pool, &dst->rdata.cname.name, &src->rdata.cname.name); 
     593    } else if (src->type == PJ_DNS_TYPE_NS) { 
     594        pj_strdup(pool, &dst->rdata.ns.name, &src->rdata.ns.name); 
     595    } else if (src->type == PJ_DNS_TYPE_PTR) { 
     596        pj_strdup(pool, &dst->rdata.ptr.name, &src->rdata.ptr.name); 
     597    } 
     598} 
     599 
     600/* 
     601 * Duplicate DNS packet. 
     602 */ 
     603PJ_DEF(void) pj_dns_packet_dup(pj_pool_t *pool, 
     604                               const pj_dns_parsed_packet*p, 
     605                               pj_dns_parsed_packet **p_dst) 
     606{ 
     607    pj_dns_parsed_packet *dst; 
     608    unsigned nametable_count = 0; 
     609#if PJ_DNS_MAX_NAMES_IN_NAMETABLE 
     610    pj_str_t nametable[PJ_DNS_MAX_NAMES_IN_NAMETABLE]; 
     611#else 
     612    pj_str_t *nametable = NULL; 
     613#endif 
     614    unsigned i; 
     615 
     616    PJ_ASSERT_ON_FAIL(pool && p && p_dst, return); 
     617 
     618    /* Create packet and copy header */ 
     619    *p_dst = dst = pj_pool_zalloc(pool, sizeof(pj_dns_parsed_packet)); 
     620    pj_memcpy(&dst->hdr, &p->hdr, sizeof(p->hdr)); 
     621 
     622    /* Initialize section counts in the target packet to zero. 
     623     * If memory allocation fails during copying process, the target packet 
     624     * should have a correct section counts. 
     625     */ 
     626    dst->hdr.qdcount = 0; 
     627    dst->hdr.anscount = 0; 
     628    dst->hdr.nscount = 0; 
     629    dst->hdr.arcount = 0; 
     630         
     631 
     632    /* Copy query section */ 
     633    if (p->hdr.qdcount) { 
     634        dst->q = pj_pool_alloc(pool, p->hdr.qdcount *  
     635                                     sizeof(pj_dns_parsed_query)); 
     636        for (i=0; i<p->hdr.qdcount; ++i) { 
     637            copy_query(pool, &dst->q[i], &p->q[i],  
     638                       &nametable_count, nametable); 
     639            ++dst->hdr.qdcount; 
     640        } 
     641    } 
     642 
     643    /* Copy answer section */ 
     644    if (p->hdr.anscount) { 
     645        dst->ans = pj_pool_alloc(pool, p->hdr.anscount *  
     646                                       sizeof(pj_dns_parsed_rr)); 
     647        for (i=0; i<p->hdr.anscount; ++i) { 
     648            copy_rr(pool, &dst->ans[i], &p->ans[i], 
     649                    &nametable_count, nametable); 
     650            ++dst->hdr.anscount; 
     651        } 
     652    } 
     653 
     654    /* Copy NS section */ 
     655    if (p->hdr.nscount) { 
     656        dst->ns = pj_pool_alloc(pool, p->hdr.nscount *  
     657                                      sizeof(pj_dns_parsed_rr)); 
     658        for (i=0; i<p->hdr.nscount; ++i) { 
     659            copy_rr(pool, &dst->ns[i], &p->ns[i], 
     660                    &nametable_count, nametable); 
     661            ++dst->hdr.nscount; 
     662        } 
     663    } 
     664 
     665    /* Copy additional info section */ 
     666    if (p->hdr.arcount) { 
     667        dst->arr = pj_pool_alloc(pool, p->hdr.arcount *  
     668                                       sizeof(pj_dns_parsed_rr)); 
     669        for (i=0; i<p->hdr.arcount; ++i) { 
     670            copy_rr(pool, &dst->arr[i], &p->arr[i], 
     671                    &nametable_count, nametable); 
     672            ++dst->hdr.arcount; 
     673        } 
     674    } 
     675} 
     676 
Note: See TracChangeset for help on using the changeset viewer.