#include #include #include #include #include #include #include #include #include #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; }