Changeset 4360


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

Location:
pjproject/trunk/pjnath
Files:
1 added
22 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/build/Makefile

    r4308 r4360  
    4141# 
    4242export PJNATH_TEST_SRCDIR = ../src/pjnath-test 
    43 export PJNATH_TEST_OBJS += ice_test.o stun.o sess_auth.o server.o \ 
     43export PJNATH_TEST_OBJS += ice_test.o stun.o sess_auth.o server.o concur_test.o \ 
    4444                            stun_sock_test.o turn_sock_test.o test.o 
    4545export PJNATH_TEST_CFLAGS += $(_CFLAGS) 
  • pjproject/trunk/pjnath/include/pjnath/ice_session.h

    r4196 r4360  
    613613    pj_pool_t           *pool;                      /**< Pool instance.     */ 
    614614    void                *user_data;                 /**< App. data.         */ 
    615     pj_mutex_t          *mutex;                     /**< Mutex.             */ 
     615    pj_grp_lock_t       *grp_lock;                  /**< Group lock         */ 
    616616    pj_ice_sess_role     role;                      /**< ICE role.          */ 
    617617    pj_ice_sess_options  opt;                       /**< Options            */ 
     
    731731 *                      generated. 
    732732 * @param local_passwd  Optional string to be used as local password. 
     733 * @param grp_lock      Optional group lock to be used by this session. 
     734 *                      If NULL, the session will create one itself. 
    733735 * @param p_ice         Pointer to receive the ICE session instance. 
    734736 * 
     
    742744                                        const pj_str_t *local_ufrag, 
    743745                                        const pj_str_t *local_passwd, 
     746                                        pj_grp_lock_t *grp_lock, 
    744747                                        pj_ice_sess **p_ice); 
    745748 
  • pjproject/trunk/pjnath/include/pjnath/stun_session.h

    r4352 r4360  
    3131#include <pjnath/stun_transaction.h> 
    3232#include <pj/list.h> 
     33#include <pj/lock.h> 
    3334#include <pj/timer.h> 
    3435 
     
    385386 * @param cb            Session callback. 
    386387 * @param fingerprint   Enable message fingerprint for outgoing messages. 
     388 * @param grp_lock      Optional group lock to be used by this session. 
     389 *                      If NULL, the session will create one itself. 
    387390 * @param p_sess        Pointer to receive STUN session instance. 
    388391 * 
     
    393396                                            const pj_stun_session_cb *cb, 
    394397                                            pj_bool_t fingerprint, 
     398                                            pj_grp_lock_t *grp_lock, 
    395399                                            pj_stun_session **p_sess); 
    396400 
     
    430434 */ 
    431435PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess); 
    432  
    433 /** 
    434  * Change the lock object used by the STUN session. By default, the STUN 
    435  * session uses a mutex to protect its internal data. If application already 
    436  * protects access to STUN session with higher layer lock, it may disable 
    437  * the mutex protection in the STUN session by changing the STUN session 
    438  * lock to a NULL mutex. 
    439  * 
    440  * @param sess      The STUN session instance. 
    441  * @param lock      New lock instance to be used by the STUN session. 
    442  * @param auto_del  Specify whether STUN session should destroy this 
    443  *                  lock instance when it's destroyed. 
    444  */ 
    445 PJ_DECL(pj_status_t) pj_stun_session_set_lock(pj_stun_session *sess, 
    446                                               pj_lock_t *lock, 
    447                                               pj_bool_t auto_del); 
    448436 
    449437/** 
  • pjproject/trunk/pjnath/include/pjnath/stun_sock.h

    r4343 r4360  
    2828#include <pjlib-util/resolver.h> 
    2929#include <pj/ioqueue.h> 
     30#include <pj/lock.h> 
    3031#include <pj/sock.h> 
    3132#include <pj/sock_qos.h> 
     
    218219typedef struct pj_stun_sock_cfg 
    219220{ 
     221    /** 
     222     * The group lock to be used by the STUN socket. If NULL, the STUN socket 
     223     * will create one internally. 
     224     * 
     225     * Default: NULL 
     226     */ 
     227    pj_grp_lock_t *grp_lock; 
     228 
    220229    /** 
    221230     * Packet buffer size. 
  • pjproject/trunk/pjnath/include/pjnath/stun_transaction.h

    r4352 r4360  
    2828#include <pjnath/stun_msg.h> 
    2929#include <pjnath/stun_config.h> 
     30#include <pj/lock.h> 
    3031 
    3132 
     
    125126 *                      various settings for the transaction. 
    126127 * @param pool          Pool to be used to allocate memory from. 
     128 * @param grp_lock      Group lock to synchronize. 
    127129 * @param cb            Callback structure, to be used by the transaction 
    128130 *                      to send message and to notify the application about 
     
    134136PJ_DECL(pj_status_t) pj_stun_client_tsx_create( pj_stun_config *cfg, 
    135137                                                pj_pool_t *pool, 
     138                                                pj_grp_lock_t *grp_lock, 
    136139                                                const pj_stun_tsx_cb *cb, 
    137140                                                pj_stun_client_tsx **p_tsx); 
     
    160163 
    161164/** 
    162  * Destroy a STUN client transaction immediately. This function can be  
    163  * called at any time to stop the transaction and destroy it. 
     165 * Stop the client transaction. 
    164166 * 
    165167 * @param tsx           The STUN transaction. 
     
    168170 *                      is NULL. 
    169171 */ 
    170 PJ_DECL(pj_status_t) pj_stun_client_tsx_destroy(pj_stun_client_tsx *tsx); 
     172PJ_DECL(pj_status_t) pj_stun_client_tsx_stop(pj_stun_client_tsx *tsx); 
    171173 
    172174 
  • pjproject/trunk/pjnath/include/pjnath/turn_session.h

    r3553 r4360  
    418418 * @param af            Address family of the client connection. Currently 
    419419 *                      pj_AF_INET() and pj_AF_INET6() are supported. 
    420  * @param conn_type     Connection type to the TURN server.  
     420 * @param conn_type     Connection type to the TURN server. 
     421 * @param grp_lock      Optional group lock object to be used by this session. 
     422 *                      If this value is NULL, the session will create 
     423 *                      a group lock internally. 
    421424 * @param cb            Callback to receive events from the TURN session. 
    422425 * @param options       Option flags, currently this value must be zero. 
     
    433436                                            int af, 
    434437                                            pj_turn_tp_type conn_type, 
     438                                            pj_grp_lock_t *grp_lock, 
    435439                                            const pj_turn_session_cb *cb, 
    436440                                            unsigned options, 
  • pjproject/trunk/pjnath/include/pjnath/turn_sock.h

    r4343 r4360  
    109109typedef struct pj_turn_sock_cfg 
    110110{ 
     111    /** 
     112     * The group lock to be used by the STUN socket. If NULL, the STUN socket 
     113     * will create one internally. 
     114     * 
     115     * Default: NULL 
     116     */ 
     117    pj_grp_lock_t *grp_lock; 
     118 
    111119    /** 
    112120     * Packet buffer size. 
  • 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} 
  • pjproject/trunk/pjnath/src/pjnath-test/sess_auth.c

    r3553 r4360  
    248248    sess_cb.on_rx_request = &server_on_rx_request; 
    249249    sess_cb.on_send_msg = &server_send_msg; 
    250     status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, &server->sess); 
     250    status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, NULL, &server->sess); 
    251251    if (status != PJ_SUCCESS) { 
    252252        destroy_server(); 
     
    480480    sess_cb.on_request_complete = &client_on_request_complete; 
    481481    sess_cb.on_send_msg = &client_send_msg; 
    482     status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, &client->sess); 
     482    status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, NULL, &client->sess); 
    483483    if (status != PJ_SUCCESS) { 
    484484        destroy_client_server(); 
  • pjproject/trunk/pjnath/src/pjnath-test/stun_sock_test.c

    r3553 r4360  
    299299    pj_str_t srv_addr; 
    300300    pj_time_val timeout, t; 
    301     int ret = 0; 
     301    int i, ret = 0; 
    302302    pj_status_t status; 
    303303 
     
    360360    destroy_server(srv); 
    361361    destroy_client(client); 
     362    for (i=0; i<7; ++i) 
     363        handle_events(cfg, 50); 
    362364    return ret; 
    363365} 
     
    374376    pj_str_t srv_addr; 
    375377    pj_time_val timeout, t; 
    376     int ret = 0; 
     378    int i, ret = 0; 
    377379    pj_status_t status; 
    378380 
     
    427429    destroy_server(srv); 
    428430    destroy_client(client); 
     431    for (i=0; i<7; ++i) 
     432        handle_events(cfg, 50); 
    429433    return ret; 
    430434} 
     
    441445    pj_str_t srv_addr; 
    442446    pj_time_val timeout, t; 
    443     int ret = 0; 
     447    int i, ret = 0; 
    444448    pj_status_t status; 
    445449 
     
    792796    destroy_server(srv); 
    793797    destroy_client(client); 
     798    for (i=0; i<7; ++i) 
     799        handle_events(cfg, 50); 
    794800    return ret; 
    795801} 
  • pjproject/trunk/pjnath/src/pjnath-test/test.c

    r3553 r4360  
    3535    pj_ioqueue_t *ioqueue; 
    3636    pj_timer_heap_t *timer_heap; 
     37    pj_lock_t *lock; 
    3738    pj_status_t status; 
    3839 
     
    5051    } 
    5152 
     53    pj_lock_create_recursive_mutex(pool, NULL, &lock); 
     54    pj_timer_heap_set_lock(timer_heap, lock, PJ_TRUE); 
     55 
    5256    pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap); 
    5357 
     
    106110    st->timer_cnt = pj_timer_heap_count(cfg->timer_heap); 
    107111     
    108     cp = (pj_caching_pool*)mem; 
     112    cp = (pj_caching_pool*)cfg->pf; 
    109113    st->pool_used_cnt = cp->used_count; 
    110114} 
     
    121125        PJ_LOG(3,("", "    error: possibly leaking timer")); 
    122126        rc |= ERR_TIMER_LEAK; 
     127 
     128#if PJ_TIMER_DEBUG 
     129        pj_timer_heap_dump(cfg->timer_heap); 
     130#endif 
    123131    } 
    124132 
     
    149157                      PJ_LOG_HAS_MICRO_SEC; 
    150158 
     159pj_log_func *orig_log_func; 
     160FILE *log_file; 
     161 
     162static void test_log_func(int level, const char *data, int len) 
     163{ 
     164    if (log_file) { 
     165        fwrite(data, len, 1, log_file); 
     166    } 
     167    if (level <= 3) 
     168        orig_log_func(level, data, len); 
     169} 
     170 
    151171static int test_inner(void) 
    152172{ 
     
    159179    pj_log_set_level(3); 
    160180    pj_log_set_decor(param_log_decor); 
     181#elif 1 
     182    log_file = fopen("pjnath-test.log", "wt"); 
     183    pj_log_set_level(5); 
     184    orig_log_func = pj_log_get_log_func(); 
     185    pj_log_set_log_func(&test_log_func); 
    161186#endif 
    162187 
     
    190215#endif 
    191216 
     217#if INCLUDE_CONCUR_TEST 
     218    DO_TEST(concur_test()); 
     219#endif 
     220 
    192221on_return: 
     222    if (log_file) 
     223        fclose(log_file); 
    193224    return rc; 
    194225} 
  • pjproject/trunk/pjnath/src/pjnath-test/test.h

    r3553 r4360  
    2626#define INCLUDE_STUN_SOCK_TEST      1 
    2727#define INCLUDE_TURN_SOCK_TEST      1 
     28#define INCLUDE_CONCUR_TEST         1 
    2829 
    2930int stun_test(void); 
     
    3233int turn_sock_test(void); 
    3334int ice_test(void); 
     35int concur_test(void); 
    3436int test_main(void); 
    3537 
    3638extern void app_perror(const char *title, pj_status_t rc); 
    3739extern pj_pool_factory *mem; 
     40 
     41int ice_one_conc_test(pj_stun_config *stun_cfg, int err_quit); 
    3842 
    3943//////////////////////////////////// 
  • pjproject/trunk/pjnath/src/pjnath/ice_session.c

    r4357 r4360  
    9898}; 
    9999 
     100#define THIS_FILE               "ice_session.c" 
    100101#define CHECK_NAME_LEN          128 
    101102#define LOG4(expr)              PJ_LOG(4,expr) 
     
    135136static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); 
    136137static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now); 
     138static void ice_on_destroy(void *obj); 
    137139static void destroy_ice(pj_ice_sess *ice, 
    138140                        pj_status_t reason); 
     
    289291    status = pj_stun_session_create(&ice->stun_cfg, NULL,  
    290292                                    &sess_cb, PJ_TRUE, 
     293                                    ice->grp_lock, 
    291294                                    &comp->stun_sess); 
    292295    if (status != PJ_SUCCESS) 
     
    333336                                       const pj_str_t *local_ufrag, 
    334337                                       const pj_str_t *local_passwd, 
     338                                       pj_grp_lock_t *grp_lock, 
    335339                                       pj_ice_sess **p_ice) 
    336340{ 
     
    360364                     name, ice); 
    361365 
    362     status = pj_mutex_create_recursive(pool, ice->obj_name,  
    363                                        &ice->mutex); 
    364     if (status != PJ_SUCCESS) { 
    365         destroy_ice(ice, status); 
    366         return status; 
    367     } 
     366    if (grp_lock) { 
     367        ice->grp_lock = grp_lock; 
     368    } else { 
     369        status = pj_grp_lock_create(pool, NULL, &ice->grp_lock); 
     370        if (status != PJ_SUCCESS) { 
     371            pj_pool_release(pool); 
     372            return status; 
     373        } 
     374    } 
     375 
     376    pj_grp_lock_add_ref(ice->grp_lock); 
     377    pj_grp_lock_add_handler(ice->grp_lock, pool, ice, 
     378                            &ice_on_destroy); 
    368379 
    369380    pj_memcpy(&ice->cb, cb, sizeof(*cb)); 
     
    445456 
    446457/* 
     458 * Callback to really destroy the session 
     459 */ 
     460static void ice_on_destroy(void *obj) 
     461{ 
     462    pj_ice_sess *ice = (pj_ice_sess*) obj; 
     463 
     464    if (ice->pool) { 
     465        pj_pool_t *pool = ice->pool; 
     466        ice->pool = NULL; 
     467        pj_pool_release(pool); 
     468    } 
     469    LOG4((THIS_FILE, "ICE session %p destroyed", ice)); 
     470} 
     471 
     472/* 
    447473 * Destroy 
    448474 */ 
     
    453479 
    454480    if (reason == PJ_SUCCESS) { 
    455         LOG4((ice->obj_name, "Destroying ICE session")); 
     481        LOG4((ice->obj_name, "Destroying ICE session %p", ice)); 
     482    } 
     483 
     484    pj_grp_lock_acquire(ice->grp_lock); 
     485 
     486    if (ice->is_destroying) { 
     487        pj_grp_lock_release(ice->grp_lock); 
     488        return; 
    456489    } 
    457490 
    458491    ice->is_destroying = PJ_TRUE; 
    459492 
    460     /* Let other callbacks finish */ 
    461     if (ice->mutex) { 
    462         pj_mutex_lock(ice->mutex); 
    463         pj_mutex_unlock(ice->mutex); 
    464     } 
    465  
    466     if (ice->timer.id) { 
    467         pj_timer_heap_cancel(ice->stun_cfg.timer_heap,  
    468                              &ice->timer); 
    469         ice->timer.id = PJ_FALSE; 
    470     } 
     493    pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, 
     494                                   &ice->timer, PJ_FALSE); 
    471495 
    472496    for (i=0; i<ice->comp_cnt; ++i) { 
     
    477501    } 
    478502 
    479     if (ice->clist.timer.id) { 
    480         pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); 
    481         ice->clist.timer.id = PJ_FALSE; 
    482     } 
    483  
    484     if (ice->mutex) { 
    485         pj_mutex_destroy(ice->mutex); 
    486         ice->mutex = NULL; 
    487     } 
    488  
    489     if (ice->pool) { 
    490         pj_pool_t *pool = ice->pool; 
    491         ice->pool = NULL; 
    492         pj_pool_release(pool); 
    493     } 
     503    pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, 
     504                                   &ice->clist.timer, 
     505                                   PJ_FALSE); 
     506 
     507    pj_grp_lock_dec_ref(ice->grp_lock); 
     508    pj_grp_lock_release(ice->grp_lock); 
    494509} 
    495510 
     
    710725    PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL); 
    711726 
    712     pj_mutex_lock(ice->mutex); 
     727    pj_grp_lock_acquire(ice->grp_lock); 
    713728 
    714729    if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) { 
     
    750765 
    751766on_error: 
    752     pj_mutex_unlock(ice->mutex); 
     767    pj_grp_lock_release(ice->grp_lock); 
    753768    return status; 
    754769} 
     
    767782    *cand_id = -1; 
    768783 
    769     pj_mutex_lock(ice->mutex); 
     784    pj_grp_lock_acquire(ice->grp_lock); 
    770785 
    771786    /* First find in valid list if we have nominated pair */ 
     
    775790        if (check->lcand->comp_id == comp_id) { 
    776791            *cand_id = GET_LCAND_ID(check->lcand); 
    777             pj_mutex_unlock(ice->mutex); 
     792            pj_grp_lock_release(ice->grp_lock); 
    778793            return PJ_SUCCESS; 
    779794        } 
     
    787802        { 
    788803            *cand_id = GET_LCAND_ID(lcand); 
    789             pj_mutex_unlock(ice->mutex); 
     804            pj_grp_lock_release(ice->grp_lock); 
    790805            return PJ_SUCCESS; 
    791806        } 
     
    800815        { 
    801816            *cand_id = GET_LCAND_ID(lcand); 
    802             pj_mutex_unlock(ice->mutex); 
     817            pj_grp_lock_release(ice->grp_lock); 
    803818            return PJ_SUCCESS; 
    804819        } 
     
    812827        { 
    813828            *cand_id = GET_LCAND_ID(lcand); 
    814             pj_mutex_unlock(ice->mutex); 
     829            pj_grp_lock_release(ice->grp_lock); 
    815830            return PJ_SUCCESS; 
    816831        } 
     
    818833 
    819834    /* Still no candidate is found! :( */ 
    820     pj_mutex_unlock(ice->mutex); 
     835    pj_grp_lock_release(ice->grp_lock); 
    821836 
    822837    pj_assert(!"Should have a candidate by now"); 
     
    11281143    pj_ice_sess *ice = (pj_ice_sess*) te->user_data; 
    11291144    enum timer_type type = (enum timer_type)te->id; 
    1130     pj_bool_t has_mutex = PJ_TRUE; 
    11311145 
    11321146    PJ_UNUSED_ARG(th); 
    11331147 
    1134     pj_mutex_lock(ice->mutex); 
     1148    pj_grp_lock_acquire(ice->grp_lock); 
    11351149 
    11361150    te->id = TIMER_NONE; 
     1151 
     1152    if (ice->is_destroying) { 
     1153        /* Stray timer, could happen when destroy is invoked while callback 
     1154         * is pending. */ 
     1155        pj_grp_lock_release(ice->grp_lock); 
     1156        return; 
     1157    } 
    11371158 
    11381159    switch (type) { 
     
    11581179            ice_status = ice->ice_status; 
    11591180            on_ice_complete = ice->cb.on_ice_complete; 
    1160             has_mutex = PJ_FALSE; 
    1161             pj_mutex_unlock(ice->mutex); 
    11621181 
    11631182            /* Notify app about ICE completion*/ 
     
    11771196    } 
    11781197 
    1179     if (has_mutex) 
    1180         pj_mutex_unlock(ice->mutex); 
     1198    pj_grp_lock_release(ice->grp_lock); 
    11811199} 
    11821200 
     
    12361254        pj_time_val_normalize(&delay); 
    12371255 
    1238         ice->timer.id = TIMER_KEEP_ALIVE; 
    1239         pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay); 
     1256        pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, 
     1257                                          &ice->timer, &delay, 
     1258                                          TIMER_KEEP_ALIVE, 
     1259                                          ice->grp_lock); 
    12401260 
    12411261    } else { 
     
    12511271        ice->ice_status = status; 
    12521272     
    1253         if (ice->timer.id != TIMER_NONE) { 
    1254             pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); 
    1255             ice->timer.id = TIMER_NONE; 
    1256         } 
     1273        pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, 
     1274                                       TIMER_NONE); 
    12571275 
    12581276        /* Log message */ 
     
    12671285            pj_time_val delay = {0, 0}; 
    12681286 
    1269             ice->timer.id = TIMER_COMPLETION_CALLBACK; 
    1270             pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
    1271                                    &ice->timer, &delay); 
     1287            pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, 
     1288                                              &ice->timer, &delay, 
     1289                                              TIMER_COMPLETION_CALLBACK, 
     1290                                              ice->grp_lock); 
    12721291        } 
    12731292    } 
     
    14971516                    pj_time_val_normalize(&delay); 
    14981517 
    1499                     ice->timer.id = TIMER_CONTROLLED_WAIT_NOM; 
    1500                     pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
    1501                                            &ice->timer, 
    1502                                            &delay); 
     1518                    pj_timer_heap_schedule_w_grp_lock( 
     1519                                        ice->stun_cfg.timer_heap, 
     1520                                        &ice->timer, &delay, 
     1521                                        TIMER_CONTROLLED_WAIT_NOM, 
     1522                                        ice->grp_lock); 
    15031523 
    15041524                    LOG5((ice->obj_name,  
     
    15761596              ice->opt.nominated_check_delay)); 
    15771597 
    1578         if (ice->timer.id != TIMER_NONE) { 
    1579             pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); 
    1580             ice->timer.id = TIMER_NONE; 
    1581         } 
     1598        pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, 
     1599                                       TIMER_NONE); 
    15821600 
    15831601        /* All components have valid pair. Let connectivity checks run for 
     
    15881606        pj_time_val_normalize(&delay); 
    15891607 
    1590         ice->timer.id = TIMER_START_NOMINATED_CHECK; 
    1591         pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay); 
     1608        pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, 
     1609                                          &ice->timer, &delay, 
     1610                                          TIMER_START_NOMINATED_CHECK, 
     1611                                          ice->grp_lock); 
    15921612        return PJ_FALSE; 
    15931613    } 
     
    16191639                     PJ_ETOOMANY); 
    16201640 
    1621     pj_mutex_lock(ice->mutex); 
     1641    pj_grp_lock_acquire(ice->grp_lock); 
    16221642 
    16231643    /* Save credentials */ 
     
    16671687 
    16681688            if (clist->count >= PJ_ICE_MAX_CHECKS) { 
    1669                 pj_mutex_unlock(ice->mutex); 
     1689                pj_grp_lock_release(ice->grp_lock); 
    16701690                return PJ_ETOOMANY; 
    16711691            }  
     
    16951715    if (clist->count == 0) { 
    16961716        LOG4((ice->obj_name,  "Error: no checklist can be created")); 
    1697         pj_mutex_unlock(ice->mutex); 
     1717        pj_grp_lock_release(ice->grp_lock); 
    16981718        return PJ_ENOTFOUND; 
    16991719    } 
     
    17051725    status = prune_checklist(ice, clist); 
    17061726    if (status != PJ_SUCCESS) { 
    1707         pj_mutex_unlock(ice->mutex); 
     1727        pj_grp_lock_release(ice->grp_lock); 
    17081728        return status; 
    17091729    } 
     
    17321752    dump_checklist("Checklist created:", ice, clist); 
    17331753 
    1734     pj_mutex_unlock(ice->mutex); 
     1754    pj_grp_lock_release(ice->grp_lock); 
    17351755 
    17361756    return PJ_SUCCESS; 
     
    18511871    clist = td->clist; 
    18521872 
    1853     if (ice->is_destroying) 
    1854         return PJ_SUCCESS; 
    1855  
    1856     pj_mutex_lock(ice->mutex); 
     1873    pj_grp_lock_acquire(ice->grp_lock); 
    18571874 
    18581875    if (ice->is_destroying) { 
    1859         pj_mutex_unlock(ice->mutex); 
     1876        pj_grp_lock_release(ice->grp_lock); 
    18601877        return PJ_SUCCESS; 
    18611878    } 
     
    18791896            status = perform_check(ice, clist, i, ice->is_nominating); 
    18801897            if (status != PJ_SUCCESS) { 
    1881                 pj_mutex_unlock(ice->mutex); 
     1898                pj_grp_lock_release(ice->grp_lock); 
    18821899                pj_log_pop_indent(); 
    18831900                return status; 
     
    18991916                status = perform_check(ice, clist, i, ice->is_nominating); 
    19001917                if (status != PJ_SUCCESS) { 
    1901                     pj_mutex_unlock(ice->mutex); 
     1918                    pj_grp_lock_release(ice->grp_lock); 
    19021919                    pj_log_pop_indent(); 
    19031920                    return status; 
     
    19161933        pj_time_val timeout = {0, PJ_ICE_TA_VAL}; 
    19171934 
    1918         te->id = PJ_TRUE; 
    19191935        pj_time_val_normalize(&timeout); 
    1920         pj_timer_heap_schedule(th, te, &timeout); 
    1921     } 
    1922  
    1923     pj_mutex_unlock(ice->mutex); 
     1936        pj_timer_heap_schedule_w_grp_lock(th, te, &timeout, PJ_TRUE, 
     1937                                          ice->grp_lock); 
     1938    } 
     1939 
     1940    pj_grp_lock_release(ice->grp_lock); 
    19241941    pj_log_pop_indent(); 
    19251942    return PJ_SUCCESS; 
     
    19411958    /* Stop our timer if it's active */ 
    19421959    if (ice->timer.id == TIMER_START_NOMINATED_CHECK) { 
    1943         pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); 
    1944         ice->timer.id = TIMER_NONE; 
     1960        pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, 
     1961                                       TIMER_NONE); 
    19451962    } 
    19461963 
     
    19701987 
    19711988    /* And (re)start the periodic check */ 
    1972     if (ice->clist.timer.id) { 
    1973         pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); 
    1974         ice->clist.timer.id = PJ_FALSE; 
    1975     } 
    1976  
    1977     ice->clist.timer.id = PJ_TRUE; 
     1989    pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, 
     1990                                   &ice->clist.timer, PJ_FALSE); 
     1991 
    19781992    delay.sec = delay.msec = 0; 
    1979     status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
    1980                                     &ice->clist.timer, &delay); 
    1981     if (status != PJ_SUCCESS) { 
    1982         ice->clist.timer.id = PJ_FALSE; 
    1983     } else { 
     1993    status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, 
     1994                                               &ice->clist.timer, &delay, 
     1995                                               PJ_TRUE, 
     1996                                               ice->grp_lock); 
     1997    if (status == PJ_SUCCESS) { 
    19841998        LOG5((ice->obj_name, "Periodic timer rescheduled..")); 
    19851999    } 
     
    20312045 
    20322046    /* Lock session */ 
    2033     pj_mutex_lock(ice->mutex); 
     2047    pj_grp_lock_acquire(ice->grp_lock); 
    20342048 
    20352049    LOG4((ice->obj_name, "Starting ICE check..")); 
     
    20612075    if (i == clist->count) { 
    20622076        pj_assert(!"Unable to find checklist for component 1"); 
    2063         pj_mutex_unlock(ice->mutex); 
     2077        pj_grp_lock_release(ice->grp_lock); 
    20642078        pj_log_pop_indent(); 
    20652079        return PJNATH_EICEINCOMPID; 
     
    21152129     * return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 
    21162130     */ 
    2117     clist->timer.id = PJ_TRUE; 
    21182131    delay.sec = delay.msec = 0; 
    2119     status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
    2120                                     &clist->timer, &delay); 
     2132    status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, 
     2133                                               &clist->timer, &delay, 
     2134                                               PJ_TRUE, ice->grp_lock); 
    21212135    if (status != PJ_SUCCESS) { 
    21222136        clist->timer.id = PJ_FALSE; 
    21232137    } 
    21242138 
    2125     pj_mutex_unlock(ice->mutex); 
     2139    pj_grp_lock_release(ice->grp_lock); 
    21262140    pj_log_pop_indent(); 
    21272141    return status; 
     
    21442158    pj_ice_sess *ice = sd->ice; 
    21452159    pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token; 
     2160    pj_status_t status; 
    21462161     
    2147     return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id, 
    2148                                 pkt, pkt_size, dst_addr, addr_len); 
     2162    pj_grp_lock_acquire(ice->grp_lock); 
     2163 
     2164    if (ice->is_destroying) { 
     2165        /* Stray retransmit timer that could happen while 
     2166         * we're being destroyed */ 
     2167        pj_grp_lock_release(ice->grp_lock); 
     2168        return PJ_EINVALIDOP; 
     2169    } 
     2170 
     2171    status = (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id, 
     2172                                  pkt, pkt_size, dst_addr, addr_len); 
     2173 
     2174    pj_grp_lock_release(ice->grp_lock); 
     2175    return status; 
    21492176} 
    21502177 
     
    21812208    check->tdata = NULL; 
    21822209 
    2183     pj_mutex_lock(ice->mutex); 
     2210    pj_grp_lock_acquire(ice->grp_lock); 
     2211 
     2212    if (ice->is_destroying) { 
     2213        /* Not sure if this is possible but just in case */ 
     2214        pj_grp_lock_release(ice->grp_lock); 
     2215        return; 
     2216    } 
    21842217 
    21852218    /* Init lcand to NULL. lcand will be found from the mapped address 
     
    22322265                          check->nominated || ice->is_nominating); 
    22332266            pj_log_pop_indent(); 
    2234             pj_mutex_unlock(ice->mutex); 
     2267            pj_grp_lock_release(ice->grp_lock); 
    22352268            return; 
    22362269        } 
     
    22472280        on_check_complete(ice, check); 
    22482281        pj_log_pop_indent(); 
    2249         pj_mutex_unlock(ice->mutex); 
     2282        pj_grp_lock_release(ice->grp_lock); 
    22502283        return; 
    22512284    } 
     
    22712304        on_check_complete(ice, check); 
    22722305        pj_log_pop_indent(); 
    2273         pj_mutex_unlock(ice->mutex); 
     2306        pj_grp_lock_release(ice->grp_lock); 
    22742307        return; 
    22752308    } 
     
    23042337                        PJNATH_ESTUNNOMAPPEDADDR); 
    23052338        on_check_complete(ice, check); 
    2306         pj_mutex_unlock(ice->mutex); 
     2339        pj_grp_lock_release(ice->grp_lock); 
    23072340        return; 
    23082341    } 
     
    23522385                            status); 
    23532386            on_check_complete(ice, check); 
    2354             pj_mutex_unlock(ice->mutex); 
     2387            pj_grp_lock_release(ice->grp_lock); 
    23552388            return; 
    23562389        } 
     
    24122445    if (on_check_complete(ice, check)) { 
    24132446        /* ICE complete! */ 
    2414         pj_mutex_unlock(ice->mutex); 
     2447        pj_grp_lock_release(ice->grp_lock); 
    24152448        return; 
    24162449    } 
    24172450 
    2418     pj_mutex_unlock(ice->mutex); 
     2451    pj_grp_lock_release(ice->grp_lock); 
    24192452} 
    24202453 
     
    24572490    ice = sd->ice; 
    24582491 
    2459     pj_mutex_lock(ice->mutex); 
     2492    pj_grp_lock_acquire(ice->grp_lock); 
     2493 
     2494    if (ice->is_destroying) { 
     2495        pj_grp_lock_release(ice->grp_lock); 
     2496        return PJ_EINVALIDOP; 
     2497    } 
    24602498 
    24612499    /* 
     
    24722510    if (prio_attr == NULL) { 
    24732511        LOG5((ice->obj_name, "Received Binding request with no PRIORITY")); 
    2474         pj_mutex_unlock(ice->mutex); 
     2512        pj_grp_lock_release(ice->grp_lock); 
    24752513        return PJ_SUCCESS; 
    24762514    } 
     
    25172555                                    NULL, token, PJ_TRUE,  
    25182556                                    src_addr, src_addr_len); 
    2519             pj_mutex_unlock(ice->mutex); 
     2557            pj_grp_lock_release(ice->grp_lock); 
    25202558            return PJ_SUCCESS; 
    25212559        } 
     
    25292567                                    NULL, token, PJ_TRUE,  
    25302568                                    src_addr, src_addr_len); 
    2531             pj_mutex_unlock(ice->mutex); 
     2569            pj_grp_lock_release(ice->grp_lock); 
    25322570            return PJ_SUCCESS; 
    25332571        } else { 
     
    25442582    status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata); 
    25452583    if (status != PJ_SUCCESS) { 
    2546         pj_mutex_unlock(ice->mutex); 
     2584        pj_grp_lock_release(ice->grp_lock); 
    25472585        return status; 
    25482586    } 
     
    25962634    } 
    25972635 
    2598     pj_mutex_unlock(ice->mutex); 
     2636    pj_grp_lock_release(ice->grp_lock); 
    25992637    return PJ_SUCCESS; 
    26002638} 
     
    28852923    } 
    28862924 
    2887     pj_mutex_lock(ice->mutex); 
     2925    pj_grp_lock_acquire(ice->grp_lock); 
     2926 
     2927    if (ice->is_destroying) { 
     2928        pj_grp_lock_release(ice->grp_lock); 
     2929        return PJ_EINVALIDOP; 
     2930    } 
    28882931 
    28892932    comp = find_comp(ice, comp_id); 
    28902933    if (comp == NULL) { 
    28912934        status = PJNATH_EICEINCOMPID; 
    2892         pj_mutex_unlock(ice->mutex); 
     2935        pj_grp_lock_release(ice->grp_lock); 
    28932936        goto on_return; 
    28942937    } 
     
    28962939    if (comp->valid_check == NULL) { 
    28972940        status = PJNATH_EICEINPROGRESS; 
    2898         pj_mutex_unlock(ice->mutex); 
     2941        pj_grp_lock_release(ice->grp_lock); 
    28992942        goto on_return; 
    29002943    } 
     
    29052948 
    29062949    /* Release the mutex now to avoid deadlock (see ticket #1451). */ 
    2907     pj_mutex_unlock(ice->mutex); 
     2950    pj_grp_lock_release(ice->grp_lock); 
     2951 
     2952    PJ_RACE_ME(5); 
    29082953 
    29092954    status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id,  
     
    29322977    PJ_ASSERT_RETURN(ice, PJ_EINVAL); 
    29332978 
    2934     pj_mutex_lock(ice->mutex); 
     2979    pj_grp_lock_acquire(ice->grp_lock); 
     2980 
     2981    if (ice->is_destroying) { 
     2982        pj_grp_lock_release(ice->grp_lock); 
     2983        return PJ_EINVALIDOP; 
     2984    } 
    29352985 
    29362986    comp = find_comp(ice, comp_id); 
    29372987    if (comp == NULL) { 
    2938         pj_mutex_unlock(ice->mutex); 
     2988        pj_grp_lock_release(ice->grp_lock); 
    29392989        return PJNATH_EICEINCOMPID; 
    29402990    } 
     
    29492999    if (msg_data == NULL) { 
    29503000        pj_assert(!"Invalid transport ID"); 
    2951         pj_mutex_unlock(ice->mutex); 
     3001        pj_grp_lock_release(ice->grp_lock); 
    29523002        return PJ_EINVAL; 
    29533003    } 
     
    29693019                  ice->tmp.errmsg)); 
    29703020        } 
    2971         pj_mutex_unlock(ice->mutex); 
     3021        pj_grp_lock_release(ice->grp_lock); 
    29723022    } else { 
    29733023        /* Not a STUN packet. Call application's callback instead, but release 
    29743024         * the mutex now or otherwise we may get deadlock. 
    29753025         */ 
    2976         pj_mutex_unlock(ice->mutex); 
     3026        pj_grp_lock_release(ice->grp_lock); 
     3027 
     3028        PJ_RACE_ME(5); 
    29773029 
    29783030        (*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size,  
  • pjproject/trunk/pjnath/src/pjnath/ice_strans.c

    r4314 r4360  
    127127 
    128128/* Forward decls */ 
     129static void ice_st_on_destroy(void *obj); 
    129130static void destroy_ice_st(pj_ice_strans *ice_st); 
    130131#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc) 
    131132static void sess_init_update(pj_ice_strans *ice_st); 
    132  
    133 static void sess_add_ref(pj_ice_strans *ice_st); 
    134 static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st); 
    135133 
    136134/** 
     
    173171    pj_ice_strans_cfg        cfg;       /**< Configuration.             */ 
    174172    pj_ice_strans_cb         cb;        /**< Application callback.      */ 
    175     pj_lock_t               *init_lock; /**< Initialization mutex.      */ 
     173    pj_grp_lock_t           *grp_lock;  /**< Group lock.                */ 
    176174 
    177175    pj_ice_strans_state      state;     /**< Session state.             */ 
     
    184182    pj_timer_entry           ka_timer;  /**< STUN keep-alive timer.     */ 
    185183 
    186     pj_atomic_t             *busy_cnt;  /**< To prevent destroy         */ 
    187184    pj_bool_t                destroy_req;/**< Destroy has been called?  */ 
    188185    pj_bool_t                cb_called; /**< Init error callback called?*/ 
     
    552549    pj_log_push_indent(); 
    553550 
    554     pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg); 
    555     pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 
    556      
    557     status = pj_atomic_create(pool, 0, &ice_st->busy_cnt); 
     551    status = pj_grp_lock_create(pool, NULL, &ice_st->grp_lock); 
    558552    if (status != PJ_SUCCESS) { 
    559         destroy_ice_st(ice_st); 
    560         return status; 
    561     } 
    562  
    563     status = pj_lock_create_recursive_mutex(pool, ice_st->obj_name,  
    564                                             &ice_st->init_lock); 
    565     if (status != PJ_SUCCESS) { 
    566         destroy_ice_st(ice_st); 
     553        pj_pool_release(pool); 
    567554        pj_log_pop_indent(); 
    568555        return status; 
    569556    } 
     557 
     558    pj_grp_lock_add_ref(ice_st->grp_lock); 
     559    pj_grp_lock_add_handler(ice_st->grp_lock, pool, ice_st, 
     560                            &ice_st_on_destroy); 
     561 
     562    pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg); 
     563    ice_st->cfg.stun.cfg.grp_lock = ice_st->grp_lock; 
     564    ice_st->cfg.turn.cfg.grp_lock = ice_st->grp_lock; 
     565    pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 
    570566 
    571567    ice_st->comp_cnt = comp_cnt; 
     
    579575     * called before we finish initialization. 
    580576     */ 
    581     pj_lock_acquire(ice_st->init_lock); 
     577    pj_grp_lock_acquire(ice_st->grp_lock); 
    582578 
    583579    for (i=0; i<comp_cnt; ++i) { 
    584580        status = create_comp(ice_st, i+1); 
    585581        if (status != PJ_SUCCESS) { 
    586             pj_lock_release(ice_st->init_lock); 
     582            pj_grp_lock_release(ice_st->grp_lock); 
    587583            destroy_ice_st(ice_st); 
    588584            pj_log_pop_indent(); 
     
    592588 
    593589    /* Done with initialization */ 
    594     pj_lock_release(ice_st->init_lock); 
    595  
    596     PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created")); 
     590    pj_grp_lock_release(ice_st->grp_lock); 
     591 
     592    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p created", ice_st)); 
    597593 
    598594    *p_ice_st = ice_st; 
     
    606602} 
    607603 
     604/* REALLY destroy ICE */ 
     605static void ice_st_on_destroy(void *obj) 
     606{ 
     607    pj_ice_strans *ice_st = (pj_ice_strans*)obj; 
     608 
     609    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p destroyed", obj)); 
     610 
     611    /* Done */ 
     612    pj_pool_release(ice_st->pool); 
     613} 
     614 
    608615/* Destroy ICE */ 
    609616static void destroy_ice_st(pj_ice_strans *ice_st) 
     
    611618    unsigned i; 
    612619 
    613     PJ_LOG(5,(ice_st->obj_name, "ICE stream transport destroying..")); 
     620    PJ_LOG(5,(ice_st->obj_name, "ICE stream transport %p destroy request..", 
     621              ice_st)); 
    614622    pj_log_push_indent(); 
     623 
     624    pj_grp_lock_acquire(ice_st->grp_lock); 
     625 
     626    if (ice_st->destroy_req) { 
     627        pj_grp_lock_release(ice_st->grp_lock); 
     628        return; 
     629    } 
     630 
     631    ice_st->destroy_req = PJ_TRUE; 
    615632 
    616633    /* Destroy ICE if we have ICE */ 
     
    624641        if (ice_st->comp[i]) { 
    625642            if (ice_st->comp[i]->stun_sock) { 
    626                 pj_stun_sock_set_user_data(ice_st->comp[i]->stun_sock, NULL); 
    627643                pj_stun_sock_destroy(ice_st->comp[i]->stun_sock); 
    628644                ice_st->comp[i]->stun_sock = NULL; 
    629645            } 
    630646            if (ice_st->comp[i]->turn_sock) { 
    631                 pj_turn_sock_set_user_data(ice_st->comp[i]->turn_sock, NULL); 
    632647                pj_turn_sock_destroy(ice_st->comp[i]->turn_sock); 
    633648                ice_st->comp[i]->turn_sock = NULL; 
     
    635650        } 
    636651    } 
    637     ice_st->comp_cnt = 0; 
    638  
    639     /* Destroy mutex */ 
    640     if (ice_st->init_lock) { 
    641         pj_lock_acquire(ice_st->init_lock); 
    642         pj_lock_release(ice_st->init_lock); 
    643         pj_lock_destroy(ice_st->init_lock); 
    644         ice_st->init_lock = NULL; 
    645     } 
    646  
    647     /* Destroy reference counter */ 
    648     if (ice_st->busy_cnt) { 
    649         pj_assert(pj_atomic_get(ice_st->busy_cnt)==0); 
    650         pj_atomic_destroy(ice_st->busy_cnt); 
    651         ice_st->busy_cnt = NULL; 
    652     } 
    653  
    654     PJ_LOG(4,(ice_st->obj_name, "ICE stream transport destroyed")); 
    655  
    656     /* Done */ 
    657     pj_pool_release(ice_st->pool); 
     652 
     653    pj_grp_lock_dec_ref(ice_st->grp_lock); 
     654    pj_grp_lock_release(ice_st->grp_lock); 
     655 
    658656    pj_log_pop_indent(); 
    659657} 
     
    740738PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st) 
    741739{ 
    742     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 
    743  
    744     sess_add_ref(ice_st); 
    745     ice_st->destroy_req = PJ_TRUE; 
    746     if (sess_dec_ref(ice_st)) { 
    747         PJ_LOG(5,(ice_st->obj_name,  
    748                   "ICE strans object is busy, will destroy later")); 
    749         return PJ_EPENDING; 
    750     } 
    751  
     740    destroy_ice_st(ice_st); 
    752741    return PJ_SUCCESS; 
    753742} 
    754743 
    755  
    756 /* 
    757  * Increment busy counter. 
    758  */ 
    759 static void sess_add_ref(pj_ice_strans *ice_st) 
    760 { 
    761     pj_atomic_inc(ice_st->busy_cnt); 
    762 } 
    763  
    764 /* 
    765  * Decrement busy counter. If the counter has reached zero and destroy 
    766  * has been requested, destroy the object and return FALSE. 
    767  */ 
    768 static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st) 
    769 { 
    770     int count = pj_atomic_dec_and_get(ice_st->busy_cnt); 
    771     pj_assert(count >= 0); 
    772     if (count==0 && ice_st->destroy_req) { 
    773         destroy_ice_st(ice_st); 
    774         return PJ_FALSE; 
    775     } else { 
    776         return PJ_TRUE; 
    777     } 
    778 } 
    779744 
    780745/* 
     
    841806    status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role, 
    842807                                ice_st->comp_cnt, &ice_cb,  
    843                                 local_ufrag, local_passwd, &ice_st->ice); 
     808                                local_ufrag, local_passwd, 
     809                                ice_st->grp_lock, 
     810                                &ice_st->ice); 
    844811    if (status != PJ_SUCCESS) 
    845812        return status; 
     
    12561223    unsigned msec; 
    12571224 
    1258     sess_add_ref(ice_st); 
     1225    pj_grp_lock_add_ref(ice_st->grp_lock); 
    12591226 
    12601227    pj_gettimeofday(&t); 
     
    13381305    } 
    13391306 
    1340     sess_dec_ref(ice_st); 
     1307    pj_grp_lock_dec_ref(ice_st->grp_lock); 
    13411308} 
    13421309 
     
    14271394    ice_st = comp->ice_st; 
    14281395 
    1429     sess_add_ref(ice_st); 
     1396    pj_grp_lock_add_ref(ice_st->grp_lock); 
    14301397 
    14311398    if (ice_st->ice == NULL) { 
     
    14521419    } 
    14531420 
    1454     return sess_dec_ref(ice_st); 
     1421    return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE; 
    14551422} 
    14561423 
     
    14831450    ice_st = comp->ice_st; 
    14841451 
    1485     sess_add_ref(ice_st); 
     1452    pj_grp_lock_add_ref(ice_st->grp_lock); 
    14861453 
    14871454    /* Wait until initialization completes */ 
    1488     pj_lock_acquire(ice_st->init_lock); 
     1455    pj_grp_lock_acquire(ice_st->grp_lock); 
    14891456 
    14901457    /* Find the srflx cancidate */ 
     
    14961463    } 
    14971464 
    1498     pj_lock_release(ice_st->init_lock); 
     1465    pj_grp_lock_release(ice_st->grp_lock); 
    14991466 
    15001467    /* It is possible that we don't have srflx candidate even though this 
     
    15031470     */ 
    15041471    if (cand == NULL) { 
    1505         return sess_dec_ref(ice_st); 
     1472        return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE; 
    15061473    } 
    15071474 
     
    16191586    } 
    16201587 
    1621     return sess_dec_ref(ice_st); 
     1588    return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE; 
    16221589} 
    16231590 
     
    16381605    } 
    16391606 
    1640     sess_add_ref(comp->ice_st); 
     1607    pj_grp_lock_add_ref(comp->ice_st->grp_lock); 
    16411608 
    16421609    if (comp->ice_st->ice == NULL) { 
     
    16651632    } 
    16661633 
    1667     sess_dec_ref(comp->ice_st); 
     1634    pj_grp_lock_dec_ref(comp->ice_st->grp_lock); 
    16681635} 
    16691636 
     
    16871654    pj_log_push_indent(); 
    16881655 
    1689     sess_add_ref(comp->ice_st); 
     1656    pj_grp_lock_add_ref(comp->ice_st->grp_lock); 
    16901657 
    16911658    if (new_state == PJ_TURN_STATE_READY) { 
     
    17011668 
    17021669        /* Wait until initialization completes */ 
    1703         pj_lock_acquire(comp->ice_st->init_lock); 
     1670        pj_grp_lock_acquire(comp->ice_st->grp_lock); 
    17041671 
    17051672        /* Find relayed candidate in the component */ 
     
    17121679        pj_assert(cand != NULL); 
    17131680 
    1714         pj_lock_release(comp->ice_st->init_lock); 
     1681        pj_grp_lock_release(comp->ice_st->grp_lock); 
    17151682 
    17161683        /* Update candidate */ 
     
    17451712        comp->turn_sock = NULL; 
    17461713 
    1747         /* Set session to fail if we're still initializing */ 
    1748         if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) { 
    1749             sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT, 
    1750                       "TURN allocation failed", info.last_status); 
    1751         } else if (comp->turn_err_cnt > 1) { 
    1752             sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE, 
    1753                       "TURN refresh failed", info.last_status); 
    1754         } else { 
    1755             PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status, 
    1756                       "Comp %d: TURN allocation failed, retrying", 
    1757                       comp->comp_id)); 
    1758             add_update_turn(comp->ice_st, comp); 
    1759         } 
    1760     } 
    1761  
    1762     sess_dec_ref(comp->ice_st); 
     1714        /* Set session to fail on error. last_status PJ_SUCCESS means normal 
     1715         * deallocation, which should not trigger sess_fail as it may have 
     1716         * been initiated by ICE destroy 
     1717         */ 
     1718        if (info.last_status != PJ_SUCCESS) { 
     1719            if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) { 
     1720                sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT, 
     1721                          "TURN allocation failed", info.last_status); 
     1722            } else if (comp->turn_err_cnt > 1) { 
     1723                sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE, 
     1724                          "TURN refresh failed", info.last_status); 
     1725            } else { 
     1726                PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status, 
     1727                          "Comp %d: TURN allocation failed, retrying", 
     1728                          comp->comp_id)); 
     1729                add_update_turn(comp->ice_st, comp); 
     1730            } 
     1731        } 
     1732    } 
     1733 
     1734    pj_grp_lock_dec_ref(comp->ice_st->grp_lock); 
    17631735 
    17641736    pj_log_pop_indent(); 
  • pjproject/trunk/pjnath/src/pjnath/nat_detect.c

    r3553 r4360  
    308308    sess_cb.on_send_msg = &on_send_msg; 
    309309    status = pj_stun_session_create(stun_cfg, pool->obj_name, &sess_cb, 
    310                                     PJ_FALSE, &sess->stun_sess); 
     310                                    PJ_FALSE, NULL, &sess->stun_sess); 
    311311    if (status != PJ_SUCCESS) 
    312312        goto on_error; 
  • pjproject/trunk/pjnath/src/pjnath/stun_session.c

    r4352 r4360  
    2626    pj_stun_config      *cfg; 
    2727    pj_pool_t           *pool; 
    28     pj_lock_t           *lock; 
    29     pj_bool_t            delete_lock; 
     28    pj_grp_lock_t       *grp_lock; 
    3029    pj_stun_session_cb   cb; 
    3130    void                *user_data; 
    32  
    33     pj_atomic_t         *busy; 
    34     pj_bool_t            destroy_request; 
     31    pj_bool_t            is_destroying; 
    3532 
    3633    pj_bool_t            use_fingerprint; 
     
    5653 
    5754#define SNAME(s_)                   ((s_)->pool->obj_name) 
    58  
    59 #if PJ_LOG_MAX_LEVEL >= 5 
     55#define THIS_FILE                   "stun_session.c" 
     56 
     57#if 1 
    6058#   define TRACE_(expr)             PJ_LOG(5,expr) 
    6159#else 
     
    6361#endif 
    6462 
    65 #define LOG_ERR_(sess,title,rc) pjnath_perror(sess->pool->obj_name,title,rc) 
     63#define LOG_ERR_(sess,title,rc) PJ_PERROR(3,(sess->pool->obj_name,rc,title)) 
    6664 
    6765#define TDATA_POOL_SIZE             PJNATH_POOL_LEN_STUN_TDATA 
     
    7876                                        pj_size_t pkt_size); 
    7977static void stun_tsx_on_destroy(pj_stun_client_tsx *tsx); 
     78static void stun_sess_on_destroy(void *comp); 
    8079 
    8180static pj_stun_tsx_cb tsx_cb =  
     
    149148 
    150149    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 
    151     tsx_erase(tdata->sess, tdata); 
    152  
    153     pj_stun_client_tsx_destroy(tsx); 
    154     pj_pool_release(tdata->pool); 
     150    pj_stun_client_tsx_stop(tsx); 
     151    if (tdata) { 
     152        tsx_erase(tdata->sess, tdata); 
     153        pj_pool_release(tdata->pool); 
     154    } 
     155 
     156    TRACE_((THIS_FILE, "STUN transaction %p destroyed", tsx)); 
    155157} 
    156158 
    157159static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force) 
    158160{ 
     161    TRACE_((THIS_FILE, "tdata %p destroy request, force=%d, tsx=%p", tdata, 
     162            force, tdata->client_tsx)); 
     163 
    159164    if (tdata->res_timer.id != PJ_FALSE) { 
    160         pj_timer_heap_cancel(tdata->sess->cfg->timer_heap,  
    161                              &tdata->res_timer); 
    162         tdata->res_timer.id = PJ_FALSE; 
     165        pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, 
     166                                       &tdata->res_timer, PJ_FALSE); 
    163167        pj_list_erase(tdata); 
    164168    } 
    165169 
    166170    if (force) { 
     171        pj_list_erase(tdata); 
    167172        if (tdata->client_tsx) { 
    168             tsx_erase(tdata->sess, tdata); 
    169             pj_stun_client_tsx_destroy(tdata->client_tsx); 
     173            pj_stun_client_tsx_stop(tdata->client_tsx); 
     174            pj_stun_client_tsx_set_data(tdata->client_tsx, NULL); 
    170175        } 
    171176        pj_pool_release(tdata->pool); 
     
    173178    } else { 
    174179        if (tdata->client_tsx) { 
    175             pj_time_val delay = {2, 0}; 
     180            /* "Probably" this is to absorb retransmission */ 
     181            pj_time_val delay = {0, 300}; 
    176182            pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay); 
    177183 
     
    207213 
    208214    pj_list_erase(tdata); 
    209     pj_stun_msg_destroy_tdata(tdata->sess, tdata); 
     215    destroy_tdata(tdata, PJ_FALSE); 
    210216} 
    211217 
     
    420426 
    421427    /* Lock the session and prevent user from destroying us in the callback */ 
    422     pj_atomic_inc(sess->busy); 
    423     pj_lock_acquire(sess->lock); 
     428    pj_grp_lock_acquire(sess->grp_lock); 
     429    if (sess->is_destroying) { 
     430        pj_stun_msg_destroy_tdata(sess, tdata); 
     431        pj_grp_lock_release(sess->grp_lock); 
     432        return; 
     433    } 
    424434 
    425435    /* Handle authentication challenge */ 
     
    435445     * from the pending list too.  
    436446     */ 
    437     pj_stun_msg_destroy_tdata(sess, tdata); 
     447    if (status == PJNATH_ESTUNTIMEDOUT) 
     448        destroy_tdata(tdata, PJ_TRUE); 
     449    else 
     450        destroy_tdata(tdata, PJ_FALSE); 
    438451    tdata = NULL; 
    439452 
    440     pj_lock_release(sess->lock); 
    441  
    442     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    443         pj_stun_session_destroy(sess); 
    444         return; 
    445     } 
     453    pj_grp_lock_release(sess->grp_lock); 
    446454} 
    447455 
     
    458466 
    459467    /* Lock the session and prevent user from destroying us in the callback */ 
    460     pj_atomic_inc(sess->busy); 
    461     pj_lock_acquire(sess->lock); 
     468    pj_grp_lock_acquire(sess->grp_lock); 
    462469     
     470    if (sess->is_destroying) { 
     471        /* Stray timer */ 
     472        pj_grp_lock_release(sess->grp_lock); 
     473        return PJ_EINVALIDOP; 
     474    } 
     475 
    463476    status = sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt,  
    464477                                  pkt_size, tdata->dst_addr,  
    465478                                  tdata->addr_len); 
    466     pj_lock_release(sess->lock); 
    467  
    468     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    469         pj_stun_session_destroy(sess); 
    470         return PJNATH_ESTUNDESTROYED; 
    471     } else { 
    472         return status; 
    473     } 
     479    if (pj_grp_lock_release(sess->grp_lock)) 
     480        return PJ_EGONE; 
     481 
     482    return status; 
    474483} 
    475484 
     
    480489                                            const pj_stun_session_cb *cb, 
    481490                                            pj_bool_t fingerprint, 
     491                                            pj_grp_lock_t *grp_lock, 
    482492                                            pj_stun_session **p_sess) 
    483493{ 
     
    502512    sess->log_flag = 0xFFFF; 
    503513 
     514    if (grp_lock) { 
     515        sess->grp_lock = grp_lock; 
     516    } else { 
     517        status = pj_grp_lock_create(pool, NULL, &sess->grp_lock); 
     518        if (status != PJ_SUCCESS) { 
     519            pj_pool_release(pool); 
     520            return status; 
     521        } 
     522    } 
     523 
     524    pj_grp_lock_add_ref(sess->grp_lock); 
     525    pj_grp_lock_add_handler(sess->grp_lock, pool, sess, 
     526                            &stun_sess_on_destroy); 
     527 
    504528    pj_stun_session_set_software_name(sess, &cfg->software_name); 
    505529 
    506     sess->rx_pool = pj_pool_create(sess->cfg->pf, name,  
    507                                    PJNATH_POOL_LEN_STUN_TDATA,  
     530    sess->rx_pool = pj_pool_create(sess->cfg->pf, name, 
     531                                   PJNATH_POOL_LEN_STUN_TDATA, 
    508532                                   PJNATH_POOL_INC_STUN_TDATA, NULL); 
    509533 
     
    511535    pj_list_init(&sess->cached_response_list); 
    512536 
    513     status = pj_lock_create_recursive_mutex(pool, name, &sess->lock); 
    514     if (status != PJ_SUCCESS) { 
    515         pj_pool_release(pool); 
    516         return status; 
    517     } 
    518     sess->delete_lock = PJ_TRUE; 
    519  
    520     status = pj_atomic_create(pool, 0, &sess->busy); 
    521     if (status != PJ_SUCCESS) { 
    522         pj_lock_destroy(sess->lock); 
    523         pj_pool_release(pool); 
    524         return status; 
    525     } 
    526  
    527537    *p_sess = sess; 
    528538 
     
    530540} 
    531541 
    532 PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) 
    533 { 
    534     PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    535  
    536     pj_lock_acquire(sess->lock); 
    537  
    538     /* Can't destroy if we're in a callback */ 
    539     sess->destroy_request = PJ_TRUE; 
    540     if (pj_atomic_get(sess->busy)) { 
    541         pj_lock_release(sess->lock); 
    542         return PJ_EPENDING; 
    543     } 
     542static void stun_sess_on_destroy(void *comp) 
     543{ 
     544    pj_stun_session *sess = (pj_stun_session*)comp; 
    544545 
    545546    while (!pj_list_empty(&sess->pending_request_list)) { 
     
    552553        destroy_tdata(tdata, PJ_TRUE); 
    553554    } 
    554     pj_lock_release(sess->lock); 
    555  
    556     if (sess->delete_lock) { 
    557         pj_lock_destroy(sess->lock); 
    558     } 
    559555 
    560556    if (sess->rx_pool) { 
     
    565561    pj_pool_release(sess->pool); 
    566562 
     563    TRACE_((THIS_FILE, "STUN session %p destroyed", sess)); 
     564} 
     565 
     566PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) 
     567{ 
     568    pj_stun_tx_data *tdata; 
     569 
     570    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     571 
     572    TRACE_((SNAME(sess), "STUN session %p destroy request, ref_cnt=%d", 
     573             sess, pj_grp_lock_get_ref(sess->grp_lock))); 
     574 
     575    pj_grp_lock_acquire(sess->grp_lock); 
     576 
     577    if (sess->is_destroying) { 
     578        /* Prevent from decrementing the ref counter more than once */ 
     579        pj_grp_lock_release(sess->grp_lock); 
     580        return PJ_EINVALIDOP; 
     581    } 
     582 
     583    sess->is_destroying = PJ_TRUE; 
     584 
     585    /* We need to stop transactions and cached response because they are 
     586     * holding the group lock's reference counter while retransmitting. 
     587     */ 
     588    tdata = sess->pending_request_list.next; 
     589    while (tdata != &sess->pending_request_list) { 
     590        if (tdata->client_tsx) 
     591            pj_stun_client_tsx_stop(tdata->client_tsx); 
     592        tdata = tdata->next; 
     593    } 
     594 
     595    tdata = sess->cached_response_list.next; 
     596    while (tdata != &sess->cached_response_list) { 
     597        pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, 
     598                                       &tdata->res_timer, PJ_FALSE); 
     599        tdata = tdata->next; 
     600    } 
     601 
     602    pj_grp_lock_dec_ref(sess->grp_lock); 
     603    pj_grp_lock_release(sess->grp_lock); 
    567604    return PJ_SUCCESS; 
    568605} 
     
    573610{ 
    574611    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    575     pj_lock_acquire(sess->lock); 
     612    pj_grp_lock_acquire(sess->grp_lock); 
    576613    sess->user_data = user_data; 
    577     pj_lock_release(sess->lock); 
     614    pj_grp_lock_release(sess->grp_lock); 
    578615    return PJ_SUCCESS; 
    579616} 
     
    585622} 
    586623 
    587 PJ_DEF(pj_status_t) pj_stun_session_set_lock( pj_stun_session *sess, 
    588                                               pj_lock_t *lock, 
    589                                               pj_bool_t auto_del) 
    590 { 
    591     pj_lock_t *old_lock = sess->lock; 
    592     pj_bool_t old_del; 
    593  
    594     PJ_ASSERT_RETURN(sess && lock, PJ_EINVAL); 
    595  
    596     pj_lock_acquire(old_lock); 
    597     sess->lock = lock; 
    598     old_del = sess->delete_lock; 
    599     sess->delete_lock = auto_del; 
    600     pj_lock_release(old_lock); 
    601  
    602     if (old_lock) 
    603         pj_lock_destroy(old_lock); 
    604  
    605     return PJ_SUCCESS; 
    606 } 
    607  
    608624PJ_DEF(pj_status_t) pj_stun_session_set_software_name(pj_stun_session *sess, 
    609625                                                      const pj_str_t *sw) 
    610626{ 
    611627    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     628    pj_grp_lock_acquire(sess->grp_lock); 
    612629    if (sw && sw->slen) 
    613630        pj_strdup(sess->pool, &sess->srv_name, sw); 
    614631    else 
    615632        sess->srv_name.slen = 0; 
     633    pj_grp_lock_release(sess->grp_lock); 
    616634    return PJ_SUCCESS; 
    617635} 
     
    623641    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    624642 
     643    pj_grp_lock_acquire(sess->grp_lock); 
    625644    sess->auth_type = auth_type; 
    626645    if (cred) { 
     
    630649        pj_bzero(&sess->cred, sizeof(sess->cred)); 
    631650    } 
     651    pj_grp_lock_release(sess->grp_lock); 
    632652 
    633653    return PJ_SUCCESS; 
     
    706726    PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 
    707727 
     728    pj_grp_lock_acquire(sess->grp_lock); 
     729    if (sess->is_destroying) { 
     730        pj_grp_lock_release(sess->grp_lock); 
     731        return PJ_EINVALIDOP; 
     732    } 
     733 
    708734    status = create_tdata(sess, &tdata); 
    709735    if (status != PJ_SUCCESS) 
    710         return status; 
     736        goto on_error; 
    711737 
    712738    /* Create STUN message */ 
    713739    status = pj_stun_msg_create(tdata->pool, method,  magic,  
    714740                                tsx_id, &tdata->msg); 
    715     if (status != PJ_SUCCESS) { 
    716         pj_pool_release(tdata->pool); 
    717         return status; 
    718     } 
     741    if (status != PJ_SUCCESS) 
     742        goto on_error; 
    719743 
    720744    /* copy the request's transaction ID as the transaction key. */ 
     
    732756        /* MUST put authentication in request */ 
    733757        status = get_auth(sess, tdata); 
    734         if (status != PJ_SUCCESS) { 
    735             pj_pool_release(tdata->pool); 
    736             return status; 
    737         } 
     758        if (status != PJ_SUCCESS) 
     759            goto on_error; 
    738760 
    739761    } else if (sess->auth_type == PJ_STUN_AUTH_LONG_TERM) { 
     
    743765        if (sess->next_nonce.slen != 0) { 
    744766            status = get_auth(sess, tdata); 
    745             if (status != PJ_SUCCESS) { 
    746                 pj_pool_release(tdata->pool); 
    747                 return status; 
    748             } 
     767            if (status != PJ_SUCCESS) 
     768                goto on_error; 
    749769            tdata->auth_info.nonce = sess->next_nonce; 
    750770            tdata->auth_info.realm = sess->server_realm; 
     
    753773    } else { 
    754774        pj_assert(!"Invalid authentication type"); 
     775        status = PJ_EBUG; 
     776        goto on_error; 
     777    } 
     778 
     779    *p_tdata = tdata; 
     780    pj_grp_lock_release(sess->grp_lock); 
     781    return PJ_SUCCESS; 
     782 
     783on_error: 
     784    if (tdata) 
    755785        pj_pool_release(tdata->pool); 
    756         return PJ_EBUG; 
    757     } 
    758  
    759     *p_tdata = tdata; 
    760     return PJ_SUCCESS; 
     786    pj_grp_lock_release(sess->grp_lock); 
     787    return status; 
    761788} 
    762789 
     
    770797    PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 
    771798 
     799    pj_grp_lock_acquire(sess->grp_lock); 
     800    if (sess->is_destroying) { 
     801        pj_grp_lock_release(sess->grp_lock); 
     802        return PJ_EINVALIDOP; 
     803    } 
     804 
    772805    status = create_tdata(sess, &tdata); 
    773     if (status != PJ_SUCCESS) 
     806    if (status != PJ_SUCCESS) { 
     807        pj_grp_lock_release(sess->grp_lock); 
    774808        return status; 
     809    } 
    775810 
    776811    /* Create STUN message */ 
     
    780815    if (status != PJ_SUCCESS) { 
    781816        pj_pool_release(tdata->pool); 
     817        pj_grp_lock_release(sess->grp_lock); 
    782818        return status; 
    783819    } 
    784820 
    785821    *p_tdata = tdata; 
     822 
     823    pj_grp_lock_release(sess->grp_lock); 
    786824    return PJ_SUCCESS; 
    787825} 
     
    799837    pj_stun_tx_data *tdata = NULL; 
    800838 
     839    pj_grp_lock_acquire(sess->grp_lock); 
     840    if (sess->is_destroying) { 
     841        pj_grp_lock_release(sess->grp_lock); 
     842        return PJ_EINVALIDOP; 
     843    } 
     844 
    801845    status = create_tdata(sess, &tdata); 
    802     if (status != PJ_SUCCESS) 
     846    if (status != PJ_SUCCESS) { 
     847        pj_grp_lock_release(sess->grp_lock); 
    803848        return status; 
     849    } 
    804850 
    805851    /* Create STUN response message */ 
     
    808854    if (status != PJ_SUCCESS) { 
    809855        pj_pool_release(tdata->pool); 
     856        pj_grp_lock_release(sess->grp_lock); 
    810857        return status; 
    811858    } 
     
    821868 
    822869    *p_tdata = tdata; 
     870 
     871    pj_grp_lock_release(sess->grp_lock); 
    823872 
    824873    return PJ_SUCCESS; 
     
    868917    PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); 
    869918 
     919    /* Lock the session and prevent user from destroying us in the callback */ 
     920    pj_grp_lock_acquire(sess->grp_lock); 
     921    if (sess->is_destroying) { 
     922        pj_grp_lock_release(sess->grp_lock); 
     923        return PJ_EINVALIDOP; 
     924    } 
     925 
    870926    pj_log_push_indent(); 
    871927 
     
    876932    tdata->token = token; 
    877933    tdata->retransmit = retransmit; 
    878  
    879     /* Lock the session and prevent user from destroying us in the callback */ 
    880     pj_atomic_inc(sess->busy); 
    881     pj_lock_acquire(sess->lock); 
    882934 
    883935    /* Apply options */ 
     
    910962 
    911963        /* Create STUN client transaction */ 
    912         status = pj_stun_client_tsx_create(sess->cfg, tdata->pool,  
     964        status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, 
     965                                           sess->grp_lock, 
    913966                                           &tsx_cb, &tdata->client_tsx); 
    914967        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     
    940993             
    941994            pj_memset(&tdata->res_timer, 0, sizeof(tdata->res_timer)); 
    942             pj_timer_entry_init(&tdata->res_timer, PJ_TRUE, tdata,  
     995            pj_timer_entry_init(&tdata->res_timer, PJ_FALSE, tdata, 
    943996                                &on_cache_timeout); 
    944997 
     
    946999            timeout.msec = sess->cfg->res_cache_msec % 1000; 
    9471000 
    948             status = pj_timer_heap_schedule(sess->cfg->timer_heap,  
    949                                             &tdata->res_timer, 
    950                                             &timeout); 
     1001            status = pj_timer_heap_schedule_w_grp_lock(sess->cfg->timer_heap, 
     1002                                                       &tdata->res_timer, 
     1003                                                       &timeout, PJ_TRUE, 
     1004                                                       sess->grp_lock); 
    9511005            if (status != PJ_SUCCESS) { 
    952                 tdata->res_timer.id = PJ_FALSE; 
    9531006                pj_stun_msg_destroy_tdata(sess, tdata); 
    9541007                LOG_ERR_(sess, "Error scheduling response timer", status); 
     
    9761029 
    9771030on_return: 
    978     pj_lock_release(sess->lock); 
    979  
    9801031    pj_log_pop_indent(); 
    9811032 
    982     /* Check if application has called destroy() in the callback */ 
    983     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    984         pj_stun_session_destroy(sess); 
    985         return PJNATH_ESTUNDESTROYED; 
    986     } 
     1033    if (pj_grp_lock_release(sess->grp_lock)) 
     1034        return PJ_EGONE; 
    9871035 
    9881036    return status; 
     
    10061054    pj_stun_tx_data *tdata; 
    10071055 
     1056    pj_grp_lock_acquire(sess->grp_lock); 
     1057    if (sess->is_destroying) { 
     1058        pj_grp_lock_release(sess->grp_lock); 
     1059        return PJ_EINVALIDOP; 
     1060    } 
     1061 
    10081062    status = pj_stun_session_create_res(sess, rdata, code,  
    10091063                                        (errmsg?pj_cstr(&reason,errmsg):NULL),  
    10101064                                        &tdata); 
    1011     if (status != PJ_SUCCESS) 
     1065    if (status != PJ_SUCCESS) { 
     1066        pj_grp_lock_release(sess->grp_lock); 
    10121067        return status; 
    1013  
    1014     return pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, 
    1015                                     dst_addr,  addr_len, tdata); 
     1068    } 
     1069 
     1070    status = pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, 
     1071                                      dst_addr,  addr_len, tdata); 
     1072 
     1073    pj_grp_lock_release(sess->grp_lock); 
     1074    return status; 
    10161075} 
    10171076 
     
    10301089 
    10311090    /* Lock the session and prevent user from destroying us in the callback */ 
    1032     pj_atomic_inc(sess->busy); 
    1033     pj_lock_acquire(sess->lock); 
     1091    pj_grp_lock_acquire(sess->grp_lock); 
     1092    if (sess->is_destroying) { 
     1093        pj_grp_lock_release(sess->grp_lock); 
     1094        return PJ_EINVALIDOP; 
     1095    } 
    10341096 
    10351097    if (notify) { 
     
    10411103    pj_stun_msg_destroy_tdata(sess, tdata); 
    10421104 
    1043     pj_lock_release(sess->lock); 
    1044  
    1045     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    1046         pj_stun_session_destroy(sess); 
    1047         return PJNATH_ESTUNDESTROYED; 
    1048     } 
     1105    pj_grp_lock_release(sess->grp_lock); 
    10491106 
    10501107    return PJ_SUCCESS; 
     
    10641121 
    10651122    /* Lock the session and prevent user from destroying us in the callback */ 
    1066     pj_atomic_inc(sess->busy); 
    1067     pj_lock_acquire(sess->lock); 
     1123    pj_grp_lock_acquire(sess->grp_lock); 
     1124    if (sess->is_destroying) { 
     1125        pj_grp_lock_release(sess->grp_lock); 
     1126        return PJ_EINVALIDOP; 
     1127    } 
    10681128 
    10691129    status = pj_stun_client_tsx_retransmit(tdata->client_tsx, mod_count); 
    10701130 
    1071     pj_lock_release(sess->lock); 
    1072  
    1073     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    1074         pj_stun_session_destroy(sess); 
    1075         return PJNATH_ESTUNDESTROYED; 
    1076     } 
     1131    pj_grp_lock_release(sess->grp_lock); 
    10771132 
    10781133    return status; 
     
    13621417    PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); 
    13631418 
     1419    /* Lock the session and prevent user from destroying us in the callback */ 
     1420    pj_grp_lock_acquire(sess->grp_lock); 
     1421 
     1422    if (sess->is_destroying) { 
     1423        pj_grp_lock_release(sess->grp_lock); 
     1424        return PJ_EINVALIDOP; 
     1425    } 
     1426 
    13641427    pj_log_push_indent(); 
    1365  
    1366     /* Lock the session and prevent user from destroying us in the callback */ 
    1367     pj_atomic_inc(sess->busy); 
    1368     pj_lock_acquire(sess->lock); 
    13691428 
    13701429    /* Reset pool */ 
     
    14191478 
    14201479on_return: 
    1421     pj_lock_release(sess->lock); 
    1422  
    14231480    pj_log_pop_indent(); 
    14241481 
    1425     /* If we've received destroy request while we're on the callback, 
    1426      * destroy the session now. 
    1427      */ 
    1428     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    1429         pj_stun_session_destroy(sess); 
    1430         return PJNATH_ESTUNDESTROYED; 
    1431     } 
     1482    if (pj_grp_lock_release(sess->grp_lock)) 
     1483        return PJ_EGONE; 
    14321484 
    14331485    return status; 
  • pjproject/trunk/pjnath/src/pjnath/stun_sock.c

    r4344 r4360  
    2929#include <pj/ip_helper.h> 
    3030#include <pj/log.h> 
     31#include <pj/os.h> 
    3132#include <pj/pool.h> 
    3233#include <pj/rand.h> 
    3334 
     35#if 1 
     36#  define TRACE_(x)     PJ_LOG(5,x) 
     37#else 
     38#  define TRACE_(x) 
     39#endif 
    3440 
    3541enum { MAX_BIND_RETRY = 100 }; 
     
    4046    pj_pool_t           *pool;          /* Pool                     */ 
    4147    void                *user_data;     /* Application user data    */ 
    42  
     48    pj_bool_t            is_destroying; /* Destroy already called   */ 
    4349    int                  af;            /* Address family           */ 
    4450    pj_stun_config       stun_cfg;      /* STUN config (ioqueue etc)*/ 
     
    5965    pj_uint16_t          tsx_id[6];     /* .. to match STUN msg     */ 
    6066    pj_stun_session     *stun_sess;     /* STUN session             */ 
    61  
     67    pj_grp_lock_t       *grp_lock;      /* Session group lock       */ 
    6268}; 
    6369 
     
    6571 * Prototypes for static functions  
    6672 */ 
     73 
     74/* Destructor for group lock */ 
     75static void stun_sock_destructor(void *obj); 
    6776 
    6877/* This callback is called by the STUN session to send packet */ 
     
    203212        stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC; 
    204213 
     214    if (cfg && cfg->grp_lock) { 
     215        stun_sock->grp_lock = cfg->grp_lock; 
     216    } else { 
     217        status = pj_grp_lock_create(pool, NULL, &stun_sock->grp_lock); 
     218        if (status != PJ_SUCCESS) { 
     219            pj_pool_release(pool); 
     220            return status; 
     221        } 
     222    } 
     223 
     224    pj_grp_lock_add_ref(stun_sock->grp_lock); 
     225    pj_grp_lock_add_handler(stun_sock->grp_lock, pool, stun_sock, 
     226                            &stun_sock_destructor); 
     227 
    205228    /* Create socket and bind socket */ 
    206229    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd); 
     
    253276 
    254277        pj_activesock_cfg_default(&activesock_cfg); 
     278        activesock_cfg.grp_lock = stun_sock->grp_lock; 
    255279        activesock_cfg.async_cnt = cfg->async_cnt; 
    256280        activesock_cfg.concurrency = 0; 
     
    291315                                        stun_sock->obj_name, 
    292316                                        &sess_cb, PJ_FALSE,  
     317                                        stun_sock->grp_lock, 
    293318                                        &stun_sock->stun_sess); 
    294319        if (status != PJ_SUCCESS) 
     
    333358    PJ_ASSERT_RETURN(stun_sock && domain && default_port, PJ_EINVAL); 
    334359 
     360    pj_grp_lock_acquire(stun_sock->grp_lock); 
     361 
    335362    /* Check whether the domain contains IP address */ 
    336363    stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)stun_sock->af; 
     
    361388 
    362389        /* Processing will resume when the DNS SRV callback is called */ 
    363         return status; 
    364390 
    365391    } else { 
     
    379405 
    380406        /* Start sending Binding request */ 
    381         return get_mapped_addr(stun_sock); 
    382     } 
    383 } 
    384  
    385 /* Destroy */ 
    386 PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock) 
    387 { 
     407        status = get_mapped_addr(stun_sock); 
     408    } 
     409 
     410    pj_grp_lock_release(stun_sock->grp_lock); 
     411    return status; 
     412} 
     413 
     414/* Destructor */ 
     415static void stun_sock_destructor(void *obj) 
     416{ 
     417    pj_stun_sock *stun_sock = (pj_stun_sock*)obj; 
     418 
    388419    if (stun_sock->q) { 
    389420        pj_dns_srv_cancel_query(stun_sock->q, PJ_FALSE); 
     
    391422    } 
    392423 
    393     if (stun_sock->stun_sess) { 
    394         pj_stun_session_set_user_data(stun_sock->stun_sess, NULL); 
    395     } 
    396      
    397     /* Destroy the active socket first just in case we'll get 
    398      * stray callback. 
    399      */ 
    400     if (stun_sock->active_sock != NULL) { 
    401         pj_activesock_t *asock = stun_sock->active_sock; 
    402         stun_sock->active_sock = NULL; 
    403         stun_sock->sock_fd = PJ_INVALID_SOCKET; 
    404         pj_activesock_set_user_data(asock, NULL); 
    405         pj_activesock_close(asock); 
    406     } else if (stun_sock->sock_fd != PJ_INVALID_SOCKET) { 
    407         pj_sock_close(stun_sock->sock_fd); 
    408         stun_sock->sock_fd = PJ_INVALID_SOCKET; 
    409     } 
    410  
    411     if (stun_sock->ka_timer.id != 0) { 
    412         pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap,  
    413                              &stun_sock->ka_timer); 
    414         stun_sock->ka_timer.id = 0; 
    415     } 
    416  
     424    /* 
    417425    if (stun_sock->stun_sess) { 
    418426        pj_stun_session_destroy(stun_sock->stun_sess); 
    419427        stun_sock->stun_sess = NULL; 
    420428    } 
     429    */ 
    421430 
    422431    if (stun_sock->pool) { 
     
    426435    } 
    427436 
     437    TRACE_(("", "STUN sock %p destroyed", stun_sock)); 
     438 
     439} 
     440 
     441/* Destroy */ 
     442PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock) 
     443{ 
     444    TRACE_((stun_sock->obj_name, "STUN sock %p request, ref_cnt=%d", 
     445            stun_sock, pj_grp_lock_get_ref(stun_sock->grp_lock))); 
     446 
     447    pj_grp_lock_acquire(stun_sock->grp_lock); 
     448    if (stun_sock->is_destroying) { 
     449        /* Destroy already called */ 
     450        pj_grp_lock_release(stun_sock->grp_lock); 
     451        return PJ_EINVALIDOP; 
     452    } 
     453 
     454    stun_sock->is_destroying = PJ_TRUE; 
     455    pj_timer_heap_cancel_if_active(stun_sock->stun_cfg.timer_heap, 
     456                                   &stun_sock->ka_timer, 0); 
     457 
     458    if (stun_sock->active_sock != NULL) { 
     459        stun_sock->sock_fd = PJ_INVALID_SOCKET; 
     460        pj_activesock_close(stun_sock->active_sock); 
     461    } else if (stun_sock->sock_fd != PJ_INVALID_SOCKET) { 
     462        pj_sock_close(stun_sock->sock_fd); 
     463        stun_sock->sock_fd = PJ_INVALID_SOCKET; 
     464    } 
     465 
     466    if (stun_sock->stun_sess) { 
     467        pj_stun_session_destroy(stun_sock->stun_sess); 
     468    } 
     469    pj_grp_lock_dec_ref(stun_sock->grp_lock); 
     470    pj_grp_lock_release(stun_sock->grp_lock); 
    428471    return PJ_SUCCESS; 
    429472} 
     
    469512    pj_stun_sock *stun_sock = (pj_stun_sock*) user_data; 
    470513 
     514    pj_grp_lock_acquire(stun_sock->grp_lock); 
     515 
    471516    /* Clear query */ 
    472517    stun_sock->q = NULL; 
     
    475520    if (status != PJ_SUCCESS) { 
    476521        sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status); 
     522        pj_grp_lock_release(stun_sock->grp_lock); 
    477523        return; 
    478524    } 
     
    491537    /* Start sending Binding request */ 
    492538    get_mapped_addr(stun_sock); 
     539 
     540    pj_grp_lock_release(stun_sock->grp_lock); 
    493541} 
    494542 
     
    534582    PJ_ASSERT_RETURN(stun_sock && info, PJ_EINVAL); 
    535583 
     584    pj_grp_lock_acquire(stun_sock->grp_lock); 
     585 
    536586    /* Copy STUN server address and mapped address */ 
    537587    pj_memcpy(&info->srv_addr, &stun_sock->srv_addr, 
     
    544594    status = pj_sock_getsockname(stun_sock->sock_fd, &info->bound_addr, 
    545595                                 &addr_len); 
    546     if (status != PJ_SUCCESS) 
     596    if (status != PJ_SUCCESS) { 
     597        pj_grp_lock_release(stun_sock->grp_lock); 
    547598        return status; 
     599    } 
    548600 
    549601    /* If socket is bound to a specific interface, then only put that 
     
    561613        /* Get the default address */ 
    562614        status = pj_gethostip(stun_sock->af, &def_addr); 
    563         if (status != PJ_SUCCESS) 
     615        if (status != PJ_SUCCESS) { 
     616            pj_grp_lock_release(stun_sock->grp_lock); 
    564617            return status; 
     618        } 
    565619         
    566620        pj_sockaddr_set_port(&def_addr, port); 
     
    570624        status = pj_enum_ip_interface(stun_sock->af, &info->alias_cnt,  
    571625                                      info->aliases); 
    572         if (status != PJ_SUCCESS) 
     626        if (status != PJ_SUCCESS) { 
     627            pj_grp_lock_release(stun_sock->grp_lock); 
    573628            return status; 
     629        } 
    574630 
    575631        /* Set the port number for each address. 
     
    591647    } 
    592648 
     649    pj_grp_lock_release(stun_sock->grp_lock); 
    593650    return PJ_SUCCESS; 
    594651} 
     
    604661{ 
    605662    pj_ssize_t size; 
     663    pj_status_t status; 
     664 
    606665    PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL); 
    607666     
     667    pj_grp_lock_acquire(stun_sock->grp_lock); 
     668 
     669    if (!stun_sock->active_sock) { 
     670        /* We have been shutdown, but this callback may still get called 
     671         * by retransmit timer. 
     672         */ 
     673        pj_grp_lock_release(stun_sock->grp_lock); 
     674        return PJ_EINVALIDOP; 
     675    } 
     676 
    608677    if (send_key==NULL) 
    609678        send_key = &stun_sock->send_key; 
    610679 
    611680    size = pkt_len; 
    612     return pj_activesock_sendto(stun_sock->active_sock, send_key,  
    613                                 pkt, &size, flag, dst_addr, addr_len); 
     681    status = pj_activesock_sendto(stun_sock->active_sock, send_key, 
     682                                  pkt, &size, flag, dst_addr, addr_len); 
     683 
     684    pj_grp_lock_release(stun_sock->grp_lock); 
     685    return status; 
    614686} 
    615687 
     
    626698 
    627699    stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess); 
    628     if (!stun_sock || !stun_sock->active_sock) 
     700    if (!stun_sock || !stun_sock->active_sock) { 
     701        /* We have been shutdown, but this callback may still get called 
     702         * by retransmit timer. 
     703         */ 
    629704        return PJ_EINVALIDOP; 
     705    } 
    630706 
    631707    pj_assert(token==INTERNAL_MSG_TOKEN); 
     
    633709 
    634710    size = pkt_size; 
    635     return pj_activesock_sendto(stun_sock->active_sock,  
     711    return pj_activesock_sendto(stun_sock->active_sock, 
    636712                                &stun_sock->int_send_key, 
    637713                                pkt, &size, 0, dst_addr, addr_len); 
     
    727803static void start_ka_timer(pj_stun_sock *stun_sock) 
    728804{ 
    729     if (stun_sock->ka_timer.id != 0) { 
    730         pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap,  
    731                              &stun_sock->ka_timer); 
    732         stun_sock->ka_timer.id = 0; 
    733     } 
     805    pj_timer_heap_cancel_if_active(stun_sock->stun_cfg.timer_heap, 
     806                                   &stun_sock->ka_timer, 0); 
    734807 
    735808    pj_assert(stun_sock->ka_interval != 0); 
    736     if (stun_sock->ka_interval > 0) { 
     809    if (stun_sock->ka_interval > 0 && !stun_sock->is_destroying) { 
    737810        pj_time_val delay; 
    738811 
     
    740813        delay.msec = 0; 
    741814 
    742         if (pj_timer_heap_schedule(stun_sock->stun_cfg.timer_heap,  
    743                                    &stun_sock->ka_timer,  
    744                                    &delay) == PJ_SUCCESS) 
    745         { 
    746             stun_sock->ka_timer.id = PJ_TRUE; 
    747         } 
     815        pj_timer_heap_schedule_w_grp_lock(stun_sock->stun_cfg.timer_heap, 
     816                                          &stun_sock->ka_timer, 
     817                                          &delay, PJ_TRUE, 
     818                                          stun_sock->grp_lock); 
    748819    } 
    749820} 
     
    757828 
    758829    PJ_UNUSED_ARG(th); 
     830    pj_grp_lock_acquire(stun_sock->grp_lock); 
    759831 
    760832    /* Time to send STUN Binding request */ 
    761     if (get_mapped_addr(stun_sock) != PJ_SUCCESS) 
     833    if (get_mapped_addr(stun_sock) != PJ_SUCCESS) { 
     834        pj_grp_lock_release(stun_sock->grp_lock); 
    762835        return; 
     836    } 
    763837 
    764838    /* Next keep-alive timer will be scheduled once the request 
    765839     * is complete. 
    766840     */ 
     841    pj_grp_lock_release(stun_sock->grp_lock); 
    767842} 
    768843 
     
    788863        return PJ_TRUE; 
    789864    } 
     865 
     866    pj_grp_lock_acquire(stun_sock->grp_lock); 
    790867 
    791868    /* Check that this is STUN message */ 
     
    824901                                       PJ_STUN_IS_DATAGRAM, NULL, NULL, 
    825902                                       src_addr, addr_len); 
    826     return status!=PJNATH_ESTUNDESTROYED ? PJ_TRUE : PJ_FALSE; 
     903 
     904    status = pj_grp_lock_release(stun_sock->grp_lock); 
     905 
     906    return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE; 
    827907 
    828908process_app_data: 
     
    832912        ret = (*stun_sock->cb.on_rx_data)(stun_sock, data, size, 
    833913                                          src_addr, addr_len); 
    834         return ret; 
    835     } 
    836  
    837     return PJ_TRUE; 
     914        status = pj_grp_lock_release(stun_sock->grp_lock); 
     915        return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE; 
     916    } 
     917 
     918    status = pj_grp_lock_release(stun_sock->grp_lock); 
     919    return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE; 
    838920} 
    839921 
     
    857939    if (stun_sock->cb.on_data_sent) { 
    858940        pj_bool_t ret; 
     941 
     942        pj_grp_lock_acquire(stun_sock->grp_lock); 
    859943 
    860944        /* If app gives NULL send_key in sendto() function, then give 
     
    867951        ret = (*stun_sock->cb.on_data_sent)(stun_sock, send_key, sent); 
    868952 
     953        pj_grp_lock_release(stun_sock->grp_lock); 
    869954        return ret; 
    870955    } 
  • pjproject/trunk/pjnath/src/pjnath/stun_transaction.c

    r4352 r4360  
    2727 
    2828 
     29#define THIS_FILE               "stun_transaction.c" 
     30#define TIMER_INACTIVE          0 
    2931#define TIMER_ACTIVE            1 
    3032 
     
    3537    pj_stun_tsx_cb       cb; 
    3638    void                *user_data; 
     39    pj_grp_lock_t       *grp_lock; 
    3740 
    3841    pj_bool_t            complete; 
     
    5255 
    5356 
     57#if 1 
     58#   define TRACE_(expr)             PJ_LOG(5,expr) 
     59#else 
     60#   define TRACE_(expr) 
     61#endif 
     62 
     63 
    5464static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,  
    5565                                      pj_timer_entry *timer); 
     
    5767                                   pj_timer_entry *timer); 
    5868 
    59 #define stun_perror(tsx,msg,rc) pjnath_perror(tsx->obj_name, msg, rc) 
    60  
    6169/* 
    6270 * Create a STUN client transaction. 
     
    6472PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_config *cfg, 
    6573                                              pj_pool_t *pool, 
     74                                              pj_grp_lock_t *grp_lock, 
    6675                                              const pj_stun_tsx_cb *cb, 
    6776                                              pj_stun_client_tsx **p_tsx) 
     
    7584    tsx->rto_msec = cfg->rto_msec; 
    7685    tsx->timer_heap = cfg->timer_heap; 
     86    tsx->grp_lock = grp_lock; 
    7787    pj_memcpy(&tsx->cb, cb, sizeof(*cb)); 
    7888 
     
    8393    tsx->destroy_timer.user_data = tsx; 
    8494 
    85     pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "stuntsx%p", tsx); 
     95    pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "utsx%p", tsx); 
    8696 
    8797    *p_tsx = tsx; 
     
    101111    PJ_ASSERT_RETURN(tsx->cb.on_destroy, PJ_EINVAL); 
    102112 
     113    pj_grp_lock_acquire(tsx->grp_lock); 
     114 
    103115    /* Cancel previously registered timer */ 
    104     if (tsx->destroy_timer.id != 0) { 
    105         pj_timer_heap_cancel(tsx->timer_heap, &tsx->destroy_timer); 
    106         tsx->destroy_timer.id = 0; 
    107     } 
     116    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->destroy_timer, 
     117                                   TIMER_INACTIVE); 
    108118 
    109119    /* Stop retransmission, just in case */ 
    110     if (tsx->retransmit_timer.id != 0) { 
    111         pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer); 
    112         tsx->retransmit_timer.id = 0; 
    113     } 
    114  
    115     status = pj_timer_heap_schedule(tsx->timer_heap, 
    116                                     &tsx->destroy_timer, delay); 
    117     if (status != PJ_SUCCESS) 
     120    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->retransmit_timer, 
     121                                   TIMER_INACTIVE); 
     122 
     123    status = pj_timer_heap_schedule_w_grp_lock(tsx->timer_heap, 
     124                                               &tsx->destroy_timer, delay, 
     125                                               TIMER_ACTIVE, tsx->grp_lock); 
     126    if (status != PJ_SUCCESS) { 
     127        pj_grp_lock_release(tsx->grp_lock); 
    118128        return status; 
    119  
    120     tsx->destroy_timer.id = TIMER_ACTIVE; 
     129    } 
     130 
    121131    tsx->cb.on_complete = NULL; 
    122132 
     133    pj_grp_lock_release(tsx->grp_lock); 
     134 
     135    TRACE_((tsx->obj_name, "STUN transaction %p schedule destroy", tsx)); 
     136 
    123137    return PJ_SUCCESS; 
    124138} 
     
    128142 * Destroy transaction immediately. 
    129143 */ 
    130 PJ_DEF(pj_status_t) pj_stun_client_tsx_destroy(pj_stun_client_tsx *tsx) 
     144PJ_DEF(pj_status_t) pj_stun_client_tsx_stop(pj_stun_client_tsx *tsx) 
    131145{ 
    132146    PJ_ASSERT_RETURN(tsx, PJ_EINVAL); 
    133147 
    134     if (tsx->retransmit_timer.id != 0) { 
    135         pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer); 
    136         tsx->retransmit_timer.id = 0; 
    137     } 
    138     if (tsx->destroy_timer.id != 0) { 
    139         pj_timer_heap_cancel(tsx->timer_heap, &tsx->destroy_timer); 
    140         tsx->destroy_timer.id = 0; 
    141     } 
    142  
    143     PJ_LOG(5,(tsx->obj_name, "STUN client transaction destroyed")); 
     148    /* Don't call grp_lock_acquire() because we might be called on 
     149     * group lock's destructor. 
     150     */ 
     151    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->retransmit_timer, 
     152                                   TIMER_INACTIVE); 
     153    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->destroy_timer, 
     154                                   TIMER_INACTIVE); 
     155 
     156    PJ_LOG(5,(tsx->obj_name, "STUN client transaction %p stopped, ref_cnt=%d", 
     157              tsx, pj_grp_lock_get_ref(tsx->grp_lock))); 
     158 
    144159    return PJ_SUCCESS; 
    145160} 
     
    186201    pj_status_t status; 
    187202 
    188     PJ_ASSERT_RETURN(tsx->retransmit_timer.id == 0 || 
     203    PJ_ASSERT_RETURN(tsx->retransmit_timer.id == TIMER_INACTIVE || 
    189204                     !tsx->require_retransmit, PJ_EBUSY); 
    190205 
     
    212227         * cancel transmission). 
    213228         */; 
    214         status = pj_timer_heap_schedule(tsx->timer_heap,  
    215                                         &tsx->retransmit_timer, 
    216                                         &tsx->retransmit_time); 
     229        status = pj_timer_heap_schedule_w_grp_lock(tsx->timer_heap, 
     230                                                   &tsx->retransmit_timer, 
     231                                                   &tsx->retransmit_time, 
     232                                                   TIMER_ACTIVE, 
     233                                                   tsx->grp_lock); 
    217234        if (status != PJ_SUCCESS) { 
    218             tsx->retransmit_timer.id = 0; 
     235            tsx->retransmit_timer.id = TIMER_INACTIVE; 
    219236            return status; 
    220237        } 
    221         tsx->retransmit_timer.id = TIMER_ACTIVE; 
    222238    } 
    223239 
     
    236252        /* We've been destroyed, don't access the object. */ 
    237253    } else if (status != PJ_SUCCESS) { 
    238         if (tsx->retransmit_timer.id != 0 && mod_count) { 
    239             pj_timer_heap_cancel(tsx->timer_heap,  
    240                                  &tsx->retransmit_timer); 
    241             tsx->retransmit_timer.id = 0; 
    242         } 
    243         stun_perror(tsx, "STUN error sending message", status); 
     254        if (mod_count) { 
     255                pj_timer_heap_cancel_if_active( tsx->timer_heap, 
     256                                                &tsx->retransmit_timer, 
     257                                                TIMER_INACTIVE); 
     258        } 
     259        PJ_PERROR(4, (tsx->obj_name, status, "STUN error sending message")); 
    244260    } 
    245261 
     
    261277    PJ_ASSERT_RETURN(tsx && pkt && pkt_len, PJ_EINVAL); 
    262278    PJ_ASSERT_RETURN(tsx->retransmit_timer.id == 0, PJ_EBUSY); 
     279 
     280    pj_grp_lock_acquire(tsx->grp_lock); 
    263281 
    264282    /* Encode message */ 
     
    287305         * cancel transmission). 
    288306         */; 
    289         status = pj_timer_heap_schedule(tsx->timer_heap,  
    290                                         &tsx->retransmit_timer, 
    291                                         &tsx->retransmit_time); 
     307        status = pj_timer_heap_schedule_w_grp_lock(tsx->timer_heap, 
     308                                                   &tsx->retransmit_timer, 
     309                                                   &tsx->retransmit_time, 
     310                                                   TIMER_ACTIVE, 
     311                                                   tsx->grp_lock); 
    292312        if (status != PJ_SUCCESS) { 
    293             tsx->retransmit_timer.id = 0; 
     313            tsx->retransmit_timer.id = TIMER_INACTIVE; 
     314            pj_grp_lock_release(tsx->grp_lock); 
    294315            return status; 
    295316        } 
    296         tsx->retransmit_timer.id = TIMER_ACTIVE; 
    297317    } 
    298318 
     
    300320    status = tsx_transmit_msg(tsx, PJ_TRUE); 
    301321    if (status != PJ_SUCCESS) { 
    302         if (tsx->retransmit_timer.id != 0) { 
    303             pj_timer_heap_cancel(tsx->timer_heap,  
    304                                  &tsx->retransmit_timer); 
    305             tsx->retransmit_timer.id = 0; 
    306         } 
     322        pj_timer_heap_cancel_if_active(tsx->timer_heap, 
     323                                       &tsx->retransmit_timer, 
     324                                       TIMER_INACTIVE); 
     325        pj_grp_lock_release(tsx->grp_lock); 
    307326        return status; 
    308327    } 
    309328 
     329    pj_grp_lock_release(tsx->grp_lock); 
    310330    return PJ_SUCCESS; 
    311331} 
     
    320340 
    321341    PJ_UNUSED_ARG(timer_heap); 
     342    pj_grp_lock_acquire(tsx->grp_lock); 
    322343 
    323344    if (tsx->transmit_count >= PJ_STUN_MAX_TRANSMIT_COUNT) { 
     
    332353            } 
    333354        } 
     355        pj_grp_lock_release(tsx->grp_lock); 
    334356        /* We might have been destroyed, don't try to access the object */ 
    335357        pj_log_pop_indent(); 
     
    339361    tsx->retransmit_timer.id = 0; 
    340362    status = tsx_transmit_msg(tsx, PJ_TRUE); 
    341     if (status == PJNATH_ESTUNDESTROYED) { 
    342         /* We've been destroyed, don't try to access the object */ 
    343     } else if (status != PJ_SUCCESS) { 
     363    if (status != PJ_SUCCESS) { 
    344364        tsx->retransmit_timer.id = 0; 
    345365        if (!tsx->complete) { 
     
    349369            } 
    350370        } 
    351         /* We might have been destroyed, don't try to access the object */ 
    352     } 
     371    } 
     372 
     373    pj_grp_lock_release(tsx->grp_lock); 
     374    /* We might have been destroyed, don't try to access the object */ 
    353375} 
    354376 
     
    363385    } 
    364386 
    365     if (tsx->retransmit_timer.id != 0) { 
    366         pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer); 
    367         tsx->retransmit_timer.id = 0; 
    368     } 
     387    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->retransmit_timer, 
     388                                   TIMER_INACTIVE); 
    369389 
    370390    return tsx_transmit_msg(tsx, mod_count); 
     
    380400 
    381401    tsx->destroy_timer.id = PJ_FALSE; 
     402 
    382403    tsx->cb.on_destroy(tsx); 
    383404    /* Don't access transaction after this */ 
     
    409430     * We can cancel retransmit timer now. 
    410431     */ 
    411     if (tsx->retransmit_timer.id) { 
    412         pj_timer_heap_cancel(tsx->timer_heap, &tsx->retransmit_timer); 
    413         tsx->retransmit_timer.id = 0; 
    414     } 
     432    pj_timer_heap_cancel_if_active(tsx->timer_heap, &tsx->retransmit_timer, 
     433                                   TIMER_INACTIVE); 
    415434 
    416435    /* Find STUN error code attribute */ 
  • pjproject/trunk/pjnath/src/pjnath/turn_session.c

    r4201 r4360  
    113113    void                *user_data; 
    114114    pj_stun_config       stun_cfg; 
    115  
    116     pj_lock_t           *lock; 
     115    pj_bool_t            is_destroying; 
     116 
     117    pj_grp_lock_t       *grp_lock; 
    117118    int                  busy; 
    118119 
     
    162163static void sess_shutdown(pj_turn_session *sess, 
    163164                          pj_status_t status); 
     165static void turn_sess_on_destroy(void *comp); 
    164166static void do_destroy(pj_turn_session *sess); 
    165167static void send_refresh(pj_turn_session *sess, int lifetime); 
     
    237239                                            int af, 
    238240                                            pj_turn_tp_type conn_type, 
     241                                            pj_grp_lock_t *grp_lock, 
    239242                                            const pj_turn_session_cb *cb, 
    240243                                            unsigned options, 
     
    245248    pj_turn_session *sess; 
    246249    pj_stun_session_cb stun_cb; 
    247     pj_lock_t *null_lock; 
    248250    pj_status_t status; 
    249251 
     
    282284 
    283285    /* Session lock */ 
    284     status = pj_lock_create_recursive_mutex(pool, sess->obj_name,  
    285                                             &sess->lock); 
    286     if (status != PJ_SUCCESS) { 
    287         do_destroy(sess); 
    288         return status; 
    289     } 
     286    if (grp_lock) { 
     287        sess->grp_lock = grp_lock; 
     288    } else { 
     289        status = pj_grp_lock_create(pool, NULL, &sess->grp_lock); 
     290        if (status != PJ_SUCCESS) { 
     291            pj_pool_release(pool); 
     292            return status; 
     293        } 
     294    } 
     295 
     296    pj_grp_lock_add_ref(sess->grp_lock); 
     297    pj_grp_lock_add_handler(sess->grp_lock, pool, sess, 
     298                            &turn_sess_on_destroy); 
    290299 
    291300    /* Timer */ 
     
    298307    stun_cb.on_rx_indication = &stun_on_rx_indication; 
    299308    status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb, 
    300                                     PJ_FALSE, &sess->stun); 
     309                                    PJ_FALSE, sess->grp_lock, &sess->stun); 
    301310    if (status != PJ_SUCCESS) { 
    302311        do_destroy(sess); 
     
    307316    pj_stun_session_set_user_data(sess->stun, sess); 
    308317 
    309     /* Replace mutex in STUN session with a NULL mutex, since access to 
    310      * STUN session is serialized. 
    311      */ 
    312     status = pj_lock_create_null_mutex(pool, name, &null_lock); 
    313     if (status != PJ_SUCCESS) { 
    314         do_destroy(sess); 
    315         return status; 
    316     } 
    317     pj_stun_session_set_lock(sess->stun, null_lock, PJ_TRUE); 
    318  
    319318    /* Done */ 
    320319 
     
    326325 
    327326 
    328 /* Destroy */ 
    329 static void do_destroy(pj_turn_session *sess) 
    330 { 
    331     /* Lock session */ 
    332     if (sess->lock) { 
    333         pj_lock_acquire(sess->lock); 
    334     } 
    335  
    336     /* Cancel pending timer, if any */ 
    337     if (sess->timer.id != TIMER_NONE) { 
    338         pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 
    339         sess->timer.id = TIMER_NONE; 
    340     } 
    341  
    342     /* Destroy STUN session */ 
    343     if (sess->stun) { 
    344         pj_stun_session_destroy(sess->stun); 
    345         sess->stun = NULL; 
    346     } 
    347  
    348     /* Destroy lock */ 
    349     if (sess->lock) { 
    350         pj_lock_release(sess->lock); 
    351         pj_lock_destroy(sess->lock); 
    352         sess->lock = NULL; 
    353     } 
     327static void turn_sess_on_destroy(void *comp) 
     328{ 
     329    pj_turn_session *sess = (pj_turn_session*) comp; 
    354330 
    355331    /* Destroy pool */ 
     
    362338        pj_pool_release(pool); 
    363339    } 
     340} 
     341 
     342/* Destroy */ 
     343static void do_destroy(pj_turn_session *sess) 
     344{ 
     345    PJ_LOG(4,(sess->obj_name, "TURN session destroy request, ref_cnt=%d", 
     346              pj_grp_lock_get_ref(sess->grp_lock))); 
     347 
     348    pj_grp_lock_acquire(sess->grp_lock); 
     349    if (sess->is_destroying) { 
     350        pj_grp_lock_release(sess->grp_lock); 
     351        return; 
     352    } 
     353 
     354    sess->is_destroying = PJ_TRUE; 
     355    pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer, TIMER_NONE); 
     356    pj_stun_session_destroy(sess->stun); 
     357 
     358    pj_grp_lock_dec_ref(sess->grp_lock); 
     359    pj_grp_lock_release(sess->grp_lock); 
    364360} 
    365361 
     
    438434        set_state(sess, PJ_TURN_STATE_DESTROYING); 
    439435 
    440         if (sess->timer.id != TIMER_NONE) { 
    441             pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 
    442             sess->timer.id = TIMER_NONE; 
    443         } 
    444  
    445         sess->timer.id = TIMER_DESTROY; 
    446         pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 
     436        pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer, 
     437                                       TIMER_NONE); 
     438        pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer, 
     439                                          &delay, TIMER_DESTROY, 
     440                                          sess->grp_lock); 
    447441    } 
    448442} 
     
    456450    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    457451 
    458     pj_lock_acquire(sess->lock); 
     452    pj_grp_lock_acquire(sess->grp_lock); 
    459453 
    460454    sess_shutdown(sess, PJ_SUCCESS); 
    461455 
    462     pj_lock_release(sess->lock); 
     456    pj_grp_lock_release(sess->grp_lock); 
    463457 
    464458    return PJ_SUCCESS; 
     
    554548    pj_status_t status; 
    555549 
    556     pj_lock_acquire(sess->lock); 
     550    pj_grp_lock_acquire(sess->grp_lock); 
    557551    status = pj_stun_session_set_software_name(sess->stun, sw); 
    558     pj_lock_release(sess->lock); 
     552    pj_grp_lock_release(sess->grp_lock); 
    559553 
    560554    return status; 
     
    577571    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP); 
    578572 
    579     pj_lock_acquire(sess->lock); 
     573    pj_grp_lock_acquire(sess->grp_lock); 
    580574 
    581575    /* See if "domain" contains just IP address */ 
     
    677671 
    678672on_return: 
    679     pj_lock_release(sess->lock); 
     673    pj_grp_lock_release(sess->grp_lock); 
    680674    return status; 
    681675} 
     
    691685    PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP); 
    692686 
    693     pj_lock_acquire(sess->lock); 
     687    pj_grp_lock_acquire(sess->grp_lock); 
    694688 
    695689    pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred); 
    696690 
    697     pj_lock_release(sess->lock); 
     691    pj_grp_lock_release(sess->grp_lock); 
    698692 
    699693    return PJ_SUCCESS; 
     
    716710                     PJ_EINVALIDOP); 
    717711 
    718     pj_lock_acquire(sess->lock); 
     712    pj_grp_lock_acquire(sess->grp_lock); 
    719713 
    720714    if (param && param != &sess->alloc_param)  
     
    727721                  state_names[sess->state])); 
    728722 
    729         pj_lock_release(sess->lock); 
     723        pj_grp_lock_release(sess->grp_lock); 
    730724        return PJ_SUCCESS; 
    731725 
     
    739733                                        PJ_STUN_MAGIC, NULL, &tdata); 
    740734    if (status != PJ_SUCCESS) { 
    741         pj_lock_release(sess->lock); 
     735        pj_grp_lock_release(sess->grp_lock); 
    742736        return status; 
    743737    } 
     
    779773    } 
    780774 
    781     pj_lock_release(sess->lock); 
     775    pj_grp_lock_release(sess->grp_lock); 
    782776    return status; 
    783777} 
     
    800794    PJ_ASSERT_RETURN(sess && addr_cnt && addr, PJ_EINVAL); 
    801795 
    802     pj_lock_acquire(sess->lock); 
     796    pj_grp_lock_acquire(sess->grp_lock); 
    803797 
    804798    /* Create a bare CreatePermission request */ 
     
    807801                                        PJ_STUN_MAGIC, NULL, &tdata); 
    808802    if (status != PJ_SUCCESS) { 
    809         pj_lock_release(sess->lock); 
     803        pj_grp_lock_release(sess->grp_lock); 
    810804        return status; 
    811805    } 
     
    858852    } 
    859853 
    860     pj_lock_release(sess->lock); 
     854    pj_grp_lock_release(sess->grp_lock); 
    861855    return PJ_SUCCESS; 
    862856 
     
    875869            invalidate_perm(sess, perm); 
    876870    } 
    877     pj_lock_release(sess->lock); 
     871    pj_grp_lock_release(sess->grp_lock); 
    878872    return status; 
    879873} 
     
    946940 
    947941    /* Lock session now */ 
    948     pj_lock_acquire(sess->lock); 
     942    pj_grp_lock_acquire(sess->grp_lock); 
    949943 
    950944    /* Lookup permission first */ 
     
    961955                                          0); 
    962956        if (status != PJ_SUCCESS) { 
    963             pj_lock_release(sess->lock); 
     957            pj_grp_lock_release(sess->grp_lock); 
    964958            return status; 
    965959        } 
     
    10361030 
    10371031on_return: 
    1038     pj_lock_release(sess->lock); 
     1032    pj_grp_lock_release(sess->grp_lock); 
    10391033    return status; 
    10401034} 
     
    10561050    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP); 
    10571051 
    1058     pj_lock_acquire(sess->lock); 
     1052    pj_grp_lock_acquire(sess->grp_lock); 
    10591053 
    10601054    /* Create blank ChannelBind request */ 
     
    10991093 
    11001094on_return: 
    1101     pj_lock_release(sess->lock); 
     1095    pj_grp_lock_release(sess->grp_lock); 
    11021096    return status; 
    11031097} 
     
    11221116 
    11231117    /* Start locking the session */ 
    1124     pj_lock_acquire(sess->lock); 
     1118    pj_grp_lock_acquire(sess->grp_lock); 
    11251119 
    11261120    is_datagram = (sess->conn_type==PJ_TURN_TP_UDP); 
     
    11941188 
    11951189on_return: 
    1196     pj_lock_release(sess->lock); 
     1190    pj_grp_lock_release(sess->grp_lock); 
    11971191    return status; 
    11981192} 
     
    13861380    /* Cancel existing keep-alive timer, if any */ 
    13871381    pj_assert(sess->timer.id != TIMER_DESTROY); 
    1388  
    1389     if (sess->timer.id != TIMER_NONE) { 
    1390         pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 
    1391         sess->timer.id = TIMER_NONE; 
     1382    if (sess->timer.id == TIMER_KEEP_ALIVE) { 
     1383        pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer, 
     1384                                       TIMER_NONE); 
    13921385    } 
    13931386 
    13941387    /* Start keep-alive timer once allocation succeeds */ 
    1395     timeout.sec = sess->ka_interval; 
    1396     timeout.msec = 0; 
    1397  
    1398     sess->timer.id = TIMER_KEEP_ALIVE; 
    1399     pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &timeout); 
    1400  
    1401     set_state(sess, PJ_TURN_STATE_READY); 
     1388    if (sess->state < PJ_TURN_STATE_DEALLOCATING) { 
     1389        timeout.sec = sess->ka_interval; 
     1390        timeout.msec = 0; 
     1391 
     1392        pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer, 
     1393                                          &timeout, TIMER_KEEP_ALIVE, 
     1394                                          sess->grp_lock); 
     1395 
     1396        set_state(sess, PJ_TURN_STATE_READY); 
     1397    } 
    14021398} 
    14031399 
     
    19491945    PJ_UNUSED_ARG(th); 
    19501946 
    1951     pj_lock_acquire(sess->lock); 
     1947    pj_grp_lock_acquire(sess->grp_lock); 
    19521948 
    19531949    eid = (enum timer_id_t) e->id; 
     
    20262022            delay.msec = 0; 
    20272023 
    2028             sess->timer.id = TIMER_KEEP_ALIVE; 
    2029             pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 
    2030         } 
    2031  
    2032         pj_lock_release(sess->lock); 
     2024            pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer, 
     2025                                              &delay, TIMER_KEEP_ALIVE, 
     2026                                              sess->grp_lock); 
     2027        } 
    20332028 
    20342029    } else if (eid == TIMER_DESTROY) { 
    20352030        /* Time to destroy */ 
    2036         pj_lock_release(sess->lock); 
    20372031        do_destroy(sess); 
    20382032    } else { 
    20392033        pj_assert(!"Unknown timer event"); 
    2040         pj_lock_release(sess->lock); 
    2041     } 
    2042 } 
    2043  
     2034    } 
     2035 
     2036    pj_grp_lock_release(sess->grp_lock); 
     2037} 
     2038 
  • pjproject/trunk/pjnath/src/pjnath/turn_sock.c

    r4343 r4360  
    4747    void                *user_data; 
    4848 
    49     pj_lock_t           *lock; 
     49    pj_bool_t            is_destroying; 
     50    pj_grp_lock_t       *grp_lock; 
    5051 
    5152    pj_turn_alloc_param  alloc_param; 
     
    5354    pj_turn_sock_cfg     setting; 
    5455 
    55     pj_bool_t            destroy_request; 
    5656    pj_timer_entry       timer; 
    5757 
     
    9494 
    9595 
     96static void turn_sock_on_destroy(void *comp); 
    9697static void destroy(pj_turn_sock *turn_sock); 
    9798static void timer_cb(pj_timer_heap_t *th, pj_timer_entry *e); 
     
    169170    } 
    170171 
    171     /* Create lock */ 
    172     status = pj_lock_create_recursive_mutex(pool, turn_sock->obj_name,  
    173                                             &turn_sock->lock); 
    174     if (status != PJ_SUCCESS) { 
    175         destroy(turn_sock); 
    176         return status; 
    177     } 
     172    /* Session lock */ 
     173    if (setting && setting->grp_lock) { 
     174        turn_sock->grp_lock = setting->grp_lock; 
     175    } else { 
     176        status = pj_grp_lock_create(pool, NULL, &turn_sock->grp_lock); 
     177        if (status != PJ_SUCCESS) { 
     178            pj_pool_release(pool); 
     179            return status; 
     180        } 
     181    } 
     182 
     183    pj_grp_lock_add_ref(turn_sock->grp_lock); 
     184    pj_grp_lock_add_handler(turn_sock->grp_lock, pool, turn_sock, 
     185                            &turn_sock_on_destroy); 
    178186 
    179187    /* Init timer */ 
     
    187195    sess_cb.on_state = &turn_on_state; 
    188196    status = pj_turn_session_create(cfg, pool->obj_name, af, conn_type, 
    189                                     &sess_cb, 0, turn_sock, &turn_sock->sess); 
     197                                    turn_sock->grp_lock, &sess_cb, 0, 
     198                                    turn_sock, &turn_sock->sess); 
    190199    if (status != PJ_SUCCESS) { 
    191200        destroy(turn_sock); 
     
    204213 * Destroy. 
    205214 */ 
    206 static void destroy(pj_turn_sock *turn_sock) 
    207 { 
    208     if (turn_sock->lock) { 
    209         pj_lock_acquire(turn_sock->lock); 
    210     } 
    211  
    212     if (turn_sock->sess) { 
    213         pj_turn_session_set_user_data(turn_sock->sess, NULL); 
    214         pj_turn_session_shutdown(turn_sock->sess); 
    215         turn_sock->sess = NULL; 
    216     } 
    217  
    218     if (turn_sock->active_sock) { 
    219         pj_activesock_set_user_data(turn_sock->active_sock, NULL); 
    220         pj_activesock_close(turn_sock->active_sock); 
    221         turn_sock->active_sock = NULL; 
    222     } 
    223  
    224     if (turn_sock->lock) { 
    225         pj_lock_release(turn_sock->lock); 
    226         pj_lock_destroy(turn_sock->lock); 
    227         turn_sock->lock = NULL; 
    228     } 
     215static void turn_sock_on_destroy(void *comp) 
     216{ 
     217    pj_turn_sock *turn_sock = (pj_turn_sock*) comp; 
    229218 
    230219    if (turn_sock->pool) { 
    231220        pj_pool_t *pool = turn_sock->pool; 
     221        PJ_LOG(4,(turn_sock->obj_name, "TURN socket destroyed")); 
    232222        turn_sock->pool = NULL; 
    233223        pj_pool_release(pool); 
     
    235225} 
    236226 
     227static void destroy(pj_turn_sock *turn_sock) 
     228{ 
     229    PJ_LOG(4,(turn_sock->obj_name, "TURN socket destroy request, ref_cnt=%d", 
     230              pj_grp_lock_get_ref(turn_sock->grp_lock))); 
     231 
     232    pj_grp_lock_acquire(turn_sock->grp_lock); 
     233    if (turn_sock->is_destroying) { 
     234        pj_grp_lock_release(turn_sock->grp_lock); 
     235        return; 
     236    } 
     237 
     238    turn_sock->is_destroying = PJ_TRUE; 
     239    if (turn_sock->sess) 
     240        pj_turn_session_shutdown(turn_sock->sess); 
     241    if (turn_sock->active_sock) 
     242        pj_activesock_close(turn_sock->active_sock); 
     243    pj_grp_lock_dec_ref(turn_sock->grp_lock); 
     244    pj_grp_lock_release(turn_sock->grp_lock); 
     245} 
    237246 
    238247PJ_DEF(void) pj_turn_sock_destroy(pj_turn_sock *turn_sock) 
    239248{ 
    240     pj_lock_acquire(turn_sock->lock); 
    241     turn_sock->destroy_request = PJ_TRUE; 
     249    pj_grp_lock_acquire(turn_sock->grp_lock); 
     250    if (turn_sock->is_destroying) { 
     251        pj_grp_lock_release(turn_sock->grp_lock); 
     252        return; 
     253    } 
    242254 
    243255    if (turn_sock->sess) { 
     
    247259         * destroy ourselves. 
    248260         */ 
    249         pj_lock_release(turn_sock->lock); 
    250261    } else { 
    251         pj_lock_release(turn_sock->lock); 
    252262        destroy(turn_sock); 
    253263    } 
    254264 
     265    pj_grp_lock_release(turn_sock->grp_lock); 
    255266} 
    256267 
     
    268279    switch (eid) { 
    269280    case TIMER_DESTROY: 
    270         PJ_LOG(5,(turn_sock->obj_name, "Destroying TURN")); 
    271281        destroy(turn_sock); 
    272282        break; 
     
    338348PJ_DEF(pj_status_t) pj_turn_sock_lock(pj_turn_sock *turn_sock) 
    339349{ 
    340     return pj_lock_acquire(turn_sock->lock); 
     350    return pj_grp_lock_acquire(turn_sock->grp_lock); 
    341351} 
    342352 
     
    346356PJ_DEF(pj_status_t) pj_turn_sock_unlock(pj_turn_sock *turn_sock) 
    347357{ 
    348     return pj_lock_release(turn_sock->lock); 
     358    return pj_grp_lock_release(turn_sock->grp_lock); 
    349359} 
    350360 
     
    381391    PJ_ASSERT_RETURN(turn_sock && domain, PJ_EINVAL); 
    382392    PJ_ASSERT_RETURN(turn_sock->sess, PJ_EINVALIDOP); 
     393 
     394    pj_grp_lock_acquire(turn_sock->grp_lock); 
    383395 
    384396    /* Copy alloc param. We will call session_alloc() only after the  
     
    396408        if (status != PJ_SUCCESS) { 
    397409            sess_fail(turn_sock, "Error setting credential", status); 
     410            pj_grp_lock_release(turn_sock->grp_lock); 
    398411            return status; 
    399412        } 
     
    405418    if (status != PJ_SUCCESS) { 
    406419        sess_fail(turn_sock, "Error setting TURN server", status); 
     420        pj_grp_lock_release(turn_sock->grp_lock); 
    407421        return status; 
    408422    } 
     
    411425     * to RESOLVED state. 
    412426     */ 
    413  
     427    pj_grp_lock_release(turn_sock->grp_lock); 
    414428    return PJ_SUCCESS; 
    415429} 
     
    473487        return PJ_FALSE; 
    474488 
     489    pj_grp_lock_acquire(turn_sock->grp_lock); 
     490 
    475491    /* TURN session may have already been destroyed here. 
    476492     * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557). 
     
    478494    if (!turn_sock->sess) { 
    479495        sess_fail(turn_sock, "TURN session already destroyed", status); 
     496        pj_grp_lock_release(turn_sock->grp_lock); 
    480497        return PJ_FALSE; 
    481498    } 
     
    483500    if (status != PJ_SUCCESS) { 
    484501        sess_fail(turn_sock, "TCP connect() error", status); 
     502        pj_grp_lock_release(turn_sock->grp_lock); 
    485503        return PJ_FALSE; 
    486504    } 
     
    501519    if (status != PJ_SUCCESS) { 
    502520        sess_fail(turn_sock, "Error sending ALLOCATE", status); 
     521        pj_grp_lock_release(turn_sock->grp_lock); 
    503522        return PJ_FALSE; 
    504523    } 
    505524 
     525    pj_grp_lock_release(turn_sock->grp_lock); 
    506526    return PJ_TRUE; 
    507527} 
     
    563583 
    564584    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock); 
    565     pj_lock_acquire(turn_sock->lock); 
    566  
    567     if (status == PJ_SUCCESS && turn_sock->sess) { 
     585    pj_grp_lock_acquire(turn_sock->grp_lock); 
     586 
     587    if (status == PJ_SUCCESS && turn_sock->sess && !turn_sock->is_destroying) { 
    568588        /* Report incoming packet to TURN session, repeat while we have 
    569589         * "packet" in the buffer (required for stream-oriented transports) 
     
    615635 
    616636on_return: 
    617     pj_lock_release(turn_sock->lock); 
     637    pj_grp_lock_release(turn_sock->grp_lock); 
    618638 
    619639    return ret; 
     
    635655    pj_status_t status; 
    636656 
    637     if (turn_sock == NULL) { 
     657    if (turn_sock == NULL || turn_sock->is_destroying) { 
    638658        /* We've been destroyed */ 
    639659        // https://trac.pjsip.org/repos/ticket/1316 
     
    681701    pj_turn_sock *turn_sock = (pj_turn_sock*)  
    682702                           pj_turn_session_get_user_data(sess); 
    683     if (turn_sock == NULL) { 
     703    if (turn_sock == NULL || turn_sock->is_destroying) { 
    684704        /* We've been destroyed */ 
    685705        return; 
     
    730750        int sock_type; 
    731751        pj_sock_t sock; 
     752        pj_activesock_cfg asock_cfg; 
    732753        pj_activesock_cb asock_cb; 
    733754        pj_sockaddr bound_addr, *cfg_bind_addr; 
     
    791812 
    792813        /* Create active socket */ 
     814        pj_activesock_cfg_default(&asock_cfg); 
     815        asock_cfg.grp_lock = turn_sock->grp_lock; 
     816 
    793817        pj_bzero(&asock_cb, sizeof(asock_cb)); 
    794818        asock_cb.on_data_read = &on_data_read; 
    795819        asock_cb.on_connect_complete = &on_connect_complete; 
    796820        status = pj_activesock_create(turn_sock->pool, sock, 
    797                                       sock_type, NULL, 
     821                                      sock_type, &asock_cfg, 
    798822                                      turn_sock->cfg.ioqueue, &asock_cb,  
    799823                                      turn_sock, 
     
    836860        pj_turn_session_set_user_data(sess, NULL); 
    837861 
    838         if (turn_sock->timer.id) { 
    839             pj_timer_heap_cancel(turn_sock->cfg.timer_heap, &turn_sock->timer); 
    840             turn_sock->timer.id = 0; 
    841         } 
    842  
    843         turn_sock->timer.id = TIMER_DESTROY; 
    844         pj_timer_heap_schedule(turn_sock->cfg.timer_heap, &turn_sock->timer,  
    845                                &delay); 
    846     } 
    847 } 
    848  
    849  
     862        pj_timer_heap_cancel_if_active(turn_sock->cfg.timer_heap, 
     863                                       &turn_sock->timer, 0); 
     864        pj_timer_heap_schedule_w_grp_lock(turn_sock->cfg.timer_heap, 
     865                                          &turn_sock->timer, 
     866                                          &delay, TIMER_DESTROY, 
     867                                          turn_sock->grp_lock); 
     868    } 
     869} 
     870 
     871 
  • pjproject/trunk/pjnath/src/pjturn-srv/allocation.c

    r3553 r4360  
    339339    sess_cb.on_rx_indication = &stun_on_rx_indication; 
    340340    status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name, 
    341                                     &sess_cb, PJ_FALSE, &alloc->sess); 
     341                                    &sess_cb, PJ_FALSE, NULL, &alloc->sess); 
    342342    if (status != PJ_SUCCESS) { 
    343343        goto on_error; 
  • pjproject/trunk/pjnath/src/pjturn-srv/server.c

    r3553 r4360  
    156156 
    157157    status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name, 
    158                                     &sess_cb, PJ_FALSE, &srv->core.stun_sess); 
     158                                    &sess_cb, PJ_FALSE, NULL, 
     159                                    &srv->core.stun_sess); 
    159160    if (status != PJ_SUCCESS) { 
    160161        goto on_error; 
Note: See TracChangeset for help on using the changeset viewer.