Formalize configuration managment

This commit is contained in:
Christopher Wellons 2019-02-03 11:08:56 -05:00
parent 3a0126bd99
commit 5c6328c6f2

View File

@ -16,10 +16,10 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#define DEFAULT_MAX_CLIENTS 4096
#define DEFAULT_LINE_LENGTH 32
#define DEFAULT_PORT 2222 #define DEFAULT_PORT 2222
#define DEFAULT_DELAY 10000 // milliseconds #define DEFAULT_DELAY 10000 /* milliseconds */
#define DEFAULT_MAX_LINE_LENGTH 32
#define DEFAULT_MAX_CLIENTS 4096
#define XSTR(s) STR(s) #define XSTR(s) STR(s)
#define STR(s) #s #define STR(s) #s
@ -245,6 +245,80 @@ sigterm_handler(int signal)
running = 0; running = 0;
} }
struct config {
int port;
int delay;
int max_line_length;
int max_clients;
};
#define CONFIG_DEFAULT { \
.port = DEFAULT_PORT, \
.delay = DEFAULT_DELAY, \
.max_line_length = DEFAULT_MAX_LINE_LENGTH, \
.max_clients = DEFAULT_MAX_CLIENTS, \
}
static void
config_set_port(struct config *c, const char *s, int hardfail)
{
errno = 0;
char *end;
long tmp = strtol(s, &end, 10);
if (errno || *end || tmp < 1 || tmp > 65535) {
fprintf(stderr, "endlessh: Invalid port: %s\n", s);
if (hardfail)
exit(EXIT_FAILURE);
} else {
c->port = tmp;
}
}
static void
config_set_delay(struct config *c, const char *s, int hardfail)
{
errno = 0;
char *end;
long tmp = strtol(s, &end, 10);
if (errno || *end || tmp < 1 || tmp > INT_MAX) {
fprintf(stderr, "endlessh: Invalid delay: %s\n", s);
if (hardfail)
exit(EXIT_FAILURE);
} else {
c->delay = tmp;
}
}
static void
config_set_max_clients(struct config *c, const char *s, int hardfail)
{
errno = 0;
char *end;
long tmp = strtol(s, &end, 10);
if (errno || *end || tmp < 1 || tmp > INT_MAX) {
fprintf(stderr, "endlessh: Invalid max clients: %s\n", s);
if (hardfail)
exit(EXIT_FAILURE);
} else {
c->max_clients = tmp;
}
}
static void
config_set_max_line_length(struct config *c, const char *s, int hardfail)
{
errno = 0;
char *end;
long tmp = strtol(s, &end, 10);
if (errno || *end || tmp < 3 || tmp > 255) {
fprintf(stderr, "endlessh: Invalid line length: %s\n", s);
if (hardfail)
exit(EXIT_FAILURE);
} else {
c->max_line_length = tmp;
}
}
static void static void
usage(FILE *f) usage(FILE *f)
{ {
@ -254,7 +328,7 @@ usage(FILE *f)
XSTR(DEFAULT_DELAY) "]\n"); XSTR(DEFAULT_DELAY) "]\n");
fprintf(f, " -h Print this help message and exit\n"); fprintf(f, " -h Print this help message and exit\n");
fprintf(f, " -l INT Maximum banner line length (3-255) [" fprintf(f, " -l INT Maximum banner line length (3-255) ["
XSTR(DEFAULT_LINE_LENGTH) "]\n"); XSTR(DEFAULT_MAX_LINE_LENGTH) "]\n");
fprintf(f, " -m INT Maximum number of clients [" fprintf(f, " -m INT Maximum number of clients ["
XSTR(DEFAULT_MAX_CLIENTS) "]\n"); XSTR(DEFAULT_MAX_CLIENTS) "]\n");
fprintf(f, " -p INT Listening port [" XSTR(DEFAULT_PORT) "]\n"); fprintf(f, " -p INT Listening port [" XSTR(DEFAULT_PORT) "]\n");
@ -265,56 +339,26 @@ usage(FILE *f)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int port = DEFAULT_PORT; struct config config = CONFIG_DEFAULT;
int max_length = DEFAULT_LINE_LENGTH;
int max_clients = DEFAULT_MAX_CLIENTS;
long delay = DEFAULT_DELAY;
int option; int option;
while ((option = getopt(argc, argv, "d:hl:m:p:v")) != -1) { while ((option = getopt(argc, argv, "d:hl:m:p:v")) != -1) {
long tmp;
char *end;
switch (option) { switch (option) {
case 'd': case 'd':
errno = 0; config_set_delay(&config, optarg, 1);
delay = strtol(optarg, &end, 10);
if (errno || *end || delay < 0) {
fprintf(stderr, "endlessh: Invalid delay: %s\n", optarg);
exit(EXIT_FAILURE);
}
break; break;
case 'h': case 'h':
usage(stdout); usage(stdout);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case 'l': case 'l':
errno = 0; config_set_max_line_length(&config, optarg, 1);
tmp = strtol(optarg, &end, 10);
if (errno || *end || tmp < 3 || tmp > 255) {
fprintf(stderr, "endlessh: Invalid line length: %s\n",
optarg);
exit(EXIT_FAILURE);
}
max_length = tmp;
break; break;
case 'm': case 'm':
errno = 0; config_set_max_clients(&config, optarg, 1);
tmp = strtol(optarg, &end, 10);
if (errno || *end || tmp < 1 || tmp > INT_MAX) {
fprintf(stderr, "endlessh: Invalid max clients: %s\n",
optarg);
exit(EXIT_FAILURE);
}
max_clients = tmp;
break; break;
case 'p': case 'p':
errno = 0; config_set_port(&config, optarg, 1);
tmp = strtol(optarg, &end, 10);
if (errno || *end || tmp < 1 || tmp > 65535) {
fprintf(stderr, "endlessh: Invalid port: %s\n", optarg);
exit(EXIT_FAILURE);
}
port = tmp;
break; break;
case 'v': case 'v':
if (!loglevel++) if (!loglevel++)
@ -326,6 +370,12 @@ main(int argc, char **argv)
} }
} }
/* Log configuration */
logmsg(LOG_INFO, "Port %d", config.port);
logmsg(LOG_INFO, "Delay %ld", config.delay);
logmsg(LOG_INFO, "MaxLineLength %d", config.max_line_length);
logmsg(LOG_INFO, "MaxClients %d", config.max_clients);
struct sigaction sa = {.sa_handler = sigterm_handler}; struct sigaction sa = {.sa_handler = sigterm_handler};
check(sigaction(SIGTERM, &sa, 0)); check(sigaction(SIGTERM, &sa, 0));
@ -343,16 +393,23 @@ main(int argc, char **argv)
int dummy = 1; int dummy = 1;
check(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy))); check(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy)));
struct sockaddr_in addr = {AF_INET, htons(port), {htonl(INADDR_ANY)}}; struct sockaddr_in addr = {
AF_INET,
htons(config.port),
{htonl(INADDR_ANY)}
};
check(bind(server, (void *)&addr, sizeof(addr))); check(bind(server, (void *)&addr, sizeof(addr)));
check(listen(server, INT_MAX)); check(listen(server, INT_MAX));
logmsg(LOG_DEBUG, "listen(port=%d)", port); logmsg(LOG_DEBUG, "listen(port=%d)", config.port);
srand(time(0)); srand(time(0));
while (running) { while (running) {
pollvec_clear(pollvec); pollvec_clear(pollvec);
pollvec_push(pollvec, nclients < max_clients ? server : -1, POLLIN); if (nclients < config.max_clients)
pollvec_push(pollvec, server, POLLIN);
else
pollvec_push(pollvec, -1, POLLIN);
/* Poll clients that are due for another message */ /* Poll clients that are due for another message */
int timeout = -1; int timeout = -1;
@ -368,7 +425,7 @@ main(int argc, char **argv)
/* Wait for next event */ /* Wait for next event */
logmsg(LOG_DEBUG, "poll(%zu, %d)%s", pollvec->fill, timeout, logmsg(LOG_DEBUG, "poll(%zu, %d)%s", pollvec->fill, timeout,
nclients >= max_clients ? " (no accept)" : ""); nclients >= config.max_clients ? " (no accept)" : "");
int r = poll(pollvec->fds, pollvec->fill, timeout); int r = poll(pollvec->fds, pollvec->fill, timeout);
logmsg(LOG_DEBUG, "= %d", r); logmsg(LOG_DEBUG, "= %d", r);
if (r == -1) { if (r == -1) {
@ -391,9 +448,9 @@ main(int argc, char **argv)
switch (errno) { switch (errno) {
case EMFILE: case EMFILE:
case ENFILE: case ENFILE:
max_clients = nclients; config.max_clients = nclients;
logmsg(LOG_INFO, logmsg(LOG_INFO,
"maximum number of clients reduced to %d", "MaxClients %d",
nclients); nclients);
break; break;
case ECONNABORTED: case ECONNABORTED:
@ -408,7 +465,8 @@ main(int argc, char **argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} else { } else {
struct client *client = client_new(fd, uepoch() + delay / 2); long long send_next = uepoch() + config.delay / 2;
struct client *client = client_new(fd, send_next);
if (!client) { if (!client) {
fprintf(stderr, "endlessh: warning: out of memory\n"); fprintf(stderr, "endlessh: warning: out of memory\n");
close(fd); close(fd);
@ -416,7 +474,7 @@ main(int argc, char **argv)
nclients++; nclients++;
logmsg(LOG_INFO, "ACCEPT host=%s:%d fd=%d n=%d/%d", logmsg(LOG_INFO, "ACCEPT host=%s:%d fd=%d n=%d/%d",
client->ipaddr, client->port, client->fd, client->ipaddr, client->port, client->fd,
nclients, max_clients); nclients, config.max_clients);
queue_append(queue, client); queue_append(queue, client);
} }
} }
@ -433,7 +491,7 @@ main(int argc, char **argv)
} else if (revents & POLLOUT) { } else if (revents & POLLOUT) {
char line[256]; char line[256];
int len = randline(line, max_length); int len = randline(line, config.max_line_length);
/* Don't really care if send is short */ /* Don't really care if send is short */
ssize_t out = send(fd, line, len, MSG_DONTWAIT); ssize_t out = send(fd, line, len, MSG_DONTWAIT);
if (out < 0) if (out < 0)
@ -441,7 +499,7 @@ main(int argc, char **argv)
else { else {
logmsg(LOG_DEBUG, "send(%d) = %d", fd, (int)out); logmsg(LOG_DEBUG, "send(%d) = %d", fd, (int)out);
client->bytes_sent += out; client->bytes_sent += out;
client->send_next = uepoch() + delay; client->send_next = uepoch() + config.delay;
queue_append(queue, client); queue_append(queue, client);
} }
} }