diff mgw/readconf.c @ 32:b3f74df7b808

beginning of themwi-mgw
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 09 Jul 2022 22:51:44 -0800
parents
children f280328e7e2e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mgw/readconf.c	Sat Jul 09 22:51:44 2022 -0800
@@ -0,0 +1,187 @@
+/*
+ * In this module we implement the reading of /var/gsm/themwi-mgw.cfg:
+ * we parse and save the configured IP address and port range for each
+ * of our two sides, GSM and PSTN.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "struct.h"
+
+struct bind_range_cfg bind_range_gsm, bind_range_pstn;
+
+static char config_file_pathname[] = "/var/gsm/themwi-mgw.cfg";
+
+struct parse_state {
+	int lineno;
+	int set_mask;
+};
+
+static void
+handle_bind_ip(st, kw, brc, line)
+	struct parse_state *st;
+	char *kw, *line;
+	struct bind_range_cfg *brc;
+{
+	char *cp, *np;
+
+	for (cp = line; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#') {
+inv_syntax:	fprintf(stderr,
+			"%s line %d: %s setting requires one argument\n",
+			config_file_pathname, st->lineno, kw);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#')
+		goto inv_syntax;
+	brc->bind_ip.s_addr = inet_addr(np);
+	if (brc->bind_ip.s_addr == INADDR_NONE) {
+		fprintf(stderr,
+			"%s line %d: invalid IP address argument \"%s\"\n",
+			config_file_pathname, st->lineno, np);
+		exit(1);
+	}
+}
+
+static void
+handle_port_range(st, kw, brc, line)
+	struct parse_state *st;
+	char *kw, *line;
+	struct bind_range_cfg *brc;
+{
+	char *cp, *np1, *np2;
+
+	for (cp = line; isspace(*cp); cp++)
+		;
+	if (!isdigit(*cp)) {
+inv_syntax:	fprintf(stderr,
+		"%s line %d: %s setting requires two numeric arguments\n",
+			config_file_pathname, st->lineno, kw);
+		exit(1);
+	}
+	for (np1 = cp; isdigit(*cp); cp++)
+		;
+	if (!isspace(*cp))
+		goto inv_syntax;
+	while (isspace(*cp))
+		cp++;
+	if (!isdigit(*cp))
+		goto inv_syntax;
+	for (np2 = cp; isdigit(*cp); cp++)
+		;
+	if (*cp && !isspace(*cp))
+		goto inv_syntax;
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#')
+		goto inv_syntax;
+	brc->port_range_start = atoi(np1);
+	brc->port_range_end = atoi(np2);
+	if (brc->port_range_start & 1) {
+		fprintf(stderr, "%s line %d: start port must be even\n",
+			config_file_pathname, st->lineno);
+		exit(1);
+	}
+	if (!(brc->port_range_end & 1)) {
+		fprintf(stderr, "%s line %d: end port must be odd\n",
+			config_file_pathname, st->lineno);
+		exit(1);
+	}
+	if (brc->port_range_end <= brc->port_range_start) {
+		fprintf(stderr,
+		"%s line %d: end port must be greater than start port\n",
+			config_file_pathname, st->lineno);
+		exit(1);
+	}
+	brc->port_next = brc->port_range_start;
+	brc->port_tries = (brc->port_range_end - brc->port_range_start + 1) / 2;
+}
+
+static void
+process_line(st, line)
+	struct parse_state *st;
+	char *line;
+{
+	char *cp, *np;
+	void (*handler)();
+	struct bind_range_cfg *ipside;
+	int set_id;
+
+	if (!index(line, '\n')) {
+		fprintf(stderr, "%s line %d: too long or missing newline\n",
+			config_file_pathname, st->lineno);
+		exit(1);
+	}
+	for (cp = line; isspace(*cp); cp++)
+		;
+	if (*cp == '\0' || *cp == '#')
+		return;
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	if (!strcmp(np, "gsm-ip-addr")) {
+		handler = handle_bind_ip;
+		ipside = &bind_range_gsm;
+		set_id = 1;
+	} else if (!strcmp(np, "gsm-port-range")) {
+		handler = handle_port_range;
+		ipside = &bind_range_gsm;
+		set_id = 2;
+	} else if (!strcmp(np, "pstn-ip-addr")) {
+		handler = handle_bind_ip;
+		ipside = &bind_range_pstn;
+		set_id = 4;
+	} else if (!strcmp(np, "pstn-port-range")) {
+		handler = handle_port_range;
+		ipside = &bind_range_pstn;
+		set_id = 8;
+	} else {
+		fprintf(stderr, "%s line %d: non-understood keyword \"%s\"\n",
+			config_file_pathname, st->lineno, np);
+		exit(1);
+	}
+	if (st->set_mask & set_id) {
+		fprintf(stderr, "%s line %d: duplicate %s setting\n",
+			config_file_pathname, st->lineno, np);
+		exit(1);
+	}
+	handler(st, np, ipside, cp);
+	st->set_mask |= set_id;
+}
+
+read_config_file()
+{
+	FILE *inf;
+	struct parse_state pst;
+	char linebuf[256];
+
+	inf = fopen(config_file_pathname, "r");
+	if (!inf) {
+		perror(config_file_pathname);
+		exit(1);
+	}
+	pst.set_mask = 0;
+	for (pst.lineno = 1; fgets(linebuf, sizeof linebuf, inf); pst.lineno++)
+		process_line(&pst, linebuf);
+	fclose(inf);
+	if (pst.set_mask != 15) {
+		fprintf(stderr, "error: %s did not set all required settings\n",
+			config_file_pathname);
+		exit(1);
+	}
+}