diff --git a/pjsip/include/pjsip-ua/sip_regc.h b/pjsip/include/pjsip-ua/sip_regc.h index 2d04f4e2c3..ee001306e6 100644 --- a/pjsip/include/pjsip-ua/sip_regc.h +++ b/pjsip/include/pjsip-ua/sip_regc.h @@ -488,6 +488,20 @@ PJ_DECL(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc, PJ_DECL(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata); +/** + * set a shared auth session to be used by this register client. + * This will try to reuse authorization headers from another source + * (e.g. subscribe dialog). + * + * If available, the internal auth session will be ignored. + * To reset client registration, pass NULL as session parameter. + * + * @param regc The client registration structure. + * @param session Pointer to the external session. + */ +PJ_DECL(pj_status_t) pjsip_regc_set_auth_sess( pjsip_regc *regc, + pjsip_auth_clt_sess *session ); + PJ_END_DECL /** diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h index 5e11664d5c..9c956bc8a7 100644 --- a/pjsip/include/pjsip/sip_auth.h +++ b/pjsip/include/pjsip/sip_auth.h @@ -343,7 +343,12 @@ typedef struct pjsip_auth_clt_sess unsigned cred_cnt; /**< Number of credentials. */ pjsip_cred_info *cred_info; /**< Array of credential information*/ pjsip_cached_auth cached_auth; /**< Cached authorization info. */ - + pj_lock_t *lock; /**< Prevent concurrent usage when + using a shared parent. Is only + used in parent. Set up by + pjsip_auth_clt_set_parent */ + struct pjsip_auth_clt_sess *parent; /**< allow a common parent + for multiple sessions. */ } pjsip_auth_clt_sess; @@ -602,6 +607,19 @@ PJ_DECL(pj_status_t) pjsip_auth_srv_init( pj_pool_t *pool, unsigned options ); +/** + * Set a parent session to be used instead of the current. + * This allows a central caching of authorization headers over multiple + * dialogs. + * + * @param sess session that will be delegating the requests. + * @param p parent that will be shared. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjsip_auth_clt_set_parent(pjsip_auth_clt_sess *sess, + const pjsip_auth_clt_sess *p); + /** * This structure describes initialization settings of server authorization * session. diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h index 4833847546..61767dca45 100644 --- a/pjsip/include/pjsip/sip_dialog.h +++ b/pjsip/include/pjsip/sip_dialog.h @@ -903,7 +903,19 @@ PJ_DECL(pj_status_t) pjsip_dlg_update_remote_cap(pjsip_dialog *dlg, const pjsip_msg *msg, pj_bool_t strict); - +/** + * set a shared auth session to be used by this dialog. + * This will try to reuse authorization headers from another source + * (e.g. register). + * + * If available, the internal auth session will be ignored. + * To reset client registration, pass NULL as session parameter. + * + * @param dlg The dialog + * @param session Pointer to the external session + */ +PJ_DECL(pj_status_t) pjsip_dlg_set_auth_sess(pjsip_dialog *dlg, + pjsip_auth_clt_sess *session); /** * @} @@ -927,7 +939,6 @@ void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata ); - PJ_END_DECL diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index da555d093a..7c4092e102 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -4661,6 +4661,19 @@ typedef struct pjsua_acc_config */ pj_bool_t enable_rtcp_xr; + /** + * Use a shared authorization session within this account. + * This will use the accounts credentials on outgoing requests, + * so that less 401/407 Responses will be returned. + * + * Needs PJSIP_AUTH_AUTO_SEND_NEXT and PJSIP_AUTH_HEADER_CACHING + * enabled to work properly, and also will grow usage of the used pool for + * the cached headers. + * + * Default: PJ_FALSE + */ + pj_bool_t use_shared_auth; + } pjsua_acc_config; diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index c370cb46f4..b14f658730 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -334,6 +334,7 @@ typedef struct pjsua_acc pjsip_transport_type_e tp_type; /**< Transport type (for local acc or transport binding) */ pjsua_ip_change_op ip_change_op;/**< IP change process progress. */ + pjsip_auth_clt_sess shared_auth_sess; /**< share one auth over all requests */ } pjsua_acc; diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp index c7eb021703..458f5644bd 100644 --- a/pjsip/include/pjsua2/account.hpp +++ b/pjsip/include/pjsua2/account.hpp @@ -298,6 +298,19 @@ struct AccountSipConfig : public PersistentObject */ pjsua_ipv6_use ipv6Use; + /** + * Use a shared authorization session within this account. + * This will use the accounts credentials on outgoing requests, + * so that less 401/407 Responses will be returned. + * + * Needs PJSIP_AUTH_AUTO_SEND_NEXT and PJSIP_AUTH_HEADER_CACHING + * enabled to work properly, and also will grow usage of the used pool for + * the cached headers. + * + * Default is disabled/false. + */ + bool useSharedAuth; + public: /** * Read this object from a container node. diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c index ed9ba6d451..7595df3ca6 100644 --- a/pjsip/src/pjsip-ua/sip_reg.c +++ b/pjsip/src/pjsip-ua/sip_reg.c @@ -96,6 +96,7 @@ struct pjsip_regc /* Authorization sessions. */ pjsip_auth_clt_sess auth_sess; + pjsip_auth_clt_sess *ext_auth_sess; /**< User defined auth session. */ /* Auto refresh registration. */ pj_bool_t auto_reg; @@ -1555,4 +1556,8 @@ PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata) return status; } - +PJ_DEF(pj_status_t) pjsip_regc_set_auth_sess( pjsip_regc *regc, + pjsip_auth_clt_sess *session ) { + PJ_ASSERT_RETURN(regc, PJ_EINVAL); + return pjsip_auth_clt_set_parent(®c->auth_sess, session); +} diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c index 989e7eaaf6..a68c7db93f 100644 --- a/pjsip/src/pjsip/sip_auth_client.c +++ b/pjsip/src/pjsip/sip_auth_client.c @@ -31,6 +31,7 @@ #include #include #include +#include #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \ @@ -105,6 +106,20 @@ const pjsip_auth_algorithm pjsip_auth_algorithms[] = { # define AUTH_TRACE_(expr) #endif +#define DO_ON_PARENT_LOCKED(sess, call) \ + do { \ + pj_status_t on_parent; \ + pj_bool_t with_parent = PJ_FALSE; \ + if (sess->parent) { \ + pj_lock_acquire(sess->parent->lock); \ + with_parent = PJ_TRUE; \ + on_parent = call; \ + pj_lock_release(sess->parent->lock); \ + } \ + if (with_parent) { \ + return on_parent; \ + } \ + } while(0) static void dup_bin(pj_pool_t *pool, pj_str_t *dst, const pj_str_t *src) { @@ -712,6 +727,17 @@ static pjsip_cached_auth *find_cached_auth( pjsip_auth_clt_sess *sess, const pj_str_t *realm, pjsip_auth_algorithm_type algorithm_type) { + pj_bool_t with_parent = PJ_FALSE; + pjsip_cached_auth * pauth = NULL; + if (sess->parent) { + pj_lock_acquire(sess->parent->lock); + pauth = find_cached_auth(sess->parent, realm, algorithm_type); + pj_lock_release(sess->parent->lock); + } + if (pauth != NULL) { + return pauth; + } + pjsip_cached_auth *auth = sess->cached_auth.next; while (auth != &sess->cached_auth) { if (pj_stricmp(&auth->realm, realm) == 0 @@ -734,6 +760,17 @@ static const pjsip_cred_info* auth_find_cred( const pjsip_auth_clt_sess *sess, PJ_UNUSED_ARG(auth_scheme); + pj_bool_t with_parent = PJ_FALSE; + const pjsip_cred_info * ptr = NULL; + if (sess->parent) { + pj_lock_acquire(sess->parent->lock); + ptr = auth_find_cred(sess->parent, realm, auth_scheme, algorithm_type); + pj_lock_release(sess->parent->lock); + } + if (ptr != NULL) { + return ptr; + } + for (i=0; icred_cnt; ++i) { switch(sess->cred_info[i].data_type) { case PJSIP_CRED_DATA_PLAIN_PASSWD: @@ -795,6 +832,21 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess, sess->cred_info = NULL; pj_list_init(&sess->cached_auth); + sess->parent = NULL; + sess->lock = NULL; + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pjsip_auth_clt_set_parent(pjsip_auth_clt_sess *sess, + const pjsip_auth_clt_sess *parent) +{ + PJ_ASSERT_RETURN(sess && parent, PJ_EINVAL); + if (parent->lock == NULL) { + pj_lock_create_simple_mutex( parent->pool, + "auth_clt_parent_lock", + &parent->lock ); + } + sess->parent = parent; return PJ_SUCCESS; } @@ -812,7 +864,12 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_deinit(pjsip_auth_clt_sess *sess) auth = auth->next; } - return PJ_SUCCESS; + sess->parent = NULL; + if (sess->lock) { + return pj_lock_destroy(sess->lock); + } else { + return PJ_SUCCESS; + } } @@ -849,6 +906,21 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool, } } + pj_status_t status; + if (sess->parent) { + pj_lock_acquire(sess->parent->lock); + sess->parent = PJ_POOL_ZALLOC_T(pool, pjsip_auth_clt_sess); + if (sess->parent == NULL) { + status = PJ_ENOMEM; + } else { + status = pjsip_auth_clt_clone(pool, sess->parent, rhs->parent); + } + pj_lock_release(sess->parent->lock); + } + if (status != PJ_SUCCESS) { + return status; + } + /* TODO note: * Cloning the full authentication client is quite a big task. * We do only the necessary bits here, i.e. cloning the credentials. @@ -868,6 +940,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess, const pjsip_cred_info *c) { PJ_ASSERT_RETURN(sess && c, PJ_EINVAL); + DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_set_credentials(sess->parent, cred_cnt, c)); if (cred_cnt == 0) { sess->cred_cnt = 0; @@ -943,6 +1016,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_prefs(pjsip_auth_clt_sess *sess, const pjsip_auth_clt_pref *p) { PJ_ASSERT_RETURN(sess && p, PJ_EINVAL); + DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_set_prefs(sess->parent, p)); pj_memcpy(&sess->pref, p, sizeof(*p)); pj_strdup(sess->pool, &sess->pref.algorithm, &p->algorithm); @@ -960,7 +1034,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_get_prefs(pjsip_auth_clt_sess *sess, pjsip_auth_clt_pref *p) { PJ_ASSERT_RETURN(sess && p, PJ_EINVAL); - + DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_get_prefs(sess->parent, p)); pj_memcpy(p, &sess->pref, sizeof(pjsip_auth_clt_pref)); return PJ_SUCCESS; } @@ -1197,6 +1271,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess, PJ_ASSERT_RETURN(tdata->msg->type==PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); + + DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_init_req(sess->parent, tdata)); /* Init list */ pj_list_init(&added); @@ -1548,6 +1624,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess, rdata->msg_info.msg->line.status.code == 407, PJSIP_EINVALIDSTATUS); + DO_ON_PARENT_LOCKED(sess, pjsip_auth_clt_reinit_req(sess->parent, rdata, old_request, new_request)); + tdata = old_request; tdata->auth_retry = PJ_FALSE; diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c index 5bb81b820d..ba37efa79b 100644 --- a/pjsip/src/pjsip/sip_dialog.c +++ b/pjsip/src/pjsip/sip_dialog.c @@ -2493,3 +2493,9 @@ PJ_DEF(pj_status_t) pjsip_dlg_remove_remote_cap_hdr(pjsip_dialog *dlg, return PJ_SUCCESS; } + +PJ_DEF(pj_status_t) pjsip_dlg_set_auth_sess( pjsip_dialog *dlg, + pjsip_auth_clt_sess *session ) { + PJ_ASSERT_RETURN(dlg, PJ_EINVAL); + return pjsip_auth_clt_set_parent(&dlg->auth_sess, session); +} diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 25ea8c1aad..692f6e988e 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -329,6 +329,7 @@ static pj_status_t initialize_acc(unsigned acc_id) } else { sip_reg_uri = NULL; } + pjsip_auth_clt_init( &acc->shared_auth_sess, pjsua_var.endpt, acc->pool, 0); if (sip_reg_uri) { acc->srv_port = sip_reg_uri->port; @@ -1297,6 +1298,9 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, unreg_first = PJ_TRUE; } + /* Shared authentication session */ + acc->cfg.use_shared_auth = cfg->use_shared_auth; + /* Registration */ if (acc->cfg.reg_timeout != cfg->reg_timeout) { acc->cfg.reg_timeout = cfg->reg_timeout; @@ -2754,6 +2758,10 @@ static pj_status_t pjsua_regc_init(int acc_id) pjsua_init_tpselector(acc_id, &tp_sel); pjsip_regc_set_transport(acc->regc, &tp_sel); + if (acc->cfg.use_shared_auth) { + pjsip_regc_set_auth_sess(acc->regc, &acc->shared_auth_sess); + } + /* Set credentials */ if (acc->cred_cnt) { diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index db020527e5..2b51aa8b87 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -983,6 +983,10 @@ PJ_DEF(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id, dlg_set_via(dlg, acc); + if (acc->cfg.use_shared_auth) { + pjsip_dlg_set_auth_sess(dlg, &acc->shared_auth_sess); + } + /* Calculate call's secure level */ call->secure_level = get_secure_level(acc_id, dest_uri); diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 569166eace..176e8d6309 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -387,6 +387,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) PJSUA_CALL_UPDATE_CONTACT | PJSUA_CALL_UPDATE_VIA; cfg->enable_rtcp_xr = (PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR); + cfg->use_shared_auth = PJ_FALSE; } PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg) diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index bb5f72526c..3a6fbc3888 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -2127,6 +2127,10 @@ static void subscribe_buddy(pjsua_buddy_id buddy_id, pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set); } + if (acc->cfg.use_shared_auth) { + pjsip_dlg_set_auth_sess(buddy->dlg, &acc->shared_auth_sess); + } + /* Set credentials */ if (acc->cred_cnt) { pjsip_auth_clt_set_credentials( &buddy->dlg->auth_sess, diff --git a/pjsip/src/pjsua2/account.cpp b/pjsip/src/pjsua2/account.cpp index a8af6a1e4a..d40a200c3d 100644 --- a/pjsip/src/pjsua2/account.cpp +++ b/pjsip/src/pjsua2/account.cpp @@ -281,6 +281,7 @@ void AccountSipConfig::readObject(const ContainerNode &node) NODE_READ_BOOL (this_node, authInitialEmpty); NODE_READ_STRING (this_node, authInitialAlgorithm); NODE_READ_INT (this_node, transportId); + NODE_READ_BOOL (this_node, useSharedAuth); ContainerNode creds_node = this_node.readArray("authCreds"); authCreds.resize(0); @@ -303,6 +304,7 @@ void AccountSipConfig::writeObject(ContainerNode &node) const NODE_WRITE_BOOL (this_node, authInitialEmpty); NODE_WRITE_STRING (this_node, authInitialAlgorithm); NODE_WRITE_INT (this_node, transportId); + NODE_WRITE_BOOL (this_node, useSharedAuth); ContainerNode creds_node = this_node.writeNewArray("authCreds"); for (unsigned i=0; i