FreeCalypso > hg > themwi-system-sw
view utils/themwi-update-outrt.c @ 178:b259e2722485
README: update for current status
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 09 Mar 2023 13:08:31 -0800 |
parents | aa278d75d757 |
children | de7c64c4d6fd |
line wrap: on
line source
/* * This program reads (parses) ThemWi config file /var/gsm/out-routes, * generates the compiled binary form of this database, and then makes * it live via atomic rename. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include "../include/out_routes.h" #define MAX_DEST_ENTRIES 16 #define MAX_INN_ENTRIES 64 #define MAX_SPC_NUM_ENTRIES 64 static struct sip_out_dest dest_records[MAX_DEST_ENTRIES]; static char *dest_names[MAX_DEST_ENTRIES]; static struct inn_route inn_records[MAX_INN_ENTRIES]; static struct special_num_route special_num_records[MAX_SPC_NUM_ENTRIES]; static unsigned dest_rec_count, inn_rec_count, special_num_count; static char *system_dir; static FILE *inf; static int lineno; static char linebuf[256]; static int find_dest_by_name(sought_name) char *sought_name; { unsigned n; for (n = 0; n < dest_rec_count; n++) if (!strcmp(dest_names[n], sought_name)) return n; return -1; } static int find_dest_by_number(target_num) char *target_num; { unsigned inn_index; struct inn_route *rec; char *pp, *tp; for (inn_index = 0; inn_index < inn_rec_count; inn_index++) { rec = inn_records + inn_index; pp = rec->prefix; tp = target_num; while (*pp && *pp == *tp) { pp++; tp++; } if (*pp) continue; return rec->sip_dest_id; } return -1; } static void handle_dest_line(cp) char *cp; { char *name, *name_copy, *domain, *ip_str, *port_str; struct sip_out_dest *rec; unsigned portnum; int rc; for (name = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { inv_syntax: fprintf(stderr, "out-routes line %d: invalid syntax for dest\n", lineno); exit(1); } for (domain = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') goto inv_syntax; for (ip_str = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') port_str = 0; else { for (port_str = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp != '\0' && *cp != '#') goto inv_syntax; } rc = find_dest_by_name(name); if (rc >= 0) { fprintf(stderr, "out-routes line %d: duplicate destination name \"%s\"\n", lineno, name); exit(1); } if (dest_rec_count >= MAX_DEST_ENTRIES) { fprintf(stderr, "out-routes line %d: MAX_DEST_ENTRIES exceeded\n", lineno); exit(1); } name_copy = strdup(name); if (!name_copy) { perror("strdup"); exit(1); } dest_names[dest_rec_count] = name_copy; rec = dest_records + dest_rec_count; if (strlen(domain) > MAX_SIP_DEST_DOMAIN) { fprintf(stderr, "out-routes line %d: dest domain string is too long\n", lineno); exit(1); } strcpy(rec->domain, domain); rec->sin.sin_family = AF_INET; rec->sin.sin_addr.s_addr = inet_addr(ip_str); if (rec->sin.sin_addr.s_addr == INADDR_NONE) { fprintf(stderr, "out-routes line %d: dest IP address is invalid\n", lineno); exit(1); } if (port_str) { portnum = strtoul(port_str, &cp, 10); if (*cp) goto inv_syntax; } else portnum = 5060; rec->sin.sin_port = htons(portnum); dest_rec_count++; } static void handle_inn_route(cp) char *cp; { char *prefix, *dest_name; struct inn_route *rec; int rc, dest_id; for (prefix = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { inv_syntax: fprintf(stderr, "out-routes line %d: invalid syntax for inn-route\n", lineno); exit(1); } for (dest_name = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp != '\0' && *cp != '#') goto inv_syntax; rc = grok_number_string(prefix, 1); if (rc < 1) goto inv_syntax; if (rc > MAX_INN_PREFIX) { fprintf(stderr, "out-routes line %d: inn-route prefix is too long\n", lineno); exit(1); } dest_id = find_dest_by_name(dest_name); if (dest_id < 0) { fprintf(stderr, "out-routes line %d: SIP destination \"%s\" not defined\n", lineno, dest_name); exit(1); } if (inn_rec_count >= MAX_INN_ENTRIES) { fprintf(stderr, "out-routes line %d: MAX_INN_ENTRIES exceeded\n", lineno); exit(1); } rec = inn_records + inn_rec_count; dehyphen_number_string(prefix, rec->prefix); rec->sip_dest_id = dest_id; inn_rec_count++; } static void preen_special_num_code(num_code) char *num_code; { char *cp; int c; unsigned n; n = 0; for (cp = num_code; *cp; ) { c = *cp++; if (is_valid_ext_digit(c)) n++; else { fprintf(stderr, "out-routes line %d: special-num string \"%s\" is invalid\n", lineno, num_code); exit(1); } } if (n > MAX_SPECIAL_NUM) { fprintf(stderr, "out-routes line %d: special-num string \"%s\" is too long\n", lineno, num_code); exit(1); } } static void handle_special_num_map_to(num_code, cp) char *num_code, *cp; { struct special_num_route *rec; char *tgt_num_src; int rc, dest_id; while (isspace(*cp)) cp++; if (*cp++ != '+') { inv_syntax: fprintf(stderr, "out-routes line %d: invalid syntax for special-num map-to\n", lineno); exit(1); } if (!isdigit(*cp)) goto inv_syntax; for (tgt_num_src = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp != '\0' && *cp != '#') goto inv_syntax; rc = grok_number_string(tgt_num_src, 1); if (rc < 1) goto inv_syntax; if (rc > MAX_E164_NUMBER) { fprintf(stderr, "out-routes line %d: map-to number is too long for E.164\n", lineno); exit(1); } rec = special_num_records + special_num_count; strcpy(rec->special_num, num_code); rec->sip_user[0] = '+'; dehyphen_number_string(tgt_num_src, rec->sip_user+1); dest_id = find_dest_by_number(rec->sip_user+1); if (dest_id < 0) { fprintf(stderr, "out-routes line %d: no inn-route for map-to number\n", lineno); exit(1); } rec->sip_dest_id = dest_id; special_num_count++; } static void handle_special_num_route_to(num_code, cp) char *num_code, *cp; { struct special_num_route *rec; char *dest_name; int dest_id; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { inv_syntax: fprintf(stderr, "out-routes line %d: invalid syntax for special-num route-to\n", lineno); exit(1); } for (dest_name = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp != '\0' && *cp != '#') goto inv_syntax; dest_id = find_dest_by_name(dest_name); if (dest_id < 0) { fprintf(stderr, "out-routes line %d: SIP destination \"%s\" not defined\n", lineno, dest_name); exit(1); } rec = special_num_records + special_num_count; strcpy(rec->special_num, num_code); strcpy(rec->sip_user, num_code); rec->sip_dest_id = dest_id; special_num_count++; } static void handle_special_num(cp) char *cp; { char *num_code, *handling_kw; for (num_code = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; preen_special_num_code(num_code); if (special_num_count >= MAX_SPC_NUM_ENTRIES) { fprintf(stderr, "out-routes line %d: MAX_SPC_NUM_ENTRIES exceeded\n", lineno); exit(1); } while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { inv_syntax: fprintf(stderr, "out-routes line %d: invalid syntax for special-num\n", lineno); exit(1); } for (handling_kw = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; if (!strcmp(handling_kw, "map-to")) handle_special_num_map_to(num_code, cp); else if (!strcmp(handling_kw, "route-to")) handle_special_num_route_to(num_code, cp); else goto inv_syntax; } static void process_line() { char *cp, *np; void (*handler)(); if (!index(linebuf, '\n')) { fprintf(stderr, "out-routes line %d: too long or missing newline\n", lineno); exit(1); } for (cp = linebuf; isspace(*cp); cp++) ; if (*cp == '\0' || *cp == '#') return; for (np = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; if (!strcmp(np, "dest")) handler = handle_dest_line; else if (!strcmp(np, "inn-route")) handler = handle_inn_route; else if (!strcmp(np, "special-num")) handler = handle_special_num; else { fprintf(stderr, "out-routes line %d: non-understood keyword \"%s\"\n", lineno, np); exit(1); } while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { fprintf(stderr, "out-routes line %d: missing argument after \"%s\" keyword\n", lineno, np); exit(1); } handler(cp); } static void emit_output() { FILE *outf; struct out_routes_header hdr; outf = fopen("out-routes.newbin", "w"); if (!outf) { perror("creating out-routes.newbin"); exit(1); } hdr.num_dest = dest_rec_count; hdr.num_inn = inn_rec_count; hdr.num_special = special_num_count; if (fwrite(&hdr, sizeof hdr, 1, outf) != 1) { write_err: fprintf(stderr, "error writing to new binary file\n"); exit(1); } if (fwrite(dest_records, sizeof(dest_records[0]), dest_rec_count, outf) != dest_rec_count) goto write_err; if (fwrite(inn_records, sizeof(inn_records[0]), inn_rec_count, outf) != inn_rec_count) goto write_err; if (fwrite(special_num_records, sizeof(special_num_records[0]), special_num_count, outf) != special_num_count) goto write_err; fclose(outf); } main(argc, argv) char **argv; { if (argc > 2) { fprintf(stderr, "usage: %s [directory]\n", argv[0]); exit(1); } if (argv[1]) system_dir = argv[1]; else system_dir = "/var/gsm"; if (chdir(system_dir) < 0) { perror(system_dir); exit(1); } inf = fopen("out-routes", "r"); if (!inf) { perror("opening out-routes"); exit(1); } for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) process_line(); fclose(inf); if (!dest_rec_count) { fprintf(stderr, "error: no SIP destinations defined\n"); exit(1); } if (!inn_rec_count && !special_num_count) { fprintf(stderr, "error: no routes defined\n"); exit(1); } emit_output(); /* make it live */ if (rename("out-routes.newbin", "out-routes.bin") < 0) { perror("rename"); exit(1); } exit(0); }