diff options
Diffstat (limited to 'src/tcp_server.c')
-rw-r--r-- | src/tcp_server.c | 92 |
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; +} |