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 }