FreeCalypso > hg > themwi-system-sw
comparison sip-in/invite.c @ 60:02761f1ae5e5
sip-in INVITE processing: got as far as CRCX completion
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 11 Sep 2022 15:42:54 -0800 |
parents | d61d0136f6a5 |
children | 7c0309df59f8 |
comparison
equal
deleted
inserted
replaced
59:bea761629c5b | 60:02761f1ae5e5 |
---|---|
3 */ | 3 */ |
4 | 4 |
5 #include <sys/types.h> | 5 #include <sys/types.h> |
6 #include <sys/socket.h> | 6 #include <sys/socket.h> |
7 #include <netinet/in.h> | 7 #include <netinet/in.h> |
8 #include <arpa/inet.h> | |
8 #include <stdio.h> | 9 #include <stdio.h> |
10 #include <stdint.h> | |
9 #include <stdlib.h> | 11 #include <stdlib.h> |
10 #include <string.h> | 12 #include <string.h> |
11 #include <strings.h> | 13 #include <strings.h> |
12 #include <syslog.h> | 14 #include <syslog.h> |
13 #include <unistd.h> | |
14 #include "../libsip/parse.h" | 15 #include "../libsip/parse.h" |
15 #include "../libsip/uas_basic.h" | 16 #include "../libsip/uas_basic.h" |
16 #include "../libsip/grok_from.h" | 17 #include "../libsip/grok_from.h" |
17 #include "../libsip/req_supp.h" | 18 #include "../libsip/req_supp.h" |
18 #include "../libsip/sdp.h" | 19 #include "../libsip/sdp.h" |
19 #include "../libsip/out_msg.h" | 20 #include "../libsip/out_msg.h" |
21 #include "call.h" | |
20 | 22 |
21 extern struct in_addr sip_bind_ip; | 23 extern struct in_addr sip_bind_ip; |
24 extern unsigned sip_bind_port; | |
22 extern int cfg_use_100rel; | 25 extern int cfg_use_100rel; |
23 | 26 extern struct call *call_list; |
27 | |
28 extern struct call *find_call_by_sip_id(); | |
24 extern char *get_single_header(); | 29 extern char *get_single_header(); |
25 | 30 |
26 void | 31 fill_invite_resp_from_call(msg, call) |
27 handle_sip_invite(req, ess, sin) | 32 struct sip_msg_out *msg; |
33 struct call *call; | |
34 { | |
35 char cseq_str[32]; | |
36 int rc; | |
37 | |
38 rc = out_msg_add_header(msg, "From", call->invite_from); | |
39 if (rc < 0) | |
40 return rc; | |
41 rc = out_msg_add_header(msg, "To", call->invite_to); | |
42 if (rc < 0) | |
43 return rc; | |
44 rc = out_msg_add_header(msg, "Call-ID", call->sip_call_id); | |
45 if (rc < 0) | |
46 return rc; | |
47 sprintf(cseq_str, "%u INVITE", call->invite_cseq); | |
48 rc = out_msg_add_header(msg, "CSeq", cseq_str); | |
49 if (rc < 0) | |
50 return rc; | |
51 return out_msg_add_header(msg, "Via", call->invite_via); | |
52 } | |
53 | |
54 fill_invite_200_resp(msg, call) | |
55 struct sip_msg_out *msg; | |
56 struct call *call; | |
57 { | |
58 char contact_str[80]; | |
59 struct sdp_gen sdp; | |
60 int rc; | |
61 | |
62 start_response_out_msg(msg, "200 CONNECT"); | |
63 rc = fill_invite_resp_from_call(msg, call); | |
64 if (rc < 0) | |
65 return rc; | |
66 sprintf(contact_str, "<sip:%s:%u;transport=udp>", | |
67 inet_ntoa(sip_bind_ip), sip_bind_port); | |
68 rc = out_msg_add_header(msg, "Contact", contact_str); | |
69 if (rc < 0) | |
70 return rc; | |
71 rc = out_msg_add_header(msg, "Content-Type", "application/sdp"); | |
72 if (rc < 0) | |
73 return rc; | |
74 bzero(&sdp, sizeof sdp); | |
75 sdp.conn_ip = call->pstn_rtp_local.sin_addr; | |
76 sdp.conn_port = ntohs(call->pstn_rtp_local.sin_port); | |
77 sdp.codec_mask = call->use_pcma ? SDP_CODEC_MASK_PCMA | |
78 : SDP_CODEC_MASK_PCMU; | |
79 sdp.session_id = (sdp.conn_port << 16) | call->sdp_addend; | |
80 sdp.owner_ip = sip_bind_ip; | |
81 return out_msg_finish_sdp(msg, &sdp); | |
82 } | |
83 | |
84 static void | |
85 invite_new_call(req, ess, sin) | |
28 struct sip_pkt_rx *req; | 86 struct sip_pkt_rx *req; |
29 struct uas_parse_hdrs *ess; | 87 struct uas_parse_hdrs *ess; |
30 struct sockaddr_in *sin; | 88 struct sockaddr_in *sin; |
31 { | 89 { |
32 char uri_user[13], *called_nanp; | 90 char uri_user[13], *called_nanp; |
35 struct supported_ext supp_ext; | 93 struct supported_ext supp_ext; |
36 char *hval, *unsup_ext; | 94 char *hval, *unsup_ext; |
37 int ext_100rel_req, ext_100rel_sup, use_100rel, use_pcma; | 95 int ext_100rel_req, ext_100rel_sup, use_100rel, use_pcma; |
38 struct sdp_parse sdp_parse; | 96 struct sdp_parse sdp_parse; |
39 struct sdp_gen sdp_gen; | 97 struct sdp_gen sdp_gen; |
40 int rc; | 98 struct call *call; |
41 | 99 char *dp; |
42 /* check for existing Call-ID will go here */ | 100 unsigned copylen; |
101 int rc; | |
102 | |
43 /* extract called number from Request-URI */ | 103 /* extract called number from Request-URI */ |
44 rc = user_from_sip_uri(req->req_uri, uri_user, 12); | 104 rc = user_from_sip_uri(req->req_uri, uri_user, 12); |
45 if (rc < 0) { | 105 if (rc < 0) { |
46 not_nanp: start_response_out_msg(&resp, | 106 not_nanp: start_response_out_msg(&resp, |
47 "416 Request-URI is not a NANP number"); | 107 "416 Request-URI is not a NANP number"); |
48 error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method); | 108 error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method); |
49 if (rc < 0) { | 109 if (rc < 0) { |
50 error_resp_toolong: syslog(LOG_ERR, | 110 error_resp_toolong: syslog(LOG_ERR, |
51 "INVITE error response length exceeded"); | 111 "INVITE early error response length exceeded"); |
52 return; | 112 return; |
53 } | 113 } |
54 out_msg_finish(&resp); | 114 out_msg_finish(&resp); |
55 sip_tx_packet(&resp, sin); | 115 sip_tx_packet(&resp, sin); |
56 return; | 116 return; |
57 } | 117 } |
58 if (uri_user[0] == '+') { | 118 if (uri_user[0] == '+') { |
59 if (grok_number_string(uri_user+1, 0) != 11 || | 119 if (grok_number_string(uri_user+1, 0) != 11 || |
60 uri_user[1] != '1') | 120 uri_user[1] != '1') |
61 goto not_nanp; | 121 goto not_nanp; |
154 sdp_gen.codec_mask = SDP_CODEC_MASK_BOTH; | 214 sdp_gen.codec_mask = SDP_CODEC_MASK_BOTH; |
155 rc = out_msg_finish_sdp(&resp, &sdp_gen); | 215 rc = out_msg_finish_sdp(&resp, &sdp_gen); |
156 if (rc < 0) | 216 if (rc < 0) |
157 goto error_resp_toolong; | 217 goto error_resp_toolong; |
158 sip_tx_packet(&resp, sin); | 218 sip_tx_packet(&resp, sin); |
159 return; | 219 return; |
160 } | 220 } |
161 /* SIP INVITE validation done - check if GSM service is up */ | 221 /* SIP INVITE validation done - check if GSM service is up */ |
162 rc = connect_gsm_mtcall(); | 222 rc = connect_gsm_mtcall(); |
163 if (rc < 0) { | 223 if (rc < 0) { |
164 start_response_out_msg(&resp, "480 GSM service is offline"); | 224 start_response_out_msg(&resp, "480 GSM service is offline"); |
165 goto error_resp; | 225 goto error_resp; |
166 } | 226 } |
167 /* stateful processing begins */ | 227 /* stateful processing begins */ |
168 } | 228 call = malloc(sizeof(struct call) + strlen(ess->call_id) + |
229 strlen(ess->from) + strlen(ess->to) + strlen(ess->via) | |
230 + 4); | |
231 if (!call) { | |
232 syslog(LOG_CRIT, "failed malloc for incoming call!"); | |
233 start_response_out_msg(&resp, | |
234 "503 Gateway resource allocation failure"); | |
235 goto error_resp; | |
236 } | |
237 bzero(call, sizeof(struct call)); | |
238 dp = (char *)(call + 1); | |
239 copylen = strlen(ess->call_id) + 1; | |
240 call->sip_call_id = dp; | |
241 bcopy(ess->call_id, dp, copylen); | |
242 dp += copylen; | |
243 copylen = strlen(ess->from) + 1; | |
244 call->invite_from = dp; | |
245 bcopy(ess->from, dp, copylen); | |
246 dp += copylen; | |
247 copylen = strlen(ess->to) + 1; | |
248 call->invite_to = dp; | |
249 bcopy(ess->to, dp, copylen); | |
250 dp += copylen; | |
251 copylen = strlen(ess->via) + 1; | |
252 call->invite_via = dp; | |
253 bcopy(ess->via, dp, copylen); | |
254 call->invite_cseq = ess->cseq_num; | |
255 bcopy(sin, &call->udp_sin, sizeof(struct sockaddr_in)); | |
256 bcopy(called_nanp, call->called_nanp, 11); | |
257 call->from_uri = call->invite_from + (gfrom.uri - ess->from); | |
258 call->from_uri_len = gfrom.uri_len; | |
259 call->from_user = call->invite_from + (gfrom.user - ess->from); | |
260 call->from_user_len = gfrom.user_len; | |
261 call->use_100rel = use_100rel; | |
262 call->pstn_rtp_remote.sin_family = AF_INET; | |
263 call->pstn_rtp_remote.sin_addr = sdp_parse.ip_addr; | |
264 call->pstn_rtp_remote.sin_port = htons(sdp_parse.audio_port); | |
265 call->use_pcma = use_pcma; | |
266 /* generate 100 response */ | |
267 start_response_out_msg(&resp, "100 Proceeding"); | |
268 rc = fill_invite_resp_from_call(&resp, call); | |
269 if (rc < 0) { | |
270 syslog(LOG_ERR, "INVITE 100 response length exceeded"); | |
271 free(call); | |
272 return; | |
273 } | |
274 out_msg_finish(&resp); | |
275 sip_tx_packet(&resp, sin); | |
276 /* add to call list */ | |
277 call->next = call_list; | |
278 call_list = call; | |
279 /* send CRCX to TMGW */ | |
280 tmgw_send_crcx(call); | |
281 call->overall_state = OVERALL_STATE_CRCX; | |
282 call->sip_state = SIP_STATE_INVITE_PROC; | |
283 } | |
284 | |
285 static void | |
286 invite_existing_call(req, ess, sin, call) | |
287 struct sip_pkt_rx *req; | |
288 struct uas_parse_hdrs *ess; | |
289 struct sockaddr_in *sin; | |
290 struct call *call; | |
291 { | |
292 struct sip_msg_out resp; | |
293 int rc; | |
294 | |
295 if (ess->cseq_num != call->invite_cseq) { | |
296 start_response_out_msg(&resp, "501 Re-INVITE not supported"); | |
297 rc = add_resp_basic_headers(&resp, ess, req->req_method); | |
298 if (rc < 0) { | |
299 syslog(LOG_ERR, | |
300 "sending 501 Re-INVITE error: response length exceeded"); | |
301 return; | |
302 } | |
303 out_msg_finish(&resp); | |
304 sip_tx_packet(&resp, sin); | |
305 return; | |
306 } | |
307 /* it's a retransmission, not a re-INVITE */ | |
308 switch (call->sip_state) { | |
309 case SIP_STATE_INVITE_PROC: | |
310 start_response_out_msg(&resp, "100 Proceeding"); | |
311 fill_invite_resp_from_call(&resp, call); | |
312 out_msg_finish(&resp); | |
313 sip_tx_packet(&resp, sin); | |
314 return; | |
315 case SIP_STATE_RINGING: | |
316 case SIP_STATE_RINGING_PRACK: | |
317 start_response_out_msg(&resp, "180 Ringing"); | |
318 fill_invite_resp_from_call(&resp, call); | |
319 out_msg_finish(&resp); | |
320 sip_tx_packet(&resp, sin); | |
321 return; | |
322 case SIP_STATE_INVITE_200: | |
323 case SIP_STATE_CONNECTED: | |
324 fill_invite_200_resp(&resp, call); | |
325 sip_tx_packet(&resp, sin); | |
326 return; | |
327 case SIP_STATE_INVITE_ERR: | |
328 start_response_out_msg(&resp, call->invite_fail); | |
329 fill_invite_resp_from_call(&resp, call); | |
330 out_msg_finish(&resp); | |
331 sip_tx_packet(&resp, sin); | |
332 return; | |
333 default: | |
334 /* silently discard */ | |
335 return; | |
336 } | |
337 } | |
338 | |
339 void | |
340 handle_sip_invite(req, ess, sin) | |
341 struct sip_pkt_rx *req; | |
342 struct uas_parse_hdrs *ess; | |
343 struct sockaddr_in *sin; | |
344 { | |
345 struct call *call; | |
346 | |
347 call = find_call_by_sip_id(ess->call_id); | |
348 if (call) | |
349 invite_existing_call(req, ess, sin, call); | |
350 else | |
351 invite_new_call(req, ess, sin); | |
352 } | |
353 | |
354 void | |
355 signal_invite_error(call) | |
356 struct call *call; | |
357 { | |
358 struct sip_msg_out resp; | |
359 int rc; | |
360 | |
361 start_response_out_msg(&resp, call->invite_fail); | |
362 rc = fill_invite_resp_from_call(&resp, call); | |
363 if (rc < 0) { | |
364 syslog(LOG_ERR, "INVITE late error response length exceeded"); | |
365 call->sip_state = SIP_STATE_MSG_SIZE_ERR; | |
366 /* TODO: transition from TEARDOWN to DEAD_SIP */ | |
367 return; | |
368 } | |
369 out_msg_finish(&resp); | |
370 sip_tx_packet(&resp, &call->udp_sin); | |
371 call->sip_state = SIP_STATE_INVITE_ERR; | |
372 call->sip_tx_count = 1; | |
373 } |