summaryrefslogtreecommitdiffstats
path: root/server/conn.c
blob: f167cddc0d9919f23d3a55943398ffcff2942f30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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;

}