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. git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@742 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
f6fd889119
commit
0a5cad8dec
|
@ -90,7 +90,7 @@ static void stereo_demo();
|
|||
static void usage(void)
|
||||
{
|
||||
puts ("Usage:");
|
||||
puts (" pjsua [options]");
|
||||
puts (" pjsua [options] [SIP URL to call]");
|
||||
puts ("");
|
||||
puts ("General options:");
|
||||
puts (" --config-file=file Read the config/arguments from file.");
|
||||
|
@ -122,6 +122,8 @@ static void usage(void)
|
|||
puts (" --local-port=port Set TCP/UDP port. This implicitly enables both ");
|
||||
puts (" TCP and UDP transports on the specified port, unless");
|
||||
puts (" if TCP or UDP is disabled.");
|
||||
puts (" --ip-addr=IP Use the specifed address as SIP and RTP addresses.");
|
||||
puts (" (Hint: the IP may be the public IP of the NAT/router)");
|
||||
puts (" --no-tcp Disable TCP transport.");
|
||||
puts (" --no-udp Disable UDP transport.");
|
||||
puts (" --outbound=url Set the URL of global outbound proxy server");
|
||||
|
@ -158,6 +160,9 @@ static void usage(void)
|
|||
puts (" --duration=SEC Set maximum call duration (default:no limit)");
|
||||
|
||||
puts ("");
|
||||
puts ("When URL is specified, pjsua will immediately initiate call to that URL");
|
||||
puts ("");
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
@ -268,8 +273,8 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
int option_index;
|
||||
enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL,
|
||||
OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,
|
||||
OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR,
|
||||
OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,
|
||||
OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY,
|
||||
OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,
|
||||
OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
|
||||
OPT_USE_STUN1, OPT_USE_STUN2,
|
||||
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
|
||||
|
@ -291,6 +296,7 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
{ "clock-rate", 1, 0, OPT_CLOCK_RATE},
|
||||
{ "null-audio", 0, 0, OPT_NULL_AUDIO},
|
||||
{ "local-port", 1, 0, OPT_LOCAL_PORT},
|
||||
{ "ip-addr", 1, 0, OPT_IP_ADDR},
|
||||
{ "no-tcp", 0, 0, OPT_NO_TCP},
|
||||
{ "no-udp", 0, 0, OPT_NO_UDP},
|
||||
{ "proxy", 1, 0, OPT_PROXY},
|
||||
|
@ -433,6 +439,11 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
cfg->udp_cfg.port = (pj_uint16_t)lval;
|
||||
break;
|
||||
|
||||
case OPT_IP_ADDR: /* ip-addr */
|
||||
cfg->udp_cfg.public_addr = pj_str(pj_optarg);
|
||||
cfg->rtp_cfg.public_addr = pj_str(pj_optarg);
|
||||
break;
|
||||
|
||||
case OPT_NO_UDP: /* no-udp */
|
||||
if (cfg->no_tcp) {
|
||||
PJ_LOG(1,(THIS_FILE,"Error: can not disable both TCP and UDP"));
|
||||
|
@ -917,6 +928,14 @@ static int write_settings(const struct app_config *config,
|
|||
pj_ansi_sprintf(line, "--local-port %d\n", config->udp_cfg.port);
|
||||
pj_strcat2(&cfg, line);
|
||||
|
||||
/* IP address, if any. */
|
||||
if (config->udp_cfg.public_addr.slen) {
|
||||
pj_ansi_sprintf(line, "--ip-addr %.*s\n",
|
||||
(int)config->udp_cfg.public_addr.slen,
|
||||
config->udp_cfg.public_addr.ptr);
|
||||
pj_strcat2(&cfg, line);
|
||||
}
|
||||
|
||||
|
||||
/* STUN */
|
||||
if (config->udp_cfg.stun_config.stun_port1) {
|
||||
|
|
|
@ -726,6 +726,8 @@ struct pjsip_tpfactory
|
|||
/** This list is managed by transport manager. */
|
||||
PJ_DECL_LIST_MEMBER(struct pjsip_tpfactory);
|
||||
|
||||
char obj_name[PJ_MAX_OBJ_NAME]; /**< Name. */
|
||||
|
||||
pj_pool_t *pool; /**< Owned memory pool. */
|
||||
pj_lock_t *lock; /**< Lock object. */
|
||||
|
||||
|
|
|
@ -78,6 +78,43 @@ PJ_DECL(pj_status_t) pjsip_tcp_transport_start(pjsip_endpoint *endpt,
|
|||
pjsip_tpfactory **p_factory);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A newer variant of #pjsip_tcp_transport_start(), which allows specifying
|
||||
* the published/public address of the TCP transport.
|
||||
*
|
||||
* @param endpt The SIP endpoint.
|
||||
* @param local Optional local address to bind, or specify the
|
||||
* address to bind the server socket to. Both IP
|
||||
* interface address and port fields are optional.
|
||||
* If IP interface address is not specified, socket
|
||||
* will be bound to PJ_INADDR_ANY. If port is not
|
||||
* specified, socket will be bound to any port
|
||||
* selected by the operating system.
|
||||
* @param a_name Optional published address, which is the address to be
|
||||
* advertised as the address of this SIP transport.
|
||||
* If this argument is NULL, then the bound address
|
||||
* will be used as the published address.
|
||||
* @param async_cnt Number of simultaneous asynchronous accept()
|
||||
* operations to be supported. It is recommended that
|
||||
* the number here corresponds to the number of
|
||||
* processors in the system (or the number of SIP
|
||||
* worker threads).
|
||||
* @param p_factory Optional pointer to receive the instance of the
|
||||
* SIP TCP transport factory just created.
|
||||
*
|
||||
* @return PJ_SUCCESS when the transport has been successfully
|
||||
* started and registered to transport manager, or
|
||||
* the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt,
|
||||
const pj_sockaddr_in *local,
|
||||
const pjsip_host_port *a_name,
|
||||
unsigned async_cnt,
|
||||
pjsip_tpfactory **p_factory);
|
||||
|
||||
|
||||
|
||||
PJ_END_DECL
|
||||
|
||||
/**
|
||||
|
|
|
@ -724,7 +724,7 @@ PJ_INLINE(void) pjsua_stun_config_default(pjsua_stun_config *cfg)
|
|||
|
||||
|
||||
/**
|
||||
* Transport configuration for creating UDP transports for both SIP
|
||||
* Transport configuration for creating transports for both SIP
|
||||
* and media.
|
||||
*/
|
||||
typedef struct pjsua_transport_config
|
||||
|
@ -738,9 +738,28 @@ typedef struct pjsua_transport_config
|
|||
unsigned port;
|
||||
|
||||
/**
|
||||
* Optional address where the socket should be bound.
|
||||
* Optional address to advertise as the address of this transport.
|
||||
* Application can specify any address or hostname for this field,
|
||||
* for example it can point to one of the interface address in the
|
||||
* system, or it can point to the public address of a NAT router
|
||||
* where port mappings have been configured for the application.
|
||||
*
|
||||
* Note: this option can be used for both UDP and TCP as well!
|
||||
*/
|
||||
pj_in_addr ip_addr;
|
||||
pj_str_t public_addr;
|
||||
|
||||
/**
|
||||
* Optional address where the socket should be bound to. This option
|
||||
* SHOULD only be used to selectively bind the socket to particular
|
||||
* interface (instead of 0.0.0.0), and SHOULD NOT be used to set the
|
||||
* published address of a transport (the public_addr field should be
|
||||
* used for that purpose).
|
||||
*
|
||||
* Note that unlike public_addr field, the address (or hostname) here
|
||||
* MUST correspond to the actual interface address in the host, since
|
||||
* this address will be specified as bind() argument.
|
||||
*/
|
||||
pj_str_t bound_addr;
|
||||
|
||||
/**
|
||||
* Flag to indicate whether STUN should be used.
|
||||
|
|
|
@ -69,7 +69,6 @@ struct pending_accept
|
|||
struct tcp_listener
|
||||
{
|
||||
pjsip_tpfactory factory;
|
||||
char obj_name[PJ_MAX_OBJ_NAME];
|
||||
pj_bool_t is_registered;
|
||||
pjsip_endpoint *endpt;
|
||||
pjsip_tpmgr *tpmgr;
|
||||
|
@ -184,8 +183,9 @@ static void sockaddr_to_host_port( pj_pool_t *pool,
|
|||
* This is the public API to create, initialize, register, and start the
|
||||
* TCP listener.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
|
||||
PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt,
|
||||
const pj_sockaddr_in *local,
|
||||
const pjsip_host_port *a_name,
|
||||
unsigned async_cnt,
|
||||
pjsip_tpfactory **p_factory)
|
||||
{
|
||||
|
@ -200,6 +200,19 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
|
|||
/* Sanity check */
|
||||
PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
|
||||
|
||||
/* Verify that address given in a_name (if any) is valid */
|
||||
if (a_name && a_name->host.slen) {
|
||||
pj_sockaddr_in tmp;
|
||||
|
||||
status = pj_sockaddr_in_init(&tmp, &a_name->host,
|
||||
(pj_uint16_t)a_name->port);
|
||||
if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY ||
|
||||
tmp.sin_addr.s_addr == PJ_INADDR_NONE)
|
||||
{
|
||||
/* Invalid address */
|
||||
return PJ_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT,
|
||||
POOL_LIS_INC);
|
||||
|
@ -214,7 +227,7 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
|
|||
pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
|
||||
listener->sock = PJ_INVALID_SOCKET;
|
||||
|
||||
pj_ansi_strcpy(listener->obj_name, "tcp");
|
||||
pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
|
||||
|
||||
status = pj_lock_create_recursive_mutex(pool, "tcplis",
|
||||
&listener->factory.lock);
|
||||
|
@ -245,25 +258,46 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
|
|||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* If the address returns 0.0.0.0, use the first interface address
|
||||
* as the transport's address.
|
||||
/* If published host/IP is specified, then use that address as the
|
||||
* listener advertised address.
|
||||
*/
|
||||
if (listener_addr->sin_addr.s_addr == 0) {
|
||||
pj_in_addr hostip;
|
||||
if (a_name && a_name->host.slen) {
|
||||
/* Copy the address */
|
||||
listener->factory.addr_name = *a_name;
|
||||
pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
|
||||
&a_name->host);
|
||||
listener->factory.addr_name.port = a_name->port;
|
||||
|
||||
status = pj_gethostip(&hostip);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
} else {
|
||||
/* No published address is given, use the bound address */
|
||||
|
||||
listener_addr->sin_addr = hostip;
|
||||
/* If the address returns 0.0.0.0, use the default
|
||||
* interface address as the transport's address.
|
||||
*/
|
||||
if (listener_addr->sin_addr.s_addr == 0) {
|
||||
pj_in_addr hostip;
|
||||
|
||||
status = pj_gethostip(&hostip);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
listener_addr->sin_addr = hostip;
|
||||
}
|
||||
|
||||
/* Save the address name */
|
||||
sockaddr_to_host_port(listener->factory.pool,
|
||||
&listener->factory.addr_name, listener_addr);
|
||||
}
|
||||
|
||||
pj_ansi_snprintf(listener->obj_name, sizeof(listener->obj_name),
|
||||
"tcp:%d", (int)pj_ntohs(listener_addr->sin_port));
|
||||
/* If port is zero, get the bound port */
|
||||
if (listener->factory.addr_name.port == 0) {
|
||||
listener->factory.addr_name.port = pj_ntohs(listener_addr->sin_port);
|
||||
}
|
||||
|
||||
pj_ansi_snprintf(listener->factory.obj_name,
|
||||
sizeof(listener->factory.obj_name),
|
||||
"tcplis:%d", listener->factory.addr_name.port);
|
||||
|
||||
/* Save the address name */
|
||||
sockaddr_to_host_port(listener->factory.pool,
|
||||
&listener->factory.addr_name, listener_addr);
|
||||
|
||||
/* Start listening to the address */
|
||||
status = pj_sock_listen(listener->sock, PJSIP_TCP_TRANSPORT_BACKLOG);
|
||||
|
@ -319,10 +353,11 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
|
|||
listener->sock, PJ_EPENDING);
|
||||
}
|
||||
|
||||
PJ_LOG(4,(listener->obj_name,
|
||||
"SIP TCP listener ready for incoming connections at %s:%d",
|
||||
pj_inet_ntoa(listener_addr->sin_addr),
|
||||
(int)pj_ntohs(listener_addr->sin_port)));
|
||||
PJ_LOG(4,(listener->factory.obj_name,
|
||||
"SIP TCP listener ready for incoming connections at %.*s:%d",
|
||||
(int)listener->factory.addr_name.host.slen,
|
||||
listener->factory.addr_name.host.ptr,
|
||||
listener->factory.addr_name.port));
|
||||
|
||||
/* Return the pointer to user */
|
||||
if (p_factory) *p_factory = &listener->factory;
|
||||
|
@ -335,6 +370,19 @@ on_error:
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is the public API to create, initialize, register, and start the
|
||||
* TCP listener.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjsip_tcp_transport_start( pjsip_endpoint *endpt,
|
||||
const pj_sockaddr_in *local,
|
||||
unsigned async_cnt,
|
||||
pjsip_tpfactory **p_factory)
|
||||
{
|
||||
return pjsip_tcp_transport_start2(endpt, local, NULL, async_cnt, p_factory);
|
||||
}
|
||||
|
||||
|
||||
/* This callback is called by transport manager to destroy listener */
|
||||
static pj_status_t lis_destroy(pjsip_tpfactory *factory)
|
||||
{
|
||||
|
@ -373,7 +421,7 @@ static pj_status_t lis_destroy(pjsip_tpfactory *factory)
|
|||
if (listener->factory.pool) {
|
||||
pj_pool_t *pool = listener->factory.pool;
|
||||
|
||||
PJ_LOG(4,(listener->obj_name, "SIP TCP listener destroyed"));
|
||||
PJ_LOG(4,(listener->factory.obj_name, "SIP TCP listener destroyed"));
|
||||
|
||||
listener->factory.pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
|
@ -855,7 +903,8 @@ static void on_accept_complete( pj_ioqueue_key_t *key,
|
|||
/*
|
||||
* Error in accept().
|
||||
*/
|
||||
tcp_perror(listener->obj_name, "Error in accept()", status);
|
||||
tcp_perror(listener->factory.obj_name, "Error in accept()",
|
||||
status);
|
||||
|
||||
/*
|
||||
* Prevent endless accept() error loop by limiting the
|
||||
|
@ -865,7 +914,7 @@ static void on_accept_complete( pj_ioqueue_key_t *key,
|
|||
*/
|
||||
++err_cnt;
|
||||
if (err_cnt >= 10) {
|
||||
PJ_LOG(1, (listener->obj_name,
|
||||
PJ_LOG(1, (listener->factory.obj_name,
|
||||
"Too many errors, listener stopping"));
|
||||
}
|
||||
|
||||
|
@ -882,7 +931,7 @@ static void on_accept_complete( pj_ioqueue_key_t *key,
|
|||
goto next_accept;
|
||||
}
|
||||
|
||||
PJ_LOG(4,(listener->obj_name,
|
||||
PJ_LOG(4,(listener->factory.obj_name,
|
||||
"TCP listener %.*s:%d: got incoming TCP connection "
|
||||
"from %s:%d, sock=%d",
|
||||
(int)listener->factory.addr_name.host.slen,
|
||||
|
|
|
@ -798,6 +798,9 @@ static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr,
|
|||
* the name of local host.
|
||||
*/
|
||||
if (stun.stun_srv1.slen) {
|
||||
/*
|
||||
* STUN is specified, resolve the address with STUN.
|
||||
*/
|
||||
status = pj_stun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock,
|
||||
&stun.stun_srv1,
|
||||
stun.stun_port1,
|
||||
|
@ -810,6 +813,13 @@ static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr,
|
|||
return status;
|
||||
}
|
||||
|
||||
} else if (p_pub_addr->sin_addr.s_addr != 0) {
|
||||
/*
|
||||
* Public address is already specified, no need to resolve the
|
||||
* address, only set the port.
|
||||
*/
|
||||
/* Do nothing */
|
||||
|
||||
} else {
|
||||
|
||||
pj_bzero(p_pub_addr, sizeof(pj_sockaddr_in));
|
||||
|
@ -866,6 +876,7 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
|
|||
*/
|
||||
pjsua_transport_config config;
|
||||
pj_sock_t sock = PJ_INVALID_SOCKET;
|
||||
pj_sockaddr_in bound_addr;
|
||||
pj_sockaddr_in pub_addr;
|
||||
pjsip_host_port addr_name;
|
||||
|
||||
|
@ -875,9 +886,36 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
|
|||
cfg = &config;
|
||||
}
|
||||
|
||||
/* Create the socket and possibly resolve the address with STUN */
|
||||
status = create_sip_udp_sock(cfg->ip_addr, cfg->port, cfg->use_stun,
|
||||
&cfg->stun_config, &sock, &pub_addr);
|
||||
/* Initialize bound address, if any */
|
||||
bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
|
||||
if (cfg->bound_addr.slen) {
|
||||
status = pj_sockaddr_in_set_str_addr(&bound_addr,&cfg->bound_addr);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE,
|
||||
"Unable to resolve transport bound address",
|
||||
status);
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the public address from the config, if any */
|
||||
pj_sockaddr_in_init(&pub_addr, NULL, (pj_uint16_t)cfg->port);
|
||||
if (cfg->public_addr.slen) {
|
||||
status = pj_sockaddr_in_set_str_addr(&pub_addr, &cfg->public_addr);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE,
|
||||
"Unable to resolve transport public address",
|
||||
status);
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the socket and possibly resolve the address with STUN
|
||||
* (only when public address is not specified).
|
||||
*/
|
||||
status = create_sip_udp_sock(bound_addr.sin_addr, cfg->port,
|
||||
cfg->use_stun, &cfg->stun_config,
|
||||
&sock, &pub_addr);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_return;
|
||||
|
||||
|
@ -906,6 +944,7 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
|
|||
* Create TCP transport.
|
||||
*/
|
||||
pjsua_transport_config config;
|
||||
pjsip_host_port a_name;
|
||||
pjsip_tpfactory *tcp;
|
||||
pj_sockaddr_in local_addr;
|
||||
|
||||
|
@ -921,12 +960,24 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
|
|||
if (cfg->port)
|
||||
local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port);
|
||||
|
||||
if (cfg->ip_addr.s_addr)
|
||||
local_addr.sin_addr.s_addr = cfg->ip_addr.s_addr;
|
||||
if (cfg->bound_addr.slen) {
|
||||
status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE,
|
||||
"Unable to resolve transport bound address",
|
||||
status);
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init published name */
|
||||
pj_bzero(&a_name, sizeof(pjsip_host_port));
|
||||
if (cfg->public_addr.slen)
|
||||
a_name.host = cfg->public_addr;
|
||||
|
||||
/* Create the TCP transport */
|
||||
status = pjsip_tcp_transport_start(pjsua_var.endpt, &local_addr, 1,
|
||||
&tcp);
|
||||
status = pjsip_tcp_transport_start2(pjsua_var.endpt, &local_addr,
|
||||
&a_name, 1, &tcp);
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error creating SIP TCP listener",
|
||||
|
@ -1029,6 +1080,7 @@ PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
|
|||
pjsua_transport_info *info)
|
||||
{
|
||||
struct transport_data *t = &pjsua_var.tpdata[id];
|
||||
pj_status_t status;
|
||||
|
||||
pj_bzero(info, sizeof(*info));
|
||||
|
||||
|
@ -1059,6 +1111,8 @@ PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
|
|||
info->local_name = tp->local_name;
|
||||
info->usage_count = pj_atomic_get(tp->ref_cnt);
|
||||
|
||||
status = PJ_SUCCESS;
|
||||
|
||||
} else if (pjsua_var.tpdata[id].type == PJSIP_TRANSPORT_TCP) {
|
||||
|
||||
pjsip_tpfactory *factory = t->data.factory;
|
||||
|
@ -1078,12 +1132,17 @@ PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
|
|||
info->local_name = factory->addr_name;
|
||||
info->usage_count = 0;
|
||||
|
||||
status = PJ_SUCCESS;
|
||||
|
||||
} else {
|
||||
pj_assert(!"Unsupported transport");
|
||||
status = PJ_EINVALIDOP;
|
||||
}
|
||||
|
||||
|
||||
PJSUA_UNLOCK();
|
||||
|
||||
return PJ_EINVALIDOP;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1120,12 +1179,29 @@ PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
|
|||
/* Make sure that transport exists */
|
||||
PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
|
||||
|
||||
/* Note: destroy() may not work if there are objects still referencing
|
||||
* the transport.
|
||||
*/
|
||||
if (force) {
|
||||
switch (pjsua_var.tpdata[id].type) {
|
||||
case PJSIP_TRANSPORT_UDP:
|
||||
return pjsip_transport_destroy(pjsua_var.tpdata[id].data.tp);
|
||||
case PJSIP_TRANSPORT_TCP:
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (pjsua_var.tpdata[id].type) {
|
||||
case PJSIP_TRANSPORT_UDP:
|
||||
return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
|
||||
case PJSIP_TRANSPORT_TCP:
|
||||
return (*pjsua_var.tpdata[id].data.factory->destroy)
|
||||
(pjsua_var.tpdata[id].data.factory);
|
||||
}
|
||||
}
|
||||
|
||||
/* To be done!! */
|
||||
PJ_UNUSED_ARG(force);
|
||||
|
||||
PJ_TODO(pjsua_transport_close);
|
||||
|
||||
/* Unreachable */
|
||||
pj_assert(!"Unknown transport");
|
||||
return PJ_EINVALIDOP;
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,7 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
|
|||
};
|
||||
int i;
|
||||
static pj_uint16_t rtp_port;
|
||||
pj_sockaddr_in bound_addr;
|
||||
pj_sockaddr_in mapped_addr[2];
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
pj_sock_t sock[2];
|
||||
|
@ -219,6 +220,15 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
|
|||
for (i=0; i<2; ++i)
|
||||
sock[i] = PJ_INVALID_SOCKET;
|
||||
|
||||
bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
|
||||
if (cfg->bound_addr.slen) {
|
||||
status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop retry to bind RTP and RTCP sockets. */
|
||||
for (i=0; i<RTP_RETRY; ++i, rtp_port += 2) {
|
||||
|
@ -230,7 +240,8 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
|
|||
return status;
|
||||
}
|
||||
|
||||
status = pj_sock_bind_in(sock[0], cfg->ip_addr.s_addr, rtp_port);
|
||||
status = pj_sock_bind_in(sock[0], bound_addr.sin_addr.s_addr,
|
||||
rtp_port);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_sock_close(sock[0]);
|
||||
sock[0] = PJ_INVALID_SOCKET;
|
||||
|
@ -245,7 +256,7 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
|
|||
return status;
|
||||
}
|
||||
|
||||
status = pj_sock_bind_in(sock[1], cfg->ip_addr.s_addr,
|
||||
status = pj_sock_bind_in(sock[1], bound_addr.sin_addr.s_addr,
|
||||
(pj_uint16_t)(rtp_port+1));
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_sock_close(sock[0]);
|
||||
|
@ -285,6 +296,20 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
|
|||
pj_sock_close(sock[1]);
|
||||
sock[1] = PJ_INVALID_SOCKET;
|
||||
|
||||
} else if (cfg->public_addr.slen) {
|
||||
|
||||
status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr,
|
||||
(pj_uint16_t)rtp_port);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr,
|
||||
(pj_uint16_t)(rtp_port+1));
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
pj_in_addr addr;
|
||||
|
||||
|
|
Loading…
Reference in New Issue