Ignore:
Timestamp:
Jun 19, 2014 9:42:02 AM (10 years ago)
Author:
nanang
Message:

Fix #1773: Added group lock to SIP transport to avoid race condition between transport callback and destroy.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c

    r4860 r4862  
    6262    pj_qos_params            qos_params; 
    6363    pj_sockopt_params        sockopt_params; 
     64 
     65    /* Group lock to be used by TCP listener and ioqueue key */ 
     66    pj_grp_lock_t           *grp_lock; 
    6467}; 
    6568 
     
    116119    /* Pending transmission list. */ 
    117120    struct delayed_tdata     delayed_list; 
     121 
     122    /* Group lock to be used by TCP transport and ioqueue key */ 
     123    pj_grp_lock_t           *grp_lock; 
    118124}; 
    119125 
     
    131137/* This callback is called by transport manager to destroy listener */ 
    132138static pj_status_t lis_destroy(pjsip_tpfactory *factory); 
     139 
     140/* Clean up listener resources (group lock handler) */ 
     141static void lis_on_destroy(void *arg); 
    133142 
    134143/* This callback is called by transport manager to create transport */ 
     
    400409        asock_cfg.async_cnt = cfg->async_cnt; 
    401410 
     411    /* Create group lock */ 
     412    status = pj_grp_lock_create(pool, NULL, &listener->grp_lock); 
     413    if (status != PJ_SUCCESS) 
     414        return status; 
     415 
     416    pj_grp_lock_add_ref(listener->grp_lock); 
     417    pj_grp_lock_add_handler(listener->grp_lock, pool, listener, 
     418                            &lis_on_destroy); 
     419 
     420    asock_cfg.grp_lock = listener->grp_lock; 
     421 
    402422    pj_bzero(&listener_cb, sizeof(listener_cb)); 
    403423    listener_cb.on_accept_complete = &on_accept_complete; 
     
    486506 
    487507 
     508/* Clean up listener resources */ 
     509static void lis_on_destroy(void *arg) 
     510{ 
     511    struct tcp_listener *listener = (struct tcp_listener *)arg; 
     512 
     513    if (listener->factory.lock) { 
     514        pj_lock_destroy(listener->factory.lock); 
     515        listener->factory.lock = NULL; 
     516    } 
     517 
     518    if (listener->factory.pool) { 
     519        pj_pool_t *pool = listener->factory.pool; 
     520 
     521        PJ_LOG(4,(listener->factory.obj_name,  "SIP TCP listener destroyed")); 
     522 
     523        listener->factory.pool = NULL; 
     524        pj_pool_release(pool); 
     525    } 
     526} 
     527 
     528 
    488529/* This callback is called by transport manager to destroy listener */ 
    489530static pj_status_t lis_destroy(pjsip_tpfactory *factory) 
     
    501542    } 
    502543 
    503     if (listener->factory.lock) { 
    504         pj_lock_destroy(listener->factory.lock); 
    505         listener->factory.lock = NULL; 
    506     } 
    507  
    508     if (listener->factory.pool) { 
    509         pj_pool_t *pool = listener->factory.pool; 
    510  
    511         PJ_LOG(4,(listener->factory.obj_name,  "SIP TCP listener destroyed")); 
    512  
    513         listener->factory.pool = NULL; 
    514         pj_pool_release(pool); 
     544    if (listener->grp_lock) { 
     545        pj_grp_lock_t *grp_lock = listener->grp_lock; 
     546        listener->grp_lock = NULL; 
     547        pj_grp_lock_dec_ref(grp_lock); 
     548        /* Listener may have been deleted at this point */ 
     549    } else { 
     550        lis_on_destroy(listener); 
    515551    } 
    516552 
     
    563599/* TCP keep-alive timer callback */ 
    564600static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e); 
     601 
     602/* Clean up TCP resources */ 
     603static void tcp_on_destroy(void *arg); 
    565604 
    566605/* 
     
    641680    tcp->base.destroy = &tcp_destroy_transport; 
    642681 
     682    /* Create group lock */ 
     683    status = pj_grp_lock_create(pool, NULL, &tcp->grp_lock); 
     684    if (status != PJ_SUCCESS) 
     685        goto on_error; 
     686 
     687    pj_grp_lock_add_ref(tcp->grp_lock); 
     688    pj_grp_lock_add_handler(tcp->grp_lock, pool, tcp, &tcp_on_destroy); 
     689 
    643690    /* Create active socket */ 
    644691    pj_activesock_cfg_default(&asock_cfg); 
    645692    asock_cfg.async_cnt = 1; 
     693    asock_cfg.grp_lock = tcp->grp_lock; 
    646694 
    647695    pj_bzero(&tcp_callback, sizeof(tcp_callback)); 
     
    781829    } 
    782830 
    783     if (tcp->rdata.tp_info.pool) { 
    784         pj_pool_release(tcp->rdata.tp_info.pool); 
    785         tcp->rdata.tp_info.pool = NULL; 
    786     } 
    787  
    788831    if (tcp->asock) { 
    789832        pj_activesock_close(tcp->asock); 
     
    795838    } 
    796839 
     840    if (tcp->grp_lock) { 
     841        pj_grp_lock_t *grp_lock = tcp->grp_lock; 
     842        tcp->grp_lock = NULL; 
     843        pj_grp_lock_dec_ref(grp_lock); 
     844        /* Transport may have been deleted at this point */ 
     845    } else { 
     846        tcp_on_destroy(tcp); 
     847    } 
     848 
     849    return PJ_SUCCESS; 
     850} 
     851 
     852/* Clean up TCP resources */ 
     853static void tcp_on_destroy(void *arg) 
     854{ 
     855    struct tcp_transport *tcp = (struct tcp_transport*)arg; 
     856 
    797857    if (tcp->base.lock) { 
    798858        pj_lock_destroy(tcp->base.lock); 
     
    805865    } 
    806866 
     867    if (tcp->rdata.tp_info.pool) { 
     868        pj_pool_release(tcp->rdata.tp_info.pool); 
     869        tcp->rdata.tp_info.pool = NULL; 
     870    } 
     871 
    807872    if (tcp->base.pool) { 
    808873        pj_pool_t *pool; 
    809874 
    810         if (reason != PJ_SUCCESS) { 
     875        if (tcp->close_reason != PJ_SUCCESS) { 
    811876            char errmsg[PJ_ERR_MSG_SIZE]; 
    812877 
    813             pj_strerror(reason, errmsg, sizeof(errmsg)); 
     878            pj_strerror(tcp->close_reason, errmsg, sizeof(errmsg)); 
    814879            PJ_LOG(4,(tcp->base.obj_name,  
    815880                      "TCP transport destroyed with reason %d: %s",  
    816                       reason, errmsg)); 
     881                      tcp->close_reason, errmsg)); 
    817882 
    818883        } else { 
     
    827892        pj_pool_release(pool); 
    828893    } 
    829  
    830     return PJ_SUCCESS; 
    831 } 
    832  
     894} 
    833895 
    834896/* 
Note: See TracChangeset for help on using the changeset viewer.