Skip to content

Commit

Permalink
external: Add previously uncommitted test programs.
Browse files Browse the repository at this point in the history
This adds two simple programs originally created for use
by developers for testing. However, given their
general utility, I'm adding them to the tree:

* leak.c: Memory leaker
* tcplog.c: netcat-like program for analyzing data
  • Loading branch information
InterLinked1 committed Dec 23, 2023
1 parent eec0c75 commit 2de063e
Show file tree
Hide file tree
Showing 2 changed files with 216 additions and 0 deletions.
44 changes: 44 additions & 0 deletions external/leak.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* LBBS -- The Lightweight Bulletin Board System
*
* Copyright (C) 2023, Naveen Albert
*
* Naveen Albert <[email protected]>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/

/*! \file
*
* \brief Memory leaker
*
* \note Create a perpetually growing memory leak until stopped (for testing resource limits)
*
* \author Naveen Albert <[email protected]>
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
size_t allocated = 0;

(void) argc;
(void) argv;

for (;;) {
char *s = malloc(1024 * 1024); /* 1 MB at a time */
if (!s) {
printf("Allocation failed\n");
break;
}
allocated++;
printf("%6lu MB now allocated\n", allocated);
usleep(50000); /* Pause 50ms for every MB allocated */
}
return 0;
}
172 changes: 172 additions & 0 deletions external/tcplog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* LBBS -- The Lightweight Bulletin Board System
*
* Copyright (C) 2023, Naveen Albert
*
* Naveen Albert <[email protected]>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/

/*! \file
*
* \brief TCP Logger
*
* \author Naveen Albert <[email protected]>
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <ctype.h>
#include <poll.h>
#include <sys/socket.h>
#include <netinet/in.h> /* use sockaddr_in */
#include <getopt.h>

static void *handler(void *varg)
{
int *fdptr = varg;
int fd = *fdptr;
unsigned char buf[8192];
int i;

fprintf(stderr, "New connection on fd %d\n", fd);

for (;;) {
int res = read(fd, (char*) buf, sizeof(buf));
if (res <= 0) {
fprintf(stderr, "read(%d) returned %d: %s\n", fd, res, strerror(errno));
break;
}
for (i = 0; i < res; i++) {
if (isprint(buf[i])) {
printf("[%d] %3d: %c\n", fd, buf[i], buf[i]);
} else {
printf("[%d] %3d\n", fd, buf[i]);
}
}
}
return NULL;
}

static int listen_port = -1;
static int listen_local = 0;
static int debug_level = 0;

static int parse_options(int argc, char *argv[])
{
static const char *getopt_settings = "lhpv";
int c;

while ((c = getopt(argc, argv, getopt_settings)) != -1) {
switch (c) {
case 'l':
listen_local = 1;
break;
case 'h':
fprintf(stderr, "tcplog [-options]\n");
fprintf(stderr, " -l Listen only on localhost\n");
fprintf(stderr, " -p port Port on which to listen\n");
fprintf(stderr, " -v Increase verbosity\n");
return -1;
case 'p':
listen_port = atoi(argv[optind++]);
break;
case 'v':
debug_level++;
break;
default:
fprintf(stderr, "Unknown option: %c\n", c);
return -1;
}
}

return 0;
}

int main(int argc, char *argv[])
{
struct sockaddr_in sinaddr;
socklen_t len;
int sfd, res;
int sock;
const int enable = 1;

if (parse_options(argc, argv)) {
return -1;
} else if (listen_port == -1) {
fprintf(stderr, "Must specify a port: tcplog -p <port>\n");
return -1;
}

sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
fprintf(stderr, "Unable to create TCP socket: %s\n", strerror(errno));
return -1;
}

/* Allow reuse so we can rerun quickly */
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
fprintf(stderr, "Unable to create setsockopt: %s\n", strerror(errno));
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
fprintf(stderr, "Unable to create setsockopt: %s\n", strerror(errno));
return -1;
}

memset(&sinaddr, 0, sizeof(sinaddr));
sinaddr.sin_family = AF_INET;
sinaddr.sin_addr.s_addr = listen_local ? INADDR_LOOPBACK : INADDR_ANY;
sinaddr.sin_port = htons(listen_port);

if (bind(sock, (struct sockaddr *) &sinaddr, sizeof(sinaddr))) {
fprintf(stderr, "Unable to bind TCP socket to port %d: %s\n", listen_port, strerror(errno));
close(sock);
return -1;
}

if (listen(sock, 2) < 0) {
fprintf(stderr, "Unable to listen on TCP socket on port %d: %s\n", listen_port, strerror(errno));
close(sock);
return -1;
}

fprintf(stderr, "Listening on port %d\n", listen_port);

for (;;) {
pthread_attr_t attr;
pthread_t thread;
sfd = accept(sock, (struct sockaddr *) &sinaddr, &len);
if (sfd < 0) {
if (errno != EINTR) {
fprintf(stderr, "accept returned %d: %s\n", sfd, strerror(errno));
break;
}
continue;
}

/* Make the thread detached, since we're not going to join it, ever */
pthread_attr_init(&attr);
res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (res) {
fprintf(stderr, "pthread_attr_setdetachstate: %s\n", strerror(res));
close(sfd);
continue;
}
if (pthread_create(&thread, &attr, handler, &sfd)) {
fprintf(stderr, "pthread_create failed: %s\n", strerror(errno));
close(sfd);
}
usleep(100000); /* Wait for thread to start and dereference sfd before we accept() and overwrite it */
}

close(sock);
fprintf(stderr, "Listener thread has exited\n");
}

0 comments on commit 2de063e

Please sign in to comment.