fix: Repetitions (T1 timer) during INVITE could cause loss of audio

This commit is contained in:
Thomas Ries 2019-11-09 17:41:08 +00:00
parent 50674bf8e7
commit a75f5c89cd
7 changed files with 74 additions and 32 deletions

View File

@ -1,5 +1,7 @@
0.8.3dev 0.8.3dev
======== ========
09-Nov-2019: - fix: Repetitions (T1 timer) during INVITE could
cause loss of audio
10-May-2019: - fix: TCP fragment reassembly fails 10-May-2019: - fix: TCP fragment reassembly fails
17-Mar-2018: - Improved syslog output (more consistent behavior) 17-Mar-2018: - Improved syslog output (more consistent behavior)
17-Jan-2018: - Deal with OPTION requests that have Max-Forwards=0 17-Jan-2018: - Deal with OPTION requests that have Max-Forwards=0

View File

@ -417,7 +417,7 @@ static void send_top_of_que(int nolock) {
sts = rtp_relay_stop_fwd(&callid, sts = rtp_relay_stop_fwd(&callid,
m->errret->direction, m->errret->direction,
m->errret->media_stream_no, m->errret->media_stream_no,
nolock); -1, nolock);
if (sts != STS_SUCCESS) { if (sts != STS_SUCCESS) {
/* force the streams to timeout on next occasion */ /* force the streams to timeout on next occasion */
m->errret->timestamp=0; m->errret->timestamp=0;

View File

@ -148,8 +148,8 @@ DEBUGC(DBCLASS_PROXY,"index i=%i",i);
/* if this is CANCEL/BYE request, stop RTP proxying */ /* if this is CANCEL/BYE request, stop RTP proxying */
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
/* stop the RTP proxying stream(s) */ /* stop the RTP proxying stream(s) */
rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING, -1);
rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING); rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING, -1);
/* check for incoming request */ /* check for incoming request */
} else if (MSG_IS_INVITE(request)) { } else if (MSG_IS_INVITE(request)) {
@ -221,8 +221,8 @@ sts=sip_obscure_callid(ticket);
/* if this is CANCEL/BYE request, stop RTP proxying */ /* if this is CANCEL/BYE request, stop RTP proxying */
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
/* stop the RTP proxying stream(s) */ /* stop the RTP proxying stream(s) */
rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING, -1);
rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING); rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING, -1);
} }
sts=sip_obscure_callid(ticket); sts=sip_obscure_callid(ticket);
@ -487,6 +487,7 @@ int proxy_response (sip_ticket_t *ticket) {
char *buffer; char *buffer;
size_t buflen; size_t buflen;
osip_message_t *response; osip_message_t *response;
int cseq;
DEBUGC(DBCLASS_PROXY,"proxy_response"); DEBUGC(DBCLASS_PROXY,"proxy_response");
@ -550,8 +551,24 @@ sts=sip_obscure_callid(ticket);
} else if ((MSG_IS_STATUS_4XX(response)) || } else if ((MSG_IS_STATUS_4XX(response)) ||
(MSG_IS_STATUS_5XX(response)) || (MSG_IS_STATUS_5XX(response)) ||
(MSG_IS_STATUS_6XX(response))) { (MSG_IS_STATUS_6XX(response))) {
rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING); //&&& in case of repetitions, this logic breaks!
rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING); // INVITE w/o auth credentials
// repeated INVITE w/o auth credentials
// 407 response to 1st INVITE
// INVITE w/ auth credentials
// 407 response to 2nd INVITE
// -> Bzzz, siproxd cancels the set-up RTP ports from INVITE(3) above
// I could:
// - simply ingore these stati (rtp relay would time-out eventually)
// - reduce rtp timeout for this stream and have if time-out quicker
// - somehow remember the CSEQ number of the last request and only do
// something if this CSEQ is equal (or higher) to the last request that changed
// the RTP relay setup
// tmp = osip_cseq_get_number(sip_msg->cseq);
cseq = atoi(osip_cseq_get_number(response->cseq));
rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING, cseq);
rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING, cseq);
} }
} /* if INVITE */ } /* if INVITE */
@ -637,8 +654,11 @@ sts=sip_obscure_callid(ticket);
} else if ((MSG_IS_STATUS_4XX(response)) || } else if ((MSG_IS_STATUS_4XX(response)) ||
(MSG_IS_STATUS_5XX(response)) || (MSG_IS_STATUS_5XX(response)) ||
(MSG_IS_STATUS_6XX(response))) { (MSG_IS_STATUS_6XX(response))) {
rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING); //&&& same here, repetitions break this logic
rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING); cseq = atoi(osip_cseq_get_number(response->cseq));
rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING, cseq);
rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING, cseq);
} }
} /* if INVITE */ } /* if INVITE */
@ -782,6 +802,7 @@ int proxy_rewrite_invitation_body(sip_ticket_t *ticket, int direction){
int call_direction=0; int call_direction=0;
int have_c_media=0; int have_c_media=0;
int isrtp = 0 ; int isrtp = 0 ;
int cseq = 0;
if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS;
@ -1116,13 +1137,14 @@ if (configuration.debuglevel)
/* /*
* Start the RTP stream * Start the RTP stream
*/ */
cseq = atoi(osip_cseq_get_number(mymsg->cseq));
sts = rtp_start_fwd(osip_message_get_call_id(mymsg), sts = rtp_start_fwd(osip_message_get_call_id(mymsg),
client_id, client_id,
rtp_direction, call_direction, rtp_direction, call_direction,
media_stream_no, media_stream_no,
map_addr, &map_port, map_addr, &map_port,
addr_media, msg_port, addr_media, msg_port,
isrtp); isrtp, cseq);
if (sts == STS_SUCCESS) { if (sts == STS_SUCCESS) {
/* and rewrite the port */ /* and rewrite the port */

View File

@ -77,7 +77,7 @@ int rtp_start_fwd (osip_call_id_t *callid, client_id_t client_id,
int direction, int call_direction, int media_stream_no, int direction, int call_direction, int media_stream_no,
struct in_addr local_ipaddr, int *local_port, struct in_addr local_ipaddr, int *local_port,
struct in_addr remote_ipaddr, int remote_port, struct in_addr remote_ipaddr, int remote_port,
int isrtp) { int isrtp, int cseq) {
int sts=STS_FAILURE; int sts=STS_FAILURE;
int dejitter=0; int dejitter=0;
@ -94,7 +94,8 @@ int rtp_start_fwd (osip_call_id_t *callid, client_id_t client_id,
sts = rtp_relay_start_fwd (callid, client_id, sts = rtp_relay_start_fwd (callid, client_id,
direction, call_direction, media_stream_no, direction, call_direction, media_stream_no,
local_ipaddr, local_port, local_ipaddr, local_port,
remote_ipaddr, remote_port, dejitter); remote_ipaddr, remote_port, dejitter,
cseq);
} else { } else {
ERROR("CONFIG: rtp_proxy_enable has invalid value: %d", ERROR("CONFIG: rtp_proxy_enable has invalid value: %d",
configuration.rtp_proxy_enable); configuration.rtp_proxy_enable);
@ -111,13 +112,13 @@ int rtp_start_fwd (osip_call_id_t *callid, client_id_t client_id,
* STS_SUCCESS on success * STS_SUCCESS on success
* STS_FAILURE on error * STS_FAILURE on error
*/ */
int rtp_stop_fwd (osip_call_id_t *callid, int direction) { int rtp_stop_fwd (osip_call_id_t *callid, int direction, int cseq) {
int sts = STS_FAILURE; int sts = STS_FAILURE;
if (configuration.rtp_proxy_enable == 0) { if (configuration.rtp_proxy_enable == 0) {
sts = STS_SUCCESS; sts = STS_SUCCESS;
} else if (configuration.rtp_proxy_enable == 1) { // Relay } else if (configuration.rtp_proxy_enable == 1) { // Relay
sts = rtp_relay_stop_fwd(callid, direction, -1, LOCK_FDSET); sts = rtp_relay_stop_fwd(callid, direction, -1, cseq, LOCK_FDSET);
} else { } else {
ERROR("CONFIG: rtp_proxy_enable has invalid value: %d", ERROR("CONFIG: rtp_proxy_enable has invalid value: %d",
configuration.rtp_proxy_enable); configuration.rtp_proxy_enable);

View File

@ -49,6 +49,7 @@ typedef struct {
char callid_number[CALLIDNUM_SIZE]; /* call ID */ char callid_number[CALLIDNUM_SIZE]; /* call ID */
char callid_host[CALLIDHOST_SIZE]; /* --"-- */ char callid_host[CALLIDHOST_SIZE]; /* --"-- */
client_id_t client_id; client_id_t client_id;
int cseq;
int direction; /* Direction of RTP stream */ int direction; /* Direction of RTP stream */
int call_direction; /* Direction of Call DIR_x */ int call_direction; /* Direction of Call DIR_x */
int media_stream_no; int media_stream_no;
@ -69,9 +70,9 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
int rtp_direction, int call_direction, int media_stream_no, int rtp_direction, int call_direction, int media_stream_no,
struct in_addr local_ipaddr, int *local_port, struct in_addr local_ipaddr, int *local_port,
struct in_addr remote_ipaddr, int remote_port, struct in_addr remote_ipaddr, int remote_port,
int dejitter); int dejitter, int cseq);
int rtp_relay_stop_fwd (osip_call_id_t *callid, int rtp_direction, int rtp_relay_stop_fwd (osip_call_id_t *callid, int rtp_direction,
int media_stream_no, int nolock); int media_stream_no, int cseq, int nolock);
#define NOLOCK_FDSET 1 #define NOLOCK_FDSET 1
#define LOCK_FDSET 0 #define LOCK_FDSET 0

View File

@ -391,7 +391,7 @@ static void *rtpproxy_main(void *arg) {
sts = rtp_relay_stop_fwd(&callid, sts = rtp_relay_stop_fwd(&callid,
rtp_proxytable[i].direction, rtp_proxytable[i].direction,
rtp_proxytable[i].media_stream_no, rtp_proxytable[i].media_stream_no,
NOLOCK_FDSET); -1, NOLOCK_FDSET);
if (sts != STS_SUCCESS) { if (sts != STS_SUCCESS) {
/* force the streams to timeout on next occasion */ /* force the streams to timeout on next occasion */
rtp_proxytable[i].timestamp=0; rtp_proxytable[i].timestamp=0;
@ -426,7 +426,7 @@ static void *rtpproxy_main(void *arg) {
sts = rtp_relay_stop_fwd(&callid, sts = rtp_relay_stop_fwd(&callid,
rtp_proxytable[i].direction, rtp_proxytable[i].direction,
rtp_proxytable[i].media_stream_no, rtp_proxytable[i].media_stream_no,
NOLOCK_FDSET); -1, NOLOCK_FDSET);
if (sts != STS_SUCCESS) { if (sts != STS_SUCCESS) {
/* force the streams to timeout on next occasion */ /* force the streams to timeout on next occasion */
rtp_proxytable[i].timestamp=0; rtp_proxytable[i].timestamp=0;
@ -482,7 +482,7 @@ static void *rtpproxy_main(void *arg) {
* just one (unused?) has timed out. Seen with VoIPEX PBX! */ * just one (unused?) has timed out. Seen with VoIPEX PBX! */
rtp_relay_stop_fwd(&callid, rtp_proxytable[i].direction, rtp_relay_stop_fwd(&callid, rtp_proxytable[i].direction,
rtp_proxytable[i].media_stream_no, rtp_proxytable[i].media_stream_no,
NOLOCK_FDSET); -1, NOLOCK_FDSET);
} /* if */ } /* if */
} /* for i */ } /* for i */
} /* if (t>...) */ } /* if (t>...) */
@ -512,7 +512,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
int rtp_direction, int call_direction, int rtp_direction, int call_direction,
int media_stream_no, struct in_addr local_ipaddr, int media_stream_no, struct in_addr local_ipaddr,
int *local_port, struct in_addr remote_ipaddr, int *local_port, struct in_addr remote_ipaddr,
int remote_port, int dejitter) { int remote_port, int dejitter, int cseq) {
static int prev_used_port = 0; static int prev_used_port = 0;
int num_ports; int num_ports;
int i2, i, j; int i2, i, j;
@ -548,11 +548,12 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
} }
DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: starting RTP proxy " DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: starting RTP proxy "
"stream for: CallID=%s@%s [Client-ID=%s] (%s,%s) #=%i", "stream for: CallID=%s@%s [Client-ID=%s] (%s,%s) "
"cseq=%i #=%i",
callid->number, callid->host, client_id.idstring, callid->number, callid->host, client_id.idstring,
((rtp_direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP"), ((rtp_direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP"),
((call_direction == DIR_INCOMING) ? "incoming Call" : "outgoing Call"), ((call_direction == DIR_INCOMING) ? "incoming Call" : "outgoing Call"),
media_stream_no); cseq, media_stream_no);
/* lock mutex */ /* lock mutex */
#define return is_forbidden_in_this_code_section #define return is_forbidden_in_this_code_section
@ -603,6 +604,12 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
sizeof(remote_ipaddr)); sizeof(remote_ipaddr));
} }
/* update CSEQ in proxytable if the current request has a higher one */
if (cseq > rtp_proxytable[i].cseq) {
rtp_proxytable[i].cseq = cseq;
}
#ifdef USE_DEJITTER #ifdef USE_DEJITTER
/* Initialize up timecrontrol for dejitter function */ /* Initialize up timecrontrol for dejitter function */
if ((configuration.rtp_input_dejitter > 0) || if ((configuration.rtp_input_dejitter > 0) ||
@ -614,11 +621,12 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
/* return the already known local port number */ /* return the already known local port number */
DEBUGC(DBCLASS_RTP,"RTP stream already active idx=%i (remaddr=%s, " DEBUGC(DBCLASS_RTP,"RTP stream already active idx=%i (remaddr=%s, "
"remport=%i, lclport=%i, id=%s, #=%i)", "remport=%i, lclport=%i, id=%s, cseq=%i, #=%i)",
i, utils_inet_ntoa(remote_ipaddr), i, utils_inet_ntoa(remote_ipaddr),
rtp_proxytable[i].remote_port, rtp_proxytable[i].remote_port,
rtp_proxytable[i].local_port, rtp_proxytable[i].local_port,
rtp_proxytable[i].callid_number, rtp_proxytable[i].callid_number,
rtp_proxytable[i].cseq,
rtp_proxytable[i].media_stream_no); rtp_proxytable[i].media_stream_no);
*local_port=rtp_proxytable[i].local_port; *local_port=rtp_proxytable[i].local_port;
sts = STS_SUCCESS; sts = STS_SUCCESS;
@ -759,6 +767,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
/* store the passed Client-ID data */ /* store the passed Client-ID data */
memcpy(&rtp_proxytable[freeidx].client_id, &client_id, sizeof(client_id_t)); memcpy(&rtp_proxytable[freeidx].client_id, &client_id, sizeof(client_id_t));
rtp_proxytable[freeidx].cseq = cseq;
rtp_proxytable[freeidx].direction = rtp_direction; rtp_proxytable[freeidx].direction = rtp_direction;
rtp_proxytable[freeidx].call_direction = call_direction; rtp_proxytable[freeidx].call_direction = call_direction;
rtp_proxytable[freeidx].media_stream_no = media_stream_no; rtp_proxytable[freeidx].media_stream_no = media_stream_no;
@ -807,12 +816,13 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id,
//&&& //&&&
DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: started RTP proxy " DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: started RTP proxy "
"stream for: CallID=%s@%s [Client-ID=%s] %s #=%i idx=%i", "stream for: CallID=%s@%s [Client-ID=%s] %s cseq=%i, "
"#=%i idx=%i",
rtp_proxytable[freeidx].callid_number, rtp_proxytable[freeidx].callid_number,
rtp_proxytable[freeidx].callid_host, rtp_proxytable[freeidx].callid_host,
rtp_proxytable[freeidx].client_id.idstring, rtp_proxytable[freeidx].client_id.idstring,
((rtp_proxytable[freeidx].direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP"), ((rtp_proxytable[freeidx].direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP"),
rtp_proxytable[freeidx].media_stream_no, freeidx); cseq, rtp_proxytable[freeidx].media_stream_no, freeidx);
unlock_and_exit: unlock_and_exit:
/* unlock mutex */ /* unlock mutex */
@ -829,13 +839,15 @@ unlock_and_exit:
* if media_stream_no == -1, all media streams will be stopped, * if media_stream_no == -1, all media streams will be stopped,
* otherwise only the specified one. * otherwise only the specified one.
* *
* if cseq == -1, it will be ignored.
*
* RETURNS * RETURNS
* STS_SUCCESS on success * STS_SUCCESS on success
* STS_FAILURE on error * STS_FAILURE on error
*/ */
int rtp_relay_stop_fwd (osip_call_id_t *callid, int rtp_relay_stop_fwd (osip_call_id_t *callid,
int rtp_direction, int rtp_direction,
int media_stream_no, int nolock) { int media_stream_no, int cseq, int nolock) {
int i, sts; int i, sts;
int retsts=STS_SUCCESS; int retsts=STS_SUCCESS;
int got_match=0; int got_match=0;
@ -847,10 +859,10 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid,
} }
DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd: stopping RTP proxy " DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd: stopping RTP proxy "
"stream for: %s@%s (%s) (nolock=%i)", "stream for: %s@%s (%s), cseq=%i (nolock=%i)",
callid->number, callid->host, callid->number, callid->host,
((rtp_direction == DIR_INCOMING) ? "incoming" : "outgoing"), ((rtp_direction == DIR_INCOMING) ? "incoming" : "outgoing"),
nolock); cseq, nolock);
/* /*
* lock mutex - only if not requested to skip the lock. * lock mutex - only if not requested to skip the lock.
@ -892,7 +904,11 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid,
(compare_callid(callid, &cid) == STS_SUCCESS) && (compare_callid(callid, &cid) == STS_SUCCESS) &&
(rtp_proxytable[i].direction == rtp_direction) && (rtp_proxytable[i].direction == rtp_direction) &&
((media_stream_no < 0) || ((media_stream_no < 0) ||
(media_stream_no == rtp_proxytable[i].media_stream_no))) { (media_stream_no == rtp_proxytable[i].media_stream_no)) &&
((cseq < 0) ||
(cseq >= rtp_proxytable[i].cseq))
) {
/* close RTP sockets */ /* close RTP sockets */
if (rtp_proxytable[i].rtp_rx_sock > 0) { if (rtp_proxytable[i].rtp_rx_sock > 0) {
sts = close(rtp_proxytable[i].rtp_rx_sock); sts = close(rtp_proxytable[i].rtp_rx_sock);
@ -1024,7 +1040,7 @@ static void rtpproxy_kill( void ) {
cid.host = rtp_proxytable[i].callid_host; cid.host = rtp_proxytable[i].callid_host;
sts = rtp_relay_stop_fwd(&cid, rtp_proxytable[i].direction, sts = rtp_relay_stop_fwd(&cid, rtp_proxytable[i].direction,
rtp_proxytable[i].media_stream_no, rtp_proxytable[i].media_stream_no,
LOCK_FDSET); -1, LOCK_FDSET);
if (sts != STS_SUCCESS) { if (sts != STS_SUCCESS) {
DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd did return error"); DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd did return error");
} }

View File

@ -237,8 +237,8 @@ int rtp_start_fwd (osip_call_id_t *callid, client_id_t client_id, /*X*/
int direction, int call_direction, int media_stream_no, int direction, int call_direction, int media_stream_no,
struct in_addr outbound_ipaddr, int *outboundport, struct in_addr outbound_ipaddr, int *outboundport,
struct in_addr lcl_client_ipaddr, int lcl_clientport, struct in_addr lcl_client_ipaddr, int lcl_clientport,
int isrtp); int isrtp, int cseq);
int rtp_stop_fwd (osip_call_id_t *callid, int direction); /*X*/ int rtp_stop_fwd (osip_call_id_t *callid, int direction, int cseq); /*X*/
/* accessctl.c */ /* accessctl.c */
int accesslist_check(struct sockaddr_in from); int accesslist_check(struct sockaddr_in from);