view utils/tcpserv-dump.c @ 217:9f6a148ceb25

tcpserv-dump: brown paper bag
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 24 Jul 2023 22:33:01 -0800
parents 6aa2cd650943
children
line wrap: on
line source

/*
 * 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 struct in_addr bind_ip;
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 rc, i;
	struct sockaddr_in sin;
	socklen_t addrlen;
	fd_set fds;

	if (argc != 4) {
		fprintf(stderr, "usage: %s bind-ip port logfile\n", argv[0]);
		exit(1);
	}
	bind_ip.s_addr = inet_addr(argv[1]);
	if (bind_ip.s_addr == INADDR_NONE) {
		fprintf(stderr, "error: invalid IP address argument \"%s\"\n",
			argv[1]);
		exit(1);
	}
	tcp_port = atoi(argv[2]);
	listener = socket(AF_INET, SOCK_STREAM, 0);
	if (listener < 0) {
		perror("socket");
		exit(1);
	}
	sin.sin_family = AF_INET;
	sin.sin_addr = bind_ip;
	sin.sin_port = htons(tcp_port);
	rc = bind(listener, (struct sockaddr *) &sin, sizeof sin);
	if (rc < 0) {
		perror("bind");
		exit(1);
	}
	logf = fopen(argv[3], "a");
	if (!logf) {
		perror(argv[3]);
		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);
	}
}