2000-06-02 19:55:14 +02:00
|
|
|
/*=========================================================================*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* IPv4 Sockets for the Lua language
|
2000-06-02 19:55:14 +02:00
|
|
|
* Diego Nehab
|
|
|
|
* 26/11/1999
|
|
|
|
*
|
2001-01-25 22:53:02 +01:00
|
|
|
* Module: luasocket.c
|
2000-06-02 19:55:14 +02:00
|
|
|
*
|
|
|
|
* This module is part of an effort to make the most important features
|
2001-01-25 22:53:02 +01:00
|
|
|
* of the IPv4 Socket layer available to Lua scripts.
|
2000-06-02 19:55:14 +02:00
|
|
|
* The Lua interface to TCP/IP follows the BSD TCP/IP API closely,
|
|
|
|
* trying to simplify all tasks involved in setting up a client connection
|
2001-03-12 21:04:25 +01:00
|
|
|
* and server connections.
|
2000-06-02 19:55:14 +02:00
|
|
|
* The provided IO routines, send and receive, follow the Lua style, being
|
2001-03-12 21:04:25 +01:00
|
|
|
* very similar to the standard Lua read and write functions.
|
2000-06-02 19:55:14 +02:00
|
|
|
* The module implements both a BSD bind and a Winsock2 bind, and has
|
|
|
|
* been tested on several Unix flavors, as well as Windows 98 and NT.
|
|
|
|
\*=========================================================================*/
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Common include files
|
|
|
|
\*=========================================================================*/
|
2001-01-13 08:10:00 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
2000-06-02 19:55:14 +02:00
|
|
|
#include <stdlib.h>
|
2001-06-09 00:22:37 +02:00
|
|
|
#include <string.h>
|
2001-03-12 21:04:25 +01:00
|
|
|
#include <ctype.h>
|
2000-06-02 19:55:14 +02:00
|
|
|
|
|
|
|
#include <lauxlib.h>
|
2001-01-13 08:10:00 +01:00
|
|
|
#include <lua.h>
|
2000-06-02 19:55:14 +02:00
|
|
|
|
2000-12-27 20:19:22 +01:00
|
|
|
#include "luasocket.h"
|
2000-06-02 19:55:14 +02:00
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* WinSock2 include files
|
|
|
|
\*=========================================================================*/
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include <winbase.h>
|
2001-01-13 08:10:00 +01:00
|
|
|
#else
|
2000-06-02 19:55:14 +02:00
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* BSD include files
|
|
|
|
\*=========================================================================*/
|
|
|
|
/* close function */
|
|
|
|
#include <unistd.h>
|
|
|
|
/* fnctnl function and associated constants */
|
|
|
|
#include <fcntl.h>
|
|
|
|
/* struct timeval and CLK_TCK */
|
|
|
|
#include <sys/time.h>
|
|
|
|
/* times function and struct tms */
|
|
|
|
#include <sys/times.h>
|
|
|
|
/* internet protocol definitions */
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
/* struct sockaddr */
|
|
|
|
#include <sys/types.h>
|
|
|
|
/* socket function */
|
|
|
|
#include <sys/socket.h>
|
|
|
|
/* gethostbyname and gethostbyaddr functions */
|
|
|
|
#include <netdb.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Datatype compatibilization and some simple changes
|
|
|
|
\*=========================================================================*/
|
|
|
|
#ifndef WIN32
|
2001-03-06 20:03:10 +01:00
|
|
|
/* WinSock2 has a closesock function instead of the regular close */
|
|
|
|
#define closesocket close
|
|
|
|
/* it defines a SOCKET type instead of using an integer file descriptor */
|
|
|
|
#define SOCKET int
|
|
|
|
/* and uses the this macro to represent and invalid socket */
|
|
|
|
#define INVALID_SOCKET (-1)
|
|
|
|
/* SunOS, does not define CLK_TCK */
|
|
|
|
#ifndef CLK_TCK
|
2001-01-25 22:53:02 +01:00
|
|
|
#define CLK_TCK 60
|
2000-06-02 19:55:14 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Module definitions
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* The send and receive function can return one of the following return
|
|
|
|
* codes. The values are mapped into Lua values by the function
|
|
|
|
* push_error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
#define NET_DONE -1 /* operation completed successfully */
|
|
|
|
#define NET_TIMEOUT 0 /* operation timed out */
|
|
|
|
#define NET_CLOSED 1 /* the connection has been closed */
|
|
|
|
#define NET_REFUSED 2 /* the data transfer has been refused */
|
2000-06-02 19:55:14 +02:00
|
|
|
|
2001-01-13 08:10:00 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Time out mode to be checked
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
#define TM_RECEIVE 1
|
|
|
|
#define TM_SEND 2
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-15 05:16:35 +01:00
|
|
|
* Each socket is represented by a table with the supported methods and
|
|
|
|
* the p_sock structure as fields.
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
#define P_SOCK "(p_sock)sock"
|
2000-06-02 19:55:14 +02:00
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Both socket types are stored in the same structure to simplify
|
2001-01-13 08:10:00 +01:00
|
|
|
* implementation. The tag value used is different, though.
|
2001-01-25 22:53:02 +01:00
|
|
|
* The buffer parameters are not used by server and UDP sockets.
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
typedef struct t_sock {
|
2001-01-25 22:53:02 +01:00
|
|
|
/* operating system socket object */
|
|
|
|
SOCKET sock;
|
|
|
|
/* start time of the current operation */
|
|
|
|
int tm_start;
|
|
|
|
/* return and blocking timeout values (-1 if no limit) */
|
|
|
|
int tm_return, tm_block;
|
|
|
|
/* buffered I/O storage */
|
2001-03-06 20:03:10 +01:00
|
|
|
unsigned char bf_buffer[LUASOCKET_TCPBUFFERSIZE];
|
2001-01-25 22:53:02 +01:00
|
|
|
/* first and last red bytes not yet passed to application */
|
|
|
|
int bf_first, bf_last;
|
|
|
|
/* is this udp socket in "connected" state? */
|
|
|
|
int is_connected;
|
2001-01-15 05:16:35 +01:00
|
|
|
#ifdef _DEBUG
|
2001-01-25 22:53:02 +01:00
|
|
|
/* end time of current operation, for debug purposes */
|
|
|
|
int tm_end;
|
2001-01-15 05:16:35 +01:00
|
|
|
#endif
|
2000-06-02 19:55:14 +02:00
|
|
|
} t_sock;
|
|
|
|
typedef t_sock *p_sock;
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Tags passed as closure values to global LuaSocket API functions
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
typedef struct t_tags {
|
2001-01-25 22:53:02 +01:00
|
|
|
int client, server, table, udp;
|
2001-01-15 05:16:35 +01:00
|
|
|
} t_tags;
|
|
|
|
typedef t_tags *p_tags;
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Macros and internal declarations
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
/* min and max macros */
|
2001-03-06 20:03:10 +01:00
|
|
|
#ifndef MIN
|
|
|
|
#define MIN(x, y) ((x) < (y) ? x : y)
|
2000-06-02 19:55:14 +02:00
|
|
|
#endif
|
2001-03-06 20:03:10 +01:00
|
|
|
#ifndef MAX
|
|
|
|
#define MAX(x, y) ((x) > (y) ? x : y)
|
2000-06-02 19:55:14 +02:00
|
|
|
#endif
|
|
|
|
|
2001-01-25 22:53:02 +01:00
|
|
|
/* we are lazy.. */
|
|
|
|
typedef struct sockaddr SA;
|
|
|
|
|
2000-12-27 20:19:22 +01:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Internal function prototypes
|
|
|
|
\*=========================================================================*/
|
2001-01-25 22:53:02 +01:00
|
|
|
/* luasocket global API functions */
|
|
|
|
static int global_tcpconnect(lua_State *L);
|
|
|
|
static int global_tcpbind(lua_State *L);
|
2001-03-06 20:03:10 +01:00
|
|
|
static int global_select(lua_State *L);
|
2001-01-25 22:53:02 +01:00
|
|
|
static int global_toip(lua_State *L);
|
|
|
|
static int global_tohostname(lua_State *L);
|
2001-03-06 20:03:10 +01:00
|
|
|
static int global_udpsocket(lua_State *L);
|
2001-01-25 22:53:02 +01:00
|
|
|
|
2001-03-12 21:04:25 +01:00
|
|
|
#ifndef LUASOCKET_NOGLOBALS
|
2001-04-24 00:37:55 +02:00
|
|
|
static int global_callfromtable(lua_State *L);
|
2001-03-12 21:04:25 +01:00
|
|
|
#endif
|
|
|
|
|
2001-01-25 22:53:02 +01:00
|
|
|
/* luasocket table method API functions */
|
|
|
|
static int table_tcpaccept(lua_State *L);
|
|
|
|
static int table_tcpsend(lua_State *L);
|
|
|
|
static int table_tcpreceive(lua_State *L);
|
|
|
|
static int table_udpsendto(lua_State *L);
|
|
|
|
static int table_udpreceivefrom(lua_State *L);
|
|
|
|
static int table_udpsetpeername(lua_State *L);
|
2001-01-15 05:16:35 +01:00
|
|
|
static int table_timeout(lua_State *L);
|
|
|
|
static int table_close(lua_State *L);
|
2001-01-25 22:53:02 +01:00
|
|
|
static int table_getpeername(lua_State *L);
|
|
|
|
static int table_getsockname(lua_State *L);
|
|
|
|
|
2001-01-13 08:10:00 +01:00
|
|
|
/* buffered I/O management */
|
|
|
|
static const unsigned char *bf_receive(p_sock sock, int *length);
|
|
|
|
static void bf_skip(p_sock sock, int length);
|
|
|
|
static int bf_isempty(p_sock sock);
|
|
|
|
|
|
|
|
/* timeout management */
|
|
|
|
static int tm_timedout(p_sock sock, int mode);
|
|
|
|
static int tm_gettimeleft(p_sock sock);
|
|
|
|
static int tm_gettime(void);
|
|
|
|
static void tm_markstart(p_sock sock);
|
|
|
|
|
|
|
|
/* I/O */
|
|
|
|
static int send_raw(p_sock sock, const char *data, int wanted, int *err);
|
|
|
|
static int receive_raw(lua_State *L, p_sock sock, int wanted);
|
2001-03-12 21:04:25 +01:00
|
|
|
static int receive_word(lua_State *L, p_sock sock);
|
2001-01-13 08:10:00 +01:00
|
|
|
static int receive_dosline(lua_State *L, p_sock sock);
|
|
|
|
static int receive_unixline(lua_State *L, p_sock sock);
|
|
|
|
static int receive_all(lua_State *L, p_sock sock);
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/* parameter manipulation functions */
|
|
|
|
static p_tags pop_tags(lua_State *L);
|
|
|
|
static p_sock pop_sock(lua_State *L);
|
2001-03-06 20:03:10 +01:00
|
|
|
static p_sock get_sock(lua_State *L, int s, p_tags tags, int *tag);
|
2001-01-25 22:53:02 +01:00
|
|
|
static p_sock get_selfsock(lua_State *L, p_tags tags, int *tag);
|
2001-01-15 05:16:35 +01:00
|
|
|
static p_sock push_servertable(lua_State *L, p_tags tags);
|
|
|
|
static p_sock push_clienttable(lua_State *L, p_tags tags);
|
2001-01-25 22:53:02 +01:00
|
|
|
static p_sock push_udptable(lua_State *L, p_tags tags);
|
2001-01-15 05:16:35 +01:00
|
|
|
static void push_error(lua_State *L, int err);
|
2001-01-25 22:53:02 +01:00
|
|
|
static void push_resolved(lua_State *L, struct hostent *hp);
|
2000-12-27 20:19:22 +01:00
|
|
|
|
2001-01-13 08:10:00 +01:00
|
|
|
/* error code translations functions */
|
2000-12-27 20:19:22 +01:00
|
|
|
static char *host_strerror(void);
|
|
|
|
static char *bind_strerror(void);
|
2001-01-25 22:53:02 +01:00
|
|
|
static char *socket_strerror(void);
|
2000-12-27 20:19:22 +01:00
|
|
|
static char *connect_strerror(void);
|
|
|
|
|
2001-01-25 22:53:02 +01:00
|
|
|
/* socket auxiliary functions */
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *tcp_trybind(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port, int backlog);
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *tcp_tryconnect(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port);
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *udp_setpeername(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port);
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *udp_setsockname(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port);
|
2001-04-24 00:37:55 +02:00
|
|
|
static int set_option(lua_State *L, p_sock sock);
|
2001-01-25 22:53:02 +01:00
|
|
|
static void set_reuseaddr(p_sock sock);
|
2000-12-27 20:19:22 +01:00
|
|
|
static void set_blocking(p_sock sock);
|
|
|
|
static void set_nonblocking(p_sock sock);
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
static int winsock_open(void);
|
2001-01-25 22:53:02 +01:00
|
|
|
#define LUASOCKET_ATON
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LUASOCKET_ATON
|
|
|
|
static int inet_aton(const char *cp, struct in_addr *inp);
|
2001-01-15 05:16:35 +01:00
|
|
|
#endif
|
|
|
|
|
2001-01-25 22:53:02 +01:00
|
|
|
/* tag methods */
|
|
|
|
static int gc_table(lua_State *L);
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Test support functions
|
|
|
|
\*=========================================================================*/
|
|
|
|
#ifdef _DEBUG
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns the time the system has been up, in secconds.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
static int global_time(lua_State *L);
|
|
|
|
static int global_time(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
lua_pushnumber(L, tm_gettime()/1000.0);
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Causes a Lua script to sleep for the specified number of secconds
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
static int global_sleep(lua_State *L);
|
|
|
|
static int global_sleep(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
|
|
|
int sec = (int) luaL_check_number(L, 1);
|
|
|
|
#ifdef WIN32
|
|
|
|
Sleep(1000*sec);
|
|
|
|
#else
|
|
|
|
sleep(sec);
|
|
|
|
#endif
|
2001-01-25 22:53:02 +01:00
|
|
|
return 0;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Lua exported functions
|
|
|
|
* These functions can be accessed from a Lua script.
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Creates a client socket and returns it to the Lua script. The timeout
|
|
|
|
* values are initialized as -1 so that the socket will block at any
|
|
|
|
* IO operation.
|
2001-01-25 22:53:02 +01:00
|
|
|
* Lua Input: address, port
|
|
|
|
* address: host name or ip address to connect to
|
2000-06-02 19:55:14 +02:00
|
|
|
* port: port number on host
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* On success: client socket object
|
2000-06-02 19:55:14 +02:00
|
|
|
* On error: nil, followed by an error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int global_tcpconnect(lua_State *L)
|
|
|
|
{
|
|
|
|
p_tags tags = pop_tags(L);
|
|
|
|
const char *address = luaL_check_string(L, 1);
|
|
|
|
unsigned short port = (unsigned short) luaL_check_number(L, 2);
|
|
|
|
p_sock sock = push_clienttable(L, tags);
|
|
|
|
const char *err;
|
|
|
|
if (!sock) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, "out of memory");
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
err = tcp_tryconnect(sock, address, port);
|
|
|
|
if (err) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, err);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
set_nonblocking(sock);
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Creates a udp socket object and returns it to the Lua script.
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* On success: udp socket
|
2001-01-15 05:16:35 +01:00
|
|
|
* On error: nil, followed by an error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int global_udpsocket(lua_State *L)
|
2001-01-15 05:16:35 +01:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_tags tags = pop_tags(L);
|
2001-04-24 00:37:55 +02:00
|
|
|
int top = lua_gettop(L);
|
2001-01-25 22:53:02 +01:00
|
|
|
p_sock sock = push_udptable(L, tags);
|
|
|
|
if (!sock) return 2;
|
2001-06-04 22:44:39 +02:00
|
|
|
if (top >= 1 ) {
|
|
|
|
if (lua_istable(L, 1)) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
while (lua_next(L, 1)) {
|
|
|
|
if (!set_option(L, sock)) lua_error(L, "error setting option");
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
} else luaL_argerror(L, 1, "invalid options");
|
2001-04-24 00:37:55 +02:00
|
|
|
}
|
2001-01-25 22:53:02 +01:00
|
|
|
return 1;
|
2001-01-15 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Waits for and returns a client socket object attempting connection
|
|
|
|
* with a server socket. The function blocks until a client shows up or
|
|
|
|
* until a timeout condition is met.
|
|
|
|
* Lua Input: sock
|
2000-06-02 19:55:14 +02:00
|
|
|
* sock: server socket created by the bind function
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* On success: client socket attempting connection
|
|
|
|
* On error: nil followed by an error message
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int table_tcpaccept(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
struct sockaddr_in client_addr;
|
|
|
|
size_t client_len = sizeof(client_addr);
|
|
|
|
p_sock server = pop_sock(L);
|
|
|
|
p_tags tags = pop_tags(L);
|
|
|
|
p_sock client = push_clienttable(L, tags);
|
|
|
|
tm_markstart(server);
|
2001-03-06 20:03:10 +01:00
|
|
|
if (tm_gettimeleft(server) >= 0) {
|
|
|
|
set_nonblocking(server);
|
|
|
|
do {
|
|
|
|
if (tm_timedout(server, TM_RECEIVE)) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
push_error(L, NET_TIMEOUT);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
client->sock = accept(server->sock, (SA *) &client_addr,
|
|
|
|
&client_len);
|
|
|
|
} while (client->sock == INVALID_SOCKET);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
set_blocking(server);
|
|
|
|
client->sock = accept(server->sock, (SA *) &client_addr, &client_len);
|
|
|
|
}
|
2001-01-25 22:53:02 +01:00
|
|
|
set_nonblocking(client);
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Associates an address to a server socket.
|
|
|
|
* Lua Input: address, port [, backlog]
|
|
|
|
* address: host name or ip address to bind to
|
|
|
|
* port: port to bind to
|
|
|
|
* backlog: connection queue length (default: 1)
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* On success: server socket bound to address
|
|
|
|
* On error: nil, followed by an error message
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int global_tcpbind(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_tags tags = pop_tags(L);
|
|
|
|
const char *address = luaL_check_string(L, 1);
|
|
|
|
unsigned short port = (unsigned short) luaL_check_number(L, 2);
|
|
|
|
int backlog = (int) luaL_opt_number(L, 3, 1);
|
|
|
|
p_sock sock = push_servertable(L, tags);
|
|
|
|
const char *err;
|
|
|
|
if (!sock) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, "out of memory");
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
err = tcp_trybind(sock, address, port, backlog);
|
|
|
|
if (err) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, err);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Associates a local address to UDP socket
|
|
|
|
* Lua Input: address, port
|
|
|
|
* address: host name or ip address to bind to
|
2000-06-02 19:55:14 +02:00
|
|
|
* port: port to bind to
|
2001-01-25 22:53:02 +01:00
|
|
|
* Lua Returns
|
|
|
|
* On success: nil
|
|
|
|
* On error: error message
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int table_udpsetsockname(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
const char *address = luaL_check_string(L, 2);
|
|
|
|
unsigned short port = (unsigned short) luaL_check_number(L, 3);
|
|
|
|
const char *err = udp_setsockname(sock, address, port);
|
|
|
|
if (err) {
|
|
|
|
lua_pushstring(L, err);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Sets a peer for a UDP socket
|
|
|
|
* Lua Input: address, port
|
|
|
|
* address: remote host name
|
|
|
|
* port: remote host port
|
|
|
|
* Lua Returns
|
|
|
|
* On success: nil
|
|
|
|
* On error: error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_udpsetpeername(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
const char *address = luaL_check_string(L, 2);
|
|
|
|
unsigned short port = (unsigned short) luaL_check_number(L, 3);
|
|
|
|
const char *err = udp_setpeername(sock, address, port);
|
|
|
|
if (err) {
|
|
|
|
lua_pushstring(L, err);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
sock->is_connected = 1;
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Sets timeout values for IO operations on a socket
|
|
|
|
* Lua Input: sock, time [, mode]
|
2000-06-02 19:55:14 +02:00
|
|
|
* sock: client socket created by the connect function
|
|
|
|
* time: time out value in seconds
|
2001-01-25 22:53:02 +01:00
|
|
|
* mode: "b" for block timeout, "r" for return timeout. (default: b)
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
static int table_timeout(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
int ms = lua_isnil(L, 2) ? -1 : (int) (luaL_check_number(L, 2)*1000.0);
|
|
|
|
const char *mode = luaL_opt_string(L, 3, "b");
|
|
|
|
switch (*mode) {
|
|
|
|
case 'b':
|
|
|
|
sock->tm_block = ms;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
sock->tm_return = ms;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
luaL_arg_check(L, 0, 3, "invalid timeout mode");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Send data through a TCP socket
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Input: sock, a_1 [, a_2, a_3 ... a_n]
|
2000-06-02 19:55:14 +02:00
|
|
|
* sock: client socket created by the connect function
|
|
|
|
* a_i: strings to be sent. The strings will be sent on the order they
|
|
|
|
* appear as parameters
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Returns
|
2000-06-02 19:55:14 +02:00
|
|
|
* On success: nil, followed by the total number of bytes sent
|
2001-01-25 22:53:02 +01:00
|
|
|
* On error: error message
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int table_tcpsend(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
int arg;
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
int total = 0;
|
|
|
|
int err = NET_DONE;
|
|
|
|
tm_markstart(sock);
|
|
|
|
for (arg = 2; arg <= top; arg++) { /* skip self table */
|
|
|
|
int sent;
|
|
|
|
size_t wanted;
|
2001-04-24 00:37:55 +02:00
|
|
|
const char *data = luaL_opt_lstr(L, arg, NULL, &wanted);
|
|
|
|
if (!data || err != NET_DONE) break;
|
2001-01-25 22:53:02 +01:00
|
|
|
err = send_raw(sock, data, wanted, &sent);
|
|
|
|
total += sent;
|
|
|
|
}
|
|
|
|
push_error(L, err);
|
|
|
|
lua_pushnumber(L, total);
|
2000-06-02 19:55:14 +02:00
|
|
|
#ifdef _DEBUG
|
2001-01-25 22:53:02 +01:00
|
|
|
/* push time elapsed during operation as the last return value */
|
|
|
|
lua_pushnumber(L, (sock->tm_end - sock->tm_start)/1000.0);
|
2000-06-02 19:55:14 +02:00
|
|
|
#endif
|
2001-01-25 22:53:02 +01:00
|
|
|
return lua_gettop(L) - top;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Send data through a unconnected UDP socket
|
|
|
|
* Lua Input: sock, data, ip, port
|
|
|
|
* sock: udp socket
|
|
|
|
* data: data to be sent
|
|
|
|
* ip: ip address of target
|
|
|
|
* port: port in target
|
|
|
|
* Lua Returns
|
|
|
|
* On success: nil, followed by the total number of bytes sent
|
|
|
|
* On error: error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_udpsendto(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
size_t wanted;
|
|
|
|
const char *data = luaL_check_lstr(L, 2, &wanted);
|
|
|
|
const char *ip = luaL_check_string(L, 3);
|
|
|
|
unsigned short port = (unsigned short) luaL_check_number(L, 4);
|
|
|
|
struct sockaddr_in peer;
|
|
|
|
int sent;
|
|
|
|
if (sock->is_connected) lua_error(L, "sendto on connected socket");
|
|
|
|
tm_markstart(sock);
|
|
|
|
if (tm_timedout(sock, TM_SEND)) {
|
|
|
|
push_error(L, NET_TIMEOUT);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
memset(&peer, 0, sizeof(peer));
|
|
|
|
peer.sin_family = AF_INET;
|
|
|
|
peer.sin_port = htons(port);
|
|
|
|
if (!inet_aton(ip, &peer.sin_addr)) lua_error(L, "invalid ip address");
|
|
|
|
sent = sendto(sock->sock, data, wanted, 0, (SA *) &peer, sizeof(peer));
|
|
|
|
if (sent >= 0) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushnumber(L, sent);
|
|
|
|
return 2;
|
|
|
|
} else {
|
|
|
|
push_error(L, NET_REFUSED);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-03-12 21:04:25 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Global function that calls corresponding table method.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
#ifndef LUASOCKET_NOGLOBALS
|
2001-04-24 00:37:55 +02:00
|
|
|
int global_callfromtable(lua_State *L)
|
2001-03-12 21:04:25 +01:00
|
|
|
{
|
2001-04-24 00:37:55 +02:00
|
|
|
p_tags tags = pop_tags(L);
|
|
|
|
if (lua_tag(L, 1) != tags->table) lua_error(L, "invalid socket object");
|
|
|
|
lua_gettable(L, 1);
|
|
|
|
lua_insert(L, 1);
|
|
|
|
lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
|
|
|
|
return lua_gettop(L);
|
2001-03-12 21:04:25 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-03-06 20:03:10 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Waits for a set of sockets until a condition is met or timeout.
|
|
|
|
* Lua Input: {input}, {output} [, timeout]
|
|
|
|
* {input}: table of sockets to be tested for input
|
|
|
|
* {output}: table of sockets to be tested for output
|
|
|
|
* timeout: maximum amount of time to wait for condition, in seconds
|
|
|
|
* Lua Returns: {input}, {output}, err
|
|
|
|
* {input}: table with sockets ready for input
|
|
|
|
* {output}: table with sockets ready for output
|
|
|
|
* err: "timeout" or nil
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
int global_select(lua_State *L)
|
|
|
|
{
|
2001-03-12 21:04:25 +01:00
|
|
|
p_tags tags = pop_tags(L);
|
|
|
|
int ms = lua_isnil(L, 3) ? -1 : (int) (luaL_opt_number(L, 3, -1) * 1000);
|
2001-03-06 20:03:10 +01:00
|
|
|
fd_set readfds, *prfds = NULL, writefds, *pwfds = NULL;
|
|
|
|
struct timeval tm, *ptm = NULL;
|
2001-03-12 21:04:25 +01:00
|
|
|
int ret;
|
2001-04-24 00:37:55 +02:00
|
|
|
unsigned max = 0;
|
|
|
|
SOCKET s;
|
2001-03-12 21:04:25 +01:00
|
|
|
int byfds, canread, canwrite;
|
|
|
|
/* reset the file descriptor sets */
|
2001-03-06 20:03:10 +01:00
|
|
|
FD_ZERO(&readfds); FD_ZERO(&writefds);
|
2001-03-12 21:04:25 +01:00
|
|
|
/* all sockets, indexed by socket number, for internal use */
|
|
|
|
lua_newtable(L); byfds = lua_gettop(L);
|
|
|
|
/* readable sockets table to be returned */
|
|
|
|
lua_newtable(L); canread = lua_gettop(L);
|
|
|
|
/* writable sockets table to be returned */
|
|
|
|
lua_newtable(L); canwrite = lua_gettop(L);
|
|
|
|
/* get sockets we will test for readability into fd_set */
|
2001-06-04 22:44:39 +02:00
|
|
|
if (lua_istable(L, 1)) {
|
2001-03-12 21:04:25 +01:00
|
|
|
lua_pushnil(L);
|
|
|
|
while (lua_next(L, 1)) {
|
2001-04-16 21:56:33 +02:00
|
|
|
if (lua_tag(L, -1) == tags->table) { /* skip strange fields */
|
2001-03-12 21:04:25 +01:00
|
|
|
p_sock sock = get_sock(L, -1, tags, NULL);
|
2001-04-24 00:37:55 +02:00
|
|
|
if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */
|
|
|
|
lua_pushnumber(L, sock->sock);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, byfds);
|
|
|
|
if (sock->sock > max) max = sock->sock;
|
|
|
|
/* a socket can have unread data in our internal
|
|
|
|
buffer. in that case, we only call select to find
|
|
|
|
out which of the other sockets can be written to
|
|
|
|
or read from immediately. */
|
|
|
|
if (!bf_isempty(sock)) {
|
|
|
|
ms = 0;
|
|
|
|
lua_pushnumber(L, lua_getn(L, canread) + 1);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, canread);
|
|
|
|
} else {
|
|
|
|
FD_SET(sock->sock, &readfds);
|
|
|
|
prfds = &readfds;
|
|
|
|
}
|
|
|
|
}
|
2001-03-12 21:04:25 +01:00
|
|
|
}
|
|
|
|
/* get rid of lua_next value and expose index */
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
2001-06-09 00:22:37 +02:00
|
|
|
} else if (!lua_isnil(L, 1)) luaL_argerror(L, 1, "expected table or nil");
|
2001-03-12 21:04:25 +01:00
|
|
|
/* get sockets we will test for writability into fd_set */
|
2001-06-04 22:44:39 +02:00
|
|
|
if (lua_istable(L, 2)) {
|
2001-03-12 21:04:25 +01:00
|
|
|
lua_pushnil(L);
|
|
|
|
while (lua_next(L, 2)) {
|
2001-04-16 21:56:33 +02:00
|
|
|
if (lua_tag(L, -1) == tags->table) { /* skip strange fields */
|
2001-03-12 21:04:25 +01:00
|
|
|
p_sock sock = get_sock(L, -1, tags, NULL);
|
2001-04-24 00:37:55 +02:00
|
|
|
if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */
|
|
|
|
lua_pushnumber(L, sock->sock);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, byfds);
|
|
|
|
if (sock->sock > max) max = sock->sock;
|
|
|
|
FD_SET(sock->sock, &writefds);
|
|
|
|
pwfds = &writefds;
|
|
|
|
}
|
2001-03-12 21:04:25 +01:00
|
|
|
}
|
|
|
|
/* get rid of lua_next value and expose index */
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
2001-06-09 00:22:37 +02:00
|
|
|
} else if (!lua_isnil(L, 2)) luaL_argerror(L, 2, "expected table or nil");
|
2001-03-12 21:04:25 +01:00
|
|
|
max++;
|
|
|
|
/* configure timeout value */
|
2001-03-06 20:03:10 +01:00
|
|
|
if (ms >= 0) {
|
2001-03-12 21:04:25 +01:00
|
|
|
ptm = &tm; /* ptm == NULL when we don't have timeout */
|
|
|
|
/* fill timeval structure */
|
|
|
|
tm.tv_sec = ms / 1000;
|
|
|
|
tm.tv_usec = (ms % 1000) * 1000;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
/* see if we can read, write or if we timedout */
|
|
|
|
ret = select(max, prfds, pwfds, NULL, ptm);
|
2001-03-12 21:04:25 +01:00
|
|
|
/* did we timeout? */
|
2001-07-23 22:13:01 +02:00
|
|
|
if (ret <= 0 && ms >= 0) {
|
2001-03-12 21:04:25 +01:00
|
|
|
push_error(L, NET_TIMEOUT);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
/* collect readable sockets */
|
|
|
|
if (prfds) {
|
|
|
|
for (s = 0; s < max; s++) {
|
|
|
|
if (FD_ISSET(s, prfds)) {
|
|
|
|
lua_pushnumber(L, lua_getn(L, canread) + 1);
|
|
|
|
lua_pushnumber(L, s);
|
|
|
|
lua_gettable(L, byfds);
|
|
|
|
lua_settable(L, canread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* collect writable sockets */
|
|
|
|
if (pwfds) {
|
|
|
|
for (s = 0; s < max; s++) {
|
|
|
|
if (FD_ISSET(s, pwfds)) {
|
|
|
|
lua_pushnumber(L, lua_getn(L, canwrite) + 1);
|
|
|
|
lua_pushnumber(L, s);
|
|
|
|
lua_gettable(L, byfds);
|
|
|
|
lua_settable(L, canwrite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 3;
|
2001-03-06 20:03:10 +01:00
|
|
|
}
|
|
|
|
|
2001-01-25 22:53:02 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns the list of ip addresses associated with a host name
|
|
|
|
* Lua Input: address
|
|
|
|
* address: ip address or hostname to dns lookup
|
|
|
|
* Lua Returns
|
|
|
|
* On success: first IP address followed by a resolved table
|
|
|
|
* On error: nil, followed by an error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int global_toip(lua_State *L)
|
|
|
|
{
|
|
|
|
const char *address = luaL_check_string(L, 1);
|
|
|
|
struct in_addr addr;
|
|
|
|
struct hostent *hp;
|
|
|
|
if (inet_aton(address, &addr))
|
|
|
|
hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
|
|
|
|
else hp = gethostbyname(address);
|
|
|
|
if (!hp) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, host_strerror());
|
|
|
|
return 2;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
addr = *((struct in_addr *) hp->h_addr);
|
2001-01-25 22:53:02 +01:00
|
|
|
lua_pushstring(L, inet_ntoa(addr));
|
|
|
|
push_resolved(L, hp);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns the list of host names associated with an ip address
|
|
|
|
* Lua Input: address
|
|
|
|
* address: ip address or host name to reverse dns lookup
|
|
|
|
* Lua Returns
|
|
|
|
* On success: canonic name followed by a resolved table
|
|
|
|
* On error: nil, followed by an error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int global_tohostname(lua_State *L)
|
|
|
|
{
|
|
|
|
const char *address = luaL_check_string(L, 1);
|
|
|
|
struct in_addr addr;
|
|
|
|
struct hostent *hp;
|
|
|
|
if (inet_aton(address, &addr))
|
|
|
|
hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
|
|
|
|
else hp = gethostbyname(address);
|
|
|
|
if (!hp) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, host_strerror());
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, hp->h_name);
|
2001-03-06 20:03:10 +01:00
|
|
|
push_resolved(L, hp);
|
2001-01-25 22:53:02 +01:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Send data through a connected UDP socket
|
|
|
|
* Lua Input: sock, data
|
|
|
|
* sock: udp socket
|
|
|
|
* data: data to be sent
|
|
|
|
* Lua Returns
|
|
|
|
* On success: nil, followed by the total number of bytes sent
|
|
|
|
* On error: error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_udpsend(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
size_t wanted;
|
|
|
|
int sent;
|
|
|
|
const char *data = luaL_check_lstr(L, 2, &wanted);
|
|
|
|
if (!sock->is_connected) lua_error(L, "send on unconnected socket");
|
|
|
|
tm_markstart(sock);
|
|
|
|
if (tm_timedout(sock, TM_SEND)) {
|
|
|
|
push_error(L, NET_TIMEOUT);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
sent = send(sock->sock, data, wanted, 0);
|
|
|
|
if (sent >= 0) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushnumber(L, sent);
|
|
|
|
return 2;
|
|
|
|
} else {
|
|
|
|
push_error(L, NET_REFUSED);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Receives a datagram from a UDP socket
|
|
|
|
* Lua Input: sock [, wanted]
|
|
|
|
* sock: client socket created by the connect function
|
2001-03-06 20:03:10 +01:00
|
|
|
* wanted: the number of bytes expected (default: LUASOCKET_UDPBUFFERSIZE)
|
2001-01-25 22:53:02 +01:00
|
|
|
* Lua Returns
|
|
|
|
* On success: datagram received, ip and port of sender
|
|
|
|
* On error: nil, followed by an error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_udpreceivefrom(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
2001-03-06 20:03:10 +01:00
|
|
|
size_t wanted = (int) luaL_opt_number(L, 2, LUASOCKET_UDPBUFFERSIZE);
|
2001-01-25 22:53:02 +01:00
|
|
|
struct sockaddr_in peer;
|
|
|
|
size_t peer_len = sizeof(peer);
|
2001-03-06 20:03:10 +01:00
|
|
|
unsigned char buffer[LUASOCKET_UDPBUFFERSIZE];
|
2001-01-25 22:53:02 +01:00
|
|
|
int got;
|
|
|
|
if (sock->is_connected) lua_error(L, "receivefrom on connected socket");
|
|
|
|
tm_markstart(sock);
|
|
|
|
if (tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
push_error(L, NET_TIMEOUT);
|
|
|
|
return 2;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
wanted = MIN(wanted, sizeof(buffer));
|
2001-01-25 22:53:02 +01:00
|
|
|
got = recvfrom(sock->sock, buffer, wanted, 0, (SA *) &peer, &peer_len);
|
|
|
|
if (got >= 0) {
|
|
|
|
lua_pushlstring(L, buffer, got);
|
|
|
|
lua_pushstring(L, inet_ntoa(peer.sin_addr));
|
|
|
|
lua_pushnumber(L, ntohs(peer.sin_port));
|
|
|
|
return 3;
|
|
|
|
} else {
|
|
|
|
lua_pushnil(L);
|
|
|
|
push_error(L, NET_REFUSED);
|
|
|
|
return 2;
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Receives data from a UDP socket
|
|
|
|
* Lua Input: sock [, wanted]
|
|
|
|
* sock: client socket created by the connect function
|
2001-03-06 20:03:10 +01:00
|
|
|
* wanted: the number of bytes expected (default: LUASOCKET_UDPBUFFERSIZE)
|
2001-01-25 22:53:02 +01:00
|
|
|
* Lua Returns
|
|
|
|
* On success: datagram received
|
|
|
|
* On error: nil, followed by an error message
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_udpreceive(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
2001-03-06 20:03:10 +01:00
|
|
|
size_t wanted = (size_t) luaL_opt_number(L, 2, LUASOCKET_UDPBUFFERSIZE);
|
|
|
|
unsigned char buffer[LUASOCKET_UDPBUFFERSIZE];
|
2001-01-25 22:53:02 +01:00
|
|
|
int got;
|
|
|
|
tm_markstart(sock);
|
|
|
|
if (tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
push_error(L, NET_TIMEOUT);
|
|
|
|
return 2;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
got = recv(sock->sock, buffer, MIN(wanted, sizeof(buffer)), 0);
|
2001-01-25 22:53:02 +01:00
|
|
|
if (got >= 0) {
|
|
|
|
lua_pushlstring(L, buffer, got);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
lua_pushnil(L);
|
|
|
|
push_error(L, NET_REFUSED);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Receive data from a TCP socket
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Input: sock [pat_1, pat_2 ... pat_n]
|
2000-06-02 19:55:14 +02:00
|
|
|
* sock: client socket created by the connect function
|
|
|
|
* pat_i: may be one of the following
|
|
|
|
* "*l": reads a text line, defined as a string of caracters terminates
|
|
|
|
* by a LF character, preceded or not by a CR character. This is
|
|
|
|
* the default pattern
|
|
|
|
* "*lu": reads a text line, terminanted by a CR character only. (Unix mode)
|
2001-01-13 08:10:00 +01:00
|
|
|
* "*a": reads until connection closed
|
2000-06-02 19:55:14 +02:00
|
|
|
* number: reads 'number' characters from the socket
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Returns
|
2000-06-02 19:55:14 +02:00
|
|
|
* On success: one string for each pattern
|
2000-12-27 20:19:22 +01:00
|
|
|
* On error: all strings for which there was no error, followed by one
|
2001-01-13 08:10:00 +01:00
|
|
|
* nil value for the remaining strings, followed by an error code
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int table_tcpreceive(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-03-12 21:04:25 +01:00
|
|
|
static const char *const modenames[] = {"*l", "*lu", "*a", "*w", NULL};
|
2001-01-25 22:53:02 +01:00
|
|
|
const char *mode;
|
|
|
|
int err = NET_DONE;
|
|
|
|
int arg;
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
tm_markstart(sock);
|
|
|
|
/* push default pattern if need be */
|
|
|
|
if (top < 2) {
|
|
|
|
lua_pushstring(L, "*l");
|
|
|
|
top++;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
/* make sure we have enough stack space */
|
|
|
|
luaL_checkstack(L, top+LUA_MINSTACK, "too many arguments");
|
2001-01-25 22:53:02 +01:00
|
|
|
/* receive all patterns */
|
|
|
|
for (arg = 2; arg <= top; arg++) {
|
2001-03-06 20:03:10 +01:00
|
|
|
/* if one pattern fails, we just skip all other patterns */
|
2001-01-25 22:53:02 +01:00
|
|
|
if (err != NET_DONE) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (lua_isnumber(L, arg)) {
|
|
|
|
int size = (int) lua_tonumber(L, arg);
|
|
|
|
err = receive_raw(L, sock, size);
|
|
|
|
} else {
|
|
|
|
mode = luaL_opt_string(L, arg, NULL);
|
|
|
|
/* get next pattern */
|
|
|
|
switch (luaL_findstring(mode, modenames)) {
|
|
|
|
/* DOS line mode */
|
2001-03-12 21:04:25 +01:00
|
|
|
case 0: err = receive_dosline(L, sock); break;
|
2001-01-25 22:53:02 +01:00
|
|
|
/* Unix line mode */
|
2001-03-12 21:04:25 +01:00
|
|
|
case 1: err = receive_unixline(L, sock); break;
|
2001-01-25 22:53:02 +01:00
|
|
|
/* until closed mode */
|
2001-03-12 21:04:25 +01:00
|
|
|
case 2: err = receive_all(L, sock); break;
|
|
|
|
/* word */
|
|
|
|
case 3: err = receive_word(L, sock); break;
|
2001-01-25 22:53:02 +01:00
|
|
|
/* else it is an error */
|
|
|
|
default:
|
|
|
|
luaL_arg_check(L, 0, arg, "invalid receive pattern");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* last return is an error code */
|
|
|
|
push_error(L, err);
|
2000-06-02 19:55:14 +02:00
|
|
|
#ifdef _DEBUG
|
2001-01-25 22:53:02 +01:00
|
|
|
/* push time elapsed during operation as the last return value */
|
|
|
|
lua_pushnumber(L, (sock->tm_end - sock->tm_start)/1000.0);
|
2000-06-02 19:55:14 +02:00
|
|
|
#endif
|
2001-01-25 22:53:02 +01:00
|
|
|
return lua_gettop(L) - top;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Retrieves socket peer name
|
|
|
|
* Lua Input: sock
|
|
|
|
* sock: socket
|
|
|
|
* Lua Returns
|
|
|
|
* On success: ip address and port of peer
|
|
|
|
* On error: nil
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_getpeername(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
struct sockaddr_in peer;
|
|
|
|
size_t peer_len = sizeof(peer);
|
|
|
|
if (getpeername(sock->sock, (SA *) &peer, &peer_len) < 0) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, inet_ntoa(peer.sin_addr));
|
|
|
|
lua_pushnumber(L, ntohs(peer.sin_port));
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Retrieves socket local name
|
|
|
|
* Lua Input: sock
|
|
|
|
* sock: socket
|
|
|
|
* Lua Returns
|
|
|
|
* On success: local ip address and port
|
|
|
|
* On error: nil
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int table_getsockname(lua_State *L)
|
|
|
|
{
|
|
|
|
p_sock sock = pop_sock(L);
|
|
|
|
struct sockaddr_in local;
|
|
|
|
size_t local_len = sizeof(local);
|
|
|
|
if (getsockname(sock->sock, (SA *) &local, &local_len) < 0) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, inet_ntoa(local.sin_addr));
|
|
|
|
lua_pushnumber(L, ntohs(local.sin_port));
|
|
|
|
return 2;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Closes a socket.
|
2001-01-15 05:16:35 +01:00
|
|
|
* Lua Input
|
2000-06-02 19:55:14 +02:00
|
|
|
* sock: socket to be closed
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
static int table_close(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
/* close socket and set value to INVALID_SOCKET so that
|
2001-03-06 20:03:10 +01:00
|
|
|
** pop_sock can later detect the use of a closed socket */
|
|
|
|
p_sock sock = (p_sock) lua_touserdata(L, -1);
|
|
|
|
if (!sock) lua_error(L, "invalid socket object");
|
|
|
|
if (sock->sock != INVALID_SOCKET) closesocket(sock->sock);
|
2001-01-25 22:53:02 +01:00
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Garbage collection fallback for the socket objects. This function
|
2001-01-15 05:16:35 +01:00
|
|
|
* makes sure that all collected sockets are closed.
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static int gc_table(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_tags tags = pop_tags(L);
|
|
|
|
p_sock sock = get_selfsock(L, tags, NULL);
|
|
|
|
/* sock might have been closed before */
|
|
|
|
if (sock->sock != INVALID_SOCKET) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
return 0;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Internal functions
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Instals a handler to ignore sigpipe. That is, unless the signal had
|
|
|
|
* already been redefined. This function is not needed on the WinSock2,
|
|
|
|
* since it's sockets don't raise this signal.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
#ifndef WIN32
|
|
|
|
static void handle_sigpipe(void);
|
|
|
|
static void handle_sigpipe(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
struct sigaction new;
|
|
|
|
memset(&new, 0, sizeof(new));
|
|
|
|
new.sa_handler = SIG_IGN;
|
|
|
|
sigaction(SIGPIPE, &new, NULL);
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Tries to create a TCP socket and connect to remote address (address, port)
|
2001-01-15 05:16:35 +01:00
|
|
|
* Input
|
2001-01-25 22:53:02 +01:00
|
|
|
* address: host name or ip address
|
|
|
|
* port: port number to bind to
|
2000-06-02 19:55:14 +02:00
|
|
|
* Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* NULL in case of success, error message otherwise
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *tcp_tryconnect(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
struct sockaddr_in remote;
|
|
|
|
memset(&remote, 0, sizeof(remote));
|
|
|
|
if (inet_aton(address, &remote.sin_addr)) {
|
|
|
|
remote.sin_family = AF_INET;
|
|
|
|
remote.sin_port = htons(port);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) return socket_strerror();
|
|
|
|
if (connect(sock->sock, (SA *) &remote, sizeof(remote)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
return connect_strerror();
|
|
|
|
}
|
|
|
|
/* go ahead and try by hostname resolution */
|
|
|
|
} else {
|
|
|
|
struct hostent *hp = gethostbyname(address);
|
|
|
|
struct in_addr **addr;
|
|
|
|
if (!hp) return host_strerror();
|
|
|
|
addr = (struct in_addr **) hp->h_addr_list;
|
|
|
|
for (; *addr != NULL; addr++) {
|
|
|
|
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
|
|
|
|
remote.sin_family = AF_INET;
|
|
|
|
remote.sin_port = htons(port);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) return socket_strerror();
|
|
|
|
if (connect(sock->sock, (SA *) &remote, sizeof(remote)) == 0)
|
2001-03-06 20:03:10 +01:00
|
|
|
break;
|
2001-01-25 22:53:02 +01:00
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
memset(&remote, 0, sizeof(remote));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sock->sock == INVALID_SOCKET) return connect_strerror();
|
|
|
|
return NULL;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
2001-01-25 22:53:02 +01:00
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Sets the SO_REUSEADDR socket option
|
|
|
|
* Input
|
|
|
|
* sock: socket to set option
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
void set_reuseaddr(p_sock sock)
|
|
|
|
{
|
|
|
|
int val = 1;
|
|
|
|
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-04-24 00:37:55 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Set socket options from a table on top of Lua stack.
|
|
|
|
* Supports SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST, and SO_LINGER options.
|
|
|
|
* Input
|
|
|
|
* L: Lua state to use
|
|
|
|
* sock: socket to set option
|
|
|
|
* Returns
|
|
|
|
* 1 if successful, 0 otherwise
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int set_option(lua_State *L, p_sock sock)
|
|
|
|
{
|
|
|
|
static const char *const optionnames[] = {
|
|
|
|
"SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", "SO_LINGER", NULL
|
|
|
|
};
|
2001-06-04 22:44:39 +02:00
|
|
|
const char *option;
|
2001-04-24 00:37:55 +02:00
|
|
|
int err;
|
2001-06-04 22:44:39 +02:00
|
|
|
if (!lua_isstring(L, -2)) return 0;
|
|
|
|
option = lua_tostring(L, -2);
|
2001-04-24 00:37:55 +02:00
|
|
|
switch (luaL_findstring(option, optionnames)) {
|
|
|
|
case 0: {
|
2001-06-04 22:44:39 +02:00
|
|
|
int bool;
|
2001-06-09 00:36:30 +02:00
|
|
|
if (!lua_isnumber(L, -1))
|
|
|
|
lua_error(L, "invalid SO_KEEPALIVE value");
|
2001-06-04 22:44:39 +02:00
|
|
|
bool = (int) lua_tonumber(L, -1);
|
2001-06-09 00:22:37 +02:00
|
|
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE,
|
|
|
|
(char *) &bool, sizeof(bool));
|
2001-04-24 00:37:55 +02:00
|
|
|
return err >= 0;
|
|
|
|
}
|
|
|
|
case 1: {
|
2001-06-04 22:44:39 +02:00
|
|
|
int bool;
|
2001-06-09 00:36:30 +02:00
|
|
|
if (!lua_isnumber(L, -1))
|
|
|
|
lua_error(L, "invalid SO_DONTROUTE value");
|
2001-06-04 22:44:39 +02:00
|
|
|
bool = (int) lua_tonumber(L, -1);
|
2001-06-09 00:22:37 +02:00
|
|
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_DONTROUTE,
|
|
|
|
(char *) &bool, sizeof(bool));
|
2001-04-24 00:37:55 +02:00
|
|
|
return err >= 0;
|
|
|
|
}
|
|
|
|
case 2: {
|
2001-06-04 22:44:39 +02:00
|
|
|
int bool;
|
2001-06-09 00:36:30 +02:00
|
|
|
if (!lua_isnumber(L, -1))
|
|
|
|
lua_error(L, "invalid SO_BROADCAST value");
|
2001-06-04 22:44:39 +02:00
|
|
|
bool = (int) lua_tonumber(L, -1);
|
2001-06-09 00:22:37 +02:00
|
|
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_BROADCAST,
|
|
|
|
(char *) &bool, sizeof(bool));
|
2001-04-24 00:37:55 +02:00
|
|
|
return err >= 0;
|
|
|
|
}
|
|
|
|
case 3: {
|
|
|
|
struct linger linger;
|
2001-06-09 00:36:30 +02:00
|
|
|
if (!lua_istable(L, -1))
|
|
|
|
lua_error(L, "invalid SO_LINGER value");
|
2001-04-24 00:37:55 +02:00
|
|
|
lua_pushstring(L, "l_onoff");
|
|
|
|
lua_gettable(L, -2);
|
2001-06-09 00:36:30 +02:00
|
|
|
if (!lua_isnumber(L, -1))
|
|
|
|
lua_error(L, "invalid SO_LINGER (l_onoff) value");
|
2001-06-09 23:22:57 +02:00
|
|
|
linger.l_onoff = (int) lua_tonumber(L, -1);
|
2001-04-24 00:37:55 +02:00
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_pushstring(L, "l_linger");
|
|
|
|
lua_gettable(L, -2);
|
2001-06-09 00:36:30 +02:00
|
|
|
if (!lua_isnumber(L, -1))
|
|
|
|
lua_error(L, "invalid SO_LINGER (l_linger) value");
|
2001-06-09 23:22:57 +02:00
|
|
|
linger.l_linger = (int) lua_tonumber(L, -1);
|
2001-04-24 00:37:55 +02:00
|
|
|
lua_pop(L, 1);
|
2001-06-09 00:22:37 +02:00
|
|
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_LINGER,
|
|
|
|
(char *) &linger, sizeof(linger));
|
2001-04-24 00:37:55 +02:00
|
|
|
return err >= 0;
|
|
|
|
}
|
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Tries to create a TCP socket and bind it to (address, port)
|
2000-06-02 19:55:14 +02:00
|
|
|
* Input
|
2001-01-25 22:53:02 +01:00
|
|
|
* address: host name or ip address
|
|
|
|
* port: port number to bind to
|
|
|
|
* backlog: backlog to set
|
2000-06-02 19:55:14 +02:00
|
|
|
* Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* NULL in case of success, error message otherwise
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *tcp_trybind(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port, int backlog)
|
|
|
|
{
|
|
|
|
struct sockaddr_in local;
|
|
|
|
memset(&local, 0, sizeof(local));
|
|
|
|
local.sin_port = htons(port);
|
|
|
|
local.sin_family = AF_INET;
|
|
|
|
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) return socket_strerror();
|
|
|
|
set_reuseaddr(sock);
|
|
|
|
/* address is either wildcard or a valid ip address */
|
|
|
|
if (!strcmp(address, "*") || inet_aton(address, &local.sin_addr)) {
|
|
|
|
if (bind(sock->sock, (SA *) &local, sizeof(local)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
return bind_strerror();
|
|
|
|
}
|
|
|
|
/* otherwise, proceed with domain name resolution */
|
|
|
|
} else {
|
|
|
|
struct hostent *hp = gethostbyname(address);
|
|
|
|
struct in_addr **addr;
|
|
|
|
if (!hp) return host_strerror();
|
|
|
|
addr = (struct in_addr **) hp->h_addr_list;
|
|
|
|
for (; *addr != NULL; addr++) {
|
|
|
|
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
|
|
|
if (bind(sock->sock, (SA *) &local, sizeof(local)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) return socket_strerror();
|
|
|
|
set_reuseaddr(sock);
|
|
|
|
} else break;
|
|
|
|
}
|
|
|
|
if (*addr == NULL) return bind_strerror();
|
|
|
|
}
|
|
|
|
/* set connection queue length */
|
|
|
|
if (listen(sock->sock, backlog) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
return "listen error";
|
|
|
|
}
|
|
|
|
/* no errors found */
|
|
|
|
return NULL;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Tries to bind the UDP socket to (address, port)
|
2001-01-15 05:16:35 +01:00
|
|
|
* Input
|
2001-01-25 22:53:02 +01:00
|
|
|
* address: host name or ip address
|
|
|
|
* port: port number to bind to
|
2001-01-15 05:16:35 +01:00
|
|
|
* Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* NULL in case of success, error message otherwise
|
2001-01-15 05:16:35 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *udp_setsockname(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port)
|
2001-01-15 05:16:35 +01:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
struct sockaddr_in local;
|
|
|
|
memset(&local, 0, sizeof(local));
|
|
|
|
local.sin_port = htons(port);
|
|
|
|
local.sin_family = AF_INET;
|
|
|
|
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
set_reuseaddr(sock);
|
|
|
|
/* address is either wildcard or a valid ip address */
|
|
|
|
if (!strcmp(address, "*") || inet_aton(address, &local.sin_addr)) {
|
|
|
|
if (bind(sock->sock, (SA *) &local, sizeof(local)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
return bind_strerror();
|
|
|
|
}
|
|
|
|
/* otherwise, proceed with domain name resolution */
|
|
|
|
} else {
|
|
|
|
struct hostent *hp = gethostbyname(address);
|
|
|
|
struct in_addr **addr;
|
|
|
|
if (!hp) return host_strerror();
|
|
|
|
addr = (struct in_addr **) hp->h_addr_list;
|
|
|
|
for (; *addr != NULL; addr++) {
|
|
|
|
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
|
|
|
if (bind(sock->sock, (SA *) &local, sizeof(local)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) return socket_strerror();
|
|
|
|
set_reuseaddr(sock);
|
|
|
|
} else break;
|
|
|
|
}
|
|
|
|
if (*addr == NULL) return bind_strerror();
|
|
|
|
}
|
|
|
|
/* no errors found */
|
|
|
|
return NULL;
|
2001-01-15 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Tries to connect a UDP to remote address (address, port)
|
2001-01-15 05:16:35 +01:00
|
|
|
* Input
|
2001-01-25 22:53:02 +01:00
|
|
|
* address: host name or ip address
|
|
|
|
* port: port number to bind to
|
2001-01-15 05:16:35 +01:00
|
|
|
* Returns
|
2001-01-25 22:53:02 +01:00
|
|
|
* NULL in case of success, error message otherwise
|
2001-01-15 05:16:35 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-04-16 21:56:33 +02:00
|
|
|
static const char *udp_setpeername(p_sock sock, const char *address,
|
2001-01-25 22:53:02 +01:00
|
|
|
unsigned short port)
|
2001-01-15 05:16:35 +01:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
struct sockaddr_in local;
|
|
|
|
memset(&local, 0, sizeof(local));
|
|
|
|
local.sin_port = htons(port);
|
|
|
|
local.sin_family = AF_INET;
|
|
|
|
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
/* address is a valid ip address */
|
|
|
|
if (inet_aton(address, &local.sin_addr)) {
|
|
|
|
if (connect(sock->sock, (SA *) &local, sizeof(local)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
return connect_strerror();
|
|
|
|
}
|
|
|
|
/* otherwise, proceed with domain name resolution */
|
|
|
|
} else {
|
|
|
|
struct hostent *hp = gethostbyname(address);
|
|
|
|
struct in_addr **addr;
|
|
|
|
if (!hp) return host_strerror();
|
|
|
|
addr = (struct in_addr **) hp->h_addr_list;
|
|
|
|
for (; *addr != NULL; addr++) {
|
|
|
|
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
|
|
|
if (connect(sock->sock, (SA *) &local, sizeof(local)) < 0) {
|
|
|
|
closesocket(sock->sock);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) return socket_strerror();
|
|
|
|
} else break;
|
|
|
|
}
|
|
|
|
if (*addr == NULL) return connect_strerror();
|
|
|
|
}
|
|
|
|
/* no errors found */
|
|
|
|
return NULL;
|
2001-01-15 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Timeout management functions
|
|
|
|
\*=========================================================================*/
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-13 08:10:00 +01:00
|
|
|
* Determines how much time we have left for the current io operation
|
|
|
|
* an IO write operation.
|
2000-06-02 19:55:14 +02:00
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* Returns
|
2001-01-13 08:10:00 +01:00
|
|
|
* the number of ms left or -1 if there is no time limit
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int tm_gettimeleft(p_sock sock)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
/* no timeout */
|
|
|
|
if (sock->tm_block < 0 && sock->tm_return < 0)
|
|
|
|
return -1;
|
|
|
|
/* there is no block timeout, we use the return timeout */
|
|
|
|
else if (sock->tm_block < 0)
|
2001-03-06 20:03:10 +01:00
|
|
|
return MAX(sock->tm_return - tm_gettime() + sock->tm_start, 0);
|
2001-01-25 22:53:02 +01:00
|
|
|
/* there is no return timeout, we use the block timeout */
|
|
|
|
else if (sock->tm_return < 0)
|
|
|
|
return sock->tm_block;
|
|
|
|
/* both timeouts are specified */
|
2001-03-06 20:03:10 +01:00
|
|
|
else return MIN(sock->tm_block,
|
|
|
|
MAX(sock->tm_return - tm_gettime() + sock->tm_start, 0));
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Determines if we have a timeout condition or if we can proceed with
|
2001-01-25 22:53:02 +01:00
|
|
|
* an IO operation.
|
2000-06-02 19:55:14 +02:00
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
2001-01-13 08:10:00 +01:00
|
|
|
* mode: TM_RECEIVE or TM_SEND
|
2000-06-02 19:55:14 +02:00
|
|
|
* Returns
|
2001-01-13 08:10:00 +01:00
|
|
|
* 1 if we can proceed, 0 if a timeout has occured
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int tm_timedout(p_sock sock, int mode)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
fd_set fds;
|
|
|
|
int ret;
|
|
|
|
fd_set *preadfds = NULL, *pwritefds = NULL;
|
|
|
|
struct timeval tm;
|
|
|
|
struct timeval *ptm = NULL;
|
|
|
|
/* find out how much time we have left, in ms */
|
|
|
|
int ms = tm_gettimeleft(sock);
|
|
|
|
/* fill file descriptor set */
|
|
|
|
FD_ZERO(&fds); FD_SET(sock->sock, &fds);
|
|
|
|
/* fill timeval structure */
|
|
|
|
tm.tv_sec = ms / 1000;
|
|
|
|
tm.tv_usec = (ms % 1000) * 1000;
|
|
|
|
/* define function parameters */
|
|
|
|
if (ms >= 0) ptm = &tm; /* ptm == NULL when we don't have timeout */
|
|
|
|
if (mode == TM_RECEIVE) preadfds = &fds;
|
|
|
|
else pwritefds = &fds;
|
|
|
|
/* see if we can read, write or if we timedout */
|
|
|
|
ret = select(sock->sock+1, preadfds, pwritefds, NULL, ptm);
|
2001-01-13 08:10:00 +01:00
|
|
|
#ifdef _DEBUG
|
2001-01-25 22:53:02 +01:00
|
|
|
/* store end time for this operation next call to OS */
|
|
|
|
sock->tm_end = tm_gettime();
|
2001-01-13 08:10:00 +01:00
|
|
|
#endif
|
2001-01-25 22:53:02 +01:00
|
|
|
return ret <= 0;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-13 08:10:00 +01:00
|
|
|
* Marks the operation start time in sock structure
|
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void tm_markstart(p_sock sock)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
sock->tm_start = tm_gettime();
|
2001-01-13 08:10:00 +01:00
|
|
|
#ifdef _DEBUG
|
2001-01-25 22:53:02 +01:00
|
|
|
sock->tm_end = sock->tm_start;
|
2001-01-13 08:10:00 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Gets time in ms, relative to system startup.
|
|
|
|
* Returns
|
|
|
|
* time in ms.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int tm_gettime(void)
|
|
|
|
{
|
2001-01-28 03:16:20 +01:00
|
|
|
#ifdef WIN32
|
2001-01-25 22:53:02 +01:00
|
|
|
return GetTickCount();
|
2001-01-15 05:16:35 +01:00
|
|
|
#else
|
2001-01-25 22:53:02 +01:00
|
|
|
struct tms t;
|
|
|
|
return (times(&t)*1000)/CLK_TCK;
|
2001-01-15 05:16:35 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Buffered I/O management functions
|
|
|
|
\*=========================================================================*/
|
2001-01-13 08:10:00 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Determines of there is any data in the read buffer
|
2000-06-02 19:55:14 +02:00
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* Returns
|
2001-01-13 08:10:00 +01:00
|
|
|
* 1 if empty, 0 if there is data
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int bf_isempty(p_sock sock)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
return sock->bf_first >= sock->bf_last;
|
2001-01-13 08:10:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Skip a given number of bytes in read buffer
|
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* length: number of bytes to skip
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void bf_skip(p_sock sock, int length)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
sock->bf_first += length;
|
|
|
|
if (bf_isempty(sock)) sock->bf_first = sock->bf_last = 0;
|
2001-01-13 08:10:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Return any data avilable in buffer, or get more data from transport layer
|
2001-01-25 22:53:02 +01:00
|
|
|
* if buffer is empty.
|
2001-01-13 08:10:00 +01:00
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* Output
|
|
|
|
* length: number of bytes available in buffer
|
|
|
|
* Returns
|
|
|
|
* pointer to start of data
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static const unsigned char *bf_receive(p_sock sock, int *length)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
if (bf_isempty(sock)) {
|
2001-03-06 20:03:10 +01:00
|
|
|
int got = recv(sock->sock, sock->bf_buffer, LUASOCKET_TCPBUFFERSIZE, 0);
|
2001-01-25 22:53:02 +01:00
|
|
|
sock->bf_first = 0;
|
|
|
|
if (got >= 0) sock->bf_last = got;
|
|
|
|
else sock->bf_last = 0;
|
|
|
|
}
|
|
|
|
*length = sock->bf_last - sock->bf_first;
|
|
|
|
return sock->bf_buffer + sock->bf_first;
|
2001-01-13 08:10:00 +01:00
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/*=========================================================================*\
|
|
|
|
* These are the function that are called for each I/O pattern
|
2001-01-25 22:53:02 +01:00
|
|
|
* The read patterns leave their result on the Lua stack
|
2001-01-15 05:16:35 +01:00
|
|
|
\*=========================================================================*/
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Sends a raw block of data through a socket. The operations are all
|
|
|
|
* non-blocking and the function respects the timeout values in sock.
|
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* data: buffer to be sent
|
|
|
|
* wanted: number of bytes in buffer
|
|
|
|
* Output
|
2001-01-15 05:16:35 +01:00
|
|
|
* total: Number of bytes written
|
2000-06-02 19:55:14 +02:00
|
|
|
* Returns
|
2001-01-15 05:16:35 +01:00
|
|
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
static int send_raw(p_sock sock, const char *data, int wanted, int *total)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
int put = 0;
|
|
|
|
*total = 0;
|
|
|
|
while (wanted > 0) {
|
|
|
|
if (tm_timedout(sock, TM_SEND)) return NET_TIMEOUT;
|
|
|
|
put = send(sock->sock, data, wanted, 0);
|
|
|
|
if (put <= 0) {
|
2001-01-15 05:16:35 +01:00
|
|
|
#ifdef WIN32
|
2001-01-25 22:53:02 +01:00
|
|
|
/* a bug in WinSock forces us to do a busy wait until we manage
|
|
|
|
** to write, because select returns immediately even though it
|
|
|
|
** should have blocked us until we could write... */
|
2001-01-28 03:16:20 +01:00
|
|
|
if (put < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
2001-01-25 22:53:02 +01:00
|
|
|
continue;
|
2001-01-15 05:16:35 +01:00
|
|
|
#endif
|
2001-01-28 03:16:20 +01:00
|
|
|
#ifdef __CYGWIN__
|
2001-03-06 20:03:10 +01:00
|
|
|
/* this is for CYGWIN, which is like Unix but with Win32 Bugs */
|
|
|
|
if (put < 0 && errno == EWOULDBLOCK)
|
|
|
|
continue;
|
2001-01-28 03:16:20 +01:00
|
|
|
#endif
|
2001-03-06 20:03:10 +01:00
|
|
|
|
2001-01-25 22:53:02 +01:00
|
|
|
return NET_CLOSED;
|
|
|
|
}
|
|
|
|
wanted -= put;
|
2001-03-06 20:03:10 +01:00
|
|
|
data += put;
|
2001-01-25 22:53:02 +01:00
|
|
|
*total += put;
|
|
|
|
}
|
|
|
|
return NET_DONE;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads a raw block of data from a socket. The operations are all
|
|
|
|
* non-blocking and the function respects the timeout values in sock.
|
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* wanted: number of bytes to be read
|
|
|
|
* Returns
|
2001-01-13 08:10:00 +01:00
|
|
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int receive_raw(lua_State *L, p_sock sock, int wanted)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
int got = 0;
|
|
|
|
const unsigned char *buffer = NULL;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
while (wanted > 0) {
|
|
|
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_TIMEOUT;
|
|
|
|
}
|
|
|
|
buffer = bf_receive(sock, &got);
|
|
|
|
if (got <= 0) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_CLOSED;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
got = MIN(got, wanted);
|
2001-01-25 22:53:02 +01:00
|
|
|
luaL_addlstring(&b, buffer, got);
|
|
|
|
bf_skip(sock, got);
|
|
|
|
wanted -= got;
|
|
|
|
}
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_DONE;
|
2000-12-27 20:19:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads everything until the connection is closed
|
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* Result
|
2001-01-25 22:53:02 +01:00
|
|
|
* operation error code. NET_DONE, NET_TIMEOUT
|
2000-12-27 20:19:22 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int receive_all(lua_State *L, p_sock sock)
|
2000-12-27 20:19:22 +01:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
int got = 0;
|
|
|
|
const unsigned char *buffer = NULL;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
for ( ;; ) {
|
|
|
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_TIMEOUT;
|
|
|
|
}
|
|
|
|
buffer = bf_receive(sock, &got);
|
|
|
|
if (got <= 0) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_DONE;
|
|
|
|
}
|
|
|
|
luaL_addlstring(&b, buffer, got);
|
|
|
|
bf_skip(sock, got);
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
2001-01-13 08:10:00 +01:00
|
|
|
* are not returned by the function and are discarded from the stream. All
|
|
|
|
* operations are non-blocking and the function respects the timeout
|
|
|
|
* values in sock.
|
2000-06-02 19:55:14 +02:00
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
2000-12-27 20:19:22 +01:00
|
|
|
* Result
|
2001-01-13 08:10:00 +01:00
|
|
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int receive_dosline(lua_State *L, p_sock sock)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-03-12 21:04:25 +01:00
|
|
|
int got, pos;
|
2001-01-25 22:53:02 +01:00
|
|
|
const unsigned char *buffer = NULL;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
for ( ;; ) {
|
|
|
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_TIMEOUT;
|
|
|
|
}
|
|
|
|
buffer = bf_receive(sock, &got);
|
2001-03-12 21:04:25 +01:00
|
|
|
if (got <= 0) {
|
2001-04-24 00:37:55 +02:00
|
|
|
luaL_pushresult(&b);
|
2001-01-25 22:53:02 +01:00
|
|
|
return NET_CLOSED;
|
2001-04-24 00:37:55 +02:00
|
|
|
}
|
|
|
|
pos = 0;
|
2001-03-12 21:04:25 +01:00
|
|
|
while (pos < got && buffer[pos] != '\n') {
|
2001-04-24 00:37:55 +02:00
|
|
|
/* we ignore all \r's */
|
|
|
|
if (buffer[pos] != '\r') luaL_putchar(&b, buffer[pos]);
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
if (pos < got) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
bf_skip(sock, pos+1); /* skip '\n' too */
|
|
|
|
return NET_DONE;
|
|
|
|
} else bf_skip(sock, pos);
|
2001-01-25 22:53:02 +01:00
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads a line terminated by a LF character, which is not returned by
|
2001-01-13 08:10:00 +01:00
|
|
|
* the function, and is skipped in the stream. All operations are
|
|
|
|
* non-blocking and the function respects the timeout values in sock.
|
2000-06-02 19:55:14 +02:00
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* Returns
|
2001-01-13 08:10:00 +01:00
|
|
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-13 08:10:00 +01:00
|
|
|
static int receive_unixline(lua_State *L, p_sock sock)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-03-12 21:04:25 +01:00
|
|
|
int got, pos;
|
2001-01-25 22:53:02 +01:00
|
|
|
const unsigned char *buffer = NULL;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
for ( ;; ) {
|
|
|
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_TIMEOUT;
|
|
|
|
}
|
|
|
|
buffer = bf_receive(sock, &got);
|
2001-03-12 21:04:25 +01:00
|
|
|
if (got <= 0) {
|
2001-04-24 00:37:55 +02:00
|
|
|
luaL_pushresult(&b);
|
2001-03-12 21:04:25 +01:00
|
|
|
return NET_CLOSED;
|
2001-04-24 00:37:55 +02:00
|
|
|
}
|
|
|
|
pos = 0;
|
2001-03-12 21:04:25 +01:00
|
|
|
while (pos < got && buffer[pos] != '\n') pos++;
|
2001-04-24 00:37:55 +02:00
|
|
|
luaL_addlstring(&b, buffer, pos);
|
|
|
|
if (pos < got) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
bf_skip(sock, pos+1); /* skip '\n' too */
|
|
|
|
return NET_DONE;
|
|
|
|
} else bf_skip(sock, pos);
|
2001-03-12 21:04:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads a word (maximal sequence of non--white-space characters), skipping
|
|
|
|
* white-spaces if needed.
|
|
|
|
* Input
|
|
|
|
* sock: socket structure being used in operation
|
|
|
|
* Result
|
|
|
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static int receive_word(lua_State *L, p_sock sock)
|
|
|
|
{
|
|
|
|
int pos, got;
|
|
|
|
const unsigned char *buffer = NULL;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
|
|
|
/* skip leading white-spaces */
|
|
|
|
for ( ;; ) {
|
|
|
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
lua_pushstring(L, "");
|
|
|
|
return NET_TIMEOUT;
|
|
|
|
}
|
|
|
|
buffer = bf_receive(sock, &got);
|
|
|
|
if (got <= 0) {
|
|
|
|
lua_pushstring(L, "");
|
|
|
|
return NET_CLOSED;
|
|
|
|
}
|
|
|
|
pos = 0;
|
|
|
|
while (pos < got && isspace(buffer[pos])) pos++;
|
|
|
|
bf_skip(sock, pos);
|
|
|
|
if (pos < got) {
|
|
|
|
buffer += pos;
|
2001-04-24 00:37:55 +02:00
|
|
|
got -= pos;
|
2001-03-12 21:04:25 +01:00
|
|
|
pos = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* capture word */
|
|
|
|
for ( ;; ) {
|
|
|
|
while (pos < got && !isspace(buffer[pos])) pos++;
|
|
|
|
luaL_addlstring(&b, buffer, pos);
|
|
|
|
bf_skip(sock, pos);
|
|
|
|
if (pos < got) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_DONE;
|
|
|
|
}
|
|
|
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_TIMEOUT;
|
|
|
|
}
|
|
|
|
buffer = bf_receive(sock, &got);
|
|
|
|
if (got <= 0) {
|
2001-01-25 22:53:02 +01:00
|
|
|
luaL_pushresult(&b);
|
|
|
|
return NET_CLOSED;
|
|
|
|
}
|
2001-03-12 21:04:25 +01:00
|
|
|
pos = 0;
|
2001-01-25 22:53:02 +01:00
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Module exported functions
|
|
|
|
\*=========================================================================*/
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2001-01-15 05:16:35 +01:00
|
|
|
* Initializes the library interface with Lua and the socket library.
|
|
|
|
* Defines the symbols exported to Lua.
|
2000-06-02 19:55:14 +02:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-06-19 21:31:22 +02:00
|
|
|
LUASOCKET_API void lua_socketlibopen(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-03-12 21:04:25 +01:00
|
|
|
struct luaL_reg funcs[] = {
|
2001-01-25 22:53:02 +01:00
|
|
|
{"bind", global_tcpbind},
|
2001-03-06 20:03:10 +01:00
|
|
|
{"connect", global_tcpconnect},
|
|
|
|
{"select", global_select},
|
2001-01-25 22:53:02 +01:00
|
|
|
{"toip", global_toip},
|
|
|
|
{"tohostname", global_tohostname},
|
2001-03-06 20:03:10 +01:00
|
|
|
{"udpsocket", global_udpsocket},
|
2001-01-25 22:53:02 +01:00
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
/* declare new Lua tags for used userdata values */
|
|
|
|
p_tags tags = (p_tags) lua_newuserdata(L, sizeof(t_tags));
|
|
|
|
if (!tags) lua_error(L, "out of memory");
|
|
|
|
tags->client = lua_newtag(L);
|
|
|
|
tags->server = lua_newtag(L);
|
|
|
|
tags->table = lua_newtag(L);
|
|
|
|
tags->udp = lua_newtag(L);
|
|
|
|
/* global functions exported */
|
|
|
|
for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) {
|
|
|
|
lua_pushuserdata(L, tags);
|
|
|
|
lua_pushcclosure(L, funcs[i].func, 1);
|
|
|
|
lua_setglobal(L, funcs[i].name);
|
|
|
|
}
|
|
|
|
/* socket garbage collection */
|
|
|
|
lua_pushuserdata(L, tags);
|
|
|
|
lua_pushcclosure(L, gc_table, 1);
|
|
|
|
lua_settagmethod(L, tags->table, "gc");
|
2001-01-15 05:16:35 +01:00
|
|
|
#ifdef WIN32
|
2001-01-25 22:53:02 +01:00
|
|
|
/* WinSock needs special initialization */
|
|
|
|
winsock_open();
|
2001-01-15 05:16:35 +01:00
|
|
|
#else
|
2001-01-25 22:53:02 +01:00
|
|
|
/* avoid getting killed by a SIGPIPE signal thrown by send */
|
|
|
|
handle_sigpipe();
|
2001-01-15 05:16:35 +01:00
|
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
2001-01-25 22:53:02 +01:00
|
|
|
/* test support functions */
|
2001-06-04 22:44:39 +02:00
|
|
|
lua_pushcfunction(L, global_sleep); lua_setglobal(L, "_sleep");
|
|
|
|
lua_pushcfunction(L, global_time); lua_setglobal(L, "_time");
|
2001-01-15 05:16:35 +01:00
|
|
|
#endif
|
2001-03-12 21:04:25 +01:00
|
|
|
#ifndef LUASOCKET_NOGLOBALS
|
2001-04-24 00:37:55 +02:00
|
|
|
{
|
|
|
|
char *global[] = {
|
|
|
|
"accept", "close", "getpeername",
|
|
|
|
"getsockname", "receive", "send",
|
|
|
|
"receivefrom", "sendto"
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < sizeof(global)/sizeof(char *); i++) {
|
|
|
|
lua_pushstring(L, global[i]);
|
|
|
|
lua_pushuserdata(L, tags);
|
|
|
|
lua_pushcclosure(L, global_callfromtable, 2);
|
|
|
|
lua_setglobal(L, global[i]);
|
|
|
|
}
|
|
|
|
}
|
2001-03-12 21:04:25 +01:00
|
|
|
#endif
|
2001-01-15 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
2001-01-25 22:53:02 +01:00
|
|
|
* Lua Stack manipulation functions
|
2001-01-15 05:16:35 +01:00
|
|
|
\*=========================================================================*/
|
2001-01-25 22:53:02 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Creates a t_sock structure with default values for a client sock.
|
|
|
|
* Pushes the Lua table with sock fields and appropriate methods
|
|
|
|
* Input
|
|
|
|
* tags: tags structure
|
|
|
|
* Returns
|
|
|
|
* pointer to allocated t_sock structure, NULL in case of error
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static p_sock push_clienttable(lua_State *L, p_tags tags)
|
|
|
|
{
|
|
|
|
static struct luaL_reg funcs[] = {
|
|
|
|
{"close", table_close},
|
|
|
|
{"getsockname", table_getsockname},
|
|
|
|
{"getpeername", table_getpeername},
|
|
|
|
{"receive", table_tcpreceive},
|
|
|
|
{"send", table_tcpsend},
|
|
|
|
{"timeout", table_timeout},
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
p_sock sock;
|
|
|
|
lua_newtable(L); lua_settag(L, tags->table);
|
|
|
|
lua_pushstring(L, P_SOCK);
|
|
|
|
sock = (p_sock) lua_newuserdata(L, sizeof(t_sock));
|
|
|
|
if (!sock) return NULL;
|
|
|
|
lua_settag(L, tags->client);
|
|
|
|
lua_settable(L, -3);
|
2001-03-12 21:04:25 +01:00
|
|
|
sock->sock = INVALID_SOCKET;
|
2001-01-25 22:53:02 +01:00
|
|
|
sock->is_connected = 0;
|
|
|
|
sock->tm_block = -1;
|
|
|
|
sock->tm_return = -1;
|
|
|
|
sock->bf_first = sock->bf_last = 0;
|
|
|
|
for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) {
|
|
|
|
lua_pushstring(L, funcs[i].name);
|
|
|
|
lua_pushusertag(L, sock, tags->client);
|
|
|
|
lua_pushcclosure(L, funcs[i].func, 1);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Creates a t_sock structure with default values for a server sock.
|
|
|
|
* Pushes the Lua table with sock fields and appropriate methods
|
|
|
|
* Input
|
|
|
|
* tags: tags structure
|
|
|
|
* Returns
|
|
|
|
* pointer to allocated t_sock structure, NULL in case of error
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static p_sock push_servertable(lua_State *L, p_tags tags)
|
|
|
|
{
|
|
|
|
static struct luaL_reg funcs[] = {
|
|
|
|
{"close", table_close},
|
|
|
|
{"getsockname", table_getsockname},
|
|
|
|
{"timeout", table_timeout},
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
p_sock sock;
|
|
|
|
lua_newtable(L); lua_settag(L, tags->table);
|
|
|
|
lua_pushstring(L, P_SOCK);
|
|
|
|
sock = (p_sock) lua_newuserdata(L, sizeof(t_sock));
|
|
|
|
if (!sock) return NULL;
|
|
|
|
lua_settag(L, tags->server);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
sock->sock = INVALID_SOCKET;
|
|
|
|
sock->tm_block = -1;
|
|
|
|
sock->tm_return = -1;
|
|
|
|
sock->bf_first = sock->bf_last = 0;
|
|
|
|
for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) {
|
|
|
|
lua_pushstring(L, funcs[i].name);
|
|
|
|
lua_pushusertag(L, sock, tags->client);
|
|
|
|
lua_pushcclosure(L, funcs[i].func, 1);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
/* the accept method is different, it needs the tags closure too */
|
|
|
|
lua_pushstring(L, "accept");
|
|
|
|
lua_pushuserdata(L, tags);
|
|
|
|
lua_pushusertag(L, sock, tags->client);
|
|
|
|
lua_pushcclosure(L, table_tcpaccept, 2);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Creates a t_sock structure with default values for a udp sock.
|
|
|
|
* Pushes the Lua table with sock fields and appropriate methods
|
|
|
|
* Input
|
|
|
|
* tags: tags structure
|
|
|
|
* Returns
|
|
|
|
* pointer to allocated t_sock structure, NULL in case of error
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static p_sock push_udptable(lua_State *L, p_tags tags)
|
|
|
|
{
|
|
|
|
static struct luaL_reg funcs[] = {
|
|
|
|
{"sendto", table_udpsendto},
|
|
|
|
{"setpeername", table_udpsetpeername},
|
|
|
|
{"setsockname", table_udpsetsockname},
|
|
|
|
{"getpeername", table_getpeername},
|
|
|
|
{"getsockname", table_getsockname},
|
|
|
|
{"receivefrom", table_udpreceivefrom},
|
|
|
|
{"receive", table_udpreceive},
|
|
|
|
{"send", table_udpsend},
|
|
|
|
{"close", table_close},
|
|
|
|
{"timeout", table_timeout},
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
p_sock sock;
|
|
|
|
lua_newtable(L); lua_settag(L, tags->table);
|
|
|
|
lua_pushstring(L, P_SOCK);
|
|
|
|
sock = (p_sock) lua_newuserdata(L, sizeof(t_sock));
|
|
|
|
if (!sock) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, "out of memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
lua_settag(L, tags->udp);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
sock->sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (sock->sock == INVALID_SOCKET) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, socket_strerror());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
sock->is_connected = 0;
|
|
|
|
sock->tm_block = -1;
|
|
|
|
sock->tm_return = -1;
|
|
|
|
sock->bf_first = sock->bf_last = 0;
|
|
|
|
for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) {
|
|
|
|
lua_pushstring(L, funcs[i].name);
|
|
|
|
lua_pushusertag(L, sock, tags->udp);
|
|
|
|
lua_pushcclosure(L, funcs[i].func, 1);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Passes all resolver information to Lua as a table
|
|
|
|
* Input
|
|
|
|
* hp: hostent structure returned by resolver
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void push_resolved(lua_State *L, struct hostent *hp)
|
|
|
|
{
|
2001-03-06 20:03:10 +01:00
|
|
|
char **alias;
|
|
|
|
struct in_addr **addr;
|
|
|
|
int i, resolved;
|
2001-01-25 22:53:02 +01:00
|
|
|
|
|
|
|
lua_newtable(L); resolved = lua_gettop(L);
|
|
|
|
|
2001-03-06 20:03:10 +01:00
|
|
|
lua_pushstring(L, "name");
|
|
|
|
lua_pushstring(L, hp->h_name);
|
|
|
|
lua_settable(L, resolved);
|
2001-01-25 22:53:02 +01:00
|
|
|
|
|
|
|
lua_pushstring(L, "ip");
|
|
|
|
lua_pushstring(L, "alias");
|
|
|
|
|
2001-03-06 20:03:10 +01:00
|
|
|
i = 1;
|
|
|
|
alias = hp->h_aliases;
|
2001-01-25 22:53:02 +01:00
|
|
|
lua_newtable(L);
|
2001-03-06 20:03:10 +01:00
|
|
|
while (*alias) {
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_pushstring(L, *alias);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
i++; alias++;
|
|
|
|
}
|
|
|
|
lua_settable(L, resolved);
|
2001-01-25 22:53:02 +01:00
|
|
|
|
2001-03-06 20:03:10 +01:00
|
|
|
i = 1;
|
2001-01-25 22:53:02 +01:00
|
|
|
lua_newtable(L);
|
2001-03-06 20:03:10 +01:00
|
|
|
addr = (struct in_addr **) hp->h_addr_list;
|
2001-01-25 22:53:02 +01:00
|
|
|
while (*addr) {
|
2001-03-06 20:03:10 +01:00
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_pushstring(L, inet_ntoa(**addr));
|
|
|
|
lua_settable(L, -3);
|
2001-01-25 22:53:02 +01:00
|
|
|
i++; addr++;
|
|
|
|
}
|
2001-03-06 20:03:10 +01:00
|
|
|
lua_settable(L, resolved);
|
2001-01-25 22:53:02 +01:00
|
|
|
}
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Passes an error code to Lua. The NET_DONE error is translated to nil.
|
|
|
|
* Input
|
|
|
|
* err: error code to be passed to Lua
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void push_error(lua_State *L, int err)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (err) {
|
|
|
|
case NET_DONE:
|
|
|
|
lua_pushnil(L);
|
|
|
|
break;
|
|
|
|
case NET_TIMEOUT:
|
|
|
|
lua_pushstring(L, "timeout");
|
|
|
|
break;
|
|
|
|
case NET_CLOSED:
|
|
|
|
lua_pushstring(L, "closed");
|
|
|
|
break;
|
|
|
|
case NET_REFUSED:
|
|
|
|
lua_pushstring(L, "refused");
|
|
|
|
break;
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
static p_tags pop_tags(lua_State *L)
|
2000-12-27 20:19:22 +01:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_tags tags = (p_tags) lua_touserdata(L, -1);
|
|
|
|
if (!tags) lua_error(L, "invalid closure! (probably misuse of library)");
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return tags;
|
2000-12-27 20:19:22 +01:00
|
|
|
}
|
|
|
|
|
2001-01-15 05:16:35 +01:00
|
|
|
static p_sock pop_sock(lua_State *L)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_sock sock = (p_sock) lua_touserdata(L, -1);
|
|
|
|
if (!sock) lua_error(L, "invalid socket object");
|
|
|
|
if (sock->sock == INVALID_SOCKET)
|
|
|
|
lua_error(L, "operation on closed socket");
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return sock;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-03-06 20:03:10 +01:00
|
|
|
static p_sock get_sock(lua_State *L, int s, p_tags tags, int *tag)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
p_sock sock;
|
2001-03-06 20:03:10 +01:00
|
|
|
if (lua_tag(L, s) != tags->table) lua_error(L, "invalid socket object");
|
2001-01-25 22:53:02 +01:00
|
|
|
lua_pushstring(L, P_SOCK);
|
2001-03-06 20:03:10 +01:00
|
|
|
lua_gettable(L, s > 0 ? s : s-1);
|
2001-01-25 22:53:02 +01:00
|
|
|
sock = lua_touserdata(L, -1);
|
|
|
|
if (!sock) lua_error(L, "invalid socket object");
|
|
|
|
if (tag) *tag = lua_tag(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return sock;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
2001-03-06 20:03:10 +01:00
|
|
|
static p_sock get_selfsock(lua_State *L, p_tags tags, int *tag)
|
2001-01-15 05:16:35 +01:00
|
|
|
{
|
2001-03-06 20:03:10 +01:00
|
|
|
return get_sock(L, 1, tags, tag);
|
2001-01-15 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
2000-06-02 19:55:14 +02:00
|
|
|
/*=========================================================================*\
|
|
|
|
* WinSock2 specific functions.
|
|
|
|
\*=========================================================================*/
|
|
|
|
#ifdef WIN32
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Initializes WinSock2 library.
|
|
|
|
* Returns
|
|
|
|
* 1 in case of success. 0 in case of error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-15 05:16:35 +01:00
|
|
|
static int winsock_open(void)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
WORD wVersionRequested;
|
|
|
|
WSADATA wsaData;
|
|
|
|
int err;
|
|
|
|
wVersionRequested = MAKEWORD(2, 0);
|
|
|
|
err = WSAStartup(wVersionRequested, &wsaData );
|
|
|
|
if (err != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) {
|
|
|
|
WSACleanup();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Put socket into blocking mode.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void set_blocking(p_sock sock)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
u_long argp = 0;
|
|
|
|
ioctlsocket(sock->sock, FIONBIO, &argp);
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Put socket into non-blocking mode.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void set_nonblocking(p_sock sock)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
u_long argp = 1;
|
|
|
|
ioctlsocket(sock->sock, FIONBIO, &argp);
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last host manipulation error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static char *host_strerror(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (WSAGetLastError()) {
|
|
|
|
case HOST_NOT_FOUND: return "host not found";
|
|
|
|
case NO_ADDRESS: return "unable to resolve host name";
|
|
|
|
case NO_RECOVERY: return "name server error";
|
|
|
|
case TRY_AGAIN: return "name server unavailable, try again later.";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last socket manipulation error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static char *socket_strerror(void)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (WSAGetLastError()) {
|
|
|
|
case WSANOTINITIALISED: return "not initialized";
|
|
|
|
case WSAENETDOWN: return "network is down";
|
|
|
|
case WSAEMFILE: return "descriptor table is full";
|
|
|
|
case WSAENOBUFS: return "insufficient buffer space";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last bind operation error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static char *bind_strerror(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (WSAGetLastError()) {
|
|
|
|
case WSANOTINITIALISED: return "not initialized";
|
|
|
|
case WSAENETDOWN: return "network is down";
|
|
|
|
case WSAEADDRINUSE: return "address already in use";
|
|
|
|
case WSAEINVAL: return "socket already bound";
|
|
|
|
case WSAENOBUFS: return "too many connections";
|
|
|
|
case WSAEFAULT: return "invalid address";
|
|
|
|
case WSAENOTSOCK: return "not a socket descriptor";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last connect operationerror.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static char *connect_strerror(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (WSAGetLastError()) {
|
|
|
|
case WSANOTINITIALISED: return "not initialized";
|
|
|
|
case WSAENETDOWN: return "network is down";
|
|
|
|
case WSAEADDRINUSE: return "address already in use";
|
|
|
|
case WSAEADDRNOTAVAIL: return "address unavailable";
|
|
|
|
case WSAECONNREFUSED: return "connection refused";
|
|
|
|
case WSAENETUNREACH: return "network is unreachable";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* BSD specific functions.
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Put socket into blocking mode.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void set_blocking(p_sock sock)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
int flags = fcntl(sock->sock, F_GETFL, 0);
|
|
|
|
flags &= (~(O_NONBLOCK));
|
|
|
|
fcntl(sock->sock, F_SETFL, flags);
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Put socket into non-blocking mode.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static void set_nonblocking(p_sock sock)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
int flags = fcntl(sock->sock, F_GETFL, 0);
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
fcntl(sock->sock, F_SETFL, flags);
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last host manipulation error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static char *host_strerror(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (h_errno) {
|
|
|
|
case HOST_NOT_FOUND: return "host not found";
|
|
|
|
case NO_ADDRESS: return "unable to resolve host name";
|
|
|
|
case NO_RECOVERY: return "name server error";
|
|
|
|
case TRY_AGAIN: return "name server unavailable, try again later";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last socket manipulation error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2001-01-25 22:53:02 +01:00
|
|
|
static char *socket_strerror(void)
|
2000-06-02 19:55:14 +02:00
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (errno) {
|
|
|
|
case EACCES: return "access denied";
|
|
|
|
case EMFILE: return "descriptor table is full";
|
|
|
|
case ENFILE: return "too many open files";
|
|
|
|
case ENOBUFS: return "insuffucient buffer space";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last bind command error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static char *bind_strerror(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (errno) {
|
|
|
|
case EBADF: return "invalid descriptor";
|
|
|
|
case EINVAL: return "socket already bound";
|
|
|
|
case EACCES: return "access denied";
|
|
|
|
case ENOTSOCK: return "not a socket descriptor";
|
|
|
|
case EADDRINUSE: return "address already in use";
|
|
|
|
case EADDRNOTAVAIL: return "address unavailable";
|
|
|
|
case ENOMEM: return "out of memory";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Returns a string describing the last connect error.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
static char *connect_strerror(void)
|
|
|
|
{
|
2001-01-25 22:53:02 +01:00
|
|
|
switch (errno) {
|
|
|
|
case EBADF: return "invalid descriptor";
|
|
|
|
case ENOTSOCK: return "not a socket descriptor";
|
|
|
|
case EADDRNOTAVAIL: return "address not availabe";
|
|
|
|
case ETIMEDOUT: return "connection timed out";
|
|
|
|
case ECONNREFUSED: return "connection refused";
|
|
|
|
case EACCES: return "access denied";
|
|
|
|
case ENETUNREACH: return "network is unreachable";
|
|
|
|
case EADDRINUSE: return "address already in use";
|
|
|
|
default: return "unknown error";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Some systems do not provide this so that we provide our own. It's not
|
|
|
|
* marvelously fast, but it works just fine.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
#ifdef LUASOCKET_ATON
|
|
|
|
static int inet_aton(const char *cp, struct in_addr *inp)
|
|
|
|
{
|
|
|
|
unsigned int a = 0, b = 0, c = 0, d = 0;
|
|
|
|
int n = 0, r;
|
|
|
|
unsigned long int addr = 0;
|
|
|
|
r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
|
|
|
|
if (r == 0 || n == 0) return 0;
|
|
|
|
cp += n;
|
|
|
|
if (*cp) return 0;
|
|
|
|
if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
|
|
|
|
if (inp) {
|
|
|
|
addr += a; addr <<= 8;
|
|
|
|
addr += b; addr <<= 8;
|
|
|
|
addr += c; addr <<= 8;
|
|
|
|
addr += d;
|
|
|
|
inp->s_addr = htonl(addr);
|
|
|
|
}
|
|
|
|
return 1;
|
2000-06-02 19:55:14 +02:00
|
|
|
}
|
|
|
|
#endif
|
2001-01-25 22:53:02 +01:00
|
|
|
|