# HG changeset patch # User Mychaela Falconia # Date 1691992885 28800 # Node ID 28441920fb35327464dd89a19b918b9462ff313b # Parent 243ed87880a141c55bed3d13ba467ee16caad51d beginning of number database version 2 diff -r 243ed87880a1 -r 28441920fb35 .hgignore --- a/.hgignore Sat Aug 05 12:52:33 2023 -0800 +++ b/.hgignore Sun Aug 13 22:01:25 2023 -0800 @@ -31,4 +31,5 @@ ^utils/themwi-dump-numdb$ ^utils/themwi-short-dial$ ^utils/themwi-update-numdb$ +^utils/themwi-update-numdb2$ ^utils/themwi-update-outrt$ diff -r 243ed87880a1 -r 28441920fb35 include/number_db_v2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/number_db_v2.h Sun Aug 13 22:01:25 2023 -0800 @@ -0,0 +1,36 @@ +/* + * This header file defines version 2 of ThemWi number database + * binary file format. + */ + +struct numdb_file_hdr { + uint32_t owned_number_count; + uint32_t short_number_count; +}; + +struct owned_number_rec { + uint16_t number[3]; /* NPA-exchange-suffix breakdown */ + uint8_t number_flags; /* properties of outside number */ + uint8_t usage; /* usage inside ThemWi */ + uint16_t remap[3]; /* secondary remap number */ +}; + +#define NUMBER_FLAG_SMSPROV 0x01 /* provisioned for outside SMS */ +#define NUMBER_FLAG_E911PROV 0x02 /* provisioned for E911 */ + +#define NUMBER_USAGE_MASK 0x0F +#define NUMBER_USAGE_TYPE_RSVD 0x00 +#define NUMBER_USAGE_TYPE_GSM_SUB 0x01 +#define NUMBER_USAGE_TYPE_ALIAS 0x02 +#define NUMBER_USAGE_FLAG_E911_VIA 0x10 + +struct short_number_rec { + uint16_t short_num; + uint8_t short_num_type; + uint8_t fullnum_flags; + uint16_t fullnum_prefix[2]; +}; + +#define SHORT_NUM_TYPE_ABBREV 0x01 +#define SHORT_NUM_TYPE_ITN 0x02 +#define SHORT_NUM_TYPE_TEST_SINK 0x03 diff -r 243ed87880a1 -r 28441920fb35 libutil/Makefile --- a/libutil/Makefile Sat Aug 05 12:52:33 2023 -0800 +++ b/libutil/Makefile Sun Aug 13 22:01:25 2023 -0800 @@ -1,7 +1,8 @@ CC= gcc CFLAGS= -O2 -OBJS= bitfunc.o crc8gen.o dtmf_valid.o extdigits.o imsi_entry.o mncc_debug.o \ - mncc_utils.o nanp_valid.o numstring.o sockinit.o tfo_msg_enc.o +OBJS= bitfunc.o crc8gen.o digit_groups.o dtmf_valid.o extdigits.o \ + imsi_entry.o mncc_debug.o mncc_utils.o nanp_valid.o numstring.o \ + sockinit.o tfo_msg_enc.o LIB= libutil.a all: ${LIB} diff -r 243ed87880a1 -r 28441920fb35 libutil/digit_groups.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/digit_groups.c Sun Aug 13 22:01:25 2023 -0800 @@ -0,0 +1,29 @@ +/* + * In version 2 of ThemWi owned number database, NANP numbers are stored as 3 + * uint16_t words: NPA, exchange and prefix, each uint16_t encoding a group of + * 3 or 4 digits of the full telephone number. This library module provides + * functions for turning groups of 3 or 4 digits into uint16_t words. + */ + +digits3_to_uint16(str) + char *str; +{ + int acc; + + acc = (str[0] - '0') * 100; + acc += (str[1] - '0') * 10; + acc += str[2] - '0'; + return acc; +} + +digits4_to_uint16(str) + char *str; +{ + int acc; + + acc = (str[0] - '0') * 1000; + acc += (str[1] - '0') * 100; + acc += (str[2] - '0') * 10; + acc += str[3] - '0'; + return acc; +} diff -r 243ed87880a1 -r 28441920fb35 utils/Makefile --- a/utils/Makefile Sat Aug 05 12:52:33 2023 -0800 +++ b/utils/Makefile Sun Aug 13 22:01:25 2023 -0800 @@ -2,7 +2,7 @@ CFLAGS= -O2 PROGS= sip-out-test sip-rx-test sip-udp-dump themwi-check-own \ themwi-dump-numdb themwi-short-dial themwi-update-numdb \ - themwi-update-outrt + themwi-update-numdb2 themwi-update-outrt NOINST= rtp-alloc-test smpp-test1 smpp-test2 tcpserv-dump LIBNUMDB=../libnumdb/libnumdb.a LIBRTPA=../librtpalloc/librtpalloc.a @@ -45,6 +45,9 @@ themwi-update-numdb: themwi-update-numdb.o ${LIBUTIL} ${CC} ${CFLAGS} -o $@ $@.o ${LIBUTIL} +themwi-update-numdb2: themwi-update-numdb2.o ${LIBUTIL} + ${CC} ${CFLAGS} -o $@ $@.o ${LIBUTIL} + themwi-update-outrt: themwi-update-outrt.o ${LIBUTIL} ${CC} ${CFLAGS} -o $@ $@.o ${LIBUTIL} diff -r 243ed87880a1 -r 28441920fb35 utils/themwi-update-numdb2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/themwi-update-numdb2.c Sun Aug 13 22:01:25 2023 -0800 @@ -0,0 +1,486 @@ +/* + * This program reads (parses) ThemWi config file /var/gsm/number-db2, + * generates the compiled binary form of this database, and then makes + * it live via atomic rename. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../include/number_db_v2.h" + +#define MAX_OWNED_NUMBERS 1000 +#define MAX_SHORT_NUMBERS 1000 + +static struct owned_number_rec owned_number_buf[MAX_OWNED_NUMBERS]; +static struct short_number_rec short_number_buf[MAX_SHORT_NUMBERS]; +static unsigned owned_number_count, short_number_count; + +static char *system_dir; +static FILE *inf; +static int lineno; +static char linebuf[256]; +static int prefix_set, prefix_allows_abbrev; +static uint16_t prefix_buf[2]; + +static void +enter_owned_number(rec) + struct owned_number_rec *rec; +{ + if (owned_number_count >= MAX_OWNED_NUMBERS) { + fprintf(stderr, "error: MAX_OWNED_NUMBERS exceeded\n"); + exit(1); + } + bcopy(rec, owned_number_buf + owned_number_count, + sizeof(struct owned_number_rec)); + owned_number_count++; +} + +static void +enter_short_number(rec) + struct short_number_rec *rec; +{ + if (short_number_count >= MAX_SHORT_NUMBERS) { + fprintf(stderr, "error: MAX_SHORT_NUMBERS exceeded\n"); + exit(1); + } + bcopy(rec, short_number_buf + short_number_count, + sizeof(struct short_number_rec)); + short_number_count++; +} + +static void +handle_prefix_line(cp) + char *cp; +{ + char *np, prefix[7]; + + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (grok_number_string(np, 1) != 6) { + fprintf(stderr, + "number-db2 line %d: prefix requires 6-digit argument\n", + lineno); + exit(1); + } + dehyphen_number_string(np, prefix); + if (!is_nanp_valid_prefix(prefix)) { + fprintf(stderr, + "number-db2 line %d: prefix violates NANP rules\n", + lineno); + exit(1); + } + prefix_buf[0] = digits3_to_uint16(prefix); + prefix_buf[1] = digits3_to_uint16(prefix + 3); + prefix_set = 1; + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') { + prefix_allows_abbrev = 0; + return; + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (!strcmp(np, "allow-abbrev")) { + prefix_allows_abbrev = 1; + return; + } + fprintf(stderr, + "number-db2 line %d: non-understood notation \"%s\" after prefix\n", + lineno, np); + exit(1); +} + +static int +parse_extra_number(rec, numstr) + struct owned_number_rec *rec; + char *numstr; +{ + char buf[11]; + int rc; + + rc = grok_number_string(numstr, 1); + switch (rc) { + case 4: + if (!prefix_set) + return(-1); + dehyphen_number_string(numstr, buf); + rec->remap[0] = prefix_buf[0]; + rec->remap[1] = prefix_buf[1]; + rec->remap[2] = digits4_to_uint16(buf); + return(0); + case 10: + dehyphen_number_string(numstr, buf); + rec->remap[0] = digits3_to_uint16(buf); + rec->remap[1] = digits3_to_uint16(buf + 3); + rec->remap[2] = digits4_to_uint16(buf + 6); + return(0); + default: + return(-1); + } +} + +static void +handle_number_attr(rec, tail) + struct owned_number_rec *rec; + char *tail; +{ + char *cp, *np; + int rc; + + for (cp = tail; ; ) { + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') + return; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (!strcmp(np, "sms")) + rec->number_flags |= NUMBER_FLAG_SMSPROV; + else if (!strcmp(np, "e911")) + rec->number_flags |= NUMBER_FLAG_E911PROV; + else if (!strcmp(np, "gsm-sub")) + rec->usage = NUMBER_USAGE_TYPE_GSM_SUB; + else if (!strcmp(np, "map-to")) { + rec->usage = NUMBER_USAGE_TYPE_ALIAS; + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') { + fprintf(stderr, + "number-db2 line %d: map-to requires an argument\n", + lineno); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + rc = parse_extra_number(rec, np); + if (rc < 0) { + fprintf(stderr, + "number-db2 line %d: map-to argument is invalid\n", + lineno); + exit(1); + } + } else if (!strcmp(np, "e911-via")) { + if (rec->usage != NUMBER_USAGE_TYPE_GSM_SUB) { + fprintf(stderr, + "number-db2 line %d: invalid usage of e911-via\n", + lineno); + exit(1); + } + rec->usage |= NUMBER_USAGE_FLAG_E911_VIA; + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') { + fprintf(stderr, + "number-db2 line %d: e911-via requires an argument\n", + lineno); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + rc = parse_extra_number(rec, np); + if (rc < 0) { + fprintf(stderr, + "number-db2 line %d: e911-via argument is invalid\n", + lineno); + exit(1); + } + } else { + fprintf(stderr, + "number-db2 line %d: invalid attribute \"%s\"\n", + lineno, np); + exit(1); + } + } +} + +static void +handle_suffix_line(cp) + char *cp; +{ + char *np; + uint16_t suffix; + struct owned_number_rec own_rec; + struct short_number_rec short_rec; + + if (!prefix_set) { + fprintf(stderr, + "number-db2 line %d: suffix not valid without preceding prefix\n", + lineno); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (grok_number_string(np, 0) != 4) { + fprintf(stderr, + "number-db2 line %d: suffix requires 4-digit argument\n", + lineno); + exit(1); + } + suffix = digits4_to_uint16(np); + bzero(&own_rec, sizeof own_rec); + own_rec.number[0] = prefix_buf[0]; + own_rec.number[1] = prefix_buf[1]; + own_rec.number[2] = suffix; + handle_number_attr(&own_rec, cp); + enter_owned_number(&own_rec); + if (!prefix_allows_abbrev || own_rec.usage != NUMBER_USAGE_TYPE_GSM_SUB) + return; + bzero(&short_rec, sizeof short_rec); + short_rec.short_num = suffix; + short_rec.short_num_type = SHORT_NUM_TYPE_ABBREV; + short_rec.fullnum_flags = own_rec.number_flags; + short_rec.fullnum_prefix[0] = prefix_buf[0]; + short_rec.fullnum_prefix[1] = prefix_buf[1]; + enter_short_number(&short_rec); +} + +static void +handle_full10_line(cp) + char *cp; +{ + char *np, full10[11]; + struct owned_number_rec own_rec; + + prefix_set = 0; /* cancel any previous prefix line */ + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (grok_number_string(np, 1) != 10) { + fprintf(stderr, + "number-db2 line %d: full10 requires 10-digit argument\n", + lineno); + exit(1); + } + dehyphen_number_string(np, full10); + if (!is_nanp_valid_prefix(full10)) { + fprintf(stderr, + "number-db2 line %d: number violates NANP rules\n", + lineno); + exit(1); + } + bzero(&own_rec, sizeof own_rec); + own_rec.number[0] = digits3_to_uint16(full10); + own_rec.number[1] = digits3_to_uint16(full10 + 3); + own_rec.number[2] = digits4_to_uint16(full10 + 6); + handle_number_attr(&own_rec, cp); + enter_owned_number(&own_rec); +} + +static void +handle_itn_line(cp) + char *cp; +{ + char *np; + struct short_number_rec short_rec; + + prefix_set = 0; /* cancel any previous prefix line */ + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (grok_number_string(np, 0) != 4) { + fprintf(stderr, + "number-db2 line %d: itn requires 4-digit argument\n", + lineno); + exit(1); + } + bzero(&short_rec, sizeof short_rec); + short_rec.short_num = digits4_to_uint16(np); + short_rec.short_num_type = SHORT_NUM_TYPE_ITN; + enter_short_number(&short_rec); +} + +static void +process_line() +{ + char *cp, *np; + void (*handler)(); + + if (!index(linebuf, '\n')) { + fprintf(stderr, + "number-db2 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, "prefix")) + handler = handle_prefix_line; + else if (!strcmp(np, "suffix")) + handler = handle_suffix_line; + else if (!strcmp(np, "full10")) + handler = handle_full10_line; + else if (!strcmp(np, "itn")) + handler = handle_itn_line; + else { + fprintf(stderr, + "number-db2 line %d: non-understood keyword \"%s\"\n", + lineno, np); + exit(1); + } + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') { + fprintf(stderr, + "number-db2 line %d: missing argument after \"%s\" keyword\n", + lineno, np); + exit(1); + } + handler(cp); +} + +static int +compare_owned_num(p1, p2) + struct owned_number_rec *p1, *p2; +{ + if (p1->number[0] < p2->number[0]) + return(-1); + if (p1->number[0] > p2->number[0]) + return(1); + if (p1->number[1] < p2->number[1]) + return(-1); + if (p1->number[1] > p2->number[1]) + return(1); + if (p1->number[2] < p2->number[2]) + return(-1); + if (p1->number[2] > p2->number[2]) + return(1); + return(0); +} + +static int +compare_short_num(p1, p2) + struct short_number_rec *p1, *p2; +{ + if (p1->short_num < p2->short_num) + return(-1); + if (p1->short_num > p2->short_num) + return(1); + return(0); +} + +static void +owned_num_check_dup() +{ + struct owned_number_rec *p, *endp; + + endp = owned_number_buf + owned_number_count - 1; + for (p = owned_number_buf; p < endp; p++) { + if (p[0].number[0] == p[1].number[0] && + p[0].number[1] == p[1].number[1] && + p[0].number[2] == p[1].number[2]) { + fprintf(stderr, + "error: NANP number %03u-%03u-%04u appears more than once\n", + p[0].number[0], p[0].number[1], p[0].number[2]); + exit(1); + } + } +} + +static void +short_num_check_dup() +{ + struct short_number_rec *p, *endp; + + endp = short_number_buf + short_number_count - 1; + for (p = short_number_buf; p < endp; p++) { + if (p[0].short_num == p[1].short_num) { + fprintf(stderr, + "error: short number %04u appears more than once\n", + (unsigned) p->short_num); + exit(1); + } + } +} + +static void +emit_output() +{ + FILE *outf; + struct numdb_file_hdr hdr; + + outf = fopen("number-db2.newbin", "w"); + if (!outf) { + perror("creating number-db2.newbin"); + exit(1); + } + hdr.owned_number_count = owned_number_count; + hdr.short_number_count = short_number_count; + if (fwrite(&hdr, sizeof hdr, 1, outf) != 1) { +write_err: fprintf(stderr, "error writing to new binary file\n"); + exit(1); + } + if (fwrite(owned_number_buf, sizeof(owned_number_buf[0]), + owned_number_count, outf) != owned_number_count) + goto write_err; + if (fwrite(short_number_buf, sizeof(short_number_buf[0]), + short_number_count, outf) != short_number_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("number-db2", "r"); + if (!inf) { + perror("opening number-db2"); + exit(1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) + process_line(); + fclose(inf); + if (owned_number_count >= 2) { + qsort(owned_number_buf, owned_number_count, + sizeof(owned_number_buf[0]), compare_owned_num); + owned_num_check_dup(); + } + if (short_number_count >= 2) { + qsort(short_number_buf, short_number_count, + sizeof(short_number_buf[0]), compare_short_num); + short_num_check_dup(); + } + emit_output(); + /* make it live */ + if (rename("number-db2.newbin", "number-db2.bin") < 0) { + perror("rename"); + exit(1); + } + exit(0); +}