Ejemplo n.º 1
0
Archivo: stream.c Proyecto: esmil/lem
static int
stream_close(lua_State *T)
{
	struct stream *s;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	s = lua_touserdata(T, 1);
	if (!s->open)
		return io_closed(T);
	if (s->r.data != NULL) {
		ev_io_stop(LEM_ &s->r);
		lem_queue(s->r.data, io_closed(s->r.data));
		s->r.data = NULL;
	}
	if (s->w.data != NULL) {
		ev_io_stop(LEM_ &s->w);
		lem_queue(s->w.data, io_closed(s->w.data));
		s->w.data = NULL;
	}

	s->open = 0;
	if (close(s->r.fd))
		return io_strerror(T, errno);

	lua_pushboolean(T, 1);
	return 1;
}
Ejemplo n.º 2
0
Archivo: server.c Proyecto: esmil/lem
static int
server_close(lua_State *T)
{
	struct ev_io *w;
	int ret;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	w = lua_touserdata(T, 1);
	if (w->fd < 0)
		return io_closed(T);

	if (w->data != NULL) {
		lem_debug("interrupting listen");
		ev_io_stop(LEM_ w);
		lua_pushnil(w->data);
		lua_pushliteral(w->data, "interrupted");
		lem_queue(w->data, 2);
		w->data = NULL;
	}

	lem_debug("closing server..");

	ret = close(w->fd);
	w->fd = -1;
	if (ret)
		return io_strerror(T, errno);

	lua_pushboolean(T, 1);
	return 1;
}
Ejemplo n.º 3
0
Archivo: server.c Proyecto: esmil/lem
static int
server_accept(lua_State *T)
{
	struct ev_io *w;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	w = lua_touserdata(T, 1);
	if (w->fd < 0)
		return io_closed(T);
	if (w->data != NULL)
		return io_busy(T);

	switch (server__accept(T, w, lua_upvalueindex(1))) {
	case 1:
		return 1;
	case 2:
		close(w->fd);
		w->fd= -1;
		return 2;
	}

	w->cb = server_accept_cb;
	w->data = T;
	ev_io_start(LEM_ w);
	lua_settop(T, 1);
	lua_pushvalue(T, lua_upvalueindex(1));
	return lua_yield(T, 2);
}
Ejemplo n.º 4
0
Archivo: server.c Proyecto: esmil/lem
static int
server_autospawn(lua_State *T)
{
	struct ev_io *w;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	luaL_checktype(T, 2, LUA_TFUNCTION);

	w = lua_touserdata(T, 1);
	if (w->fd < 0)
		return io_closed(T);
	if (w->data != NULL)
		return io_busy(T);

	w->cb = server_autospawn_cb;
	w->data = T;
	ev_io_start(LEM_ w);

	lem_debug("yielding");

	/* yield server object, function and metatable*/
	lua_settop(T, 2);
	lua_pushvalue(T, lua_upvalueindex(1));
	return lua_yield(T, 3);
}
Ejemplo n.º 5
0
Archivo: file.c Proyecto: halfd/lem
static int
file_seek(lua_State *T)
{
	static const int mode[] = { SEEK_SET, SEEK_CUR, SEEK_END };
	static const char *const modenames[] = { "set", "cur", "end", NULL };
	struct file *f;
	int op;
	lua_Number offset;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	op = luaL_checkoption(T, 2, "cur", modenames);
	offset = luaL_optnumber(T, 3, 0.);
	f = lua_touserdata(T, 1);
	f->seek.offset = (off_t)offset;
	luaL_argcheck(T, (lua_Number)f->seek.offset == offset, 3,
			"not an integer in proper range");
	if (f->fd < 0)
		return io_closed(T);
	if (f->T != NULL)
		return io_busy(T);

	/* flush input buffer */
	lem_inputbuf_init(&f->buf);

	f->T = T;
	f->seek.whence = mode[op];
	lem_async_do(&f->a, file_seek_work, file_seek_reap);

	lua_settop(T, 1);
	return lua_yield(T, 1);
}
Ejemplo n.º 6
0
Archivo: file.c Proyecto: halfd/lem
static int
file_readp(lua_State *T)
{
	struct file *f;
	struct lem_parser *p;
	int ret;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	ret = lua_type(T, 2);
	if (ret != LUA_TUSERDATA && ret != LUA_TLIGHTUSERDATA)
		return luaL_argerror(T, 2, "expected userdata");

	f = lua_touserdata(T, 1);
	if (f->fd < 0)
		return io_closed(T);
	if (f->T != NULL)
		return io_busy(T);

	p = lua_touserdata(T, 2);
	if (p->init)
		p->init(T, &f->buf);

	ret = p->process(T, &f->buf);
	if (ret > 0)
		return ret;

	f->T = T;
	f->readp.p = p;
	lem_async_do(&f->a, file_readp_work, file_readp_reap);
	return lua_yield(T, lua_gettop(T));
}
Ejemplo n.º 7
0
Archivo: stream.c Proyecto: esmil/lem
static void
stream_readp_cb(EV_P_ struct ev_io *w, int revents)
{
	struct stream *s = STREAM_FROM_WATCH(w, r);
	lua_State *T = s->r.data;
	int ret;

	(void)revents;

	if (!s->open) {
		ret = 0;
		if (s->p->destroy)
			ret = s->p->destroy(T, &s->buf, LEM_PCLOSED);
		if (ret <= 0)
			ret = io_closed(T);
	} else {
		ret = stream__readp(T, s);
		if (ret == 0)
			return;
	}

	ev_io_stop(EV_A_ &s->r);
	s->r.data = NULL;
	lem_queue(T, ret);
}
Ejemplo n.º 8
0
Archivo: stream.c Proyecto: esmil/lem
/*
 * stream:write() method
 */
