aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jail.c9
-rw-r--r--src/pevent.c95
-rw-r--r--src/pevent.h13
-rw-r--r--src/server.c298
4 files changed, 220 insertions, 195 deletions
diff --git a/src/jail.c b/src/jail.c
index 749305e..7bb0f70 100644
--- a/src/jail.c
+++ b/src/jail.c
@@ -21,11 +21,6 @@ typedef struct jail_prisoner_process {
char *newroot;
} jail_prisoner_process;
-typedef enum connection_state {
- CON_OK, CON_IN_TERMINATED, CON_OUT_TERMINATED,
- CON_IN_ERROR, CON_OUT_ERROR
-} connection_state;
-
static int jail_mainloop_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz)
__attribute__((noreturn));
static int jail_accept_client(jail_ctx *ctx[],
@@ -33,7 +28,7 @@ static int jail_accept_client(jail_ctx *ctx[],
static int jail_childfn(jail_prisoner_process *ctx)
__attribute__((noreturn));
static int jail_socket_tty_epoll(jail_prisoner_process *ctx, int tty_fd);
-static connection_state
+static forward_state
jail_socket_tty_io_epoll(struct epoll_event *ev, int dest_fd);
@@ -390,7 +385,7 @@ static int jail_socket_tty_epoll(jail_prisoner_process *ctx, int tty_fd)
return 0;
}
-static connection_state
+static forward_state
jail_socket_tty_io_epoll(struct epoll_event *ev, int dest_fd)
{
return CON_OK;
diff --git a/src/pevent.c b/src/pevent.c
index a8845d3..053564c 100644
--- a/src/pevent.c
+++ b/src/pevent.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -20,6 +21,13 @@ void event_init(event_ctx **ctx)
(*ctx)->epoll_fd = -1;
}
+void event_free(event_ctx **ctx)
+{
+ close((*ctx)->epoll_fd);
+ free((*ctx));
+ *ctx = NULL;
+}
+
int event_setup(event_ctx *ctx)
{
assert(ctx);
@@ -83,16 +91,91 @@ int event_loop(event_ctx *ctx, on_event_cb on_event, void *user_data)
{
E_STRERR("Event epoll for descriptor %d",
ctx->events[i].data.fd);
- close(ctx->events[i].data.fd);
- continue;
+ ctx->active = 0;
+ break;
} 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);
+ ctx->current_event = i;
+ if (!on_event(ctx, ctx->events[i].data.fd, user_data))
+ W2("Event callback failed: [fd: %d , npoll: %d]",
+ ctx->events[i].data.fd, n);
}
+
+ if (!ctx->active)
+ break;
}
}
return ctx->active == 0;
}
+
+forward_state
+event_forward_connection(event_ctx *ctx, int dest_fd)
+{
+ int data_avail = 1;
+ int has_input;
+ int saved_errno;
+ forward_state rc = CON_OK;
+ ssize_t siz;
+ char buf[BUFSIZ+sizeof(long)];
+ struct epoll_event *ev;
+
+ assert(ctx->current_event >= 0 &&
+ ctx->current_event < POTD_MAXEVENTS);
+ ev = &ctx->events[ctx->current_event];
+
+ while (data_avail) {
+ has_input = 0;
+ saved_errno = 0;
+ siz = -1;
+
+ if (ev->events & EPOLLIN) {
+ has_input = 1;
+ errno = 0;
+ siz = read(ev->data.fd, &buf[0], BUFSIZ);
+ saved_errno = errno;
+ } else break;
+
+ if (saved_errno == EAGAIN)
+ break;
+
+ switch (siz) {
+ case -1:
+ E_STRERR("Client read from fd %d", ev->data.fd);
+ rc = CON_IN_ERROR;
+ break;
+ case 0:
+ rc = CON_IN_TERMINATED;
+ break;
+ default:
+ buf[siz] = 0;
+ D2("Read %lu bytes from fd %d", siz, ev->data.fd);
+ break;
+ }
+
+ if (rc != CON_OK)
+ break;
+
+ if (has_input) {
+ siz = write(dest_fd, &buf[0], siz);
+
+ switch (siz) {
+ case -1:
+ rc = CON_OUT_ERROR;
+ break;
+ case 0:
+ rc = CON_OUT_TERMINATED;
+ break;
+ default:
+ D2("Written %lu bytes from fd %d to fd %d",
+ siz, ev->data.fd, dest_fd);
+ break;
+ }
+ }
+
+ if (rc != CON_OK)
+ break;
+ }
+
+ D2("Connection state: %d", rc);
+ return rc;
+}
diff --git a/src/pevent.h b/src/pevent.h
index da09f59..c7b61e1 100644
--- a/src/pevent.h
+++ b/src/pevent.h
@@ -8,17 +8,25 @@
#define POTD_MAXFD 32
#define POTD_MAXEVENTS 64
+typedef enum forward_state {
+ CON_OK, CON_IN_TERMINATED, CON_OUT_TERMINATED,
+ CON_IN_ERROR, CON_OUT_ERROR
+} forward_state;
+
typedef struct event_ctx {
int epoll_fd;
int active;
struct epoll_event events[POTD_MAXEVENTS];
+ int current_event;
} event_ctx;
-typedef int (*on_event_cb) (int fd, void *user_data);
+typedef int (*on_event_cb) (event_ctx *ev_ctx, int fd, void *user_data);
void event_init(event_ctx **ctx);
+void event_free(event_ctx **ctx);
+
int event_setup(event_ctx *ctx);
int event_add_sock(event_ctx *ctx, psocket *sock);
@@ -27,4 +35,7 @@ int event_add_fd(event_ctx *ctx, int fd);
int event_loop(event_ctx *ctx, on_event_cb on_event, void *user_data);
+forward_state
+event_forward_connection(event_ctx *ctx, int dest_fd);
+
#endif
diff --git a/src/server.c b/src/server.c
index 4dd3a94..e0b8738 100644
--- a/src/server.c
+++ b/src/server.c
@@ -13,28 +13,30 @@
typedef struct client_thread_args {
pthread_t self;
- psocket client_psock;
+ psocket client_sock;
char host_buf[NI_MAXHOST], service_buf[NI_MAXSERV];
const server_ctx *server_ctx;
} client_thread_args;
-typedef struct server_args {
- server_ctx **srv_ctx;
- size_t siz;
-} server_args;
+typedef struct server_event {
+ const server_ctx **srv_ctx;
+ const size_t siz;
+} server_event;
-typedef enum connection_state {
- CON_OK, CON_IN_TERMINATED, CON_OUT_TERMINATED,
- CON_IN_ERROR, CON_OUT_ERROR
-} connection_state;
+typedef struct client_event {
+ const psocket *fwd_sock;
+ const client_thread_args *client_args;
+} client_event;
+static forward_state
+fwd_state_string(const forward_state c_state, const client_thread_args *args,
+ const psocket *fwd);
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);
+server_mainloop(event_ctx *ev_ctx, const server_ctx *srv_ctx[], size_t siz);
+static int server_accept_client(event_ctx *ev_ctx, 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);
+client_mainloop(void *arg);
+static int client_io(event_ctx *ev_ctx, int src_fd, void *user_data);
void server_init_ctx(server_ctx **ctx, forward_ctx *fwd_ctx)
@@ -92,6 +94,7 @@ int server_setup_event(server_ctx *srv_ctx[], size_t siz, event_ctx **ev_ctx)
assert(srv_ctx && ev_ctx);
assert(siz > 0 && siz < POTD_MAXFD);
+
event_init(ev_ctx);
if (event_setup(*ev_ctx))
return 1;
@@ -141,7 +144,7 @@ pid_t server_daemonize(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz)
return -1;
case 0:
N("%s", "Server daemon mainloop");
- server_mainloop(ev_ctx, srv_ctx, siz);
+ server_mainloop(ev_ctx, (const server_ctx **) srv_ctx, siz);
break;
}
D2("Server daemon pid: %d", p);
@@ -149,34 +152,73 @@ pid_t server_daemonize(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz)
return p;
}
-static int server_mainloop(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz)
+static forward_state
+fwd_state_string(const forward_state c_state, const client_thread_args *args,
+ const psocket *fwd)
{
- server_args srv_args = { srv_ctx, siz };
+ switch (c_state) {
+ case CON_OK:
+ break;
+ case CON_IN_ERROR:
+ N("Lost connection to %s:%s: %d",
+ args->host_buf, args->service_buf,
+ args->client_sock.fd);
+ break;
+ case CON_IN_TERMINATED:
+ N("Connection terminated: %s:%s: %d",
+ args->host_buf, args->service_buf,
+ args->client_sock.fd);
+ break;
+ case CON_OUT_ERROR:
+ N("Lost forward connection to %s:%s: %d",
+ args->server_ctx->fwd_ctx->host_buf,
+ args->server_ctx->fwd_ctx->service_buf,
+ fwd->fd);
+ break;
+ case CON_OUT_TERMINATED:
+ N("Forward connection terminated: %s:%s: %d",
+ args->server_ctx->fwd_ctx->host_buf,
+ args->server_ctx->fwd_ctx->service_buf,
+ fwd->fd);
+ break;
+ }
+
+ return c_state;
+}
+
+static int server_mainloop(event_ctx *ev_ctx, const server_ctx *srv_ctx[], size_t siz)
+{
+ int rc;
+ server_event ev_srv = { srv_ctx, siz };
set_procname("[potd] server");
assert( set_child_sighandler() == 0 );
- return event_loop(ev_ctx, server_accept_client, &srv_args);
+ rc = event_loop(ev_ctx, server_accept_client, &ev_srv);
+ event_free(&ev_ctx);
+
+ return rc;
}
-static int server_accept_client(int fd, void *user_data)
+static int server_accept_client(event_ctx *ev_ctx, int fd, void *user_data)
{
size_t i;
int s;
- server_args *srv_args = (server_args *) user_data;
+ server_event *ev_srv = (server_event *) user_data;
client_thread_args *args;
- server_ctx *srv_ctx;
+ const server_ctx *srv_ctx;
- assert(srv_args);
+ (void) ev_ctx;
+ assert(ev_srv);
- for (i = 0; i < srv_args->siz; ++i) {
- srv_ctx = srv_args->srv_ctx[i];
+ for (i = 0; i < ev_srv->siz; ++i) {
+ srv_ctx = ev_srv->srv_ctx[i];
if (srv_ctx->sock.fd == fd) {
args = (client_thread_args *) calloc(1, sizeof(*args));
assert(args);
if (socket_accept_in(&srv_ctx->sock,
- &args->client_psock))
+ &args->client_sock))
{
E_STRERR("Could not accept client connection on fd %d",
srv_ctx->sock.fd);
@@ -184,7 +226,7 @@ static int server_accept_client(int fd, void *user_data)
}
args->server_ctx = srv_ctx;
- s = socket_addrtostr_in(&args->client_psock,
+ s = socket_addrtostr_in(&args->client_sock,
args->host_buf, args->service_buf);
if (s) {
E_GAIERR(s, "Convert socket address to string");
@@ -193,20 +235,20 @@ static int server_accept_client(int fd, void *user_data)
N2("New connection from %s:%s to %s:%s: %d",
args->host_buf, args->service_buf,
srv_ctx->host_buf, srv_ctx->service_buf,
- args->client_psock.fd);
+ args->client_sock.fd);
if (pthread_create(&args->self, NULL,
- client_mainloop_epoll, args))
+ client_mainloop, args))
{
E_STRERR("Thread creation for %s:%s on fd %d",
args->host_buf, args->service_buf,
- args->client_psock.fd);
+ args->client_sock.fd);
goto error;
}
return 1;
error:
- socket_close(&args->client_psock);
+ socket_close(&args->client_sock);
free(args);
return 0;
}
@@ -216,25 +258,21 @@ error:
}
static void *
-client_mainloop_epoll(void *arg)
+client_mainloop(void *arg)
{
client_thread_args *args;
- int s, epoll_fd, dest_fd, active = 1;
- struct epoll_event event = {0,{0}};
- struct epoll_event *events;
- sigset_t eset;
- connection_state cs;
+ client_event ev_cli;
+ int s;
+ event_ctx *ev_ctx = NULL;
psocket fwd;
assert(arg);
args = (client_thread_args *) arg;
pthread_detach(args->self);
- events = (struct epoll_event *) calloc(POTD_MAXEVENTS, sizeof(*events));
- assert(events);
- epoll_fd = epoll_create1(0);
- if (epoll_fd < 0) {
- E_STRERR("Client Epoll descriptor creation for server fd %d",
+ event_init(&ev_ctx);
+ if (event_setup(ev_ctx)) {
+ E_STRERR("Client event descriptor creation for server fd %d",
args->server_ctx->sock.fd);
goto finish;
}
@@ -250,11 +288,8 @@ client_mainloop_epoll(void *arg)
args->server_ctx->fwd_ctx->host_buf,
args->server_ctx->fwd_ctx->service_buf, fwd.fd);
- event.data.fd = fwd.fd;
- event.events = EPOLLIN | EPOLLET;
- s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fwd.fd, &event);
- if (s) {
- E_STRERR("Forward Epoll descriptor add to %s:%s forward fd %d",
+ if (event_add_sock(ev_ctx, &fwd)) {
+ E_STRERR("Forward event descriptor add to %s:%s forward fd %d",
args->server_ctx->fwd_ctx->host_buf,
args->server_ctx->fwd_ctx->service_buf, fwd.fd);
goto finish;
@@ -264,160 +299,61 @@ client_mainloop_epoll(void *arg)
* We got the client socket from our main thread, so fd flags like
* O_NONBLOCK are not inherited!
*/
- s = socket_nonblock(&args->client_psock);
+ s = socket_nonblock(&args->client_sock);
if (s) {
E_STRERR("Socket non blocking mode to %s:%s forward fd %d",
args->server_ctx->fwd_ctx->host_buf,
args->server_ctx->fwd_ctx->service_buf, fwd.fd);
goto finish;
}
- event.data.fd = args->client_psock.fd;
- event.events = EPOLLIN | EPOLLET;
-
- s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, args->client_psock.fd, &event);
- if (s) {
- E_STRERR("Forward Epoll descriptor add to %s:%s forward fd %d",
+ if (event_add_sock(ev_ctx, &args->client_sock)) {
+ E_STRERR("Forward event descriptor add to %s:%s forward fd %d",
args->server_ctx->fwd_ctx->host_buf,
args->server_ctx->fwd_ctx->service_buf, fwd.fd);
goto finish;
}
- sigemptyset(&eset);
-
- while (active) {
- int n, i;
-
- n = epoll_pwait(epoll_fd, events, POTD_MAXEVENTS, -1, &eset);
- if (n < 0)
- break;
-
- 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", events[i].data.fd);
- active = 0;
- break;
- } else {
- if (events[i].data.fd == fwd.fd) {
- dest_fd = args->client_psock.fd;
- } else if (events[i].data.fd == args->client_psock.fd) {
- dest_fd = fwd.fd;
- } else continue;
-
- cs = client_io_epoll(&events[i], dest_fd);
- if (cs == CON_OK)
- continue;
-
- switch (cs) {
- case CON_OK:
- break;
- case CON_IN_ERROR:
- N("Lost connection to %s:%s: %d",
- args->host_buf, args->service_buf,
- args->client_psock.fd);
- active = 0;
- break;
- case CON_IN_TERMINATED:
- N("Connection terminated: %s:%s: %d",
- args->host_buf, args->service_buf,
- args->client_psock.fd);
- active = 0;
- break;
- case CON_OUT_ERROR:
- N("Lost forward connection to %s:%s: %d",
- args->server_ctx->fwd_ctx->host_buf,
- args->server_ctx->fwd_ctx->service_buf,
- fwd.fd);
- active = 0;
- break;
- case CON_OUT_TERMINATED:
- N("Forward connection terminated: %s:%s: %d",
- args->server_ctx->fwd_ctx->host_buf,
- args->server_ctx->fwd_ctx->service_buf,
- fwd.fd);
- active = 0;
- break;
- }
- if (!active)
- break;
- }
- W2("I/O forwarder failed: [fd: %d , npoll: %d]", events[i].data.fd, n);
- }
- }
+ ev_cli.client_args = args;
+ ev_cli.fwd_sock = &fwd;
+ event_loop(ev_ctx, client_io, &ev_cli);
finish:
- close(epoll_fd);
+ event_free(&ev_ctx);
socket_close(&fwd);
- socket_close(&args->client_psock);
- free(events);
+ socket_close(&args->client_sock);
free(args);
return NULL;
}
-static connection_state
-client_io_epoll(struct epoll_event *ev, int dest_fd)
+static int
+client_io(event_ctx *ev_ctx, int src_fd, void *user_data)
{
- int data_avail = 1;
- int has_input;
- int saved_errno;
- connection_state rc = CON_OK;
- ssize_t siz;
- char buf[BUFSIZ+sizeof(long)];
-
- while (data_avail) {
- has_input = 0;
- saved_errno = 0;
- siz = -1;
-
- if (ev->events & EPOLLIN) {
- has_input = 1;
- errno = 0;
- siz = read(ev->data.fd, &buf[0], BUFSIZ);
- saved_errno = errno;
- } else break;
- if (saved_errno == EAGAIN)
- break;
-
- switch (siz) {
- case -1:
- E_STRERR("Client read from fd %d", ev->data.fd);
- rc = CON_IN_ERROR;
- break;
- case 0:
- rc = CON_IN_TERMINATED;
- break;
- default:
- buf[siz] = 0;
- D2("Read %lu bytes from fd %d", siz, ev->data.fd);
- break;
- }
-
- if (rc != CON_OK)
- break;
-
- if (has_input) {
- siz = write(dest_fd, &buf[0], siz);
-
- switch (siz) {
- case -1:
- rc = CON_OUT_ERROR;
- break;
- case 0:
- rc = CON_OUT_TERMINATED;
- break;
- default:
- D2("Written %lu bytes from fd %d to fd %d",
- siz, ev->data.fd, dest_fd);
- break;
- }
- }
-
- if (rc != CON_OK)
- break;
+ int dest_fd;
+ client_event *ev_cli = (client_event *) user_data;
+ const psocket *client_sock = &ev_cli->client_args->client_sock;
+ forward_state fwd_state;
+
+ if (src_fd == ev_cli->fwd_sock->fd) {
+ dest_fd = client_sock->fd;
+ } else if (src_fd == client_sock->fd) {
+ dest_fd = ev_cli->fwd_sock->fd;
+ } else return 0;
+
+ fwd_state = event_forward_connection(ev_ctx, dest_fd);
+
+ switch (fwd_state_string(fwd_state, ev_cli->client_args,
+ ev_cli->fwd_sock))
+ {
+ case CON_IN_TERMINATED:
+ case CON_OUT_TERMINATED:
+ ev_ctx->active = 0;
+ case CON_OK:
+ return 1;
+ case CON_IN_ERROR:
+ case CON_OUT_ERROR:
+ ev_ctx->active = 0;
+ return 0;
}
- D2("Connection state: %d", rc);
- return rc;
+ return 1;
}