Changeset 1499


Ignore:
Timestamp:
Oct 13, 2007 9:27:21 AM (17 years ago)
Author:
bennylp
Message:

Related to ticket #399: optimize NAT detection to complete faster

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath/nat_detect.c

    r1498 r1499  
    2424#include <pj/os.h> 
    2525#include <pj/pool.h> 
     26#include <pj/rand.h> 
    2627#include <pj/string.h> 
    2728#include <pj/timer.h> 
     
    4243 
    4344 
    44 #define CHANGE_ADDR             4 
    45 #define CHANGE_PORT             2 
    46 #define CHANGE_ADDR_PORT        (CHANGE_ADDR | CHANGE_PORT) 
    47  
    48  
    49 enum state 
     45#define CHANGE_IP_FLAG          4 
     46#define CHANGE_PORT_FLAG        2 
     47#define CHANGE_IP_PORT_FLAG     (CHANGE_IP_FLAG | CHANGE_PORT_FLAG) 
     48#define TEST_INTERVAL           50 
     49 
     50enum test_type 
    5051{ 
    5152    ST_TEST_1, 
    5253    ST_TEST_2, 
     54    ST_TEST_3, 
    5355    ST_TEST_1B, 
    54     ST_TEST_3 
     56    ST_MAX 
    5557}; 
    5658 
     
    5961    "Test I: Binding request", 
    6062    "Test II: Binding request with change address and port request", 
    61     "Test IB: Binding request to alternate address", 
    62     "Test III: Binding request with change port request" 
     63    "Test III: Binding request with change port request", 
     64    "Test IB: Binding request to alternate address" 
     65}; 
     66 
     67enum timer_type 
     68{ 
     69    TIMER_TEST      = 1, 
     70    TIMER_DESTROY   = 2 
    6371}; 
    6472 
     
    6977 
    7078    pj_timer_heap_t         *timer_heap; 
    71     pj_timer_entry           destroy_timer; 
     79    pj_timer_entry           timer; 
    7280 
    7381    void                    *user_data; 
     
    7987    pj_sockaddr_in          *cur_server; 
    8088    pj_stun_session         *stun_sess; 
    81     enum state               state; 
    8289 
    8390    pj_ioqueue_op_key_t      read_op, write_op; 
     
    8794    int                      src_addr_len; 
    8895 
    89     pj_bool_t                test1_same_ip; 
    90     pj_sockaddr_in           test1_ma;      /* MAPPED-ADDRESS */ 
    91     pj_sockaddr_in           test1_ca;      /* CHANGED-ADDRESS */ 
     96    struct result 
     97    { 
     98        pj_bool_t       executed; 
     99        pj_bool_t       complete; 
     100        pj_status_t     status; 
     101        pj_sockaddr_in  ma; 
     102        pj_sockaddr_in  ca; 
     103    } result[ST_MAX]; 
    92104 
    93105} nat_detect_session; 
     
    109121                               unsigned addr_len); 
    110122 
    111 static pj_status_t start_test(nat_detect_session *sess, 
    112                               enum state state, 
    113                               const pj_sockaddr_in *alt_addr, 
    114                               pj_uint32_t change_flag); 
    115 static void on_timer_destroy(pj_timer_heap_t *th, 
     123static pj_status_t send_test(nat_detect_session *sess, 
     124                             enum test_type test_id, 
     125                             const pj_sockaddr_in *alt_addr, 
     126                             pj_uint32_t change_flag); 
     127static void on_sess_timer(pj_timer_heap_t *th, 
    116128                             pj_timer_entry *te); 
    117129static void sess_destroy(nat_detect_session *sess); 
     130 
     131 
     132static int test_executed(nat_detect_session *sess) 
     133{ 
     134    unsigned i, count; 
     135    for (i=0, count=0; i<PJ_ARRAY_SIZE(sess->result); ++i) { 
     136        if (sess->result[i].executed) 
     137            ++count; 
     138    } 
     139    return count; 
     140} 
     141 
     142static int test_completed(nat_detect_session *sess) 
     143{ 
     144    unsigned i, count; 
     145    for (i=0, count=0; i<PJ_ARRAY_SIZE(sess->result); ++i) { 
     146        if (sess->result[i].complete) 
     147            ++count; 
     148    } 
     149    return count; 
     150} 
    118151 
    119152static pj_status_t get_local_interface(const pj_sockaddr_in *server, 
     
    193226     */ 
    194227    sess->timer_heap = stun_cfg->timer_heap; 
    195     sess->destroy_timer.cb = &on_timer_destroy; 
    196     sess->destroy_timer.user_data = sess; 
     228    sess->timer.cb = &on_sess_timer; 
     229    sess->timer.user_data = sess; 
    197230 
    198231 
     
    232265              pj_inet_ntoa(sess->local_addr.sin_addr),  
    233266              pj_ntohs(sess->local_addr.sin_port))); 
     267 
     268    PJ_LOG(5,(sess->pool->obj_name, "Server set to %s:%d", 
     269              pj_inet_ntoa(server->sin_addr),  
     270              pj_ntohs(server->sin_port))); 
    234271 
    235272    /* 
     
    269306     * Start TEST_1 
    270307     */ 
    271     PJ_LOG(5,(sess->pool->obj_name, "Server set to %s:%d", 
    272               pj_inet_ntoa(server->sin_addr),  
    273               pj_ntohs(server->sin_port))); 
    274  
    275     status = start_test(sess, ST_TEST_1, NULL, 0); 
    276     if (status != PJ_SUCCESS) 
    277         goto on_error; 
     308    sess->timer.id = TIMER_TEST; 
     309    on_sess_timer(stun_cfg->timer_heap, &sess->timer); 
    278310 
    279311    return PJ_SUCCESS; 
     
    307339 
    308340 
    309 static pj_status_t start_test(nat_detect_session *sess, 
    310                               enum state state, 
    311                               const pj_sockaddr_in *alt_addr, 
    312                               pj_uint32_t change_flag) 
    313 { 
    314     pj_stun_tx_data *tdata; 
    315     pj_status_t status; 
    316  
    317     /* Create BIND request */ 
    318     status = pj_stun_session_create_req(sess->stun_sess,  
    319                                         PJ_STUN_BINDING_REQUEST, 0x83224, 
    320                                         NULL, &tdata); 
    321     if (status != PJ_SUCCESS) 
    322         return status; 
    323  
    324     /* Add CHANGE-REQUEST attribute */ 
    325     status = pj_stun_msg_add_uint_attr(sess->pool, tdata->msg, 
    326                                        PJ_STUN_ATTR_CHANGE_REQUEST, 
    327                                        change_flag); 
    328     if (status != PJ_SUCCESS) 
    329         return status; 
    330  
    331     /* Configure alternate address */ 
    332     if (alt_addr) 
    333         sess->cur_server = (pj_sockaddr_in*) alt_addr; 
    334     else 
    335         sess->cur_server = &sess->server; 
    336  
    337     PJ_LOG(5,(sess->pool->obj_name,  
    338               "Performing %s to %s:%d",  
    339               test_names[state], 
    340               pj_inet_ntoa(sess->cur_server->sin_addr), 
    341               pj_ntohs(sess->cur_server->sin_port))); 
    342  
    343     /* Send the request */ 
    344     status = pj_stun_session_send_msg(sess->stun_sess, PJ_TRUE,  
    345                                       sess->cur_server,  
    346                                       sizeof(pj_sockaddr_in), 
    347                                       tdata); 
    348     if (status != PJ_SUCCESS) 
    349         return status; 
    350  
    351     sess->state = state; 
    352  
    353     return PJ_SUCCESS; 
    354 } 
    355  
    356  
    357341static void end_session(nat_detect_session *sess, 
    358342                        pj_status_t status, 
     
    378362    delay.msec = 0; 
    379363 
    380     pj_timer_heap_schedule(sess->timer_heap, &sess->destroy_timer, &delay); 
     364    sess->timer.id = TIMER_DESTROY; 
     365    pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 
    381366} 
    382367 
     
    441426    nat_detect_session *sess; 
    442427    pj_ssize_t pkt_len; 
     428    pj_status_t status; 
    443429 
    444430    sess = (nat_detect_session*) pj_stun_session_get_user_data(stun_sess); 
    445431 
    446432    pkt_len = pkt_size; 
    447     return pj_ioqueue_sendto(sess->key, &sess->write_op, pkt, &pkt_len, 0, 
    448                              dst_addr, addr_len); 
     433    status = pj_ioqueue_sendto(sess->key, &sess->write_op, pkt, &pkt_len, 0, 
     434                               dst_addr, addr_len); 
     435 
     436    return status; 
    449437 
    450438} 
     
    462450    nat_detect_session *sess; 
    463451    pj_stun_sockaddr_attr *mattr = NULL; 
     452    pj_stun_changed_addr_attr *ca = NULL; 
     453    pj_uint32_t *tsx_id; 
     454    int cmp; 
     455    unsigned test_id; 
    464456 
    465457    PJ_UNUSED_ARG(tdata); 
     
    503495                status = PJNATH_ESTUNNOMAPPEDADDR; 
    504496            } 
     497 
     498            /* Get CHANGED-ADDRESS attribute */ 
     499            ca = (pj_stun_changed_addr_attr*) 
     500                 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_CHANGED_ADDR, 0); 
     501 
     502            if (ca == NULL) { 
     503                status = PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_SERVER_ERROR); 
     504            } 
     505 
    505506        } 
    506507    } 
     508 
     509    /* Save the result */ 
     510    tsx_id = (pj_uint32_t*) tdata->msg->hdr.tsx_id; 
     511    test_id = tsx_id[2]; 
     512 
     513    if (test_id >= ST_MAX) { 
     514        PJ_LOG(4,(sess->pool->obj_name, "Invalid transaction ID %u in response", 
     515                  test_id)); 
     516        end_session(sess, status,  
     517                    PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_SERVER_ERROR)); 
     518        return; 
     519    } 
     520 
     521    PJ_LOG(5,(sess->pool->obj_name, "Completed %s, status=%d", 
     522              test_names[test_id], status)); 
     523 
     524    sess->result[test_id].complete = PJ_TRUE; 
     525    sess->result[test_id].status = status; 
     526    if (status == PJ_SUCCESS) { 
     527        pj_memcpy(&sess->result[test_id].ma, &mattr->sockaddr.ipv4, 
     528                  sizeof(pj_sockaddr_in)); 
     529        pj_memcpy(&sess->result[test_id].ca, &ca->sockaddr.ipv4, 
     530                  sizeof(pj_sockaddr_in)); 
     531    } 
     532 
     533    if (test_id == ST_TEST_1 && status == PJ_SUCCESS) { 
     534        cmp = pj_memcmp(&sess->local_addr, &sess->result[ST_TEST_1].ma, 
     535                        sizeof(pj_sockaddr_in)); 
     536        if (cmp != 0) 
     537            send_test(sess, ST_TEST_1B, &sess->result[test_id].ca, 0); 
     538    } 
     539 
     540    if (test_completed(sess)<3 || test_completed(sess)!=test_executed(sess)) 
     541        return; 
    507542 
    508543    /* Handle the test result according to RFC 3489 page 22: 
     
    555590     */ 
    556591 
    557     switch (sess->state) { 
    558     case ST_TEST_1: 
    559         if (status == PJ_SUCCESS) { 
    560             pj_stun_changed_addr_attr *ca; 
    561  
    562             /* Get CHANGED-ADDRESS attribute */ 
    563             ca = (pj_stun_changed_addr_attr*) 
    564                  pj_stun_msg_find_attr(response, PJ_STUN_ATTR_CHANGED_ADDR, 0); 
    565  
    566             if (ca) { 
    567                 pj_memcpy(&sess->test1_ca, &ca->sockaddr,  
    568                           sizeof(pj_sockaddr_in)); 
    569             } 
    570  
    571             /* Save mapped address */ 
    572             pj_memcpy(&sess->test1_ma, &mattr->sockaddr, 
    573                       sizeof(pj_sockaddr_in)); 
    574  
    575             /* Compare mapped address with local address */ 
    576             sess->test1_same_ip=(pj_memcmp(&sess->local_addr, &mattr->sockaddr, 
    577                                            sizeof(pj_sockaddr_in))==0); 
    578              
    579             /* Execute test 2: 
    580              * Send BINDING_REQUEST with both the "change IP" and "change port"  
    581              * flags from the CHANGE-REQUEST attribute set 
     592    switch (sess->result[ST_TEST_1].status) { 
     593    case PJNATH_ESTUNTIMEDOUT: 
     594        /* 
     595         * Test 1 has timed-out. Conclude with NAT_TYPE_BLOCKED.  
     596         */ 
     597        end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_BLOCKED); 
     598        break; 
     599    case PJ_SUCCESS: 
     600        /* 
     601         * Test 1 is successful. Further tests are needed to detect 
     602         * NAT type. Compare the MAPPED-ADDRESS with the local address. 
     603         */ 
     604        cmp = pj_memcmp(&sess->local_addr, &sess->result[ST_TEST_1].ma, 
     605                        sizeof(pj_sockaddr_in)); 
     606        if (cmp==0) { 
     607            /* 
     608             * MAPPED-ADDRESS and local address is equal. Need one more 
     609             * test to determine NAT type. 
    582610             */ 
    583             start_test(sess, ST_TEST_2, NULL, CHANGE_ADDR_PORT); 
    584  
    585         } else { 
    586             /* Test 1 has completed with error. 
    587              * Terminate our test session. 
    588              */ 
    589             if (status == PJNATH_ESTUNTIMEDOUT) 
    590                 end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_BLOCKED); 
    591             else 
    592                 end_session(sess, status, PJ_STUN_NAT_TYPE_UNKNOWN); 
    593         } 
    594         break; 
    595  
    596     case ST_TEST_2: 
    597         if (sess->test1_same_ip) { 
    598             if (status == PJ_SUCCESS) { 
     611            switch (sess->result[ST_TEST_2].status) { 
     612            case PJ_SUCCESS: 
     613                /* 
     614                 * Test 2 is also successful. We're in the open. 
     615                 */ 
    599616                end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_OPEN); 
    600             } else if (status == PJNATH_ESTUNTIMEDOUT) { 
     617                break; 
     618            case PJNATH_ESTUNTIMEDOUT: 
     619                /* 
     620                 * Test 2 has timed out. We're behind somekind of UDP 
     621                 * firewall. 
     622                 */ 
    601623                end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP); 
    602             } else { 
    603                 end_session(sess, status, PJ_STUN_NAT_TYPE_UNKNOWN); 
     624                break; 
     625            default: 
     626                /* 
     627                 * We've got other error with Test 2. 
     628                 */ 
     629                end_session(sess, sess->result[ST_TEST_2].status,  
     630                            PJ_STUN_NAT_TYPE_UNKNOWN); 
     631                break; 
    604632            } 
    605633        } else { 
    606             if (status == PJ_SUCCESS) { 
     634            /* 
     635             * MAPPED-ADDRESS is different than local address. 
     636             * We're behind NAT. 
     637             */ 
     638            switch (sess->result[ST_TEST_2].status) { 
     639            case PJ_SUCCESS: 
     640                /* 
     641                 * Test 2 is successful. We're behind a full-cone NAT. 
     642                 */ 
    607643                end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_FULL_CONE); 
    608             } else if (status == PJNATH_ESTUNTIMEDOUT) { 
    609                 if (sess->test1_ca.sin_family == 0) { 
    610                     PJ_LOG(4,(sess->pool->obj_name,  
    611                               "CHANGED-ADDRESS attribute not present in " 
    612                               "Binding response, unable to continue test")); 
    613                     end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_UNKNOWN); 
    614                 } else { 
    615                     /* Execute TEST_1B */ 
    616                     start_test(sess, ST_TEST_1B, &sess->test1_ca, 0); 
     644                break; 
     645            case PJNATH_ESTUNTIMEDOUT: 
     646                /* 
     647                 * Test 2 has timed-out Check result of test 1B.. 
     648                 */ 
     649                switch (sess->result[ST_TEST_1B].status) { 
     650                case PJ_SUCCESS: 
     651                    /* 
     652                     * Compare the MAPPED-ADDRESS of test 1B with the 
     653                     * MAPPED-ADDRESS returned in test 1.. 
     654                     */ 
     655                    cmp = pj_memcmp(&sess->result[ST_TEST_1].ma, 
     656                                    &sess->result[ST_TEST_1B].ma, 
     657                                    sizeof(pj_sockaddr_in)); 
     658                    if (cmp != 0) { 
     659                        /* 
     660                         * MAPPED-ADDRESS is different, we're behind a 
     661                         * symmetric NAT. 
     662                         */ 
     663                        end_session(sess, PJ_SUCCESS, 
     664                                    PJ_STUN_NAT_TYPE_SYMMETRIC); 
     665                    } else { 
     666                        /* 
     667                         * MAPPED-ADDRESS is equal. We're behind a restricted 
     668                         * or port-restricted NAT, depending on the result of 
     669                         * test 3. 
     670                         */ 
     671                        switch (sess->result[ST_TEST_3].status) { 
     672                        case PJ_SUCCESS: 
     673                            /* 
     674                             * Test 3 is successful, we're behind a restricted 
     675                             * NAT. 
     676                             */ 
     677                            end_session(sess, PJ_SUCCESS, 
     678                                        PJ_STUN_NAT_TYPE_RESTRICTED); 
     679                            break; 
     680                        case PJNATH_ESTUNTIMEDOUT: 
     681                            /* 
     682                             * Test 3 failed, we're behind a port restricted 
     683                             * NAT. 
     684                             */ 
     685                            end_session(sess, PJ_SUCCESS, 
     686                                        PJ_STUN_NAT_TYPE_PORT_RESTRICTED); 
     687                            break; 
     688                        default: 
     689                            /* 
     690                             * Got other error with test 3. 
     691                             */ 
     692                            end_session(sess, sess->result[ST_TEST_3].status, 
     693                                        PJ_STUN_NAT_TYPE_UNKNOWN); 
     694                            break; 
     695                        } 
     696                    } 
     697                    break; 
     698                case PJNATH_ESTUNTIMEDOUT: 
     699                    /* 
     700                     * Strangely test 1B has failed. Maybe connectivity was 
     701                     * lost? 
     702                     */ 
     703                    end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_BLOCKED); 
     704                    break; 
     705                default: 
     706                    /* 
     707                     * Got other error with test 1B. 
     708                     */ 
     709                    end_session(sess, sess->result[ST_TEST_1B].status, 
     710                                PJ_STUN_NAT_TYPE_UNKNOWN); 
     711                    break; 
    617712                } 
    618             } else { 
    619                 end_session(sess, status, PJ_STUN_NAT_TYPE_UNKNOWN); 
     713                break; 
     714            default: 
     715                /* 
     716                 * We've got other error with Test 2. 
     717                 */ 
     718                end_session(sess, sess->result[ST_TEST_2].status,  
     719                            PJ_STUN_NAT_TYPE_UNKNOWN); 
     720                break; 
    620721            } 
    621722        } 
    622723        break; 
    623  
    624     case ST_TEST_1B: 
    625         if (status == PJ_SUCCESS) { 
    626             int cmp; 
    627  
    628             /* Compare MAPPED-ADDRESS with the one from TEST_1 */ 
    629             cmp = pj_memcmp(&mattr->sockaddr, &sess->test1_ma,  
    630                             sizeof(pj_sockaddr_in)); 
    631  
    632             if (cmp!=0) { 
    633                 /* Different address, this is symmetric NAT */ 
    634                 end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_SYMMETRIC); 
    635             } else { 
    636                 /* Same address. Check if this is port restricted. 
    637                  * Execute TEST_3 
    638                  */ 
    639                 start_test(sess, ST_TEST_3, NULL, CHANGE_PORT); 
    640             } 
     724    default: 
     725        /* 
     726         * We've got other error with Test 1. 
     727         */ 
     728        end_session(sess, sess->result[ST_TEST_1].status,  
     729                    PJ_STUN_NAT_TYPE_UNKNOWN); 
     730        break; 
     731    } 
     732 
     733    pj_mutex_unlock(sess->mutex); 
     734} 
     735 
     736 
     737/* Perform test */ 
     738static pj_status_t send_test(nat_detect_session *sess, 
     739                             enum test_type test_id, 
     740                             const pj_sockaddr_in *alt_addr, 
     741                             pj_uint32_t change_flag) 
     742{ 
     743    pj_stun_tx_data *tdata; 
     744    pj_uint32_t magic, tsx_id[3]; 
     745    pj_status_t status; 
     746 
     747    sess->result[test_id].executed = PJ_TRUE; 
     748 
     749    /* Randomize tsx id */ 
     750    do { 
     751        magic = pj_rand(); 
     752    } while (magic == PJ_STUN_MAGIC); 
     753 
     754    tsx_id[0] = pj_rand(); 
     755    tsx_id[1] = pj_rand(); 
     756    tsx_id[2] = test_id; 
     757 
     758    /* Create BIND request */ 
     759    status = pj_stun_session_create_req(sess->stun_sess,  
     760                                        PJ_STUN_BINDING_REQUEST, magic, 
     761                                        (pj_uint8_t*)tsx_id, &tdata); 
     762    if (status != PJ_SUCCESS) 
     763        goto on_error; 
     764 
     765    /* Add CHANGE-REQUEST attribute */ 
     766    status = pj_stun_msg_add_uint_attr(sess->pool, tdata->msg, 
     767                                       PJ_STUN_ATTR_CHANGE_REQUEST, 
     768                                       change_flag); 
     769    if (status != PJ_SUCCESS) 
     770        goto on_error; 
     771 
     772    /* Configure alternate address */ 
     773    if (alt_addr) 
     774        sess->cur_server = (pj_sockaddr_in*) alt_addr; 
     775    else 
     776        sess->cur_server = &sess->server; 
     777 
     778    PJ_LOG(5,(sess->pool->obj_name,  
     779              "Performing %s to %s:%d",  
     780              test_names[test_id], 
     781              pj_inet_ntoa(sess->cur_server->sin_addr), 
     782              pj_ntohs(sess->cur_server->sin_port))); 
     783 
     784    /* Send the request */ 
     785    status = pj_stun_session_send_msg(sess->stun_sess, PJ_TRUE,  
     786                                      sess->cur_server,  
     787                                      sizeof(pj_sockaddr_in), 
     788                                      tdata); 
     789    if (status != PJ_SUCCESS) 
     790        goto on_error; 
     791 
     792    return PJ_SUCCESS; 
     793 
     794on_error: 
     795    sess->result[test_id].complete = PJ_TRUE; 
     796    sess->result[test_id].status = status; 
     797 
     798    return status; 
     799} 
     800 
     801 
     802/* Timer callback */ 
     803static void on_sess_timer(pj_timer_heap_t *th, 
     804                             pj_timer_entry *te) 
     805{ 
     806    nat_detect_session *sess; 
     807 
     808    sess = (nat_detect_session*) te->user_data; 
     809 
     810    if (te->id == TIMER_DESTROY) { 
     811        pj_mutex_lock(sess->mutex); 
     812        pj_ioqueue_unregister(sess->key); 
     813        sess->key = NULL; 
     814        te->id = 0; 
     815        pj_mutex_unlock(sess->mutex); 
     816 
     817        sess_destroy(sess); 
     818 
     819    } else if (te->id == TIMER_TEST) { 
     820 
     821        int executed; 
     822        pj_bool_t next_timer; 
     823 
     824        pj_mutex_lock(sess->mutex); 
     825 
     826        executed = test_executed(sess); 
     827        next_timer = PJ_FALSE; 
     828 
     829        if (executed == ST_TEST_1) { 
     830            send_test(sess, ST_TEST_1, NULL, 0); 
     831            next_timer = PJ_TRUE; 
     832        } else if (executed == ST_TEST_2) { 
     833            send_test(sess, ST_TEST_2, NULL, CHANGE_IP_PORT_FLAG); 
     834            next_timer = PJ_TRUE; 
     835        } else if (executed == ST_TEST_3) { 
     836            send_test(sess, ST_TEST_3, NULL, CHANGE_PORT_FLAG); 
    641837        } else { 
    642             end_session(sess, status, PJ_STUN_NAT_TYPE_UNKNOWN); 
     838            pj_assert(!"Shouldn't have timer at this state"); 
    643839        } 
    644         break; 
    645  
    646     case ST_TEST_3: 
    647         if (status == PJ_SUCCESS) { 
    648             end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_RESTRICTED); 
    649         } else if (status == PJNATH_ESTUNTIMEDOUT) { 
    650             end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_PORT_RESTRICTED); 
     840 
     841        if (next_timer) { 
     842            pj_time_val delay = {0, TEST_INTERVAL}; 
     843            pj_timer_heap_schedule(th, te, &delay); 
    651844        } else { 
    652             end_session(sess, status, PJ_STUN_NAT_TYPE_UNKNOWN); 
     845            te->id = 0; 
    653846        } 
    654         break; 
    655     } 
    656  
    657     pj_mutex_unlock(sess->mutex); 
    658 } 
    659  
    660  
    661 static void on_timer_destroy(pj_timer_heap_t *th, 
    662                              pj_timer_entry *te) 
    663 { 
    664     nat_detect_session *sess; 
    665  
    666     PJ_UNUSED_ARG(th); 
    667  
    668     sess = (nat_detect_session*) te->user_data; 
    669  
    670     pj_mutex_lock(sess->mutex); 
    671     pj_ioqueue_unregister(sess->key); 
    672     sess->key = NULL; 
    673     pj_mutex_unlock(sess->mutex); 
    674  
    675     sess_destroy(sess); 
    676 } 
    677  
     847 
     848        pj_mutex_unlock(sess->mutex); 
     849 
     850    } else { 
     851        pj_assert(!"Invalid timer ID"); 
     852    } 
     853} 
     854 
Note: See TracChangeset for help on using the changeset viewer.