diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-21 18:40:52 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-21 18:40:52 +0000 |
| commit | 195069cf5f929f445b0ce20e531cd482d2559083 (patch) | |
| tree | 6444d37c4ce32395428ba26ee0d16c0c372bd9da | |
| parent | e63f500d24ff0238425c9e13f220daf09a277ef5 (diff) | |
| download | luasocket-195069cf5f929f445b0ce20e531cd482d2559083.tar.gz luasocket-195069cf5f929f445b0ce20e531cd482d2559083.tar.bz2 luasocket-195069cf5f929f445b0ce20e531cd482d2559083.zip | |
Fixed functions that return messages in ?socket.c.
Moved complexity of connect and accept there.
Created a new options.c module to take care of options.
Auxiliar.c is now cleaner.
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | src/auxiliar.c | 20 | ||||
| -rw-r--r-- | src/auxiliar.h | 1 | ||||
| -rw-r--r-- | src/inet.c | 56 | ||||
| -rw-r--r-- | src/inet.h | 7 | ||||
| -rw-r--r-- | src/options.c | 137 | ||||
| -rw-r--r-- | src/options.h | 30 | ||||
| -rw-r--r-- | src/socket.h | 21 | ||||
| -rw-r--r-- | src/tcp.c | 82 | ||||
| -rw-r--r-- | src/tcp.h | 1 | ||||
| -rw-r--r-- | src/timeout.c | 3 | ||||
| -rw-r--r-- | src/timeout.h | 2 | ||||
| -rw-r--r-- | src/udp.c | 99 | ||||
| -rw-r--r-- | src/usocket.c | 78 | ||||
| -rw-r--r-- | test/httptest.lua | 5 | ||||
| -rw-r--r-- | test/testclnt.lua | 16 |
16 files changed, 284 insertions, 275 deletions
| @@ -22,6 +22,7 @@ tests | |||
| 22 | trust character constants in mime.c? noooooo. | 22 | trust character constants in mime.c? noooooo. |
| 23 | smtp.lua needs stuff filter | 23 | smtp.lua needs stuff filter |
| 24 | 24 | ||
| 25 | add comments into each C module. | ||
| 25 | new option.c module to put all options (TCP and UDP share...)? | 26 | new option.c module to put all options (TCP and UDP share...)? |
| 26 | testar os options! | 27 | testar os options! |
| 27 | add _tostring methods! | 28 | add _tostring methods! |
diff --git a/src/auxiliar.c b/src/auxiliar.c index 4b3a0f6..6888f9c 100644 --- a/src/auxiliar.c +++ b/src/auxiliar.c | |||
| @@ -66,26 +66,6 @@ int aux_checkboolean(lua_State *L, int objidx) | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | /*-------------------------------------------------------------------------*\ | 68 | /*-------------------------------------------------------------------------*\ |
| 69 | * Calls appropriate option handler | ||
| 70 | \*-------------------------------------------------------------------------*/ | ||
| 71 | int aux_meth_setoption(lua_State *L, luaL_reg *opt) | ||
| 72 | { | ||
| 73 | const char *name = luaL_checkstring(L, 2); /* obj, name, args */ | ||
| 74 | while (opt->name && strcmp(name, opt->name)) | ||
| 75 | opt++; | ||
| 76 | if (!opt->func) { | ||
| 77 | char msg[45]; | ||
| 78 | sprintf(msg, "unknown option `%.35s'", name); | ||
| 79 | luaL_argerror(L, 2, msg); | ||
| 80 | } | ||
| 81 | lua_remove(L, 2); /* obj, args */ | ||
| 82 | lua_pushcfunction(L, opt->func); /* obj, args, func */ | ||
| 83 | lua_insert(L, 1); /* func, obj, args */ | ||
| 84 | lua_call(L, lua_gettop(L)-1, LUA_MULTRET); | ||
| 85 | return lua_gettop(L); | ||
| 86 | } | ||
| 87 | |||
| 88 | /*-------------------------------------------------------------------------*\ | ||
| 89 | * Return userdata pointer if object belongs to a given class, abort with | 69 | * Return userdata pointer if object belongs to a given class, abort with |
| 90 | * error otherwise | 70 | * error otherwise |
| 91 | \*-------------------------------------------------------------------------*/ | 71 | \*-------------------------------------------------------------------------*/ |
diff --git a/src/auxiliar.h b/src/auxiliar.h index 324e800..b98eb9c 100644 --- a/src/auxiliar.h +++ b/src/auxiliar.h | |||
| @@ -48,7 +48,6 @@ void *aux_checkclass(lua_State *L, const char *classname, int objidx); | |||
| 48 | void *aux_checkgroup(lua_State *L, const char *groupname, int objidx); | 48 | void *aux_checkgroup(lua_State *L, const char *groupname, int objidx); |
| 49 | void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); | 49 | void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); |
| 50 | void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); | 50 | void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); |
| 51 | int aux_meth_setoption(lua_State *L, luaL_reg *opt); | ||
| 52 | int aux_checkboolean(lua_State *L, int objidx); | 51 | int aux_checkboolean(lua_State *L, int objidx); |
| 53 | 52 | ||
| 54 | #endif /* AUX_H */ | 53 | #endif /* AUX_H */ |
| @@ -178,13 +178,21 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | /*-------------------------------------------------------------------------*\ | 180 | /*-------------------------------------------------------------------------*\ |
| 181 | * Tries to create a new inet socket | ||
| 182 | \*-------------------------------------------------------------------------*/ | ||
| 183 | const char *inet_trycreate(p_sock ps, int type) | ||
| 184 | { | ||
| 185 | return sock_create(ps, AF_INET, type, 0); | ||
| 186 | } | ||
| 187 | |||
| 188 | /*-------------------------------------------------------------------------*\ | ||
| 181 | * Tries to connect to remote address (address, port) | 189 | * Tries to connect to remote address (address, port) |
| 182 | \*-------------------------------------------------------------------------*/ | 190 | \*-------------------------------------------------------------------------*/ |
| 183 | const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address, | 191 | const char *inet_tryconnect(p_sock ps, const char *address, |
| 184 | unsigned short port) | 192 | unsigned short port, p_tm tm) |
| 185 | { | 193 | { |
| 186 | struct sockaddr_in remote; | 194 | struct sockaddr_in remote; |
| 187 | int err; | 195 | const char *err; |
| 188 | memset(&remote, 0, sizeof(remote)); | 196 | memset(&remote, 0, sizeof(remote)); |
| 189 | remote.sin_family = AF_INET; | 197 | remote.sin_family = AF_INET; |
| 190 | remote.sin_port = htons(port); | 198 | remote.sin_port = htons(port); |
| @@ -197,14 +205,9 @@ const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address, | |||
| 197 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); | 205 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); |
| 198 | } | 206 | } |
| 199 | } else remote.sin_family = AF_UNSPEC; | 207 | } else remote.sin_family = AF_UNSPEC; |
| 200 | do err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm_getretry(tm)); | 208 | err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm); |
| 201 | while (err == IO_RETRY && tm_getretry(tm)); | 209 | if (err) sock_destroy(ps); |
| 202 | if (err != IO_DONE) { | 210 | return err; |
| 203 | sock_destroy(ps); | ||
| 204 | *ps = SOCK_INVALID; | ||
| 205 | if (err == IO_ERROR) return sock_connectstrerror(); | ||
| 206 | else return io_strerror(err); | ||
| 207 | } else return NULL; | ||
| 208 | } | 211 | } |
| 209 | 212 | ||
| 210 | /*-------------------------------------------------------------------------*\ | 213 | /*-------------------------------------------------------------------------*\ |
| @@ -214,6 +217,7 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port, | |||
| 214 | int backlog) | 217 | int backlog) |
| 215 | { | 218 | { |
| 216 | struct sockaddr_in local; | 219 | struct sockaddr_in local; |
| 220 | const char *err; | ||
| 217 | memset(&local, 0, sizeof(local)); | 221 | memset(&local, 0, sizeof(local)); |
| 218 | /* address is either wildcard or a valid ip address */ | 222 | /* address is either wildcard or a valid ip address */ |
| 219 | local.sin_addr.s_addr = htonl(INADDR_ANY); | 223 | local.sin_addr.s_addr = htonl(INADDR_ANY); |
| @@ -228,10 +232,10 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port, | |||
| 228 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); | 232 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); |
| 229 | } | 233 | } |
| 230 | sock_setblocking(ps); | 234 | sock_setblocking(ps); |
| 231 | if (sock_bind(ps, (SA *) &local, sizeof(local)) != IO_DONE) { | 235 | err = sock_bind(ps, (SA *) &local, sizeof(local)); |
| 236 | if (err) { | ||
| 232 | sock_destroy(ps); | 237 | sock_destroy(ps); |
| 233 | *ps = SOCK_INVALID; | 238 | return err; |
| 234 | return sock_bindstrerror(); | ||
| 235 | } else { | 239 | } else { |
| 236 | sock_setnonblocking(ps); | 240 | sock_setnonblocking(ps); |
| 237 | if (backlog >= 0) sock_listen(ps, backlog); | 241 | if (backlog >= 0) sock_listen(ps, backlog); |
| @@ -240,30 +244,6 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port, | |||
| 240 | } | 244 | } |
| 241 | 245 | ||
| 242 | /*-------------------------------------------------------------------------*\ | 246 | /*-------------------------------------------------------------------------*\ |
| 243 | * Tries to create a new inet socket | ||
| 244 | \*-------------------------------------------------------------------------*/ | ||
| 245 | const char *inet_trycreate(p_sock ps, int type) | ||
| 246 | { | ||
| 247 | if (sock_create(ps, AF_INET, type, 0) == IO_DONE) return NULL; | ||
| 248 | else return sock_createstrerror(); | ||
| 249 | } | ||
| 250 | |||
| 251 | /*-------------------------------------------------------------------------*\ | ||
| 252 | * Tries to accept an inet socket | ||
| 253 | \*-------------------------------------------------------------------------*/ | ||
| 254 | const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc) | ||
| 255 | { | ||
| 256 | struct sockaddr_in addr; | ||
| 257 | socklen_t addr_len = sizeof(addr); | ||
| 258 | int err; | ||
| 259 | /* loop until connection accepted or timeout happens */ | ||
| 260 | do err = sock_accept(ps, pc, (SA *) &addr, &addr_len, tm_getretry(tm)); | ||
| 261 | while (err == IO_RETRY && tm_getretry(tm) != 0); | ||
| 262 | if (err == IO_RETRY) err = IO_TIMEOUT; | ||
| 263 | return io_strerror(err); | ||
| 264 | } | ||
| 265 | |||
| 266 | /*-------------------------------------------------------------------------*\ | ||
| 267 | * Some systems do not provide this so that we provide our own. It's not | 247 | * Some systems do not provide this so that we provide our own. It's not |
| 268 | * marvelously fast, but it works just fine. | 248 | * marvelously fast, but it works just fine. |
| 269 | \*-------------------------------------------------------------------------*/ | 249 | \*-------------------------------------------------------------------------*/ |
| @@ -26,12 +26,11 @@ | |||
| 26 | 26 | ||
| 27 | void inet_open(lua_State *L); | 27 | void inet_open(lua_State *L); |
| 28 | 28 | ||
| 29 | const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address, | 29 | const char *inet_trycreate(p_sock ps, int type); |
| 30 | unsigned short port); | 30 | const char *inet_tryconnect(p_sock ps, const char *address, |
| 31 | unsigned short port, p_tm tm); | ||
| 31 | const char *inet_trybind(p_sock ps, const char *address, | 32 | const char *inet_trybind(p_sock ps, const char *address, |
| 32 | unsigned short port, int backlog); | 33 | unsigned short port, int backlog); |
| 33 | const char *inet_trycreate(p_sock ps, int type); | ||
| 34 | const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc); | ||
| 35 | 34 | ||
| 36 | int inet_meth_getpeername(lua_State *L, p_sock ps); | 35 | int inet_meth_getpeername(lua_State *L, p_sock ps); |
| 37 | int inet_meth_getsockname(lua_State *L, p_sock ps); | 36 | int inet_meth_getsockname(lua_State *L, p_sock ps); |
diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..32a98d6 --- /dev/null +++ b/src/options.c | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | #include <lauxlib.h> | ||
| 2 | #include <string.h> | ||
| 3 | |||
| 4 | #include "auxiliar.h" | ||
| 5 | #include "options.h" | ||
| 6 | |||
| 7 | static int opt_setmembership(lua_State *L, p_sock ps, int level, int name); | ||
| 8 | static int opt_setboolean(lua_State *L, p_sock ps, int level, int name); | ||
| 9 | static int opt_set(lua_State *L, p_sock ps, int level, int name, | ||
| 10 | void *val, int len); | ||
| 11 | |||
| 12 | /*=========================================================================*\ | ||
| 13 | * Exported functions | ||
| 14 | \*=========================================================================*/ | ||
| 15 | /*-------------------------------------------------------------------------*\ | ||
| 16 | * Calls appropriate option handler | ||
| 17 | \*-------------------------------------------------------------------------*/ | ||
| 18 | int opt_meth_setoption(lua_State *L, p_opt opt, p_sock ps) | ||
| 19 | { | ||
| 20 | const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ | ||
| 21 | while (opt->name && strcmp(name, opt->name)) | ||
| 22 | opt++; | ||
| 23 | if (!opt->func) { | ||
| 24 | char msg[45]; | ||
| 25 | sprintf(msg, "unsupported option `%.35s'", name); | ||
| 26 | luaL_argerror(L, 2, msg); | ||
| 27 | } | ||
| 28 | return opt->func(L, ps); | ||
| 29 | } | ||
| 30 | |||
| 31 | /* enables reuse of local address */ | ||
| 32 | int opt_reuseaddr(lua_State *L, p_sock ps) | ||
| 33 | { | ||
| 34 | return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* disables the Naggle algorithm */ | ||
| 38 | int opt_tcp_nodelay(lua_State *L, p_sock ps) | ||
| 39 | { | ||
| 40 | return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); | ||
| 41 | } | ||
| 42 | |||
| 43 | int opt_keepalive(lua_State *L, p_sock ps) | ||
| 44 | { | ||
| 45 | return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); | ||
| 46 | } | ||
| 47 | |||
| 48 | int opt_dontroute(lua_State *L, p_sock ps) | ||
| 49 | { | ||
| 50 | return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); | ||
| 51 | } | ||
| 52 | |||
| 53 | int opt_broadcast(lua_State *L, p_sock ps) | ||
| 54 | { | ||
| 55 | return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); | ||
| 56 | } | ||
| 57 | |||
| 58 | int opt_ip_multicast_loop(lua_State *L, p_sock ps) | ||
| 59 | { | ||
| 60 | return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); | ||
| 61 | } | ||
| 62 | |||
| 63 | int opt_linger(lua_State *L, p_sock ps) | ||
| 64 | { | ||
| 65 | struct linger li; /* obj, name, table */ | ||
| 66 | if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE)); | ||
| 67 | lua_pushstring(L, "on"); | ||
| 68 | lua_gettable(L, 3); | ||
| 69 | if (!lua_isboolean(L, -1)) | ||
| 70 | luaL_argerror(L, 3, "boolean 'on' field expected"); | ||
| 71 | li.l_onoff = lua_toboolean(L, -1); | ||
| 72 | lua_pushstring(L, "timeout"); | ||
| 73 | lua_gettable(L, 3); | ||
| 74 | if (!lua_isnumber(L, -1)) | ||
| 75 | luaL_argerror(L, 3, "number 'timeout' field expected"); | ||
| 76 | li.l_linger = (int) lua_tonumber(L, -1); | ||
| 77 | return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); | ||
| 78 | } | ||
| 79 | |||
| 80 | int opt_ip_multicast_ttl(lua_State *L, p_sock ps) | ||
| 81 | { | ||
| 82 | int val = (int) luaL_checknumber(L, 3); /* obj, name, int */ | ||
| 83 | return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &val, sizeof(val)); | ||
| 84 | } | ||
| 85 | |||
| 86 | int opt_ip_add_membership(lua_State *L, p_sock ps) | ||
| 87 | { | ||
| 88 | return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); | ||
| 89 | } | ||
| 90 | |||
| 91 | int opt_ip_drop_membersip(lua_State *L, p_sock ps) | ||
| 92 | { | ||
| 93 | return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); | ||
| 94 | } | ||
| 95 | |||
| 96 | /*=========================================================================*\ | ||
| 97 | * Auxiliar functions | ||
| 98 | \*=========================================================================*/ | ||
| 99 | static int opt_setmembership(lua_State *L, p_sock ps, int level, int name) | ||
| 100 | { | ||
| 101 | struct ip_mreq val; /* obj, name, table */ | ||
| 102 | if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE)); | ||
| 103 | lua_pushstring(L, "multiaddr"); | ||
| 104 | lua_gettable(L, 3); | ||
| 105 | if (!lua_isstring(L, -1)) | ||
| 106 | luaL_argerror(L, 3, "string 'multiaddr' field expected"); | ||
| 107 | if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) | ||
| 108 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
| 109 | lua_pushstring(L, "interface"); | ||
| 110 | lua_gettable(L, 3); | ||
| 111 | if (!lua_isstring(L, -1)) | ||
| 112 | luaL_argerror(L, 3, "string 'interface' field expected"); | ||
| 113 | val.imr_interface.s_addr = htonl(INADDR_ANY); | ||
| 114 | if (strcmp(lua_tostring(L, -1), "*") && | ||
| 115 | !inet_aton(lua_tostring(L, -1), &val.imr_interface)) | ||
| 116 | luaL_argerror(L, 3, "invalid 'interface' ip address"); | ||
| 117 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
| 118 | } | ||
| 119 | |||
| 120 | static | ||
| 121 | int opt_set(lua_State *L, p_sock ps, int level, int name, void *val, int len) | ||
| 122 | { | ||
| 123 | if (setsockopt(*ps, level, name, (char *) val, len) < 0) { | ||
| 124 | lua_pushnil(L); | ||
| 125 | lua_pushstring(L, "setsockopt failed"); | ||
| 126 | return 2; | ||
| 127 | } | ||
| 128 | lua_pushnumber(L, 1); | ||
| 129 | return 1; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int opt_setboolean(lua_State *L, p_sock ps, int level, int name) | ||
| 133 | { | ||
| 134 | int val = aux_checkboolean(L, 3); /* obj, name, bool */ | ||
| 135 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
| 136 | } | ||
| 137 | |||
diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..ec75fc0 --- /dev/null +++ b/src/options.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #ifndef OPTIONS_H | ||
| 2 | #define OPTIONS_H | ||
| 3 | |||
| 4 | #include <lua.h> | ||
| 5 | #include "socket.h" | ||
| 6 | |||
| 7 | /* option registry */ | ||
| 8 | typedef struct t_opt { | ||
| 9 | const char *name; | ||
| 10 | int (*func)(lua_State *L, p_sock ps); | ||
| 11 | } t_opt; | ||
| 12 | typedef t_opt *p_opt; | ||
| 13 | |||
| 14 | /* supported options */ | ||
| 15 | int opt_dontroute(lua_State *L, p_sock ps); | ||
| 16 | int opt_broadcast(lua_State *L, p_sock ps); | ||
| 17 | int opt_reuseaddr(lua_State *L, p_sock ps); | ||
| 18 | int opt_tcp_nodelay(lua_State *L, p_sock ps); | ||
| 19 | int opt_keepalive(lua_State *L, p_sock ps); | ||
| 20 | int opt_linger(lua_State *L, p_sock ps); | ||
| 21 | int opt_reuseaddr(lua_State *L, p_sock ps); | ||
| 22 | int opt_ip_multicast_ttl(lua_State *L, p_sock ps); | ||
| 23 | int opt_ip_multicast_loop(lua_State *L, p_sock ps); | ||
| 24 | int opt_ip_add_membership(lua_State *L, p_sock ps); | ||
| 25 | int opt_ip_drop_membersip(lua_State *L, p_sock ps); | ||
| 26 | |||
| 27 | /* invokes the appropriate option handler */ | ||
| 28 | int opt_meth_setoption(lua_State *L, p_opt opt, p_sock ps); | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/src/socket.h b/src/socket.h index 739dedd..7c84baa 100644 --- a/src/socket.h +++ b/src/socket.h | |||
| @@ -22,6 +22,14 @@ | |||
| 22 | #include "usocket.h" | 22 | #include "usocket.h" |
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | /*=========================================================================*\ | ||
| 26 | * The connect and accept functions accept a timeout and their | ||
| 27 | * implementations are somewhat complicated. We chose to move | ||
| 28 | * the timeout control into this module for these functions in | ||
| 29 | * order to simplify the modules that use them. | ||
| 30 | \*=========================================================================*/ | ||
| 31 | #include "timeout.h" | ||
| 32 | |||
| 25 | /* we are lazy... */ | 33 | /* we are lazy... */ |
| 26 | typedef struct sockaddr SA; | 34 | typedef struct sockaddr SA; |
| 27 | 35 | ||
| @@ -30,12 +38,7 @@ typedef struct sockaddr SA; | |||
| 30 | * interface to sockets | 38 | * interface to sockets |
| 31 | \*=========================================================================*/ | 39 | \*=========================================================================*/ |
| 32 | int sock_open(void); | 40 | int sock_open(void); |
| 33 | int sock_create(p_sock ps, int domain, int type, int protocol); | ||
| 34 | void sock_destroy(p_sock ps); | 41 | void sock_destroy(p_sock ps); |
| 35 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | ||
| 36 | int timeout); | ||
| 37 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout); | ||
| 38 | int sock_bind(p_sock ps, SA *addr, socklen_t addr_len); | ||
| 39 | void sock_listen(p_sock ps, int backlog); | 42 | void sock_listen(p_sock ps, int backlog); |
| 40 | void sock_shutdown(p_sock ps, int how); | 43 | void sock_shutdown(p_sock ps, int how); |
| 41 | int sock_send(p_sock ps, const char *data, size_t count, | 44 | int sock_send(p_sock ps, const char *data, size_t count, |
| @@ -48,10 +51,10 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, | |||
| 48 | size_t *got, SA *addr, socklen_t *addr_len, int timeout); | 51 | size_t *got, SA *addr, socklen_t *addr_len, int timeout); |
| 49 | void sock_setnonblocking(p_sock ps); | 52 | void sock_setnonblocking(p_sock ps); |
| 50 | void sock_setblocking(p_sock ps); | 53 | void sock_setblocking(p_sock ps); |
| 51 | 54 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm); | |
| 55 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); | ||
| 56 | const char *sock_create(p_sock ps, int domain, int type, int protocol); | ||
| 57 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len); | ||
| 52 | const char *sock_hoststrerror(void); | 58 | const char *sock_hoststrerror(void); |
| 53 | const char *sock_createstrerror(void); | ||
| 54 | const char *sock_bindstrerror(void); | ||
| 55 | const char *sock_connectstrerror(void); | ||
| 56 | 59 | ||
| 57 | #endif /* SOCK_H */ | 60 | #endif /* SOCK_H */ |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "auxiliar.h" | 14 | #include "auxiliar.h" |
| 15 | #include "socket.h" | 15 | #include "socket.h" |
| 16 | #include "inet.h" | 16 | #include "inet.h" |
| 17 | #include "options.h" | ||
| 17 | #include "tcp.h" | 18 | #include "tcp.h" |
| 18 | 19 | ||
| 19 | /*=========================================================================*\ | 20 | /*=========================================================================*\ |
| @@ -33,10 +34,6 @@ static int meth_setoption(lua_State *L); | |||
| 33 | static int meth_settimeout(lua_State *L); | 34 | static int meth_settimeout(lua_State *L); |
| 34 | static int meth_fd(lua_State *L); | 35 | static int meth_fd(lua_State *L); |
| 35 | static int meth_dirty(lua_State *L); | 36 | static int meth_dirty(lua_State *L); |
| 36 | static int opt_tcp_nodelay(lua_State *L); | ||
| 37 | static int opt_keepalive(lua_State *L); | ||
| 38 | static int opt_linger(lua_State *L); | ||
| 39 | static int opt_reuseaddr(lua_State *L); | ||
| 40 | 37 | ||
| 41 | /* tcp object methods */ | 38 | /* tcp object methods */ |
| 42 | static luaL_reg tcp[] = { | 39 | static luaL_reg tcp[] = { |
| @@ -60,7 +57,7 @@ static luaL_reg tcp[] = { | |||
| 60 | }; | 57 | }; |
| 61 | 58 | ||
| 62 | /* socket option handlers */ | 59 | /* socket option handlers */ |
| 63 | static luaL_reg opt[] = { | 60 | static t_opt opt[] = { |
| 64 | {"keepalive", opt_keepalive}, | 61 | {"keepalive", opt_keepalive}, |
| 65 | {"reuseaddr", opt_reuseaddr}, | 62 | {"reuseaddr", opt_reuseaddr}, |
| 66 | {"tcp-nodelay", opt_tcp_nodelay}, | 63 | {"tcp-nodelay", opt_tcp_nodelay}, |
| @@ -116,65 +113,12 @@ static int meth_receive(lua_State *L) | |||
| 116 | } | 113 | } |
| 117 | 114 | ||
| 118 | /*-------------------------------------------------------------------------*\ | 115 | /*-------------------------------------------------------------------------*\ |
| 119 | * Option handlers | 116 | * Just call option handler |
| 120 | \*-------------------------------------------------------------------------*/ | 117 | \*-------------------------------------------------------------------------*/ |
| 121 | static int meth_setoption(lua_State *L) | 118 | static int meth_setoption(lua_State *L) |
| 122 | { | 119 | { |
| 123 | return aux_meth_setoption(L, opt); | 120 | p_tcp tcp = aux_checkgroup(L, "tcp{any}", 1); |
| 124 | } | 121 | return opt_meth_setoption(L, opt, &tcp->sock); |
| 125 | |||
| 126 | static int opt_boolean(lua_State *L, int level, int name) | ||
| 127 | { | ||
| 128 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); | ||
| 129 | int val = aux_checkboolean(L, 2); | ||
| 130 | if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | ||
| 131 | lua_pushnil(L); | ||
| 132 | lua_pushstring(L, "setsockopt failed"); | ||
| 133 | return 2; | ||
| 134 | } | ||
| 135 | lua_pushnumber(L, 1); | ||
| 136 | return 1; | ||
| 137 | } | ||
| 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 | |||
| 145 | /* disables the Naggle algorithm */ | ||
| 146 | static int opt_tcp_nodelay(lua_State *L) | ||
| 147 | { | ||
| 148 | return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY); | ||
| 149 | } | ||
| 150 | |||
| 151 | static int opt_keepalive(lua_State *L) | ||
| 152 | { | ||
| 153 | return opt_boolean(L, SOL_SOCKET, SO_KEEPALIVE); | ||
| 154 | } | ||
| 155 | |||
| 156 | static int opt_linger(lua_State *L) | ||
| 157 | { | ||
| 158 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); | ||
| 159 | struct linger li; | ||
| 160 | if (!lua_istable(L, 2)) | ||
| 161 | luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); | ||
| 162 | lua_pushstring(L, "on"); | ||
| 163 | lua_gettable(L, 2); | ||
| 164 | if (!lua_isboolean(L, -1)) luaL_argerror(L, 2, "invalid 'on' field"); | ||
| 165 | li.l_onoff = lua_toboolean(L, -1); | ||
| 166 | lua_pushstring(L, "timeout"); | ||
| 167 | lua_gettable(L, 2); | ||
| 168 | if (!lua_isnumber(L, -1)) luaL_argerror(L, 2, "invalid 'timeout' field"); | ||
| 169 | li.l_linger = (int) lua_tonumber(L, -1); | ||
| 170 | if (setsockopt(tcp->sock, SOL_SOCKET, SO_LINGER, | ||
| 171 | (char *) &li, sizeof(li) < 0)) { | ||
| 172 | lua_pushnil(L); | ||
| 173 | lua_pushstring(L, "setsockopt failed"); | ||
| 174 | return 2; | ||
| 175 | } | ||
| 176 | lua_pushnumber(L, 1); | ||
| 177 | return 1; | ||
| 178 | } | 122 | } |
| 179 | 123 | ||
| 180 | /*-------------------------------------------------------------------------*\ | 124 | /*-------------------------------------------------------------------------*\ |
| @@ -201,13 +145,11 @@ static int meth_dirty(lua_State *L) | |||
| 201 | static int meth_accept(lua_State *L) | 145 | static int meth_accept(lua_State *L) |
| 202 | { | 146 | { |
| 203 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); | 147 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); |
| 204 | p_tm tm = &server->tm; | 148 | p_tm tm = tm_markstart(&server->tm); |
| 205 | t_sock sock; | 149 | t_sock sock; |
| 206 | const char *err; | 150 | int err = sock_accept(&server->sock, &sock, NULL, NULL, tm); |
| 207 | tm_markstart(tm); | ||
| 208 | err = inet_tryaccept(&server->sock, tm, &sock); | ||
| 209 | /* if successful, push client socket */ | 151 | /* if successful, push client socket */ |
| 210 | if (!err) { | 152 | if (err == IO_DONE) { |
| 211 | p_tcp clnt = lua_newuserdata(L, sizeof(t_tcp)); | 153 | p_tcp clnt = lua_newuserdata(L, sizeof(t_tcp)); |
| 212 | aux_setclass(L, "tcp{client}", -1); | 154 | aux_setclass(L, "tcp{client}", -1); |
| 213 | /* initialize structure fields */ | 155 | /* initialize structure fields */ |
| @@ -218,7 +160,7 @@ static int meth_accept(lua_State *L) | |||
| 218 | return 1; | 160 | return 1; |
| 219 | } else { | 161 | } else { |
| 220 | lua_pushnil(L); | 162 | lua_pushnil(L); |
| 221 | lua_pushstring(L, err); | 163 | io_pusherror(L, err); |
| 222 | return 2; | 164 | return 2; |
| 223 | } | 165 | } |
| 224 | } | 166 | } |
| @@ -252,10 +194,8 @@ static int meth_connect(lua_State *L) | |||
| 252 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | 194 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); |
| 253 | const char *address = luaL_checkstring(L, 2); | 195 | const char *address = luaL_checkstring(L, 2); |
| 254 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); | 196 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); |
| 255 | p_tm tm = &tcp->tm; | 197 | p_tm tm = tm_markstart(&tcp->tm); |
| 256 | const char *err; | 198 | const char *err = inet_tryconnect(&tcp->sock, address, port, tm); |
| 257 | tm_markstart(tm); | ||
| 258 | err = inet_tryconnect(&tcp->sock, tm, address, port); | ||
| 259 | if (err) { | 199 | if (err) { |
| 260 | lua_pushnil(L); | 200 | lua_pushnil(L); |
| 261 | lua_pushstring(L, err); | 201 | lua_pushstring(L, err); |
| @@ -28,6 +28,7 @@ typedef struct t_tcp_ { | |||
| 28 | t_buf buf; | 28 | t_buf buf; |
| 29 | t_tm tm; | 29 | t_tm tm; |
| 30 | } t_tcp; | 30 | } t_tcp; |
| 31 | |||
| 31 | typedef t_tcp *p_tcp; | 32 | typedef t_tcp *p_tcp; |
| 32 | 33 | ||
| 33 | void tcp_open(lua_State *L); | 34 | void tcp_open(lua_State *L); |
diff --git a/src/timeout.c b/src/timeout.c index 09cb53d..83bffc9 100644 --- a/src/timeout.c +++ b/src/timeout.c | |||
| @@ -114,9 +114,10 @@ int tm_getretry(p_tm tm) | |||
| 114 | * Input | 114 | * Input |
| 115 | * tm: timeout control structure | 115 | * tm: timeout control structure |
| 116 | \*-------------------------------------------------------------------------*/ | 116 | \*-------------------------------------------------------------------------*/ |
| 117 | void tm_markstart(p_tm tm) | 117 | p_tm tm_markstart(p_tm tm) |
| 118 | { | 118 | { |
| 119 | tm->start = tm_gettime(); | 119 | tm->start = tm_gettime(); |
| 120 | return tm; | ||
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | /*-------------------------------------------------------------------------*\ | 123 | /*-------------------------------------------------------------------------*\ |
diff --git a/src/timeout.h b/src/timeout.h index 0a036f4..6584a8e 100644 --- a/src/timeout.h +++ b/src/timeout.h | |||
| @@ -20,7 +20,7 @@ void tm_open(lua_State *L); | |||
| 20 | void tm_init(p_tm tm, int block, int total); | 20 | void tm_init(p_tm tm, int block, int total); |
| 21 | int tm_get(p_tm tm); | 21 | int tm_get(p_tm tm); |
| 22 | int tm_getretry(p_tm tm); | 22 | int tm_getretry(p_tm tm); |
| 23 | void tm_markstart(p_tm tm); | 23 | p_tm tm_markstart(p_tm tm); |
| 24 | int tm_getstart(p_tm tm); | 24 | int tm_getstart(p_tm tm); |
| 25 | int tm_gettime(void); | 25 | int tm_gettime(void); |
| 26 | int tm_meth_settimeout(lua_State *L, p_tm tm); | 26 | int tm_meth_settimeout(lua_State *L, p_tm tm); |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "auxiliar.h" | 14 | #include "auxiliar.h" |
| 15 | #include "socket.h" | 15 | #include "socket.h" |
| 16 | #include "inet.h" | 16 | #include "inet.h" |
| 17 | #include "options.h" | ||
| 17 | #include "udp.h" | 18 | #include "udp.h" |
| 18 | 19 | ||
| 19 | /*=========================================================================*\ | 20 | /*=========================================================================*\ |
| @@ -34,13 +35,6 @@ static int meth_setoption(lua_State *L); | |||
| 34 | static int meth_settimeout(lua_State *L); | 35 | static int meth_settimeout(lua_State *L); |
| 35 | static int meth_fd(lua_State *L); | 36 | static int meth_fd(lua_State *L); |
| 36 | static int meth_dirty(lua_State *L); | 37 | static int meth_dirty(lua_State *L); |
| 37 | static int opt_dontroute(lua_State *L); | ||
| 38 | static int opt_broadcast(lua_State *L); | ||
| 39 | static int opt_reuseaddr(lua_State *L); | ||
| 40 | static int opt_ip_multicast_ttl(lua_State *L); | ||
| 41 | static int opt_ip_multicast_loop(lua_State *L); | ||
| 42 | static int opt_ip_add_membership(lua_State *L); | ||
| 43 | static int opt_ip_drop_membersip(lua_State *L); | ||
| 44 | 38 | ||
| 45 | /* udp object methods */ | 39 | /* udp object methods */ |
| 46 | static luaL_reg udp[] = { | 40 | static luaL_reg udp[] = { |
| @@ -63,7 +57,7 @@ static luaL_reg udp[] = { | |||
| 63 | }; | 57 | }; |
| 64 | 58 | ||
| 65 | /* socket options */ | 59 | /* socket options */ |
| 66 | static luaL_reg opt[] = { | 60 | static t_opt opt[] = { |
| 67 | {"dontroute", opt_dontroute}, | 61 | {"dontroute", opt_dontroute}, |
| 68 | {"broadcast", opt_broadcast}, | 62 | {"broadcast", opt_broadcast}, |
| 69 | {"reuseaddr", opt_reuseaddr}, | 63 | {"reuseaddr", opt_reuseaddr}, |
| @@ -231,95 +225,12 @@ static int meth_getsockname(lua_State *L) | |||
| 231 | } | 225 | } |
| 232 | 226 | ||
| 233 | /*-------------------------------------------------------------------------*\ | 227 | /*-------------------------------------------------------------------------*\ |
| 234 | * Option handlers | 228 | * Just call option handler |
| 235 | \*-------------------------------------------------------------------------*/ | 229 | \*-------------------------------------------------------------------------*/ |
| 236 | static int meth_setoption(lua_State *L) | 230 | static int meth_setoption(lua_State *L) |
| 237 | { | 231 | { |
| 238 | return aux_meth_setoption(L, opt); | ||
| 239 | } | ||
| 240 | |||
| 241 | static int opt_boolean(lua_State *L, int level, int name) | ||
| 242 | { | ||
| 243 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
| 244 | int val = aux_checkboolean(L, 2); | ||
| 245 | if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | ||
| 246 | lua_pushnil(L); | ||
| 247 | lua_pushstring(L, "setsockopt failed"); | ||
| 248 | return 2; | ||
| 249 | } | ||
| 250 | lua_pushnumber(L, 1); | ||
| 251 | return 1; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int opt_dontroute(lua_State *L) | ||
| 255 | { | ||
| 256 | return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); | ||
| 257 | } | ||
| 258 | |||
| 259 | static int opt_reuseaddr(lua_State *L) | ||
| 260 | { | ||
| 261 | return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); | ||
| 262 | } | ||
| 263 | |||
| 264 | static int opt_broadcast(lua_State *L) | ||
| 265 | { | ||
| 266 | return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); | ||
| 267 | } | ||
| 268 | |||
| 269 | static int opt_ip_multicast_loop(lua_State *L) | ||
| 270 | { | ||
| 271 | return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int opt_ip_multicast_ttl(lua_State *L) | ||
| 275 | { | ||
| 276 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
| 277 | int val = (int) luaL_checknumber(L, 2); | ||
| 278 | if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, | ||
| 279 | (char *) &val, sizeof(val)) < 0) { | ||
| 280 | lua_pushnil(L); | ||
| 281 | lua_pushstring(L, "setsockopt failed"); | ||
| 282 | return 2; | ||
| 283 | } | ||
| 284 | lua_pushnumber(L, 1); | ||
| 285 | return 1; | ||
| 286 | } | ||
| 287 | |||
| 288 | static int opt_membership(lua_State *L, int level, int name) | ||
| 289 | { | ||
| 290 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | 232 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); |
| 291 | struct ip_mreq val; | 233 | return opt_meth_setoption(L, opt, &udp->sock); |
| 292 | if (!lua_istable(L, 2)) | ||
| 293 | luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); | ||
| 294 | lua_pushstring(L, "multiaddr"); | ||
| 295 | lua_gettable(L, 2); | ||
| 296 | if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field"); | ||
| 297 | if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) | ||
| 298 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
| 299 | lua_pushstring(L, "interface"); | ||
| 300 | lua_gettable(L, 2); | ||
| 301 | if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field"); | ||
| 302 | val.imr_interface.s_addr = htonl(INADDR_ANY); | ||
| 303 | if (strcmp(lua_tostring(L, -1), "*") && | ||
| 304 | !inet_aton(lua_tostring(L, -1), &val.imr_interface)) | ||
| 305 | luaL_argerror(L, 3, "invalid 'interface' ip address"); | ||
| 306 | if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | ||
| 307 | lua_pushnil(L); | ||
| 308 | lua_pushstring(L, "setsockopt failed"); | ||
| 309 | return 2; | ||
| 310 | } | ||
| 311 | lua_pushnumber(L, 1); | ||
| 312 | return 1; | ||
| 313 | } | ||
| 314 | |||
| 315 | static int opt_ip_add_membership(lua_State *L) | ||
| 316 | { | ||
| 317 | return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP); | ||
| 318 | } | ||
| 319 | |||
| 320 | static int opt_ip_drop_membersip(lua_State *L) | ||
| 321 | { | ||
| 322 | return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP); | ||
| 323 | } | 234 | } |
| 324 | 235 | ||
| 325 | /*-------------------------------------------------------------------------*\ | 236 | /*-------------------------------------------------------------------------*\ |
| @@ -343,7 +254,7 @@ static int meth_setpeername(lua_State *L) | |||
| 343 | unsigned short port = connecting ? | 254 | unsigned short port = connecting ? |
| 344 | (unsigned short) luaL_checknumber(L, 3) : | 255 | (unsigned short) luaL_checknumber(L, 3) : |
| 345 | (unsigned short) luaL_optnumber(L, 3, 0); | 256 | (unsigned short) luaL_optnumber(L, 3, 0); |
| 346 | const char *err = inet_tryconnect(&udp->sock, tm, address, port); | 257 | const char *err = inet_tryconnect(&udp->sock, address, port, tm); |
| 347 | if (err) { | 258 | if (err) { |
| 348 | lua_pushnil(L); | 259 | lua_pushnil(L); |
| 349 | lua_pushstring(L, err); | 260 | lua_pushstring(L, err); |
diff --git a/src/usocket.c b/src/usocket.c index f5939a9..54f203b 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
| @@ -20,6 +20,10 @@ | |||
| 20 | 20 | ||
| 21 | #include "socket.h" | 21 | #include "socket.h" |
| 22 | 22 | ||
| 23 | static const char *sock_createstrerror(void); | ||
| 24 | static const char *sock_bindstrerror(void); | ||
| 25 | static const char *sock_connectstrerror(void); | ||
| 26 | |||
| 23 | /*-------------------------------------------------------------------------*\ | 27 | /*-------------------------------------------------------------------------*\ |
| 24 | * Initializes module | 28 | * Initializes module |
| 25 | \*-------------------------------------------------------------------------*/ | 29 | \*-------------------------------------------------------------------------*/ |
| @@ -50,31 +54,37 @@ void sock_destroy(p_sock ps) | |||
| 50 | /*-------------------------------------------------------------------------*\ | 54 | /*-------------------------------------------------------------------------*\ |
| 51 | * Creates and sets up a socket | 55 | * Creates and sets up a socket |
| 52 | \*-------------------------------------------------------------------------*/ | 56 | \*-------------------------------------------------------------------------*/ |
| 53 | int sock_create(p_sock ps, int domain, int type, int protocol) | 57 | const char *sock_create(p_sock ps, int domain, int type, int protocol) |
| 54 | { | 58 | { |
| 55 | int val = 1; | 59 | int val = 1; |
| 56 | t_sock sock = socket(domain, type, protocol); | 60 | t_sock sock = socket(domain, type, protocol); |
| 57 | if (sock == SOCK_INVALID) return IO_ERROR; | 61 | if (sock == SOCK_INVALID) return sock_createstrerror(); |
| 58 | *ps = sock; | 62 | *ps = sock; |
| 59 | sock_setnonblocking(ps); | 63 | sock_setnonblocking(ps); |
| 60 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); | 64 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); |
| 61 | return IO_DONE; | 65 | return NULL; |
| 62 | } | 66 | } |
| 63 | 67 | ||
| 64 | /*-------------------------------------------------------------------------*\ | 68 | /*-------------------------------------------------------------------------*\ |
| 65 | * Connects or returns error message | 69 | * Connects or returns error message |
| 66 | \*-------------------------------------------------------------------------*/ | 70 | \*-------------------------------------------------------------------------*/ |
| 67 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) | 71 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) |
| 68 | { | 72 | { |
| 69 | t_sock sock = *ps; | 73 | t_sock sock = *ps; |
| 70 | if (sock == SOCK_INVALID) return IO_CLOSED; | 74 | int err; |
| 71 | /* if connect fails, we have to find out why */ | 75 | /* don't call on closed socket */ |
| 72 | if (connect(sock, addr, addr_len) < 0) { | 76 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); |
| 77 | /* ask system to connect */ | ||
| 78 | err = connect(sock, addr, addr_len); | ||
| 79 | /* if no error, we're done */ | ||
| 80 | if (err == 0) return NULL; | ||
| 81 | /* make sure the system is trying to connect */ | ||
| 82 | if (errno != EINPROGRESS) return io_strerror(IO_ERROR); | ||
| 83 | /* wait for a timeout or for the system's answer */ | ||
| 84 | for ( ;; ) { | ||
| 73 | struct timeval tv; | 85 | struct timeval tv; |
| 74 | fd_set rfds, efds, wfds; | 86 | fd_set rfds, wfds, efds; |
| 75 | int err; | 87 | int timeout = tm_getretry(tm); |
| 76 | /* make sure the system is trying to connect */ | ||
| 77 | if (errno != EINPROGRESS) return IO_ERROR; | ||
| 78 | tv.tv_sec = timeout / 1000; | 88 | tv.tv_sec = timeout / 1000; |
| 79 | tv.tv_usec = (timeout % 1000) * 1000; | 89 | tv.tv_usec = (timeout % 1000) * 1000; |
| 80 | FD_ZERO(&rfds); FD_SET(sock, &rfds); | 90 | FD_ZERO(&rfds); FD_SET(sock, &rfds); |
| @@ -82,28 +92,29 @@ int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) | |||
| 82 | FD_ZERO(&efds); FD_SET(sock, &efds); | 92 | FD_ZERO(&efds); FD_SET(sock, &efds); |
| 83 | /* we run select to avoid busy waiting */ | 93 | /* we run select to avoid busy waiting */ |
| 84 | err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL); | 94 | err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL); |
| 85 | /* if select was interrupted, ask the user to retry */ | 95 | /* if select was interrupted, try again */ |
| 86 | if (err < 0 && errno == EINTR) return IO_RETRY; | 96 | if (err < 0 && errno == EINTR) continue; |
| 87 | /* if selects readable, try reading */ | 97 | /* if selects readable, try reading */ |
| 88 | if (err > 0) { | 98 | if (err > 0) { |
| 89 | char dummy; | 99 | char dummy; |
| 90 | /* try reading so that errno is set */ | 100 | /* recv will set errno to the value a blocking connect would set */ |
| 91 | if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) | 101 | if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) |
| 92 | return IO_ERROR; | 102 | return sock_connectstrerror(); |
| 93 | else return IO_DONE; | 103 | else |
| 104 | return NULL; | ||
| 94 | /* if no event happened, there was a timeout */ | 105 | /* if no event happened, there was a timeout */ |
| 95 | } else return IO_TIMEOUT; | 106 | } else return io_strerror(IO_TIMEOUT); |
| 96 | /* otherwise connection succeeded */ | 107 | } |
| 97 | } else return IO_DONE; | 108 | return io_strerror(IO_TIMEOUT); /* can't get here */ |
| 98 | } | 109 | } |
| 99 | 110 | ||
| 100 | /*-------------------------------------------------------------------------*\ | 111 | /*-------------------------------------------------------------------------*\ |
| 101 | * Binds or returns error message | 112 | * Binds or returns error message |
| 102 | \*-------------------------------------------------------------------------*/ | 113 | \*-------------------------------------------------------------------------*/ |
| 103 | int sock_bind(p_sock ps, SA *addr, socklen_t addr_len) | 114 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) |
| 104 | { | 115 | { |
| 105 | if (bind(*ps, addr, addr_len) < 0) return IO_ERROR; | 116 | if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); |
| 106 | else return IO_DONE; | 117 | else return NULL; |
| 107 | } | 118 | } |
| 108 | 119 | ||
| 109 | /*-------------------------------------------------------------------------*\ | 120 | /*-------------------------------------------------------------------------*\ |
| @@ -125,8 +136,7 @@ void sock_shutdown(p_sock ps, int how) | |||
| 125 | /*-------------------------------------------------------------------------*\ | 136 | /*-------------------------------------------------------------------------*\ |
| 126 | * Accept with timeout | 137 | * Accept with timeout |
| 127 | \*-------------------------------------------------------------------------*/ | 138 | \*-------------------------------------------------------------------------*/ |
| 128 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | 139 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm) |
| 129 | int timeout) | ||
| 130 | { | 140 | { |
| 131 | t_sock sock = *ps; | 141 | t_sock sock = *ps; |
| 132 | SA dummy_addr; | 142 | SA dummy_addr; |
| @@ -134,19 +144,21 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | |||
| 134 | if (sock == SOCK_INVALID) return IO_CLOSED; | 144 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 135 | if (!addr) addr = &dummy_addr; | 145 | if (!addr) addr = &dummy_addr; |
| 136 | if (!addr_len) addr_len = &dummy_len; | 146 | if (!addr_len) addr_len = &dummy_len; |
| 137 | *pa = accept(sock, addr, addr_len); | 147 | for (;;) { |
| 138 | if (*pa == SOCK_INVALID) { | 148 | int timeout = tm_getretry(tm); |
| 139 | struct timeval tv; | 149 | struct timeval tv; |
| 140 | fd_set fds; | 150 | fd_set fds; |
| 151 | *pa = accept(sock, addr, addr_len); | ||
| 152 | if (*pa != SOCK_INVALID) return IO_DONE; | ||
| 153 | if (timeout == 0) return IO_TIMEOUT; | ||
| 141 | tv.tv_sec = timeout / 1000; | 154 | tv.tv_sec = timeout / 1000; |
| 142 | tv.tv_usec = (timeout % 1000) * 1000; | 155 | tv.tv_usec = (timeout % 1000) * 1000; |
| 143 | FD_ZERO(&fds); | 156 | FD_ZERO(&fds); |
| 144 | FD_SET(sock, &fds); | 157 | FD_SET(sock, &fds); |
| 145 | /* just call select to avoid busy-wait. doesn't really matter | 158 | /* call select just to avoid busy-wait. */ |
| 146 | * what happens. the caller will choose to retry or not */ | ||
| 147 | select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL); | 159 | select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL); |
| 148 | return IO_RETRY; | 160 | } |
| 149 | } else return IO_DONE; | 161 | return IO_TIMEOUT; /* can't get here */ |
| 150 | } | 162 | } |
| 151 | 163 | ||
| 152 | /*-------------------------------------------------------------------------*\ | 164 | /*-------------------------------------------------------------------------*\ |
| @@ -314,7 +326,7 @@ const char *sock_hoststrerror(void) | |||
| 314 | } | 326 | } |
| 315 | } | 327 | } |
| 316 | 328 | ||
| 317 | const char *sock_createstrerror(void) | 329 | static const char *sock_createstrerror(void) |
| 318 | { | 330 | { |
| 319 | switch (errno) { | 331 | switch (errno) { |
| 320 | case EACCES: return "access denied"; | 332 | case EACCES: return "access denied"; |
| @@ -325,7 +337,7 @@ const char *sock_createstrerror(void) | |||
| 325 | } | 337 | } |
| 326 | } | 338 | } |
| 327 | 339 | ||
| 328 | const char *sock_bindstrerror(void) | 340 | static const char *sock_bindstrerror(void) |
| 329 | { | 341 | { |
| 330 | switch (errno) { | 342 | switch (errno) { |
| 331 | case EBADF: return "invalid descriptor"; | 343 | case EBADF: return "invalid descriptor"; |
| @@ -339,7 +351,7 @@ const char *sock_bindstrerror(void) | |||
| 339 | } | 351 | } |
| 340 | } | 352 | } |
| 341 | 353 | ||
| 342 | const char *sock_connectstrerror(void) | 354 | static const char *sock_connectstrerror(void) |
| 343 | { | 355 | { |
| 344 | switch (errno) { | 356 | switch (errno) { |
| 345 | case EBADF: return "invalid descriptor"; | 357 | case EBADF: return "invalid descriptor"; |
diff --git a/test/httptest.lua b/test/httptest.lua index 4667605..8bf3980 100644 --- a/test/httptest.lua +++ b/test/httptest.lua | |||
| @@ -49,8 +49,7 @@ local check_result = function(response, expect, ignore) | |||
| 49 | for i,v in response do | 49 | for i,v in response do |
| 50 | if not ignore[i] then | 50 | if not ignore[i] then |
| 51 | if v ~= expect[i] then | 51 | if v ~= expect[i] then |
| 52 | v = string.sub(type(v) == "string" and v or "", 1, 70) | 52 | print(string.sub(tostring(v), 1, 70)) |
| 53 | print(v) | ||
| 54 | fail(i .. " differs!") | 53 | fail(i .. " differs!") |
| 55 | end | 54 | end |
| 56 | end | 55 | end |
| @@ -59,7 +58,7 @@ local check_result = function(response, expect, ignore) | |||
| 59 | if not ignore[i] then | 58 | if not ignore[i] then |
| 60 | if v ~= response[i] then | 59 | if v ~= response[i] then |
| 61 | v = string.sub(type(v) == "string" and v or "", 1, 70) | 60 | v = string.sub(type(v) == "string" and v or "", 1, 70) |
| 62 | print(v) | 61 | print(string.sub(tostring(v), 1, 70)) |
| 63 | fail(i .. " differs!") | 62 | fail(i .. " differs!") |
| 64 | end | 63 | end |
| 65 | end | 64 | end |
diff --git a/test/testclnt.lua b/test/testclnt.lua index 5a001b3..a0d9fda 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
| @@ -379,6 +379,19 @@ function connect_timeout() | |||
| 379 | end | 379 | end |
| 380 | 380 | ||
| 381 | ------------------------------------------------------------------------ | 381 | ------------------------------------------------------------------------ |
| 382 | function rebind_test() | ||
| 383 | local c = socket.bind("localhost", 0) | ||
| 384 | local i, p = c:getsockname() | ||
| 385 | local s, e = socket.tcp() | ||
| 386 | assert(s, e) | ||
| 387 | s:setoption("reuseaddr", false) | ||
| 388 | r, e = s:bind("localhost", p) | ||
| 389 | assert(not r, "managed to rebind!") | ||
| 390 | assert(e == "address already in use") | ||
| 391 | print("ok") | ||
| 392 | end | ||
| 393 | |||
| 394 | ------------------------------------------------------------------------ | ||
| 382 | test("method registration") | 395 | test("method registration") |
| 383 | test_methods(socket.tcp(), { | 396 | test_methods(socket.tcp(), { |
| 384 | "connect", | 397 | "connect", |
| @@ -416,6 +429,9 @@ test_selectbugs() | |||
| 416 | test("empty host connect: ") | 429 | test("empty host connect: ") |
| 417 | empty_connect() | 430 | empty_connect() |
| 418 | 431 | ||
| 432 | test("rebinding: ") | ||
| 433 | rebind_test() | ||
| 434 | |||
| 419 | test("active close: ") | 435 | test("active close: ") |
| 420 | active_close() | 436 | active_close() |
| 421 | 437 | ||
