Ignore:
Timestamp:
Feb 21, 2013 11:26:35 AM (11 years ago)
Author:
bennylp
Message:

Fixed #1617: major synchronization fixes in PJNATH with incorporation of group lock to avoid deadlock and crashes due to race conditions

File:
1 edited

Legend:

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

    r3553 r4360  
    3030#define NODELAY         0xFFFFFFFF 
    3131#define SRV_DOMAIN      "pjsip.lab.domain" 
    32  
     32#define MAX_THREADS     16 
     33 
     34#define THIS_FILE       "ice_test.c" 
    3335#define INDENT          "    " 
    3436 
     
    4951}; 
    5052 
    51  
     53/*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
    5254/* Test session configuration */ 
    5355struct test_cfg 
     
    6163 
    6264    unsigned    answer_delay;   /* Delay before sending SDP     */ 
    63     unsigned    send_delay;     /* Delay before sending data    */ 
    64     unsigned    destroy_delay;  /* Delay before destroy()       */ 
     65    unsigned    send_delay;     /* unused */ 
     66    unsigned    destroy_delay;  /* unused */ 
    6567 
    6668    struct test_result expected;/* Expected result              */ 
     
    8082}; 
    8183 
     84/* Session param */ 
     85struct sess_param 
     86{ 
     87    unsigned             worker_cnt; 
     88    unsigned             worker_timeout; 
     89    pj_bool_t            worker_quit; 
     90 
     91    pj_bool_t            destroy_after_create; 
     92    pj_bool_t            destroy_after_one_done; 
     93}; 
     94 
    8295/* The test session */ 
    8396struct test_sess 
     
    87100    pj_dns_resolver     *resolver; 
    88101 
     102    struct sess_param   *param; 
     103 
    89104    test_server         *server; 
     105 
     106    pj_thread_t         *worker_threads[MAX_THREADS]; 
    90107 
    91108    unsigned             server_flag; 
     
    191208                       struct test_cfg *caller_cfg, 
    192209                       struct test_cfg *callee_cfg, 
     210                       struct sess_param *test_param, 
    193211                       struct test_sess **p_sess) 
    194212{ 
     
    205223    sess->pool = pool; 
    206224    sess->stun_cfg = stun_cfg; 
     225    sess->param = test_param; 
    207226 
    208227    pj_memcpy(&sess->caller.cfg, caller_cfg, sizeof(*caller_cfg)); 
     
    262281static void destroy_sess(struct test_sess *sess, unsigned wait_msec) 
    263282{ 
     283    unsigned i; 
     284 
    264285    if (sess->caller.ice) { 
    265286        pj_ice_strans_destroy(sess->caller.ice); 
     
    270291        pj_ice_strans_destroy(sess->callee.ice); 
    271292        sess->callee.ice = NULL; 
     293    } 
     294 
     295    sess->param->worker_quit = PJ_TRUE; 
     296    for (i=0; i<sess->param->worker_cnt; ++i) { 
     297        if (sess->worker_threads[i]) 
     298            pj_thread_join(sess->worker_threads[i]); 
    272299    } 
    273300 
     
    327354        ept->result.nego_status = status; 
    328355        break; 
     356    case PJ_ICE_STRANS_OP_KEEP_ALIVE: 
     357        /* keep alive failed? */ 
     358        break; 
    329359    default: 
    330360        pj_assert(!"Unknown op"); 
     
    385415        c1 = pj_ice_strans_get_valid_pair(ept1->ice, i+1); 
    386416        if (c1 == NULL) { 
    387             PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice1 " 
     417            PJ_LOG(3,(THIS_FILE, INDENT "err: unable to get valid pair for ice1 " 
    388418                          "component %d", i+1)); 
    389419            return start_err - 2; 
     
    392422        c2 = pj_ice_strans_get_valid_pair(ept2->ice, i+1); 
    393423        if (c2 == NULL) { 
    394             PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice2 " 
     424            PJ_LOG(3,(THIS_FILE, INDENT "err: unable to get valid pair for ice2 " 
    395425                          "component %d", i+1)); 
    396426            return start_err - 4; 
     
    398428 
    399429        if (pj_sockaddr_cmp(&c1->rcand->addr, &c2->lcand->addr) != 0) { 
    400             PJ_LOG(3,("", INDENT "err: candidate pair does not match " 
     430            PJ_LOG(3,(THIS_FILE, INDENT "err: candidate pair does not match " 
    401431                          "for component %d", i+1)); 
    402432            return start_err - 6; 
     
    409439            pj_ice_strans_get_valid_pair(ept1->ice, i+1) != NULL)  
    410440        { 
    411             PJ_LOG(3,("", INDENT "err: ice1 shouldn't have valid pair " 
     441            PJ_LOG(3,(THIS_FILE, INDENT "err: ice1 shouldn't have valid pair " 
    412442                          "for component %d", i+1)); 
    413443            return start_err - 8; 
     
    416446            pj_ice_strans_get_valid_pair(ept2->ice, i+1) != NULL)  
    417447        { 
    418             PJ_LOG(3,("", INDENT "err: ice2 shouldn't have valid pair " 
     448            PJ_LOG(3,(THIS_FILE, INDENT "err: ice2 shouldn't have valid pair " 
    419449                          "for component %d", i+1)); 
    420450            return start_err - 9; 
     
    437467                                        break; \ 
    438468                                    } \ 
    439                                     if (t.sec - t0.sec > (timeout)) break; \ 
     469                                    PJ_TIME_VAL_SUB(t, t0); \ 
     470                                    if (PJ_TIME_VAL_MSEC(t) >= (timeout)) break; \ 
    440471                                } \ 
    441472                            } 
    442473 
    443  
    444 static int perform_test(const char *title, 
    445                         pj_stun_config *stun_cfg, 
    446                         unsigned server_flag, 
    447                         struct test_cfg *caller_cfg, 
    448                         struct test_cfg *callee_cfg) 
     474int worker_thread_proc(void *data) 
     475{ 
     476    pj_status_t rc; 
     477    struct test_sess *sess = (struct test_sess *) data; 
     478    pj_stun_config *stun_cfg = sess->stun_cfg; 
     479     
     480    /* Wait until negotiation is complete on both endpoints */ 
     481#define ALL_DONE    (sess->param->worker_quit || \ 
     482                        (sess->caller.result.nego_status!=PJ_EPENDING && \ 
     483                         sess->callee.result.nego_status!=PJ_EPENDING)) 
     484    WAIT_UNTIL(sess->param->worker_timeout, ALL_DONE, rc); 
     485     
     486    return 0; 
     487} 
     488 
     489static int perform_test2(const char *title, 
     490                         pj_stun_config *stun_cfg, 
     491                         unsigned server_flag, 
     492                         struct test_cfg *caller_cfg, 
     493                         struct test_cfg *callee_cfg, 
     494                         struct sess_param *test_param) 
    449495{ 
    450496    pjlib_state pjlib_state; 
    451497    struct test_sess *sess; 
     498    unsigned i; 
    452499    int rc; 
    453500 
    454     PJ_LOG(3,("", INDENT "%s", title)); 
     501    PJ_LOG(3,(THIS_FILE, INDENT "%s", title)); 
    455502 
    456503    capture_pjlib_state(stun_cfg, &pjlib_state); 
    457504 
    458     rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, &sess); 
     505    rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, test_param, &sess); 
    459506    if (rc != 0) 
    460507        return rc; 
     
    464511 
    465512    /* Wait until both ICE transports are initialized */ 
    466     WAIT_UNTIL(30, ALL_READY, rc); 
     513    WAIT_UNTIL(30000, ALL_READY, rc); 
    467514 
    468515    if (!ALL_READY) { 
    469         PJ_LOG(3,("", INDENT "err: init timed-out")); 
     516        PJ_LOG(3,(THIS_FILE, INDENT "err: init timed-out")); 
    470517        destroy_sess(sess, 500); 
    471518        return -100; 
     
    490537        goto on_return; 
    491538    } 
    492  
    493539    /* Init ICE on caller */ 
    494540    rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role,  
     
    508554        return -110; 
    509555    } 
    510  
    511556    /* Start ICE on callee */ 
    512557    rc = start_ice(&sess->callee, &sess->caller); 
     
    515560        return -120; 
    516561    } 
    517  
    518562    /* Wait for callee's answer_delay */ 
    519563    poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE); 
    520  
    521564    /* Start ICE on caller */ 
    522565    rc = start_ice(&sess->caller, &sess->callee); 
     
    526569    } 
    527570 
    528     /* Wait until negotiation is complete on both endpoints */ 
    529 #define ALL_DONE    (sess->caller.result.nego_status!=PJ_EPENDING && \ 
    530                      sess->callee.result.nego_status!=PJ_EPENDING) 
    531     WAIT_UNTIL(30, ALL_DONE, rc); 
    532  
     571    for (i=0; i<sess->param->worker_cnt; ++i) { 
     572        pj_status_t status; 
     573 
     574        status = pj_thread_create(sess->pool, "worker_thread", 
     575                                  worker_thread_proc, sess, 0, 0, 
     576                                  &sess->worker_threads[i]); 
     577        if (status != PJ_SUCCESS) { 
     578            PJ_LOG(3,(THIS_FILE, INDENT "err: create thread")); 
     579            destroy_sess(sess, 500); 
     580            return -135; 
     581        } 
     582    } 
     583 
     584    if (sess->param->destroy_after_create) 
     585        goto on_destroy; 
     586 
     587    if (sess->param->destroy_after_one_done) { 
     588        while (sess->caller.result.init_status==PJ_EPENDING && 
     589               sess->callee.result.init_status==PJ_EPENDING) 
     590        { 
     591            if (sess->param->worker_cnt) 
     592                pj_thread_sleep(0); 
     593            else 
     594                poll_events(stun_cfg, 0, PJ_FALSE); 
     595        } 
     596        goto on_destroy; 
     597    } 
     598     
     599    WAIT_UNTIL(30000, ALL_DONE, rc); 
    533600    if (!ALL_DONE) { 
    534         PJ_LOG(3,("", INDENT "err: negotiation timed-out")); 
     601        PJ_LOG(3,(THIS_FILE, INDENT "err: negotiation timed-out")); 
    535602        destroy_sess(sess, 500); 
    536603        return -140; 
     
    562629 
    563630    /* Looks like everything is okay */ 
     631on_destroy: 
    564632 
    565633    /* Destroy ICE stream transports first to let it de-allocate 
     
    579647on_return: 
    580648    /* Wait.. */ 
    581     poll_events(stun_cfg, 500, PJ_FALSE); 
     649    poll_events(stun_cfg, 200, PJ_FALSE); 
    582650 
    583651    /* Now destroy everything */ 
     
    592660    } 
    593661 
    594     return 0; 
     662    return rc; 
     663} 
     664 
     665static int perform_test(const char *title, 
     666                        pj_stun_config *stun_cfg, 
     667                        unsigned server_flag, 
     668                        struct test_cfg *caller_cfg, 
     669                        struct test_cfg *callee_cfg) 
     670{ 
     671    struct sess_param test_param; 
     672 
     673    pj_bzero(&test_param, sizeof(test_param)); 
     674    return perform_test2(title, stun_cfg, server_flag, caller_cfg, 
     675                         callee_cfg, &test_param); 
    595676} 
    596677 
     
    681762            goto on_return; 
    682763    } 
    683  
     764     
    684765    /* Simple test first with srflx candidate */ 
    685766    if (1) { 
     
    745826        }; 
    746827 
    747         rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     828        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 
    748829                          &cfg.ua1, &cfg.ua2); 
    749830        if (rc != 0) 
     
    786867    } 
    787868 
     869 
    788870    /* STUN failure, testing TURN deallocation */ 
    789871    if (1) { 
     
    793875            0xFFFF & (~(CREATE_STUN_SERVER)), 
    794876            /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
    795             {ROLE1,     2,       YES,    YES,   YES,    0,    0,            0,      0, {PJNATH_ESTUNTIMEDOUT, -1}}, 
    796             {ROLE2,     2,       YES,    YES,   YES,    0,    0,            0,      0, {PJNATH_ESTUNTIMEDOUT, -1}} 
     877            {ROLE1,     1,       YES,    YES,   YES,    0,    0,            0,      0, {PJNATH_ESTUNTIMEDOUT, -1}}, 
     878            {ROLE2,     1,       YES,    YES,   YES,    0,    0,            0,      0, {PJNATH_ESTUNTIMEDOUT, -1}} 
    797879        }; 
    798880 
    799         rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag,  
     881        rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 
    800882                          &cfg.ua1, &cfg.ua2); 
    801883        if (rc != 0) 
     
    819901        unsigned d; 
    820902 
    821         PJ_LOG(3,("", "  %s", cfg->title)); 
     903        PJ_LOG(3,(THIS_FILE, "  %s", cfg->title)); 
    822904 
    823905        /* For each test item, test with various answer delay */ 
     
    877959} 
    878960 
     961int ice_one_conc_test(pj_stun_config *stun_cfg, int err_quit) 
     962{ 
     963    struct sess_cfg_t { 
     964        const char      *title; 
     965        unsigned         server_flag; 
     966        struct test_cfg  ua1; 
     967        struct test_cfg  ua2; 
     968    } cfg = 
     969    { 
     970        "Concurrency test", 
     971        0xFFFF, 
     972        /*  Role    comp#   host?   stun?   turn?   flag?  ans_del snd_del des_del */ 
     973        {ROLE1, 1,      YES,     YES,       YES,    0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}}, 
     974        {ROLE2, 1,      YES,     YES,       YES,    0,      0,      0,      0, {PJ_SUCCESS, PJ_SUCCESS}} 
     975    }; 
     976    struct sess_param test_param; 
     977    int rc; 
     978 
     979 
     980    /* test a: destroy as soon as nego starts */ 
     981    cfg.title = "    ice test a: immediate destroy"; 
     982    pj_bzero(&test_param, sizeof(test_param)); 
     983    test_param.worker_cnt = 4; 
     984    test_param.worker_timeout = 1000; 
     985    test_param.destroy_after_create = PJ_TRUE; 
     986 
     987    rc = perform_test2(cfg.title, stun_cfg, cfg.server_flag, 
     988                       &cfg.ua1, &cfg.ua2, &test_param); 
     989    if (rc != 0 && err_quit) 
     990        return rc; 
     991 
     992    /* test b: destroy as soon as one is done */ 
     993    cfg.title = "    ice test b: destroy after 1 success"; 
     994    test_param.destroy_after_create = PJ_FALSE; 
     995    test_param.destroy_after_one_done = PJ_TRUE; 
     996 
     997    rc = perform_test2(cfg.title, stun_cfg, cfg.server_flag, 
     998                       &cfg.ua1, &cfg.ua2, &test_param); 
     999    if (rc != 0 && err_quit) 
     1000        return rc; 
     1001 
     1002    /* test c: normal */ 
     1003    cfg.title = "    ice test c: normal flow"; 
     1004    pj_bzero(&test_param, sizeof(test_param)); 
     1005    test_param.worker_cnt = 4; 
     1006    test_param.worker_timeout = 1000; 
     1007 
     1008    rc = perform_test2(cfg.title, stun_cfg, cfg.server_flag, 
     1009                       &cfg.ua1, &cfg.ua2, &test_param); 
     1010    if (rc != 0 && err_quit) 
     1011        return rc; 
     1012 
     1013    return 0; 
     1014} 
     1015 
     1016int ice_conc_test(void) 
     1017{ 
     1018    const int LOOP = 100; 
     1019    pj_pool_t *pool; 
     1020    pj_stun_config stun_cfg; 
     1021    unsigned i; 
     1022    int rc; 
     1023     
     1024    pool = pj_pool_create(mem, NULL, 512, 512, NULL); 
     1025    rc = create_stun_config(pool, &stun_cfg); 
     1026    if (rc != PJ_SUCCESS) { 
     1027        pj_pool_release(pool); 
     1028        return -7; 
     1029    } 
     1030     
     1031    for (i = 0; i < LOOP; i++) { 
     1032        PJ_LOG(3,(THIS_FILE, INDENT "Test %d of %d", i+1, LOOP)); 
     1033        rc = ice_one_conc_test(&stun_cfg, PJ_TRUE); 
     1034        if (rc) 
     1035            break; 
     1036    } 
     1037     
     1038on_return: 
     1039    destroy_stun_config(&stun_cfg); 
     1040    pj_pool_release(pool); 
     1041 
     1042    return rc; 
     1043} 
Note: See TracChangeset for help on using the changeset viewer.