summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorJason Parker <jparker@digium.com>2013-03-11 15:09:56 -0500
committerJason Parker <jparker@digium.com>2013-03-11 15:09:56 -0500
commit483805f79570115ab95c69698792d238c1719b1b (patch)
tree6b53ab2fd2b2478f864ccc8bd1b0bfaedc4d2050 /pjsip
parentf3ab456a17af1c89a6e3be4d20c5944853df1cb0 (diff)
Import pjproject-2.1
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/build/Makefile2
-rw-r--r--pjsip/include/pjsip/sip_auth.h79
-rw-r--r--pjsip/include/pjsip/sip_config.h50
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h73
-rw-r--r--pjsip/include/pjsip/sip_transport.h110
-rw-r--r--pjsip/include/pjsip/sip_transport_tls.h42
-rw-r--r--pjsip/include/pjsip/sip_types.h7
-rw-r--r--pjsip/include/pjsip/sip_uri.h10
-rw-r--r--pjsip/include/pjsip/sip_util.h9
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h346
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h31
-rw-r--r--pjsip/src/pjsip-simple/publishc.c9
-rw-r--r--pjsip/src/pjsip-ua/sip_100rel.c6
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c100
-rw-r--r--pjsip/src/pjsip-ua/sip_reg.c11
-rw-r--r--pjsip/src/pjsip-ua/sip_replaces.c19
-rw-r--r--pjsip/src/pjsip-ua/sip_timer.c29
-rw-r--r--pjsip/src/pjsip/sip_auth_client.c17
-rw-r--r--pjsip/src/pjsip/sip_auth_server.c47
-rw-r--r--pjsip/src/pjsip/sip_config.c4
-rw-r--r--pjsip/src/pjsip/sip_dialog.c23
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c160
-rw-r--r--pjsip/src/pjsip/sip_parser.c11
-rw-r--r--pjsip/src/pjsip/sip_tel_uri.c6
-rw-r--r--pjsip/src/pjsip/sip_transaction.c43
-rw-r--r--pjsip/src/pjsip/sip_transport.c243
-rw-r--r--pjsip/src/pjsip/sip_transport_tcp.c174
-rw-r--r--pjsip/src/pjsip/sip_transport_tls.c191
-rw-r--r--pjsip/src/pjsip/sip_ua_layer.c50
-rw-r--r--pjsip/src/pjsip/sip_uri.c7
-rw-r--r--pjsip/src/pjsip/sip_util_proxy.c4
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c290
-rw-r--r--pjsip/src/pjsua-lib/pjsua_aud.c36
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c724
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c178
-rw-r--r--pjsip/src/pjsua-lib/pjsua_dump.c30
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c767
-rw-r--r--pjsip/src/pjsua-lib/pjsua_pres.c76
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c32
-rw-r--r--pjsip/src/test/tsx_uac_test.c34
-rw-r--r--pjsip/src/test/tsx_uas_test.c76
-rw-r--r--pjsip/src/test/uri_test.c24
42 files changed, 3174 insertions, 1006 deletions
diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
index 2605be0..0f8fd13 100644
--- a/pjsip/build/Makefile
+++ b/pjsip/build/Makefile
@@ -138,7 +138,7 @@ pjsip-simple:
pjsua-lib:
$(MAKE) -f $(RULES_MAK) APP=PJSUA_LIB app=pjsua-lib $(PJSUA_LIB_LIB)
-pjsip-test:
+pjsip-test: pjsip
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjsip-test $(TEST_EXE)
.PHONY: ../lib/pjsip.ko
diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h
index 613e0d5..cd59372 100644
--- a/pjsip/include/pjsip/sip_auth.h
+++ b/pjsip/include/pjsip/sip_auth.h
@@ -1,4 +1,4 @@
-/* $Id: sip_auth.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_auth.h 4214 2012-07-25 14:29:28Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -275,6 +275,37 @@ typedef pj_status_t pjsip_auth_lookup_cred( pj_pool_t *pool,
const pj_str_t *acc_name,
pjsip_cred_info *cred_info );
+
+/**
+ * This structure describes input param for credential lookup.
+ */
+typedef struct pjsip_auth_lookup_cred_param
+{
+ pj_str_t realm; /**< Realm to find the account. */
+ pj_str_t acc_name; /**< Account name to look for. */
+ pjsip_rx_data *rdata; /**< Incoming request to be authenticated. */
+
+} pjsip_auth_lookup_cred_param;
+
+
+/**
+ * Type of function to lookup credential for the specified name.
+ *
+ * @param pool Pool to initialize the credential info.
+ * @param param The input param for credential lookup.
+ * @param cred_info The structure to put the credential when it's found.
+ *
+ * @return The function MUST return PJ_SUCCESS when it found
+ * a correct credential for the specified account and
+ * realm. Otherwise it may return PJSIP_EAUTHACCNOTFOUND
+ * or PJSIP_EAUTHACCDISABLED.
+ */
+typedef pj_status_t pjsip_auth_lookup_cred2(
+ pj_pool_t *pool,
+ const pjsip_auth_lookup_cred_param *param,
+ pjsip_cred_info *cred_info );
+
+
/** Flag to specify that server is a proxy. */
#define PJSIP_AUTH_SRV_IS_PROXY 1
@@ -286,7 +317,8 @@ typedef struct pjsip_auth_srv
pj_str_t realm; /**< Realm to serve. */
pj_bool_t is_proxy; /**< Will issue 407 instead of 401 */
pjsip_auth_lookup_cred *lookup; /**< Lookup function. */
-
+ pjsip_auth_lookup_cred2 *lookup2; /**< Lookup function with additional
+ info in its input param. */
} pjsip_auth_srv;
@@ -434,6 +466,49 @@ PJ_DECL(pj_status_t) pjsip_auth_srv_init( pj_pool_t *pool,
/**
+ * This structure describes initialization settings of server authorization
+ * session.
+ */
+typedef struct pjsip_auth_srv_init_param
+{
+ /**
+ * Realm to be served by the server.
+ */
+ const pj_str_t *realm;
+
+ /**
+ * Account lookup function.
+ */
+ pjsip_auth_lookup_cred2 *lookup2;
+
+ /**
+ * Options, bitmask of:
+ * - PJSIP_AUTH_SRV_IS_PROXY: to specify that the server will authorize
+ * clients as a proxy server (instead of as UAS), which means that
+ * Proxy-Authenticate will be used instead of WWW-Authenticate.
+ */
+ unsigned options;
+
+} pjsip_auth_srv_init_param;
+
+
+/**
+ * Initialize server authorization session data structure to serve the
+ * specified realm and to use lookup_func function to look for the credential
+ * info.
+ *
+ * @param pool Pool used to initialize the authentication server.
+ * @param auth_srv The authentication server structure.
+ * @param param The initialization param.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_auth_srv_init2(
+ pj_pool_t *pool,
+ pjsip_auth_srv *auth_srv,
+ const pjsip_auth_srv_init_param *param);
+
+/**
* Request the authorization server framework to verify the authorization
* information in the specified request in rdata.
*
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 9035b1e..bde0777 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -1,4 +1,4 @@
-/* $Id: sip_config.h 4172 2012-06-19 14:35:18Z nanang $ */
+/* $Id: sip_config.h 4285 2012-10-19 04:23:57Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -73,18 +73,41 @@ typedef struct pjsip_cfg_t
/**
* Specify port number should be allowed to appear in To and From
* header. Note that RFC 3261 disallow this, see Table 1 in section
- * 19.1.1 of the RFC. Default is PJSIP_ALLOW_PORT_IN_FROMTO_HDR.
+ * 19.1.1 of the RFC.
+ *
+ * Default is PJSIP_ALLOW_PORT_IN_FROMTO_HDR.
*/
pj_bool_t allow_port_in_fromto_hdr;
/**
+ * Accept call replace in early state when invite is not initiated
+ * by the user agent. RFC 3891 Section 3 disallows this, however,
+ * for better interoperability reason, this might be ignored.
+ *
+ * Default is PJSIP_ACCEPT_REPLACE_IN_EARLY_STATE.
+ */
+ pj_bool_t accept_replace_in_early_state;
+
+ /**
+ * Allow hash character ('#') to appear in outgoing URIs. See
+ * https://trac.pjsip.org/repos/ticket/1569.
+ *
+ * Default is PJ_FALSE.
+ */
+ pj_bool_t allow_tx_hash_in_uri;
+
+ /**
* Disable rport in request.
+ *
+ * Default is PJ_FALSE.
*/
pj_bool_t disable_rport;
/**
* Disable automatic switching from UDP to TCP if outgoing request
- * is greater than 1300 bytes. See PJSIP_DONT_SWITCH_TO_TCP.
+ * is greater than 1300 bytes.
+ *
+ * Default is PJSIP_DONT_SWITCH_TO_TCP.
*/
pj_bool_t disable_tcp_switch;
@@ -269,6 +292,21 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
/**
+ * Accept call replace in early state when invite is not initiated
+ * by the user agent. RFC 3891 Section 3 disallows this, however,
+ * for better interoperability reason, this might be ignored.
+ *
+ * This option can also be controlled at run-time by the
+ * \a accept_replace_in_early_state setting in pjsip_cfg_t.
+ *
+ * Default is 0 (no).
+ */
+#ifndef PJSIP_ACCEPT_REPLACE_IN_EARLY_STATE
+# define PJSIP_ACCEPT_REPLACE_IN_EARLY_STATE 0
+#endif
+
+
+/**
* This setting controls the threshold of the UDP packet, which if it's
* larger than this value the request will be sent with TCP. This setting
* is useful only when PJSIP_DONT_SWITCH_TO_TCP is set to 0.
@@ -362,9 +400,13 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
* response is received, the response will be discarded since its Via
* sent-by now contains address that is different than the transport
* address.
+ *
+ * Update:
+ * As of version 2.1, the default value is 0. This change was part of
+ * https://trac.pjsip.org/repos/ticket/1412
*/
#ifndef PJSIP_CHECK_VIA_SENT_BY
-# define PJSIP_CHECK_VIA_SENT_BY 1
+# define PJSIP_CHECK_VIA_SENT_BY 0
#endif
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index ac3f525..63c65d7 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -1,4 +1,4 @@
-/* $Id: sip_endpoint.h 4154 2012-06-05 10:41:17Z bennylp $ */
+/* $Id: sip_endpoint.h 4275 2012-10-04 06:11:58Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -213,6 +213,77 @@ PJ_DECL(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt,
PJ_DECL(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,
pjsip_module *module );
+/**
+ * This describes additional parameters to pjsip_endpt_process_rx_data()
+ * function. Application MUST call pjsip_process_rdata_param_default() to
+ * initialize this structure.
+ */
+typedef struct pjsip_process_rdata_param
+{
+ /**
+ * Specify the minimum priority number of the modules that are allowed
+ * to process the message. Default is zero to allow all modules to
+ * process the message.
+ */
+ unsigned start_prio;
+
+ /**
+ * Specify the pointer of the module where processing will start.
+ * The default is NULL, meaning processing will start from the start
+ * of the module list.
+ */
+ void *start_mod;
+
+ /**
+ * Set to N, then processing will start at Nth module after start
+ * module (where start module can be an explicit module as specified
+ * by \a start_mod or the start of module list when \a start_mod is
+ * NULL). For example, if set to 1, then processing will start from
+ * the next module after start module. Default is zero.
+ */
+ unsigned idx_after_start;
+
+ /**
+ * Print nothing to log. Default is PJ_FALSE.
+ */
+ pj_bool_t silent;
+
+} pjsip_process_rdata_param;
+
+/**
+ * Initialize with default.
+ *
+ * @param p The param.
+ */
+PJ_DECL(void) pjsip_process_rdata_param_default(pjsip_process_rdata_param *p);
+
+/**
+ * Manually distribute the specified pjsip_rx_data to registered modules.
+ * Normally application does not need to call this function because received
+ * messages will be given to endpoint automatically by transports.
+ *
+ * Application can use this function when it has postponed the processing of
+ * an incoming message, for example to perform long operations such as
+ * database operation or to consult other servers to decide what to do with
+ * the message. In this case, application clones the original rdata, return
+ * from the callback, and perform the long operation. Upon completing the
+ * long operation, it resumes pjsip's module processing by calling this
+ * function, and then free the cloned rdata.
+ *
+ * @param endpt The endpoint instance.
+ * @param rdata The rdata to be distributed.
+ * @param p Optional pointer to param to specify from which module
+ * the processing should start.
+ * @param p_handled Optional pointer to receive last return value of
+ * module's \a on_rx_request() or \a on_rx_response()
+ * callback.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_process_rx_data(pjsip_endpoint *endpt,
+ pjsip_rx_data *rdata,
+ pjsip_process_rdata_param *p,
+ pj_bool_t *p_handled);
/**
* Create pool from the endpoint. All SIP components should allocate their
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index c8ea6fd..21b2238 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transport.h 4173 2012-06-20 10:39:05Z ming $ */
+/* $Id: sip_transport.h 4275 2012-10-04 06:11:58Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -427,6 +427,42 @@ struct pjsip_rx_data
*/
PJ_DECL(char*) pjsip_rx_data_get_info(pjsip_rx_data *rdata);
+/**
+ * Clone pjsip_rx_data. This will duplicate the contents of
+ * pjsip_rx_data and add reference count to the transport.
+ * Once application has finished using the cloned pjsip_rx_data,
+ * it must release it by calling #pjsip_rx_data_free_cloned().
+ *
+ * By default (if flags is set to zero), this function copies the
+ * transport pointer in \a tp_info, duplicates the \a pkt_info,
+ * perform deep clone of the \a msg_info parts of the rdata, and
+ * fills the \a endpt_info (i.e. the \a mod_data) with zeros.
+ *
+ * @param src The source to be cloned.
+ * @param flags Optional flags. Must be zero for now.
+ * @param p_rdata Pointer to receive the cloned rdata.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pjsip_rx_data_clone(const pjsip_rx_data *src,
+ unsigned flags,
+ pjsip_rx_data **p_rdata);
+
+/**
+ * Free cloned pjsip_rx_data. This function must be and must only
+ * be called for a cloned pjsip_rx_data. Specifically, it must NOT
+ * be called for the original pjsip_rx_data that is returned by
+ * transports.
+ *
+ * This function will free the memory used by the pjsip_rx_data and
+ * decrement the transport reference counter.
+ *
+ * @param rdata The receive data buffer.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pjsip_rx_data_free_cloned(pjsip_rx_data *rdata);
+
/*****************************************************************************
*
@@ -1076,6 +1112,8 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
* In this implementation, it will only select the transport based on
* the transport type in the request.
*
+ * @see pjsip_tpmgr_find_local_addr2()
+ *
* @param tpmgr The transport manager.
* @param pool Pool to allocate memory for the IP address.
* @param type Destination address to contact.
@@ -1093,6 +1131,76 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
int *port);
/**
+ * Parameter for pjsip_tpmgr_find_local_addr2() function.
+ */
+typedef struct pjsip_tpmgr_fla2_param
+{
+ /**
+ * Specify transport type to use. This must be set.
+ */
+ pjsip_transport_type_e tp_type;
+
+ /**
+ * Optional pointer to preferred transport, if any.
+ */
+ const pjsip_tpselector *tp_sel;
+
+ /**
+ * Destination host, if known. The destination host is needed
+ * if \a local_if field below is set.
+ */
+ pj_str_t dst_host;
+
+ /**
+ * Specify if the function should return which local interface
+ * to use for the specified destination in \a dst_host. By definition,
+ * the returned address will always be local interface address.
+ */
+ pj_bool_t local_if;
+
+ /**
+ * The returned address.
+ */
+ pj_str_t ret_addr;
+
+ /**
+ * The returned port.
+ */
+ pj_uint16_t ret_port;
+
+ /**
+ * Returned pointer to the transport. Only set if local_if is set.
+ */
+ const void *ret_tp;
+
+} pjsip_tpmgr_fla2_param;
+
+/**
+ * Initialize with default values.
+ *
+ * @param prm The parameter to be initialized.
+ */
+PJ_DECL(void) pjsip_tpmgr_fla2_param_default(pjsip_tpmgr_fla2_param *prm);
+
+/**
+ * Find out the appropriate local address info (IP address and port) to
+ * advertise in Contact or Via header header based on the remote address
+ * to be contacted. The local address info would be the address name of the
+ * transport or listener which will be used to send the request.
+ *
+ * @see pjsip_tpmgr_find_local_addr()
+ *
+ * @param tpmgr The transport manager.
+ * @param pool Pool to allocate memory for the IP address.
+ * @param param Function input and output parameters.
+ *
+ * @return PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr,
+ pj_pool_t *pool,
+ pjsip_tpmgr_fla2_param *prm);
+
+/**
* Return number of transports currently registered to the transport
* manager.
*
diff --git a/pjsip/include/pjsip/sip_transport_tls.h b/pjsip/include/pjsip/sip_transport_tls.h
index cbc1d75..8164c63 100644
--- a/pjsip/include/pjsip/sip_transport_tls.h
+++ b/pjsip/include/pjsip/sip_transport_tls.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tls.h 3999 2012-03-30 07:10:13Z bennylp $ */
+/* $Id: sip_transport_tls.h 4262 2012-09-20 06:00:23Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -262,6 +262,8 @@ PJ_INLINE(void) pjsip_tls_setting_copy(pj_pool_t *pool,
* instance of SIP TLS transport factory and register it to the
* transport manager.
*
+ * See also #pjsip_tls_transport_start2() which supports IPv6.
+ *
* @param endpt The SIP endpoint.
* @param opt Optional TLS settings.
* @param local Optional local address to bind, or specify the
@@ -294,7 +296,43 @@ PJ_DECL(pj_status_t) pjsip_tls_transport_start(pjsip_endpoint *endpt,
unsigned async_cnt,
pjsip_tpfactory **p_factory);
-
+/**
+ * Variant of #pjsip_tls_transport_start() that supports IPv6. To instantiate
+ * IPv6 listener, set the address family of the "local" argument to IPv6
+ * (the host and port part may be left unspecified if not desired, i.e. by
+ * filling them with zeroes).
+ *
+ * @param endpt The SIP endpoint.
+ * @param opt Optional TLS settings.
+ * @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 any address. 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 TLS 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_tls_transport_start2(pjsip_endpoint *endpt,
+ const pjsip_tls_setting *opt,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name,
+ unsigned async_cnt,
+ pjsip_tpfactory **p_factory);
PJ_END_DECL
diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index 8cd98ae..9809983 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -1,4 +1,4 @@
-/* $Id: sip_types.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_types.h 4262 2012-09-20 06:00:23Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -92,7 +92,10 @@ typedef enum pjsip_transport_type_e
PJSIP_TRANSPORT_UDP6 = PJSIP_TRANSPORT_UDP + PJSIP_TRANSPORT_IPV6,
/** TCP over IPv6 */
- PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6
+ PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6,
+
+ /** TLS over IPv6 */
+ PJSIP_TRANSPORT_TLS6 = PJSIP_TRANSPORT_TLS + PJSIP_TRANSPORT_IPV6
} pjsip_transport_type_e;
diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h
index 849392f..47b63bd 100644
--- a/pjsip/include/pjsip/sip_uri.h
+++ b/pjsip/include/pjsip/sip_uri.h
@@ -1,4 +1,4 @@
-/* $Id: sip_uri.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_uri.h 4370 2013-02-26 05:30:00Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -226,12 +226,12 @@ struct pjsip_uri
};
/**
- * This macro checks that the URL is a "sip:" or "sips:" URL.
+ * This macro checks that the URL is a "sip:" URL.
* @param url The URL (pointer to)
* @return non-zero if TRUE.
*/
#define PJSIP_URI_SCHEME_IS_SIP(url) \
- (pj_strnicmp2(pjsip_uri_get_scheme(url), "sip", 3)==0)
+ (pj_stricmp2(pjsip_uri_get_scheme(url), "sip")==0)
/**
* This macro checks that the URL is a "sips:" URL (not SIP).
@@ -239,7 +239,7 @@ struct pjsip_uri
* @return non-zero if TRUE.
*/
#define PJSIP_URI_SCHEME_IS_SIPS(url) \
- (pj_strnicmp2(pjsip_uri_get_scheme(url), "sips", 4)==0)
+ (pj_stricmp2(pjsip_uri_get_scheme(url), "sips")==0)
/**
* This macro checks that the URL is a "tel:" URL.
@@ -247,7 +247,7 @@ struct pjsip_uri
* @return non-zero if TRUE.
*/
#define PJSIP_URI_SCHEME_IS_TEL(url) \
- (pj_strnicmp2(pjsip_uri_get_scheme(url), "tel", 3)==0)
+ (pj_stricmp2(pjsip_uri_get_scheme(url), "tel")==0)
/**
diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h
index 6efa45f..018ad87 100644
--- a/pjsip/include/pjsip/sip_util.h
+++ b/pjsip/include/pjsip/sip_util.h
@@ -1,4 +1,4 @@
-/* $Id: sip_util.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_util.h 4347 2013-02-13 10:19:25Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -92,6 +92,13 @@ typedef enum pjsip_redirect_op
PJSIP_REDIRECT_ACCEPT,
/**
+ * Accept the redirection to the current target and replace the To
+ * header in the INVITE request with the current target. The INVITE
+ * request will be resent to the current target.
+ */
+ PJSIP_REDIRECT_ACCEPT_REPLACE,
+
+ /**
* Defer the redirection decision, for example to request permission
* from the end user.
*/
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 856d853..88c0d46 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1,4 +1,4 @@
-/* $Id: pjsua.h 4180 2012-06-26 09:37:41Z ming $ */
+/* $Id: pjsua.h 4347 2013-02-13 10:19:25Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -906,9 +906,10 @@ typedef struct pjsua_callback
* callback.
* - it may delay the processing of the request, for example to request
* user permission whether to accept or reject the request. In this
- * case, the application MUST set the \a code argument to 202, and
- * later calls #pjsua_pres_notify() to accept or reject the
- * subscription request.
+ * case, the application MUST set the \a code argument to 202, then
+ * IMMEDIATELY calls #pjsua_pres_notify() with state
+ * PJSIP_EVSUB_STATE_PENDING and later calls #pjsua_pres_notify()
+ * again to accept or reject the subscription request.
*
* Any \a code other than 200 and 202 will be treated as 200.
*
@@ -1124,9 +1125,8 @@ typedef struct pjsua_callback
* INVITE request to the specified target, following the previously
* received redirection response.
*
- * Application may accept the redirection to the specified target
- * (the default behavior if this callback is implemented), reject
- * this target only and make the session continue to try the next
+ * Application may accept the redirection to the specified target,
+ * reject this target only and make the session continue to try the next
* target in the list if such target exists, stop the whole
* redirection process altogether and cause the session to be
* disconnected, or defer the decision to ask for user confirmation.
@@ -1146,9 +1146,12 @@ typedef struct pjsua_callback
* @return Action to be performed for the target. Set this
* parameter to one of the value below:
* - PJSIP_REDIRECT_ACCEPT: immediately accept the
- * redirection (default value). When set, the
- * call will immediately resend INVITE request
- * to the target.
+ * redirection. When set, the call will immediately
+ * resend INVITE request to the target.
+ * - PJSIP_REDIRECT_ACCEPT_REPLACE: immediately accept
+ * the redirection and replace the To header with the
+ * current target. When set, the call will immediately
+ * resend INVITE request to the target.
* - PJSIP_REDIRECT_REJECT: immediately reject this
* target. The call will continue retrying with
* next target if present, or disconnect the call
@@ -1461,6 +1464,15 @@ typedef struct pjsua_config
pj_bool_t stun_ignore_failure;
/**
+ * This specifies whether STUN requests for resolving socket mapped
+ * address should use the new format, i.e: having STUN magic cookie
+ * in its transaction ID.
+ *
+ * Default: PJ_FALSE
+ */
+ pj_bool_t stun_map_use_stun2;
+
+ /**
* Support for adding and parsing NAT type in the SDP to assist
* troubleshooting. The valid values are:
* - 0: no information will be added in SDP, and parsing is disabled.
@@ -2143,6 +2155,15 @@ typedef struct pjsua_transport_config
unsigned port;
/**
+ * Specify the port range for socket binding, relative to the start
+ * port number specified in \a port. Note that this setting is only
+ * applicable when the start port number is non zero.
+ *
+ * Default value is zero.
+ */
+ unsigned port_range;
+
+ /**
* 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
@@ -2566,6 +2587,147 @@ typedef enum pjsua_call_hold_type
#endif
/**
+ * This enumeration controls the use of STUN in the account.
+ */
+typedef enum pjsua_stun_use
+{
+ /**
+ * Follow the default setting in the global \a pjsua_config.
+ */
+ PJSUA_STUN_USE_DEFAULT,
+
+ /**
+ * Disable STUN. If STUN is not enabled in the global \a pjsua_config,
+ * this setting has no effect.
+ */
+ PJSUA_STUN_USE_DISABLED
+
+} pjsua_stun_use;
+
+/**
+ * This enumeration controls the use of ICE settings in the account.
+ */
+typedef enum pjsua_ice_config_use
+{
+ /**
+ * Use the default settings in the global \a pjsua_media_config.
+ */
+ PJSUA_ICE_CONFIG_USE_DEFAULT,
+
+ /**
+ * Use the custom \a pjsua_ice_config setting in the account.
+ */
+ PJSUA_ICE_CONFIG_USE_CUSTOM
+
+} pjsua_ice_config_use;
+
+/**
+ * This enumeration controls the use of TURN settings in the account.
+ */
+typedef enum pjsua_turn_config_use
+{
+ /**
+ * Use the default setting in the global \a pjsua_media_config.
+ */
+ PJSUA_TURN_CONFIG_USE_DEFAULT,
+
+ /**
+ * Use the custom \a pjsua_turn_config setting in the account.
+ */
+ PJSUA_TURN_CONFIG_USE_CUSTOM
+
+} pjsua_turn_config_use;
+
+/**
+ * ICE setting. This setting is used in the pjsua_acc_config.
+ */
+typedef struct pjsua_ice_config
+{
+ /**
+ * Enable ICE.
+ */
+ pj_bool_t enable_ice;
+
+ /**
+ * Set the maximum number of host candidates.
+ *
+ * Default: -1 (maximum not set)
+ */
+ int ice_max_host_cands;
+
+ /**
+ * ICE session options.
+ */
+ pj_ice_sess_options ice_opt;
+
+ /**
+ * Disable RTCP component.
+ *
+ * Default: no
+ */
+ pj_bool_t ice_no_rtcp;
+
+ /**
+ * Send re-INVITE/UPDATE every after ICE connectivity check regardless
+ * the default ICE transport address is changed or not. When this is set
+ * to PJ_FALSE, re-INVITE/UPDATE will be sent only when the default ICE
+ * transport address is changed.
+ *
+ * Default: yes
+ */
+ pj_bool_t ice_always_update;
+
+} pjsua_ice_config;
+
+/**
+ * TURN setting. This setting is used in the pjsua_acc_config.
+ */
+typedef struct pjsua_turn_config
+{
+ /**
+ * Enable TURN candidate in ICE.
+ */
+ pj_bool_t enable_turn;
+
+ /**
+ * Specify TURN domain name or host name, in in "DOMAIN:PORT" or
+ * "HOST:PORT" format.
+ */
+ pj_str_t turn_server;
+
+ /**
+ * Specify the connection type to be used to the TURN server. Valid
+ * values are PJ_TURN_TP_UDP or PJ_TURN_TP_TCP.
+ *
+ * Default: PJ_TURN_TP_UDP
+ */
+ pj_turn_tp_type turn_conn_type;
+
+ /**
+ * Specify the credential to authenticate with the TURN server.
+ */
+ pj_stun_auth_cred turn_auth_cred;
+
+} pjsua_turn_config;
+
+/**
+ * Specify how IPv6 transport should be used in account config.
+ */
+typedef enum pjsua_ipv6_use
+{
+ /**
+ * IPv6 is not used.
+ */
+ PJSUA_IPV6_DISABLED,
+
+ /**
+ * IPv6 is enabled.
+ */
+ PJSUA_IPV6_ENABLED
+
+} pjsua_ipv6_use;
+
+/**
* This structure describes account configuration to be specified when
* adding a new account with #pjsua_acc_add(). Application MUST initialize
* this structure first by calling #pjsua_acc_config_default().
@@ -2588,7 +2750,8 @@ typedef struct pjsua_acc_config
/**
* The full SIP URL for the account. The value can take name address or
- * URL format, and will look something like "sip:account@serviceprovider".
+ * URL format, and will look something like "sip:account@serviceprovider"
+ * or "\"Display Name\" <sip:account@provider>".
*
* This field is mandatory.
*/
@@ -2743,6 +2906,15 @@ typedef struct pjsua_acc_config
*/
pj_str_t proxy[PJSUA_ACC_MAX_PROXIES];
+ /**
+ * If remote sends SDP answer containing more than one format or codec in
+ * the media line, send re-INVITE or UPDATE with just one codec to lock
+ * which codec to use.
+ *
+ * Default: 1 (Yes). Set to zero to disable.
+ */
+ unsigned lock_codec;
+
/**
* Optional interval for registration, in seconds. If the value is zero,
* default interval will be used (PJSUA_REG_INTERVAL, 300 seconds).
@@ -2957,13 +3129,60 @@ typedef struct pjsua_acc_config
pjsua_transport_config rtp_cfg;
/**
+ * Specify whether IPv6 should be used on media.
+ */
+ pjsua_ipv6_use ipv6_media_use;
+
+ /**
+ * Control the use of STUN for the SIP signaling.
+ *
+ * Default: PJSUA_STUN_USE_DEFAULT
+ */
+ pjsua_stun_use sip_stun_use;
+
+ /**
+ * Control the use of STUN for the media transports.
+ *
+ * Default: PJSUA_STUN_USE_DEFAULT
+ */
+ pjsua_stun_use media_stun_use;
+
+ /**
+ * Control the use of ICE in the account. By default, the settings in the
+ * \a pjsua_media_config will be used.
+ *
+ * Default: PJSUA_ICE_CONFIG_USE_DEFAULT
+ */
+ pjsua_ice_config_use ice_cfg_use;
+
+ /**
+ * The custom ICE setting for this account. This setting will only be
+ * used if \a ice_cfg_use is set to PJSUA_ICE_CONFIG_USE_CUSTOM
+ */
+ pjsua_ice_config ice_cfg;
+
+ /**
+ * Control the use of TURN in the account. By default, the settings in the
+ * \a pjsua_media_config will be used
+ *
+ * Default: PJSUA_TURN_CONFIG_USE_DEFAULT
+ */
+ pjsua_turn_config_use turn_cfg_use;
+
+ /**
+ * The custom TURN setting for this account. This setting will only be
+ * used if \a turn_cfg_use is set to PJSUA_TURN_CONFIG_USE_CUSTOM
+ */
+ pjsua_turn_config turn_cfg;
+
+ /**
* Specify whether secure media transport should be used for this account.
* Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
* PJMEDIA_SRTP_MANDATORY.
*
* Default: #PJSUA_DEFAULT_USE_SRTP
*/
- pjmedia_srtp_use use_srtp;
+ pjmedia_srtp_use use_srtp;
/**
* Specify whether SRTP requires secure signaling to be used. This option
@@ -3061,6 +3280,52 @@ typedef struct pjsua_acc_config
/**
+ * Initialize ICE config from a media config. If the \a pool argument
+ * is NULL, a simple memcpy() will be used.
+ *
+ * @param pool Memory to duplicate strings.
+ * @param dst Destination config.
+ * @param src Source config.
+ */
+PJ_DECL(void) pjsua_ice_config_from_media_config(pj_pool_t *pool,
+ pjsua_ice_config *dst,
+ const pjsua_media_config *src);
+
+/**
+ * Clone. If the \a pool argument is NULL, a simple memcpy() will be used.
+ *
+ * @param pool Memory to duplicate strings.
+ * @param dst Destination config.
+ * @param src Source config.
+ */
+PJ_DECL(void) pjsua_ice_config_dup( pj_pool_t *pool,
+ pjsua_ice_config *dst,
+ const pjsua_ice_config *src);
+
+/**
+ * Initialize TURN config from a media config. If the \a pool argument
+ * is NULL, a simple memcpy() will be used.
+ *
+ * @param pool Memory to duplicate strings.
+ * @param dst Destination config.
+ * @param src Source config.
+ */
+PJ_DECL(void) pjsua_turn_config_from_media_config(pj_pool_t *pool,
+ pjsua_turn_config *dst,
+ const pjsua_media_config *src);
+
+/**
+ * Clone. If the \a pool argument is NULL, a simple memcpy() will be used.
+ *
+ * @param pool Memory to duplicate strings.
+ * @param dst Destination config.
+ * @param src Source config.
+ */
+PJ_DECL(void) pjsua_turn_config_dup(pj_pool_t *pool,
+ pjsua_turn_config *dst,
+ const pjsua_turn_config *src);
+
+/**
* Call this function to initialize account config with default values.
*
* @param cfg The account config to be initialized.
@@ -4291,7 +4556,8 @@ PJ_DECL(pj_status_t) pjsua_call_update2(pjsua_call_id call_id,
* of the call transfer request.
*
* @param call_id The call id to be transfered.
- * @param dest Address of new target to be contacted.
+ * @param dest URI of new target to be contacted. The URI may be
+ * in name address or addr-spec format.
* @param msg_data Optional message components to be sent with
* the request.
*
@@ -5015,6 +5281,28 @@ PJ_DECL(pj_status_t) pjsua_im_typing(pjsua_acc_id acc_id,
/**
+ * Specify whether the third party stream has the capability of retrieving
+ * the stream info, i.e: pjmedia_stream_get_info() and
+ * pjmedia_vid_stream_get_info(). Currently this capability is required
+ * by smart media update and call dump.
+ */
+#ifndef PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO
+# define PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO 0
+#endif
+
+
+/**
+ * Specify whether the third party stream has the capability of retrieving
+ * the stream statistics, i.e: pjmedia_stream_get_stat() and
+ * pjmedia_vid_stream_get_stat(). Currently this capability is required
+ * by call dump.
+ */
+#ifndef PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT
+# define PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT 0
+#endif
+
+
+/**
* Max ports in the conference bridge. This setting is the default value
* for pjsua_media_config.max_media_ports.
*/
@@ -5081,6 +5369,14 @@ PJ_DECL(pj_status_t) pjsua_im_typing(pjsua_acc_id acc_id,
/**
+ * Enable/disable "c=" line in SDP session level. Set to zero to disable it.
+ */
+#ifndef PJSUA_SDP_SESS_HAS_CONN
+# define PJSUA_SDP_SESS_HAS_CONN 0
+#endif
+
+
+/**
* This structure describes media configuration, which will be specified
* when calling #pjsua_init(). Application MUST initialize this structure
* by calling #pjsua_media_config_default().
@@ -5276,6 +5572,16 @@ struct pjsua_media_config
pj_bool_t ice_no_rtcp;
/**
+ * Send re-INVITE/UPDATE every after ICE connectivity check regardless
+ * the default ICE transport address is changed or not. When this is set
+ * to PJ_FALSE, re-INVITE/UPDATE will be sent only when the default ICE
+ * transport address is changed.
+ *
+ * Default: yes
+ */
+ pj_bool_t ice_always_update;
+
+ /**
* Enable TURN relay candidate in ICE.
*/
pj_bool_t enable_turn;
@@ -5319,6 +5625,20 @@ struct pjsua_media_config
* Default: PJ_TRUE
*/
pj_bool_t vid_preview_enable_native;
+
+ /**
+ * Disable smart media update (ticket #1568). The smart media update
+ * will check for any changes in the media properties after a successful
+ * SDP negotiation and the media will only be reinitialized when any
+ * change is found. When it is disabled, media streams will always be
+ * reinitialized after a successful SDP negotiation.
+ *
+ * Note for third party media, the smart media update requires stream info
+ * retrieval capability, see #PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO.
+ *
+ * Default: PJ_FALSE
+ */
+ pj_bool_t no_smart_media_update;
};
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index c228513..3b38679 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -1,4 +1,4 @@
-/* $Id: pjsua_internal.h 4175 2012-06-22 08:53:11Z nanang $ */
+/* $Id: pjsua_internal.h 4342 2013-02-06 13:48:45Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -155,10 +155,7 @@ struct pjsua_call
char last_text_buf_[128]; /**< Buffer for last_text. */
struct {
- pj_timer_entry reinv_timer;/**< Reinvite retry timer. */
- pj_uint32_t sdp_ver; /**< SDP version of the bad answer */
int retry_cnt; /**< Retry count. */
- pj_bool_t pending; /**< Pending until CONFIRMED state */
} lock_codec; /**< Data for codec locking when answer
contains multiple codecs. */
@@ -170,6 +167,7 @@ struct pjsua_call
union {
struct {
pjsua_msg_data *msg_data;/**< Headers for outgoing INVITE. */
+ pj_bool_t hangup; /**< Call is hangup? */
} out_call;
struct {
call_answer answers;/**< A list of call answers. */
@@ -184,6 +182,10 @@ struct pjsua_call
offer. */
unsigned rem_vid_cnt; /**< No of active video in last remote
offer. */
+
+ pj_timer_entry reinv_timer; /**< Reinvite retry timer. */
+ pj_bool_t reinv_pending;/**< Pending until CONFIRMED state. */
+ pj_bool_t reinv_ice_sent;/**< Has reinvite for ICE upd sent? */
};
@@ -336,6 +338,9 @@ typedef struct pjsua_stun_resolve
PJ_DECL_LIST_MEMBER(struct pjsua_stun_resolve);
pj_pool_t *pool; /**< Pool */
+ int ref_cnt; /**< Reference count */
+ pj_bool_t destroy_flag; /**< To be destroyed */
+ pj_bool_t has_result;
unsigned count; /**< # of entries */
pj_str_t *srv; /**< Array of entries */
unsigned idx; /**< Current index */
@@ -583,6 +588,20 @@ pj_status_t resolve_stun_server(pj_bool_t wait);
*/
pj_status_t normalize_route_uri(pj_pool_t *pool, pj_str_t *uri);
+/* acc use stun? */
+pj_bool_t pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id);
+
+/* Get local transport address suitable to be used for Via or Contact address
+ * to send request to the specified destination URI.
+ */
+pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
+ pj_pool_t *pool,
+ const pj_str_t *dst_uri,
+ pjsip_host_port *addr,
+ pjsip_transport_type_e *p_tp_type,
+ int *p_secure,
+ const void **p_tp);
+
/**
* Handle incoming invite request.
*/
@@ -798,6 +817,10 @@ PJ_DECL(void) pjsua_vid_win_reset(pjsua_vid_win_id wid);
# define pjsua_vid_win_reset(wid)
#endif
+/*
+ * Schedule check for the need of re-INVITE/UPDATE after media update
+ */
+void pjsua_call_schedule_reinvite_check(pjsua_call *call, unsigned delay_ms);
PJ_END_DECL
diff --git a/pjsip/src/pjsip-simple/publishc.c b/pjsip/src/pjsip-simple/publishc.c
index efee6fb..ab007ba 100644
--- a/pjsip/src/pjsip-simple/publishc.c
+++ b/pjsip/src/pjsip-simple/publishc.c
@@ -1,4 +1,4 @@
-/* $Id: publishc.c 4173 2012-06-20 10:39:05Z ming $ */
+/* $Id: publishc.c 4206 2012-07-16 02:45:09Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -355,8 +355,11 @@ PJ_DEF(pj_status_t) pjsip_publishc_set_via_sent_by(pjsip_publishc *pubc,
if (!via_addr)
pj_bzero(&pubc->via_addr, sizeof(pubc->via_addr));
- else
- pubc->via_addr = *via_addr;
+ else {
+ if (pj_strcmp(&pubc->via_addr.host, &via_addr->host))
+ pj_strdup(pubc->pool, &pubc->via_addr.host, &via_addr->host);
+ pubc->via_addr.port = via_addr->port;
+ }
pubc->via_tp = via_tp;
return PJ_SUCCESS;
diff --git a/pjsip/src/pjsip-ua/sip_100rel.c b/pjsip/src/pjsip-ua/sip_100rel.c
index 07122c4..f64ef19 100644
--- a/pjsip/src/pjsip-ua/sip_100rel.c
+++ b/pjsip/src/pjsip-ua/sip_100rel.c
@@ -1,4 +1,4 @@
-/* $Id: sip_100rel.c 3841 2011-10-24 09:28:13Z ming $ */
+/* $Id: sip_100rel.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -273,7 +273,7 @@ PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
/* Find UAC state for the specified call leg */
uac_state = dd->uac_state_list;
while (uac_state) {
- if (pj_strcmp(&uac_state->tag, to_tag)==0)
+ if (pj_stricmp(&uac_state->tag, to_tag)==0)
break;
uac_state = uac_state->next;
}
@@ -320,7 +320,7 @@ PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
/* If this response is a forked response from a different call-leg,
* update the req URI (https://trac.pjsip.org/repos/ticket/1364)
*/
- if (pj_strcmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
+ if (pj_stricmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
const pjsip_contact_hdr *mhdr;
mhdr = (const pjsip_contact_hdr*)
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 8db5308..dec4ee5 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -1,4 +1,4 @@
-/* $Id: sip_inv.c 4156 2012-06-06 07:24:08Z bennylp $ */
+/* $Id: sip_inv.c 4367 2013-02-21 20:49:19Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -829,7 +829,7 @@ PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)
sdp_info->body.slen,
&sdp_info->sdp);
if (status == PJ_SUCCESS)
- status = pjmedia_sdp_validate(sdp_info->sdp);
+ status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE);
if (status != PJ_SUCCESS) {
sdp_info->sdp = NULL;
@@ -1745,7 +1745,7 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
if (tsx->role == PJSIP_ROLE_UAC &&
rdata->msg_info.msg->line.status.code/100 == 2 &&
tsx_inv_data->done_early &&
- pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
+ pj_stricmp(&tsx_inv_data->done_tag, &res_tag))
{
const pjmedia_sdp_session *reoffer_sdp = NULL;
@@ -2329,6 +2329,7 @@ static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
/* Check what the application wants to do now */
switch (op) {
case PJSIP_REDIRECT_ACCEPT:
+ case PJSIP_REDIRECT_ACCEPT_REPLACE:
case PJSIP_REDIRECT_STOP:
/* Must increment session counter, that's the convention of the
* pjsip_inv_process_redirect().
@@ -2394,6 +2395,7 @@ PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
/* See what the application wants to do now */
switch (op) {
case PJSIP_REDIRECT_ACCEPT:
+ case PJSIP_REDIRECT_ACCEPT_REPLACE:
/* User accept the redirection. Reset the session and resend the
* INVITE request.
*/
@@ -2419,6 +2421,51 @@ PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
via->branch_param.slen = 0;
+ /* Process PJSIP_REDIRECT_ACCEPT_REPLACE */
+ if (op == PJSIP_REDIRECT_ACCEPT_REPLACE) {
+ pjsip_to_hdr *to;
+ pjsip_dialog *dlg = inv->dlg;
+ enum { TMP_LEN = 128 };
+ char tmp[TMP_LEN];
+ int len;
+
+ /* Replace To header */
+ to = PJSIP_MSG_TO_HDR(tdata->msg);
+ to->uri = (pjsip_uri*)
+ pjsip_uri_clone(tdata->pool,
+ dlg->target_set.current->uri);
+ to->tag.slen = 0;
+ pj_list_init(&to->other_param);
+
+ /* Re-init dialog remote info */
+ dlg->remote.info = (pjsip_to_hdr*)
+ pjsip_hdr_clone(dlg->pool, to);
+
+ /* Remove header param from remote info */
+ if (PJSIP_URI_SCHEME_IS_SIP(dlg->remote.info->uri) ||
+ PJSIP_URI_SCHEME_IS_SIPS(dlg->remote.info->uri))
+ {
+ pjsip_sip_uri *sip_uri = (pjsip_sip_uri *)
+ pjsip_uri_get_uri(dlg->remote.info->uri);
+ if (!pj_list_empty(&sip_uri->header_param)) {
+ /* Remove all header param */
+ pj_list_init(&sip_uri->header_param);
+ }
+ }
+
+ /* Print the remote info. */
+ len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR,
+ dlg->remote.info->uri, tmp, TMP_LEN);
+ if (len < 1) {
+ pj_ansi_strcpy(tmp, "<-error: uri too long->");
+ len = pj_ansi_strlen(tmp);
+ }
+ pj_strdup2_with_null(dlg->pool, &dlg->remote.info_str, tmp);
+
+ /* Secure? */
+ dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(to->uri);
+ }
+
/* Reset message destination info (see #1248). */
pj_bzero(&tdata->dest_info, sizeof(tdata->dest_info));
@@ -2572,6 +2619,7 @@ PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
pjsip_contact_hdr *contact_hdr = NULL;
pjsip_tx_data *tdata = NULL;
pjmedia_sdp_session *sdp_copy;
+ const pjsip_hdr *hdr;
pj_status_t status = PJ_SUCCESS;
/* Verify arguments. */
@@ -2640,13 +2688,24 @@ PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
}
- /* Unlock dialog. */
- pjsip_dlg_dec_lock(inv->dlg);
+ /* Session Timers spec (RFC 4028) says that Supported header MUST be put
+ * in refresh requests. So here we'll just put the Supported header in
+ * all cases regardless of whether session timers is used or not, just
+ * in case this is a common behavior.
+ */
+ hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
+ if (hdr) {
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
+ pjsip_hdr_shallow_clone(tdata->pool, hdr));
+ }
status = pjsip_timer_update_req(inv, tdata);
if (status != PJ_SUCCESS)
goto on_error;
+ /* Unlock dialog. */
+ pjsip_dlg_dec_lock(inv->dlg);
+
*p_tdata = tdata;
pj_log_pop_indent();
@@ -2957,8 +3016,16 @@ static void inv_respond_incoming_update(pjsip_inv_session *inv,
neg_state = pjmedia_sdp_neg_get_state(inv->neg);
+ /* If UPDATE doesn't contain SDP, just respond with 200/OK.
+ * This is a valid scenario according to session-timer draft.
+ */
+ if (rdata->msg_info.msg->body == NULL) {
+
+ status = pjsip_dlg_create_response(inv->dlg, rdata,
+ 200, NULL, &tdata);
+ }
/* Send 491 if we receive UPDATE while we're waiting for an answer */
- if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
+ else if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
status = pjsip_dlg_create_response(inv->dlg, rdata,
PJSIP_SC_REQUEST_PENDING, NULL,
&tdata);
@@ -2967,18 +3034,18 @@ static void inv_respond_incoming_update(pjsip_inv_session *inv,
* receive UPDATE while we haven't sent answer.
*/
else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
- neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
- status = pjsip_dlg_create_response(inv->dlg, rdata,
+ neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO)
+ {
+ pjsip_retry_after_hdr *ra_hdr;
+ int val;
+
+ status = pjsip_dlg_create_response(inv->dlg, rdata,
PJSIP_SC_INTERNAL_SERVER_ERROR,
NULL, &tdata);
- /* If UPDATE doesn't contain SDP, just respond with 200/OK.
- * This is a valid scenario according to session-timer draft.
- */
- } else if (rdata->msg_info.msg->body == NULL) {
-
- status = pjsip_dlg_create_response(inv->dlg, rdata,
- 200, NULL, &tdata);
+ val = (pj_rand() % 10);
+ ra_hdr = pjsip_retry_after_hdr_create(tdata->pool, val);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)ra_hdr);
} else {
/* We receive new offer from remote */
@@ -3305,8 +3372,7 @@ static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
tsx->method.id != PJSIP_CANCEL_METHOD) ||
tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
- tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
- tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
+ tsx->status_code == PJSIP_SC_TSX_TIMEOUT))
{
pjsip_tx_data *bye;
pj_status_t status;
diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c
index bd1fb21..b76a1f6 100644
--- a/pjsip/src/pjsip-ua/sip_reg.c
+++ b/pjsip/src/pjsip-ua/sip_reg.c
@@ -1,4 +1,4 @@
-/* $Id: sip_reg.c 4173 2012-06-20 10:39:05Z ming $ */
+/* $Id: sip_reg.c 4319 2013-01-16 10:20:55Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -336,7 +336,7 @@ PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc,
pj_status_t status;
PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url &&
- contact_cnt && contact && expires, PJ_EINVAL);
+ expires, PJ_EINVAL);
/* Copy server URL. */
pj_strdup_with_null(regc->pool, &regc->str_srv_url, srv_url);
@@ -818,8 +818,11 @@ PJ_DEF(pj_status_t) pjsip_regc_set_via_sent_by( pjsip_regc *regc,
if (!via_addr)
pj_bzero(&regc->via_addr, sizeof(regc->via_addr));
- else
- regc->via_addr = *via_addr;
+ else {
+ if (pj_strcmp(&regc->via_addr.host, &via_addr->host))
+ pj_strdup(regc->pool, &regc->via_addr.host, &via_addr->host);
+ regc->via_addr.port = via_addr->port;
+ }
regc->via_tp = via_tp;
return PJ_SUCCESS;
diff --git a/pjsip/src/pjsip-ua/sip_replaces.c b/pjsip/src/pjsip-ua/sip_replaces.c
index b961cf9..a37546f 100644
--- a/pjsip/src/pjsip-ua/sip_replaces.c
+++ b/pjsip/src/pjsip-ua/sip_replaces.c
@@ -1,4 +1,4 @@
-/* $Id: sip_replaces.c 3999 2012-03-30 07:10:13Z bennylp $ */
+/* $Id: sip_replaces.c 4268 2012-09-28 08:56:08Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -305,10 +305,19 @@ PJ_DEF(pj_status_t) pjsip_replaces_verify_request( pjsip_rx_data *rdata,
* initiated by this UA, it returns a 481 (Call/Transaction Does Not
* Exist) response to the new INVITE.
*/
- if (inv->state <= PJSIP_INV_STATE_EARLY && inv->role != PJSIP_ROLE_UAC) {
- code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
- warn_text = "Found early INVITE session but not initiated by this UA";
- goto on_return;
+ if (inv->state <= PJSIP_INV_STATE_EARLY && inv->role != PJSIP_ROLE_UAC)
+ {
+ /* Really return 481 only if call haven't reached early state or
+ * accept-replace-in-early-state (ticket #1587) is not allowed.
+ */
+ if (inv->state != PJSIP_INV_STATE_EARLY ||
+ pjsip_cfg()->endpt.accept_replace_in_early_state == PJ_FALSE)
+ {
+ code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
+ warn_text = "Found early INVITE session but not initiated by "
+ "this UA";
+ goto on_return;
+ }
}
diff --git a/pjsip/src/pjsip-ua/sip_timer.c b/pjsip/src/pjsip-ua/sip_timer.c
index 2c70791..a48c71d 100644
--- a/pjsip/src/pjsip-ua/sip_timer.c
+++ b/pjsip/src/pjsip-ua/sip_timer.c
@@ -1,4 +1,4 @@
-/* $Id: sip_timer.c 3999 2012-03-30 07:10:13Z bennylp $ */
+/* $Id: sip_timer.c 4213 2012-07-23 13:31:26Z nanang $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -1030,6 +1030,33 @@ PJ_DEF(pj_status_t) pjsip_timer_update_resp(pjsip_inv_session *inv,
if (inv->timer && inv->timer->active) {
/* Add Session-Expires header and start the timer */
add_timer_headers(inv, tdata, PJ_TRUE, PJ_FALSE);
+
+ /* Add 'timer' to Require header (see ticket #1560). */
+ if (inv->timer->refresher == TR_UAC) {
+ pjsip_require_hdr *req_hdr;
+ pj_bool_t req_hdr_has_timer = PJ_FALSE;
+
+ req_hdr = (pjsip_require_hdr*)
+ pjsip_msg_find_hdr(tdata->msg, PJSIP_H_REQUIRE,
+ NULL);
+ if (req_hdr == NULL) {
+ req_hdr = pjsip_require_hdr_create(tdata->pool);
+ PJ_ASSERT_RETURN(req_hdr, PJ_ENOMEM);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
+ } else {
+ unsigned i;
+ for (i = 0; i < req_hdr->count; ++i) {
+ if (pj_stricmp(&req_hdr->values[i], &STR_TIMER)) {
+ req_hdr_has_timer = PJ_TRUE;
+ break;
+ }
+ }
+ }
+ if (!req_hdr_has_timer)
+ req_hdr->values[req_hdr->count++] = STR_TIMER;
+ }
+
+ /* Finally, start timer. */
start_timer(inv);
}
}
diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
index ae850b1..0facc7b 100644
--- a/pjsip/src/pjsip/sip_auth_client.c
+++ b/pjsip/src/pjsip/sip_auth_client.c
@@ -1,4 +1,4 @@
-/* $Id: sip_auth_client.c 3999 2012-03-30 07:10:13Z bennylp $ */
+/* $Id: sip_auth_client.c 4322 2013-01-17 10:09:09Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -920,13 +920,13 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
* or add an empty authorization header.
*/
unsigned i;
- char *uri_str;
- int len;
+ pj_str_t uri;
- uri_str = (char*)pj_pool_alloc(tdata->pool, PJSIP_MAX_URL_SIZE);
- len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri,
- uri_str, PJSIP_MAX_URL_SIZE);
- if (len < 1 || len >= PJSIP_MAX_URL_SIZE)
+ uri.ptr = (char*)pj_pool_alloc(tdata->pool, PJSIP_MAX_URL_SIZE);
+ uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
+ tdata->msg->line.req.uri,
+ uri.ptr, PJSIP_MAX_URL_SIZE);
+ if (uri.slen < 1 || uri.slen >= PJSIP_MAX_URL_SIZE)
return PJSIP_EURITOOLONG;
for (i=0; i<sess->cred_cnt; ++i) {
@@ -946,8 +946,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
&c->username);
pj_strdup(tdata->pool, &hs->credential.digest.realm,
&c->realm);
- pj_strdup2(tdata->pool, &hs->credential.digest.uri,
- uri_str);
+ pj_strdup(tdata->pool, &hs->credential.digest.uri, &uri);
pj_strdup(tdata->pool, &hs->credential.digest.algorithm,
&sess->pref.algorithm);
diff --git a/pjsip/src/pjsip/sip_auth_server.c b/pjsip/src/pjsip/sip_auth_server.c
index 248e6cc..c38b40c 100644
--- a/pjsip/src/pjsip/sip_auth_server.c
+++ b/pjsip/src/pjsip/sip_auth_server.c
@@ -1,4 +1,4 @@
-/* $Id: sip_auth_server.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_auth_server.c 4214 2012-07-25 14:29:28Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -40,6 +40,7 @@ PJ_DEF(pj_status_t) pjsip_auth_srv_init( pj_pool_t *pool,
{
PJ_ASSERT_RETURN(pool && auth_srv && realm && lookup, PJ_EINVAL);
+ pj_bzero(auth_srv, sizeof(*auth_srv));
pj_strdup( pool, &auth_srv->realm, realm);
auth_srv->lookup = lookup;
auth_srv->is_proxy = (options & PJSIP_AUTH_SRV_IS_PROXY);
@@ -47,6 +48,26 @@ PJ_DEF(pj_status_t) pjsip_auth_srv_init( pj_pool_t *pool,
return PJ_SUCCESS;
}
+/*
+ * Initialize server authorization session data structure to serve the
+ * specified realm and to use lookup_func function to look for the credential
+ * info.
+ */
+PJ_DEF(pj_status_t) pjsip_auth_srv_init2(
+ pj_pool_t *pool,
+ pjsip_auth_srv *auth_srv,
+ const pjsip_auth_srv_init_param *param)
+{
+ PJ_ASSERT_RETURN(pool && auth_srv && param, PJ_EINVAL);
+
+ pj_bzero(auth_srv, sizeof(*auth_srv));
+ pj_strdup( pool, &auth_srv->realm, param->realm);
+ auth_srv->lookup2 = param->lookup2;
+ auth_srv->is_proxy = (param->options & PJSIP_AUTH_SRV_IS_PROXY);
+
+ return PJ_SUCCESS;
+}
+
/* Verify incoming Authorization/Proxy-Authorization header against the
* specified credential.
@@ -148,11 +169,25 @@ PJ_DEF(pj_status_t) pjsip_auth_srv_verify( pjsip_auth_srv *auth_srv,
}
/* Find the credential information for the account. */
- status = (*auth_srv->lookup)(rdata->tp_info.pool, &auth_srv->realm,
- &acc_name, &cred_info);
- if (status != PJ_SUCCESS) {
- *status_code = PJSIP_SC_FORBIDDEN;
- return status;
+ if (auth_srv->lookup2) {
+ pjsip_auth_lookup_cred_param param;
+
+ pj_bzero(&param, sizeof(param));
+ param.realm = auth_srv->realm;
+ param.acc_name = acc_name;
+ param.rdata = rdata;
+ status = (*auth_srv->lookup2)(rdata->tp_info.pool, &param, &cred_info);
+ if (status != PJ_SUCCESS) {
+ *status_code = PJSIP_SC_FORBIDDEN;
+ return status;
+ }
+ } else {
+ status = (*auth_srv->lookup)(rdata->tp_info.pool, &auth_srv->realm,
+ &acc_name, &cred_info);
+ if (status != PJ_SUCCESS) {
+ *status_code = PJSIP_SC_FORBIDDEN;
+ return status;
+ }
}
/* Authenticate with the specified credential. */
diff --git a/pjsip/src/pjsip/sip_config.c b/pjsip/src/pjsip/sip_config.c
index 8742c8a..92b8805 100644
--- a/pjsip/src/pjsip/sip_config.c
+++ b/pjsip/src/pjsip/sip_config.c
@@ -1,4 +1,4 @@
-/* $Id: sip_config.c 3999 2012-03-30 07:10:13Z bennylp $ */
+/* $Id: sip_config.c 4285 2012-10-19 04:23:57Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -26,6 +26,8 @@ pjsip_cfg_t pjsip_sip_cfg_var =
/* Global settings */
{
PJSIP_ALLOW_PORT_IN_FROMTO_HDR,
+ PJSIP_ACCEPT_REPLACE_IN_EARLY_STATE,
+ 0,
0,
PJSIP_DONT_SWITCH_TO_TCP
},
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index 008cad2..0e70d33 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -1,4 +1,4 @@
-/* $Id: sip_dialog.c 4173 2012-06-20 10:39:05Z ming $ */
+/* $Id: sip_dialog.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -206,8 +206,8 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
/* Calculate hash value of local tag. */
- dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
- dlg->local.info->tag.slen);
+ dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL,
+ &dlg->local.info->tag);
/* Randomize local CSeq. */
dlg->local.first_cseq = pj_rand() & 0x7FFF;
@@ -374,8 +374,7 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
pj_strdup(dlg->pool, &dlg->local.info_str, &tmp);
/* Calculate hash value of local tag. */
- dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
- dlg->local.info->tag.slen);
+ dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
/* Randomize local cseq */
@@ -522,8 +521,7 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
++dlg->tsx_count;
/* Calculate hash value of remote tag. */
- dlg->remote.tag_hval = pj_hash_calc(0, dlg->remote.info->tag.ptr,
- dlg->remote.info->tag.slen);
+ dlg->remote.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->remote.info->tag);
/* Update remote capabilities info */
pjsip_dlg_update_remote_cap(dlg, rdata->msg_info.msg, PJ_TRUE);
@@ -596,8 +594,11 @@ PJ_DEF(pj_status_t) pjsip_dlg_set_via_sent_by( pjsip_dialog *dlg,
if (!via_addr)
pj_bzero(&dlg->via_addr, sizeof(dlg->via_addr));
- else
- dlg->via_addr = *via_addr;
+ else {
+ if (pj_strcmp(&dlg->via_addr.host, &via_addr->host))
+ pj_strdup(dlg->pool, &dlg->via_addr.host, &via_addr->host);
+ dlg->via_addr.port = via_addr->port;
+ }
dlg->via_tp = via_tp;
return PJ_SUCCESS;
@@ -1814,7 +1815,7 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
res_code > 100 &&
res_code/100 <= 2 &&
pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) &&
- pj_strcmp(&dlg->remote.info->tag, &rdata->msg_info.to->tag)))
+ pj_stricmp(&dlg->remote.info->tag, &rdata->msg_info.to->tag)))
{
pjsip_contact_hdr *contact;
@@ -1823,7 +1824,7 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
* with To-tag or forking, apply strict update.
*/
pjsip_dlg_update_remote_cap(dlg, rdata->msg_info.msg,
- pj_strcmp(&dlg->remote.info->tag,
+ pj_stricmp(&dlg->remote.info->tag,
&rdata->msg_info.to->tag));
/* Update To tag. */
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 2510d14..ae55990 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -1,4 +1,4 @@
-/* $Id: sip_endpoint.c 4154 2012-06-05 10:41:17Z bennylp $ */
+/* $Id: sip_endpoint.c 4411 2013-03-04 04:34:38Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -812,6 +812,104 @@ PJ_DEF(pj_timer_heap_t*) pjsip_endpt_get_timer_heap(pjsip_endpoint *endpt)
return endpt->timer_heap;
}
+/* Init with default */
+PJ_DEF(void) pjsip_process_rdata_param_default(pjsip_process_rdata_param *p)
+{
+ pj_bzero(p, sizeof(*p));
+}
+
+/* Distribute rdata */
+PJ_DEF(pj_status_t) pjsip_endpt_process_rx_data( pjsip_endpoint *endpt,
+ pjsip_rx_data *rdata,
+ pjsip_process_rdata_param *p,
+ pj_bool_t *p_handled)
+{
+ pjsip_msg *msg;
+ pjsip_process_rdata_param def_prm;
+ pjsip_module *mod;
+ pj_bool_t handled = PJ_FALSE;
+ unsigned i;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);
+
+ if (p==NULL) {
+ p = &def_prm;
+ pjsip_process_rdata_param_default(p);
+ }
+
+ msg = rdata->msg_info.msg;
+
+ if (p_handled)
+ *p_handled = PJ_FALSE;
+
+ if (!p->silent) {
+ PJ_LOG(5, (THIS_FILE, "Distributing rdata to modules: %s",
+ pjsip_rx_data_get_info(rdata)));
+ pj_log_push_indent();
+ }
+
+ LOCK_MODULE_ACCESS(endpt);
+
+ /* Find start module */
+ if (p->start_mod) {
+ mod = (pjsip_module*)
+ pj_list_find_node(&endpt->module_list, p->start_mod);
+ if (!mod) {
+ status = PJ_ENOTFOUND;
+ goto on_return;
+ }
+ } else {
+ mod = endpt->module_list.next;
+ }
+
+ /* Start after the specified index */
+ for (i=0; i < p->idx_after_start && mod != &endpt->module_list; ++i) {
+ mod = mod->next;
+ }
+
+ /* Start with the specified priority */
+ while (mod != &endpt->module_list && mod->priority < (int)p->start_prio) {
+ mod = mod->next;
+ }
+
+ if (mod == &endpt->module_list) {
+ status = PJ_ENOTFOUND;
+ goto on_return;
+ }
+
+ /* Distribute */
+ if (msg->type == PJSIP_REQUEST_MSG) {
+ do {
+ if (mod->on_rx_request)
+ handled = (*mod->on_rx_request)(rdata);
+ if (handled)
+ break;
+ mod = mod->next;
+ } while (mod != &endpt->module_list);
+ } else {
+ do {
+ if (mod->on_rx_response)
+ handled = (*mod->on_rx_response)(rdata);
+ if (handled)
+ break;
+ mod = mod->next;
+ } while (mod != &endpt->module_list);
+ }
+
+ status = PJ_SUCCESS;
+
+on_return:
+ if (p_handled)
+ *p_handled = handled;
+
+ UNLOCK_MODULE_ACCESS(endpt);
+ if (!p->silent) {
+ pj_log_pop_indent();
+ }
+ return status;
+}
+
/*
* This is the callback that is called by the transport manager when it
* receives a message from the network.
@@ -820,7 +918,8 @@ static void endpt_on_rx_msg( pjsip_endpoint *endpt,
pj_status_t status,
pjsip_rx_data *rdata )
{
- pjsip_msg *msg = rdata->msg_info.msg;
+ pjsip_process_rdata_param proc_prm;
+ pj_bool_t handled = PJ_FALSE;
if (status != PJ_SUCCESS) {
char info[30];
@@ -927,57 +1026,20 @@ static void endpt_on_rx_msg( pjsip_endpoint *endpt,
}
#endif
+ pjsip_process_rdata_param_default(&proc_prm);
+ proc_prm.silent = PJ_TRUE;
- /* Distribute to modules, starting from modules with highest priority */
- LOCK_MODULE_ACCESS(endpt);
-
- if (msg->type == PJSIP_REQUEST_MSG) {
- pjsip_module *mod;
- pj_bool_t handled = PJ_FALSE;
-
- mod = endpt->module_list.next;
- while (mod != &endpt->module_list) {
- if (mod->on_rx_request)
- handled = (*mod->on_rx_request)(rdata);
- if (handled)
- break;
- mod = mod->next;
- }
-
- /* No module is able to handle the request. */
- if (!handled) {
- PJ_TODO(ENDPT_RESPOND_UNHANDLED_REQUEST);
- PJ_LOG(4,(THIS_FILE, "Message %s from %s:%d was dropped/unhandled by"
- " any modules",
- pjsip_rx_data_get_info(rdata),
- rdata->pkt_info.src_name,
- rdata->pkt_info.src_port));
- }
-
- } else {
- pjsip_module *mod;
- pj_bool_t handled = PJ_FALSE;
+ pjsip_endpt_process_rx_data(endpt, rdata, &proc_prm, &handled);
- mod = endpt->module_list.next;
- while (mod != &endpt->module_list) {
- if (mod->on_rx_response)
- handled = (*mod->on_rx_response)(rdata);
- if (handled)
- break;
- mod = mod->next;
- }
-
- if (!handled) {
- PJ_LOG(4,(THIS_FILE, "Message %s from %s:%d was dropped/unhandled"
- " by any modules",
- pjsip_rx_data_get_info(rdata),
- rdata->pkt_info.src_name,
- rdata->pkt_info.src_port));
- }
+ /* No module is able to handle the message */
+ if (!handled) {
+ PJ_LOG(4,(THIS_FILE, "%s from %s:%d was dropped/unhandled by"
+ " any modules",
+ pjsip_rx_data_get_info(rdata),
+ rdata->pkt_info.src_name,
+ rdata->pkt_info.src_port));
}
- UNLOCK_MODULE_ACCESS(endpt);
-
/* Must clear mod_data before returning rdata to transport, since
* rdata may be reused.
*/
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index 2d46fe9..26f4aca 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -1,4 +1,4 @@
-/* $Id: sip_parser.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_parser.c 4288 2012-10-26 09:30:37Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -1522,8 +1522,15 @@ static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner,
/* Get the SIP-URL */
has_bracket = (*scanner->curptr == '<');
- if (has_bracket)
+ if (has_bracket) {
pj_scan_get_char(scanner);
+ } else if (name_addr->display.slen) {
+ /* Must have bracket now (2012-10-26).
+ * Allowing (invalid) name-addr to pass URI verification will
+ * cause us to send invalid URI to the wire.
+ */
+ PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
+ }
name_addr->uri = int_parse_uri( scanner, pool, PJ_TRUE );
if (has_bracket) {
if (pj_scan_get_char(scanner) != '>')
diff --git a/pjsip/src/pjsip/sip_tel_uri.c b/pjsip/src/pjsip/sip_tel_uri.c
index 4120ae0..b98db57 100644
--- a/pjsip/src/pjsip/sip_tel_uri.c
+++ b/pjsip/src/pjsip/sip_tel_uri.c
@@ -1,4 +1,4 @@
-/* $Id: sip_tel_uri.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_tel_uri.c 4322 2013-01-17 10:09:09Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -182,7 +182,7 @@ static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
{
int printed;
char *startbuf = buf;
- char *endbuf = buf+size;
+ char *endbuf = buf+size-1;
const pjsip_parser_const_t *pc = pjsip_parser_const();
PJ_UNUSED_ARG(context);
@@ -217,6 +217,8 @@ static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
return -1;
buf += printed;
+ *buf = '\0';
+
return (buf-startbuf);
}
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 4b3dd12..1321d9f 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transaction.c 4165 2012-06-14 09:04:20Z bennylp $ */
+/* $Id: sip_transaction.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -403,7 +403,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key,
*/
const pj_str_t *branch = &rdata->msg_info.via->branch_param;
- if (pj_strncmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) {
+ if (pj_strnicmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) {
/* Create transaction key. */
return create_tsx_key_3261(pool, key, role, method, branch);
@@ -548,10 +548,10 @@ static pj_status_t mod_tsx_layer_register_tsx( pjsip_transaction *tsx)
* Do not use PJ_ASSERT_RETURN since it evaluates the expression
* twice!
*/
- if(pj_hash_get(mod_tsx_layer.htable,
- tsx->transaction_key.ptr,
- tsx->transaction_key.slen,
- NULL))
+ if(pj_hash_get_lower(mod_tsx_layer.htable,
+ tsx->transaction_key.ptr,
+ tsx->transaction_key.slen,
+ NULL))
{
pj_mutex_unlock(mod_tsx_layer.mutex);
PJ_LOG(2,(THIS_FILE,
@@ -568,11 +568,13 @@ static pj_status_t mod_tsx_layer_register_tsx( pjsip_transaction *tsx)
/* Register the transaction to the hash table. */
#ifdef PRECALC_HASH
- pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, tsx->hashed_key, tsx);
+ pj_hash_set_lower( tsx->pool, mod_tsx_layer.htable,
+ tsx->transaction_key.ptr,
+ tsx->transaction_key.slen, tsx->hashed_key, tsx);
#else
- pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, 0, tsx);
+ pj_hash_set_lower( tsx->pool, mod_tsx_layer.htable,
+ tsx->transaction_key.ptr,
+ tsx->transaction_key.slen, 0, tsx);
#endif
/* Unlock mutex. */
@@ -604,11 +606,11 @@ static void mod_tsx_layer_unregister_tsx( pjsip_transaction *tsx)
/* Register the transaction to the hash table. */
#ifdef PRECALC_HASH
- pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, tsx->hashed_key, NULL);
+ pj_hash_set_lower( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
+ tsx->transaction_key.slen, tsx->hashed_key, NULL);
#else
- pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, 0, NULL);
+ pj_hash_set_lower( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
+ tsx->transaction_key.slen, 0, NULL);
#endif
TSX_TRACE_((THIS_FILE,
@@ -651,7 +653,8 @@ PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
pj_mutex_lock(mod_tsx_layer.mutex);
tsx = (pjsip_transaction*)
- pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen, &hval );
+ pj_hash_get_lower( mod_tsx_layer.htable, key->ptr, key->slen,
+ &hval );
pj_mutex_unlock(mod_tsx_layer.mutex);
TSX_TRACE_((THIS_FILE,
@@ -785,7 +788,7 @@ static pj_bool_t mod_tsx_layer_on_rx_request(pjsip_rx_data *rdata)
pj_mutex_lock( mod_tsx_layer.mutex );
tsx = (pjsip_transaction*)
- pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, &hval );
+ pj_hash_get_lower( mod_tsx_layer.htable, key.ptr, key.slen, &hval );
TSX_TRACE_((THIS_FILE,
@@ -834,7 +837,7 @@ static pj_bool_t mod_tsx_layer_on_rx_response(pjsip_rx_data *rdata)
pj_mutex_lock( mod_tsx_layer.mutex );
tsx = (pjsip_transaction*)
- pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, &hval );
+ pj_hash_get_lower( mod_tsx_layer.htable, key.ptr, key.slen, &hval );
TSX_TRACE_((THIS_FILE,
@@ -1299,8 +1302,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uac( pjsip_module *tsx_user,
/* Calculate hashed key value. */
#ifdef PRECALC_HASH
- tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
- tsx->transaction_key.slen);
+ tsx->hashed_key = pj_hash_calc_tolower(0, NULL, &tsx->transaction_key);
#endif
PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
@@ -1432,8 +1434,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
/* Calculate hashed key value. */
#ifdef PRECALC_HASH
- tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
- tsx->transaction_key.slen);
+ tsx->hashed_key = pj_hash_calc_tolower(0, NULL, &tsx->transaction_key);
#endif
/* Duplicate branch parameter for transaction. */
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 4d8b77e..1598241 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport.c 4094 2012-04-26 09:31:00Z bennylp $ */
+/* $Id: sip_transport.c 4295 2012-11-06 05:22:11Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -24,6 +24,7 @@
#include <pjsip/sip_private.h>
#include <pjsip/sip_errno.h>
#include <pjsip/sip_module.h>
+#include <pj/addr_resolv.h>
#include <pj/except.h>
#include <pj/os.h>
#include <pj/log.h>
@@ -197,6 +198,13 @@ struct transport_names_t
"TCP IPv6 transport",
PJSIP_TRANSPORT_RELIABLE
},
+ {
+ PJSIP_TRANSPORT_TLS6,
+ 5061,
+ {"TLS", 3},
+ "TLS IPv6 transport",
+ PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE
+ },
};
static void tp_state_callback(pjsip_transport *tp,
@@ -594,6 +602,89 @@ PJ_DEF(char*) pjsip_rx_data_get_info(pjsip_rx_data *rdata)
return rdata->msg_info.info;
}
+/* Clone pjsip_rx_data. */
+PJ_DEF(pj_status_t) pjsip_rx_data_clone( const pjsip_rx_data *src,
+ unsigned flags,
+ pjsip_rx_data **p_rdata)
+{
+ pj_pool_t *pool;
+ pjsip_rx_data *dst;
+ pjsip_hdr *hdr;
+
+ PJ_ASSERT_RETURN(src && flags==0 && p_rdata, PJ_EINVAL);
+
+ pool = pj_pool_create(src->tp_info.pool->factory,
+ "rtd%p",
+ PJSIP_POOL_RDATA_LEN,
+ PJSIP_POOL_RDATA_INC,
+ NULL);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ dst = PJ_POOL_ZALLOC_T(pool, pjsip_rx_data);
+
+ /* Parts of tp_info */
+ dst->tp_info.pool = pool;
+ dst->tp_info.transport = (pjsip_transport*)src->tp_info.transport;
+
+ /* pkt_info can be memcopied */
+ pj_memcpy(&dst->pkt_info, &src->pkt_info, sizeof(src->pkt_info));
+
+ /* msg_info needs deep clone */
+ dst->msg_info.msg_buf = dst->pkt_info.packet;
+ dst->msg_info.len = src->msg_info.len;
+ dst->msg_info.msg = pjsip_msg_clone(pool, src->msg_info.msg);
+ pj_list_init(&dst->msg_info.parse_err);
+
+#define GET_MSG_HDR2(TYPE, type, var) \
+ case PJSIP_H_##TYPE: \
+ if (!dst->msg_info.var) { \
+ dst->msg_info.var = (pjsip_##type##_hdr*)hdr; \
+ } \
+ break
+#define GET_MSG_HDR(TYPE, var_type) GET_MSG_HDR2(TYPE, var_type, var_type)
+
+ hdr = dst->msg_info.msg->hdr.next;
+ while (hdr != &dst->msg_info.msg->hdr) {
+ switch (hdr->type) {
+ GET_MSG_HDR(CALL_ID, cid);
+ GET_MSG_HDR(FROM, from);
+ GET_MSG_HDR(TO, to);
+ GET_MSG_HDR(VIA, via);
+ GET_MSG_HDR(CSEQ, cseq);
+ GET_MSG_HDR(MAX_FORWARDS, max_fwd);
+ GET_MSG_HDR(ROUTE, route);
+ GET_MSG_HDR2(RECORD_ROUTE, rr, record_route);
+ GET_MSG_HDR(CONTENT_TYPE, ctype);
+ GET_MSG_HDR(CONTENT_LENGTH, clen);
+ GET_MSG_HDR(REQUIRE, require);
+ GET_MSG_HDR(SUPPORTED, supported);
+ default:
+ break;
+ }
+ hdr = hdr->next;
+ }
+
+#undef GET_MSG_HDR
+#undef GET_MSG_HDR2
+
+ *p_rdata = dst;
+
+ /* Finally add transport ref */
+ return pjsip_transport_add_ref(dst->tp_info.transport);
+}
+
+/* Free previously cloned pjsip_rx_data. */
+PJ_DEF(pj_status_t) pjsip_rx_data_free_cloned(pjsip_rx_data *rdata)
+{
+ PJ_ASSERT_RETURN(rdata, PJ_EINVAL);
+
+ pjsip_transport_dec_ref(rdata->tp_info.transport);
+ pj_pool_release(rdata->tp_info.pool);
+
+ return PJ_SUCCESS;
+}
+
/*****************************************************************************
*
* TRANSPORT KEY
@@ -1080,6 +1171,10 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_unregister_tpfactory( pjsip_tpmgr *mgr,
return PJ_SUCCESS;
}
+PJ_DECL(void) pjsip_tpmgr_fla2_param_default(pjsip_tpmgr_fla2_param *prm)
+{
+ pj_bzero(prm, sizeof(*prm));
+}
/*****************************************************************************
*
@@ -1138,7 +1233,27 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
return PJ_SUCCESS;
}
+/* Get the interface to send packet to the specified address */
+static pj_status_t get_net_interface(pjsip_transport_type_e tp_type,
+ const pj_str_t *dst,
+ pj_str_t *itf_str_addr)
+{
+ int af;
+ pj_sockaddr itf_addr;
+ pj_status_t status;
+
+ af = (tp_type & PJSIP_TRANSPORT_IPV6)? PJ_AF_INET6 : PJ_AF_INET;
+ status = pj_getipinterface(af, dst, &itf_addr, PJ_FALSE, NULL);
+ if (status != PJ_SUCCESS)
+ return status;
+ /* Print address */
+ pj_sockaddr_print(&itf_addr, itf_str_addr->ptr,
+ PJ_INET6_ADDRSTRLEN, 0);
+ itf_str_addr->slen = pj_ansi_strlen(itf_str_addr->ptr);
+
+ return PJ_SUCCESS;
+}
/*
* Find out the appropriate local address info (IP address and port) to
@@ -1149,46 +1264,66 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
* In this implementation, it will only select the transport based on
* the transport type in the request.
*/
-PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
+PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr,
pj_pool_t *pool,
- pjsip_transport_type_e type,
- const pjsip_tpselector *sel,
- pj_str_t *ip_addr,
- int *port)
+ pjsip_tpmgr_fla2_param *prm)
{
+ char tmp_buf[PJ_INET6_ADDRSTRLEN+10];
+ pj_str_t tmp_str;
pj_status_t status = PJSIP_EUNSUPTRANSPORT;
unsigned flag;
/* Sanity checks */
- PJ_ASSERT_RETURN(tpmgr && pool && ip_addr && port, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tpmgr && pool && prm, PJ_EINVAL);
- ip_addr->slen = 0;
- *port = 0;
+ pj_strset(&tmp_str, tmp_buf, 0);
+ prm->ret_addr.slen = 0;
+ prm->ret_port = 0;
+ prm->ret_tp = NULL;
- flag = pjsip_transport_get_flag_from_type(type);
+ flag = pjsip_transport_get_flag_from_type(prm->tp_type);
- if (sel && sel->type == PJSIP_TPSELECTOR_TRANSPORT &&
- sel->u.transport)
+ if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_TRANSPORT &&
+ prm->tp_sel->u.transport)
{
- pj_strdup(pool, ip_addr, &sel->u.transport->local_name.host);
- *port = sel->u.transport->local_name.port;
+ const pjsip_transport *tp = prm->tp_sel->u.transport;
+ if (prm->local_if) {
+ status = get_net_interface((pjsip_transport_type_e)tp->key.type,
+ &prm->dst_host, &tmp_str);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ pj_strdup(pool, &prm->ret_addr, &tmp_str);
+ prm->ret_port = pj_sockaddr_get_port(&tp->local_addr);
+ prm->ret_tp = tp;
+ } else {
+ pj_strdup(pool, &prm->ret_addr, &tp->local_name.host);
+ prm->ret_port = (pj_uint16_t)tp->local_name.port;
+ }
status = PJ_SUCCESS;
- } else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER &&
- sel->u.listener)
+ } else if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_LISTENER &&
+ prm->tp_sel->u.listener)
{
- pj_strdup(pool, ip_addr, &sel->u.listener->addr_name.host);
- *port = sel->u.listener->addr_name.port;
+ if (prm->local_if) {
+ status = get_net_interface(prm->tp_sel->u.listener->type,
+ &prm->dst_host, &tmp_str);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ pj_strdup(pool, &prm->ret_addr, &tmp_str);
+ } else {
+ pj_strdup(pool, &prm->ret_addr,
+ &prm->tp_sel->u.listener->addr_name.host);
+ }
+ prm->ret_port = (pj_uint16_t)prm->tp_sel->u.listener->addr_name.port;
status = PJ_SUCCESS;
} else if ((flag & PJSIP_TRANSPORT_DATAGRAM) != 0) {
-
pj_sockaddr remote;
int addr_len;
pjsip_transport *tp;
pj_bzero(&remote, sizeof(remote));
- if (type & PJSIP_TRANSPORT_IPV6) {
+ if (prm->tp_type & PJSIP_TRANSPORT_IPV6) {
addr_len = sizeof(pj_sockaddr_in6);
remote.addr.sa_family = pj_AF_INET6();
} else {
@@ -1196,13 +1331,23 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
remote.addr.sa_family = pj_AF_INET();
}
- status = pjsip_tpmgr_acquire_transport(tpmgr, type, &remote,
+ status = pjsip_tpmgr_acquire_transport(tpmgr, prm->tp_type, &remote,
addr_len, NULL, &tp);
if (status == PJ_SUCCESS) {
- pj_strdup(pool, ip_addr, &tp->local_name.host);
- *port = tp->local_name.port;
- status = PJ_SUCCESS;
+ if (prm->local_if) {
+ status = get_net_interface((pjsip_transport_type_e)
+ tp->key.type,
+ &prm->dst_host, &tmp_str);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ pj_strdup(pool, &prm->ret_addr, &tmp_str);
+ prm->ret_port = pj_sockaddr_get_port(&tp->local_addr);
+ prm->ret_tp = tp;
+ } else {
+ pj_strdup(pool, &prm->ret_addr, &tp->local_name.host);
+ prm->ret_port = (pj_uint16_t)tp->local_name.port;
+ }
pjsip_transport_dec_ref(tp);
}
@@ -1215,22 +1360,66 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
f = tpmgr->factory_list.next;
while (f != &tpmgr->factory_list) {
- if (f->type == type)
+ if (f->type == prm->tp_type)
break;
f = f->next;
}
if (f != &tpmgr->factory_list) {
- pj_strdup(pool, ip_addr, &f->addr_name.host);
- *port = f->addr_name.port;
+ if (prm->local_if) {
+ status = get_net_interface(f->type, &prm->dst_host,
+ &tmp_str);
+ if (status == PJ_SUCCESS) {
+ pj_strdup(pool, &prm->ret_addr, &tmp_str);
+ } else {
+ /* It could fail "normally" on certain cases, e.g.
+ * when connecting to IPv6 link local address, it
+ * will wail with EINVAL.
+ * In this case, fallback to use the default interface
+ * rather than failing the call.
+ */
+ PJ_PERROR(5,(THIS_FILE, status, "Warning: unable to "
+ "determine local interface"));
+ pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
+ status = PJ_SUCCESS;
+ }
+ } else {
+ pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
+ }
+ prm->ret_port = (pj_uint16_t)f->addr_name.port;
status = PJ_SUCCESS;
}
pj_lock_release(tpmgr->lock);
}
+on_return:
return status;
}
+PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
+ pj_pool_t *pool,
+ pjsip_transport_type_e type,
+ const pjsip_tpselector *sel,
+ pj_str_t *ip_addr,
+ int *port)
+{
+ pjsip_tpmgr_fla2_param prm;
+ pj_status_t status;
+
+ pjsip_tpmgr_fla2_param_default(&prm);
+ prm.tp_type = type;
+ prm.tp_sel = sel;
+
+ status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &prm);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ *ip_addr = prm.ret_addr;
+ *port = prm.ret_port;
+
+ return PJ_SUCCESS;
+}
+
/*
* Return number of transports currently registered to the transport
* manager.
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index 141434b..808cee9 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tcp.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_transport_tcp.c 4294 2012-11-06 05:02:10Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -57,6 +57,7 @@ struct tcp_listener
pjsip_endpoint *endpt;
pjsip_tpmgr *tpmgr;
pj_activesock_t *asock;
+ pj_sockaddr bound_addr;
pj_qos_type qos_type;
pj_qos_params qos_params;
};
@@ -73,6 +74,7 @@ struct delayed_tdata
{
PJ_DECL_LIST_MEMBER(struct delayed_tdata);
pjsip_tx_data_op_key *tdata_op_key;
+ pj_time_val timeout;
};
@@ -140,8 +142,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
static pj_status_t tcp_create(struct tcp_listener *listener,
pj_pool_t *pool,
pj_sock_t sock, pj_bool_t is_server,
- const pj_sockaddr_in *local,
- const pj_sockaddr_in *remote,
+ const pj_sockaddr *local,
+ const pj_sockaddr *remote,
struct tcp_transport **p_tcp);
@@ -158,10 +160,10 @@ static void tcp_perror(const char *sender, const char *title,
static void sockaddr_to_host_port( pj_pool_t *pool,
pjsip_host_port *host_port,
- const pj_sockaddr_in *addr )
+ const pj_sockaddr *addr )
{
host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+4);
- pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 2);
+ pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 0);
host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
host_port->port = pj_sockaddr_get_port(addr);
}
@@ -266,17 +268,21 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
listener->factory.pool = pool;
- listener->factory.type = PJSIP_TRANSPORT_TCP;
- listener->factory.type_name = "tcp";
+ listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
+ PJSIP_TRANSPORT_TCP6;
+ listener->factory.type_name = (char*)
+ pjsip_transport_get_type_name(listener->factory.type);
listener->factory.flag =
- pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
+ pjsip_transport_get_flag_from_type(listener->factory.type);
listener->qos_type = cfg->qos_type;
pj_memcpy(&listener->qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
+ if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
+ pj_ansi_strcat(listener->factory.obj_name, "6");
- status = pj_lock_create_recursive_mutex(pool, "tcplis",
+ status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
&listener->factory.lock);
if (status != PJ_SUCCESS)
goto on_error;
@@ -292,6 +298,11 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
2, listener->factory.obj_name,
"SIP TCP listener socket");
+ /* Bind address may be different than factory.local_addr because
+ * factory.local_addr will be resolved below.
+ */
+ pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);
+
/* Bind socket */
listener_addr = &listener->factory.local_addr;
pj_sockaddr_cp(listener_addr, &cfg->bind_addr);
@@ -326,19 +337,18 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
if (!pj_sockaddr_has_addr(listener_addr)) {
pj_sockaddr hostip;
- status = pj_gethostip(pj_AF_INET(), &hostip);
+ status = pj_gethostip(listener->bound_addr.addr.sa_family,
+ &hostip);
if (status != PJ_SUCCESS)
goto on_error;
- pj_memcpy(pj_sockaddr_get_addr(listener_addr),
- pj_sockaddr_get_addr(&hostip),
- pj_sockaddr_get_addr_len(&hostip));
+ pj_sockaddr_copy_addr(listener_addr, &hostip);
}
/* Save the address name */
sockaddr_to_host_port(listener->factory.pool,
&listener->factory.addr_name,
- (pj_sockaddr_in*)listener_addr);
+ listener_addr);
}
/* If port is zero, get the bound port */
@@ -535,8 +545,8 @@ static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e);
static pj_status_t tcp_create( struct tcp_listener *listener,
pj_pool_t *pool,
pj_sock_t sock, pj_bool_t is_server,
- const pj_sockaddr_in *local,
- const pj_sockaddr_in *remote,
+ const pj_sockaddr *local,
+ const pj_sockaddr *remote,
struct tcp_transport **p_tcp)
{
struct tcp_transport *tcp;
@@ -544,6 +554,7 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
pj_activesock_cfg asock_cfg;
pj_activesock_cb tcp_callback;
const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
+ char print_addr[PJ_INET6_ADDRSTRLEN+10];
pj_status_t status;
@@ -579,18 +590,21 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
goto on_error;
}
- tcp->base.key.type = PJSIP_TRANSPORT_TCP;
- pj_memcpy(&tcp->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
- tcp->base.type_name = "tcp";
- tcp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
+ tcp->base.key.type = listener->factory.type;
+ pj_sockaddr_cp(&tcp->base.key.rem_addr, remote);
+ tcp->base.type_name = (char*)pjsip_transport_get_type_name(
+ (pjsip_transport_type_e)tcp->base.key.type);
+ tcp->base.flag = pjsip_transport_get_flag_from_type(
+ (pjsip_transport_type_e)tcp->base.key.type);
tcp->base.info = (char*) pj_pool_alloc(pool, 64);
- pj_ansi_snprintf(tcp->base.info, 64, "TCP to %s:%d",
- pj_inet_ntoa(remote->sin_addr),
- (int)pj_ntohs(remote->sin_port));
+ pj_ansi_snprintf(tcp->base.info, 64, "%s to %s",
+ tcp->base.type_name,
+ pj_sockaddr_print(remote, print_addr,
+ sizeof(print_addr), 3));
- tcp->base.addr_len = sizeof(pj_sockaddr_in);
- pj_memcpy(&tcp->base.local_addr, local, sizeof(pj_sockaddr_in));
+ tcp->base.addr_len = pj_sockaddr_get_len(remote);
+ pj_sockaddr_cp(&tcp->base.local_addr, local);
sockaddr_to_host_port(pool, &tcp->base.local_name, local);
sockaddr_to_host_port(pool, &tcp->base.remote_name, remote);
tcp->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
@@ -601,7 +615,6 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
tcp->base.do_shutdown = &tcp_shutdown;
tcp->base.destroy = &tcp_destroy_transport;
-
/* Create active socket */
pj_activesock_cfg_default(&asock_cfg);
asock_cfg.async_cnt = 1;
@@ -649,6 +662,9 @@ on_error:
/* Flush all delayed transmision once the socket is connected. */
static void tcp_flush_pending_tx(struct tcp_transport *tcp)
{
+ pj_time_val now;
+
+ pj_gettickcount(&now);
pj_lock_acquire(tcp->base.lock);
while (!pj_list_empty(&tcp->delayed_list)) {
struct delayed_tdata *pending_tx;
@@ -663,12 +679,20 @@ static void tcp_flush_pending_tx(struct tcp_transport *tcp)
tdata = pending_tx->tdata_op_key->tdata;
op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
+ if (pending_tx->timeout.sec > 0 &&
+ PJ_TIME_VAL_GT(now, pending_tx->timeout))
+ {
+ continue;
+ }
+
/* send! */
size = tdata->buf.cur - tdata->buf.start;
status = pj_activesock_send(tcp->asock, op_key, tdata->buf.start,
&size, 0);
if (status != PJ_EPENDING) {
+ pj_lock_release(tcp->base.lock);
on_data_sent(tcp->asock, op_key, size);
+ pj_lock_acquire(tcp->base.lock);
}
}
@@ -791,7 +815,7 @@ static pj_status_t tcp_start_read(struct tcp_transport *tcp)
{
pj_pool_t *pool;
pj_ssize_t size;
- pj_sockaddr_in *rem_addr;
+ pj_sockaddr *rem_addr;
void *readbuf[1];
pj_status_t status;
@@ -814,11 +838,11 @@ static pj_status_t tcp_start_read(struct tcp_transport *tcp)
sizeof(pj_ioqueue_op_key_t));
tcp->rdata.pkt_info.src_addr = tcp->base.key.rem_addr;
- tcp->rdata.pkt_info.src_addr_len = sizeof(pj_sockaddr_in);
- rem_addr = (pj_sockaddr_in*) &tcp->base.key.rem_addr;
- pj_ansi_strcpy(tcp->rdata.pkt_info.src_name,
- pj_inet_ntoa(rem_addr->sin_addr));
- tcp->rdata.pkt_info.src_port = pj_ntohs(rem_addr->sin_port);
+ tcp->rdata.pkt_info.src_addr_len = sizeof(tcp->rdata.pkt_info.src_addr);
+ rem_addr = &tcp->base.key.rem_addr;
+ pj_sockaddr_print(rem_addr, tcp->rdata.pkt_info.src_name,
+ sizeof(tcp->rdata.pkt_info.src_name), 0);
+ tcp->rdata.pkt_info.src_port = pj_sockaddr_get_port(rem_addr);
size = sizeof(tcp->rdata.pkt_info.packet);
readbuf[0] = tcp->rdata.pkt_info.packet;
@@ -848,23 +872,25 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
struct tcp_listener *listener;
struct tcp_transport *tcp;
pj_sock_t sock;
- pj_sockaddr_in local_addr;
+ pj_sockaddr local_addr;
pj_status_t status;
/* Sanity checks */
PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
addr_len && p_transport, PJ_EINVAL);
- /* Check that address is a sockaddr_in */
- PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() &&
- addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL);
+ /* Check that address is a sockaddr_in or sockaddr_in6*/
+ PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
+ addr_len == sizeof(pj_sockaddr_in)) ||
+ (rem_addr->addr.sa_family == pj_AF_INET6() &&
+ addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);
listener = (struct tcp_listener*)factory;
-
/* Create socket */
- status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
+ status = pj_sock_socket(rem_addr->addr.sa_family, pj_SOCK_STREAM(),
+ 0, &sock);
if (status != PJ_SUCCESS)
return status;
@@ -874,15 +900,20 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
2, listener->factory.obj_name,
"outgoing SIP TCP socket");
- /* Bind to any port */
- status = pj_sock_bind_in(sock, 0, 0);
+ /* Bind to listener's address and any port */
+ pj_bzero(&local_addr, sizeof(local_addr));
+ pj_sockaddr_cp(&local_addr, &listener->bound_addr);
+ pj_sockaddr_set_port(&local_addr, 0);
+
+ status = pj_sock_bind(sock, &local_addr,
+ pj_sockaddr_get_len(&local_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
return status;
}
/* Get the local port */
- addr_len = sizeof(pj_sockaddr_in);
+ addr_len = sizeof(local_addr);
status = pj_sock_getsockname(sock, &local_addr, &addr_len);
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
@@ -890,12 +921,13 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
}
/* Initially set the address from the listener's address */
- local_addr.sin_addr.s_addr =
- ((pj_sockaddr_in*)&listener->factory.local_addr)->sin_addr.s_addr;
+ if (!pj_sockaddr_has_addr(&local_addr)) {
+ pj_sockaddr_copy_addr(&local_addr, &listener->factory.local_addr);
+ }
/* Create the transport descriptor */
status = tcp_create(listener, NULL, sock, PJ_FALSE, &local_addr,
- (pj_sockaddr_in*)rem_addr, &tcp);
+ rem_addr, &tcp);
if (status != PJ_SUCCESS)
return status;
@@ -903,7 +935,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Start asynchronous connect() operation */
tcp->has_pending_connect = PJ_TRUE;
status = pj_activesock_start_connect(tcp->asock, tcp->base.pool, rem_addr,
- sizeof(pj_sockaddr_in));
+ addr_len);
if (status == PJ_SUCCESS) {
on_connect_complete(tcp->asock, PJ_SUCCESS);
} else if (status != PJ_EPENDING) {
@@ -915,18 +947,17 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Update (again) local address, just in case local address currently
* set is different now that asynchronous connect() is started.
*/
- addr_len = sizeof(pj_sockaddr_in);
+ addr_len = sizeof(local_addr);
if (pj_sock_getsockname(sock, &local_addr, &addr_len)==PJ_SUCCESS) {
- pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr;
+ pj_sockaddr *tp_addr = &tcp->base.local_addr;
/* Some systems (like old Win32 perhaps) may not set local address
* properly before socket is fully connected.
*/
- if (tp_addr->sin_addr.s_addr != local_addr.sin_addr.s_addr &&
- local_addr.sin_addr.s_addr != 0)
+ if (pj_sockaddr_cmp(tp_addr, &local_addr) &&
+ pj_sockaddr_get_port(&local_addr) != 0)
{
- tp_addr->sin_addr.s_addr = local_addr.sin_addr.s_addr;
- tp_addr->sin_port = local_addr.sin_port;
+ pj_sockaddr_cp(tp_addr, &local_addr);
sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name,
&local_addr);
}
@@ -962,6 +993,7 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
struct tcp_transport *tcp;
char addr[PJ_INET6_ADDRSTRLEN+10];
pjsip_tp_state_callback state_cb;
+ pj_sockaddr tmp_src_addr;
pj_status_t status;
PJ_UNUSED_ARG(src_addr_len);
@@ -985,13 +1017,19 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
2, listener->factory.obj_name,
"incoming SIP TCP socket");
+ /* tcp_create() expect pj_sockaddr, so copy src_addr to temporary var,
+ * just in case.
+ */
+ pj_bzero(&tmp_src_addr, sizeof(tmp_src_addr));
+ pj_sockaddr_cp(&tmp_src_addr, src_addr);
+
/*
* Incoming connection!
* Create TCP transport for the new socket.
*/
status = tcp_create( listener, NULL, sock, PJ_TRUE,
- (const pj_sockaddr_in*)&listener->factory.local_addr,
- (const pj_sockaddr_in*)src_addr, &tcp);
+ &listener->factory.local_addr,
+ &tmp_src_addr, &tcp);
if (status == PJ_SUCCESS) {
status = tcp_start_read(tcp);
if (status != PJ_SUCCESS) {
@@ -1095,9 +1133,9 @@ static pj_status_t tcp_send_msg(pjsip_transport *transport,
PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
/* Check the address is supported */
- PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
-
-
+ PJ_ASSERT_RETURN(rem_addr && (addr_len==sizeof(pj_sockaddr_in) ||
+ addr_len==sizeof(pj_sockaddr_in6)),
+ PJ_EINVAL);
/* Init op key. */
tdata->op_key.tdata = tdata;
@@ -1122,10 +1160,19 @@ static pj_status_t tcp_send_msg(pjsip_transport *transport,
/*
* connect() is still in progress. Put the transmit data to
* the delayed list.
+ * Starting from #1583 (https://trac.pjsip.org/repos/ticket/1583),
+ * we also add timeout value for the transmit data. When the
+ * connect() is completed, the timeout value will be checked to
+ * determine whether the transmit data needs to be sent.
*/
- delayed_tdata = PJ_POOL_ALLOC_T(tdata->pool,
- struct delayed_tdata);
+ delayed_tdata = PJ_POOL_ZALLOC_T(tdata->pool,
+ struct delayed_tdata);
delayed_tdata->tdata_op_key = &tdata->op_key;
+ if (tdata->msg && tdata->msg->type == PJSIP_REQUEST_MSG) {
+ pj_gettickcount(&delayed_tdata->timeout);
+ delayed_tdata->timeout.msec += pjsip_cfg()->tsx.td;
+ pj_time_val_normalize(&delayed_tdata->timeout);
+ }
pj_list_push_back(&tcp->delayed_list, delayed_tdata);
status = PJ_EPENDING;
@@ -1269,7 +1316,7 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
pj_status_t status)
{
struct tcp_transport *tcp;
- pj_sockaddr_in addr;
+ pj_sockaddr addr;
int addrlen;
pjsip_tp_state_callback state_cb;
@@ -1314,15 +1361,14 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
* set is different now that the socket is connected (could happen
* on some systems, like old Win32 probably?).
*/
- addrlen = sizeof(pj_sockaddr_in);
+ addrlen = sizeof(addr);
if (pj_sock_getsockname(tcp->sock, &addr, &addrlen)==PJ_SUCCESS) {
- pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr;
+ pj_sockaddr *tp_addr = &tcp->base.local_addr;
if (pj_sockaddr_has_addr(&addr) &&
- tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr)
+ pj_sockaddr_cmp(&addr, tp_addr) != 0)
{
- tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
- tp_addr->sin_port = addr.sin_port;
+ pj_sockaddr_cp(tp_addr, &addr);
sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name,
tp_addr);
}
diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
index 878b6db..2f244cc 100644
--- a/pjsip/src/pjsip/sip_transport_tls.c
+++ b/pjsip/src/pjsip/sip_transport_tls.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tls.c 4146 2012-05-30 06:35:59Z nanang $ */
+/* $Id: sip_transport_tls.c 4411 2013-03-04 04:34:38Z nanang $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -55,6 +55,7 @@ struct tls_listener
pjsip_endpoint *endpt;
pjsip_tpmgr *tpmgr;
pj_ssl_sock_t *ssock;
+ pj_sockaddr bound_addr;
pj_ssl_cert_t *cert;
pjsip_tls_setting tls_setting;
};
@@ -71,6 +72,7 @@ struct delayed_tdata
{
PJ_DECL_LIST_MEMBER(struct delayed_tdata);
pjsip_tx_data_op_key *tdata_op_key;
+ pj_time_val timeout;
};
@@ -146,8 +148,8 @@ static pj_status_t tls_create(struct tls_listener *listener,
pj_pool_t *pool,
pj_ssl_sock_t *ssock,
pj_bool_t is_server,
- const pj_sockaddr_in *local,
- const pj_sockaddr_in *remote,
+ const pj_sockaddr *local,
+ const pj_sockaddr *remote,
const pj_str_t *remote_name,
struct tls_transport **p_tls);
@@ -165,10 +167,10 @@ static void tls_perror(const char *sender, const char *title,
static void sockaddr_to_host_port( pj_pool_t *pool,
pjsip_host_port *host_port,
- const pj_sockaddr_in *addr )
+ const pj_sockaddr *addr )
{
host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+4);
- pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 2);
+ pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 0);
host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
host_port->port = pj_sockaddr_get_port(addr);
}
@@ -234,29 +236,50 @@ static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status)
*/
PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
const pjsip_tls_setting *opt,
- const pj_sockaddr_in *local,
+ const pj_sockaddr_in *local_in,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_tpfactory **p_factory)
{
+ pj_sockaddr local;
+
+ if (local_in)
+ pj_sockaddr_cp(&local, local_in);
+
+ return pjsip_tls_transport_start2(endpt, opt, (local_in? &local : NULL),
+ a_name, async_cnt, p_factory);
+}
+
+PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
+ const pjsip_tls_setting *opt,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name,
+ unsigned async_cnt,
+ pjsip_tpfactory **p_factory)
+{
pj_pool_t *pool;
+ pj_bool_t is_ipv6;
+ int af;
struct tls_listener *listener;
pj_ssl_sock_param ssock_param;
- pj_sockaddr_in *listener_addr;
+ pj_sockaddr *listener_addr;
pj_bool_t has_listener;
pj_status_t status;
/* Sanity check */
PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
+ is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());
+ af = is_ipv6 ? pj_AF_INET6() : pj_AF_INET();
+
/* Verify that address given in a_name (if any) is valid */
if (a_name && a_name->host.slen) {
- pj_sockaddr_in tmp;
+ pj_sockaddr 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)
+ status = pj_sockaddr_init(af, &tmp, &a_name->host,
+ (pj_uint16_t)a_name->port);
+ if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
+ (!is_ipv6 && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
{
/* Invalid address */
return PJ_EINVAL;
@@ -269,19 +292,25 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
listener = PJ_POOL_ZALLOC_T(pool, struct tls_listener);
listener->factory.pool = pool;
- listener->factory.type = PJSIP_TRANSPORT_TLS;
- listener->factory.type_name = "tls";
+ if (is_ipv6)
+ listener->factory.type = PJSIP_TRANSPORT_TLS6;
+ else
+ listener->factory.type = PJSIP_TRANSPORT_TLS;
+ listener->factory.type_name = (char*)
+ pjsip_transport_get_type_name(listener->factory.type);
listener->factory.flag =
- pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
+ pjsip_transport_get_flag_from_type(listener->factory.type);
pj_ansi_strcpy(listener->factory.obj_name, "tlslis");
+ if (is_ipv6)
+ pj_ansi_strcat(listener->factory.obj_name, "6");
if (opt)
pjsip_tls_setting_copy(pool, &listener->tls_setting, opt);
else
pjsip_tls_setting_default(&listener->tls_setting);
- status = pj_lock_create_recursive_mutex(pool, "tlslis",
+ status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
&listener->factory.lock);
if (status != PJ_SUCCESS)
goto on_error;
@@ -291,6 +320,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* Build SSL socket param */
pj_ssl_sock_param_default(&ssock_param);
+ ssock_param.sock_af = af;
ssock_param.cb.on_accept_complete = &on_accept_complete;
ssock_param.cb.on_data_read = &on_data_read;
ssock_param.cb.on_data_sent = &on_data_sent;
@@ -337,12 +367,17 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
if (status != PJ_SUCCESS)
goto on_error;
- listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr;
+ /* Bind address may be different than factory.local_addr because
+ * factory.local_addr will be resolved below.
+ */
+ listener_addr = &listener->factory.local_addr;
if (local) {
pj_sockaddr_cp((pj_sockaddr_t*)listener_addr,
(const pj_sockaddr_t*)local);
+ pj_sockaddr_cp(&listener->bound_addr, local);
} else {
- pj_sockaddr_in_init(listener_addr, NULL, 0);
+ pj_sockaddr_init(af, listener_addr, NULL, 0);
+ pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
}
/* Check if certificate/CA list for SSL socket is set */
@@ -400,14 +435,14 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* 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) {
+ if (!pj_sockaddr_has_addr(listener_addr)) {
pj_sockaddr hostip;
- status = pj_gethostip(pj_AF_INET(), &hostip);
+ status = pj_gethostip(af, &hostip);
if (status != PJ_SUCCESS)
goto on_error;
- listener_addr->sin_addr.s_addr = hostip.ipv4.sin_addr.s_addr;
+ pj_sockaddr_copy_addr(listener_addr, &hostip);
}
/* Save the address name */
@@ -417,7 +452,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* 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);
+ listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
}
pj_ansi_snprintf(listener->factory.obj_name,
@@ -534,13 +569,14 @@ static pj_status_t tls_create( struct tls_listener *listener,
pj_pool_t *pool,
pj_ssl_sock_t *ssock,
pj_bool_t is_server,
- const pj_sockaddr_in *local,
- const pj_sockaddr_in *remote,
+ const pj_sockaddr *local,
+ const pj_sockaddr *remote,
const pj_str_t *remote_name,
struct tls_transport **p_tls)
{
struct tls_transport *tls;
const pj_str_t ka_pkt = PJSIP_TLS_KEEP_ALIVE_DATA;
+ char print_addr[PJ_INET6_ADDRSTRLEN+10];
pj_status_t status;
@@ -578,17 +614,21 @@ static pj_status_t tls_create( struct tls_listener *listener,
if (remote_name)
pj_strdup(pool, &tls->remote_name, remote_name);
- tls->base.key.type = PJSIP_TRANSPORT_TLS;
- pj_memcpy(&tls->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
- tls->base.type_name = "tls";
- tls->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
+ tls->base.key.type = listener->factory.type;
+ pj_sockaddr_cp(&tls->base.key.rem_addr, remote);
+ tls->base.type_name = (char*)pjsip_transport_get_type_name(
+ (pjsip_transport_type_e)tls->base.key.type);
+ tls->base.flag = pjsip_transport_get_flag_from_type(
+ (pjsip_transport_type_e)tls->base.key.type);
tls->base.info = (char*) pj_pool_alloc(pool, 64);
- pj_ansi_snprintf(tls->base.info, 64, "TLS to %s:%d",
- pj_inet_ntoa(remote->sin_addr),
- (int)pj_ntohs(remote->sin_port));
+ pj_ansi_snprintf(tls->base.info, 64, "%s to %s",
+ tls->base.type_name,
+ pj_sockaddr_print(remote, print_addr,
+ sizeof(print_addr), 3));
- tls->base.addr_len = sizeof(pj_sockaddr_in);
+
+ tls->base.addr_len = pj_sockaddr_get_len(remote);
tls->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
/* Set initial local address */
@@ -599,11 +639,10 @@ static pj_status_t tls_create( struct tls_listener *listener,
pj_sockaddr_cp(&tls->base.local_addr, local);
}
- sockaddr_to_host_port(pool, &tls->base.local_name,
- (pj_sockaddr_in*)&tls->base.local_addr);
+ sockaddr_to_host_port(pool, &tls->base.local_name, &tls->base.local_addr);
if (tls->remote_name.slen) {
tls->base.remote_name.host = tls->remote_name;
- tls->base.remote_name.port = pj_sockaddr_in_get_port(remote);
+ tls->base.remote_name.port = pj_sockaddr_get_port(remote);
} else {
sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
}
@@ -647,6 +686,9 @@ on_error:
/* Flush all delayed transmision once the socket is connected. */
static void tls_flush_pending_tx(struct tls_transport *tls)
{
+ pj_time_val now;
+
+ pj_gettickcount(&now);
pj_lock_acquire(tls->base.lock);
while (!pj_list_empty(&tls->delayed_list)) {
struct delayed_tdata *pending_tx;
@@ -661,13 +703,21 @@ static void tls_flush_pending_tx(struct tls_transport *tls)
tdata = pending_tx->tdata_op_key->tdata;
op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
+ if (pending_tx->timeout.sec > 0 &&
+ PJ_TIME_VAL_GT(now, pending_tx->timeout))
+ {
+ continue;
+ }
+
/* send! */
size = tdata->buf.cur - tdata->buf.start;
status = pj_ssl_sock_send(tls->ssock, op_key, tdata->buf.start,
&size, 0);
if (status != PJ_EPENDING) {
+ pj_lock_release(tls->base.lock);
on_data_sent(tls->ssock, op_key, size);
+ pj_lock_acquire(tls->base.lock);
}
}
pj_lock_release(tls->base.lock);
@@ -784,7 +834,7 @@ static pj_status_t tls_start_read(struct tls_transport *tls)
{
pj_pool_t *pool;
pj_ssize_t size;
- pj_sockaddr_in *rem_addr;
+ pj_sockaddr *rem_addr;
void *readbuf[1];
pj_status_t status;
@@ -807,11 +857,11 @@ static pj_status_t tls_start_read(struct tls_transport *tls)
sizeof(pj_ioqueue_op_key_t));
tls->rdata.pkt_info.src_addr = tls->base.key.rem_addr;
- tls->rdata.pkt_info.src_addr_len = sizeof(pj_sockaddr_in);
- rem_addr = (pj_sockaddr_in*) &tls->base.key.rem_addr;
- pj_ansi_strcpy(tls->rdata.pkt_info.src_name,
- pj_inet_ntoa(rem_addr->sin_addr));
- tls->rdata.pkt_info.src_port = pj_ntohs(rem_addr->sin_port);
+ tls->rdata.pkt_info.src_addr_len = sizeof(tls->rdata.pkt_info.src_addr);
+ rem_addr = &tls->base.key.rem_addr;
+ pj_sockaddr_print(rem_addr, tls->rdata.pkt_info.src_name,
+ sizeof(tls->rdata.pkt_info.src_name), 0);
+ tls->rdata.pkt_info.src_port = pj_sockaddr_get_port(rem_addr);
size = sizeof(tls->rdata.pkt_info.packet);
readbuf[0] = tls->rdata.pkt_info.packet;
@@ -844,7 +894,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
pj_pool_t *pool;
pj_ssl_sock_t *ssock;
pj_ssl_sock_param ssock_param;
- pj_sockaddr_in local_addr;
+ pj_sockaddr local_addr;
pj_str_t remote_name;
pj_status_t status;
@@ -852,9 +902,11 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
addr_len && p_transport, PJ_EINVAL);
- /* Check that address is a sockaddr_in */
- PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() &&
- addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL);
+ /* Check that address is a sockaddr_in or sockaddr_in6*/
+ PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
+ addr_len == sizeof(pj_sockaddr_in)) ||
+ (rem_addr->addr.sa_family == pj_AF_INET6() &&
+ addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);
listener = (struct tls_listener*)factory;
@@ -871,6 +923,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Build SSL socket param */
pj_ssl_sock_param_default(&ssock_param);
+ ssock_param.sock_af = (factory->type & PJSIP_TRANSPORT_IPV6) ?
+ pj_AF_INET6() : pj_AF_INET();
ssock_param.cb.on_connect_complete = &on_connect_complete;
ssock_param.cb.on_data_read = &on_data_read;
ssock_param.cb.on_data_sent = &on_data_sent;
@@ -921,12 +975,14 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
return status;
}
- /* Initially set bind address to PJ_INADDR_ANY port 0 */
- pj_sockaddr_in_init(&local_addr, NULL, 0);
+ /* Initially set bind address to listener's bind address */
+ pj_sockaddr_init(listener->bound_addr.addr.sa_family,
+ &local_addr, NULL, 0);
+ pj_sockaddr_copy_addr(&local_addr, &listener->bound_addr);
/* Create the transport descriptor */
status = tls_create(listener, pool, ssock, PJ_FALSE, &local_addr,
- (pj_sockaddr_in*)rem_addr, &remote_name, &tls);
+ rem_addr, &remote_name, &tls);
if (status != PJ_SUCCESS)
return status;
@@ -973,7 +1029,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
}
sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
- (pj_sockaddr_in*)&tls->base.local_addr);
+ &tls->base.local_addr);
}
PJ_LOG(4,(tls->base.obj_name,
@@ -1007,6 +1063,7 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
pj_ssl_sock_info ssl_info;
char addr[PJ_INET6_ADDRSTRLEN+10];
pjsip_tp_state_callback state_cb;
+ pj_sockaddr tmp_src_addr;
pj_bool_t is_shutdown;
pj_status_t status;
@@ -1034,13 +1091,17 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
return PJ_TRUE;
}
+ /* Copy to larger buffer, just in case */
+ pj_bzero(&tmp_src_addr, sizeof(tmp_src_addr));
+ pj_sockaddr_cp(&tmp_src_addr, src_addr);
+
/*
* Incoming connection!
* Create TLS transport for the new socket.
*/
status = tls_create( listener, NULL, new_ssock, PJ_TRUE,
- (const pj_sockaddr_in*)&listener->factory.local_addr,
- (const pj_sockaddr_in*)src_addr, NULL, &tls);
+ &listener->factory.local_addr,
+ &tmp_src_addr, NULL, &tls);
if (status != PJ_SUCCESS)
return PJ_TRUE;
@@ -1190,9 +1251,9 @@ static pj_status_t tls_send_msg(pjsip_transport *transport,
PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
/* Check the address is supported */
- PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
-
-
+ PJ_ASSERT_RETURN(rem_addr && (addr_len==sizeof(pj_sockaddr_in) ||
+ addr_len==sizeof(pj_sockaddr_in6)),
+ PJ_EINVAL);
/* Init op key. */
tdata->op_key.tdata = tdata;
@@ -1217,10 +1278,19 @@ static pj_status_t tls_send_msg(pjsip_transport *transport,
/*
* connect() is still in progress. Put the transmit data to
* the delayed list.
+ * Starting from #1583 (https://trac.pjsip.org/repos/ticket/1583),
+ * we also add timeout value for the transmit data. When the
+ * connect() is completed, the timeout value will be checked to
+ * determine whether the transmit data needs to be sent.
*/
- delayed_tdata = PJ_POOL_ALLOC_T(tdata->pool,
- struct delayed_tdata);
+ delayed_tdata = PJ_POOL_ZALLOC_T(tdata->pool,
+ struct delayed_tdata);
delayed_tdata->tdata_op_key = &tdata->op_key;
+ if (tdata->msg && tdata->msg->type == PJSIP_REQUEST_MSG) {
+ pj_gettickcount(&delayed_tdata->timeout);
+ delayed_tdata->timeout.msec += pjsip_cfg()->tsx.td;
+ pj_time_val_normalize(&delayed_tdata->timeout);
+ }
pj_list_push_back(&tls->delayed_list, delayed_tdata);
status = PJ_EPENDING;
@@ -1365,7 +1435,7 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
{
struct tls_transport *tls;
pj_ssl_sock_info ssl_info;
- pj_sockaddr_in addr, *tp_addr;
+ pj_sockaddr addr, *tp_addr;
pjsip_tp_state_callback state_cb;
pj_bool_t is_shutdown;
@@ -1403,12 +1473,11 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
* set is different now that the socket is connected (could happen
* on some systems, like old Win32 probably?).
*/
- tp_addr = (pj_sockaddr_in*)&tls->base.local_addr;
+ tp_addr = &tls->base.local_addr;
pj_sockaddr_cp((pj_sockaddr_t*)&addr,
(pj_sockaddr_t*)&ssl_info.local_addr);
- if (tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr) {
- tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
- tp_addr->sin_port = addr.sin_port;
+ if (pj_sockaddr_cmp(tp_addr, &addr) != 0) {
+ pj_sockaddr_cp(tp_addr, &addr);
sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
tp_addr);
}
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
index 7128891..723c061 100644
--- a/pjsip/src/pjsip/sip_ua_layer.c
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -1,4 +1,4 @@
-/* $Id: sip_ua_layer.c 3664 2011-07-19 03:42:28Z nanang $ */
+/* $Id: sip_ua_layer.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -302,9 +302,10 @@ PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
struct dlg_set *dlg_set;
dlg_set = (struct dlg_set*)
- pj_hash_get( mod_ua.dlg_table, dlg->local.info->tag.ptr,
- dlg->local.info->tag.slen,
- &dlg->local.tag_hval);
+ pj_hash_get_lower( mod_ua.dlg_table,
+ dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen,
+ &dlg->local.tag_hval);
if (dlg_set) {
/* This is NOT the first dialog in the dialog set.
@@ -326,9 +327,11 @@ PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
dlg->dlg_set = dlg_set;
/* Register the dialog set in the hash table. */
- pj_hash_set_np(mod_ua.dlg_table,
- dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
- dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+ pj_hash_set_np_lower(mod_ua.dlg_table,
+ dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen,
+ dlg->local.tag_hval, dlg_set->ht_entry,
+ dlg_set);
}
} else {
@@ -341,9 +344,10 @@ PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
dlg->dlg_set = dlg_set;
- pj_hash_set_np(mod_ua.dlg_table,
- dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
- dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+ pj_hash_set_np_lower(mod_ua.dlg_table,
+ dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen,
+ dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
}
/* Unlock user agent. */
@@ -387,8 +391,9 @@ PJ_DEF(pj_status_t) pjsip_ua_unregister_dlg( pjsip_user_agent *ua,
/* If dialog list is empty, remove the dialog set from the hash table. */
if (pj_list_empty(&dlg_set->dlg_list)) {
- pj_hash_set(NULL, mod_ua.dlg_table, dlg->local.info->tag.ptr,
- dlg->local.info->tag.slen, dlg->local.tag_hval, NULL);
+ pj_hash_set_lower(NULL, mod_ua.dlg_table, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen, dlg->local.tag_hval,
+ NULL);
/* Return dlg_set to free nodes. */
pj_list_push_back(&mod_ua.free_dlgset_nodes, dlg_set);
@@ -449,8 +454,8 @@ PJ_DEF(pjsip_dialog*) pjsip_ua_find_dialog(const pj_str_t *call_id,
/* Lookup the dialog set. */
dlg_set = (struct dlg_set*)
- pj_hash_get(mod_ua.dlg_table, local_tag->ptr, local_tag->slen,
- NULL);
+ pj_hash_get_lower(mod_ua.dlg_table, local_tag->ptr,
+ local_tag->slen, NULL);
if (dlg_set == NULL) {
/* Not found */
pj_mutex_unlock(mod_ua.mutex);
@@ -462,7 +467,7 @@ PJ_DEF(pjsip_dialog*) pjsip_ua_find_dialog(const pj_str_t *call_id,
*/
dlg = dlg_set->dlg_list.next;
while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
- if (pj_strcmp(&dlg->remote.info->tag, remote_tag) == 0)
+ if (pj_stricmp(&dlg->remote.info->tag, remote_tag) == 0)
break;
dlg = dlg->next;
}
@@ -563,7 +568,8 @@ static struct dlg_set *find_dlg_set_for_msg( pjsip_rx_data *rdata )
/* Lookup the dialog set. */
dlg_set = (struct dlg_set*)
- pj_hash_get(mod_ua.dlg_table, tag->ptr, tag->slen, NULL);
+ pj_hash_get_lower(mod_ua.dlg_table, tag->ptr, tag->slen,
+ NULL);
return dlg_set;
}
}
@@ -624,7 +630,7 @@ retry_on_deadlock:
dlg = dlg_set->dlg_list.next;
while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
- if (pj_strcmp(&dlg->remote.info->tag, from_tag) == 0)
+ if (pj_stricmp(&dlg->remote.info->tag, from_tag) == 0)
break;
dlg = dlg->next;
@@ -761,10 +767,10 @@ retry_on_deadlock:
/* Get the dialog set. */
dlg_set = (struct dlg_set*)
- pj_hash_get(mod_ua.dlg_table,
- rdata->msg_info.from->tag.ptr,
- rdata->msg_info.from->tag.slen,
- NULL);
+ pj_hash_get_lower(mod_ua.dlg_table,
+ rdata->msg_info.from->tag.ptr,
+ rdata->msg_info.from->tag.slen,
+ NULL);
if (!dlg_set) {
/* Unlock dialog hash table. */
@@ -812,7 +818,7 @@ retry_on_deadlock:
break;
/* Otherwise find the one with matching To tag. */
- if (pj_strcmp(to_tag, &dlg->remote.info->tag) == 0)
+ if (pj_stricmp(to_tag, &dlg->remote.info->tag) == 0)
break;
dlg = dlg->next;
diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c
index fba163c..4d54e2e 100644
--- a/pjsip/src/pjsip/sip_uri.c
+++ b/pjsip/src/pjsip/sip_uri.c
@@ -1,4 +1,4 @@
-/* $Id: sip_uri.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_uri.c 4228 2012-08-13 07:26:03Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -269,7 +269,10 @@ static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
/* Print "user:password@", if any. */
if (url->user.slen) {
- copy_advance_escape(buf, url->user, pc->pjsip_USER_SPEC);
+ const pj_cis_t *spec = pjsip_cfg()->endpt.allow_tx_hash_in_uri ?
+ &pc->pjsip_USER_SPEC_LENIENT :
+ &pc->pjsip_USER_SPEC;
+ copy_advance_escape(buf, url->user, *spec);
if (url->passwd.slen) {
*buf++ = ':';
copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC);
diff --git a/pjsip/src/pjsip/sip_util_proxy.c b/pjsip/src/pjsip/sip_util_proxy.c
index 7a34534..02069b9 100644
--- a/pjsip/src/pjsip/sip_util_proxy.c
+++ b/pjsip/src/pjsip/sip_util_proxy.c
@@ -1,4 +1,4 @@
-/* $Id: sip_util_proxy.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_util_proxy.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -345,7 +345,7 @@ PJ_DEF(pj_str_t) pjsip_calculate_branch_id( pjsip_rx_data *rdata )
/* If incoming request does not have RFC 3261 branch value, create
* a branch value from GUID .
*/
- if (pj_strncmp(&rdata->msg_info.via->branch_param,
+ if (pj_strnicmp(&rdata->msg_info.via->branch_param,
&rfc3261_branch, PJSIP_RFC3261_BRANCH_LEN) != 0 )
{
pj_str_t tmp;
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index c5278c4..5d7695d 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_acc.c 4185 2012-06-28 14:16:05Z ming $ */
+/* $Id: pjsua_acc.c 4318 2013-01-16 09:51:45Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -133,6 +133,9 @@ PJ_DEF(void) pjsua_acc_config_dup( pj_pool_t *pool,
pjsua_transport_config_dup(pool, &dst->rtp_cfg, &src->rtp_cfg);
+ pjsua_ice_config_dup(pool, &dst->ice_cfg, &src->ice_cfg);
+ pjsua_turn_config_dup(pool, &dst->turn_cfg, &src->turn_cfg);
+
pj_strdup(pool, &dst->ka_data, &src->ka_data);
}
@@ -283,7 +286,7 @@ static pj_status_t initialize_acc(unsigned acc_id)
* contact params.
*/
#if PJSUA_ADD_ICE_TAGS
- if (pjsua_var.media_cfg.enable_ice) {
+ if (acc_cfg->ice_cfg.enable_ice) {
unsigned new_len;
pj_str_t new_prm;
@@ -348,6 +351,18 @@ static pj_status_t initialize_acc(unsigned acc_id)
}
}
+ /* If account's ICE and TURN customization is not set, then
+ * initialize it with the settings from the global media config.
+ */
+ if (acc->cfg.ice_cfg_use == PJSUA_ICE_CONFIG_USE_DEFAULT) {
+ pjsua_ice_config_from_media_config(NULL, &acc->cfg.ice_cfg,
+ &pjsua_var.media_cfg);
+ }
+ if (acc->cfg.turn_cfg_use == PJSUA_TURN_CONFIG_USE_DEFAULT) {
+ pjsua_turn_config_from_media_config(NULL, &acc->cfg.turn_cfg,
+ &pjsua_var.media_cfg);
+ }
+
/* Mark account as valid */
pjsua_var.acc[acc_id].valid = PJ_TRUE;
@@ -470,6 +485,10 @@ PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg,
/* Otherwise subscribe to MWI, if it's enabled */
if (pjsua_var.acc[id].cfg.mwi_enabled)
pjsua_start_mwi(id, PJ_TRUE);
+
+ /* Start publish too */
+ if (acc->cfg.publish_enabled)
+ pjsua_pres_init_publish_acc(id);
}
pj_log_pop_indent();
@@ -1152,6 +1171,70 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
update_reg = PJ_TRUE;
}
+ /* Video settings */
+ acc->cfg.vid_in_auto_show = cfg->vid_in_auto_show;
+ acc->cfg.vid_out_auto_transmit = cfg->vid_out_auto_transmit;
+ acc->cfg.vid_wnd_flags = cfg->vid_wnd_flags;
+ acc->cfg.vid_cap_dev = cfg->vid_cap_dev;
+ acc->cfg.vid_rend_dev = cfg->vid_rend_dev;
+ acc->cfg.vid_stream_rc_cfg = cfg->vid_stream_rc_cfg;
+
+ /* Media settings */
+ if (pj_stricmp(&acc->cfg.rtp_cfg.public_addr, &cfg->rtp_cfg.public_addr) ||
+ pj_stricmp(&acc->cfg.rtp_cfg.bound_addr, &cfg->rtp_cfg.bound_addr))
+ {
+ pjsua_transport_config_dup(acc->pool, &acc->cfg.rtp_cfg,
+ &cfg->rtp_cfg);
+ } else {
+ /* ..to save memory by not using the pool */
+ acc->cfg.rtp_cfg = cfg->rtp_cfg;
+ }
+
+ acc->cfg.ipv6_media_use = cfg->ipv6_media_use;
+
+ /* STUN and Media customization */
+ if (acc->cfg.sip_stun_use != cfg->sip_stun_use) {
+ acc->cfg.sip_stun_use = cfg->sip_stun_use;
+ update_reg = PJ_TRUE;
+ }
+ acc->cfg.media_stun_use = cfg->media_stun_use;
+
+ /* ICE settings */
+ acc->cfg.ice_cfg_use = cfg->ice_cfg_use;
+ switch (acc->cfg.ice_cfg_use) {
+ case PJSUA_ICE_CONFIG_USE_DEFAULT:
+ /* Copy ICE settings from media settings so that we don't need to
+ * check the media config if we look for ICE config.
+ */
+ pjsua_ice_config_from_media_config(NULL, &acc->cfg.ice_cfg,
+ &pjsua_var.media_cfg);
+ break;
+ case PJSUA_ICE_CONFIG_USE_CUSTOM:
+ pjsua_ice_config_dup(acc->pool, &acc->cfg.ice_cfg, &cfg->ice_cfg);
+ break;
+ }
+
+ /* TURN settings */
+ acc->cfg.turn_cfg_use = cfg->turn_cfg_use;
+ switch (acc->cfg.turn_cfg_use) {
+ case PJSUA_TURN_CONFIG_USE_DEFAULT:
+ /* Copy TURN settings from media settings so that we don't need to
+ * check the media config if we look for TURN config.
+ */
+ pjsua_turn_config_from_media_config(NULL, &acc->cfg.turn_cfg,
+ &pjsua_var.media_cfg);
+ break;
+ case PJSUA_TURN_CONFIG_USE_CUSTOM:
+ pjsua_turn_config_dup(acc->pool, &acc->cfg.turn_cfg,
+ &cfg->turn_cfg);
+ break;
+ }
+
+ acc->cfg.use_srtp = cfg->use_srtp;
+
+ /* Call hold type */
+ acc->cfg.call_hold_type = cfg->call_hold_type;
+
/* Unregister first */
if (unreg_first) {
pjsua_acc_set_registration(acc->index, PJ_FALSE);
@@ -1174,16 +1257,6 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
pjsua_start_mwi(acc_id, PJ_TRUE);
}
- /* Video settings */
- acc->cfg.vid_in_auto_show = cfg->vid_in_auto_show;
- acc->cfg.vid_out_auto_transmit = cfg->vid_out_auto_transmit;
- acc->cfg.vid_wnd_flags = cfg->vid_wnd_flags;
- acc->cfg.vid_cap_dev = cfg->vid_cap_dev;
- acc->cfg.vid_rend_dev = cfg->vid_rend_dev;
-
- /* Call hold type */
- acc->cfg.call_hold_type = cfg->call_hold_type;
-
on_return:
PJSUA_UNLOCK();
pj_log_pop_indent();
@@ -1515,6 +1588,7 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
const char *ob = ";ob";
char *tmp;
const char *beginquote, *endquote;
+ char transport_param[32];
int len;
/* Enclose IPv6 address in square brackets */
@@ -1525,9 +1599,21 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
beginquote = endquote = "";
}
+ /* Don't add transport parameter if it's UDP */
+ if (tp->key.type != PJSIP_TRANSPORT_UDP &&
+ tp->key.type != PJSIP_TRANSPORT_UDP6)
+ {
+ pj_ansi_snprintf(transport_param, sizeof(transport_param),
+ ";transport=%s",
+ pjsip_transport_get_type_name(
+ (pjsip_transport_type_e)tp->key.type));
+ } else {
+ transport_param[0] = '\0';
+ }
+
tmp = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
len = pj_ansi_snprintf(tmp, PJSIP_MAX_URL_SIZE,
- "<sip:%.*s%s%s%.*s%s:%d;transport=%s%.*s%s>%.*s",
+ "<sip:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
(int)acc->user_part.slen,
acc->user_part.ptr,
(acc->user_part.slen? "@" : ""),
@@ -1536,7 +1622,7 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
via_addr->ptr,
endquote,
rport,
- tp->type_name,
+ transport_param,
(int)acc->cfg.contact_uri_params.slen,
acc->cfg.contact_uri_params.ptr,
(acc->cfg.use_rfc5626? ob: ""),
@@ -1776,9 +1862,26 @@ static void update_keep_alive(pjsua_acc *acc, pj_bool_t start,
/* Save transport and destination address. */
acc->ka_transport = param->rdata->tp_info.transport;
pjsip_transport_add_ref(acc->ka_transport);
- pj_memcpy(&acc->ka_target, &param->rdata->pkt_info.src_addr,
- param->rdata->pkt_info.src_addr_len);
- acc->ka_target_len = param->rdata->pkt_info.src_addr_len;
+
+ /* https://trac.pjsip.org/repos/ticket/1607:
+ * Calculate the destination address from the original request. Some
+ * (broken) servers send the response using different source address
+ * than the one that receives the request, which is forbidden by RFC
+ * 3581.
+ */
+ {
+ pjsip_transaction *tsx;
+ pjsip_tx_data *req;
+
+ tsx = pjsip_rdata_get_tsx(param->rdata);
+ PJ_ASSERT_ON_FAIL(tsx, return);
+
+ req = tsx->last_tx;
+
+ pj_memcpy(&acc->ka_target, &req->tp_info.dst_addr,
+ req->tp_info.dst_addr_len);
+ acc->ka_target_len = req->tp_info.dst_addr_len;
+ }
/* Setup and start the timer */
acc->ka_timer.cb = &keep_alive_timer_cb;
@@ -2146,6 +2249,13 @@ static pj_status_t pjsua_regc_init(int acc_id)
return PJ_SUCCESS;
}
+pj_bool_t pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id)
+{
+ pjsua_acc *acc = &pjsua_var.acc[acc_id];
+
+ return acc->cfg.sip_stun_use != PJSUA_STUN_USE_DISABLED &&
+ pjsua_var.ua_cfg.stun_srv_cnt != 0;
+}
/*
* Update registration or perform unregistration.
@@ -2153,6 +2263,7 @@ static pj_status_t pjsua_regc_init(int acc_id)
PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
pj_bool_t renew)
{
+ pjsua_acc *acc;
pj_status_t status = 0;
pjsip_tx_data *tdata = 0;
@@ -2166,6 +2277,8 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
PJSUA_LOCK();
+ acc = &pjsua_var.acc[acc_id];
+
/* Cancel any re-registration timer */
if (pjsua_var.acc[acc_id].auto_rereg.timer.id) {
pjsua_var.acc[acc_id].auto_rereg.timer.id = PJ_FALSE;
@@ -2232,6 +2345,15 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
pjsip_regc_set_via_sent_by(pjsua_var.acc[acc_id].regc,
&pjsua_var.acc[acc_id].via_addr,
pjsua_var.acc[acc_id].via_tp);
+ } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
+ /* Choose local interface to use in Via if acc is not using
+ * STUN
+ */
+ pjsua_acc_get_uac_addr(acc_id, tdata->pool,
+ &acc->cfg.reg_uri,
+ &tdata->via_addr,
+ NULL, NULL,
+ &tdata->via_tp);
}
//pjsua_process_msg_data(tdata, NULL);
@@ -2605,6 +2727,15 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id,
{
tdata->via_addr = pjsua_var.acc[acc_id].via_addr;
tdata->via_tp = pjsua_var.acc[acc_id].via_tp;
+ } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
+ /* Choose local interface to use in Via if acc is not using
+ * STUN
+ */
+ pjsua_acc_get_uac_addr(acc_id, tdata->pool,
+ target,
+ &tdata->via_addr,
+ NULL, NULL,
+ &tdata->via_tp);
}
/* Done */
@@ -2612,46 +2743,40 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id,
return PJ_SUCCESS;
}
-
-PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
- pj_str_t *contact,
- pjsua_acc_id acc_id,
- const pj_str_t *suri)
+/* Get local transport address suitable to be used for Via or Contact address
+ * to send request to the specified destination URI.
+ */
+pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
+ pj_pool_t *pool,
+ const pj_str_t *dst_uri,
+ pjsip_host_port *addr,
+ pjsip_transport_type_e *p_tp_type,
+ int *secure,
+ const void **p_tp)
{
pjsua_acc *acc;
pjsip_sip_uri *sip_uri;
pj_status_t status;
pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
- pj_str_t local_addr;
- pjsip_tpselector tp_sel;
unsigned flag;
- int secure;
- int local_port;
- const char *beginquote, *endquote;
- char transport_param[32];
- const char *ob = ";ob";
+ pjsip_tpselector tp_sel;
+ pjsip_tpmgr *tpmgr;
+ pjsip_tpmgr_fla2_param tfla2_prm;
-
PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
acc = &pjsua_var.acc[acc_id];
- /* If force_contact is configured, then use use it */
- if (acc->cfg.force_contact.slen) {
- *contact = acc->cfg.force_contact;
- return PJ_SUCCESS;
- }
-
- /* If route-set is configured for the account, then URI is the
+ /* If route-set is configured for the account, then URI is the
* first entry of the route-set.
*/
if (!pj_list_empty(&acc->route_set)) {
- sip_uri = (pjsip_sip_uri*)
+ sip_uri = (pjsip_sip_uri*)
pjsip_uri_get_uri(acc->route_set.next->name_addr.uri);
} else {
pj_str_t tmp;
pjsip_uri *uri;
- pj_strdup_with_null(pool, &tmp, suri);
+ pj_strdup_with_null(pool, &tmp, dst_uri);
uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
if (uri == NULL)
@@ -2671,7 +2796,7 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
tp_type = PJSIP_TRANSPORT_UDP;
} else
tp_type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
-
+
if (tp_type == PJSIP_TRANSPORT_UNSPECIFIED)
return PJSIP_EUNSUPTRANSPORT;
@@ -2682,15 +2807,66 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
tp_type = (pjsip_transport_type_e)(((int)tp_type) + PJSIP_TRANSPORT_IPV6);
flag = pjsip_transport_get_flag_from_type(tp_type);
- secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
/* Init transport selector. */
- pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+ pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
/* Get local address suitable to send request from */
- status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
- pool, tp_type, &tp_sel,
- &local_addr, &local_port);
+ pjsip_tpmgr_fla2_param_default(&tfla2_prm);
+ tfla2_prm.tp_type = tp_type;
+ tfla2_prm.tp_sel = &tp_sel;
+ tfla2_prm.dst_host = sip_uri->host;
+ tfla2_prm.local_if = (!pjsua_sip_acc_is_using_stun(acc_id) ||
+ (flag & PJSIP_TRANSPORT_RELIABLE));
+
+ tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
+ status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ addr->host = tfla2_prm.ret_addr;
+ addr->port = tfla2_prm.ret_port;
+
+ if (p_tp_type)
+ *p_tp_type = tp_type;
+
+ if (secure) {
+ *secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
+ }
+
+ if (p_tp)
+ *p_tp = tfla2_prm.ret_tp;
+
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
+ pj_str_t *contact,
+ pjsua_acc_id acc_id,
+ const pj_str_t *suri)
+{
+ pjsua_acc *acc;
+ pj_status_t status;
+ pjsip_transport_type_e tp_type;
+ pjsip_host_port addr;
+ int secure;
+ const char *beginquote, *endquote;
+ char transport_param[32];
+ const char *ob = ";ob";
+
+
+ PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
+ acc = &pjsua_var.acc[acc_id];
+
+ /* If force_contact is configured, then use use it */
+ if (acc->cfg.force_contact.slen) {
+ *contact = acc->cfg.force_contact;
+ return PJ_SUCCESS;
+ }
+
+ status = pjsua_acc_get_uac_addr(acc_id, pool, suri, &addr,
+ &tp_type, &secure, NULL);
if (status != PJ_SUCCESS)
return status;
@@ -2725,10 +2901,10 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
acc->user_part.ptr,
(acc->user_part.slen?"@":""),
beginquote,
- (int)local_addr.slen,
- local_addr.ptr,
+ (int)addr.host.slen,
+ addr.host.ptr,
endquote,
- local_port,
+ addr.port,
transport_param,
(int)acc->cfg.contact_uri_params.slen,
acc->cfg.contact_uri_params.ptr,
@@ -2760,6 +2936,8 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool,
pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
pj_str_t local_addr;
pjsip_tpselector tp_sel;
+ pjsip_tpmgr *tpmgr;
+ pjsip_tpmgr_fla2_param tfla2_prm;
unsigned flag;
int secure;
int local_port;
@@ -2847,12 +3025,22 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool,
pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
/* Get local address suitable to send request from */
- status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
- pool, tp_type, &tp_sel,
- &local_addr, &local_port);
+ pjsip_tpmgr_fla2_param_default(&tfla2_prm);
+ tfla2_prm.tp_type = tp_type;
+ tfla2_prm.tp_sel = &tp_sel;
+ tfla2_prm.dst_host = sip_uri->host;
+ tfla2_prm.local_if = (!pjsua_sip_acc_is_using_stun(acc_id) ||
+ (flag & PJSIP_TRANSPORT_RELIABLE));
+
+ tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
+ status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm);
if (status != PJ_SUCCESS)
return status;
+ local_addr = tfla2_prm.ret_addr;
+ local_port = tfla2_prm.ret_port;
+
+
/* Enclose IPv6 address in square brackets */
if (tp_type & PJSIP_TRANSPORT_IPV6) {
beginquote = "[";
diff --git a/pjsip/src/pjsua-lib/pjsua_aud.c b/pjsip/src/pjsua-lib/pjsua_aud.c
index 557a147..1163e08 100644
--- a/pjsip/src/pjsua-lib/pjsua_aud.c
+++ b/pjsip/src/pjsua-lib/pjsua_aud.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_aud.c 4145 2012-05-22 23:13:22Z bennylp $ */
+/* $Id: pjsua_aud.c 4336 2013-01-29 08:15:02Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -291,7 +291,8 @@ pj_status_t pjsua_aud_subsys_init()
/* Init the passthrough codec with supported formats only */
codec_cfg.passthrough.setting.fmt_cnt = ext_fmt_cnt;
codec_cfg.passthrough.setting.fmts = ext_fmts;
- codec_cfg.passthrough.setting.ilbc_mode = cfg->ilbc_mode;
+ codec_cfg.passthrough.setting.ilbc_mode =
+ pjsua_var.media_cfg.ilbc_mode;
}
#endif /* PJMEDIA_HAS_PASSTHROUGH_CODECS */
@@ -559,7 +560,12 @@ static void dtmf_callback(pjmedia_stream *strm, void *user_data,
pj_log_pop_indent();
}
-
+/* Internal function: update audio channel after SDP negotiation.
+ * Warning: do not use temporary/flip-flop pool, e.g: inv->pool_prov,
+ * for creating stream, etc, as after SDP negotiation and when
+ * the SDP media is not changed, the stream should remain running
+ * while the temporary/flip-flop pool may be released.
+ */
pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
pj_pool_t *tmp_pool,
pjmedia_stream_info *si,
@@ -583,20 +589,6 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
/* Check if no media is active */
if (si->dir != PJMEDIA_DIR_NONE) {
- /* Override ptime, if this option is specified. */
- if (pjsua_var.media_cfg.ptime != 0) {
- si->param->setting.frm_per_pkt = (pj_uint8_t)
- (pjsua_var.media_cfg.ptime / si->param->info.frm_ptime);
- if (si->param->setting.frm_per_pkt == 0)
- si->param->setting.frm_per_pkt = 1;
- }
-
- /* Disable VAD, if this option is specified. */
- if (pjsua_var.media_cfg.no_vad) {
- si->param->setting.vad = 0;
- }
-
-
/* Optionally, application may modify other stream settings here
* (such as jitter buffer parameters, codec ptime, etc.)
*/
@@ -678,7 +670,7 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
port_name = pj_str("call");
}
status = pjmedia_conf_add_port( pjsua_var.mconf,
- call->inv->pool_prov,
+ call->inv->pool,
media_port,
&port_name,
(unsigned*)
@@ -1571,6 +1563,14 @@ static pj_status_t create_aud_param(pjmedia_aud_param *param,
param->flags &= ~(PJMEDIA_AUD_DEV_CAP_EC|PJMEDIA_AUD_DEV_CAP_EC_TAIL);
}
+ /* VAD settings */
+ if (pjsua_var.media_cfg.no_vad) {
+ param->flags &= ~PJMEDIA_AUD_DEV_CAP_VAD;
+ } else {
+ param->flags |= PJMEDIA_AUD_DEV_CAP_VAD;
+ param->vad_enabled = PJ_TRUE;
+ }
+
return PJ_SUCCESS;
}
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 6f14709..7329333 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_call.c 4176 2012-06-23 03:06:52Z nanang $ */
+/* $Id: pjsua_call.c 4411 2013-03-04 04:34:38Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -106,6 +106,12 @@ static pj_status_t create_sdp_of_call_hold(pjsua_call *call,
static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
+/* Timer callback to send re-INVITE/UPDATE to lock codec or ICE update */
+static void reinv_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry);
+
+/* Check and send reinvite for lock codec and ICE update */
+static pj_status_t process_pending_reinvite(pjsua_call *call);
+
/*
* Reset call descriptor.
*/
@@ -128,6 +134,8 @@ static void reset_call(pjsua_call_id id)
call_med->tp_auto_del = PJ_TRUE;
}
pjsua_call_setting_default(&call->opt);
+ pj_timer_entry_init(&call->reinv_timer, PJ_FALSE,
+ (void*)(pj_size_t)id, &reinv_timer_cb);
}
@@ -179,6 +187,10 @@ pj_status_t pjsua_call_subsys_init(const pjsua_config *cfg)
pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_SUPPORTED,
NULL, 1, &str_norefersub);
+ /* Add "INFO" in Allow header, for DTMF and video key frame request. */
+ pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_ALLOW,
+ NULL, 1, &pjsip_info_method.name);
+
return status;
}
@@ -359,6 +371,7 @@ on_make_call_med_tp_complete(pjsua_call_id call_id,
pjsip_dialog *dlg = call->async_call.dlg;
unsigned options = 0;
pjsip_tx_data *tdata;
+ pj_bool_t cb_called = PJ_FALSE;
pj_status_t status = (info? info->status: PJ_SUCCESS);
PJSUA_LOCK();
@@ -387,9 +400,16 @@ on_make_call_med_tp_complete(pjsua_call_id call_id,
goto on_error;
}
- /* pjsua_media_channel_deinit() has been called. */
- if (call->async_call.med_ch_deinit)
+ /* pjsua_media_channel_deinit() has been called or
+ * call has been hung up.
+ */
+ if (call->async_call.med_ch_deinit ||
+ call->async_call.call_var.out_call.hangup)
+ {
+ PJ_LOG(4,(THIS_FILE, "Call has been hung up or media channel has "
+ "been deinitialized"));
goto on_error;
+ }
/* Create offer */
status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL,
@@ -476,8 +496,7 @@ on_make_call_med_tp_complete(pjsua_call_id call_id,
status = pjsip_inv_send_msg(inv, tdata);
if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to send initial INVITE request",
- status);
+ cb_called = PJ_TRUE;
/* Upon failure to send first request, the invite
* session would have been cleared.
@@ -487,6 +506,7 @@ on_make_call_med_tp_complete(pjsua_call_id call_id,
}
/* Done. */
+ call->med_ch_cb = NULL;
pjsip_dlg_dec_lock(dlg);
PJSUA_UNLOCK();
@@ -494,8 +514,11 @@ on_make_call_med_tp_complete(pjsua_call_id call_id,
return PJ_SUCCESS;
on_error:
- if (inv == NULL && call_id != -1 && pjsua_var.ua_cfg.cb.on_call_state)
+ if (inv == NULL && call_id != -1 && !cb_called &&
+ pjsua_var.ua_cfg.cb.on_call_state)
+ {
(*pjsua_var.ua_cfg.cb.on_call_state)(call_id, NULL);
+ }
if (dlg) {
/* This may destroy the dialog */
@@ -511,6 +534,10 @@ on_error:
pjsua_media_channel_deinit(call_id);
}
+ call->med_ch_cb = NULL;
+
+ pjsua_check_snd_dev_idle();
+
PJSUA_UNLOCK();
return status;
}
@@ -547,35 +574,23 @@ static pj_status_t apply_call_setting(pjsua_call *call,
pj_assert(opt->vid_cnt == 0);
#endif
+ call->opt = *opt;
+
/* If call is established, reinit media channel */
if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
- pjsua_call_setting old_opt;
+ pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC;
pj_status_t status;
- old_opt = call->opt;
- call->opt = *opt;
-
- /* Reinit media channel when media count is changed or we are the
- * answerer (as remote offer may 'extremely' modify the existing
- * media session, e.g: media type order).
- */
- if (rem_sdp ||
- opt->aud_cnt!=old_opt.aud_cnt || opt->vid_cnt!=old_opt.vid_cnt)
- {
- pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC;
- status = pjsua_media_channel_init(call->index, role,
- call->secure_level,
- call->inv->pool_prov,
- rem_sdp, NULL,
- PJ_FALSE, NULL);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error re-initializing media channel",
- status);
- return status;
- }
+ status = pjsua_media_channel_init(call->index, role,
+ call->secure_level,
+ call->inv->pool_prov,
+ rem_sdp, NULL,
+ PJ_FALSE, NULL);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error re-initializing media channel",
+ status);
+ return status;
}
- } else {
- call->opt = *opt;
}
return PJ_SUCCESS;
@@ -811,8 +826,8 @@ static pj_status_t process_incoming_call_replace(pjsua_call *call,
{
pjsip_inv_session *replaced_inv;
struct pjsua_call *replaced_call;
- pjsip_tx_data *tdata;
- pj_status_t status;
+ pjsip_tx_data *tdata = NULL;
+ pj_status_t status = PJ_SUCCESS;
/* Get the invite session in the dialog */
replaced_inv = pjsip_dlg_get_inv_session(replaced_dlg);
@@ -825,12 +840,29 @@ static pj_status_t process_incoming_call_replace(pjsua_call *call,
pjsua_var.ua_cfg.cb.on_call_replaced(replaced_call->index,
call->index);
- PJ_LOG(4,(THIS_FILE, "Answering replacement call %d with 200/OK",
- call->index));
+ if (replaced_call->inv->state <= PJSIP_INV_STATE_EARLY &&
+ replaced_call->inv->role != PJSIP_ROLE_UAC)
+ {
+ if (replaced_call->last_code > 100 && replaced_call->last_code < 200)
+ {
+ pjsip_status_code code = replaced_call->last_code;
+ pj_str_t *text = &replaced_call->last_text;
+
+ PJ_LOG(4,(THIS_FILE, "Answering replacement call %d with %d/%.*s",
+ call->index, code, text->slen, text->ptr));
+
+ /* Answer the new call with last response in the replaced call */
+ status = pjsip_inv_answer(call->inv, code, text, NULL, &tdata);
+ }
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Answering replacement call %d with 200/OK",
+ call->index));
+
+ /* Answer the new call with 200 response */
+ status = pjsip_inv_answer(call->inv, 200, NULL, NULL, &tdata);
+ }
- /* Answer the new call with 200 response */
- status = pjsip_inv_answer(call->inv, 200, NULL, NULL, &tdata);
- if (status == PJ_SUCCESS)
+ if (status == PJ_SUCCESS && tdata)
status = pjsip_inv_send_msg(call->inv, tdata);
if (status != PJ_SUCCESS)
@@ -997,7 +1029,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
int acc_id;
pjsua_call *call;
int call_id = -1;
- int sip_err_code;
+ int sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
pjmedia_sdp_session *offer=NULL;
pj_status_t status;
@@ -1182,7 +1214,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
options |= PJSIP_INV_SUPPORT_TIMER;
if (pjsua_var.acc[acc_id].cfg.require_100rel == PJSUA_100REL_MANDATORY)
options |= PJSIP_INV_REQUIRE_100REL;
- if (pjsua_var.media_cfg.enable_ice)
+ if (pjsua_var.acc[acc_id].cfg.ice_cfg.enable_ice)
options |= PJSIP_INV_SUPPORT_ICE;
if (pjsua_var.acc[acc_id].cfg.use_timer == PJSUA_SIP_TIMER_REQUIRED)
options |= PJSIP_INV_REQUIRE_TIMER;
@@ -1488,6 +1520,7 @@ pj_status_t acquire_call(const char *title,
pj_bool_t has_pjsua_lock = PJ_FALSE;
pj_status_t status = PJ_SUCCESS;
pj_time_val time_start, timeout;
+ pjsip_dialog *dlg = NULL;
pj_gettimeofday(&time_start);
timeout.sec = 0;
@@ -1515,14 +1548,18 @@ pj_status_t acquire_call(const char *title,
has_pjsua_lock = PJ_TRUE;
call = &pjsua_var.calls[call_id];
+ if (call->inv)
+ dlg = call->inv->dlg;
+ else
+ dlg = call->async_call.dlg;
- if (call->inv == NULL) {
+ if (dlg == NULL) {
PJSUA_UNLOCK();
PJ_LOG(3,(THIS_FILE, "Invalid call_id %d in %s", call_id, title));
return PJSIP_ESESSIONTERMINATED;
}
- status = pjsip_dlg_try_inc_lock(call->inv->dlg);
+ status = pjsip_dlg_try_inc_lock(dlg);
if (status != PJ_SUCCESS) {
PJSUA_UNLOCK();
pj_thread_sleep(retry/10);
@@ -1547,7 +1584,7 @@ pj_status_t acquire_call(const char *title,
}
*p_call = call;
- *p_dlg = call->inv->dlg;
+ *p_dlg = dlg;
return PJ_SUCCESS;
}
@@ -1992,7 +2029,7 @@ PJ_DEF(pj_status_t) pjsua_call_answer2(pjsua_call_id call_id,
* answer code 183 or 2xx is issued
*/
if (!call->med_ch_cb &&
- (call->opt_inited || (code==183 && code/100==2)) &&
+ (call->opt_inited || (code==183 || code/100==2)) &&
(!call->inv->neg ||
pjmedia_sdp_neg_get_state(call->inv->neg) ==
PJMEDIA_SDP_NEG_STATE_NULL))
@@ -2120,6 +2157,25 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
if (status != PJ_SUCCESS)
goto on_return;
+ /* If media transport creation is not yet completed, we will hangup
+ * the call in the media transport creation callback instead.
+ */
+ if (call->med_ch_cb && !call->inv) {
+ PJ_LOG(4,(THIS_FILE, "Pending call %d hangup upon completion "
+ "of media transport", call_id));
+ call->async_call.call_var.out_call.hangup = PJ_TRUE;
+ if (code == 0)
+ call->last_code = PJSIP_SC_REQUEST_TERMINATED;
+ else
+ call->last_code = (pjsip_status_code)code;
+ if (reason) {
+ pj_strncpy(&call->last_text, reason,
+ sizeof(call->last_text_buf_));
+ }
+
+ goto on_return;
+ }
+
if (code==0) {
if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
code = PJSIP_SC_OK;
@@ -2156,11 +2212,10 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
goto on_return;
}
- /* Stop lock codec timer, if it is active */
- if (call->lock_codec.reinv_timer.id) {
- pjsip_endpt_cancel_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer);
- call->lock_codec.reinv_timer.id = PJ_FALSE;
+ /* Stop reinvite timer, if it is active */
+ if (call->reinv_timer.id) {
+ pjsua_cancel_timer(&call->reinv_timer);
+ call->reinv_timer.id = PJ_FALSE;
}
on_return:
@@ -2337,7 +2392,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite2(pjsua_call_id call_id,
goto on_return;
}
- if ((call->opt.flag & PJSUA_CALL_UPDATE_CONTACT) &
+ if ((call->opt.flag & PJSUA_CALL_UPDATE_CONTACT) &&
pjsua_acc_is_valid(call->acc_id))
{
new_contact = &pjsua_var.acc[call->acc_id].contact;
@@ -2433,7 +2488,7 @@ PJ_DEF(pj_status_t) pjsua_call_update2(pjsua_call_id call_id,
goto on_return;
}
- if ((call->opt.flag & PJSUA_CALL_UPDATE_CONTACT) &
+ if ((call->opt.flag & PJSUA_CALL_UPDATE_CONTACT) &&
pjsua_acc_is_valid(call->acc_id))
{
new_contact = &pjsua_var.acc[call->acc_id].contact;
@@ -2850,12 +2905,8 @@ PJ_DEF(void) pjsua_call_hangup_all(void)
}
-/* Proto */
-static pj_status_t perform_lock_codec(pjsua_call *call);
-
-/* Timer callback to send re-INVITE or UPDATE to lock codec */
-static void reinv_timer_cb(pj_timer_heap_t *th,
- pj_timer_entry *entry)
+/* Timer callback to send re-INVITE/UPDATE to lock codec or ICE update */
+static void reinv_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry)
{
pjsua_call_id call_id = (pjsua_call_id)(pj_size_t)entry->user_data;
pjsip_dialog *dlg;
@@ -2864,21 +2915,27 @@ static void reinv_timer_cb(pj_timer_heap_t *th,
PJ_UNUSED_ARG(th);
- pjsua_var.calls[call_id].lock_codec.reinv_timer.id = PJ_FALSE;
+ pjsua_var.calls[call_id].reinv_timer.id = PJ_FALSE;
+
+ pj_log_push_indent();
status = acquire_call("reinv_timer_cb()", call_id, &call, &dlg);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pj_log_pop_indent();
return;
+ }
- status = perform_lock_codec(call);
+ process_pending_reinvite(call);
pjsip_dlg_dec_lock(dlg);
+
+ pj_log_pop_indent();
}
/* Check if the specified format can be skipped in counting codecs */
static pj_bool_t is_non_av_fmt(const pjmedia_sdp_media *m,
- const pj_str_t *fmt)
+ const pj_str_t *fmt)
{
const pj_str_t STR_TEL = {"telephone-event", 15};
unsigned pt;
@@ -2911,62 +2968,62 @@ static pj_bool_t is_non_av_fmt(const pjmedia_sdp_media *m,
}
-/* Send re-INVITE or UPDATE with new SDP offer to select only one codec
- * out of several codecs presented by callee in his answer.
+/* Schedule check for the need of re-INVITE/UPDATE after media update, cases:
+ * - lock codec if remote answerer has given us more than one codecs
+ * - update ICE default transport address if it has changed after ICE
+ * connectivity check.
*/
-static pj_status_t perform_lock_codec(pjsua_call *call)
+void pjsua_call_schedule_reinvite_check(pjsua_call *call, unsigned delay_ms)
+{
+ pj_time_val delay;
+
+ /* Stop reinvite timer, if it is active */
+ if (call->reinv_timer.id)
+ pjsua_cancel_timer(&call->reinv_timer);
+
+ delay.sec = 0;
+ delay.msec = delay_ms;
+ pj_time_val_normalize(&delay);
+ call->reinv_timer.id = PJ_TRUE;
+ pjsua_schedule_timer(&call->reinv_timer, &delay);
+}
+
+
+/* Check if lock codec is needed */
+static pj_bool_t check_lock_codec(pjsua_call *call)
{
- const pj_str_t STR_UPDATE = {"UPDATE", 6};
- const pjmedia_sdp_session *local_sdp = NULL, *new_sdp;
+ const pjmedia_sdp_session *local_sdp, *remote_sdp;
+ pj_bool_t has_mult_fmt = PJ_FALSE;
unsigned i;
- pj_bool_t rem_can_update;
- pj_bool_t need_lock_codec = PJ_FALSE;
- pjsip_tx_data *tdata;
pj_status_t status;
- PJ_ASSERT_RETURN(call->lock_codec.reinv_timer.id==PJ_FALSE,
- PJ_EINVALIDOP);
+ /* Check if lock codec is disabled */
+ if (!pjsua_var.acc[call->acc_id].cfg.lock_codec)
+ return PJ_FALSE;
- /* Verify if another SDP negotiation is in progress, e.g: session timer
- * or another re-INVITE.
- */
- if (call->inv==NULL || call->inv->neg==NULL ||
- pjmedia_sdp_neg_get_state(call->inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE)
- {
- return PJMEDIA_SDPNEG_EINSTATE;
- }
+ /* Check lock codec retry count */
+ if (call->lock_codec.retry_cnt >= LOCK_CODEC_MAX_RETRY)
+ return PJ_FALSE;
- /* Don't do this if call is disconnecting! */
- if (call->inv->state > PJSIP_INV_STATE_CONFIRMED ||
- call->inv->cause >= 200)
- {
- return PJ_EINVALIDOP;
- }
+ /* Check if we are the answerer, we shouldn't need to lock codec */
+ if (!call->inv->neg || !pjmedia_sdp_neg_was_answer_remote(call->inv->neg))
+ return PJ_FALSE;
- /* Verify if another SDP negotiation has been completed by comparing
- * the SDP version.
- */
+ /* Check if remote answerer has given us more than one codecs. */
status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
if (status != PJ_SUCCESS)
- return status;
- if (local_sdp->origin.version > call->lock_codec.sdp_ver)
- return PJMEDIA_SDP_EINVER;
-
- PJ_LOG(3, (THIS_FILE, "Updating media session to use only one codec.."));
-
- /* Update the new offer so it contains only a codec. Note that formats
- * order in the offer should have been matched to the answer, so we can
- * just directly update the offer without looking-up the answer.
- */
- new_sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, local_sdp);
+ return PJ_FALSE;
+ status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
+ if (status != PJ_SUCCESS)
+ return PJ_FALSE;
- for (i = 0; i < call->med_cnt; ++i) {
- unsigned j = 0, codec_cnt = 0;
- const pjmedia_sdp_media *ref_m;
- pjmedia_sdp_media *m;
+ for (i = 0; i < call->med_cnt && !has_mult_fmt; ++i) {
pjsua_call_media *call_med = &call->media[i];
+ const pjmedia_sdp_media *rem_m, *loc_m;
+ unsigned codec_cnt = 0;
+ unsigned j;
- /* Verify if media is deactivated */
+ /* Skip this if the media is inactive or error */
if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
call_med->state == PJSUA_CALL_MEDIA_ERROR ||
call_med->dir == PJMEDIA_DIR_NONE)
@@ -2974,192 +3031,336 @@ static pj_status_t perform_lock_codec(pjsua_call *call)
continue;
}
- ref_m = local_sdp->media[i];
- m = new_sdp->media[i];
-
- /* Verify that media must be active. */
- pj_assert(ref_m->desc.port);
+ /* Remote may answer with less media lines. */
+ if (i >= remote_sdp->media_count)
+ continue;
- while (j < m->desc.fmt_count) {
- pjmedia_sdp_attr *a;
- pj_str_t *fmt = &m->desc.fmt[j];
+ rem_m = remote_sdp->media[i];
+ loc_m = local_sdp->media[i];
- if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) {
- ++j;
- continue;
- }
+ /* Verify that media must be active. */
+ pj_assert(loc_m->desc.port && rem_m->desc.port);
- /* Remove format */
- a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt);
- if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
- a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt);
- if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
- pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]),
- m->desc.fmt_count, j);
- --m->desc.fmt_count;
+ /* Count the formats in the answer. */
+ for (j=0; j<rem_m->desc.fmt_count && codec_cnt <= 1; ++j) {
+ if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[j]) && ++codec_cnt > 1)
+ has_mult_fmt = PJ_TRUE;
}
-
- need_lock_codec |= (ref_m->desc.fmt_count > m->desc.fmt_count);
}
- /* Last check if SDP trully needs to be updated. It is possible that OA
- * negotiations have completed and SDP has changed but we didn't
- * increase the SDP version (should not happen!).
- */
- if (!need_lock_codec)
- return PJ_SUCCESS;
+ /* Reset retry count when remote answer has one codec */
+ if (!has_mult_fmt)
+ call->lock_codec.retry_cnt = 0;
- /* Send UPDATE or re-INVITE */
- rem_can_update = pjsip_dlg_remote_has_cap(call->inv->dlg,
- PJSIP_H_ALLOW,
- NULL, &STR_UPDATE) ==
- PJSIP_DIALOG_CAP_SUPPORTED;
- if (rem_can_update) {
- status = pjsip_inv_update(call->inv, NULL, new_sdp, &tdata);
- } else {
- status = pjsip_inv_reinvite(call->inv, NULL, new_sdp, &tdata);
- }
+ return has_mult_fmt;
+}
- if (status==PJ_EINVALIDOP &&
- ++call->lock_codec.retry_cnt <= LOCK_CODEC_MAX_RETRY)
- {
- /* Ups, let's reschedule again */
- pj_time_val delay = {0, LOCK_CODEC_RETRY_INTERVAL};
- pj_time_val_normalize(&delay);
- call->lock_codec.reinv_timer.id = PJ_TRUE;
- pjsip_endpt_schedule_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer, &delay);
- return status;
- } else if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error creating UPDATE/re-INVITE to lock codec",
- status);
- return status;
- }
+/* Check if ICE setup is complete and if it needs to send reinvite */
+static pj_bool_t check_ice_complete(pjsua_call *call, pj_bool_t *need_reinv)
+{
+ pj_bool_t ice_need_reinv = PJ_FALSE;
+ pj_bool_t ice_complete = PJ_TRUE;
+ unsigned i;
- /* Send the UPDATE/re-INVITE request */
- status = pjsip_inv_send_msg(call->inv, tdata);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error sending UPDATE/re-INVITE in lock codec",
- status);
- return status;
- }
+ /* Check if ICE setup is complete and if it needs reinvite */
+ for (i = 0; i < call->med_cnt; ++i) {
+ pjsua_call_media *call_med = &call->media[i];
+ pjmedia_transport_info tpinfo;
+ pjmedia_ice_transport_info *ice_info;
+
+ if (call_med->tp_st == PJSUA_MED_TP_NULL ||
+ call_med->tp_st == PJSUA_MED_TP_DISABLED ||
+ call_med->state == PJSUA_CALL_MEDIA_ERROR)
+ {
+ continue;
+ }
+
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(call_med->tp, &tpinfo);
+ ice_info = (pjmedia_ice_transport_info*)
+ pjmedia_transport_info_get_spc_info(
+ &tpinfo, PJMEDIA_TRANSPORT_TYPE_ICE);
+
+ /* Check if ICE is active */
+ if (!ice_info || !ice_info->active)
+ continue;
- return status;
+ /* Check if ICE setup not completed yet */
+ if (ice_info->sess_state < PJ_ICE_STRANS_STATE_RUNNING) {
+ ice_complete = PJ_FALSE;
+ break;
+ }
+
+ /* Check if ICE needs to send reinvite */
+ if (!ice_need_reinv &&
+ ice_info->sess_state == PJ_ICE_STRANS_STATE_RUNNING &&
+ ice_info->role == PJ_ICE_SESS_ROLE_CONTROLLING)
+ {
+ pjsua_ice_config *cfg=&pjsua_var.acc[call->acc_id].cfg.ice_cfg;
+ if ((cfg->ice_always_update && !call->reinv_ice_sent) ||
+ pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name,
+ &call_med->rtp_addr))
+ {
+ ice_need_reinv = PJ_TRUE;
+ }
+ }
+ }
+
+ if (ice_complete && need_reinv)
+ *need_reinv = ice_need_reinv;
+
+ return ice_complete;
}
-/* Check if remote answerer has given us more than one codecs. If so,
- * create another offer with one codec only to lock down the codec.
- */
-static pj_status_t lock_codec(pjsua_call *call)
+/* Check and send reinvite for lock codec and ICE update */
+static pj_status_t process_pending_reinvite(pjsua_call *call)
{
+ const pj_str_t ST_UPDATE = {"UPDATE", 6};
+ pj_pool_t *pool = call->inv->pool_prov;
pjsip_inv_session *inv = call->inv;
- const pjmedia_sdp_session *local_sdp, *remote_sdp;
- pj_time_val delay = {0, 0};
- const pj_str_t st_update = {"UPDATE", 6};
+ pj_bool_t ice_need_reinv;
+ pj_bool_t ice_completed;
+ pj_bool_t need_lock_codec;
+ pj_bool_t rem_can_update;
+ pjmedia_sdp_session *new_offer;
+ pjsip_tx_data *tdata;
unsigned i;
- pj_bool_t has_mult_fmt = PJ_FALSE;
pj_status_t status;
- /* Stop lock codec timer, if it is active */
- if (call->lock_codec.reinv_timer.id) {
- pjsip_endpt_cancel_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer);
- call->lock_codec.reinv_timer.id = PJ_FALSE;
+ /* Verify if another SDP negotiation is in progress, e.g: session timer
+ * or another re-INVITE.
+ */
+ if (inv==NULL || inv->neg==NULL ||
+ pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE)
+ {
+ return PJMEDIA_SDPNEG_EINSTATE;
}
- /* Skip this if we are the answerer */
- if (!inv->neg || !pjmedia_sdp_neg_was_answer_remote(inv->neg)) {
- return PJ_SUCCESS;
+ /* Don't do this if call is disconnecting! */
+ if (inv->state > PJSIP_INV_STATE_CONFIRMED || inv->cause >= 200)
+ {
+ return PJ_EINVALIDOP;
}
/* Delay this when the SDP negotiation done in call state EARLY and
* remote does not support UPDATE method.
*/
if (inv->state == PJSIP_INV_STATE_EARLY &&
- pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)!=
+ pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &ST_UPDATE)!=
PJSIP_DIALOG_CAP_SUPPORTED)
{
- call->lock_codec.pending = PJ_TRUE;
- return PJ_SUCCESS;
+ call->reinv_pending = PJ_TRUE;
+ return PJ_EPENDING;
}
- status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
- if (status != PJ_SUCCESS)
- return status;
- status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
- if (status != PJ_SUCCESS)
- return status;
+ /* Check if ICE setup is complete and if it needs reinvite */
+ ice_completed = check_ice_complete(call, &ice_need_reinv);
+ if (!ice_completed)
+ return PJ_EPENDING;
- /* Find multiple codecs answer in all media */
- for (i = 0; i < call->med_cnt; ++i) {
- pjsua_call_media *call_med = &call->media[i];
- const pjmedia_sdp_media *rem_m, *loc_m;
- unsigned codec_cnt = 0;
+ /* Check if we need to lock codec */
+ need_lock_codec = check_lock_codec(call);
- /* Skip this if the media is inactive or error */
- if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
- call_med->state == PJSUA_CALL_MEDIA_ERROR ||
- call_med->dir == PJMEDIA_DIR_NONE)
- {
- continue;
- }
+ /* Check if reinvite is really needed */
+ if (!need_lock_codec && !ice_need_reinv)
+ return PJ_SUCCESS;
- /* Remote may answer with less media lines. */
- if (i >= remote_sdp->media_count)
- continue;
+
+ /* Okay! So we need to send re-INVITE/UPDATE */
- rem_m = remote_sdp->media[i];
- loc_m = local_sdp->media[i];
+ /* Check if remote support UPDATE */
+ rem_can_update = pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL,
+ &ST_UPDATE) ==
+ PJSIP_DIALOG_CAP_SUPPORTED;
- /* Verify that media must be active. */
- pj_assert(loc_m->desc.port && rem_m->desc.port);
+ /* Logging stuff */
+ {
+ const char *ST_ICE_UPDATE = "ICE transport address after "
+ "ICE negotiation";
+ const char *ST_LOCK_CODEC = "media session to use only one codec";
+ PJ_LOG(4,(THIS_FILE, "Call %d sending %s for updating %s%s%s",
+ call->index,
+ (rem_can_update? "UPDATE" : "re-INVITE"),
+ (ice_need_reinv? ST_ICE_UPDATE : ST_LOCK_CODEC),
+ (ice_need_reinv && need_lock_codec? " and " : ""),
+ (ice_need_reinv && need_lock_codec? ST_LOCK_CODEC : "")
+ ));
+ }
+
+ /* Generate SDP re-offer */
+ status = pjsua_media_channel_create_sdp(call->index, pool, NULL,
+ &new_offer, NULL);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Unable to create local SDP", status);
+ return status;
+ }
- /* Count the formats in the answer. */
- if (rem_m->desc.fmt_count==1) {
- codec_cnt = 1;
- } else {
- unsigned j;
- for (j=0; j<rem_m->desc.fmt_count && codec_cnt <= 1; ++j) {
- if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[j]))
- ++codec_cnt;
- }
+ /* Update the new offer so it contains only a codec. Note that
+ * SDP nego has removed unmatched codecs from the offer and the codec
+ * order in the offer has been matched to the answer, so we'll override
+ * the codecs in the just generated SDP with the ones from the active
+ * local SDP and leave just one codec for the next SDP re-offer.
+ */
+ if (need_lock_codec) {
+ const pjmedia_sdp_session *ref_sdp;
+
+ /* Get local active SDP as reference */
+ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &ref_sdp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Verify media count. Note that remote may add/remove media line
+ * in the answer. When answer has less media, it must have been
+ * handled by pjsua_media_channel_update() as disabled media.
+ * When answer has more media, it must have been ignored (treated
+ * as non-exist) anywhere. Local media count should not be updated
+ * at this point, as modifying media count operation (i.e: reinvite,
+ * update, vid_set_strm) is currently blocking, protected with
+ * dialog mutex, and eventually reset SDP nego state to LOCAL OFFER.
+ */
+ if (call->med_cnt != ref_sdp->media_count ||
+ ref_sdp->media_count != new_offer->media_count)
+ {
+ /* Anyway, just in case, let's just return error */
+ return PJMEDIA_SDPNEG_EINSTATE;
}
- if (codec_cnt > 1) {
- has_mult_fmt = PJ_TRUE;
- break;
+ for (i = 0; i < call->med_cnt; ++i) {
+ unsigned j, codec_cnt = 0;
+ const pjmedia_sdp_media *ref_m = ref_sdp->media[i];
+ pjmedia_sdp_media *m = new_offer->media[i];
+ pjsua_call_media *call_med = &call->media[i];
+
+ /* Verify if media is deactivated */
+ if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
+ call_med->state == PJSUA_CALL_MEDIA_ERROR ||
+ call_med->dir == PJMEDIA_DIR_NONE)
+ {
+ continue;
+ }
+
+ /* Reset formats */
+ m->desc.fmt_count = 0;
+ pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "rtpmap");
+ pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "fmtp");
+
+ /* Copy only the first format + any non-AV formats from
+ * the active local SDP.
+ */
+ for (j = 0; j < ref_m->desc.fmt_count; ++j) {
+ const pj_str_t *fmt = &ref_m->desc.fmt[j];
+
+ if (is_non_av_fmt(ref_m, fmt) || (++codec_cnt == 1)) {
+ pjmedia_sdp_attr *a;
+
+ m->desc.fmt[m->desc.fmt_count++] = *fmt;
+ a = pjmedia_sdp_attr_find2(ref_m->attr_count, ref_m->attr,
+ "rtpmap", fmt);
+ if (a) pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
+ a = pjmedia_sdp_attr_find2(ref_m->attr_count, ref_m->attr,
+ "fmtp", fmt);
+ if (a) pjmedia_sdp_attr_add(&m->attr_count, m->attr, a);
+ }
+ }
}
}
- /* Each media in the answer already contains single codec. */
- if (!has_mult_fmt) {
- call->lock_codec.retry_cnt = 0;
- return PJ_SUCCESS;
- }
+ /* Put back original direction and "c=0.0.0.0" line */
+ {
+ const pjmedia_sdp_session *cur_sdp;
+
+ /* Get local active SDP */
+ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &cur_sdp);
+ if (status != PJ_SUCCESS)
+ return status;
- /* Remote keeps answering with multiple codecs, let's just give up
- * locking codec to avoid infinite retry loop.
- */
- if (++call->lock_codec.retry_cnt > LOCK_CODEC_MAX_RETRY)
- return PJ_SUCCESS;
+ /* Make sure media count has not been changed */
+ if (call->med_cnt != cur_sdp->media_count)
+ return PJMEDIA_SDPNEG_EINSTATE;
+
+ for (i = 0; i < call->med_cnt; ++i) {
+ const pjmedia_sdp_media *m = cur_sdp->media[i];
+ pjmedia_sdp_media *new_m = new_offer->media[i];
+ pjsua_call_media *call_med = &call->media[i];
+ pjmedia_sdp_attr *a = NULL;
+
+ /* Update direction to the current dir */
+ pjmedia_sdp_media_remove_all_attr(new_m, "sendrecv");
+ pjmedia_sdp_media_remove_all_attr(new_m, "sendonly");
+ pjmedia_sdp_media_remove_all_attr(new_m, "recvonly");
+ pjmedia_sdp_media_remove_all_attr(new_m, "inactive");
+
+ if (call_med->dir == PJMEDIA_DIR_ENCODING_DECODING) {
+ a = pjmedia_sdp_attr_create(pool, "sendrecv", NULL);
+ } else if (call_med->dir == PJMEDIA_DIR_ENCODING) {
+ a = pjmedia_sdp_attr_create(pool, "sendonly", NULL);
+ } else if (call_med->dir == PJMEDIA_DIR_DECODING) {
+ a = pjmedia_sdp_attr_create(pool, "recvonly", NULL);
+ } else {
+ const pjmedia_sdp_conn *conn;
+ a = pjmedia_sdp_attr_create(pool, "inactive", NULL);
+
+ /* Also check if the original c= line address is zero */
+ conn = m->conn;
+ if (!conn)
+ conn = cur_sdp->conn;
+ if (pj_strcmp2(&conn->addr, "0.0.0.0")==0 ||
+ pj_strcmp2(&conn->addr, "0")==0)
+ {
+ if (!new_m->conn) {
+ new_m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
+ }
+
+ if (pj_strcmp2(&new_m->conn->addr, "0.0.0.0")) {
+ new_m->conn->net_type = pj_str("IN");
+ new_m->conn->addr_type = pj_str("IP4");
+ new_m->conn->addr = pj_str("0.0.0.0");
+ }
+ }
+ }
- PJ_LOG(4, (THIS_FILE, "Got answer with multiple codecs, scheduling "
- "updating media session to use only one codec.."));
+ pj_assert(a);
+ pjmedia_sdp_media_add_attr(new_m, a);
+ }
+ }
- call->lock_codec.sdp_ver = local_sdp->origin.version;
+
+ if (rem_can_update) {
+ status = pjsip_inv_update(inv, NULL, new_offer, &tdata);
+ } else {
+ status = pjsip_inv_reinvite(inv, NULL, new_offer, &tdata);
+ }
- /* Can't send UPDATE or re-INVITE now, so just schedule it immediately.
- * See: https://trac.pjsip.org/repos/ticket/1149
- */
- pj_timer_entry_init(&call->lock_codec.reinv_timer, PJ_TRUE,
- (void*)(pj_size_t)call->index,
- &reinv_timer_cb);
- pjsip_endpt_schedule_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer, &delay);
+ if (status==PJ_EINVALIDOP &&
+ ++call->lock_codec.retry_cnt < LOCK_CODEC_MAX_RETRY)
+ {
+ /* Ups, let's reschedule again */
+ pjsua_call_schedule_reinvite_check(call, LOCK_CODEC_RETRY_INTERVAL);
+ return PJ_SUCCESS;
+ } else if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating UPDATE/re-INVITE",
+ status);
+ return status;
+ }
+ /* Send the UPDATE/re-INVITE request */
+ status = pjsip_inv_send_msg(inv, tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error sending UPDATE/re-INVITE",
+ status);
+ return status;
+ }
+
+ /* Update flags */
+ if (ice_need_reinv)
+ call->reinv_ice_sent = PJ_TRUE;
+ if (need_lock_codec)
+ ++call->lock_codec.retry_cnt;
+
return PJ_SUCCESS;
}
+
/*
* This callback receives notification from invite session when the
* session state has changed.
@@ -3194,16 +3395,12 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
case PJSIP_INV_STATE_CONFIRMED:
pj_gettimeofday(&call->conn_time);
- /* See if lock codec was pended as media update was done in the
+ /* See if auto reinvite was pended as media update was done in the
* EARLY state and remote does not support UPDATE.
*/
- if (call->lock_codec.pending) {
- pj_status_t status;
- status = lock_codec(call);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to lock codec", status);
- }
- call->lock_codec.pending = PJ_FALSE;
+ if (call->reinv_pending) {
+ call->reinv_pending = PJ_FALSE;
+ pjsua_call_schedule_reinvite_check(call, 0);
}
break;
case PJSIP_INV_STATE_DISCONNECTED:
@@ -3225,11 +3422,10 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
sizeof(call->last_text_buf_));
}
- /* Stop lock codec timer, if it is active */
- if (call->lock_codec.reinv_timer.id) {
- pjsip_endpt_cancel_timer(pjsua_var.endpt,
- &call->lock_codec.reinv_timer);
- call->lock_codec.reinv_timer.id = PJ_FALSE;
+ /* Stop reinvite timer, if it is active */
+ if (call->reinv_timer.id) {
+ pjsua_cancel_timer(&call->reinv_timer);
+ call->reinv_timer.id = PJ_FALSE;
}
break;
default:
@@ -3307,6 +3503,15 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
}
}
+ /* Ticket #1627: Invoke on_call_tsx_state() when call is disconnected. */
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
+ e->type == PJSIP_EVENT_TSX_STATE &&
+ call->inv &&
+ pjsua_var.ua_cfg.cb.on_call_tsx_state)
+ {
+ (*pjsua_var.ua_cfg.cb.on_call_tsx_state)(call->index,
+ e->body.tsx_state.tsx, e);
+ }
if (pjsua_var.ua_cfg.cb.on_call_state)
(*pjsua_var.ua_cfg.cb.on_call_state)(call->index, e);
@@ -3512,10 +3717,7 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv,
}
/* Ticket #476: make sure only one codec is specified in the answer. */
- status = lock_codec(call);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Unable to lock codec", status);
- }
+ pjsua_call_schedule_reinvite_check(call, 0);
/* Call application callback, if any */
if (pjsua_var.ua_cfg.cb.on_call_media_state)
@@ -4221,11 +4423,7 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
goto on_return;
if (call->inv == NULL) {
- /* Shouldn't happen. It happens only when we don't terminate the
- * server subscription caused by REFER after the call has been
- * transfered (and this call has been disconnected), and we
- * receive another REFER for this call.
- */
+ /* Call has been disconnected. */
goto on_return;
}
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index f4f9508..e352238 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_core.c 4173 2012-06-20 10:39:05Z ming $ */
+/* $Id: pjsua_core.c 4370 2013-02-26 05:30:00Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -196,12 +196,65 @@ PJ_DEF(void) pjsua_transport_config_dup(pj_pool_t *pool,
pjsua_transport_config *dst,
const pjsua_transport_config *src)
{
+ pj_memcpy(dst, src, sizeof(*src));
+ pj_strdup(pool, &dst->public_addr, &src->public_addr);
+ pj_strdup(pool, &dst->bound_addr, &src->bound_addr);
+}
+
+PJ_DEF(void) pjsua_ice_config_from_media_config( pj_pool_t *pool,
+ pjsua_ice_config *dst,
+ const pjsua_media_config *src)
+{
+ PJ_UNUSED_ARG(pool);
+
+ dst->enable_ice = src->enable_ice;
+ dst->ice_max_host_cands = src->ice_max_host_cands;
+ dst->ice_opt = src->ice_opt;
+ dst->ice_no_rtcp = src->ice_no_rtcp;
+ dst->ice_always_update = src->ice_always_update;
+}
+
+PJ_DEF(void) pjsua_ice_config_dup( pj_pool_t *pool,
+ pjsua_ice_config *dst,
+ const pjsua_ice_config *src)
+{
PJ_UNUSED_ARG(pool);
pj_memcpy(dst, src, sizeof(*src));
}
+PJ_DEF(void) pjsua_turn_config_from_media_config(pj_pool_t *pool,
+ pjsua_turn_config *dst,
+ const pjsua_media_config *src)
+{
+ dst->enable_turn = src->enable_turn;
+ dst->turn_conn_type = src->turn_conn_type;
+ if (pool == NULL) {
+ dst->turn_server = src->turn_server;
+ dst->turn_auth_cred = src->turn_auth_cred;
+ } else {
+ if (pj_stricmp(&dst->turn_server, &src->turn_server))
+ pj_strdup(pool, &dst->turn_server, &src->turn_server);
+ pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
+ &src->turn_auth_cred);
+ }
+}
+
+PJ_DEF(void) pjsua_turn_config_dup(pj_pool_t *pool,
+ pjsua_turn_config *dst,
+ const pjsua_turn_config *src)
+{
+ pj_memcpy(dst, src, sizeof(*src));
+ if (pool) {
+ pj_strdup(pool, &dst->turn_server, &src->turn_server);
+ pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
+ &src->turn_auth_cred);
+ }
+}
+
PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
{
+ pjsua_media_config med_cfg;
+
pj_bzero(cfg, sizeof(*cfg));
cfg->reg_timeout = PJSUA_REG_INTERVAL;
@@ -215,6 +268,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
cfg->require_100rel = pjsua_var.ua_cfg.require_100rel;
cfg->use_timer = pjsua_var.ua_cfg.use_timer;
cfg->timer_setting = pjsua_var.ua_cfg.timer_setting;
+ cfg->lock_codec = 1;
cfg->ka_interval = 15;
cfg->ka_data = pj_str("\r\n");
cfg->vid_cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
@@ -223,6 +277,11 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg);
#endif
pjsua_transport_config_default(&cfg->rtp_cfg);
+
+ pjsua_media_config_default(&med_cfg);
+ pjsua_ice_config_from_media_config(NULL, &cfg->ice_cfg, &med_cfg);
+ pjsua_turn_config_from_media_config(NULL, &cfg->turn_cfg, &med_cfg);
+
cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer;
@@ -266,6 +325,7 @@ PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg)
cfg->snd_auto_close_time = 1;
cfg->ice_max_host_cands = -1;
+ cfg->ice_always_update = PJ_TRUE;
pj_ice_sess_options_default(&cfg->ice_opt);
cfg->turn_conn_type = PJ_TURN_TP_UDP;
@@ -898,7 +958,7 @@ PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
if (pjsua_var.ua_cfg.force_lr) {
pjsip_sip_uri *sip_url;
if (!PJSIP_URI_SCHEME_IS_SIP(r->name_addr.uri) &&
- !PJSIP_URI_SCHEME_IS_SIP(r->name_addr.uri))
+ !PJSIP_URI_SCHEME_IS_SIPS(r->name_addr.uri))
{
status = PJSIP_EINVALIDSCHEME;
goto on_error;
@@ -1017,7 +1077,7 @@ static void busy_sleep(unsigned msec)
{
pj_time_val timeout, now;
- pj_gettimeofday(&timeout);
+ pj_gettickcount(&timeout);
timeout.msec += msec;
pj_time_val_normalize(&timeout);
@@ -1026,15 +1086,21 @@ static void busy_sleep(unsigned msec)
i = msec / 10;
while (pjsua_handle_events(10) > 0 && i > 0)
--i;
- pj_gettimeofday(&now);
+ pj_gettickcount(&now);
} while (PJ_TIME_VAL_LT(now, timeout));
}
-/* Internal function to destroy STUN resolution session
- * (pj_stun_resolve).
- */
+static void stun_resolve_add_ref(pjsua_stun_resolve *sess)
+{
+ ++sess->ref_cnt;
+}
+
static void destroy_stun_resolve(pjsua_stun_resolve *sess)
{
+ sess->destroy_flag = PJ_TRUE;
+ if (sess->ref_cnt > 0)
+ return;
+
PJSUA_LOCK();
pj_list_erase(sess);
PJSUA_UNLOCK();
@@ -1043,6 +1109,14 @@ static void destroy_stun_resolve(pjsua_stun_resolve *sess)
pj_pool_release(sess->pool);
}
+static void stun_resolve_dec_ref(pjsua_stun_resolve *sess)
+{
+ --sess->ref_cnt;
+ if (sess->ref_cnt <= 0 && sess->destroy_flag)
+ destroy_stun_resolve(sess);
+}
+
+
/* This is the internal function to be called when STUN resolution
* session (pj_stun_resolve) has completed.
*/
@@ -1050,11 +1124,15 @@ static void stun_resolve_complete(pjsua_stun_resolve *sess)
{
pj_stun_resolve_result result;
+ if (sess->has_result)
+ goto on_return;
+
pj_bzero(&result, sizeof(result));
result.token = sess->token;
result.status = sess->status;
result.name = sess->srv[sess->idx];
pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr));
+ sess->has_result = PJ_TRUE;
if (result.status == PJ_SUCCESS) {
char addr[PJ_INET6_ADDRSTRLEN+10];
@@ -1070,8 +1148,11 @@ static void stun_resolve_complete(pjsua_stun_resolve *sess)
PJ_LOG(1,(THIS_FILE, "STUN resolution failed: %s", errmsg));
}
+ stun_resolve_add_ref(sess);
sess->cb(&result);
+ stun_resolve_dec_ref(sess);
+on_return:
if (!sess->blocking) {
destroy_stun_resolve(sess);
}
@@ -1133,22 +1214,27 @@ static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock,
*/
static void resolve_stun_entry(pjsua_stun_resolve *sess)
{
+ stun_resolve_add_ref(sess);
+
/* Loop while we have entry to try */
for (; sess->idx < sess->count; ++sess->idx) {
const int af = pj_AF_INET();
+ char target[64];
pj_str_t hostpart;
pj_uint16_t port;
pj_stun_sock_cb stun_sock_cb;
pj_assert(sess->idx < sess->count);
+ pj_ansi_snprintf(target, sizeof(target), "%.*s",
+ (int)sess->srv[sess->idx].slen,
+ sess->srv[sess->idx].ptr);
+
/* Parse the server entry into host:port */
sess->status = pj_sockaddr_parse2(af, 0, &sess->srv[sess->idx],
&hostpart, &port, NULL);
if (sess->status != PJ_SUCCESS) {
- PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %.*s",
- (int)sess->srv[sess->idx].slen,
- sess->srv[sess->idx].ptr));
+ PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %s", target));
continue;
}
@@ -1158,10 +1244,8 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
pj_assert(sess->stun_sock == NULL);
- PJ_LOG(4,(THIS_FILE, "Trying STUN server %.*s (%d of %d)..",
- (int)sess->srv[sess->idx].slen,
- sess->srv[sess->idx].ptr,
- sess->idx+1, sess->count));
+ PJ_LOG(4,(THIS_FILE, "Trying STUN server %s (%d of %d)..",
+ target, sess->idx+1, sess->count));
/* Use STUN_sock to test this entry */
pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
@@ -1173,9 +1257,8 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(sess->status, errmsg, sizeof(errmsg));
PJ_LOG(4,(THIS_FILE,
- "Error creating STUN socket for %.*s: %s",
- (int)sess->srv[sess->idx].slen,
- sess->srv[sess->idx].ptr, errmsg));
+ "Error creating STUN socket for %s: %s",
+ target, errmsg));
continue;
}
@@ -1186,19 +1269,20 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(sess->status, errmsg, sizeof(errmsg));
PJ_LOG(4,(THIS_FILE,
- "Error starting STUN socket for %.*s: %s",
- (int)sess->srv[sess->idx].slen,
- sess->srv[sess->idx].ptr, errmsg));
+ "Error starting STUN socket for %s: %s",
+ target, errmsg));
- pj_stun_sock_destroy(sess->stun_sock);
- sess->stun_sock = NULL;
+ if (sess->stun_sock) {
+ pj_stun_sock_destroy(sess->stun_sock);
+ sess->stun_sock = NULL;
+ }
continue;
}
/* Done for now, testing will resume/complete asynchronously in
* stun_sock_cb()
*/
- return;
+ goto on_return;
}
if (sess->idx >= sess->count) {
@@ -1207,6 +1291,9 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
sess->status = PJ_EUNKNOWN);
stun_resolve_complete(sess);
}
+
+on_return:
+ stun_resolve_dec_ref(sess);
}
@@ -1837,6 +1924,8 @@ static pj_status_t create_sip_udp_sock(int af,
pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
} else if (stun_srv.slen) {
+ pjstun_setting stun_opt;
+
/*
* STUN is specified, resolve the address with STUN.
*/
@@ -1846,10 +1935,13 @@ static pj_status_t create_sip_udp_sock(int af,
return PJ_EAFNOTSUP;
}
- status = pjstun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock,
- &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
- &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
- &p_pub_addr->ipv4);
+ pj_bzero(&stun_opt, sizeof(stun_opt));
+ stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
+ stun_opt.srv1 = stun_opt.srv2 = stun_srv;
+ stun_opt.port1 = stun_opt.port2 =
+ pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
+ status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
+ 1, &sock, &p_pub_addr->ipv4);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
pj_sock_close(sock);
@@ -1977,8 +2069,10 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
pjsua_transport_config config;
pjsip_tpfactory *tcp;
pjsip_tcp_transport_cfg tcp_cfg;
+ int af;
- pjsip_tcp_transport_cfg_default(&tcp_cfg, pj_AF_INET());
+ af = (type==PJSIP_TRANSPORT_TCP6) ? pj_AF_INET6() : pj_AF_INET();
+ pjsip_tcp_transport_cfg_default(&tcp_cfg, af);
/* Supply default config if it's not specified */
if (cfg == NULL) {
@@ -2028,14 +2122,15 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
#endif /* PJ_HAS_TCP */
#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
- } else if (type == PJSIP_TRANSPORT_TLS) {
+ } else if (type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_TLS6) {
/*
* Create TLS transport.
*/
pjsua_transport_config config;
pjsip_host_port a_name;
pjsip_tpfactory *tls;
- pj_sockaddr_in local_addr;
+ pj_sockaddr local_addr;
+ int af;
/* Supply default config if it's not specified */
if (cfg == NULL) {
@@ -2045,13 +2140,15 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
}
/* Init local address */
- pj_sockaddr_in_init(&local_addr, 0, 0);
+ af = (type==PJSIP_TRANSPORT_TLS) ? pj_AF_INET() : pj_AF_INET6();
+ pj_sockaddr_init(af, &local_addr, NULL, 0);
if (cfg->port)
- local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port);
+ pj_sockaddr_set_port(&local_addr, (pj_uint16_t)cfg->port);
if (cfg->bound_addr.slen) {
- status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr);
+ status = pj_sockaddr_set_str_addr(af, &local_addr,
+ &cfg->bound_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Unable to resolve transport bound address",
@@ -2065,9 +2162,9 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
if (cfg->public_addr.slen)
a_name.host = cfg->public_addr;
- status = pjsip_tls_transport_start(pjsua_var.endpt,
- &cfg->tls_setting,
- &local_addr, &a_name, 1, &tls);
+ status = pjsip_tls_transport_start2(pjsua_var.endpt,
+ &cfg->tls_setting,
+ &local_addr, &a_name, 1, &tls);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating SIP TLS listener",
status);
@@ -2087,7 +2184,7 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
}
/* Set transport state callback */
- if (pjsua_var.ua_cfg.cb.on_transport_state) {
+ {
pjsip_tp_state_callback tpcb;
pjsip_tpmgr *tpmgr;
@@ -2743,7 +2840,7 @@ pj_status_t normalize_route_uri(pj_pool_t *pool, pj_str_t *uri)
}
if (!PJSIP_URI_SCHEME_IS_SIP(uri_obj) &&
- !PJSIP_URI_SCHEME_IS_SIP(uri_obj))
+ !PJSIP_URI_SCHEME_IS_SIPS(uri_obj))
{
PJ_LOG(1,(THIS_FILE, "Route URI must be SIP URI: %.*s",
(int)uri->slen, uri->ptr));
@@ -2804,6 +2901,7 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
PJ_LOG(3,(THIS_FILE, "Dumping media transports:"));
for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
pjsua_call *call = &pjsua_var.calls[i];
+ pjsua_acc_config *acc_cfg;
pjmedia_transport *tp[PJSUA_MAX_CALL_MEDIA*2];
unsigned tp_cnt = 0;
unsigned j;
@@ -2829,6 +2927,8 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
}
}
+ acc_cfg = &pjsua_var.acc[call->acc_id].cfg;
+
/* Dump the media transports in this call */
for (j = 0; j < tp_cnt; ++j) {
pjmedia_transport_info tpinfo;
@@ -2837,7 +2937,7 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
pjmedia_transport_info_init(&tpinfo);
pjmedia_transport_get_info(tp[j], &tpinfo);
PJ_LOG(3,(THIS_FILE, " %s: %s",
- (pjsua_var.media_cfg.enable_ice ? "ICE" : "UDP"),
+ (acc_cfg->ice_cfg.enable_ice ? "ICE" : "UDP"),
pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name,
addr_buf,
sizeof(addr_buf), 3)));
diff --git a/pjsip/src/pjsua-lib/pjsua_dump.c b/pjsip/src/pjsua-lib/pjsua_dump.c
index 0b23a97..a24b71a 100644
--- a/pjsip/src/pjsua-lib/pjsua_dump.c
+++ b/pjsip/src/pjsua-lib/pjsua_dump.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_dump.c 4085 2012-04-25 07:45:22Z nanang $ */
+/* $Id: pjsua_dump.c 4300 2012-11-26 02:04:17Z ming $ */
/*
* Copyright (C) 2011-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -212,6 +212,10 @@ static unsigned dump_media_stat(const char *indent,
/* Dump media session */
+#if PJSUA_MEDIA_HAS_PJMEDIA || \
+ (PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO && \
+ PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT)
+
static void dump_media_session(const char *indent,
char *buf, unsigned maxlen,
pjsua_call *call)
@@ -858,6 +862,24 @@ static void dump_media_session(const char *indent,
}
}
+#else /* PJSUA_MEDIA_HAS_PJMEDIA ||
+ (PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO &&
+ PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT) */
+
+static void dump_media_session(const char *indent,
+ char *buf, unsigned maxlen,
+ pjsua_call *call)
+{
+ PJ_UNUSED_ARG(indent);
+ PJ_UNUSED_ARG(buf);
+ PJ_UNUSED_ARG(maxlen);
+ PJ_UNUSED_ARG(call);
+}
+
+#endif /* PJSUA_MEDIA_HAS_PJMEDIA ||
+ (PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO &&
+ PJSUA_THIRD_PARTY_STREAM_HAS_GET_STAT) */
+
/* Print call info */
void print_call(const char *title,
@@ -866,11 +888,12 @@ void print_call(const char *title,
{
int len;
pjsip_inv_session *inv = pjsua_var.calls[call_id].inv;
- pjsip_dialog *dlg = inv->dlg;
+ pjsip_dialog *dlg;
char userinfo[128];
/* Dump invite sesion info. */
+ dlg = (inv? inv->dlg: pjsua_var.calls[call_id].async_call.dlg);
len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo));
if (len < 0)
pj_ansi_strcpy(userinfo, "<--uri too long-->");
@@ -879,7 +902,8 @@ void print_call(const char *title,
len = pj_ansi_snprintf(buf, size, "%s[%s] %s",
title,
- pjsip_inv_state_name(inv->state),
+ pjsip_inv_state_name(inv? inv->state:
+ PJSIP_INV_STATE_DISCONNECTED),
userinfo);
if (len < 1 || len >= (int)size) {
pj_ansi_strcpy(buf, "<--uri too long-->");
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index 8bcb0da..27069a1 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_media.c 4182 2012-06-27 07:12:23Z ming $ */
+/* $Id: pjsua_media.c 4412 2013-03-05 03:12:32Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -165,9 +165,11 @@ pj_status_t pjsua_media_subsys_start(void)
#endif
/* Perform NAT detection */
- status = pjsua_detect_nat_type();
- if (status != PJ_SUCCESS) {
- PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed"));
+ if (pjsua_var.ua_cfg.stun_srv_cnt) {
+ status = pjsua_detect_nat_type();
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed"));
+ }
}
pj_log_pop_indent();
@@ -226,24 +228,33 @@ pj_status_t pjsua_media_subsys_destroy(unsigned flags)
* Create RTP and RTCP socket pair, and possibly resolve their public
* address via STUN.
*/
-static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
+static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
+ const pjsua_transport_config *cfg,
pjmedia_sock_info *skinfo)
{
enum {
RTP_RETRY = 100
};
int i;
- pj_sockaddr_in bound_addr;
- pj_sockaddr_in mapped_addr[2];
+ pj_bool_t use_ipv6;
+ int af;
+ pj_sockaddr bound_addr;
+ pj_sockaddr mapped_addr[2];
pj_status_t status = PJ_SUCCESS;
- char addr_buf[PJ_INET6_ADDRSTRLEN+2];
+ char addr_buf[PJ_INET6_ADDRSTRLEN+10];
pj_sock_t sock[2];
+ use_ipv6 = (pjsua_var.acc[call_med->call->acc_id].cfg.ipv6_media_use !=
+ PJSUA_IPV6_DISABLED);
+ af = use_ipv6 ? pj_AF_INET6() : pj_AF_INET();
+
/* Make sure STUN server resolution has completed */
- status = resolve_stun_server(PJ_TRUE);
- if (status != PJ_SUCCESS) {
- pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
- return status;
+ if (!use_ipv6 && pjsua_sip_acc_is_using_stun(call_med->call->acc_id)) {
+ status = resolve_stun_server(PJ_TRUE);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
+ return status;
+ }
}
if (next_rtp_port == 0)
@@ -255,9 +266,9 @@ 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;
+ pj_sockaddr_init(af, &bound_addr, NULL, 0);
if (cfg->bound_addr.slen) {
- status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr);
+ status = pj_sockaddr_set_str_addr(af, &bound_addr, &cfg->bound_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",
status);
@@ -269,7 +280,7 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) {
/* Create RTP socket. */
- status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]);
+ status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[0]);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "socket() error", status);
return status;
@@ -281,8 +292,9 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
2, THIS_FILE, "RTP socket");
/* Bind RTP socket */
- status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),
- next_rtp_port);
+ pj_sockaddr_set_port(&bound_addr, next_rtp_port);
+ status=pj_sock_bind(sock[0], &bound_addr,
+ pj_sockaddr_get_len(&bound_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock[0]);
sock[0] = PJ_INVALID_SOCKET;
@@ -290,7 +302,7 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
}
/* Create RTCP socket. */
- status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]);
+ status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[1]);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "socket() error", status);
pj_sock_close(sock[0]);
@@ -303,8 +315,9 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
2, THIS_FILE, "RTCP socket");
/* Bind RTCP socket */
- status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),
- (pj_uint16_t)(next_rtp_port+1));
+ pj_sockaddr_set_port(&bound_addr, (pj_uint16_t)(next_rtp_port+1));
+ status=pj_sock_bind(sock[1], &bound_addr,
+ pj_sockaddr_get_len(&bound_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock[0]);
sock[0] = PJ_INVALID_SOCKET;
@@ -318,26 +331,55 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
* If we're configured to use STUN, then find out the mapped address,
* and make sure that the mapped RTCP port is adjacent with the RTP.
*/
- if (pjsua_var.stun_srv.addr.sa_family != 0) {
+ if (!use_ipv6 && pjsua_sip_acc_is_using_stun(call_med->call->acc_id) &&
+ pjsua_var.stun_srv.addr.sa_family != 0)
+ {
char ip_addr[32];
pj_str_t stun_srv;
+ pj_sockaddr_in resolved_addr[2];
+ pjstun_setting stun_opt;
pj_ansi_strcpy(ip_addr,
pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
stun_srv = pj_str(ip_addr);
- status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock,
- &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
- &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port),
- mapped_addr);
+ pj_bzero(&stun_opt, sizeof(stun_opt));
+ stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
+ stun_opt.srv1 = stun_opt.srv2 = stun_srv;
+ stun_opt.port1 = stun_opt.port2 =
+ pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
+ status=pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
+ 2, sock, resolved_addr);
+#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
+ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
+ /* Handle EPIPE (Broken Pipe) error, which happens on UDP socket
+ * after app wakes up from suspended state. In this case, simply
+ * just retry.
+ * P.S.: The magic status is PJ_STATUS_FROM_OS(EPIPE)
+ */
+ if (status == 120032) {
+ PJ_LOG(4,(THIS_FILE, "Got EPIPE error, retrying.."));
+ pj_sock_close(sock[0]);
+ sock[0] = PJ_INVALID_SOCKET;
+
+ pj_sock_close(sock[1]);
+ sock[1] = PJ_INVALID_SOCKET;
+
+ continue;
+ }
+ else
+#endif
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STUN resolve error", status);
goto on_error;
}
+ pj_sockaddr_cp(&mapped_addr[0], &resolved_addr[0]);
+ pj_sockaddr_cp(&mapped_addr[1], &resolved_addr[1]);
+
#if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
- if (pj_ntohs(mapped_addr[1].sin_port) ==
- pj_ntohs(mapped_addr[0].sin_port)+1)
+ if (pj_sockaddr_get_port(&mapped_addr[1]) ==
+ pj_sockaddr_get_port(&mapped_addr[0])+1)
{
/* Success! */
break;
@@ -349,14 +391,14 @@ 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 (pj_ntohs(mapped_addr[1].sin_port) !=
- pj_ntohs(mapped_addr[0].sin_port)+1)
+ if (pj_sockaddr_get_port(&mapped_addr[1]) !=
+ pj_sockaddr_get_port(&mapped_addr[0])+1)
{
PJ_LOG(4,(THIS_FILE,
"Note: STUN mapped RTCP port %d is not adjacent"
" to RTP port %d",
- pj_ntohs(mapped_addr[1].sin_port),
- pj_ntohs(mapped_addr[0].sin_port)));
+ pj_sockaddr_get_port(&mapped_addr[1]),
+ pj_sockaddr_get_port(&mapped_addr[0])));
}
/* Success! */
break;
@@ -364,13 +406,13 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
} else if (cfg->public_addr.slen) {
- status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr,
- (pj_uint16_t)next_rtp_port);
+ status = pj_sockaddr_init(af, &mapped_addr[0], &cfg->public_addr,
+ (pj_uint16_t)next_rtp_port);
if (status != PJ_SUCCESS)
goto on_error;
- status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr,
- (pj_uint16_t)(next_rtp_port+1));
+ status = pj_sockaddr_init(af, &mapped_addr[1], &cfg->public_addr,
+ (pj_uint16_t)(next_rtp_port+1));
if (status != PJ_SUCCESS)
goto on_error;
@@ -378,24 +420,24 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
} else {
- if (bound_addr.sin_addr.s_addr == 0) {
+ if (!pj_sockaddr_has_addr(&bound_addr)) {
pj_sockaddr addr;
/* Get local IP address. */
- status = pj_gethostip(pj_AF_INET(), &addr);
+ status = pj_gethostip(af, &addr);
if (status != PJ_SUCCESS)
goto on_error;
- bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr;
+ pj_sockaddr_copy_addr(&bound_addr, &addr);
}
for (i=0; i<2; ++i) {
- pj_sockaddr_in_init(&mapped_addr[i], NULL, 0);
- mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr;
+ pj_sockaddr_init(af, &mapped_addr[i], NULL, 0);
+ pj_sockaddr_copy_addr(&mapped_addr[i], &bound_addr);
+ pj_sockaddr_set_port(&mapped_addr[i],
+ (pj_uint16_t)(next_rtp_port+i));
}
- mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port);
- mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1));
break;
}
}
@@ -408,12 +450,10 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg,
skinfo->rtp_sock = sock[0];
- pj_memcpy(&skinfo->rtp_addr_name,
- &mapped_addr[0], sizeof(pj_sockaddr_in));
+ pj_sockaddr_cp(&skinfo->rtp_addr_name, &mapped_addr[0]);
skinfo->rtcp_sock = sock[1];
- pj_memcpy(&skinfo->rtcp_addr_name,
- &mapped_addr[1], sizeof(pj_sockaddr_in));
+ pj_sockaddr_cp(&skinfo->rtcp_addr_name, &mapped_addr[1]);
PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",
pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,
@@ -440,7 +480,7 @@ static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg,
pjmedia_sock_info skinfo;
pj_status_t status;
- status = create_rtp_rtcp_sock(cfg, &skinfo);
+ status = create_rtp_rtcp_sock(call_med, cfg, &skinfo);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket",
status);
@@ -512,21 +552,59 @@ on_error:
}
#endif
-static void med_tp_timer_cb(void *user_data)
+/* Deferred callback to notify ICE init complete */
+static void ice_init_complete_cb(void *user_data)
{
pjsua_call_media *call_med = (pjsua_call_media*)user_data;
- pjsua_call *call = NULL;
- pjsip_dialog *dlg = NULL;
- acquire_call("med_tp_timer_cb", call_med->call->index, &call, &dlg);
+ if (call_med->call == NULL)
+ return;
+ /* No need to acquire_call() if we only change the tp_ready flag
+ * (i.e. transport is being created synchronously). Otherwise
+ * calling acquire_call() here may cause deadlock. See
+ * https://trac.pjsip.org/repos/ticket/1578
+ */
call_med->tp_ready = call_med->tp_result;
- if (call_med->med_create_cb)
+
+ if (call_med->med_create_cb) {
+ pjsua_call *call = NULL;
+ pjsip_dialog *dlg = NULL;
+
+ if (acquire_call("ice_init_complete_cb", call_med->call->index,
+ &call, &dlg) != PJ_SUCCESS)
+ {
+ /* Call have been terminated */
+ return;
+ }
+
(*call_med->med_create_cb)(call_med, call_med->tp_ready,
call_med->call->secure_level, NULL);
+ if (dlg)
+ pjsip_dlg_dec_lock(dlg);
+ }
+}
+
+/* Deferred callback to notify ICE negotiation failure */
+static void ice_failed_nego_cb(void *user_data)
+{
+ int call_id = (int)(long)user_data;
+ pjsua_call *call = NULL;
+ pjsip_dialog *dlg = NULL;
+
+ if (acquire_call("ice_failed_nego_cb", call_id,
+ &call, &dlg) != PJ_SUCCESS)
+ {
+ /* Call have been terminated */
+ return;
+ }
+
+ pjsua_var.ua_cfg.cb.on_call_media_state(call_id);
+
if (dlg)
- pjsip_dlg_dec_lock(dlg);
+ pjsip_dlg_dec_lock(dlg);
+
}
/* This callback is called when ICE negotiation completes */
@@ -535,73 +613,43 @@ static void on_ice_complete(pjmedia_transport *tp,
pj_status_t result)
{
pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data;
+ pjsua_call *call;
if (!call_med)
return;
+ call = call_med->call;
+
switch (op) {
case PJ_ICE_STRANS_OP_INIT:
call_med->tp_result = result;
- pjsua_schedule_timer2(&med_tp_timer_cb, call_med, 1);
+ pjsua_schedule_timer2(&ice_init_complete_cb, call_med, 1);
break;
case PJ_ICE_STRANS_OP_NEGOTIATION:
- if (result != PJ_SUCCESS) {
+ if (result == PJ_SUCCESS) {
+ /* Update RTP address */
+ pjmedia_transport_info tpinfo;
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(call_med->tp, &tpinfo);
+ pj_sockaddr_cp(&call_med->rtp_addr, &tpinfo.sock_info.rtp_addr_name);
+ } else {
call_med->state = PJSUA_CALL_MEDIA_ERROR;
call_med->dir = PJMEDIA_DIR_NONE;
-
- if (call_med->call && pjsua_var.ua_cfg.cb.on_call_media_state) {
- pjsua_var.ua_cfg.cb.on_call_media_state(call_med->call->index);
- }
- } else if (call_med->call) {
- /* Send UPDATE if default transport address is different than
- * what was advertised (ticket #881)
- */
- pjmedia_transport_info tpinfo;
- pjmedia_ice_transport_info *ii = NULL;
- unsigned i;
-
- pjmedia_transport_info_init(&tpinfo);
- pjmedia_transport_get_info(tp, &tpinfo);
- for (i=0; i<tpinfo.specific_info_cnt; ++i) {
- if (tpinfo.spc_info[i].type==PJMEDIA_TRANSPORT_TYPE_ICE) {
- ii = (pjmedia_ice_transport_info*)
- tpinfo.spc_info[i].buffer;
- break;
- }
- }
-
- if (ii && ii->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
- pj_sockaddr_cmp(&tpinfo.sock_info.rtp_addr_name,
- &call_med->rtp_addr))
- {
- pj_bool_t use_update;
- const pj_str_t STR_UPDATE = { "UPDATE", 6 };
- pjsip_dialog_cap_status support_update;
- pjsip_dialog *dlg;
-
- dlg = call_med->call->inv->dlg;
- support_update = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_ALLOW,
- NULL, &STR_UPDATE);
- use_update = (support_update == PJSIP_DIALOG_CAP_SUPPORTED);
-
- PJ_LOG(4,(THIS_FILE,
- "ICE default transport address has changed for "
- "call %d, sending %s",
- call_med->call->index,
- (use_update ? "UPDATE" : "re-INVITE")));
-
- if (use_update)
- pjsua_call_update(call_med->call->index, 0, NULL);
- else
- pjsua_call_reinvite(call_med->call->index, 0, NULL);
+ if (call && pjsua_var.ua_cfg.cb.on_call_media_state) {
+ /* Defer the callback to a timer */
+ pjsua_schedule_timer2(&ice_failed_nego_cb,
+ (void*)(long)call->index, 1);
}
- }
+ }
+ /* Check if default ICE transport address is changed */
+ call->reinv_ice_sent = PJ_FALSE;
+ pjsua_call_schedule_reinvite_check(call, 0);
break;
case PJ_ICE_STRANS_OP_KEEP_ALIVE:
if (result != PJ_SUCCESS) {
PJ_PERROR(4,(THIS_FILE, result,
"ICE keep alive failure for transport %d:%d",
- call_med->call->index, call_med->idx));
+ call->index, call_med->idx));
}
if (pjsua_var.ua_cfg.cb.on_call_media_transport_state) {
pjsua_med_tp_state_info info;
@@ -612,10 +660,10 @@ static void on_ice_complete(pjmedia_transport *tp,
info.status = result;
info.ext_info = &op;
(*pjsua_var.ua_cfg.cb.on_call_media_transport_state)(
- call_med->call->index, &info);
+ call->index, &info);
}
if (pjsua_var.ua_cfg.cb.on_ice_transport_error) {
- pjsua_call_id id = call_med->call->index;
+ pjsua_call_id id = call->index;
(*pjsua_var.ua_cfg.cb.on_ice_transport_error)(id, op, result,
NULL);
}
@@ -657,12 +705,15 @@ static pj_status_t create_ice_media_transport(
pj_bool_t async)
{
char stunip[PJ_INET6_ADDRSTRLEN];
+ pjsua_acc_config *acc_cfg;
pj_ice_strans_cfg ice_cfg;
pjmedia_ice_cb ice_cb;
char name[32];
unsigned comp_cnt;
pj_status_t status;
+ acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg;
+
/* Make sure STUN server resolution has completed */
status = resolve_stun_server(PJ_TRUE);
if (status != PJ_SUCCESS) {
@@ -679,7 +730,7 @@ static pj_status_t create_ice_media_transport(
ice_cfg.af = pj_AF_INET();
ice_cfg.resolver = pjsua_var.resolver;
- ice_cfg.opt = pjsua_var.media_cfg.ice_opt;
+ ice_cfg.opt = acc_cfg->ice_cfg.ice_opt;
/* Configure STUN settings */
if (pj_sockaddr_has_addr(&pjsua_var.stun_srv)) {
@@ -687,8 +738,16 @@ static pj_status_t create_ice_media_transport(
ice_cfg.stun.server = pj_str(stunip);
ice_cfg.stun.port = pj_sockaddr_get_port(&pjsua_var.stun_srv);
}
- if (pjsua_var.media_cfg.ice_max_host_cands >= 0)
- ice_cfg.stun.max_host_cands = pjsua_var.media_cfg.ice_max_host_cands;
+ if (acc_cfg->ice_cfg.ice_max_host_cands >= 0)
+ ice_cfg.stun.max_host_cands = acc_cfg->ice_cfg.ice_max_host_cands;
+
+ /* Copy binding port setting to STUN setting */
+ pj_sockaddr_init(ice_cfg.af, &ice_cfg.stun.cfg.bound_addr,
+ &cfg->bound_addr, (pj_uint16_t)cfg->port);
+ ice_cfg.stun.cfg.port_range = (pj_uint16_t)cfg->port_range;
+ if (cfg->port != 0 && ice_cfg.stun.cfg.port_range == 0)
+ ice_cfg.stun.cfg.port_range =
+ (pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
/* Copy QoS setting to STUN setting */
ice_cfg.stun.cfg.qos_type = cfg->qos_type;
@@ -696,8 +755,8 @@ static pj_status_t create_ice_media_transport(
sizeof(cfg->qos_params));
/* Configure TURN settings */
- if (pjsua_var.media_cfg.enable_turn) {
- status = parse_host_port(&pjsua_var.media_cfg.turn_server,
+ if (acc_cfg->turn_cfg.enable_turn) {
+ status = parse_host_port(&acc_cfg->turn_cfg.turn_server,
&ice_cfg.turn.server,
&ice_cfg.turn.port);
if (status != PJ_SUCCESS || ice_cfg.turn.server.slen == 0) {
@@ -706,24 +765,36 @@ static pj_status_t create_ice_media_transport(
}
if (ice_cfg.turn.port == 0)
ice_cfg.turn.port = 3479;
- ice_cfg.turn.conn_type = pjsua_var.media_cfg.turn_conn_type;
+ ice_cfg.turn.conn_type = acc_cfg->turn_cfg.turn_conn_type;
pj_memcpy(&ice_cfg.turn.auth_cred,
- &pjsua_var.media_cfg.turn_auth_cred,
+ &acc_cfg->turn_cfg.turn_auth_cred,
sizeof(ice_cfg.turn.auth_cred));
/* Copy QoS setting to TURN setting */
ice_cfg.turn.cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.turn.cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
+
+ /* Copy binding port setting to TURN setting */
+ pj_sockaddr_init(ice_cfg.af, &ice_cfg.turn.cfg.bound_addr,
+ &cfg->bound_addr, (pj_uint16_t)cfg->port);
+ ice_cfg.turn.cfg.port_range = (pj_uint16_t)cfg->port_range;
+ if (cfg->port != 0 && ice_cfg.turn.cfg.port_range == 0)
+ ice_cfg.turn.cfg.port_range =
+ (pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
}
+ /* Configure packet size for STUN and TURN sockets */
+ ice_cfg.stun.cfg.max_pkt_size = PJMEDIA_MAX_MRU;
+ ice_cfg.turn.cfg.max_pkt_size = PJMEDIA_MAX_MRU;
+
pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb));
ice_cb.on_ice_complete = &on_ice_complete;
pj_ansi_snprintf(name, sizeof(name), "icetp%02d", call_med->idx);
call_med->tp_ready = PJ_EPENDING;
comp_cnt = 1;
- if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp)
+ if (PJMEDIA_ADVERTISE_RTCP && !acc_cfg->ice_cfg.ice_no_rtcp)
++comp_cnt;
status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt,
@@ -761,7 +832,7 @@ static pj_status_t create_ice_media_transport(
pjmedia_transport_simulate_lost(call_med->tp, PJMEDIA_DIR_DECODING,
pjsua_var.media_cfg.rx_drop_pct);
-
+
return PJ_SUCCESS;
on_error:
@@ -851,7 +922,7 @@ PJ_DEF(pj_status_t) pjsua_media_transports_create(
pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg);
/* Create the transports */
- if (pjsua_var.media_cfg.enable_ice) {
+ if (pjsua_var.ice_cfg.enable_ice) {
status = create_ice_media_transports(&cfg);
} else {
status = create_udp_media_transports(&cfg);
@@ -1237,7 +1308,7 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_CREATING);
- if (pjsua_var.media_cfg.enable_ice) {
+ if (pjsua_var.acc[call_med->call->acc_id].cfg.ice_cfg.enable_ice) {
status = create_ice_media_transport(tcfg, call_med, async);
if (async && status == PJ_EPENDING) {
/* We will resume call media initialization in the
@@ -1245,7 +1316,7 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
*/
call_med->med_create_cb = &call_media_init_cb;
call_med->med_init_cb = cb;
-
+
return PJ_EPENDING;
}
} else {
@@ -1344,7 +1415,7 @@ static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
}
if (call_med->use_custom_med_tp) {
- unsigned custom_med_tp_flags = 0;
+ unsigned custom_med_tp_flags = PJSUA_MED_TP_CLOSE_MEMBER;
/* Use custom media transport returned by the application */
call_med->tp =
@@ -1388,12 +1459,12 @@ on_return:
/* Clean up media transports in provisional media that is not used
* by call media.
*/
-void pjsua_media_prov_clean_up(pjsua_call_id call_id)
+static void media_prov_clean_up(pjsua_call_id call_id, int idx)
{
pjsua_call *call = &pjsua_var.calls[call_id];
unsigned i;
- for (i = 0; i < call->med_prov_cnt; ++i) {
+ for (i = idx; i < call->med_prov_cnt; ++i) {
pjsua_call_media *call_med = &call->media_prov[i];
unsigned j;
pj_bool_t used = PJ_FALSE;
@@ -1420,6 +1491,11 @@ void pjsua_media_prov_clean_up(pjsua_call_id call_id)
}
}
+void pjsua_media_prov_clean_up(pjsua_call_id call_id)
+{
+ media_prov_clean_up(call_id, 0);
+}
+
pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
pjsip_role_e role,
@@ -1452,8 +1528,10 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
* (e.g. in reinvites, updates, etc).
*/
- if (pjsua_get_state() != PJSUA_STATE_RUNNING)
+ if (pjsua_get_state() != PJSUA_STATE_RUNNING) {
+ if (sip_err_code) *sip_err_code = PJSIP_SC_SERVICE_UNAVAILABLE;
return PJ_EBUSY;
+ }
if (async) {
pj_pool_t *tmppool = (call->inv? call->inv->pool_prov:
@@ -1831,6 +1909,8 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
if (rem_sdp && mi >= rem_sdp->media_count) {
/* Remote might have removed some media lines. */
+ media_prov_clean_up(call->index, rem_sdp->media_count);
+ call->med_prov_cnt = rem_sdp->media_count;
break;
}
@@ -1848,10 +1928,6 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
m->desc.transport = pj_str("RTP/AVP");
m->desc.fmt_count = 1;
- m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
- m->conn->net_type = pj_str("IN");
- m->conn->addr_type = pj_str("IP4");
- m->conn->addr = pj_str("127.0.0.1");
switch (call_med->type) {
case PJMEDIA_TYPE_AUDIO:
@@ -1881,6 +1957,24 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
}
}
+ /* Add connection line, if none */
+ if (m->conn == NULL && sdp->conn == NULL) {
+ pj_bool_t use_ipv6;
+
+ use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
+ PJSUA_IPV6_DISABLED);
+
+ m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
+ m->conn->net_type = pj_str("IN");
+ if (use_ipv6) {
+ m->conn->addr_type = pj_str("IP6");
+ m->conn->addr = pj_str("::1");
+ } else {
+ m->conn->addr_type = pj_str("IP4");
+ m->conn->addr = pj_str("127.0.0.1");
+ }
+ }
+
sdp->media[sdp->media_count++] = m;
continue;
}
@@ -1919,12 +2013,14 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
return status;
}
+#if PJSUA_SDP_SESS_HAS_CONN
/* Copy c= line of the first media to session level,
* if there's none.
*/
if (sdp->conn == NULL) {
sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn);
}
+#endif
/* Find media bandwidth info */
@@ -2049,63 +2145,73 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
}
-static void stop_media_session(pjsua_call_id call_id)
+static void stop_media_stream(pjsua_call *call, unsigned med_idx)
{
- pjsua_call *call = &pjsua_var.calls[call_id];
- unsigned mi;
+ pjsua_call_media *call_med = &call->media[med_idx];
- pj_log_push_indent();
+ /* Check if stream does not exist */
+ if (med_idx >= call->med_cnt)
+ return;
- for (mi=0; mi<call->med_cnt; ++mi) {
- pjsua_call_media *call_med = &call->media[mi];
+ pj_log_push_indent();
- if (call_med->type == PJMEDIA_TYPE_AUDIO) {
- pjsua_aud_stop_stream(call_med);
- }
+ if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+ pjsua_aud_stop_stream(call_med);
+ }
#if PJMEDIA_HAS_VIDEO
- else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
- pjsua_vid_stop_stream(call_med);
- }
+ else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+ pjsua_vid_stop_stream(call_med);
+ }
#endif
- PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed",
- call_id, mi));
- call_med->prev_state = call_med->state;
- call_med->state = PJSUA_CALL_MEDIA_NONE;
+ PJ_LOG(4,(THIS_FILE, "Media stream call%02d:%d is destroyed",
+ call->index, med_idx));
+ call_med->prev_state = call_med->state;
+ call_med->state = PJSUA_CALL_MEDIA_NONE;
- /* Try to sync recent changes to provisional media */
- if (mi<call->med_prov_cnt && call->media_prov[mi].tp==call_med->tp)
- {
- pjsua_call_media *prov_med = &call->media_prov[mi];
+ /* Try to sync recent changes to provisional media */
+ if (med_idx < call->med_prov_cnt &&
+ call->media_prov[med_idx].tp == call_med->tp)
+ {
+ pjsua_call_media *prov_med = &call->media_prov[med_idx];
- /* Media state */
- prov_med->prev_state = call_med->prev_state;
- prov_med->state = call_med->state;
+ /* Media state */
+ prov_med->prev_state = call_med->prev_state;
+ prov_med->state = call_med->state;
- /* RTP seq/ts */
- prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
- prov_med->rtp_tx_seq = call_med->rtp_tx_seq;
- prov_med->rtp_tx_ts = call_med->rtp_tx_ts;
+ /* RTP seq/ts */
+ prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
+ prov_med->rtp_tx_seq = call_med->rtp_tx_seq;
+ prov_med->rtp_tx_ts = call_med->rtp_tx_ts;
- /* Stream */
- if (call_med->type == PJMEDIA_TYPE_AUDIO) {
- prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
- prov_med->strm.a.stream = call_med->strm.a.stream;
- }
+ /* Stream */
+ if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+ prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
+ prov_med->strm.a.stream = call_med->strm.a.stream;
+ }
#if PJMEDIA_HAS_VIDEO
- else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
- prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
- prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
- prov_med->strm.v.stream = call_med->strm.v.stream;
- }
-#endif
+ else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+ prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
+ prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
+ prov_med->strm.v.stream = call_med->strm.v.stream;
}
+#endif
}
pj_log_pop_indent();
}
+static void stop_media_session(pjsua_call_id call_id)
+{
+ pjsua_call *call = &pjsua_var.calls[call_id];
+ unsigned mi;
+
+ for (mi=0; mi<call->med_cnt; ++mi) {
+ stop_media_stream(call, mi);
+ }
+}
+
pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
{
pjsua_call *call = &pjsua_var.calls[call_id];
@@ -2153,6 +2259,197 @@ pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
}
+/* Match codec fmtp. This will compare the values and the order. */
+static pj_bool_t match_codec_fmtp(const pjmedia_codec_fmtp *fmtp1,
+ const pjmedia_codec_fmtp *fmtp2)
+{
+ unsigned i;
+
+ if (fmtp1->cnt != fmtp2->cnt)
+ return PJ_FALSE;
+
+ for (i = 0; i < fmtp1->cnt; ++i) {
+ if (pj_stricmp(&fmtp1->param[i].name, &fmtp2->param[i].name))
+ return PJ_FALSE;
+ if (pj_stricmp(&fmtp1->param[i].val, &fmtp2->param[i].val))
+ return PJ_FALSE;
+ }
+
+ return PJ_TRUE;
+}
+
+#if PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO
+
+static pj_bool_t is_ice_running(pjmedia_transport *tp)
+{
+ pjmedia_transport_info tpinfo;
+ pjmedia_ice_transport_info *ice_info;
+
+ pjmedia_transport_info_init(&tpinfo);
+ pjmedia_transport_get_info(tp, &tpinfo);
+ ice_info = (pjmedia_ice_transport_info*)
+ pjmedia_transport_info_get_spc_info(&tpinfo,
+ PJMEDIA_TRANSPORT_TYPE_ICE);
+ return (ice_info && ice_info->sess_state == PJ_ICE_STRANS_STATE_RUNNING);
+}
+
+
+static pj_bool_t is_media_changed(const pjsua_call *call,
+ unsigned med_idx,
+ const pjsua_stream_info *new_si_)
+{
+ const pjsua_call_media *call_med = &call->media[med_idx];
+
+ /* Check for newly added media */
+ if (med_idx >= call->med_cnt)
+ return PJ_TRUE;
+
+ /* Compare media type */
+ if (call_med->type != new_si_->type)
+ return PJ_TRUE;
+
+ /* Audio update checks */
+ if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+ pjmedia_stream_info the_old_si;
+ const pjmedia_stream_info *old_si = NULL;
+ const pjmedia_stream_info *new_si = &new_si_->info.aud;
+ const pjmedia_codec_info *old_ci = NULL;
+ const pjmedia_codec_info *new_ci = &new_si->fmt;
+ const pjmedia_codec_param *old_cp = NULL;
+ const pjmedia_codec_param *new_cp = new_si->param;
+
+ /* Compare media direction */
+ if (call_med->dir != new_si->dir)
+ return PJ_TRUE;
+
+ /* Get current active stream info */
+ if (call_med->strm.a.stream) {
+ pjmedia_stream_get_info(call_med->strm.a.stream, &the_old_si);
+ old_si = &the_old_si;
+ old_ci = &old_si->fmt;
+ old_cp = old_si->param;
+ } else {
+ /* The stream is inactive. */
+ return (new_si->dir != PJMEDIA_DIR_NONE);
+ }
+
+ /* Compare remote RTP address. If ICE is running, change in default
+ * address can happen after negotiation, this can be handled
+ * internally by ICE and does not need to cause media restart.
+ */
+ if (!is_ice_running(call_med->tp) &&
+ pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
+ {
+ return PJ_TRUE;
+ }
+
+ /* Compare codec info */
+ if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
+ old_ci->clock_rate != new_ci->clock_rate ||
+ old_ci->channel_cnt != new_ci->channel_cnt ||
+ old_si->rx_pt != new_si->rx_pt ||
+ old_si->tx_pt != new_si->tx_pt ||
+ old_si->rx_event_pt != new_si->tx_event_pt ||
+ old_si->tx_event_pt != new_si->tx_event_pt)
+ {
+ return PJ_TRUE;
+ }
+
+ /* Compare codec param */
+ if (old_cp->setting.frm_per_pkt != new_cp->setting.frm_per_pkt ||
+ old_cp->setting.vad != new_cp->setting.vad ||
+ old_cp->setting.cng != new_cp->setting.cng ||
+ old_cp->setting.plc != new_cp->setting.plc ||
+ old_cp->setting.penh != new_cp->setting.penh ||
+ !match_codec_fmtp(&old_cp->setting.dec_fmtp,
+ &new_cp->setting.dec_fmtp) ||
+ !match_codec_fmtp(&old_cp->setting.enc_fmtp,
+ &new_cp->setting.enc_fmtp))
+ {
+ return PJ_TRUE;
+ }
+ }
+
+#if PJMEDIA_HAS_VIDEO
+ else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+ pjmedia_vid_stream_info the_old_si;
+ const pjmedia_vid_stream_info *old_si = NULL;
+ const pjmedia_vid_stream_info *new_si = &new_si_->info.vid;
+ const pjmedia_vid_codec_info *old_ci = NULL;
+ const pjmedia_vid_codec_info *new_ci = &new_si->codec_info;
+ const pjmedia_vid_codec_param *old_cp = NULL;
+ const pjmedia_vid_codec_param *new_cp = new_si->codec_param;
+
+ /* Compare media direction */
+ if (call_med->dir != new_si->dir)
+ return PJ_TRUE;
+
+ /* Get current active stream info */
+ if (call_med->strm.v.stream) {
+ pjmedia_vid_stream_get_info(call_med->strm.v.stream, &the_old_si);
+ old_si = &the_old_si;
+ old_ci = &old_si->codec_info;
+ old_cp = old_si->codec_param;
+ } else {
+ /* The stream is inactive. */
+ return (new_si->dir != PJMEDIA_DIR_NONE);
+ }
+
+ /* Compare remote RTP address. If ICE is running, change in default
+ * address can happen after negotiation, this can be handled
+ * internally by ICE and does not need to cause media restart.
+ */
+ if (!is_ice_running(call_med->tp) &&
+ pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
+ {
+ return PJ_TRUE;
+ }
+
+ /* Compare codec info */
+ if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) ||
+ old_si->rx_pt != new_si->rx_pt ||
+ old_si->tx_pt != new_si->tx_pt)
+ {
+ return PJ_TRUE;
+ }
+
+ /* Compare codec param */
+ if (/* old_cp->enc_mtu != new_cp->enc_mtu || */
+ pj_memcmp(&old_cp->enc_fmt.det, &new_cp->enc_fmt.det,
+ sizeof(pjmedia_video_format_detail)) ||
+ !match_codec_fmtp(&old_cp->dec_fmtp, &new_cp->dec_fmtp) ||
+ !match_codec_fmtp(&old_cp->enc_fmtp, &new_cp->enc_fmtp))
+ {
+ return PJ_TRUE;
+ }
+ }
+
+#endif
+
+ else {
+ /* Just return PJ_TRUE for other media type */
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+#else /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
+
+static pj_bool_t is_media_changed(const pjsua_call *call,
+ unsigned med_idx,
+ const pjsua_stream_info *new_si_)
+{
+ PJ_UNUSED_ARG(call);
+ PJ_UNUSED_ARG(med_idx);
+ PJ_UNUSED_ARG(new_si_);
+ /* Always assume that media has been changed */
+ return PJ_TRUE;
+}
+
+#endif /* PJSUA_MEDIA_HAS_PJMEDIA || PJSUA_THIRD_PARTY_STREAM_HAS_GET_INFO */
+
+
pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
const pjmedia_sdp_session *local_sdp,
const pjmedia_sdp_session *remote_sdp)
@@ -2181,7 +2478,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
pj_log_push_indent();
/* Destroy existing media session, if any. */
- stop_media_session(call->index);
+ //stop_media_session(call->index);
/* Call media count must be at least equal to SDP media. Note that
* it may not be equal when remote removed any SDP media line.
@@ -2235,6 +2532,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* Process each media stream */
for (mi=0; mi < call->med_prov_cnt; ++mi) {
pjsua_call_media *call_med = &call->media_prov[mi];
+ pj_bool_t media_changed = PJ_FALSE;
if (mi >= local_sdp->media_count ||
mi >= remote_sdp->media_count)
@@ -2242,8 +2540,12 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* This may happen when remote removed any SDP media lines in
* its re-offer.
*/
+
+ /* Stop stream */
+ stop_media_stream(call, mi);
+
+ /* Close the media transport */
if (call_med->tp) {
- /* Close the media transport */
pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
pjmedia_transport_close(call_med->tp);
call_med->tp = call_med->tp_orig = NULL;
@@ -2258,11 +2560,14 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
#endif
}
+ /* Apply media update action */
if (call_med->type==PJMEDIA_TYPE_AUDIO) {
pjmedia_stream_info the_si, *si = &the_si;
+ pjsua_stream_info stream_info;
- status = pjmedia_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt,
- local_sdp, remote_sdp, mi);
+ status = pjmedia_stream_info_from_sdp(
+ si, tmp_pool, pjsua_var.med_endpt,
+ local_sdp, remote_sdp, mi);
if (status != PJ_SUCCESS) {
PJ_PERROR(1,(THIS_FILE, status,
"pjmedia_stream_info_from_sdp() failed "
@@ -2271,14 +2576,43 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
continue;
}
+ /* Override ptime, if this option is specified. */
+ if (pjsua_var.media_cfg.ptime != 0) {
+ si->param->setting.frm_per_pkt = (pj_uint8_t)
+ (pjsua_var.media_cfg.ptime / si->param->info.frm_ptime);
+ if (si->param->setting.frm_per_pkt == 0)
+ si->param->setting.frm_per_pkt = 1;
+ }
+
+ /* Disable VAD, if this option is specified. */
+ if (pjsua_var.media_cfg.no_vad) {
+ si->param->setting.vad = 0;
+ }
+
+ /* Check if this media is changed */
+ stream_info.type = PJMEDIA_TYPE_AUDIO;
+ stream_info.info.aud = the_si;
+ if (pjsua_var.media_cfg.no_smart_media_update ||
+ is_media_changed(call, mi, &stream_info))
+ {
+ media_changed = PJ_TRUE;
+ /* Stop the media */
+ stop_media_stream(call, mi);
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (audio) unchanged.",
+ call_id, mi));
+ }
+
/* Check if no media is active */
if (si->dir == PJMEDIA_DIR_NONE) {
+
/* Update call media state and direction */
call_med->state = PJSUA_CALL_MEDIA_NONE;
call_med->dir = PJMEDIA_DIR_NONE;
} else {
pjmedia_transport_info tp_info;
+ pjmedia_srtp_info *srtp_info;
/* Start/restart media transport based on info in SDP */
status = pjmedia_transport_media_start(call_med->tp,
@@ -2297,17 +2631,24 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* Get remote SRTP usage policy */
pjmedia_transport_info_init(&tp_info);
pjmedia_transport_get_info(call_med->tp, &tp_info);
- if (tp_info.specific_info_cnt > 0) {
- unsigned i;
- for (i = 0; i < tp_info.specific_info_cnt; ++i) {
- if (tp_info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_SRTP)
- {
- pjmedia_srtp_info *srtp_info =
- (pjmedia_srtp_info*) tp_info.spc_info[i].buffer;
-
- call_med->rem_srtp_use = srtp_info->peer_use;
- break;
- }
+ srtp_info = (pjmedia_srtp_info*)
+ pjmedia_transport_info_get_spc_info(
+ &tp_info, PJMEDIA_TRANSPORT_TYPE_SRTP);
+ if (srtp_info) {
+ call_med->rem_srtp_use = srtp_info->peer_use;
+ }
+
+ /* Update audio channel */
+ if (media_changed) {
+ status = pjsua_aud_channel_update(call_med,
+ call->inv->pool, si,
+ local_sdp, remote_sdp);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "pjsua_aud_channel_update() failed "
+ "for call_id %d media %d",
+ call_id, mi));
+ continue;
}
}
@@ -2323,17 +2664,6 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
}
- /* Call implementation */
- status = pjsua_aud_channel_update(call_med, tmp_pool, si,
- local_sdp, remote_sdp);
- if (status != PJ_SUCCESS) {
- PJ_PERROR(1,(THIS_FILE, status,
- "pjsua_aud_channel_update() failed "
- "for call_id %d media %d",
- call_id, mi));
- continue;
- }
-
/* Print info. */
if (status == PJ_SUCCESS) {
char info[80];
@@ -2378,9 +2708,11 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
} else if (call_med->type==PJMEDIA_TYPE_VIDEO) {
pjmedia_vid_stream_info the_si, *si = &the_si;
+ pjsua_stream_info stream_info;
- status = pjmedia_vid_stream_info_from_sdp(si, tmp_pool, pjsua_var.med_endpt,
- local_sdp, remote_sdp, mi);
+ status = pjmedia_vid_stream_info_from_sdp(
+ si, tmp_pool, pjsua_var.med_endpt,
+ local_sdp, remote_sdp, mi);
if (status != PJ_SUCCESS) {
PJ_PERROR(1,(THIS_FILE, status,
"pjmedia_vid_stream_info_from_sdp() failed "
@@ -2389,14 +2721,28 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
continue;
}
+ /* Check if this media is changed */
+ stream_info.type = PJMEDIA_TYPE_VIDEO;
+ stream_info.info.vid = the_si;
+ if (is_media_changed(call, mi, &stream_info)) {
+ media_changed = PJ_TRUE;
+ /* Stop the media */
+ stop_media_stream(call, mi);
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Call %d: stream #%d (video) unchanged.",
+ call_id, mi));
+ }
+
/* Check if no media is active */
if (si->dir == PJMEDIA_DIR_NONE) {
+
/* Update call media state and direction */
call_med->state = PJSUA_CALL_MEDIA_NONE;
call_med->dir = PJMEDIA_DIR_NONE;
} else {
pjmedia_transport_info tp_info;
+ pjmedia_srtp_info *srtp_info;
/* Start/restart media transport */
status = pjmedia_transport_media_start(call_med->tp,
@@ -2415,17 +2761,24 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
/* Get remote SRTP usage policy */
pjmedia_transport_info_init(&tp_info);
pjmedia_transport_get_info(call_med->tp, &tp_info);
- if (tp_info.specific_info_cnt > 0) {
- unsigned i;
- for (i = 0; i < tp_info.specific_info_cnt; ++i) {
- if (tp_info.spc_info[i].type ==
- PJMEDIA_TRANSPORT_TYPE_SRTP)
- {
- pjmedia_srtp_info *sri;
- sri=(pjmedia_srtp_info*)tp_info.spc_info[i].buffer;
- call_med->rem_srtp_use = sri->peer_use;
- break;
- }
+ srtp_info = (pjmedia_srtp_info*)
+ pjmedia_transport_info_get_spc_info(
+ &tp_info, PJMEDIA_TRANSPORT_TYPE_SRTP);
+ if (srtp_info) {
+ call_med->rem_srtp_use = srtp_info->peer_use;
+ }
+
+ /* Update audio channel */
+ if (media_changed) {
+ status = pjsua_vid_channel_update(call_med,
+ call->inv->pool, si,
+ local_sdp, remote_sdp);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "pjsua_vid_channel_update() failed "
+ "for call_id %d media %d",
+ call_id, mi));
+ continue;
}
}
@@ -2441,16 +2794,6 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
call_med->state = PJSUA_CALL_MEDIA_ACTIVE;
}
- status = pjsua_vid_channel_update(call_med, tmp_pool, si,
- local_sdp, remote_sdp);
- if (status != PJ_SUCCESS) {
- PJ_PERROR(1,(THIS_FILE, status,
- "pjsua_vid_channel_update() failed "
- "for call_id %d media %d",
- call_id, mi));
- continue;
- }
-
/* Print info. */
{
char info[80];
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index 4551c91..591f65b 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_pres.c 4186 2012-06-29 01:37:50Z ming $ */
+/* $Id: pjsua_pres.c 4294 2012-11-06 05:02:10Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -864,8 +864,31 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
return PJ_TRUE;
}
- if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0)
+ if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) {
pjsip_dlg_set_via_sent_by(dlg, &acc->via_addr, acc->via_tp);
+ } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
+ /* Choose local interface to use in Via if acc is not using
+ * STUN. See https://trac.pjsip.org/repos/ticket/1412
+ */
+ char target_buf[PJSIP_MAX_URL_SIZE];
+ pj_str_t target;
+ pjsip_host_port via_addr;
+ const void *via_tp;
+
+ target.ptr = target_buf;
+ target.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
+ dlg->target,
+ target_buf, sizeof(target_buf));
+ if (target.slen < 0) target.slen = 0;
+
+ if (pjsua_acc_get_uac_addr(acc_id, dlg->pool, &target,
+ &via_addr, NULL, NULL,
+ &via_tp) == PJ_SUCCESS)
+ {
+ pjsip_dlg_set_via_sent_by(dlg, &via_addr,
+ (pjsip_transport*)via_tp);
+ }
+ }
/* Set credentials and preference. */
pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred);
@@ -1236,6 +1259,20 @@ static pj_status_t send_publish(int acc_id, pj_bool_t active)
if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) {
pjsip_publishc_set_via_sent_by(acc->publish_sess, &acc->via_addr,
acc->via_tp);
+ } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
+ /* Choose local interface to use in Via if acc is not using
+ * STUN. See https://trac.pjsip.org/repos/ticket/1412
+ */
+ pjsip_host_port via_addr;
+ const void *via_tp;
+
+ if (pjsua_acc_get_uac_addr(acc_id, acc->pool, &acc_cfg->id,
+ &via_addr, NULL, NULL,
+ &via_tp) == PJ_SUCCESS)
+ {
+ pjsip_publishc_set_via_sent_by(acc->publish_sess, &via_addr,
+ (pjsip_transport*)via_tp);
+ }
}
/* Send the PUBLISH request */
@@ -1789,8 +1826,24 @@ static void subscribe_buddy_presence(pjsua_buddy_id buddy_id)
*/
pjsip_dlg_inc_lock(buddy->dlg);
- if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0)
+ if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) {
pjsip_dlg_set_via_sent_by(buddy->dlg, &acc->via_addr, acc->via_tp);
+ } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
+ /* Choose local interface to use in Via if acc is not using
+ * STUN. See https://trac.pjsip.org/repos/ticket/1412
+ */
+ pjsip_host_port via_addr;
+ const void *via_tp;
+
+ if (pjsua_acc_get_uac_addr(acc_id, buddy->dlg->pool, &buddy->uri,
+ &via_addr, NULL, NULL,
+ &via_tp) == PJ_SUCCESS)
+ {
+ pjsip_dlg_set_via_sent_by(buddy->dlg, &via_addr,
+ (pjsip_transport*)via_tp);
+ }
+ }
+
status = pjsip_pres_create_uac( buddy->dlg, &pres_callback,
PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub);
@@ -2114,8 +2167,23 @@ pj_status_t pjsua_start_mwi(pjsua_acc_id acc_id, pj_bool_t force_renew)
*/
pjsip_dlg_inc_lock(acc->mwi_dlg);
- if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0)
+ if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) {
pjsip_dlg_set_via_sent_by(acc->mwi_dlg, &acc->via_addr, acc->via_tp);
+ } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
+ /* Choose local interface to use in Via if acc is not using
+ * STUN. See https://trac.pjsip.org/repos/ticket/1412
+ */
+ pjsip_host_port via_addr;
+ const void *via_tp;
+
+ if (pjsua_acc_get_uac_addr(acc_id, acc->mwi_dlg->pool, &acc->cfg.id,
+ &via_addr, NULL, NULL,
+ &via_tp) == PJ_SUCCESS)
+ {
+ pjsip_dlg_set_via_sent_by(acc->mwi_dlg, &via_addr,
+ (pjsip_transport*)via_tp);
+ }
+ }
/* Create UAC subscription */
status = pjsip_mwi_create_uac(acc->mwi_dlg, &mwi_cb,
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index eb74ee1..c92ec56 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_vid.c 4071 2012-04-24 05:40:32Z nanang $ */
+/* $Id: pjsua_vid.c 4341 2013-02-05 12:21:30Z nanang $ */
/*
* Copyright (C) 2011-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -705,7 +705,12 @@ pj_status_t pjsua_vid_channel_init(pjsua_call_media *call_med)
return PJ_SUCCESS;
}
-/* Internal function: update video channel after SDP negotiation */
+/* Internal function: update video channel after SDP negotiation.
+ * Warning: do not use temporary/flip-flop pool, e.g: inv->pool_prov,
+ * for creating stream, etc, as after SDP negotiation and when
+ * the SDP media is not changed, the stream should remain running
+ * while the temporary/flip-flop pool may be released.
+ */
pj_status_t pjsua_vid_channel_update(pjsua_call_media *call_med,
pj_pool_t *tmp_pool,
pjmedia_vid_stream_info *si,
@@ -1743,11 +1748,13 @@ static pj_status_t call_modify_video(pjsua_call *call,
sdp->media[med_idx] = sdp_m;
- /* Update SDP media line by media transport */
- status = pjmedia_transport_encode_sdp(call_med->tp, pool,
- sdp, NULL, call_med->idx);
- if (status != PJ_SUCCESS)
- goto on_error;
+ if (call_med->dir == PJMEDIA_DIR_NONE) {
+ /* Update SDP media line by media transport */
+ status = pjmedia_transport_encode_sdp(call_med->tp, pool,
+ sdp, NULL, call_med->idx);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+ }
on_error:
if (status != PJ_SUCCESS) {
@@ -2029,6 +2036,7 @@ PJ_DEF(pj_status_t) pjsua_call_set_vid_strm (
const pjsua_call_vid_strm_op_param *param)
{
pjsua_call *call;
+ pjsip_dialog *dlg;
pjsua_call_vid_strm_op_param param_;
pj_status_t status;
@@ -2040,9 +2048,9 @@ PJ_DEF(pj_status_t) pjsua_call_set_vid_strm (
call_id, op));
pj_log_push_indent();
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
+ status = acquire_call("pjsua_call_set_vid_strm()", call_id, &call, &dlg);
+ if (status != PJ_SUCCESS)
+ goto on_return;
if (param) {
param_ = *param;
@@ -2097,9 +2105,9 @@ PJ_DEF(pj_status_t) pjsua_call_set_vid_strm (
break;
}
- PJSUA_UNLOCK();
+on_return:
+ if (dlg) pjsip_dlg_dec_lock(dlg);
pj_log_pop_indent();
-
return status;
}
diff --git a/pjsip/src/test/tsx_uac_test.c b/pjsip/src/test/tsx_uac_test.c
index c8f3074..eec92fc 100644
--- a/pjsip/src/test/tsx_uac_test.c
+++ b/pjsip/src/test/tsx_uac_test.c
@@ -1,4 +1,4 @@
-/* $Id: tsx_uac_test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: tsx_uac_test.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -159,7 +159,7 @@ static struct my_timer
*/
static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
{
- if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) {
+ if (pj_stricmp2(&tsx->branch, TEST1_BRANCH_ID)==0) {
/*
* Transaction with TEST1_BRANCH_ID should terminate with transaction
* timeout status.
@@ -213,7 +213,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
}
- } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST2_BRANCH_ID)==0) {
/*
* Transaction with TEST2_BRANCH_ID should terminate with transport error.
*/
@@ -231,7 +231,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
test_complete = 1;
}
- } else if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
/*
* This test terminates the transaction while resolver is still
* running.
@@ -256,7 +256,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
- } else if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
/*
* This test simulates transport failure after several
* retransmissions.
@@ -284,7 +284,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
- } else if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
/*
* This test simulates transport failure after several
* retransmissions.
@@ -312,7 +312,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
- } else if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
/*
* Successfull non-INVITE transaction.
*/
@@ -355,7 +355,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
- } else if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST7_BRANCH_ID)==0) {
/*
* Successfull non-INVITE transaction.
*/
@@ -408,7 +408,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
- } else if (pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST8_BRANCH_ID)==0) {
/*
* Failed INVITE transaction.
*/
@@ -468,7 +468,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
- } else if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
+ } else if (pj_stricmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
/*
* Failed INVITE transaction with provisional response.
*/
@@ -583,7 +583,7 @@ static void terminate_tsx_callback( pj_timer_heap_t *timer_heap,
*/
static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
{
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) {
/*
* The TEST1_BRANCH_ID test performs the verifications for transaction
* retransmission mechanism. It will not answer the incoming request
@@ -651,7 +651,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
return PJ_TRUE;
} else
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) {
/*
* The TEST4_BRANCH_ID test simulates transport failure after several
* retransmissions.
@@ -672,7 +672,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
} else
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) {
/*
* The TEST5_BRANCH_ID test simulates user terminating the transaction
* after several retransmissions.
@@ -703,7 +703,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
return PJ_TRUE;
} else
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) {
/*
* The TEST6_BRANCH_ID test successfull non-INVITE transaction.
*/
@@ -728,7 +728,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
} else
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) {
/*
* The TEST7_BRANCH_ID test successfull non-INVITE transaction
* with provisional response.
@@ -778,7 +778,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
} else
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) {
/*
* The TEST8_BRANCH_ID test failed INVITE transaction.
*/
@@ -841,7 +841,7 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
} else
- if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) {
/*
* The TEST9_BRANCH_ID test failed INVITE transaction with
* provisional response.
diff --git a/pjsip/src/test/tsx_uas_test.c b/pjsip/src/test/tsx_uas_test.c
index 045e958..6da1c4c 100644
--- a/pjsip/src/test/tsx_uas_test.c
+++ b/pjsip/src/test/tsx_uas_test.c
@@ -1,4 +1,4 @@
-/* $Id: tsx_uas_test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: tsx_uas_test.c 4208 2012-07-18 07:52:33Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -352,8 +352,8 @@ static void schedule_terminate_tsx( pjsip_transaction *tsx,
*/
static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
{
- if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 ||
- pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0)
+ if (pj_stricmp2(&tsx->branch, TEST1_BRANCH_ID)==0 ||
+ pj_stricmp2(&tsx->branch, TEST2_BRANCH_ID)==0)
{
/*
* TEST1_BRANCH_ID tests that non-INVITE transaction transmits final
@@ -362,7 +362,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
*
* TEST2_BRANCH_ID does similar test for non-2xx final response.
*/
- int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ?
+ int status_code = (pj_stricmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ?
TEST1_STATUS_CODE : TEST2_STATUS_CODE;
if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
@@ -392,7 +392,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
else
- if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
+ if (pj_stricmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
/*
* TEST3_BRANCH_ID tests sending provisional response.
*/
@@ -455,7 +455,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
} else
- if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
+ if (pj_stricmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
/*
* TEST4_BRANCH_ID tests receiving retransmissions in TRYING state.
*/
@@ -488,7 +488,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
} else
- if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
+ if (pj_stricmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
/*
* TEST5_BRANCH_ID tests receiving retransmissions in PROCEEDING state
*/
@@ -525,7 +525,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
}
} else
- if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
+ if (pj_stricmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
/*
* TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state
*/
@@ -560,8 +560,8 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
} else
- if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0 ||
- pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0)
+ if (pj_stricmp2(&tsx->branch, TEST7_BRANCH_ID)==0 ||
+ pj_stricmp2(&tsx->branch, TEST8_BRANCH_ID)==0)
{
/*
* TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of
@@ -569,7 +569,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
*/
int code;
- if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID) == 0)
+ if (pj_stricmp2(&tsx->branch, TEST7_BRANCH_ID) == 0)
code = TEST7_STATUS_CODE;
else
code = TEST8_STATUS_CODE;
@@ -637,7 +637,7 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
} else
- if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
+ if (pj_stricmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
/*
* TEST9_BRANCH_ID tests that retransmission of INVITE final response
* must cease when ACK is received.
@@ -701,9 +701,9 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
} else
- if (pj_strcmp2(&tsx->branch, TEST10_BRANCH_ID)==0 ||
- pj_strcmp2(&tsx->branch, TEST11_BRANCH_ID)==0 ||
- pj_strcmp2(&tsx->branch, TEST12_BRANCH_ID)==0)
+ if (pj_stricmp2(&tsx->branch, TEST10_BRANCH_ID)==0 ||
+ pj_stricmp2(&tsx->branch, TEST11_BRANCH_ID)==0 ||
+ pj_stricmp2(&tsx->branch, TEST12_BRANCH_ID)==0)
{
if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
@@ -739,8 +739,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
pj_str_t branch_param = rdata->msg_info.via->branch_param;
pj_status_t status;
- if (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0 ||
- pj_strcmp2(&branch_param, TEST2_BRANCH_ID) == 0)
+ if (pj_stricmp2(&branch_param, TEST1_BRANCH_ID) == 0 ||
+ pj_stricmp2(&branch_param, TEST2_BRANCH_ID) == 0)
{
/*
* TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx
@@ -749,7 +749,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
*
* TEST2_BRANCH_ID performs similar test for non-2xx final response.
*/
- int status_code = (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0) ?
+ int status_code = (pj_stricmp2(&branch_param, TEST1_BRANCH_ID) == 0) ?
TEST1_STATUS_CODE : TEST2_STATUS_CODE;
if (msg->type == PJSIP_REQUEST_MSG) {
@@ -789,7 +789,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
}
return PJ_TRUE;
- } else if (pj_strcmp2(&branch_param, TEST3_BRANCH_ID) == 0) {
+ } else if (pj_stricmp2(&branch_param, TEST3_BRANCH_ID) == 0) {
/* TEST3_BRANCH_ID tests provisional response. */
@@ -838,9 +838,9 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
}
return PJ_TRUE;
- } else if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0 ||
- pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0 ||
- pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0)
+ } else if (pj_stricmp2(&branch_param, TEST4_BRANCH_ID) == 0 ||
+ pj_stricmp2(&branch_param, TEST5_BRANCH_ID) == 0 ||
+ pj_stricmp2(&branch_param, TEST6_BRANCH_ID) == 0)
{
/* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */
@@ -863,12 +863,12 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
- if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
- } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
+ } else if (pj_stricmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
send_response(rdata, tsx, TEST5_PROVISIONAL_CODE);
- } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
+ } else if (pj_stricmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
PJ_LOG(4,(THIS_FILE, " sending provisional response"));
send_response(rdata, tsx, TEST6_PROVISIONAL_CODE);
PJ_LOG(4,(THIS_FILE, " sending final response"));
@@ -882,11 +882,11 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
++recv_count;
- if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
test_complete = -132;
- } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
+ } else if (pj_stricmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) {
PJ_LOG(3,(THIS_FILE, " error: incorrect status code!"));
@@ -898,7 +898,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
test_complete = -134;
}
- } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
+ } else if (pj_stricmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
int code = rdata->msg_info.msg->line.status.code;
@@ -927,8 +927,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
return PJ_TRUE;
- } else if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0 ||
- pj_strcmp2(&branch_param, TEST8_BRANCH_ID) == 0)
+ } else if (pj_stricmp2(&branch_param, TEST7_BRANCH_ID) == 0 ||
+ pj_stricmp2(&branch_param, TEST8_BRANCH_ID) == 0)
{
/*
@@ -950,7 +950,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
pjsip_tsx_recv_msg(tsx, rdata);
save_key(tsx);
- if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) {
+ if (pj_stricmp2(&branch_param, TEST7_BRANCH_ID) == 0) {
send_response(rdata, tsx, TEST7_STATUS_CODE);
@@ -965,7 +965,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
++recv_count;
- if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0)
+ if (pj_stricmp2(&branch_param, TEST7_BRANCH_ID) == 0)
code = TEST7_STATUS_CODE;
else
code = TEST8_STATUS_CODE;
@@ -1013,7 +1013,7 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
}
return PJ_TRUE;
- } else if (pj_strcmp2(&branch_param, TEST9_BRANCH_ID) == 0) {
+ } else if (pj_stricmp2(&branch_param, TEST9_BRANCH_ID) == 0) {
/*
* TEST9_BRANCH_ID tests that the retransmission of INVITE final
@@ -1118,15 +1118,15 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
}
return PJ_TRUE;
- } else if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0 ||
- pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0 ||
- pj_strcmp2(&branch_param, TEST12_BRANCH_ID) == 0)
+ } else if (pj_stricmp2(&branch_param, TEST10_BRANCH_ID) == 0 ||
+ pj_stricmp2(&branch_param, TEST11_BRANCH_ID) == 0 ||
+ pj_stricmp2(&branch_param, TEST12_BRANCH_ID) == 0)
{
int test_num, code1, code2;
- if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0)
+ if (pj_stricmp2(&branch_param, TEST10_BRANCH_ID) == 0)
test_num=10, code1 = 100, code2 = 0;
- else if (pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0)
+ else if (pj_stricmp2(&branch_param, TEST11_BRANCH_ID) == 0)
test_num=11, code1 = 100, code2 = 200;
else
test_num=12, code1 = 200, code2 = 0;
diff --git a/pjsip/src/test/uri_test.c b/pjsip/src/test/uri_test.c
index 8527faa..c8b0b3e 100644
--- a/pjsip/src/test/uri_test.c
+++ b/pjsip/src/test/uri_test.c
@@ -1,4 +1,4 @@
-/* $Id: uri_test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: uri_test.c 4210 2012-07-19 01:00:07Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -67,6 +67,7 @@ static pjsip_uri *create_uri14( pj_pool_t *pool );
static pjsip_uri *create_uri15( pj_pool_t *pool );
static pjsip_uri *create_uri16( pj_pool_t *pool );
static pjsip_uri *create_uri17( pj_pool_t *pool );
+static pjsip_uri *create_uri18( pj_pool_t *pool );
static pjsip_uri *create_uri25( pj_pool_t *pool );
static pjsip_uri *create_uri26( pj_pool_t *pool );
static pjsip_uri *create_uri27( pj_pool_t *pool );
@@ -81,6 +82,7 @@ static pjsip_uri *create_uri35( pj_pool_t *pool );
static pjsip_uri *create_uri36( pj_pool_t *pool );
static pjsip_uri *create_uri37( pj_pool_t *pool );
static pjsip_uri *create_uri38( pj_pool_t *pool );
+static pjsip_uri *create_uri39( pj_pool_t *pool );
static pjsip_uri *create_dummy( pj_pool_t *pool );
#define ERR_NOT_EQUAL -1001
@@ -349,6 +351,12 @@ struct uri_test
"\xC0\x81 <sip:localhost>",
&create_uri38,
"\"\xC0\x81\" <sip:localhost>"
+ },
+ {
+ /* Even number of backslash before end quote in display name. */
+ PJ_SUCCESS,
+ "\"User\\\\\" <sip:localhost>",
+ &create_uri39,
}
};
@@ -759,6 +767,20 @@ static pjsip_uri *create_uri38( pj_pool_t *pool )
}
+/* "\"User\\\\\" <sip:localhost>" */
+static pjsip_uri *create_uri39(pj_pool_t *pool)
+{
+ pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
+ pjsip_sip_uri *url;
+
+ url = pjsip_sip_uri_create(pool, 0);
+ name_addr->uri = (pjsip_uri*) url;
+
+ pj_strdup2(pool, &name_addr->display, "User\\\\");
+ pj_strdup2(pool, &url->host, "localhost");
+ return (pjsip_uri*)name_addr;
+}
+
static pjsip_uri *create_dummy(pj_pool_t *pool)
{
PJ_UNUSED_ARG(pool);