Tested in windows. Still needs more testing, but progress has been made.

This commit is contained in:
Diego Nehab 2004-01-17 00:17:46 +00:00
parent 89f3ecf782
commit 076451c753
11 changed files with 620 additions and 296 deletions

11
TODO
View File

@ -1,8 +1,13 @@
change send/recv to avoid using select
check for interrupt compliance
add connect with timeout
add gethostname and use it in HTTP, SMTP etc, and add manual entry.
add local connect, and manual entry
add shutdown, and manual entry
add shutdown manual entry
only allocate in case of success
only call select if io fails...
@ -65,6 +70,8 @@ Ajeitar o protocolo da luaopen_socket()... sei l
- testar os options!
- adicionar exemplos de expansão: pipe, local, named pipe
* add shutdown
* change send/recv to avoid using select
* O location do "redirect" pode ser relativo ao servidor atual (não pode,
mas os servidores fazem merda...)
* Ajeitar para Lua 5.0

23
luasocket.sln Normal file
View File

@ -0,0 +1,23 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasocket", "luasocket.vcproj", "{4FAAB633-F0E7-4D12-B680-D150A0DD7268}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Debug.ActiveCfg = Debug|Win32
{4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Debug.Build.0 = Debug|Win32
{4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Release.ActiveCfg = Release|Win32
{4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionItems) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

216
luasocket.vcproj Normal file
View File

@ -0,0 +1,216 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="luasocket"
ProjectGUID="{4FAAB633-F0E7-4D12-B680-D150A0DD7268}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="."
IntermediateDirectory="."
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="net/include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE, LUASOCKET_DEBUG"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="lua.lib lualib.lib ws2_32.lib"
OutputFile="$(OutDir)/luasocket.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="net/lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/luasocket.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="."
IntermediateDirectory="."
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="net/include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE, LUASOCKET_DEBUG"
RuntimeLibrary="4"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="lua.lib lualib.lib ws2_32.lib"
OutputFile="$(OutDir)/luasocket.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="net/lib"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\auxiliar.c">
</File>
<File
RelativePath=".\buffer.c">
</File>
<File
RelativePath=".\code.c">
</File>
<File
RelativePath=".\error.c">
</File>
<File
RelativePath=".\inet.c">
</File>
<File
RelativePath=".\io.c">
</File>
<File
RelativePath=".\lua.c">
</File>
<File
RelativePath=".\luasocket.c">
</File>
<File
RelativePath=".\select.c">
</File>
<File
RelativePath=".\tcp.c">
</File>
<File
RelativePath=".\timeout.c">
</File>
<File
RelativePath=".\udp.c">
</File>
<File
RelativePath=".\wsocket.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\auxiliar.h">
</File>
<File
RelativePath=".\buffer.h">
</File>
<File
RelativePath=".\code.h">
</File>
<File
RelativePath=".\error.h">
</File>
<File
RelativePath=".\inet.h">
</File>
<File
RelativePath=".\io.h">
</File>
<File
RelativePath=".\luasocket.h">
</File>
<File
RelativePath=".\select.h">
</File>
<File
RelativePath=".\socket.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
<File
RelativePath=".\tcp.h">
</File>
<File
RelativePath=".\timeout.h">
</File>
<File
RelativePath=".\udp.h">
</File>
<File
RelativePath=".\wsocket.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -19,6 +19,10 @@
#include <lua.h>
#include "socket.h"
#ifdef WIN32
#define INET_ATON
#endif
void inet_open(lua_State *L);
const char *inet_tryconnect(p_sock ps, const char *address,
unsigned short port);

View File

@ -18,7 +18,9 @@
/*-------------------------------------------------------------------------*\
* Library's namespace
\*-------------------------------------------------------------------------*/
#ifndef LUASOCKET_LIBNAME
#define LUASOCKET_LIBNAME "socket"
#endif
/*-------------------------------------------------------------------------*\
* This macro prefixes all exported API functions

View File

@ -36,6 +36,7 @@ static int meth_dirty(lua_State *L);
static int opt_tcp_nodelay(lua_State *L);
static int opt_keepalive(lua_State *L);
static int opt_linger(lua_State *L);
static int opt_reuseaddr(lua_State *L);
/* tcp object methods */
static luaL_reg tcp[] = {
@ -61,6 +62,7 @@ static luaL_reg tcp[] = {
/* socket option handlers */
static luaL_reg opt[] = {
{"keepalive", opt_keepalive},
{"reuseaddr", opt_reuseaddr},
{"tcp-nodelay", opt_tcp_nodelay},
{"linger", opt_linger},
{NULL, NULL}
@ -123,7 +125,7 @@ static int meth_setoption(lua_State *L)
static int opt_boolean(lua_State *L, int level, int name)
{
p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client,server}", 1);
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);
@ -134,16 +136,16 @@ static int opt_boolean(lua_State *L, int level, int name)
return 1;
}
/* enables reuse of local address */
static int opt_reuseaddr(lua_State *L)
{
return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR);
}
/* disables the Naggle algorithm */
static int opt_tcp_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);
return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY);
}
static int opt_keepalive(lua_State *L)

