Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion pjsip-apps/src/pjsua/pjsua_app.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -2190,6 +2190,13 @@ static pj_status_t app_init(void)

app_config_init_video(&app_config.acc_cfg[i]);
app_config.acc_cfg[i].txt_red_level = app_config.txt_red_level;
if (app_config.instance_id.slen &&
!app_config.acc_cfg[i].rfc5626_instance_id.slen)
{
app_config.acc_cfg[i].rfc5626_instance_id = app_config.instance_id;
}
if (app_config.outb_disable)
app_config.acc_cfg[i].use_rfc5626 = PJ_FALSE;

status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL);
if (status != PJ_SUCCESS)
Expand Down
5 changes: 4 additions & 1 deletion pjsip-apps/src/pjsua/pjsua_app_cli.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -843,6 +843,9 @@ static pj_status_t cmd_add_account(pj_cli_cmd_val *cval)

acc_cfg.rtp_cfg = app_config.rtp_cfg;
acc_cfg.txt_red_level = app_config.txt_red_level;
acc_cfg.rfc5626_instance_id = app_config.instance_id;
if (app_config.outb_disable)
acc_cfg.use_rfc5626 = PJ_FALSE;
app_config_init_video(&acc_cfg);

status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL);
Expand Down
4 changes: 3 additions & 1 deletion pjsip-apps/src/pjsua/pjsua_app_common.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -89,6 +89,8 @@ typedef struct pjsua_app_config
pj_bool_t no_udp;
pj_bool_t use_tls;
pj_bool_t keep_call_on_tsx_fail;
pj_str_t instance_id;
pj_bool_t outb_disable;
pjsua_transport_config udp_cfg;
pjsua_transport_config rtp_cfg;
pj_bool_t enable_rtcp_mux;
Expand Down
23 changes: 22 additions & 1 deletion pjsip-apps/src/pjsua/pjsua_app_config.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -97,6 +97,9 @@ static void usage(void)
PJSIP_SESS_TIMER_DEF_SE);
puts (" --timer-min-se=N Session timers minimum expiration period, in secs (def:90)");
puts (" --outb-rid=string Set SIP outbound reg-id (default:1)");
puts (" --instance-id=URN Set the SIP instance ID of all accounts, e.g.");
puts (" \"<urn:uuid:00000000-0000-1000-8000-AABBCCDDEEFF>\"");
puts (" --outb-disable Disable SIP outbound (RFC 5626) for all accounts");
puts (" --auto-update-nat=N Enable/disable SIP traversal behind symmetric NAT (def: 1)");
puts (" 0: disabled, 1:enabled with exception, 2: fully enabled");
puts (" --disable-stun Disable STUN for this account");
Expand Down Expand Up @@ -409,6 +412,7 @@ static pj_status_t parse_args(int argc, char *argv[],
OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD, OPT_AKA_OP, OPT_AKA_AMF,
OPT_REG_RETRY_INTERVAL, OPT_REG_USE_PROXY,
OPT_MWI, OPT_NAMESERVER, OPT_STUN_SRV, OPT_UPNP, OPT_OUTB_RID,
OPT_INSTANCE_ID, OPT_OUTB_DISABLE,
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
OPT_AUTO_ANSWER, OPT_AUTO_PLAY, OPT_AUTO_PLAY_HANGUP, OPT_AUTO_LOOP,
OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO,
Expand Down Expand Up @@ -596,6 +600,8 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "timer-se", 1, 0, OPT_TIMER_SE},
{ "timer-min-se", 1, 0, OPT_TIMER_MIN_SE},
{ "outb-rid", 1, 0, OPT_OUTB_RID},
{ "instance-id", 1, 0, OPT_INSTANCE_ID},
{ "outb-disable", 0, 0, OPT_OUTB_DISABLE},
{ "video", 0, 0, OPT_VIDEO},
{ "text", 0, 0, OPT_TEXT},
{ "text-red", 1, 0, OPT_TEXT_RED},
Expand Down Expand Up @@ -911,6 +917,14 @@ static pj_status_t parse_args(int argc, char *argv[],
cur_acc->rfc5626_reg_id = pj_str(pj_optarg);
break;

case OPT_INSTANCE_ID:
cfg->instance_id = pj_str(pj_optarg);
break;

case OPT_OUTB_DISABLE:
cfg->outb_disable = PJ_TRUE;
break;

case OPT_USE_IMS: /* Activate IMS settings */
cur_acc->auth_pref.initial_auth = PJ_TRUE;
break;
Expand Down Expand Up @@ -2399,6 +2413,13 @@ int write_settings(pjsua_app_config *config, char *buf, pj_size_t max)
if (config->cfg.server_failover)
cfg_add(&cfg, max, "--server-failover\n");

if (config->instance_id.slen) {
cfg_addf(&cfg, max, "--instance-id %.*s\n",
(int)config->instance_id.slen, config->instance_id.ptr);
}
if (config->outb_disable)
cfg_add(&cfg, max, "--outb-disable\n");

/* Outbound proxy */
for (i=0; i<config->cfg.outbound_proxy_cnt; ++i) {
cfg_addf(&cfg, max, "--outbound %.*s\n",
Expand Down
5 changes: 4 additions & 1 deletion pjsip-apps/src/pjsua/pjsua_app_legacy.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -1051,6 +1051,9 @@ static void ui_add_account(pjsua_transport_config *rtp_cfg)

acc_cfg.rtp_cfg = *rtp_cfg;
acc_cfg.txt_red_level = app_config.txt_red_level;
acc_cfg.rfc5626_instance_id = app_config.instance_id;
if (app_config.outb_disable)
acc_cfg.use_rfc5626 = PJ_FALSE;
app_config_init_video(&acc_cfg);

status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL);
Expand Down
7 changes: 7 additions & 0 deletions pjsip/include/pjsua-lib/pjsua.h
Original file line number Diff line number Diff line change
Expand Up @@ -4841,6 +4841,13 @@ typedef struct pjsua_acc_config
* value will look like "<urn:uuid:00000000-0000-1000-8000-AABBCCDDEEFF>"
* without the doublequote.
*
* An instance ID set here is sent in every REGISTER, also without SIP
* outbound. Registrars such as Kamailio and Flexisip then treat contacts
* with the same instance ID as one device and replace the older binding,
* so the ID must be unique to the device and persistent (RFC 5626
* section 4.1). The generated one is sent only with outbound: it is the
* same for all instances on one host, and on iOS ("localhost").
*
* Default: empty
*/
pj_str_t rfc5626_instance_id;
Expand Down
7 changes: 7 additions & 0 deletions pjsip/include/pjsua2/account.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,13 @@ struct AccountNatConfig : public PersistentObject
* value will look like "<urn:uuid:00000000-0000-1000-8000-AABBCCDDEEFF>"
* without the double-quotes.
*
* An instance ID set here is sent in every REGISTER, also without SIP
* outbound. Registrars such as Kamailio and Flexisip then treat contacts
* with the same instance ID as one device and replace the older binding,
* so the ID must be unique to the device and persistent (RFC 5626
* section 4.1). The generated one is sent only with outbound: it is the
* same for all instances on one host, and on iOS ("localhost").
*
* Default: empty
*/
string sipOutboundInstanceId;
Expand Down
25 changes: 17 additions & 8 deletions pjsip/src/pjsua-lib/pjsua_acc.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ static void init_outbound_setting(pjsua_acc *acc)
(int)acc_cfg->rfc5626_instance_id.slen,
acc_cfg->rfc5626_instance_id.ptr);
acc->rfc5626_instprm.slen = len;
PJ_LOG(4,(THIS_FILE, "Acc %d: instance ID %.*s is sent in every "
"REGISTER", acc->index,
(int)acc_cfg->rfc5626_instance_id.slen,
acc_cfg->rfc5626_instance_id.ptr));
}

