Improve support for Solaris and its derivatives

Requires extensions to be enabled due to incomplete support for
POSIX.1-2008. However one of the now-exposed extensions is tragically
named "struct queue". This struct was been renamed to "struct fifo".

Thanks to @yvoinov for reporting this issue and collaborating on a
solution.

Closes #14, #17.
This commit is contained in:
Christopher Wellons
2019-03-26 23:09:44 -04:00
parent a6d5425cba
commit b1c1599d32
2 changed files with 43 additions and 21 deletions

View File

@@ -73,11 +73,27 @@ LogLevel 0
## Build issues ## Build issues
RHEL 6 and CentOS 6 use a version of glibc older than 2.17 (December Some more esoteric systems require extra configuration when building.
2012), and `clock_gettime(2)` is still in librt. For these systems you
will need to link against librt: ### RHEL 6 / CentOS 6
This system uses a version of glibc older than 2.17 (December 2012), and
`clock_gettime(2)` is still in librt. For these systems you will need to
link against librt:
make LDLIBS=-lrt make LDLIBS=-lrt
### Solaris / illumos
These systems don't include all the necessary functionality in libc and
the linker requires some extra libraries:
make CC=gcc LDLIBS='-lnsl -lrt -lsocket'
If you're not using GCC or Clang, also override `CFLAGS` and `LDFLAGS`
to remove GCC-specific options. For example, on Solaris:
make CFLAGS=-fast LDFLAGS= LDLIBS='-lnsl -lrt -lsocket'
[np]: https://nullprogram.com/blog/2019/03/22/ [np]: https://nullprogram.com/blog/2019/03/22/

View File

