summaryrefslogtreecommitdiffstats
path: root/bin/conn.c
blob: f953d09af4f14a64caa86c6a2603ce94014a2291 (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
140
141
142
143
144
145

#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

#ifndef MSG_MAX_SIZE
#define MSG_MAX_SIZE 16386
#endif

static struct ev_io accept_io;

struct conn {
        struct ev_io io;
        struct ev_timer timeout;
        size_t num_read;
	char msg[MSG_MAX_SIZE];
};

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);
	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->io.fd, conn->msg, conn->num_read);

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);
}


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;

}