Finished implementation of LuaSocket 2.0 alpha on Linux.

Some testing still needed.
This commit is contained in:
Diego Nehab 2003-06-26 18:47:49 +00:00
parent f330540576
commit 71f6bb60bf
41 changed files with 700 additions and 339 deletions

4
NEW
View File

@ -8,7 +8,9 @@ a given domain/family and protocol. Then connect or bind if needed. Then
use IO functions. use IO functions.
All functions return a non-nil value as first return value if successful. All functions return a non-nil value as first return value if successful.
All functions return nil followed by error message in case of error. All functions return whatever could be retrieved followed by error message
in case of error. The best way to check for errors is to check for the
presence of an error message.
WARNING: The send function was affected. WARNING: The send function was affected.
Better error messages and parameter checking. Better error messages and parameter checking.

26
TODO
View File

@ -1,24 +1,26 @@
- Melhorar a interface de setoptions (aceitar nada como true, por exemplo)
- Inicializaccao das classes pode falhar? - Inicializaccao das classes pode falhar?
- Ajeitar melhor a hierarquia de classes. Ajeitar o file... - Ajeitar melhor a hierarquia de classes. Ajeitar o file...
- GARBAGE COLLECTOR!
- Adicionar um método sock:setoption???
- testar em várias plataformas
- adicionar exemplos de expansão: pipe, local, named pipe
* Como mostrar um erro em lua_socketlibopen()... * Como mostrar um erro em lua_socketlibopen()...
* O location do "redirect" pode ser relativo ao servidor atual (não pode, * O location do "redirect" pode ser relativo ao servidor atual (não pode,
mas os servidores fazem merda...) mas os servidores fazem merda...)
* - Ajeitar para Lua 4.1 * Ajeitar para Lua 5.0
* Padronizar os retornos de funccao
* Separar as classes em arquivos
* Retorno de sendto em datagram sockets pode ser refused
* Fazer compilar com g++
- Padronizar os retornos de funccao
- Thread-safe - Thread-safe
- proteger gethostby*.* com um mutex GLOBAL! - proteger gethostby*.* com um mutex GLOBAL!
- proteger o atomizar o conjunto (timedout, receive), (timedout, send) - proteger ou atomizar o conjunto (timedout, receive), (timedout, send)
- Usar "require" nos módulos - inet_ntoa também é uma merda.
- SSL - SSL
- Fazer compilar com g++ - Proxy support pro http
- usar lua_verror
- separar as classes em arquivos
- criar mais uma classe, a de stream, entre p_sock e p_client
- criar um internal include file ls.h
- impedir que voe quando chamar accept(udpsocket())
- trocar recv and send por read e write (ver se funciona)
- checar operações em closed sockets - checar operações em closed sockets
- checar teste de writable socket com select - checar teste de writable socket com select
@ -34,6 +36,4 @@
- unix 92 bytes maximo no endereço, incluindo o zero - unix 92 bytes maximo no endereço, incluindo o zero
- unix 9216 maximo de datagram size - unix 9216 maximo de datagram size
- retorno de send/receive em datagram sockets pode ser refused...
- adicionar um método sock:setoption???

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program that checks links in HTML files -- Little program that checks links in HTML files
-- LuaSocket 1.5 sample files. -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program to download DICT word definitions -- Little program to download DICT word definitions
-- LuaSocket 1.5 sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program to download files from URLs -- Little program to download files from URLs
-- LuaSocket 1.5 sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- TFTP support for the Lua language -- TFTP support for the Lua language
-- LuaSocket 1.5 toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- Conforming to: RFC 783, LTN7 -- Conforming to: RFC 783, LTN7
-- RCS ID: $Id$ -- RCS ID: $Id$

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- UDP sample: daytime protocol client -- UDP sample: daytime protocol client
-- LuaSocket 1.5 sample files. -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- UDP sample: echo protocol client -- UDP sample: echo protocol client
-- LuaSocket 1.5 sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- UDP sample: echo protocol server -- UDP sample: echo protocol server
-- LuaSocket 1.5 sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- TCP sample: Little program to dump lines received at a given port -- TCP sample: Little program to dump lines received at a given port
-- LuaSocket 1.5 sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- TCP sample: Little program to send text lines to a given host/port -- TCP sample: Little program to send text lines to a given host/port
-- LuaSocket 1.5 sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Select sample: simple text line server -- Select sample: simple text line server
-- LuaSocket 1.5 sample files. -- LuaSocket sample files.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$ -- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -1,142 +1,167 @@
/*=========================================================================*\ /*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation * Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h>
#include "luasocket.h"
#include "auxiliar.h" #include "auxiliar.h"
/*=========================================================================*\ /*=========================================================================*\
* Exported functions * Exported functions
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a new class. A class has methods given by the func array and the * Initializes the module
* field 'class' tells the object class. The table 'group' list the class
* groups the object belongs to.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void aux_newclass(lua_State *L, const char *name, luaL_reg *func) void aux_open(lua_State *L)
{ {
lua_pushstring(L, name); /* create namespace table */
lua_pushstring(L, LUASOCKET_LIBNAME);
lua_newtable(L); lua_newtable(L);
lua_pushstring(L, "__index"); #ifdef LUASOCKET_DEBUG
lua_newtable(L); lua_pushstring(L, "debug");
luaL_openlib(L, NULL, func, 0);
lua_pushstring(L, "class");
lua_pushstring(L, name);
lua_rawset(L, -3);
lua_pushstring(L, "group");
lua_newtable(L);
lua_rawset(L, -3);
lua_rawset(L, -3);
lua_rawset(L, LUA_REGISTRYINDEX);
}
/*-------------------------------------------------------------------------*\
* Add group to object list of groups.
\*-------------------------------------------------------------------------*/
void aux_add2group(lua_State *L, const char *name, const char *group)
{
lua_pushstring(L, name);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushstring(L, "__index");
lua_rawget(L, -2);
lua_pushstring(L, "group");
lua_rawget(L, -2);
lua_pushstring(L, group);
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
lua_rawset(L, -3); lua_rawset(L, -3);
lua_pop(L, 3); #endif
lua_settable(L, LUA_GLOBALSINDEX);
/* make sure modules know what is our namespace */
lua_pushstring(L, "LUASOCKET_LIBNAME");
lua_pushstring(L, LUASOCKET_LIBNAME);
lua_settable(L, LUA_GLOBALSINDEX);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata making sure the object belongs to a given class. * Creates a new class with given methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *aux_checkclass(lua_State *L, const char *name, int objidx) void aux_newclass(lua_State *L, const char *classname, luaL_reg *func)
{ {
void *data = aux_getclassudata(L, name, objidx); luaL_newmetatable(L, classname); /* mt */
lua_pushstring(L, "__index"); /* mt,"__index" */
lua_newtable(L); /* mt,"__index",it */
luaL_openlib(L, NULL, func, 0);
#ifdef LUASOCKET_DEBUG
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
lua_rawset(L, -3); /* mt,"__index",it */
#endif
/* get __gc method from class and use it for garbage collection */
lua_pushstring(L, "__gc"); /* mt,"__index",it,"__gc" */
lua_pushstring(L, "__gc"); /* mt,"__index",it,"__gc","__gc" */
lua_rawget(L, -3); /* mt,"__index",it,"__gc",fn */
lua_rawset(L, -5); /* mt,"__index",it */
lua_rawset(L, -3); /* mt */
lua_pop(L, 1);
}
/*-------------------------------------------------------------------------*\
* Insert class into group
\*-------------------------------------------------------------------------*/
void aux_add2group(lua_State *L, const char *classname, const char *groupname)
{
luaL_getmetatable(L, classname);
lua_pushstring(L, groupname);
lua_pushboolean(L, 1);
lua_rawset(L, -3);
lua_pop(L, 1);
}
/*-------------------------------------------------------------------------*\
* Make sure argument is a boolean
\*-------------------------------------------------------------------------*/
int aux_checkboolean(lua_State *L, int objidx)
{
if (!lua_isboolean(L, objidx))
luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
return lua_toboolean(L, objidx);
}
/*-------------------------------------------------------------------------*\
* Calls appropriate option handler
\*-------------------------------------------------------------------------*/
int aux_meth_setoption(lua_State *L, luaL_reg *opt)
{
const char *name = luaL_checkstring(L, 2); /* obj, name, args */
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[45];
sprintf(msg, "unknown option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
lua_remove(L, 2); /* obj, args */
lua_pushcfunction(L, opt->func); /* obj, args, func */
lua_insert(L, 1); /* func, obj, args */
lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
return lua_gettop(L);
}
/*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given class, abort with
* error otherwise
\*-------------------------------------------------------------------------*/
void *aux_checkclass(lua_State *L, const char *classname, int objidx)
{
void *data = aux_getclassudata(L, classname, objidx);
if (!data) { if (!data) {
char msg[45]; char msg[45];
sprintf(msg, "%.35s expected", name); sprintf(msg, "%.35s expected", classname);
luaL_argerror(L, objidx, msg); luaL_argerror(L, objidx, msg);
} }
return data; return data;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata making sure the object belongs to a given group. * Return userdata pointer if object belongs to a given group, abort with
* error otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *aux_checkgroup(lua_State *L, const char *group, int objidx) void *aux_checkgroup(lua_State *L, const char *groupname, int objidx)
{ {
void *data = aux_getgroupudata(L, group, objidx); void *data = aux_getgroupudata(L, groupname, objidx);
if (!data) { if (!data) {
char msg[45]; char msg[45];
sprintf(msg, "%.35s expected", group); sprintf(msg, "%.35s expected", groupname);
luaL_argerror(L, objidx, msg); luaL_argerror(L, objidx, msg);
} }
return data; return data;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Set object class. * Set object class
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void aux_setclass(lua_State *L, const char *name, int objidx) void aux_setclass(lua_State *L, const char *classname, int objidx)
{ {
lua_pushstring(L, name); luaL_getmetatable(L, classname);
lua_rawget(L, LUA_REGISTRYINDEX);
if (objidx < 0) objidx--; if (objidx < 0) objidx--;
lua_setmetatable(L, objidx); lua_setmetatable(L, objidx);
} }
/*=========================================================================*\
* Internal functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata if object belongs to a given group. * Get a userdata pointer if object belongs to a given group. Return NULL
* otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *aux_getgroupudata(lua_State *L, const char *group, int objidx) void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx)
{ {
if (!lua_getmetatable(L, objidx)) if (!lua_getmetatable(L, objidx))
return NULL; return NULL;
lua_pushstring(L, "__index"); lua_pushstring(L, groupname);
lua_rawget(L, -2);
if (!lua_istable(L, -1)) {
lua_pop(L, 2);
return NULL;
}
lua_pushstring(L, "group");
lua_rawget(L, -2);
if (!lua_istable(L, -1)) {
lua_pop(L, 3);
return NULL;
}
lua_pushstring(L, group);
lua_rawget(L, -2); lua_rawget(L, -2);
if (lua_isnil(L, -1)) { if (lua_isnil(L, -1)) {
lua_pop(L, 4); lua_pop(L, 2);
return NULL; return NULL;
} else {
lua_pop(L, 2);
return lua_touserdata(L, objidx);
} }
lua_pop(L, 4);
return lua_touserdata(L, objidx);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata if object belongs to a given class. * Get a userdata pointer if object belongs to a given class. Return NULL
* otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *aux_getclassudata(lua_State *L, const char *group, int objidx) void *aux_getclassudata(lua_State *L, const char *classname, int objidx)
{ {
if (!lua_getmetatable(L, objidx)) return luaL_checkudata(L, objidx, classname);
return NULL;
lua_pushstring(L, "__index");
lua_rawget(L, -2);
if (!lua_istable(L, -1)) {
lua_pop(L, 2);
return NULL;
}
lua_pushstring(L, "class");
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 3);
return NULL;
}
lua_pop(L, 3);
return lua_touserdata(L, objidx);
} }

View File

@ -1,22 +1,37 @@
#ifndef AUX_H
#define AUX_H
/*=========================================================================*\ /*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation * Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit
*
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
* group is a name associated to a class. A class can belong to any number
* of groups. This module provides the functionality to:
*
* - create new classes
* - add classes to groups
* - set the class of object
* - check if an object belongs to a given class or group
*
* LuaSocket class names follow the convention <module>{<class>}. Modules
* can define any number of classes and groups. The module tcp.c, for
* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
* the groups tcp{client, server} and tcp{any}. Module functions can then
* perform type-checking on it's arguments by either class or group.
*
* LuaSocket metatables define the __index metamethod as being a table. This
* table has one field for each method supported by the class. In DEBUG
* mode, it also has one field with the class name.
*
* The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib.
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef AUX_H
#define AUX_H
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
void aux_newclass(lua_State *L, const char *name, luaL_reg *func);
void aux_add2group(lua_State *L, const char *name, const char *group);
void *aux_checkclass(lua_State *L, const char *name, int objidx);
void *aux_checkgroup(lua_State *L, const char *group, int objidx);
void *aux_getclassudata(lua_State *L, const char *group, int objidx);
void *aux_getgroupudata(lua_State *L, const char *group, int objidx);
void aux_setclass(lua_State *L, const char *name, int objidx);
/* min and max macros */ /* min and max macros */
#ifndef MIN #ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y) #define MIN(x, y) ((x) < (y) ? x : y)
@ -25,4 +40,15 @@ void aux_setclass(lua_State *L, const char *name, int objidx);
#define MAX(x, y) ((x) > (y) ? x : y) #define MAX(x, y) ((x) > (y) ? x : y)
#endif #endif
#endif void aux_open(lua_State *L);
void aux_newclass(lua_State *L, const char *classname, luaL_reg *func);
void aux_add2group(lua_State *L, const char *classname, const char *group);
void aux_setclass(lua_State *L, const char *classname, int objidx);
void *aux_checkclass(lua_State *L, const char *classname, int objidx);
void *aux_checkgroup(lua_State *L, const char *groupname, int objidx);
void *aux_getclassudata(lua_State *L, const char *groupname, int objidx);
void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx);
int aux_meth_setoption(lua_State *L, luaL_reg *opt);
int aux_checkboolean(lua_State *L, int objidx);
#endif /* AUX_H */

View File

@ -1,12 +1,12 @@
/*=========================================================================*\ /*=========================================================================*\
* Buffered input/output routines * Input/Output interface for Lua programs
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
#include "error.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "buffer.h" #include "buffer.h"
@ -42,7 +42,7 @@ void buf_init(p_buf buf, p_io io, p_tm tm)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Send data through buffered object * object:send() interface
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int buf_meth_send(lua_State *L, p_buf buf) int buf_meth_send(lua_State *L, p_buf buf)
{ {
@ -59,7 +59,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
total += sent; total += sent;
} }
lua_pushnumber(L, total); lua_pushnumber(L, total);
error_push(L, err); io_pusherror(L, err);
#ifdef LUASOCKET_DEBUG #ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */ /* push time elapsed during operation as the last return value */
lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0); lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0);
@ -68,7 +68,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Receive data from a buffered object * object:receive() interface
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int buf_meth_receive(lua_State *L, p_buf buf) int buf_meth_receive(lua_State *L, p_buf buf)
{ {
@ -101,13 +101,13 @@ int buf_meth_receive(lua_State *L, p_buf buf)
luaL_argcheck(L, 0, arg, "invalid receive pattern"); luaL_argcheck(L, 0, arg, "invalid receive pattern");
break; break;
} }
/* raw pattern */ /* get a fixed number of bytes */
} else err = recvraw(L, buf, (size_t) lua_tonumber(L, arg)); } else err = recvraw(L, buf, (size_t) lua_tonumber(L, arg));
} }
/* push nil for each pattern after an error */ /* push nil for each pattern after an error */
for ( ; arg <= top; arg++) lua_pushnil(L); for ( ; arg <= top; arg++) lua_pushnil(L);
/* last return is an error code */ /* last return is an error code */
error_push(L, err); io_pusherror(L, err);
#ifdef LUASOCKET_DEBUG #ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */ /* push time elapsed during operation as the last return value */
lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0); lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0);
@ -127,9 +127,10 @@ int buf_isempty(p_buf buf)
* Internal functions * Internal functions
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Sends a raw block of data through a buffered object. * Sends a block of data (unbuffered)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) static
int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
{ {
p_io io = buf->io; p_io io = buf->io;
p_tm tm = buf->tm; p_tm tm = buf->tm;
@ -145,7 +146,7 @@ static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Reads a raw block of data from a buffered object. * Reads a fixed number of bytes (buffered)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static static
int recvraw(lua_State *L, p_buf buf, size_t wanted) int recvraw(lua_State *L, p_buf buf, size_t wanted)
@ -167,7 +168,7 @@ int recvraw(lua_State *L, p_buf buf, size_t wanted)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Reads everything until the connection is closed * Reads everything until the connection is closed (buffered)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static static
int recvall(lua_State *L, p_buf buf) int recvall(lua_State *L, p_buf buf)
@ -187,12 +188,12 @@ int recvall(lua_State *L, p_buf buf)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
* are not returned by the function and are discarded from the buffer. * are not returned by the function and are discarded from the buffer
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static static
int recvline(lua_State *L, p_buf buf) int recvline(lua_State *L, p_buf buf)
{ {
int err = 0; int err = IO_DONE;
luaL_Buffer b; luaL_Buffer b;
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
while (err == IO_DONE) { while (err == IO_DONE) {
@ -215,7 +216,8 @@ int recvline(lua_State *L, p_buf buf)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Skips a given number of bytes in read buffer * Skips a given number of bytes from read buffer. No data is read from the
* transport layer
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static static
void buf_skip(p_buf buf, size_t count) void buf_skip(p_buf buf, size_t count)
@ -227,7 +229,7 @@ void buf_skip(p_buf buf, size_t count)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Return any data available in buffer, or get more data from transport layer * Return any data available in buffer, or get more data from transport layer
* if buffer is empty. * if buffer is empty
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static static
int buf_get(p_buf buf, const char **data, size_t *count) int buf_get(p_buf buf, const char **data, size_t *count)
@ -245,3 +247,4 @@ int buf_get(p_buf buf, const char **data, size_t *count)
*data = buf->data + buf->first; *data = buf->data + buf->first;
return err; return err;
} }

View File

@ -1,21 +1,31 @@
#ifndef BUF_H
#define BUF_H
/*=========================================================================*\ /*=========================================================================*\
* Buffered input/output routines * Input/Output interface for Lua programs
* LuaSocket toolkit
*
* Line patterns require buffering. Reading one character at a time involves
* too many system calls and is very slow. This module implements the
* LuaSocket interface for input/output on connected objects, as seen by
* Lua programs.
*
* Input is buffered. Output is *not* buffered because there was no simple
* way of making sure the buffered output data would ever be sent.
*
* The module is built on top of the I/O abstraction defined in io.h and the
* timeout management is done with the timeout.h interface.
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef BUF_H
#define BUF_H
#include <lua.h> #include <lua.h>
#include "io.h" #include "io.h"
#include "timeout.h" #include "timeout.h"
/* buffer size in bytes */ /* buffer size in bytes */
#define BUF_SIZE 8192 #define BUF_SIZE 8192
/*-------------------------------------------------------------------------*\ /* buffer control structure */
* Buffer control structure
\*-------------------------------------------------------------------------*/
typedef struct t_buf_ { typedef struct t_buf_ {
p_io io; /* IO driver used for this buffer */ p_io io; /* IO driver used for this buffer */
p_tm tm; /* timeout management for this buffer */ p_tm tm; /* timeout management for this buffer */
@ -24,9 +34,6 @@ typedef struct t_buf_ {
} t_buf; } t_buf;
typedef t_buf *p_buf; typedef t_buf *p_buf;
/*-------------------------------------------------------------------------*\
* Exported functions
\*-------------------------------------------------------------------------*/
void buf_open(lua_State *L); void buf_open(lua_State *L);
void buf_init(p_buf buf, p_io io, p_tm tm); void buf_init(p_buf buf, p_io io, p_tm tm);
int buf_meth_send(lua_State *L, p_buf buf); int buf_meth_send(lua_State *L, p_buf buf);

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- FTP support for the Lua language -- FTP support for the Lua language
-- LuaSocket 1.5 toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- Conforming to: RFC 959, LTN7 -- Conforming to: RFC 959, LTN7
-- RCS ID: $Id$ -- RCS ID: $Id$

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- HTTP/1.1 client support for the Lua language. -- HTTP/1.1 client support for the Lua language.
-- LuaSocket 1.5 toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- Conforming to: RFC 2616, LTN7 -- Conforming to: RFC 2616, LTN7
-- RCS ID: $Id$ -- RCS ID: $Id$

View File

@ -1,8 +1,10 @@
/*=========================================================================*\ /*=========================================================================*\
* Internet domain functions * Internet domain functions
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <stdio.h>
#include <string.h> #include <string.h>
#include <lua.h> #include <lua.h>
@ -16,7 +18,6 @@
\*=========================================================================*/ \*=========================================================================*/
static int inet_global_toip(lua_State *L); static int inet_global_toip(lua_State *L);
static int inet_global_tohostname(lua_State *L); static int inet_global_tohostname(lua_State *L);
static void inet_pushresolved(lua_State *L, struct hostent *hp); static void inet_pushresolved(lua_State *L, struct hostent *hp);
static luaL_reg func[] = { static luaL_reg func[] = {
@ -43,11 +44,6 @@ void inet_open(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name * Returns all information provided by the resolver given a host name
* or ip address * or ip address
* 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 inet_global_toip(lua_State *L) static int inet_global_toip(lua_State *L)
{ {
@ -72,11 +68,6 @@ static int inet_global_toip(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name * Returns all information provided by the resolver given a host name
* or ip address * or 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 inet_global_tohostname(lua_State *L) static int inet_global_tohostname(lua_State *L)
{ {
@ -102,11 +93,6 @@ static int inet_global_tohostname(lua_State *L)
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Retrieves socket peer name * Retrieves socket peer name
* Input:
* sock: socket
* Lua Returns
* On success: ip address and port of peer
* On error: nil
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int inet_meth_getpeername(lua_State *L, p_sock ps) int inet_meth_getpeername(lua_State *L, p_sock ps)
{ {
@ -123,11 +109,6 @@ int inet_meth_getpeername(lua_State *L, p_sock ps)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Retrieves socket local name * Retrieves socket local name
* Input:
* sock: socket
* Lua Returns
* On success: local ip address and port
* On error: nil
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int inet_meth_getsockname(lua_State *L, p_sock ps) int inet_meth_getsockname(lua_State *L, p_sock ps)
{ {
@ -147,8 +128,6 @@ int inet_meth_getsockname(lua_State *L, p_sock ps)
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Passes all resolver information to Lua as a table * Passes all resolver information to Lua as a table
* Input
* hp: hostent structure returned by resolver
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static void inet_pushresolved(lua_State *L, struct hostent *hp) static void inet_pushresolved(lua_State *L, struct hostent *hp)
{ {
@ -185,12 +164,6 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Tries to connect to remote address (address, port) * Tries to connect to remote address (address, port)
* Input
* ps: pointer to socket
* address: host name or ip address
* port: port number to bind to
* Returns
* NULL in case of success, error message otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_tryconnect(p_sock ps, const char *address, const char *inet_tryconnect(p_sock ps, const char *address,
unsigned short port) unsigned short port)
@ -224,12 +197,6 @@ const char *inet_tryconnect(p_sock ps, const char *address,
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Tries to bind socket to (address, port) * Tries to bind socket to (address, port)
* Input
* sock: pointer to socket
* address: host name or ip address
* port: port number to bind to
* Returns
* NULL in case of success, error message otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_trybind(p_sock ps, const char *address, unsigned short port, const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
int backlog) int backlog)
@ -264,10 +231,6 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Tries to create a new inet socket * Tries to create a new inet socket
* Input
* sock: pointer to socket
* Returns
* NULL if successfull, error message on error
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_trycreate(p_sock ps, int type) const char *inet_trycreate(p_sock ps, int type)
{ {
@ -299,3 +262,5 @@ int inet_aton(const char *cp, struct in_addr *inp)
return 1; return 1;
} }
#endif #endif

View File

@ -1,25 +1,30 @@
#ifndef INET_H
#define INET_H
/*=========================================================================*\ /*=========================================================================*\
* Internet domain functions * Internet domain functions
* LuaSocket toolkit
*
* This module implements the creation and connection of internet domain
* sockets, on top of the socket.h interface, and the interface of with the
* resolver.
*
* The function inet_aton is provided for the platforms where it is not
* available. The module also implements the interface of the internet
* getpeername and getsockname functions as seen by Lua programs.
*
* The Lua functions toip and tohostname are also implemented here.
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef INET_H
#define INET_H
#include <lua.h> #include <lua.h>
#include "socket.h" #include "socket.h"
/*-------------------------------------------------------------------------*\
* Exported functions
\*-------------------------------------------------------------------------*/
void inet_open(lua_State *L); void inet_open(lua_State *L);
const char *inet_tryconnect(p_sock ps, const char *address, const char *inet_tryconnect(p_sock ps, const char *address,
unsigned short port); unsigned short port);
const char *inet_trybind(p_sock ps, const char *address, const char *inet_trybind(p_sock ps, const char *address,
unsigned short port, int backlog); unsigned short port, int backlog);
const char *inet_trycreate(p_sock ps, int type); const char *inet_trycreate(p_sock ps, int type);
int inet_meth_getpeername(lua_State *L, p_sock ps); int inet_meth_getpeername(lua_State *L, p_sock ps);
int inet_meth_getsockname(lua_State *L, p_sock ps); int inet_meth_getsockname(lua_State *L, p_sock ps);
@ -27,4 +32,4 @@ int inet_meth_getsockname(lua_State *L, p_sock ps);
int inet_aton(const char *cp, struct in_addr *inp); int inet_aton(const char *cp, struct in_addr *inp);
#endif #endif
#endif /* INET_H_ */ #endif /* INET_H */

View File

@ -1,8 +1,48 @@
/*=========================================================================*\
* Input/Output abstraction
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "io.h" #include "io.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
void io_init(p_io io, p_send send, p_recv recv, void *ctx) void io_init(p_io io, p_send send, p_recv recv, void *ctx)
{ {
io->send = send; io->send = send;
io->recv = recv; io->recv = recv;
io->ctx = ctx; io->ctx = ctx;
} }
/*-------------------------------------------------------------------------*\
* Translate error codes to Lua
\*-------------------------------------------------------------------------*/
void io_pusherror(lua_State *L, int code)
{
switch (code) {
case IO_DONE:
lua_pushnil(L);
break;
case IO_TIMEOUT:
lua_pushstring(L, "timeout");
break;
case IO_LIMITED:
lua_pushstring(L, "limited");
break;
case IO_CLOSED:
lua_pushstring(L, "closed");
break;
case IO_REFUSED:
lua_pushstring(L, "refused");
break;
default:
lua_pushstring(L, "unknown error");
break;
}
}

View File

@ -1,16 +1,30 @@
#ifndef IO_H #ifndef IO_H
#define IO_H #define IO_H
/*=========================================================================*\
* Input/Output abstraction
* LuaSocket toolkit
*
* This module defines the interface that LuaSocket expects from the
* transport layer for streamed input/output. The idea is that if any
* transport implements this interface, then the buffer.c functions
* automatically work on it.
*
* The module socket.h implements this interface, and thus the module tcp.h
* is very simple.
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h> #include <stdio.h>
#include <lua.h>
/* IO error codes */ /* IO error codes */
enum { enum {
IO_DONE, /* operation completed successfully */ IO_DONE, /* operation completed successfully */
IO_TIMEOUT, /* operation timed out */ IO_TIMEOUT, /* operation timed out */
IO_CLOSED, /* the connection has been closed */ IO_CLOSED, /* the connection has been closed */
IO_ERROR, /* something wrong... */ IO_ERROR, /* something wrong... */
IO_REFUSED, /* transfer has been refused */ IO_REFUSED, /* transfer has been refused */
IO_LIMITED /* maximum number of bytes reached */ IO_LIMITED /* maximum number of bytes reached */
}; };
/* interface to send function */ /* interface to send function */
@ -39,6 +53,7 @@ typedef struct t_io_ {
} t_io; } t_io;
typedef t_io *p_io; typedef t_io *p_io;
void io_pusherror(lua_State *L, int code);
void io_init(p_io io, p_send send, p_recv recv, void *ctx); void io_init(p_io io, p_send send, p_recv recv, void *ctx);
#endif /* IO_H */ #endif /* IO_H */

View File

@ -1,4 +1,5 @@
/*=========================================================================*\ /*=========================================================================*\
* LuaSocket toolkit
* Networking support for the Lua language * Networking support for the Lua language
* Diego Nehab * Diego Nehab
* 26/11/1999 * 26/11/1999
@ -7,7 +8,7 @@
* connectivity of the Lua language. The Lua interface to networking * connectivity of the Lua language. The Lua interface to networking
* functions follows the Sockets API closely, trying to simplify all tasks * functions follows the Sockets API closely, trying to simplify all tasks
* involved in setting up both client and server connections. The provided * involved in setting up both client and server connections. The provided
* IO routines, however, follow the Lua style, being very similar to the * IO routines, however, follow the Lua style, being very similar to the
* standard Lua read and write functions. * standard Lua read and write functions.
* *
* RCS ID: $Id$ * RCS ID: $Id$
@ -24,6 +25,7 @@
\*=========================================================================*/ \*=========================================================================*/
#include "luasocket.h" #include "luasocket.h"
#include "auxiliar.h"
#include "timeout.h" #include "timeout.h"
#include "buffer.h" #include "buffer.h"
#include "socket.h" #include "socket.h"
@ -38,23 +40,11 @@
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes all library modules. * Initializes all library modules.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socketlib(lua_State *L) LUASOCKET_API int luaopen_socket(lua_State *L)
{ {
if (!sock_open()) return 0; if (!sock_open()) return 0;
/* create namespace table */
lua_pushstring(L, LUASOCKET_LIBNAME);
lua_newtable(L);
#ifdef LUASOCKET_DEBUG
lua_pushstring(L, "debug");
lua_pushnumber(L, 1);
lua_settable(L, -3);
#endif
lua_settable(L, LUA_GLOBALSINDEX);
/* make sure modules know what is our namespace */
lua_pushstring(L, "LUASOCKET_LIBNAME");
lua_pushstring(L, LUASOCKET_LIBNAME);
lua_settable(L, LUA_GLOBALSINDEX);
/* initialize all modules */ /* initialize all modules */
aux_open(L);
tm_open(L); tm_open(L);
buf_open(L); buf_open(L);
inet_open(L); inet_open(L);

View File

@ -1,17 +1,19 @@
#ifndef LUASOCKET_H
#define LUASOCKET_H
/*=========================================================================*\ /*=========================================================================*\
* LuaSocket toolkit
* Networking support for the Lua language * Networking support for the Lua language
* Diego Nehab * Diego Nehab
* 9/11/1999 * 9/11/1999
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef LUASOCKET_H #include <lua.h>
#define LUASOCKET_H
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Current luasocket version * Current luasocket version
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#define LUASOCKET_VERSION "LuaSocket 1.5 (alpha)" #define LUASOCKET_VERSION "LuaSocket 2.0 (alpha)"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Library's namespace * Library's namespace
@ -28,6 +30,6 @@
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes the library. * Initializes the library.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socketlib(lua_State *L); LUASOCKET_API int luaopen_socket(lua_State *L);
#endif /* LUASOCKET_H */ #endif /* LUASOCKET_H */

View File

@ -1,5 +1,7 @@
/*=========================================================================*\ /*=========================================================================*\
* Select implementation * Select implementation
* LuaSocket toolkit
*
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include <string.h>
@ -12,6 +14,9 @@
#include "auxiliar.h" #include "auxiliar.h"
#include "select.h" #include "select.h"
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static int meth_set(lua_State *L); static int meth_set(lua_State *L);
static int meth_isset(lua_State *L); static int meth_isset(lua_State *L);
static int c_select(lua_State *L); static int c_select(lua_State *L);
@ -31,6 +36,12 @@ static luaL_reg func[] = {
{NULL, NULL} {NULL, NULL}
}; };
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
void select_open(lua_State *L) void select_open(lua_State *L)
{ {
/* get select auxiliar lua function from lua code and register /* get select auxiliar lua function from lua code and register
@ -45,6 +56,9 @@ void select_open(lua_State *L)
aux_newclass(L, "select{fd_set}", set); aux_newclass(L, "select{fd_set}", set);
} }
/*=========================================================================*\
* Global Lua functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Waits for a set of sockets until a condition is met or timeout. * Waits for a set of sockets until a condition is met or timeout.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@ -63,10 +77,10 @@ static int global_select(lua_State *L)
lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1); lua_insert(L, 1);
/* pass fd_set objects */ /* pass fd_set objects */
read_fd_set = lua_newuserdata(L, sizeof(fd_set)); read_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set));
FD_ZERO(read_fd_set); FD_ZERO(read_fd_set);
aux_setclass(L, "select{fd_set}", -1); aux_setclass(L, "select{fd_set}", -1);
write_fd_set = lua_newuserdata(L, sizeof(fd_set)); write_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set));
FD_ZERO(write_fd_set); FD_ZERO(write_fd_set);
aux_setclass(L, "select{fd_set}", -1); aux_setclass(L, "select{fd_set}", -1);
/* pass select auxiliar C function */ /* pass select auxiliar C function */
@ -76,20 +90,9 @@ static int global_select(lua_State *L)
return 3; return 3;
} }
static int c_select(lua_State *L) /*=========================================================================*\
{ * Lua methods
int max_fd = (int) lua_tonumber(L, 1); \*=========================================================================*/
fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2);
fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3);
int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000);
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL,
timeout < 0 ? NULL : &tv));
return 1;
}
static int meth_set(lua_State *L) static int meth_set(lua_State *L)
{ {
fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1);
@ -107,6 +110,23 @@ static int meth_isset(lua_State *L)
return 1; return 1;
} }
/*=========================================================================*\
* Internal functions
\*=========================================================================*/
static int c_select(lua_State *L)
{
int max_fd = (int) lua_tonumber(L, 1);
fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2);
fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3);
int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000);
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL,
timeout < 0 ? NULL : &tv));
return 1;
}
static void check_obj_tab(lua_State *L, int tabidx) static void check_obj_tab(lua_State *L, int tabidx)
{ {
if (tabidx < 0) tabidx = lua_gettop(L) + tabidx + 1; if (tabidx < 0) tabidx = lua_gettop(L) + tabidx + 1;

View File

@ -1,9 +1,19 @@
/*=========================================================================*\
* Select implementation
* RCS ID: $Id$
\*=========================================================================*/
#ifndef SELECT_H #ifndef SELECT_H
#define SELECT_H #define SELECT_H
/*=========================================================================*\
* Select implementation
* LuaSocket toolkit
*
* To make the code as simple as possible, the select function is
* implemented int Lua, with a few helper functions written in C.
*
* Each object that can be passed to the select function has to be in the
* group select{able} and export two methods: fd() and dirty(). Fd returns
* the descriptor to be passed to the select function. Dirty() should return
* true if there is data ready for reading (required for buffered input).
*
* RCS ID: $Id$
\*=========================================================================*/
void select_open(lua_State *L); void select_open(lua_State *L);

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- SMTP support for the Lua language. -- SMTP support for the Lua language.
-- LuaSocket 1.5 toolkit -- LuaSocket toolkit
-- Author: Diego Nehab -- Author: Diego Nehab
-- Conforming to: RFC 821, LTN7 -- Conforming to: RFC 821, LTN7
-- RCS ID: $Id$ -- RCS ID: $Id$

View File

@ -1,11 +1,16 @@
#ifndef SOCK_H
#define SOCK_H
/*=========================================================================*\ /*=========================================================================*\
* Socket compatibilization module * Socket compatibilization module
* LuaSocket toolkit
*
* BSD Sockets and WinSock are similar, but there are a few irritating
* differences. Also, not all *nix platforms behave the same. This module
* (and the associated usocket.h and wsocket.h) factor these differences and
* creates a interface compatible with the io.h module.
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef SOCK_H
#define SOCK_H
#include "io.h" #include "io.h"
/*=========================================================================*\ /*=========================================================================*\
@ -32,7 +37,6 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len); const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len);
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len); const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
void sock_listen(p_sock ps, int backlog); void sock_listen(p_sock ps, int backlog);
int sock_send(p_sock ps, const char *data, size_t count, int sock_send(p_sock ps, const char *data, size_t count,
size_t *sent, int timeout); size_t *sent, int timeout);
int sock_recv(p_sock ps, char *data, size_t count, int sock_recv(p_sock ps, char *data, size_t count,
@ -41,11 +45,8 @@ int sock_sendto(p_sock ps, const char *data, size_t count,
size_t *sent, SA *addr, socklen_t addr_len, int timeout); size_t *sent, SA *addr, socklen_t addr_len, int timeout);
int sock_recvfrom(p_sock ps, char *data, size_t count, int sock_recvfrom(p_sock ps, char *data, size_t count,
size_t *got, SA *addr, socklen_t *addr_len, int timeout); size_t *got, SA *addr, socklen_t *addr_len, int timeout);
void sock_setnonblocking(p_sock ps); void sock_setnonblocking(p_sock ps);
void sock_setblocking(p_sock ps); void sock_setblocking(p_sock ps);
void sock_setreuseaddr(p_sock ps);
const char *sock_hoststrerror(void); const char *sock_hoststrerror(void);
const char *sock_createstrerror(void); const char *sock_createstrerror(void);
const char *sock_bindstrerror(void); const char *sock_bindstrerror(void);

View File

@ -1,5 +1,6 @@
/*=========================================================================*\ /*=========================================================================*\
* TCP object * TCP object
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
@ -13,7 +14,6 @@
#include "auxiliar.h" #include "auxiliar.h"
#include "socket.h" #include "socket.h"
#include "inet.h" #include "inet.h"
#include "error.h"
#include "tcp.h" #include "tcp.h"
/*=========================================================================*\ /*=========================================================================*\
@ -28,9 +28,13 @@ static int meth_getpeername(lua_State *L);
static int meth_receive(lua_State *L); static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L); static int meth_accept(lua_State *L);
static int meth_close(lua_State *L); static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_timeout(lua_State *L); static int meth_timeout(lua_State *L);
static int meth_fd(lua_State *L); static int meth_fd(lua_State *L);
static int meth_dirty(lua_State *L); static int meth_dirty(lua_State *L);
static int opt_nodelay(lua_State *L);
static int opt_keepalive(lua_State *L);
static int opt_linger(lua_State *L);
/* tcp object methods */ /* tcp object methods */
static luaL_reg tcp[] = { static luaL_reg tcp[] = {
@ -45,11 +49,21 @@ static luaL_reg tcp[] = {
{"getsockname", meth_getsockname}, {"getsockname", meth_getsockname},
{"timeout", meth_timeout}, {"timeout", meth_timeout},
{"close", meth_close}, {"close", meth_close},
{"setoption", meth_setoption},
{"__gc", meth_close},
{"fd", meth_fd}, {"fd", meth_fd},
{"dirty", meth_dirty}, {"dirty", meth_dirty},
{NULL, NULL} {NULL, NULL}
}; };
/* socket option handlers */
static luaL_reg opt[] = {
{"keepalive", opt_keepalive},
{"nodelay", opt_nodelay},
{"linger", opt_linger},
{NULL, NULL}
};
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_reg func[] = {
{"tcp", global_create}, {"tcp", global_create},
@ -71,6 +85,7 @@ void tcp_open(lua_State *L)
aux_add2group(L, "tcp{server}", "tcp{any}"); aux_add2group(L, "tcp{server}", "tcp{any}");
aux_add2group(L, "tcp{client}", "tcp{client, server}"); aux_add2group(L, "tcp{client}", "tcp{client, server}");
aux_add2group(L, "tcp{server}", "tcp{client, server}"); aux_add2group(L, "tcp{server}", "tcp{client, server}");
/* both server and client objects are selectable */
aux_add2group(L, "tcp{client}", "select{able}"); aux_add2group(L, "tcp{client}", "select{able}");
aux_add2group(L, "tcp{server}", "select{able}"); aux_add2group(L, "tcp{server}", "select{able}");
/* define library functions */ /* define library functions */
@ -96,19 +111,81 @@ static int meth_receive(lua_State *L)
return buf_meth_receive(L, &tcp->buf); return buf_meth_receive(L, &tcp->buf);
} }
/*-------------------------------------------------------------------------*\
* Option handlers
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L)
{
return aux_meth_setoption(L, opt);
}
static int opt_boolean(lua_State *L, int level, int name)
{
p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1);
int val = aux_checkboolean(L, 2);
if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) {
lua_pushnil(L);
lua_pushstring(L, "setsockopt failed");
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/* disables the Nagle algorithm */
static int opt_nodelay(lua_State *L)
{
struct protoent *pe = getprotobyname("TCP");
if (!pe) {
lua_pushnil(L);
lua_pushstring(L, "getprotobyname");
return 2;
}
return opt_boolean(L, pe->p_proto, TCP_NODELAY);
}
static int opt_keepalive(lua_State *L)
{
return opt_boolean(L, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_linger(lua_State *L)
{
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1);
struct linger li;
if (!lua_istable(L, 2))
luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "onoff");
lua_gettable(L, 2);
if (!lua_isnumber(L, -1)) luaL_argerror(L, 2, "invalid onoff field");
li.l_onoff = (int) lua_tonumber(L, -1);
lua_pushstring(L, "linger");
lua_gettable(L, 2);
if (!lua_isnumber(L, -1)) luaL_argerror(L, 2, "invalid linger field");
li.l_linger = (int) lua_tonumber(L, -1);
if (setsockopt(tcp->sock, SOL_SOCKET, SO_LINGER,
(char *) &li, sizeof(li) < 0)) {
lua_pushnil(L);
lua_pushstring(L, "setsockopt failed");
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Select support methods * Select support methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_fd(lua_State *L) static int meth_fd(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client, server}", 1); p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1);
lua_pushnumber(L, tcp->sock); lua_pushnumber(L, tcp->sock);
return 1; return 1;
} }
static int meth_dirty(lua_State *L) static int meth_dirty(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client, server}", 1); p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1);
lua_pushboolean(L, !buf_isempty(&tcp->buf)); lua_pushboolean(L, !buf_isempty(&tcp->buf));
return 1; return 1;
} }
@ -207,7 +284,7 @@ static int meth_accept(lua_State *L)
if (client->sock == SOCK_INVALID) { if (client->sock == SOCK_INVALID) {
if (tm_get(tm) == 0) { if (tm_get(tm) == 0) {
lua_pushnil(L); lua_pushnil(L);
error_push(L, IO_TIMEOUT); io_pusherror(L, IO_TIMEOUT);
return 2; return 2;
} }
} else break; } else break;

View File

@ -1,6 +1,21 @@
#ifndef TCP_H #ifndef TCP_H
#define TCP_H #define TCP_H
/*=========================================================================*\
* TCP object
* LuaSocket toolkit
*
* The tcp.h module is basicly a glue that puts together modules buffer.h,
* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET,
* SOCK_STREAM) support.
*
* Three classes are defined: master, client and server. The master class is
* a newly created tcp object, that has not been bound or connected. Server
* objects are tcp objects bound to some local address. Client objects are
* tcp objects either connected to some address or returned by the accept
* method of a server object.
*
* RCS ID: $Id$
\*=========================================================================*/
#include <lua.h> #include <lua.h>
#include "buffer.h" #include "buffer.h"
@ -17,4 +32,4 @@ typedef t_tcp *p_tcp;
void tcp_open(lua_State *L); void tcp_open(lua_State *L);
#endif #endif /* TCP_H */

View File

@ -1,8 +1,6 @@
/*=========================================================================*\ /*=========================================================================*\
* Timeout management functions * Timeout management functions
* Global Lua functions: * LuaSocket toolkit
* _sleep
* _time
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/

View File

@ -1,11 +1,11 @@
#ifndef TM_H
#define TM_H
/*=========================================================================*\ /*=========================================================================*\
* Timeout management functions * Timeout management functions
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef TM_H
#define TM_H
#include <lua.h> #include <lua.h>
/* timeout control structure */ /* timeout control structure */
@ -28,4 +28,4 @@ int tm_get(p_tm tm);
int tm_gettime(void); int tm_gettime(void);
int tm_meth_timeout(lua_State *L, p_tm tm); int tm_meth_timeout(lua_State *L, p_tm tm);
#endif #endif /* TM_H */

View File

@ -1,5 +1,6 @@
/*=========================================================================*\ /*=========================================================================*\
* UDP object * UDP object
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
@ -13,7 +14,6 @@
#include "auxiliar.h" #include "auxiliar.h"
#include "socket.h" #include "socket.h"
#include "inet.h" #include "inet.h"
#include "error.h"
#include "udp.h" #include "udp.h"
/*=========================================================================*\ /*=========================================================================*\
@ -29,9 +29,12 @@ static int meth_getpeername(lua_State *L);
static int meth_setsockname(lua_State *L); static int meth_setsockname(lua_State *L);
static int meth_setpeername(lua_State *L); static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L); static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_timeout(lua_State *L); static int meth_timeout(lua_State *L);
static int meth_fd(lua_State *L); static int meth_fd(lua_State *L);
static int meth_dirty(lua_State *L); static int meth_dirty(lua_State *L);
static int opt_dontroute(lua_State *L);
static int opt_broadcast(lua_State *L);
/* udp object methods */ /* udp object methods */
static luaL_reg udp[] = { static luaL_reg udp[] = {
@ -45,11 +48,20 @@ static luaL_reg udp[] = {
{"receivefrom", meth_receivefrom}, {"receivefrom", meth_receivefrom},
{"timeout", meth_timeout}, {"timeout", meth_timeout},
{"close", meth_close}, {"close", meth_close},
{"setoption", meth_setoption},
{"__gc", meth_close},
{"fd", meth_fd}, {"fd", meth_fd},
{"dirty", meth_dirty}, {"dirty", meth_dirty},
{NULL, NULL} {NULL, NULL}
}; };
/* socket options */
static luaL_reg opt[] = {
{"dontroute", opt_dontroute},
{"broadcast", opt_broadcast},
{NULL, NULL}
};
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_reg func[] = {
{"udp", global_create}, {"udp", global_create},
@ -91,7 +103,9 @@ static int meth_send(lua_State *L)
err = sock_send(&udp->sock, data, count, &sent, tm_get(tm)); err = sock_send(&udp->sock, data, count, &sent, tm_get(tm));
if (err == IO_DONE) lua_pushnumber(L, sent); if (err == IO_DONE) lua_pushnumber(L, sent);
else lua_pushnil(L); else lua_pushnil(L);
error_push(L, err); /* a 'closed' error on an unconnected means the target address was not
* accepted by the transport layer */
io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err);
return 2; return 2;
} }
@ -118,7 +132,9 @@ static int meth_sendto(lua_State *L)
(SA *) &addr, sizeof(addr), tm_get(tm)); (SA *) &addr, sizeof(addr), tm_get(tm));
if (err == IO_DONE) lua_pushnumber(L, sent); if (err == IO_DONE) lua_pushnumber(L, sent);
else lua_pushnil(L); else lua_pushnil(L);
error_push(L, err == IO_CLOSED ? IO_REFUSED : err); /* a 'closed' error on an unconnected means the target address was not
* accepted by the transport layer */
io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err);
return 2; return 2;
} }
@ -137,7 +153,7 @@ static int meth_receive(lua_State *L)
err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm)); err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm));
if (err == IO_DONE) lua_pushlstring(L, buffer, got); if (err == IO_DONE) lua_pushlstring(L, buffer, got);
else lua_pushnil(L); else lua_pushnil(L);
error_push(L, err); io_pusherror(L, err);
return 2; return 2;
} }
@ -164,7 +180,7 @@ static int meth_receivefrom(lua_State *L)
return 3; return 3;
} else { } else {
lua_pushnil(L); lua_pushnil(L);
error_push(L, err); io_pusherror(L, err);
return 2; return 2;
} }
} }
@ -174,14 +190,14 @@ static int meth_receivefrom(lua_State *L)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_fd(lua_State *L) static int meth_fd(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{any}", 1); p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
lua_pushnumber(L, udp->sock); lua_pushnumber(L, udp->sock);
return 1; return 1;
} }
static int meth_dirty(lua_State *L) static int meth_dirty(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{any}", 1); p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
(void) udp; (void) udp;
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
return 1; return 1;
@ -202,6 +218,37 @@ static int meth_getsockname(lua_State *L)
return inet_meth_getsockname(L, &udp->sock); return inet_meth_getsockname(L, &udp->sock);
} }
/*-------------------------------------------------------------------------*\
* Option handlers
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L)
{
return aux_meth_setoption(L, opt);
}
static int opt_boolean(lua_State *L, int level, int name)
{
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
int val = aux_checkboolean(L, 2);
if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) {
lua_pushnil(L);
lua_pushstring(L, "setsockopt failed");
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
static int opt_dontroute(lua_State *L)
{
return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE);
}
static int opt_broadcast(lua_State *L)
{
return opt_boolean(L, SOL_SOCKET, SO_BROADCAST);
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call tm methods * Just call tm methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/

View File

@ -1,6 +1,19 @@
#ifndef UDP_H #ifndef UDP_H
#define UDP_H #define UDP_H
/*=========================================================================*\
* UDP object
* LuaSocket toolkit
*
* The udp.h module provides LuaSocket with support for UDP protocol
* (AF_INET, SOCK_DGRAM).
*
* Two classes are defined: connected and unconnected. UDP objects are
* originally unconnected. They can be "connected" to a given address
* with a call to the setpeername function. The same function can be used to
* break the connection.
*
* RCS ID: $Id$
\*=========================================================================*/
#include <lua.h> #include <lua.h>
#include "timeout.h" #include "timeout.h"
@ -16,4 +29,4 @@ typedef t_udp *p_udp;
void udp_open(lua_State *L); void udp_open(lua_State *L);
#endif #endif /* UDP_H */

