Ignore:
Timestamp:
Apr 20, 2011 9:16:27 AM (13 years ago)
Author:
bennylp
Message:

Fix #1229: bug fix and enhancements for PJLIB-UTIL STUN client:

Bug:

  1. Bug: if UDP packet is lost, the resolver will wait until all retransmissions are done, which means 4 seconds delay.

Enhancements:

  1. Allow caller to specify only 1 STUN server, for faster result.
  2. If both servers point to the same address, only one will be used.
  3. Decrease retransmission delay from 1000 ms to 500 ms for more responsive result.
  4. Reduce memory consumption (from 1024 to 400 bytes).
File:
1 edited

Legend:

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

    r3235 r3540  
    2929 
    3030enum { MAX_REQUEST = 4 }; 
    31 static int stun_timer[] = {1000, 1000, 1000, 1000 }; 
     31static int stun_timer[] = {500, 500, 500, 500 }; 
    3232#define STUN_MAGIC 0x2112A442 
    3333 
     
    3535#define LOG_ADDR(addr)  pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port) 
    3636 
     37#define TRACE_(x)       PJ_LOG(6,x) 
    3738 
    3839PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf, 
     
    4243                                            pj_sockaddr_in mapped_addr[]) 
    4344{ 
     45    unsigned srv_cnt; 
    4446    pj_sockaddr_in srv_addr[2]; 
    4547    int i, j, send_cnt = 0; 
     
    5860    PJ_CHECK_STACK(); 
    5961 
     62    TRACE_((THIS_FILE, "Entering pjstun_get_mapped_addr()")); 
     63 
    6064    /* Create pool. */ 
    61     pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL); 
     65    pool = pj_pool_create(pf, "stun%p", 400, 400, NULL); 
    6266    if (!pool) 
    6367        return PJ_ENOMEM; 
     
    7175    } 
    7276 
     77    TRACE_((THIS_FILE, "  Memory allocated.")); 
    7378 
    7479    /* Create the outgoing BIND REQUEST message template */ 
     
    7883        goto on_error; 
    7984 
     85    TRACE_((THIS_FILE, "  Binding request created.")); 
     86 
    8087    /* Resolve servers. */ 
    8188    status = pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1); 
     
    8390        goto on_error; 
    8491 
    85     status = pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2); 
    86     if (status != PJ_SUCCESS) 
    87         goto on_error; 
     92    srv_cnt = 1; 
     93 
     94    if (srv2 && port2) { 
     95        status = pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2); 
     96        if (status != PJ_SUCCESS) 
     97            goto on_error; 
     98 
     99        if (srv_addr[1].sin_addr.s_addr != srv_addr[0].sin_addr.s_addr && 
     100            srv_addr[1].sin_port != srv_addr[0].sin_port) 
     101        { 
     102            srv_cnt++; 
     103        } 
     104    } 
     105 
     106    TRACE_((THIS_FILE, "  Server initialized, using %d server(s)", srv_cnt)); 
    88107 
    89108    /* Init mapped addresses to zero */ 
    90109    pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); 
     110 
     111    /* We need these many responses */ 
     112    wait_resp = sock_cnt * srv_cnt; 
     113 
     114    TRACE_((THIS_FILE, "  Done initialization.")); 
    91115 
    92116    /* Main retransmission loop. */ 
     
    100124        /* Send messages to servers that has not given us response. */ 
    101125        for (i=0; i<sock_cnt && status==PJ_SUCCESS; ++i) { 
    102             for (j=0; j<2 && status==PJ_SUCCESS; ++j) { 
     126            for (j=0; j<srv_cnt && status==PJ_SUCCESS; ++j) { 
    103127                pjstun_msg_hdr *msg_hdr = (pjstun_msg_hdr*) out_msg; 
    104128                pj_ssize_t sent_len; 
     
    114138                sent_len = out_msg_len; 
    115139                status = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, 
    116                                         (pj_sockaddr_t*)&srv_addr[j],  
     140                                        (pj_sockaddr_t*)&srv_addr[j], 
    117141                                        sizeof(pj_sockaddr_in)); 
    118                 if (status == PJ_SUCCESS) 
    119                     ++wait_resp; 
    120142            } 
    121143        } 
     
    126148         * we'll go to the next retransmission iteration. 
    127149         */ 
     150        TRACE_((THIS_FILE, "  Request(s) sent, counter=%d", send_cnt)); 
    128151 
    129152        /* Calculate time of next retransmission. */ 
     
    148171 
    149172            select_rc = pj_sock_select(PJ_IOQUEUE_MAX_HANDLES, &r, NULL, NULL, &timeout); 
     173            TRACE_((THIS_FILE, "  select() rc=%d", select_rc)); 
    150174            if (select_rc < 1) 
    151175                continue; 
     
    202226                srv_idx = pj_ntohl(msg.hdr->tsx[3]); 
    203227 
    204                 if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) { 
     228                if (sock_idx<0 || sock_idx>=sock_cnt || sock_idx!=i || 
     229                        srv_idx<0 || srv_idx>=2) 
     230                { 
    205231                    status = PJLIB_UTIL_ESTUNININDEX; 
    206232                    continue; 
     
    209235                if (pj_ntohs(msg.hdr->type) != PJSTUN_BINDING_RESPONSE) { 
    210236                    status = PJLIB_UTIL_ESTUNNOBINDRES; 
     237                    continue; 
     238                } 
     239 
     240                if (rec[sock_idx].srv[srv_idx].mapped_port != 0) { 
     241                    /* Already got response */ 
    211242                    continue; 
    212243                } 
     
    249280    } 
    250281 
     282    TRACE_((THIS_FILE, "  All responses received, calculating result..")); 
     283 
    251284    for (i=0; i<sock_cnt && status==PJ_SUCCESS; ++i) { 
    252         if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr && 
    253             rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port) 
     285        if (srv_cnt == 1) { 
     286            mapped_addr[i].sin_family = pj_AF_INET(); 
     287            mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr; 
     288            mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port; 
     289 
     290            if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) { 
     291                status = PJLIB_UTIL_ESTUNNOTRESPOND; 
     292                break; 
     293            } 
     294        } else if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr && 
     295                   rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port) 
    254296        { 
    255297            mapped_addr[i].sin_family = pj_AF_INET(); 
     
    267309    } 
    268310 
     311    TRACE_((THIS_FILE, "  Pool usage=%d of %d", pj_pool_get_used_size(pool), 
     312            pj_pool_get_capacity(pool))); 
     313 
    269314    pj_pool_release(pool); 
    270315 
     316    TRACE_((THIS_FILE, "  Done.")); 
    271317    return status; 
    272318 
Note: See TracChangeset for help on using the changeset viewer.