View File

@ -16,6 +16,7 @@
#ifdef WIN32
#include <windows.h>
#else
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>

View File

@ -35,6 +35,11 @@ static int meth_fd(lua_State *L);
static int meth_dirty(lua_State *L);
static int opt_dontroute(lua_State *L);
static int opt_broadcast(lua_State *L);
static int opt_reuseaddr(lua_State *L);
static int opt_ip_multicast_ttl(lua_State *L);
static int opt_ip_multicast_loop(lua_State *L);
static int opt_ip_add_membership(lua_State *L);
static int opt_ip_drop_membersip(lua_State *L);
/* udp object methods */
static luaL_reg udp[] = {
@ -57,8 +62,13 @@ static luaL_reg udp[] = {
/* socket options */
static luaL_reg opt[] = {
{"dontroute", opt_dontroute},
{"broadcast", opt_broadcast},
{"dontroute", opt_dontroute},
{"broadcast", opt_broadcast},
{"reuseaddr", opt_reuseaddr},
{"ip-multicast-ttl", opt_ip_multicast_ttl},
{"ip-multicast-loop", opt_ip_multicast_loop},
{"ip-add-membership", opt_ip_add_membership},
{"ip-drop-membership", opt_ip_drop_membersip},
{NULL, NULL}
};
@ -244,11 +254,72 @@ static int opt_dontroute(lua_State *L)
return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE);
}
static int opt_reuseaddr(lua_State *L)
{
return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR);
}
static int opt_broadcast(lua_State *L)
{
return opt_boolean(L, SOL_SOCKET, SO_BROADCAST);
}
static int opt_ip_multicast_loop(lua_State *L)
{
return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP);
}
static int opt_ip_multicast_ttl(lua_State *L)
{
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
int val = (int) luaL_checknumber(L, 2);
if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL,
(char *) &val, sizeof(val)) < 0) {
lua_pushnil(L);
lua_pushstring(L, "setsockopt failed");
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
static int opt_membership(lua_State *L, int level, int name)
{
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
struct ip_mreq val;
if (!lua_istable(L, 2))
luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 2);
if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field");
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface");
lua_gettable(L, 2);
if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field");
val.imr_interface.s_addr = htonl(INADDR_ANY);
if (strcmp(lua_tostring(L, -1), "*") &&
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
luaL_argerror(L, 3, "invalid 'interface' ip address");
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_ip_add_membership(lua_State *L)
{
return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP);
}
static int opt_ip_drop_membersip(lua_State *L)
{
return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP);
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/

View File

@ -145,7 +145,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
else return IO_TIMEOUT;
/* here we know the connection has been closed */
} else return IO_CLOSED;
/* here we sent successfully sent something */
/* here we successfully sent something */
} else {
*sent = put;
return IO_DONE;
@ -159,34 +159,36 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t addr_len, int timeout)
{
t_sock sock = *ps;
struct timeval tv;
fd_set fds;
ssize_t put = 0;
int err;
ssize_t put;
int ret;
/* avoid making system calls on closed sockets */
if (sock == SOCK_INVALID) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) {
put = sendto(sock, data, count, 0, addr, addr_len);
if (put <= 0) {
err = IO_CLOSED;
#ifdef __CYGWIN__
/* this is for CYGWIN, which is like Unix but has Win32 bugs */
if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE;
#endif
*sent = 0;
} else {
*sent = put;
err = IO_DONE;
}
return err;
} else {
/* make sure we repeat in case the call was interrupted */
do put = sendto(sock, data, count, 0, addr, addr_len);
while (put <= 0 && errno == EINTR);
/* deal with failure */
if (put <= 0) {
/* in any case, nothing has been sent */
*sent = 0;
return IO_TIMEOUT;
/* run select to avoid busy wait */
if (errno != EPIPE) {
struct timeval tv;
fd_set fds;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
/* tell the caller to call us again because there is more data */
if (ret > 0) return IO_DONE;
/* tell the caller there was no data before timeout */
else return IO_TIMEOUT;
/* here we know the connection has been closed */
} else return IO_CLOSED;
/* here we successfully sent something */
} else {
*sent = put;
return IO_DONE;
}
}
@ -232,28 +234,26 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *addr_len, int timeout)
{
t_sock sock = *ps;
struct timeval tv;
fd_set fds;
int ret;
ssize_t taken;
if (sock == SOCK_INVALID) return IO_CLOSED;
ssize_t taken = 0;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) {
taken = recvfrom(sock, data, count, 0, addr, addr_len);
if (taken <= 0) {
*got = 0;
return IO_CLOSED;
} else {
*got = taken;
return IO_DONE;
}
} else {
do taken = recvfrom(sock, data, count, 0, addr, addr_len);
while (taken <= 0 && errno == EINTR);
if (taken <= 0) {
struct timeval tv;
fd_set fds;
int ret;
*got = 0;
return IO_TIMEOUT;
if (taken == 0) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) return IO_DONE;
else return IO_TIMEOUT;
} else {
*got = taken;
return IO_DONE;
}
}

