Changeset 6002


Ignore:
Timestamp:
May 23, 2019 5:21:59 PM (9 months ago)
Author:
riza
Message:

Close #1019: Support for multiple listeners.

Location:
pjproject/trunk/pjsip
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/include/pjsip/sip_config.h

    r5869 r6002  
    434434 * \a accept_multiple_sdp_answers setting in pjsip_cfg_t. 
    435435 * 
    436  * Default is PJ_FALSE. 
     436 * Default is PJ_TRUE. 
    437437 */ 
    438438#ifndef PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS 
     
    693693 * pjsip_tcp_transport_cfg structure. 
    694694 * 
    695  * Default is FALSE on Windows and TRUE on non-Windows. 
     695 * Default is 0 on Windows and 1 on non-Windows. 
    696696 * 
    697697 * @see PJSIP_TLS_TRANSPORT_REUSEADDR 
     
    719719 * able to accept connections.  
    720720 * 
    721  * Default is FALSE (listener will be created). 
     721 * Default is 0 (listener will be created). 
    722722 */ 
    723723#ifndef PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER 
     
    739739 * able to accept connections. 
    740740 * 
    741  * Default is FALSE (listener will be created). 
     741 * Default is 0 (listener will be created). 
    742742 */ 
    743743#ifndef PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER 
     
    882882 * Specify whether TLS listener should use SO_REUSEADDR option. 
    883883 * 
    884  * Default is FALSE on Windows and TRUE on non-Windows. 
     884 * Default is 0 on Windows and 1 on non-Windows. 
    885885 * 
    886886 * @see PJSIP_TCP_TRANSPORT_REUSEADDR 
  • pjproject/trunk/pjsip/src/pjsip/sip_transport.c

    r5984 r6002  
    5555#endif 
    5656 
     57/* Specify the initial size of the transport manager's pool. */ 
     58#ifndef  TPMGR_POOL_INIT_SIZE 
     59#   define TPMGR_POOL_INIT_SIZE 64 
     60#endif 
     61 
     62/* Specify the increment size of the transport manager's pool. */ 
     63#ifndef TPMGR_POOL_INC_SIZE 
     64    #define TPMGR_POOL_INC_SIZE 64 
     65#endif 
     66 
     67/* Specify transport entry allocation count. When registering a new transport, 
     68 * a new entry will be picked from a free list. This setting will determine 
     69 * the size of the free list size. If all entry is used, then the same number 
     70 * of entry will be allocated. 
     71 */ 
     72#ifndef PJSIP_TRANSPORT_ENTRY_ALLOC_CNT 
     73#   define PJSIP_TRANSPORT_ENTRY_ALLOC_CNT  16 
     74#endif 
     75 
    5776/* Prototype. */ 
    5877static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata); 
     
    82101{ 
    83102    PJ_DECL_LIST_MEMBER(struct transport); 
     103    pj_hash_entry_buf tp_buf; 
    84104    pjsip_transport *tp; 
    85105} transport; 
     
    94114    pjsip_endpoint  *endpt; 
    95115    pjsip_tpfactory  factory_list; 
     116    pj_pool_t       *pool; 
    96117#if defined(PJ_DEBUG) && PJ_DEBUG!=0 
    97118    pj_atomic_t     *tdata_counter; 
     
    106127     */ 
    107128    pjsip_tx_data    tdata_list; 
    108      
    109     /* List of transports which are NOT stored in the hash table, so 
    110      * that it can be properly cleaned up when transport manager 
    111      * is destroyed. 
    112      */ 
    113     transport        tp_list; 
     129 
     130    /* List of free transport entry. */ 
     131    transport        tp_entry_freelist; 
    114132}; 
    115133 
     
    10251043                                    int key_len) 
    10261044{ 
    1027     transport *tp_iter; 
    1028  
    1029     if (pj_hash_get(tpmgr->table, key, key_len, NULL) == (void*)tp) { 
    1030         return PJ_TRUE; 
    1031     } 
    1032  
    1033     tp_iter = tpmgr->tp_list.next; 
    1034     while (tp_iter != &tpmgr->tp_list) { 
    1035         if (tp_iter->tp == tp) { 
    1036             return PJ_TRUE; 
    1037         } 
    1038         tp_iter = tp_iter->next; 
     1045    transport *tp_entry; 
     1046 
     1047    tp_entry = (transport *)pj_hash_get(tpmgr->table, key, key_len, NULL); 
     1048    if (tp_entry != NULL) { 
     1049 
     1050        transport *tp_iter = tp_entry; 
     1051        do { 
     1052            if (tp_iter->tp == tp) { 
     1053                return PJ_TRUE; 
     1054            } 
     1055            tp_iter = tp_iter->next; 
     1056        } while (tp_iter != tp_entry); 
    10391057    } 
    10401058 
     
    11361154 
    11371155    /* Dec ref transport group lock, if any */ 
    1138     if (tp->grp_lock) 
     1156    if (tp->grp_lock) { 
    11391157        pj_grp_lock_dec_ref(tp->grp_lock); 
     1158    } 
    11401159 
    11411160    return PJ_SUCCESS; 
     
    11511170    int key_len; 
    11521171    pj_uint32_t hval; 
    1153     void *entry; 
     1172    transport *tp_ref = NULL; 
     1173    transport *tp_add = NULL; 
    11541174 
    11551175    /* Init. */ 
     
    11591179    tp->idle_timer.cb = &transport_idle_callback; 
    11601180 
    1161     /*  
     1181    /* 
    11621182     * Register to hash table (see Trac ticket #42). 
    11631183     */ 
     
    11651185    pj_lock_acquire(mgr->lock); 
    11661186 
    1167     /* If entry already occupied, unregister previous entry */ 
    11681187    hval = 0; 
    1169     entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval); 
    1170     if (entry != NULL) { 
    1171         transport *tp_ref; 
    1172          
    1173         tp_ref = PJ_POOL_ZALLOC_T(((pjsip_transport *)entry)->pool, transport); 
    1174          
    1175         /* 
    1176          * Add transport to the list before removing it from the hash table. 
    1177          * See ticket #1774 for more details. 
    1178          */ 
    1179         tp_ref->tp = (pjsip_transport *)entry; 
    1180         pj_list_push_back(&mgr->tp_list, tp_ref); 
    1181         pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval, NULL); 
    1182     } 
    1183  
    1184     /* Register new entry */ 
    1185     pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, hval, tp); 
     1188    tp_ref = (transport *)pj_hash_get(mgr->table, &tp->key, key_len, &hval); 
     1189 
     1190    /* Get an empty entry from the freelist. */ 
     1191    if (pj_list_empty(&mgr->tp_entry_freelist)) { 
     1192        unsigned i = 0; 
     1193 
     1194        TRACE_((THIS_FILE, "Transport list is full, allocate new entry")); 
     1195        /* Allocate new entry for the freelist. */ 
     1196        for (; i < PJSIP_TRANSPORT_ENTRY_ALLOC_CNT; ++i) { 
     1197            tp_add = PJ_POOL_ZALLOC_T(mgr->pool, transport); 
     1198            if (!tp_add) 
     1199                return PJ_ENOMEM; 
     1200            pj_list_init(tp_add); 
     1201            pj_list_push_back(&mgr->tp_entry_freelist, tp_add); 
     1202        } 
     1203    } 
     1204    tp_add = mgr->tp_entry_freelist.next; 
     1205    tp_add->tp = tp; 
     1206    pj_list_erase(tp_add); 
     1207 
     1208    if (tp_ref) { 
     1209        /* There'a already a transport list from the hash table. Add the  
     1210         * new transport to the list. 
     1211         */ 
     1212        pj_list_push_back(tp_ref, tp_add); 
     1213    } else { 
     1214        /* Transport list not found, add it to the hash table. */ 
     1215        pj_hash_set_np(mgr->table, &tp->key, key_len, hval, tp_add->tp_buf, 
     1216                       tp_add); 
     1217    } 
    11861218 
    11871219    /* Add ref transport group lock, if any */ 
     
    12301262    hval = 0; 
    12311263    entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval); 
    1232     if (entry == (void*)tp) { 
    1233         pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval, NULL); 
    1234     } else { 
    1235         /* If not found in hash table, remove from the tranport list. */ 
    1236         transport *tp_iter = mgr->tp_list.next; 
    1237         while (tp_iter != &mgr->tp_list) { 
    1238             if (tp_iter->tp == tp) { 
    1239                 pj_list_erase(tp_iter); 
    1240                 break; 
    1241             } 
    1242             tp_iter = tp_iter->next; 
    1243         } 
     1264    if (entry) { 
     1265        transport *tp_ref = (transport *)entry; 
     1266        transport *tp_iter = tp_ref; 
     1267        /* Search the matching entry from the transport list. */ 
     1268        do { 
     1269            if (tp_iter->tp == tp) { 
     1270                transport *tp_next = tp_iter->next; 
     1271 
     1272                /* Update hash table : 
     1273                 * - transport list only contain single element, or 
     1274                 * - the entry is the first element of the transport list. 
     1275                 */ 
     1276                if (tp_iter == tp_ref) { 
     1277                    pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval, 
     1278                                NULL); 
     1279 
     1280                    if (tp_ref->next != tp_ref) { 
     1281                        /* The transport list has multiple entry. */ 
     1282                        pj_hash_set_np(mgr->table, &tp_next->tp->key, key_len, 
     1283                                       hval, tp_next->tp_buf, tp_next); 
     1284                    } 
     1285                } 
     1286 
     1287                pj_list_erase(tp_iter); 
     1288                /* Put back to the transport freelist. */ 
     1289                pj_list_push_back(&mgr->tp_entry_freelist, tp_iter); 
     1290 
     1291                break; 
     1292            } 
     1293            tp_iter = tp_iter->next; 
     1294        } while (tp_iter != tp_ref); 
    12441295    } 
    12451296 
     
    12481299 
    12491300    /* Dec ref transport group lock, if any */ 
    1250     if (tp->grp_lock) 
     1301    if (tp->grp_lock) { 
    12511302        pj_grp_lock_dec_ref(tp->grp_lock); 
     1303    } 
    12521304 
    12531305    /* Destroy. */ 
     
    13631415    pj_lock_acquire(mgr->lock); 
    13641416 
    1365     /* Check that no factory with the same type has been registered. */ 
     1417    /* Check that no same factory has been registered. */ 
    13661418    status = PJ_SUCCESS; 
    13671419    for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) { 
    1368         if (p->type == tpf->type) { 
    1369             status = PJSIP_ETYPEEXISTS; 
    1370             break; 
    1371         } 
    13721420        if (p == tpf) { 
    13731421            status = PJ_EEXISTS; 
     
    14441492    pjsip_tpmgr *mgr; 
    14451493    pj_status_t status; 
     1494    unsigned i = 0; 
     1495    pj_pool_t *mgr_pool; 
    14461496 
    14471497    PJ_ASSERT_RETURN(pool && endpt && rx_cb && p_mgr, PJ_EINVAL); 
     
    14531503 
    14541504    /* Create and initialize transport manager. */ 
    1455     mgr = PJ_POOL_ZALLOC_T(pool, pjsip_tpmgr); 
     1505    mgr_pool = pjsip_endpt_create_pool(endpt, "tpmgr", 
     1506                                       TPMGR_POOL_INIT_SIZE, 
     1507                                       TPMGR_POOL_INC_SIZE); 
     1508    mgr = PJ_POOL_ZALLOC_T(mgr_pool, pjsip_tpmgr); 
    14561509    mgr->endpt = endpt; 
    14571510    mgr->on_rx_msg = rx_cb; 
    14581511    mgr->on_tx_msg = tx_cb; 
     1512    mgr->pool = mgr_pool; 
     1513 
     1514    if (!mgr->pool) 
     1515        return PJ_ENOMEM; 
     1516 
    14591517    pj_list_init(&mgr->factory_list); 
    14601518    pj_list_init(&mgr->tdata_list); 
    1461     pj_list_init(&mgr->tp_list); 
    1462  
    1463     mgr->table = pj_hash_create(pool, PJSIP_TPMGR_HTABLE_SIZE); 
     1519    pj_list_init(&mgr->tp_entry_freelist); 
     1520 
     1521    mgr->table = pj_hash_create(mgr->pool, PJSIP_TPMGR_HTABLE_SIZE); 
    14641522    if (!mgr->table) 
    14651523        return PJ_ENOMEM; 
    14661524 
    1467     status = pj_lock_create_recursive_mutex(pool, "tmgr%p", &mgr->lock); 
     1525    status = pj_lock_create_recursive_mutex(mgr->pool, "tmgr%p", &mgr->lock); 
    14681526    if (status != PJ_SUCCESS) 
    14691527        return status; 
    14701528 
     1529    for (; i < PJSIP_TRANSPORT_ENTRY_ALLOC_CNT; ++i) { 
     1530        transport *tp_add = NULL; 
     1531 
     1532        tp_add = PJ_POOL_ZALLOC_T(mgr->pool, transport); 
     1533        if (!tp_add) 
     1534            return PJ_ENOMEM; 
     1535        pj_list_init(tp_add); 
     1536        pj_list_push_back(&mgr->tp_entry_freelist, tp_add); 
     1537    } 
     1538 
    14711539#if defined(PJ_DEBUG) && PJ_DEBUG!=0 
    1472     status = pj_atomic_create(pool, 0, &mgr->tdata_counter); 
     1540    status = pj_atomic_create(mgr->pool, 0, &mgr->tdata_counter); 
    14731541    if (status != PJ_SUCCESS) { 
    14741542        pj_lock_destroy(mgr->lock); 
     
    16981766    pj_hash_iterator_t *itr; 
    16991767    int nr_of_transports = 0; 
    1700      
     1768 
    17011769    pj_lock_acquire(mgr->lock); 
    1702      
     1770 
    17031771    itr = pj_hash_first(mgr->table, &itr_val); 
    17041772    while (itr) { 
    1705         nr_of_transports++; 
     1773        transport *tp_entry = (transport *)pj_hash_this(mgr->table, itr); 
     1774        nr_of_transports += pj_list_size(tp_entry); 
    17061775        itr = pj_hash_next(mgr->table, itr); 
    17071776    } 
    1708      
     1777 
    17091778    pj_lock_release(mgr->lock); 
    17101779 
     
    17231792    pjsip_tpfactory *factory; 
    17241793    pjsip_endpoint *endpt = mgr->endpt; 
    1725      
     1794 
    17261795    PJ_LOG(5, (THIS_FILE, "Destroying transport manager")); 
    17271796 
     
    17311800     * Destroy all transports in the hash table. 
    17321801     */ 
    1733     itr = pj_hash_first(mgr->table, &itr_val); 
    1734     while (itr != NULL) { 
    1735         pj_hash_iterator_t *next; 
    1736         pjsip_transport *transport; 
    1737          
    1738         transport = (pjsip_transport*) pj_hash_this(mgr->table, itr); 
    1739  
    1740         next = pj_hash_next(mgr->table, itr); 
    1741  
    1742         destroy_transport(mgr, transport); 
    1743  
    1744         itr = next; 
    1745     } 
    1746  
    1747     /* 
    1748      * Destroy transports in the list. 
    1749      */ 
    1750     if (!pj_list_empty(&mgr->tp_list)) { 
    1751         transport *tp_iter = mgr->tp_list.next; 
    1752         while (tp_iter != &mgr->tp_list) { 
    1753             transport *next = tp_iter->next; 
    1754             destroy_transport(mgr, tp_iter->tp); 
    1755             tp_iter = next; 
    1756         } 
    1757     } 
    1758      
     1802    for (itr = pj_hash_first(mgr->table, &itr_val); itr; 
     1803         itr = pj_hash_first(mgr->table, &itr_val)) 
     1804    { 
     1805        transport *tp_ref; 
     1806        tp_ref = pj_hash_this(mgr->table, itr); 
     1807        destroy_transport(mgr, tp_ref->tp); 
     1808    } 
     1809 
    17591810    /* 
    17601811     * Destroy all factories/listeners. 
     
    17631814    while (factory != &mgr->factory_list) { 
    17641815        pjsip_tpfactory *next = factory->next; 
    1765          
     1816 
    17661817        factory->destroy(factory); 
    17671818 
     
    18051856    if (mod_msg_print.id != -1) { 
    18061857        pjsip_endpt_unregister_module(endpt, &mod_msg_print); 
     1858    } 
     1859 
     1860    if (mgr->pool) { 
     1861        pjsip_endpt_release_pool( mgr->endpt, mgr->pool ); 
    18071862    } 
    18081863 
     
    21672222        pjsip_transport_key key; 
    21682223        int key_len; 
    2169         pjsip_transport *transport = NULL; 
     2224        pjsip_transport *tp_ref = NULL; 
     2225        transport *tp_entry = NULL; 
     2226 
    21702227 
    21712228        /* If listener is specified, verify that the listener type matches 
     
    21882245            pj_memcpy(&key.rem_addr, remote, addr_len); 
    21892246 
    2190             transport = (pjsip_transport*) 
    2191                         pj_hash_get(mgr->table, &key, key_len, NULL); 
    2192         } 
    2193  
    2194         if (transport == NULL && 
     2247            tp_entry = (transport *)pj_hash_get(mgr->table, &key, key_len, 
     2248                                                NULL); 
     2249            if (tp_entry) { 
     2250                if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER) { 
     2251                    transport *tp_iter = tp_entry; 
     2252                    do { 
     2253                        if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && 
     2254                            sel->u.listener && 
     2255                            tp_iter->tp->factory == sel->u.listener) 
     2256                        { 
     2257                            tp_ref = tp_iter->tp; 
     2258                            break; 
     2259                        } 
     2260                        tp_iter = tp_iter->next; 
     2261                    } while (tp_iter != tp_entry); 
     2262                } else { 
     2263                    tp_ref = tp_entry->tp; 
     2264                } 
     2265            } 
     2266        } 
     2267 
     2268        if (tp_ref == NULL && 
    21952269            (!sel || sel->disable_connection_reuse == PJ_FALSE)) 
    21962270        { 
     
    22072281                pj_bzero(addr, addr_len); 
    22082282                key_len = sizeof(key.type) + addr_len; 
    2209                 transport = (pjsip_transport*)  
    2210                             pj_hash_get(mgr->table, &key, key_len, NULL); 
     2283                tp_entry = (transport *) pj_hash_get(mgr->table, &key, 
     2284                                                     key_len, NULL); 
     2285                if (tp_entry) { 
     2286                    tp_ref = tp_entry->tp; 
     2287                } 
    22112288            } 
    22122289            /* For datagram transports, try lookup with zero address. 
     
    22202297 
    22212298                key_len = sizeof(key.type) + addr_len; 
    2222                 transport = (pjsip_transport*) 
    2223                             pj_hash_get(mgr->table, &key, key_len, NULL); 
     2299                tp_entry = (transport *) pj_hash_get(mgr->table, &key, 
     2300                                                     key_len, NULL); 
     2301                if (tp_entry) { 
     2302                    tp_ref = tp_entry->tp; 
     2303                } 
    22242304            } 
    22252305        } 
     
    22272307        /* If transport is found and listener is specified, verify listener */ 
    22282308        else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && 
    2229                  sel->u.listener && transport->factory != sel->u.listener) 
     2309                 sel->u.listener && tp_ref->factory != sel->u.listener) 
    22302310        { 
    2231             transport = NULL; 
     2311            tp_ref = NULL; 
    22322312            /* This will cause a new transport to be created which will be a 
    22332313             * 'duplicate' of the existing transport (same type & remote addr, 
     
    22362316        } 
    22372317 
    2238         if (transport!=NULL && !transport->is_shutdown) { 
     2318        if (tp_ref!=NULL && !tp_ref->is_shutdown) { 
    22392319            /* 
    22402320             * Transport found! 
    22412321             */ 
    2242             pjsip_transport_add_ref(transport); 
     2322            pjsip_transport_add_ref(tp_ref); 
    22432323            pj_lock_release(mgr->lock); 
    2244             *tp = transport; 
    2245  
    2246             TRACE_((THIS_FILE, "Transport %s acquired", transport->obj_name)); 
     2324            *tp = tp_ref; 
     2325 
     2326            TRACE_((THIS_FILE, "Transport %s acquired", tp_ref->obj_name)); 
    22472327            return PJ_SUCCESS; 
    22482328        } 
     
    23062386    if (factory->create_transport2) { 
    23072387        status = factory->create_transport2(factory, mgr, mgr->endpt, 
    2308                                             (const pj_sockaddr*) remote,  
     2388                                            (const pj_sockaddr*) remote, 
    23092389                                            addr_len, tdata, tp); 
    23102390    } else { 
    23112391        status = factory->create_transport(factory, mgr, mgr->endpt, 
    2312                                            (const pj_sockaddr*) remote,  
     2392                                           (const pj_sockaddr*) remote, 
    23132393                                           addr_len, tp); 
    23142394    } 
    23152395    if (status == PJ_SUCCESS) { 
    2316         PJ_ASSERT_ON_FAIL(tp!=NULL,  
     2396        PJ_ASSERT_ON_FAIL(tp!=NULL, 
    23172397            {pj_lock_release(mgr->lock); return PJ_EBUG;}); 
    23182398        pjsip_transport_add_ref(*tp); 
     
    23572437 
    23582438        do { 
    2359             pjsip_transport *t = (pjsip_transport*)  
    2360                                  pj_hash_this(mgr->table, itr); 
    2361  
    2362             PJ_LOG(3, (THIS_FILE, "  %s %s (refcnt=%d%s)",  
    2363                        t->obj_name, 
    2364                        t->info, 
    2365                        pj_atomic_get(t->ref_cnt), 
    2366                        (t->idle_timer.id ? " [idle]" : ""))); 
    2367  
     2439            transport *tp_entry = (transport *) pj_hash_this(mgr->table, itr); 
     2440            if (tp_entry) { 
     2441                transport *tp_iter = tp_entry; 
     2442 
     2443                do { 
     2444                    pjsip_transport *tp_ref = tp_iter->tp; 
     2445 
     2446                    PJ_LOG(3, (THIS_FILE, "  %s %s%s%s%s(refcnt=%d%s)", 
     2447                               tp_ref->obj_name, 
     2448                               tp_ref->info, 
     2449                               (tp_ref->factory)?" listener[":"", 
     2450                               (tp_ref->factory)?tp_ref->factory->obj_name:"", 
     2451                               (tp_ref->factory)?"]":"", 
     2452                               pj_atomic_get(tp_ref->ref_cnt), 
     2453                               (tp_ref->idle_timer.id ? " [idle]" : ""))); 
     2454 
     2455                    tp_iter = tp_iter->next; 
     2456                } while (tp_iter != tp_entry); 
     2457            } 
    23682458            itr = pj_hash_next(mgr->table, itr); 
    23692459        } while (itr); 
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_loop.c

    r5535 r6002  
    377377        goto on_error; 
    378378    loop->base.key.type = PJSIP_TRANSPORT_LOOP_DGRAM; 
    379     //loop->base.key.rem_addr.sa_family = pj_AF_INET(); 
     379    loop->base.key.rem_addr.addr.sa_family = pj_AF_INET(); 
    380380    loop->base.type_name = "LOOP-DGRAM"; 
    381381    loop->base.info = "LOOP-DGRAM"; 
  • pjproject/trunk/pjsip/src/test/test.c

    r4420 r6002  
    380380    flush_events(500); 
    381381 
     382    /* Show additional info on the log. e.g: not released memory pool. */ 
     383    pj_log_set_level(4); 
     384 
    382385    /* Dumping memory pool usage */ 
    383386    PJ_LOG(3,(THIS_FILE, "Peak memory size=%u MB", 
  • pjproject/trunk/pjsip/src/test/transport_tcp_test.c

    r5311 r6002  
    3030 */ 
    3131#if PJ_HAS_TCP 
     32 
     33static pj_status_t multi_listener_test(pjsip_tpfactory *factory[], 
     34                                       unsigned num_factory, 
     35                                       pjsip_transport *tp[], 
     36                                       unsigned *num_tp) 
     37{ 
     38    pj_status_t status; 
     39    unsigned i = 0; 
     40    pj_str_t s; 
     41    pjsip_transport *tcp; 
     42    pjsip_tpfactory *tpfactory = NULL; 
     43    pj_sockaddr_in rem_addr; 
     44    pjsip_tpselector tp_sel; 
     45    unsigned ntp = 0; 
     46 
     47    for (;i<num_factory;++i) 
     48    { 
     49        /* Start TCP listener on arbitrary port. */ 
     50        status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); 
     51        if (status != PJ_SUCCESS) { 
     52            app_perror("   Error: unable to start TCP transport", status); 
     53            return -10; 
     54        } 
     55 
     56        factory[i] = tpfactory; 
     57    } 
     58 
     59    /* Get the last listener address */ 
     60    status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, 
     61                                 (pj_uint16_t)tpfactory->addr_name.port); 
     62    if (status != PJ_SUCCESS) { 
     63        app_perror("   Error: possibly invalid TCP address name", status); 
     64        return -11; 
     65    } 
     66 
     67    /* Acquire transport without selector. */ 
     68    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, 
     69                                           &rem_addr, sizeof(rem_addr), 
     70                                           NULL, &tcp); 
     71    if (status != PJ_SUCCESS || tcp == NULL) { 
     72        app_perror("   Error: unable to acquire TCP transport", status); 
     73        return -12; 
     74    } 
     75    tp[ntp++] = tcp; 
     76 
     77    /* After pjsip_endpt_acquire_transport, TCP transport must have 
     78     * reference counter 1. 
     79     */ 
     80    if (pj_atomic_get(tcp->ref_cnt) != 1) 
     81        return -13; 
     82 
     83    /* Acquire with the same remote address, should return the same tp. */ 
     84    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, 
     85                                           &rem_addr, sizeof(rem_addr), 
     86                                           NULL, &tcp); 
     87    if (status != PJ_SUCCESS || tcp == NULL) { 
     88        app_perror("   Error: unable to acquire TCP transport", status); 
     89        return -14; 
     90    } 
     91 
     92    /* Should return existing transport. */ 
     93    if (tp[ntp-1] != tcp) { 
     94        return -15; 
     95    } 
     96 
     97    /* Using the same TCP transport, it must have reference counter 2. 
     98     */ 
     99    if (pj_atomic_get(tcp->ref_cnt) != 2) 
     100        return -16; 
     101 
     102    /* Decrease the reference. */ 
     103    pjsip_transport_dec_ref(tcp); 
     104 
     105    /* Test basic transport attributes */ 
     106    status = generic_transport_test(tcp); 
     107    if (status != PJ_SUCCESS) 
     108        return status; 
     109 
     110    /* Check again that reference counter is 1. */ 
     111    if (pj_atomic_get(tcp->ref_cnt) != 1) 
     112        return -17; 
     113 
     114    /* Acquire transport test with selector. */ 
     115    pj_bzero(&tp_sel, sizeof(tp_sel)); 
     116    tp_sel.type = PJSIP_TPSELECTOR_LISTENER; 
     117    tp_sel.u.listener = factory[num_factory/2]; 
     118    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); 
     119    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, 
     120                                           &rem_addr, sizeof(rem_addr), 
     121                                           &tp_sel, &tcp); 
     122    if (status != PJ_SUCCESS) { 
     123        app_perror("   Error: unable to acquire TCP transport", status); 
     124        return -18; 
     125    } 
     126 
     127    /* The transport should have the same factory set on the selector. */ 
     128    if (tcp->factory != factory[num_factory/2]) 
     129        return -19; 
     130 
     131    /* The transport should be newly created. */ 
     132    for (i = 0; i < ntp; ++i) { 
     133        if (tp[i] == tcp) { 
     134            break; 
     135        } 
     136    } 
     137    if (i != ntp) 
     138        return -20; 
     139 
     140    tp[ntp++] = tcp; 
     141 
     142    for (i = 0; i<ntp; ++i) { 
     143        if (pj_atomic_get(tp[i]->ref_cnt) != 1) 
     144            return -21; 
     145    } 
     146    *num_tp = ntp; 
     147 
     148    return PJ_SUCCESS; 
     149} 
     150 
    32151int transport_tcp_test(void) 
    33152{ 
    34153    enum { SEND_RECV_LOOP = 8 }; 
    35     pjsip_tpfactory *tpfactory; 
    36     pjsip_transport *tcp; 
     154    enum { NUM_LISTENER = 4 }; 
     155    enum { NUM_TP = 8 }; 
     156    pjsip_tpfactory *tpfactory[NUM_LISTENER]; 
     157    pjsip_transport *tcp[NUM_TP]; 
    37158    pj_sockaddr_in rem_addr; 
    38159    pj_status_t status; 
     
    40161    char addr[PJ_INET_ADDRSTRLEN]; 
    41162    int rtt[SEND_RECV_LOOP], min_rtt; 
    42     int i, pkt_lost; 
    43  
    44     /* Start TCP listener on arbitrary port. */ 
    45     status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); 
    46     if (status != PJ_SUCCESS) { 
    47         app_perror("   Error: unable to start TCP transport", status); 
    48         return -10; 
    49     } 
    50  
    51  
    52     /* Get the listener address */ 
    53     status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, 
    54                                  (pj_uint16_t)tpfactory->addr_name.port); 
    55     if (status != PJ_SUCCESS) { 
    56         app_perror("   Error: possibly invalid TCP address name", status); 
    57         return -14; 
    58     } 
     163    int pkt_lost; 
     164    unsigned i; 
     165    unsigned num_listener = NUM_LISTENER; 
     166    unsigned num_tp = NUM_TP; 
     167 
     168    status = multi_listener_test(tpfactory, num_listener, tcp, &num_tp); 
     169    if (status != PJ_SUCCESS) 
     170        return status; 
     171 
     172    /* Get the last listener address */ 
     173    status = pj_sockaddr_in_init(&rem_addr, &tpfactory[0]->addr_name.host, 
     174                                 (pj_uint16_t)tpfactory[0]->addr_name.port); 
    59175 
    60176    pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", 
    61177                    pj_inet_ntop2(pj_AF_INET(), &rem_addr.sin_addr, addr, 
    62                                   sizeof(addr)), 
     178                                  sizeof(addr)), 
    63179                    pj_ntohs(rem_addr.sin_port)); 
    64  
    65  
    66     /* Acquire one TCP transport. */ 
    67     status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP,  
    68                                            &rem_addr, sizeof(rem_addr), 
    69                                            NULL, &tcp); 
    70     if (status != PJ_SUCCESS || tcp == NULL) { 
    71         app_perror("   Error: unable to acquire TCP transport", status); 
    72         return -17; 
    73     } 
    74  
    75     /* After pjsip_endpt_acquire_transport, TCP transport must have 
    76      * reference counter 1.  
    77      */ 
    78     if (pj_atomic_get(tcp->ref_cnt) != 1) 
    79         return -20; 
    80  
    81     /* Test basic transport attributes */ 
    82     status = generic_transport_test(tcp); 
    83     if (status != PJ_SUCCESS) 
    84         return status; 
    85  
    86  
    87     /* Check again that reference counter is 1. */ 
    88     if (pj_atomic_get(tcp->ref_cnt) != 1) 
    89         return -40; 
    90180 
    91181    /* Load test */ 
     
    95185    /* Basic transport's send/receive loopback test. */ 
    96186    for (i=0; i<SEND_RECV_LOOP; ++i) { 
    97         status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp, url, &rtt[i]); 
     187        status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp[0], url, 
     188                                          &rtt[i]); 
    98189 
    99190        if (status != 0) { 
    100             pjsip_transport_dec_ref(tcp); 
     191            for (i = 0; i < num_tp ; ++i) { 
     192                pjsip_transport_dec_ref(tcp[i]); 
     193            } 
    101194            flush_events(500); 
    102195            return -72; 
     
    116209 
    117210    /* Multi-threaded round-trip test. */ 
    118     status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp, url, &pkt_lost); 
     211    status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp[0], url, &pkt_lost); 
    119212    if (status != 0) { 
    120         pjsip_transport_dec_ref(tcp); 
     213        for (i = 0; i < num_tp ; ++i) { 
     214            pjsip_transport_dec_ref(tcp[i]); 
     215        } 
    121216        return status; 
    122217    } 
     
    126221 
    127222    /* Check again that reference counter is still 1. */ 
    128     if (pj_atomic_get(tcp->ref_cnt) != 1) 
    129         return -80; 
    130  
    131     /* Destroy this transport. */ 
    132     pjsip_transport_dec_ref(tcp); 
    133  
    134     /* Force destroy this transport. */ 
    135     status = pjsip_transport_destroy(tcp); 
    136     if (status != PJ_SUCCESS) 
    137         return -90; 
    138  
    139     /* Unregister factory */ 
    140     status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt),  
    141                                               tpfactory); 
    142     if (status != PJ_SUCCESS) 
    143         return -95; 
     223    for (i = 0; i < num_tp; ++i) { 
     224        if (pj_atomic_get(tcp[i]->ref_cnt) != 1) 
     225            return -80; 
     226    } 
     227 
     228    for (i = 0; i < num_tp; ++i) { 
     229        /* Destroy this transport. */ 
     230        pjsip_transport_dec_ref(tcp[i]); 
     231 
     232        /* Force destroy this transport. */ 
     233        status = pjsip_transport_destroy(tcp[i]); 
     234        if (status != PJ_SUCCESS) 
     235            return -90; 
     236    } 
     237 
     238    for (i = 0; i < num_listener; ++i) { 
     239        /* Unregister factory */ 
     240        status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), 
     241                                                  tpfactory[i]); 
     242        if (status != PJ_SUCCESS) 
     243            return -95; 
     244    } 
    144245 
    145246    /* Flush events. */ 
  • pjproject/trunk/pjsip/src/test/transport_udp_test.c

    r3553 r6002  
    2525#define THIS_FILE   "transport_udp_test.c" 
    2626 
     27static pj_status_t multi_transport_test(pjsip_transport *tp[], unsigned num_tp) 
     28{ 
     29    pj_status_t status; 
     30    pj_uint16_t i = 0; 
     31    pj_str_t s; 
     32    pjsip_transport *udp_tp; 
     33    pj_sockaddr_in rem_addr;     
     34    pjsip_tpselector tp_sel; 
     35 
     36    for (;i<num_tp;++i) 
     37    { 
     38        pj_sockaddr_in addr; 
     39 
     40        pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT+i); 
     41 
     42        /* Start UDP transport. */ 
     43        status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp); 
     44        if (status != PJ_SUCCESS) { 
     45            app_perror("   Error: unable to start UDP transport", status); 
     46            return -110; 
     47        } 
     48 
     49        /* UDP transport must have initial reference counter set to 1. */ 
     50        if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
     51            return -120; 
     52 
     53        /* Test basic transport attributes */ 
     54        status = generic_transport_test(udp_tp); 
     55        if (status != PJ_SUCCESS) 
     56            return status; 
     57 
     58        tp[i] = udp_tp; 
     59    } 
     60 
     61    for (i = 0; i < num_tp; ++i) { 
     62        udp_tp = tp[i]; 
     63        if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
     64            return -130; 
     65    } 
     66 
     67    /* Acquire transport test without selector. */ 
     68    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); 
     69    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, 
     70                                           &rem_addr, sizeof(rem_addr), 
     71                                           NULL, &udp_tp); 
     72    if (status != PJ_SUCCESS) 
     73        return -140; 
     74 
     75    for (i = 0; i < num_tp; ++i) { 
     76        if (udp_tp == tp[i]) { 
     77            break; 
     78        } 
     79    } 
     80    if (i == num_tp) 
     81        return -150; 
     82 
     83    pjsip_transport_dec_ref(udp_tp); 
     84 
     85    if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
     86        return -160; 
     87 
     88    /* Acquire transport test with selector. */ 
     89    pj_bzero(&tp_sel, sizeof(tp_sel)); 
     90    tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT; 
     91    tp_sel.u.transport = tp[num_tp-1]; 
     92    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); 
     93    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, 
     94                                           &rem_addr, sizeof(rem_addr), 
     95                                           &tp_sel, &udp_tp); 
     96    if (status != PJ_SUCCESS) 
     97        return -170; 
     98 
     99    if (udp_tp != tp[num_tp-1]) 
     100        return -180; 
     101 
     102    pjsip_transport_dec_ref(udp_tp); 
     103 
     104    if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
     105        return -190; 
     106 
     107    return PJ_SUCCESS; 
     108} 
    27109 
    28110/* 
     
    32114{ 
    33115    enum { SEND_RECV_LOOP = 8 }; 
    34     pjsip_transport *udp_tp, *tp; 
    35     pj_sockaddr_in addr, rem_addr; 
     116    enum { NUM_TP = 4 }; 
     117    pjsip_transport *tp[NUM_TP], *udp_tp; 
     118    pj_sockaddr_in rem_addr; 
    36119    pj_str_t s; 
    37120    pj_status_t status; 
     
    39122    int i, pkt_lost; 
    40123 
    41     pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); 
    42  
    43     /* Start UDP transport. */ 
    44     status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp); 
    45     if (status != PJ_SUCCESS) { 
    46         app_perror("   Error: unable to start UDP transport", status); 
    47         return -10; 
    48     } 
    49  
    50     /* UDP transport must have initial reference counter set to 1. */ 
    51     if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
    52         return -20; 
    53  
    54     /* Test basic transport attributes */ 
    55     status = generic_transport_test(udp_tp); 
     124    status = multi_transport_test(&tp[0], NUM_TP); 
    56125    if (status != PJ_SUCCESS) 
    57126        return status; 
    58  
    59     /* Test that transport manager is returning the correct 
    60      * transport. 
    61      */ 
    62     pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); 
    63     status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP,  
    64                                            &rem_addr, sizeof(rem_addr), 
    65                                            NULL, &tp); 
    66     if (status != PJ_SUCCESS) 
    67         return -50; 
    68     if (tp != udp_tp) 
    69         return -60; 
    70  
    71     /* pjsip_endpt_acquire_transport() adds reference, so we need 
    72      * to decrement it. 
    73      */ 
    74     pjsip_transport_dec_ref(tp); 
    75  
    76     /* Check again that reference counter is 1. */ 
    77     if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
    78         return -70; 
    79127 
    80128    /* Basic transport's send/receive loopback test. */ 
    81129    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); 
    82130    for (i=0; i<SEND_RECV_LOOP; ++i) { 
    83         status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp,  
     131        status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp[0],  
    84132                                          "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR, 
    85133                                          &rtt[i]); 
     
    99147 
    100148    /* Multi-threaded round-trip test. */ 
    101     status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp,  
     149    status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp[0],  
    102150                               "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR,  
    103151                               &pkt_lost); 
     
    108156        PJ_LOG(3,(THIS_FILE, "   note: %d packet(s) was lost", pkt_lost)); 
    109157 
    110     /* Check again that reference counter is 1. */ 
    111     if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
    112         return -80; 
     158    for (i = 0; i < NUM_TP; ++i) { 
     159        udp_tp = tp[i]; 
    113160 
    114     /* Destroy this transport. */ 
    115     pjsip_transport_dec_ref(udp_tp); 
     161        /* Check again that reference counter is 1. */ 
     162        if (pj_atomic_get(udp_tp->ref_cnt) != 1) 
     163            return -80; 
    116164 
    117     /* Force destroy this transport. */ 
    118     status = pjsip_transport_destroy(udp_tp); 
    119     if (status != PJ_SUCCESS) 
    120         return -90; 
     165        /* Destroy this transport. */ 
     166        pjsip_transport_dec_ref(udp_tp); 
     167        status = pjsip_transport_destroy(udp_tp); 
     168        if (status != PJ_SUCCESS) 
     169            return -90; 
     170    } 
    121171 
    122172    /* Flush events. */ 
Note: See TracChangeset for help on using the changeset viewer.