From b394d6fc8573b63ac56a69f2be1521190b45ac83 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 14 Mar 2023 20:33:04 +0100 Subject: [PATCH] New osmo-gsmtap-logsend utility This utility can be used to "pipe" stdin or some file as log lines via GSMTAP logging. Change-Id: Ida96e87d84e0c349c5069edc67fec1c3cf19d1ab --- .gitignore | 1 + debian/libosmocore-utils.install | 1 + utils/Makefile.am | 4 +- utils/gsmtap-logsend.c | 139 +++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 utils/gsmtap-logsend.c diff --git a/.gitignore b/.gitignore index 167d1e20c..d90013850 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ tests/*/*_test utils/osmo-arfcn utils/osmo-auc-gen utils/osmo-config-merge +utils/osmo-gsmtap-logsend utils/osmo-sim-test utils/osmo-aka-verify diff --git a/debian/libosmocore-utils.install b/debian/libosmocore-utils.install index 9501bec96..0e411978d 100644 --- a/debian/libosmocore-utils.install +++ b/debian/libosmocore-utils.install @@ -2,3 +2,4 @@ usr/bin/osmo-arfcn usr/bin/osmo-auc-gen usr/bin/osmo-aka-verify usr/bin/osmo-config-merge +usr/bin/osmo-gsmtap-logsend diff --git a/utils/Makefile.am b/utils/Makefile.am index 8937ad9dd..3ec71ea3a 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -8,7 +8,7 @@ LDADD = $(top_builddir)/src/core/libosmocore.la $(top_builddir)/src/gsm/libosmog if ENABLE_UTILITIES EXTRA_DIST = conv_gen.py conv_codes_gsm.py -bin_PROGRAMS += osmo-arfcn osmo-auc-gen osmo-config-merge osmo-aka-verify +bin_PROGRAMS += osmo-arfcn osmo-auc-gen osmo-config-merge osmo-aka-verify osmo-gsmtap-logsend osmo_arfcn_SOURCES = osmo-arfcn.c @@ -16,6 +16,8 @@ osmo_auc_gen_SOURCES = osmo-auc-gen.c osmo_aka_verify_SOURCES = osmo-aka-verify.c +osmo_gsmtap_logsend_SOURCES = gsmtap-logsend.c + osmo_config_merge_SOURCES = osmo-config-merge.c osmo_config_merge_LDADD = $(LDADD) $(TALLOC_LIBS) diff --git a/utils/gsmtap-logsend.c b/utils/gsmtap-logsend.c new file mode 100644 index 000000000..97a838b50 --- /dev/null +++ b/utils/gsmtap-logsend.c @@ -0,0 +1,139 @@ +/* Small program to read an input file / stdin and send each line via GSMTAP logging */ +/* (C) 2023 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static char *proc_name = "gsmtap-logsend"; +static char *subsys_name = "unknown"; +static char *dest_host = "localhost"; +static int dest_port = GSMTAP_UDP_PORT; + +static void help(void) +{ + printf("osmo-gsmtap-logsend Usage:\n" + "\t[ -r DESTADDR ] [ -p PORTNR ] [ -n PROC_NAME ] [ -s SUBSYS ] [ INFILE ]\n" + "\n" + " -a --remote-address HOSTNAME Destination IP destination address (default: localhost)\n" + " -p --remote-port PORTNR Destination UDP Port number (default: 4729)\n" + " -n --process-name PROC_NAME Process name to include in GSMTAP LOG header\n" + " -s --subsys-name SUBSYS Subsystem name to include in GSMTAP LOG header\n" + " -h --help This help message\n" + ); +} + +int main(int argc, char **argv) +{ + char buf[1024]; + int gsmtap_fd; + FILE *infile; + char *line; + int rc; + + while (1) { + static const struct option long_options[] = { + { "remote-address", 1, 0, 'a' }, + { "remote-port", 1, 0, 'p' }, + { "process-name", 1, 0, 'n' }, + { "subsys-name", 1, 0, 's' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + int c, option_index; + + c = getopt_long(argc, argv, "a:p:n:s:h", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'a': + dest_host = optarg; + break; + case 'p': + dest_port = atoi(optarg); + break; + case 'n': + proc_name = optarg; + break; + case 's': + subsys_name = optarg; + break; + case 'h': + help(); + exit(0); + break; + default: + help(); + exit(1); + } + } + + if (argc <= optind) { + infile = stdin; + } else { + infile = fopen(argv[optind], "r"); + if (!infile) { + fprintf(stderr, "Unable to open %s: %s\n", argv[optind], strerror(errno)); + exit(2); + } + } + + gsmtap_fd = gsmtap_source_init_fd(dest_host, dest_port); + if (gsmtap_fd < 0) { + fprintf(stderr, "Unable to create GSMTAP soicket: %s\n", strerror(errno)); + exit(2); + } + + /* prepare all the data structures that don't change for each line */ + struct { + struct gsmtap_hdr gsmtap; + struct gsmtap_osmocore_log_hdr log; + } __attribute__ ((packed)) hdr; + struct timeval tv; + + memset(&hdr, 0, sizeof(hdr)); + hdr.gsmtap.version = GSMTAP_VERSION; + hdr.gsmtap.hdr_len = sizeof(hdr.gsmtap)/4; + hdr.gsmtap.type = GSMTAP_TYPE_OSMOCORE_LOG; + + OSMO_STRLCPY_ARRAY(hdr.log.proc_name, proc_name); + OSMO_STRLCPY_ARRAY(hdr.log.subsys, subsys_name); + hdr.log.level = LOGL_INFO; + + while ((line = fgets(buf, sizeof(buf), infile))) { + struct iovec iov[2] = { + { .iov_base = &hdr, .iov_len = sizeof(hdr) }, + { .iov_base = buf, .iov_len = strlen(line) + 1 }, + }; + osmo_gettimeofday(&tv, NULL); + hdr.log.ts.sec = osmo_htonl(tv.tv_sec); + hdr.log.ts.usec = osmo_htonl(tv.tv_usec); + + rc = writev(gsmtap_fd, iov, ARRAY_SIZE(iov)); + if (rc <= 0) { + fprintf(stderr, "Short write on GSMTAP socket: %d (%s)\n", rc, strerror(errno)); + exit(1); + } + } +}