|
|
|
@ -24992,6 +24992,145 @@ static int handle_request_update(struct sip_pvt *p, struct sip_request *req)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* \internal \brief Check Session Timers for an INVITE request
|
|
|
|
|
*
|
|
|
|
|
* \retval 0 ok
|
|
|
|
|
* \retval -1 failure
|
|
|
|
|
*/
|
|
|
|
|
static int handle_request_invite_st(struct sip_pvt *p, struct sip_request *req,
|
|
|
|
|
const char *required, int reinvite)
|
|
|
|
|
{
|
|
|
|
|
const char *p_uac_se_hdr; /* UAC's Session-Expires header string */
|
|
|
|
|
const char *p_uac_min_se; /* UAC's requested Min-SE interval (char string) */
|
|
|
|
|
int uac_max_se = -1; /* UAC's Session-Expires in integer format */
|
|
|
|
|
int uac_min_se = -1; /* UAC's Min-SE in integer format */
|
|
|
|
|
int st_active = FALSE; /* Session-Timer on/off boolean */
|
|
|
|
|
int st_interval = 0; /* Session-Timer negotiated refresh interval */
|
|
|
|
|
enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher */
|
|
|
|
|
int dlg_min_se = -1;
|
|
|
|
|
int dlg_max_se = global_max_se;
|
|
|
|
|
int rtn;
|
|
|
|
|
|
|
|
|
|
/* Session-Timers */
|
|
|
|
|
if ((p->sipoptions & SIP_OPT_TIMER)) {
|
|
|
|
|
enum st_refresher_param st_ref_param = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
/* The UAC has requested session-timers for this session. Negotiate
|
|
|
|
|
the session refresh interval and who will be the refresher */
|
|
|
|
|
ast_debug(2, "Incoming INVITE with 'timer' option supported\n");
|
|
|
|
|
|
|
|
|
|
/* Allocate Session-Timers struct w/in the dialog */
|
|
|
|
|
if (!p->stimer) {
|
|
|
|
|
sip_st_alloc(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the Session-Expires header */
|
|
|
|
|
p_uac_se_hdr = sip_get_header(req, "Session-Expires");
|
|
|
|
|
if (!ast_strlen_zero(p_uac_se_hdr)) {
|
|
|
|
|
ast_debug(2, "INVITE also has \"Session-Expires\" header.\n");
|
|
|
|
|
rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
|
|
|
|
|
tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
|
|
|
|
|
if (rtn != 0) {
|
|
|
|
|
transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the Min-SE header */
|
|
|
|
|
p_uac_min_se = sip_get_header(req, "Min-SE");
|
|
|
|
|
if (!ast_strlen_zero(p_uac_min_se)) {
|
|
|
|
|
ast_debug(2, "INVITE also has \"Min-SE\" header.\n");
|
|
|
|
|
rtn = parse_minse(p_uac_min_se, &uac_min_se);
|
|
|
|
|
if (rtn != 0) {
|
|
|
|
|
transmit_response_reliable(p, "400 Min-SE Invalid Syntax", req);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlg_min_se = st_get_se(p, FALSE);
|
|
|
|
|
switch (st_get_mode(p, 1)) {
|
|
|
|
|
case SESSION_TIMER_MODE_ACCEPT:
|
|
|
|
|
case SESSION_TIMER_MODE_ORIGINATE:
|
|
|
|
|
if (uac_max_se > 0 && uac_max_se < dlg_min_se) {
|
|
|
|
|
transmit_response_with_minse(p, "422 Session Interval Too Small", req, dlg_min_se);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->stimer->st_active_peer_ua = TRUE;
|
|
|
|
|
st_active = TRUE;
|
|
|
|
|
if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
|
|
|
|
|
tmp_st_ref = st_get_refresher(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlg_max_se = st_get_se(p, TRUE);
|
|
|
|
|
if (uac_max_se > 0) {
|
|
|
|
|
if (dlg_max_se >= uac_min_se) {
|
|
|
|
|
st_interval = (uac_max_se < dlg_max_se) ? uac_max_se : dlg_max_se;
|
|
|
|
|
} else {
|
|
|
|
|
st_interval = uac_max_se;
|
|
|
|
|
}
|
|
|
|
|
} else if (uac_min_se > 0) {
|
|
|
|
|
st_interval = MAX(dlg_max_se, uac_min_se);
|
|
|
|
|
} else {
|
|
|
|
|
st_interval = dlg_max_se;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SESSION_TIMER_MODE_REFUSE:
|
|
|
|
|
if (p->reqsipoptions & SIP_OPT_TIMER) {
|
|
|
|
|
transmit_response_with_unsupported(p, "420 Option Disabled", req, required);
|
|
|
|
|
ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ast_log(LOG_ERROR, "Internal Error %d at %s:%d\n", st_get_mode(p, 1), __FILE__, __LINE__);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* The UAC did not request session-timers. Asterisk (UAS), will now decide
|
|
|
|
|
(based on session-timer-mode in sip.conf) whether to run session-timers for
|
|
|
|
|
this session or not. */
|
|
|
|
|
switch (st_get_mode(p, 1)) {
|
|
|
|
|
case SESSION_TIMER_MODE_ORIGINATE:
|
|
|
|
|
st_active = TRUE;
|
|
|
|
|
st_interval = st_get_se(p, TRUE);
|
|
|
|
|
tmp_st_ref = SESSION_TIMER_REFRESHER_US;
|
|
|
|
|
p->stimer->st_active_peer_ua = (p->sipoptions & SIP_OPT_TIMER) ? TRUE : FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reinvite == 0) {
|
|
|
|
|
/* Session-Timers: Start session refresh timer based on negotiation/config */
|
|
|
|
|
if (st_active == TRUE) {
|
|
|
|
|
p->stimer->st_active = TRUE;
|
|
|
|
|
p->stimer->st_interval = st_interval;
|
|
|
|
|
p->stimer->st_ref = tmp_st_ref;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (p->stimer->st_active == TRUE) {
|
|
|
|
|
/* Session-Timers: A re-invite request sent within a dialog will serve as
|
|
|
|
|
a refresh request, no matter whether the re-invite was sent for refreshing
|
|
|
|
|
the session or modifying it.*/
|
|
|
|
|
ast_debug (2, "Restarting session-timers on a refresh - %s\n", p->callid);
|
|
|
|
|
|
|
|
|
|
/* The UAC may be adjusting the session-timers mid-session */
|
|
|
|
|
if (st_interval > 0) {
|
|
|
|
|
p->stimer->st_interval = st_interval;
|
|
|
|
|
p->stimer->st_ref = tmp_st_ref;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \brief Handle incoming INVITE request
|
|
|
|
|
* \note If the INVITE has a Replaces header, it is part of an
|
|
|
|
@ -25010,19 +25149,9 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
|
|
|
|
|
struct ast_channel *c = NULL; /* New channel */
|
|
|
|
|
struct sip_peer *authpeer = NULL; /* Matching Peer */
|
|
|
|
|
int reinvite = 0;
|
|
|
|
|
int rtn;
|
|
|
|
|
struct ast_party_redirecting redirecting;
|
|
|
|
|
struct ast_set_party_redirecting update_redirecting;
|
|
|
|
|
|
|
|
|
|
const char *p_uac_se_hdr; /* UAC's Session-Expires header string */
|
|
|
|
|
const char *p_uac_min_se; /* UAC's requested Min-SE interval (char string) */
|
|
|
|
|
int uac_max_se = -1; /* UAC's Session-Expires in integer format */
|
|
|
|
|
int uac_min_se = -1; /* UAC's Min-SE in integer format */
|
|
|
|
|
int st_active = FALSE; /* Session-Timer on/off boolean */
|
|
|
|
|
int st_interval = 0; /* Session-Timer negotiated refresh interval */
|
|
|
|
|
enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher */
|
|
|
|
|
int dlg_min_se = -1;
|
|
|
|
|
int dlg_max_se = global_max_se;
|
|
|
|
|
struct {
|
|
|
|
|
char exten[AST_MAX_EXTENSION];
|
|
|
|
|
char context[AST_MAX_CONTEXT];
|
|
|
|
@ -25481,6 +25610,14 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
|
|
|
|
|
/* Initialize our tag */
|
|
|
|
|
|
|
|
|
|
make_our_tag(p);
|
|
|
|
|
|
|
|
|
|
if (handle_request_invite_st(p, req, required, reinvite)) {
|
|
|
|
|
p->invitestate = INV_COMPLETED;
|
|
|
|
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
|
|
|
|
res = INV_REQ_ERROR;
|
|
|
|
|
goto request_invite_cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* First invitation - create the channel. Allocation
|
|
|
|
|
* failures are handled below. */
|
|
|
|
|
|
|
|
|
@ -25515,6 +25652,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
|
|
|
|
|
}
|
|
|
|
|
if (!req->ignore)
|
|
|
|
|
reinvite = 1;
|
|
|
|
|
|
|
|
|
|
if (handle_request_invite_st(p, req, required, reinvite)) {
|
|
|
|
|
p->invitestate = INV_COMPLETED;
|
|
|
|
|
if (!p->lastinvite) {
|
|
|
|
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
res = INV_REQ_ERROR;
|
|
|
|
|
goto request_invite_cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = p->owner;
|
|
|
|
|
change_redirecting_information(p, req, &redirecting, &update_redirecting, FALSE); /*Will return immediately if no Diversion header is present */
|
|
|
|
|
if (c) {
|
|
|
|
@ -25526,140 +25673,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
|
|
|
|
|
/* Check if OLI/ANI-II is present in From: */
|
|
|
|
|
parse_oli(req, p->owner);
|
|
|
|
|
|
|
|
|
|
/* Session-Timers */
|
|
|
|
|
if ((p->sipoptions & SIP_OPT_TIMER)) {
|
|
|
|
|
enum st_refresher_param st_ref_param = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
/* The UAC has requested session-timers for this session. Negotiate
|
|
|
|
|
the session refresh interval and who will be the refresher */
|
|
|
|
|
ast_debug(2, "Incoming INVITE with 'timer' option supported\n");
|
|
|
|
|
|
|
|
|
|
/* Allocate Session-Timers struct w/in the dialog */
|
|
|
|
|
if (!p->stimer)
|
|
|
|
|
sip_st_alloc(p);
|
|
|
|
|
|
|
|
|
|
/* Parse the Session-Expires header */
|
|
|
|
|
p_uac_se_hdr = sip_get_header(req, "Session-Expires");
|
|
|
|
|
if (!ast_strlen_zero(p_uac_se_hdr)) {
|
|
|
|
|
ast_debug(2, "INVITE also has \"Session-Expires\" header.\n");
|
|
|
|
|
rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
|
|
|
|
|
tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
|
|
|
|
|
if (rtn != 0) {
|
|
|
|
|
transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
|
|
|
|
|
p->invitestate = INV_COMPLETED;
|
|
|
|
|
if (!p->lastinvite) {
|
|
|
|
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
res = INV_REQ_ERROR;
|
|
|
|
|
goto request_invite_cleanup;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the Min-SE header */
|
|
|
|
|
p_uac_min_se = sip_get_header(req, "Min-SE");
|
|
|
|
|
if (!ast_strlen_zero(p_uac_min_se)) {
|
|
|
|
|
ast_debug(2, "INVITE also has \"Min-SE\" header.\n");
|
|
|
|
|
rtn = parse_minse(p_uac_min_se, &uac_min_se);
|
|
|
|
|
if (rtn != 0) {
|
|
|
|
|
transmit_response_reliable(p, "400 Min-SE Invalid Syntax", req);
|
|
|
|
|
p->invitestate = INV_COMPLETED;
|
|
|
|
|
if (!p->lastinvite) {
|
|
|
|
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
res = INV_REQ_ERROR;
|
|
|
|
|
goto request_invite_cleanup;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlg_min_se = st_get_se(p, FALSE);
|
|
|
|
|
switch (st_get_mode(p, 1)) {
|
|
|
|
|
case SESSION_TIMER_MODE_ACCEPT:
|
|
|
|
|
case SESSION_TIMER_MODE_ORIGINATE:
|
|
|
|
|
if (uac_max_se > 0 && uac_max_se < dlg_min_se) {
|
|
|
|
|
transmit_response_with_minse(p, "422 Session Interval Too Small", req, dlg_min_se);
|
|
|
|
|
p->invitestate = INV_COMPLETED;
|
|
|
|
|
if (!p->lastinvite) {
|
|
|
|
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
res = INV_REQ_ERROR;
|
|
|
|
|
goto request_invite_cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->stimer->st_active_peer_ua = TRUE;
|
|
|
|
|
st_active = TRUE;
|
|
|
|
|
if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
|
|
|
|
|
tmp_st_ref = st_get_refresher(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlg_max_se = st_get_se(p, TRUE);
|
|
|
|
|
if (uac_max_se > 0) {
|
|
|
|
|
if (dlg_max_se >= uac_min_se) {
|
|
|
|
|
st_interval = (uac_max_se < dlg_max_se) ? uac_max_se : dlg_max_se;
|
|
|
|
|
} else {
|
|
|
|
|
st_interval = uac_max_se;
|
|
|
|
|
}
|
|
|
|
|
} else if (uac_min_se > 0) {
|
|
|
|
|
st_interval = MAX(dlg_max_se, uac_min_se);
|
|
|
|
|
} else {
|
|
|
|
|
st_interval = dlg_max_se;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SESSION_TIMER_MODE_REFUSE:
|
|
|
|
|
if (p->reqsipoptions & SIP_OPT_TIMER) {
|
|
|
|
|
transmit_response_with_unsupported(p, "420 Option Disabled", req, required);
|
|
|
|
|
ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required);
|
|
|
|
|
p->invitestate = INV_COMPLETED;
|
|
|
|
|
if (!p->lastinvite) {
|
|
|
|
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
res = INV_REQ_ERROR;
|
|
|
|
|
goto request_invite_cleanup;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ast_log(LOG_ERROR, "Internal Error %d at %s:%d\n", st_get_mode(p, 1), __FILE__, __LINE__);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* The UAC did not request session-timers. Asterisk (UAS), will now decide
|
|
|
|
|
(based on session-timer-mode in sip.conf) whether to run session-timers for
|
|
|
|
|
this session or not. */
|
|
|
|
|
switch (st_get_mode(p, 1)) {
|
|
|
|
|
case SESSION_TIMER_MODE_ORIGINATE:
|
|
|
|
|
st_active = TRUE;
|
|
|
|
|
st_interval = st_get_se(p, TRUE);
|
|
|
|
|
tmp_st_ref = SESSION_TIMER_REFRESHER_US;
|
|
|
|
|
p->stimer->st_active_peer_ua = (p->sipoptions & SIP_OPT_TIMER) ? TRUE : FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reinvite == 0) {
|
|
|
|
|
/* Session-Timers: Start session refresh timer based on negotiation/config */
|
|
|
|
|
if (st_active == TRUE) {
|
|
|
|
|
p->stimer->st_active = TRUE;
|
|
|
|
|
p->stimer->st_interval = st_interval;
|
|
|
|
|
p->stimer->st_ref = tmp_st_ref;
|
|
|
|
|
if (p->stimer->st_active == TRUE) {
|
|
|
|
|
if (reinvite == 0) {
|
|
|
|
|
start_session_timer(p);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (p->stimer->st_active == TRUE) {
|
|
|
|
|
/* Session-Timers: A re-invite request sent within a dialog will serve as
|
|
|
|
|
a refresh request, no matter whether the re-invite was sent for refreshing
|
|
|
|
|
the session or modifying it.*/
|
|
|
|
|
ast_debug (2, "Restarting session-timers on a refresh - %s\n", p->callid);
|
|
|
|
|
|
|
|
|
|
/* The UAC may be adjusting the session-timers mid-session */
|
|
|
|
|
if (st_interval > 0) {
|
|
|
|
|
p->stimer->st_interval = st_interval;
|
|
|
|
|
p->stimer->st_ref = tmp_st_ref;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
restart_session_timer(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|