Skip to content

Commit

Permalink
Merge pull request #318 from squeek502/libuv-1.27.0
Browse files Browse the repository at this point in the history
Update to Libuv 1.27.0
  • Loading branch information
zhaozg committed Mar 22, 2019
2 parents 749a8a2 + 892b610 commit 727c883
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 21 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ endif()
project (luv C ASM)

set(LUV_VERSION_MAJOR 1)
set(LUV_VERSION_MINOR 26)
set(LUV_VERSION_MINOR 27)
set(LUV_VERSION_PATCH 0)
set(LUV_VERSION ${LUV_VERSION_MAJOR}.${LUV_VERSION_MINOR}.${LUV_VERSION_PATCH})

Expand Down
8 changes: 8 additions & 0 deletions src/luv.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ static const luaL_Reg luv_functions[] = {
{"udp_try_send", luv_udp_try_send},
{"udp_recv_start", luv_udp_recv_start},
{"udp_recv_stop", luv_udp_recv_stop},
#if LUV_UV_VERSION_GEQ(1, 27, 0)
{"udp_connect", luv_udp_connect},
{"udp_getpeername", luv_udp_getpeername},
#endif

// fs_event.c
{"new_fs_event", luv_new_fs_event},
Expand Down Expand Up @@ -436,6 +440,10 @@ static const luaL_Reg luv_udp_methods[] = {
{"try_send", luv_udp_try_send},
{"recv_start", luv_udp_recv_start},
{"recv_stop", luv_udp_recv_stop},
#if LUV_UV_VERSION_GEQ(1, 27, 0)
{"connect", luv_udp_connect},
{"getpeername", luv_udp_getpeername},
#endif
{NULL, NULL}
};

Expand Down
93 changes: 74 additions & 19 deletions src/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,25 +171,63 @@ static void luv_udp_send_cb(uv_udp_send_t* req, int status) {
req->data = NULL;
}

static struct sockaddr* luv_check_addr(lua_State *L, struct sockaddr_storage* addr, int hostidx, int portidx) {
const char* host;
int port;
#if LUV_UV_VERSION_GEQ(1, 27, 0)
int host_type, port_type;
host_type = lua_type(L, hostidx);
port_type = lua_type(L, portidx);
if (host_type == LUA_TNIL && port_type == LUA_TNIL) {
return NULL;
}
host = lua_tostring(L, hostidx);
port = lua_tointeger(L, portidx);
if (host_type == LUA_TSTRING && port_type == LUA_TNUMBER) {
if (uv_ip4_addr(host, port, (struct sockaddr_in*)addr) &&
uv_ip6_addr(host, port, (struct sockaddr_in6*)addr)) {
luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
return NULL;
}
return (struct sockaddr*)addr;
}
else {
if (host_type == LUA_TNIL || port_type == LUA_TNIL) {
luaL_argerror(L, host_type == LUA_TNIL ? portidx : hostidx,
"Both host and port must be nil if one is nil");
}
luaL_argcheck(L, host_type == LUA_TNIL || host_type == LUA_TSTRING, hostidx,
"Host must be string or nil");
luaL_argcheck(L, port_type == LUA_TNIL || port_type == LUA_TNUMBER, portidx,
"Port must be number or nil");
}
#else
host = luaL_checkstring(L, hostidx);
port = luaL_checkinteger(L, portidx);
if (uv_ip4_addr(host, port, (struct sockaddr_in*)addr) &&
uv_ip6_addr(host, port, (struct sockaddr_in6*)addr)) {
luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
return NULL;
}
return (struct sockaddr*)addr;
#endif
}

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;
int ret, ref;
struct sockaddr_storage addr;
struct sockaddr* addr_ptr;

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);
}
addr_ptr = luv_check_addr(L, &addr, 3, 4);
ref = luv_check_continuation(L, 5);
req = (uv_udp_send_t*)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);
ret = uv_udp_send(req, handle, &buf, 1, addr_ptr, luv_udp_send_cb);
if (ret < 0) {
luv_cleanup_req(L, (luv_req_t*)req->data);
lua_pop(L, 1);
Expand All @@ -200,24 +238,19 @@ static int luv_udp_send(lua_State* L) {
((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pop(L, 1);

lua_pushinteger(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;
int ret;
struct sockaddr_storage addr;
struct sockaddr* addr_ptr;
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);
addr_ptr = luv_check_addr(L, &addr, 3, 4);
ret = uv_udp_try_send(handle, &buf, 1, addr_ptr);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
Expand Down Expand Up @@ -290,3 +323,25 @@ static int luv_udp_recv_stop(lua_State* L) {
lua_pushinteger(L, ret);
return 1;
}

#if LUV_UV_VERSION_GEQ(1, 27, 0)
static int luv_udp_connect(lua_State* L) {
uv_udp_t* handle = luv_check_udp(L, 1);
struct sockaddr_storage addr;
struct sockaddr* addr_ptr = luv_check_addr(L, &addr, 2, 3);
int ret = uv_udp_connect(handle, addr_ptr);
if (ret < 0) return luv_error(L, ret);
lua_pushinteger(L, ret);
return 1;
}

static int luv_udp_getpeername(lua_State* L) {
uv_udp_t* handle = luv_check_udp(L, 1);
struct sockaddr_storage address;
int addrlen = sizeof(address);
int ret = uv_udp_getpeername(handle, (struct sockaddr*)&address, &addrlen);
if (ret < 0) return luv_error(L, ret);
parse_sockaddr(L, &address);
return 1;
}
#endif
159 changes: 159 additions & 0 deletions tests/test-udp.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
local TEST_PORT = 9123

return require('lib/tap')(function (test)
test("basic udp server and client (ipv4)", function (print, p, expect, uv)
local server = uv.new_udp()
assert(uv.udp_bind(server, "0.0.0.0", TEST_PORT))
assert(uv.udp_recv_start(server, expect(function (err, data, addr, flags)
p("server on recv", server, data, addr, flags)
assert(not err, err)
assert(data == "PING")
uv.close(server, expect(function()
p("server on close", server)
end))
end)))
p{server=server}

local client = uv.new_udp()
local req = assert(uv.udp_send(client, "PING", "127.0.0.1", TEST_PORT, expect(function (err)
p("client on send", client, err)
assert(not err, err)
uv.close(client, expect(function()
p("client on close", client)
end))
end)))
p{client=client,req=req}
end)

test("basic udp server and client (ipv6)", function (print, p, expect, uv)
local server = uv.new_udp()
local _, err = uv.udp_bind(server, "::1", TEST_PORT)
if err then
p("ipv6 unavailable", err)
uv.close(server)
return
end
assert(uv.udp_recv_start(server, expect(function (err, data, addr, flags)
p("server on recv", server, data, addr, flags)
assert(not err, err)
assert(data == "PING")
uv.close(server, expect(function()
p("server on close", server)
end))
end)))
p{server=server}

local client = uv.new_udp()
local req = assert(uv.udp_send(client, "PING", "::1", TEST_PORT, expect(function (err)
p("client on send", client, err)
assert(not err, err)
uv.close(client, expect(function()
p("client on close", client)
end))
end)))
p{client=client,req=req}
end)

test("udp send args", function(print, p, expect, uv)
local version = 0x10000 + 27*0x100 + 0
if uv.version() < version then
print("skipped, requires libuv >= 1.27.0")
return
end

local udp = uv.new_udp()

local _, err = pcall(function() uv.udp_send(udp, "PING", 5, 5) end)
print(assert(err))
_, err = pcall(function() uv.udp_send(udp, "PING", "host", "port") end)
print(assert(err))
_, err = pcall(function() uv.udp_send(udp, "PING", "host", nil) end)
print(assert(err))
_, err = pcall(function() uv.udp_send(udp, "PING", nil, 5) end)
print(assert(err))

uv.close(udp)
end)

test("udp connect", function(print, p, expect, uv)
local version = 0x10000 + 27*0x100 + 0
if uv.version() < version then
print("skipped, requires libuv >= 1.27.0")
return
end

local server = uv.new_udp()
local client = uv.new_udp()

assert(uv.udp_bind(server, "0.0.0.0", TEST_PORT))
local numRecvs = 0
assert(uv.udp_recv_start(server, function (err, data, addr, flags)
p("server on recv", server, data, addr, flags)
assert(not err, err)
-- nil data signifies nothing more to read
if data ~= nil then
assert(data == "PING", data)
numRecvs = numRecvs + 1
if numRecvs == 4 then
uv.close(server, expect(function()
p("server on close", server)
end))
uv.close(client, expect(function()
p("client on close", client)
end))
end
end
end))
p{server=server}

assert(uv.udp_connect(client, "127.0.0.1", TEST_PORT))
local _, err = uv.udp_connect(client, "8.8.8.8", TEST_PORT)
assert(err and err:sub(1,7) == "EISCONN", err)

local addr = assert(uv.udp_getpeername(client))
p(addr)
assert(addr.ip == "127.0.0.1")
assert(addr.port == TEST_PORT)

-- To send messages in connected UDP sockets addr must be NULL
_, err = uv.udp_try_send(client, "PING", "127.0.0.1", TEST_PORT)
assert(err and err:sub(1,7) == "EISCONN", err)

local r = assert(uv.udp_try_send(client, "PING", nil, nil))
assert(r == 4)

_, err = uv.udp_try_send(client, "PING", "8.8.8.8", TEST_PORT)
assert(err and err:sub(1,7) == "EISCONN", err)

assert(uv.udp_connect(client, nil, nil))
_, err = uv.udp_connect(client, nil, nil)
assert(err and err:sub(1,8) == "ENOTCONN", err)

_, err = uv.udp_getpeername(client)
assert(err and err:sub(1,8) == "ENOTCONN", err)

r = uv.udp_try_send(client, "PING", "127.0.0.1", TEST_PORT)
assert(r == 4)
_, err = uv.udp_try_send(client, "PING", nil, nil)
assert(err and err:sub(1,12) == "EDESTADDRREQ", err)

assert(uv.udp_connect(client, "127.0.0.1", TEST_PORT))
_, err = uv.udp_send(client, "PING", "127.0.0.1", TEST_PORT, function()
error("this send should fail")
end)
assert(err and err:sub(1,7) == "EISCONN", err)

assert(uv.udp_send(client, "PING", nil, nil, expect(function(err)
assert(not err, err)
uv.udp_connect(client, nil, nil)
_, err = uv.udp_send(client, "PING", nil, nil, function()
error("this send should fail")
end)
assert(err and err:sub(1,12) == "EDESTADDRREQ", err)

uv.udp_send(client, "PING", "127.0.0.1", TEST_PORT, expect(function(err)
assert(not err, err)
end))
end)))
end)
end)

0 comments on commit 727c883

Please sign in to comment.