summaryrefslogtreecommitdiffstats
path: root/server/conn.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/conn.c')
-rw-r--r--server/conn.c139
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;
+
+}