View File

@ -100,7 +100,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
FD_ZERO(&fds);
FD_SET(sock, &fds);
*pa = SOCK_INVALID;
if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0)
if (select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0)
return IO_TIMEOUT;
if (!addr) addr = &dummy_addr;
if (!addr_len) addr_len = &dummy_len;
@ -116,34 +116,35 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
int timeout)
{
t_sock sock = *ps;
struct timeval tv;
fd_set fds;
ssize_t put = 0;
if (sock == SOCK_INVALID) return IO_CLOSED;
int err;
ssize_t put;
int ret;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) {
put = send(sock, data, count, 0);
if (put <= 0) {
/* a bug in WinSock forces us to do a busy wait until we manage
** to write, because select returns immediately even though it
** should have blocked us until we could write... */
if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE;
else err = IO_CLOSED;
*sent = 0;
} else {
*sent = put;
err = IO_DONE;
}
return err;
} else {
/* avoid making system calls on closed sockets */
if (sock == SOCK_INVALID) return IO_CLOSED;
/* try to send something */
put = send(sock, data, (int) count, 0);
/* deal with failure */
if (put <= 0) {
/* in any case, nothing has been sent */
*sent = 0;
return IO_TIMEOUT;
/* run select to avoid busy wait */
if (WSAGetLastError() == WSAEWOULDBLOCK) {
struct timeval tv;
fd_set fds;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
/* tell the caller to call us again because there is more data */
if (ret > 0) return IO_DONE;
/* tell the caller there was no data before timeout */
else return IO_TIMEOUT;
/* here we know the connection has been closed */
} else return IO_CLOSED;
/* here we successfully sent something */
} else {
*sent = put;
return IO_DONE;
}
}
@ -154,34 +155,35 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t addr_len, int timeout)
{
t_sock sock = *ps;
struct timeval tv;
fd_set fds;
ssize_t put = 0;
int err;
ssize_t put;
int ret;
/* avoid making system calls on closed sockets */
if (sock == SOCK_INVALID) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) {
put = sendto(sock, data, count, 0, addr, addr_len);
if (put <= 0) {
/* a bug in WinSock forces us to do a busy wait until we manage
** to write, because select returns immediately even though it
** should have blocked us until we could write... */
if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE;
else err = IO_CLOSED;
*sent = 0;
} else {
*sent = put;
err = IO_DONE;
}
return err;
} else {
/* try to send something */
put = sendto(sock, data, (int) count, 0, addr, addr_len);
/* deal with failure */
if (put <= 0) {
/* in any case, nothing has been sent */
*sent = 0;
return IO_TIMEOUT;
/* run select to avoid busy wait */
if (WSAGetLastError() == WSAEWOULDBLOCK) {
struct timeval tv;
fd_set fds;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
/* tell the caller to call us again because there is more data */
if (ret > 0) return IO_DONE;
/* tell the caller there was no data before timeout */
else return IO_TIMEOUT;
/* here we know the connection has been closed */
} else return IO_CLOSED;
/* here we successfully sent something */
} else {
*sent = put;
return IO_DONE;
}
}
@ -191,28 +193,25 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
{
t_sock sock = *ps;
struct timeval tv;
fd_set fds;
int ret;
ssize_t taken = 0;
ssize_t taken;
if (sock == SOCK_INVALID) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) {
taken = recv(sock, data, count, 0);
if (taken <= 0) {
*got = 0;
return IO_CLOSED;
} else {
*got = taken;
return IO_DONE;
}
} else {
taken = recv(sock, data, (int) count, 0);
if (taken <= 0) {
struct timeval tv;
fd_set fds;
int ret;
*got = 0;
return IO_TIMEOUT;
if (taken == 0) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) return IO_DONE;
else return IO_TIMEOUT;
} else {
*got = taken;
return IO_DONE;
}
}
@ -223,28 +222,25 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *addr_len, int timeout)
{
t_sock sock = *ps;
struct timeval tv;
fd_set fds;
int ret;
ssize_t taken = 0;
ssize_t taken;
if (sock == SOCK_INVALID) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) {
taken = recvfrom(sock, data, count, 0, addr, addr_len);
if (taken <= 0) {
*got = 0;
return IO_CLOSED;
} else {
*got = taken;
return IO_DONE;
}
} else {
taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
if (taken <= 0) {
struct timeval tv;
fd_set fds;
int ret;
*got = 0;
return IO_TIMEOUT;
if (taken == 0) return IO_CLOSED;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
if (ret > 0) return IO_DONE;
else return IO_TIMEOUT;
} else {
*got = taken;
return IO_DONE;
}
}

