diff options
-rw-r--r-- | src/server.c | 109 |
1 files changed, 101 insertions, 8 deletions
diff --git a/src/server.c b/src/server.c index 6a76f1b..0adf9d6 100644 --- a/src/server.c +++ b/src/server.c @@ -1,3 +1,4 @@ +#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> @@ -20,6 +21,7 @@ static int server_accept_client(const server_ctx ctx[], size_t siz, struct epoll_event *event); static void * client_mainloop_epoll(void *arg); +static int client_io_epoll(struct epoll_event *ev); server_ctx * @@ -144,9 +146,10 @@ static int server_accept_client(const server_ctx ctx[], E_GAIERR(s, "Convert socket address to string"); goto error; } - N("New connection from %s:%s to %s:%s", + N("New connection from %s:%s to %s:%s: %d", args->host_buf, args->service_buf, - ctx[i].host_buf, ctx[i].service_buf); + ctx[i].host_buf, ctx[i].service_buf, + args->client_psock.fd); if (pthread_create(&args->self, NULL, client_mainloop_epoll, args)) @@ -170,8 +173,8 @@ static void * client_mainloop_epoll(void *arg) { client_thread_args *args; - int s, epoll_fd; - struct epoll_event event; + int s, epoll_fd, active = 1; + struct epoll_event event = {0,{0}}; struct epoll_event *events; assert(arg); @@ -181,15 +184,48 @@ client_mainloop_epoll(void *arg) assert(events); epoll_fd = epoll_create1(0); - if (epoll_fd < 0) + if (epoll_fd < 0) { + E_STRERR("Client epoll_create1"); goto finish; + } event.data.fd = args->client_psock.fd; - event.events = EPOLLIN | EPOLLOUT | EPOLLET; - memset(&event, 0, sizeof(event)); + event.events = EPOLLIN | EPOLLET; s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, args->client_psock.fd, &event); - if (s) + if (s) { + E_STRERR("Client epoll_ctl"); goto finish; + } + + while (active) { + int n, i; + + n = epoll_wait(epoll_fd, events, POTD_MAXEVENTS, -1); + if (n < 0) + break; + + for (i = 0; i < n; ++i) { + if ((events[i].events & EPOLLERR) || + (events[i].events & EPOLLHUP) || + (!(events[i].events & EPOLLIN) && + !(events[i].events & EPOLLOUT))) + { + E("Epoll for descriptor %d failed", events[i].data.fd); + E_STRERR("epoll_wait"); + close(events[i].data.fd); + continue; + } else { + if (client_io_epoll(&events[i])) { + N("Lost connection to %s:%s: %d", + args->host_buf, args->service_buf, + args->client_psock.fd); + active = 0; + break; + } + } + W2("I/O forwarder failed: [fd: %d , npoll: %d]", events[i].data.fd, n); + } + } finish: close(epoll_fd); @@ -198,3 +234,60 @@ finish: free(args); return NULL; } + +static int client_io_epoll(struct epoll_event *ev) +{ + int data_avail = 1; + int has_input; + int saved_errno, io_fail = 0; + ssize_t siz; + char buf[BUFSIZ]; + + while (data_avail) { + has_input = 0; + saved_errno = 0; + siz = -1; + + if (ev->events & EPOLLIN) { + has_input = 1; + siz = read(ev->data.fd, &buf[0], BUFSIZ); + saved_errno = errno; + } else if (ev->events & EPOLLOUT) { + W("%s", "Suffering from buffer bloat"); + continue; + } + + switch (siz) { + case -1: + E_STRERR("Client read"); + if (saved_errno != EAGAIN) + io_fail = 1; + break; + case 0: + printf("DISCONNECT !!!\n"); + io_fail = 1; + break; + default: + buf[siz] = 0; + break; + } + + if (io_fail) + break; + + if (has_input) { + printf("INPUT: ___%s___\n", buf); + if (strncmp(buf, "QUIT", 4) == 0) + io_fail = 1; + if (strncmp(buf, "TEST", 4) == 0) { + printf("------------\n"); + write(ev->data.fd, "BLABLABLA\n", 10); + } + } + + if (io_fail) + break; + } + + return io_fail != 0; +} |