Changeset 742


Ignore:
Timestamp:
Sep 26, 2006 1:21:02 PM (18 years ago)
Author:
bennylp
Message:

Added support for specifying IP address in PJSUA-LIB/pjsua.
This option can be used for example to select the IP
interface of SIP/RTP/RTCP transports, or to specify the
public IP address of NAT/router in case port forwarding is
used.

For SIP transports, this feature works for both UDP and
TCP transports.

Changes:

  • added public_ip field in pjsua_transport_config, and change SIP and media transport creation to consider this option.
  • added --ip-addr option in pjsua
  • added pjsip_tcp_transport_start2() which allows specifying alternate TCP published address when creating TCP transports.
Location:
pjproject/trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r737 r742  
    9191{ 
    9292    puts  ("Usage:"); 
    93     puts  ("  pjsua [options]"); 
     93    puts  ("  pjsua [options] [SIP URL to call]"); 
    9494    puts  (""); 
    9595    puts  ("General options:"); 
     
    123123    puts  ("                      TCP and UDP transports on the specified port, unless"); 
    124124    puts  ("                      if TCP or UDP is disabled."); 
     125    puts  ("  --ip-addr=IP        Use the specifed address as SIP and RTP addresses."); 
     126    puts  ("                      (Hint: the IP may be the public IP of the NAT/router)"); 
    125127    puts  ("  --no-tcp            Disable TCP transport."); 
    126128    puts  ("  --no-udp            Disable UDP transport."); 
     
    159161 
    160162    puts  (""); 
     163    puts  ("When URL is specified, pjsua will immediately initiate call to that URL"); 
     164    puts  (""); 
     165 
    161166    fflush(stdout); 
    162167} 
     
    269274    enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL,  
    270275           OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,  
    271            OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, 
    272            OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,  
     276           OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY,  
     277           OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT, 
    273278           OPT_REALM, OPT_USERNAME, OPT_PASSWORD, 
    274279           OPT_USE_STUN1, OPT_USE_STUN2,  
     
    292297        { "null-audio", 0, 0, OPT_NULL_AUDIO}, 
    293298        { "local-port", 1, 0, OPT_LOCAL_PORT}, 
     299        { "ip-addr",    1, 0, OPT_IP_ADDR}, 
    294300        { "no-tcp",     0, 0, OPT_NO_TCP}, 
    295301        { "no-udp",     0, 0, OPT_NO_UDP}, 
     
    434440            break; 
    435441 
     442        case OPT_IP_ADDR: /* ip-addr */ 
     443            cfg->udp_cfg.public_addr = pj_str(pj_optarg); 
     444            cfg->rtp_cfg.public_addr = pj_str(pj_optarg); 
     445            break; 
     446 
    436447        case OPT_NO_UDP: /* no-udp */ 
    437448            if (cfg->no_tcp) { 
     
    917928    pj_ansi_sprintf(line, "--local-port %d\n", config->udp_cfg.port); 
    918929    pj_strcat2(&cfg, line); 
     930 
     931    /* IP address, if any. */ 
     932    if (config->udp_cfg.public_addr.slen) { 
     933        pj_ansi_sprintf(line, "--ip-addr %.*s\n",  
     934                        (int)config->udp_cfg.public_addr.slen, 
     935                        config->udp_cfg.public_addr.ptr); 
     936        pj_strcat2(&cfg, line); 
     937    } 
    919938 
    920939 
  • pjproject/trunk/pjsip/include/pjsip/sip_transport.h

    r736 r742  
    727727    PJ_DECL_LIST_MEMBER(struct pjsip_tpfactory); 
    728728 
     729    char                    obj_name[PJ_MAX_OBJ_NAME];  /**< Name.      */ 
     730 
    729731    pj_pool_t              *pool;           /**< Owned memory pool.     */ 
    730732    pj_lock_t              *lock;           /**< Lock object.           */ 
  • pjproject/trunk/pjsip/include/pjsip/sip_transport_tcp.h

    r563 r742  
    7979 
    8080 
     81 
     82/** 
     83 * A newer variant of #pjsip_tcp_transport_start(), which allows specifying 
     84 * the published/public address of the TCP transport. 
     85 * 
     86 * @param endpt         The SIP endpoint. 
     87 * @param local         Optional local address to bind, or specify the 
     88 *                      address to bind the server socket to. Both IP  
     89 *                      interface address and port fields are optional. 
     90 *                      If IP interface address is not specified, socket 
     91 *                      will be bound to PJ_INADDR_ANY. If port is not 
     92 *                      specified, socket will be bound to any port 
     93 *                      selected by the operating system. 
     94 * @param a_name        Optional published address, which is the address to be 
     95 *                      advertised as the address of this SIP transport.  
     96 *                      If this argument is NULL, then the bound address 
     97 *                      will be used as the published address. 
     98 * @param async_cnt     Number of simultaneous asynchronous accept() 
     99 *                      operations to be supported. It is recommended that 
     100 *                      the number here corresponds to the number of 
     101 *                      processors in the system (or the number of SIP 
     102 *                      worker threads). 
     103 * @param p_factory     Optional pointer to receive the instance of the 
     104 *                      SIP TCP transport factory just created. 
     105 * 
     106 * @return              PJ_SUCCESS when the transport has been successfully 
     107 *                      started and registered to transport manager, or 
     108 *                      the appropriate error code. 
     109 */ 
     110PJ_DECL(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt, 
     111                                                const pj_sockaddr_in *local, 
     112                                                const pjsip_host_port *a_name, 
     113                                                unsigned async_cnt, 
     114                                                pjsip_tpfactory **p_factory); 
     115 
     116 
     117 
    81118PJ_END_DECL 
    82119 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r738 r742  
    725725 
    726726/** 
    727  * Transport configuration for creating UDP transports for both SIP 
     727 * Transport configuration for creating transports for both SIP 
    728728 * and media. 
    729729 */ 
     
    739739 
    740740    /** 
    741      * Optional address where the socket should be bound. 
    742      */ 
    743     pj_in_addr          ip_addr; 
     741     * Optional address to advertise as the address of this transport. 
     742     * Application can specify any address or hostname for this field, 
     743     * for example it can point to one of the interface address in the 
     744     * system, or it can point to the public address of a NAT router 
     745     * where port mappings have been configured for the application. 
     746     * 
     747     * Note: this option can be used for both UDP and TCP as well! 
     748     */ 
     749    pj_str_t            public_addr; 
     750 
     751    /** 
     752     * Optional address where the socket should be bound to. This option 
     753     * SHOULD only be used to selectively bind the socket to particular 
     754     * interface (instead of 0.0.0.0), and SHOULD NOT be used to set the 
     755     * published address of a transport (the public_addr field should be 
     756     * used for that purpose). 
     757     * 
     758     * Note that unlike public_addr field, the address (or hostname) here  
     759     * MUST correspond to the actual interface address in the host, since 
     760     * this address will be specified as bind() argument. 
     761     */ 
     762    pj_str_t            bound_addr; 
    744763 
    745764    /** 
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c

    r721 r742  
    7070{ 
    7171    pjsip_tpfactory          factory; 
    72     char                     obj_name[PJ_MAX_OBJ_NAME]; 
    7372    pj_bool_t                is_registered; 
    7473    pjsip_endpoint          *endpt; 
     
    185184 * TCP listener. 
    186185 */ 
    187 PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt, 
     186PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt, 
    188187                                               const pj_sockaddr_in *local, 
     188                                               const pjsip_host_port *a_name, 
    189189                                               unsigned async_cnt, 
    190190                                               pjsip_tpfactory **p_factory) 
     
    201201    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); 
    202202 
     203    /* Verify that address given in a_name (if any) is valid */ 
     204    if (a_name && a_name->host.slen) { 
     205        pj_sockaddr_in tmp; 
     206 
     207        status = pj_sockaddr_in_init(&tmp, &a_name->host,  
     208                                     (pj_uint16_t)a_name->port); 
     209        if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY || 
     210            tmp.sin_addr.s_addr == PJ_INADDR_NONE) 
     211        { 
     212            /* Invalid address */ 
     213            return PJ_EINVAL; 
     214        } 
     215    } 
    203216 
    204217    pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT,  
     
    215228    listener->sock = PJ_INVALID_SOCKET; 
    216229 
    217     pj_ansi_strcpy(listener->obj_name, "tcp"); 
     230    pj_ansi_strcpy(listener->factory.obj_name, "tcplis"); 
    218231 
    219232    status = pj_lock_create_recursive_mutex(pool, "tcplis",  
     
    246259        goto on_error; 
    247260 
    248     /* If the address returns 0.0.0.0, use the first interface address 
    249      * as the transport's address. 
     261    /* If published host/IP is specified, then use that address as the 
     262     * listener advertised address. 
    250263     */ 
    251     if (listener_addr->sin_addr.s_addr == 0) { 
    252         pj_in_addr hostip; 
    253  
    254         status = pj_gethostip(&hostip); 
    255         if (status != PJ_SUCCESS) 
    256             goto on_error; 
    257  
    258         listener_addr->sin_addr = hostip; 
    259     } 
    260  
    261     pj_ansi_snprintf(listener->obj_name, sizeof(listener->obj_name),  
    262                      "tcp:%d",  (int)pj_ntohs(listener_addr->sin_port)); 
    263  
    264     /* Save the address name */ 
    265     sockaddr_to_host_port(listener->factory.pool,  
    266                           &listener->factory.addr_name, listener_addr); 
     264    if (a_name && a_name->host.slen) { 
     265        /* Copy the address */ 
     266        listener->factory.addr_name = *a_name; 
     267        pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,  
     268                  &a_name->host); 
     269        listener->factory.addr_name.port = a_name->port; 
     270 
     271    } else { 
     272        /* No published address is given, use the bound address */ 
     273 
     274        /* If the address returns 0.0.0.0, use the default 
     275         * interface address as the transport's address. 
     276         */ 
     277        if (listener_addr->sin_addr.s_addr == 0) { 
     278            pj_in_addr hostip; 
     279 
     280            status = pj_gethostip(&hostip); 
     281            if (status != PJ_SUCCESS) 
     282                goto on_error; 
     283 
     284            listener_addr->sin_addr = hostip; 
     285        } 
     286 
     287        /* Save the address name */ 
     288        sockaddr_to_host_port(listener->factory.pool,  
     289                              &listener->factory.addr_name, listener_addr); 
     290    } 
     291 
     292    /* If port is zero, get the bound port */ 
     293    if (listener->factory.addr_name.port == 0) { 
     294        listener->factory.addr_name.port = pj_ntohs(listener_addr->sin_port); 
     295    } 
     296 
     297    pj_ansi_snprintf(listener->factory.obj_name,  
     298                     sizeof(listener->factory.obj_name), 
     299                     "tcplis:%d",  listener->factory.addr_name.port); 
     300 
    267301 
    268302    /* Start listening to the address */ 
     
    320354    } 
    321355 
    322     PJ_LOG(4,(listener->obj_name,  
    323              "SIP TCP listener ready for incoming connections at %s:%d", 
    324              pj_inet_ntoa(listener_addr->sin_addr),  
    325              (int)pj_ntohs(listener_addr->sin_port))); 
     356    PJ_LOG(4,(listener->factory.obj_name,  
     357             "SIP TCP listener ready for incoming connections at %.*s:%d", 
     358             (int)listener->factory.addr_name.host.slen, 
     359             listener->factory.addr_name.host.ptr, 
     360             listener->factory.addr_name.port)); 
    326361 
    327362    /* Return the pointer to user */ 
     
    333368    lis_destroy(&listener->factory); 
    334369    return status; 
     370} 
     371 
     372 
     373/* 
     374 * This is the public API to create, initialize, register, and start the 
     375 * TCP listener. 
     376 */ 
     377PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt, 
     378                                               const pj_sockaddr_in *local, 
     379                                               unsigned async_cnt, 
     380                                               pjsip_tpfactory **p_factory) 
     381{ 
     382    return pjsip_tcp_transport_start2(endpt, local, NULL, async_cnt, p_factory); 
    335383} 
    336384 
     
    374422        pj_pool_t *pool = listener->factory.pool; 
    375423 
    376         PJ_LOG(4,(listener->obj_name,  "SIP TCP listener destroyed")); 
     424        PJ_LOG(4,(listener->factory.obj_name,  "SIP TCP listener destroyed")); 
    377425 
    378426        listener->factory.pool = NULL; 
     
    856904             * Error in accept(). 
    857905             */ 
    858             tcp_perror(listener->obj_name, "Error in accept()", status); 
     906            tcp_perror(listener->factory.obj_name, "Error in accept()",  
     907                       status); 
    859908 
    860909            /* 
     
    866915            ++err_cnt; 
    867916            if (err_cnt >= 10) { 
    868                 PJ_LOG(1, (listener->obj_name,  
     917                PJ_LOG(1, (listener->factory.obj_name,  
    869918                           "Too many errors, listener stopping")); 
    870919            } 
     
    883932            } 
    884933 
    885             PJ_LOG(4,(listener->obj_name,  
     934            PJ_LOG(4,(listener->factory.obj_name,  
    886935                      "TCP listener %.*s:%d: got incoming TCP connection " 
    887936                      "from %s:%d, sock=%d", 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r721 r742  
    799799     */ 
    800800    if (stun.stun_srv1.slen) { 
     801        /* 
     802         * STUN is specified, resolve the address with STUN. 
     803         */ 
    801804        status = pj_stun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock, 
    802805                                         &stun.stun_srv1,  
     
    811814        } 
    812815 
     816    } else if (p_pub_addr->sin_addr.s_addr != 0) { 
     817        /* 
     818         * Public address is already specified, no need to resolve the  
     819         * address, only set the port. 
     820         */ 
     821        /* Do nothing */ 
     822 
    813823    } else { 
    814824 
     
    867877        pjsua_transport_config config; 
    868878        pj_sock_t sock = PJ_INVALID_SOCKET; 
     879        pj_sockaddr_in bound_addr; 
    869880        pj_sockaddr_in pub_addr; 
    870881        pjsip_host_port addr_name; 
     
    876887        } 
    877888 
    878         /* Create the socket and possibly resolve the address with STUN */ 
    879         status = create_sip_udp_sock(cfg->ip_addr, cfg->port, cfg->use_stun, 
    880                                      &cfg->stun_config, &sock, &pub_addr); 
     889        /* Initialize bound address, if any */ 
     890        bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 
     891        if (cfg->bound_addr.slen) { 
     892            status = pj_sockaddr_in_set_str_addr(&bound_addr,&cfg->bound_addr); 
     893            if (status != PJ_SUCCESS) { 
     894                pjsua_perror(THIS_FILE,  
     895                             "Unable to resolve transport bound address",  
     896                             status); 
     897                goto on_return; 
     898            } 
     899        } 
     900 
     901        /* Initialize the public address from the config, if any */ 
     902        pj_sockaddr_in_init(&pub_addr, NULL, (pj_uint16_t)cfg->port); 
     903        if (cfg->public_addr.slen) { 
     904            status = pj_sockaddr_in_set_str_addr(&pub_addr, &cfg->public_addr); 
     905            if (status != PJ_SUCCESS) { 
     906                pjsua_perror(THIS_FILE,  
     907                             "Unable to resolve transport public address",  
     908                             status); 
     909                goto on_return; 
     910            } 
     911        } 
     912 
     913        /* Create the socket and possibly resolve the address with STUN  
     914         * (only when public address is not specified). 
     915         */ 
     916        status = create_sip_udp_sock(bound_addr.sin_addr, cfg->port,  
     917                                     cfg->use_stun, &cfg->stun_config,  
     918                                     &sock, &pub_addr); 
    881919        if (status != PJ_SUCCESS) 
    882920            goto on_return; 
     
    907945         */ 
    908946        pjsua_transport_config config; 
     947        pjsip_host_port a_name; 
    909948        pjsip_tpfactory *tcp; 
    910949        pj_sockaddr_in local_addr; 
     
    922961            local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port); 
    923962 
    924         if (cfg->ip_addr.s_addr) 
    925             local_addr.sin_addr.s_addr = cfg->ip_addr.s_addr; 
     963        if (cfg->bound_addr.slen) { 
     964            status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr); 
     965            if (status != PJ_SUCCESS) { 
     966                pjsua_perror(THIS_FILE,  
     967                             "Unable to resolve transport bound address",  
     968                             status); 
     969                goto on_return; 
     970            } 
     971        } 
     972 
     973        /* Init published name */ 
     974        pj_bzero(&a_name, sizeof(pjsip_host_port)); 
     975        if (cfg->public_addr.slen) 
     976            a_name.host = cfg->public_addr; 
    926977 
    927978        /* Create the TCP transport */ 
    928         status = pjsip_tcp_transport_start(pjsua_var.endpt, &local_addr, 1, 
    929                                            &tcp); 
     979        status = pjsip_tcp_transport_start2(pjsua_var.endpt, &local_addr,  
     980                                            &a_name, 1, &tcp); 
    930981 
    931982        if (status != PJ_SUCCESS) { 
     
    10301081{ 
    10311082    struct transport_data *t = &pjsua_var.tpdata[id]; 
     1083    pj_status_t status; 
    10321084 
    10331085    pj_bzero(info, sizeof(*info)); 
     
    10601112        info->usage_count = pj_atomic_get(tp->ref_cnt); 
    10611113 
     1114        status = PJ_SUCCESS; 
     1115 
    10621116    } else if (pjsua_var.tpdata[id].type == PJSIP_TRANSPORT_TCP) { 
    10631117 
     
    10791133        info->usage_count = 0; 
    10801134 
     1135        status = PJ_SUCCESS; 
     1136 
     1137    } else { 
     1138        pj_assert(!"Unsupported transport"); 
     1139        status = PJ_EINVALIDOP; 
    10811140    } 
    10821141 
     
    10841143    PJSUA_UNLOCK(); 
    10851144 
    1086     return PJ_EINVALIDOP; 
     1145    return status; 
    10871146} 
    10881147 
     
    11211180    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 
    11221181 
    1123  
    1124     /* To be done!! */ 
    1125     PJ_UNUSED_ARG(force); 
    1126  
    1127     PJ_TODO(pjsua_transport_close); 
    1128  
     1182    /* Note: destroy() may not work if there are objects still referencing 
     1183     *       the transport. 
     1184     */ 
     1185    if (force) { 
     1186        switch (pjsua_var.tpdata[id].type) { 
     1187        case PJSIP_TRANSPORT_UDP: 
     1188            return pjsip_transport_destroy(pjsua_var.tpdata[id].data.tp); 
     1189        case PJSIP_TRANSPORT_TCP: 
     1190            break; 
     1191        } 
     1192         
     1193    } else { 
     1194        switch (pjsua_var.tpdata[id].type) { 
     1195        case PJSIP_TRANSPORT_UDP: 
     1196            return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp); 
     1197        case PJSIP_TRANSPORT_TCP: 
     1198            return (*pjsua_var.tpdata[id].data.factory->destroy) 
     1199                        (pjsua_var.tpdata[id].data.factory); 
     1200        } 
     1201    } 
     1202 
     1203    /* Unreachable */ 
     1204    pj_assert(!"Unknown transport"); 
    11291205    return PJ_EINVALIDOP; 
    11301206} 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c

    r721 r742  
    210210    int i; 
    211211    static pj_uint16_t rtp_port; 
     212    pj_sockaddr_in bound_addr; 
    212213    pj_sockaddr_in mapped_addr[2]; 
    213214    pj_status_t status = PJ_SUCCESS; 
     
    220221        sock[i] = PJ_INVALID_SOCKET; 
    221222 
     223    bound_addr.sin_addr.s_addr = PJ_INADDR_ANY; 
     224    if (cfg->bound_addr.slen) { 
     225        status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr); 
     226        if (status != PJ_SUCCESS) { 
     227            pjsua_perror(THIS_FILE, "Unable to resolve transport bind address", 
     228                         status); 
     229            return status; 
     230        } 
     231    } 
    222232 
    223233    /* Loop retry to bind RTP and RTCP sockets. */ 
     
    231241        } 
    232242 
    233         status = pj_sock_bind_in(sock[0], cfg->ip_addr.s_addr, rtp_port); 
     243        status = pj_sock_bind_in(sock[0], bound_addr.sin_addr.s_addr,  
     244                                 rtp_port); 
    234245        if (status != PJ_SUCCESS) { 
    235246            pj_sock_close(sock[0]);  
     
    246257        } 
    247258 
    248         status = pj_sock_bind_in(sock[1], cfg->ip_addr.s_addr,  
     259        status = pj_sock_bind_in(sock[1], bound_addr.sin_addr.s_addr,  
    249260                                 (pj_uint16_t)(rtp_port+1)); 
    250261        if (status != PJ_SUCCESS) { 
     
    286297            sock[1] = PJ_INVALID_SOCKET; 
    287298 
     299        } else if (cfg->public_addr.slen) { 
     300 
     301            status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr, 
     302                                         (pj_uint16_t)rtp_port); 
     303            if (status != PJ_SUCCESS) 
     304                goto on_error; 
     305 
     306            status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr, 
     307                                         (pj_uint16_t)(rtp_port+1)); 
     308            if (status != PJ_SUCCESS) 
     309                goto on_error; 
     310 
     311            break; 
     312 
    288313        } else { 
    289314            pj_in_addr addr; 
Note: See TracChangeset for help on using the changeset viewer.