Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
269 lines (245 sloc) 7.52 KB
/*
* Copyright 2014 The Luvit Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "luv.h"
static void luv_check_buf(lua_State *L, int idx, uv_buf_t *pbuf) {
size_t len;
pbuf->base = (char*)luaL_checklstring(L, idx, &len);
pbuf->len = len;
}
static uv_stream_t* luv_check_stream(lua_State* L, int index) {
int isStream;
void *udata;
uv_stream_t* handle;
if (!(udata = lua_touserdata(L, index))) { goto fail; }
if (!(handle = *(uv_stream_t**) udata)) { goto fail; }
if (!handle->data) { goto fail; }
lua_getfield(L, LUA_REGISTRYINDEX, "uv_stream");
lua_getmetatable(L, index < 0 ? index - 1 : index);
lua_rawget(L, -2);
isStream = lua_toboolean(L, -1);
lua_pop(L, 2);
if (isStream) { return handle; }
fail: luaL_argerror(L, index, "Expected uv_stream userdata");
return NULL;
}
static void luv_shutdown_cb(uv_shutdown_t* req, int status) {
lua_State* L = luv_state(req->handle->loop);
luv_status(L, status);
luv_fulfill_req(L, (luv_req_t*)req->data, 1);
luv_cleanup_req(L, (luv_req_t*)req->data);
req->data = NULL;
}
static int luv_shutdown(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
int ref = luv_check_continuation(L, 2);
uv_shutdown_t* req = (uv_shutdown_t*)lua_newuserdata(L, sizeof(*req));
int ret;
req->data = luv_setup_req(L, ref);
ret = uv_shutdown(req, handle, luv_shutdown_cb);
if (ret < 0) {
luv_cleanup_req(L, (luv_req_t*)req->data);
lua_pop(L, 1);
return luv_error(L, ret);
}
return 1;
}
static void luv_connection_cb(uv_stream_t* handle, int status) {
lua_State* L = luv_state(handle->loop);
luv_status(L, status);
luv_call_callback(L, (luv_handle_t*)handle->data, LUV_CONNECTION, 1);
}
static int luv_listen(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
int backlog = luaL_checkinteger(L, 2);
int ret;
luv_check_callback(L, (luv_handle_t*)handle->data, LUV_CONNECTION, 3);
ret = uv_listen(handle, backlog, luv_connection_cb);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}
static int luv_accept(lua_State* L) {
uv_stream_t* server = luv_check_stream(L, 1);
uv_stream_t* client = luv_check_stream(L, 2);
int ret = uv_accept(server, client);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}
static void luv_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
(void)handle;
buf->base = (char*)malloc(suggested_size);
assert(buf->base);
buf->len = suggested_size;
}
static void luv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
lua_State* L = luv_state(handle->loop);
int nargs;
if (nread > 0) {
lua_pushnil(L);
lua_pushlstring(L, buf->base, nread);
nargs = 2;
}
free(buf->base);
if (nread == 0) return;
if (nread == UV_EOF) {
nargs = 0;
}
else if (nread < 0) {
luv_status(L, nread);
nargs = 1;
}
luv_call_callback(L, (luv_handle_t*)handle->data, LUV_READ, nargs);
}
static int luv_read_start(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
int ret;
luv_check_callback(L, (luv_handle_t*)handle->data, LUV_READ, 2);
ret = uv_read_start(handle, luv_alloc_cb, luv_read_cb);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}
static int luv_read_stop(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
int ret = uv_read_stop(handle);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}
static void luv_write_cb(uv_write_t* req, int status) {
lua_State* L = luv_state(req->handle->loop);
luv_status(L, status);
luv_fulfill_req(L, (luv_req_t*)req->data, 1);
luv_cleanup_req(L, (luv_req_t*)req->data);
req->data = NULL;
}
static uv_buf_t* luv_prep_bufs(lua_State* L, int index, size_t *count) {
uv_buf_t *bufs;
size_t i;
*count = lua_rawlen(L, index);
bufs = (uv_buf_t*)malloc(sizeof(uv_buf_t) * *count);
for (i = 0; i < *count; ++i) {
lua_rawgeti(L, index, i + 1);
luv_check_buf(L, -1, &bufs[i]);
lua_pop(L, 1);
}
return bufs;
}
static int luv_write(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
uv_write_t* req;
int ret, ref;
ref = luv_check_continuation(L, 3);
req = (uv_write_t *)lua_newuserdata(L, sizeof(*req));
req->data = (luv_req_t*)luv_setup_req(L, ref);
if (lua_istable(L, 2)) {
size_t count;
uv_buf_t *bufs = luv_prep_bufs(L, 2, &count);
ret = uv_write(req, handle, bufs, count, luv_write_cb);
free(bufs);
}
else if (lua_isstring(L, 2)) {
uv_buf_t buf;
luv_check_buf(L, 2, &buf);
ret = uv_write(req, handle, &buf, 1, luv_write_cb);
}
else {
return luaL_argerror(L, 2, "data must be string or table of strings");
}
if (ret < 0) {
luv_cleanup_req(L, (luv_req_t*)req->data);
lua_pop(L, 1);
return luv_error(L, ret);
}
lua_pushvalue(L, 2);
((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX);
return 1;
}
static int luv_write2(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
uv_write_t* req;
int ret, ref;
uv_stream_t* send_handle;
send_handle = luv_check_stream(L, 3);
ref = luv_check_continuation(L, 4);
req = (uv_write_t *)lua_newuserdata(L, sizeof(*req));
req->data = luv_setup_req(L, ref);
if (lua_istable(L, 2)) {
size_t count;
uv_buf_t *bufs = luv_prep_bufs(L, 2, &count);
ret = uv_write2(req, handle, bufs, count, send_handle, luv_write_cb);
free(bufs);
}
else if (lua_isstring(L, 2)) {
uv_buf_t buf;
luv_check_buf(L, 2, &buf);
ret = uv_write2(req, handle, &buf, 1, send_handle, luv_write_cb);
}
else {
return luaL_argerror(L, 2, "data must be string or table of strings");
}
if (ret < 0) {
luv_cleanup_req(L, (luv_req_t*)req->data);
lua_pop(L, 1);
return luv_error(L, ret);
}
lua_pushvalue(L, 2);
((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX);
return 1;
}
static int luv_try_write(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
int ret;
if (lua_istable(L, 2)) {
size_t count;
uv_buf_t *bufs = luv_prep_bufs(L, 2, &count);
ret = uv_try_write(handle, bufs, count);
free(bufs);
}
else if (lua_isstring(L, 2)) {
uv_buf_t buf;
luv_check_buf(L, 2, &buf);
ret = uv_try_write(handle, &buf, 1);
}
else {
return luaL_argerror(L, 2, "data must be string or table of strings");
}
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}
static int luv_is_readable(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
lua_pushboolean(L, uv_is_readable(handle));
return 1;
}
static int luv_is_writable(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
lua_pushboolean(L, uv_is_writable(handle));
return 1;
}
static int luv_stream_set_blocking(lua_State* L) {
uv_stream_t* handle = luv_check_stream(L, 1);
int blocking, ret;
luaL_checktype(L, 2, LUA_TBOOLEAN);
blocking = lua_toboolean(L, 2);
ret = uv_stream_set_blocking(handle, blocking);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}
You can’t perform that action at this time.