static int luv_new_udp(lua_State* L) { uv_udp_t* handle = (uv_udp_t*)luv_newuserdata(L, sizeof(*handle)); int ret; if (lua_isnoneornil(L, 1)) { ret = uv_udp_init(luv_loop(L), handle); } else { ret = uv_udp_init_ex(luv_loop(L), handle, lua_tointeger(L, 1)); } if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_new_work(lua_State* L) { size_t len; const char* buff; luv_work_ctx_t* ctx; buff = luv_thread_dumped(L, 1, &len); luaL_checktype(L, 2, LUA_TFUNCTION); if(!lua_isnoneornil(L, 3)) luaL_checktype(L, 3, LUA_TFUNCTION); ctx = lua_newuserdata(L, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx)); ctx->len = len; ctx->code = malloc(ctx->len); memcpy(ctx->code, buff, len); lua_pushvalue(L, 2); ctx->after_work_cb = luaL_ref(L, LUA_REGISTRYINDEX); if (lua_gettop(L) == 4) { lua_pushvalue(L, 3); ctx->async_cb = luaL_ref(L, LUA_REGISTRYINDEX); uv_async_init(luv_loop(L), &ctx->async, async_cb); } else ctx->async_cb = LUA_REFNIL; ctx->L = L; luaL_getmetatable(L, "luv_work_ctx"); lua_setmetatable(L, -2); return 1; }
static int luv_queue_channel_new(lua_State* L) { const char* name = luv_queue_lua_arg_string(L, 1, NULL, queue_usage_new); int limit = luv_queue_lua_arg_integer(L, 2, 1, 0, queue_usage_new); luv_queue_t* queue = luv_queue_create(name, limit); if (lua_gettop(L) >= 3) { lua_pushvalue(L, 3); queue->async_cb = luaL_ref(L, LUA_REGISTRYINDEX); uv_async_init(luv_loop(L), &queue->async, luv_queue_async_callback); queue->async.data = queue; } else { queue->async_cb = LUA_REFNIL; queue->async.data = NULL; } queue->L = L; if (!luv_queues_add(queue)) { luv_queue_destroy(queue); lua_pushnil(L); lua_pushstring(L, "chan name duplicated"); return 2; } luv_queue_channel_push_queue(L, queue); return 1; }
static int luv_queue_work(lua_State* L) { luv_work_ctx_t* ctx; luv_work_t* work; int ret; int top = lua_gettop(L); ctx = luv_check_work_ctx(L, 1); // ctx should ref up work = lua_newuserdata(L, sizeof(*work)); //work should ref up memset(work, 0, sizeof(*work)); luv_thread_arg_set(L, &work->arg, 2, top); work->ctx = ctx; work->work.data = work; ret = uv_queue_work(luv_loop(L), &work->work, luv_work_cb, luv_after_work_cb); if (ret < 0) return luv_error(L, ret); lua_pushlightuserdata(L, work->ctx); lua_pushvalue(L, 1); lua_settable(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, work); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); lua_pushboolean(L, 1); return 1; }
static int luv_new_signal(lua_State* L) { uv_signal_t* handle = luv_newuserdata(L, sizeof(*handle)); int ret = uv_signal_init(luv_loop(L), handle); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int loop_gc(lua_State *L) { uv_loop_t* loop = luv_loop(L); // Call uv_close on every active handle uv_walk(loop, walk_cb, NULL); // Run the event loop until all handles are successfully closed while (uv_loop_close(loop)) { uv_run(loop, UV_RUN_DEFAULT); } return 0; }
static int luv_new_socket_poll(lua_State* L) { int fd = luaL_checkinteger(L, 1); uv_poll_t* handle = (uv_poll_t*)luv_newuserdata(L, sizeof(*handle)); int ret = uv_poll_init_socket(luv_loop(L), handle, fd); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_new_tty(lua_State* L) { int readable, ret; uv_tty_t* handle; uv_file fd = luaL_checkinteger(L, 1); luaL_checktype(L, 2, LUA_TBOOLEAN); readable = lua_toboolean(L, 2); handle = (uv_tty_t*)luv_newuserdata(L, sizeof(*handle)); ret = uv_tty_init(luv_loop(L), handle, fd, readable); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_queue_work(lua_State* L) { int top = lua_gettop(L); luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1); luv_work_t* work = malloc(sizeof(*work)); int ret; luv_thread_arg_set(L, &work->arg, 2, top); work->ctx = ctx; work->work.data = work; ret = uv_queue_work(luv_loop(L), &work->work, luv_work_cb, luv_after_work_cb); if (ret < 0) { free(work); return luv_error(L, ret); } //ref up to ctx lua_pushlightuserdata(L, work); lua_pushvalue(L, 1); lua_rawset(L, LUA_REGISTRYINDEX); lua_pushboolean(L, 1); return 1; }
static int luv_spawn(lua_State* L) { uv_process_t* handle; uv_process_options_t options; size_t i, len = 0; int ret; memset(&options, 0, sizeof(options)); options.exit_cb = exit_cb; options.file = luaL_checkstring(L, 1); options.flags = 0; // Make sure the 2nd argument is a table luaL_checktype(L, 2, LUA_TTABLE); // get the args list lua_getfield(L, 2, "args"); // +1 for inserted command at front if (lua_type(L, -1) == LUA_TTABLE) { len = 1 + lua_rawlen(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 3, "args option must be table"); } else { len = 1; } // +1 for null terminator at end options.args = malloc((len + 1) * sizeof(*options.args)); if (!options.args) { luv_clean_options(&options); return luaL_error(L, "Problem allocating args"); } options.args[0] = (char*)options.file; for (i = 1; i < len; ++i) { lua_rawgeti(L, -1, i); options.args[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } options.args[len] = NULL; lua_pop(L, 1); // get the stdio list lua_getfield(L, 2, "stdio"); if (lua_type(L, -1) == LUA_TTABLE) { options.stdio_count = len = lua_rawlen(L, -1); options.stdio = malloc(len * sizeof(*options.stdio)); if (!options.stdio) { luv_clean_options(&options); return luaL_error(L, "Problem allocating stdio"); } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); // integers are assumed to be file descripters if (lua_type(L, -1) == LUA_TNUMBER) { options.stdio[i].flags = UV_INHERIT_FD; options.stdio[i].data.fd = lua_tointeger(L, -1); } // userdata is assumed to be a uv_stream_t instance else if (lua_type(L, -1) == LUA_TUSERDATA) { uv_os_fd_t fd; uv_stream_t* stream = luv_check_stream(L, -1); int err = uv_fileno((uv_handle_t*)stream, &fd); if (err == UV_EINVAL || err == UV_EBADF) { options.stdio[i].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE; } else { options.stdio[i].flags = UV_INHERIT_STREAM; } options.stdio[i].data.stream = stream; } else if (lua_type(L, -1) == LUA_TNIL) { options.stdio[i].flags = UV_IGNORE; } else { luv_clean_options(&options); return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer"); } lua_pop(L, 1); } } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "stdio option must be table"); } lua_pop(L, 1); // Get the env lua_getfield(L, 2, "env"); if (lua_type(L, -1) == LUA_TTABLE) { len = lua_rawlen(L, -1); options.env = malloc((len + 1) * sizeof(*options.env)); if (!options.env) { luv_clean_options(&options); return luaL_error(L, "Problem allocating env"); } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); options.env[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } options.env[len] = NULL; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "env option must be table"); } lua_pop(L, 1); // Get the cwd lua_getfield(L, 2, "cwd"); if (lua_type(L, -1) == LUA_TSTRING) { options.cwd = (char*)lua_tostring(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "cwd option must be string"); } lua_pop(L, 1); // Check for uid lua_getfield(L, 2, "uid"); if (lua_type(L, -1) == LUA_TNUMBER) { options.uid = lua_tointeger(L, -1); options.flags |= UV_PROCESS_SETUID; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "uid option must be number"); } lua_pop(L, 1); // Check for gid lua_getfield(L, 2, "gid"); if (lua_type(L, -1) == LUA_TNUMBER) { options.gid = lua_tointeger(L, -1); options.flags |= UV_PROCESS_SETGID; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "gid option must be number"); } lua_pop(L, 1); // Check for the boolean flags lua_getfield(L, 2, "verbatim"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; } lua_pop(L, 1); lua_getfield(L, 2, "detached"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_DETACHED; } lua_pop(L, 1); lua_getfield(L, 2, "hide"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_WINDOWS_HIDE; } lua_pop(L, 1); handle = lua_newuserdata(L, sizeof(*handle)); handle->type = UV_PROCESS; handle->data = luv_setup_handle(L); if (!lua_isnoneornil(L, 3)) { luv_check_callback(L, handle->data, LUV_EXIT, 3); } ret = uv_spawn(luv_loop(L), handle, &options); luv_clean_options(&options); if (ret < 0) { /* The async callback is required here because luajit GC may reclaim the * luv handle before libuv is done closing it down. */ uv_close((uv_handle_t*)handle, luv_spawn_close_cb); return luv_error(L, ret); } lua_pushinteger(L, handle->pid); return 2; }
static int lua_SpawnServiceCtrlDispatcher(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); luaL_checktype(L, 3, LUA_TFUNCTION); if (gBatons) { return luaL_error(L, "ServiceCtrlDispatcher is already running"); } /* structure allocation/setup */ BOOL ret = FALSE; size_t len = 0; svc_dispatch_info *info = LocalAlloc(LPTR, sizeof(svc_dispatch_info)); uv_async_init(luv_loop(L), &info->end_async_handle, svcdispatcher_end_cb); svc_baton** baton_pp = &gBatons; /* Convert the table to a service table and setup the baton table */ lua_pushnil(L); /* first key */ while (lua_next(L, 1) != 0) { /* uses 'key' (at index -2) and 'value' (at index -1) */ const char* name = luaL_checkstring(L, -2); luaL_checktype(L, -1, LUA_TTABLE); lua_pushvalue(L, -1); lua_pushnil(L); lua_next(L, -2); luaL_checktype(L, -1, LUA_TFUNCTION); lua_pushvalue(L, -1); int main_ref = luaL_ref(L, LUA_REGISTRYINDEX); lua_pop(L, 1); lua_next(L, -2); luaL_checktype(L, -1, LUA_TFUNCTION); lua_pushvalue(L, -1); int cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); lua_pop(L, 3); *baton_pp = svc_create_baton(luv_loop(L), _strdup(name), main_ref, cb_ref); baton_pp = &(*baton_pp)->next; // count the entries ++len; /* removes 'value'; keeps 'key' for next iteration */ lua_pop(L, 1); } if (len == 0) { return luaL_error(L, "Service Dispatch Table is empty"); } lua_pushvalue(L, 2); info->lua_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); /* store the error cb in the registry */ lua_pushstring(L, "winsvc_error_cb"); lua_pushvalue(L, 3); lua_settable(L, LUA_REGISTRYINDEX); /* Create Windows Service Entry Table */ info->svc_table = LocalAlloc(LPTR, sizeof(SERVICE_TABLE_ENTRY) * (len + 1)); svc_baton* baton_it = gBatons; SERVICE_TABLE_ENTRY* entry_it = info->svc_table; while(baton_it) { entry_it->lpServiceName = baton_it->name; entry_it->lpServiceProc = ServiceMain; baton_it = baton_it->next; ++entry_it; } /* Start */ HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&StartServiceCtrlDispatcherThread, info, 0, NULL); ret = thread != NULL; lua_pushboolean(L, ret); if (ret) { lua_pushnil(L); } else { lua_pushinteger(L, GetLastError()); } return 2; }
static int luv_getaddrinfo(lua_State* L) { uv_getaddrinfo_t* req; const char* node; const char* service; struct addrinfo hints_s; struct addrinfo* hints = &hints_s; int ret, ref; if (lua_isnoneornil(L, 1)) node = NULL; else node = luaL_checkstring(L, 1); if (lua_isnoneornil(L, 2)) service = NULL; else service = luaL_checkstring(L, 2); if (!lua_isnoneornil(L, 3)) luaL_checktype(L, 3, LUA_TTABLE); else hints = NULL; if (hints) { // Initialize the hints memset(hints, 0, sizeof(*hints)); // Process the `family` hint. lua_getfield(L, 3, "family"); if (lua_isnumber(L, -1)) { hints->ai_family = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { hints->ai_family = luv_af_string_to_num(lua_tostring(L, -1)); } else if (lua_isnil(L, -1)) { hints->ai_family = AF_UNSPEC; } else { luaL_argerror(L, 3, "family hint must be string if set"); } lua_pop(L, 1); // Process `socktype` hint lua_getfield(L, 3, "socktype"); if (lua_isnumber(L, -1)) { hints->ai_socktype = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { hints->ai_socktype = luv_sock_string_to_num(lua_tostring(L, -1)); } else if (!lua_isnil(L, -1)) { return luaL_argerror(L, 3, "socktype hint must be string if set"); } lua_pop(L, 1); // Process the `protocol` hint lua_getfield(L, 3, "protocol"); if (lua_isnumber(L, -1)) { hints->ai_protocol = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { int protocol = luv_af_string_to_num(lua_tostring(L, -1)); if (protocol) { hints->ai_protocol = protocol; } else { return luaL_argerror(L, 3, "Invalid protocol hint"); } } else if (!lua_isnil(L, -1)) { return luaL_argerror(L, 3, "protocol hint must be string if set"); } lua_pop(L, 1); lua_getfield(L, 3, "addrconfig"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ADDRCONFIG; lua_pop(L, 1); #ifdef AI_V4MAPPED lua_getfield(L, 3, "v4mapped"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_V4MAPPED; lua_pop(L, 1); #endif #ifdef AI_ALL lua_getfield(L, 3, "all"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ALL; lua_pop(L, 1); #endif lua_getfield(L, 3, "numerichost"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_NUMERICHOST; lua_pop(L, 1); lua_getfield(L, 3, "passive"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_PASSIVE; lua_pop(L, 1); lua_getfield(L, 3, "numericserv"); if (lua_toboolean(L, -1)) { hints->ai_flags |= AI_NUMERICSERV; /* On OS X upto at least OSX 10.9, getaddrinfo crashes * if AI_NUMERICSERV is set and the servname is NULL or "0". * This workaround avoids a segfault in libsystem. */ if (NULL == service) service = "00"; } lua_pop(L, 1); lua_getfield(L, 3, "canonname"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_CANONNAME; lua_pop(L, 1); } ref = luv_check_continuation(L, 4); req = (uv_getaddrinfo_t*)lua_newuserdata(L, sizeof(*req)); req->data = luv_setup_req(L, ref); ret = uv_getaddrinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getaddrinfo_cb, node, service, hints); if (ret < 0) { luv_cleanup_req(L, (luv_req_t*)req->data); lua_pop(L, 1); return luv_error(L, ret); } if (ref == LUA_NOREF) { lua_pop(L, 1); luv_pushaddrinfo(L, req->addrinfo); uv_freeaddrinfo(req->addrinfo); luv_cleanup_req(L, (luv_req_t*)req->data); } return 1; }
static int luv_getnameinfo(lua_State* L) { uv_getnameinfo_t* req; struct sockaddr_storage addr; const char* ip = NULL; int flags = 0; int ret, ref, port = 0; luaL_checktype(L, 1, LUA_TTABLE); memset(&addr, 0, sizeof(addr)); lua_getfield(L, 1, "ip"); if (lua_isstring(L, -1)) { ip = lua_tostring(L, -1); } else if (!lua_isnil(L, -1)) { luaL_argerror(L, 1, "ip property must be string if set"); } lua_pop(L, 1); lua_getfield(L, 1, "port"); if (lua_isnumber(L, -1)) { port = lua_tointeger(L, -1); } else if (!lua_isnil(L, -1)) { luaL_argerror(L, 1, "port property must be integer if set"); } lua_pop(L, 1); if (ip || port) { if (!ip) ip = "0.0.0.0"; if (!uv_ip4_addr(ip, port, (struct sockaddr_in*)&addr)) { addr.ss_family = AF_INET; } else if (!uv_ip6_addr(ip, port, (struct sockaddr_in6*)&addr)) { addr.ss_family = AF_INET6; } else { return luaL_argerror(L, 1, "Invalid ip address or port"); } } lua_getfield(L, 1, "family"); if (lua_isnumber(L, -1)) { addr.ss_family = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { addr.ss_family = luv_af_string_to_num(lua_tostring(L, -1)); } else if (!lua_isnil(L, -1)) { luaL_argerror(L, 1, "family must be string if set"); } lua_pop(L, 1); ref = luv_check_continuation(L, 2); req = (uv_getnameinfo_t*)lua_newuserdata(L, sizeof(*req)); req->data = luv_setup_req(L, ref); ret = uv_getnameinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getnameinfo_cb, (struct sockaddr*)&addr, flags); if (ret < 0) { luv_cleanup_req(L, (luv_req_t*)req->data); lua_pop(L, 1); return luv_error(L, ret); } if (ref == LUA_NOREF) { lua_pop(L, 1); lua_pushstring(L, req->host); lua_pushstring(L, req->service); luv_cleanup_req(L, (luv_req_t*)req->data); return 2; } return 1; }
static int luv_print_active_handles(lua_State* L){ uv_print_active_handles(luv_loop(L), stderr); return 0; }