Changeset 563 for pjproject/trunk


Ignore:
Timestamp:
Jun 28, 2006 4:46:49 PM (18 years ago)
Author:
bennylp
Message:

Major improvements in PJSIP to support TCP. The changes fall into these categories: (1) the TCP transport implementation itself (*.[hc]), (2) bug-fix in SIP transaction when using reliable transports, (3) support for TCP transport in PJSUA-LIB/PJSUA, and (4) changes in PJSIP-TEST to support TCP testing.

Location:
pjproject/trunk
Files:
2 added
28 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/src/pj/config.c

    r503 r563  
    2222 
    2323static const char *id = "config.c"; 
    24 const char *PJ_VERSION = "0.5.6.0"; 
     24const char *PJ_VERSION = "0.5.6.1"; 
    2525 
    2626PJ_DEF(void) pj_dump_config(void) 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r544 r563  
    3030    pjsua_logging_config    log_cfg; 
    3131    pjsua_media_config      media_cfg; 
     32    pj_bool_t               no_tcp; 
     33    pj_bool_t               no_udp; 
    3234    pjsua_transport_config  udp_cfg; 
    3335    pjsua_transport_config  rtp_cfg; 
     
    9698    puts  (""); 
    9799    puts  ("Transport Options:"); 
    98     puts  ("  --local-port=port   Set TCP/UDP port"); 
     100    puts  ("  --local-port=port   Set TCP/UDP port. This implicitly enables both "); 
     101    puts  ("                      TCP and UDP transports on the specified port, unless"); 
     102    puts  ("                      if TCP or UDP is disabled."); 
     103    puts  ("  --no-tcp            Disable TCP transport."); 
     104    puts  ("  --no-udp            Disable UDP transport."); 
    99105    puts  ("  --outbound=url      Set the URL of global outbound proxy server"); 
    100106    puts  ("                      May be specified multiple times"); 
     
    240246           OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, 
    241247           OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS,  
    242            OPT_DURATION, 
     248           OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, 
    243249    }; 
    244250    struct pj_getopt_option long_options[] = { 
     
    252258        { "null-audio", 0, 0, OPT_NULL_AUDIO}, 
    253259        { "local-port", 1, 0, OPT_LOCAL_PORT}, 
     260        { "no-tcp",     0, 0, OPT_NO_TCP}, 
     261        { "no-udp",     0, 0, OPT_NO_UDP}, 
    254262        { "proxy",      1, 0, OPT_PROXY}, 
    255263        { "outbound",   1, 0, OPT_OUTBOUND_PROXY}, 
     
    385393            break; 
    386394 
     395        case OPT_NO_UDP: /* no-udp */ 
     396            if (cfg->no_tcp) { 
     397              PJ_LOG(1,(THIS_FILE,"Error: can not disable both TCP and UDP")); 
     398              return PJ_EINVAL; 
     399            } 
     400 
     401            cfg->no_udp = PJ_TRUE; 
     402            break; 
     403 
     404        case OPT_NO_TCP: /* no-tcp */ 
     405            if (cfg->no_udp) { 
     406              PJ_LOG(1,(THIS_FILE,"Error: can not disable both TCP and UDP")); 
     407              return PJ_EINVAL; 
     408            } 
     409 
     410            cfg->no_tcp = PJ_TRUE; 
     411            break; 
     412 
    387413        case OPT_PROXY:   /* proxy */ 
    388414            if (pjsua_verify_sip_url(pj_optarg) != 0) { 
     
    20472073pj_status_t app_init(int argc, char *argv[]) 
    20482074{ 
    2049     pjsua_transport_id transport_id; 
     2075    pjsua_transport_id transport_id = -1; 
    20502076    unsigned i; 
    20512077    pj_status_t status; 
     
    20972123    } 
    20982124 
    2099     /* Add UDP transport */ 
    2100     status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, 
    2101                                     &app_config.udp_cfg,  
    2102                                     &transport_id); 
    2103     if (status != PJ_SUCCESS) 
     2125 
     2126    /* Add TCP transport unless it's disabled */ 
     2127    if (!app_config.no_tcp) { 
     2128        status = pjsua_transport_create(PJSIP_TRANSPORT_TCP, 
     2129                                        &app_config.udp_cfg,  
     2130                                        &transport_id); 
     2131        if (status != PJ_SUCCESS) 
     2132            goto on_error; 
     2133 
     2134        /* Add local account */ 
     2135        pjsua_acc_add_local(transport_id, PJ_TRUE, &current_acc); 
     2136        pjsua_acc_set_online_status(current_acc, PJ_TRUE); 
     2137 
     2138    } 
     2139 
     2140 
     2141    /* Add UDP transport unless it's disabled. */ 
     2142    if (!app_config.no_udp) { 
     2143        status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, 
     2144                                        &app_config.udp_cfg,  
     2145                                        &transport_id); 
     2146        if (status != PJ_SUCCESS) 
     2147            goto on_error; 
     2148 
     2149        /* Add local account */ 
     2150        pjsua_acc_add_local(transport_id, PJ_TRUE, &current_acc); 
     2151        pjsua_acc_set_online_status(current_acc, PJ_TRUE); 
     2152    } 
     2153 
     2154    if (transport_id == -1) { 
     2155        PJ_LOG(3,(THIS_FILE, "Error: no transport is configured")); 
     2156        status = -1; 
    21042157        goto on_error; 
    2105  
    2106     /* Add local account */ 
    2107     pjsua_acc_add_local(transport_id, PJ_TRUE, &current_acc); 
    2108     pjsua_acc_set_online_status(current_acc, PJ_TRUE); 
     2158    } 
    21092159 
    21102160 
  • pjproject/trunk/pjsip/build

    • Property svn:ignore
      •  

        old new  
        1010*.sln 
        1111*.suo 
         12*.htm 
         13*.html 
  • pjproject/trunk/pjsip/build/Makefile

    r528 r563  
    2626                   $(subst /,$(HOST_PSEP),$(PJSIP_SIMPLE_LIB)) \ 
    2727                   $(subst /,$(HOST_PSEP),$(PJSIP_LIB)) \ 
    28                    $(subst /,$(HOST_PSEP),$(PJMEDIA_CODEC_LIB)) \ 
    2928                   $(subst /,$(HOST_PSEP),$(PJMEDIA_LIB)) \ 
    3029                   $(subst /,$(HOST_PSEP),$(PJLIB_UTIL_LIB)) \ 
     
    4140                sip_errno.o sip_msg.o sip_parser.o sip_tel_uri.o sip_uri.o \ 
    4241                sip_endpoint.o sip_util.o sip_util_proxy.o \ 
    43                 sip_resolve.o sip_transport.o sip_transport_loop.o sip_transport_udp.o \ 
    44                 sip_auth_client.o sip_auth_msg.o sip_auth_parser.o sip_auth_server.o \ 
     42                sip_resolve.o sip_transport.o sip_transport_loop.o \ 
     43                sip_transport_udp.o sip_transport_tcp.o \ 
     44                sip_auth_client.o sip_auth_msg.o sip_auth_parser.o \ 
     45                sip_auth_server.o \ 
    4546                sip_transaction.o sip_util_statefull.o \ 
    4647                sip_dialog.o sip_ua_layer.o 
     
    7778 
    7879export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT  
     80 
     81############################################################################### 
     82# Defines for building test application 
     83# 
     84export TEST_SRCDIR = ../src/test-pjsip 
     85export TEST_OBJS += dlg_core_test.o msg_err_test.o msg_logger.o msg_test.o \ 
     86                    test.o transport_loop_test.o transport_tcp_test.o \ 
     87                    transport_test.o transport_udp_test.o \ 
     88                    tsx_basic_test.o tsx_bench.o tsx_uac_test.o \ 
     89                    tsx_uas_test.o txdata_test.o uri_test.o 
     90export TEST_OBJS += main.o 
     91export TEST_CFLAGS += $(_CFLAGS) 
     92export TEST_LDFLAGS += $(_LDFLAGS) 
     93export TEST_EXE := ../bin/pjsip-test-$(TARGET_NAME)$(HOST_EXE) 
     94 
     95         
     96export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT  
    7997############################################################################### 
    8098# Main entry 
    8199# 
    82100# 
    83 TARGETS := pjsip pjsip-ua pjsip-simple pjsua-lib 
     101TARGETS := pjsip pjsip-ua pjsip-simple pjsua-lib pjsip-test 
    84102 
    85103.PHONY: $(TARGETS) 
     
    106124pjsua-lib:  
    107125        $(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $(PJSUA_LIB_LIB) 
     126 
     127pjsip-test: 
     128        $(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $(TEST_EXE) 
    108129 
    109130.PHONY: ../lib/pjsip.ko 
     
    132153        $(MAKE) -f $(RULES_MAK) APP=PJSIP_SIMPLE app=pjsip-simple $@ 
    133154        $(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $@ 
     155        $(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $@ 
    134156 
    135157realclean: 
     
    141163        $(MAKE) -f $(RULES_MAK) APP=PJSIP_UA app=pjsip-ua $@ 
    142164        $(MAKE) -f $(RULES_MAK) APP=PJSIP_SIMPLE app=pjsip-simple $@ 
     165        $(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $@ 
    143166        $(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $@ 
    144167 
  • pjproject/trunk/pjsip/build/test_pjsip.dsp

    r547 r563  
    118118# Begin Source File 
    119119 
     120SOURCE="..\src\test-pjsip\transport_tcp_test.c" 
     121# End Source File 
     122# Begin Source File 
     123 
    120124SOURCE="..\src\test-pjsip\transport_test.c" 
    121125# End Source File 
     
    127131 
    128132SOURCE="..\src\test-pjsip\tsx_basic_test.c" 
     133# End Source File 
     134# Begin Source File 
     135 
     136SOURCE="..\src\test-pjsip\tsx_bench.c" 
    129137# End Source File 
    130138# Begin Source File 
  • pjproject/trunk/pjsip/include/pjsip.h

    r127 r563  
    4040#include <pjsip/sip_transport_udp.h> 
    4141#include <pjsip/sip_transport_loop.h> 
     42#include <pjsip/sip_transport_tcp.h> 
    4243#include <pjsip/sip_resolve.h> 
    4344 
  • pjproject/trunk/pjsip/include/pjsip/sip_transport.h

    r550 r563  
    705705 
    706706    pjsip_transport_type_e  type;           /**< Transport type.        */ 
    707     char                    type_name[8];   /**< Type string name.      */ 
     707    char                   *type_name;      /**< Type string name.      */ 
    708708    unsigned                flag;           /**< Transport flag.        */ 
    709709 
     
    722722                                    int addr_len, 
    723723                                    pjsip_transport **transport); 
     724 
     725    /** 
     726     * Destroy the listener. 
     727     */ 
     728    pj_status_t (*destroy)(pjsip_tpfactory *factory); 
    724729 
    725730    /* 
  • pjproject/trunk/pjsip/include/pjsip/sip_transport_tcp.h

    r550 r563  
    3939 
    4040/** 
    41  * Create, register, and start TCP transport. 
     41 * The TCP incoming connection backlog number. 
     42 * Default: 5 
     43 */ 
     44#ifndef PJSIP_TCP_TRANSPORT_BACKLOG 
     45#   define PJSIP_TCP_TRANSPORT_BACKLOG  5 
     46#endif 
     47 
     48 
     49/** 
     50 * Register support for SIP TCP transport by creating TCP listener on 
     51 * the specified address and port. This function will create an 
     52 * instance of SIP TCP transport factory and register it to the 
     53 * transport manager. 
    4254 * 
    4355 * @param endpt         The SIP endpoint. 
    44  * @param local         Local address to bind. 
    45  * @param async_cnt     Number of simultaneous async operations. 
     56 * @param local         Optional local address to bind, or specify the 
     57 *                      address to bind the server socket to. Both IP  
     58 *                      interface address and port fields are optional. 
     59 *                      If IP interface address is not specified, socket 
     60 *                      will be bound to PJ_INADDR_ANY. If port is not 
     61 *                      specified, socket will be bound to any port 
     62 *                      selected by the operating system. 
     63 * @param async_cnt     Number of simultaneous asynchronous accept() 
     64 *                      operations to be supported. It is recommended that 
     65 *                      the number here corresponds to the number of 
     66 *                      processors in the system (or the number of SIP 
     67 *                      worker threads). 
     68 * @param p_factory     Optional pointer to receive the instance of the 
     69 *                      SIP TCP transport factory just created. 
    4670 * 
    4771 * @return              PJ_SUCCESS when the transport has been successfully 
     
    5175PJ_DECL(pj_status_t) pjsip_tcp_transport_start(pjsip_endpoint *endpt, 
    5276                                               const pj_sockaddr_in *local, 
    53                                                unsigned async_cnt); 
     77                                               unsigned async_cnt, 
     78                                               pjsip_tpfactory **p_factory); 
    5479 
    5580 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r503 r563  
    105105typedef struct transport_data 
    106106{ 
    107     int                  index; 
    108     pjsip_transport     *tp; 
     107    int                      index; 
     108    pjsip_transport_type_e   type; 
     109    pjsip_host_port          local_name; 
     110 
     111    union { 
     112        pjsip_transport     *tp; 
     113        pjsip_tpfactory     *factory; 
     114        void                *ptr; 
     115    } data; 
     116 
    109117} transport_data; 
    110118 
  • pjproject/trunk/pjsip/src/pjsip/sip_transaction.c

    r556 r563  
    13001300        pj_memcpy(&tsx->addr, &tsx->res_addr.addr, tsx->res_addr.addr_len); 
    13011301        tsx->addr_len = tsx->res_addr.addr_len; 
     1302        tsx->is_reliable = PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport); 
    13021303    } 
    13031304 
     
    21312132            } 
    21322133 
    2133             /* Start timer H for transaction termination */ 
    2134             pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer, 
    2135                                        &timeout_timer_val); 
     2134            /* For INVITE, start timer H for transaction termination  
     2135             * regardless whether transport is reliable or not. 
     2136             * For non-INVITE, start timer J with the value of 64*T1 for 
     2137             * non-reliable transports, and zero for reliable transports. 
     2138             */ 
     2139            if (tsx->method.id == PJSIP_INVITE_METHOD) { 
     2140                /* Start timer H for INVITE */ 
     2141                pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer, 
     2142                                           &timeout_timer_val); 
     2143            } else if (!tsx->is_reliable) { 
     2144                /* Start timer J on 64*T1 seconds for non-INVITE */ 
     2145                pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer, 
     2146                                           &timeout_timer_val); 
     2147            } else { 
     2148                /* Start timer J on zero seconds for non-INVITE */ 
     2149                pj_time_val zero_time = { 0, 0 }; 
     2150                pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer, 
     2151                                           &zero_time); 
     2152            } 
    21362153 
    21372154            /* For INVITE, if unreliable transport is used, retransmission  
  • pjproject/trunk/pjsip/src/pjsip/sip_transport.c

    r550 r563  
    3737#define THIS_FILE    "sip_transport.c" 
    3838 
     39#if 0 
     40#   define TRACE_(x)    PJ_LOG(5,x) 
     41#else 
     42#   define TRACE_(x) 
     43#endif 
     44 
    3945/* Prototype. */ 
    4046static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata); 
     
    602608    pj_lock_release(mgr->lock); 
    603609 
     610    TRACE_((THIS_FILE,"Transport %s registered: type=%s, remote=%s:%d", 
     611                       tp->obj_name, 
     612                       pjsip_transport_get_type_name(tp->key.type), 
     613                       pj_inet_ntoa(((pj_sockaddr_in*)&tp->key.rem_addr)->sin_addr), 
     614                       pj_ntohs(((pj_sockaddr_in*)&tp->key.rem_addr)->sin_port))); 
     615 
    604616    return PJ_SUCCESS; 
    605617} 
     
    610622{ 
    611623    int key_len; 
     624 
     625    TRACE_((THIS_FILE, "Transport %s is being destroyed", tp->obj_name)); 
    612626 
    613627    pj_lock_acquire(tp->lock); 
     
    627641     */ 
    628642    key_len = sizeof(tp->key.type) + tp->addr_len; 
     643    pj_assert(pj_hash_get(mgr->table, &tp->key, key_len, NULL) != NULL); 
    629644    pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, NULL); 
    630645 
     
    643658    pjsip_tpmgr *mgr; 
    644659    pj_status_t status; 
     660 
     661    TRACE_((THIS_FILE, "Transport %s shutting down", tp->obj_name)); 
    645662 
    646663    pj_lock_acquire(tp->lock); 
     
    808825    pj_hash_iterator_t itr_val; 
    809826    pj_hash_iterator_t *itr; 
     827    pjsip_tpfactory *factory; 
    810828    pjsip_endpoint *endpt = mgr->endpt; 
    811829     
     
    814832    pj_lock_acquire(mgr->lock); 
    815833 
     834    /* 
     835     * Destroy all transports. 
     836     */ 
    816837    itr = pj_hash_first(mgr->table, &itr_val); 
    817838    while (itr != NULL) { 
     
    828849    } 
    829850 
     851    /* 
     852     * Destroy all factories/listeners. 
     853     */ 
     854    factory = mgr->factory_list.next; 
     855    while (factory != &mgr->factory_list) { 
     856        pjsip_tpfactory *next = factory->next; 
     857         
     858        factory->destroy(factory); 
     859 
     860        factory = next; 
     861    } 
     862 
    830863    pj_lock_release(mgr->lock); 
    831864    pj_lock_destroy(mgr->lock); 
     
    843876    //pj_assert(pj_atomic_get(mgr->tdata_counter) == 0); 
    844877    if (pj_atomic_get(mgr->tdata_counter) != 0) { 
    845         PJ_LOG(4,(THIS_FILE, "Warning: %d transmit buffers are not freed!", 
     878        PJ_LOG(3,(THIS_FILE, "Warning: %d transmit buffer(s) not freed!", 
    846879                  pj_atomic_get(mgr->tdata_counter))); 
    847880    } 
     
    880913 
    881914    /* Process all message fragments. */ 
    882     while (total_processed < remaining_len) { 
     915    while (remaining_len > 0) { 
    883916 
    884917        pjsip_msg *msg; 
    885         pj_size_t msg_fragment_size = 0; 
     918        pj_size_t msg_fragment_size; 
    886919 
    887920        /* Initialize default fragment size. */ 
     
    10391072    pj_status_t status; 
    10401073 
     1074    TRACE_((THIS_FILE,"Acquiring transport type=%s, remote=%s:%d", 
     1075                       pjsip_transport_get_type_name(type), 
     1076                       pj_inet_ntoa(((pj_sockaddr_in*)remote)->sin_addr), 
     1077                       pj_ntohs(((pj_sockaddr_in*)remote)->sin_port))); 
     1078 
    10411079    pj_lock_acquire(mgr->lock); 
    10421080 
     
    10841122        pj_lock_release(mgr->lock); 
    10851123        *tp = transport; 
     1124 
     1125        TRACE_((THIS_FILE, "Transport %s acquired", transport->obj_name)); 
    10861126        return PJ_SUCCESS; 
    10871127    } 
     
    11011141        /* No factory can create the transport! */ 
    11021142        pj_lock_release(mgr->lock); 
     1143        TRACE_((THIS_FILE, "No suitable factory was found either")); 
    11031144        return PJSIP_EUNSUPTRANSPORT; 
    11041145    } 
     1146 
     1147    TRACE_((THIS_FILE, "%s, creating new one from factory", 
     1148           (transport?"Transport is shutdown":"No transport found"))); 
    11051149 
    11061150    /* Request factory to create transport. */ 
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_loop.c

    r315 r563  
    7474 
    7575    pool = pjsip_endpt_create_pool(loop->base.endpt, "rdata",  
    76                                    PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC); 
     76                                   PJSIP_POOL_RDATA_LEN,  
     77                                   PJSIP_POOL_RDATA_INC+5); 
    7778    if (!pool) 
    7879        return NULL; 
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c

    r554 r563  
    2121#include <pjsip/sip_errno.h> 
    2222#include <pj/compat/socket.h> 
     23#include <pj/addr_resolv.h> 
    2324#include <pj/assert.h> 
    2425#include <pj/ioqueue.h> 
     
    3435#define MAX_ASYNC_CNT   16 
    3536#define POOL_LIS_INIT   4000 
    36 #define POOL_LIS_INC    4000 
     37#define POOL_LIS_INC    4001 
    3738#define POOL_TP_INIT    4000 
    38 #define POOL_TP_INC     4000 
     39#define POOL_TP_INC     4002 
    3940 
    4041 
     
    4344 
    4445 
     46/* 
     47 * This structure is "descendant" of pj_ioqueue_op_key_t, and it is used to 
     48 * track pending/asynchronous accept() operation. TCP transport may have 
     49 * more than one pending accept() operations, depending on the value of 
     50 * async_cnt. 
     51 */ 
    4552struct pending_accept 
    4653{ 
     
    5360}; 
    5461 
    55 struct pending_connect 
    56 { 
    57     pj_ioqueue_op_key_t      op_key; 
    58     struct tcp_transport    *transport; 
    59 }; 
    60  
    61  
     62 
     63/* 
     64 * This is the TCP listener, which is a "descendant" of pjsip_tpfactory (the 
     65 * SIP transport factory). 
     66 */ 
    6267struct tcp_listener 
    6368{ 
    6469    pjsip_tpfactory          factory; 
    65     char                     name[PJ_MAX_OBJ_NAME]; 
    66     pj_bool_t                active; 
     70    char                     obj_name[PJ_MAX_OBJ_NAME]; 
     71    pj_bool_t                is_registered; 
    6772    pjsip_endpoint          *endpt; 
    6873    pjsip_tpmgr             *tpmgr; 
     
    7479 
    7580 
    76 struct pending_tdata 
    77 { 
    78     PJ_DECL_LIST_MEMBER(struct pending_tdata); 
     81/* 
     82 * This structure is used to keep delayed transmit operation in a list. 
     83 * A delayed transmission occurs when application sends tx_data when 
     84 * the TCP connect/establishment is still in progress. These delayed 
     85 * transmission will be "flushed" once the socket is connected (either 
     86 * successfully or with errors). 
     87 */ 
     88struct delayed_tdata 
     89{ 
     90    PJ_DECL_LIST_MEMBER(struct delayed_tdata); 
    7991    pjsip_tx_data_op_key    *tdata_op_key; 
    8092}; 
    8193 
    8294 
     95/* 
     96 * This structure describes the TCP transport, and it's descendant of 
     97 * pjsip_transport. 
     98 */ 
    8399struct tcp_transport 
    84100{ 
    85101    pjsip_transport          base; 
     102    pj_bool_t                is_server; 
    86103    struct tcp_listener     *listener; 
    87104    pj_bool_t                is_registered; 
    88105    pj_bool_t                is_closing; 
     106    pj_status_t              close_reason; 
    89107    pj_sock_t                sock; 
    90108    pj_ioqueue_key_t        *key; 
    91109    pj_bool_t                has_pending_connect; 
    92     struct pending_connect   connect_op; 
    93110 
    94111 
     
    100117 
    101118    /* Pending transmission list. */ 
    102     struct pending_tdata     tx_list; 
     119    struct delayed_tdata     delayed_list; 
    103120}; 
    104121 
    105122 
    106 /* 
    107  * This callback is called when #pj_ioqueue_accept completes. 
    108  */ 
     123/**************************************************************************** 
     124 * PROTOTYPES 
     125 */ 
     126 
     127/* This callback is called when pending accept() operation completes. */ 
    109128static void on_accept_complete( pj_ioqueue_key_t *key,  
    110129                                pj_ioqueue_op_key_t *op_key,  
     
    112131                                pj_status_t status); 
    113132 
    114 static pj_status_t lis_destroy(struct tcp_listener *listener); 
     133/* This callback is called by transport manager to destroy listener */ 
     134static pj_status_t lis_destroy(pjsip_tpfactory *factory); 
     135 
     136/* This callback is called by transport manager to create transport */ 
    115137static pj_status_t lis_create_transport(pjsip_tpfactory *factory, 
    116138                                        pjsip_tpmgr *mgr, 
     
    120142                                        pjsip_transport **transport); 
    121143 
    122  
    123 static pj_status_t create_tcp_transport(struct tcp_listener *listener, 
    124                                         pj_sock_t sock, 
    125                                         const pj_sockaddr_in *local, 
    126                                         const pj_sockaddr_in *remote, 
    127                                         struct tcp_transport **p_tcp); 
     144/* Common function to create and initialize transport */ 
     145static pj_status_t tcp_create(struct tcp_listener *listener, 
     146                              pj_sock_t sock, pj_bool_t is_server, 
     147                              const pj_sockaddr_in *local, 
     148                              const pj_sockaddr_in *remote, 
     149                              struct tcp_transport **p_tcp); 
    128150 
    129151 
     
    139161 
    140162 
     163static void sockaddr_to_host_port( pj_pool_t *pool, 
     164                                   pjsip_host_port *host_port, 
     165                                   const pj_sockaddr_in *addr ) 
     166{ 
     167    host_port->host.ptr = pj_pool_alloc(pool, 48); 
     168    host_port->host.slen = pj_ansi_sprintf( host_port->host.ptr, "%s",  
     169                                            pj_inet_ntoa(addr->sin_addr)); 
     170    host_port->port = pj_ntohs(addr->sin_port); 
     171} 
     172 
     173 
     174 
     175/**************************************************************************** 
     176 * The TCP listener/transport factory. 
     177 */ 
     178 
     179/* 
     180 * This is the public API to create, initialize, register, and start the 
     181 * TCP listener. 
     182 */ 
    141183PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt, 
    142184                                               const pj_sockaddr_in *local, 
    143                                                unsigned async_cnt) 
     185                                               unsigned async_cnt, 
     186                                               pjsip_tpfactory **p_factory) 
    144187{ 
    145188    pj_pool_t *pool; 
    146189    struct tcp_listener *listener; 
    147190    pj_ioqueue_callback listener_cb; 
     191    pj_sockaddr_in *listener_addr; 
     192    int addr_len; 
    148193    unsigned i; 
    149194    pj_status_t status; 
    150195 
    151196    /* Sanity check */ 
    152     PJ_ASSERT_RETURN(endpt && local && async_cnt, PJ_EINVAL); 
     197    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); 
    153198 
    154199 
     
    159204 
    160205    listener = pj_pool_zalloc(pool, sizeof(struct tcp_listener)); 
    161     pj_ansi_sprintf(listener->name, "tcp:%d", (int)pj_ntohs(local->sin_port)); 
    162206    listener->factory.pool = pool; 
    163207    listener->factory.type = PJSIP_TRANSPORT_TCP; 
    164     pj_ansi_strcpy(listener->factory.type_name, "tcp"); 
     208    listener->factory.type_name = "tcp"; 
    165209    listener->factory.flag =  
    166210        pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP); 
    167211    listener->sock = PJ_INVALID_SOCKET; 
     212 
     213    pj_ansi_strcpy(listener->obj_name, "tcp"); 
    168214 
    169215    status = pj_lock_create_recursive_mutex(pool, "tcplis",  
     
    178224        goto on_error; 
    179225 
    180     pj_memcpy(&listener->factory.local_addr, local, sizeof(pj_sockaddr_in)); 
    181     status = pj_sock_bind(listener->sock, local, sizeof(*local)); 
     226    listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr; 
     227    if (local) { 
     228        pj_memcpy(listener_addr, local, sizeof(pj_sockaddr_in)); 
     229    } else { 
     230        pj_sockaddr_in_init(listener_addr, NULL, 0); 
     231    } 
     232 
     233    status = pj_sock_bind(listener->sock, listener_addr,  
     234                          sizeof(pj_sockaddr_in)); 
    182235    if (status != PJ_SUCCESS) 
    183236        goto on_error; 
     237 
     238    /* Retrieve the bound address */ 
     239    addr_len = sizeof(pj_sockaddr_in); 
     240    status = pj_sock_getsockname(listener->sock, listener_addr, &addr_len); 
     241    if (status != PJ_SUCCESS) 
     242        goto on_error; 
     243 
     244    /* If the address returns 0.0.0.0, use the first interface address 
     245     * as the transport's address. 
     246     */ 
     247    if (listener_addr->sin_addr.s_addr == 0) { 
     248        const pj_str_t *hostname; 
     249        struct pj_hostent he; 
     250 
     251        hostname = pj_gethostname(); 
     252        status = pj_gethostbyname(hostname, &he); 
     253        if (status != PJ_SUCCESS) 
     254            goto on_error; 
     255 
     256        listener_addr->sin_addr = *(pj_in_addr*)he.h_addr; 
     257    } 
     258 
     259    pj_ansi_sprintf(listener->obj_name, "tcp:%d",  
     260                     (int)pj_ntohs(listener_addr->sin_port)); 
     261 
     262    /* Save the address name */ 
     263    sockaddr_to_host_port(listener->factory.pool,  
     264                          &listener->factory.addr_name, listener_addr); 
     265 
     266    /* Start listening to the address */ 
     267    status = pj_sock_listen(listener->sock, PJSIP_TCP_TRANSPORT_BACKLOG); 
     268    if (status != PJ_SUCCESS) 
     269        goto on_error; 
     270 
    184271 
    185272    /* Register socket to ioqeuue */ 
     
    192279        goto on_error; 
    193280 
    194     /* Start pending accept() operation */ 
     281    /* Register to transport manager */ 
     282    listener->endpt = endpt; 
     283    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); 
     284    listener->factory.create_transport = lis_create_transport; 
     285    listener->factory.destroy = lis_destroy; 
     286    listener->is_registered = PJ_TRUE; 
     287    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, 
     288                                            &listener->factory); 
     289    if (status != PJ_SUCCESS) { 
     290        listener->is_registered = PJ_FALSE; 
     291        goto on_error; 
     292    } 
     293 
     294 
     295    /* Start pending accept() operations */ 
    195296    if (async_cnt > MAX_ASYNC_CNT) async_cnt = MAX_ASYNC_CNT; 
    196297    listener->async_cnt = async_cnt; 
     
    201302        listener->accept_op[i].listener = listener; 
    202303 
    203         status = pj_ioqueue_accept(listener->key,  
    204                                    &listener->accept_op[i].op_key, 
    205                                    &listener->accept_op[i].new_sock, 
    206                                    &listener->accept_op[i].local_addr, 
    207                                    &listener->accept_op[i].remote_addr, 
    208                                    &listener->accept_op[i].addr_len); 
    209         if (status != PJ_SUCCESS && status != PJ_EPENDING) 
    210             goto on_error; 
    211     } 
    212  
    213     /* Register to transport manager */ 
    214     listener->endpt = endpt; 
    215     listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); 
    216     listener->factory.create_transport = lis_create_transport; 
    217     status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, 
    218                                             &listener->factory); 
    219     if (status != PJ_SUCCESS) 
    220         goto on_error; 
    221  
    222     /* Done! */ 
    223     listener->active = PJ_TRUE; 
    224  
    225     PJ_LOG(4,(listener->name,  
    226              "SIP TCP transport listening for incoming connections at %s:%d", 
    227              pj_inet_ntoa(local->sin_addr), (int)pj_ntohs(local->sin_port))); 
     304        on_accept_complete(listener->key, &listener->accept_op[i].op_key, 
     305                           listener->sock, PJ_EPENDING); 
     306    } 
     307 
     308    PJ_LOG(4,(listener->obj_name,  
     309             "SIP TCP listener ready for incoming connections at %s:%d", 
     310             pj_inet_ntoa(listener_addr->sin_addr),  
     311             (int)pj_ntohs(listener_addr->sin_port))); 
     312 
     313    /* Return the pointer to user */ 
     314    if (p_factory) *p_factory = &listener->factory; 
    228315 
    229316    return PJ_SUCCESS; 
    230317 
    231318on_error: 
    232     lis_destroy(listener); 
     319    lis_destroy(&listener->factory); 
    233320    return status; 
    234321} 
    235322 
    236323 
    237 static pj_status_t lis_destroy(struct tcp_listener *listener) 
    238 { 
    239     if (listener->active) { 
     324/* This callback is called by transport manager to destroy listener */ 
     325static pj_status_t lis_destroy(pjsip_tpfactory *factory) 
     326{ 
     327    struct tcp_listener *listener = (struct tcp_listener *)factory; 
     328 
     329    if (listener->is_registered) { 
    240330        pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory); 
    241         listener->active = PJ_FALSE; 
     331        listener->is_registered = PJ_FALSE; 
    242332    } 
    243333 
     
    259349 
    260350    if (listener->factory.pool) { 
    261         PJ_LOG(4,(listener->name,  "SIP TCP transport destroyed")); 
    262         pj_pool_release(listener->factory.pool); 
     351        pj_pool_t *pool = listener->factory.pool; 
     352 
     353        PJ_LOG(4,(listener->obj_name,  "SIP TCP listener destroyed")); 
     354 
    263355        listener->factory.pool = NULL; 
     356        pj_pool_release(pool); 
    264357    } 
    265358 
     
    289382static pj_status_t tcp_shutdown(pjsip_transport *transport); 
    290383 
    291 /* Called by transport manager to destroy */ 
    292 static pj_status_t tcp_destroy(pjsip_transport *transport); 
     384/* Called by transport manager to destroy transport */ 
     385static pj_status_t tcp_destroy_transport(pjsip_transport *transport); 
     386 
     387/* Utility to destroy transport */ 
     388static pj_status_t tcp_destroy(pjsip_transport *transport, 
     389                               pj_status_t reason); 
    293390 
    294391/* Callback from ioqueue on incoming packet */ 
     
    307404 
    308405 
    309 static void sockaddr_to_host_port( pj_pool_t *pool, 
    310                                    pjsip_host_port *host_port, 
    311                                    const pj_sockaddr_in *addr ) 
    312 { 
    313     host_port->host.ptr = pj_pool_alloc(pool, 48); 
    314     host_port->host.slen = pj_ansi_sprintf( host_port->host.ptr, "%s",  
    315                                             pj_inet_ntoa(addr->sin_addr)); 
    316     host_port->port = pj_ntohs(addr->sin_port); 
    317 } 
    318  
    319  
    320406/* 
    321  * Utilities to create TCP transport. 
    322  */ 
    323 static pj_status_t create_tcp_transport(struct tcp_listener *listener, 
    324                                         pj_sock_t sock, 
    325                                         const pj_sockaddr_in *local, 
    326                                         const pj_sockaddr_in *remote, 
    327                                         struct tcp_transport **p_tcp) 
     407 * Common function to create TCP transport, called when pending accept() and 
     408 * pending connect() complete. 
     409 */ 
     410static pj_status_t tcp_create( struct tcp_listener *listener, 
     411                               pj_sock_t sock, pj_bool_t is_server, 
     412                               const pj_sockaddr_in *local, 
     413                               const pj_sockaddr_in *remote, 
     414                               struct tcp_transport **p_tcp) 
    328415{ 
    329416    struct tcp_transport *tcp; 
     
    333420    pj_status_t status; 
    334421     
    335     pool = pjsip_endpt_create_pool(listener->endpt, "tcp",  
     422 
     423    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_EINVAL); 
     424 
     425 
     426    pool = pjsip_endpt_create_pool(listener->endpt, "tcp", 
    336427                                   POOL_TP_INIT, POOL_TP_INC); 
     428    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); 
    337429     
     430 
    338431    /* 
    339432     * Create and initialize basic transport structure. 
     
    341434    tcp = pj_pool_zalloc(pool, sizeof(*tcp)); 
    342435    tcp->sock = sock; 
     436    tcp->is_server = is_server; 
    343437    tcp->listener = listener; 
    344     pj_list_init(&tcp->tx_list); 
    345  
    346  
    347     pj_ansi_snprintf(tcp->base.obj_name, PJ_MAX_OBJ_NAME, "tcp%p", tcp); 
     438    pj_list_init(&tcp->delayed_list); 
    348439    tcp->base.pool = pool; 
    349440 
     441    pj_ansi_snprintf(tcp->base.obj_name, PJ_MAX_OBJ_NAME,  
     442                     (is_server ? "tcps%p" :"tcpc%p"), tcp); 
     443 
    350444    status = pj_atomic_create(pool, 0, &tcp->base.ref_cnt); 
    351     if (status != PJ_SUCCESS) 
     445    if (status != PJ_SUCCESS) { 
    352446        goto on_error; 
     447    } 
    353448 
    354449    status = pj_lock_create_recursive_mutex(pool, "tcp", &tcp->base.lock); 
    355     if (status != PJ_SUCCESS) 
     450    if (status != PJ_SUCCESS) { 
    356451        goto on_error; 
     452    } 
    357453 
    358454    tcp->base.key.type = PJSIP_TRANSPORT_TCP; 
     
    375471    tcp->base.send_msg = &tcp_send_msg; 
    376472    tcp->base.do_shutdown = &tcp_shutdown; 
    377     tcp->base.destroy = &tcp_destroy; 
     473    tcp->base.destroy = &tcp_destroy_transport; 
    378474 
    379475 
     
    387483    status = pj_ioqueue_register_sock(pool, ioqueue, sock,  
    388484                                      tcp, &tcp_callback, &tcp->key); 
    389     if (status != PJ_SUCCESS) 
     485    if (status != PJ_SUCCESS) { 
    390486        goto on_error; 
     487    } 
    391488 
    392489    /* Register transport to transport manager */ 
    393490    status = pjsip_transport_register(listener->tpmgr, &tcp->base); 
    394     if (status != PJ_SUCCESS) 
     491    if (status != PJ_SUCCESS) { 
    395492        goto on_error; 
     493    } 
    396494 
    397495    tcp->is_registered = PJ_TRUE; 
     
    400498    *p_tcp = tcp; 
    401499 
     500    PJ_LOG(4,(tcp->base.obj_name, "TCP %s transport created", 
     501              (tcp->is_server ? "server" : "client"))); 
     502 
     503    return PJ_SUCCESS; 
     504 
    402505on_error: 
    403     tcp_destroy(&tcp->base); 
     506    tcp_destroy(&tcp->base, status); 
    404507    return status; 
    405508} 
    406509 
    407510 
    408 /* Flush all pending send operations */ 
    409 static tcp_flush_pending_tx(struct tcp_transport *tcp) 
     511/* Flush all delayed transmision once the socket is connected. */ 
     512static void tcp_flush_pending_tx(struct tcp_transport *tcp) 
    410513{ 
    411514    pj_lock_acquire(tcp->base.lock); 
    412     while (!pj_list_empty(&tcp->tx_list)) { 
    413         struct pending_tdata *pending_tx; 
     515    while (!pj_list_empty(&tcp->delayed_list)) { 
     516        struct delayed_tdata *pending_tx; 
    414517        pjsip_tx_data *tdata; 
    415518        pj_ioqueue_op_key_t *op_key; 
     
    417520        pj_status_t status; 
    418521 
    419         pending_tx = tcp->tx_list.next; 
     522        pending_tx = tcp->delayed_list.next; 
    420523        pj_list_erase(pending_tx); 
    421524 
     
    437540 
    438541 
     542/* Called by transport manager to destroy transport */ 
     543static pj_status_t tcp_destroy_transport(pjsip_transport *transport) 
     544{ 
     545    struct tcp_transport *tcp = (struct tcp_transport*)transport; 
     546 
     547    /* Transport would have been unregistered by now since this callback 
     548     * is called by transport manager. 
     549     */ 
     550    tcp->is_registered = PJ_FALSE; 
     551 
     552    return tcp_destroy(transport, tcp->close_reason); 
     553} 
     554 
    439555 
    440556/* Destroy TCP transport */ 
    441 static pj_status_t tcp_destroy(pjsip_transport *transport) 
     557static pj_status_t tcp_destroy(pjsip_transport *transport,  
     558                               pj_status_t reason) 
    442559{ 
    443560    struct tcp_transport *tcp = (struct tcp_transport*)transport; 
    444561 
    445     /* Cancel all pending transmits */ 
    446     while (!pj_list_empty(&tcp->tx_list)) { 
    447         struct pending_tdata *pending_tx; 
     562    if (tcp->close_reason == 0) 
     563        tcp->close_reason = reason; 
     564 
     565    if (tcp->is_registered) { 
     566        tcp->is_registered = PJ_FALSE; 
     567        pjsip_transport_destroy(transport); 
     568 
     569        /* pjsip_transport_destroy will recursively call this function 
     570         * again. 
     571         */ 
     572        return PJ_SUCCESS; 
     573    } 
     574 
     575    /* Mark transport as closing */ 
     576    tcp->is_closing = PJ_TRUE; 
     577 
     578    /* Cancel all delayed transmits */ 
     579    while (!pj_list_empty(&tcp->delayed_list)) { 
     580        struct delayed_tdata *pending_tx; 
    448581        pj_ioqueue_op_key_t *op_key; 
    449582 
    450         pending_tx = tcp->tx_list.next; 
     583        pending_tx = tcp->delayed_list.next; 
    451584        pj_list_erase(pending_tx); 
    452585 
    453586        op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key; 
    454587 
    455         on_write_complete(tcp->key, op_key,  
    456                           -PJ_RETURN_OS_ERROR(OSERR_ENOTCONN)); 
    457     } 
    458  
    459     if (tcp->is_registered) { 
    460         pjsip_transport_destroy(transport); 
    461         tcp->is_registered = PJ_FALSE; 
     588        on_write_complete(tcp->key, op_key, -reason); 
    462589    } 
    463590 
     
    470597        pj_ioqueue_unregister(tcp->key); 
    471598        tcp->key = NULL; 
     599        tcp->sock = PJ_INVALID_SOCKET; 
     600    } 
     601 
     602    if (tcp->sock != PJ_INVALID_SOCKET) { 
     603        pj_sock_close(tcp->sock); 
     604        tcp->sock = PJ_INVALID_SOCKET; 
    472605    } 
    473606 
     
    483616 
    484617    if (tcp->base.pool) { 
    485         PJ_LOG(4,(tcp->base.obj_name, "TCP transport destroyed")); 
    486         pj_pool_release(tcp->base.pool); 
     618        pj_pool_t *pool; 
     619 
     620        if (reason != PJ_SUCCESS) { 
     621            char errmsg[PJ_ERR_MSG_SIZE]; 
     622 
     623            pj_strerror(reason, errmsg, sizeof(errmsg)); 
     624            PJ_LOG(4,(tcp->base.obj_name,  
     625                      "TCP transport destroyed with reason %d: %s",  
     626                      reason, errmsg)); 
     627 
     628        } else { 
     629 
     630            PJ_LOG(4,(tcp->base.obj_name,  
     631                      "TCP transport destroyed normally")); 
     632 
     633        } 
     634 
     635        pool = tcp->base.pool; 
    487636        tcp->base.pool = NULL; 
     637        pj_pool_release(pool); 
    488638    } 
    489639 
     
    494644/* 
    495645 * This utility function creates receive data buffers and start 
    496  * asynchronous recv() operations from the socket. 
     646 * asynchronous recv() operations from the socket. It is called after 
     647 * accept() or connect() operation complete. 
    497648 */ 
    498649static pj_status_t tcp_start_read(struct tcp_transport *tcp) 
     
    532683                             tcp->rdata.pkt_info.packet, &size, 
    533684                             PJ_IOQUEUE_ALWAYS_ASYNC); 
    534     if (status != PJ_SUCCESS) { 
     685    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    535686        tcp_perror(tcp->base.obj_name, "ioqueue recv() error", status); 
    536687        return status; 
     
    594745 
    595746    /* Create the transport descriptor */ 
    596     status = create_tcp_transport(listener, sock, &local_addr,  
    597                                   (pj_sockaddr_in*)rem_addr, &tcp); 
     747    status = tcp_create(listener, sock, PJ_FALSE, &local_addr,  
     748                        (pj_sockaddr_in*)rem_addr, &tcp); 
    598749    if (status != PJ_SUCCESS) 
    599750        return status; 
    600          
     751 
     752 
    601753    /* Start asynchronous connect() operation */ 
    602754    tcp->has_pending_connect = PJ_TRUE; 
    603     pj_ioqueue_op_key_init(&tcp->connect_op.op_key,  
    604                            sizeof(tcp->connect_op.op_key)); 
    605     tcp->connect_op.transport = tcp; 
    606755    status = pj_ioqueue_connect(tcp->key, rem_addr, sizeof(pj_sockaddr_in)); 
    607     if (status != PJ_SUCCESS) { 
    608         tcp_destroy(&tcp->base); 
     756    if (status == PJ_SUCCESS) { 
     757        tcp->has_pending_connect = PJ_FALSE; 
     758    } else if (status != PJ_EPENDING) { 
     759        tcp_destroy(&tcp->base, status); 
    609760        return status; 
    610761    } 
     
    630781    } 
    631782 
     783    if (tcp->has_pending_connect) { 
     784        PJ_LOG(4,(tcp->base.obj_name,  
     785                  "TCP transport %.*s:%d is connecting to %.*s:%d...", 
     786                  (int)tcp->base.local_name.host.slen, 
     787                  tcp->base.local_name.host.ptr, 
     788                  tcp->base.local_name.port, 
     789                  (int)tcp->base.remote_name.host.slen, 
     790                  tcp->base.remote_name.host.ptr, 
     791                  tcp->base.remote_name.port)); 
     792    } 
     793 
    632794    /* Done */ 
    633795    *p_transport = &tcp->base; 
     
    654816    accept_op = (struct pending_accept*) op_key; 
    655817 
     818    /* 
     819     * Loop while there is immediate connection or when there is error. 
     820     */ 
    656821    do { 
    657         if (status != PJ_SUCCESS) { 
    658             tcp_perror(listener->name, "Error in accept()", status); 
    659  
     822        if (status == PJ_EPENDING) { 
     823            /* 
     824             * This can only happen when this function is called during 
     825             * initialization to kick off asynchronous accept(). 
     826             */ 
     827 
     828        } else if (status != PJ_SUCCESS) { 
     829 
     830            /* 
     831             * Error in accept(). 
     832             */ 
     833            tcp_perror(listener->obj_name, "Error in accept()", status); 
     834 
     835            /* 
     836             * Prevent endless accept() error loop by limiting the 
     837             * number of consecutive errors. Once the number of errors 
     838             * is equal to maximum, we treat this as permanent error, and 
     839             * we stop the accept() operation. 
     840             */ 
    660841            ++err_cnt; 
    661             if (err_cnt >= 5) { 
    662                 PJ_LOG(1, (listener->name,  
     842            if (err_cnt >= 10) { 
     843                PJ_LOG(1, (listener->obj_name,  
    663844                           "Too many errors, listener stopping")); 
    664845            } 
    665846 
    666             goto start_next_accept; 
    667         } 
    668  
    669         status = create_tcp_transport( listener, sock,  
    670                                        &accept_op->local_addr,  
    671                                        &accept_op->remote_addr, &tcp); 
    672         if (status == PJ_SUCCESS) { 
    673             status = tcp_start_read(tcp); 
    674             if (status != PJ_SUCCESS) { 
    675                 PJ_LOG(3,(tcp->base.obj_name, "New transport cancelled")); 
    676                 tcp_destroy(&tcp->base); 
     847        } else { 
     848 
     849            if (sock == PJ_INVALID_SOCKET) { 
     850                sock = accept_op->new_sock; 
     851                PJ_LOG(4,(listener->obj_name,  
     852                          "Warning: ioqueue reports -1 in on_accept_complete()" 
     853                          " sock argument")); 
     854            } 
     855 
     856            PJ_LOG(4,(listener->obj_name,  
     857                      "TCP listener %.*s:%d: got incoming TCP connection " 
     858                      "from %s:%d, sock=%d", 
     859                      (int)listener->factory.addr_name.host.slen, 
     860                      listener->factory.addr_name.host.ptr, 
     861                      listener->factory.addr_name.port, 
     862                      pj_inet_ntoa(accept_op->remote_addr.sin_addr), 
     863                      pj_ntohs(accept_op->remote_addr.sin_port), 
     864                      sock)); 
     865 
     866            /*  
     867             * Incoming connections! 
     868             * Create TCP transport for the new socket. 
     869             */ 
     870            status = tcp_create( listener, sock, PJ_TRUE, 
     871                                 &accept_op->local_addr,  
     872                                 &accept_op->remote_addr, &tcp); 
     873            if (status == PJ_SUCCESS) { 
     874                status = tcp_start_read(tcp); 
     875                if (status != PJ_SUCCESS) { 
     876                    PJ_LOG(3,(tcp->base.obj_name, "New transport cancelled")); 
     877                    tcp_destroy(&tcp->base, status); 
     878                } 
    677879            } 
    678880        } 
    679881 
    680 start_next_accept: 
     882        /* 
     883         * Start the next asynchronous accept() operation. 
     884         */ 
     885        accept_op->addr_len = sizeof(pj_sockaddr_in); 
     886        accept_op->new_sock = PJ_INVALID_SOCKET; 
    681887 
    682888        status = pj_ioqueue_accept(listener->key,  
     
    687893                                   &accept_op->addr_len); 
    688894 
     895        /* 
     896         * Loop while we have immediate connection or when there is error. 
     897         */ 
     898 
    689899    } while (status != PJ_EPENDING); 
    690900} 
    691901 
    692902 
    693 /* Callback from ioqueue when packet is sent */ 
     903/*  
     904 * Callback from ioqueue when packet is sent. 
     905 */ 
    694906static void on_write_complete(pj_ioqueue_key_t *key,  
    695907                              pj_ioqueue_op_key_t *op_key,  
    696908                              pj_ssize_t bytes_sent) 
    697909{ 
    698     struct tcp_transport *tp = pj_ioqueue_get_user_data(key); 
     910    struct tcp_transport *tcp = pj_ioqueue_get_user_data(key); 
    699911    pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key; 
    700912 
    701913    tdata_op_key->tdata = NULL; 
    702914 
     915    /* Check for error/closure */ 
     916    if (bytes_sent <= 0) { 
     917        pj_status_t status; 
     918 
     919        PJ_LOG(5,(tcp->base.obj_name, "TCP send() error, sent=%d",  
     920                  bytes_sent)); 
     921 
     922        status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) : 
     923                                     -bytes_sent; 
     924        if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status; 
     925        pjsip_transport_shutdown(&tcp->base); 
     926    } 
     927 
    703928    if (tdata_op_key->callback) { 
    704         tdata_op_key->callback(&tp->base, tdata_op_key->token, bytes_sent); 
    705     } 
    706 } 
    707  
    708  
    709 /* This callback is called by transport manager to send SIP message */ 
     929        /* 
     930         * Notify sip_transport.c that packet has been sent. 
     931         */ 
     932        tdata_op_key->callback(&tcp->base, tdata_op_key->token, bytes_sent); 
     933    } 
     934} 
     935 
     936 
     937/*  
     938 * This callback is called by transport manager to send SIP message  
     939 */ 
    710940static pj_status_t tcp_send_msg(pjsip_transport *transport,  
    711941                                pjsip_tx_data *tdata, 
     
    719949    struct tcp_transport *tcp = (struct tcp_transport*)transport; 
    720950    pj_ssize_t size; 
    721     pj_status_t status; 
     951    pj_bool_t delayed = PJ_FALSE; 
     952    pj_status_t status = PJ_SUCCESS; 
    722953 
    723954    /* Sanity check */ 
     
    738969 
    739970    /* If asynchronous connect() has not completed yet, just put the 
    740      * transmit data in the pending transmission list. 
     971     * transmit data in the pending transmission list since we can not 
     972     * use the socket yet. 
    741973     */ 
    742     pj_lock_acquire(tcp->base.lock); 
    743  
    744974    if (tcp->has_pending_connect) { 
    745         struct pending_tdata *pending_tdata; 
    746  
    747         /* Pust to list */ 
    748         pending_tdata = pj_pool_alloc(tdata->pool, sizeof(*pending_tdata)); 
    749         pending_tdata->tdata_op_key = &tdata->op_key; 
    750  
    751         pj_list_push_back(&tcp->tx_list, pending_tdata); 
    752         status = PJ_EPENDING; 
    753  
    754     } else { 
    755         /* send to ioqueue! */ 
     975 
     976        /* 
     977         * Looks like connect() is still in progress. Check again (this time 
     978         * with holding the lock) to be sure. 
     979         */ 
     980        pj_lock_acquire(tcp->base.lock); 
     981 
     982        if (tcp->has_pending_connect) { 
     983            struct delayed_tdata *delayed_tdata; 
     984 
     985            /* 
     986             * connect() is still in progress. Put the transmit data to 
     987             * the delayed list. 
     988             */ 
     989            delayed_tdata = pj_pool_alloc(tdata->pool,  
     990                                          sizeof(*delayed_tdata)); 
     991            delayed_tdata->tdata_op_key = &tdata->op_key; 
     992 
     993            pj_list_push_back(&tcp->delayed_list, delayed_tdata); 
     994            status = PJ_EPENDING; 
     995 
     996            /* Prevent pj_ioqueue_send() to be called below */ 
     997            delayed = PJ_TRUE; 
     998        } 
     999 
     1000        pj_lock_release(tcp->base.lock); 
     1001    }  
     1002     
     1003    if (!delayed) { 
     1004        /* 
     1005         * Transport is ready to go. Send the packet to ioqueue to be 
     1006         * sent asynchronously. 
     1007         */ 
    7561008        size = tdata->buf.cur - tdata->buf.start; 
    7571009        status = pj_ioqueue_send(tcp->key,  
     
    7591011                                 tdata->buf.start, &size, 0); 
    7601012 
    761         if (status != PJ_EPENDING) 
     1013        if (status != PJ_EPENDING) { 
     1014            /* Not pending (could be immediate success or error) */ 
    7621015            tdata->op_key.tdata = NULL; 
    763     } 
    764  
    765     pj_lock_release(tcp->base.lock); 
     1016 
     1017            /* Shutdown transport on closure/errors */ 
     1018            if (size <= 0) { 
     1019 
     1020                PJ_LOG(5,(tcp->base.obj_name, "TCP send() error, sent=%d",  
     1021                          size)); 
     1022 
     1023                if (status == PJ_SUCCESS)  
     1024                    status = PJ_RETURN_OS_ERROR(OSERR_ENOTCONN); 
     1025                if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status; 
     1026                pjsip_transport_shutdown(&tcp->base); 
     1027            } 
     1028        } 
     1029    } 
    7661030 
    7671031    return status; 
     
    7691033 
    7701034 
    771 /* This callback is called by transport manager to shutdown transport */ 
     1035/*  
     1036 * This callback is called by transport manager to shutdown transport. 
     1037 * This normally is only used by UDP transport. 
     1038 */ 
    7721039static pj_status_t tcp_shutdown(pjsip_transport *transport) 
    7731040{ 
     
    7801047 
    7811048 
    782 /* Callback from ioqueue on incoming packet */ 
     1049/*  
     1050 * Callback from ioqueue that an incoming data is received from the socket. 
     1051 */ 
    7831052static void on_read_complete(pj_ioqueue_key_t *key,  
    7841053                             pj_ioqueue_op_key_t *op_key,  
     
    7881057    pjsip_rx_data_op_key *rdata_op_key = (pjsip_rx_data_op_key*) op_key; 
    7891058    pjsip_rx_data *rdata = rdata_op_key->rdata; 
    790     struct tcp_transport *tp = (struct tcp_transport*)rdata->tp_info.transport; 
     1059    struct tcp_transport *tcp =  
     1060        (struct tcp_transport*)rdata->tp_info.transport; 
    7911061    int i; 
    7921062    pj_status_t status; 
    7931063 
    7941064    /* Don't do anything if transport is closing. */ 
    795     if (tp->is_closing) { 
    796         tp->is_closing++; 
     1065    if (tcp->is_closing) { 
     1066        tcp->is_closing++; 
    7971067        return; 
    7981068    } 
     
    8071077        pj_uint32_t flags; 
    8081078 
    809         /* Report the packet to transport manager. */ 
     1079        /* Houston, we have packet! Report the packet to transport manager 
     1080         * to be parsed. 
     1081         */ 
    8101082        if (bytes_read > 0) { 
    8111083            pj_size_t size_eaten; 
     
    8161088            pj_gettimeofday(&rdata->pkt_info.timestamp); 
    8171089 
     1090            /* Report to transport manager. 
     1091             * The transport manager will tell us how many bytes of the packet 
     1092             * have been processed (as valid SIP message). 
     1093             */ 
    8181094            size_eaten =  
    8191095                pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr,  
     
    8341110 
    8351111            /* Transport is closed */ 
    836             PJ_LOG(4,(tp->base.obj_name, "tcp connection closed")); 
    837             tcp_destroy(&tp->base); 
     1112            PJ_LOG(4,(tcp->base.obj_name, "TCP connection closed")); 
     1113             
     1114            /* We can not destroy the transport since high level objects may 
     1115             * still keep reference to this transport. So we can only  
     1116             * instruct transport manager to gracefully start the shutdown 
     1117             * procedure for this transport. 
     1118             */ 
     1119            if (tcp->close_reason==PJ_SUCCESS)  
     1120                tcp->close_reason = PJ_RETURN_OS_ERROR(OSERR_ENOTCONN); 
     1121            pjsip_transport_shutdown(&tcp->base); 
     1122 
    8381123            return; 
    8391124 
    840         } else if (bytes_read < 0)  { 
     1125        //} else if (bytes_read < 0)  { 
     1126        } else if (-bytes_read != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) && 
     1127                   -bytes_read != PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) &&  
     1128                   -bytes_read != PJ_STATUS_FROM_OS(OSERR_ECONNRESET))  
     1129        { 
    8411130 
    8421131            /* Report error to endpoint. */ 
    8431132            PJSIP_ENDPT_LOG_ERROR((rdata->tp_info.transport->endpt, 
    8441133                                   rdata->tp_info.transport->obj_name, 
    845                                    -bytes_read, "tcp recv() error")); 
    846  
    847             /* Transport error, close transport */ 
    848             tcp_destroy(&tp->base); 
     1134                                   -bytes_read, "TCP recv() error")); 
     1135 
     1136            /* We can not destroy the transport since high level objects may 
     1137             * still keep reference to this transport. So we can only  
     1138             * instruct transport manager to gracefully start the shutdown 
     1139             * procedure for this transport. 
     1140             */ 
     1141            if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = -bytes_read; 
     1142            pjsip_transport_shutdown(&tcp->base); 
     1143 
    8491144            return; 
    8501145        } 
    8511146 
    8521147        if (i >= MAX_IMMEDIATE_PACKET) { 
    853             /* Force ioqueue_recv() to return PJ_EPENDING */ 
     1148            /* Receive quota reached. Force ioqueue_recv() to  
     1149             * return PJ_EPENDING  
     1150             */ 
    8541151            flags = PJ_IOQUEUE_ALWAYS_ASYNC; 
    8551152        } else { 
     
    8681165 
    8691166        if (status == PJ_SUCCESS) { 
     1167 
    8701168            /* Continue loop. */ 
    8711169            pj_assert(i < MAX_IMMEDIATE_PACKET); 
     
    8801178                                   status, "tcp recv() error")); 
    8811179 
    882             /* Transport error, close transport */ 
    883             tcp_destroy(&tp->base); 
     1180            /* We can not destroy the transport since high level objects may 
     1181             * still keep reference to this transport. So we can only  
     1182             * instruct transport manager to gracefully start the shutdown 
     1183             * procedure for this transport. 
     1184             */ 
     1185            if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status; 
     1186            pjsip_transport_shutdown(&tcp->base); 
     1187 
    8841188            return; 
    8851189        } 
     
    8881192 
    8891193 
    890 /* Callback from ioqueue when connect completes */ 
     1194/*  
     1195 * Callback from ioqueue when asynchronous connect() operation completes. 
     1196 */ 
    8911197static void on_connect_complete(pj_ioqueue_key_t *key,  
    8921198                                pj_status_t status) 
    8931199{ 
    894     struct pending_connect *connect_op = (struct pending_connect *)key; 
    895     struct tcp_transport *tcp = connect_op->transport; 
     1200    struct tcp_transport *tcp; 
    8961201    pj_sockaddr_in addr; 
    8971202    int addrlen; 
    8981203 
     1204    tcp = pj_ioqueue_get_user_data(key); 
     1205 
     1206    PJ_LOG(4,(tcp->base.obj_name,  
     1207              "TCP transport %.*s:%d is connected to %.*s:%d", 
     1208              (int)tcp->base.local_name.host.slen, 
     1209              tcp->base.local_name.host.ptr, 
     1210              tcp->base.local_name.port, 
     1211              (int)tcp->base.remote_name.host.slen, 
     1212              tcp->base.remote_name.host.ptr, 
     1213              tcp->base.remote_name.port)); 
     1214 
    8991215    /* Mark that pending connect() operation has completed. */ 
    9001216    tcp->has_pending_connect = PJ_FALSE; 
     
    9021218    /* Check connect() status */ 
    9031219    if (status != PJ_SUCCESS) { 
     1220 
    9041221        tcp_perror(tcp->base.obj_name, "TCP connect() error", status); 
    905         tcp_destroy(&tcp->base); 
     1222 
     1223        /* We can not destroy the transport since high level objects may 
     1224         * still keep reference to this transport. So we can only  
     1225         * instruct transport manager to gracefully start the shutdown 
     1226         * procedure for this transport. 
     1227         */ 
     1228        if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status; 
     1229        pjsip_transport_shutdown(&tcp->base); 
    9061230        return; 
    9071231    } 
     
    9261250    status = tcp_start_read(tcp); 
    9271251    if (status != PJ_SUCCESS) { 
    928         tcp_destroy(&tcp->base); 
     1252        /* We can not destroy the transport since high level objects may 
     1253         * still keep reference to this transport. So we can only  
     1254         * instruct transport manager to gracefully start the shutdown 
     1255         * procedure for this transport. 
     1256         */ 
     1257        if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status; 
     1258        pjsip_transport_shutdown(&tcp->base); 
    9291259        return; 
    9301260    } 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c

    r512 r563  
    7878{ 
    7979    pjsua_acc *acc = &pjsua_var.acc[acc_id]; 
    80     pjsip_transport *tp = pjsua_var.tpdata[tp_id].tp; 
     80    struct transport_data *t = &pjsua_var.tpdata[tp_id]; 
    8181    char uri[80]; 
    8282 
    8383    /* Transport must be valid */ 
    84     pj_assert(tp != NULL); 
     84    pj_assert(t->data.ptr != NULL); 
    8585     
    8686    /* Build URI for the account */ 
    8787    pj_ansi_sprintf(uri, "<sip:%.*s:%d;transport=%s>",  
    88                          (int)tp->local_name.host.slen, 
    89                          tp->local_name.host.ptr, 
    90                          tp->local_name.port, 
    91                          pjsip_transport_get_type_name(tp->key.type)); 
     88                         (int)t->local_name.host.slen, 
     89                         t->local_name.host.ptr, 
     90                         t->local_name.port, 
     91                         pjsip_transport_get_type_name(t->type)); 
    9292 
    9393 
     
    145145 
    146146    PJ_TODO(attach_account_to_transport); 
    147     if (pjsua_var.tpdata[0].tp) 
     147    if (pjsua_var.tpdata[0].data.ptr) 
    148148        update_acc_contact(acc_id, 0); 
    149149 
     
    221221 
    222222    /* Must have a transport */ 
    223     PJ_ASSERT_RETURN(pjsua_var.tpdata[0].tp != NULL, PJ_EINVALIDOP); 
     223    PJ_TODO(associate_acc_with_transport); 
     224    PJ_ASSERT_RETURN(pjsua_var.tpdata[0].data.ptr != NULL, PJ_EINVALIDOP); 
    224225 
    225226    PJSUA_LOCK(); 
     
    282283{ 
    283284    pjsua_acc_config cfg; 
    284     pjsip_transport *tp; 
     285    struct transport_data *t = &pjsua_var.tpdata[tid]; 
    285286    char uri[62]; 
    286287 
     288    /* ID must be valid */ 
     289    PJ_ASSERT_RETURN(tid>=0 && tid<PJ_ARRAY_SIZE(pjsua_var.tpdata), PJ_EINVAL); 
     290 
    287291    /* Transport must be valid */ 
    288     tp = pjsua_var.tpdata[tid].tp; 
    289     PJ_ASSERT_RETURN(tp != NULL, PJ_EINVAL); 
     292    PJ_ASSERT_RETURN(t->data.ptr != NULL, PJ_EINVAL); 
    290293     
    291294    pjsua_acc_config_default(&cfg); 
    292295 
    293296    /* Build URI for the account */ 
    294     pj_ansi_sprintf(uri, "<sip:%.*s:%d>",  
    295                          (int)tp->local_name.host.slen, 
    296                          tp->local_name.host.ptr, 
    297                          tp->local_name.port); 
     297    pj_ansi_sprintf(uri, "<sip:%.*s:%d;transport=%s>",  
     298                         (int)t->local_name.host.slen, 
     299                         t->local_name.host.ptr, 
     300                         t->local_name.port, 
     301                         pjsip_transport_get_type_name(t->type)); 
    298302 
    299303    cfg.id = pj_str(uri); 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r509 r563  
    730730    /* Find empty transport slot */ 
    731731    for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { 
    732         if (pjsua_var.tpdata[id].tp == NULL) 
     732        if (pjsua_var.tpdata[id].data.ptr == NULL) 
    733733            break; 
    734734    } 
     
    742742    /* Create the transport */ 
    743743    if (type == PJSIP_TRANSPORT_UDP) { 
    744  
     744        /* 
     745         * Create UDP transport. 
     746         */ 
    745747        pjsua_transport_config config; 
    746748        pj_sock_t sock = PJ_INVALID_SOCKET; 
     
    774776        } 
    775777 
     778 
     779        /* Save the transport */ 
     780        pjsua_var.tpdata[id].type = type; 
     781        pjsua_var.tpdata[id].local_name = tp->local_name; 
     782        pjsua_var.tpdata[id].data.tp = tp; 
     783 
     784    } else if (type == PJSIP_TRANSPORT_TCP) { 
     785        /* 
     786         * Create TCP transport. 
     787         */ 
     788        pjsua_transport_config config; 
     789        pjsip_tpfactory *tcp; 
     790        pj_sockaddr_in local_addr; 
     791 
     792        /* Supply default config if it's not specified */ 
     793        if (cfg == NULL) { 
     794            pjsua_transport_config_default(&config); 
     795            cfg = &config; 
     796        } 
     797 
     798        /* Init local address */ 
     799        pj_sockaddr_in_init(&local_addr, 0, 0); 
     800 
     801        if (cfg->port) 
     802            local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port); 
     803 
     804        if (cfg->ip_addr.s_addr) 
     805            local_addr.sin_addr.s_addr = cfg->ip_addr.s_addr; 
     806 
     807        /* Create the TCP transport */ 
     808        status = pjsip_tcp_transport_start(pjsua_var.endpt, &local_addr, 1, 
     809                                           &tcp); 
     810 
     811        if (status != PJ_SUCCESS) { 
     812            pjsua_perror(THIS_FILE, "Error creating SIP TCP listener",  
     813                         status); 
     814            goto on_return; 
     815        } 
     816 
     817        /* Save the transport */ 
     818        pjsua_var.tpdata[id].type = type; 
     819        pjsua_var.tpdata[id].local_name = tcp->addr_name; 
     820        pjsua_var.tpdata[id].data.factory = tcp; 
     821 
    776822    } else { 
    777823        status = PJSIP_EUNSUPTRANSPORT; 
     
    780826    } 
    781827 
    782     /* Save the transport */ 
    783     pjsua_var.tpdata[id].tp = tp; 
    784828 
    785829    /* Return the ID */ 
     
    808852    /* Find empty transport slot */ 
    809853    for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) { 
    810         if (pjsua_var.tpdata[id].tp == NULL) 
     854        if (pjsua_var.tpdata[id].data.ptr == NULL) 
    811855            break; 
    812856    } 
     
    819863 
    820864    /* Save the transport */ 
    821     pjsua_var.tpdata[id].tp = tp; 
     865    pjsua_var.tpdata[id].type = tp->key.type; 
     866    pjsua_var.tpdata[id].local_name = tp->local_name; 
     867    pjsua_var.tpdata[id].data.tp = tp; 
    822868 
    823869    /* Return the ID */ 
     
    843889         ++i)  
    844890    { 
    845         if (!pjsua_var.tpdata[i].tp) 
     891        if (!pjsua_var.tpdata[i].data.ptr) 
    846892            continue; 
    847893 
     
    863909                                              pjsua_transport_info *info) 
    864910{ 
    865     pjsip_transport *tp; 
     911    struct transport_data *t = &pjsua_var.tpdata[id]; 
    866912 
    867913    pj_memset(info, 0, sizeof(*info)); 
     
    871917 
    872918    /* Make sure that transport exists */ 
    873     PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 
     919    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 
    874920 
    875921    PJSUA_LOCK(); 
    876922 
    877     tp = pjsua_var.tpdata[id].tp; 
    878     if (tp == NULL) { 
    879         PJSUA_UNLOCK(); 
    880         return PJ_EINVALIDOP; 
    881     } 
     923    if (pjsua_var.tpdata[id].type == PJSIP_TRANSPORT_UDP) { 
     924 
     925        pjsip_transport *tp = t->data.tp; 
     926 
     927        if (tp == NULL) { 
     928            PJSUA_UNLOCK(); 
     929            return PJ_EINVALIDOP; 
     930        } 
    882931     
    883     info->id = id; 
    884     info->type = tp->key.type; 
    885     info->type_name = pj_str(tp->type_name); 
    886     info->info = pj_str(tp->info); 
    887     info->flag = tp->flag; 
    888     info->addr_len = tp->addr_len; 
    889     info->local_addr = tp->local_addr; 
    890     info->local_name = tp->local_name; 
    891     info->usage_count = pj_atomic_get(tp->ref_cnt); 
     932        info->id = id; 
     933        info->type = tp->key.type; 
     934        info->type_name = pj_str(tp->type_name); 
     935        info->info = pj_str(tp->info); 
     936        info->flag = tp->flag; 
     937        info->addr_len = tp->addr_len; 
     938        info->local_addr = tp->local_addr; 
     939        info->local_name = tp->local_name; 
     940        info->usage_count = pj_atomic_get(tp->ref_cnt); 
     941 
     942    } else if (pjsua_var.tpdata[id].type == PJSIP_TRANSPORT_TCP) { 
     943 
     944        pjsip_tpfactory *factory = t->data.factory; 
     945 
     946        if (factory == NULL) { 
     947            PJSUA_UNLOCK(); 
     948            return PJ_EINVALIDOP; 
     949        } 
     950     
     951        info->id = id; 
     952        info->type = t->type; 
     953        info->type_name = pj_str("TCP"); 
     954        info->info = pj_str("TCP transport"); 
     955        info->flag = factory->flag; 
     956        info->addr_len = sizeof(factory->local_addr); 
     957        info->local_addr = factory->local_addr; 
     958        info->local_name = factory->addr_name; 
     959        info->usage_count = 0; 
     960 
     961    } 
     962 
    892963 
    893964    PJSUA_UNLOCK(); 
     
    907978 
    908979    /* Make sure that transport exists */ 
    909     PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 
     980    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 
    910981 
    911982 
     
    927998 
    928999    /* Make sure that transport exists */ 
    929     PJ_ASSERT_RETURN(pjsua_var.tpdata[id].tp != NULL, PJ_EINVAL); 
     1000    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 
    9301001 
    9311002 
  • pjproject/trunk/pjsip/src/test-pjsip/main.c

    r111 r563  
    2121#include <string.h> 
    2222#include <stdlib.h> 
     23 
     24extern const char *system_name; 
    2325 
    2426static void usage() 
     
    5860            } 
    5961            log_level = atoi(*opt_arg); 
     62        } else  if (strcmp(*opt_arg, "-s") == 0 || 
     63            strcmp(*opt_arg, "--system") == 0) 
     64        { 
     65            ++opt_arg; 
     66            if (!opt_arg) { 
     67                usage(); 
     68                return 1; 
     69            } 
     70            system_name = *opt_arg; 
    6071        } else { 
    6172            usage(); 
     
    6879    retval = test_main(); 
    6980 
    70     if (argc != 1) { 
     81    if (interractive) { 
    7182        char s[10]; 
    72         printf("<Press ENTER to quit>\n"); 
     83        printf("<Press ENTER to quit>\n"); fflush(stdout); 
    7384        fgets(s, sizeof(s), stdin); 
    7485    } 
  • pjproject/trunk/pjsip/src/test-pjsip/msg_logger.c

    r547 r563  
    2828{ 
    2929    if (msg_log_enabled) { 
    30         PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" 
    31                              "%s\n" 
     30        PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%s:%d:\n" 
     31                             "%.*s\n" 
    3232                             "--end msg--", 
    3333                             rdata->msg_info.len, 
    3434                             pjsip_rx_data_get_info(rdata), 
     35                             rdata->tp_info.transport->type_name, 
    3536                             rdata->pkt_info.src_name, 
    3637                             rdata->pkt_info.src_port, 
     38                             rdata->msg_info.len, 
    3739                             rdata->msg_info.msg_buf)); 
    3840    } 
     
    4446{ 
    4547    if (msg_log_enabled) { 
    46         PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" 
    47                              "%s\n" 
     48        PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%s:%d:\n" 
     49                             "%.*s\n" 
    4850                             "--end msg--", 
    4951                             (tdata->buf.cur - tdata->buf.start), 
    5052                             pjsip_tx_data_get_info(tdata), 
     53                             tdata->tp_info.transport->type_name, 
    5154                             tdata->tp_info.dst_name, 
    5255                             tdata->tp_info.dst_port, 
     56                             (tdata->buf.cur - tdata->buf.start), 
    5357                             tdata->buf.start)); 
    5458    } 
  • pjproject/trunk/pjsip/src/test-pjsip/msg_test.c

    r127 r563  
    2222 
    2323#define POOL_SIZE       8000 
    24 #define LOOP            10000 
     24#if defined(PJ_DEBUG) && PJ_DEBUG!=0 
     25#   define LOOP         10000 
     26#else 
     27#   define LOOP         100000 
     28#endif 
    2529#define AVERAGE_MSG_LEN 800 
    2630#define THIS_FILE       "msg_test.c" 
     
    3539#define FLAG_PARSE_ONLY         4 
    3640#define FLAG_PRINT_ONLY         8 
    37  
    38 static int flag = 0; 
    3941 
    4042struct test_msg 
     
    102104}; 
    103105 
    104 static pj_highprec_t detect_len, parse_len, print_len; 
    105 static pj_timestamp  detect_time, parse_time, print_time; 
     106static struct 
     107{ 
     108    int flag; 
     109    pj_highprec_t detect_len, parse_len, print_len; 
     110    pj_timestamp  detect_time, parse_time, print_time; 
     111} var; 
    106112 
    107113static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) 
     
    122128    entry->len = pj_native_strlen(entry->msg); 
    123129 
    124     if (flag & FLAG_PARSE_ONLY) 
     130    if (var.flag & FLAG_PARSE_ONLY) 
    125131        goto parse_msg; 
    126132 
    127     if (flag & FLAG_PRINT_ONLY) { 
     133    if (var.flag & FLAG_PRINT_ONLY) { 
    128134        if (print_msg == NULL) 
    129135            print_msg = entry->creator(pool); 
     
    132138 
    133139    /* Detect message. */ 
    134     detect_len = detect_len + entry->len; 
     140    var.detect_len = var.detect_len + entry->len; 
    135141    pj_get_timestamp(&t1); 
    136142    status = pjsip_find_msg(entry->msg, entry->len, PJ_FALSE, &msg_size); 
     
    149155    pj_get_timestamp(&t2); 
    150156    pj_sub_timestamp(&t2, &t1); 
    151     pj_add_timestamp(&detect_time, &t2); 
    152  
    153     if (flag & FLAG_DETECT_ONLY) 
     157    pj_add_timestamp(&var.detect_time, &t2); 
     158 
     159    if (var.flag & FLAG_DETECT_ONLY) 
    154160        return PJ_SUCCESS; 
    155161     
    156162    /* Parse message. */ 
    157163parse_msg: 
    158     parse_len = parse_len + entry->len; 
     164    var.parse_len = var.parse_len + entry->len; 
    159165    pj_get_timestamp(&t1); 
    160166    pj_list_init(&err_list); 
     
    172178    pj_get_timestamp(&t2); 
    173179    pj_sub_timestamp(&t2, &t1); 
    174     pj_add_timestamp(&parse_time, &t2); 
    175  
    176     if (flag & FLAG_PARSE_ONLY) 
     180    pj_add_timestamp(&var.parse_time, &t2); 
     181 
     182    if (var.flag & FLAG_PARSE_ONLY) 
    177183        return PJ_SUCCESS; 
    178184 
     
    307313    /* Print message. */ 
    308314print_msg: 
    309     print_len = print_len + entry->len; 
     315    var.print_len = var.print_len + entry->len; 
    310316    pj_get_timestamp(&t1); 
    311     if (flag && FLAG_PRINT_ONLY) 
     317    if (var.flag && FLAG_PRINT_ONLY) 
    312318        ref_msg = print_msg; 
    313319    len = pjsip_msg_print(ref_msg, msgbuf1, PJSIP_MAX_PKT_LEN); 
     
    318324    pj_get_timestamp(&t2); 
    319325    pj_sub_timestamp(&t2, &t1); 
    320     pj_add_timestamp(&print_time, &t2); 
     326    pj_add_timestamp(&var.print_time, &t2); 
    321327 
    322328 
     
    675681/*****************************************************************************/ 
    676682 
    677 int msg_test(void) 
     683static pj_status_t simple_test(void) 
     684{ 
     685    unsigned i; 
     686    pj_status_t status; 
     687 
     688    PJ_LOG(3,(THIS_FILE, "  simple test..")); 
     689    for (i=0; i<PJ_ARRAY_SIZE(test_array); ++i) { 
     690        pj_pool_t *pool; 
     691        pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE); 
     692        status = test_entry( pool, &test_array[i] ); 
     693        pjsip_endpt_release_pool(endpt, pool); 
     694 
     695        if (status != PJ_SUCCESS) 
     696            return status; 
     697    } 
     698 
     699    return PJ_SUCCESS; 
     700} 
     701 
     702 
     703static int msg_benchmark(unsigned *p_detect, unsigned *p_parse,  
     704                         unsigned *p_print) 
    678705{ 
    679706    pj_status_t status; 
     
    684711    pj_highprec_t avg_detect, avg_parse, avg_print, kbytes; 
    685712 
    686     PJ_LOG(3,(THIS_FILE, "  simple test..")); 
    687     for (i=0; i<PJ_ARRAY_SIZE(test_array); ++i) { 
    688         pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE); 
    689         status = test_entry( pool, &test_array[i] ); 
    690         pjsip_endpt_release_pool(endpt, pool); 
    691  
    692         if (status != PJ_SUCCESS) 
    693             return status; 
    694     } 
    695  
    696     PJ_LOG(3,(THIS_FILE, "  benchmarking..")); 
    697     detect_len = parse_len = print_len = 0; 
    698     zero.u64 = detect_time.u64 = parse_time.u64 = print_time.u64 = 0; 
    699      
     713 
     714    pj_memset(&var, 0, sizeof(var)); 
     715    zero.u64 = 0; 
     716 
    700717    for (loop=0; loop<LOOP; ++loop) { 
    701718        for (i=0; i<PJ_ARRAY_SIZE(test_array); ++i) { 
     
    709726    } 
    710727 
    711     kbytes = detect_len; 
     728    kbytes = var.detect_len; 
    712729    pj_highprec_mod(kbytes, 1000000); 
    713730    pj_highprec_div(kbytes, 100000); 
    714     elapsed = pj_elapsed_time(&zero, &detect_time); 
    715     avg_detect = pj_elapsed_usec(&zero, &detect_time); 
     731    elapsed = pj_elapsed_time(&zero, &var.detect_time); 
     732    avg_detect = pj_elapsed_usec(&zero, &var.detect_time); 
    716733    pj_highprec_mul(avg_detect, AVERAGE_MSG_LEN); 
    717     pj_highprec_div(avg_detect, detect_len); 
     734    pj_highprec_div(avg_detect, var.detect_len); 
    718735    avg_detect = 1000000 / avg_detect; 
    719736 
    720737    PJ_LOG(3,(THIS_FILE,  
    721738              "    %u.%u MB detected in %d.%03ds (avg=%d msg detection/sec)",  
    722               (unsigned)(detect_len/1000000), (unsigned)kbytes, 
     739              (unsigned)(var.detect_len/1000000), (unsigned)kbytes, 
    723740              elapsed.sec, elapsed.msec, 
    724741              (unsigned)avg_detect)); 
    725  
    726     kbytes = parse_len; 
     742    *p_detect = (unsigned)avg_detect; 
     743 
     744    kbytes = var.parse_len; 
    727745    pj_highprec_mod(kbytes, 1000000); 
    728746    pj_highprec_div(kbytes, 100000); 
    729     elapsed = pj_elapsed_time(&zero, &parse_time); 
    730     avg_parse = pj_elapsed_usec(&zero, &parse_time); 
     747    elapsed = pj_elapsed_time(&zero, &var.parse_time); 
     748    avg_parse = pj_elapsed_usec(&zero, &var.parse_time); 
    731749    pj_highprec_mul(avg_parse, AVERAGE_MSG_LEN); 
    732     pj_highprec_div(avg_parse, parse_len); 
     750    pj_highprec_div(avg_parse, var.parse_len); 
    733751    avg_parse = 1000000 / avg_parse; 
    734752 
    735753    PJ_LOG(3,(THIS_FILE,  
    736754              "    %u.%u MB parsed in %d.%03ds (avg=%d msg parsing/sec)",  
    737               (unsigned)(parse_len/1000000), (unsigned)kbytes, 
     755              (unsigned)(var.parse_len/1000000), (unsigned)kbytes, 
    738756              elapsed.sec, elapsed.msec, 
    739757              (unsigned)avg_parse)); 
    740  
    741     kbytes = print_len; 
     758    *p_parse = (unsigned)avg_parse; 
     759 
     760    kbytes = var.print_len; 
    742761    pj_highprec_mod(kbytes, 1000000); 
    743762    pj_highprec_div(kbytes, 100000); 
    744     elapsed = pj_elapsed_time(&zero, &print_time); 
    745     avg_print = pj_elapsed_usec(&zero, &print_time); 
     763    elapsed = pj_elapsed_time(&zero, &var.print_time); 
     764    avg_print = pj_elapsed_usec(&zero, &var.print_time); 
    746765    pj_highprec_mul(avg_print, AVERAGE_MSG_LEN); 
    747     pj_highprec_div(avg_print, print_len); 
     766    pj_highprec_div(avg_print, var.print_len); 
    748767    avg_print = 1000000 / avg_print; 
    749768 
    750769    PJ_LOG(3,(THIS_FILE,  
    751770              "    %u.%u MB printed in %d.%03ds (avg=%d msg print/sec)",  
    752               (unsigned)(print_len/1000000), (unsigned)kbytes, 
     771              (unsigned)(var.print_len/1000000), (unsigned)kbytes, 
    753772              elapsed.sec, elapsed.msec, 
    754773              (unsigned)avg_print)); 
    755774 
     775    *p_print = (unsigned)avg_print; 
    756776    return status; 
    757777} 
    758778 
    759779/*****************************************************************************/ 
     780 
     781int msg_test(void) 
     782{ 
     783    enum { COUNT = 4, DETECT=0, PARSE=1, PRINT=2 }; 
     784    struct { 
     785        unsigned detect; 
     786        unsigned parse; 
     787        unsigned print; 
     788    } run[COUNT]; 
     789    unsigned i, max, avg_len; 
     790    char desc[250]; 
     791    pj_status_t status; 
     792 
     793 
     794    status = simple_test(); 
     795    if (status != PJ_SUCCESS) 
     796        return status; 
     797 
     798    for (i=0; i<COUNT; ++i) { 
     799        PJ_LOG(3,(THIS_FILE, "  benchmarking (%d of %d)..", i+1, COUNT)); 
     800        status = msg_benchmark(&run[i].detect, &run[i].parse, &run[i].print); 
     801        if (status != PJ_SUCCESS) 
     802            return status; 
     803    } 
     804 
     805    /* Calculate average message length */ 
     806    for (i=0, avg_len=0; i<PJ_ARRAY_SIZE(test_array); ++i) { 
     807        avg_len += test_array[i].len; 
     808    } 
     809    avg_len /= PJ_ARRAY_SIZE(test_array); 
     810 
     811 
     812    /* Print maximum detect/sec */ 
     813    for (i=0, max=0; i<COUNT; ++i) 
     814        if (run[i].detect > max) max = run[i].detect; 
     815 
     816    PJ_LOG(3,("", "  Maximum message detection/sec=%u", max)); 
     817 
     818    pj_ansi_sprintf(desc, "Number of SIP messages " 
     819                          "can be pre-parse by <tt>pjsip_find_msg()</tt> " 
     820                          "per second (tested with %d message sets with " 
     821                          "average message length of " 
     822                          "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); 
     823    report_ival("msg-detect-per-sec", max, "msg/sec", desc); 
     824 
     825    /* Print maximum parse/sec */ 
     826    for (i=0, max=0; i<COUNT; ++i) 
     827        if (run[i].parse > max) max = run[i].parse; 
     828 
     829    PJ_LOG(3,("", "  Maximum message parsing/sec=%u", max)); 
     830 
     831    pj_ansi_sprintf(desc, "Number of SIP messages " 
     832                          "can be <b>parsed</b> by <tt>pjsip_parse_msg()</tt> " 
     833                          "per second (tested with %d message sets with " 
     834                          "average message length of " 
     835                          "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); 
     836    report_ival("msg-parse-per-sec", max, "msg/sec", desc); 
     837 
     838    /* Msg parsing bandwidth */ 
     839    report_ival("msg-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", 
     840                "Message parsing bandwidth in megabytes (number of megabytes" 
     841                " worth of SIP messages that can be parsed per second). " 
     842                "The value is derived from msg-parse-per-sec above."); 
     843 
     844 
     845    /* Print maximum print/sec */ 
     846    for (i=0, max=0; i<COUNT; ++i) 
     847        if (run[i].print > max) max = run[i].print; 
     848 
     849    PJ_LOG(3,("", "  Maximum message print/sec=%u", max)); 
     850 
     851    pj_ansi_sprintf(desc, "Number of SIP messages " 
     852                          "can be <b>printed</b> by <tt>pjsip_msg_print()</tt>" 
     853                          " per second (tested with %d message sets with " 
     854                          "average message length of " 
     855                          "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); 
     856 
     857    report_ival("msg-print-per-sec", max, "msg/sec", desc); 
     858 
     859    /* Msg print bandwidth */ 
     860    report_ival("msg-printed-bandwidth-mb", avg_len*max/1000000, "MB/sec", 
     861                "Message print bandwidth in megabytes (total size of " 
     862                "SIP messages printed per second). " 
     863                "The value is derived from msg-print-per-sec above."); 
     864 
     865 
     866    return PJ_SUCCESS; 
     867} 
     868 
  • pjproject/trunk/pjsip/src/test-pjsip/test.c

    r555 r563  
    3434                        } while (0) 
    3535 
     36#define DO_TSX_TEST(test, param) \ 
     37                        do { \ 
     38                            PJ_LOG(3, (THIS_FILE, "Running %s(%s)...", #test, (param)->tp_type));  \ 
     39                            rc = test(param); \ 
     40                            PJ_LOG(3, (THIS_FILE,  \ 
     41                                       "%s(%d)",  \ 
     42                                       (rc ? "..ERROR" : "..success"), rc)); \ 
     43                            if (rc!=0) goto on_return; \ 
     44                        } while (0) 
    3645 
    3746 
    3847pjsip_endpoint *endpt; 
    3948int log_level = 3; 
     49 
     50static pj_oshandle_t fd_report; 
     51const char *system_name = "Unknown"; 
     52static char buf[1024]; 
    4053 
    4154void app_perror(const char *msg, pj_status_t rc) 
     
    7689} 
    7790 
     91static pj_status_t init_report(void) 
     92{ 
     93    char tmp[80]; 
     94    pj_time_val timestamp; 
     95    pj_parsed_time date_time; 
     96    pj_ssize_t len; 
     97    pj_status_t status; 
     98     
     99    pj_ansi_sprintf(tmp, "pjsip-static-bench-%s-%s.htm", PJ_OS_NAME, PJ_CC_NAME); 
     100 
     101    status = pj_file_open(NULL, tmp, PJ_O_WRONLY, &fd_report); 
     102    if (status != PJ_SUCCESS) 
     103        return status; 
     104 
     105    /* Title */ 
     106    len = pj_ansi_sprintf(buf, "<HTML>\n" 
     107                               " <HEAD>\n" 
     108                               "  <TITLE>PJSIP %s (%s) - Static Benchmark</TITLE>\n" 
     109                               " </HEAD>\n" 
     110                               "<BODY>\n" 
     111                               "\n",  
     112                               PJ_VERSION, 
     113                               (PJ_DEBUG ? "Debug" : "Release")); 
     114    pj_file_write(fd_report, buf, &len); 
     115 
     116 
     117    /* Title */ 
     118    len = pj_ansi_sprintf(buf, "<H1>PJSIP %s (%s) - Static Benchmark</H1>\n",  
     119                               PJ_VERSION, 
     120                               (PJ_DEBUG ? "Debug" : "Release")); 
     121    pj_file_write(fd_report, buf, &len); 
     122 
     123    len = pj_ansi_sprintf(buf, "<P>Below is the benchmark result generated " 
     124                               "by <b>test-pjsip</b> program. The program " 
     125                               "is single-threaded only.</P>\n"); 
     126    pj_file_write(fd_report, buf, &len); 
     127 
     128 
     129    /* Write table heading */ 
     130    len = pj_ansi_sprintf(buf, "<TABLE border=\"1\" cellpadding=\"4\">\n" 
     131                               "  <TR><TD bgColor=\"aqua\" align=\"center\">Variable</TD>\n" 
     132                               "      <TD bgColor=\"aqua\" align=\"center\">Value</TD>\n" 
     133                               "      <TD bgColor=\"aqua\" align=\"center\">Description</TD>\n" 
     134                               "  </TR>\n"); 
     135    pj_file_write(fd_report, buf, &len); 
     136 
     137 
     138    /* Write version */ 
     139    report_sval("version", PJ_VERSION, "", "PJLIB/PJSIP version"); 
     140 
     141 
     142    /* Debug or release */ 
     143    report_sval("build-type", (PJ_DEBUG ? "Debug" : "Release"), "", "Build type"); 
     144 
     145 
     146    /* Write timestamp */ 
     147    pj_gettimeofday(&timestamp); 
     148    report_ival("timestamp", timestamp.sec, "", "System timestamp of the test"); 
     149 
     150 
     151    /* Write time of day */ 
     152    pj_time_decode(&timestamp, &date_time); 
     153    len = pj_ansi_sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", 
     154                               date_time.year, date_time.mon+1, date_time.day, 
     155                               date_time.hour, date_time.min, date_time.sec); 
     156    report_sval("date-time", tmp, "", "Date/time of the test"); 
     157 
     158 
     159    /* Write System */ 
     160    report_sval("system", system_name, "", "System description"); 
     161 
     162 
     163    /* Write OS type */ 
     164    report_sval("os-family", PJ_OS_NAME, "", "Operating system family"); 
     165 
     166 
     167    /* Write CC name */ 
     168    len = pj_ansi_sprintf(tmp, "%s-%d.%d.%d", PJ_CC_NAME,  
     169                          PJ_CC_VER_1, PJ_CC_VER_2, PJ_CC_VER_2); 
     170    report_sval("cc-name", tmp, "", "Compiler name and version"); 
     171 
     172 
     173    return PJ_SUCCESS; 
     174} 
     175 
     176void report_sval(const char *name, const char* value, const char *valname,  
     177                 const char *desc) 
     178{ 
     179    pj_ssize_t len; 
     180 
     181    len = pj_ansi_sprintf(buf, "  <TR><TD><TT>%s</TT></TD>\n" 
     182                               "      <TD align=\"right\"><B>%s %s</B></TD>\n" 
     183                               "      <TD>%s</TD>\n" 
     184                               "  </TR>\n", 
     185                               name, value, valname, desc); 
     186    pj_file_write(fd_report, buf, &len); 
     187} 
     188 
     189 
     190void report_ival(const char *name, int value, const char *valname,  
     191                 const char *desc) 
     192{ 
     193    pj_ssize_t len; 
     194 
     195    len = pj_ansi_sprintf(buf, "  <TR><TD><TT>%s</TT></TD>\n" 
     196                               "      <TD align=\"right\"><B>%d %s</B></TD>\n" 
     197                               "      <TD>%s</TD>\n" 
     198                               "  </TR>\n", 
     199                               name, value, valname, desc); 
     200    pj_file_write(fd_report, buf, &len); 
     201 
     202} 
     203 
     204static void close_report(void) 
     205{ 
     206    pj_ssize_t len; 
     207 
     208    if (fd_report) { 
     209        len = pj_ansi_sprintf(buf, "</TABLE>\n</BODY>\n</HTML>\n"); 
     210        pj_file_write(fd_report, buf, &len); 
     211 
     212        pj_file_close(fd_report); 
     213    } 
     214} 
     215 
     216 
    78217int test_main(void) 
    79218{ 
     
    81220    pj_caching_pool caching_pool; 
    82221    const char *filename; 
     222    unsigned i, tsx_test_cnt=0; 
     223    struct tsx_test_param tsx_test[10]; 
     224    pj_status_t status; 
     225    pjsip_transport *tp; 
     226    pjsip_tpfactory *tpfactory; 
    83227    int line; 
    84228 
     
    93237        return rc; 
    94238    } 
     239 
     240    status = init_report(); 
     241    if (status != PJ_SUCCESS) 
     242        return status; 
    95243 
    96244    pj_dump_config(); 
     
    125273        goto on_return; 
    126274    } 
     275    tsx_test[tsx_test_cnt].port = 5060; 
     276    tsx_test[tsx_test_cnt].tp_type = "loop-dgram"; 
     277    tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_LOOP_DGRAM; 
     278    ++tsx_test_cnt; 
     279 
    127280 
    128281#if INCLUDE_URI_TEST 
     
    139292#endif 
    140293 
     294#if INCLUDE_TSX_BENCH 
     295    DO_TEST(tsx_bench()); 
     296#endif 
     297 
    141298#if INCLUDE_UDP_TEST 
    142299    DO_TEST(transport_udp_test()); 
     
    147304#endif 
    148305 
     306#if INCLUDE_TCP_TEST 
     307    DO_TEST(transport_tcp_test()); 
     308#endif 
     309 
     310 
    149311#if INCLUDE_TSX_TEST 
    150     DO_TEST(tsx_basic_test()); 
    151     DO_TEST(tsx_uac_test()); 
    152     DO_TEST(tsx_uas_test()); 
     312    status = pjsip_udp_transport_start(endpt, NULL, NULL, 1,  &tp); 
     313    if (status == PJ_SUCCESS) { 
     314        tsx_test[tsx_test_cnt].port = tp->local_name.port; 
     315        tsx_test[tsx_test_cnt].tp_type = "udp"; 
     316        tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_UDP; 
     317        ++tsx_test_cnt; 
     318    } 
     319 
     320    status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); 
     321    if (status == PJ_SUCCESS) { 
     322        tsx_test[tsx_test_cnt].port = tpfactory->addr_name.port; 
     323        tsx_test[tsx_test_cnt].tp_type = "tcp"; 
     324        tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_TCP; 
     325        ++tsx_test_cnt; 
     326    } else { 
     327        app_perror("Unable to create TCP", status); 
     328        rc = -4; 
     329        goto on_return; 
     330    } 
     331 
     332 
     333    for (i=0; i<tsx_test_cnt; ++i) { 
     334        DO_TSX_TEST(tsx_basic_test, &tsx_test[i]); 
     335        DO_TSX_TEST(tsx_uac_test, &tsx_test[i]); 
     336        DO_TSX_TEST(tsx_uas_test, &tsx_test[i]); 
     337    } 
    153338#endif 
    154339 
    155340 
    156341on_return: 
    157  
     342    flush_events(500); 
    158343    pjsip_endpt_destroy(endpt); 
    159344    pj_caching_pool_destroy(&caching_pool); 
     
    170355        PJ_LOG(3,(THIS_FILE, "Test completed with error(s)")); 
    171356 
     357    report_ival("test-status", rc, "", "Overall test status/result (0==success)"); 
     358    close_report(); 
    172359    return rc; 
    173360} 
  • pjproject/trunk/pjsip/src/test-pjsip/test.h

    r555 r563  
    3232#define INCLUDE_TSX_GROUP           1 
    3333 
     34/* 
     35 * Include tests that normally would fail under certain gcc 
     36 * optimization levels. 
     37 */ 
     38#ifndef INCLUDE_GCC_TEST 
     39#   define INCLUDE_GCC_TEST         0 
     40#endif 
    3441 
    3542 
     
    3744#define INCLUDE_MSG_TEST        INCLUDE_MESSAGING_GROUP 
    3845#define INCLUDE_TXDATA_TEST     INCLUDE_MESSAGING_GROUP 
     46#define INCLUDE_TSX_BENCH       INCLUDE_MESSAGING_GROUP 
    3947#define INCLUDE_UDP_TEST        INCLUDE_TRANSPORT_GROUP 
    4048#define INCLUDE_LOOP_TEST       INCLUDE_TRANSPORT_GROUP 
     49#define INCLUDE_TCP_TEST        INCLUDE_TRANSPORT_GROUP 
    4150#define INCLUDE_TSX_TEST        INCLUDE_TSX_GROUP 
    4251 
     
    4857int msg_err_test(void); 
    4958int txdata_test(void); 
     59int tsx_bench(void); 
    5060int transport_udp_test(void); 
    5161int transport_loop_test(void); 
    52 int tsx_basic_test(void); 
    53 int tsx_uac_test(void); 
    54 int tsx_uas_test(void); 
     62int transport_tcp_test(void); 
     63 
     64struct tsx_test_param 
     65{ 
     66    int type; 
     67    int port; 
     68    char *tp_type; 
     69}; 
     70 
     71int tsx_basic_test(struct tsx_test_param *param); 
     72int tsx_uac_test(struct tsx_test_param *param); 
     73int tsx_uas_test(struct tsx_test_param *param); 
    5574 
    5675/* Transport test helpers (transport_test.c). */ 
     
    5877int transport_send_recv_test( pjsip_transport_type_e tp_type, 
    5978                              pjsip_transport *ref_tp, 
    60                               char *target_url ); 
     79                              char *target_url, 
     80                              int *p_usec_rtt); 
    6181int transport_rt_test( pjsip_transport_type_e tp_type, 
    6282                       pjsip_transport *ref_tp, 
     
    6989/* Test utilities. */ 
    7090void app_perror(const char *msg, pj_status_t status); 
    71 int init_msg_logger(void); 
    72 int msg_logger_set_enabled(pj_bool_t enabled); 
     91int  init_msg_logger(void); 
     92int  msg_logger_set_enabled(pj_bool_t enabled); 
    7393void flush_events(unsigned duration); 
     94 
     95 
     96void report_ival(const char *name, int value, const char *valname, const char *desc); 
     97void report_sval(const char *name, const char* value, const char *valname, const char *desc); 
     98 
    7499 
    75100/* Settings. */ 
  • pjproject/trunk/pjsip/src/test-pjsip/transport_loop_test.c

    r127 r563  
    2626static int datagram_loop_test() 
    2727{ 
     28    enum { LOOP = 8 }; 
    2829    pjsip_transport *loop; 
    2930    int i, pkt_lost; 
    3031    pj_sockaddr_in addr; 
    3132    pj_status_t status; 
     33    long ref_cnt; 
     34    unsigned rtt[LOOP], min_rtt; 
    3235 
    3336    PJ_LOG(3,(THIS_FILE, "testing datagram loop transport")); 
     
    4144    } 
    4245 
     46    /* Get initial reference counter */ 
     47    ref_cnt = pj_atomic_get(loop->ref_cnt); 
     48 
    4349    /* Test basic transport attributes */ 
    4450    status = generic_transport_test(loop); 
     
    4753 
    4854    /* Basic transport's send/receive loopback test. */ 
    49     for (i=0; i<2; ++i) { 
     55    for (i=0; i<LOOP; ++i) { 
    5056        status = transport_send_recv_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop,  
    51                                           "sip:bob@130.0.0.1;transport=loop-dgram"); 
     57                                          "sip:bob@130.0.0.1;transport=loop-dgram", 
     58                                          &rtt[i]); 
    5259        if (status != 0) 
    5360            return status; 
    5461    } 
     62 
     63    min_rtt = 0xFFFFFFF; 
     64    for (i=0; i<LOOP; ++i) 
     65        if (rtt[i] < min_rtt) min_rtt = rtt[i]; 
     66 
     67    report_ival("loop-rtt-usec", min_rtt, "usec", 
     68                "Best Loopback transport round trip time, in microseconds " 
     69                "(time from sending request until response is received. " 
     70                "Tests were performed on local machine only)"); 
     71 
    5572 
    5673    /* Multi-threaded round-trip test. */ 
     
    85102    pjsip_loop_set_delay(loop, 0); 
    86103 
    87     /* Check that reference counter is one. */ 
    88     if (pj_atomic_get(loop->ref_cnt) != 1) { 
    89         return -50; 
     104    /* Check reference counter. */ 
     105    if (pj_atomic_get(loop->ref_cnt) != ref_cnt) { 
     106        PJ_LOG(3,(THIS_FILE, "   error: ref counter is not %d (%d)",  
     107                             ref_cnt, pj_atomic_get(loop->ref_cnt))); 
     108        return -51; 
    90109    } 
    91110 
  • pjproject/trunk/pjsip/src/test-pjsip/transport_test.c

    r547 r563  
    174174int transport_send_recv_test( pjsip_transport_type_e tp_type, 
    175175                              pjsip_transport *ref_tp, 
    176                               char *target_url ) 
     176                              char *target_url, 
     177                              int *p_usec_rtt) 
    177178{ 
    178179    pj_bool_t msg_log_enabled; 
     
    221222 
    222223    /* Send the message (statelessly). */ 
     224    PJ_LOG(5,(THIS_FILE, "Sending request to %.*s",  
     225                         (int)target.slen, target.ptr)); 
    223226    status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, 
    224227                                                 &send_msg_callback); 
     
    229232    } 
    230233 
    231     /* Set the timeout (1 second from now) */ 
     234    /* Set the timeout (2 seconds from now) */ 
    232235    pj_gettimeofday(&timeout); 
    233     timeout.sec += 1; 
     236    timeout.sec += 2; 
    234237 
    235238    /* Loop handling events until we get status */ 
     
    269272        unsigned usec_rt; 
    270273        usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); 
     274 
    271275        PJ_LOG(3,(THIS_FILE, "    round-trip = %d usec", usec_rt)); 
     276 
     277        *p_usec_rtt = usec_rt; 
    272278    } 
    273279 
     
    517523    unsigned total_recv; 
    518524 
    519  
    520525    PJ_LOG(3,(THIS_FILE, "  multithreaded round-trip test (%d threads)...", 
    521526                  THREADS)); 
  • pjproject/trunk/pjsip/src/test-pjsip/transport_udp_test.c

    r550 r563  
    3030int transport_udp_test(void) 
    3131{ 
    32     enum { SEND_RECV_LOOP = 2 }; 
     32    enum { SEND_RECV_LOOP = 8 }; 
    3333    pjsip_transport *udp_tp, *tp; 
    3434    pj_sockaddr_in addr, rem_addr; 
    3535    pj_str_t s; 
    3636    pj_status_t status; 
     37    unsigned rtt[SEND_RECV_LOOP], min_rtt; 
    3738    int i, pkt_lost; 
    3839 
     
    8081    for (i=0; i<SEND_RECV_LOOP; ++i) { 
    8182        status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp,  
    82                                           "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR); 
     83                                          "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR, 
     84                                          &rtt[i]); 
    8385        if (status != 0) 
    8486            return status; 
    8587    } 
     88 
     89    min_rtt = 0xFFFFFFF; 
     90    for (i=0; i<SEND_RECV_LOOP; ++i) 
     91        if (rtt[i] < min_rtt) min_rtt = rtt[i]; 
     92 
     93    report_ival("udp-rtt-usec", min_rtt, "usec", 
     94                "Best UDP transport round trip time, in microseconds " 
     95                "(time from sending request until response is received. " 
     96                "Tests were performed on local machine only)"); 
     97 
    8698 
    8799    /* Multi-threaded round-trip test. */ 
  • pjproject/trunk/pjsip/src/test-pjsip/tsx_basic_test.c

    r127 r563  
    2424#define THIS_FILE   "tsx_basic_test.c" 
    2525 
     26static char TARGET_URI[128]; 
     27static char FROM_URI[128]; 
     28 
     29 
    2630/* Test transaction layer. */ 
    2731static int tsx_layer_test(void) 
     
    3438    PJ_LOG(3,(THIS_FILE, "  transaction layer test")); 
    3539 
    36     target = pj_str("sip:alice@localhost"); 
    37     from = pj_str("sip:bob@localhost"); 
     40    target = pj_str(TARGET_URI); 
     41    from = pj_str(FROM_URI); 
    3842 
    3943    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, 
     
    7882    PJ_LOG(3,(THIS_FILE, "  double terminate test")); 
    7983 
    80     target = pj_str("sip:alice@localhost;transport=loop-dgram"); 
    81     from = pj_str("sip:bob@localhost"); 
     84    target = pj_str(TARGET_URI); 
     85    from = pj_str(FROM_URI); 
    8286 
    8387    /* Create request. */ 
     
    132136} 
    133137 
    134 int tsx_basic_test(void) 
     138int tsx_basic_test(struct tsx_test_param *param) 
    135139{ 
    136140    int status; 
     141 
     142    pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s",  
     143                    param->port, param->tp_type); 
     144    pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s",  
     145                    param->port, param->tp_type); 
    137146 
    138147    status = tsx_layer_test(); 
  • pjproject/trunk/pjsip/src/test-pjsip/tsx_uac_test.c

    r555 r563  
    9292#define      TEST5_RETRANSMIT_CNT   3 
    9393 
     94static char TARGET_URI[128]; 
     95static char FROM_URI[128]; 
     96static unsigned tp_flag; 
     97static struct tsx_test_param *test_param; 
    9498 
    9599static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); 
     
    141145 
    142146/* General timer entry to be used by tests. */ 
    143 static pj_timer_entry timer; 
     147static struct my_timer 
     148{ 
     149    pj_timer_entry  entry; 
     150    char            key_buf[1024]; 
     151    pj_str_t        tsx_key; 
     152} timer; 
    144153 
    145154/* 
     
    167176                test_complete = -710; 
    168177            } 
     178 
     179 
     180            /* If transport is reliable, then there must not be any 
     181             * retransmissions. 
     182             */ 
     183            if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { 
     184                if (recv_count != 1) { 
     185                    PJ_LOG(3,(THIS_FILE,  
     186                           "    error: there were %d (re)transmissions", 
     187                           recv_count)); 
     188                    test_complete = -715; 
     189                } 
     190            } else { 
     191                /* Check the number of transmissions, which must be 
     192                 * 6 for INVITE and 10 for non-INVITE  
     193                 */ 
     194                if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) { 
     195                    PJ_LOG(3,(THIS_FILE,  
     196                           "    error: there were %d (re)transmissions", 
     197                           recv_count)); 
     198                    test_complete = -716; 
     199                } else 
     200                if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) { 
     201                    PJ_LOG(3,(THIS_FILE,  
     202                           "    error: there were %d (re)transmissions", 
     203                           recv_count)); 
     204                    test_complete = -717; 
     205                } else 
     206                if (tsx->method.id!=PJSIP_INVITE_METHOD &&  
     207                    tsx->method.id!=PJSIP_OPTIONS_METHOD) 
     208                { 
     209                    PJ_LOG(3,(THIS_FILE, "    error: unexpected method")); 
     210                    test_complete = -718; 
     211                } 
     212            } 
    169213        } 
    170214 
     
    516560                                    struct pj_timer_entry *entry) 
    517561{ 
    518     pjsip_transaction *tsx = entry->user_data; 
     562    struct my_timer *m = (struct my_timer *)entry; 
     563    pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE); 
    519564    int status_code = entry->id; 
    520565 
     
    721766            pjsip_transport_add_ref(r->res_addr.transport); 
    722767 
    723         timer.cb = &send_response_callback; 
    724         timer.user_data = r; 
    725         pjsip_endpt_schedule_timer(endpt, &timer, &delay); 
     768        timer.entry.cb = &send_response_callback; 
     769        timer.entry.user_data = r; 
     770        pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); 
    726771 
    727772        return PJ_TRUE; 
     
    769814                                     rdata); 
    770815 
    771                 timer.user_data = pjsip_tsx_layer_find_tsx(&key, PJ_FALSE); 
    772                 timer.id = 301; 
    773                 timer.cb = &terminate_tsx_callback; 
    774  
    775                 pjsip_endpt_schedule_timer(endpt, &timer, &delay); 
     816                pj_strcpy(&timer.tsx_key, &key); 
     817                timer.entry.id = 301; 
     818                timer.entry.cb = &terminate_tsx_callback; 
     819 
     820                pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); 
    776821            } 
    777822 
     
    842887                pjsip_transport_add_ref(r->res_addr.transport); 
    843888 
    844             timer.cb = &send_response_callback; 
    845             timer.user_data = r; 
    846             pjsip_endpt_schedule_timer(endpt, &timer, &delay); 
     889            timer.entry.cb = &send_response_callback; 
     890            timer.entry.user_data = r; 
     891            pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); 
    847892 
    848893        } else if (method->id == PJSIP_ACK_METHOD) { 
     
    860905                                     rdata); 
    861906 
    862                 timer.user_data = pjsip_tsx_layer_find_tsx(&key, PJ_FALSE); 
    863                 timer.id = 302; 
    864                 timer.cb = &terminate_tsx_callback; 
    865  
    866                 pjsip_endpt_schedule_timer(endpt, &timer, &delay); 
     907                pj_strcpy(&timer.tsx_key, &key); 
     908                timer.entry.id = 302; 
     909                timer.entry.cb = &terminate_tsx_callback; 
     910 
     911                pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); 
    867912            } 
    868913 
     
    9811026        pjsip_tx_data_dec_ref(tdata); 
    9821027        return test_complete; 
    983     } 
    984  
    985     /* Allow transaction to destroy itself */ 
    986     flush_events(500); 
     1028 
     1029    } else { 
     1030        pj_time_val now; 
     1031 
     1032        /* Allow transaction to destroy itself */ 
     1033        flush_events(500); 
     1034 
     1035        /* Wait until test completes */ 
     1036        pj_gettimeofday(&now); 
     1037 
     1038        if (PJ_TIME_VAL_LT(now, timeout)) { 
     1039            pj_time_val interval; 
     1040            interval = timeout; 
     1041            PJ_TIME_VAL_SUB(interval, now); 
     1042            flush_events(PJ_TIME_VAL_MSEC(interval)); 
     1043        } 
     1044    } 
    9871045 
    9881046    /* Make sure transaction has been destroyed. */ 
     
    10531111 
    10541112        /* Do the test. */ 
    1055         status = perform_tsx_test(-500, "sip:bob@127.0.0.1;transport=loop-dgram", 
    1056                                   "sip:alice@127.0.0.1;transport=loop-dgram",  
     1113        status = perform_tsx_test(-500, TARGET_URI, FROM_URI,  
    10571114                                  TEST1_BRANCH_ID, 
    10581115                                  35, sub_test[i].method); 
     
    10941151 
    10951152    status = perform_tsx_test(-800,  
    1096                               "sip:bob@unresolved-host;transport=loop-dgram", 
    1097                               "sip:alice@127.0.0.1;transport=loop-dgram",  
    1098                               TEST2_BRANCH_ID, 10,  
     1153                              "sip:bob@unresolved-host", 
     1154                              FROM_URI,  TEST2_BRANCH_ID, 10,  
    10991155                              &pjsip_options_method); 
    11001156    if (status != 0) 
     
    11061162    PJ_LOG(3,(THIS_FILE, "   variant b: error via callback")); 
    11071163 
    1108     /* Set loop transport to return delayed error. */ 
    1109     pjsip_loop_set_failure(loop, 2, NULL); 
    1110     pjsip_loop_set_send_callback_delay(loop, 10, NULL); 
    1111  
    1112     status = perform_tsx_test(-800, "sip:bob@127.0.0.1;transport=loop-dgram", 
    1113                               "sip:alice@127.0.0.1;transport=loop-dgram",  
    1114                               TEST2_BRANCH_ID, 2,  
    1115                               &pjsip_options_method); 
    1116     if (status != 0) 
    1117         return status; 
    1118  
    1119     /* Restore loop transport settings. */ 
    1120     pjsip_loop_set_failure(loop, 0, NULL); 
    1121     pjsip_loop_set_send_callback_delay(loop, 0, NULL); 
     1164    /* This only applies to "loop-dgram" transport */ 
     1165    if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { 
     1166        /* Set loop transport to return delayed error. */ 
     1167        pjsip_loop_set_failure(loop, 2, NULL); 
     1168        pjsip_loop_set_send_callback_delay(loop, 10, NULL); 
     1169 
     1170        status = perform_tsx_test(-800, TARGET_URI, FROM_URI,  
     1171                                  TEST2_BRANCH_ID, 2,  
     1172                                  &pjsip_options_method); 
     1173        if (status != 0) 
     1174            return status; 
     1175 
     1176        /* Restore loop transport settings. */ 
     1177        pjsip_loop_set_failure(loop, 0, NULL); 
     1178        pjsip_loop_set_send_callback_delay(loop, 0, NULL); 
     1179    } 
    11221180 
    11231181    return status; 
     
    11441202 
    11451203    /* Start the test. */ 
    1146     status = perform_tsx_test(-900, "sip:127.0.0.1;transport=loop-dgram", 
    1147                               "sip:127.0.0.1;transport=loop-dgram", 
     1204    status = perform_tsx_test(-900, TARGET_URI, FROM_URI, 
    11481205                              TEST3_BRANCH_ID, 2, &pjsip_options_method); 
    11491206 
     
    11871244 
    11881245        /* Start the test. */ 
    1189         status = perform_tsx_test(-1000, "sip:127.0.0.1;transport=loop-dgram", 
    1190                                   "sip:127.0.0.1;transport=loop-dgram", 
     1246        status = perform_tsx_test(-1000, TARGET_URI, FROM_URI, 
    11911247                                  TEST4_BRANCH_ID, 6, &pjsip_options_method); 
    11921248 
     
    12191275 
    12201276    /* Do the test. */ 
    1221     status = perform_tsx_test(-1100, "sip:bob@127.0.0.1;transport=loop-dgram", 
    1222                               "sip:alice@127.0.0.1;transport=loop-dgram",  
     1277    status = perform_tsx_test(-1100, TARGET_URI, FROM_URI,  
    12231278                              TEST5_BRANCH_ID, 
    12241279                              6, &pjsip_options_method); 
     
    12501305    for (i=0; i<PJ_ARRAY_SIZE(delay); ++i) { 
    12511306         
    1252         PJ_LOG(3,(THIS_FILE, "   variant %c: with %d ms transport delay", 
    1253                              ('a'+i), delay[i])); 
    1254  
    1255         pjsip_loop_set_delay(loop, delay[i]); 
    1256  
    1257         status = perform_tsx_test(-1200,  
    1258                                   "sip:bob@127.0.0.1;transport=loop-dgram", 
    1259                                   "sip:alice@127.0.0.1;transport=loop-dgram", 
    1260                                   branch_id, 
    1261                                   10, method); 
     1307        if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { 
     1308            PJ_LOG(3,(THIS_FILE, "   variant %c: with %d ms transport delay", 
     1309                                 ('a'+i), delay[i])); 
     1310 
     1311            pjsip_loop_set_delay(loop, delay[i]); 
     1312        } 
     1313 
     1314        status = perform_tsx_test(-1200, TARGET_URI, FROM_URI, 
     1315                                  branch_id, 10, method); 
    12621316        if (status != 0) 
    12631317            return status; 
     1318 
     1319        if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) 
     1320            break; 
    12641321    } 
    12651322 
     
    12771334 ***************************************************************************** 
    12781335 */ 
    1279 int tsx_uac_test(void) 
     1336int tsx_uac_test(struct tsx_test_param *param) 
    12801337{ 
    12811338    pj_sockaddr_in addr; 
    12821339    pj_status_t status; 
     1340 
     1341    timer.tsx_key.ptr = timer.key_buf; 
     1342 
     1343    test_param = param; 
     1344 
     1345    /* Get transport flag */ 
     1346    tp_flag = pjsip_transport_get_flag_from_type(test_param->type); 
     1347 
     1348    pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s",  
     1349                    param->port, param->tp_type); 
     1350    pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s",  
     1351                    param->port, param->tp_type); 
    12831352 
    12841353    /* Check if loop transport is configured. */ 
     
    13171386        return status; 
    13181387 
    1319     /* TEST4_BRANCH_ID: Transport failed after several retransmissions */ 
    1320     status = tsx_retransmit_fail_test(); 
    1321     if (status != 0) 
    1322         return status; 
    1323  
    1324     /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions */ 
    1325     status = tsx_terminate_after_retransmit_test(); 
    1326     if (status != 0) 
    1327         return status; 
     1388    /* TEST4_BRANCH_ID: Transport failed after several retransmissions. 
     1389     *                  Only applies to loop transport. 
     1390     */ 
     1391    if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { 
     1392        status = tsx_retransmit_fail_test(); 
     1393        if (status != 0) 
     1394            return status; 
     1395    } 
     1396 
     1397    /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions  
     1398     *                  Only applicable to non-reliable transports. 
     1399     */ 
     1400    if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { 
     1401        status = tsx_terminate_after_retransmit_test(); 
     1402        if (status != 0) 
     1403            return status; 
     1404    } 
    13281405 
    13291406    /* TEST6_BRANCH_ID: Successfull non-invite transaction */ 
     
    13531430        return status; 
    13541431 
    1355  
    13561432    pjsip_transport_dec_ref(loop); 
     1433    flush_events(500); 
     1434 
     1435    /* Unregister modules. */ 
     1436    status = pjsip_endpt_unregister_module(endpt, &tsx_user); 
     1437    if (status != PJ_SUCCESS) { 
     1438        app_perror("   Error: unable to unregister module", status); 
     1439        return -31; 
     1440    } 
     1441    status = pjsip_endpt_unregister_module(endpt, &msg_receiver); 
     1442    if (status != PJ_SUCCESS) { 
     1443        app_perror("   Error: unable to unregister module", status); 
     1444        return -41; 
     1445    } 
     1446 
    13571447    return 0; 
    13581448} 
  • pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c

    r555 r563  
    3636 **     Test that non-INVITE transaction returns 2xx response to the correct 
    3737 **     transport and correctly terminates the transaction. 
     38 **     This also checks that transaction is destroyed immediately after 
     39 **     it sends final response when reliable transport is used. 
    3840 ** 
    3941 ** TEST2_BRANCH_ID 
     
    5456 ** TEST6_BRANCH_ID 
    5557 **     As above, in COMPLETED state, with first sending provisional response. 
     58 **     (Only applicable for non-reliable transports). 
    5659 ** 
    5760 ** TEST7_BRANCH_ID 
     
    6669 **     until it's terminated by user). 
    6770 **     Transaction also MUST terminate in T4 seconds. 
     71 **     (Only applicable for non-reliable transports). 
    6872 ** 
    6973 ** TEST11_BRANCH_ID 
     
    129133 
    130134 
     135static char TARGET_URI[128]; 
     136static char FROM_URI[128]; 
     137static struct tsx_test_param *test_param; 
     138static unsigned tp_flag; 
     139 
     140 
    131141#define TEST_TIMEOUT_ERROR      -30 
    132142#define MAX_ALLOWED_DIFF        150 
     
    522532            /* Check that status code is status_code. */ 
    523533            if (tsx->status_code != TEST6_STATUS_CODE) { 
    524                 PJ_LOG(3,(THIS_FILE, "    error: incorrect status code")); 
     534                PJ_LOG(3,(THIS_FILE, "    error: incorrect status code %d " 
     535                          "(expecting %d)", tsx->status_code,  
     536                          TEST6_STATUS_CODE)); 
    525537                test_complete = -140; 
    526538            } 
     
    576588                PJ_LOG(3,(THIS_FILE, "    error: incorrect prev_state")); 
    577589                test_complete = -151; 
     590            } 
     591 
     592            /* Check the number of retransmissions */ 
     593            if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { 
     594 
     595                if (tsx->retransmit_count != 0) { 
     596                    PJ_LOG(3,(THIS_FILE, "    error: should not retransmit")); 
     597                    test_complete = -1510; 
     598                } 
     599 
     600            } else { 
     601 
     602                if (tsx->retransmit_count != 10) { 
     603                    PJ_LOG(3,(THIS_FILE,  
     604                              "    error: incorrect retransmit count %d " 
     605                              "(expecting 10)", 
     606                              tsx->retransmit_count)); 
     607                    test_complete = -1510; 
     608                } 
     609 
    578610            } 
    579611 
     
    815847            pjsip_transaction *tsx; 
    816848 
     849            PJ_LOG(4,(THIS_FILE, "    received request (probably retransmission)")); 
     850 
    817851            status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); 
    818852            if (status != PJ_SUCCESS) { 
     
    831865 
    832866            } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { 
     867                PJ_LOG(4,(THIS_FILE, "    sending provisional response")); 
    833868                send_response(rdata, tsx, TEST6_PROVISIONAL_CODE); 
     869                PJ_LOG(4,(THIS_FILE, "    sending final response")); 
    834870                send_response(rdata, tsx, TEST6_STATUS_CODE); 
    835871            } 
     
    838874            /* Verify the response received. */ 
    839875             
     876            PJ_LOG(4,(THIS_FILE, "    received response number %d", recv_count)); 
     877 
    840878            ++recv_count; 
    841879 
     
    870908                case 3: 
    871909                    if (code != TEST6_STATUS_CODE) { 
    872                         PJ_LOG(3,(THIS_FILE, "    error: invalid code!")); 
     910                        PJ_LOG(3,(THIS_FILE, "    error: invalid code %d " 
     911                                  "(expecting %d)", code, TEST6_STATUS_CODE)); 
    873912                        test_complete = -136; 
    874913                    } 
     
    11841223 
    11851224            /* (Re)Send the request. */ 
     1225            PJ_LOG(4,(THIS_FILE, "    (re)sending request %d", sent_cnt)); 
     1226 
    11861227            status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0); 
    11871228            if (status != PJ_SUCCESS) { 
     
    12561297static int tsx_basic_final_response_test(void) 
    12571298{ 
     1299    unsigned duration; 
    12581300    int status; 
    12591301 
    12601302    PJ_LOG(3,(THIS_FILE,"  test1: basic sending 2xx final response")); 
    12611303 
    1262     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1263                           "sip:129.0.0.1;transport=loop-dgram", 
    1264                           TEST1_BRANCH_ID, 
    1265                           33, /* Test duration must be greater than 32 secs */ 
    1266                           &pjsip_options_method, 1, 0, 0); 
     1304    /* Test duration must be greater than 32 secs if unreliable transport 
     1305     * is used. 
     1306     */ 
     1307    duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; 
     1308 
     1309    status = perform_test(TARGET_URI, FROM_URI, TEST1_BRANCH_ID, 
     1310                          duration,  &pjsip_options_method, 1, 0, 0); 
    12671311    if (status != 0) 
    12681312        return status; 
     
    12701314    PJ_LOG(3,(THIS_FILE,"  test2: basic sending non-2xx final response")); 
    12711315 
    1272     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1273                           "sip:129.0.0.1;transport=loop-dgram", 
    1274                           TEST2_BRANCH_ID, 
    1275                           33, /* Test duration must be greater than 32 secs */ 
    1276                           &pjsip_options_method, 1, 0, 0); 
     1316    status = perform_test(TARGET_URI, FROM_URI, TEST2_BRANCH_ID, 
     1317                          duration, &pjsip_options_method, 1, 0, 0); 
    12771318    if (status != 0) 
    12781319        return status; 
     
    12901331static int tsx_basic_provisional_response_test(void) 
    12911332{ 
     1333    unsigned duration; 
    12921334    int status; 
    12931335 
    12941336    PJ_LOG(3,(THIS_FILE,"  test3: basic sending 2xx final response")); 
    12951337 
    1296     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1297                           "sip:129.0.0.1;transport=loop-dgram", 
    1298                           TEST3_BRANCH_ID, 
    1299                           35, 
     1338    duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; 
     1339    duration += 2; 
     1340 
     1341    status = perform_test(TARGET_URI, FROM_URI, TEST3_BRANCH_ID, duration, 
    13001342                          &pjsip_options_method, 1, 0, 0); 
    13011343 
     
    13211363    PJ_LOG(3,(THIS_FILE,"  %s", title)); 
    13221364 
    1323     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1324                           "sip:129.0.0.1;transport=loop-dgram", 
    1325                           branch_id, 
    1326                           5, 
     1365    status = perform_test(TARGET_URI, FROM_URI, branch_id, 5, 
    13271366                          &pjsip_options_method,  
    13281367                          request_cnt, 1000, 1); 
     
    13581397              "  test7: INVITE non-2xx final response retransmission")); 
    13591398 
    1360     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1361                           "sip:129.0.0.1;transport=loop-dgram", 
    1362                           TEST7_BRANCH_ID, 
     1399    status = perform_test(TARGET_URI, FROM_URI, TEST7_BRANCH_ID, 
    13631400                          33, /* Test duration must be greater than 32 secs */ 
    13641401                          &pjsip_invite_method, 1, 0, 0); 
     
    13691406              "  test8: INVITE 2xx final response retransmission")); 
    13701407 
    1371     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1372                           "sip:129.0.0.1;transport=loop-dgram", 
    1373                           TEST8_BRANCH_ID, 
     1408    status = perform_test(TARGET_URI, FROM_URI, TEST8_BRANCH_ID, 
    13741409                          33, /* Test duration must be greater than 32 secs */ 
    13751410                          &pjsip_invite_method, 1, 0, 0); 
     
    13951430              "  test9: receiving ACK for non-2xx final response")); 
    13961431 
    1397     status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1398                           "sip:129.0.0.1;transport=loop-dgram", 
    1399                           TEST9_BRANCH_ID, 
     1432    status = perform_test(TARGET_URI, FROM_URI, TEST9_BRANCH_ID, 
    14001433                          20, /* allow 5 retransmissions */ 
    14011434                          &pjsip_invite_method, 1, 0, 0); 
     
    14441477        pjsip_loop_set_delay(loop, tests[i].transport_delay); 
    14451478 
    1446         status = perform_test("sip:129.0.0.1;transport=loop-dgram", 
    1447                               "sip:129.0.0.1;transport=loop-dgram", 
    1448                               tests[i].branch_id, 
    1449                               0, 
    1450                               &pjsip_invite_method, 1, 0, 1); 
     1479        status = perform_test(TARGET_URI, FROM_URI, tests[i].branch_id, 
     1480                              0, &pjsip_invite_method, 1, 0, 1); 
    14511481        if (status && status != TEST_TIMEOUT_ERROR) 
    14521482            return status; 
     
    14951525 ***************************************************************************** 
    14961526 */ 
    1497 int tsx_uas_test(void) 
     1527int tsx_uas_test(struct tsx_test_param *param) 
    14981528{ 
    14991529    pj_sockaddr_in addr; 
    15001530    pj_status_t status; 
     1531 
     1532    test_param = param; 
     1533    tp_flag = pjsip_transport_get_flag_from_type(param->type); 
     1534 
     1535    pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s",  
     1536                    param->port, param->tp_type); 
     1537    pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s",  
     1538                    param->port, param->tp_type); 
    15011539 
    15021540    /* Check if loop transport is configured. */ 
     
    15051543    if (status != PJ_SUCCESS) { 
    15061544        PJ_LOG(3,(THIS_FILE, "  Error: loop transport is not configured!")); 
    1507         return -1; 
    1508     } 
    1509  
     1545        return -10; 
     1546    } 
    15101547    /* Register modules. */ 
    15111548    status = pjsip_endpt_register_module(endpt, &tsx_user); 
     
    15511588        return status; 
    15521589 
    1553     /* TEST6_BRANCH_ID: retransmit last response in PROCEEDING state 
     1590    /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state 
     1591     *                  This only applies to non-reliable transports, 
     1592     *                  since UAS transaction is destroyed as soon 
     1593     *                  as final response is sent for reliable transports. 
    15541594     */ 
    1555     status = tsx_retransmit_last_response_test(TEST6_TITLE, 
    1556                                                TEST6_BRANCH_ID,  
    1557                                                TEST6_REQUEST_COUNT, 
    1558                                                TEST6_STATUS_CODE); 
    1559     if (status != 0) 
    1560         return status; 
     1595    if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { 
     1596        status = tsx_retransmit_last_response_test(TEST6_TITLE, 
     1597                                                   TEST6_BRANCH_ID,  
     1598                                                   TEST6_REQUEST_COUNT, 
     1599                                                   TEST6_STATUS_CODE); 
     1600        if (status != 0) 
     1601            return status; 
     1602    } 
    15611603 
    15621604    /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test 
    15631605     * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test 
    15641606     */ 
    1565  
    15661607    status = tsx_final_response_retransmission_test(); 
    15671608    if (status != 0) 
     
    15701611    /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must  
    15711612     * cease when ACK is received 
     1613     * Only applicable for non-reliable transports. 
    15721614     */ 
    1573     status = tsx_ack_test(); 
    1574     if (status != 0) 
    1575         return status; 
     1615    if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { 
     1616        status = tsx_ack_test(); 
     1617        if (status != 0) 
     1618            return status; 
     1619    } 
     1620 
    15761621 
    15771622    /* TEST10_BRANCH_ID: test transport failure in TRYING state. 
     
    15801625     * TEST13_BRANCH_ID: test transport failure in CONFIRMED state. 
    15811626     */ 
    1582     status = tsx_transport_failure_test(); 
    1583     if (status != 0) 
    1584         return status; 
    1585  
    1586  
    1587     pjsip_transport_dec_ref(loop); 
     1627    /* Only valid for loop-dgram */ 
     1628    if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { 
     1629        status = tsx_transport_failure_test(); 
     1630        if (status != 0) 
     1631            return status; 
     1632    } 
     1633 
     1634 
     1635    /* Register modules. */ 
     1636    status = pjsip_endpt_unregister_module(endpt, &tsx_user); 
     1637    if (status != PJ_SUCCESS) { 
     1638        app_perror("   Error: unable to unregister module", status); 
     1639        return -8; 
     1640    } 
     1641    status = pjsip_endpt_unregister_module(endpt, &msg_sender); 
     1642    if (status != PJ_SUCCESS) { 
     1643        app_perror("   Error: unable to unregister module", status); 
     1644        return -9; 
     1645    } 
     1646 
     1647 
     1648    if (loop) 
     1649        pjsip_transport_dec_ref(loop); 
     1650 
    15881651    return 0; 
    1589  
    15901652} 
    15911653 
  • pjproject/trunk/pjsip/src/test-pjsip/txdata_test.c

    r127 r563  
    2222#include <pjlib.h> 
    2323 
     24 
     25#define THIS_FILE   "txdata_test.c" 
     26 
     27 
    2428#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) 
    2529 
    26 #define THIS_FILE   "txdata_test.c" 
     30#if defined(PJ_DEBUG) && PJ_DEBUG!=0 
     31#   define LOOP     10000 
     32#else 
     33#   define LOOP     100000 
     34#endif 
    2735 
    2836 
     
    323331    return 0; 
    324332} 
     333 
     334 
     335 
     336/*  
     337 * This test demonstrate the bug as reported in: 
     338 *  http://bugzilla.pjproject.net/show_bug.cgi?id=49 
     339 */ 
     340static int gcc_test() 
     341{ 
     342    char msgbuf[512]; 
     343    pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" 
     344                             "?X-Hdr-1=Header%201" 
     345                             "&X-Empty-Hdr="); 
     346    pjsip_tx_data *tdata; 
     347    pjsip_parser_err_report err_list; 
     348    pjsip_msg *msg; 
     349    int len; 
     350    pj_status_t status; 
     351 
     352    PJ_LOG(3,(THIS_FILE, "   header param in URI to create request")); 
     353 
     354    /* Create request with header param in target URI. */ 
     355    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, 
     356                                        &target, &target, &target, NULL, -1, 
     357                                        NULL, &tdata); 
     358    if (status != 0) { 
     359        app_perror("   error: Unable to create request", status); 
     360        return -200; 
     361    } 
     362 
     363    /* Print and parse the request. 
     364     * We'll check that header params are not present in 
     365     */ 
     366    len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); 
     367    if (len < 1) { 
     368        PJ_LOG(3,(THIS_FILE, "   error: printing message")); 
     369        pjsip_tx_data_dec_ref(tdata); 
     370        return -250; 
     371    } 
     372    msgbuf[len] = '\0'; 
     373 
     374    PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" 
     375                         "%s\n" 
     376                         "--end-msg--", len, msgbuf)); 
     377 
     378    /* Now parse the message. */ 
     379    pj_list_init(&err_list); 
     380    msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); 
     381    if (msg == NULL) { 
     382        pjsip_parser_err_report *e; 
     383 
     384        PJ_LOG(3,(THIS_FILE, "   error: parsing message message")); 
     385 
     386        e = err_list.next; 
     387        while (e != &err_list) { 
     388            PJ_LOG(3,(THIS_FILE, "     %s in line %d col %d hname=%.*s", 
     389                                 pj_exception_id_name(e->except_code),  
     390                                 e->line, e->col+1, 
     391                                 (int)e->hname.slen, 
     392                                 e->hname.ptr)); 
     393            e = e->next; 
     394        } 
     395 
     396        pjsip_tx_data_dec_ref(tdata); 
     397        return -255; 
     398    } 
     399 
     400    pjsip_tx_data_dec_ref(tdata); 
     401    return 0; 
     402} 
     403 
    325404 
    326405/* This tests the request creating functions against the following 
     
    346425    pjsip_sip_uri *uri; 
    347426    pjsip_param *param; 
     427    pjsip_via_hdr *via; 
     428    pjsip_parser_err_report err_list; 
    348429    pjsip_msg *msg; 
    349430    int len; 
     
    361442    } 
    362443 
     444    /* Fill up the Via header to prevent syntax error on parsing */ 
     445    via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); 
     446    via->transport = pj_str("TCP"); 
     447    via->sent_by.host = pj_str("127.0.0.1"); 
     448 
    363449    /* Print and parse the request. 
    364450     * We'll check that header params are not present in 
     
    377463 
    378464    /* Now parse the message. */ 
    379     msg = pjsip_parse_msg( tdata->pool, msgbuf, len, NULL); 
     465    pj_list_init(&err_list); 
     466    msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); 
    380467    if (msg == NULL) { 
    381         app_perror("   error: parsing message message", status); 
    382         pjsip_tx_data_dec_ref(tdata); 
    383         return -250; 
     468        pjsip_parser_err_report *e; 
     469 
     470        PJ_LOG(3,(THIS_FILE, "   error: parsing message message")); 
     471 
     472        e = err_list.next; 
     473        while (e != &err_list) { 
     474            PJ_LOG(3,(THIS_FILE, "     %s in line %d col %d hname=%.*s", 
     475                                 pj_exception_id_name(e->except_code),  
     476                                 e->line, e->col+1, 
     477                                 (int)e->hname.slen, 
     478                                 e->hname.ptr)); 
     479            e = e->next; 
     480        } 
     481 
     482        pjsip_tx_data_dec_ref(tdata); 
     483        return -256; 
    384484    } 
    385485 
     
    513613} 
    514614 
     615 
     616/* 
     617 * create request benchmark 
     618 */ 
     619static int create_request_bench(pj_timestamp *p_elapsed) 
     620{ 
     621    enum { COUNT = 100 }; 
     622    unsigned i, j; 
     623    pjsip_tx_data *tdata[COUNT]; 
     624    pj_timestamp t1, t2, elapsed; 
     625    pj_status_t status; 
     626 
     627    pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); 
     628    pj_str_t str_from = pj_str("\"Local User\" <sip:localuser@serviceprovider.com>"); 
     629    pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>"); 
     630    pj_str_t str_contact = str_from; 
     631 
     632    elapsed.u64 = 0; 
     633 
     634    for (i=0; i<LOOP; i+=COUNT) { 
     635        pj_memset(tdata, 0, sizeof(tdata)); 
     636 
     637        pj_get_timestamp(&t1); 
     638 
     639        for (j=0; j<COUNT; ++j) { 
     640            status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, 
     641                                                &str_target, &str_from, &str_to, 
     642                                                &str_contact, NULL, -1, NULL, 
     643                                                &tdata[j]); 
     644            if (status != PJ_SUCCESS) { 
     645                app_perror("    error: unable to create request", status); 
     646                goto on_error; 
     647            } 
     648        } 
     649 
     650        pj_get_timestamp(&t2); 
     651        pj_sub_timestamp(&t2, &t1); 
     652        pj_add_timestamp(&elapsed, &t2); 
     653         
     654        for (j=0; j<COUNT; ++j) 
     655            pjsip_tx_data_dec_ref(tdata[j]); 
     656    } 
     657 
     658    p_elapsed->u64 = elapsed.u64; 
     659    return PJ_SUCCESS; 
     660 
     661on_error: 
     662    for (i=0; i<COUNT; ++i) { 
     663        if (tdata[i]) 
     664            pjsip_tx_data_dec_ref(tdata[i]); 
     665    } 
     666    return -400; 
     667} 
     668 
     669 
     670 
     671/* 
     672 * create response benchmark 
     673 */ 
     674static int create_response_bench(pj_timestamp *p_elapsed) 
     675{ 
     676    enum { COUNT = 100 }; 
     677    unsigned i, j; 
     678    pjsip_via_hdr *via; 
     679    pjsip_rx_data rdata; 
     680    pjsip_tx_data *request; 
     681    pjsip_tx_data *tdata[COUNT]; 
     682    pj_timestamp t1, t2, elapsed; 
     683    pj_status_t status; 
     684 
     685    /* Create the request first. */ 
     686    pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); 
     687    pj_str_t str_from = pj_str("\"Local User\" <sip:localuser@serviceprovider.com>"); 
     688    pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>"); 
     689    pj_str_t str_contact = str_from; 
     690 
     691    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, 
     692                                        &str_target, &str_from, &str_to, 
     693                                        &str_contact, NULL, -1, NULL, 
     694                                        &request); 
     695    if (status != PJ_SUCCESS) { 
     696        app_perror("    error: unable to create request", status); 
     697        return status; 
     698    } 
     699 
     700    /* Create several Via headers */ 
     701    via = pjsip_via_hdr_create(request->pool); 
     702    via->sent_by.host = pj_str("192.168.0.7"); 
     703    via->sent_by.port = 5061; 
     704    via->transport = pj_str("udp"); 
     705    via->rport_param = 0; 
     706    via->branch_param = pj_str("012345678901234567890123456789"); 
     707    via->recvd_param = pj_str("192.168.0.7"); 
     708    pjsip_msg_insert_first_hdr(request->msg, pjsip_hdr_clone(request->pool, via)); 
     709    pjsip_msg_insert_first_hdr(request->msg, pjsip_hdr_clone(request->pool, via)); 
     710    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); 
     711     
     712 
     713    /* Create "dummy" rdata from the tdata */ 
     714    pj_memset(&rdata, 0, sizeof(pjsip_rx_data)); 
     715    rdata.tp_info.pool = request->pool; 
     716    rdata.msg_info.msg = request->msg; 
     717    rdata.msg_info.from = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); 
     718    rdata.msg_info.to = pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); 
     719    rdata.msg_info.cseq = pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); 
     720    rdata.msg_info.cid = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); 
     721    rdata.msg_info.via = via; 
     722 
     723    /* 
     724     * Now benchmark create_response 
     725     */ 
     726    elapsed.u64 = 0; 
     727 
     728    for (i=0; i<LOOP; i+=COUNT) { 
     729        pj_memset(tdata, 0, sizeof(tdata)); 
     730 
     731        pj_get_timestamp(&t1); 
     732 
     733        for (j=0; j<COUNT; ++j) { 
     734            status = pjsip_endpt_create_response(endpt, &rdata, 200, NULL, &tdata[j]); 
     735            if (status != PJ_SUCCESS) { 
     736                app_perror("    error: unable to create request", status); 
     737                goto on_error; 
     738            } 
     739        } 
     740 
     741        pj_get_timestamp(&t2); 
     742        pj_sub_timestamp(&t2, &t1); 
     743        pj_add_timestamp(&elapsed, &t2); 
     744         
     745        for (j=0; j<COUNT; ++j) 
     746            pjsip_tx_data_dec_ref(tdata[j]); 
     747    } 
     748 
     749    p_elapsed->u64 = elapsed.u64; 
     750    pjsip_tx_data_dec_ref(request); 
     751    return PJ_SUCCESS; 
     752 
     753on_error: 
     754    for (i=0; i<COUNT; ++i) { 
     755        if (tdata[i]) 
     756            pjsip_tx_data_dec_ref(tdata[i]); 
     757    } 
     758    return -400; 
     759} 
     760 
     761 
    515762int txdata_test(void) 
    516763{ 
     764    enum { REPEAT = 4 }; 
     765    unsigned i, msgs; 
     766    pj_timestamp usec[REPEAT], min, freq; 
    517767    int status; 
     768 
     769    status = pj_get_timestamp_freq(&freq); 
     770    if (status != PJ_SUCCESS) 
     771        return status; 
    518772 
    519773    status = core_txdata_test(); 
     
    521775        return status; 
    522776 
     777#if INCLUDE_GCC_TEST 
     778    status = gcc_test(); 
     779    if (status != 0) 
     780        return status; 
     781#endif 
    523782 
    524783    status = txdata_test_uri_params(); 
     
    526785        return status; 
    527786 
     787 
     788    /* 
     789     * Benchmark create_request() 
     790     */ 
     791    PJ_LOG(3,(THIS_FILE, "   benchmarking request creation:")); 
     792    for (i=0; i<REPEAT; ++i) { 
     793        PJ_LOG(3,(THIS_FILE, "    test %d of %d..", 
     794                  i+1, REPEAT)); 
     795        status = create_request_bench(&usec[i]); 
     796        if (status != PJ_SUCCESS) 
     797            return status; 
     798    } 
     799 
     800    min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF); 
     801    for (i=0; i<REPEAT; ++i) { 
     802        if (usec[i].u64 < min.u64) min.u64 = usec[i].u64; 
     803    } 
     804 
     805    msgs = (unsigned)(freq.u64 * LOOP / min.u64); 
     806 
     807    PJ_LOG(3,(THIS_FILE, "    Requests created at %d requests/sec", msgs)); 
     808 
     809    report_ival("create-request-per-sec",  
     810                msgs, "msg/sec", 
     811                "Number of typical request messages that can be created " 
     812                "per second with <tt>pjsip_endpt_create_request()</tt>"); 
     813 
     814 
     815    /* 
     816     * Benchmark create_response() 
     817     */ 
     818    PJ_LOG(3,(THIS_FILE, "   benchmarking response creation:")); 
     819    for (i=0; i<REPEAT; ++i) { 
     820        PJ_LOG(3,(THIS_FILE, "    test %d of %d..", 
     821                  i+1, REPEAT)); 
     822        status = create_response_bench(&usec[i]); 
     823        if (status != PJ_SUCCESS) 
     824            return status; 
     825    } 
     826 
     827    min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF); 
     828    for (i=0; i<REPEAT; ++i) { 
     829        if (usec[i].u64 < min.u64) min.u64 = usec[i].u64; 
     830    } 
     831 
     832    msgs = (unsigned)(freq.u64 * LOOP / min.u64); 
     833 
     834    PJ_LOG(3,(THIS_FILE, "    Responses created at %d responses/sec", msgs)); 
     835 
     836    report_ival("create-response-per-sec",  
     837                msgs, "msg/sec", 
     838                "Number of typical response messages that can be created " 
     839                "per second with <tt>pjsip_endpt_create_response()</tt>"); 
     840 
     841 
    528842    return 0; 
    529843} 
     844  
  • pjproject/trunk/pjsip/src/test-pjsip/uri_test.c

    r127 r563  
    3333 
    3434#define POOL_SIZE       8000 
    35 #define LOOP_COUNT      10000 
     35#if defined(PJ_DEBUG) && PJ_DEBUG!=0 
     36#   define LOOP_COUNT   10000 
     37#else 
     38#   define LOOP_COUNT   40000 
     39#endif 
    3640#define AVERAGE_URL_LEN 80 
    3741#define THREAD_COUNT    4 
    3842 
    39 static pj_highprec_t parse_len, print_len, cmp_len; 
    40 static pj_timestamp parse_time, print_time, cmp_time; 
     43static struct 
     44{ 
     45    pj_highprec_t parse_len, print_len, cmp_len; 
     46    pj_timestamp  parse_time, print_time, cmp_time; 
     47} var; 
    4148 
    4249 
     
    687694    /* Parse URI text. */ 
    688695    pj_get_timestamp(&t1); 
    689     parse_len = parse_len + entry->len; 
     696    var.parse_len = var.parse_len + entry->len; 
    690697    parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0); 
    691698    if (!parsed_uri) { 
     
    703710    pj_get_timestamp(&t2); 
    704711    pj_sub_timestamp(&t2, &t1); 
    705     pj_add_timestamp(&parse_time, &t2); 
     712    pj_add_timestamp(&var.parse_time, &t2); 
    706713 
    707714    /* Create the reference URI. */ 
     
    721728    s1.slen = len; 
    722729 
    723     print_len = print_len + len; 
     730    var.print_len = var.print_len + len; 
    724731    pj_get_timestamp(&t2); 
    725732    pj_sub_timestamp(&t2, &t1); 
    726     pj_add_timestamp(&print_time, &t2); 
     733    pj_add_timestamp(&var.print_time, &t2); 
    727734 
    728735    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); 
     
    756763    } 
    757764 
    758     cmp_len = cmp_len + len; 
     765    var.cmp_len = var.cmp_len + len; 
    759766    pj_get_timestamp(&t2); 
    760767    pj_sub_timestamp(&t2, &t1); 
    761     pj_add_timestamp(&cmp_time, &t2); 
     768    pj_add_timestamp(&var.cmp_time, &t2); 
    762769 
    763770    /* Compare text. */ 
     
    786793} 
    787794 
    788 int uri_test() 
    789 { 
    790     unsigned i, loop; 
     795 
     796static int simple_uri_test(void) 
     797{ 
     798    unsigned i; 
    791799    pj_pool_t *pool; 
    792800    pj_status_t status; 
    793     pj_timestamp zero; 
    794     pj_time_val elapsed; 
    795     pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; 
    796  
    797     zero.u32.hi = zero.u32.lo = 0; 
    798801 
    799802    PJ_LOG(3,(THIS_FILE, "  simple test")); 
     
    804807            PJ_LOG(3,(THIS_FILE, "  error %d when testing entry %d", 
    805808                      status, i)); 
    806             goto on_return; 
     809            return status; 
    807810        } 
    808811    } 
    809812    pjsip_endpt_release_pool(endpt, pool); 
    810813 
    811     PJ_LOG(3,(THIS_FILE, "  benchmarking...")); 
    812     parse_len = print_len = cmp_len = 0; 
    813     parse_time.u32.hi = parse_time.u32.lo = 0; 
    814     print_time.u32.hi = print_time.u32.lo = 0; 
    815     cmp_time.u32.hi = cmp_time.u32.lo = 0; 
     814    return 0; 
     815} 
     816 
     817static int uri_benchmark(unsigned *p_parse, unsigned *p_print, unsigned *p_cmp) 
     818{ 
     819    unsigned i, loop; 
     820    pj_pool_t *pool; 
     821    pj_status_t status; 
     822    pj_timestamp zero; 
     823    pj_time_val elapsed; 
     824    pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; 
     825 
     826    pj_memset(&var, 0, sizeof(var)); 
     827 
     828    zero.u32.hi = zero.u32.lo = 0; 
     829 
     830    var.parse_len = var.print_len = var.cmp_len = 0; 
     831    var.parse_time.u32.hi = var.parse_time.u32.lo = 0; 
     832    var.print_time.u32.hi = var.print_time.u32.lo = 0; 
     833    var.cmp_time.u32.hi = var.cmp_time.u32.lo = 0; 
    816834    for (loop=0; loop<LOOP_COUNT; ++loop) { 
    817835        pool = pjsip_endpt_create_pool(endpt, "", POOL_SIZE, POOL_SIZE); 
     
    828846    } 
    829847 
    830     kbytes = parse_len; 
     848    kbytes = var.parse_len; 
    831849    pj_highprec_mod(kbytes, 1000000); 
    832850    pj_highprec_div(kbytes, 100000); 
    833     elapsed = pj_elapsed_time(&zero, &parse_time); 
    834     avg_parse = pj_elapsed_usec(&zero, &parse_time); 
     851    elapsed = pj_elapsed_time(&zero, &var.parse_time); 
     852    avg_parse = pj_elapsed_usec(&zero, &var.parse_time); 
    835853    pj_highprec_mul(avg_parse, AVERAGE_URL_LEN); 
    836     pj_highprec_div(avg_parse, parse_len); 
     854    pj_highprec_div(avg_parse, var.parse_len); 
    837855    avg_parse = 1000000 / avg_parse; 
    838856 
    839857    PJ_LOG(3,(THIS_FILE,  
    840858              "    %u.%u MB of urls parsed in %d.%03ds (avg=%d urls/sec)",  
    841               (unsigned)(parse_len/1000000), (unsigned)kbytes, 
     859              (unsigned)(var.parse_len/1000000), (unsigned)kbytes, 
    842860              elapsed.sec, elapsed.msec, 
    843861              (unsigned)avg_parse)); 
    844862 
    845     kbytes = print_len; 
     863    *p_parse = (unsigned)avg_parse; 
     864 
     865    kbytes = var.print_len; 
    846866    pj_highprec_mod(kbytes, 1000000); 
    847867    pj_highprec_div(kbytes, 100000); 
    848     elapsed = pj_elapsed_time(&zero, &print_time); 
    849     avg_print = pj_elapsed_usec(&zero, &print_time); 
     868    elapsed = pj_elapsed_time(&zero, &var.print_time); 
     869    avg_print = pj_elapsed_usec(&zero, &var.print_time); 
    850870    pj_highprec_mul(avg_print, AVERAGE_URL_LEN); 
    851     pj_highprec_div(avg_print, parse_len); 
     871    pj_highprec_div(avg_print, var.parse_len); 
    852872    avg_print = 1000000 / avg_print; 
    853873 
    854874    PJ_LOG(3,(THIS_FILE,  
    855875              "    %u.%u MB of urls printed in %d.%03ds (avg=%d urls/sec)",  
    856               (unsigned)(print_len/1000000), (unsigned)kbytes, 
     876              (unsigned)(var.print_len/1000000), (unsigned)kbytes, 
    857877              elapsed.sec, elapsed.msec, 
    858878              (unsigned)avg_print)); 
    859879 
    860     kbytes = cmp_len; 
     880    *p_print = (unsigned)avg_print; 
     881 
     882    kbytes = var.cmp_len; 
    861883    pj_highprec_mod(kbytes, 1000000); 
    862884    pj_highprec_div(kbytes, 100000); 
    863     elapsed = pj_elapsed_time(&zero, &cmp_time); 
    864     avg_cmp = pj_elapsed_usec(&zero, &cmp_time); 
     885    elapsed = pj_elapsed_time(&zero, &var.cmp_time); 
     886    avg_cmp = pj_elapsed_usec(&zero, &var.cmp_time); 
    865887    pj_highprec_mul(avg_cmp, AVERAGE_URL_LEN); 
    866     pj_highprec_div(avg_cmp, cmp_len); 
     888    pj_highprec_div(avg_cmp, var.cmp_len); 
    867889    avg_cmp = 1000000 / avg_cmp; 
    868890 
    869891    PJ_LOG(3,(THIS_FILE,  
    870892              "    %u.%u MB of urls compared in %d.%03ds (avg=%d urls/sec)",  
    871               (unsigned)(cmp_len/1000000), (unsigned)kbytes, 
     893              (unsigned)(var.cmp_len/1000000), (unsigned)kbytes, 
    872894              elapsed.sec, elapsed.msec, 
    873895              (unsigned)avg_cmp)); 
    874896 
    875     PJ_LOG(3,(THIS_FILE, "  multithreaded test")); 
    876  
     897    *p_cmp = (unsigned)avg_cmp; 
    877898 
    878899on_return: 
     
    880901} 
    881902 
     903 
     904/*****************************************************************************/ 
     905 
     906int uri_test(void) 
     907{ 
     908    enum { COUNT = 4, DETECT=0, PARSE=1, PRINT=2 }; 
     909    struct { 
     910        unsigned parse; 
     911        unsigned print; 
     912        unsigned cmp; 
     913    } run[COUNT]; 
     914    unsigned i, max, avg_len; 
     915    char desc[200]; 
     916    pj_status_t status; 
     917 
     918    status = simple_uri_test(); 
     919    if (status != PJ_SUCCESS) 
     920        return status; 
     921 
     922    for (i=0; i<COUNT; ++i) { 
     923        PJ_LOG(3,(THIS_FILE, "  benchmarking (%d of %d)...", i+1, COUNT)); 
     924        status = uri_benchmark(&run[i].parse, &run[i].print, &run[i].cmp); 
     925        if (status != PJ_SUCCESS) 
     926            return status; 
     927    } 
     928 
     929    /* Calculate average URI length */ 
     930    for (i=0, avg_len=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) { 
     931        avg_len += uri_test_array[i].len; 
     932    } 
     933    avg_len /= PJ_ARRAY_SIZE(uri_test_array); 
     934 
     935 
     936    /*  
     937     * Print maximum parse/sec  
     938     */ 
     939    for (i=0, max=0; i<COUNT; ++i) 
     940        if (run[i].parse > max) max = run[i].parse; 
     941 
     942    PJ_LOG(3,("", "  Maximum URI parse/sec=%u", max)); 
     943 
     944    pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be <B>parsed</B> with " 
     945                          "<tt>pjsip_parse_uri()</tt> per second " 
     946                          "(tested with %d URI set, with average length of " 
     947                          "%d chars)", 
     948                          PJ_ARRAY_SIZE(uri_test_array), avg_len); 
     949 
     950    report_ival("uri-parse-per-sec", max, "URI/sec", desc); 
     951 
     952    /* URI parsing bandwidth */ 
     953    report_ival("uri-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", 
     954                "URI parsing bandwidth in megabytes (number of megabytes " 
     955                "worth of URI that can be parsed per second)"); 
     956 
     957 
     958    /* Print maximum print/sec */ 
     959    for (i=0, max=0; i<COUNT; ++i) 
     960        if (run[i].print > max) max = run[i].print; 
     961 
     962    PJ_LOG(3,("", "  Maximum URI print/sec=%u", max)); 
     963 
     964    pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be <B>printed</B> with " 
     965                          "<tt>pjsip_uri_print()</tt> per second " 
     966                          "(tested with %d URI set, with average length of " 
     967                          "%d chars)", 
     968                          PJ_ARRAY_SIZE(uri_test_array), avg_len); 
     969 
     970    report_ival("uri-print-per-sec", max, "URI/sec", desc); 
     971 
     972    /* Print maximum detect/sec */ 
     973    for (i=0, max=0; i<COUNT; ++i) 
     974        if (run[i].cmp > max) max = run[i].cmp; 
     975 
     976    PJ_LOG(3,("", "  Maximum URI comparison/sec=%u", max)); 
     977 
     978    pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be <B>compared</B> with " 
     979                          "<tt>pjsip_uri_cmp()</tt> per second " 
     980                          "(tested with %d URI set, with average length of " 
     981                          "%d chars)", 
     982                          PJ_ARRAY_SIZE(uri_test_array), avg_len); 
     983 
     984    report_ival("uri-cmp-per-sec", max, "URI/sec", desc); 
     985 
     986    return PJ_SUCCESS; 
     987} 
     988 
Note: See TracChangeset for help on using the changeset viewer.