diff sip-out/readconf.c @ 154:e54b0a9e322f

beginning of themwi-sip-out
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 11 Oct 2022 23:04:01 -0800
parents sip-in/readconf.c@7e04d28fae8b
children 0bacca1f2f7b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sip-out/readconf.c	Tue Oct 11 23:04:01 2022 -0800
@@ -0,0 +1,237 @@
+/*
+ * In this module we implement the reading of /var/gsm/themwi-sip-out.cfg:
+ * the main settings are bind-ip and bind-port, but we also have some
+ * optional config settings.
+ */
+
+#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>
+
+struct in_addr sip_bind_ip;
+unsigned sip_bind_port;
+unsigned cfg_retrans_timeout = 500;
+unsigned cfg_retrans_count = 10;
+unsigned max_forwards = 70;
+unsigned sip_linger_timeout = 10;
+unsigned sip_linger_invite_err = 10;
+unsigned sip_linger_gotbye = 30;
+unsigned sip_linger_bye_out_ok = 5;
+unsigned sip_linger_bye_out_err = 180;
+int block_1900_numbers = 1;
+
+static char config_file_pathname[] = "/var/gsm/themwi-sip-out.cfg";
+
+struct parse_state {
+	int lineno;
+	int set_mask;
+};
+
+static void
+require_one_arg(st, kw, arg)
+	struct parse_state *st;
+	char *kw, *arg;
+{
+	char *cp;
+
+	if (*arg == '\0' || *arg == '#') {
+inv_syntax:	fprintf(stderr,
+			"%s line %d: %s setting requires one argument\n",
+			config_file_pathname, st->lineno, kw);
+		exit(1);
+	}
+	for (cp = arg; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#')
+		goto inv_syntax;
+}
+
+static void
+handle_ip(st, kw, arg, var)
+	struct parse_state *st;
+	char *kw, *arg;
+	struct in_addr *var;
+{
+	require_one_arg(st, kw, arg);
+	var->s_addr = inet_addr(arg);
+	if (var->s_addr == INADDR_NONE) {
+		fprintf(stderr,
+			"%s line %d: invalid IP address argument \"%s\"\n",
+			config_file_pathname, st->lineno, arg);
+		exit(1);
+	}
+}
+
+static void
+handle_num(st, kw, arg, var)
+	struct parse_state *st;
+	char *kw, *arg;
+	unsigned *var;
+{
+	char *endp;
+
+	require_one_arg(st, kw, arg);
+	*var = strtoul(arg, &endp, 10);
+	if (*endp) {
+		fprintf(stderr, "%s line %d: invalid numeric argument \"%s\"\n",
+			config_file_pathname, st->lineno, arg);
+		exit(1);
+	}
+}
+
+static void
+handle_bool(st, kw, arg, var)
+	struct parse_state *st;
+	char *kw, *arg;
+	int *var;
+{
+	require_one_arg(st, kw, arg);
+	if (!strcmp(arg, "true") || !strcmp(arg, "on") || !strcmp(arg, "yes")
+	    || !strcmp(arg, "1")) {
+		*var = 1;
+		return;
+	}
+	if (!strcmp(arg, "false") || !strcmp(arg, "off") || !strcmp(arg, "no")
+	    || !strcmp(arg, "0")) {
+		*var = 0;
+		return;
+	}
+	fprintf(stderr, "%s line %d: invalid boolean argument \"%s\"\n",
+		config_file_pathname, st->lineno, arg);
+	exit(1);
+}
+
+static void
+handle_retrans_conf(st, kw, arg)
+	struct parse_state *st;
+	char *kw, *arg;
+{
+	char *cp = arg;
+
+	if (!isdigit(*cp)) {
+inv:		fprintf(stderr,
+		"%s line %d: %s setting requires two numeric arguments\n",
+			config_file_pathname, st->lineno, kw);
+		exit(1);
+	}
+	cfg_retrans_timeout = strtoul(cp, &cp, 10);
+	while (isspace(*cp))
+		cp++;
+	if (!isdigit(*cp))
+		goto inv;
+	cfg_retrans_count = strtoul(cp, &cp, 10);
+	while (isspace(*cp))
+		cp++;
+	if (*cp != '\0' && *cp != '#')
+		goto inv;
+}
+
+static void
+process_line(st, line)
+	struct parse_state *st;
+	char *line;
+{
+	char *cp, *kw;
+	void (*handler)(), *var;
+	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 (kw = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	if (!strcmp(kw, "bind-ip")) {
+		handler = handle_ip;
+		var = &sip_bind_ip;
+		set_id = 1;
+	} else if (!strcmp(kw, "bind-port")) {
+		handler = handle_num;
+		var = &sip_bind_port;
+		set_id = 2;
+	} else if (!strcmp(kw, "sip-udp-retrans")) {
+		handler = handle_retrans_conf;
+		var = (void *) 0;
+		set_id = 0;
+	} else if (!strcmp(kw, "sip-linger-timeout")) {
+		handler = handle_num;
+		var = &sip_linger_timeout;
+		set_id = 0;
+	} else if (!strcmp(kw, "sip-linger-invite-error")) {
+		handler = handle_num;
+		var = &sip_linger_invite_err;
+		set_id = 0;
+	} else if (!strcmp(kw, "sip-linger-got-bye")) {
+		handler = handle_num;
+		var = &sip_linger_gotbye;
+		set_id = 0;
+	} else if (!strcmp(kw, "sip-linger-bye-out-ok")) {
+		handler = handle_num;
+		var = &sip_linger_bye_out_ok;
+		set_id = 0;
+	} else if (!strcmp(kw, "sip-linger-bye-out-error")) {
+		handler = handle_num;
+		var = &sip_linger_bye_out_err;
+		set_id = 0;
+	} else if (!strcmp(kw, "max-forwards")) {
+		handler = &handle_num;
+		var = &max_forwards;
+		set_id = 0;
+	} else if (!strcmp(kw, "block-1900")) {
+		handler = handle_bool;
+		var = &block_1900_numbers;
+		set_id = 0;
+	} else {
+		fprintf(stderr, "%s line %d: non-understood keyword \"%s\"\n",
+			config_file_pathname, st->lineno, kw);
+		exit(1);
+	}
+	if (st->set_mask & set_id) {
+		fprintf(stderr, "%s line %d: duplicate %s setting\n",
+			config_file_pathname, st->lineno, kw);
+		exit(1);
+	}
+	while (isspace(*cp))
+		cp++;
+	handler(st, kw, cp, var);
+	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 != 3) {
+		fprintf(stderr, "error: %s did not set all required settings\n",
+			config_file_pathname);
+		exit(1);
+	}
+}