@@ -1,4 +1,4 @@
#ifdef __FreeBSD__ #if defined(__FreeBSD__)
# define _WITH_GETLINE # define _WITH_GETLINE
/* The MSG_DONTWAIT send(2) flag is non-standard, but widely available. /* The MSG_DONTWAIT send(2) flag is non-standard, but widely available.
* However, FreeBSD doesn't define this flag when using POSIX feature * However, FreeBSD doesn't define this flag when using POSIX feature
@@ -13,6 +13,12 @@
* test macro or use the FreeBSD-specific _WITH_GETLINE macro. Since we * test macro or use the FreeBSD-specific _WITH_GETLINE macro. Since we
* can't use the former, we'll have to go with the latter. * can't use the former, we'll have to go with the latter.
*/ */
#elif defined(__sun__)
/* Solaris and its illumos derivatives consider getline(3) to be an
* extension despite this function being standardized by POSIX.1-2008
* more than a decade ago. As a workaround just enable all extensions.
*/
# define __EXTENSIONS__
#else #else
# define _POSIX_C_SOURCE 200809L # define _POSIX_C_SOURCE 200809L
#endif #endif
@@ -149,21 +155,21 @@ client_destroy(struct client *client)
free(client); free(client);
} }
struct queue { struct fifo {
struct client *head; struct client *head;
struct client *tail; struct client *tail;
int length; int length;
}; };
static void static void
queue_init(struct queue *q) fifo_init(struct fifo *q)
{ {
q->head = q->tail = 0; q->head = q->tail = 0;
q->length = 0; q->length = 0;
} }
static struct client * static struct client *
queue_remove(struct queue *q, int fd) fifo_remove(struct fifo *q, int fd)
{ {
/* Yes, this is a linear search, but the element we're looking for /* Yes, this is a linear search, but the element we're looking for
* is virtually always one of the first few elements. * is virtually always one of the first few elements.
@@ -190,7 +196,7 @@ queue_remove(struct queue *q, int fd)
} }
static void static void
queue_append(struct queue *q, struct client *c) fifo_append(struct fifo *q, struct client *c)
{ {
if (!q->tail) { if (!q->tail) {
q->head = q->tail = c; q->head = q->tail = c;
@@ -202,7 +208,7 @@ queue_append(struct queue *q, struct client *c)
} }
static void static void
queue_destroy(struct queue *q) fifo_destroy(struct fifo *q)
{ {
struct client *c = q->head; struct client *c = q->head;
while (c) { while (c) {
@@ -622,8 +628,8 @@ main(int argc, char **argv)
die(); die();
} }
struct queue queue[1]; struct fifo fifo[1];
queue_init(queue); fifo_init(fifo);
struct pollvec pollvec[1]; struct pollvec pollvec[1];
pollvec_init(pollvec); pollvec_init(pollvec);
@@ -647,7 +653,7 @@ main(int argc, char **argv)
/* Enqueue the listening socket first */ /* Enqueue the listening socket first */
pollvec_clear(pollvec); pollvec_clear(pollvec);
if (queue->length < config.max_clients) if (fifo->length < config.max_clients)
pollvec_push(pollvec, server, POLLIN); pollvec_push(pollvec, server, POLLIN);
else else
pollvec_push(pollvec, -1, 0); pollvec_push(pollvec, -1, 0);
@@ -655,7 +661,7 @@ main(int argc, char **argv)
/* Enqueue clients that are due for another message */ /* Enqueue clients that are due for another message */
int timeout = -1; int timeout = -1;
long long now = uepoch(); long long now = uepoch();
for (struct client *c = queue->head; c; c = c->next) { for (struct client *c = fifo->head; c; c = c->next) {
if (c->send_next <= now) { if (c->send_next <= now) {
pollvec_push(pollvec, c->fd, POLLOUT); pollvec_push(pollvec, c->fd, POLLOUT);
} else { } else {
@@ -666,7 +672,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,
queue->length >= config.max_clients ? " (no accept)" : ""); fifo->length >= 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) {
@@ -689,10 +695,10 @@ main(int argc, char **argv)
switch (errno) { switch (errno) {
case EMFILE: case EMFILE:
case ENFILE: case ENFILE:
config.max_clients = queue->length; config.max_clients = fifo->length;
logmsg(LOG_INFO, logmsg(LOG_INFO,
"MaxClients %d", "MaxClients %d",
queue->length); fifo->length);
break; break;
case ECONNABORTED: case ECONNABORTED:
case EINTR: case EINTR:
@@ -712,10 +718,10 @@ main(int argc, char **argv)
fprintf(stderr, "endlessh: warning: out of memory\n"); fprintf(stderr, "endlessh: warning: out of memory\n");
close(fd); close(fd);
} }
queue_append(queue, client); fifo_append(fifo, client);
logmsg(LOG_INFO, "ACCEPT host=%s port=%d fd=%d n=%d/%d", logmsg(LOG_INFO, "ACCEPT host=%s port=%d fd=%d n=%d/%d",
client->ipaddr, client->port, client->fd, client->ipaddr, client->port, client->fd,
queue->length, config.max_clients); fifo->length, config.max_clients);
} }
} }
@@ -723,7 +729,7 @@ main(int argc, char **argv)
for (size_t i = 1; i < pollvec->fill; i++) { for (size_t i = 1; i < pollvec->fill; i++) {
short fd = pollvec->fds[i].fd; short fd = pollvec->fds[i].fd;
short revents = pollvec->fds[i].revents; short revents = pollvec->fds[i].revents;
struct client *client = queue_remove(queue, fd); struct client *client = fifo_remove(fifo, fd);
if (revents & POLLHUP) { if (revents & POLLHUP) {
client_destroy(client); client_destroy(client);
@@ -743,7 +749,7 @@ main(int argc, char **argv)
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() + config.delay; client->send_next = uepoch() + config.delay;
queue_append(queue, client); fifo_append(fifo, client);
break; break;
} }
} }
@@ -752,5 +758,5 @@ main(int argc, char **argv)
} }
pollvec_free(pollvec); pollvec_free(pollvec);
queue_destroy(queue); fifo_destroy(fifo);
} }