Fixed a bunch of stuff. Added mike's patches.

master
Diego Nehab 2004-07-16 06:48:48 +00:00
parent 9a79d500eb
commit e4e2223cff
13 changed files with 249 additions and 327 deletions

2
FIX
View File

@ -1,9 +1,9 @@
fix bug that caused select return tables not to be associative on windows
compiles with g++
new sample unix domain support
new sample LPD support
comprehensive error messages in the default case.
new getstats method to help throttle.
setup error messages in the default case.
listen defaults to 32 backlog
smtp/ftp/http fail gracefully
accept/connect/select interrupt safe

6
TODO
View File

@ -1,6 +1,6 @@
test associativity of socket.select
probably if is dirty, no assoc is created. wonder why...
change sock:send to use indices just like string.sub?
use mike's "don't set to blocking before closing unless needed" patch?
take a look at DB's smtp patch
optmize aux_getgroupudata (Mike idea)
@ -12,7 +12,6 @@ add error message stuff to the manual
make sure all modules that can use it actually use socket.newtry
adicionar exemplos de expansão: pipe, local, named pipe
Add service name translation.
testar os options!
- Thread-safe
- proteger get*by*.* com um mutex GLOBAL!
@ -29,3 +28,4 @@ testar os options!
*use GetSystemTimeAsFileTime in windows (WinCE will suffer document)
*add getstats to the manual
*Fazer compilar com g++
*test associativity of socket.select

View File

@ -67,13 +67,13 @@
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="H:\include"
AdditionalIncludeDirectories="../../include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport); LUASOCKET_DEBUG"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool

View File

@ -67,13 +67,13 @@
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="H:\include"
AdditionalIncludeDirectories="../../include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS; MIME_API=__declspec(dllexport)"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool

View File

@ -1,25 +1,25 @@
-----------------------------------------------------------------------------
-- TCP sample: Little program to dump lines received at a given port
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "*"
port = port or 8080
if arg then
host = arg[1] or host
port = arg[2] or port
end
print("Binding to host '" ..host.. "' and port " ..port.. "...")
s = socket.try(socket.bind(host, port))
i, p = socket.try(s:getsockname())
print("Waiting connection from talker on " .. i .. ":" .. p .. "...")
c = socket.try(s:accept())
print("Connected. Here is the stuff:")
l, e = c:receive()
while not e do
print(l)
l, e = c:receive()
end
print(e)
-----------------------------------------------------------------------------
-- TCP sample: Little program to dump lines received at a given port
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "*"
port = port or 8080
if arg then
host = arg[1] or host
port = arg[2] or port
end
print("Binding to host '" ..host.. "' and port " ..port.. "...")
s = socket.try(socket.bind(host, port))
i, p = socket.try(s:getsockname())
print("Waiting connection from talker on " .. i .. ":" .. p .. "...")
c = socket.try(s:accept())
print("Connected. Here is the stuff:")
l, e = c:receive()
while not e do
print(l)
l, e = c:receive()
end
print(e)

View File