static int
stream__write(lua_State *T, struct stream *s)
{
	ssize_t bytes;
	int err;

	while ((bytes = write(s->w.fd, s->out, s->out_len)) > 0) {
		lem_debug("wrote %ld bytes to fd %d", bytes, s->w.fd);
		s->out += bytes;
		s->out_len -= bytes;
		while (s->out_len == 0) {
			if (s->idx == lua_gettop(T)) {
				lua_pushboolean(T, 1);
				return 1;
			}
			s->out = lua_tolstring(T, ++s->idx, &s->out_len);
		}
	}
	err = errno;
	lem_debug("wrote %ld bytes to fd %d", bytes, s->w.fd);

	if (bytes < 0 && (err == EAGAIN || err == EINTR))
		return 0;

	s->open = 0;
	close(s->w.fd);

	if (bytes == 0 || err == ECONNRESET || err == EPIPE)
		return io_closed(T);

	return io_strerror(T, err);
}
Ejemplo n.º 9
0
Archivo: file.c Proyecto: halfd/lem
static int
file_close(lua_State *T)
{
	struct file *f;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	f = lua_touserdata(T, 1);
	if (f->fd < 0)
		return io_closed(T);
	if (f->T != NULL)
		return io_busy(T);

	f->T = T;
	lem_async_do(&f->a, file_close_work, file_close_reap);
	lua_settop(T, 1);
	return lua_yield(T, 1);
}
Ejemplo n.º 10
0
Archivo: stream.c Proyecto: esmil/lem
static int
stream_setcork(lua_State *T, int state)
{
	struct stream *s;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	s = lua_touserdata(T, 1);
	if (!s->open)
		return io_closed(T);
	if (s->w.data != NULL)
		return io_busy(T);

	if (setsockopt(s->w.fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(int)))
		return io_strerror(T, errno);

	lua_pushboolean(T, 1);
	return 1;
}
Ejemplo n.º 11
0
Archivo: stream.c Proyecto: esmil/lem
static int
stream_write(lua_State *T)
{
	struct stream *s;
	const char *out;
	size_t out_len;
	int idx;
	int i;
	int top;
	int ret;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	top = lua_gettop(T);
	idx = 1;
	do {
		out = luaL_checklstring(T, ++idx, &out_len);
	} while (out_len == 0 && idx < top);
	for (i = idx+1; i <= top; i++)
		(void)luaL_checkstring(T, i);

	s = lua_touserdata(T, 1);
	if (!s->open)
		return io_closed(T);
	if (s->w.data != NULL)
		return io_busy(T);
	if (out_len == 0) {
		lua_pushboolean(T, 1);
		return 1;
	}

	s->out = out;
	s->out_len = out_len;
	s->idx = idx;
	ret = stream__write(T, s);
	if (ret > 0)
		return ret;

	s->w.data = T;
	s->w.cb = stream_write_cb;
	ev_io_start(LEM_ &s->w);
	return lua_yield(T, top);
}
Ejemplo n.º 12
0
Archivo: stream.c Proyecto: esmil/lem
/*
 * stream:readp() method
 */
