aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2018-04-13 21:23:34 +0200
committerToni Uhlig <matzeton@googlemail.com>2018-04-13 21:23:34 +0200
commitecf35293f80bba8b83a0dbf28f097812aa4353cb (patch)
tree51f8dea80d0fda06e85b2f910f76a9ea872d2fa5 /src
parent0e9015400269e004d8dbe006d47fa9e4556603ec (diff)
POTD skeleton #3.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/log.h8
-rw-r--r--src/main.c13
-rw-r--r--src/server.c79
-rw-r--r--src/server.h4
-rw-r--r--src/socket.c29
-rw-r--r--src/socket.h2
-rw-r--r--src/thread_mgmt.c62
-rw-r--r--src/thread_mgmt.h15
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
diff --git a/src/log.h b/src/log.h
index 02f56df..cfc4471 100644
--- a/src/log.h
+++ b/src/log.h
@@ -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
diff --git a/src/main.c b/src/main.c
index b0c23b3..099888b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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