view sip-in/invite.c @ 57:d61d0136f6a5

sip-in INVITE processing: return "GSM service is offline" indication
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Sep 2022 13:39:42 -0800
parents f1d59210f7b2
children 02761f1ae5e5
line wrap: on
line source

/*
 * Here we implement our handling of SIP INVITE method.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include <unistd.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"

extern struct in_addr sip_bind_ip;
extern int cfg_use_100rel;

extern char *get_single_header();

void
handle_sip_invite(req, ess, sin)
	struct sip_pkt_rx *req;
	struct uas_parse_hdrs *ess;
	struct sockaddr_in *sin;
{
	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;
	int rc;

	/* check for existing Call-ID will go here */
	/* 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 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;
	}
	/* 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:
	case SDP_CODEC_MASK_BOTH:
		use_pcma = 0;
		break;
	case SDP_CODEC_MASK_PCMA:
	case SDP_CODEC_MASK_BOTH | SDP_CODEC_MASK_PCMA_PREF:
		use_pcma = 1;
		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 - check if GSM service is up */
	rc = connect_gsm_mtcall();
	if (rc < 0) {
		start_response_out_msg(&resp, "480 GSM service is offline");
		goto error_resp;
	}
	/* stateful processing begins */
}