comparison sip-in/prack.c @ 108:0d6435808bcd

sip-in: implement 100rel for 180 Ringing response
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 28 Sep 2022 14:29:10 -0800
parents
children 9b87894704eb
comparison
equal deleted inserted replaced
107:372209628038 108:0d6435808bcd
1 /*
2 * Here we implement our handling of SIP PRACK, expected from callers
3 * when we send them a reliable 180 Ringing response.
4 */
5
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <strings.h>
15 #include <syslog.h>
16 #include "../include/gsm48_const.h"
17 #include "../libsip/parse.h"
18 #include "../libsip/uas_basic.h"
19 #include "../libsip/out_msg.h"
20 #include "call.h"
21
22 extern char *get_single_header();
23 extern struct call *find_call_by_sip_id();
24
25 void
26 handle_sip_prack(req, ess, sin)
27 struct sip_pkt_rx *req;
28 struct uas_parse_hdrs *ess;
29 struct sockaddr_in *sin;
30 {
31 struct call *call;
32 struct sip_msg_out resp;
33 char *rack, *orig_method, *cp;
34 unsigned rseq, orig_num;
35 int rc;
36
37 call = find_call_by_sip_id(ess->call_id);
38 if (!call) {
39 start_response_out_msg(&resp, "481 Call-ID not found");
40 error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method);
41 if (rc < 0)
42 return;
43 out_msg_finish(&resp);
44 sip_tx_packet(&resp, sin);
45 return;
46 }
47 rack = get_single_header(req, "RAck", (char *) 0, (int *) 0);
48 if (!rack) {
49 start_response_out_msg(&resp, "400 Missing RAck header");
50 goto error_resp;
51 }
52 if (!isdigit(*rack)) {
53 malformed: start_response_out_msg(&resp, "400 Malformed RAck header");
54 goto error_resp;
55 }
56 rseq = strtoul(rack, &cp, 10);
57 if (!isspace(*cp))
58 goto malformed;
59 while (isspace(*cp))
60 cp++;
61 if (!isdigit(*cp))
62 goto malformed;
63 orig_num = strtoul(cp, &cp, 10);
64 if (!isspace(*cp))
65 goto malformed;
66 while (isspace(*cp))
67 cp++;
68 if (!isupper(*cp))
69 goto malformed;
70 orig_method = cp;
71 while (isalnum(*cp))
72 cp++;
73 if (*cp)
74 goto malformed;
75 if (rseq != 1 || orig_num != call->invite_cseq ||
76 strcmp(orig_method, "INVITE")) {
77 start_response_out_msg(&resp,
78 "481 RAck fails to match our 100rel response");
79 goto error_resp;
80 }
81 switch (call->sip_state) {
82 case SIP_STATE_RINGING_REL:
83 call->sip_state = SIP_STATE_RINGING;
84 start_response_out_msg(&resp, "200 OK");
85 rc = add_resp_basic_headers(&resp, ess, req->req_method);
86 if (rc < 0) {
87 syslog(LOG_ERR, "PRACK 200 response length exceeded");
88 call->sip_state = SIP_STATE_MSG_SIZE_ERR;
89 call->overall_state = OVERALL_STATE_TEARDOWN;
90 disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
91 GSM48_CC_CAUSE_INTERWORKING);
92 disconnect_tmgw(call);
93 /* TODO: transition from TEARDOWN to DEAD_SIP */
94 return;
95 }
96 out_msg_finish(&resp);
97 sip_tx_packet(&resp, sin);
98 return;
99 case SIP_STATE_RINGING:
100 case SIP_STATE_INVITE_200:
101 start_response_out_msg(&resp, "200 OK");
102 rc = add_resp_basic_headers(&resp, ess, req->req_method);
103 if (rc < 0)
104 return;
105 out_msg_finish(&resp);
106 sip_tx_packet(&resp, sin);
107 return;
108 case SIP_STATE_INVITE_PROC:
109 case SIP_STATE_CONNECTED:
110 case SIP_STATE_BYE_SENT:
111 case SIP_STATE_INVITE_ERR:
112 case SIP_STATE_ENDED:
113 start_response_out_msg(&resp,
114 "481 No outstanding 100rel response");
115 goto error_resp;
116 }
117 }