Compiles and runs on windows.

This commit is contained in:
Diego Nehab 2004-07-02 18:44:05 +00:00
parent 63807d6476
commit b1a4ad2b19
6 changed files with 292 additions and 251 deletions

4
FIX
View File

@ -1,3 +1,6 @@
new sample unix domain support
new sample LPD support
comprehensive error messages in the default case.
added getstats to help throttle.
setup error messages in the default case.
listen defaults to 32 backlog
@ -7,5 +10,4 @@ accepted sockets are nonblocking
new timming functions. higher resolution, no wrap around
bug fixes in the manual
getfd missing cast
added unix domain support example
fixed local domain socket kludge of name size

View File

@ -28,7 +28,7 @@
/* buffer control structure */
typedef struct t_buf_ {
double birthday; /* throttle support info: creation time, */
int sent, received; /* bytes sent, and bytes received */
size_t sent, received; /* bytes sent, and bytes received */
p_io io; /* IO driver used for this buffer */
p_tm tm; /* timeout management for this buffer */
size_t first, last; /* index of first and last bytes of stored data */

View File

@ -2,16 +2,9 @@
* Socket compatibilization module for Unix
* LuaSocket toolkit
*
* We are now treating EINTRs, but if an interrupt happens in the middle of
* a select function call, we don't guarantee values timeouts anymore.
* It's not a big deal, since we are not real-time anyways.
*
* We also exchanged the order of the calls to send/recv and select.
* The idea is that the outer loop (whoever is calling sock_send/recv)
* will call the function again if we didn't time out, so we can
* call write and then select only if it fails. This moves the penalty
* to when data is not available, maximizing the bandwidth if data is
* always available.
* The code is now interrupt-safe.
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
*
* RCS ID: $Id$
\*=========================================================================*/
@ -177,9 +170,9 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
FD_SET(sock, &fds);
err = sock_select(sock+1, &fds, NULL, NULL, tm);
if (err == 0) return io_strerror(IO_TIMEOUT);
else if (err < 0) return sock_strerror();
else if (err < 0) break;
}
return io_strerror(IO_TIMEOUT); /* can't get here */
return sock_strerror();
}
/*-------------------------------------------------------------------------*\
@ -217,9 +210,10 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
FD_SET(sock, &fds);
ret = sock_select(sock+1, NULL, &fds, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
if (ret < 0) return IO_USER;
else if (ret < 0) break;
/* otherwise, try sending again */
}
return IO_USER;
}
/*-------------------------------------------------------------------------*\
@ -250,8 +244,9 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
FD_SET(sock, &fds);
ret = sock_select(sock+1, NULL, &fds, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
if (ret < 0) return IO_USER;
else if (ret < 0) break;
}
return IO_USER;
}
/*-------------------------------------------------------------------------*\
@ -278,8 +273,9 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
FD_SET(sock, &fds);
ret = sock_select(sock+1, &fds, NULL, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
if (ret < 0) return IO_USER;
else if (ret < 0) break;
}
return IO_USER;
}
/*-------------------------------------------------------------------------*\
@ -307,8 +303,9 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
FD_SET(sock, &fds);
ret = sock_select(sock+1, &fds, NULL, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
if (ret < 0) return IO_USER;
else if (ret < 0) break;
}
return IO_USER;
}
/*-------------------------------------------------------------------------*\
@ -333,7 +330,12 @@ void sock_setnonblocking(p_sock ps) {
* Error translation functions
\*-------------------------------------------------------------------------*/
const char *sock_hoststrerror(void) {
return hstrerror(h_errno);
switch (h_errno) {
case HOST_NOT_FOUND:
return "host not found";
default:
return hstrerror(h_errno);
}
}
/* make sure important error messages are standard */

View File

