changeset 215:67289fac8a44

utils: new program tcpserv-dump
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 24 Jul 2023 21:49:09 -0800
parents 10a4b0b0a239
children 6aa2cd650943
files .hgignore utils/Makefile utils/tcpserv-dump.c
diffstat 3 files changed, 178 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat Jul 08 13:32:32 2023 -0800
+++ b/.hgignore	Mon Jul 24 21:49:09 2023 -0800
@@ -20,6 +20,7 @@
 ^utils/sip-out-test$
 ^utils/sip-rx-test$
 ^utils/sip-udp-dump$
+^utils/tcpserv-dump$
 ^utils/themwi-check-own$
 ^utils/themwi-dump-numdb$
 ^utils/themwi-short-dial$
--- a/utils/Makefile	Sat Jul 08 13:32:32 2023 -0800
+++ b/utils/Makefile	Mon Jul 24 21:49:09 2023 -0800
@@ -3,7 +3,7 @@
 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
-NOINST=	rtp-alloc-test
+NOINST=	rtp-alloc-test tcpserv-dump
 LIBNUMDB=../libnumdb/libnumdb.a
 LIBRTPA=../librtpalloc/librtpalloc.a
 LIBSIP=	../libsip/libsip.a
@@ -24,6 +24,9 @@
 sip-udp-dump:	sip-udp-dump.c
 	${CC} ${CFLAGS} -o $@ $@.c
 
+tcpserv-dump:	tcpserv-dump.c
+	${CC} ${CFLAGS} -o $@ $@.c
+
 themwi-check-own:	themwi-check-own.o ${LIBNUMDB} ${LIBUTIL}
 	${CC} ${CFLAGS} -o $@ $@.o ${LIBNUMDB} ${LIBUTIL}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/tcpserv-dump.c	Mon Jul 24 21:49:09 2023 -0800
@@ -0,0 +1,173 @@
+/*
+ * This debug utility binds to a TCP port specified on the command line,
+ * accepts incoming TCP connections and reads any bytes sent by a client
+ * on an opened connection - but never sends anything back.  A log file
+ * is written, recording all received connections and bytes.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <unistd.h>
+
+#define	MAXCONN	10
+
+static int tcp_port;
+static int listener, nconn, conns[MAXCONN], max_fd;
+static FILE *logf;
+static struct timeval curtime;
+static char fmt_time[32];
+
+static void
+format_time()
+{
+	struct tm *tm;
+
+	tm = gmtime(&curtime.tv_sec);
+	sprintf(fmt_time, "%d-%02d-%02dT%02d:%02d:%02dZ",
+		tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+		tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+static void
+handle_accept(newfd, sin)
+	struct sockaddr_in *sin;
+{
+	fprintf(logf, "\n%s Accept conn from %s:%u fd %d\n", fmt_time,
+		inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), newfd);
+	if (nconn < MAXCONN) {
+		conns[nconn] = newfd;
+		nconn++;
+		if (newfd > max_fd)
+			max_fd = newfd;
+	} else {
+		fprintf(logf, "MAXCONN exceeded, closing new fd\n");
+		close(newfd);
+	}
+}
+
+static int
+handle_conn_fd(fd)
+{
+	u_char buf[512];
+	int cc, off, chunk, i, c;
+
+	cc = read(fd, buf, sizeof buf);
+	fprintf(logf, "\n%s fd %d read %d\n", fmt_time, fd, cc);
+	if (cc <= 0) {
+		fprintf(logf, "closing fd\n");
+		return(1);
+	}
+	for (off = 0; off < cc; off += chunk) {
+		fprintf(logf, "%04X:  ", off);
+		chunk = cc - off;
+		if (chunk > 16)
+			chunk = 16;
+		for (i = 0; i < 16; i++) {
+			if (i < chunk)
+				fprintf(logf, "%02X ", buf[off + i]);
+			else
+				fputs("   ", logf);
+			if (i == 7 || i == 15)
+				putc(' ', logf);
+		}
+		for (i = 0; i < chunk; i++) {
+			c = buf[off + i];
+			if (c < ' ' || c > '~')
+				c = '.';
+			putc(c, logf);
+		}
+		putc('\n', logf);
+	}
+	return(0);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	int max_fd, rc, i;
+	struct sockaddr_in sin;
+	socklen_t addrlen;
+	fd_set fds;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s port logfile\n", argv[0]);
+		exit(1);
+	}
+	tcp_port = atoi(argv[1]);
+	listener = socket(AF_INET, SOCK_STREAM, 0);
+	if (listener < 0) {
+		perror("socket");
+		exit(1);
+	}
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = INADDR_ANY;
+	sin.sin_port = htons(tcp_port);
+	rc = bind(listener, (struct sockaddr *) &sin, sizeof sin);
+	if (rc < 0) {
+		perror("bind");
+		exit(1);
+	}
+	logf = fopen(argv[2], "a");
+	if (!logf) {
+		perror(argv[2]);
+		exit(1);
+	}
+	rc = listen(listener, 5);
+	if (rc < 0) {
+		perror("listen");
+		exit(1);
+	}
+	gettimeofday(&curtime, 0);
+	format_time();
+	fprintf(logf, "\n%s Test server started\n", fmt_time);
+	fflush(logf);
+	nconn = 0;
+	max_fd = listener;
+	for (;;) {
+		FD_ZERO(&fds);
+		FD_SET(listener, &fds);
+		for (i = 0; i < nconn; i++)
+			FD_SET(conns[i], &fds);
+		rc = select(max_fd+1, &fds, 0, 0, 0);
+		if (rc < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("select");
+			exit(1);
+		}
+		gettimeofday(&curtime, 0);
+		format_time();
+		for (i = 0; i < nconn; ) {
+			if (!FD_ISSET(conns[i], &fds)) {
+				i++;
+				continue;
+			}
+			if (handle_conn_fd(conns[i])) {
+				close(conns[i]);
+				nconn--;
+				conns[i] = conns[nconn];
+			} else
+				i++;
+		}
+		if (FD_ISSET(listener, &fds)) {
+			addrlen = sizeof(struct sockaddr_in);
+			rc = accept(listener, (struct sockaddr *) &sin,
+					&addrlen);
+			if (rc >= 0)
+				handle_accept(rc, &sin);
+			else
+				fprintf(logf, "\n%s accept syscall error!\n",
+					fmt_time);
+		}
+		fflush(logf);
+	}
+}