diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/inet.h | 4 | ||||
| -rw-r--r-- | src/luasocket.h | 2 | ||||
| -rw-r--r-- | src/tcp.c | 18 | ||||
| -rw-r--r-- | src/timeout.c | 1 | ||||
| -rw-r--r-- | src/udp.c | 75 | ||||
| -rw-r--r-- | src/usocket.c | 92 | ||||
| -rw-r--r-- | src/wsocket.c | 180 |
7 files changed, 224 insertions, 148 deletions
| @@ -19,6 +19,10 @@ | |||
| 19 | #include <lua.h> | 19 | #include <lua.h> |
| 20 | #include "socket.h" | 20 | #include "socket.h" |
| 21 | 21 | ||
| 22 | #ifdef WIN32 | ||
| 23 | #define INET_ATON | ||
| 24 | #endif | ||
| 25 | |||
| 22 | void inet_open(lua_State *L); | 26 | void inet_open(lua_State *L); |
| 23 | const char *inet_tryconnect(p_sock ps, const char *address, | 27 | const char *inet_tryconnect(p_sock ps, const char *address, |
| 24 | unsigned short port); | 28 | 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 @@ | |||
| 18 | /*-------------------------------------------------------------------------*\ | 18 | /*-------------------------------------------------------------------------*\ |
| 19 | * Library's namespace | 19 | * Library's namespace |
| 20 | \*-------------------------------------------------------------------------*/ | 20 | \*-------------------------------------------------------------------------*/ |
| 21 | #ifndef LUASOCKET_LIBNAME | ||
| 21 | #define LUASOCKET_LIBNAME "socket" | 22 | #define LUASOCKET_LIBNAME "socket" |
| 23 | #endif | ||
| 22 | 24 | ||
| 23 | /*-------------------------------------------------------------------------*\ | 25 | /*-------------------------------------------------------------------------*\ |
| 24 | * This macro prefixes all exported API functions | 26 | * This macro prefixes all exported API functions |
| @@ -36,6 +36,7 @@ static int meth_dirty(lua_State *L); | |||
| 36 | static int opt_tcp_nodelay(lua_State *L); | 36 | static int opt_tcp_nodelay(lua_State *L); |
| 37 | static int opt_keepalive(lua_State *L); | 37 | static int opt_keepalive(lua_State *L); |
| 38 | static int opt_linger(lua_State *L); | 38 | static int opt_linger(lua_State *L); |
| 39 | static int opt_reuseaddr(lua_State *L); | ||
| 39 | 40 | ||
| 40 | /* tcp object methods */ | 41 | /* tcp object methods */ |
| 41 | static luaL_reg tcp[] = { | 42 | static luaL_reg tcp[] = { |
| @@ -61,6 +62,7 @@ static luaL_reg tcp[] = { | |||
| 61 | /* socket option handlers */ | 62 | /* socket option handlers */ |
| 62 | static luaL_reg opt[] = { | 63 | static luaL_reg opt[] = { |
| 63 | {"keepalive", opt_keepalive}, | 64 | {"keepalive", opt_keepalive}, |
| 65 | {"reuseaddr", opt_reuseaddr}, | ||
| 64 | {"tcp-nodelay", opt_tcp_nodelay}, | 66 | {"tcp-nodelay", opt_tcp_nodelay}, |
| 65 | {"linger", opt_linger}, | 67 | {"linger", opt_linger}, |
| 66 | {NULL, NULL} | 68 | {NULL, NULL} |
| @@ -123,7 +125,7 @@ static int meth_setoption(lua_State *L) | |||
| 123 | 125 | ||
| 124 | static int opt_boolean(lua_State *L, int level, int name) | 126 | static int opt_boolean(lua_State *L, int level, int name) |
| 125 | { | 127 | { |
| 126 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client,server}", 1); | 128 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); |
| 127 | int val = aux_checkboolean(L, 2); | 129 | int val = aux_checkboolean(L, 2); |
| 128 | if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | 130 | if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { |
| 129 | lua_pushnil(L); | 131 | lua_pushnil(L); |
| @@ -134,16 +136,16 @@ static int opt_boolean(lua_State *L, int level, int name) | |||
| 134 | return 1; | 136 | return 1; |
| 135 | } | 137 | } |
| 136 | 138 | ||
| 139 | /* enables reuse of local address */ | ||
| 140 | static int opt_reuseaddr(lua_State *L) | ||
| 141 | { | ||
| 142 | return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); | ||
| 143 | } | ||
| 144 | |||
| 137 | /* disables the Naggle algorithm */ | 145 | /* disables the Naggle algorithm */ |
| 138 | static int opt_tcp_nodelay(lua_State *L) | 146 | static int opt_tcp_nodelay(lua_State *L) |
| 139 | { | 147 | { |
| 140 | struct protoent *pe = getprotobyname("TCP"); | 148 | return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY); |
| 141 | if (!pe) { | ||
| 142 | lua_pushnil(L); | ||
| 143 | lua_pushstring(L, "getprotobyname"); | ||
| 144 | return 2; | ||
| 145 | } | ||
| 146 | return opt_boolean(L, pe->p_proto, TCP_NODELAY); | ||
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | static int opt_keepalive(lua_State *L) | 151 | 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 @@ | |||
| 16 | #ifdef WIN32 | 16 | #ifdef WIN32 |
| 17 | #include <windows.h> | 17 | #include <windows.h> |
| 18 | #else | 18 | #else |
| 19 | #include <time.h> | ||
| 19 | #include <sys/time.h> | 20 | #include <sys/time.h> |
| 20 | #include <sys/times.h> | 21 | #include <sys/times.h> |
| 21 | #include <unistd.h> | 22 | #include <unistd.h> |
| @@ -35,6 +35,11 @@ static int meth_fd(lua_State *L); | |||
| 35 | static int meth_dirty(lua_State *L); | 35 | static int meth_dirty(lua_State *L); |
| 36 | static int opt_dontroute(lua_State *L); | 36 | static int opt_dontroute(lua_State *L); |
| 37 | static int opt_broadcast(lua_State *L); | 37 | static int opt_broadcast(lua_State *L); |
| 38 | static int opt_reuseaddr(lua_State *L); | ||
| 39 | static int opt_ip_multicast_ttl(lua_State *L); | ||
| 40 | static int opt_ip_multicast_loop(lua_State *L); | ||
| 41 | static int opt_ip_add_membership(lua_State *L); | ||
| 42 | static int opt_ip_drop_membersip(lua_State *L); | ||
| 38 | 43 | ||
| 39 | /* udp object methods */ | 44 | /* udp object methods */ |
| 40 | static luaL_reg udp[] = { | 45 | static luaL_reg udp[] = { |
| @@ -57,8 +62,13 @@ static luaL_reg udp[] = { | |||
| 57 | 62 | ||
| 58 | /* socket options */ | 63 | /* socket options */ |
| 59 | static luaL_reg opt[] = { | 64 | static luaL_reg opt[] = { |
| 60 | {"dontroute", opt_dontroute}, | 65 | {"dontroute", opt_dontroute}, |
| 61 | {"broadcast", opt_broadcast}, | 66 | {"broadcast", opt_broadcast}, |
| 67 | {"reuseaddr", opt_reuseaddr}, | ||
| 68 | {"ip-multicast-ttl", opt_ip_multicast_ttl}, | ||
| 69 | {"ip-multicast-loop", opt_ip_multicast_loop}, | ||
| 70 | {"ip-add-membership", opt_ip_add_membership}, | ||
| 71 | {"ip-drop-membership", opt_ip_drop_membersip}, | ||
| 62 | {NULL, NULL} | 72 | {NULL, NULL} |
| 63 | }; | 73 | }; |
| 64 | 74 | ||
| @@ -244,11 +254,72 @@ static int opt_dontroute(lua_State *L) | |||
| 244 | return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); | 254 | return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); |
| 245 | } | 255 | } |
| 246 | 256 | ||
| 257 | static int opt_reuseaddr(lua_State *L) | ||
| 258 | { | ||
| 259 | return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); | ||
| 260 | } | ||
| 261 | |||
| 247 | static int opt_broadcast(lua_State *L) | 262 | static int opt_broadcast(lua_State *L) |
| 248 | { | 263 | { |
| 249 | return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); | 264 | return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); |
| 250 | } | 265 | } |
| 251 | 266 | ||
| 267 | static int opt_ip_multicast_loop(lua_State *L) | ||
| 268 | { | ||
| 269 | return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP); | ||
| 270 | } | ||
| 271 | |||
| 272 | static int opt_ip_multicast_ttl(lua_State *L) | ||
| 273 | { | ||
| 274 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
| 275 | int val = (int) luaL_checknumber(L, 2); | ||
| 276 | if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, | ||
| 277 | (char *) &val, sizeof(val)) < 0) { | ||
| 278 | lua_pushnil(L); | ||
| 279 | lua_pushstring(L, "setsockopt failed"); | ||
| 280 | return 2; | ||
| 281 | } | ||
| 282 | lua_pushnumber(L, 1); | ||
| 283 | return 1; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int opt_membership(lua_State *L, int level, int name) | ||
| 287 | { | ||
| 288 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
| 289 | struct ip_mreq val; | ||
| 290 | if (!lua_istable(L, 2)) | ||
| 291 | luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); | ||
| 292 | lua_pushstring(L, "multiaddr"); | ||
| 293 | lua_gettable(L, 2); | ||
| 294 | if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field"); | ||
| 295 | if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) | ||
| 296 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
| 297 | lua_pushstring(L, "interface"); | ||
| 298 | lua_gettable(L, 2); | ||
| 299 | if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field"); | ||
| 300 | val.imr_interface.s_addr = htonl(INADDR_ANY); | ||
| 301 | if (strcmp(lua_tostring(L, -1), "*") && | ||
| 302 | !inet_aton(lua_tostring(L, -1), &val.imr_interface)) | ||
| 303 | luaL_argerror(L, 3, "invalid 'interface' ip address"); | ||
| 304 | if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | ||
| 305 | lua_pushnil(L); | ||
| 306 | lua_pushstring(L, "setsockopt failed"); | ||
| 307 | return 2; | ||
| 308 | } | ||
| 309 | lua_pushnumber(L, 1); | ||
| 310 | return 1; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int opt_ip_add_membership(lua_State *L) | ||
| 314 | { | ||
| 315 | return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP); | ||
| 316 | } | ||
| 317 | |||
| 318 | static int opt_ip_drop_membersip(lua_State *L) | ||
| 319 | { | ||
| 320 | return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP); | ||
| 321 | } | ||
| 322 | |||
| 252 | /*-------------------------------------------------------------------------*\ | 323 | /*-------------------------------------------------------------------------*\ |
| 253 | * Just call tm methods | 324 | * Just call tm methods |
| 254 | \*-------------------------------------------------------------------------*/ | 325 | \*-------------------------------------------------------------------------*/ |
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, | |||
| 145 | else return IO_TIMEOUT; | 145 | else return IO_TIMEOUT; |
| 146 | /* here we know the connection has been closed */ | 146 | /* here we know the connection has been closed */ |
| 147 | } else return IO_CLOSED; | 147 | } else return IO_CLOSED; |
| 148 | /* here we sent successfully sent something */ | 148 | /* here we successfully sent something */ |
| 149 | } else { | 149 | } else { |
| 150 | *sent = put; | 150 | *sent = put; |
| 151 | return IO_DONE; | 151 | return IO_DONE; |
| @@ -159,34 +159,36 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 159 | SA *addr, socklen_t addr_len, int timeout) | 159 | SA *addr, socklen_t addr_len, int timeout) |
| 160 | { | 160 | { |
| 161 | t_sock sock = *ps; | 161 | t_sock sock = *ps; |
| 162 | struct timeval tv; | 162 | ssize_t put; |
| 163 | fd_set fds; | ||
| 164 | ssize_t put = 0; | ||
| 165 | int err; | ||
| 166 | int ret; | 163 | int ret; |
| 164 | /* avoid making system calls on closed sockets */ | ||
| 167 | if (sock == SOCK_INVALID) return IO_CLOSED; | 165 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 168 | tv.tv_sec = timeout / 1000; | 166 | /* make sure we repeat in case the call was interrupted */ |
| 169 | tv.tv_usec = (timeout % 1000) * 1000; | 167 | do put = sendto(sock, data, count, 0, addr, addr_len); |
| 170 | FD_ZERO(&fds); | 168 | while (put <= 0 && errno == EINTR); |
| 171 | FD_SET(sock, &fds); | 169 | /* deal with failure */ |
| 172 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 170 | if (put <= 0) { |
| 173 | if (ret > 0) { | 171 | /* in any case, nothing has been sent */ |
| 174 | put = sendto(sock, data, count, 0, addr, addr_len); | ||
| 175 | if (put <= 0) { | ||
| 176 | err = IO_CLOSED; | ||
| 177 | #ifdef __CYGWIN__ | ||
| 178 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ | ||
| 179 | if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE; | ||
| 180 | #endif | ||
| 181 | *sent = 0; | ||
| 182 | } else { | ||
| 183 | *sent = put; | ||
| 184 | err = IO_DONE; | ||
| 185 | } | ||
| 186 | return err; | ||
| 187 | } else { | ||
| 188 | *sent = 0; | 172 | *sent = 0; |
| 189 | return IO_TIMEOUT; | 173 | /* run select to avoid busy wait */ |
| 174 | if (errno != EPIPE) { | ||
| 175 | struct timeval tv; | ||
| 176 | fd_set fds; | ||
| 177 | tv.tv_sec = timeout / 1000; | ||
| 178 | tv.tv_usec = (timeout % 1000) * 1000; | ||
| 179 | FD_ZERO(&fds); | ||
| 180 | FD_SET(sock, &fds); | ||
| 181 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | ||
| 182 | /* tell the caller to call us again because there is more data */ | ||
| 183 | if (ret > 0) return IO_DONE; | ||
| 184 | /* tell the caller there was no data before timeout */ | ||
| 185 | else return IO_TIMEOUT; | ||
| 186 | /* here we know the connection has been closed */ | ||
| 187 | } else return IO_CLOSED; | ||
| 188 | /* here we successfully sent something */ | ||
| 189 | } else { | ||
| 190 | *sent = put; | ||
| 191 | return IO_DONE; | ||
| 190 | } | 192 | } |
| 191 | } | 193 | } |
| 192 | 194 | ||
| @@ -232,28 +234,26 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
| 232 | SA *addr, socklen_t *addr_len, int timeout) | 234 | SA *addr, socklen_t *addr_len, int timeout) |
| 233 | { | 235 | { |
| 234 | t_sock sock = *ps; | 236 | t_sock sock = *ps; |
| 235 | struct timeval tv; | 237 | ssize_t taken; |
| 236 | fd_set fds; | ||
| 237 | int ret; | ||
| 238 | if (sock == SOCK_INVALID) return IO_CLOSED; | 238 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 239 | ssize_t taken = 0; | 239 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); |
| 240 | tv.tv_sec = timeout / 1000; | 240 | while (taken <= 0 && errno == EINTR); |
| 241 | tv.tv_usec = (timeout % 1000) * 1000; | 241 | if (taken <= 0) { |
| 242 | FD_ZERO(&fds); | 242 | struct timeval tv; |
| 243 | FD_SET(sock, &fds); | 243 | fd_set fds; |
| 244 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 244 | int ret; |
| 245 | if (ret > 0) { | ||
| 246 | taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
| 247 | if (taken <= 0) { | ||
| 248 | *got = 0; | ||
| 249 | return IO_CLOSED; | ||
| 250 | } else { | ||
| 251 | *got = taken; | ||
| 252 | return IO_DONE; | ||
| 253 | } | ||
| 254 | } else { | ||
| 255 | *got = 0; | 245 | *got = 0; |
| 256 | return IO_TIMEOUT; | 246 | if (taken == 0) return IO_CLOSED; |
| 247 | tv.tv_sec = timeout / 1000; | ||
| 248 | tv.tv_usec = (timeout % 1000) * 1000; | ||
| 249 | FD_ZERO(&fds); | ||
| 250 | FD_SET(sock, &fds); | ||
| 251 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
| 252 | if (ret > 0) return IO_DONE; | ||
| 253 | else return IO_TIMEOUT; | ||
| 254 | } else { | ||
| 255 | *got = taken; | ||
| 256 | return IO_DONE; | ||
| 257 | } | 257 | } |
| 258 | } | 258 | } |
| 259 | 259 | ||
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, | |||
| 100 | FD_ZERO(&fds); | 100 | FD_ZERO(&fds); |
| 101 | FD_SET(sock, &fds); | 101 | FD_SET(sock, &fds); |
| 102 | *pa = SOCK_INVALID; | 102 | *pa = SOCK_INVALID; |
| 103 | if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) | 103 | if (select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) |
| 104 | return IO_TIMEOUT; | 104 | return IO_TIMEOUT; |
| 105 | if (!addr) addr = &dummy_addr; | 105 | if (!addr) addr = &dummy_addr; |
| 106 | if (!addr_len) addr_len = &dummy_len; | 106 | 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, | |||
| 116 | int timeout) | 116 | int timeout) |
| 117 | { | 117 | { |
| 118 | t_sock sock = *ps; | 118 | t_sock sock = *ps; |
| 119 | struct timeval tv; | 119 | ssize_t put; |
| 120 | fd_set fds; | ||
| 121 | ssize_t put = 0; | ||
| 122 | if (sock == SOCK_INVALID) return IO_CLOSED; | ||
| 123 | int err; | ||
| 124 | int ret; | 120 | int ret; |
| 125 | tv.tv_sec = timeout / 1000; | 121 | /* avoid making system calls on closed sockets */ |
| 126 | tv.tv_usec = (timeout % 1000) * 1000; | 122 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 127 | FD_ZERO(&fds); | 123 | /* try to send something */ |
| 128 | FD_SET(sock, &fds); | 124 | put = send(sock, data, (int) count, 0); |
| 129 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 125 | /* deal with failure */ |
| 130 | if (ret > 0) { | 126 | if (put <= 0) { |
| 131 | put = send(sock, data, count, 0); | 127 | /* in any case, nothing has been sent */ |
| 132 | if (put <= 0) { | ||
| 133 | /* a bug in WinSock forces us to do a busy wait until we manage | ||
| 134 | ** to write, because select returns immediately even though it | ||
| 135 | ** should have blocked us until we could write... */ | ||
| 136 | if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; | ||
| 137 | else err = IO_CLOSED; | ||
| 138 | *sent = 0; | ||
| 139 | } else { | ||
| 140 | *sent = put; | ||
| 141 | err = IO_DONE; | ||
| 142 | } | ||
| 143 | return err; | ||
| 144 | } else { | ||
| 145 | *sent = 0; | 128 | *sent = 0; |
| 146 | return IO_TIMEOUT; | 129 | /* run select to avoid busy wait */ |
| 130 | if (WSAGetLastError() == WSAEWOULDBLOCK) { | ||
| 131 | struct timeval tv; | ||
| 132 | fd_set fds; | ||
| 133 | tv.tv_sec = timeout / 1000; | ||
| 134 | tv.tv_usec = (timeout % 1000) * 1000; | ||
| 135 | FD_ZERO(&fds); | ||
| 136 | FD_SET(sock, &fds); | ||
| 137 | ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | ||
| 138 | /* tell the caller to call us again because there is more data */ | ||
| 139 | if (ret > 0) return IO_DONE; | ||
| 140 | /* tell the caller there was no data before timeout */ | ||
| 141 | else return IO_TIMEOUT; | ||
| 142 | /* here we know the connection has been closed */ | ||
| 143 | } else return IO_CLOSED; | ||
| 144 | /* here we successfully sent something */ | ||
| 145 | } else { | ||
| 146 | *sent = put; | ||
| 147 | return IO_DONE; | ||
| 147 | } | 148 | } |
| 148 | } | 149 | } |
| 149 | 150 | ||
| @@ -154,34 +155,35 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 154 | SA *addr, socklen_t addr_len, int timeout) | 155 | SA *addr, socklen_t addr_len, int timeout) |
| 155 | { | 156 | { |
| 156 | t_sock sock = *ps; | 157 | t_sock sock = *ps; |
| 157 | struct timeval tv; | 158 | ssize_t put; |
| 158 | fd_set fds; | ||
| 159 | ssize_t put = 0; | ||
| 160 | int err; | ||
| 161 | int ret; | 159 | int ret; |
| 160 | /* avoid making system calls on closed sockets */ | ||
| 162 | if (sock == SOCK_INVALID) return IO_CLOSED; | 161 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 163 | tv.tv_sec = timeout / 1000; | 162 | /* try to send something */ |
| 164 | tv.tv_usec = (timeout % 1000) * 1000; | 163 | put = sendto(sock, data, (int) count, 0, addr, addr_len); |
| 165 | FD_ZERO(&fds); | 164 | /* deal with failure */ |
| 166 | FD_SET(sock, &fds); | 165 | if (put <= 0) { |
| 167 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 166 | /* in any case, nothing has been sent */ |
| 168 | if (ret > 0) { | ||
| 169 | put = sendto(sock, data, count, 0, addr, addr_len); | ||
| 170 | if (put <= 0) { | ||
| 171 | /* a bug in WinSock forces us to do a busy wait until we manage | ||
| 172 | ** to write, because select returns immediately even though it | ||
| 173 | ** should have blocked us until we could write... */ | ||
| 174 | if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; | ||
| 175 | else err = IO_CLOSED; | ||
| 176 | *sent = 0; | ||
| 177 | } else { | ||
| 178 | *sent = put; | ||
| 179 | err = IO_DONE; | ||
| 180 | } | ||
| 181 | return err; | ||
| 182 | } else { | ||
| 183 | *sent = 0; | 167 | *sent = 0; |
| 184 | return IO_TIMEOUT; | 168 | /* run select to avoid busy wait */ |
| 169 | if (WSAGetLastError() == WSAEWOULDBLOCK) { | ||
| 170 | struct timeval tv; | ||
| 171 | fd_set fds; | ||
| 172 | tv.tv_sec = timeout / 1000; | ||
| 173 | tv.tv_usec = (timeout % 1000) * 1000; | ||
| 174 | FD_ZERO(&fds); | ||
| 175 | FD_SET(sock, &fds); | ||
| 176 | ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | ||
| 177 | /* tell the caller to call us again because there is more data */ | ||
| 178 | if (ret > 0) return IO_DONE; | ||
| 179 | /* tell the caller there was no data before timeout */ | ||
| 180 | else return IO_TIMEOUT; | ||
| 181 | /* here we know the connection has been closed */ | ||
| 182 | } else return IO_CLOSED; | ||
| 183 | /* here we successfully sent something */ | ||
| 184 | } else { | ||
| 185 | *sent = put; | ||
| 186 | return IO_DONE; | ||
| 185 | } | 187 | } |
| 186 | } | 188 | } |
| 187 | 189 | ||
| @@ -191,28 +193,25 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 191 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 193 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
| 192 | { | 194 | { |
| 193 | t_sock sock = *ps; | 195 | t_sock sock = *ps; |
| 194 | struct timeval tv; | 196 | ssize_t taken; |
| 195 | fd_set fds; | ||
| 196 | int ret; | ||
| 197 | ssize_t taken = 0; | ||
| 198 | if (sock == SOCK_INVALID) return IO_CLOSED; | 197 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 199 | tv.tv_sec = timeout / 1000; | 198 | taken = recv(sock, data, (int) count, 0); |
| 200 | tv.tv_usec = (timeout % 1000) * 1000; | 199 | if (taken <= 0) { |
| 201 | FD_ZERO(&fds); | 200 | struct timeval tv; |
| 202 | FD_SET(sock, &fds); | 201 | fd_set fds; |
| 203 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 202 | int ret; |
| 204 | if (ret > 0) { | ||
| 205 | taken = recv(sock, data, count, 0); | ||
| 206 | if (taken <= 0) { | ||
| 207 | *got = 0; | ||
| 208 | return IO_CLOSED; | ||
| 209 | } else { | ||
| 210 | *got = taken; | ||
| 211 | return IO_DONE; | ||
| 212 | } | ||
| 213 | } else { | ||
| 214 | *got = 0; | 203 | *got = 0; |
| 215 | return IO_TIMEOUT; | 204 | if (taken == 0) return IO_CLOSED; |
| 205 | tv.tv_sec = timeout / 1000; | ||
| 206 | tv.tv_usec = (timeout % 1000) * 1000; | ||
| 207 | FD_ZERO(&fds); | ||
| 208 | FD_SET(sock, &fds); | ||
| 209 | ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
| 210 | if (ret > 0) return IO_DONE; | ||
| 211 | else return IO_TIMEOUT; | ||
| 212 | } else { | ||
| 213 | *got = taken; | ||
| 214 | return IO_DONE; | ||
| 216 | } | 215 | } |
| 217 | } | 216 | } |
| 218 | 217 | ||
| @@ -223,28 +222,25 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
| 223 | SA *addr, socklen_t *addr_len, int timeout) | 222 | SA *addr, socklen_t *addr_len, int timeout) |
| 224 | { | 223 | { |
| 225 | t_sock sock = *ps; | 224 | t_sock sock = *ps; |
| 226 | struct timeval tv; | 225 | ssize_t taken; |
| 227 | fd_set fds; | ||
| 228 | int ret; | ||
| 229 | ssize_t taken = 0; | ||
| 230 | if (sock == SOCK_INVALID) return IO_CLOSED; | 226 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 231 | tv.tv_sec = timeout / 1000; | 227 | taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); |
| 232 | tv.tv_usec = (timeout % 1000) * 1000; | 228 | if (taken <= 0) { |
| 233 | FD_ZERO(&fds); | 229 | struct timeval tv; |
| 234 | FD_SET(sock, &fds); | 230 | fd_set fds; |
| 235 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 231 | int ret; |
| 236 | if (ret > 0) { | ||
| 237 | taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
| 238 | if (taken <= 0) { | ||
| 239 | *got = 0; | ||
| 240 | return IO_CLOSED; | ||
| 241 | } else { | ||
| 242 | *got = taken; | ||
| 243 | return IO_DONE; | ||
| 244 | } | ||
| 245 | } else { | ||
| 246 | *got = 0; | 232 | *got = 0; |
| 247 | return IO_TIMEOUT; | 233 | if (taken == 0) return IO_CLOSED; |
| 234 | tv.tv_sec = timeout / 1000; | ||
| 235 | tv.tv_usec = (timeout % 1000) * 1000; | ||
| 236 | FD_ZERO(&fds); | ||
| 237 | FD_SET(sock, &fds); | ||
| 238 | ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
| 239 | if (ret > 0) return IO_DONE; | ||
| 240 | else return IO_TIMEOUT; | ||
| 241 | } else { | ||
| 242 | *got = taken; | ||
| 243 | return IO_DONE; | ||
| 248 | } | 244 | } |
| 249 | } | 245 | } |
| 250 | 246 | ||
