Compare commits

...

2 Commits

Author SHA1 Message Date
Pau Espin bc62ddb345 sip_transport: tcp: shutdown transport if unable to keep decoding stream
If pjsip_find_msg() starts failing because there's some missing header
like Content-Length, log the issue and shutdown the transport to avoid
staying in a broken state.
2024-05-14 14:04:08 +02:00
Pau Espin b5644c9165 pjsip_find_msg: Log warning if Content-Length field not found
The pjsip_find_msg() is used when in TCP to find the message boundaries
in the stream. For that, it uses the Content-Length field, which is only
mandatory in SIP TCP according to spec. Since this function is used only
in TCP transport, that's totally fine.
However, a SIP test written in TTCN-3 was recently sending a message
without Content-Length field (because there was no body at all in the
message). That made Asterisk discard the message without any kind of
feedback, as if it was a black hole.
Write down some log line explaining the user that a Content-Length value
is expected.
2024-05-14 14:00:59 +02:00
2 changed files with 50 additions and 32 deletions

View File

@ -937,6 +937,8 @@ PJ_DEF(pj_status_t) pjsip_find_msg( const char *buf, pj_size_t size,
/* Found Content-Length? */
if (content_length == -1) {
/* As per RFC3261 7.4.2, 7.5, 20.14, Content-Length is mandatory over TCP. */
PJ_LOG(2, (THIS_FILE, "Field Content-Length not found!"));
return status;
}

View File

@ -2068,41 +2068,57 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
pj_status_t msg_status;
msg_status = pjsip_find_msg(current_pkt, remaining_len, PJ_FALSE,
&msg_fragment_size);
if (msg_status != PJ_SUCCESS) {
if (remaining_len == PJSIP_MAX_PKT_LEN) {
mgr->on_rx_msg(mgr->endpt, PJSIP_ERXOVERFLOW, rdata);
/* Notify application about the message overflow */
if (mgr->tp_drop_data_cb) {
pjsip_tp_dropped_data dd;
pj_bzero(&dd, sizeof(dd));
dd.tp = tr;
dd.data = current_pkt;
dd.len = msg_fragment_size;
dd.status = PJSIP_ERXOVERFLOW;
(*mgr->tp_drop_data_cb)(&dd);
}
if (rdata->tp_info.transport->idle_timer.id ==
INITIAL_IDLE_TIMER_ID)
{
/* We are not getting the first valid SIP message
* as expected, close the transport.
*/
PJ_LOG(4, (THIS_FILE, "Unexpected data was received "\
"while waiting for a valid initial SIP messages. "\
"Shutting down transport %s",
rdata->tp_info.transport->obj_name));
pjsip_transport_shutdown(rdata->tp_info.transport);
}
/* Exhaust all data. */
return rdata->pkt_info.len;
} else {
switch (msg_status) {
case PJ_SUCCESS;
/* continue below */
break;
case PJSIP_EPARTIALMSG:
if (remaining_len != PJSIP_MAX_PKT_LEN) {
/* Not enough data in packet. */
return total_processed;
}
mgr->on_rx_msg(mgr->endpt, PJSIP_ERXOVERFLOW, rdata);
/* Notify application about the message overflow */
if (mgr->tp_drop_data_cb) {
pjsip_tp_dropped_data dd;
pj_bzero(&dd, sizeof(dd));
dd.tp = tr;
dd.data = current_pkt;
dd.len = msg_fragment_size;
dd.status = PJSIP_ERXOVERFLOW;
(*mgr->tp_drop_data_cb)(&dd);
}
if (rdata->tp_info.transport->idle_timer.id ==
INITIAL_IDLE_TIMER_ID)
{
/* We are not getting the first valid SIP message
* as expected, close the transport.
*/
PJ_LOG(4, (THIS_FILE, "Unexpected data was received "\
"while waiting for a valid initial SIP messages. "\
"Shutting down transport %s",
rdata->tp_info.transport->obj_name));
pjsip_transport_shutdown(rdata->tp_info.transport);
}
/* Exhaust all data. */
return rdata->pkt_info.len;
case PJSIP_EMISSINGHDR:
case PJSIP_EINVALIDHDR:
default:
{
char errbuf[128];
PJ_LOG(1, (THIS_FILE, "Unable to match whole message (%s)."\
"Shutting down transport %s",
pjsip_strerror(msg_status, errbuf, sizeof(errbuf));
rdata->tp_info.transport->obj_name));
pjsip_transport_shutdown(rdata->tp_info.transport);
return rdata->pkt_info.len;
break;
}
}
}