aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-21 18:40:52 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-21 18:40:52 +0000
commit195069cf5f929f445b0ce20e531cd482d2559083 (patch)
tree6444d37c4ce32395428ba26ee0d16c0c372bd9da
parente63f500d24ff0238425c9e13f220daf09a277ef5 (diff)
downloadluasocket-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--TODO1
-rw-r--r--src/auxiliar.c20
-rw-r--r--src/auxiliar.h1
-rw-r--r--src/inet.c56
-rw-r--r--src/inet.h7
-rw-r--r--src/options.c137
-rw-r--r--src/options.h30
-rw-r--r--src/socket.h21
-rw-r--r--src/tcp.c82
-rw-r--r--src/tcp.h1
-rw-r--r--src/timeout.c3
-rw-r--r--src/timeout.h2
-rw-r--r--src/udp.c99
-rw-r--r--src/usocket.c78
-rw-r--r--test/httptest.lua5
-rw-r--r--test/testclnt.lua16
16 files changed, 284 insertions, 275 deletions
diff --git a/TODO b/TODO
index b24f9e5..835929f 100644
--- a/TODO
+++ b/TODO
@@ -22,6 +22,7 @@ tests
22trust character constants in mime.c? noooooo. 22trust character constants in mime.c? noooooo.
23smtp.lua needs stuff filter 23smtp.lua needs stuff filter
24 24
25add comments into each C module.
25new option.c module to put all options (TCP and UDP share...)? 26new option.c module to put all options (TCP and UDP share...)?
26testar os options! 27testar os options!
27add _tostring methods! 28add _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\*-------------------------------------------------------------------------*/
71int 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);
48void *aux_checkgroup(lua_State *L, const char *groupname, int objidx); 48void *aux_checkgroup(lua_State *L, const char *groupname, int objidx);
49void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); 49void *aux_getclassudata(lua_State *L, const char *groupname, int objidx);
50void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); 50void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx);
51int aux_meth_setoption(lua_State *L, luaL_reg *opt);
52int aux_checkboolean(lua_State *L, int objidx); 51int aux_checkboolean(lua_State *L, int objidx);
53 52
54#endif /* AUX_H */ 53#endif /* AUX_H */
diff --git a/src/inet.c b/src/inet.c
index 6aea596..f6c2a6f 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -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\*-------------------------------------------------------------------------*/
183const 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\*-------------------------------------------------------------------------*/
183const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address, 191const 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\*-------------------------------------------------------------------------*/
245const 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\*-------------------------------------------------------------------------*/
254const 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\*-------------------------------------------------------------------------*/
diff --git a/src/inet.h b/src/inet.h
index ad52801..28cf823 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -26,12 +26,11 @@
26 26
27void inet_open(lua_State *L); 27void inet_open(lua_State *L);
28 28
29const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address, 29const char *inet_trycreate(p_sock ps, int type);
30 unsigned short port); 30const char *inet_tryconnect(p_sock ps, const char *address,
31 unsigned short port, p_tm tm);
31const char *inet_trybind(p_sock ps, const char *address, 32const char *inet_trybind(p_sock ps, const char *address,
32 unsigned short port, int backlog); 33 unsigned short port, int backlog);
33const char *inet_trycreate(p_sock ps, int type);
34const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc);
35 34
36int inet_meth_getpeername(lua_State *L, p_sock ps); 35int inet_meth_getpeername(lua_State *L, p_sock ps);
37int inet_meth_getsockname(lua_State *L, p_sock ps); 36int 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
7static int opt_setmembership(lua_State *L, p_sock ps, int level, int name);
8static int opt_setboolean(lua_State *L, p_sock ps, int level, int name);
9static 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\*-------------------------------------------------------------------------*/
18int 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 */
32int 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 */
38int opt_tcp_nodelay(lua_State *L, p_sock ps)
39{
40 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
41}
42
43int opt_keepalive(lua_State *L, p_sock ps)
44{
45 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
46}
47
48int opt_dontroute(lua_State *L, p_sock ps)
49{
50 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
51}
52
53int opt_broadcast(lua_State *L, p_sock ps)
54{
55 return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
56}
57
58int opt_ip_multicast_loop(lua_State *L, p_sock ps)
59{
60 return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
61}
62
63int 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
80int 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
86int opt_ip_add_membership(lua_State *L, p_sock ps)
87{
88 return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
89}
90
91int 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\*=========================================================================*/
99static 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
120static
121int 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
132static 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 */
8typedef struct t_opt {
9 const char *name;
10 int (*func)(lua_State *L, p_sock ps);
11} t_opt;
12typedef t_opt *p_opt;
13
14/* supported options */
15int opt_dontroute(lua_State *L, p_sock ps);
16int opt_broadcast(lua_State *L, p_sock ps);
17int opt_reuseaddr(lua_State *L, p_sock ps);
18int opt_tcp_nodelay(lua_State *L, p_sock ps);
19int opt_keepalive(lua_State *L, p_sock ps);
20int opt_linger(lua_State *L, p_sock ps);
21int opt_reuseaddr(lua_State *L, p_sock ps);
22int opt_ip_multicast_ttl(lua_State *L, p_sock ps);
23int opt_ip_multicast_loop(lua_State *L, p_sock ps);
24int opt_ip_add_membership(lua_State *L, p_sock ps);
25int opt_ip_drop_membersip(lua_State *L, p_sock ps);
26
27/* invokes the appropriate option handler */
28int 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... */
26typedef struct sockaddr SA; 34typedef struct sockaddr SA;
27 35
@@ -30,12 +38,7 @@ typedef struct sockaddr SA;
30* interface to sockets 38* interface to sockets
31\*=========================================================================*/ 39\*=========================================================================*/
32int sock_open(void); 40int sock_open(void);
33int sock_create(p_sock ps, int domain, int type, int protocol);
34void sock_destroy(p_sock ps); 41void sock_destroy(p_sock ps);
35int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
36 int timeout);
37int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout);
38int sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
39void sock_listen(p_sock ps, int backlog); 42void sock_listen(p_sock ps, int backlog);
40void sock_shutdown(p_sock ps, int how); 43void sock_shutdown(p_sock ps, int how);
41int sock_send(p_sock ps, const char *data, size_t count, 44int 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);
49void sock_setnonblocking(p_sock ps); 52void sock_setnonblocking(p_sock ps);
50void sock_setblocking(p_sock ps); 53void sock_setblocking(p_sock ps);
51 54int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm);
55const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm);
56const char *sock_create(p_sock ps, int domain, int type, int protocol);
57const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
52const char *sock_hoststrerror(void); 58const char *sock_hoststrerror(void);
53const char *sock_createstrerror(void);
54const char *sock_bindstrerror(void);
55const char *sock_connectstrerror(void);
56 59
57#endif /* SOCK_H */ 60#endif /* SOCK_H */
diff --git a/src/tcp.c b/src/tcp.c
index 5505848..01b07ee 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -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);
33static int meth_settimeout(lua_State *L); 34static int meth_settimeout(lua_State *L);
34static int meth_fd(lua_State *L); 35static int meth_fd(lua_State *L);
35static int meth_dirty(lua_State *L); 36static int meth_dirty(lua_State *L);
36static int opt_tcp_nodelay(lua_State *L);
37static int opt_keepalive(lua_State *L);
38static int opt_linger(lua_State *L);
39static int opt_reuseaddr(lua_State *L);
40 37
41/* tcp object methods */ 38/* tcp object methods */
42static luaL_reg tcp[] = { 39static luaL_reg tcp[] = {
@@ -60,7 +57,7 @@ static luaL_reg tcp[] = {
60}; 57};
61 58
62/* socket option handlers */ 59/* socket option handlers */
63static luaL_reg opt[] = { 60static 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\*-------------------------------------------------------------------------*/
121static int meth_setoption(lua_State *L) 118static 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
126static 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 */
140static int opt_reuseaddr(lua_State *L)
141{
142 return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR);
143}
144
145/* disables the Naggle algorithm */
146static int opt_tcp_nodelay(lua_State *L)
147{
148 return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY);
149}
150
151static int opt_keepalive(lua_State *L)
152{
153 return opt_boolean(L, SOL_SOCKET, SO_KEEPALIVE);
154}
155
156static 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)
201static int meth_accept(lua_State *L) 145static 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);
diff --git a/src/tcp.h b/src/tcp.h
index 82b88a9..ae99b8c 100644
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -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
31typedef t_tcp *p_tcp; 32typedef t_tcp *p_tcp;
32 33
33void tcp_open(lua_State *L); 34void 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\*-------------------------------------------------------------------------*/
117void tm_markstart(p_tm tm) 117p_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);
20void tm_init(p_tm tm, int block, int total); 20void tm_init(p_tm tm, int block, int total);
21int tm_get(p_tm tm); 21int tm_get(p_tm tm);
22int tm_getretry(p_tm tm); 22int tm_getretry(p_tm tm);
23void tm_markstart(p_tm tm); 23p_tm tm_markstart(p_tm tm);
24int tm_getstart(p_tm tm); 24int tm_getstart(p_tm tm);
25int tm_gettime(void); 25int tm_gettime(void);
26int tm_meth_settimeout(lua_State *L, p_tm tm); 26int tm_meth_settimeout(lua_State *L, p_tm tm);
diff --git a/src/udp.c b/src/udp.c
index c5e14d1..115e749 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -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);
34static int meth_settimeout(lua_State *L); 35static int meth_settimeout(lua_State *L);
35static int meth_fd(lua_State *L); 36static int meth_fd(lua_State *L);
36static int meth_dirty(lua_State *L); 37static int meth_dirty(lua_State *L);
37static int opt_dontroute(lua_State *L);
38static int opt_broadcast(lua_State *L);
39static int opt_reuseaddr(lua_State *L);
40static int opt_ip_multicast_ttl(lua_State *L);
41static int opt_ip_multicast_loop(lua_State *L);
42static int opt_ip_add_membership(lua_State *L);
43static int opt_ip_drop_membersip(lua_State *L);
44 38
45/* udp object methods */ 39/* udp object methods */
46static luaL_reg udp[] = { 40static luaL_reg udp[] = {
@@ -63,7 +57,7 @@ static luaL_reg udp[] = {
63}; 57};
64 58
65/* socket options */ 59/* socket options */
66static luaL_reg opt[] = { 60static 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\*-------------------------------------------------------------------------*/
236static int meth_setoption(lua_State *L) 230static int meth_setoption(lua_State *L)
237{ 231{
238 return aux_meth_setoption(L, opt);
239}
240
241static 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
254static int opt_dontroute(lua_State *L)
255{
256 return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE);
257}
258
259static int opt_reuseaddr(lua_State *L)
260{
261 return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR);
262}
263
264static int opt_broadcast(lua_State *L)
265{
266 return opt_boolean(L, SOL_SOCKET, SO_BROADCAST);
267}
268
269static int opt_ip_multicast_loop(lua_State *L)
270{
271 return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP);
272}
273
274static 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
288static 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
315static int opt_ip_add_membership(lua_State *L)
316{
317 return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP);
318}
319
320static 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
23static const char *sock_createstrerror(void);
24static const char *sock_bindstrerror(void);
25static 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\*-------------------------------------------------------------------------*/
53int sock_create(p_sock ps, int domain, int type, int protocol) 57const 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\*-------------------------------------------------------------------------*/
67int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) 71const 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\*-------------------------------------------------------------------------*/
103int sock_bind(p_sock ps, SA *addr, socklen_t addr_len) 114const 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\*-------------------------------------------------------------------------*/
128int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, 139int 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
317const char *sock_createstrerror(void) 329static 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
328const char *sock_bindstrerror(void) 340static 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
342const char *sock_connectstrerror(void) 354static 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()
379end 379end
380 380
381------------------------------------------------------------------------ 381------------------------------------------------------------------------
382function 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")
392end
393
394------------------------------------------------------------------------
382test("method registration") 395test("method registration")
383test_methods(socket.tcp(), { 396test_methods(socket.tcp(), {
384 "connect", 397 "connect",
@@ -416,6 +429,9 @@ test_selectbugs()
416test("empty host connect: ") 429test("empty host connect: ")
417empty_connect() 430empty_connect()
418 431
432test("rebinding: ")
433rebind_test()
434
419test("active close: ") 435test("active close: ")
420active_close() 436active_close()
421 437