if (acc_cfg->rfc5626_reg_id.slen == 0) {
Expand All @@ -279,7 +283,8 @@ static void init_outbound_setting(pjsua_acc *acc)
acc->rfc5626_regprm.slen = len;
}

acc->rfc5626_status = OUTBOUND_WANTED;
if (acc_cfg->use_rfc5626)
acc->rfc5626_status = OUTBOUND_WANTED;
}

/* Forget a 439 recorded against a first hop we may no longer be talking to,
Expand Down Expand Up @@ -532,7 +537,7 @@ static pj_status_t initialize_acc(unsigned acc_id)
/* If SIP outbound is enabled, generate instance and reg ID if they are
* not specified
*/
if (acc_cfg->use_rfc5626) {
if (acc_cfg->use_rfc5626 || acc_cfg->rfc5626_instance_id.slen) {
init_outbound_setting(acc);
}

Expand Down Expand Up @@ -2163,6 +2168,7 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc,
pjsua_acc_config *acc_cfg = &acc->cfg;
const pj_str_t *contact = new_contact ? new_contact : &acc->contact;
pj_bool_t need_outbound = PJ_FALSE;
pj_bool_t need_instance;
pj_str_t prev_reg_contact = acc->reg_contact;
unsigned prev_status = acc->rfc5626_status;
const pj_str_t tcp_param = pj_str(";transport=tcp");
Expand Down Expand Up @@ -2192,6 +2198,10 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc,
need_outbound = PJ_TRUE;

done:
/* A configured instance ID is sent without reg-id too, which RFC 5626
* section 6 allows. The generated one only goes with outbound.
*/
need_instance = need_outbound || acc_cfg->rfc5626_instance_id.slen;
{
pj_ssize_t len;
pj_str_t reg_contact;
Expand All @@ -2200,8 +2210,8 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc,
acc->cfg.contact_params.slen +
acc->cfg.reg_contact_params.slen +
acc->cfg.reg_contact_uri_params.slen +
(need_outbound?
(acc->rfc5626_instprm.slen + acc->rfc5626_regprm.slen): 0) +
(need_outbound? acc->rfc5626_regprm.slen: 0) +
(need_instance? acc->rfc5626_instprm.slen: 0) +
5; /* allowance */
reg_contact.ptr = (char*) pj_pool_alloc(acc->pool, len);

Expand Down Expand Up @@ -2272,14 +2282,13 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc,
if (need_outbound) {
acc->rfc5626_status = OUTBOUND_WANTED;

/* Need to use outbound, append the contact with
* +sip.instance and reg-id parameters.
*/
/* Need to use outbound, append the reg-id parameter */
pj_strcat(&reg_contact, &acc->rfc5626_regprm);
pj_strcat(&reg_contact, &acc->rfc5626_instprm);
} else {
acc->rfc5626_status = OUTBOUND_NA;
}
if (need_instance)
pj_strcat(&reg_contact, &acc->rfc5626_instprm);

/* Contact params */
pj_strcat(&reg_contact, &acc->cfg.reg_contact_params);
Expand Down
14 changes: 14 additions & 0 deletions tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
# An instance ID with SIP outbound disabled, over TCP: the REGISTER carries
# +sip.instance without reg-id and does not offer outbound. SIPp checks the
# REGISTER, see the XML scenario.
#
PJSUA = ['--null-audio --outb-disable '
'--instance-id="<urn:uuid:00000000-0000-1000-8000-000a95a0e128>"']

# Add the account only once SIPp listens: a start-up REGISTER would be
# refused, and an "rr" racing it could be lost to PJSIP_EBUSY.
PJSUA_EXPECTS = [[0, "", "+a sip:pjsua@127.0.0.1 "
"sip:127.0.0.1:$SIPP_PORT;transport=tcp * pjsua pjsua"]]

SIPP_TRANSPORT = "t1"
45 changes: 45 additions & 0 deletions tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">

<!-- An account with an instance ID and SIP outbound (RFC 5626) disabled, -->
<!-- over TCP: the Contact carries +sip.instance without reg-id, and the -->
<!-- REGISTER does not offer outbound (#5292). -->

<scenario name="REGISTER with +sip.instance and outbound disabled">
<recv request="REGISTER" crlf="true">
<action>
<ereg regexp="\+sip\.instance=.*000a95a0e128" search_in="hdr"
header="Contact:" check_it="true" assign_to="1"/>
<ereg regexp="reg-id=" search_in="hdr" header="Contact:"
check_it_inverse="true" assign_to="2"/>
<ereg regexp="outbound" search_in="hdr" header="Supported:"
check_it_inverse="true" assign_to="3"/>
</action>
</recv>

<send>
<![CDATA[

SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
[last_Contact:]
Expires: 300
Content-Length: 0

]]>
</send>

<!-- The variables only carry the checks above. -->
<Reference variables="1,2,3"/>

<!-- definition of the response time repartition table (unit is ms) -->
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>

<!-- definition of the call length repartition table (unit is ms) -->
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>

</scenario>
13 changes: 13 additions & 0 deletions tests/pjsua/scripts-sipp/uas-register-instance-norequire.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# As uas-register-outbound-norequire, with an instance ID configured: the
# refresh keeps +sip.instance. SIPp checks the REGISTERs, see the XML scenario.
#
PJSUA = ['--null-audio '
'--instance-id="<urn:uuid:00000000-0000-1000-8000-000a95a0e128>"']

# Add the account only once SIPp listens: a start-up REGISTER would be
# refused, and an "rr" racing it could be lost to PJSIP_EBUSY.
PJSUA_EXPECTS = [[0, "", "+a sip:pjsua@127.0.0.1 "
"sip:127.0.0.1:$SIPP_PORT;transport=tcp * pjsua pjsua"]]

SIPP_TRANSPORT = "t1"
69 changes: 69 additions & 0 deletions tests/pjsua/scripts-sipp/uas-register-instance-norequire.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">

<!-- Registrar without SIP outbound (RFC 5626) support, over TCP, and an -->
<!-- account with a configured instance ID: the refresh Contact drops -->
<!-- reg-id but keeps +sip.instance (#5292). -->

<scenario name="REGISTER refresh keeps a configured +sip.instance">
<!-- The first REGISTER must offer outbound, or the refresh below would -->
<!-- have no reg-id to drop. -->
<recv request="REGISTER" crlf="true">
<action>
<ereg regexp="reg-id=" search_in="hdr" header="Contact:"
check_it="true" assign_to="1"/>
</action>
</recv>

<send>
<![CDATA[

SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
[last_Contact:]
Expires: 10
Content-Length: 0

]]>
</send>

<!-- The refresh, sent 5 seconds before the 10 seconds expire. -->
<recv request="REGISTER" crlf="true">
<action>
<ereg regexp="\+sip\.instance=.*000a95a0e128" search_in="hdr"
header="Contact:" check_it="true" assign_to="2"/>
<ereg regexp="reg-id=" search_in="hdr" header="Contact:"
check_it_inverse="true" assign_to="3"/>
</action>
</recv>

<send>
<![CDATA[

SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
[last_Contact:]
Expires: 10
Content-Length: 0

]]>
</send>

<!-- The variables only carry the checks above. -->
<Reference variables="1,2,3"/>

<!-- definition of the response time repartition table (unit is ms) -->
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>

<!-- definition of the call length repartition table (unit is ms) -->
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>

</scenario>
10 changes: 10 additions & 0 deletions tests/pjsua/scripts-sipp/uas-register-instance-udp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# pjsua never offers SIP outbound over UDP, so +sip.instance appears here
# only because an instance ID is configured. SIPp checks the REGISTER, see
# the XML scenario.
#
PJSUA = ['--null-audio --id=sip:pjsua@127.0.0.1 --registrar=$SIPP_URI '
'--realm=* --username=pjsua --password=pjsua '
'--instance-id="<urn:uuid:00000000-0000-1000-8000-000a95a0e128>"']

PJSUA_EXPECTS = []
Loading
Loading