comparison sip-out/invite.c @ 156:0bacca1f2f7b

sip-out: handle all INVITE responses, except errors
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 12 Oct 2022 07:13:55 -0800
parents
children 7643b779dbea
comparison
equal deleted inserted replaced
155:2730ccb44549 156:0bacca1f2f7b
1 /*
2 * In this module we handle responses to INVITE.
3 */
4
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/time.h>
8 #include <netinet/in.h>
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <strings.h>
14 #include <syslog.h>
15 #include "../include/gsm48_const.h"
16 #include "../include/out_routes.h"
17 #include "../libsip/parse.h"
18 #include "../libsip/sdp.h"
19 #include "../libsip/out_msg.h"
20 #include "call.h"
21
22 extern char *get_single_header();
23 extern char *extract_to_tag();
24
25 extern unsigned sip_linger_response_err;
26
27 static
28 check_sdp_present(msg)
29 struct sip_pkt_rx *msg;
30 {
31 char *hval;
32
33 if (!msg->msg_body_len)
34 return 0;
35 hval = get_single_header(msg, "Content-Type", "c", (int *) 0);
36 if (!hval)
37 return 0;
38 if (!strcasecmp(hval, "application/sdp"))
39 return 1;
40 else
41 return 0;
42 }
43
44 static
45 extract_sdp(call, msg)
46 struct call *call;
47 struct sip_pkt_rx *msg;
48 {
49 struct sdp_parse sdp_parse;
50 int rc, use_pcma;
51
52 rc = parse_incoming_sdp(msg->msg_body, msg->msg_body_len, &sdp_parse);
53 if (rc < 0)
54 return rc;
55 switch (sdp_parse.codec_mask) {
56 case SDP_CODEC_MASK_PCMU:
57 case SDP_CODEC_MASK_BOTH:
58 use_pcma = 0;
59 break;
60 case SDP_CODEC_MASK_PCMA:
61 case SDP_CODEC_MASK_BOTH | SDP_CODEC_MASK_PCMA_PREF:
62 use_pcma = 1;
63 break;
64 default:
65 return -2;
66 }
67 call->pstn_rtp_remote.sin_family = AF_INET;
68 call->pstn_rtp_remote.sin_addr = sdp_parse.ip_addr;
69 call->pstn_rtp_remote.sin_port = htons(sdp_parse.audio_port);
70 call->use_pcma = use_pcma;
71 return 0;
72 }
73
74 static void
75 handle_1xx(call, msg, tag, sin)
76 struct call *call;
77 struct sip_pkt_rx *msg;
78 char *tag;
79 struct sockaddr_in *sin;
80 {
81 int rc;
82
83 switch (call->sip_state) {
84 case SIP_STATE_INV_SENT:
85 call->sip_state = SIP_STATE_100_RCVD;
86 /* FALL THRU */
87 case SIP_STATE_100_RCVD:
88 if (msg->status_code == 180)
89 call->overall_state = OVERALL_STATE_RINGING;
90 if (check_sdp_present(msg) &&
91 call->mgw_state == MGW_STATE_ALLOCATED) {
92 rc = extract_sdp(call, msg);
93 if (rc < 0) {
94 syslog(LOG_ERR, "bad SDP in %03u response",
95 msg->status_code);
96 call->overall_state = OVERALL_STATE_TEARDOWN;
97 disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
98 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
99 disconnect_tmgw(call);
100 initiate_sip_cancel(call);
101 return;
102 }
103 tmgw_send_mdcx_connect(call, 1);
104 } else if (msg->status_code == 180)
105 mncc_signal_alerting(call);
106 return;
107 case SIP_STATE_ACCEPT_100:
108 initiate_sip_cancel(call);
109 return;
110 }
111 }
112
113 static
114 send_ack(call, tag, sin)
115 struct call *call;
116 char *tag;
117 struct sockaddr_in *sin;
118 {
119 struct sip_msg_out msg;
120 int rc;
121
122 rc = start_request_out_msg(&msg, "ACK", call->to_uri);
123 if (rc < 0)
124 return rc;
125 rc = add_req_boilerplate(&msg, call, "1 ACK", tag);
126 if (rc < 0)
127 return rc;
128 out_msg_finish(&msg);
129 sip_tx_packet(&msg, sin);
130 return 0;
131 }
132
133 static void
134 handle_200(call, msg, tag, sin)
135 struct call *call;
136 struct sip_pkt_rx *msg;
137 char *tag;
138 struct sockaddr_in *sin;
139 {
140 int rc;
141
142 switch (call->sip_state) {
143 case SIP_STATE_INV_SENT:
144 case SIP_STATE_100_RCVD:
145 rc = send_ack(call, tag, sin);
146 if (rc < 0) {
147 syslog(LOG_CRIT,
148 "ACK to %03u response exceeds msg size!",
149 msg->status_code);
150 call->overall_state = OVERALL_STATE_TEARDOWN;
151 disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
152 GSM48_CC_CAUSE_DEST_OOO);
153 disconnect_tmgw(call);
154 call->sip_state = SIP_STATE_ENDED;
155 sip_mark_end_time(call, sip_linger_response_err);
156 return;
157 }
158 if (tag)
159 strcpy(call->to_tag, tag);
160 call->sip_state = SIP_STATE_CONNECTED;
161 if (!check_sdp_present(msg)) {
162 syslog(LOG_ERR, "error: %03u response has no SDP",
163 msg->status_code);
164 call->overall_state = OVERALL_STATE_TEARDOWN;
165 disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
166 GSM48_CC_CAUSE_DEST_OOO);
167 disconnect_tmgw(call);
168 initiate_bye(call);
169 return;
170 }
171 rc = extract_sdp(call, msg);
172 if (rc < 0) {
173 syslog(LOG_ERR, "bad SDP in %03u response",
174 msg->status_code);
175 call->overall_state = OVERALL_STATE_TEARDOWN;
176 disconnect_mncc(call, GSM48_CAUSE_LOC_PRN_S_LU,
177 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
178 disconnect_tmgw(call);
179 initiate_bye(call);
180 return;
181 }
182 call->overall_state = OVERALL_STATE_CONNECTED;
183 switch (call->mgw_state) {
184 case MGW_STATE_ALLOCATED:
185 case MGW_STATE_IBT_CONN:
186 tmgw_send_mdcx_connect(call, 0);
187 return;
188 case MGW_STATE_MDCX_IBT:
189 return;
190 default:
191 syslog(LOG_CRIT,
192 "FATAL: invalid MGW state 0x%x on INVITE %03u response",
193 call->mgw_state, msg->status_code);
194 exit(1);
195 }
196 case SIP_STATE_CONNECTED:
197 case SIP_STATE_BYE_SENT:
198 if (tag && call->to_tag[0] && strcmp(call->to_tag, tag)) {
199 syslog(LOG_ERR,
200 "received %u response with different To tag, ignoring",
201 msg->status_code);
202 return;
203 }
204 send_ack(call, call->to_tag, sin);
205 return;
206 case SIP_STATE_CANCEL_SENT:
207 case SIP_STATE_ACCEPT_100:
208 case SIP_STATE_ACCEPT_200:
209 rc = send_ack(call, tag, sin);
210 if (rc < 0) {
211 syslog(LOG_CRIT,
212 "ACK to %03u response exceeds msg size!",
213 msg->status_code);
214 call->sip_state = SIP_STATE_ENDED;
215 sip_mark_end_time(call, sip_linger_response_err);
216 return;
217 }
218 if (tag)
219 strcpy(call->to_tag, tag);
220 initiate_bye(call);
221 return;
222 case SIP_STATE_ENDED:
223 return;
224 default:
225 syslog(LOG_CRIT,
226 "FATAL: invalid SIP state 0x%x on INVITE %03u response",
227 call->sip_state, msg->status_code);
228 exit(1);
229 }
230 }
231
232 static void
233 handle_error(call, msg, tag, sin)
234 struct call *call;
235 struct sip_pkt_rx *msg;
236 char *tag;
237 struct sockaddr_in *sin;
238 {
239
240 }
241
242 void
243 handle_invite_response(call, msg, sin)
244 struct call *call;
245 struct sip_pkt_rx *msg;
246 struct sockaddr_in *sin;
247 {
248 char *tag;
249
250 tag = extract_to_tag(msg, call->to_uri);
251 if (tag) {
252 if (!*tag) {
253 syslog(LOG_ERR,
254 "To tag in INVITE %03u response is null",
255 msg->status_code);
256 tag = 0;
257 } else if (strlen(tag) > MAX_SIP_TO_TAG) {
258 syslog(LOG_ERR,
259 "To tag in INVITE %03u response exceeds length limit",
260 msg->status_code);
261 tag = 0;
262 }
263 }
264 if (msg->status_code >= 100 && msg->status_code <= 199)
265 handle_1xx(call, msg, tag, sin);
266 else if (msg->status_code >= 200 && msg->status_code <= 299)
267 handle_200(call, msg, tag, sin);
268 else
269 handle_error(call, msg, tag, sin);
270 }