summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/luv/src/udp.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/luv/src/udp.c')
-rw-r--r--3rdparty/luv/src/udp.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/3rdparty/luv/src/udp.c b/3rdparty/luv/src/udp.c
new file mode 100644
index 00000000000..9cc25555559
--- /dev/null
+++ b/3rdparty/luv/src/udp.c
@@ -0,0 +1,260 @@
+/*
+ * 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 uv_udp_t* luv_check_udp(lua_State* L, int index) {
+ uv_udp_t* handle = luv_checkudata(L, index, "uv_udp");
+ luaL_argcheck(L, handle->type == UV_UDP && handle->data, index, "Expected uv_udp_t");
+ return handle;
+}
+
+static int luv_new_udp(lua_State* L) {
+ uv_udp_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_udp_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 luv_udp_open(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ uv_os_sock_t sock = luaL_checkinteger(L, 2);
+ int ret = uv_udp_open(handle, sock);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_bind(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ const char* host = luaL_checkstring(L, 2);
+ int port = luaL_checkinteger(L, 3);
+ unsigned int flags = 0;
+ struct sockaddr_storage addr;
+ int ret;
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ if (lua_type(L, 4) == LUA_TTABLE) {
+ luaL_checktype(L, 4, LUA_TTABLE);
+ lua_getfield(L, 4, "reuseaddr");
+ if (lua_toboolean(L, -1)) flags |= UV_UDP_REUSEADDR;
+ lua_pop(L, 1);
+ lua_getfield(L, 4, "ipv6only");
+ if (lua_toboolean(L, -1)) flags |= UV_UDP_IPV6ONLY;
+ lua_pop(L, 1);
+ }
+ ret = uv_udp_bind(handle, (struct sockaddr*)&addr, flags);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_getsockname(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ struct sockaddr_storage address;
+ int addrlen = sizeof(address);
+ int ret = uv_udp_getsockname(handle, (struct sockaddr*)&address, &addrlen);
+ if (ret < 0) return luv_error(L, ret);
+ parse_sockaddr(L, &address, addrlen);
+ return 1;
+}
+
+// These are the same order as uv_membership which also starts at 0
+static const char *const luv_membership_opts[] = {
+ "leave", "join", NULL
+};
+
+static int luv_udp_set_membership(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ const char* multicast_addr = luaL_checkstring(L, 2);
+ const char* interface_addr = luaL_checkstring(L, 3);
+ uv_membership membership = luaL_checkoption(L, 4, NULL, luv_membership_opts);
+ int ret = uv_udp_set_membership(handle, multicast_addr, interface_addr, membership);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_multicast_loop(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int on, ret;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ on = lua_toboolean(L, 2);
+ ret = uv_udp_set_multicast_loop(handle, on);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_multicast_ttl(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ttl, ret;
+ ttl = luaL_checkinteger(L, 2);
+ ret = uv_udp_set_multicast_ttl(handle, ttl);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_multicast_interface(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ const char* interface_addr = luaL_checkstring(L, 2);
+ int ret = uv_udp_set_multicast_interface(handle, interface_addr);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_broadcast(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int on, ret;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ on = lua_toboolean(L, 2);
+ ret =uv_udp_set_broadcast(handle, on);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_ttl(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ttl, ret;
+ ttl = luaL_checknumber(L, 2);
+ ret = uv_udp_set_ttl(handle, ttl);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void luv_udp_send_cb(uv_udp_send_t* req, int status) {
+ lua_State* L = luv_state(req->handle->loop);
+ luv_status(L, status);
+ luv_fulfill_req(L, req->data, 1);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+}
+
+static int luv_udp_send(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ uv_udp_send_t* req;
+ uv_buf_t buf;
+ int ret, port, ref;
+ const char* host;
+ struct sockaddr_storage addr;
+ luv_check_buf(L, 2, &buf);
+ host = luaL_checkstring(L, 3);
+ port = luaL_checkinteger(L, 4);
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ ref = luv_check_continuation(L, 5);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ ret = uv_udp_send(req, handle, &buf, 1, (struct sockaddr*)&addr, luv_udp_send_cb);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ return 1;
+
+}
+
+static int luv_udp_try_send(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ uv_buf_t buf;
+ int ret, port;
+ const char* host;
+ struct sockaddr_storage addr;
+ luv_check_buf(L, 2, &buf);
+ host = luaL_checkstring(L, 3);
+ port = luaL_checkinteger(L, 4);
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ ret = uv_udp_try_send(handle, &buf, 1, (struct sockaddr*)&addr);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void luv_udp_recv_cb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
+ lua_State* L = luv_state(handle->loop);
+
+ // err
+ if (nread < 0) {
+ luv_status(L, nread);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ // data
+ if (nread == 0) {
+ if (addr) {
+ lua_pushstring(L, "");
+ }
+ else {
+ lua_pushnil(L);
+ }
+ }
+ else if (nread > 0) {
+ lua_pushlstring(L, buf->base, nread);
+ }
+ if (buf) free(buf->base);
+
+ // address
+ if (addr) {
+ parse_sockaddr(L, (struct sockaddr_storage*)addr, sizeof *addr);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ // flags
+ lua_newtable(L);
+ if (flags & UV_UDP_PARTIAL) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, -2, "partial");
+ }
+
+ luv_call_callback(L, handle->data, LUV_RECV, 4);
+}
+
+static int luv_udp_recv_start(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_RECV, 2);
+ ret = uv_udp_recv_start(handle, luv_alloc_cb, luv_udp_recv_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_recv_stop(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ret = uv_udp_recv_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}