aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/tcp_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcp_server.c')
-rw-r--r--src/tcp_server.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/tcp_server.c b/src/tcp_server.c
new file mode 100644
index 0000000..dc7d47b
--- /dev/null
+++ b/src/tcp_server.c
@@ -0,0 +1,92 @@
+#include "tcp_server.h"
+#include "log.h"
+#include "net.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int tcp_server_create(struct tcp_server *server, const char *port)
+{
+ server->fd = net_bind(port);
+ if (server->fd < 0)
+ return server->fd;
+
+ return 0;
+}
+
+void tcp_server_destroy(const struct tcp_server *server)
+{
+ close(server->fd);
+}
+
+struct child_context {
+ int fd;
+ tcp_server_conn_handler handler;
+ void *arg;
+};
+
+static void *connection_thread(void *_ctx)
+{
+ struct child_context *ctx = (struct child_context *)_ctx;
+ ctx->handler(ctx->fd, ctx->arg);
+ close(ctx->fd);
+ free(ctx);
+ return NULL;
+}
+
+int tcp_server_accept(const struct tcp_server *server, tcp_server_conn_handler handler, void *arg)
+{
+ struct child_context *ctx;
+ pthread_attr_t child_attr;
+ pthread_t child;
+ int conn_fd, ret = 0;
+
+ ret = net_accept(server->fd);
+ if (ret < 0) {
+ print_errno("accept");
+ return ret;
+ }
+ conn_fd = ret;
+
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx) {
+ print_errno("malloc");
+ ret = -1;
+ goto close_conn;
+ }
+ *ctx = (struct child_context){conn_fd, handler, arg};
+
+ ret = pthread_attr_init(&child_attr);
+ if (ret < 0) {
+ print_errno("pthread_attr_init");
+ goto free_ctx;
+ }
+
+ ret = pthread_attr_setdetachstate(&child_attr, PTHREAD_CREATE_DETACHED);
+ if (ret < 0) {
+ print_errno("pthread_attr_setdetachstate");
+ goto destroy_attr;
+ }
+
+ ret = pthread_create(&child, &child_attr, connection_thread, ctx);
+ if (ret < 0) {
+ print_errno("pthread_create");
+ goto destroy_attr;
+ }
+
+ pthread_attr_destroy(&child_attr);
+
+ return ret;
+
+destroy_attr:
+ pthread_attr_destroy(&child_attr);
+
+free_ctx:
+ free(ctx);
+
+close_conn:
+ close(conn_fd);
+
+ return ret;
+}