View File

@ -1,6 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- URI parsing, composition and relative URL resolution -- URI parsing, composition and relative URL resolution
-- LuaSocket 1.5 toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- Conforming to: RFC 2396, LTN7 -- Conforming to: RFC 2396, LTN7
-- RCS ID: $Id$ -- RCS ID: $Id$

View File

@ -1,49 +1,78 @@
/*=========================================================================*\
* Socket compatibilization module for Unix
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h> #include <string.h>
#include "socket.h" #include "socket.h"
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int sock_open(void) int sock_open(void)
{ {
/* instals a handler to ignore sigpipe. */ /* instals a handler to ignore sigpipe or it will crash us */
struct sigaction new; struct sigaction ignore;
memset(&new, 0, sizeof(new)); memset(&ignore, 0, sizeof(ignore));
new.sa_handler = SIG_IGN; ignore.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &new, NULL); sigaction(SIGPIPE, &ignore, NULL);
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void sock_destroy(p_sock ps) void sock_destroy(p_sock ps)
{ {
close(*ps); close(*ps);
*ps = SOCK_INVALID;
} }
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
const char *sock_create(p_sock ps, int domain, int type, int protocol) const char *sock_create(p_sock ps, int domain, int type, int protocol)
{ {
int val = 1;
t_sock sock = socket(domain, type, protocol); t_sock sock = socket(domain, type, protocol);
if (sock == SOCK_INVALID) return sock_createstrerror(); if (sock == SOCK_INVALID) return sock_createstrerror();
*ps = sock; *ps = sock;
sock_setnonblocking(ps); sock_setnonblocking(ps);
sock_setreuseaddr(ps); setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
return NULL; return NULL;
} }
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len) const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len)
{ {
if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror(); if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror();
else return NULL; else return NULL;
} }
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
{ {
if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror();
else return NULL; else return NULL;
} }
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void sock_listen(p_sock ps, int backlog) void sock_listen(p_sock ps, int backlog)
{ {
listen(*ps, backlog); listen(*ps, backlog);
} }
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
int timeout) int timeout)
{ {
@ -65,6 +94,9 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
else return IO_DONE; else return IO_DONE;
} }
/*-------------------------------------------------------------------------*\
* Send with timeout
\*-------------------------------------------------------------------------*/
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
int timeout) int timeout)
{ {
@ -99,6 +131,9 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
} }
} }
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t addr_len, int timeout) SA *addr, socklen_t addr_len, int timeout)
{ {
@ -133,6 +168,9 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
} }
} }
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
{ {
t_sock sock = *ps; t_sock sock = *ps;
@ -160,6 +198,9 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
} }
} }
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *addr_len, int timeout) SA *addr, socklen_t *addr_len, int timeout)
{ {
@ -188,6 +229,29 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
} }
} }
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void sock_setblocking(p_sock ps)
{
int flags = fcntl(*ps, F_GETFL, 0);
flags &= (~(O_NONBLOCK));
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void sock_setnonblocking(p_sock ps)
{
int flags = fcntl(*ps, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
const char *sock_hoststrerror(void) const char *sock_hoststrerror(void)
{ {
switch (h_errno) { switch (h_errno) {
@ -238,23 +302,3 @@ const char *sock_connectstrerror(void)
default: return "unknown error"; default: return "unknown error";
} }
} }
void sock_setreuseaddr(p_sock ps)
{
int val = 1;
setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
}
void sock_setblocking(p_sock ps)
{
int flags = fcntl(*ps, F_GETFL, 0);
flags &= (~(O_NONBLOCK));
fcntl(*ps, F_SETFL, flags);
}
void sock_setnonblocking(p_sock ps)
{
int flags = fcntl(*ps, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(*ps, F_SETFL, flags);
}

View File

@ -1,10 +1,11 @@
#ifndef USOCKET_H
#define USOCKET_H
/*=========================================================================*\ /*=========================================================================*\
* Socket compatibilization module for Unix * Socket compatibilization module for Unix
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef USOCKET_H
#define USOCKET_H
/*=========================================================================*\ /*=========================================================================*\
* BSD include files * BSD include files
@ -30,9 +31,11 @@
/* IP stuff*/ /* IP stuff*/
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
/* TCP options (nagle algorithm disable) */
#include <netinet/tcp.h>
#ifdef __APPLE__ #ifdef __APPLE__
/* for some reason socklen_t is not defined in mac os x */ /* for some reason socklen_t is not defined in Mac Os X */
typedef int socklen_t; typedef int socklen_t;
#endif #endif

View File

@ -1,14 +1,21 @@
/*=========================================================================*\
* Socket compatibilization module for Win32
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h> #include <string.h>
#include "socket.h" #include "socket.h"
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int sock_open(void) int sock_open(void)
{ {
WORD wVersionRequested;
WSADATA wsaData; WSADATA wsaData;
int err; WORD wVersionRequested = MAKEWORD(2, 0);
wVersionRequested = MAKEWORD(2, 0); int err = WSAStartup(wVersionRequested, &wsaData );
err = WSAStartup(wVersionRequested, &wsaData );
if (err != 0) return 0; if (err != 0) return 0;
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) {
WSACleanup(); WSACleanup();
@ -17,38 +24,58 @@ int sock_open(void)
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void sock_destroy(p_sock ps) void sock_destroy(p_sock ps)
{ {
closesocket(*ps); closesocket(*ps);
*ps = SOCK_INVALID;
} }
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
const char *sock_create(p_sock ps, int domain, int type, int protocol) const char *sock_create(p_sock ps, int domain, int type, int protocol)
{ {
int val = 1;
t_sock sock = socket(domain, type, protocol); t_sock sock = socket(domain, type, protocol);
if (sock == SOCK_INVALID) return sock_createstrerror(); if (sock == SOCK_INVALID) return sock_createstrerror();
*ps = sock; *ps = sock;
sock_setnonblocking(ps); sock_setnonblocking(ps);
sock_setreuseaddr(ps); setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
return NULL; return NULL;
} }
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len) const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len)
{ {
if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror(); if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror();
else return NULL; else return NULL;
} }
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
{ {
if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror();
else return NULL; else return NULL;
} }
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void sock_listen(p_sock ps, int backlog) void sock_listen(p_sock ps, int backlog)
{ {
listen(*ps, backlog); listen(*ps, backlog);
} }
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
int timeout) int timeout)
{ {
@ -70,6 +97,9 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
else return IO_DONE; else return IO_DONE;
} }
/*-------------------------------------------------------------------------*\
* Send with timeout
\*-------------------------------------------------------------------------*/
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
int timeout) int timeout)
{ {
@ -104,6 +134,9 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
} }
} }
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t addr_len, int timeout) SA *addr, socklen_t addr_len, int timeout)
{ {
@ -138,6 +171,9 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
} }
} }
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
{ {
t_sock sock = *ps; t_sock sock = *ps;
@ -165,6 +201,9 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
} }
} }
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *addr_len, int timeout) SA *addr, socklen_t *addr_len, int timeout)
{ {
@ -193,6 +232,27 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
} }
} }
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void sock_setblocking(p_sock ps)
{
u_long argp = 0;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void sock_setnonblocking(p_sock ps)
{
u_long argp = 1;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
const char *sock_hoststrerror(void) const char *sock_hoststrerror(void)
{ {
switch (WSAGetLastError()) { switch (WSAGetLastError()) {
@ -241,21 +301,3 @@ const char *sock_connectstrerror(void)
default: return "unknown error"; default: return "unknown error";
} }
} }
void sock_setreuseaddr(p_sock ps)
{
int val = 1;
setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
}
void sock_setblocking(p_sock ps)
{
u_long argp = 0;
ioctlsocket(*ps, FIONBIO, &argp);
}
void sock_setnonblocking(p_sock ps)
{
u_long argp = 1;
ioctlsocket(*ps, FIONBIO, &argp);
}

View File

@ -1,16 +1,16 @@
#ifndef WSOCKET_H
#define WSOCKET_H
/*=========================================================================*\ /*=========================================================================*\
* Socket compatibilization module for Win32 * Socket compatibilization module for Win32
* LuaSocket toolkit
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef WSOCKET_H
#define WSOCKET_H
/*=========================================================================*\ /*=========================================================================*\
* WinSock2 include files * WinSock include files
\*=========================================================================*/ \*=========================================================================*/
#include <winsock2.h> #include <winsock.h>
#include <winbase.h>
typedef int socklen_t; typedef int socklen_t;
typedef int ssize_t; typedef int ssize_t;

View File

@ -17,12 +17,14 @@ function warn(...)
io.write("WARNING: ", s, "\n") io.write("WARNING: ", s, "\n")
end end
pad = string.rep(" ", 8192)
function remote(...) function remote(...)
local s = string.format(unpack(arg)) local s = string.format(unpack(arg))
s = string.gsub(s, "\n", ";") s = string.gsub(s, "\n", ";")
s = string.gsub(s, "%s+", " ") s = string.gsub(s, "%s+", " ")
s = string.gsub(s, "^%s*", "") s = string.gsub(s, "^%s*", "")
control:send(s, "\n") control:send(pad, s, "\n")
control:receive() control:receive()
end end
@ -82,16 +84,19 @@ function reconnect()
remote [[ remote [[
if data then data:close() data = nil end if data then data:close() data = nil end
data = server:accept() data = server:accept()
data:setoption("nodelay", true)
]] ]]
data, err = socket.connect(host, port) data, err = socket.connect(host, port)
if not data then fail(err) if not data then fail(err)
else pass("connected!") end else pass("connected!") end
data:setoption("nodelay", true)
end end
pass("attempting control connection...") pass("attempting control connection...")
control, err = socket.connect(host, port) control, err = socket.connect(host, port)
if err then fail(err) if err then fail(err)
else pass("connected!") end else pass("connected!") end
control:setoption("nodelay", true)
------------------------------------------------------------------------ ------------------------------------------------------------------------
test("method registration") test("method registration")
@ -157,16 +162,21 @@ remote "data:send(str); data:close()"
end end
test_mixed(1) --test_mixed(1)
test_mixed(17) --test_mixed(17)
test_mixed(200) --test_mixed(200)
test_mixed(4091) --test_mixed(4091)
test_mixed(80199) --test_mixed(80199)
test_mixed(4091) --test_mixed(4091)
test_mixed(200) --test_mixed(200)
test_mixed(17) --test_mixed(17)
test_mixed(1) --test_mixed(1)
test_mixed(4091)
test_mixed(4091)
test_mixed(4091)
test_mixed(4091)
test_mixed(4091)
------------------------------------------------------------------------ ------------------------------------------------------------------------
test("character line") test("character line")
reconnect() reconnect()

View File

@ -3,9 +3,11 @@ port = port or "8080"
server, error = socket.bind(host, port) server, error = socket.bind(host, port)
if not server then print("server: " .. tostring(error)) os.exit() end if not server then print("server: " .. tostring(error)) os.exit() end
ack = "\n"
while 1 do while 1 do
print("server: waiting for client connection..."); print("server: waiting for client connection...");
control = server:accept() control = server:accept()
control:setoption("nodelay", true)
while 1 do while 1 do
command, error = control:receive() command, error = control:receive()
if error then if error then
@ -13,13 +15,12 @@ while 1 do
print("server: closing connection...") print("server: closing connection...")
break break
end end
sent, error = control:send("\n") sent, error = control:send(ack)
if error then if error then
control:close() control:close()
print("server: closing connection...") print("server: closing connection...")
break break
end end
print(command);
(loadstring(command))() (loadstring(command))()
end end
end end