Ignore:
Timestamp:
Jun 19, 2014 9:42:02 AM (8 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_tls.c

    r4860 r4862  
    5959    pj_ssl_cert_t           *cert; 
    6060    pjsip_tls_setting        tls_setting; 
     61 
     62    /* Group lock to be used by TLS transport and ioqueue key */ 
     63    pj_grp_lock_t           *grp_lock; 
    6164}; 
    6265 
     
    107110    /* Pending transmission list. */ 
    108111    struct delayed_tdata     delayed_list; 
     112 
     113    /* Group lock to be used by TLS transport and ioqueue key */ 
     114    pj_grp_lock_t           *grp_lock; 
    109115}; 
    110116 
     
    134140/* This callback is called by transport manager to destroy listener */ 
    135141static pj_status_t lis_destroy(pjsip_tpfactory *factory); 
     142 
     143/* Clean up listener resources (group lock handler) */ 
     144static void lis_on_destroy(void *arg); 
    136145 
    137146/* This callback is called by transport manager to create transport */ 
     
    377386    } 
    378387 
     388    /* Create group lock */ 
     389    status = pj_grp_lock_create(pool, NULL, &listener->grp_lock); 
     390    if (status != PJ_SUCCESS) 
     391        return status; 
     392 
     393    /* Setup group lock handler */ 
     394    pj_grp_lock_add_ref(listener->grp_lock); 
     395    pj_grp_lock_add_handler(listener->grp_lock, pool, listener, 
     396                            &lis_on_destroy); 
     397 
     398    ssock_param.grp_lock = listener->grp_lock; 
     399 
    379400    /* Create SSL socket */ 
    380401    status = pj_ssl_sock_create(pool, &ssock_param, &listener->ssock); 
     
    510531 
    511532 
     533/* Clean up listener resources */ 
     534static void lis_on_destroy(void *arg) 
     535{ 
     536    struct tls_listener *listener = (struct tls_listener*)arg; 
     537 
     538    if (listener->factory.lock) { 
     539        pj_lock_destroy(listener->factory.lock); 
     540        listener->factory.lock = NULL; 
     541    } 
     542 
     543    if (listener->factory.pool) { 
     544        pj_pool_t *pool = listener->factory.pool; 
     545 
     546        PJ_LOG(4,(listener->factory.obj_name,  "SIP TLS listener destroyed")); 
     547 
     548        listener->factory.pool = NULL; 
     549        pj_pool_release(pool); 
     550    } 
     551} 
     552 
     553 
    512554/* This callback is called by transport manager to destroy listener */ 
    513555static pj_status_t lis_destroy(pjsip_tpfactory *factory) 
     
    525567    } 
    526568 
    527     if (listener->factory.lock) { 
    528         pj_lock_destroy(listener->factory.lock); 
    529         listener->factory.lock = NULL; 
    530     } 
    531  
    532     if (listener->factory.pool) { 
    533         pj_pool_t *pool = listener->factory.pool; 
    534  
    535         PJ_LOG(4,(listener->factory.obj_name,  "SIP TLS listener destroyed")); 
    536  
    537         listener->factory.pool = NULL; 
    538         pj_pool_release(pool); 
     569    if (listener->grp_lock) { 
     570        pj_grp_lock_t *grp_lock = listener->grp_lock; 
     571        listener->grp_lock = NULL; 
     572        pj_grp_lock_dec_ref(grp_lock); 
     573        /* Listener may have been deleted at this point */ 
     574    } else { 
     575        lis_on_destroy(listener); 
    539576    } 
    540577 
     
    753790 
    754791 
     792/* Clean up TLS resources */ 
     793static void tls_on_destroy(void *arg) 
     794{ 
     795    struct tls_transport *tls = (struct tls_transport*)arg; 
     796 
     797    if (tls->rdata.tp_info.pool) { 
     798        pj_pool_release(tls->rdata.tp_info.pool); 
     799        tls->rdata.tp_info.pool = NULL; 
     800    } 
     801 
     802    if (tls->base.lock) { 
     803        pj_lock_destroy(tls->base.lock); 
     804        tls->base.lock = NULL; 
     805    } 
     806 
     807    if (tls->base.ref_cnt) { 
     808        pj_atomic_destroy(tls->base.ref_cnt); 
     809        tls->base.ref_cnt = NULL; 
     810    } 
     811 
     812    if (tls->base.pool) { 
     813        pj_pool_t *pool; 
     814 
     815        if (tls->close_reason != PJ_SUCCESS) { 
     816            char errmsg[PJ_ERR_MSG_SIZE]; 
     817 
     818            pj_strerror(tls->close_reason, errmsg, sizeof(errmsg)); 
     819            PJ_LOG(4,(tls->base.obj_name,  
     820                      "TLS transport destroyed with reason %d: %s",  
     821                      tls->close_reason, errmsg)); 
     822 
     823        } else { 
     824 
     825            PJ_LOG(4,(tls->base.obj_name,  
     826                      "TLS transport destroyed normally")); 
     827 
     828        } 
     829 
     830        pool = tls->base.pool; 
     831        tls->base.pool = NULL; 
     832        pj_pool_release(pool); 
     833    } 
     834} 
     835 
    755836/* Destroy TLS transport */ 
    756837static pj_status_t tls_destroy(pjsip_transport *transport,  
     
    794875    } 
    795876 
    796     if (tls->rdata.tp_info.pool) { 
    797         pj_pool_release(tls->rdata.tp_info.pool); 
    798         tls->rdata.tp_info.pool = NULL; 
    799     } 
    800  
    801877    if (tls->ssock) { 
    802878        pj_ssl_sock_close(tls->ssock); 
    803879        tls->ssock = NULL; 
    804880    } 
    805     if (tls->base.lock) { 
    806         pj_lock_destroy(tls->base.lock); 
    807         tls->base.lock = NULL; 
    808     } 
    809  
    810     if (tls->base.ref_cnt) { 
    811         pj_atomic_destroy(tls->base.ref_cnt); 
    812         tls->base.ref_cnt = NULL; 
    813     } 
    814  
    815     if (tls->base.pool) { 
    816         pj_pool_t *pool; 
    817  
    818         if (reason != PJ_SUCCESS) { 
    819             char errmsg[PJ_ERR_MSG_SIZE]; 
    820  
    821             pj_strerror(reason, errmsg, sizeof(errmsg)); 
    822             PJ_LOG(4,(tls->base.obj_name,  
    823                       "TLS transport destroyed with reason %d: %s",  
    824                       reason, errmsg)); 
    825  
    826         } else { 
    827  
    828             PJ_LOG(4,(tls->base.obj_name,  
    829                       "TLS transport destroyed normally")); 
    830  
    831         } 
    832  
    833         pool = tls->base.pool; 
    834         tls->base.pool = NULL; 
    835         pj_pool_release(pool); 
     881 
     882    if (tls->grp_lock) { 
     883        pj_grp_lock_t *grp_lock = tls->grp_lock; 
     884        tls->grp_lock = NULL; 
     885        pj_grp_lock_dec_ref(grp_lock); 
     886        /* Transport may have been deleted at this point */ 
     887    } else { 
     888        tls_on_destroy(tls); 
    836889    } 
    837890 
     
    907960    struct tls_transport *tls; 
    908961    pj_pool_t *pool; 
     962    pj_grp_lock_t *glock; 
    909963    pj_ssl_sock_t *ssock; 
    910964    pj_ssl_sock_param ssock_param; 
     
    9861040    } 
    9871041 
    988     status = pj_ssl_sock_create(pool, &ssock_param, &ssock); 
     1042    /* Create group lock */ 
     1043    status = pj_grp_lock_create(pool, NULL, &glock); 
    9891044    if (status != PJ_SUCCESS) 
    9901045        return status; 
     1046 
     1047    ssock_param.grp_lock = glock; 
     1048    status = pj_ssl_sock_create(pool, &ssock_param, &ssock); 
     1049    if (status != PJ_SUCCESS) { 
     1050        pj_grp_lock_destroy(glock); 
     1051        return status; 
     1052    } 
    9911053 
    9921054    /* Apply SSL certificate */ 
    9931055    if (listener->cert) { 
    9941056        status = pj_ssl_sock_set_certificate(ssock, pool, listener->cert); 
    995         if (status != PJ_SUCCESS) 
     1057        if (status != PJ_SUCCESS) { 
     1058            pj_grp_lock_destroy(glock); 
    9961059            return status; 
     1060        } 
    9971061    } 
    9981062 
     
    10051069    status = tls_create(listener, pool, ssock, PJ_FALSE, &local_addr,  
    10061070                        rem_addr, &remote_name, &tls); 
    1007     if (status != PJ_SUCCESS) 
     1071    if (status != PJ_SUCCESS) { 
     1072        pj_grp_lock_destroy(glock); 
    10081073        return status; 
     1074    } 
    10091075 
    10101076    /* Set the "pending" SSL socket user data */ 
    10111077    pj_ssl_sock_set_user_data(tls->ssock, tls); 
     1078 
     1079    /* Set up the group lock */ 
     1080    tls->grp_lock = glock; 
     1081    pj_grp_lock_add_ref(tls->grp_lock); 
     1082    pj_grp_lock_add_handler(tls->grp_lock, pool, tls, &tls_on_destroy); 
    10121083 
    10131084    /* Start asynchronous connect() operation */ 
     
    11301201    /* Set the "pending" SSL socket user data */ 
    11311202    pj_ssl_sock_set_user_data(new_ssock, tls); 
     1203 
     1204    /* Set up the group lock */ 
     1205    if (ssl_info.grp_lock) { 
     1206        tls->grp_lock = ssl_info.grp_lock; 
     1207        pj_grp_lock_add_ref(tls->grp_lock); 
     1208        pj_grp_lock_add_handler(tls->grp_lock, tls->base.pool, tls, 
     1209                                &tls_on_destroy); 
     1210    } 
    11321211 
    11331212    /* Prevent immediate transport destroy as application may access it  
Note: See TracChangeset for help on using the changeset viewer.