FreeCalypso > hg > themwi-system-sw
comparison utils/themwi-update-out-routes.c @ 130:44dc809ffec0
themwi-update-out-routes utility written, compiles
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 06 Oct 2022 20:56:14 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
129:b7cd66acb123 | 130:44dc809ffec0 |
---|---|
1 /* | |
2 * This program reads (parses) ThemWi config file /var/gsm/out-routes, | |
3 * generates the compiled binary form of this database, and then makes | |
4 * it live via atomic rename. | |
5 */ | |
6 | |
7 #include <sys/types.h> | |
8 #include <sys/socket.h> | |
9 #include <netinet/in.h> | |
10 #include <arpa/inet.h> | |
11 #include <ctype.h> | |
12 #include <stdio.h> | |
13 #include <stdint.h> | |
14 #include <stdlib.h> | |
15 #include <string.h> | |
16 #include <strings.h> | |
17 #include <unistd.h> | |
18 #include "../include/out_routes.h" | |
19 | |
20 #define MAX_DEST_ENTRIES 16 | |
21 #define MAX_INN_ENTRIES 64 | |
22 #define MAX_SPC_NUM_ENTRIES 64 | |
23 | |
24 static struct sip_out_dest dest_records[MAX_DEST_ENTRIES]; | |
25 static char *dest_names[MAX_DEST_ENTRIES]; | |
26 static struct inn_route inn_records[MAX_INN_ENTRIES]; | |
27 static struct special_num_route special_num_records[MAX_SPC_NUM_ENTRIES]; | |
28 static unsigned dest_rec_count, inn_rec_count, special_num_count; | |
29 | |
30 static char *system_dir; | |
31 static FILE *inf; | |
32 static int lineno; | |
33 static char linebuf[256]; | |
34 | |
35 static int | |
36 find_dest_by_name(sought_name) | |
37 char *sought_name; | |
38 { | |
39 unsigned n; | |
40 | |
41 for (n = 0; n < dest_rec_count; n++) | |
42 if (!strcmp(dest_names[n], sought_name)) | |
43 return n; | |
44 return -1; | |
45 } | |
46 | |
47 static int | |
48 find_dest_by_number(target_num) | |
49 char *target_num; | |
50 { | |
51 unsigned inn_index; | |
52 struct inn_route *rec; | |
53 char *pp, *tp; | |
54 | |
55 for (inn_index = 0; inn_index < inn_rec_count; inn_index++) { | |
56 rec = inn_records + inn_index; | |
57 pp = rec->prefix; | |
58 tp = target_num; | |
59 while (*pp && *pp == *tp) { | |
60 pp++; | |
61 tp++; | |
62 } | |
63 if (*pp) | |
64 continue; | |
65 return rec->sip_dest_id; | |
66 } | |
67 return -1; | |
68 } | |
69 | |
70 static void | |
71 handle_dest_line(cp) | |
72 char *cp; | |
73 { | |
74 char *name, *name_copy, *domain, *ip_str, *port_str; | |
75 struct sip_out_dest *rec; | |
76 unsigned portnum; | |
77 int rc; | |
78 | |
79 for (name = cp; *cp && !isspace(*cp); cp++) | |
80 ; | |
81 if (*cp) | |
82 *cp++ = '\0'; | |
83 while (isspace(*cp)) | |
84 cp++; | |
85 if (*cp == '\0' || *cp == '#') { | |
86 inv_syntax: fprintf(stderr, "out-routes line %d: invalid syntax for dest\n", | |
87 lineno); | |
88 exit(1); | |
89 } | |
90 for (domain = cp; *cp && !isspace(*cp); cp++) | |
91 ; | |
92 if (*cp) | |
93 *cp++ = '\0'; | |
94 while (isspace(*cp)) | |
95 cp++; | |
96 if (*cp == '\0' || *cp == '#') | |
97 goto inv_syntax; | |
98 for (ip_str = cp; *cp && !isspace(*cp); cp++) | |
99 ; | |
100 if (*cp) | |
101 *cp++ = '\0'; | |
102 while (isspace(*cp)) | |
103 cp++; | |
104 if (*cp == '\0' || *cp == '#') | |
105 port_str = 0; | |
106 else { | |
107 for (port_str = cp; *cp && !isspace(*cp); cp++) | |
108 ; | |
109 if (*cp) | |
110 *cp++ = '\0'; | |
111 while (isspace(*cp)) | |
112 cp++; | |
113 if (*cp != '\0' && *cp != '#') | |
114 goto inv_syntax; | |
115 } | |
116 rc = find_dest_by_name(name); | |
117 if (rc >= 0) { | |
118 fprintf(stderr, | |
119 "out-routes line %d: duplicate destination name \"%s\"\n", | |
120 lineno, name); | |
121 exit(1); | |
122 } | |
123 if (dest_rec_count >= MAX_DEST_ENTRIES) { | |
124 fprintf(stderr, | |
125 "out-routes line %d: MAX_DEST_ENTRIES exceeded\n", | |
126 lineno); | |
127 exit(1); | |
128 } | |
129 name_copy = strdup(name); | |
130 if (!name_copy) { | |
131 perror("strdup"); | |
132 exit(1); | |
133 } | |
134 dest_names[dest_rec_count] = name_copy; | |
135 rec = dest_records + dest_rec_count; | |
136 if (strlen(domain) > MAX_SIP_DEST_DOMAIN) { | |
137 fprintf(stderr, | |
138 "out-routes line %d: dest domain string is too long\n", | |
139 lineno); | |
140 exit(1); | |
141 } | |
142 strcpy(rec->domain, domain); | |
143 rec->sin.sin_family = AF_INET; | |
144 rec->sin.sin_addr.s_addr = inet_addr(ip_str); | |
145 if (rec->sin.sin_addr.s_addr == INADDR_NONE) { | |
146 fprintf(stderr, | |
147 "out-routes line %d: dest IP address is invalid\n", | |
148 lineno); | |
149 exit(1); | |
150 } | |
151 if (port_str) { | |
152 portnum = strtoul(port_str, &cp, 10); | |
153 if (*cp) | |
154 goto inv_syntax; | |
155 } else | |
156 portnum = 5060; | |
157 rec->sin.sin_port = htons(portnum); | |
158 dest_rec_count++; | |
159 } | |
160 | |
161 static void | |
162 handle_inn_route(cp) | |
163 char *cp; | |
164 { | |
165 char *prefix, *dest_name; | |
166 struct inn_route *rec; | |
167 int rc, dest_id; | |
168 | |
169 for (prefix = cp; *cp && !isspace(*cp); cp++) | |
170 ; | |
171 if (*cp) | |
172 *cp++ = '\0'; | |
173 while (isspace(*cp)) | |
174 cp++; | |
175 if (*cp == '\0' || *cp == '#') { | |
176 inv_syntax: fprintf(stderr, | |
177 "out-routes line %d: invalid syntax for inn-route\n", | |
178 lineno); | |
179 exit(1); | |
180 } | |
181 for (dest_name = cp; *cp && !isspace(*cp); cp++) | |
182 ; | |
183 if (*cp) | |
184 *cp++ = '\0'; | |
185 while (isspace(*cp)) | |
186 cp++; | |
187 if (*cp != '\0' && *cp != '#') | |
188 goto inv_syntax; | |
189 rc = grok_number_string(prefix, 1); | |
190 if (rc < 1) | |
191 goto inv_syntax; | |
192 if (rc > MAX_INN_PREFIX) { | |
193 fprintf(stderr, | |
194 "out-routes line %d: inn-route prefix is too long\n", | |
195 lineno); | |
196 exit(1); | |
197 } | |
198 dest_id = find_dest_by_name(dest_name); | |
199 if (dest_id < 0) { | |
200 fprintf(stderr, | |
201 "out-routes line %d: SIP destination \"%s\" not defined\n", | |
202 lineno, dest_name); | |
203 exit(1); | |
204 } | |
205 if (inn_rec_count >= MAX_INN_ENTRIES) { | |
206 fprintf(stderr, | |
207 "out-routes line %d: MAX_INN_ENTRIES exceeded\n", | |
208 lineno); | |
209 exit(1); | |
210 } | |
211 rec = inn_records + inn_rec_count; | |
212 dehyphen_number_string(prefix, rec->prefix); | |
213 rec->sip_dest_id = dest_id; | |
214 inn_rec_count++; | |
215 } | |
216 | |
217 static void | |
218 preen_special_num_code(num_code) | |
219 char *num_code; | |
220 { | |
221 char *cp; | |
222 int c; | |
223 unsigned n; | |
224 | |
225 n = 0; | |
226 for (cp = num_code; *cp; ) { | |
227 c = *cp++; | |
228 if (is_valid_ext_digit(c)) | |
229 n++; | |
230 else { | |
231 fprintf(stderr, | |
232 "out-routes line %d: special-num string \"%s\" is invalid\n", | |
233 lineno, num_code); | |
234 exit(1); | |
235 } | |
236 } | |
237 if (n > MAX_SPECIAL_NUM) { | |
238 fprintf(stderr, | |
239 "out-routes line %d: special-num string \"%s\" is too long\n", | |
240 lineno, num_code); | |
241 exit(1); | |
242 } | |
243 } | |
244 | |
245 static void | |
246 handle_special_num_map_to(num_code, cp) | |
247 char *num_code, *cp; | |
248 { | |
249 struct special_num_route *rec; | |
250 char *tgt_num_src; | |
251 int rc, dest_id; | |
252 | |
253 while (isspace(*cp)) | |
254 cp++; | |
255 if (*cp++ != '+') { | |
256 inv_syntax: fprintf(stderr, | |
257 "out-routes line %d: invalid syntax for special-num map-to\n", | |
258 lineno); | |
259 exit(1); | |
260 } | |
261 if (!isdigit(*cp)) | |
262 goto inv_syntax; | |
263 for (tgt_num_src = cp; *cp && !isspace(*cp); cp++) | |
264 ; | |
265 if (*cp) | |
266 *cp++ = '\0'; | |
267 while (isspace(*cp)) | |
268 cp++; | |
269 if (*cp != '\0' && *cp != '#') | |
270 goto inv_syntax; | |
271 rc = grok_number_string(tgt_num_src, 1); | |
272 if (rc < 1) | |
273 goto inv_syntax; | |
274 if (rc > MAX_E164_NUMBER) { | |
275 fprintf(stderr, | |
276 "out-routes line %d: map-to number is too long for E.164\n", | |
277 lineno); | |
278 exit(1); | |
279 } | |
280 rec = special_num_records + special_num_count; | |
281 strcpy(rec->special_num, num_code); | |
282 rec->sip_user[0] = '+'; | |
283 dehyphen_number_string(tgt_num_src, rec->sip_user+1); | |
284 dest_id = find_dest_by_number(rec->sip_user+1); | |
285 if (dest_id < 0) { | |
286 fprintf(stderr, | |
287 "out-routes line %d: no inn-route for map-to number\n", | |
288 lineno); | |
289 exit(1); | |
290 } | |
291 rec->sip_dest_id = dest_id; | |
292 special_num_count++; | |
293 } | |
294 | |
295 static void | |
296 handle_special_num_route_to(num_code, cp) | |
297 char *num_code, *cp; | |
298 { | |
299 struct special_num_route *rec; | |
300 char *dest_name; | |
301 int dest_id; | |
302 | |
303 while (isspace(*cp)) | |
304 cp++; | |
305 if (*cp == '\0' || *cp == '#') { | |
306 inv_syntax: fprintf(stderr, | |
307 "out-routes line %d: invalid syntax for special-num route-to\n", | |
308 lineno); | |
309 exit(1); | |
310 } | |
311 for (dest_name = cp; *cp && !isspace(*cp); cp++) | |
312 ; | |
313 if (*cp) | |
314 *cp++ = '\0'; | |
315 while (isspace(*cp)) | |
316 cp++; | |
317 if (*cp != '\0' && *cp != '#') | |
318 goto inv_syntax; | |
319 dest_id = find_dest_by_name(dest_name); | |
320 if (dest_id < 0) { | |
321 fprintf(stderr, | |
322 "out-routes line %d: SIP destination \"%s\" not defined\n", | |
323 lineno, dest_name); | |
324 exit(1); | |
325 } | |
326 rec = special_num_records + special_num_count; | |
327 strcpy(rec->special_num, num_code); | |
328 strcpy(rec->sip_user, num_code); | |
329 rec->sip_dest_id = dest_id; | |
330 special_num_count++; | |
331 } | |
332 | |
333 static void | |
334 handle_special_num(cp) | |
335 char *cp; | |
336 { | |
337 char *num_code, *handling_kw; | |
338 | |
339 for (num_code = cp; *cp && !isspace(*cp); cp++) | |
340 ; | |
341 if (*cp) | |
342 *cp++ = '\0'; | |
343 preen_special_num_code(num_code); | |
344 if (special_num_count >= MAX_SPC_NUM_ENTRIES) { | |
345 fprintf(stderr, | |
346 "out-routes line %d: MAX_SPC_NUM_ENTRIES exceeded\n", | |
347 lineno); | |
348 exit(1); | |
349 } | |
350 while (isspace(*cp)) | |
351 cp++; | |
352 if (*cp == '\0' || *cp == '#') { | |
353 inv_syntax: fprintf(stderr, | |
354 "out-routes line %d: invalid syntax for special-num\n", | |
355 lineno); | |
356 exit(1); | |
357 } | |
358 for (handling_kw = cp; *cp && !isspace(*cp); cp++) | |
359 ; | |
360 if (*cp) | |
361 *cp++ = '\0'; | |
362 if (!strcmp(handling_kw, "map-to")) | |
363 handle_special_num_map_to(num_code, cp); | |
364 else if (!strcmp(handling_kw, "route-to")) | |
365 handle_special_num_route_to(num_code, cp); | |
366 else | |
367 goto inv_syntax; | |
368 } | |
369 | |
370 static void | |
371 process_line() | |
372 { | |
373 char *cp, *np; | |
374 void (*handler)(); | |
375 | |
376 if (!index(linebuf, '\n')) { | |
377 fprintf(stderr, | |
378 "out-routes line %d: too long or missing newline\n", | |
379 lineno); | |
380 exit(1); | |
381 } | |
382 for (cp = linebuf; isspace(*cp); cp++) | |
383 ; | |
384 if (*cp == '\0' || *cp == '#') | |
385 return; | |
386 for (np = cp; *cp && !isspace(*cp); cp++) | |
387 ; | |
388 if (*cp) | |
389 *cp++ = '\0'; | |
390 if (!strcmp(np, "dest")) | |
391 handler = handle_dest_line; | |
392 else if (!strcmp(np, "inn-route")) | |
393 handler = handle_inn_route; | |
394 else if (!strcmp(np, "special-num")) | |
395 handler = handle_special_num; | |
396 else { | |
397 fprintf(stderr, | |
398 "out-routes line %d: non-understood keyword \"%s\"\n", | |
399 lineno, np); | |
400 exit(1); | |
401 } | |
402 while (isspace(*cp)) | |
403 cp++; | |
404 if (*cp == '\0' || *cp == '#') { | |
405 fprintf(stderr, | |
406 "out-routes line %d: missing argument after \"%s\" keyword\n", | |
407 lineno, np); | |
408 exit(1); | |
409 } | |
410 handler(cp); | |
411 } | |
412 | |
413 static void | |
414 emit_output() | |
415 { | |
416 FILE *outf; | |
417 struct out_routes_header hdr; | |
418 | |
419 outf = fopen("out-routes.newbin", "w"); | |
420 if (!outf) { | |
421 perror("creating out-routes.newbin"); | |
422 exit(1); | |
423 } | |
424 hdr.num_dest = dest_rec_count; | |
425 hdr.num_inn = inn_rec_count; | |
426 hdr.num_special = special_num_count; | |
427 if (fwrite(&hdr, sizeof hdr, 1, outf) != 1) { | |
428 write_err: fprintf(stderr, "error writing to new binary file\n"); | |
429 exit(1); | |
430 } | |
431 if (fwrite(dest_records, sizeof(dest_records[0]), dest_rec_count, outf) | |
432 != dest_rec_count) | |
433 goto write_err; | |
434 if (fwrite(inn_records, sizeof(inn_records[0]), inn_rec_count, outf) | |
435 != inn_rec_count) | |
436 goto write_err; | |
437 if (fwrite(special_num_records, sizeof(special_num_records[0]), | |
438 special_num_count, outf) != special_num_count) | |
439 goto write_err; | |
440 fclose(outf); | |
441 } | |
442 | |
443 main(argc, argv) | |
444 char **argv; | |
445 { | |
446 if (argc > 2) { | |
447 fprintf(stderr, "usage: %s [directory]\n", argv[0]); | |
448 exit(1); | |
449 } | |
450 if (argv[1]) | |
451 system_dir = argv[1]; | |
452 else | |
453 system_dir = "/var/gsm"; | |
454 if (chdir(system_dir) < 0) { | |
455 perror(system_dir); | |
456 exit(1); | |
457 } | |
458 inf = fopen("out-routes", "r"); | |
459 if (!inf) { | |
460 perror("opening out-routes"); | |
461 exit(1); | |
462 } | |
463 for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) | |
464 process_line(); | |
465 fclose(inf); | |
466 emit_output(); | |
467 /* make it live */ | |
468 if (rename("out-routes.newbin", "out-routes.bin") < 0) { | |
469 perror("rename"); | |
470 exit(1); | |
471 } | |
472 exit(0); | |
473 } |