Changeset 4862 for pjproject/trunk


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.

Location:
pjproject/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/include/pj/ssl_sock.h

    r4860 r4862  
    553553    unsigned long       last_native_err; 
    554554 
     555    /** 
     556     * Group lock assigned to the ioqueue key. 
     557     */ 
     558    pj_grp_lock_t *grp_lock; 
     559 
    555560} pj_ssl_sock_info; 
    556561 
     
    561566typedef struct pj_ssl_sock_param 
    562567{ 
     568    /** 
     569     * Optional group lock to be assigned to the ioqueue key. 
     570     * 
     571     * Note that when a secure socket listener is configured with a group 
     572     * lock, any new secure socket of an accepted incoming connection 
     573     * will have its own group lock created automatically by the library, 
     574     * this group lock can be queried via pj_ssl_sock_get_info() in the info 
     575     * field pj_ssl_sock_info::grp_lock. 
     576     */ 
     577    pj_grp_lock_t *grp_lock; 
     578 
    563579    /** 
    564580     * Specifies socket address family, either pj_AF_INET() and pj_AF_INET6(). 
  • pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c

    r4860 r4862  
    16941694    asock_cfg.concurrency = ssock->param.concurrency; 
    16951695    asock_cfg.whole_data = PJ_TRUE; 
     1696     
     1697    /* If listener socket has group lock, automatically create group lock 
     1698     * for the new socket. 
     1699     */ 
     1700    if (ssock_parent->param.grp_lock) { 
     1701        pj_grp_lock_t *glock; 
     1702 
     1703        status = pj_grp_lock_create(ssock->pool, NULL, &glock); 
     1704        if (status != PJ_SUCCESS) 
     1705            goto on_return; 
     1706 
     1707        /* Temporarily add ref the group lock until active socket creation, 
     1708         * to make sure that group lock is destroyed if the active socket 
     1709         * creation fails. 
     1710         */ 
     1711        pj_grp_lock_add_ref(glock); 
     1712        asock_cfg.grp_lock = ssock->param.grp_lock = glock; 
     1713    } 
    16961714 
    16971715    pj_bzero(&asock_cb, sizeof(asock_cb)); 
     
    17071725                                  ssock, 
    17081726                                  &ssock->asock); 
     1727 
     1728    /* This will destroy the group lock if active socket creation fails */ 
     1729    if (asock_cfg.grp_lock) { 
     1730        pj_grp_lock_dec_ref(asock_cfg.grp_lock); 
     1731    } 
    17091732 
    17101733    if (status != PJ_SUCCESS) 
     
    21222145    /* Last known OpenSSL error code */ 
    21232146    info->last_native_err = ssock->last_err; 
     2147 
     2148    /* Group lock */ 
     2149    info->grp_lock = ssock->param.grp_lock; 
    21242150 
    21252151    return PJ_SUCCESS; 
     
    24892515    asock_cfg.concurrency = ssock->param.concurrency; 
    24902516    asock_cfg.whole_data = PJ_TRUE; 
     2517    asock_cfg.grp_lock = ssock->param.grp_lock; 
    24912518 
    24922519    pj_bzero(&asock_cb, sizeof(asock_cb)); 
     
    25752602    asock_cfg.concurrency = ssock->param.concurrency; 
    25762603    asock_cfg.whole_data = PJ_TRUE; 
     2604    asock_cfg.grp_lock = ssock->param.grp_lock; 
    25772605 
    25782606    pj_bzero(&asock_cb, sizeof(asock_cb)); 
  • 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/* 
  • 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  
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c

    r4712 r4862  
    7777    int                 is_closing; 
    7878    pj_bool_t           is_paused; 
     79 
     80    /* Group lock to be used by UDP transport and ioqueue key */ 
     81    pj_grp_lock_t      *grp_lock; 
    7982}; 
    8083 
     
    346349} 
    347350 
     351 
     352/* Clean up UDP resources */ 
     353static void udp_on_destroy(void *arg) 
     354{ 
     355    struct udp_transport *tp = (struct udp_transport*)arg; 
     356    int i; 
     357 
     358    /* Destroy rdata */ 
     359    for (i=0; i<tp->rdata_cnt; ++i) { 
     360        pj_pool_release(tp->rdata[i]->tp_info.pool); 
     361    } 
     362 
     363    /* Destroy reference counter. */ 
     364    if (tp->base.ref_cnt) 
     365        pj_atomic_destroy(tp->base.ref_cnt); 
     366 
     367    /* Destroy lock */ 
     368    if (tp->base.lock) 
     369        pj_lock_destroy(tp->base.lock); 
     370 
     371    /* Destroy pool. */ 
     372    pjsip_endpt_release_pool(tp->base.endpt, tp->base.pool); 
     373} 
     374 
     375 
    348376/* 
    349377 * udp_destroy() 
     
    398426    } 
    399427 
    400     /* Destroy rdata */ 
    401     for (i=0; i<tp->rdata_cnt; ++i) { 
    402         pj_pool_release(tp->rdata[i]->tp_info.pool); 
    403     } 
    404  
    405     /* Destroy reference counter. */ 
    406     if (tp->base.ref_cnt) 
    407         pj_atomic_destroy(tp->base.ref_cnt); 
    408  
    409     /* Destroy lock */ 
    410     if (tp->base.lock) 
    411         pj_lock_destroy(tp->base.lock); 
    412  
    413     /* Destroy pool. */ 
    414     pjsip_endpt_release_pool(tp->base.endpt, tp->base.pool); 
     428    if (tp->grp_lock) { 
     429        pj_grp_lock_t *grp_lock = tp->grp_lock; 
     430        tp->grp_lock = NULL; 
     431        pj_grp_lock_dec_ref(grp_lock); 
     432        /* Transport may have been deleted at this point */ 
     433    } else { 
     434        udp_on_destroy(tp); 
     435    } 
    415436 
    416437    return PJ_SUCCESS; 
     
    603624    pj_ioqueue_t *ioqueue; 
    604625    pj_ioqueue_callback ioqueue_cb; 
     626    pj_status_t status; 
    605627 
    606628    /* Ignore if already registered */ 
    607629    if (tp->key != NULL) 
    608630        return PJ_SUCCESS; 
     631 
     632    /* Create group lock */ 
     633    status = pj_grp_lock_create(tp->base.pool, NULL, &tp->grp_lock); 
     634    if (status != PJ_SUCCESS) 
     635        return status; 
     636 
     637    pj_grp_lock_add_ref(tp->grp_lock); 
     638    pj_grp_lock_add_handler(tp->grp_lock, tp->base.pool, tp, &udp_on_destroy); 
    609639     
    610640    /* Register to ioqueue. */ 
     
    614644    ioqueue_cb.on_write_complete = &udp_on_write_complete; 
    615645 
    616     return pj_ioqueue_register_sock(tp->base.pool, ioqueue, tp->sock, tp, 
    617                                     &ioqueue_cb, &tp->key); 
     646    return pj_ioqueue_register_sock2(tp->base.pool, ioqueue, tp->sock, 
     647                                     tp->grp_lock, tp, &ioqueue_cb, &tp->key); 
    618648} 
    619649 
Note: See TracChangeset for help on using the changeset viewer.