FreeCalypso > hg > themwi-system-sw
changeset 145:4b685a5d9bd4
sip-in code: split invite.c into 3 separate C modules
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 08 Oct 2022 19:31:05 -0800 |
parents | 4e16aeafbfbf |
children | 54c2f271380d |
files | sip-in/Makefile sip-in/invite.c sip-in/invite_dup.c sip-in/invite_init.c sip-in/invite_resp.c |
diffstat | 5 files changed, 543 insertions(+), 504 deletions(-) [+] |
line wrap: on
line diff
--- a/sip-in/Makefile Sat Oct 08 19:06:24 2022 -0800 +++ b/sip-in/Makefile Sat Oct 08 19:31:05 2022 -0800 @@ -2,9 +2,9 @@ CFLAGS= -O2 PROG= themwi-sip-in OBJS= bye_in.o bye_out.o call_clear.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 prack.o readconf.o retrans.o shutdown.o sip_ack.o sip_log.o\ - sip_uas.o sip_udp.o + disconnect.o invite_dup.o invite_init.o invite_resp.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
--- a/sip-in/invite.c Sat Oct 08 19:06:24 2022 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,501 +0,0 @@ -/* - * Here we implement our handling of SIP INVITE method. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <syslog.h> -#include "../include/gsm48_const.h" -#include "../libsip/parse.h" -#include "../libsip/uas_basic.h" -#include "../libsip/grok_from.h" -#include "../libsip/req_supp.h" -#include "../libsip/sdp.h" -#include "../libsip/out_msg.h" -#include "call.h" - -extern struct in_addr sip_bind_ip; -extern unsigned sip_bind_port; -extern int cfg_use_100rel; -extern int cfg_force_pcma; -extern struct call *call_list; -extern unsigned sip_linger_error; - -extern struct call *find_call_by_sip_id(); -extern char *get_single_header(); - -fill_invite_resp_from_call(msg, call) - struct sip_msg_out *msg; - struct call *call; -{ - char cseq_str[32]; - int rc; - - rc = out_msg_add_header(msg, "From", call->invite_from); - if (rc < 0) - return rc; - rc = out_msg_add_header(msg, "To", call->invite_to); - if (rc < 0) - return rc; - rc = out_msg_add_header(msg, "Call-ID", call->sip_call_id); - if (rc < 0) - return rc; - sprintf(cseq_str, "%u INVITE", call->invite_cseq); - rc = out_msg_add_header(msg, "CSeq", cseq_str); - if (rc < 0) - return rc; - return out_msg_add_header(msg, "Via", call->invite_via); -} - -fill_invite_200_resp(msg, call) - struct sip_msg_out *msg; - struct call *call; -{ - char contact_str[80]; - struct sdp_gen sdp; - int rc; - - start_response_out_msg(msg, "200 CONNECT"); - rc = fill_invite_resp_from_call(msg, call); - if (rc < 0) - return rc; - sprintf(contact_str, "<sip:%s:%u;transport=udp>", - inet_ntoa(sip_bind_ip), sip_bind_port); - rc = out_msg_add_header(msg, "Contact", contact_str); - if (rc < 0) - return rc; - rc = out_msg_add_header(msg, "Content-Type", "application/sdp"); - if (rc < 0) - return rc; - bzero(&sdp, sizeof sdp); - sdp.conn_ip = call->pstn_rtp_local.sin_addr; - sdp.conn_port = ntohs(call->pstn_rtp_local.sin_port); - sdp.codec_mask = call->use_pcma ? SDP_CODEC_MASK_PCMA - : SDP_CODEC_MASK_PCMU; - sdp.session_id = (sdp.conn_port << 16) | call->sdp_addend; - sdp.owner_ip = sip_bind_ip; - return out_msg_finish_sdp(msg, &sdp); -} - -static void -invite_new_call(req, ess, sin) - struct sip_pkt_rx *req; - struct uas_parse_hdrs *ess; - struct sockaddr_in *sin; -{ - static unsigned cycle_tag_num, cycle_sdp_addend; - char uri_user[13], *called_nanp; - struct sip_msg_out resp; - struct grok_from gfrom; - struct supported_ext supp_ext; - char *hval, *unsup_ext; - int ext_100rel_req, ext_100rel_sup, use_100rel, use_pcma; - struct sdp_parse sdp_parse; - struct sdp_gen sdp_gen; - struct call *call; - char *dp, cdr_str[80]; - unsigned cdr_num_len, cdr_cnam_len; - unsigned req_uri_len, to_hdr_len, copylen; - int rc; - - /* extract called number from Request-URI */ - rc = user_from_sip_uri(req->req_uri, uri_user, 12); - if (rc < 0) { -not_nanp: start_response_out_msg(&resp, - "416 Request-URI is not a NANP number"); -error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method); - if (rc < 0) { -error_resp_toolong: syslog(LOG_ERR, - "INVITE early error response length exceeded"); - return; - } - out_msg_finish(&resp); - sip_tx_packet(&resp, sin); - return; - } - if (uri_user[0] == '+') { - if (grok_number_string(uri_user+1, 0) != 11 || - uri_user[1] != '1') - goto not_nanp; - called_nanp = uri_user + 2; - } else switch (grok_number_string(uri_user)) { - case 10: - called_nanp = uri_user; - break; - case 11: - if (uri_user[0] != '1') - goto not_nanp; - called_nanp = uri_user + 1; - break; - default: - goto not_nanp; - } - if (!is_nanp_valid_prefix(called_nanp)) - goto not_nanp; - /* it is valid NANP - but is it one of ours? */ - refresh_number_db(); - if (!is_nanp_locally_owned(called_nanp)) { - start_response_out_msg(&resp, - "404 Called number does not belong here"); - goto error_resp; - } - /* parse and validate From header */ - rc = grok_from_header(ess->from, &gfrom); - if (rc < 0) { - start_response_out_msg(&resp, "400 Malformed From header"); - goto error_resp; - } - /* validate To header for the purpose of tag addition */ - req_uri_len = strlen(req->req_uri); - to_hdr_len = strlen(ess->to); - if (to_hdr_len == req_uri_len) { - if (strcasecmp(ess->to, req->req_uri)) { -bad_to_header: start_response_out_msg(&resp, "400 Bad To header"); - goto error_resp; - } - } else if (to_hdr_len == req_uri_len + 2) { - if (ess->to[0] != '<') - goto bad_to_header; - if (strncasecmp(ess->to+1, req->req_uri, req_uri_len)) - goto bad_to_header; - if (ess->to[req_uri_len+1] != '>') - goto bad_to_header; - } else - goto bad_to_header; - /* check 100rel and catch any unsupported requirements */ - supp_ext.name = "100rel"; - supp_ext.req_flag = &ext_100rel_req; - supp_ext.sup_flag = &ext_100rel_sup; - ext_100rel_req = ext_100rel_sup = 0; - rc = parse_require_supported(req, &supp_ext, 1, &unsup_ext); - if (rc < 0) { - start_response_out_msg(&resp, "420 Extension not supported"); - rc = out_msg_add_header(&resp, "Unsupported", unsup_ext); - if (rc < 0) - goto error_resp_toolong; - goto error_resp; - } - if (ext_100rel_req) - use_100rel = 1; - else if (ext_100rel_sup) - use_100rel = cfg_use_100rel; - else - use_100rel = 0; - /* did the caller send an SDP message body? */ - if (!req->msg_body_len) { - start_response_out_msg(&resp, "415 Missing SDP body"); -error_415: rc = out_msg_add_header(&resp, "Accept", "application/sdp"); - if (rc < 0) - goto error_resp_toolong; - goto error_resp; - } - hval = get_single_header(req, "Content-Type", "c", (int *) 0); - if (!hval) { - start_response_out_msg(&resp, - "415 Missing Content-Type header"); - goto error_415; - } - if (strcasecmp(hval, "application/sdp")) { - start_response_out_msg(&resp, "415 Unsupported Content-Type"); - goto error_415; - } - rc = parse_incoming_sdp(req->msg_body, req->msg_body_len, &sdp_parse); - if (rc < 0) { - start_response_out_msg(&resp, "488 Malformed SDP body"); - goto error_resp; - } - switch (sdp_parse.codec_mask) { - case SDP_CODEC_MASK_PCMU: - use_pcma = 0; - break; - case SDP_CODEC_MASK_PCMA: - case SDP_CODEC_MASK_BOTH | SDP_CODEC_MASK_PCMA_PREF: - use_pcma = 1; - break; - case SDP_CODEC_MASK_BOTH: - use_pcma = cfg_force_pcma; - break; - default: - start_response_out_msg(&resp, - "488 Unsupported codec selection"); - rc = add_resp_basic_headers(&resp, ess, req->req_method); - if (rc < 0) - goto error_resp_toolong; - rc = out_msg_add_header(&resp, "Content-Type", - "application/sdp"); - if (rc < 0) - goto error_resp_toolong; - bzero(&sdp_gen, sizeof sdp_gen); - sdp_gen.owner_ip = sip_bind_ip; - sdp_gen.conn_ip = sip_bind_ip; - sdp_gen.codec_mask = SDP_CODEC_MASK_BOTH; - rc = out_msg_finish_sdp(&resp, &sdp_gen); - if (rc < 0) - goto error_resp_toolong; - sip_tx_packet(&resp, sin); - return; - } - /* SIP INVITE validation done - gather CDR info */ - cdr_num_len = gfrom.user_len; - if (cdr_num_len > 33) - cdr_num_len = 33; - cdr_cnam_len = gfrom.cnam_len; - if (cdr_cnam_len > 33) - cdr_cnam_len = 33; - if (cdr_cnam_len) - sprintf(cdr_str, "%.*s (%s%.*s%s)", cdr_num_len, gfrom.user, - gfrom.cnam_quoted ? "\"" : "", cdr_cnam_len, gfrom.cnam, - gfrom.cnam_quoted ? "\"" : ""); - else - sprintf(cdr_str, "%.*s", cdr_num_len, gfrom.user); - hval = get_single_header(req, "P-Asserted-Identity", (char *) 0, - (int *) 0); - /* check if GSM service is up */ - rc = connect_gsm_mtcall(); - if (rc < 0) { -gsm_offline: syslog(LOG_INFO, "Down-call from %s to %s", cdr_str, uri_user); - if (hval) - syslog(LOG_INFO, "Down-call PAI: %.100s", hval); - start_response_out_msg(&resp, "480 GSM service is offline"); - goto error_resp; - } - rc = connect_tmgw_socket(); - if (rc < 0) - goto gsm_offline; - /* stateful processing begins */ - call = malloc(sizeof(struct call) + strlen(ess->call_id) + - strlen(ess->from) + req_uri_len + strlen(ess->via) + 19); - if (!call) { - syslog(LOG_CRIT, "failed malloc for incoming call!"); - start_response_out_msg(&resp, - "503 Gateway resource allocation failure"); - goto error_resp; - } - cycle_tag_num++; - if (cycle_tag_num >= 1000000) - cycle_tag_num = 0; - cycle_sdp_addend++; - if (cycle_sdp_addend >= 0x10000) - cycle_sdp_addend = 0; - bzero(call, sizeof(struct call)); - dp = (char *)(call + 1); - copylen = strlen(ess->call_id) + 1; - call->sip_call_id = dp; - bcopy(ess->call_id, dp, copylen); - dp += copylen; - copylen = strlen(ess->from) + 1; - call->invite_from = dp; - bcopy(ess->from, dp, copylen); - dp += copylen; - call->invite_to = dp; - *dp++ = '<'; - bcopy(req->req_uri, dp, req_uri_len); - dp += req_uri_len; - *dp++ = '>'; - sprintf(dp, ";tag=in%06u", cycle_tag_num); - dp += 14; - copylen = strlen(ess->via) + 1; - call->invite_via = dp; - bcopy(ess->via, dp, copylen); - call->invite_cseq = ess->cseq_num; - bcopy(sin, &call->udp_sin, sizeof(struct sockaddr_in)); - bcopy(called_nanp, call->called_nanp, 11); - call->from_uri = call->invite_from + (gfrom.uri - ess->from); - call->from_uri_len = gfrom.uri_len; - call->from_user = call->invite_from + (gfrom.user - ess->from); - call->from_user_len = gfrom.user_len; - call->use_100rel = use_100rel; - call->pstn_rtp_remote.sin_family = AF_INET; - call->pstn_rtp_remote.sin_addr = sdp_parse.ip_addr; - call->pstn_rtp_remote.sin_port = htons(sdp_parse.audio_port); - call->use_pcma = use_pcma; - call->in_tag_num = cycle_tag_num; - call->sdp_addend = cycle_sdp_addend; - /* generate 100 response */ - start_response_out_msg(&resp, "100 Proceeding"); - rc = fill_invite_resp_from_call(&resp, call); - if (rc < 0) { - syslog(LOG_ERR, "INVITE 100 response length exceeded"); - free(call); - return; - } - out_msg_finish(&resp); - sip_tx_packet(&resp, sin); - /* add to call list */ - call->next = call_list; - call_list = call; - syslog(LOG_INFO, "Call in%06u from %s to %s", call->in_tag_num, - cdr_str, uri_user); - if (hval) - syslog(LOG_INFO, "Call in%06u PAI: %.100s", call->in_tag_num, - hval); - /* send CRCX to TMGW */ - tmgw_send_crcx(call); - call->overall_state = OVERALL_STATE_CRCX; - call->sip_state = SIP_STATE_INVITE_PROC; -} - -static void -invite_existing_call(req, ess, sin, call) - struct sip_pkt_rx *req; - struct uas_parse_hdrs *ess; - struct sockaddr_in *sin; - struct call *call; -{ - struct sip_msg_out resp; - int rc; - - if (ess->cseq_num != call->invite_cseq) { - start_response_out_msg(&resp, "501 Re-INVITE not supported"); - rc = add_resp_basic_headers(&resp, ess, req->req_method); - if (rc < 0) { - syslog(LOG_ERR, - "sending 501 Re-INVITE error: response length exceeded"); - return; - } - out_msg_finish(&resp); - sip_tx_packet(&resp, sin); - return; - } - /* it's a retransmission, not a re-INVITE */ - switch (call->sip_state) { - case SIP_STATE_INVITE_PROC: - start_response_out_msg(&resp, "100 Proceeding"); - fill_invite_resp_from_call(&resp, call); - out_msg_finish(&resp); - sip_tx_packet(&resp, sin); - return; - case SIP_STATE_RINGING: - 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); - sip_tx_packet(&resp, sin); - return; - case SIP_STATE_INVITE_ERR: - start_response_out_msg(&resp, call->invite_fail); - fill_invite_resp_from_call(&resp, call); - out_msg_finish(&resp); - sip_tx_packet(&resp, sin); - return; - default: - /* silently discard */ - return; - } -} - -void -handle_sip_invite(req, ess, sin) - struct sip_pkt_rx *req; - struct uas_parse_hdrs *ess; - struct sockaddr_in *sin; -{ - struct call *call; - - call = find_call_by_sip_id(ess->call_id); - if (call) - invite_existing_call(req, ess, sin, call); - else - invite_new_call(req, ess, sin); -} - -void -signal_invite_ringing(call) - struct call *call; -{ - struct sip_msg_out resp; - int rc; - - start_response_out_msg(&resp, "180 Ringing"); - 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); - sip_mark_end_time(call, sip_linger_error); - 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); - if (call->use_100rel) { - call->sip_state = SIP_STATE_RINGING_REL; - call->sip_tx_count = 1; - } else - call->sip_state = SIP_STATE_RINGING; -} - -void -signal_invite_200(call) - struct call *call; -{ - struct sip_msg_out resp; - int rc; - - rc = fill_invite_200_resp(&resp, call); - if (rc < 0) { - syslog(LOG_ERR, "INVITE 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); - sip_mark_end_time(call, sip_linger_error); - return; - } - sip_tx_packet(&resp, &call->udp_sin); - call->sip_state = SIP_STATE_INVITE_200; - call->sip_tx_count = 1; -} - -void -signal_invite_error(call) - struct call *call; -{ - struct sip_msg_out resp; - int rc; - - start_response_out_msg(&resp, call->invite_fail); - rc = fill_invite_resp_from_call(&resp, call); - if (rc < 0) { - syslog(LOG_ERR, "INVITE late error response length exceeded"); - call->sip_state = SIP_STATE_MSG_SIZE_ERR; - sip_mark_end_time(call, sip_linger_error); - transition_dead_sip(call); - return; - } - out_msg_finish(&resp); - sip_tx_packet(&resp, &call->udp_sin); - call->sip_state = SIP_STATE_INVITE_ERR; - call->sip_tx_count = 1; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/invite_dup.c Sat Oct 08 19:31:05 2022 -0800 @@ -0,0 +1,81 @@ +/* + * Here we process SIP INVITE retransmissions and/or re-INVITEs + * for existing calls. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include "../libsip/parse.h" +#include "../libsip/uas_basic.h" +#include "../libsip/sdp.h" +#include "../libsip/out_msg.h" +#include "call.h" + +void +invite_existing_call(req, ess, sin, call) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; + struct call *call; +{ + struct sip_msg_out resp; + int rc; + + if (ess->cseq_num != call->invite_cseq) { + start_response_out_msg(&resp, "501 Re-INVITE not supported"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { + syslog(LOG_ERR, + "sending 501 Re-INVITE error: response length exceeded"); + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + } + /* it's a retransmission, not a re-INVITE */ + switch (call->sip_state) { + case SIP_STATE_INVITE_PROC: + start_response_out_msg(&resp, "100 Proceeding"); + fill_invite_resp_from_call(&resp, call); + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + case SIP_STATE_RINGING: + 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); + sip_tx_packet(&resp, sin); + return; + case SIP_STATE_INVITE_ERR: + start_response_out_msg(&resp, call->invite_fail); + fill_invite_resp_from_call(&resp, call); + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + default: + /* silently discard */ + return; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/invite_init.c Sat Oct 08 19:31:05 2022 -0800 @@ -0,0 +1,302 @@ +/* + * Here we implement our initial processing of SIP INVITE requests. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include "../libsip/parse.h" +#include "../libsip/uas_basic.h" +#include "../libsip/grok_from.h" +#include "../libsip/req_supp.h" +#include "../libsip/sdp.h" +#include "../libsip/out_msg.h" +#include "call.h" + +extern struct in_addr sip_bind_ip; +extern int cfg_use_100rel; +extern int cfg_force_pcma; +extern struct call *call_list; + +extern struct call *find_call_by_sip_id(); +extern char *get_single_header(); + +void +invite_new_call(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + static unsigned cycle_tag_num, cycle_sdp_addend; + char uri_user[13], *called_nanp; + struct sip_msg_out resp; + struct grok_from gfrom; + struct supported_ext supp_ext; + char *hval, *unsup_ext; + int ext_100rel_req, ext_100rel_sup, use_100rel, use_pcma; + struct sdp_parse sdp_parse; + struct sdp_gen sdp_gen; + struct call *call; + char *dp, cdr_str[80]; + unsigned cdr_num_len, cdr_cnam_len; + unsigned req_uri_len, to_hdr_len, copylen; + int rc; + + /* extract called number from Request-URI */ + rc = user_from_sip_uri(req->req_uri, uri_user, 12); + if (rc < 0) { +not_nanp: start_response_out_msg(&resp, + "416 Request-URI is not a NANP number"); +error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { +error_resp_toolong: syslog(LOG_ERR, + "INVITE early error response length exceeded"); + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + return; + } + if (uri_user[0] == '+') { + if (grok_number_string(uri_user+1, 0) != 11 || + uri_user[1] != '1') + goto not_nanp; + called_nanp = uri_user + 2; + } else switch (grok_number_string(uri_user)) { + case 10: + called_nanp = uri_user; + break; + case 11: + if (uri_user[0] != '1') + goto not_nanp; + called_nanp = uri_user + 1; + break; + default: + goto not_nanp; + } + if (!is_nanp_valid_prefix(called_nanp)) + goto not_nanp; + /* it is valid NANP - but is it one of ours? */ + refresh_number_db(); + if (!is_nanp_locally_owned(called_nanp)) { + start_response_out_msg(&resp, + "404 Called number does not belong here"); + goto error_resp; + } + /* parse and validate From header */ + rc = grok_from_header(ess->from, &gfrom); + if (rc < 0) { + start_response_out_msg(&resp, "400 Malformed From header"); + goto error_resp; + } + /* validate To header for the purpose of tag addition */ + req_uri_len = strlen(req->req_uri); + to_hdr_len = strlen(ess->to); + if (to_hdr_len == req_uri_len) { + if (strcasecmp(ess->to, req->req_uri)) { +bad_to_header: start_response_out_msg(&resp, "400 Bad To header"); + goto error_resp; + } + } else if (to_hdr_len == req_uri_len + 2) { + if (ess->to[0] != '<') + goto bad_to_header; + if (strncasecmp(ess->to+1, req->req_uri, req_uri_len)) + goto bad_to_header; + if (ess->to[req_uri_len+1] != '>') + goto bad_to_header; + } else + goto bad_to_header; + /* check 100rel and catch any unsupported requirements */ + supp_ext.name = "100rel"; + supp_ext.req_flag = &ext_100rel_req; + supp_ext.sup_flag = &ext_100rel_sup; + ext_100rel_req = ext_100rel_sup = 0; + rc = parse_require_supported(req, &supp_ext, 1, &unsup_ext); + if (rc < 0) { + start_response_out_msg(&resp, "420 Extension not supported"); + rc = out_msg_add_header(&resp, "Unsupported", unsup_ext); + if (rc < 0) + goto error_resp_toolong; + goto error_resp; + } + if (ext_100rel_req) + use_100rel = 1; + else if (ext_100rel_sup) + use_100rel = cfg_use_100rel; + else + use_100rel = 0; + /* did the caller send an SDP message body? */ + if (!req->msg_body_len) { + start_response_out_msg(&resp, "415 Missing SDP body"); +error_415: rc = out_msg_add_header(&resp, "Accept", "application/sdp"); + if (rc < 0) + goto error_resp_toolong; + goto error_resp; + } + hval = get_single_header(req, "Content-Type", "c", (int *) 0); + if (!hval) { + start_response_out_msg(&resp, + "415 Missing Content-Type header"); + goto error_415; + } + if (strcasecmp(hval, "application/sdp")) { + start_response_out_msg(&resp, "415 Unsupported Content-Type"); + goto error_415; + } + rc = parse_incoming_sdp(req->msg_body, req->msg_body_len, &sdp_parse); + if (rc < 0) { + start_response_out_msg(&resp, "488 Malformed SDP body"); + goto error_resp; + } + switch (sdp_parse.codec_mask) { + case SDP_CODEC_MASK_PCMU: + use_pcma = 0; + break; + case SDP_CODEC_MASK_PCMA: + case SDP_CODEC_MASK_BOTH | SDP_CODEC_MASK_PCMA_PREF: + use_pcma = 1; + break; + case SDP_CODEC_MASK_BOTH: + use_pcma = cfg_force_pcma; + break; + default: + start_response_out_msg(&resp, + "488 Unsupported codec selection"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) + goto error_resp_toolong; + rc = out_msg_add_header(&resp, "Content-Type", + "application/sdp"); + if (rc < 0) + goto error_resp_toolong; + bzero(&sdp_gen, sizeof sdp_gen); + sdp_gen.owner_ip = sip_bind_ip; + sdp_gen.conn_ip = sip_bind_ip; + sdp_gen.codec_mask = SDP_CODEC_MASK_BOTH; + rc = out_msg_finish_sdp(&resp, &sdp_gen); + if (rc < 0) + goto error_resp_toolong; + sip_tx_packet(&resp, sin); + return; + } + /* SIP INVITE validation done - gather CDR info */ + cdr_num_len = gfrom.user_len; + if (cdr_num_len > 33) + cdr_num_len = 33; + cdr_cnam_len = gfrom.cnam_len; + if (cdr_cnam_len > 33) + cdr_cnam_len = 33; + if (cdr_cnam_len) + sprintf(cdr_str, "%.*s (%s%.*s%s)", cdr_num_len, gfrom.user, + gfrom.cnam_quoted ? "\"" : "", cdr_cnam_len, gfrom.cnam, + gfrom.cnam_quoted ? "\"" : ""); + else + sprintf(cdr_str, "%.*s", cdr_num_len, gfrom.user); + hval = get_single_header(req, "P-Asserted-Identity", (char *) 0, + (int *) 0); + /* check if GSM service is up */ + rc = connect_gsm_mtcall(); + if (rc < 0) { +gsm_offline: syslog(LOG_INFO, "Down-call from %s to %s", cdr_str, uri_user); + if (hval) + syslog(LOG_INFO, "Down-call PAI: %.100s", hval); + start_response_out_msg(&resp, "480 GSM service is offline"); + goto error_resp; + } + rc = connect_tmgw_socket(); + if (rc < 0) + goto gsm_offline; + /* stateful processing begins */ + call = malloc(sizeof(struct call) + strlen(ess->call_id) + + strlen(ess->from) + req_uri_len + strlen(ess->via) + 19); + if (!call) { + syslog(LOG_CRIT, "failed malloc for incoming call!"); + start_response_out_msg(&resp, + "503 Gateway resource allocation failure"); + goto error_resp; + } + cycle_tag_num++; + if (cycle_tag_num >= 1000000) + cycle_tag_num = 0; + cycle_sdp_addend++; + if (cycle_sdp_addend >= 0x10000) + cycle_sdp_addend = 0; + bzero(call, sizeof(struct call)); + dp = (char *)(call + 1); + copylen = strlen(ess->call_id) + 1; + call->sip_call_id = dp; + bcopy(ess->call_id, dp, copylen); + dp += copylen; + copylen = strlen(ess->from) + 1; + call->invite_from = dp; + bcopy(ess->from, dp, copylen); + dp += copylen; + call->invite_to = dp; + *dp++ = '<'; + bcopy(req->req_uri, dp, req_uri_len); + dp += req_uri_len; + *dp++ = '>'; + sprintf(dp, ";tag=in%06u", cycle_tag_num); + dp += 14; + copylen = strlen(ess->via) + 1; + call->invite_via = dp; + bcopy(ess->via, dp, copylen); + call->invite_cseq = ess->cseq_num; + bcopy(sin, &call->udp_sin, sizeof(struct sockaddr_in)); + bcopy(called_nanp, call->called_nanp, 11); + call->from_uri = call->invite_from + (gfrom.uri - ess->from); + call->from_uri_len = gfrom.uri_len; + call->from_user = call->invite_from + (gfrom.user - ess->from); + call->from_user_len = gfrom.user_len; + call->use_100rel = use_100rel; + call->pstn_rtp_remote.sin_family = AF_INET; + call->pstn_rtp_remote.sin_addr = sdp_parse.ip_addr; + call->pstn_rtp_remote.sin_port = htons(sdp_parse.audio_port); + call->use_pcma = use_pcma; + call->in_tag_num = cycle_tag_num; + call->sdp_addend = cycle_sdp_addend; + /* generate 100 response */ + start_response_out_msg(&resp, "100 Proceeding"); + rc = fill_invite_resp_from_call(&resp, call); + if (rc < 0) { + syslog(LOG_ERR, "INVITE 100 response length exceeded"); + free(call); + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); + /* add to call list */ + call->next = call_list; + call_list = call; + syslog(LOG_INFO, "Call in%06u from %s to %s", call->in_tag_num, + cdr_str, uri_user); + if (hval) + syslog(LOG_INFO, "Call in%06u PAI: %.100s", call->in_tag_num, + hval); + /* send CRCX to TMGW */ + tmgw_send_crcx(call); + call->overall_state = OVERALL_STATE_CRCX; + call->sip_state = SIP_STATE_INVITE_PROC; +} + +void +handle_sip_invite(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + struct call *call; + + call = find_call_by_sip_id(ess->call_id); + if (call) + invite_existing_call(req, ess, sin, call); + else + invite_new_call(req, ess, sin); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/invite_resp.c Sat Oct 08 19:31:05 2022 -0800 @@ -0,0 +1,157 @@ +/* + * Here we implement SIP INVITE response generation. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include "../include/gsm48_const.h" +#include "../libsip/sdp.h" +#include "../libsip/out_msg.h" +#include "call.h" + +extern struct in_addr sip_bind_ip; +extern unsigned sip_bind_port; +extern unsigned sip_linger_error; + +fill_invite_resp_from_call(msg, call) + struct sip_msg_out *msg; + struct call *call; +{ + char cseq_str[32]; + int rc; + + rc = out_msg_add_header(msg, "From", call->invite_from); + if (rc < 0) + return rc; + rc = out_msg_add_header(msg, "To", call->invite_to); + if (rc < 0) + return rc; + rc = out_msg_add_header(msg, "Call-ID", call->sip_call_id); + if (rc < 0) + return rc; + sprintf(cseq_str, "%u INVITE", call->invite_cseq); + rc = out_msg_add_header(msg, "CSeq", cseq_str); + if (rc < 0) + return rc; + return out_msg_add_header(msg, "Via", call->invite_via); +} + +fill_invite_200_resp(msg, call) + struct sip_msg_out *msg; + struct call *call; +{ + char contact_str[80]; + struct sdp_gen sdp; + int rc; + + start_response_out_msg(msg, "200 CONNECT"); + rc = fill_invite_resp_from_call(msg, call); + if (rc < 0) + return rc; + sprintf(contact_str, "<sip:%s:%u;transport=udp>", + inet_ntoa(sip_bind_ip), sip_bind_port); + rc = out_msg_add_header(msg, "Contact", contact_str); + if (rc < 0) + return rc; + rc = out_msg_add_header(msg, "Content-Type", "application/sdp"); + if (rc < 0) + return rc; + bzero(&sdp, sizeof sdp); + sdp.conn_ip = call->pstn_rtp_local.sin_addr; + sdp.conn_port = ntohs(call->pstn_rtp_local.sin_port); + sdp.codec_mask = call->use_pcma ? SDP_CODEC_MASK_PCMA + : SDP_CODEC_MASK_PCMU; + sdp.session_id = (sdp.conn_port << 16) | call->sdp_addend; + sdp.owner_ip = sip_bind_ip; + return out_msg_finish_sdp(msg, &sdp); +} + +void +signal_invite_ringing(call) + struct call *call; +{ + struct sip_msg_out resp; + int rc; + + start_response_out_msg(&resp, "180 Ringing"); + 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); + sip_mark_end_time(call, sip_linger_error); + 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); + if (call->use_100rel) { + call->sip_state = SIP_STATE_RINGING_REL; + call->sip_tx_count = 1; + } else + call->sip_state = SIP_STATE_RINGING; +} + +void +signal_invite_200(call) + struct call *call; +{ + struct sip_msg_out resp; + int rc; + + rc = fill_invite_200_resp(&resp, call); + if (rc < 0) { + syslog(LOG_ERR, "INVITE 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); + sip_mark_end_time(call, sip_linger_error); + return; + } + sip_tx_packet(&resp, &call->udp_sin); + call->sip_state = SIP_STATE_INVITE_200; + call->sip_tx_count = 1; +} + +void +signal_invite_error(call) + struct call *call; +{ + struct sip_msg_out resp; + int rc; + + start_response_out_msg(&resp, call->invite_fail); + rc = fill_invite_resp_from_call(&resp, call); + if (rc < 0) { + syslog(LOG_ERR, "INVITE late error response length exceeded"); + call->sip_state = SIP_STATE_MSG_SIZE_ERR; + sip_mark_end_time(call, sip_linger_error); + transition_dead_sip(call); + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, &call->udp_sin); + call->sip_state = SIP_STATE_INVITE_ERR; + call->sip_tx_count = 1; +}