Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Jitter #81

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions endlessh.1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
.Nm endless
.Op Fl 46chsvV
.Op Fl d Ar delay
.Op Fl j Ar jitter
.Op Fl f Ar config
.Op Fl l Ar max banner length
.Op Fl m Ar max clients
Expand Down Expand Up @@ -40,6 +41,8 @@ Forces
to use IPv6 addresses only.
.It Fl d Ar delay
Message milliseconds delay. Default: 10000
.It Fl j Ar jitter
Randomizes the delay by j% (0-100). Default: 0 (no jitter)
.It Fl f Ar config
Set and load config file.
By default
Expand Down
45 changes: 42 additions & 3 deletions endlessh.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#define DEFAULT_PORT 2222
#define DEFAULT_DELAY 10000 /* milliseconds */
#define DEFAULT_DELAY_JITTER 0 /* Percent; for backward compatibility */
#define DEFAULT_MAX_LINE_LENGTH 32
#define DEFAULT_MAX_CLIENTS 4096

Expand Down Expand Up @@ -105,6 +106,14 @@ logsyslog(enum loglevel level, const char *format, ...)
}
}

static long long random_delay(int delay, uint16_t jitter) {
if(!jitter)
return delay;

long long max_difference = delay*jitter/100;
return delay+(rand()%(2*max_difference))-max_difference; //insecure rand() was used on purpose to avoid potential performance bottleneck
}

static struct {
long long connects;
long long milliseconds;
Expand Down Expand Up @@ -298,6 +307,7 @@ sigusr1_handler(int signal)
struct config {
int port;
int delay;
uint16_t jitter;
int max_line_length;
int max_clients;
int bind_family;
Expand All @@ -306,6 +316,7 @@ struct config {
#define CONFIG_DEFAULT { \
.port = DEFAULT_PORT, \
.delay = DEFAULT_DELAY, \
.jitter = DEFAULT_DELAY_JITTER, \
.max_line_length = DEFAULT_MAX_LINE_LENGTH, \
.max_clients = DEFAULT_MAX_CLIENTS, \
.bind_family = DEFAULT_BIND_FAMILY, \
Expand Down Expand Up @@ -341,6 +352,21 @@ config_set_delay(struct config *c, const char *s, int hardfail)
}
}

static void
config_set_jitter(struct config *c, const char *s, int hardfail) //TODO
{
errno = 0;
char *end;
long tmp = strtol(s, &end, 10);
if (errno || *end || tmp < 0 || tmp > 100) {
fprintf(stderr, "endlessh: Invalid jitter: %s (0 <= jitter <= 100)\n", s);
if (hardfail)
exit(EXIT_FAILURE);
} else {
c->jitter = (uint16_t)tmp;
}
}

static void
config_set_max_clients(struct config *c, const char *s, int hardfail)
{
Expand Down Expand Up @@ -396,6 +422,7 @@ enum config_key {
KEY_INVALID,
KEY_PORT,
KEY_DELAY,
KEY_JITTER,
KEY_MAX_LINE_LENGTH,
KEY_MAX_CLIENTS,
KEY_LOG_LEVEL,
Expand All @@ -408,6 +435,7 @@ config_key_parse(const char *tok)
static const char *const table[] = {
[KEY_PORT] = "Port",
[KEY_DELAY] = "Delay",
[KEY_JITTER] = "Jitter",
[KEY_MAX_LINE_LENGTH] = "MaxLineLength",
[KEY_MAX_CLIENTS] = "MaxClients",
[KEY_LOG_LEVEL] = "LogLevel",
Expand Down Expand Up @@ -472,6 +500,9 @@ config_load(struct config *c, const char *file, int hardfail)
case KEY_DELAY:
config_set_delay(c, tokens[1], hardfail);
break;
case KEY_JITTER:
config_set_jitter(c, tokens[1], hardfail);
break;
case KEY_MAX_LINE_LENGTH:
config_set_max_line_length(c, tokens[1], hardfail);
break;
Expand Down Expand Up @@ -505,6 +536,7 @@ config_log(const struct config *c)
{
logmsg(log_info, "Port %d", c->port);
logmsg(log_info, "Delay %d", c->delay);
logmsg(log_info, "Jitter %d", c->jitter);
logmsg(log_info, "MaxLineLength %d", c->max_line_length);
logmsg(log_info, "MaxClients %d", c->max_clients);
logmsg(log_info, "BindFamily %s",
Expand All @@ -522,6 +554,8 @@ usage(FILE *f)
fprintf(f, " -6 Bind to IPv6 only\n");
fprintf(f, " -d INT Message millisecond delay ["
XSTR(DEFAULT_DELAY) "]\n");
fprintf(f, " -j FLOAT Delay Jitter in Percent ["
XSTR(DEFAULT_DELAY_JITTER) "]\n");
fprintf(f, " -f Set and load config file ["
DEFAULT_CONFIG_FILE "]\n");
fprintf(f, " -h Print this help message and exit\n");
Expand Down Expand Up @@ -632,6 +666,8 @@ main(int argc, char **argv)
struct config config = CONFIG_DEFAULT;
const char *config_file = DEFAULT_CONFIG_FILE;

srand((unsigned int)time(NULL)); //insecure rand() was used on purpose to avoid potential performance bottleneck

#if defined(__OpenBSD__)
unveil(config_file, "r"); /* return ignored as the file may not exist */
if (pledge("inet stdio rpath unveil", 0) == -1)
Expand All @@ -641,7 +677,7 @@ main(int argc, char **argv)
config_load(&config, config_file, 1);

int option;
while ((option = getopt(argc, argv, "46d:f:hl:m:p:svV")) != -1) {
while ((option = getopt(argc, argv, "46d:j:f:hl:m:p:svV")) != -1) {
switch (option) {
case '4':
config_set_bind_family(&config, "4", 1);
Expand All @@ -652,6 +688,9 @@ main(int argc, char **argv)
case 'd':
config_set_delay(&config, optarg, 1);
break;
case 'j':
config_set_jitter(&config, optarg, 1);
break;
case 'f':
config_file = optarg;

Expand Down Expand Up @@ -765,7 +804,7 @@ main(int argc, char **argv)
if (fifo->head->send_next <= now) {
struct client *c = fifo_pop(fifo);
if (sendline(c, config.max_line_length, &rng)) {
c->send_next = now + config.delay;
c->send_next = now + random_delay(config.delay, config.jitter);
fifo_append(fifo, c);
}
} else {
Expand Down Expand Up @@ -818,7 +857,7 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
} else {
long long send_next = epochms() + config.delay;
long long send_next = epochms() + random_delay(config.delay, config.jitter);
struct client *client = client_new(fd, send_next);
int flags = fcntl(fd, F_GETFL, 0); /* cannot fail */
fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* cannot fail */
Expand Down