Example #1
0
int luv_udp_recv_start(lua_State* L) {
  uv_udp_t* handle = (uv_udp_t*)luv_checkudata(L, 1, "udp");
  int rc = uv_udp_recv_start(handle, luv_on_alloc, luv_on_udp_recv);
  if (rc && uv_last_error(luv_get_loop(L)).code != UV_EALREADY) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "udp_recv_start: %s", uv_strerror(err));
  }
  luv_handle_ref(L, handle->data, 1);
  return 0;
}
Example #2
0
static int luv__udp_bind(lua_State *L, int family) {
  uv_udp_t* handle = (uv_udp_t*)luv_checkudata(L, 1, "udp");
  const char* host = luaL_checkstring(L, 2);
  int port = luaL_checkint(L, 3);
  int flags = 0;
  int rc = 0;

  switch (family) {
  case AF_INET:
    rc = uv_udp_bind(handle, uv_ip4_addr(host, port), flags);
    break;
  case AF_INET6:
    rc = uv_udp_bind6(handle, uv_ip6_addr(host, port), flags);
    break;
  default:
    assert(0 && "unexpected family type");
    abort();
  }

  if (rc) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "udp_bind: %s", uv_strerror(err));
  }

  return 0;
}
Example #3
0
static void luv_on_udp_send(uv_udp_send_t* req, int status) {
  luv_udp_ref_t *ref;
  /* load the lua state and the userdata */
  lua_State *L = luv_handle_get_lua(req->handle->data);
  lua_pop(L, 1); /* We don't need the userdata */
  /* load the callback */
  ref =  req->data;
  lua_rawgeti(L, LUA_REGISTRYINDEX, ref->ref);
  luaL_unref(L, LUA_REGISTRYINDEX, ref->ref);
  free(ref);

  if (lua_isfunction(L, -1)) {
    if (status != 0) {
      luv_push_async_error(L, uv_last_error(luv_get_loop(L)), "on_udp_send", NULL);
      luv_acall(L, 1, 0, "on_udp_send");
    } else {
      luv_acall(L, 0, 0, "on_udp_send");
    }
  } else {
    lua_pop(L, 1);
  }

  luv_handle_unref(L, req->handle->data);
  free(req);
}
Example #4
0
int luv_tcp_connect6(lua_State* L) {
  int before = lua_gettop(L);
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");

  const char* ip_address = luaL_checkstring(L, 2);
  int port = luaL_checkint(L, 3);

  struct sockaddr_in6 address = uv_ip6_addr(ip_address, port);

  luv_connect_ref_t* ref = (luv_connect_ref_t*)malloc(sizeof(luv_connect_ref_t));

  /* Store a reference to the userdata */
  ref->L = L;
  lua_pushvalue(L, 1);
  ref->r = luaL_ref(L, LUA_REGISTRYINDEX);

  /* Give the connect_req access to this */
  ref->connect_req.data = ref;

  if (uv_tcp_connect6(&ref->connect_req, handle, address, luv_after_connect)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_connect6: %s", uv_strerror(err));
  }

  assert(lua_gettop(L) == before);
  return 0;
}
Example #5
0
void luv_on_fs_event(uv_fs_event_t* handle, const char* filename, int events, int status) {

  /* load the lua state and the userdata */
  luv_ref_t* ref = handle->data;
  lua_State *L = ref->L;
  int before = lua_gettop(L);
  lua_rawgeti(L, LUA_REGISTRYINDEX, ref->r);

  if (status == -1) {
    luv_push_async_error(L, uv_last_error(luv_get_loop(L)), "on_fs_event", NULL);
    luv_emit_event(L, "error", 1);
  } else {

    switch (events) {
      case UV_RENAME: lua_pushstring(L, "rename"); break;
      case UV_CHANGE: lua_pushstring(L, "change"); break;
      default: lua_pushnil(L); break;
    }

    if (filename) {
      lua_pushstring(L, filename);
    } else {
      lua_pushnil(L);
    }

    luv_emit_event(L, "change", 2);

  }

  assert(lua_gettop(L) == before);

}
Example #6
0
int luv_new_fs_watcher (lua_State* L) {
  int before = lua_gettop(L);
  const char* filename = luaL_checkstring(L, 1);
  luv_ref_t* ref;

  uv_fs_event_t* handle = (uv_fs_event_t*)lua_newuserdata(L, sizeof(uv_fs_event_t));

  uv_fs_event_init(luv_get_loop(L), handle, filename, luv_on_fs_event, 0);

  /* Set metatable for type */
  luaL_getmetatable(L, "luv_fs_watcher");
  lua_setmetatable(L, -2);

  /* Create a local environment for storing stuff */
  lua_newtable(L);
  lua_setfenv (L, -2);

  /* Store a reference to the userdata in the handle */
  ref = (luv_ref_t*)malloc(sizeof(luv_ref_t));
  ref->L = L;
  lua_pushvalue(L, -1); /* duplicate so we can _ref it */
  ref->r = luaL_ref(L, LUA_REGISTRYINDEX);
  handle->data = ref;

  assert(lua_gettop(L) == before + 1);
  /* return the userdata */
  return 1;
}
Example #7
0
int luv_tcp_getsockname(lua_State* L) {
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");
  int port = 0;
  char ip[INET6_ADDRSTRLEN];
  int family;

  struct sockaddr_storage address;
  int addrlen = sizeof(address);

  if (uv_tcp_getsockname(handle, (struct sockaddr*)(&address), &addrlen)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_getsockname: %s", uv_strerror(err));
  }

  family = address.ss_family;
  if (family == AF_INET) {
    struct sockaddr_in* addrin = (struct sockaddr_in*)&address;
    uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, INET6_ADDRSTRLEN);
    port = ntohs(addrin->sin_port);
  } else if (family == AF_INET6) {
    struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)&address;
    uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, INET6_ADDRSTRLEN);
    port = ntohs(addrin6->sin6_port);
  }

  lua_newtable(L);
  lua_pushnumber(L, port);
  lua_setfield(L, -2, "port");
  lua_pushnumber(L, family);
  lua_setfield(L, -2, "family");
  lua_pushstring(L, ip);
  lua_setfield(L, -2, "address");

  return 1;
}
Example #8
0
int luv_new_udp (lua_State* L) {
  uv_udp_t* handle = luv_create_udp(L);
  /* uv_udp_init memset's the handle so we need to reset the data baton */
  void *data = handle->data;
  uv_udp_init(luv_get_loop(L), handle);
  handle->data = data;
  return 1;
}
Example #9
0
int luv_udp_recv_stop(lua_State* L) {
  uv_udp_t* handle = (uv_udp_t*)luv_checkudata(L, 1, "udp");
  if (uv_udp_recv_stop(handle)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "udp_recv_stop: %s", uv_strerror(err));
  }
  luv_handle_unref(L, handle->data);
  return 0;
}
Example #10
0
int luv_execpath(lua_State* L) {
  size_t size = 2*PATH_MAX;
  char exec_path[2*PATH_MAX];
  if (uv_exepath(exec_path, &size)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "uv_exepath: %s", uv_strerror(err));
  }
  lua_pushlstring(L, exec_path, size);
  return 1;
}
Example #11
0
int luv_tcp_nodelay (lua_State* L) {
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");
  int enable = lua_toboolean(L, 2);

  if (uv_tcp_nodelay(handle, enable)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_nodelay: %s", uv_strerror(err));
  }
  return 0;
}
Example #12
0
// Kills the process with the specified signal. The user must still call close
// on the process.
int luv_process_kill(lua_State* L) {
  uv_process_t* handle = (uv_process_t*)luv_checkudata(L, 1, "process");
  int signum = luaL_checkint(L, 2);

  if (uv_process_kill(handle, signum)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "process_kill: %s", uv_strerror(err));
  }

  return 0;
}
Example #13
0
int luv_tcp_keepalive (lua_State* L) {
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");
  int enable = lua_toboolean(L, 2);
  int delay = lua_tointeger(L, 3);

  if (uv_tcp_keepalive(handle, enable, delay)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_keepalive: %s", uv_strerror(err));
  }
  return 0;

}
Example #14
0
File: luv_udp.c Project: xming/lev
static void luv_on_udp_recv(uv_udp_t* handle,
                            ssize_t nread,
                            uv_buf_t buf,
                            struct sockaddr* addr,
                            unsigned flags) {
  int port;
  char ip[INET6_ADDRSTRLEN];

  /* load the lua state and the userdata */
  lua_State *L = luv_handle_get_lua(handle->data);

  /* perform some magic */
  /* the base buffer is the offset of the slab block + sizeof(MemBlock) */
  MemBlock *mb = (MemBlock *)(buf.base - sizeof(MemBlock));
  printf("luv_on_read: %p pool=%p\n", mb, mb->pool);

  if (nread == 0) {
    return;
  }

  if (nread < 0) {
    uv_close((uv_handle_t *)handle, luv_on_close);
    luv_push_async_error(L, uv_last_error(luv_get_loop(L)), "on_recv", NULL);
    luv_emit_event(L, "error", 1);
    return;
  }

  lua_pushlstring(L, buf.base, nread);
  lua_newtable(L);

  if (addr->sa_family == AF_INET) {
    uv_inet_ntop(AF_INET, &(((struct sockaddr_in*)addr)->sin_addr), ip, INET6_ADDRSTRLEN);
    port = ntohs(((struct sockaddr_in*)addr)->sin_port);
  } else if (addr->sa_family == AF_INET6){
    uv_inet_ntop(AF_INET6, &(((struct sockaddr_in6*)addr)->sin6_addr), ip, INET6_ADDRSTRLEN);
    port = ntohs(((struct sockaddr_in6*)addr)->sin6_port);
  }

  lua_pushstring(L, ip);
  lua_setfield(L, -2, "address");
  lua_pushnumber(L, port);
  lua_setfield(L, -2, "port");
  lua_pushboolean(L, flags == UV_UDP_PARTIAL);
  lua_setfield(L, -2, "partial");
  lua_pushnumber(L, nread);
  lua_setfield(L, -2, "size");
  luv_emit_event(L, "message", 2);

  lev_slab_decRef( mb );
  /*free(buf.base);*/
}
Example #15
0
/*  const char* interface_addr, uv_membership membership);*/
int luv_udp_set_membership(lua_State* L) {
  uv_udp_t* handle = (uv_udp_t*)luv_checkudata(L, 1, "udp");
  const char* multicast_addr = luaL_checkstring(L, 2);
  const char* interface_addr = luaL_checkstring(L, 3);
  int option = luaL_checkoption (L, 4, "membership", luv_membership_options);
  uv_membership membership = option ? UV_LEAVE_GROUP : UV_JOIN_GROUP;

  if (uv_udp_set_membership(handle, multicast_addr, interface_addr, membership)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "udp_set_membership: %s", uv_strerror(err));
  }

  return 0;
}
Example #16
0
int luv_tcp_bind6(lua_State* L) {
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");
  const char* host = luaL_checkstring(L, 2);
  int port = luaL_checkint(L, 3);

  struct sockaddr_in6 address = uv_ip6_addr(host, port);

  if (uv_tcp_bind6(handle, address)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_bind6: %s", uv_strerror(err));
  }

  return 0;
}
Example #17
0
static int luv_udp__send(lua_State* L, int family) {
  uv_buf_t buf;
  uv_udp_t* handle = (uv_udp_t*)luv_checkudata(L, 1, "udp");
  size_t len;
  const char* chunk = luaL_checklstring(L, 2, &len);
  luv_udp_ref_t *ref;

  uv_udp_send_t* req = (uv_udp_send_t*)malloc(sizeof(uv_udp_send_t));
  int port = luaL_checkint(L, 3);
  const char* host = luaL_checkstring(L, 4);
  struct sockaddr_in dest;
  struct sockaddr_in6 dest6;
  int rc;

  /* Store a reference to the callback */
  lua_pushvalue(L, 5);
  ref = malloc(sizeof(*ref));
  ref->ref = luaL_ref(L, LUA_REGISTRYINDEX);
  req->data = ref;

  luv_handle_ref(L, handle->data, 1);

  /* Store the chunk
   * TODO: this is probably unsafe, should investigate
   */
  buf = uv_buf_init((char*)chunk, len);

  switch(family) {
  case AF_INET:
    dest = uv_ip4_addr(host, port);
    rc = uv_udp_send(req, handle, &buf, 1, dest, luv_on_udp_send);
    break;
  case AF_INET6:
    dest6 = uv_ip6_addr(host, port);
    rc = uv_udp_send6(req, handle, &buf, 1, dest6, luv_on_udp_send);
    break;
  default:
    assert(0 && "unexpected family type");
    abort();
  }

  if (rc) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "udp_send: %s", uv_strerror(err));
  }

  return 0;
}
Example #18
0
int luv_tcp_bind (lua_State* L) {
  int before = lua_gettop(L);
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");
  const char* host = luaL_checkstring(L, 2);
  int port = luaL_checkint(L, 3);

  struct sockaddr_in address = uv_ip4_addr(host, port);

  if (uv_tcp_bind(handle, address)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_bind: %s", uv_strerror(err));
  }

  assert(lua_gettop(L) == before);
  return 0;
}
Example #19
0
static void luv_on_udp_recv(uv_udp_t* handle,
                            ssize_t nread,
                            uv_buf_t buf,
                            struct sockaddr* addr,
                            unsigned flags) {
  int port;
  char ip[INET6_ADDRSTRLEN];

  /* load the lua state and the userdata */
  lua_State *L = luv_handle_get_lua(handle->data);

  if (nread == 0) {
    return;
  }

  if (nread < 0) {
    uv_close((uv_handle_t *)handle, luv_on_close);
    luv_push_async_error(L, uv_last_error(luv_get_loop(L)), "on_recv", NULL);
    luv_emit_event(L, "error", 1);
    return;
  }

  lua_pushlstring(L, buf.base, nread);
  lua_newtable(L);

  if (addr->sa_family == AF_INET) {
    uv_inet_ntop(AF_INET, &(((struct sockaddr_in*)addr)->sin_addr), ip, INET6_ADDRSTRLEN);
    port = ntohs(((struct sockaddr_in*)addr)->sin_port);
  } else if (addr->sa_family == AF_INET6){
    uv_inet_ntop(AF_INET6, &(((struct sockaddr_in6*)addr)->sin6_addr), ip, INET6_ADDRSTRLEN);
    port = ntohs(((struct sockaddr_in6*)addr)->sin6_port);
  }

  lua_pushstring(L, ip);
  lua_setfield(L, -2, "address");
  lua_pushnumber(L, port);
  lua_setfield(L, -2, "port");
  lua_pushboolean(L, flags == UV_UDP_PARTIAL);
  lua_setfield(L, -2, "partial");
  lua_pushnumber(L, nread);
  lua_setfield(L, -2, "size");
  luv_emit_event(L, "message", 2);

  free(buf.base);
  buf.base = NULL;
}
Example #20
0
int luv_tcp_connect6(lua_State* L) {
  uv_tcp_t* handle = (uv_tcp_t*)luv_checkudata(L, 1, "tcp");

  const char* ip_address = luaL_checkstring(L, 2);
  int port = luaL_checkint(L, 3);

  struct sockaddr_in6 address = uv_ip6_addr(ip_address, port);

  uv_connect_t* req = (uv_connect_t*)malloc(sizeof(uv_connect_t));

  if (uv_tcp_connect6(req, handle, address, luv_after_connect)) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "tcp_connect6: %s", uv_strerror(err));
  }

  luv_handle_ref(L, handle->data, 1);

  return 0;
}
Example #21
0
static int luv_run(lua_State* L)
{
    int r = 0;
    int args = lua_gettop(L);
    uv_run_mode mode = UV_RUN_DEFAULT;
    assert(args >= 0 && args <= 1);
    if (args == 1)
    {
        const char* smode = luaL_checkstring(L, 1);
        if (strcmp(smode, "once") == 0)
        {
            mode = UV_RUN_ONCE;
        }
        else if (strcmp(smode, "nowait") == 0)
        {
            mode = UV_RUN_NOWAIT;
        }
    }
    r = uv_run(luv_get_loop(L), mode);
    lua_pushinteger(L, r);
    return 1;
}
Example #22
0
int luv_run(lua_State* L) {
  uv_run(luv_get_loop(L), UV_RUN_DEFAULT);
  return 0;
}
Example #23
0
int luvit_init(lua_State *L, uv_loop_t* loop, int argc, char *argv[])
{
  int index, rc;
  ares_channel channel;
  struct ares_options options;

  luvit__suck_in_symbols();

  memset(&options, 0, sizeof(options));

  rc = ares_library_init(ARES_LIB_INIT_ALL);
  assert(rc == ARES_SUCCESS);

  // Pull up the preload table
  lua_getglobal(L, "package");
  lua_getfield(L, -1, "preload");
  lua_remove(L, -2);

  // Register yajl
  lua_pushcfunction(L, luaopen_yajl);
  lua_setfield(L, -2, "yajl");
  // Register os
  lua_pushcfunction(L, luaopen_os_binding);
  lua_setfield(L, -2, "os_binding");
  // Register http_parser
  lua_pushcfunction(L, luaopen_http_parser);
  lua_setfield(L, -2, "http_parser");
  // Register uv
  lua_pushcfunction(L, luaopen_uv);
  lua_setfield(L, -2, "uv");
  // Register env
  lua_pushcfunction(L, luaopen_env);
  lua_setfield(L, -2, "env");
  // Register constants
  lua_pushcfunction(L, luaopen_constants);
  lua_setfield(L, -2, "constants");

  // We're done with preload, put it away
  lua_pop(L, 1);

  // Get argv
  lua_createtable (L, argc, 0);
  for (index = 0; index < argc; index++) {
    lua_pushstring (L, argv[index]);
    lua_rawseti(L, -2, index);
  }
  lua_setglobal(L, "argv");

  lua_pushcfunction(L, luvit_exit);
  lua_setglobal(L, "exit_process");

  lua_pushcfunction(L, luvit_print_stderr);
  lua_setglobal(L, "print_stderr");

  lua_pushcfunction(L, luvit_getcwd);
  lua_setglobal(L, "getcwd");

  lua_pushstring(L, LUVIT_VERSION);
  lua_setglobal(L, "VERSION");

  lua_pushstring(L, UV_VERSION);
  lua_setglobal(L, "UV_VERSION");
  
  lua_pushstring(L, LUAJIT_VERSION);
  lua_setglobal(L, "LUAJIT_VERSION");

  lua_pushstring(L, HTTP_VERSION);
  lua_setglobal(L, "HTTP_VERSION");

  lua_pushstring(L, YAJL_VERSIONISH);
  lua_setglobal(L, "YAJL_VERSION");

  // Hold a reference to the main thread in the registry
  assert(lua_pushthread(L) == 1);
  lua_setfield(L, LUA_REGISTRYINDEX, "main_thread");

  // Store the loop within the registry
  luv_set_loop(L, loop);

  // Store the ARES Channel
  uv_ares_init_options(luv_get_loop(L), &channel, &options, 0);
  luv_set_ares_channel(L, &channel);

  return 0;
}
Example #24
0
int luv_new_tcp (lua_State* L) {
  uv_tcp_t* handle = luv_create_tcp(L);
  uv_tcp_init(luv_get_loop(L), handle);
  return 1;
}
Example #25
0
int luv_now(lua_State* L) {
  double now = (double)uv_now(luv_get_loop(L));
  lua_pushnumber(L, now);
  return 1;
}
Example #26
0
int luv_print_all_handles(lua_State* L) {
  uv_print_all_handles(luv_get_loop(L));
  return 0;
}
Example #27
0
static int luv_now(lua_State* L)
{
    uint64_t now = uv_now(luv_get_loop(L));
    lua_pushnumber(L, (lua_Number)now);
    return 1;
}
Example #28
0
int luv_update_time(lua_State* L) {
  uv_update_time(luv_get_loop(L));
  return 0;
}
Example #29
0
uv_loop_t* virgo_get_loop(virgo_t *v) {
  return luv_get_loop(v->L);
}
Example #30
0
// Initializes uv_process_t and starts the process.
int luv_spawn(lua_State* L) {
  int before = lua_gettop(L);
  uv_pipe_t* stdin_stream = (uv_pipe_t*)luv_checkudata(L, 1, "pipe");
  uv_pipe_t* stdout_stream = (uv_pipe_t*)luv_checkudata(L, 2, "pipe");
  uv_pipe_t* stderr_stream = (uv_pipe_t*)luv_checkudata(L, 3, "pipe");
  const char* command = luaL_checkstring(L, 4);
  size_t argc;
  char** args;
  int i;
  char* cwd;
  char** env;
  uv_process_options_t options;
  uv_process_t* handle;
  int r;
  luv_ref_t* ref;

  luaL_checktype(L, 5, LUA_TTABLE); // args
  luaL_checktype(L, 6, LUA_TTABLE); // options

  // Parse the args array
  argc = lua_objlen(L, 5) + 1;
  args = malloc((argc + 1) * sizeof(char*));
  args[0] = (char*)command;
  for (i = 1; i < argc; i++) {
    lua_rawgeti(L, 5, i);
    args[i] = (char*)lua_tostring(L, -1);
    lua_pop(L, 1);
  }
  args[argc] = NULL;

  // Get the cwd
  lua_getfield(L, 6, "cwd");
  cwd = (char*)lua_tostring(L, -1);
  lua_pop(L, 1);

  // Get the env
  lua_getfield(L, 6, "env");
  env = NULL;
  if (lua_type(L, -1) == LUA_TTABLE) {
    argc = lua_objlen(L, -1);
    env = malloc((argc + 1) * sizeof(char*));
    for (i = 0; i < argc; i++) {
      lua_rawgeti(L, -1, i + 1);
      env[i] = (char*)lua_tostring(L, -1);
      lua_pop(L, 1);
    }
    env[argc] = NULL;
  }
  lua_pop(L, 1);

  options.exit_cb = luv_process_on_exit;
  options.file = command;
  options.args = args;
  
  options.env = env ? env : luv_os_environ();
  options.cwd = cwd;
  options.stdin_stream = stdin_stream;
  options.stdout_stream = stdout_stream;
  options.stderr_stream = stderr_stream;

  // Create the userdata
  handle = (uv_process_t*)lua_newuserdata(L, sizeof(uv_process_t));
  r = uv_spawn(luv_get_loop(L), handle, options);
  free(args);
  if (env) free(env);
  if (r) {
    uv_err_t err = uv_last_error(luv_get_loop(L));
    return luaL_error(L, "spawn: %s", uv_strerror(err));
  }

  // Set metatable for type
  luaL_getmetatable(L, "luv_process");
  lua_setmetatable(L, -2);

  // Create a local environment for storing stuff
  lua_newtable(L);
  lua_setfenv (L, -2);

  // Store a reference to the userdata in the handle
  ref = (luv_ref_t*)malloc(sizeof(luv_ref_t));
  ref->L = L;
  lua_pushvalue(L, -1); // duplicate so we can _ref it
  ref->r = luaL_ref(L, LUA_REGISTRYINDEX);
  handle->data = ref;

  assert(lua_gettop(L) == before + 1);
  // return the userdata
  return 1;
}