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

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath/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 
Note: See TracChangeset for help on using the changeset viewer.