From b1a4ad2b1996936744c679e6ae563986ff701a3a Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Fri, 2 Jul 2004 18:44:05 +0000 Subject: [PATCH] Compiles and runs on windows. --- FIX | 4 +- src/buffer.h | 2 +- src/usocket.c | 38 ++-- src/wsocket.c | 475 ++++++++++++++++++++++++---------------------- test/mimetest.lua | 2 +- test/testclnt.lua | 22 +++ 6 files changed, 292 insertions(+), 251 deletions(-) diff --git a/FIX b/FIX index d126226..b1e5851 100644 --- a/FIX +++ b/FIX @@ -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 diff --git a/src/buffer.h b/src/buffer.h index 3ea2648..3cc885f 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -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 */ diff --git a/src/usocket.c b/src/usocket.c index b99eaa8..0e3d30c 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -2,20 +2,13 @@ * 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$ \*=========================================================================*/ -#include +#include #include #include "socket.h" @@ -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 */ diff --git a/src/wsocket.c b/src/wsocket.c index 7f3e066..a264452 100644 --- a/src/wsocket.c +++ b/src/wsocket.c @@ -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); @@ -106,15 +93,17 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) /* if no error, we're done */ if (err == 0) return NULL; /* make sure the system is trying to connect */ - err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK) return sock_connectstrerror(err); + 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, 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"; +const char *sock_hoststrerror(void) { + int err = WSAGetLastError(); + switch (err) { + case WSAHOST_NOT_FOUND: + return "host not found"; + default: + return wstrerror(err); } } -/* return error messages for the known errors reported by socket */ -static const char *sock_createstrerror(int err) -{ +const char *sock_strerror(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 WSAEADDRINUSE: + return "address already in use"; + default: + return wstrerror(err); } } -/* return error messages for the known errors reported by accept */ -static const char *sock_acceptstrerror(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 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 WSAECONNRESET: + case WSAECONNABORTED: + case WSAESHUTDOWN: + case WSAENOTCONN: + return 1; + default: + return 0; } } -/* return error messages for the known errors reported by bind */ -static const char *sock_bindstrerror(int err) -{ +static const char *wstrerror(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"; - } - -} - -/* return error messages for the known errors reported by listen */ -static const char *sock_listenstrerror(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"; } } diff --git a/test/mimetest.lua b/test/mimetest.lua index 0b3db33..413a83b 100644 --- a/test/mimetest.lua +++ b/test/mimetest.lua @@ -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" diff --git a/test/testclnt.lua b/test/testclnt.lua index 38dc19a..cdd2c08 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua @@ -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)