View File

@ -99,8 +99,6 @@ else pass("connected!") end
control:setoption("tcp-nodelay", true)
------------------------------------------------------------------------
test("method registration")
function test_methods(sock, methods)
for _, v in methods do
if type(sock[v]) ~= "function" then
@ -110,38 +108,7 @@ function test_methods(sock, methods)
pass(sock.class .. " methods are ok")
end
test_methods(socket.tcp(), {
"connect",
"send",
"receive",
"bind",
"accept",
"setpeername",
"setsockname",
"getpeername",
"getsockname",
"setoption",
"settimeout",
"close",
})
test_methods(socket.udp(), {
"getpeername",
"getsockname",
"setsockname",
"setpeername",
"send",
"sendto",
"receive",
"receivefrom",
"setoption",
"settimeout",
"close",
})
------------------------------------------------------------------------
test("mixed patterns")
function test_mixed(len)
reconnect()
local inter = math.ceil(len/4)
@ -163,21 +130,7 @@ remote "data:send(str); data:close()"
else fail("patterns don't match") end
end
test_mixed(1)
test_mixed(17)
test_mixed(200)
test_mixed(4091)
test_mixed(80199)
test_mixed(4091)
test_mixed(200)
test_mixed(17)
test_mixed(1)
------------------------------------------------------------------------
test("character line")
reconnect()
function test_asciiline(len)
local str, str10, back, err
str = string.rep("x", math.mod(len, 10))
@ -194,22 +147,7 @@ remote "data:send(str, '\\n')"
else fail("lines don't match") end
end
test_asciiline(1)
test_asciiline(17)
test_asciiline(200)
test_asciiline(4091)
test_asciiline(80199)
test_asciiline(800000)
test_asciiline(80199)
test_asciiline(4091)
test_asciiline(200)
test_asciiline(17)
test_asciiline(1)
------------------------------------------------------------------------
test("binary line")
reconnect()
function test_rawline(len)
local str, str10, back, err
str = string.rep(string.char(47), math.mod(len, 10))
@ -227,22 +165,7 @@ remote "data:send(str, '\\n')"
else fail("lines don't match") end
end
test_rawline(1)
test_rawline(17)
test_rawline(200)
test_rawline(4091)
test_rawline(80199)
test_rawline(800000)
test_rawline(80199)
test_rawline(4091)
test_rawline(200)
test_rawline(17)
test_rawline(1)
------------------------------------------------------------------------
test("raw transfer")
reconnect()
function test_raw(len)
local half = math.floor(len/2)
local s1, s2, back, err
@ -261,38 +184,7 @@ remote "data:send(str)"
else fail("blocks don't match") end
end
test_raw(1)
test_raw(17)
test_raw(200)
test_raw(4091)
test_raw(80199)
test_raw(800000)
test_raw(80199)
test_raw(4091)
test_raw(200)
test_raw(17)
test_raw(1)
------------------------------------------------------------------------
test("non-blocking transfer")
reconnect()
-- the value is not important, we only want
-- to test non-blockin I/O anyways
data:settimeout(200)
test_raw(1)
test_raw(17)
test_raw(200)
test_raw(4091)
test_raw(80199)
test_raw(800000)
test_raw(80199)
test_raw(4091)
test_raw(200)
test_raw(17)
test_raw(1)
------------------------------------------------------------------------
test("total timeout on receive")
function test_totaltimeoutreceive(len, tm, sl)
local str, err, total
reconnect()
@ -311,13 +203,8 @@ function test_totaltimeoutreceive(len, tm, sl)
check_timeout(tm, sl, elapsed, err, "receive", "total",
string.len(str) == 2*len)
end
test_totaltimeoutreceive(800091, 1, 3)
test_totaltimeoutreceive(800091, 2, 3)
test_totaltimeoutreceive(800091, 3, 2)
test_totaltimeoutreceive(800091, 3, 1)
------------------------------------------------------------------------
test("total timeout on send")
function test_totaltimeoutsend(len, tm, sl)
local str, err, total
reconnect()
@ -336,13 +223,8 @@ function test_totaltimeoutsend(len, tm, sl)
check_timeout(tm, sl, elapsed, err, "send", "total",
total == 2*len)
end
test_totaltimeoutsend(800091, 1, 3)
test_totaltimeoutsend(800091, 2, 3)
test_totaltimeoutsend(800091, 3, 2)
test_totaltimeoutsend(800091, 3, 1)
------------------------------------------------------------------------
test("blocking timeout on receive")
function test_blockingtimeoutreceive(len, tm, sl)
local str, err, total
reconnect()
@ -361,13 +243,8 @@ function test_blockingtimeoutreceive(len, tm, sl)
check_timeout(tm, sl, elapsed, err, "receive", "blocking",
string.len(str) == 2*len)
end
test_blockingtimeoutreceive(800091, 1, 3)
test_blockingtimeoutreceive(800091, 2, 3)
test_blockingtimeoutreceive(800091, 3, 2)
test_blockingtimeoutreceive(800091, 3, 1)
------------------------------------------------------------------------
test("blocking timeout on send")
function test_blockingtimeoutsend(len, tm, sl)
local str, err, total
reconnect()
@ -386,15 +263,8 @@ function test_blockingtimeoutsend(len, tm, sl)
check_timeout(tm, sl, elapsed, err, "send", "blocking",
total == 2*len)
end
test_blockingtimeoutsend(800091, 1, 3)
test_blockingtimeoutsend(800091, 2, 3)
test_blockingtimeoutsend(800091, 3, 2)
test_blockingtimeoutsend(800091, 3, 1)
------------------------------------------------------------------------
test("bugs")
io.write("empty host connect: ")
function empty_connect()
if data then data:close() data = nil end
remote [[
@ -408,27 +278,25 @@ function empty_connect()
else fail("should not have connected!") end
end
empty_connect()
------------------------------------------------------------------------
function isclosed(c)
return c:fd() == -1 or c:fd() == (2^32-1)
end
-- io.write("active close: ")
function active_close()
reconnect()
if socket._isclosed(data) then fail("should not be closed") end
if isclosed(data) then fail("should not be closed") end
data:close()
if not socket._isclosed(data) then fail("should be closed") end
if not isclosed(data) then fail("should be closed") end
data = nil
local udp = socket.udp()
if socket._isclosed(udp) then fail("should not be closed") end
if isclosed(udp) then fail("should not be closed") end
udp:close()
if not socket._isclosed(udp) then fail("should be closed") end
if not isclosed(udp) then fail("should be closed") end
pass("ok")
end
-- active_close()
------------------------------------------------------------------------
test("closed connection detection")
function test_closed()
local back, err
local str = 'little string'
@ -453,18 +321,15 @@ function test_closed()
]]
total, err = data:send(string.rep("ugauga", 100000))
if not err then
pass("failed: output buffer is at least %d bytes long!", total)
pass("failed: output buffer is at least %d bytes long!", total)
elseif err ~= "closed" then
fail("got '"..err.."' instead of 'closed'.")
fail("got '"..err.."' instead of 'closed'.")
else
pass("graceful 'closed' received after %d bytes were sent", total)
pass("graceful 'closed' received after %d bytes were sent", total)
end
end
test_closed()
------------------------------------------------------------------------
test("select function")
function test_selectbugs()
local r, s, e = socket.select(nil, nil, 0.1)
assert(type(r) == "table" and type(s) == "table" and e == "timeout")
@ -481,7 +346,144 @@ function test_selectbugs()
pass("invalid input: ok")
end
test("method registration")
test_methods(socket.tcp(), {
"connect",
"send",
"receive",
"bind",
"accept",
"setpeername",
"setsockname",
"getpeername",
"getsockname",
"setoption",
"settimeout",
"close",
})
test_methods(socket.udp(), {
"getpeername",
"getsockname",
"setsockname",
"setpeername",
"send",
"sendto",
"receive",
"receivefrom",
"setoption",
"settimeout",
"close",
})
test("mixed patterns")
reconnect()
test_mixed(1)
test_mixed(17)
test_mixed(200)
test_mixed(4091)
test_mixed(801990)
test_mixed(4091)
test_mixed(200)
test_mixed(17)
test_mixed(1)
test("character line")
reconnect()
test_asciiline(1)
test_asciiline(17)
test_asciiline(200)
test_asciiline(4091)
test_asciiline(80199)
test_asciiline(8000000)
test_asciiline(80199)
test_asciiline(4091)
test_asciiline(200)
test_asciiline(17)
test_asciiline(1)
test("binary line")
reconnect()
test_rawline(1)
test_rawline(17)
test_rawline(200)
test_rawline(4091)
test_rawline(80199)
test_rawline(8000000)
test_rawline(80199)
test_rawline(4091)
test_rawline(200)
test_rawline(17)
test_rawline(1)
test("raw transfer")
reconnect()
test_raw(1)
test_raw(17)
test_raw(200)
test_raw(4091)
test_raw(80199)
test_raw(8000000)
test_raw(80199)
test_raw(4091)
test_raw(200)
test_raw(17)
test_raw(1)
test("non-blocking transfer")
reconnect()
-- the value is not important, we only want
-- to test non-blockin I/O anyways
data:settimeout(200)
test_raw(1)
test_raw(17)
test_raw(200)
test_raw(4091)
test_raw(80199)
test_raw(8000000)
test_raw(80199)
test_raw(4091)
test_raw(200)
test_raw(17)
test_raw(1)
test("select function")
test_selectbugs()
test("empty host connect: ")
empty_connect()
test("active close: ")
active_close()
test("closed connection detection: ")
test_closed()
a = [[
test("total timeout on send")
test_totaltimeoutsend(800091, 1, 3)
test_totaltimeoutsend(800091, 2, 3)
test_totaltimeoutsend(800091, 3, 2)
test_totaltimeoutsend(800091, 3, 1)
test("total timeout on receive")
test_totaltimeoutreceive(800091, 1, 3)
test_totaltimeoutreceive(800091, 2, 3)
test_totaltimeoutreceive(800091, 3, 2)
test_totaltimeoutreceive(800091, 3, 1)
test("blocking timeout on send")
test_blockingtimeoutsend(800091, 1, 3)
test_blockingtimeoutsend(800091, 2, 3)
test_blockingtimeoutsend(800091, 3, 2)
test_blockingtimeoutsend(800091, 3, 1)
test("blocking timeout on receive")
test_blockingtimeoutreceive(800091, 1, 3)
test_blockingtimeoutreceive(800091, 2, 3)
test_blockingtimeoutreceive(800091, 3, 2)
test_blockingtimeoutreceive(800091, 3, 1)
]]
socket.done()
test(string.format("done in %.2fs", socket.time() - start))