mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 04:28:20 +01:00
Tested in windows. Still needs more testing, but progress has been made.
This commit is contained in:
parent
89f3ecf782
commit
076451c753
11
TODO
11
TODO
@ -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
23
luasocket.sln
Normal 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
216
luasocket.vcproj
Normal 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>
|
@ -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);
|
||||
|
@ -18,7 +18,9 @@
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Library's namespace
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef LUASOCKET_LIBNAME
|
||||
#define LUASOCKET_LIBNAME "socket"
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* This macro prefixes all exported API functions
|
||||
|
18
src/tcp.c
18
src/tcp.c
@ -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)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <unistd.h>
|
||||
|
71
src/udp.c
71
src/udp.c
@ -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[] = {
|
||||
@ -59,6 +64,11 @@ static luaL_reg udp[] = {
|
||||
static luaL_reg opt[] = {
|
||||
{"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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
|
@ -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;
|
||||
ssize_t put;
|
||||
int ret;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
/* 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;
|
||||
/* run select to avoid busy wait */
|
||||
if (errno != EPIPE) {
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
ssize_t put = 0;
|
||||
int err;
|
||||
int ret;
|
||||
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;
|
||||
/* 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;
|
||||
err = IO_DONE;
|
||||
}
|
||||
return err;
|
||||
} else {
|
||||
*sent = 0;
|
||||
return IO_TIMEOUT;
|
||||
return IO_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,29 +234,27 @@ 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;
|
||||
ssize_t taken;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
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;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
ssize_t taken = 0;
|
||||
*got = 0;
|
||||
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) {
|
||||
taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
||||
if (taken <= 0) {
|
||||
*got = 0;
|
||||
return IO_CLOSED;
|
||||
if (ret > 0) return IO_DONE;
|
||||
else return IO_TIMEOUT;
|
||||
} else {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
} else {
|
||||
*got = 0;
|
||||
return IO_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
|
126
src/wsocket.c
126
src/wsocket.c
@ -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;
|
||||
ssize_t put;
|
||||
int ret;
|
||||
/* 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;
|
||||
/* run select to avoid busy wait */
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
ssize_t put = 0;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
int err;
|
||||
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;
|
||||
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;
|
||||
err = IO_DONE;
|
||||
}
|
||||
return err;
|
||||
} else {
|
||||
*sent = 0;
|
||||
return IO_TIMEOUT;
|
||||
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;
|
||||
ssize_t put;
|
||||
int ret;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
/* 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;
|
||||
/* run select to avoid busy wait */
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
ssize_t put = 0;
|
||||
int err;
|
||||
int ret;
|
||||
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;
|
||||
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;
|
||||
err = IO_DONE;
|
||||
}
|
||||
return err;
|
||||
} else {
|
||||
*sent = 0;
|
||||
return IO_TIMEOUT;
|
||||
return IO_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,29 +193,26 @@ 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;
|
||||
ssize_t taken;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
taken = recv(sock, data, (int) count, 0);
|
||||
if (taken <= 0) {
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
int ret;
|
||||
ssize_t taken = 0;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
*got = 0;
|
||||
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) {
|
||||
taken = recv(sock, data, count, 0);
|
||||
if (taken <= 0) {
|
||||
*got = 0;
|
||||
return IO_CLOSED;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
*got = 0;
|
||||
return IO_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
@ -223,29 +222,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;
|
||||
ssize_t taken;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
|
||||
if (taken <= 0) {
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
int ret;
|
||||
ssize_t taken = 0;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
*got = 0;
|
||||
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) {
|
||||
taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
||||
if (taken <= 0) {
|
||||
*got = 0;
|
||||
return IO_CLOSED;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
*got = 0;
|
||||
return IO_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user