diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2018-05-07 11:04:58 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2018-05-07 11:04:58 +0200 |
commit | be4352e2bb6ffcc1d548cf9e8cf9f497e2865af0 (patch) | |
tree | d692109ddb4b9304ecc65be09e9cd44481551580 | |
parent | 14d2b4d0134ac00a6262d5c8229ffe0d3b5ecd48 (diff) |
POTD skeleton #44.
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/main.c | 12 | ||||
-rw-r--r-- | src/pevent.c | 98 | ||||
-rw-r--r-- | src/pevent.h | 30 | ||||
-rw-r--r-- | src/server.c | 128 | ||||
-rw-r--r-- | src/server.h | 7 |
6 files changed, 186 insertions, 91 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index f6c7a20..711632d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,4 +2,4 @@ AM_CFLAGS = -pedantic -Wall -std=gnu99 -fstrict-aliasing -D_GNU_SOURCE=1 $(libss AM_LDFLAGS = $(libssh_LIBS) sbin_PROGRAMS = potd -potd_SOURCES = utils.c log.c log_colored.c socket.c jail.c forward.c server.c server_ssh.c main.c +potd_SOURCES = utils.c log.c log_colored.c socket.c pevent.c jail.c forward.c server.c server_ssh.c main.c @@ -23,7 +23,8 @@ int main(int argc, char *argv[]) server_ctx *srv[srv_siz]; jail_ctx *jail[jail_siz]; forward_ctx *ssh_fwd = NULL; - int jail_epoll_fd, srv_epoll_fd, proc_status; + event_ctx *srv_event = NULL; + int jail_epoll_fd, proc_status; pid_t daemon_pid, srv_pid, jail_pid, wpid; (void) argc; @@ -89,17 +90,16 @@ int main(int argc, char *argv[]) "Server validation" ); } - D2("%s", "Server epoll setup"); - srv_epoll_fd = server_setup_epoll( srv, srv_siz ); - D2("Server epoll fd: %d", srv_epoll_fd); - ABORT_ON_FATAL( srv_epoll_fd < 0, "Server epoll setup" ); + D2("%s", "Server event setup"); + ABORT_ON_FATAL( server_setup_event( srv, srv_siz, &srv_event ), + "Server event setup" ); D2("Server dropping privileges to %s:%s", "nobody", "NULL"); ABORT_ON_FATAL( change_user_group("nobody", NULL), "Server dropping privileges" ); N("%s", "Server epoll mainloop"); - srv_pid = server_daemonize( srv_epoll_fd, srv, srv_siz ); + srv_pid = server_daemonize( srv_event, srv, srv_siz ); ABORT_ON_FATAL( srv_pid < 1, "Server epoll mainloop" ); while (1) { diff --git a/src/pevent.c b/src/pevent.c new file mode 100644 index 0000000..a8845d3 --- /dev/null +++ b/src/pevent.c @@ -0,0 +1,98 @@ +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <sys/epoll.h> +#include <assert.h> + +#include "pevent.h" +#include "log.h" + + +void event_init(event_ctx **ctx) +{ + assert(ctx); + if (!*ctx) + *ctx = (event_ctx *) malloc(sizeof(**ctx)); + assert(*ctx); + + memset(*ctx, 0, sizeof(**ctx)); + (*ctx)->epoll_fd = -1; +} + +int event_setup(event_ctx *ctx) +{ + assert(ctx); + + if (ctx->epoll_fd < 0) + ctx->epoll_fd = epoll_create1(0); + + return ctx->epoll_fd < 0; +} + +int event_add_sock(event_ctx *ctx, psocket *sock) +{ + int s; + struct epoll_event ev = {0,{0}}; + + assert(ctx && sock); + + ev.data.fd = sock->fd; + ev.events = EPOLLIN | EPOLLET; + s = epoll_ctl(ctx->epoll_fd, EPOLL_CTL_ADD, sock->fd, &ev); + if (s) + return 1; + + return 0; +} + +int event_add_fd(event_ctx *ctx, int fd) +{ + int s; + struct epoll_event ev = {0,{0}}; + + assert(ctx); + + ev.data.fd = fd; + ev.events = EPOLLIN | EPOLLET; + s = epoll_ctl(ctx->epoll_fd, EPOLL_CTL_ADD, fd, &ev); + if (s) + return 1; + + return 0; +} + +int event_loop(event_ctx *ctx, on_event_cb on_event, void *user_data) +{ + int n, i; + sigset_t eset; + + assert(ctx && on_event); + sigemptyset(&eset); + ctx->active = 1; + + while (ctx->active) { + n = epoll_pwait(ctx->epoll_fd, ctx->events, POTD_MAXEVENTS, -1, &eset); + if (n < 0) + break; + + for (i = 0; i < n; ++i) { + if ((ctx->events[i].events & EPOLLERR) || + (ctx->events[i].events & EPOLLHUP) || + (!(ctx->events[i].events & EPOLLIN))) + { + E_STRERR("Event epoll for descriptor %d", + ctx->events[i].data.fd); + close(ctx->events[i].data.fd); + continue; + } else { + if (on_event(ctx->events[i].data.fd, user_data)) + continue; + W2("Event callback failed: [fd: %d , npoll: %d]", + ctx->events[i].data.fd, n); + } + } + } + + return ctx->active == 0; +} diff --git a/src/pevent.h b/src/pevent.h new file mode 100644 index 0000000..da09f59 --- /dev/null +++ b/src/pevent.h @@ -0,0 +1,30 @@ +#ifndef POTD_EVENT_H +#define POTD_EVENT_H 1 + +#include <sys/epoll.h> + +#include "socket.h" + +#define POTD_MAXFD 32 +#define POTD_MAXEVENTS 64 + +typedef struct event_ctx { + int epoll_fd; + int active; + struct epoll_event events[POTD_MAXEVENTS]; +} event_ctx; + +typedef int (*on_event_cb) (int fd, void *user_data); + + +void event_init(event_ctx **ctx); + +int event_setup(event_ctx *ctx); + +int event_add_sock(event_ctx *ctx, psocket *sock); + +int event_add_fd(event_ctx *ctx, int fd); + +int event_loop(event_ctx *ctx, on_event_cb on_event, void *user_data); + +#endif diff --git a/src/server.c b/src/server.c index a4f816b..4dd3a94 100644 --- a/src/server.c +++ b/src/server.c @@ -3,7 +3,6 @@ #include <unistd.h> #include <string.h> #include <signal.h> -#include <sys/epoll.h> #include <pthread.h> #include <assert.h> @@ -19,19 +18,23 @@ typedef struct client_thread_args { const server_ctx *server_ctx; } client_thread_args; +typedef struct server_args { + server_ctx **srv_ctx; + size_t siz; +} server_args; + typedef enum connection_state { CON_OK, CON_IN_TERMINATED, CON_OUT_TERMINATED, CON_IN_ERROR, CON_OUT_ERROR } connection_state; -static int server_accept_client(server_ctx *ctx[], - size_t siz, struct epoll_event *event); +static int +server_mainloop(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz); +static int server_accept_client(int fd, void *user_data); static void * client_mainloop_epoll(void *arg); static connection_state client_io_epoll(struct epoll_event *ev, int dest_fd); -static int -server_mainloop_epoll(int epoll_fd, server_ctx *ctx[], size_t siz); void server_init_ctx(server_ctx **ctx, forward_ctx *fwd_ctx) @@ -83,53 +86,48 @@ int server_validate_ctx(const server_ctx *ctx) return 0; } -int server_setup_epoll(server_ctx *ctx[], size_t siz) +int server_setup_event(server_ctx *srv_ctx[], size_t siz, event_ctx **ev_ctx) { - int s, fd = epoll_create1(0); /* flags == 0 -> obsolete size arg is dropped */ - struct epoll_event ev; + int s; - assert(ctx); + assert(srv_ctx && ev_ctx); assert(siz > 0 && siz < POTD_MAXFD); - if (fd < 0) - return -1; + event_init(ev_ctx); + if (event_setup(*ev_ctx)) + return 1; for (size_t i = 0; i < siz; ++i) { - memset(&ev, 0, sizeof(ev)); - ev.data.fd = ctx[i]->sock.fd; - ev.events = EPOLLIN | EPOLLET; - - s = socket_addrtostr_in(&ctx[i]->sock, - ctx[i]->host_buf, ctx[i]->service_buf); - if (s) { - E_GAIERR(s, "Convert socket address to string"); - return -2; + if (event_add_sock(*ev_ctx, &srv_ctx[i]->sock)) { + return 1; } - N("Redirector service listening on %s:%s: %d", - ctx[i]->host_buf, ctx[i]->service_buf, ev.data.fd); - s = epoll_ctl(fd, EPOLL_CTL_ADD, ctx[i]->sock.fd, &ev); + s = socket_addrtostr_in(&srv_ctx[i]->sock, + srv_ctx[i]->host_buf, srv_ctx[i]->service_buf); if (s) { - close(fd); - return -3; + E_GAIERR(s, "Convert socket address to string"); + return 1; } + N("Redirector service listening on %s:%s", + srv_ctx[i]->host_buf, srv_ctx[i]->service_buf); } - return fd; + return 0; } -pid_t server_daemonize(int epoll_fd, server_ctx *ctx[], size_t siz) +pid_t server_daemonize(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz) { pid_t p; int s; size_t i; - assert(ctx); - assert(siz > 0); + assert(ev_ctx && srv_ctx); + assert(siz > 0 && siz < POTD_MAXFD); for (i = 0; i < siz; ++i) { - assert(ctx[i]); - s = socket_addrtostr_in(&ctx[i]->sock, - ctx[i]->host_buf, ctx[i]->service_buf); + assert(srv_ctx[i]); + s = socket_addrtostr_in(&srv_ctx[i]->sock, + srv_ctx[i]->host_buf, + srv_ctx[i]->service_buf); if (s) { E_GAIERR(s, "Could not initialise server daemon socket"); return 1; @@ -143,7 +141,7 @@ pid_t server_daemonize(int epoll_fd, server_ctx *ctx[], size_t siz) return -1; case 0: N("%s", "Server daemon mainloop"); - server_mainloop_epoll(epoll_fd, ctx, siz); + server_mainloop(ev_ctx, srv_ctx, siz); break; } D2("Server daemon pid: %d", p); @@ -151,71 +149,41 @@ pid_t server_daemonize(int epoll_fd, server_ctx *ctx[], size_t siz) return p; } -static int server_mainloop_epoll(int epoll_fd, server_ctx *ctx[], size_t siz) +static int server_mainloop(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz) { - static struct epoll_event *events = NULL; - sigset_t eset; - - if (!events) - events = (struct epoll_event *) calloc(POTD_MAXEVENTS, sizeof(*events)); - - assert(events); - assert(ctx); - assert(siz > 0 && siz < POTD_MAXFD); + server_args srv_args = { srv_ctx, siz }; set_procname("[potd] server"); assert( set_child_sighandler() == 0 ); - sigemptyset(&eset); - while (1) { - int n, i; - - n = epoll_pwait(epoll_fd, events, POTD_MAXEVENTS, -1, &eset); - if (n < 0) - goto error; - - for (i = 0; i < n; ++i) { - if ((events[i].events & EPOLLERR) || - (events[i].events & EPOLLHUP) || - (!(events[i].events & EPOLLIN))) - { - E_STRERR("Epoll for descriptor %d failed", events[i].data.fd); - close(events[i].data.fd); - continue; - } else { - if (server_accept_client(ctx, siz, &events[i])) { - /* new client connection, accept succeeded */ - continue; - } - W2("Server accept client failed: [fd: %d , npoll: %d]", events[i].data.fd, n); - } - } - } - - return 0; -error: - return 1; + return event_loop(ev_ctx, server_accept_client, &srv_args); } -static int server_accept_client(server_ctx *ctx[], - size_t siz, struct epoll_event *event) +static int server_accept_client(int fd, void *user_data) { size_t i; int s; + server_args *srv_args = (server_args *) user_data; client_thread_args *args; + server_ctx *srv_ctx; - for (i = 0; i < siz; ++i) { - if (ctx[i]->sock.fd == event->data.fd) { + assert(srv_args); + + for (i = 0; i < srv_args->siz; ++i) { + srv_ctx = srv_args->srv_ctx[i]; + if (srv_ctx->sock.fd == fd) { args = (client_thread_args *) calloc(1, sizeof(*args)); assert(args); - if (socket_accept_in(&ctx[i]->sock, &args->client_psock)) { + if (socket_accept_in(&srv_ctx->sock, + &args->client_psock)) + { E_STRERR("Could not accept client connection on fd %d", - ctx[i]->sock.fd); + srv_ctx->sock.fd); goto error; } - args->server_ctx = ctx[i]; + args->server_ctx = srv_ctx; s = socket_addrtostr_in(&args->client_psock, args->host_buf, args->service_buf); if (s) { @@ -224,7 +192,7 @@ static int server_accept_client(server_ctx *ctx[], } N2("New connection from %s:%s to %s:%s: %d", args->host_buf, args->service_buf, - ctx[i]->host_buf, ctx[i]->service_buf, + srv_ctx->host_buf, srv_ctx->service_buf, args->client_psock.fd); if (pthread_create(&args->self, NULL, diff --git a/src/server.h b/src/server.h index 65e1797..b1163fc 100644 --- a/src/server.h +++ b/src/server.h @@ -3,9 +3,8 @@ #include "socket.h" #include "forward.h" +#include "pevent.h" -#define POTD_MAXFD 32 -#define POTD_MAXEVENTS 64 typedef struct server_ctx { forward_ctx *fwd_ctx; @@ -21,8 +20,8 @@ int server_setup(server_ctx *ctx, int server_validate_ctx(const server_ctx *ctx); -int server_setup_epoll(server_ctx *ctx[], size_t siz); +int server_setup_event(server_ctx *srv_ctx[], size_t siz, event_ctx **ev_ctx); -pid_t server_daemonize(int epoll_fd, server_ctx *ctx[], size_t siz); +pid_t server_daemonize(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz); #endif |