From 076451c75336b30e6152bd5c02f355db39107f7d Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Sat, 17 Jan 2004 00:17:46 +0000 Subject: Tested in windows. Still needs more testing, but progress has been made. --- src/inet.h | 4 ++ src/luasocket.h | 2 + src/tcp.c | 18 +++--- src/timeout.c | 1 + src/udp.c | 75 ++++++++++++++++++++++- src/usocket.c | 92 ++++++++++++++--------------- src/wsocket.c | 180 +++++++++++++++++++++++++++----------------------------- 7 files changed, 224 insertions(+), 148 deletions(-) (limited to 'src') diff --git a/src/inet.h b/src/inet.h index 244a310..b69e82d 100644 --- a/src/inet.h +++ b/src/inet.h @@ -19,6 +19,10 @@ #include #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); diff --git a/src/luasocket.h b/src/luasocket.h index 7756605..ac26824 100644 --- a/src/luasocket.h +++ b/src/luasocket.h @@ -18,7 +18,9 @@ /*-------------------------------------------------------------------------*\ * Library's namespace \*-------------------------------------------------------------------------*/ +#ifndef LUASOCKET_LIBNAME #define LUASOCKET_LIBNAME "socket" +#endif /*-------------------------------------------------------------------------*\ * This macro prefixes all exported API functions diff --git a/src/tcp.c b/src/tcp.c index afa0477..a67b44a 100644 --- a/src/tcp.c +++ b/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) diff --git a/src/timeout.c b/src/timeout.c index 5d6de99..2d88ded 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -16,6 +16,7 @@ #ifdef WIN32 #include #else +#include #include #include #include diff --git a/src/udp.c b/src/udp.c index 58119cd..21730ab 100644 --- a/src/udp.c +++ b/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[] = { @@ -57,8 +62,13 @@ static luaL_reg udp[] = { /* socket options */ static luaL_reg opt[] = { - {"dontroute", opt_dontroute}, - {"broadcast", opt_broadcast}, + {"dontroute", opt_dontroute}, + {"broadcast", opt_broadcast}, + {"reuseaddr", opt_reuseaddr}, + {"ip-multicast-ttl", opt_ip_multicast_ttl}, + {"ip-multicast-loop", opt_ip_multicast_loop}, + {"ip-add-membership", opt_ip_add_membership}, + {"ip-drop-membership", opt_ip_drop_membersip}, {NULL, NULL} }; @@ -244,11 +254,72 @@ static int opt_dontroute(lua_State *L) return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); } +static int opt_reuseaddr(lua_State *L) +{ + return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); +} + static int opt_broadcast(lua_State *L) { return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); } +static int opt_ip_multicast_loop(lua_State *L) +{ + return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +static int opt_ip_multicast_ttl(lua_State *L) +{ + p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); + int val = (int) luaL_checknumber(L, 2); + if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, + (char *) &val, sizeof(val)) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_membership(lua_State *L, int level, int name) +{ + p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); + struct ip_mreq val; + if (!lua_istable(L, 2)) + luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 2); + if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field"); + if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 2); + if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field"); + val.imr_interface.s_addr = htonl(INADDR_ANY); + if (strcmp(lua_tostring(L, -1), "*") && + !inet_aton(lua_tostring(L, -1), &val.imr_interface)) + luaL_argerror(L, 3, "invalid 'interface' ip address"); + if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_ip_add_membership(lua_State *L) +{ + return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP); +} + +static int opt_ip_drop_membersip(lua_State *L) +{ + return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP); +} + /*-------------------------------------------------------------------------*\ * Just call tm methods \*-------------------------------------------------------------------------*/ diff --git a/src/usocket.c b/src/usocket.c index f2d9f01..89be85e 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -145,7 +145,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, else return IO_TIMEOUT; /* here we know the connection has been closed */ } else return IO_CLOSED; - /* here we sent successfully sent something */ + /* here we successfully sent something */ } else { *sent = put; return IO_DONE; @@ -159,34 +159,36 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - ssize_t put = 0; - int err; + ssize_t put; int ret; + /* avoid making system calls on closed sockets */ if (sock == SOCK_INVALID) return IO_CLOSED; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - put = sendto(sock, data, count, 0, addr, addr_len); - if (put <= 0) { - err = IO_CLOSED; -#ifdef __CYGWIN__ - /* this is for CYGWIN, which is like Unix but has Win32 bugs */ - if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE; -#endif - *sent = 0; - } else { - *sent = put; - err = IO_DONE; - } - return err; - } else { + /* make sure we repeat in case the call was interrupted */ + do put = sendto(sock, data, count, 0, addr, addr_len); + while (put <= 0 && errno == EINTR); + /* deal with failure */ + if (put <= 0) { + /* in any case, nothing has been sent */ *sent = 0; - return IO_TIMEOUT; + /* run select to avoid busy wait */ + if (errno != EPIPE) { + struct timeval tv; + fd_set fds; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); + /* tell the caller to call us again because there is more data */ + if (ret > 0) return IO_DONE; + /* tell the caller there was no data before timeout */ + else return IO_TIMEOUT; + /* here we know the connection has been closed */ + } else return IO_CLOSED; + /* here we successfully sent something */ + } else { + *sent = put; + return IO_DONE; } } @@ -232,28 +234,26 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - int ret; + ssize_t taken; if (sock == SOCK_INVALID) return IO_CLOSED; - ssize_t taken = 0; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - taken = recvfrom(sock, data, count, 0, addr, addr_len); - if (taken <= 0) { - *got = 0; - return IO_CLOSED; - } else { - *got = taken; - return IO_DONE; - } - } else { + do taken = recvfrom(sock, data, count, 0, addr, addr_len); + while (taken <= 0 && errno == EINTR); + if (taken <= 0) { + struct timeval tv; + fd_set fds; + int ret; *got = 0; - return IO_TIMEOUT; + if (taken == 0) return IO_CLOSED; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + if (ret > 0) return IO_DONE; + else return IO_TIMEOUT; + } else { + *got = taken; + return IO_DONE; } } diff --git a/src/wsocket.c b/src/wsocket.c index 59d88df..30208b9 100644 --- a/src/wsocket.c +++ b/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; - struct timeval tv; - fd_set fds; - ssize_t put = 0; - if (sock == SOCK_INVALID) return IO_CLOSED; - int err; + ssize_t put; int ret; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - put = send(sock, data, count, 0); - if (put <= 0) { - /* a bug in WinSock forces us to do a busy wait until we manage - ** to write, because select returns immediately even though it - ** should have blocked us until we could write... */ - if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; - else err = IO_CLOSED; - *sent = 0; - } else { - *sent = put; - err = IO_DONE; - } - return err; - } else { + /* avoid making system calls on closed sockets */ + if (sock == SOCK_INVALID) return IO_CLOSED; + /* try to send something */ + put = send(sock, data, (int) count, 0); + /* deal with failure */ + if (put <= 0) { + /* in any case, nothing has been sent */ *sent = 0; - return IO_TIMEOUT; + /* run select to avoid busy wait */ + if (WSAGetLastError() == WSAEWOULDBLOCK) { + struct timeval tv; + fd_set fds; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); + /* tell the caller to call us again because there is more data */ + if (ret > 0) return IO_DONE; + /* tell the caller there was no data before timeout */ + else return IO_TIMEOUT; + /* here we know the connection has been closed */ + } else return IO_CLOSED; + /* here we successfully sent something */ + } else { + *sent = put; + return IO_DONE; } } @@ -154,34 +155,35 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - ssize_t put = 0; - int err; + ssize_t put; int ret; + /* avoid making system calls on closed sockets */ if (sock == SOCK_INVALID) return IO_CLOSED; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - put = sendto(sock, data, count, 0, addr, addr_len); - if (put <= 0) { - /* a bug in WinSock forces us to do a busy wait until we manage - ** to write, because select returns immediately even though it - ** should have blocked us until we could write... */ - if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; - else err = IO_CLOSED; - *sent = 0; - } else { - *sent = put; - err = IO_DONE; - } - return err; - } else { + /* try to send something */ + put = sendto(sock, data, (int) count, 0, addr, addr_len); + /* deal with failure */ + if (put <= 0) { + /* in any case, nothing has been sent */ *sent = 0; - return IO_TIMEOUT; + /* run select to avoid busy wait */ + if (WSAGetLastError() == WSAEWOULDBLOCK) { + struct timeval tv; + fd_set fds; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); + /* tell the caller to call us again because there is more data */ + if (ret > 0) return IO_DONE; + /* tell the caller there was no data before timeout */ + else return IO_TIMEOUT; + /* here we know the connection has been closed */ + } else return IO_CLOSED; + /* here we successfully sent something */ + } else { + *sent = put; + return IO_DONE; } } @@ -191,28 +193,25 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - int ret; - ssize_t taken = 0; + ssize_t taken; if (sock == SOCK_INVALID) return IO_CLOSED; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - taken = recv(sock, data, count, 0); - if (taken <= 0) { - *got = 0; - return IO_CLOSED; - } else { - *got = taken; - return IO_DONE; - } - } else { + taken = recv(sock, data, (int) count, 0); + if (taken <= 0) { + struct timeval tv; + fd_set fds; + int ret; *got = 0; - return IO_TIMEOUT; + if (taken == 0) return IO_CLOSED; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + if (ret > 0) return IO_DONE; + else return IO_TIMEOUT; + } else { + *got = taken; + return IO_DONE; } } @@ -223,28 +222,25 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - int ret; - ssize_t taken = 0; + ssize_t taken; if (sock == SOCK_INVALID) return IO_CLOSED; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - taken = recvfrom(sock, data, count, 0, addr, addr_len); - if (taken <= 0) { - *got = 0; - return IO_CLOSED; - } else { - *got = taken; - return IO_DONE; - } - } else { + taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); + if (taken <= 0) { + struct timeval tv; + fd_set fds; + int ret; *got = 0; - return IO_TIMEOUT; + if (taken == 0) return IO_CLOSED; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + if (ret > 0) return IO_DONE; + else return IO_TIMEOUT; + } else { + *got = taken; + return IO_DONE; } } -- cgit v1.2.3-55-g6feb