Ignore:
Timestamp:
Jun 6, 2008 2:47:10 PM (16 years ago)
Author:
bennylp
Message:

Major major modifications related to ticket #485 (support for TURN-07):

  • Added STUN socket transport pj_stun_sock
  • Integration of TURN-07 to ICE
  • Major refactoring in ICE stream transport to make it simpler
  • Major modification (i.e. API change) in almost everywhere else
  • Much more elaborate STUN, TURN, and ICE tests in pjnath-test
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath-test/ice_test.c

    r1288 r1988  
    1818 */ 
    1919#include "test.h" 
    20  
    21 #define THIS_FILE   "ice_test.c" 
    22  
    23  
    24 struct ice_data 
    25 { 
    26     const char     *obj_name; 
    27     pj_bool_t       complete; 
    28     pj_status_t     err_code; 
    29     unsigned        rx_rtp_cnt; 
    30     unsigned        rx_rtcp_cnt; 
    31  
    32     unsigned        rx_rtp_count; 
    33     char            last_rx_rtp_data[32]; 
    34     unsigned        rx_rtcp_count; 
    35     char            last_rx_rtcp_data[32]; 
     20#include "server.h" 
     21 
     22enum 
     23{ 
     24    NO  = 0, 
     25    YES = 1, 
     26    SRV = 3, 
    3627}; 
    3728 
    38 static pj_stun_config stun_cfg; 
    39  
    40 static void on_ice_complete(pj_ice_strans *icest,  
    41                             pj_status_t status) 
    42 { 
    43     struct ice_data *id = (struct ice_data*) icest->user_data; 
    44     id->complete = PJ_TRUE; 
    45     id->err_code = status; 
    46     PJ_LOG(3,(THIS_FILE, "     ICE %s complete %s", id->obj_name, 
    47               (status==PJ_SUCCESS ? "successfully" : "with failure"))); 
     29#define NODELAY         0xFFFFFFFF 
     30#define SRV_DOMAIN      "pjsip.lab.domain" 
     31 
     32#define INDENT          "    " 
     33 
     34/* Client flags */ 
     35enum 
     36{ 
     37    WRONG_TURN  = 1, 
     38    DEL_ON_ERR  = 2, 
     39}; 
     40 
     41 
     42/* Test results */ 
     43struct test_result 
     44{ 
     45    pj_status_t init_status;    /* init successful?             */ 
     46    pj_status_t nego_status;    /* negotiation successful?      */ 
     47    unsigned    rx_cnt[4];      /* Number of data received      */ 
     48}; 
     49 
     50 
     51/* Test session configuration */ 
     52struct test_cfg 
     53{ 
     54    pj_ice_sess_role role;      /* Role.                        */ 
     55    unsigned    comp_cnt;       /* Component count              */ 
     56    unsigned    enable_host;    /* Enable host candidates       */ 
     57    unsigned    enable_stun;    /* Enable srflx candidates      */ 
     58    unsigned    enable_turn;    /* Enable turn candidates       */ 
     59    unsigned    client_flag;    /* Client flags                 */ 
     60 
     61    unsigned    answer_delay;   /* Delay before sending SDP     */ 
     62    unsigned    send_delay;     /* Delay before sending data    */ 
     63    unsigned    destroy_delay;  /* Delay before destroy()       */ 
     64 
     65    struct test_result expected;/* Expected result              */ 
     66}; 
     67 
     68/* ICE endpoint state */ 
     69struct ice_ept 
     70{ 
     71    struct test_cfg      cfg;   /* Configuratino.               */ 
     72    pj_ice_strans       *ice;   /* ICE stream transport         */ 
     73    struct test_result   result;/* Test result.                 */ 
     74 
     75    pj_str_t             ufrag; /* username fragment.           */ 
     76    pj_str_t             pass;  /* password                     */ 
     77}; 
     78 
     79/* The test session */ 
     80struct test_sess 
     81{ 
     82    pj_pool_t           *pool; 
     83    pj_stun_config      *stun_cfg; 
     84    pj_dns_resolver     *resolver; 
     85 
     86    test_server         *server; 
     87 
     88    unsigned             server_flag; 
     89    struct ice_ept       caller; 
     90    struct ice_ept       callee; 
     91}; 
     92 
     93 
     94static void ice_on_rx_data(pj_ice_strans *ice_st, 
     95                           unsigned comp_id,  
     96                           void *pkt, pj_size_t size, 
     97                           const pj_sockaddr_t *src_addr, 
     98                           unsigned src_addr_len); 
     99static void ice_on_ice_complete(pj_ice_strans *ice_st,  
     100                                pj_ice_strans_op op, 
     101                                pj_status_t status); 
     102static void destroy_sess(struct test_sess *sess, unsigned wait_msec); 
     103 
     104/* Create ICE stream transport */ 
     105static int create_ice_strans(struct test_sess *test_sess, 
     106                             struct ice_ept *ept, 
     107                             pj_ice_strans **p_ice) 
     108{ 
     109    pj_ice_strans *ice; 
     110    pj_ice_strans_cb ice_cb; 
     111    pj_ice_strans_cfg ice_cfg; 
     112    pj_sockaddr hostip; 
     113    char serverip[PJ_INET6_ADDRSTRLEN]; 
     114    pj_status_t status; 
     115 
     116    status = pj_gethostip(pj_AF_INET(), &hostip); 
     117    if (status != PJ_SUCCESS) 
     118        return -1030; 
     119 
     120    pj_sockaddr_print(&hostip, serverip, sizeof(serverip), 0); 
     121 
     122    /* Init callback structure */ 
     123    pj_bzero(&ice_cb, sizeof(ice_cb)); 
     124    ice_cb.on_rx_data = &ice_on_rx_data; 
     125    ice_cb.on_ice_complete = &ice_on_ice_complete; 
     126 
     127    /* Init ICE stream transport configuration structure */ 
     128    pj_ice_strans_cfg_default(&ice_cfg); 
     129    pj_memcpy(&ice_cfg.stun_cfg, test_sess->stun_cfg, sizeof(pj_stun_config)); 
     130    if ((ept->cfg.enable_stun & SRV)==SRV || (ept->cfg.enable_turn & SRV)==SRV) 
     131        ice_cfg.resolver = test_sess->resolver; 
     132 
     133    if (ept->cfg.enable_stun & YES) { 
     134        if ((ept->cfg.enable_stun & SRV) == SRV) { 
     135            ice_cfg.stun.server = pj_str(SRV_DOMAIN); 
     136        } else { 
     137            ice_cfg.stun.server = pj_str(serverip); 
     138        } 
     139        ice_cfg.stun.port = STUN_SERVER_PORT; 
     140    } 
     141 
     142    if (ept->cfg.enable_host == 0) { 
     143        ice_cfg.stun.no_host_cands = PJ_TRUE; 
     144    } else { 
     145        ice_cfg.stun.no_host_cands = PJ_FALSE; 
     146        ice_cfg.stun.loop_addr = PJ_TRUE; 
     147    } 
     148 
     149 
     150    if (ept->cfg.enable_turn & YES) { 
     151        if ((ept->cfg.enable_turn & SRV) == SRV) { 
     152            ice_cfg.turn.server = pj_str(SRV_DOMAIN); 
     153        } else { 
     154            ice_cfg.turn.server = pj_str(serverip); 
     155        } 
     156        ice_cfg.turn.port = TURN_SERVER_PORT; 
     157        ice_cfg.turn.conn_type = PJ_TURN_TP_UDP; 
     158        ice_cfg.turn.auth_cred.type = PJ_STUN_AUTH_CRED_STATIC; 
     159        ice_cfg.turn.auth_cred.data.static_cred.realm = pj_str(SRV_DOMAIN); 
     160        if (ept->cfg.client_flag & WRONG_TURN) 
     161            ice_cfg.turn.auth_cred.data.static_cred.username = pj_str("xxx"); 
     162        else 
     163            ice_cfg.turn.auth_cred.data.static_cred.username = pj_str(TURN_USERNAME); 
     164        ice_cfg.turn.auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; 
     165        ice_cfg.turn.auth_cred.data.static_cred.data = pj_str(TURN_PASSWD); 
     166    } 
     167 
     168    /* Create ICE stream transport */ 
     169    status = pj_ice_strans_create(NULL, &ice_cfg, ept->cfg.comp_cnt, 
     170                                  (void*)ept, &ice_cb, 
     171                                  &ice); 
     172    if (status != PJ_SUCCESS) { 
     173        app_perror(INDENT "err: pj_ice_strans_create()", status); 
     174        return status; 
     175    } 
     176 
     177    pj_create_unique_string(test_sess->pool, &ept->ufrag); 
     178    pj_create_unique_string(test_sess->pool, &ept->pass); 
     179 
     180    /* Looks alright */ 
     181    *p_ice = ice; 
     182    return PJ_SUCCESS; 
    48183} 
    49  
    50  
    51 static void on_rx_data(pj_ice_strans *icest, unsigned comp_id,  
    52                        void *pkt, pj_size_t size, 
    53                        const pj_sockaddr_t *src_addr, 
    54                        unsigned src_addr_len) 
    55 { 
    56     struct ice_data *id = (struct ice_data*) icest->user_data; 
    57  
    58     if (comp_id == 1) { 
    59         id->rx_rtp_cnt++; 
    60         pj_memcpy(id->last_rx_rtp_data, pkt, size); 
    61         id->last_rx_rtp_data[size] = '\0'; 
    62     } else if (comp_id == 2) { 
    63         id->rx_rtcp_cnt++; 
    64         pj_memcpy(id->last_rx_rtcp_data, pkt, size); 
    65         id->last_rx_rtcp_data[size] = '\0'; 
    66     } else { 
    67         pj_assert(!"Invalid component ID"); 
    68     } 
    69  
     184                              
     185/* Create test session */ 
     186static int create_sess(pj_stun_config *stun_cfg, 
     187                       unsigned server_flag, 
     188                       struct test_cfg *caller_cfg, 
     189                       struct test_cfg *callee_cfg, 
     190                       struct test_sess **p_sess) 
     191{ 
     192    pj_pool_t *pool; 
     193    struct test_sess *sess; 
     194    pj_str_t ns_ip; 
     195    pj_uint16_t ns_port; 
     196    unsigned flags; 
     197    pj_status_t status; 
     198 
     199    /* Create session structure */ 
     200    pool = pj_pool_create(mem, "testsess", 512, 512, NULL); 
     201    sess = PJ_POOL_ZALLOC_T(pool, struct test_sess); 
     202    sess->pool = pool; 
     203    sess->stun_cfg = stun_cfg; 
     204 
     205    pj_memcpy(&sess->caller.cfg, caller_cfg, sizeof(*caller_cfg)); 
     206    sess->caller.result.init_status = sess->caller.result.nego_status = PJ_EPENDING; 
     207 
     208    pj_memcpy(&sess->callee.cfg, callee_cfg, sizeof(*callee_cfg)); 
     209    sess->callee.result.init_status = sess->callee.result.nego_status = PJ_EPENDING; 
     210 
     211    /* Create server */ 
     212    flags = server_flag; 
     213    status = create_test_server(stun_cfg, flags, SRV_DOMAIN, &sess->server); 
     214    if (status != PJ_SUCCESS) { 
     215        app_perror(INDENT "error: create_test_server()", status); 
     216        destroy_sess(sess, 500); 
     217        return -10; 
     218    } 
     219    sess->server->turn_respond_allocate =  
     220        sess->server->turn_respond_refresh = PJ_TRUE; 
     221 
     222    /* Create resolver */ 
     223    status = pj_dns_resolver_create(mem, NULL, 0, stun_cfg->timer_heap, 
     224                                    stun_cfg->ioqueue, &sess->resolver); 
     225    if (status != PJ_SUCCESS) { 
     226        app_perror(INDENT "error: pj_dns_resolver_create()", status); 
     227        destroy_sess(sess, 500); 
     228        return -20; 
     229    } 
     230 
     231    ns_ip = pj_str("127.0.0.1"); 
     232    ns_port = (pj_uint16_t)DNS_SERVER_PORT; 
     233    status = pj_dns_resolver_set_ns(sess->resolver, 1, &ns_ip, &ns_port); 
     234    if (status != PJ_SUCCESS) { 
     235        app_perror( INDENT "error: pj_dns_resolver_set_ns()", status); 
     236        destroy_sess(sess, 500); 
     237        return -21; 
     238    } 
     239 
     240    /* Create caller ICE stream transport */ 
     241    status = create_ice_strans(sess, &sess->caller, &sess->caller.ice); 
     242    if (status != PJ_SUCCESS) { 
     243        destroy_sess(sess, 500); 
     244        return -30; 
     245    } 
     246 
     247    /* Create callee ICE stream transport */ 
     248    status = create_ice_strans(sess, &sess->callee, &sess->callee.ice); 
     249    if (status != PJ_SUCCESS) { 
     250        destroy_sess(sess, 500); 
     251        return -40; 
     252    } 
     253 
     254    *p_sess = sess; 
     255    return 0; 
     256} 
     257 
     258/* Destroy test session */ 
     259static void destroy_sess(struct test_sess *sess, unsigned wait_msec) 
     260{ 
     261    if (sess->caller.ice) { 
     262        pj_ice_strans_destroy(sess->caller.ice); 
     263        sess->caller.ice = NULL; 
     264    } 
     265 
     266    if (sess->callee.ice) { 
     267        pj_ice_strans_destroy(sess->callee.ice); 
     268        sess->callee.ice = NULL; 
     269    } 
     270 
     271    poll_events(sess->stun_cfg, wait_msec, PJ_FALSE); 
     272 
     273    if (sess->resolver) { 
     274        pj_dns_resolver_destroy(sess->resolver, PJ_FALSE); 
     275        sess->resolver = NULL; 
     276    } 
     277 
     278    if (sess->server) { 
     279        destroy_test_server(sess->server); 
     280        sess->server = NULL; 
     281    } 
     282 
     283    if (sess->pool) { 
     284        pj_pool_t *pool = sess->pool; 
     285        sess->pool = NULL; 
     286        pj_pool_release(pool); 
     287    } 
     288} 
     289 
     290static void ice_on_rx_data(pj_ice_strans *ice_st, 
     291                           unsigned comp_id,  
     292                           void *pkt, pj_size_t size, 
     293                           const pj_sockaddr_t *src_addr, 
     294                           unsigned src_addr_len) 
     295{ 
     296    struct ice_ept *ept; 
     297 
     298    PJ_UNUSED_ARG(pkt); 
     299    PJ_UNUSED_ARG(size); 
    70300    PJ_UNUSED_ARG(src_addr); 
    71301    PJ_UNUSED_ARG(src_addr_len); 
     302 
     303    ept = (struct ice_ept*) pj_ice_strans_get_user_data(ice_st); 
     304    ept->result.rx_cnt[comp_id]++; 
    72305} 
    73306 
    74307 
    75 static void handle_events(unsigned msec_timeout) 
    76 { 
    77     pj_time_val delay; 
    78  
    79     pj_timer_heap_poll(stun_cfg.timer_heap, NULL); 
    80  
    81     delay.sec = 0; 
    82     delay.msec = msec_timeout; 
    83     pj_time_val_normalize(&delay); 
    84  
    85     pj_ioqueue_poll(stun_cfg.ioqueue, &delay); 
     308static void ice_on_ice_complete(pj_ice_strans *ice_st,  
     309                                pj_ice_strans_op op, 
     310                                pj_status_t status) 
     311{ 
     312    struct ice_ept *ept; 
     313 
     314    ept = (struct ice_ept*) pj_ice_strans_get_user_data(ice_st); 
     315    switch (op) { 
     316    case PJ_ICE_STRANS_OP_INIT: 
     317        ept->result.init_status = status; 
     318        if (status != PJ_SUCCESS && (ept->cfg.client_flag & DEL_ON_ERR)) { 
     319            pj_ice_strans_destroy(ice_st); 
     320            ept->ice = NULL; 
     321        } 
     322        break; 
     323    case PJ_ICE_STRANS_OP_NEGOTIATION: 
     324        ept->result.nego_status = status; 
     325        break; 
     326    default: 
     327        pj_assert(!"Unknown op"); 
     328    } 
    86329} 
    87330 
    88331 
    89 /* Basic create and destroy test */ 
    90 static int ice_basic_create_destroy_test() 
    91 { 
    92     pj_ice_strans *im; 
    93     pj_ice_strans_cb icest_cb; 
     332/* Start ICE negotiation on the endpoint, based on parameter from 
     333 * the other endpoint. 
     334 */ 
     335static pj_status_t start_ice(struct ice_ept *ept, const struct ice_ept *remote) 
     336{ 
     337    pj_ice_sess_cand rcand[32]; 
     338    unsigned i, rcand_cnt = 0; 
    94339    pj_status_t status; 
    95340 
    96     PJ_LOG(3,(THIS_FILE, "...basic create/destroy")); 
    97  
    98     pj_bzero(&icest_cb, sizeof(icest_cb)); 
    99     icest_cb.on_ice_complete = &on_ice_complete; 
    100     icest_cb.on_rx_data = &on_rx_data; 
    101  
    102     status = pj_ice_strans_create(&stun_cfg, "icetest", 2, NULL, &icest_cb, &im); 
    103     if (status != PJ_SUCCESS) 
    104         return -10; 
    105  
    106     pj_ice_strans_destroy(im); 
     341    /* Enum remote candidates */ 
     342    for (i=0; i<remote->cfg.comp_cnt; ++i) { 
     343        unsigned cnt = PJ_ARRAY_SIZE(rcand) - rcand_cnt; 
     344        status = pj_ice_strans_enum_cands(remote->ice, i+1, &cnt, rcand+rcand_cnt); 
     345        if (status != PJ_SUCCESS) { 
     346            app_perror(INDENT "err: pj_ice_strans_enum_cands()", status); 
     347            return status; 
     348        } 
     349        rcand_cnt += cnt; 
     350    } 
     351 
     352    status = pj_ice_strans_start_ice(ept->ice, &remote->ufrag, &remote->pass, 
     353                                     rcand_cnt, rcand); 
     354    if (status != PJ_SUCCESS) { 
     355        app_perror(INDENT "err: pj_ice_strans_start_ice()", status); 
     356        return status; 
     357    } 
     358 
     359    return PJ_SUCCESS; 
     360} 
     361 
     362 
     363/* Check that the pair in both agents are matched */ 
     364static int check_pair(const struct ice_ept *ept1, const struct ice_ept *ept2, 
     365                      int start_err) 
     366{ 
     367    unsigned i, min_cnt, max_cnt; 
     368 
     369    if (ept1->cfg.comp_cnt < ept2->cfg.comp_cnt) { 
     370        min_cnt = ept1->cfg.comp_cnt; 
     371        max_cnt = ept2->cfg.comp_cnt; 
     372    } else { 
     373        min_cnt = ept2->cfg.comp_cnt; 
     374        max_cnt = ept1->cfg.comp_cnt; 
     375    } 
     376 
     377    /* Must have valid pair for common components */ 
     378    for (i=0; i<min_cnt; ++i) { 
     379        const pj_ice_sess_check *c1; 
     380        const pj_ice_sess_check *c2; 
     381 
     382        c1 = pj_ice_strans_get_valid_pair(ept1->ice, i+1); 
     383        if (c1 == NULL) { 
     384            PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice1 " 
     385                          "component %d", i+1)); 
     386            return start_err - 2; 
     387        } 
     388 
     389        c2 = pj_ice_strans_get_valid_pair(ept2->ice, i+1); 
     390        if (c2 == NULL) { 
     391            PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice2 " 
     392                          "component %d", i+1)); 
     393            return start_err - 4; 
     394        } 
     395 
     396        if (pj_sockaddr_cmp(&c1->rcand->addr, &c2->lcand->addr) != 0) { 
     397            PJ_LOG(3,("", INDENT "err: candidate pair does not match " 
     398                          "for component %d", i+1)); 
     399            return start_err - 6; 
     400        } 
     401    } 
     402 
     403    /* Extra components must not have valid pair */ 
     404    for (; i<max_cnt; ++i) { 
     405        if (ept1->cfg.comp_cnt>i && 
     406            pj_ice_strans_get_valid_pair(ept1->ice, i+1) != NULL)  
     407        { 
     408            PJ_LOG(3,("", INDENT "err: ice1 shouldn't have valid pair " 
     409                          "for component %d", i+1)); 
     410            return start_err - 8; 
     411        } 
     412        if (ept2->cfg.comp_cnt>i && 
     413            pj_ice_strans_get_valid_pair(ept2->ice, i+1) != NULL)  
     414        { 
     415            PJ_LOG(3,("", INDENT "err: ice2 shouldn't have valid pair " 
     416                          "for component %d", i+1)); 
     417            return start_err - 9; 
     418        } 
     419    } 
    107420 
    108421    return 0; 
     
    110423 
    111424 
    112 static pj_status_t start_ice(pj_ice_strans *ist, pj_ice_strans *remote) 
    113 { 
    114     unsigned count; 
    115     pj_ice_sess_cand cand[PJ_ICE_MAX_CAND]; 
    116     pj_status_t status; 
    117  
    118     count = PJ_ARRAY_SIZE(cand); 
    119     status = pj_ice_strans_enum_cands(remote, &count, cand); 
    120     if (status != PJ_SUCCESS) 
    121         return status; 
    122  
    123     return pj_ice_strans_start_ice(ist, &remote->ice->rx_ufrag, &remote->ice->rx_pass, 
    124                                count, cand); 
    125 } 
    126  
    127  
    128 struct dummy_cand 
    129 { 
    130     unsigned             comp_id; 
    131     pj_ice_cand_type     type; 
    132     const char          *addr; 
    133     unsigned             port; 
    134 }; 
    135  
    136 static int init_ice_st(pj_ice_strans *ice_st, 
    137                        pj_bool_t add_valid_comp, 
    138                        unsigned dummy_cnt, 
    139                        struct dummy_cand cand[]) 
    140 { 
    141     pj_str_t a; 
    142     pj_status_t status; 
    143     unsigned i; 
    144  
    145     /* Create components */ 
    146     for (i=0; i<ice_st->comp_cnt; ++i) { 
    147         status = pj_ice_strans_create_comp(ice_st, i+1, PJ_ICE_ST_OPT_DONT_ADD_CAND, NULL); 
    148         if (status != PJ_SUCCESS) 
    149             return -21; 
    150     } 
    151  
    152     /* Add dummy candidates */ 
    153     for (i=0; i<dummy_cnt; ++i) { 
    154         pj_sockaddr_in addr; 
    155  
    156         pj_sockaddr_in_init(&addr, pj_cstr(&a, cand[i].addr), (pj_uint16_t)cand[i].port); 
    157         status = pj_ice_strans_add_cand(ice_st, cand[i].comp_id, cand[i].type, 
    158                                     65535, &addr, PJ_FALSE); 
    159         if (status != PJ_SUCCESS) 
    160             return -22; 
    161     } 
    162  
    163     /* Add the real candidate */ 
    164     if (add_valid_comp) { 
    165         for (i=0; i<ice_st->comp_cnt; ++i) { 
    166             status = pj_ice_strans_add_cand(ice_st, i+1, PJ_ICE_CAND_TYPE_HOST, 65535, 
    167                                         &ice_st->comp[i]->local_addr.ipv4, PJ_TRUE); 
    168             if (status != PJ_SUCCESS) 
    169                 return -23; 
    170         } 
     425#define WAIT_UNTIL(timeout,expr, RC)  { \ 
     426                                pj_time_val t0, t; \ 
     427                                pj_gettimeofday(&t0); \ 
     428                                RC = -1; \ 
     429                                for (;;) { \ 
     430                                    poll_events(stun_cfg, 10, PJ_FALSE); \ 
     431                                    pj_gettimeofday(&t); \ 
     432                                    if (expr) { \ 
     433                                        rc = PJ_SUCCESS; \ 
     434                                        break; \ 
     435                                    } \ 
     436                                    if (t.sec - t0.sec > (timeout)) break; \ 
     437                                } \ 
     438                            } 
     439 
     440 
     441static int perform_test(const char *title, 
     442                        pj_stun_config *stun_cfg, 
     443                        unsigned server_flag, 
     444                        struct test_cfg *caller_cfg, 
     445                        struct test_cfg *callee_cfg) 
     446{ 
     447    pjlib_state pjlib_state; 
     448    struct test_sess *sess; 
     449    int rc; 
     450 
     451    PJ_LOG(3,("", INDENT "%s", title)); 
     452 
     453    capture_pjlib_state(stun_cfg, &pjlib_state); 
     454 
     455    rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, &sess); 
     456    if (rc != 0) 
     457        return rc; 
     458 
     459#define ALL_READY   (sess->caller.result.init_status!=PJ_EPENDING && \ 
     460                     sess->callee.result.init_status!=PJ_EPENDING) 
     461 
     462    /* Wait until both ICE transports are initialized */ 
     463    WAIT_UNTIL(30, ALL_READY, rc); 
     464 
     465    if (!ALL_READY) { 
     466        PJ_LOG(3,("", INDENT "err: init timed-out")); 
     467        destroy_sess(sess, 500); 
     468        return -100; 
     469    } 
     470 
     471    if (sess->caller.result.init_status != sess->caller.cfg.expected.init_status) { 
     472        app_perror(INDENT "err: caller init", sess->caller.result.init_status); 
     473        destroy_sess(sess, 500); 
     474        return -102; 
     475    } 
     476    if (sess->callee.result.init_status != sess->callee.cfg.expected.init_status) { 
     477        app_perror(INDENT "err: callee init", sess->callee.result.init_status); 
     478        destroy_sess(sess, 500); 
     479        return -104; 
     480    } 
     481 
     482    /* Failure condition */ 
     483    if (sess->caller.result.init_status != PJ_SUCCESS || 
     484        sess->callee.result.init_status != PJ_SUCCESS) 
     485    { 
     486        rc = 0; 
     487        goto on_return; 
     488    } 
     489 
     490    /* Init ICE on caller */ 
     491    rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role,  
     492                                &sess->caller.ufrag, &sess->caller.pass); 
     493    if (rc != PJ_SUCCESS) { 
     494        app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc); 
     495        destroy_sess(sess, 500); 
     496        return -100; 
     497    } 
     498 
     499    /* Init ICE on callee */ 
     500    rc = pj_ice_strans_init_ice(sess->callee.ice, sess->callee.cfg.role,  
     501                                &sess->callee.ufrag, &sess->callee.pass); 
     502    if (rc != PJ_SUCCESS) { 
     503        app_perror(INDENT "err: callee pj_ice_strans_init_ice()", rc); 
     504        destroy_sess(sess, 500); 
     505        return -110; 
     506    } 
     507 
     508    /* Start ICE on callee */ 
     509    rc = start_ice(&sess->callee, &sess->caller); 
     510    if (rc != PJ_SUCCESS) { 
     511        destroy_sess(sess, 500); 
     512        return -120; 
     513    } 
     514 
     515    /* Wait for callee's answer_delay */ 
     516    poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE); 
     517 
     518    /* Start ICE on caller */ 
     519    rc = start_ice(&sess->caller, &sess->callee); 
     520    if (rc != PJ_SUCCESS) { 
     521        destroy_sess(sess, 500); 
     522        return -130; 
     523    } 
     524 
     525    /* Wait until negotiation is complete on both endpoints */ 
     526#define ALL_DONE    (sess->caller.result.nego_status!=PJ_EPENDING && \ 
     527                     sess->callee.result.nego_status!=PJ_EPENDING) 
     528    WAIT_UNTIL(30, ALL_DONE, rc); 
     529 
     530    if (!ALL_DONE) { 
     531        PJ_LOG(3,("", INDENT "err: negotiation timed-out")); 
     532        destroy_sess(sess, 500); 
     533        return -140; 
     534    } 
     535 
     536    if (sess->caller.result.nego_status != sess->caller.cfg.expected.nego_status) { 
     537        app_perror(INDENT "err: caller negotiation failed", sess->caller.result.nego_status); 
     538        destroy_sess(sess, 500); 
     539        return -150; 
     540    } 
     541 
     542    if (sess->callee.result.nego_status != sess->callee.cfg.expected.nego_status) { 
     543        app_perror(INDENT "err: callee negotiation failed", sess->callee.result.nego_status); 
     544        destroy_sess(sess, 500); 
     545        return -160; 
     546    } 
     547 
     548    /* Verify that both agents have agreed on the same pair */ 
     549    rc = check_pair(&sess->caller, &sess->callee, -170); 
     550    if (rc != 0) { 
     551        destroy_sess(sess, 500); 
     552        return rc; 
     553    } 
     554    rc = check_pair(&sess->callee, &sess->caller, -180); 
     555    if (rc != 0) { 
     556        destroy_sess(sess, 500); 
     557        return rc; 
     558    } 
     559 
     560    /* Looks like everything is okay */ 
     561 
     562    /* Destroy ICE stream transports first to let it de-allocate 
     563     * TURN relay (otherwise there'll be timer/memory leak, unless 
     564     * we wait for long time in the last poll_events() below). 
     565     */ 
     566    if (sess->caller.ice) { 
     567        pj_ice_strans_destroy(sess->caller.ice); 
     568        sess->caller.ice = NULL; 
     569    } 
     570 
     571    if (sess->callee.ice) { 
     572        pj_ice_strans_destroy(sess->callee.ice); 
     573        sess->callee.ice = NULL; 
     574    } 
     575 
     576on_return: 
     577    /* Wait.. */ 
     578    poll_events(stun_cfg, 500, PJ_FALSE); 
     579 
     580    /* Now destroy everything */ 
     581    destroy_sess(sess, 500); 
     582 
     583    /* Flush events */ 
     584    poll_events(stun_cfg, 100, PJ_FALSE); 
     585 
     586    rc = check_pjlib_state(stun_cfg, &pjlib_state); 
     587    if (rc != 0) { 
     588        return rc; 
    171589    } 
    172590 
     
    174592} 
    175593 
    176  
    177 /* When ICE completes, both agents should agree on the same candidate pair. 
    178  * Check that the remote address selected by agent1 is equal to the 
    179  * local address of selected by agent 2. 
    180  */ 
    181 static int verify_address(pj_ice_strans *agent1, pj_ice_strans *agent2, 
    182                           unsigned comp_id) 
    183 { 
    184     pj_ice_sess_cand *rcand, *lcand; 
    185     int lcand_id; 
    186  
    187     if (agent1->ice->comp[comp_id-1].valid_check == NULL) { 
    188         PJ_LOG(3,(THIS_FILE, "....error: valid_check not set for comp_id %d", comp_id)); 
    189         return -60; 
    190     } 
    191  
    192     /* Get default remote candidate of agent 1 */ 
    193     rcand = agent1->ice->comp[comp_id-1].valid_check->rcand; 
    194  
    195     /* Get default local candidate of agent 2 */ 
    196     pj_ice_sess_find_default_cand(agent2->ice, comp_id, &lcand_id); 
    197     if (lcand_id < 0) 
    198         return -62; 
    199  
    200     lcand = &agent2->ice->lcand[lcand_id]; 
    201  
    202     if (pj_memcmp(&rcand->addr, &lcand->addr, sizeof(pj_sockaddr_in))!=0) { 
    203         PJ_LOG(3,(THIS_FILE, "....error: the selected addresses are incorrect for comp_id %d", comp_id)); 
    204         return -64; 
    205     } 
    206  
    207     return 0; 
    208 } 
    209  
    210  
    211 /* Perform ICE test with the following parameters: 
    212  * 
    213  * - title:     The title of the test 
    214  * - ocand_cnt, 
    215  *   ocand      Additional candidates to be added to offerer 
    216  * - acand_cnt, 
    217  *   acand      Additional candidates to be added to answerer 
    218  * 
    219  * The additional candidates are normally invalid candidates, meaning  
    220  * they won't be reachable by the agents. They are used to "confuse" 
    221  * ICE processing. 
    222  */ 
    223 static int perform_ice_test(const char *title, 
    224                             pj_bool_t expected_success, 
    225                             unsigned comp_cnt, 
    226                             pj_bool_t add_valid_comp, 
    227                             unsigned wait_before_send, 
    228                             unsigned max_total_time, 
    229                             unsigned ocand_cnt, 
    230                             struct dummy_cand ocand[], 
    231                             unsigned acand_cnt, 
    232                             struct dummy_cand acand[]) 
    233 { 
    234     pj_ice_strans *im1, *im2; 
    235     pj_ice_strans_cb icest_cb; 
    236     struct ice_data *id1, *id2; 
    237     pj_timestamp t_start, t_end; 
     594#define ROLE1   PJ_ICE_SESS_ROLE_CONTROLLED 
     595#define ROLE2   PJ_ICE_SESS_ROLE_CONTROLLING 
     596 
     597int ice_test(void) 
     598{ 
     599    pj_pool_t *pool; 
     600    pj_stun_config stun_cfg; 
    238601    unsigned i; 
    239     pj_str_t data_from_offerer, data_from_answerer; 
    240     pj_status_t status; 
    241  
    242 #define CHECK_COMPLETE()    if (id1->complete && id2->complete) { \ 
    243                                 if (t_end.u32.lo==0) pj_get_timestamp(&t_end); \ 
    244                             } else {} 
    245  
    246     PJ_LOG(3,(THIS_FILE, "...%s", title)); 
    247  
    248     pj_bzero(&t_end, sizeof(t_end)); 
    249  
    250     pj_bzero(&icest_cb, sizeof(icest_cb)); 
    251     icest_cb.on_ice_complete = &on_ice_complete; 
    252     icest_cb.on_rx_data = &on_rx_data; 
    253  
    254     /* Create first ICE */ 
    255     status = pj_ice_strans_create(&stun_cfg, "offerer", comp_cnt, NULL, &icest_cb, &im1); 
    256     if (status != PJ_SUCCESS) 
    257         return -20; 
    258  
    259     id1 = PJ_POOL_ZALLOC_T(im1->pool, struct ice_data); 
    260     id1->obj_name = "offerer"; 
    261     im1->user_data = id1; 
    262  
    263     /* Init components */ 
    264     status = init_ice_st(im1, add_valid_comp, ocand_cnt, ocand); 
    265     if (status != 0) 
    266         return status; 
    267  
    268     /* Create second ICE */ 
    269     status = pj_ice_strans_create(&stun_cfg, "answerer", comp_cnt, NULL, &icest_cb, &im2); 
    270     if (status != PJ_SUCCESS) 
    271         return -25; 
    272  
    273     id2 = PJ_POOL_ZALLOC_T(im2->pool, struct ice_data); 
    274     id2->obj_name = "answerer"; 
    275     im2->user_data = id2; 
    276  
    277     /* Init components */ 
    278     status = init_ice_st(im2, add_valid_comp, acand_cnt, acand); 
    279     if (status != 0) 
    280         return status; 
    281  
    282  
    283     /* Init ICE on im1 */ 
    284     status = pj_ice_strans_init_ice(im1, PJ_ICE_SESS_ROLE_CONTROLLING, NULL, NULL); 
    285     if (status != PJ_SUCCESS) 
    286         return -29; 
    287  
    288     /* Init ICE on im2 */ 
    289     status = pj_ice_strans_init_ice(im2, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL); 
    290     if (status != PJ_SUCCESS) 
    291         return -29; 
    292  
    293     /* Start ICE on im2 */ 
    294     status = start_ice(im2, im1); 
    295     if (status != PJ_SUCCESS) { 
    296         app_perror("   error starting ICE", status); 
    297         return -30; 
    298     } 
    299  
    300     /* Start ICE on im1 */ 
    301     status = start_ice(im1, im2); 
    302     if (status != PJ_SUCCESS) 
    303         return -35; 
    304  
    305     /* Apply delay to let other checks commence */ 
    306     pj_thread_sleep(40); 
    307  
    308     /* Mark start time */ 
    309     pj_get_timestamp(&t_start); 
    310  
    311     /* Poll for wait_before_send msecs before we send the first data */ 
    312     if (expected_success) { 
    313         for (;;) { 
    314             pj_timestamp t_now; 
    315  
    316             handle_events(1); 
    317  
    318             CHECK_COMPLETE(); 
    319  
    320             pj_get_timestamp(&t_now); 
    321             if (pj_elapsed_msec(&t_start, &t_now) >= wait_before_send) 
    322                 break; 
    323         } 
    324  
    325         /* Send data. It must be successful! */ 
    326         data_from_offerer = pj_str("from offerer"); 
    327         status = pj_ice_sess_send_data(im1->ice, 1, data_from_offerer.ptr, data_from_offerer.slen); 
    328         if (status != PJ_SUCCESS) 
    329             return -47; 
    330  
    331         data_from_answerer = pj_str("from answerer"); 
    332         status = pj_ice_sess_send_data(im2->ice, 1, data_from_answerer.ptr, data_from_answerer.slen); 
    333         if (status != PJ_SUCCESS) { 
    334             app_perror("   error sending packet", status); 
    335             return -48; 
    336         } 
    337  
    338         /* Poll to allow data to be received */ 
    339         for (;;) { 
    340             pj_timestamp t_now; 
    341             handle_events(1); 
    342             CHECK_COMPLETE(); 
    343             pj_get_timestamp(&t_now); 
    344             if (pj_elapsed_msec(&t_start, &t_now) >= (wait_before_send + 200)) 
    345                 break; 
    346         } 
    347     } 
    348  
    349     /* Just wait until both completes, or timed out */ 
    350     while (!id1->complete || !id2->complete) { 
    351         pj_timestamp t_now; 
    352  
    353         handle_events(1); 
    354  
    355         CHECK_COMPLETE(); 
    356         pj_get_timestamp(&t_now); 
    357         if (pj_elapsed_msec(&t_start, &t_now) >= max_total_time) { 
    358             PJ_LOG(3,(THIS_FILE, "....error: timed-out")); 
    359             return -50; 
    360         } 
    361     } 
    362  
    363     /* Mark end-time */ 
    364     CHECK_COMPLETE(); 
    365  
    366     /* If expected to fail, then just check that both fail */ 
    367     if (!expected_success) { 
    368         /* Check status */ 
    369         if (id1->err_code == PJ_SUCCESS) 
    370             return -51; 
    371         if (id2->err_code == PJ_SUCCESS) 
    372             return -52; 
    373         goto on_return; 
    374     } 
    375  
    376     /* Check status */ 
    377     if (id1->err_code != PJ_SUCCESS) 
    378         return -53; 
    379     if (id2->err_code != PJ_SUCCESS) 
    380         return -56; 
    381  
    382     /* Verify that offerer gets answerer's transport address */ 
    383     for (i=0; i<comp_cnt; ++i) { 
    384         status = verify_address(im1, im2, i+1); 
    385         if (status != 0) 
    386             return status; 
    387     } 
    388  
    389     /* And the other way around */ 
    390     for (i=0; i<comp_cnt; ++i) { 
    391         status = verify_address(im2, im1, i+1); 
    392         if (status != 0) 
    393             return status; 
    394     } 
    395  
    396     /* Check that data is received in offerer */ 
    397     if (id1->rx_rtp_cnt != 1) { 
    398         PJ_LOG(3,(THIS_FILE, "....error: data not received in offerer")); 
    399         return -80; 
    400     } 
    401     if (pj_strcmp2(&data_from_answerer, id1->last_rx_rtp_data) != 0) { 
    402         PJ_LOG(3,(THIS_FILE, "....error: data mismatch in offerer")); 
    403         return -82; 
    404     } 
    405  
    406     /* And the same in answerer */ 
    407     if (id2->rx_rtp_cnt != 1) { 
    408         PJ_LOG(3,(THIS_FILE, "....error: data not received in answerer")); 
    409         return -84; 
    410     } 
    411     if (pj_strcmp2(&data_from_offerer, id2->last_rx_rtp_data) != 0) { 
    412         PJ_LOG(3,(THIS_FILE, "....error: data mismatch in answerer")); 
    413         return -82; 
    414     } 
    415  
     602    int rc; 
     603    struct sess_cfg_t { 
     604        const char      *title; 
     605        unsigned         server_flag; 
     606        struct test_cfg  ua1; 
     607        struct test_cfg  ua2; 
     608    } sess_cfg[] =  
     609    { 
     610        /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     611        { 
     612            "hosts candidates only", 
     613            0xFFFF, 
     614            {ROLE1, 1,      YES,    NO,     NO,     NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     615            {ROLE2, 1,      YES,    NO,     NO,     NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     616        }, 
     617        { 
     618            "host and srflxes", 
     619            0xFFFF, 
     620            {ROLE1, 1,      YES,    YES,    NO,     NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     621            {ROLE2, 1,      YES,    YES,    NO,     NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     622        }, 
     623        { 
     624            "host vs relay", 
     625            0xFFFF, 
     626            {ROLE1, 1,      YES,    NO,    NO,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     627            {ROLE2, 1,      NO,     NO,    YES,     NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     628        }, 
     629        { 
     630            "relay vs host", 
     631            0xFFFF, 
     632            {ROLE1, 1,      NO,     NO,   YES,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     633            {ROLE2, 1,     YES,     NO,    NO,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     634        }, 
     635        { 
     636            "relay vs relay", 
     637            0xFFFF, 
     638            {ROLE1, 1,      NO,     NO,   YES,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     639            {ROLE2, 1,      NO,     NO,   YES,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     640        }, 
     641        { 
     642            "all candidates", 
     643            0xFFFF, 
     644            {ROLE1, 1,     YES,    YES,   YES,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     645            {ROLE2, 1,     YES,    YES,   YES,      NO,     0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     646        }, 
     647    }; 
     648 
     649    pool = pj_pool_create(mem, NULL, 512, 512, NULL); 
     650    rc = create_stun_config(pool, &stun_cfg); 
     651    if (rc != PJ_SUCCESS) { 
     652        pj_pool_release(pool); 
     653        return -7; 
     654    } 
     655 
     656    /* Simple test first with host candidate */ 
     657    if (1) { 
     658        struct sess_cfg_t cfg =  
     659        { 
     660            "Basic with host candidates", 
     661            0x0, 
     662            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     663            {ROLE1,     1,      YES,     NO,        NO,     0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     664            {ROLE2,     1,      YES,     NO,        NO,     0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     665        }; 
     666 
     667        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     668                          &cfg.ua1, &cfg.ua2); 
     669        if (rc != 0) 
     670            goto on_return; 
     671 
     672        cfg.ua1.comp_cnt = 4; 
     673        cfg.ua2.comp_cnt = 4; 
     674        rc = perform_test("Basic with host candidates, 4 components",  
     675                          &stun_cfg, cfg.server_flag,  
     676                          &cfg.ua1, &cfg.ua2); 
     677        if (rc != 0) 
     678            goto on_return; 
     679    } 
     680 
     681    /* Simple test first with srflx candidate */ 
     682    if (1) { 
     683        struct sess_cfg_t cfg =  
     684        { 
     685            "Basic with srflx candidates", 
     686            0xFFFF, 
     687            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     688            {ROLE1,     1,      YES,    YES,        NO,     0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     689            {ROLE2,     1,      YES,    YES,        NO,     0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     690        }; 
     691 
     692        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     693                          &cfg.ua1, &cfg.ua2); 
     694        if (rc != 0) 
     695            goto on_return; 
     696 
     697        cfg.ua1.comp_cnt = 4; 
     698        cfg.ua2.comp_cnt = 4; 
     699 
     700        rc = perform_test("Basic with srflx candidates, 4 components",  
     701                          &stun_cfg, cfg.server_flag,  
     702                          &cfg.ua1, &cfg.ua2); 
     703        if (rc != 0) 
     704            goto on_return; 
     705    } 
     706 
     707    /* Simple test with relay candidate */ 
     708    if (1) { 
     709        struct sess_cfg_t cfg =  
     710        { 
     711            "Basic with relay candidates", 
     712            0xFFFF, 
     713            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     714            {ROLE1,     1,       NO,     NO,      YES,      0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     715            {ROLE2,     1,       NO,     NO,      YES,      0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     716        }; 
     717 
     718        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     719                          &cfg.ua1, &cfg.ua2); 
     720        if (rc != 0) 
     721            goto on_return; 
     722 
     723        cfg.ua1.comp_cnt = 4; 
     724        cfg.ua2.comp_cnt = 4; 
     725 
     726        rc = perform_test("Basic with relay candidates, 4 components",  
     727                          &stun_cfg, cfg.server_flag,  
     728                          &cfg.ua1, &cfg.ua2); 
     729        if (rc != 0) 
     730            goto on_return; 
     731    } 
     732 
     733    /* Failure test with STUN resolution */ 
     734    if (1) { 
     735        struct sess_cfg_t cfg =  
     736        { 
     737            "STUN resolution failure", 
     738            0x0, 
     739            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     740            {ROLE1,     2,       NO,    YES,        NO,     0,      0,      0,      0, {PJNATH_ESTUNTIMEDOUT, -1}}, 
     741            {ROLE2,     2,       NO,    YES,        NO,     0,      0,      0,      0, {PJNATH_ESTUNTIMEDOUT, -1}} 
     742        }; 
     743 
     744        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     745                          &cfg.ua1, &cfg.ua2); 
     746        if (rc != 0) 
     747            goto on_return; 
     748 
     749        cfg.ua1.client_flag |= DEL_ON_ERR; 
     750        cfg.ua2.client_flag |= DEL_ON_ERR; 
     751 
     752        rc = perform_test("STUN resolution failure with destroy on callback",  
     753                          &stun_cfg, cfg.server_flag,  
     754                          &cfg.ua1, &cfg.ua2); 
     755        if (rc != 0) 
     756            goto on_return; 
     757    } 
     758 
     759    /* Failure test with TURN resolution */ 
     760    if (1) { 
     761        struct sess_cfg_t cfg =  
     762        { 
     763            "TURN allocation failure", 
     764            0xFFFF, 
     765            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     766            {ROLE1,     4,       NO,    NO,     YES, WRONG_TURN,    0,      0,      0, {PJ_STATUS_FROM_STUN_CODE(401), -1}}, 
     767            {ROLE2,     4,       NO,    NO,     YES, WRONG_TURN,    0,      0,      0, {PJ_STATUS_FROM_STUN_CODE(401), -1}} 
     768        }; 
     769 
     770        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     771                          &cfg.ua1, &cfg.ua2); 
     772        if (rc != 0) 
     773            goto on_return; 
     774 
     775        cfg.ua1.client_flag |= DEL_ON_ERR; 
     776        cfg.ua2.client_flag |= DEL_ON_ERR; 
     777 
     778        rc = perform_test("TURN allocation failure with destroy on callback",  
     779                          &stun_cfg, cfg.server_flag,  
     780                          &cfg.ua1, &cfg.ua2); 
     781        if (rc != 0) 
     782            goto on_return; 
     783    } 
     784 
     785    /* STUN failure, testing TURN deallocation */ 
     786    if (1) { 
     787        struct sess_cfg_t cfg =  
     788        { 
     789            "STUN failure, testing TURN deallocation", 
     790            0xFFFF & (~(CREATE_STUN_SERVER)), 
     791            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     792            {ROLE1,     2,       YES,    YES,   YES,    0,    0,            0,      0, {PJNATH_ESTUNTIMEDOUT, -1}}, 
     793            {ROLE2,     2,       YES,    YES,   YES,    0,    0,            0,      0, {PJNATH_ESTUNTIMEDOUT, -1}} 
     794        }; 
     795 
     796        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     797                          &cfg.ua1, &cfg.ua2); 
     798        if (rc != 0) 
     799            goto on_return; 
     800 
     801        cfg.ua1.client_flag |= DEL_ON_ERR; 
     802        cfg.ua2.client_flag |= DEL_ON_ERR; 
     803 
     804        rc = perform_test("STUN failure, testing TURN deallocation (cb)",  
     805                          &stun_cfg, cfg.server_flag,  
     806                          &cfg.ua1, &cfg.ua2); 
     807        if (rc != 0) 
     808            goto on_return; 
     809    } 
     810 
     811    rc = 0; 
     812    /* Iterate each test item */ 
     813    for (i=0; i<PJ_ARRAY_SIZE(sess_cfg); ++i) { 
     814        struct sess_cfg_t *cfg = &sess_cfg[i]; 
     815        unsigned delay[] = { 50, 2000 }; 
     816        unsigned d; 
     817 
     818        PJ_LOG(3,("", "  %s", cfg->title)); 
     819 
     820        /* For each test item, test with various answer delay */ 
     821        for (d=0; d<PJ_ARRAY_SIZE(delay); ++d) { 
     822            struct role_t { 
     823                pj_ice_sess_role        ua1; 
     824                pj_ice_sess_role        ua2; 
     825            } role[] =  
     826            { 
     827                { ROLE1, ROLE2}, 
     828                { ROLE2, ROLE1}, 
     829                { ROLE1, ROLE1}, 
     830                { ROLE2, ROLE2} 
     831            }; 
     832            unsigned j; 
     833 
     834            cfg->ua1.answer_delay = delay[d]; 
     835            cfg->ua2.answer_delay = delay[d]; 
     836 
     837            /* For each test item, test with role conflict scenarios */ 
     838            for (j=0; j<PJ_ARRAY_SIZE(role); ++j) { 
     839                unsigned k1; 
     840 
     841                cfg->ua1.role = role[j].ua1; 
     842                cfg->ua2.role = role[j].ua2; 
     843 
     844                /* For each test item, test with different number of components */ 
     845                for (k1=1; k1<=2; ++k1) { 
     846                    unsigned k2; 
     847 
     848                    cfg->ua1.comp_cnt = k1; 
     849 
     850                    for (k2=1; k2<=2; ++k2) { 
     851                        char title[120]; 
     852 
     853                        sprintf(title,  
     854                                "%s/%s, %dms answer delay, %d vs %d components",  
     855                                pj_ice_sess_role_name(role[j].ua1), 
     856                                pj_ice_sess_role_name(role[j].ua2), 
     857                                delay[d], k1, k2); 
     858 
     859                        cfg->ua2.comp_cnt = k2; 
     860                        rc = perform_test(title, &stun_cfg, cfg->server_flag,  
     861                                          &cfg->ua1, &cfg->ua2); 
     862                        if (rc != 0) 
     863                            goto on_return; 
     864                    } 
     865                } 
     866            } 
     867        } 
     868    } 
    416869 
    417870on_return: 
    418  
    419     /* Done */ 
    420     PJ_LOG(3,(THIS_FILE, "....success: ICE completed in %d msec, waiting..",  
    421               pj_elapsed_msec(&t_start, &t_end))); 
    422  
    423     /* Wait for some more time */ 
    424     for (;;) { 
    425         pj_timestamp t_now; 
    426  
    427         pj_get_timestamp(&t_now); 
    428         if (pj_elapsed_msec(&t_start, &t_now) > max_total_time) 
    429             break; 
    430  
    431         handle_events(1); 
    432     } 
    433  
    434  
    435     pj_ice_strans_destroy(im1); 
    436     pj_ice_strans_destroy(im2); 
    437     handle_events(100); 
    438     return 0; 
    439 } 
    440  
    441  
    442 int ice_test(void) 
    443 { 
    444     int rc = 0; 
    445     pj_pool_t *pool; 
    446     pj_ioqueue_t *ioqueue; 
    447     pj_timer_heap_t *timer_heap; 
    448     enum { D1=500, D2=5000, D3=15000 }; 
    449     struct dummy_cand ocand[] =  
    450     { 
    451         {1, PJ_ICE_CAND_TYPE_SRFLX, "127.1.1.1", 65534 }, 
    452         {2, PJ_ICE_CAND_TYPE_SRFLX, "127.1.1.1", 65535 }, 
    453     }; 
    454     struct dummy_cand acand[] = 
    455     { 
    456         {1, PJ_ICE_CAND_TYPE_SRFLX, "127.2.2.2", 65534 }, 
    457         {2, PJ_ICE_CAND_TYPE_SRFLX, "127.2.2.2", 65535 }, 
    458     }; 
    459  
    460     pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); 
    461     pj_ioqueue_create(pool, 12, &ioqueue); 
    462     pj_timer_heap_create(pool, 100, &timer_heap); 
    463      
    464     pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap); 
    465  
    466 #if 0 
    467     pj_log_set_level(5); 
    468 #endif 
    469  
    470     //goto test; 
    471  
    472     /* Basic create/destroy */ 
    473     rc = ice_basic_create_destroy_test(); 
    474     if (rc != 0) 
    475         goto on_return; 
    476  
    477     /* Direct communication */ 
    478     rc = perform_ice_test("Simple test (1 component)", PJ_TRUE, 1, PJ_TRUE, D1, D2, 0, NULL, 0, NULL); 
    479     if (rc != 0) 
    480         goto on_return; 
    481  
    482     /* Failure case (all checks fail) */ 
    483 #if 0 
    484     /* Cannot just add an SRFLX candidate; it needs a base */ 
    485     rc = perform_ice_test("Failure case (all checks fail)", PJ_FALSE, 1, PJ_FALSE, D3, D3, 1, ocand, 1, acand); 
    486     if (rc != 0) 
    487         goto on_return; 
    488 #endif 
    489  
    490     /* Direct communication with invalid address */ 
    491     rc = perform_ice_test("With 1 unreachable address", PJ_TRUE, 1, PJ_TRUE, D1, D2, 1, ocand, 0, NULL); 
    492     if (rc != 0) 
    493         goto on_return; 
    494  
    495     /* Direct communication with invalid address */ 
    496     rc = perform_ice_test("With 2 unreachable addresses (one each)", PJ_TRUE, 1, PJ_TRUE, D1, D2, 1, ocand, 1, acand); 
    497     if (rc != 0) 
    498         goto on_return; 
    499  
    500     /* Direct communication with two components */ 
    501 //test: 
    502     rc = perform_ice_test("With two components (RTP and RTCP)", PJ_TRUE, 2, PJ_TRUE, D1, D2, 0, NULL, 0, NULL); 
    503     if (rc != 0) 
    504         goto on_return; 
    505  
    506     goto on_return; 
    507  
    508     /* Direct communication with mismatch number of components */ 
    509  
    510     /* Direct communication with 2 components and 2 invalid address */ 
    511     rc = perform_ice_test("With 2 two components and 2 unreachable address", PJ_TRUE, 2, PJ_TRUE, D1, D2, 1, ocand, 1, acand); 
    512     if (rc != 0) 
    513         goto on_return; 
    514  
    515  
    516  
    517 on_return: 
    518     pj_log_set_level(3); 
    519     pj_ioqueue_destroy(stun_cfg.ioqueue); 
     871    destroy_stun_config(&stun_cfg); 
    520872    pj_pool_release(pool); 
    521873    return rc; 
Note: See TracChangeset for help on using the changeset viewer.