buldthensnip/src/lua_tcp.h

194 lines
4.2 KiB
C

/*
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/>.
*/
#ifndef _MSC_VER
#include <unistd.h> //fixes some warning, some POSIX shit ~Dany0
#endif
int whitelist_validate(const char *name, int port);
int icelua_fn_common_tcp_connect(lua_State *L) {
int top = icelua_assert_stack(L, 2, 2);
struct addrinfo hints, *res;
int ret, sockfd;
const char *host;
char port_ch[18];
int port = 0;
if (lua_isstring(L, 1)) {
host = lua_tostring(L, 1);
} else {
return luaL_error(L, "not a string");
}
if (lua_isnumber(L, 2)) {
port = lua_tonumber(L, 2);
} 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!");
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(port_ch, 17, "%u", port);
if(getaddrinfo(host, port_ch, &hints, &res) != 0)
{
if(res != NULL) freeaddrinfo(res);
return 0;
}
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
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!");
}
if (ret < 0) {
// API change in 0.1-2: return nil on connection failure
//luaL_error(L, "connect() failed");
return 0;
}
lua_pushnumber(L, sockfd);
return 1;
}
int icelua_fn_common_tcp_recv(lua_State *L) {
int top = icelua_assert_stack(L, 1, 1);
int sockfd;
int n = 0;
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;
}
n = recv(sockfd, buf, sizeof(buf) - 1, 0);
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);
return 1;
}
int icelua_fn_common_tcp_send(lua_State *L) {
int top = icelua_assert_stack(L, 2, 2);
int sockfd;
const char *data;
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;
}
length = lua_strlen(L, 2);
sent = send(sockfd, data, length, 0);
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_tcp_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;
}