static int
stream__readp(lua_State *T, struct stream *s)
{
	ssize_t bytes;
	int ret;
	int err;
	enum lem_preason res;

	while ((bytes = read(s->r.fd, s->buf.buf + s->buf.end,
					LEM_INPUTBUF_SIZE - s->buf.end)) > 0) {
		lem_debug("read %ld bytes from %d", bytes, s->r.fd);

		s->buf.end += bytes;

		ret = s->p->process(T, &s->buf);
		if (ret > 0)
			return ret;
	}
	err = errno;
	lem_debug("read %ld bytes from %d", bytes, s->r.fd);

	if (bytes < 0 && (err == EAGAIN || err == EINTR))
		return 0;

	if (bytes == 0 || err == ECONNRESET || err == EPIPE)
		res = LEM_PCLOSED;
	else
		res = LEM_PERROR;

	s->open = 0;
	close(s->r.fd);

	if (s->p->destroy && (ret = s->p->destroy(T, &s->buf, res)) > 0)
		return ret;

	lua_settop(T, 0);
	if (res == LEM_PCLOSED)
		return io_closed(T);

	return io_strerror(T, err);
}
Ejemplo n.º 13
0
Archivo: stream.c Proyecto: esmil/lem
static void
stream_write_cb(EV_P_ struct ev_io *w, int revents)
{
	struct stream *s = STREAM_FROM_WATCH(w, w);
	lua_State *T = s->w.data;
	int ret;

	(void)revents;

	if (!s->open)
		ret = io_closed(T);
	else {
		ret = stream__write(T, s);
		if (ret == 0)
			return;
	}

	ev_io_stop(EV_A_ &s->w);
	s->w.data = NULL;
	lem_queue(T, ret);
}
Ejemplo n.º 14
0
Archivo: stream.c Proyecto: esmil/lem
static int
stream_sendfile(lua_State *T)
{
	struct stream *s;
	struct file *f;
	off_t size;
	off_t offset;
	struct sfhandle *sf;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	luaL_checktype(T, 2, LUA_TUSERDATA);
	size = (off_t)luaL_checknumber(T, 3);
	offset = (off_t)luaL_optnumber(T, 4, 0);

	s = lua_touserdata(T, 1);
	if (!s->open)
		return io_closed(T);
	if (s->w.data != NULL)
		return io_busy(T);

	f = lua_touserdata(T, 2);
	if (f->fd < 0) {
		lua_pushnil(T);
		lua_pushliteral(T, "file closed");
		return 2;
	}

	s->w.data = T;

	sf = lem_xmalloc(sizeof(struct sfhandle));
	sf->T = T;
	sf->s = s;
	sf->size = size;
	sf->offset = offset;
	sf->fd = f->fd;
	lem_async_do(&sf->a, stream_sendfile_work, stream_sendfile_reap);

	lua_settop(T, 2);
	return lua_yield(T, 2);
}
Ejemplo n.º 15
0
Archivo: file.c Proyecto: halfd/lem
static int
file_write(lua_State *T)
{
	struct file *f;
	const char *str;
	size_t len;
	int idx;
	int i;
	int top;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	top = lua_gettop(T);
	idx = 1;
	do {
		str = luaL_checklstring(T, ++idx, &len);
	} while (len == 0 && idx < top);
	for (i = idx+1; i <= top; i++)
		(void)luaL_checkstring(T, i);

	f = lua_touserdata(T, 1);
	if (f->fd < 0)
		return io_closed(T);
	if (f->T != NULL)
		return io_busy(T);
	if (len == 0) {
		lua_pushboolean(T, 1);
		return 1;
	}

	f->T = T;
	f->write.str = str;
	f->write.len = len;
	f->write.idx = idx;
	lem_async_do(&f->a, file_write_work, file_write_reap);

	return lua_yield(T, top);
}
Ejemplo n.º 16
0
Archivo: stream.c Proyecto: esmil/lem
static int
stream_readp(lua_State *T)
{
	struct stream *s;
	struct lem_parser *p;
	int ret;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	ret = lua_type(T, 2);
	if (ret != LUA_TUSERDATA && ret != LUA_TLIGHTUSERDATA)
		return luaL_argerror(T, 2, "expected userdata");

	s = lua_touserdata(T, 1);
	if (!s->open)
		return io_closed(T);
	if (s->r.data != NULL)
		return io_busy(T);

	p = lua_touserdata(T, 2);
	if (p->init)
		p->init(T, &s->buf);

	ret = p->process(T, &s->buf);
	if (ret > 0)
		return ret;

	s->p = p;
	ret = stream__readp(T, s);
	if (ret > 0)
		return ret;

	s->r.data = T;
	s->r.cb = stream_readp_cb;
	ev_io_start(LEM_ &s->r);
	return lua_yield(T, lua_gettop(T));
}
Ejemplo n.º 17
0
Archivo: file.c Proyecto: halfd/lem
/*
 * file:lock() method
 */
