# HG changeset patch # User Mychaela Falconia # Date 1664404150 28800 # Node ID 0d6435808bcd7b154df97cd91ec6da2246c24158 # Parent 3722096280385015e63ae418efc0292fe0b344eb sip-in: implement 100rel for 180 Ringing response diff -r 372209628038 -r 0d6435808bcd sip-in/Makefile --- a/sip-in/Makefile Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/Makefile Wed Sep 28 14:29:10 2022 -0800 @@ -2,7 +2,7 @@ CFLAGS= -O2 PROG= themwi-sip-in OBJS= bye_in.o bye_out.o call_list.o call_setup.o cancel.o disconnect.o \ - invite.o main.o mgw_ops.o mgw_sock.o mncc_handle.o mncc_sock.o \ + invite.o main.o mgw_ops.o mgw_sock.o mncc_handle.o mncc_sock.o prack.o \ readconf.o retrans.o shutdown.o sip_ack.o sip_log.o sip_uas.o sip_udp.o LIBS= ../libnumdb/libnumdb.a ../libsip/libsip.a ../libutil/libutil.a INSTBIN=/usr/local/bin diff -r 372209628038 -r 0d6435808bcd sip-in/bye_in.c --- a/sip-in/bye_in.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/bye_in.c Wed Sep 28 14:29:10 2022 -0800 @@ -43,7 +43,7 @@ switch (call->sip_state) { case SIP_STATE_INVITE_PROC: case SIP_STATE_RINGING: - case SIP_STATE_RINGING_PRACK: + case SIP_STATE_RINGING_REL: call->overall_state = OVERALL_STATE_TEARDOWN; disconnect_mncc(call, GSM48_CAUSE_LOC_NET_BEYOND, GSM48_CC_CAUSE_NORM_CALL_CLEAR); diff -r 372209628038 -r 0d6435808bcd sip-in/call.h --- a/sip-in/call.h Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/call.h Wed Sep 28 14:29:10 2022 -0800 @@ -52,7 +52,7 @@ #define SIP_STATE_INVITE_PROC 1 #define SIP_STATE_RINGING 2 -#define SIP_STATE_RINGING_PRACK 3 +#define SIP_STATE_RINGING_REL 3 #define SIP_STATE_INVITE_200 4 #define SIP_STATE_CONNECTED 5 #define SIP_STATE_BYE_SENT 6 diff -r 372209628038 -r 0d6435808bcd sip-in/call_list.c --- a/sip-in/call_list.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/call_list.c Wed Sep 28 14:29:10 2022 -0800 @@ -61,6 +61,7 @@ for (call = call_list; call; call = call->next) { switch (call->sip_state) { + case SIP_STATE_RINGING_REL: case SIP_STATE_INVITE_200: case SIP_STATE_INVITE_ERR: case SIP_STATE_BYE_SENT: diff -r 372209628038 -r 0d6435808bcd sip-in/cancel.c --- a/sip-in/cancel.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/cancel.c Wed Sep 28 14:29:10 2022 -0800 @@ -92,7 +92,7 @@ switch (call->sip_state) { case SIP_STATE_INVITE_PROC: case SIP_STATE_RINGING: - case SIP_STATE_RINGING_PRACK: + case SIP_STATE_RINGING_REL: call->overall_state = OVERALL_STATE_TEARDOWN; disconnect_mncc(call, GSM48_CAUSE_LOC_NET_BEYOND, GSM48_CC_CAUSE_NORM_CALL_CLEAR); diff -r 372209628038 -r 0d6435808bcd sip-in/disconnect.c --- a/sip-in/disconnect.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/disconnect.c Wed Sep 28 14:29:10 2022 -0800 @@ -92,7 +92,7 @@ switch (call->sip_state) { case SIP_STATE_INVITE_PROC: case SIP_STATE_RINGING: - case SIP_STATE_RINGING_PRACK: + case SIP_STATE_RINGING_REL: strcpy(call->invite_fail, cause_to_invite_err(cause)); signal_invite_error(call); break; diff -r 372209628038 -r 0d6435808bcd sip-in/invite.c --- a/sip-in/invite.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/invite.c Wed Sep 28 14:29:10 2022 -0800 @@ -347,12 +347,19 @@ sip_tx_packet(&resp, sin); return; case SIP_STATE_RINGING: - case SIP_STATE_RINGING_PRACK: start_response_out_msg(&resp, "180 Ringing"); fill_invite_resp_from_call(&resp, call); out_msg_finish(&resp); sip_tx_packet(&resp, sin); return; + case SIP_STATE_RINGING_REL: + start_response_out_msg(&resp, "180 Ringing"); + fill_invite_resp_from_call(&resp, call); + out_msg_add_header(&resp, "Require", "100rel"); + out_msg_add_header(&resp, "RSeq", "1"); + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; case SIP_STATE_INVITE_200: case SIP_STATE_CONNECTED: fill_invite_200_resp(&resp, call); @@ -390,12 +397,35 @@ struct call *call; { struct sip_msg_out resp; + int rc; start_response_out_msg(&resp, "180 Ringing"); - fill_invite_resp_from_call(&resp, call); + rc = fill_invite_resp_from_call(&resp, call); + if (rc < 0) { +msg_size_err: syslog(LOG_ERR, "INVITE 180 response length exceeded"); + call->sip_state = SIP_STATE_MSG_SIZE_ERR; + call->overall_state = OVERALL_STATE_TEARDOWN; + disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_INTERWORKING); + disconnect_tmgw(call); + /* TODO: transition from TEARDOWN to DEAD_SIP */ + return; + } + if (call->use_100rel) { + rc = out_msg_add_header(&resp, "Require", "100rel"); + if (rc < 0) + goto msg_size_err; + rc = out_msg_add_header(&resp, "RSeq", "1"); + if (rc < 0) + goto msg_size_err; + } out_msg_finish(&resp); sip_tx_packet(&resp, &call->udp_sin); - call->sip_state = SIP_STATE_RINGING; + if (call->use_100rel) { + call->sip_state = SIP_STATE_RINGING_REL; + call->sip_tx_count = 1; + } else + call->sip_state = SIP_STATE_RINGING; } void diff -r 372209628038 -r 0d6435808bcd sip-in/prack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/prack.c Wed Sep 28 14:29:10 2022 -0800 @@ -0,0 +1,117 @@ +/* + * Here we implement our handling of SIP PRACK, expected from callers + * when we send them a reliable 180 Ringing response. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/gsm48_const.h" +#include "../libsip/parse.h" +#include "../libsip/uas_basic.h" +#include "../libsip/out_msg.h" +#include "call.h" + +extern char *get_single_header(); +extern struct call *find_call_by_sip_id(); + +void +handle_sip_prack(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + struct call *call; + struct sip_msg_out resp; + char *rack, *orig_method, *cp; + unsigned rseq, orig_num; + int rc; + + call = find_call_by_sip_id(ess->call_id); + if (!call) { + start_response_out_msg(&resp, "481 Call-ID not found"); +error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) + return; + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + } + rack = get_single_header(req, "RAck", (char *) 0, (int *) 0); + if (!rack) { + start_response_out_msg(&resp, "400 Missing RAck header"); + goto error_resp; + } + if (!isdigit(*rack)) { +malformed: start_response_out_msg(&resp, "400 Malformed RAck header"); + goto error_resp; + } + rseq = strtoul(rack, &cp, 10); + if (!isspace(*cp)) + goto malformed; + while (isspace(*cp)) + cp++; + if (!isdigit(*cp)) + goto malformed; + orig_num = strtoul(cp, &cp, 10); + if (!isspace(*cp)) + goto malformed; + while (isspace(*cp)) + cp++; + if (!isupper(*cp)) + goto malformed; + orig_method = cp; + while (isalnum(*cp)) + cp++; + if (*cp) + goto malformed; + if (rseq != 1 || orig_num != call->invite_cseq || + strcmp(orig_method, "INVITE")) { + start_response_out_msg(&resp, + "481 RAck fails to match our 100rel response"); + goto error_resp; + } + switch (call->sip_state) { + case SIP_STATE_RINGING_REL: + call->sip_state = SIP_STATE_RINGING; + start_response_out_msg(&resp, "200 OK"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { + syslog(LOG_ERR, "PRACK 200 response length exceeded"); + call->sip_state = SIP_STATE_MSG_SIZE_ERR; + call->overall_state = OVERALL_STATE_TEARDOWN; + disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_INTERWORKING); + disconnect_tmgw(call); + /* TODO: transition from TEARDOWN to DEAD_SIP */ + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + case SIP_STATE_RINGING: + case SIP_STATE_INVITE_200: + start_response_out_msg(&resp, "200 OK"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) + return; + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + case SIP_STATE_INVITE_PROC: + case SIP_STATE_CONNECTED: + case SIP_STATE_BYE_SENT: + case SIP_STATE_INVITE_ERR: + case SIP_STATE_ENDED: + start_response_out_msg(&resp, + "481 No outstanding 100rel response"); + goto error_resp; + } +} diff -r 372209628038 -r 0d6435808bcd sip-in/readconf.c --- a/sip-in/readconf.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/readconf.c Wed Sep 28 14:29:10 2022 -0800 @@ -16,7 +16,7 @@ struct in_addr sip_bind_ip; unsigned sip_bind_port; -int cfg_use_100rel; +int cfg_use_100rel = 1; int cfg_force_pcma; unsigned cfg_retrans_timeout = 500; unsigned cfg_retrans_count = 10; diff -r 372209628038 -r 0d6435808bcd sip-in/retrans.c --- a/sip-in/retrans.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/retrans.c Wed Sep 28 14:29:10 2022 -0800 @@ -27,6 +27,25 @@ for (call = call_list; call; call = call->next) { switch (call->sip_state) { + case SIP_STATE_RINGING_REL: + if (call->sip_tx_count < cfg_retrans_count) { + start_response_out_msg(&msg, "180 Ringing"); + fill_invite_resp_from_call(&msg, call); + out_msg_add_header(&msg, "Require", "100rel"); + out_msg_add_header(&msg, "RSeq", "1"); + out_msg_finish(&msg); + sip_tx_packet(&msg, &call->udp_sin); + call->sip_tx_count++; + } else { + call->overall_state = OVERALL_STATE_TEARDOWN; + disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_INTERWORKING); + disconnect_tmgw(call); + strcpy(call->invite_fail, + "504 100rel retransmissions exhausted"); + signal_invite_error(call); + } + break; case SIP_STATE_INVITE_200: if (call->sip_tx_count < cfg_retrans_count) { fill_invite_200_resp(&msg, call); diff -r 372209628038 -r 0d6435808bcd sip-in/sip_uas.c --- a/sip-in/sip_uas.c Tue Sep 27 23:45:40 2022 -0800 +++ b/sip-in/sip_uas.c Wed Sep 28 14:29:10 2022 -0800 @@ -29,7 +29,7 @@ too_long: syslog(LOG_ERR, "sending 501 error: response length exceeded"); return; } - rc = out_msg_add_header(&resp, "Allow", "INVITE,ACK,CANCEL,BYE"); + rc = out_msg_add_header(&resp, "Allow", "INVITE,ACK,PRACK,CANCEL,BYE"); if (rc < 0) goto too_long; out_msg_finish(&resp); @@ -55,6 +55,8 @@ handle_sip_invite(msg, &ess, sin); else if (!strcmp(msg->req_method, "ACK")) handle_sip_ack(msg, &ess, sin); + else if (!strcmp(msg->req_method, "PRACK")) + handle_sip_prack(msg, &ess, sin); else if (!strcmp(msg->req_method, "CANCEL")) handle_sip_cancel(msg, &ess, sin); else if (!strcmp(msg->req_method, "BYE"))