[0.1.1-1] raw UDP support \:D/
This commit is contained in:
parent
5091a86bdc
commit
f59063c97c
@ -582,6 +582,25 @@ remain = common.tcp_send(tcpsockfd, data) @
|
||||
common.tcp_close(tcpsockfd) @
|
||||
closes a TCP socket
|
||||
|
||||
udpsockfd = common.udp_open() @
|
||||
creates a raw UDP socket
|
||||
returns nil on socket creation failure
|
||||
throws an error in other weird situations
|
||||
|
||||
data, host, port = common.udp_recvfrom(udpsockfd) @
|
||||
receives from a UDP socket
|
||||
returns an empty string + nils if nothing arrived
|
||||
returns false on error, such as disconnection
|
||||
|
||||
remain = common.udp_sendto(udpsockfd, data, host, port) @
|
||||
sends data to a host using a UDP socket
|
||||
|
||||
returns the data that wasn't quite sent just yet, which can be an empty string
|
||||
returns false on error, such as disconnection
|
||||
|
||||
common.udp_close(udpsockfd) @
|
||||
closes a UDP socket
|
||||
|
||||
wav = common.wav_load(fname) @
|
||||
loads a sound with filename "fname"
|
||||
remember to free it when you're done
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define VERSION_X 1
|
||||
#define VERSION_Y 1
|
||||
#define VERSION_A 0
|
||||
#define VERSION_Z 0
|
||||
#define VERSION_Z 1
|
||||
// Remember to bump "Z" basically every time you change the engine!
|
||||
// Remember to bump the version in Lua too!
|
||||
// Remember to document API changes in a new version!
|
||||
|
@ -21,6 +21,21 @@ if common.version.num < 4227072 then
|
||||
-- but I *do* want the server to stay up to date.
|
||||
end
|
||||
|
||||
-- UDP port test.
|
||||
if false then
|
||||
local sk = common.udp_open()
|
||||
print("sk:", sk)
|
||||
m = common.udp_sendto(sk, "Hello World!", "127.0.0.1", 9999)
|
||||
print("M:", m)
|
||||
local ctime = common.time()
|
||||
while common.time() <= ctime do end
|
||||
local m2, h, p
|
||||
m2, h, p = common.udp_recvfrom(sk)
|
||||
print("recv:", m2, h, p)
|
||||
common.udp_sendto(sk, "pang", h, p)
|
||||
common.udp_close(sk)
|
||||
end
|
||||
|
||||
dofile("pkg/base/preconf.lua")
|
||||
dofile("pkg/base/lib_util.lua")
|
||||
|
||||
|
@ -100,5 +100,7 @@ VERSION_BUGS = {
|
||||
{intro=4194304+3, fix=nil, msg="[OpenGL] Frustum culling still screws up on occasion"},
|
||||
{intro=nil, fix=4194304+8, msg="Occasional crash when music is stopped"},
|
||||
{intro=4194304+1, fix=4194304+9, msg="Raw TCP still throws a lua error if it can't connect"},
|
||||
{intro=nil, fix=4227072+1, msg="Arbitrary UDP connections not supported"},
|
||||
{intro=4227072+1, fix=nil, msg="Raw UDP support might be a bit flaky - if you find bugs, please tell us!"},
|
||||
}
|
||||
|
||||
|
@ -87,8 +87,9 @@ int icelua_force_get_integer(lua_State *L, int table, char *name)
|
||||
#include "lua_model.h"
|
||||
#include "lua_net.h"
|
||||
#include "lua_tcp.h"
|
||||
#include "lua_wav.h"
|
||||
#include "lua_udp.h"
|
||||
#include "lua_util.h"
|
||||
#include "lua_wav.h"
|
||||
|
||||
// common functions
|
||||
|
||||
@ -172,6 +173,10 @@ struct icelua_entry icelua_common[] = {
|
||||
{icelua_fn_common_tcp_send, "tcp_send"},
|
||||
{icelua_fn_common_tcp_recv, "tcp_recv"},
|
||||
{icelua_fn_common_tcp_close, "tcp_close"},
|
||||
{icelua_fn_common_udp_open, "udp_open"},
|
||||
{icelua_fn_common_udp_sendto, "udp_sendto"},
|
||||
{icelua_fn_common_udp_recvfrom, "udp_recvfrom"},
|
||||
{icelua_fn_common_udp_close, "udp_close"},
|
||||
{icelua_fn_common_wav_load, "wav_load"},
|
||||
{icelua_fn_common_wav_free, "wav_free"},
|
||||
{icelua_fn_common_mus_load_it, "mus_load_it"},
|
||||
|
@ -51,6 +51,7 @@ int icelua_fn_common_tcp_connect(lua_State *L) {
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
|
||||
ret = connect(sockfd, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo(res);
|
||||
if(ret == -1)
|
||||
return 0;
|
||||
#ifdef WIN32
|
||||
|
201
src/lua_udp.h
Normal file
201
src/lua_udp.h
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
This file is part of Iceball.
|
||||
|
||||
Iceball is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Iceball is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Iceball. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
|
||||
|
||||
int whitelist_validate(const char *name, int port);
|
||||
|
||||
int icelua_fn_common_udp_open(lua_State *L) {
|
||||
int top = icelua_assert_stack(L, 0, 0);
|
||||
|
||||
int ret, sockfd;
|
||||
const char *host;
|
||||
char port_ch[18];
|
||||
int port = 0;
|
||||
|
||||
// TODO: support IPv6
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sockfd == -1)
|
||||
return 0;
|
||||
#ifdef WIN32
|
||||
int yes = 1;
|
||||
if (ioctlsocket(sockfd, FIONBIO, (u_long *)&yes) == -1) {
|
||||
#else
|
||||
if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK) == -1) {
|
||||
#endif
|
||||
return luaL_error(L, "Could not set up a nonblocking connection!");
|
||||
}
|
||||
|
||||
lua_pushnumber(L, sockfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int icelua_fn_common_udp_recvfrom(lua_State *L) {
|
||||
int top = icelua_assert_stack(L, 1, 1);
|
||||
|
||||
int sockfd;
|
||||
int n = 0;
|
||||
|
||||
struct sockaddr_in saddr;
|
||||
char buf[4096];
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
sockfd = lua_tonumber(L, 1);
|
||||
} else {
|
||||
luaL_error(L, "not a number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
socklen_t sadlen = sizeof(saddr);
|
||||
n = recvfrom(sockfd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&saddr, &sadlen);
|
||||
if (n == -1) {
|
||||
#ifdef WIN32
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) {
|
||||
#else
|
||||
int err = errno;
|
||||
if (err != EAGAIN && err != EWOULDBLOCK) {
|
||||
#endif
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
#ifdef WIN32
|
||||
} else if (err == WSAEWOULDBLOCK) {
|
||||
#else
|
||||
} else if (err == EWOULDBLOCK || err == EAGAIN) {
|
||||
#endif
|
||||
lua_pushstring(L, "");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushlstring(L, buf, n);
|
||||
|
||||
// TODO: support IPv6
|
||||
char dst_buf[50];
|
||||
const char *astr = inet_ntop(AF_INET, &(saddr.sin_addr.s_addr), dst_buf, sizeof(dst_buf)-1);
|
||||
if(astr == NULL)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
lua_pushstring(L, astr);
|
||||
|
||||
lua_pushinteger(L, ntohs(saddr.sin_port));
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
int icelua_fn_common_udp_sendto(lua_State *L) {
|
||||
int top = icelua_assert_stack(L, 4, 4);
|
||||
|
||||
int sockfd;
|
||||
struct addrinfo hints, *res;
|
||||
char port_ch[18];
|
||||
const char *data;
|
||||
const char *host;
|
||||
int port = 0;
|
||||
int length;
|
||||
int sent;
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
sockfd = lua_tonumber(L, 1);
|
||||
} else {
|
||||
luaL_error(L, "not a number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lua_isstring(L, 2)) {
|
||||
data = lua_tostring(L, 2);
|
||||
} else {
|
||||
luaL_error(L, "not a string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lua_isstring(L, 3)) {
|
||||
host = lua_tostring(L, 3);
|
||||
} else {
|
||||
return luaL_error(L, "not a string");
|
||||
}
|
||||
|
||||
if (lua_isnumber(L, 4)) {
|
||||
port = lua_tonumber(L, 4);
|
||||
} else {
|
||||
return luaL_error(L, "not a number");
|
||||
}
|
||||
|
||||
if(L == lstate_client && !whitelist_validate(host, port))
|
||||
return luaL_error(L, "address/port not on whitelist!");
|
||||
|
||||
// FIXME: the host lookup result should ideally be cached
|
||||
// FIXME: make note of the address family used / socktype
|
||||
// TODO: support IPv6
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
snprintf(port_ch, 17, "%u", port);
|
||||
|
||||
getaddrinfo(host, port_ch, &hints, &res);
|
||||
|
||||
length = lua_strlen(L, 2);
|
||||
sent = sendto(sockfd, data, length, 0, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo(res);
|
||||
|
||||
if (sent <= 0) {
|
||||
#ifdef WIN32
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) {
|
||||
#else
|
||||
int err = errno;
|
||||
if (err != EAGAIN && err != EWOULDBLOCK) {
|
||||
#endif
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
#ifdef WIN32
|
||||
} else if (err == WSAEWOULDBLOCK) {
|
||||
#else
|
||||
} else if (err == EWOULDBLOCK || err == EAGAIN) {
|
||||
#endif
|
||||
lua_pushlstring(L, data, length);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sent < length)
|
||||
lua_pushlstring(L, data + sent, length - sent);
|
||||
else
|
||||
lua_pushstring(L, "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int icelua_fn_common_udp_close(lua_State *L) {
|
||||
int top = icelua_assert_stack(L, 1, 1);
|
||||
|
||||
int sockfd;
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
sockfd = lua_tonumber(L, 1);
|
||||
} else {
|
||||
luaL_error(L, "not a number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user