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 | ||