@ -209,8 +209,8 @@ const char *inet_tryconnect(p_sock ps, const char *address,
memset(&remote, 0, sizeof(remote));
remote.sin_family = AF_INET;
remote.sin_port = htons(port);
if (strcmp(address, "*")) {
if (!strlen(address) || !inet_aton(address, &remote.sin_addr)) {
if (strcmp(address, "*")) {
if (!inet_aton(address, &remote.sin_addr)) {
struct hostent *hp = NULL;
struct in_addr **addr;
err = sock_gethostbyname(address, &hp);
@ -236,8 +236,7 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port)
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
local.sin_family = AF_INET;
if (strcmp(address, "*") &&
(!strlen(address) || !inet_aton(address, &local.sin_addr))) {
if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
struct hostent *hp = NULL;
struct in_addr **addr;
err = sock_gethostbyname(address, &hp);

View File

@ -24,18 +24,19 @@ enum {
IO_DONE = 0, /* operation completed successfully */
IO_TIMEOUT = -1, /* operation timed out */
IO_CLOSED = -2, /* the connection has been closed */
IO_CLIPPED = -3 /* maxium bytes count reached */
IO_CLIPPED = -3, /* maxium bytes count reached */
IO_UNKNOWN = -4
};
/* interface to error message function */
typedef const char *(*p_error) (
void *ctx, /* context needed by send */
void *ctx, /* context needed by send */
int err /* error code */
);
/* interface to send function */
typedef int (*p_send) (
void *ctx, /* context needed by send */
void *ctx, /* context needed by send */
const char *data, /* pointer to buffer with data to send */
size_t count, /* number of bytes to send from buffer */
size_t *sent, /* number of bytes sent uppon return */
@ -44,7 +45,7 @@ typedef int (*p_send) (
/* interface to recv function */
typedef int (*p_recv) (
void *ctx, /* context needed by recv */
void *ctx, /* context needed by recv */
char *data, /* pointer to buffer where data will be writen */
size_t count, /* number of bytes to receive into buffer */
size_t *got, /* number of bytes received uppon return */
@ -61,6 +62,6 @@ typedef struct t_io_ {
typedef t_io *p_io;
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
const char *io_strerror(int err);
const char *io_strerror(int err);
#endif /* IO_H */
#endif /* IO_H */

View File

@ -64,7 +64,7 @@ static int global_select(lua_State *L) {
tm_init(&tm, t, -1);
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
ret = sock_select(max_fd+1, &rset, &wset, NULL, &tm);
if (ret > 0 || (ret == 0 && ndirty > 0)) {
if (ret > 0 || ndirty > 0) {
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
make_assoc(L, rtab);

View File

@ -192,7 +192,8 @@ int tm_lua_sleep(lua_State *L)
struct timespec t, r;
t.tv_sec = (int) n;
n -= t.tv_sec;
t.tv_nsec = (int) (n * 1000000000) % 1000000000;
t.tv_nsec = (int) (n * 1000000000);
if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999;
nanosleep(&t, &r);
#endif
return 0;

View File

@ -19,7 +19,7 @@
#include "timeout.h"
#include "socket.h"
#define UDP_DATAGRAMSIZE 576
#define UDP_DATAGRAMSIZE 8192
typedef struct t_udp_ {
t_sock sock;

View File

@ -179,11 +179,11 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) {
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) {
SA daddr;
socklen_t dlen = sizeof(daddr);
int err;
if (*ps == SOCK_INVALID) return IO_CLOSED;
if (!addr) addr = &daddr;
if (!len) len = &dlen;
for ( ;; ) {
int err;
if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE;
err = errno;
if (err == EINTR) continue;
@ -191,7 +191,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) {
if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
}
/* can't reach here */
return err;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -223,7 +223,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
}
/* can't reach here */
return err;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -247,7 +247,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
if (err != EAGAIN) return err;
if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
}
return err;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -269,7 +269,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
if (err != EAGAIN) return err;
if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return err;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -292,7 +292,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
if (err != EAGAIN) return err;
if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return err;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -345,10 +345,10 @@ const char *sock_strerror(int err) {
switch (err) {
case EADDRINUSE: return "eaddrinuse";
case EACCES: return "eaccess";
case ECONNABORTED: return "econnaborted";
case ECONNREFUSED: return "econnrefused";
case ECONNRESET: return "econnreset";
case ETIMEDOUT: return "etimedout";
case ECONNABORTED: return "closed";
case ECONNRESET: return "closed";
case ETIMEDOUT: return "timedout";
default: return strerror(errno);
}
}

View File

@ -13,7 +13,6 @@
/* WinSock doesn't have a strerror... */
static const char *wstrerror(int err);
static int wisclosed(int err);
/*-------------------------------------------------------------------------*\
* Initializes module
@ -38,15 +37,44 @@ int sock_close(void) {
return 1;
}
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
#define WAITFD_R 1
#define WAITFD_W 2
#define WAITFD_E 4
#define WAITFD_C (WAITFD_E|WAITFD_W)
static int sock_waitfd(t_sock fd, int sw, p_tm tm) {
int ret;
fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
struct timeval tv, *tp = NULL;
double t;
if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rp = &rfds; }
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(fd, &wfds); wp = &wfds; }
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(fd, &efds); ep = &efds; }
if ((t = tm_get(tm)) >= 0.0) {
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(0, rp, wp, ep, tp);
if (ret == -1) return WSAGetLastError();
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(fd, &efds)) return IO_CLOSED;
return IO_DONE;
}
/*-------------------------------------------------------------------------*\
* Select with int timeout in ms
\*-------------------------------------------------------------------------*/
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
struct timeval tv;
struct timeval tv;
double t = tm_get(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
return select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL);
return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
}
/*-------------------------------------------------------------------------*\
@ -72,62 +100,45 @@ void sock_shutdown(p_sock ps, int how) {
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
const char *sock_create(p_sock ps, int domain, int type, int protocol) {
t_sock sock = socket(domain, type, protocol);
if (sock == SOCK_INVALID) return sock_strerror();
*ps = sock;
return NULL;
int sock_create(p_sock ps, int domain, int type, int protocol) {
*ps = socket(domain, type, protocol);
if (*ps != SOCK_INVALID) return IO_DONE;
else return WSAGetLastError();
}
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) {
t_sock sock = *ps;
int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) {
int err;
fd_set efds, wfds;
/* don't call on closed socket */
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
if (*ps == SOCK_INVALID) return IO_CLOSED;
/* ask system to connect */
err = connect(sock, addr, addr_len);
/* if no error, we're done */
if (err == 0) return NULL;
if (connect(*ps, addr, len) == 0) return IO_DONE;
/* make sure the system is trying to connect */
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return wstrerror(err);
/* optimize for timeout=0 */
if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
/* wait for a timeout or for the system's answer */
FD_ZERO(&wfds); FD_SET(sock, &wfds);
FD_ZERO(&efds); FD_SET(sock, &efds);
/* we run select to wait */
err = sock_select(0, NULL, &wfds, &efds, tm);
/* if select returned due to an event */
if (err > 0) {
/* if was in efds, we failed */
if (FD_ISSET(sock, &efds)) {
int why, len = sizeof(why);
/* give windows time to set the error (disgusting) */
Sleep(0);
/* find out why we failed */
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len);
/* we KNOW there was an error. if why is 0, we will return
* "unknown error", but it's not really our fault */
return wstrerror(why);
/* otherwise it must be in wfds, so we succeeded */
} else return NULL;
/* if no event happened, we timed out */
} else if (err == 0) return io_strerror(IO_TIMEOUT);
return sock_strerror();
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
/* we wait until something happens */
if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) {
int len = sizeof(err);
/* give windows time to set the error (yes, disgusting) */
Sleep(0);
/* find out why we failed */
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
/* we KNOW there was an error. if why is 0, we will return
* "unknown error", but it's not really our fault */
return err > 0? err: IO_UNKNOWN;
/* here we deal with the case in which it worked, timedout or weird errors */
} else return err;
}
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
const char *err = NULL;
int sock_bind(p_sock ps, SA *addr, socklen_t len) {
int err = IO_DONE;
sock_setblocking(ps);
if (bind(*ps, addr, addr_len) < 0) err = sock_strerror();
if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
sock_setnonblocking(ps);
return err;
}
@ -135,10 +146,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
const char *sock_listen(p_sock ps, int backlog) {
const char *err = NULL;
int sock_listen(p_sock ps, int backlog) {
int err = IO_DONE;
sock_setblocking(ps);
if (listen(*ps, backlog) < 0) err = sock_strerror();
if (listen(*ps, backlog) < 0) err = WSAGetLastError();
sock_setnonblocking(ps);
return err;
}
@ -146,35 +157,25 @@ const char *sock_listen(p_sock ps, int backlog) {
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
socklen_t *addr_len, p_tm tm) {
t_sock sock = *ps;
SA dummy_addr;
socklen_t dummy_len = sizeof(dummy_addr);
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
if (!addr) addr = &dummy_addr;
if (!addr_len) addr_len = &dummy_len;
for (;;) {
fd_set rfds;
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) {
SA daddr;
socklen_t dlen = sizeof(daddr);
if (*ps == SOCK_INVALID) return IO_CLOSED;
if (!addr) addr = &daddr;
if (!len) len = &dlen;
for ( ;; ) {
int err;
/* try to get client socket */
*pa = accept(sock, addr, addr_len);
/* if return is valid, we are done */
if (*pa != SOCK_INVALID) return NULL;
/* otherwise find out why we failed */
if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE;
/* find out why we failed */
err = WSAGetLastError();
/* if we failed because there was no connectoin, keep trying */
if (err != WSAEWOULDBLOCK) return wstrerror(err);
/* optimize for the timeout=0 case */
if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
/* call select to avoid busy wait */
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
err = sock_select(0, &rfds, NULL, NULL, tm);
if (err == 0) return io_strerror(IO_TIMEOUT);
else if (err < 0) break;
if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return sock_strerror();
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -182,131 +183,93 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
\*-------------------------------------------------------------------------*/
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
{
t_sock sock = *ps;
int err;
/* avoid making system calls on closed sockets */
if (sock == SOCK_INVALID) return IO_CLOSED;
if (*ps == SOCK_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
*sent = 0;
for ( ;; ) {
fd_set fds;
int ret, put;
/* try to send something */
put = send(sock, data, (int) count, 0);
int put = send(*ps, data, (int) count, 0);
/* if we sent something, we are done */
if (put > 0) {
*sent = put;
return IO_DONE;
}
/* deal with failure */
*sent = 0;
ret = WSAGetLastError();
/* check for connection closed */
if (wisclosed(ret)) return IO_CLOSED;
err = WSAGetLastError();
/* we can only proceed if there was no serious error */
if (ret != WSAEWOULDBLOCK) return IO_USER;
/* optimize for the timeout = 0 case */
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
/* run select to avoid busy wait */
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = sock_select(0, NULL, &fds, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
else if (ret < 0) break;
if (err != WSAEWOULDBLOCK) return err;
/* avoid busy wait */
if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
}
return IO_USER;
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t addr_len, p_tm tm)
SA *addr, socklen_t len, p_tm tm)
{
t_sock sock = *ps;
/* avoid making system calls on closed sockets */
if (sock == SOCK_INVALID) return IO_CLOSED;
int err;
if (*ps == SOCK_INVALID) return IO_CLOSED;
*sent = 0;
for ( ;; ) {
fd_set fds;
int ret, put;
/* try to send something */
put = sendto(sock, data, (int) count, 0, addr, addr_len);
/* if we sent something, we are done */
int put = send(*ps, data, (int) count, 0);
if (put > 0) {
*sent = put;
return IO_DONE;
}
/* deal with failure */
*sent = 0;
ret = WSAGetLastError();
/* check for connection closed */
if (wisclosed(ret)) return IO_CLOSED;
/* we can only proceed if there was no serious error */
if (ret != WSAEWOULDBLOCK) return IO_USER;
/* optimize for the timeout = 0 case */
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
/* run select to avoid busy wait */
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = sock_select(0, NULL, &fds, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
else if (ret < 0) break;
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
}
return IO_USER;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm)
{
t_sock sock = *ps;
if (sock == SOCK_INVALID) return IO_CLOSED;
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
int err;
if (*ps == SOCK_INVALID) return IO_CLOSED;
*got = 0;
for ( ;; ) {
fd_set fds;
int ret, taken;
taken = recv(sock, data, (int) count, 0);
int taken = recv(*ps, data, (int) count, 0);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
*got = 0;
if (taken == 0 || wisclosed(ret = WSAGetLastError())) return IO_CLOSED;
if (ret != WSAEWOULDBLOCK) return IO_USER;
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = sock_select(0, &fds, NULL, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
else if (ret < 0) break;
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_TIMEOUT;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *addr_len, p_tm tm)
{
t_sock sock = *ps;
if (sock == SOCK_INVALID) return IO_CLOSED;
SA *addr, socklen_t *len, p_tm tm) {
int err;
if (*ps == SOCK_INVALID) return IO_CLOSED;
*got = 0;
for ( ;; ) {
fd_set fds;
int ret, taken;
taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
*got = 0;
if (taken == 0 || wisclosed(ret = WSAGetLastError())) return IO_CLOSED;
if (ret != WSAEWOULDBLOCK) return IO_USER;
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = sock_select(0, &fds, NULL, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
else if (ret < 0) break;
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_TIMEOUT;
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
@ -325,139 +288,97 @@ void sock_setnonblocking(p_sock ps) {
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* DNS helpers
\*-------------------------------------------------------------------------*/
int sock_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
if (*hp) return IO_DONE;
else return h_errno;
}
int sock_gethostbyname(const char *addr, struct hostent **hp) {
*hp = gethostbyname(addr);
if (*hp) return IO_DONE;
else return h_errno;
}
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
const char *sock_hoststrerror(void) {
int err = WSAGetLastError();
const char *sock_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAHOST_NOT_FOUND:
return "host not found";
default:
return wstrerror(err);
case WSAHOST_NOT_FOUND: return "host_not_found";
default: return wstrerror(err);
}
}
const char *sock_strerror(void) {
int err = WSAGetLastError();
const char *sock_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAEADDRINUSE:
return "address already in use";
default:
return wstrerror(err);
case WSAEADDRINUSE: return "eaddrinuse";
case WSAECONNREFUSED: return "econnrefused";
case WSAECONNABORTED: return "closed";
case WSAECONNRESET: return "closed";
case WSAETIMEDOUT: return "timeout";
default: return wstrerror(err);
}
}
const char *sock_geterr(p_sock ps, int code) {
(void) ps;
(void) code;
return sock_strerror();
}
int wisclosed(int err) {
switch (err) {
case WSAECONNRESET:
case WSAECONNABORTED:
case WSAESHUTDOWN:
case WSAENOTCONN:
return 1;
default:
return 0;
}
const char *sock_ioerror(p_sock ps, int err) {
(void) ps;
return sock_strerror(err);
}
static const char *wstrerror(int err) {
switch (err) {
case WSAEINTR:
return "WSAEINTR: Interrupted function call";
case WSAEACCES:
return "WSAEACCES: Permission denied";
case WSAEFAULT:
return "WSAEFAULT: Bad address";
case WSAEINVAL:
return "WSAEINVAL: Invalid argument";
case WSAEMFILE:
return "WSAEMFILE: Too many open files";
case WSAEWOULDBLOCK:
return "WSAEWOULDBLOCK: Resource temporarily unavailable";
case WSAEINPROGRESS:
return "WSAEINPROGRESS: Operation now in progress";
case WSAEALREADY:
return "WSAEALREADY: Operation already in progress";
case WSAENOTSOCK:
return "WSAENOTSOCK: Socket operation on nonsocket";
case WSAEDESTADDRREQ:
return "WSAEDESTADDRREQ: Destination address required";
case WSAEMSGSIZE:
return "WSAEMSGSIZE: Message too long";
case WSAEPROTOTYPE:
return "WSAEPROTOTYPE: Protocol wrong type for socket";
case WSAENOPROTOOPT:
return "WSAENOPROTOOPT: Bad protocol option";
case WSAEPROTONOSUPPORT:
return "WSAEPROTONOSUPPORT: Protocol not supported";
case WSAESOCKTNOSUPPORT:
return "WSAESOCKTNOSUPPORT: Socket type not supported";
case WSAEOPNOTSUPP:
return "WSAEOPNOTSUPP: Operation not supported";
case WSAEPFNOSUPPORT:
return "WSAEPFNOSUPPORT: Protocol family not supported";
case WSAEAFNOSUPPORT:
return "WSAEAFNOSUPPORT: Address family not supported by "
"protocol family";
case WSAEADDRINUSE:
return "WSAEADDRINUSE: Address already in use";
case WSAEADDRNOTAVAIL:
return "WSAEADDRNOTAVAIL: Cannot assign requested address";
case WSAENETDOWN:
return "WSAENETDOWN: Network is down";
case WSAENETUNREACH:
return "WSAENETUNREACH: Network is unreachable";
case WSAENETRESET:
return "WSAENETRESET: Network dropped connection on reset";
case WSAECONNABORTED:
return "WSAECONNABORTED: Software caused connection abort";
case WSAECONNRESET:
return "WSAECONNRESET: Connection reset by peer";
case WSAENOBUFS:
return "WSAENOBUFS: No buffer space available";
case WSAEISCONN:
return "WSAEISCONN: Socket is already connected";
case WSAENOTCONN:
return "WSAENOTCONN: Socket is not connected";
case WSAESHUTDOWN:
return "WSAESHUTDOWN: Cannot send after socket shutdown";
case WSAETIMEDOUT:
return "WSAETIMEDOUT: Connection timed out";
case WSAECONNREFUSED:
return "WSAECONNREFUSED: Connection refused";
case WSAEHOSTDOWN:
return "WSAEHOSTDOWN: Host is down";
case WSAEHOSTUNREACH:
return "WSAEHOSTUNREACH: No route to host";
case WSAEPROCLIM:
return "WSAEPROCLIM: Too many processes";
case WSASYSNOTREADY:
return "WSASYSNOTREADY: Network subsystem is unavailable";
case WSAVERNOTSUPPORTED:
return "WSAVERNOTSUPPORTED: Winsock.dll version out of range";
case WSANOTINITIALISED:
return "WSANOTINITIALISED: Successful WSAStartup not yet performed";
case WSAEDISCON:
return "WSAEDISCON: Graceful shutdown in progress";
case WSATYPE_NOT_FOUND:
return "WSATYPE_NOT_FOUND: Class type not found";
case WSAHOST_NOT_FOUND:
return "WSAHOST_NOT_FOUND: Host not found";
case WSATRY_AGAIN:
return "WSATRY_AGAIN: Nonauthoritative host not found";
case WSANO_RECOVERY:
return "WSANO_RECOVERY: Nonrecoverable name lookup error";
case WSANO_DATA:
return "WSANO_DATA: Valid name, no data record of requested type";
case WSASYSCALLFAILURE:
return "WSASYSCALLFAILURE: System call failure";
default:
return "Unknown error";
case WSAEINTR: return "Interrupted function call";
case WSAEACCES: return "Permission denied";
case WSAEFAULT: return "Bad address";
case WSAEINVAL: return "Invalid argument";
case WSAEMFILE: return "Too many open files";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
case WSAEINPROGRESS: return "Operation now in progress";
case WSAEALREADY: return "Operation already in progress";
case WSAENOTSOCK: return "Socket operation on nonsocket";
case WSAEDESTADDRREQ: return "Destination address required";
case WSAEMSGSIZE: return "Message too long";
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
case WSAENOPROTOOPT: return "Bad protocol option";
case WSAEPROTONOSUPPORT: return "Protocol not supported";
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
case WSAEOPNOTSUPP: return "Operation not supported";
case WSAEPFNOSUPPORT: return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE: return "Address already in use";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
case WSAENETDOWN: return "Network is down";
case WSAENETUNREACH: return "Network is unreachable";
case WSAENETRESET: return "Network dropped connection on reset";
case WSAECONNABORTED: return "Software caused connection abort";
case WSAECONNRESET: return "Connection reset by peer";
case WSAENOBUFS: return "No buffer space available";
case WSAEISCONN: return "Socket is already connected";
case WSAENOTCONN: return "Socket is not connected";
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
case WSAETIMEDOUT: return "Connection timed out";
case WSAECONNREFUSED: return "Connection refused";
case WSAEHOSTDOWN: return "Host is down";
case WSAEHOSTUNREACH: return "No route to host";
case WSAEPROCLIM: return "Too many processes";
case WSASYSNOTREADY: return "Network subsystem is unavailable";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
case WSANOTINITIALISED:
return "Successful WSAStartup not yet performed";
case WSAEDISCON: return "Graceful shutdown in progress";
case WSATYPE_NOT_FOUND: return "Class type not found";
case WSAHOST_NOT_FOUND: return "Host not found";
case WSATRY_AGAIN: return "Nonauthoritative host not found";
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
case WSANO_DATA: return "Valid name, no data record of requested type";
case WSASYSCALLFAILURE: return "System call failure";
default: return "Unknown error";
}
}

View File

@ -283,7 +283,9 @@ function empty_connect()
if not data then
pass("ok")
data = socket.connect(host, port)
else fail("should not have connected!") end
else
pass("gethostbyname returns localhost on empty string...")
end
end
------------------------------------------------------------------------
@ -374,19 +376,17 @@ end
------------------------------------------------------------------------
function connect_timeout()
io.stderr:write("connect with timeout (if it hangs, it failed): ")
io.stderr:write("connect with timeout (if it hangs, it failed!): ")
local t = socket.gettime()
local c, e = socket.tcp()
assert(c, e)
c:settimeout(0.1)
ip = socket.dns.toip("ibere.tecgraf.puc-rio.br")
if not ip then return end
local t = socket.gettime()
local r, e = c:connect(ip, 80)
local r, e = c:connect("127.0.0.2", 80)
assert(not r, "should not connect")
--assert(e == "timeout", e)
assert(socket.gettime() - t < 2, "took too long to give up.")
c:close()
print("ok")
end
------------------------------------------------------------------------