static void
file_lock_work(struct lem_async *a)
{
	struct file *f = (struct file *)a;
	struct flock fl = {
		.l_type = f->lock.type,
		.l_whence = SEEK_SET,
		.l_start = f->lock.start,
		.l_len = f->lock.len,
	};

	if (fcntl(f->fd, F_SETLK, &fl) == -1)
		f->ret = errno;
	else
		f->ret = 0;
}

static void
file_lock_reap(struct lem_async *a)
{
	struct file *f = (struct file *)a;
	lua_State *T = f->T;

	f->T = NULL;

	if (f->ret) {
		lem_queue(T, io_strerror(T, f->ret));
		return;
	}

	lua_pushboolean(T, 1);
	lem_queue(T, 1);
}

static int
file_lock(lua_State *T)
{
	static const short mode[] = { F_RDLCK, F_WRLCK, F_UNLCK };
	static const char *const modenames[] = { "r", "w", "u", NULL };
	struct file *f;
	int op;
	lua_Number start;
	lua_Number len;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	op = luaL_checkoption(T, 2, NULL, modenames);
	start = luaL_optnumber(T, 3, 0);
	len = luaL_optnumber(T, 4, 0);
	f = lua_touserdata(T, 1);
	f->lock.start = (off_t)start;
	luaL_argcheck(T, (lua_Number)f->lock.start == start, 3,
			"not an integer in proper range");
	f->lock.len = (off_t)len;
	luaL_argcheck(T, (lua_Number)f->lock.len == len, 4,
			"not an integer in proper range");
	if (f->fd < 0)
		return io_closed(T);
	if (f->T != NULL)
		return io_busy(T);

	f->T = T;
	f->lock.type = mode[op];
	lem_async_do(&f->a, file_lock_work, file_lock_reap);

	lua_settop(T, 1);
	return lua_yield(T, 1);
}
Ejemplo n.º 18
0
Archivo: stream.c Proyecto: esmil/lem
static int
stream_getpeer(lua_State *T)
{
	struct stream *s;
	union {
		struct sockaddr all;
		struct sockaddr_in in;
		struct sockaddr_in6 in6;
	} addr;
	socklen_t len;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	s = lua_touserdata(T, 1);
	if (!s->open)
		return io_closed(T);

	len = sizeof(addr);
	if (getpeername(s->r.fd, &addr.all, &len))
		return io_strerror(T, errno);

	switch (addr.all.sa_family) {
	case AF_UNIX: {
#if defined(__FreeBSD__) || defined(__APPLE__)
			struct xucred cred;

			len = sizeof(struct xucred);
			if (getsockopt(s->r.fd, 0, LOCAL_PEERCRED, &cred, &len))
				return io_strerror(T, errno);

			if (len != sizeof(struct xucred) ||
					cred.cr_version != XUCRED_VERSION) {
				lua_pushnil(T);
				lua_pushliteral(T, "version mismatch");
				return 2;
			}

			lua_pushliteral(T, "*unix");
			lua_pushinteger(T, cred.cr_uid);
			lua_pushinteger(T, cred.cr_gid);
#else
			struct ucred cred;

			len = sizeof(struct ucred);
			if (getsockopt(s->r.fd, SOL_SOCKET, SO_PEERCRED, &cred, &len))
				return io_strerror(T, errno);

			lua_pushliteral(T, "*unix");
			lua_pushinteger(T, cred.uid);
			lua_pushinteger(T, cred.gid);
#endif
			return 3;
		}

	case AF_INET: {
			char buf[INET_ADDRSTRLEN];

			if (inet_ntop(addr.in.sin_family, &addr.in.sin_addr,
						buf, sizeof(buf)) == NULL)
				return io_strerror(T, errno);

			lua_pushstring(T, buf);
			lua_pushinteger(T, ntohs(addr.in.sin_port));
			return 2;
		}

	case AF_INET6: {
			char buf[INET6_ADDRSTRLEN];

			if (inet_ntop(addr.in6.sin6_family, &addr.in6.sin6_addr,
						buf, sizeof(buf)) == NULL)
				return io_strerror(T, errno);

			lua_pushstring(T, buf);
			lua_pushinteger(T, ntohs(addr.in6.sin6_port));
			return 2;
		}
	}

	return io_strerror(T, EINVAL);
}