@ -2,12 +2,8 @@
* Socket compatibilization module for Win32
* LuaSocket toolkit
*
* We also exchanged the order of the calls to send/recv and select.
* The idea is that the outer loop (whoever is calling sock_send/recv)
* will call the function again if we didn't time out, so we can
* call write and then select only if it fails. This moves the penalty
* to when data is not available, maximizing the bandwidth if data is
* always available.
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
*
* RCS ID: $Id$
\*=========================================================================*/
@ -15,17 +11,14 @@
#include "socket.h"
static const char *sock_createstrerror(int err);
static const char *sock_bindstrerror(int err);
static const char *sock_connectstrerror(int err);
static const char *sock_acceptstrerror(int err);
static const char *sock_listenstrerror(int err);
/* WinSock doesn't have a strerror... */
static const char *wstrerror(int err);
static int wisclosed(int err);
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int sock_open(void)
{
int sock_open(void) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
int err = WSAStartup(wVersionRequested, &wsaData );
@ -40,8 +33,7 @@ int sock_open(void)
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int sock_close(void)
{
int sock_close(void) {
WSACleanup();
return 1;
}
@ -49,19 +41,18 @@ int sock_close(void)
/*-------------------------------------------------------------------------*\
* Select with int timeout in ms
\*-------------------------------------------------------------------------*/
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout)
{
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL);
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);
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void sock_destroy(p_sock ps)
{
void sock_destroy(p_sock ps) {
if (*ps != SOCK_INVALID) {
sock_setblocking(ps); /* close can take a long time on WIN32 */
closesocket(*ps);
@ -72,8 +63,7 @@ void sock_destroy(p_sock ps)
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void sock_shutdown(p_sock ps, int how)
{
void sock_shutdown(p_sock ps, int how) {
sock_setblocking(ps);
shutdown(*ps, how);
sock_setnonblocking(ps);
@ -82,11 +72,9 @@ 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)
{
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_createstrerror(WSAGetLastError());
if (sock == SOCK_INVALID) return sock_strerror();
*ps = sock;
return NULL;
}
@ -94,10 +82,9 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
{
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) {
t_sock sock = *ps;
int err, timeout = tm_getretry(tm);
int err;
fd_set efds, wfds;
/* don't call on closed socket */
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
@ -107,14 +94,16 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
if (err == 0) return NULL;
/* make sure the system is trying to connect */
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return sock_connectstrerror(err);
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, timeout);
err = sock_select(0, NULL, &wfds, &efds, tm);
/* if select returned due to an event */
if (err > 0 ) {
if (err > 0) {
/* if was in efds, we failed */
if (FD_ISSET(sock, &efds)) {
int why, len = sizeof(why);
@ -124,22 +113,21 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
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 sock_connectstrerror(why);
return wstrerror(why);
/* otherwise it must be in wfds, so we succeeded */
} else return NULL;
/* if no event happened, we timed out */
} else return io_strerror(IO_TIMEOUT);
} else if (err == 0) return io_strerror(IO_TIMEOUT);
return sock_strerror();
}
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
{
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
const char *err = NULL;
sock_setblocking(ps);
if (bind(*ps, addr, addr_len) < 0)
err = sock_bindstrerror(WSAGetLastError());
if (bind(*ps, addr, addr_len) < 0) err = sock_strerror();
sock_setnonblocking(ps);
return err;
}
@ -147,12 +135,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 *sock_listen(p_sock ps, int backlog) {
const char *err = NULL;
sock_setblocking(ps);
if (listen(*ps, backlog) < 0)
err = sock_listenstrerror(WSAGetLastError());
if (listen(*ps, backlog) < 0) err = sock_strerror();
sock_setnonblocking(ps);
return err;
}
@ -161,8 +147,7 @@ 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)
{
socklen_t *addr_len, p_tm tm) {
t_sock sock = *ps;
SA dummy_addr;
socklen_t dummy_len = sizeof(dummy_addr);
@ -171,151 +156,163 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
if (!addr_len) addr_len = &dummy_len;
for (;;) {
fd_set rfds;
int timeout = tm_getretry(tm);
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;
/* optimization */
if (timeout == 0) return io_strerror(IO_TIMEOUT);
/* otherwise find out why we failed */
err = WSAGetLastError();
/* if we failed because there was no connectoin, keep trying*/
if (err != WSAEWOULDBLOCK) return sock_acceptstrerror(err);
/* 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);
/* call select to avoid busy wait */
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
err = sock_select(0, &rfds, NULL, NULL, timeout);
if (err <= 0) return io_strerror(IO_TIMEOUT);
err = sock_select(0, &rfds, NULL, NULL, tm);
if (err == 0) return io_strerror(IO_TIMEOUT);
else if (err < 0) break;
}
return io_strerror(IO_TIMEOUT); /* can't get here */
return sock_strerror();
}
/*-------------------------------------------------------------------------*\
* Send with timeout
\*-------------------------------------------------------------------------*/
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
int timeout)
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
{
t_sock sock = *ps;
int put;
/* 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 */
for ( ;; ) {
fd_set fds;
int ret, put;
/* try to send something */
put = send(sock, 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;
/* 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 */
if (WSAGetLastError() == WSAEWOULDBLOCK) {
fd_set fds;
int ret;
/* optimize for the timeout = 0 case */
if (timeout == 0) return IO_TIMEOUT;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = sock_select(0, NULL, &fds, NULL, timeout);
/* tell the caller to call us again because now we can send */
if (ret > 0) return IO_RETRY;
/* tell the caller we can't send anything before timint out */
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;
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;
}
return IO_USER;
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t addr_len, int timeout)
SA *addr, socklen_t addr_len, p_tm tm)
{
t_sock sock = *ps;
int put;
/* avoid making system calls on closed sockets */
if (sock == SOCK_INVALID) return IO_CLOSED;
put = sendto(sock, data, (int) count, 0, addr, addr_len);
if (put <= 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 */
if (put > 0) {
*sent = put;
return IO_DONE;
}
/* deal with failure */
*sent = 0;
if (WSAGetLastError() == WSAEWOULDBLOCK) {
fd_set fds;
int ret;
if (timeout == 0) return IO_TIMEOUT;
FD_ZERO(&fds);
FD_SET(sock, &fds);
ret = sock_select(0, NULL, &fds, NULL, timeout);
if (ret > 0) return IO_RETRY;
else return IO_TIMEOUT;
} else return IO_CLOSED;
} else {
*sent = put;
return IO_DONE;
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;
}
return IO_USER;
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm)
{
t_sock sock = *ps;
int taken;
if (sock == SOCK_INVALID) return IO_CLOSED;
taken = recv(sock, data, (int) count, 0);
if (taken <= 0) {
for ( ;; ) {
fd_set fds;
int ret;
int ret, taken;
taken = recv(sock, data, (int) count, 0);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
*got = 0;
if (taken == 0 || WSAGetLastError() != WSAEWOULDBLOCK) return IO_CLOSED;
if (timeout == 0) return IO_TIMEOUT;
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, timeout);
if (ret > 0) return IO_RETRY;
else return IO_TIMEOUT;
} else {
*got = taken;
return IO_DONE;
ret = sock_select(0, &fds, NULL, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
else if (ret < 0) break;
}
return IO_TIMEOUT;
}
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *addr_len, int timeout)
SA *addr, socklen_t *addr_len, p_tm tm)
{
t_sock sock = *ps;
int taken;
if (sock == SOCK_INVALID) return IO_CLOSED;
taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
if (taken <= 0) {
for ( ;; ) {
fd_set fds;
int ret;
int ret, taken;
taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
*got = 0;
if (taken == 0 || WSAGetLastError() != WSAEWOULDBLOCK) return IO_CLOSED;
if (timeout == 0) return IO_TIMEOUT;
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, timeout);
if (ret > 0) return IO_RETRY;
else return IO_TIMEOUT;
} else {
*got = taken;
return IO_DONE;
ret = sock_select(0, &fds, NULL, NULL, tm);
if (ret == 0) return IO_TIMEOUT;
else if (ret < 0) break;
}
return IO_TIMEOUT;
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void sock_setblocking(p_sock ps)
{
void sock_setblocking(p_sock ps) {
u_long argp = 0;
ioctlsocket(*ps, FIONBIO, &argp);
}
@ -323,8 +320,7 @@ void sock_setblocking(p_sock ps)
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void sock_setnonblocking(p_sock ps)
{
void sock_setnonblocking(p_sock ps) {
u_long argp = 1;
ioctlsocket(*ps, FIONBIO, &argp);
}
@ -332,117 +328,136 @@ void sock_setnonblocking(p_sock ps)
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
/* return error messages for the known errors reported by gethostbyname */
const char *sock_hoststrerror(void)
{
switch (WSAGetLastError()) {
case WSANOTINITIALISED: return "not initialized";
case WSAENETDOWN: return "network is down";
case WSAHOST_NOT_FOUND: return "host not found";
case WSATRY_AGAIN: return "name server unavailable, try again later";
case WSANO_RECOVERY: return "name server error";
case WSANO_DATA: return "host not found";
case WSAEINPROGRESS: return "another call in progress";
case WSAEFAULT: return "invalid memory address";
case WSAEINTR: return "call interrupted";
default: return "unknown error";
}
}
/* return error messages for the known errors reported by socket */
static const char *sock_createstrerror(int err)
{
const char *sock_hoststrerror(void) {
int err = WSAGetLastError();
switch (err) {
case WSANOTINITIALISED: return "not initialized";
case WSAENETDOWN: return "network is down";
case WSAEAFNOSUPPORT: return "address family not supported";
case WSAEINPROGRESS: return "another call in progress";
case WSAEMFILE: return "descriptor table is full";
case WSAENOBUFS: return "insufficient buffer space";
case WSAEPROTONOSUPPORT: return "protocol not supported";
case WSAEPROTOTYPE: return "wrong protocol type";
case WSAESOCKTNOSUPPORT: return "socket type not supported by family";
default: return "unknown error";
case WSAHOST_NOT_FOUND:
return "host not found";
default:
return wstrerror(err);
}
}
/* return error messages for the known errors reported by accept */
static const char *sock_acceptstrerror(int err)
{
const char *sock_strerror(void) {
int err = WSAGetLastError();
switch (err) {
case WSANOTINITIALISED: return "not initialized";
case WSAENETDOWN: return "network is down";
case WSAEFAULT: return "invalid memory address";
case WSAEINTR: return "call interrupted";
case WSAEINPROGRESS: return "another call in progress";
case WSAEINVAL: return "not listening";
case WSAEMFILE: return "descriptor table is full";
case WSAENOBUFS: return "insufficient buffer space";
case WSAENOTSOCK: return "descriptor not a socket";
case WSAEOPNOTSUPP: return "not supported";
case WSAEWOULDBLOCK: return "call would block";
default: return "unknown error";
case WSAEADDRINUSE:
return "address already in use";
default:
return wstrerror(err);
}
}
/* return error messages for the known errors reported by bind */
static const char *sock_bindstrerror(int err)
{
const char *sock_geterr(p_sock ps, int code) {
(void) ps;
(void) code;
return sock_strerror();
}
int wisclosed(int err) {
switch (err) {
case WSANOTINITIALISED: return "not initialized";
case WSAENETDOWN: return "network is down";
case WSAEACCES: return "broadcast not enabled for socket";
case WSAEADDRINUSE: return "address already in use";
case WSAEADDRNOTAVAIL: return "address not available in local host";
case WSAEFAULT: return "invalid memory address";
case WSAEINPROGRESS: return "another call in progress";
case WSAEINVAL: return "already bound";
case WSAENOBUFS: return "insuficient buffer space";
case WSAENOTSOCK: return "descriptor not a socket";
default: return "unknown error";
case WSAECONNRESET:
case WSAECONNABORTED:
case WSAESHUTDOWN:
case WSAENOTCONN:
return 1;
default:
return 0;
}
}
/* return error messages for the known errors reported by listen */
static const char *sock_listenstrerror(int err)
{
static const char *wstrerror(int err) {
switch (err) {
case WSANOTINITIALISED: return "not initialized";
case WSAENETDOWN: return "network is down";
case WSAEADDRINUSE: return "local address already in use";
case WSAEINPROGRESS: return "another call in progress";
case WSAEINVAL: return "not bound";
case WSAEISCONN: return "already connected";
case WSAEMFILE: return "descriptor table is full";
case WSAENOBUFS: return "insuficient buffer space";
case WSAENOTSOCK: return "descriptor not a socket";
case WSAEOPNOTSUPP: return "not supported";
default: return "unknown error";
}
}
/* return error messages for the known errors reported by connect */
static const char *sock_connectstrerror(int err)
{
switch (err) {
case WSANOTINITIALISED: return "not initialized";
case WSAENETDOWN: return "network is down";
case WSAEADDRINUSE: return "local address already in use";
case WSAEINTR: return "call interrupted";
case WSAEINPROGRESS: return "another call in progress";
case WSAEALREADY: return "connect already in progress";
case WSAEADDRNOTAVAIL: return "invalid remote address";
case WSAEAFNOSUPPORT: return "address family not supported";
case WSAECONNREFUSED: return "connection refused";
case WSAEFAULT: return "invalid memory address";
case WSAEINVAL: return "socket is listening";
case WSAEISCONN: return "socket already connected";
case WSAENETUNREACH: return "network is unreachable";
case WSAENOTSOCK: return "descriptor not a socket";
case WSAETIMEDOUT: return io_strerror(IO_TIMEOUT);
case WSAEWOULDBLOCK: return "would block";
case WSAEACCES: return "broadcast not enabled";
default: return "unknown error";
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";
}
}

View File

@ -8,7 +8,7 @@ local qptest = "qptest.bin"
local eqptest = "qptest.bin2"
local dqptest = "qptest.bin3"
local b64test = "luasocket.dylib"
local b64test = "luasocket.dll"
local eb64test = "b64test.bin"
local db64test = "b64test.bin2"

View File

@ -437,6 +437,25 @@ function rebind_test()
print("ok: ", e)
end
------------------------------------------------------------------------
function getstats_test()
reconnect()
local t = 0
for i = 1, 25 do
local c = math.random(1, 100)
remote (string.format ([[
str = data:receive(%d)
data:send(str)
]], c))
c:send(string.rep("a", c))
c:receive(c)
local r, s, a = c:getstats()
assert(r == t, "received count failed")
assert(s == t, "sent count failed")
end
print("ok")
end
------------------------------------------------------------------------
test("method registration")
test_methods(socket.tcp(), {
@ -499,6 +518,9 @@ test("accept function: ")
accept_timeout()
accept_errors()
test("getstats test")
getstats_test()
test("character line")
test_asciiline(1)
test_asciiline(17)