FreeCalypso > hg > themwi-system-sw
comparison sip-in/invite_init.c @ 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 | sip-in/invite.c@c93c339271a7 |
children | 257da5474e77 |
comparison
equal
deleted
inserted
replaced
144:4e16aeafbfbf | 145:4b685a5d9bd4 |
---|---|
1 /* | |
2 * Here we implement our initial processing of SIP INVITE requests. | |
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 "../libsip/parse.h" | |
16 #include "../libsip/uas_basic.h" | |
17 #include "../libsip/grok_from.h" | |
18 #include "../libsip/req_supp.h" | |
19 #include "../libsip/sdp.h" | |
20 #include "../libsip/out_msg.h" | |
21 #include "call.h" | |
22 | |
23 extern struct in_addr sip_bind_ip; | |
24 extern int cfg_use_100rel; | |
25 extern int cfg_force_pcma; | |
26 extern struct call *call_list; | |
27 | |
28 extern struct call *find_call_by_sip_id(); | |
29 extern char *get_single_header(); | |
30 | |
31 void | |
32 invite_new_call(req, ess, sin) | |
33 struct sip_pkt_rx *req; | |
34 struct uas_parse_hdrs *ess; | |
35 struct sockaddr_in *sin; | |
36 { | |
37 static unsigned cycle_tag_num, cycle_sdp_addend; | |
38 char uri_user[13], *called_nanp; | |
39 struct sip_msg_out resp; | |
40 struct grok_from gfrom; | |
41 struct supported_ext supp_ext; | |
42 char *hval, *unsup_ext; | |
43 int ext_100rel_req, ext_100rel_sup, use_100rel, use_pcma; | |
44 struct sdp_parse sdp_parse; | |
45 struct sdp_gen sdp_gen; | |
46 struct call *call; | |
47 char *dp, cdr_str[80]; | |
48 unsigned cdr_num_len, cdr_cnam_len; | |
49 unsigned req_uri_len, to_hdr_len, copylen; | |
50 int rc; | |
51 | |
52 /* extract called number from Request-URI */ | |
53 rc = user_from_sip_uri(req->req_uri, uri_user, 12); | |
54 if (rc < 0) { | |
55 not_nanp: start_response_out_msg(&resp, | |
56 "416 Request-URI is not a NANP number"); | |
57 error_resp: rc = add_resp_basic_headers(&resp, ess, req->req_method); | |
58 if (rc < 0) { | |
59 error_resp_toolong: syslog(LOG_ERR, | |
60 "INVITE early error response length exceeded"); | |
61 return; | |
62 } | |
63 out_msg_finish(&resp); | |
64 sip_tx_packet(&resp, sin); | |
65 return; | |
66 } | |
67 if (uri_user[0] == '+') { | |
68 if (grok_number_string(uri_user+1, 0) != 11 || | |
69 uri_user[1] != '1') | |
70 goto not_nanp; | |
71 called_nanp = uri_user + 2; | |
72 } else switch (grok_number_string(uri_user)) { | |
73 case 10: | |
74 called_nanp = uri_user; | |
75 break; | |
76 case 11: | |
77 if (uri_user[0] != '1') | |
78 goto not_nanp; | |
79 called_nanp = uri_user + 1; | |
80 break; | |
81 default: | |
82 goto not_nanp; | |
83 } | |
84 if (!is_nanp_valid_prefix(called_nanp)) | |
85 goto not_nanp; | |
86 /* it is valid NANP - but is it one of ours? */ | |
87 refresh_number_db(); | |
88 if (!is_nanp_locally_owned(called_nanp)) { | |
89 start_response_out_msg(&resp, | |
90 "404 Called number does not belong here"); | |
91 goto error_resp; | |
92 } | |
93 /* parse and validate From header */ | |
94 rc = grok_from_header(ess->from, &gfrom); | |
95 if (rc < 0) { | |
96 start_response_out_msg(&resp, "400 Malformed From header"); | |
97 goto error_resp; | |
98 } | |
99 /* validate To header for the purpose of tag addition */ | |
100 req_uri_len = strlen(req->req_uri); | |
101 to_hdr_len = strlen(ess->to); | |
102 if (to_hdr_len == req_uri_len) { | |
103 if (strcasecmp(ess->to, req->req_uri)) { | |
104 bad_to_header: start_response_out_msg(&resp, "400 Bad To header"); | |
105 goto error_resp; | |
106 } | |
107 } else if (to_hdr_len == req_uri_len + 2) { | |
108 if (ess->to[0] != '<') | |
109 goto bad_to_header; | |
110 if (strncasecmp(ess->to+1, req->req_uri, req_uri_len)) | |
111 goto bad_to_header; | |
112 if (ess->to[req_uri_len+1] != '>') | |
113 goto bad_to_header; | |
114 } else | |
115 goto bad_to_header; | |
116 /* check 100rel and catch any unsupported requirements */ | |
117 supp_ext.name = "100rel"; | |
118 supp_ext.req_flag = &ext_100rel_req; | |
119 supp_ext.sup_flag = &ext_100rel_sup; | |
120 ext_100rel_req = ext_100rel_sup = 0; | |
121 rc = parse_require_supported(req, &supp_ext, 1, &unsup_ext); | |
122 if (rc < 0) { | |
123 start_response_out_msg(&resp, "420 Extension not supported"); | |
124 rc = out_msg_add_header(&resp, "Unsupported", unsup_ext); | |
125 if (rc < 0) | |
126 goto error_resp_toolong; | |
127 goto error_resp; | |
128 } | |
129 if (ext_100rel_req) | |
130 use_100rel = 1; | |
131 else if (ext_100rel_sup) | |
132 use_100rel = cfg_use_100rel; | |
133 else | |
134 use_100rel = 0; | |
135 /* did the caller send an SDP message body? */ | |
136 if (!req->msg_body_len) { | |
137 start_response_out_msg(&resp, "415 Missing SDP body"); | |
138 error_415: rc = out_msg_add_header(&resp, "Accept", "application/sdp"); | |
139 if (rc < 0) | |
140 goto error_resp_toolong; | |
141 goto error_resp; | |
142 } | |
143 hval = get_single_header(req, "Content-Type", "c", (int *) 0); | |
144 if (!hval) { | |
145 start_response_out_msg(&resp, | |
146 "415 Missing Content-Type header"); | |
147 goto error_415; | |
148 } | |
149 if (strcasecmp(hval, "application/sdp")) { | |
150 start_response_out_msg(&resp, "415 Unsupported Content-Type"); | |
151 goto error_415; | |
152 } | |
153 rc = parse_incoming_sdp(req->msg_body, req->msg_body_len, &sdp_parse); | |
154 if (rc < 0) { | |
155 start_response_out_msg(&resp, "488 Malformed SDP body"); | |
156 goto error_resp; | |
157 } | |
158 switch (sdp_parse.codec_mask) { | |
159 case SDP_CODEC_MASK_PCMU: | |
160 use_pcma = 0; | |
161 break; | |
162 case SDP_CODEC_MASK_PCMA: | |
163 case SDP_CODEC_MASK_BOTH | SDP_CODEC_MASK_PCMA_PREF: | |
164 use_pcma = 1; | |
165 break; | |
166 case SDP_CODEC_MASK_BOTH: | |
167 use_pcma = cfg_force_pcma; | |
168 break; | |
169 default: | |
170 start_response_out_msg(&resp, | |
171 "488 Unsupported codec selection"); | |
172 rc = add_resp_basic_headers(&resp, ess, req->req_method); | |
173 if (rc < 0) | |
174 goto error_resp_toolong; | |
175 rc = out_msg_add_header(&resp, "Content-Type", | |
176 "application/sdp"); | |
177 if (rc < 0) | |
178 goto error_resp_toolong; | |
179 bzero(&sdp_gen, sizeof sdp_gen); | |
180 sdp_gen.owner_ip = sip_bind_ip; | |
181 sdp_gen.conn_ip = sip_bind_ip; | |
182 sdp_gen.codec_mask = SDP_CODEC_MASK_BOTH; | |
183 rc = out_msg_finish_sdp(&resp, &sdp_gen); | |
184 if (rc < 0) | |
185 goto error_resp_toolong; | |
186 sip_tx_packet(&resp, sin); | |
187 return; | |
188 } | |
189 /* SIP INVITE validation done - gather CDR info */ | |
190 cdr_num_len = gfrom.user_len; | |
191 if (cdr_num_len > 33) | |
192 cdr_num_len = 33; | |
193 cdr_cnam_len = gfrom.cnam_len; | |
194 if (cdr_cnam_len > 33) | |
195 cdr_cnam_len = 33; | |
196 if (cdr_cnam_len) | |
197 sprintf(cdr_str, "%.*s (%s%.*s%s)", cdr_num_len, gfrom.user, | |
198 gfrom.cnam_quoted ? "\"" : "", cdr_cnam_len, gfrom.cnam, | |
199 gfrom.cnam_quoted ? "\"" : ""); | |
200 else | |
201 sprintf(cdr_str, "%.*s", cdr_num_len, gfrom.user); | |
202 hval = get_single_header(req, "P-Asserted-Identity", (char *) 0, | |
203 (int *) 0); | |
204 /* check if GSM service is up */ | |
205 rc = connect_gsm_mtcall(); | |
206 if (rc < 0) { | |
207 gsm_offline: syslog(LOG_INFO, "Down-call from %s to %s", cdr_str, uri_user); | |
208 if (hval) | |
209 syslog(LOG_INFO, "Down-call PAI: %.100s", hval); | |
210 start_response_out_msg(&resp, "480 GSM service is offline"); | |
211 goto error_resp; | |
212 } | |
213 rc = connect_tmgw_socket(); | |
214 if (rc < 0) | |
215 goto gsm_offline; | |
216 /* stateful processing begins */ | |
217 call = malloc(sizeof(struct call) + strlen(ess->call_id) + | |
218 strlen(ess->from) + req_uri_len + strlen(ess->via) + 19); | |
219 if (!call) { | |
220 syslog(LOG_CRIT, "failed malloc for incoming call!"); | |
221 start_response_out_msg(&resp, | |
222 "503 Gateway resource allocation failure"); | |
223 goto error_resp; | |
224 } | |
225 cycle_tag_num++; | |
226 if (cycle_tag_num >= 1000000) | |
227 cycle_tag_num = 0; | |
228 cycle_sdp_addend++; | |
229 if (cycle_sdp_addend >= 0x10000) | |
230 cycle_sdp_addend = 0; | |
231 bzero(call, sizeof(struct call)); | |
232 dp = (char *)(call + 1); | |
233 copylen = strlen(ess->call_id) + 1; | |
234 call->sip_call_id = dp; | |
235 bcopy(ess->call_id, dp, copylen); | |
236 dp += copylen; | |
237 copylen = strlen(ess->from) + 1; | |
238 call->invite_from = dp; | |
239 bcopy(ess->from, dp, copylen); | |
240 dp += copylen; | |
241 call->invite_to = dp; | |
242 *dp++ = '<'; | |
243 bcopy(req->req_uri, dp, req_uri_len); | |
244 dp += req_uri_len; | |
245 *dp++ = '>'; | |
246 sprintf(dp, ";tag=in%06u", cycle_tag_num); | |
247 dp += 14; | |
248 copylen = strlen(ess->via) + 1; | |
249 call->invite_via = dp; | |
250 bcopy(ess->via, dp, copylen); | |
251 call->invite_cseq = ess->cseq_num; | |
252 bcopy(sin, &call->udp_sin, sizeof(struct sockaddr_in)); | |
253 bcopy(called_nanp, call->called_nanp, 11); | |
254 call->from_uri = call->invite_from + (gfrom.uri - ess->from); | |
255 call->from_uri_len = gfrom.uri_len; | |
256 call->from_user = call->invite_from + (gfrom.user - ess->from); | |
257 call->from_user_len = gfrom.user_len; | |
258 call->use_100rel = use_100rel; | |
259 call->pstn_rtp_remote.sin_family = AF_INET; | |
260 call->pstn_rtp_remote.sin_addr = sdp_parse.ip_addr; | |
261 call->pstn_rtp_remote.sin_port = htons(sdp_parse.audio_port); | |
262 call->use_pcma = use_pcma; | |
263 call->in_tag_num = cycle_tag_num; | |
264 call->sdp_addend = cycle_sdp_addend; | |
265 /* generate 100 response */ | |
266 start_response_out_msg(&resp, "100 Proceeding"); | |
267 rc = fill_invite_resp_from_call(&resp, call); | |
268 if (rc < 0) { | |
269 syslog(LOG_ERR, "INVITE 100 response length exceeded"); | |
270 free(call); | |
271 return; | |
272 } | |
273 out_msg_finish(&resp); | |
274 sip_tx_packet(&resp, sin); | |
275 /* add to call list */ | |
276 call->next = call_list; | |
277 call_list = call; | |
278 syslog(LOG_INFO, "Call in%06u from %s to %s", call->in_tag_num, | |
279 cdr_str, uri_user); | |
280 if (hval) | |
281 syslog(LOG_INFO, "Call in%06u PAI: %.100s", call->in_tag_num, | |
282 hval); | |
283 /* send CRCX to TMGW */ | |
284 tmgw_send_crcx(call); | |
285 call->overall_state = OVERALL_STATE_CRCX; | |
286 call->sip_state = SIP_STATE_INVITE_PROC; | |
287 } | |
288 | |
289 void | |
290 handle_sip_invite(req, ess, sin) | |
291 struct sip_pkt_rx *req; | |
292 struct uas_parse_hdrs *ess; | |
293 struct sockaddr_in *sin; | |
294 { | |
295 struct call *call; | |
296 | |
297 call = find_call_by_sip_id(ess->call_id); | |
298 if (call) | |
299 invite_existing_call(req, ess, sin, call); | |
300 else | |
301 invite_new_call(req, ess, sin); | |
302 } |