diff options
Diffstat (limited to 'server/conn.c')
-rw-r--r-- | server/conn.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/server/conn.c b/server/conn.c new file mode 100644 index 0000000..f167cdd --- /dev/null +++ b/server/conn.c @@ -0,0 +1,139 @@ + +#include <sys/socket.h> +#include <sys/un.h> + +#include <stdio.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ev.h> + +#include "list.h" +#include "conn.h" +#include "lua-privsep.h" + + +#ifndef DEBUG +#define log_debug(x) printf("%s\n", x) +#define log_perror(x) perror(x) +#endif + +static struct ev_io accept_io; + +static void conn_free(struct ev_loop *loop, struct conn *rm) +{ + int fd = rm->io.fd; + + ev_io_stop(loop, &rm->io); + ev_timer_stop(loop, &rm->timeout); + close(fd); + close_lua(rm); + free(rm); + log_debug("Connection closed"); +} + +static void conn_recv_cb (struct ev_loop *loop, struct ev_io *w, + int revents) +{ + struct conn *conn = container_of(w, struct conn, io); + int len, i; + char *args; + + len = recv(conn->io.fd, conn->msg, sizeof(conn->msg) - conn->num_read, + MSG_DONTWAIT); + if (len < 0 && errno == EAGAIN) + return; + if (len <= 0) + goto err; + + conn->num_read += len; + if (conn->num_read >= sizeof(conn->msg)) + goto err; + + call_lua(conn, conn->msg, conn->num_read); + conn->num_read = 0; + return; + +err: + conn_free(loop, conn); +} + +static void conn_timeout_cb (struct ev_loop *loop, struct ev_timer *t, + int revents) +{ + log_debug("Connection timed out"); + conn_free(loop, container_of(t, struct conn, timeout)); +} + +static void conn_accept_cb(struct ev_loop *loop, struct ev_io *w, + int revents) +{ + struct conn *conn; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + int fd; + + fd = accept(w->fd, (struct sockaddr *) &from, &fromlen); + if (fd < 0) { + log_perror("accept"); + return; + } + log_debug("New connection"); + fcntl(fd, F_SETFD, FD_CLOEXEC); + conn = calloc(1, sizeof(struct conn)); + + ev_io_init(&conn->io, conn_recv_cb, fd, EV_READ); + ev_io_start(loop, &conn->io); + ev_timer_init(&conn->timeout, conn_timeout_cb, 10.0, 0.); + ev_timer_start(loop, &conn->timeout); + + init_lua(conn); +} + + +int conn_init(struct ev_loop *loop, const char *socket_path) +{ + struct sockaddr_un sun; + char *p; + int fd; + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, socket_path, sizeof(sun.sun_path)); + + /* create the dir */ + p = strrchr(sun.sun_path, '/'); + if (p) { + *p = '\0'; + mkdir(sun.sun_path, 0755); + *p = '/'; + } + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + log_perror("socket"); + return -1; + } + + fcntl(fd, F_SETFD, FD_CLOEXEC); + unlink(socket_path); + if (bind(fd, (struct sockaddr *) &sun, sizeof(sun)) < 0) + goto perr_close; + + if (listen(fd, 5) < 0) + goto perr_close; + + ev_io_init(&accept_io, conn_accept_cb, fd, EV_READ); + ev_io_start(loop, &accept_io); + return 0; + +perr_close: + log_perror(socket_path); + close(fd); + return -1; + +} |