FreeCalypso > hg > themwi-system-sw
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/themwi-update-out-routes.c Thu Oct 06 20:56:14 2022 -0800 @@ -0,0 +1,473 @@ +/* + * 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); + emit_output(); + /* make it live */ + if (rename("out-routes.newbin", "out-routes.bin") < 0) { + perror("rename"); + exit(1); + } + exit(0); +}