diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2018-04-13 21:23:34 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2018-04-13 21:23:34 +0200 |
commit | ecf35293f80bba8b83a0dbf28f097812aa4353cb (patch) | |
tree | 51f8dea80d0fda06e85b2f910f76a9ea872d2fa5 /src | |
parent | 0e9015400269e004d8dbe006d47fa9e4556603ec (diff) |
POTD skeleton #3.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/log.h | 8 | ||||
-rw-r--r-- | src/main.c | 13 | ||||
-rw-r--r-- | src/server.c | 79 | ||||
-rw-r--r-- | src/server.h | 4 | ||||
-rw-r--r-- | src/socket.c | 29 | ||||
-rw-r--r-- | src/socket.h | 2 | ||||
-rw-r--r-- | src/thread_mgmt.c | 62 | ||||
-rw-r--r-- | src/thread_mgmt.h | 15 |
9 files changed, 194 insertions, 24 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index db612f1..04678c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ -AM_CFLAGS = -pedantic -Wall -std=gnu99 -D_GNU_SOURCE=1 -AM_LDFLAGS = -lssh +AM_CFLAGS = -pedantic -Wall -std=gnu99 -D_GNU_SOURCE=1 $(libssh_CFLAGS) +AM_LDFLAGS = $(libssh_LIBS) sbin_PROGRAMS = potd -potd_SOURCES = main.c utils.c log.c log_colored.c socket.c server.c server_ssh.c +potd_SOURCES = main.c utils.c log.c log_colored.c thread_mgmt.c socket.c server.c server_ssh.c @@ -24,9 +24,13 @@ #define E_STRERR(msg) { if (errno) E2("%s failed: %s", msg, strerror(errno)); } #define E_GAIERR(ret, msg) { if (ret) { E2("%s failed: %s", msg, gai_strerror(ret)); } } #define ABORT_ON_FATAL(expr, msg) \ - { errno = 0; if (expr) { E_STRERR(msg); abort(); } } + { errno = 0; long rv = (long) expr; \ + if (rv) { E2("`%s` returned: %ld", #expr, rv); \ + E_STRERR(msg); abort(); } } #define GAI_ABORT_ON_FATAL(expr, msg) \ - { int rv = expr; if (rv) { E_GAIERR(rv, msg); abort(); } } + { int rv = expr; \ + if (rv) { E2("`%s` returned: %d", #expr, rv); \ + E_GAIERR(rv, msg); abort(); } } typedef enum log_priority { DEBUG = 0, NOTICE, WARNING, ERROR @@ -1,5 +1,6 @@ #include "log.h" #include "log_colored.h" +#include "thread_mgmt.h" #include "server.h" #include "server_ssh.h" #ifdef HAVE_CONFIG_H @@ -20,12 +21,13 @@ int main(int argc, char *argv[]) LOG_SET_FUNCS_VA(LOG_COLORED_FUNCS); N("%s (C) 2018 Toni Uhlig (%s)", PACKAGE_STRING, PACKAGE_BUGREPORT); + thread_manager_init(8); memset(&srv[0], 0, sizeof(srv)); ssh_ports[0] = "2222"; ssh_ports[1] = "2223"; ssh_ports[2] = "22050"; - for (int i = 0; i < srv_siz; ++i) { + for (size_t i = 0; i < srv_siz; ++i) { N("Initialising SSH server on port %s", ssh_ports[i]); ABORT_ON_FATAL( server_init_ctx(&srv[i], ssh_init_cb), @@ -46,11 +48,12 @@ int main(int argc, char *argv[]) } D2("%s", "Server epoll setup"); - epoll_fd = server_setup_epoll( (const server_ctx **) &srv, srv_siz ); - ABORT_ON_FATAL( epoll_fd >= 0, "Server epoll setup" ); + epoll_fd = server_setup_epoll( &srv[0], srv_siz ); + D2("epoll_fd: %d", epoll_fd); + ABORT_ON_FATAL( epoll_fd < 0, "Server epoll setup" ); - D2("%s", "Server epoll mainloop"); - ABORT_ON_FATAL( server_mainloop_epoll( epoll_fd, (const server_ctx **) &srv, srv_siz ), + N("%s", "Server epoll mainloop"); + ABORT_ON_FATAL( server_mainloop_epoll( epoll_fd, &srv[0], srv_siz ), "Server epoll mainloop" ); return 0; } diff --git a/src/server.c b/src/server.c index 6c0a7a2..6c32a85 100644 --- a/src/server.c +++ b/src/server.c @@ -5,6 +5,18 @@ #include <assert.h> #include "server.h" +#include "socket.h" +#include "log.h" + +typedef struct client_thread_args { + int client_fd; + server_ctx *server_ctx; +} client_thread_args; + +static int server_accept_client(const server_ctx ctx[], + size_t siz, struct epoll_event *event); +static void * +client_mainloop_epoll(void *arg); server_ctx * @@ -31,7 +43,7 @@ int server_validate_ctx(const server_ctx *ctx) return 0; } -int server_setup_epoll(const server_ctx *ctx[], size_t siz) +int server_setup_epoll(const server_ctx ctx[], size_t siz) { int s; int fd = epoll_create1(0); /* flags == 0 -> obsolete size arg is dropped */ @@ -42,35 +54,86 @@ int server_setup_epoll(const server_ctx *ctx[], size_t siz) if (fd < 0) return -1; - for (int i = 0; i < siz; ++i) { + for (size_t i = 0; i < siz; ++i) { memset(&ev, 0, sizeof(ev)); - ev.data.fd = ctx[i]->sock.fd; + ev.data.fd = ctx[i].sock.fd; ev.events = EPOLLIN | EPOLLET; - s = epoll_ctl(fd, EPOLL_CTL_ADD, ctx[i]->sock.fd, &ev); + s = epoll_ctl(fd, EPOLL_CTL_ADD, ctx[i].sock.fd, &ev); if (s) { close(fd); - return -1; + return -2; } } return fd; } -int server_mainloop_epoll(int epoll_fd, const server_ctx *ctx[], size_t siz) +int server_mainloop_epoll(int epoll_fd, const server_ctx ctx[], size_t siz) { - struct epoll_event *events = calloc(POTD_MAXEVENTS, sizeof(*events)); + static struct epoll_event *events = NULL; + + if (!events) + events = (struct epoll_event *) calloc(POTD_MAXEVENTS, sizeof(*events)); assert(events); assert(ctx); assert(siz > 0 && siz < POTD_MAXFD); while (1) { - int n; + int n, i; n = epoll_wait(epoll_fd, events, POTD_MAXEVENTS, -1); + if (n < 0) + return 1; + + for (i = 0; i < n; ++i) { + if ((events[i].events & EPOLLERR) || + (events[i].events & EPOLLHUP) || + (!(events[i].events & EPOLLIN))) + { + E("Epoll for descriptor %d failed", events[i].data.fd); + E_STRERR("epoll_wait"); + close(events[i].data.fd); + continue; + } else { + if (server_accept_client(ctx, siz, &events[i])) { + /* new client connection, accept succeeded */ + continue; + } + D2("FD: %d/%lu , %d", events[i].data.fd, siz, n); + } + } } free(events); return 0; } + +static int server_accept_client(const server_ctx ctx[], + size_t siz, struct epoll_event *event) +{ + size_t i; + int client_fd; + struct sockaddr_in clientaddr; + + for (i = 0; i < siz; ++i) { + if (ctx[i].sock.fd == event->data.fd) { + client_fd = socket_accept_in(&ctx[i].sock, &clientaddr); + if (client_fd < 0) { + E_STRERR("Could not accept client connection"); + } else { + return 1; + } + } + } + + return 0; +} + +static void * +client_mainloop_epoll(void *arg) +{ + (void) arg; + return NULL; +} diff --git a/src/server.h b/src/server.h index 9cf2af9..93343b9 100644 --- a/src/server.h +++ b/src/server.h @@ -44,8 +44,8 @@ server_init_ctx(server_ctx *ctx, init_cb init_fn); int server_validate_ctx(const server_ctx *ctx); -int server_setup_epoll(const server_ctx *ctx[], size_t siz); +int server_setup_epoll(const server_ctx ctx[], size_t siz); -int server_mainloop_epoll(int epoll_fd, const server_ctx *ctx[], size_t siz); +int server_mainloop_epoll(int epoll_fd, const server_ctx ctx[], size_t siz); #endif diff --git a/src/socket.c b/src/socket.c index 7edbda2..e7a4e2d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <unistd.h> +#include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> @@ -9,7 +10,7 @@ #include "socket.h" -static int socket_nonblock(psocket *psocket) +static int socket_nonblock(const psocket *psocket) { int flags; @@ -25,10 +26,12 @@ static int socket_nonblock(psocket *psocket) int socket_init_in(psocket *psocket, const char *listen_addr, const char *listen_port, struct addrinfo **results) { - struct addrinfo hints = {0}; + struct addrinfo hints; assert(psocket); assert(listen_addr || listen_port); /* getaddrinfo wants either node or service */ + + memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* IPV4 && IPV6 */ hints.ai_socktype = SOCK_STREAM; /* TCP */ hints.ai_flags = AI_PASSIVE; /* all interfaces */ @@ -38,7 +41,7 @@ int socket_init_in(psocket *psocket, const char *listen_addr, int socket_bind_in(psocket *psocket, struct addrinfo *results) { - int fd = -1, rv; + int fd = -1, rv, reuse_enable = 1; struct addrinfo *rp = NULL; assert(psocket && results); @@ -48,7 +51,7 @@ int socket_bind_in(psocket *psocket, struct addrinfo *results) if (fd < 0) continue; rv = bind(fd, rp->ai_addr, rp->ai_addrlen); - if (!rv) + if (!rv) break; close(fd); } @@ -56,6 +59,8 @@ int socket_bind_in(psocket *psocket, struct addrinfo *results) if (!rp) return -1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_enable, sizeof(int)) < 0) + return -2; psocket->fd = fd; psocket->addr = *rp; freeaddrinfo(results); @@ -68,3 +73,19 @@ int socket_listen_in(psocket *psocket) return listen(psocket->fd, POTD_BACKLOG); } + +int socket_accept_in(const psocket *psocket, struct sockaddr_in *clientaddr) +{ + int fd; + socklen_t addr_len = {0}; + + assert(psocket && clientaddr); + + fd = accept(psocket->fd, (struct sockaddr*) clientaddr, &addr_len); + if (fd < 0) + return -1; + if (socket_nonblock(psocket)) + return -2; + + return fd; +} diff --git a/src/socket.h b/src/socket.h index 289c4f1..b523744 100644 --- a/src/socket.h +++ b/src/socket.h @@ -18,4 +18,6 @@ int socket_bind_in(psocket *psocket, struct addrinfo *results); int socket_listen_in(psocket *psocket); +int socket_accept_in(const psocket *psocket, struct sockaddr_in *clientaddr); + #endif diff --git a/src/thread_mgmt.c b/src/thread_mgmt.c new file mode 100644 index 0000000..6a7934e --- /dev/null +++ b/src/thread_mgmt.c @@ -0,0 +1,62 @@ +#include <stdlib.h> +#include <pthread.h> +#include <assert.h> + +#include "thread_mgmt.h" + +typedef struct thread_ctx { + int used; + pthread_t thread; + thread_cb fn; + void *user_data; +} thread_ctx; + +static size_t max_threads = 0; +static thread_ctx *threads = NULL; +static pthread_mutex_t list_mtx = PTHREAD_MUTEX_INITIALIZER; + +static void * +thread_fn(void *arg); + + +void thread_manager_init(size_t __max_threads) +{ + max_threads = __max_threads; + assert(max_threads > 0); + assert(!threads); + threads = (thread_ctx *) calloc(max_threads, sizeof(thread_ctx)); + assert(threads); +} + +int thread_add(thread_cb fn, void *user_data) +{ + int rv = -1; + + assert(fn); + pthread_mutex_lock(&list_mtx); + for (size_t i = 0; i < max_threads; ++i) { + if (threads[i].used) + continue; + threads[i].used = 1; + threads[i].fn = fn; + threads[i].user_data = user_data; + rv = pthread_create(&threads[i].thread, NULL, &thread_fn, &threads[i]); + } + pthread_mutex_unlock(&list_mtx); + return rv; +} + +void thread_manager_free(void) +{ + assert(threads); + free(threads); + threads = NULL; + max_threads = 0; +} + +static void * +thread_fn(void *arg) +{ + (void) arg; + return NULL; +} diff --git a/src/thread_mgmt.h b/src/thread_mgmt.h new file mode 100644 index 0000000..c9de258 --- /dev/null +++ b/src/thread_mgmt.h @@ -0,0 +1,15 @@ +#ifndef POTD_THREAD_MGMT +#define POTD_THREAD_MGMT 1 + +#include <stdlib.h> + +typedef int (*thread_cb) (void *user_data); + + +void thread_manager_init(size_t max_threads); + +int thread_add(thread_cb fn, void *user_data); + +void thread_manager_free(void); + +#endif |