diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-15 06:11:53 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-15 06:11:53 +0000 |
commit | 9a79d500eb3e015f5bf579aab714916d49c1f289 (patch) | |
tree | db658e87a17e5417ec01ab4a1b0249bdaf2bd1d2 | |
parent | 471334c3d07f398e4b0859c43276341a28b91504 (diff) | |
download | luasocket-9a79d500eb3e015f5bf579aab714916d49c1f289.tar.gz luasocket-9a79d500eb3e015f5bf579aab714916d49c1f289.tar.bz2 luasocket-9a79d500eb3e015f5bf579aab714916d49c1f289.zip |
Still need to fix windows. :o/
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | src/buffer.c | 22 | ||||
-rw-r--r-- | src/inet.c | 70 | ||||
-rw-r--r-- | src/io.c | 24 | ||||
-rw-r--r-- | src/io.h | 28 | ||||
-rw-r--r-- | src/socket.h | 27 | ||||
-rw-r--r-- | src/tcp.c | 16 | ||||
-rw-r--r-- | src/timeout.h | 2 | ||||
-rw-r--r-- | src/udp.c | 54 | ||||
-rw-r--r-- | src/usocket.c | 368 | ||||
-rw-r--r-- | test/httptest.lua | 2 |
11 files changed, 315 insertions, 301 deletions
@@ -1,3 +1,6 @@ | |||
1 | test associativity of socket.select | ||
2 | probably if is dirty, no assoc is created. wonder why... | ||
3 | |||
1 | take a look at DB's smtp patch | 4 | take a look at DB's smtp patch |
2 | 5 | ||
3 | optmize aux_getgroupudata (Mike idea) | 6 | optmize aux_getgroupudata (Mike idea) |
diff --git a/src/buffer.c b/src/buffer.c index baa248a..33fae84 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
@@ -77,7 +77,7 @@ int buf_meth_send(lua_State *L, p_buf buf) { | |||
77 | /* check if there was an error */ | 77 | /* check if there was an error */ |
78 | if (err != IO_DONE) { | 78 | if (err != IO_DONE) { |
79 | lua_pushnil(L); | 79 | lua_pushnil(L); |
80 | io_pusherror(L, buf->io, err); | 80 | lua_pushstring(L, buf->io->error(buf->io->ctx, err)); |
81 | lua_pushnumber(L, total); | 81 | lua_pushnumber(L, total); |
82 | } else { | 82 | } else { |
83 | lua_pushnumber(L, total); | 83 | lua_pushnumber(L, total); |
@@ -98,22 +98,26 @@ int buf_meth_receive(lua_State *L, p_buf buf) { | |||
98 | int err = IO_DONE, top = lua_gettop(L); | 98 | int err = IO_DONE, top = lua_gettop(L); |
99 | p_tm tm = tm_markstart(buf->tm); | 99 | p_tm tm = tm_markstart(buf->tm); |
100 | luaL_Buffer b; | 100 | luaL_Buffer b; |
101 | size_t size; | ||
102 | const char *part = luaL_optlstring(L, 3, "", &size); | ||
103 | /* initialize buffer with optional extra prefix | ||
104 | * (useful for concatenating previous partial results) */ | ||
101 | luaL_buffinit(L, &b); | 105 | luaL_buffinit(L, &b); |
102 | /* receive all patterns */ | 106 | luaL_addlstring(&b, part, size); |
107 | /* receive new patterns */ | ||
103 | if (!lua_isnumber(L, 2)) { | 108 | if (!lua_isnumber(L, 2)) { |
104 | static const char *patternnames[] = {"*l", "*a", NULL}; | 109 | const char *p= luaL_optstring(L, 2, "*l"); |
105 | const char *pattern = luaL_optstring(L, 2, "*l"); | 110 | if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); |
106 | /* get next pattern */ | 111 | else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); |
107 | int p = luaL_findstring(pattern, patternnames); | ||
108 | if (p == 0) err = recvline(buf, &b); | ||
109 | else if (p == 1) err = recvall(buf, &b); | ||
110 | else luaL_argcheck(L, 0, 2, "invalid receive pattern"); | 112 | else luaL_argcheck(L, 0, 2, "invalid receive pattern"); |
111 | /* get a fixed number of bytes */ | 113 | /* get a fixed number of bytes */ |
112 | } else err = recvraw(buf, (size_t) lua_tonumber(L, 2), &b); | 114 | } else err = recvraw(buf, (size_t) lua_tonumber(L, 2), &b); |
113 | /* check if there was an error */ | 115 | /* check if there was an error */ |
114 | if (err != IO_DONE) { | 116 | if (err != IO_DONE) { |
117 | /* we can't push anyting in the stack before pushing the | ||
118 | * contents of the buffer. this is the reason for the complication */ | ||
115 | luaL_pushresult(&b); | 119 | luaL_pushresult(&b); |
116 | io_pusherror(L, buf->io, err); | 120 | lua_pushstring(L, buf->io->error(buf->io->ctx, err)); |
117 | lua_pushvalue(L, -2); | 121 | lua_pushvalue(L, -2); |
118 | lua_pushnil(L); | 122 | lua_pushnil(L); |
119 | lua_replace(L, -4); | 123 | lua_replace(L, -4); |
@@ -50,22 +50,28 @@ int inet_open(lua_State *L) | |||
50 | * Returns all information provided by the resolver given a host name | 50 | * Returns all information provided by the resolver given a host name |
51 | * or ip address | 51 | * or ip address |
52 | \*-------------------------------------------------------------------------*/ | 52 | \*-------------------------------------------------------------------------*/ |
53 | static int inet_global_toip(lua_State *L) | 53 | static int inet_gethost(const char *address, struct hostent **hp) { |
54 | { | ||
55 | const char *address = luaL_checkstring(L, 1); | ||
56 | struct in_addr addr; | 54 | struct in_addr addr; |
57 | struct hostent *hp; | ||
58 | if (inet_aton(address, &addr)) | 55 | if (inet_aton(address, &addr)) |
59 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); | 56 | return sock_gethostbyaddr((char *) &addr, sizeof(addr), hp); |
60 | else | 57 | else |
61 | hp = gethostbyname(address); | 58 | return sock_gethostbyname(address, hp); |
62 | if (!hp) { | 59 | } |
60 | |||
61 | /*-------------------------------------------------------------------------*\ | ||
62 | * Returns all information provided by the resolver given a host name | ||
63 | * or ip address | ||
64 | \*-------------------------------------------------------------------------*/ | ||
65 | static int inet_global_tohostname(lua_State *L) { | ||
66 | const char *address = luaL_checkstring(L, 1); | ||
67 | struct hostent *hp = NULL; | ||
68 | int err = inet_gethost(address, &hp); | ||
69 | if (err != IO_DONE) { | ||
63 | lua_pushnil(L); | 70 | lua_pushnil(L); |
64 | lua_pushstring(L, sock_hoststrerror()); | 71 | lua_pushstring(L, sock_hoststrerror(err)); |
65 | return 2; | 72 | return 2; |
66 | } | 73 | } |
67 | addr = *((struct in_addr *) hp->h_addr); | 74 | lua_pushstring(L, hp->h_name); |
68 | lua_pushstring(L, inet_ntoa(addr)); | ||
69 | inet_pushresolved(L, hp); | 75 | inet_pushresolved(L, hp); |
70 | return 2; | 76 | return 2; |
71 | } | 77 | } |
@@ -74,25 +80,22 @@ static int inet_global_toip(lua_State *L) | |||
74 | * Returns all information provided by the resolver given a host name | 80 | * Returns all information provided by the resolver given a host name |
75 | * or ip address | 81 | * or ip address |
76 | \*-------------------------------------------------------------------------*/ | 82 | \*-------------------------------------------------------------------------*/ |
77 | static int inet_global_tohostname(lua_State *L) | 83 | static int inet_global_toip(lua_State *L) |
78 | { | 84 | { |
79 | const char *address = luaL_checkstring(L, 1); | 85 | const char *address = luaL_checkstring(L, 1); |
80 | struct in_addr addr; | 86 | struct hostent *hp = NULL; |
81 | struct hostent *hp; | 87 | int err = inet_gethost(address, &hp); |
82 | if (inet_aton(address, &addr)) | 88 | if (err != IO_DONE) { |
83 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); | ||
84 | else | ||
85 | hp = gethostbyname(address); | ||
86 | if (!hp) { | ||
87 | lua_pushnil(L); | 89 | lua_pushnil(L); |
88 | lua_pushstring(L, sock_hoststrerror()); | 90 | lua_pushstring(L, sock_hoststrerror(err)); |
89 | return 2; | 91 | return 2; |
90 | } | 92 | } |
91 | lua_pushstring(L, hp->h_name); | 93 | lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); |
92 | inet_pushresolved(L, hp); | 94 | inet_pushresolved(L, hp); |
93 | return 2; | 95 | return 2; |
94 | } | 96 | } |
95 | 97 | ||
98 | |||
96 | /*-------------------------------------------------------------------------*\ | 99 | /*-------------------------------------------------------------------------*\ |
97 | * Gets the host name | 100 | * Gets the host name |
98 | \*-------------------------------------------------------------------------*/ | 101 | \*-------------------------------------------------------------------------*/ |
@@ -191,9 +194,8 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
191 | /*-------------------------------------------------------------------------*\ | 194 | /*-------------------------------------------------------------------------*\ |
192 | * Tries to create a new inet socket | 195 | * Tries to create a new inet socket |
193 | \*-------------------------------------------------------------------------*/ | 196 | \*-------------------------------------------------------------------------*/ |
194 | const char *inet_trycreate(p_sock ps, int type) | 197 | const char *inet_trycreate(p_sock ps, int type) { |
195 | { | 198 | return sock_strerror(sock_create(ps, AF_INET, type, 0)); |
196 | return sock_create(ps, AF_INET, type, 0); | ||
197 | } | 199 | } |
198 | 200 | ||
199 | /*-------------------------------------------------------------------------*\ | 201 | /*-------------------------------------------------------------------------*\ |
@@ -203,22 +205,23 @@ const char *inet_tryconnect(p_sock ps, const char *address, | |||
203 | unsigned short port, p_tm tm) | 205 | unsigned short port, p_tm tm) |
204 | { | 206 | { |
205 | struct sockaddr_in remote; | 207 | struct sockaddr_in remote; |
206 | const char *err; | 208 | int err; |
207 | memset(&remote, 0, sizeof(remote)); | 209 | memset(&remote, 0, sizeof(remote)); |
208 | remote.sin_family = AF_INET; | 210 | remote.sin_family = AF_INET; |
209 | remote.sin_port = htons(port); | 211 | remote.sin_port = htons(port); |
210 | if (strcmp(address, "*")) { | 212 | if (strcmp(address, "*")) { |
211 | if (!strlen(address) || !inet_aton(address, &remote.sin_addr)) { | 213 | if (!strlen(address) || !inet_aton(address, &remote.sin_addr)) { |
212 | struct hostent *hp = gethostbyname(address); | 214 | struct hostent *hp = NULL; |
213 | struct in_addr **addr; | 215 | struct in_addr **addr; |
214 | if (!hp) return sock_hoststrerror(); | 216 | err = sock_gethostbyname(address, &hp); |
217 | if (err != IO_DONE) return sock_hoststrerror(err); | ||
215 | addr = (struct in_addr **) hp->h_addr_list; | 218 | addr = (struct in_addr **) hp->h_addr_list; |
216 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); | 219 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); |
217 | } | 220 | } |
218 | } else remote.sin_family = AF_UNSPEC; | 221 | } else remote.sin_family = AF_UNSPEC; |
219 | err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm); | 222 | err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm); |
220 | if (err) sock_destroy(ps); | 223 | if (err != IO_DONE) sock_destroy(ps); |
221 | return err; | 224 | return sock_strerror(err); |
222 | } | 225 | } |
223 | 226 | ||
224 | /*-------------------------------------------------------------------------*\ | 227 | /*-------------------------------------------------------------------------*\ |
@@ -227,7 +230,7 @@ const char *inet_tryconnect(p_sock ps, const char *address, | |||
227 | const char *inet_trybind(p_sock ps, const char *address, unsigned short port) | 230 | const char *inet_trybind(p_sock ps, const char *address, unsigned short port) |
228 | { | 231 | { |
229 | struct sockaddr_in local; | 232 | struct sockaddr_in local; |
230 | const char *err; | 233 | int err; |
231 | memset(&local, 0, sizeof(local)); | 234 | memset(&local, 0, sizeof(local)); |
232 | /* address is either wildcard or a valid ip address */ | 235 | /* address is either wildcard or a valid ip address */ |
233 | local.sin_addr.s_addr = htonl(INADDR_ANY); | 236 | local.sin_addr.s_addr = htonl(INADDR_ANY); |
@@ -235,15 +238,16 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port) | |||
235 | local.sin_family = AF_INET; | 238 | local.sin_family = AF_INET; |
236 | if (strcmp(address, "*") && | 239 | if (strcmp(address, "*") && |
237 | (!strlen(address) || !inet_aton(address, &local.sin_addr))) { | 240 | (!strlen(address) || !inet_aton(address, &local.sin_addr))) { |
238 | struct hostent *hp = gethostbyname(address); | 241 | struct hostent *hp = NULL; |
239 | struct in_addr **addr; | 242 | struct in_addr **addr; |
240 | if (!hp) return sock_hoststrerror(); | 243 | err = sock_gethostbyname(address, &hp); |
244 | if (err != IO_DONE) return sock_hoststrerror(err); | ||
241 | addr = (struct in_addr **) hp->h_addr_list; | 245 | addr = (struct in_addr **) hp->h_addr_list; |
242 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); | 246 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); |
243 | } | 247 | } |
244 | err = sock_bind(ps, (SA *) &local, sizeof(local)); | 248 | err = sock_bind(ps, (SA *) &local, sizeof(local)); |
245 | if (err) sock_destroy(ps); | 249 | if (err != IO_DONE) sock_destroy(ps); |
246 | return err; | 250 | return sock_strerror(err); |
247 | } | 251 | } |
248 | 252 | ||
249 | /*-------------------------------------------------------------------------*\ | 253 | /*-------------------------------------------------------------------------*\ |
@@ -12,34 +12,22 @@ | |||
12 | /*-------------------------------------------------------------------------*\ | 12 | /*-------------------------------------------------------------------------*\ |
13 | * Initializes C structure | 13 | * Initializes C structure |
14 | \*-------------------------------------------------------------------------*/ | 14 | \*-------------------------------------------------------------------------*/ |
15 | void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx) { | 15 | void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { |
16 | io->send = send; | 16 | io->send = send; |
17 | io->recv = recv; | 17 | io->recv = recv; |
18 | io->geterr = geterr; | 18 | io->error = error; |
19 | io->ctx = ctx; | 19 | io->ctx = ctx; |
20 | } | 20 | } |
21 | 21 | ||
22 | /*-------------------------------------------------------------------------*\ | 22 | /*-------------------------------------------------------------------------*\ |
23 | * Translate error codes to Lua | 23 | * I/O error strings |
24 | \*-------------------------------------------------------------------------*/ | 24 | \*-------------------------------------------------------------------------*/ |
25 | const char *io_strerror(int code) { | 25 | const char *io_strerror(int err) { |
26 | switch (code) { | 26 | switch (err) { |
27 | case IO_DONE: return NULL; | 27 | case IO_DONE: return NULL; |
28 | case IO_CLOSED: return "closed"; | 28 | case IO_CLOSED: return "closed"; |
29 | case IO_TIMEOUT: return "timeout"; | 29 | case IO_TIMEOUT: return "timeout"; |
30 | case IO_CLIPPED: return "clipped"; | 30 | case IO_CLIPPED: return "clipped"; |
31 | default: return "unknown error"; | 31 | default: return "unknown error"; |
32 | } | 32 | } |
33 | } | 33 | } |
34 | |||
35 | /*-------------------------------------------------------------------------*\ | ||
36 | * Push error message from code or from driver | ||
37 | \*-------------------------------------------------------------------------*/ | ||
38 | void io_pusherror(lua_State *L, p_io io, int code) | ||
39 | { | ||
40 | const char *err = NULL; | ||
41 | if (code < IO_USER) err = io_strerror(code); | ||
42 | else err = io->geterr(io->ctx, code); | ||
43 | if (err) lua_pushstring(L, err); | ||
44 | else lua_pushnil(L); | ||
45 | } | ||
@@ -21,13 +21,18 @@ | |||
21 | 21 | ||
22 | /* IO error codes */ | 22 | /* IO error codes */ |
23 | enum { | 23 | enum { |
24 | IO_DONE, /* operation completed successfully */ | 24 | IO_DONE = 0, /* operation completed successfully */ |
25 | IO_TIMEOUT, /* operation timed out */ | 25 | IO_TIMEOUT = -1, /* operation timed out */ |
26 | IO_CLOSED, /* the connection has been closed */ | 26 | IO_CLOSED = -2, /* the connection has been closed */ |
27 | IO_CLIPPED, /* maxium bytes count reached */ | 27 | IO_CLIPPED = -3 /* maxium bytes count reached */ |
28 | IO_USER /* last element in enum is user custom error */ | ||
29 | }; | 28 | }; |
30 | 29 | ||
30 | /* interface to error message function */ | ||
31 | typedef const char *(*p_error) ( | ||
32 | void *ctx, /* context needed by send */ | ||
33 | int err /* error code */ | ||
34 | ); | ||
35 | |||
31 | /* interface to send function */ | 36 | /* interface to send function */ |
32 | typedef int (*p_send) ( | 37 | typedef int (*p_send) ( |
33 | void *ctx, /* context needed by send */ | 38 | void *ctx, /* context needed by send */ |
@@ -37,12 +42,6 @@ typedef int (*p_send) ( | |||
37 | p_tm tm /* timeout control */ | 42 | p_tm tm /* timeout control */ |
38 | ); | 43 | ); |
39 | 44 | ||
40 | /* returns an error string */ | ||
41 | typedef const char *(*p_geterr) ( | ||
42 | void *ctx, /* context needed by geterror */ | ||
43 | int code /* error code */ | ||
44 | ); | ||
45 | |||
46 | /* interface to recv function */ | 45 | /* interface to recv function */ |
47 | typedef int (*p_recv) ( | 46 | typedef int (*p_recv) ( |
48 | void *ctx, /* context needed by recv */ | 47 | void *ctx, /* context needed by recv */ |
@@ -57,12 +56,11 @@ typedef struct t_io_ { | |||
57 | void *ctx; /* context needed by send/recv */ | 56 | void *ctx; /* context needed by send/recv */ |
58 | p_send send; /* send function pointer */ | 57 | p_send send; /* send function pointer */ |
59 | p_recv recv; /* receive function pointer */ | 58 | p_recv recv; /* receive function pointer */ |
60 | p_geterr geterr; /* receive function pointer */ | 59 | p_error error; /* strerror function */ |
61 | } t_io; | 60 | } t_io; |
62 | typedef t_io *p_io; | 61 | typedef t_io *p_io; |
63 | 62 | ||
64 | const char *io_strerror(int code); | 63 | void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); |
65 | void io_pusherror(lua_State *L, p_io io, int code); | 64 | const char *io_strerror(int err); |
66 | void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx); | ||
67 | 65 | ||
68 | #endif /* IO_H */ | 66 | #endif /* IO_H */ |
diff --git a/src/socket.h b/src/socket.h index 787b7a5..368c2b6 100644 --- a/src/socket.h +++ b/src/socket.h | |||
@@ -41,8 +41,6 @@ int sock_open(void); | |||
41 | int sock_close(void); | 41 | int sock_close(void); |
42 | void sock_destroy(p_sock ps); | 42 | void sock_destroy(p_sock ps); |
43 | void sock_shutdown(p_sock ps, int how); | 43 | void sock_shutdown(p_sock ps, int how); |
44 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm); | ||
45 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm); | ||
46 | int sock_sendto(p_sock ps, const char *data, size_t count, | 44 | int sock_sendto(p_sock ps, const char *data, size_t count, |
47 | size_t *sent, SA *addr, socklen_t addr_len, p_tm tm); | 45 | size_t *sent, SA *addr, socklen_t addr_len, p_tm tm); |
48 | int sock_recvfrom(p_sock ps, char *data, size_t count, | 46 | int sock_recvfrom(p_sock ps, char *data, size_t count, |
@@ -51,15 +49,22 @@ void sock_setnonblocking(p_sock ps); | |||
51 | void sock_setblocking(p_sock ps); | 49 | void sock_setblocking(p_sock ps); |
52 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm); | 50 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm); |
53 | 51 | ||
54 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); | 52 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); |
55 | const char *sock_create(p_sock ps, int domain, int type, int protocol); | 53 | int sock_create(p_sock ps, int domain, int type, int protocol); |
56 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len); | 54 | int sock_bind(p_sock ps, SA *addr, socklen_t addr_len); |
57 | const char *sock_listen(p_sock ps, int backlog); | 55 | int sock_listen(p_sock ps, int backlog); |
58 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | 56 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm); |
59 | socklen_t *addr_len, p_tm tm); | 57 | |
58 | const char *sock_hoststrerror(int err); | ||
59 | const char *sock_strerror(int err); | ||
60 | |||
61 | /* these are perfect to use with the io abstraction module | ||
62 | and the buffered input module */ | ||
63 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm); | ||
64 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm); | ||
65 | const char *sock_ioerror(p_sock ps, int err); | ||
60 | 66 | ||
61 | const char *sock_geterr(p_sock ps, int code); | 67 | int sock_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); |
62 | const char *sock_hoststrerror(void); | 68 | int sock_gethostbyname(const char *addr, struct hostent **hp); |
63 | const char *sock_strerror(void); | ||
64 | 69 | ||
65 | #endif /* SOCK_H */ | 70 | #endif /* SOCK_H */ |
@@ -160,22 +160,22 @@ static int meth_accept(lua_State *L) | |||
160 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); | 160 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); |
161 | p_tm tm = tm_markstart(&server->tm); | 161 | p_tm tm = tm_markstart(&server->tm); |
162 | t_sock sock; | 162 | t_sock sock; |
163 | const char *err = sock_accept(&server->sock, &sock, NULL, NULL, tm); | 163 | int err = sock_accept(&server->sock, &sock, NULL, NULL, tm); |
164 | /* if successful, push client socket */ | 164 | /* if successful, push client socket */ |
165 | if (!err) { | 165 | if (err == IO_DONE) { |
166 | p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | 166 | p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); |
167 | aux_setclass(L, "tcp{client}", -1); | 167 | aux_setclass(L, "tcp{client}", -1); |
168 | /* initialize structure fields */ | 168 | /* initialize structure fields */ |
169 | sock_setnonblocking(&sock); | 169 | sock_setnonblocking(&sock); |
170 | clnt->sock = sock; | 170 | clnt->sock = sock; |
171 | io_init(&clnt->io, (p_send) sock_send, (p_recv) sock_recv, | 171 | io_init(&clnt->io, (p_send) sock_send, (p_recv) sock_recv, |
172 | (p_geterr) sock_geterr, &clnt->sock); | 172 | (p_error) sock_ioerror, &clnt->sock); |
173 | tm_init(&clnt->tm, -1, -1); | 173 | tm_init(&clnt->tm, -1, -1); |
174 | buf_init(&clnt->buf, &clnt->io, &clnt->tm); | 174 | buf_init(&clnt->buf, &clnt->io, &clnt->tm); |
175 | return 1; | 175 | return 1; |
176 | } else { | 176 | } else { |
177 | lua_pushnil(L); | 177 | lua_pushnil(L); |
178 | lua_pushstring(L, err); | 178 | lua_pushstring(L, sock_strerror(err)); |
179 | return 2; | 179 | return 2; |
180 | } | 180 | } |
181 | } | 181 | } |
@@ -236,10 +236,10 @@ static int meth_listen(lua_State *L) | |||
236 | { | 236 | { |
237 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | 237 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); |
238 | int backlog = (int) luaL_optnumber(L, 2, 32); | 238 | int backlog = (int) luaL_optnumber(L, 2, 32); |
239 | const char *err = sock_listen(&tcp->sock, backlog); | 239 | int err = sock_listen(&tcp->sock, backlog); |
240 | if (err) { | 240 | if (err != IO_DONE) { |
241 | lua_pushnil(L); | 241 | lua_pushnil(L); |
242 | lua_pushstring(L, err); | 242 | lua_pushstring(L, sock_strerror(err)); |
243 | return 2; | 243 | return 2; |
244 | } | 244 | } |
245 | /* turn master object into a server object */ | 245 | /* turn master object into a server object */ |
@@ -320,7 +320,7 @@ static int global_create(lua_State *L) | |||
320 | sock_setnonblocking(&sock); | 320 | sock_setnonblocking(&sock); |
321 | tcp->sock = sock; | 321 | tcp->sock = sock; |
322 | io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, | 322 | io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, |
323 | (p_geterr) sock_geterr, &tcp->sock); | 323 | (p_error) sock_ioerror, &tcp->sock); |
324 | tm_init(&tcp->tm, -1, -1); | 324 | tm_init(&tcp->tm, -1, -1); |
325 | buf_init(&tcp->buf, &tcp->io, &tcp->tm); | 325 | buf_init(&tcp->buf, &tcp->io, &tcp->tm); |
326 | return 1; | 326 | return 1; |
diff --git a/src/timeout.h b/src/timeout.h index 817922f..595aac2 100644 --- a/src/timeout.h +++ b/src/timeout.h | |||
@@ -25,4 +25,6 @@ double tm_getstart(p_tm tm); | |||
25 | double tm_gettime(void); | 25 | double 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); |
27 | 27 | ||
28 | #define tm_iszero(tm) ((tm)->block == 0.0) | ||
29 | |||
28 | #endif /* TM_H */ | 30 | #endif /* TM_H */ |
@@ -41,7 +41,6 @@ static int meth_settimeout(lua_State *L); | |||
41 | static int meth_getfd(lua_State *L); | 41 | static int meth_getfd(lua_State *L); |
42 | static int meth_setfd(lua_State *L); | 42 | static int meth_setfd(lua_State *L); |
43 | static int meth_dirty(lua_State *L); | 43 | static int meth_dirty(lua_State *L); |
44 | static void pusherror(lua_State *L, int code); | ||
45 | 44 | ||
46 | /* udp object methods */ | 45 | /* udp object methods */ |
47 | static luaL_reg udp[] = { | 46 | static luaL_reg udp[] = { |
@@ -100,18 +99,14 @@ int udp_open(lua_State *L) | |||
100 | return 0; | 99 | return 0; |
101 | } | 100 | } |
102 | 101 | ||
103 | |||
104 | /*=========================================================================*\ | 102 | /*=========================================================================*\ |
105 | * Lua methods | 103 | * Lua methods |
106 | \*=========================================================================*/ | 104 | \*=========================================================================*/ |
107 | /*-------------------------------------------------------------------------*\ | 105 | const char *udp_strerror(int err) { |
108 | * Pushes the error message | 106 | /* a 'closed' error on an unconnected means the target address was not |
109 | \*-------------------------------------------------------------------------*/ | 107 | * accepted by the transport layer */ |
110 | void pusherror(lua_State *L, int code) { | 108 | if (err == IO_CLOSED) return "refused"; |
111 | const char *err = code != IO_USER? io_strerror(code): "refused"; | 109 | else return sock_strerror(err); |
112 | err = err? err: sock_strerror(); | ||
113 | if (err) lua_pushstring(L, err); | ||
114 | else lua_pushnil(L); | ||
115 | } | 110 | } |
116 | 111 | ||
117 | /*-------------------------------------------------------------------------*\ | 112 | /*-------------------------------------------------------------------------*\ |
@@ -125,12 +120,13 @@ static int meth_send(lua_State *L) { | |||
125 | const char *data = luaL_checklstring(L, 2, &count); | 120 | const char *data = luaL_checklstring(L, 2, &count); |
126 | tm_markstart(tm); | 121 | tm_markstart(tm); |
127 | err = sock_send(&udp->sock, data, count, &sent, tm); | 122 | err = sock_send(&udp->sock, data, count, &sent, tm); |
128 | if (err == IO_DONE) lua_pushnumber(L, sent); | 123 | if (err != IO_DONE) { |
129 | else lua_pushnil(L); | 124 | lua_pushnil(L); |
130 | /* a 'closed' error on an unconnected means the target address was not | 125 | lua_pushstring(L, udp_strerror(err)); |
131 | * accepted by the transport layer */ | 126 | return 2; |
132 | pusherror(L, err == IO_CLOSED ? IO_USER : err); | 127 | } |
133 | return 2; | 128 | lua_pushnumber(L, sent); |
129 | return 1; | ||
134 | } | 130 | } |
135 | 131 | ||
136 | /*-------------------------------------------------------------------------*\ | 132 | /*-------------------------------------------------------------------------*\ |
@@ -153,12 +149,13 @@ static int meth_sendto(lua_State *L) { | |||
153 | tm_markstart(tm); | 149 | tm_markstart(tm); |
154 | err = sock_sendto(&udp->sock, data, count, &sent, | 150 | err = sock_sendto(&udp->sock, data, count, &sent, |
155 | (SA *) &addr, sizeof(addr), tm); | 151 | (SA *) &addr, sizeof(addr), tm); |
156 | if (err == IO_DONE) lua_pushnumber(L, sent); | 152 | if (err != IO_DONE) { |
157 | else lua_pushnil(L); | 153 | lua_pushnil(L); |
158 | /* a 'closed' error on an unconnected means the target address was not | 154 | lua_pushstring(L, udp_strerror(err)); |
159 | * accepted by the transport layer */ | 155 | return 2; |
160 | pusherror(L, err == IO_CLOSED ? IO_USER : err); | 156 | } |
161 | return 2; | 157 | lua_pushnumber(L, sent); |
158 | return 1; | ||
162 | } | 159 | } |
163 | 160 | ||
164 | /*-------------------------------------------------------------------------*\ | 161 | /*-------------------------------------------------------------------------*\ |
@@ -173,10 +170,13 @@ static int meth_receive(lua_State *L) { | |||
173 | count = MIN(count, sizeof(buffer)); | 170 | count = MIN(count, sizeof(buffer)); |
174 | tm_markstart(tm); | 171 | tm_markstart(tm); |
175 | err = sock_recv(&udp->sock, buffer, count, &got, tm); | 172 | err = sock_recv(&udp->sock, buffer, count, &got, tm); |
176 | if (err == IO_DONE) lua_pushlstring(L, buffer, got); | 173 | if (err != IO_DONE) { |
177 | else lua_pushnil(L); | 174 | lua_pushnil(L); |
178 | pusherror(L, err); | 175 | lua_pushstring(L, udp_strerror(err)); |
179 | return 2; | 176 | return 2; |
177 | } | ||
178 | lua_pushlstring(L, buffer, got); | ||
179 | return 1; | ||
180 | } | 180 | } |
181 | 181 | ||
182 | /*-------------------------------------------------------------------------*\ | 182 | /*-------------------------------------------------------------------------*\ |
@@ -201,7 +201,7 @@ static int meth_receivefrom(lua_State *L) { | |||
201 | return 3; | 201 | return 3; |
202 | } else { | 202 | } else { |
203 | lua_pushnil(L); | 203 | lua_pushnil(L); |
204 | pusherror(L, err); | 204 | lua_pushstring(L, udp_strerror(err)); |
205 | return 2; | 205 | return 2; |
206 | } | 206 | } |
207 | } | 207 | } |
diff --git a/src/usocket.c b/src/usocket.c index 4e73a96..4d4f092 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
@@ -14,6 +14,63 @@ | |||
14 | #include "socket.h" | 14 | #include "socket.h" |
15 | 15 | ||
16 | /*-------------------------------------------------------------------------*\ | 16 | /*-------------------------------------------------------------------------*\ |
17 | * Wait for readable/writable/connected socket with timeout | ||
18 | \*-------------------------------------------------------------------------*/ | ||
19 | #ifdef SOCK_POLL | ||
20 | #include <sys/poll.h> | ||
21 | |||
22 | #define WAITFD_R POLLIN | ||
23 | #define WAITFD_W POLLOUT | ||
24 | #define WAITFD_C (POLLIN|POLLOUT) | ||
25 | static int sock_waitfd(int fd, int sw, p_tm tm) { | ||
26 | int ret; | ||
27 | struct pollfd pfd; | ||
28 | pfd.fd = fd; | ||
29 | pfd.events = sw; | ||
30 | pfd.revents = 0; | ||
31 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | ||
32 | do ret = poll(&pfd, 1, (int)(tm_getretry(tm)*1e3)); | ||
33 | while (ret == -1 && errno == EINTR); | ||
34 | if (ret == -1) return errno; | ||
35 | if (ret == 0) return IO_TIMEOUT; | ||
36 | if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; | ||
37 | return IO_DONE; | ||
38 | } | ||
39 | #else | ||
40 | |||
41 | #define WAITFD_R 1 | ||
42 | #define WAITFD_W 2 | ||
43 | #define WAITFD_C (WAITFD_R|WAITFD_W) | ||
44 | |||
45 | static int sock_waitfd(int fd, int sw, p_tm tm) { | ||
46 | int ret; | ||
47 | fd_set rfds, wfds, *rp, *wp; | ||
48 | struct timeval tv, *tp; | ||
49 | double t; | ||
50 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | ||
51 | do { | ||
52 | /* must set bits within loop, because select may have modifed them */ | ||
53 | rp = wp = NULL; | ||
54 | if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rp = &rfds; } | ||
55 | if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(fd, &wfds); wp = &wfds; } | ||
56 | t = tm_getretry(tm); | ||
57 | tp = NULL; | ||
58 | if (t >= 0.0) { | ||
59 | tv.tv_sec = (int)t; | ||
60 | tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); | ||
61 | tp = &tv; | ||
62 | } | ||
63 | ret = select(fd+1, rp, wp, NULL, tp); | ||
64 | } while (ret == -1 && errno == EINTR); | ||
65 | if (ret == -1) return errno; | ||
66 | if (ret == 0) return IO_TIMEOUT; | ||
67 | if (sw == WAITFD_C && FD_ISSET(fd, &rfds)) return IO_CLOSED; | ||
68 | return IO_DONE; | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | |||
73 | /*-------------------------------------------------------------------------*\ | ||
17 | * Initializes module | 74 | * Initializes module |
18 | \*-------------------------------------------------------------------------*/ | 75 | \*-------------------------------------------------------------------------*/ |
19 | int sock_open(void) { | 76 | int sock_open(void) { |
@@ -58,59 +115,19 @@ int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) { | |||
58 | /*-------------------------------------------------------------------------*\ | 115 | /*-------------------------------------------------------------------------*\ |
59 | * Creates and sets up a socket | 116 | * Creates and sets up a socket |
60 | \*-------------------------------------------------------------------------*/ | 117 | \*-------------------------------------------------------------------------*/ |
61 | const char *sock_create(p_sock ps, int domain, int type, int protocol) { | 118 | int sock_create(p_sock ps, int domain, int type, int protocol) { |
62 | t_sock sock = socket(domain, type, protocol); | 119 | *ps = socket(domain, type, protocol); |
63 | if (sock == SOCK_INVALID) return sock_strerror(); | 120 | if (*ps != SOCK_INVALID) return IO_DONE; |
64 | *ps = sock; | 121 | else return errno; |
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | /*-------------------------------------------------------------------------*\ | ||
69 | * Connects or returns error message | ||
70 | \*-------------------------------------------------------------------------*/ | ||
71 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) { | ||
72 | t_sock sock = *ps; | ||
73 | int err; | ||
74 | /* don't call on closed socket */ | ||
75 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); | ||
76 | /* ask system to connect */ | ||
77 | do err = connect(sock, addr, addr_len); | ||
78 | while (err < 0 && errno == EINTR); | ||
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 sock_strerror(); | ||
83 | /* optimize for timeout = 0 */ | ||
84 | if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); | ||
85 | /* wait for a timeout or for the system's answer */ | ||
86 | for ( ;; ) { | ||
87 | fd_set rfds, wfds; | ||
88 | FD_ZERO(&rfds); FD_SET(sock, &rfds); | ||
89 | FD_ZERO(&wfds); FD_SET(sock, &wfds); | ||
90 | /* we run select to avoid busy waiting */ | ||
91 | err = sock_select(sock+1, &rfds, &wfds, NULL, tm); | ||
92 | /* if there was an event, check what happened */ | ||
93 | if (err > 0) { | ||
94 | char dummy; | ||
95 | /* recv will set errno to the value a blocking connect would set */ | ||
96 | if (err > 1 && FD_ISSET(sock, &rfds) && | ||
97 | recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) | ||
98 | return sock_strerror(); | ||
99 | else | ||
100 | return NULL; | ||
101 | /* if no event happened, there was a timeout */ | ||
102 | } else if (err == 0) return io_strerror(IO_TIMEOUT); | ||
103 | } | ||
104 | return sock_strerror(); | ||
105 | } | 122 | } |
106 | 123 | ||
107 | /*-------------------------------------------------------------------------*\ | 124 | /*-------------------------------------------------------------------------*\ |
108 | * Binds or returns error message | 125 | * Binds or returns error message |
109 | \*-------------------------------------------------------------------------*/ | 126 | \*-------------------------------------------------------------------------*/ |
110 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { | 127 | int sock_bind(p_sock ps, SA *addr, socklen_t len) { |
111 | const char *err = NULL; | 128 | int err = IO_DONE; |
112 | sock_setblocking(ps); | 129 | sock_setblocking(ps); |
113 | if (bind(*ps, addr, addr_len) < 0) err = sock_strerror(); | 130 | if (bind(*ps, addr, len) < 0) err = errno; |
114 | sock_setnonblocking(ps); | 131 | sock_setnonblocking(ps); |
115 | return err; | 132 | return err; |
116 | } | 133 | } |
@@ -118,10 +135,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { | |||
118 | /*-------------------------------------------------------------------------*\ | 135 | /*-------------------------------------------------------------------------*\ |
119 | * | 136 | * |
120 | \*-------------------------------------------------------------------------*/ | 137 | \*-------------------------------------------------------------------------*/ |
121 | const char* sock_listen(p_sock ps, int backlog) { | 138 | int sock_listen(p_sock ps, int backlog) { |
122 | const char *err = NULL; | 139 | int err = IO_DONE; |
123 | sock_setblocking(ps); | 140 | sock_setblocking(ps); |
124 | if (listen(*ps, backlog)) err = sock_strerror(); | 141 | if (listen(*ps, backlog)) err = errno; |
125 | sock_setnonblocking(ps); | 142 | sock_setnonblocking(ps); |
126 | return err; | 143 | return err; |
127 | } | 144 | } |
@@ -136,37 +153,45 @@ void sock_shutdown(p_sock ps, int how) { | |||
136 | } | 153 | } |
137 | 154 | ||
138 | /*-------------------------------------------------------------------------*\ | 155 | /*-------------------------------------------------------------------------*\ |
156 | * Connects or returns error message | ||
157 | \*-------------------------------------------------------------------------*/ | ||
158 | int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { | ||
159 | int err; | ||
160 | /* avoid calling on closed sockets */ | ||
161 | if (*ps == SOCK_INVALID) return IO_CLOSED; | ||
162 | /* call connect until done or failed without being interrupted */ | ||
163 | do if (connect(*ps, addr, len) == 0) return IO_DONE; | ||
164 | while ((err = errno) == EINTR); | ||
165 | /* if connection failed immediately, return error code */ | ||
166 | if (err != EINPROGRESS && err != EAGAIN) return err; | ||
167 | /* wait until we have the result of the connection attempt or timeout */ | ||
168 | if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) { | ||
169 | /* finaly find out if we succeeded connecting */ | ||
170 | if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; | ||
171 | else return errno; | ||
172 | /* timed out or some weirder error */ | ||
173 | } else return err; | ||
174 | } | ||
175 | |||
176 | /*-------------------------------------------------------------------------*\ | ||
139 | * Accept with timeout | 177 | * Accept with timeout |
140 | \*-------------------------------------------------------------------------*/ | 178 | \*-------------------------------------------------------------------------*/ |
141 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | 179 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) { |
142 | socklen_t *addr_len, p_tm tm) { | 180 | SA daddr; |
143 | t_sock sock = *ps; | 181 | socklen_t dlen = sizeof(daddr); |
144 | SA dummy_addr; | 182 | int err; |
145 | socklen_t dummy_len = sizeof(dummy_addr); | 183 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
146 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); | 184 | if (!addr) addr = &daddr; |
147 | if (!addr) addr = &dummy_addr; | 185 | if (!len) len = &dlen; |
148 | if (!addr_len) addr_len = &dummy_len; | 186 | for ( ;; ) { |
149 | for (;;) { | 187 | if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE; |
150 | int err; | 188 | err = errno; |
151 | fd_set fds; | 189 | if (err == EINTR) continue; |
152 | /* try to accept */ | 190 | if (err != EAGAIN && err != ECONNABORTED) return err; |
153 | do *pa = accept(sock, addr, addr_len); | 191 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; |
154 | while (*pa < 0 && errno == EINTR); | 192 | } |
155 | /* if result is valid, we are done */ | 193 | /* can't reach here */ |
156 | if (*pa != SOCK_INVALID) return NULL; | 194 | return err; |
157 | /* find out if we failed for a fatal reason */ | ||
158 | /* if connection was aborted, we can try again if we have time */ | ||
159 | if (errno != EAGAIN && errno != ECONNABORTED) return sock_strerror(); | ||
160 | /* optimize for timeout = 0 case */ | ||
161 | if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); | ||
162 | /* call select to avoid busy-wait. */ | ||
163 | FD_ZERO(&fds); | ||
164 | FD_SET(sock, &fds); | ||
165 | err = sock_select(sock+1, &fds, NULL, NULL, tm); | ||
166 | if (err == 0) return io_strerror(IO_TIMEOUT); | ||
167 | else if (err < 0) break; | ||
168 | } | ||
169 | return sock_strerror(); | ||
170 | } | 195 | } |
171 | 196 | ||
172 | /*-------------------------------------------------------------------------*\ | 197 | /*-------------------------------------------------------------------------*\ |
@@ -174,132 +199,100 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | |||
174 | \*-------------------------------------------------------------------------*/ | 199 | \*-------------------------------------------------------------------------*/ |
175 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) | 200 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) |
176 | { | 201 | { |
177 | t_sock sock = *ps; | 202 | int err; |
178 | /* avoid making system calls on closed sockets */ | 203 | /* avoid making system calls on closed sockets */ |
179 | if (sock == SOCK_INVALID) return IO_CLOSED; | 204 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
180 | /* loop until we send something or we give up on error */ | 205 | /* loop until we send something or we give up on error */ |
206 | *sent = 0; | ||
181 | for ( ;; ) { | 207 | for ( ;; ) { |
182 | int ret; | 208 | ssize_t put = send(*ps, data, count, 0); |
183 | fd_set fds; | 209 | /* if we sent anything, we are done */ |
184 | ssize_t put; | 210 | if (put > 0) { |
185 | /* make sure we repeat in case the call was interrupted */ | ||
186 | do put = send(sock, data, count, 0); | ||
187 | while (put < 0 && errno == EINTR); | ||
188 | /* if we sent something, get out */ | ||
189 | if (put > 0) { | ||
190 | *sent = put; | 211 | *sent = put; |
191 | return IO_DONE; | 212 | return IO_DONE; |
192 | } | 213 | } |
193 | /* deal with failure */ | 214 | err = errno; |
194 | *sent = 0; | 215 | /* send can't really return 0, but EPIPE means the connection was |
195 | /* here we know the connection has been closed */ | 216 | closed */ |
196 | if (put < 0 && errno == EPIPE) return IO_CLOSED; | 217 | if (put == 0 || err == EPIPE) return IO_CLOSED; |
197 | /* send shouldn't return zero and we can only proceed if | 218 | /* we call was interrupted, just try again */ |
198 | * there was no serious error */ | 219 | if (err == EINTR) continue; |
199 | if (put == 0 || errno != EAGAIN) return IO_USER; | 220 | /* if failed fatal reason, report error */ |
200 | /* optimize for the timeout = 0 case */ | 221 | if (err != EAGAIN) return err; |
201 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 222 | /* wait until we can send something or we timeout */ |
202 | /* run select to avoid busy wait */ | 223 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; |
203 | FD_ZERO(&fds); | 224 | } |
204 | FD_SET(sock, &fds); | 225 | /* can't reach here */ |
205 | ret = sock_select(sock+1, NULL, &fds, NULL, tm); | 226 | return err; |
206 | if (ret == 0) return IO_TIMEOUT; | ||
207 | else if (ret < 0) break; | ||
208 | /* otherwise, try sending again */ | ||
209 | } | ||
210 | return IO_USER; | ||
211 | } | 227 | } |
212 | 228 | ||
213 | /*-------------------------------------------------------------------------*\ | 229 | /*-------------------------------------------------------------------------*\ |
214 | * Sendto with timeout | 230 | * Sendto with timeout |
215 | \*-------------------------------------------------------------------------*/ | 231 | \*-------------------------------------------------------------------------*/ |
216 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | 232 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, |
217 | SA *addr, socklen_t addr_len, p_tm tm) | 233 | SA *addr, socklen_t len, p_tm tm) |
218 | { | 234 | { |
219 | t_sock sock = *ps; | 235 | int err; |
220 | /* avoid making system calls on closed sockets */ | 236 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
221 | if (sock == SOCK_INVALID) return IO_CLOSED; | 237 | *sent = 0; |
222 | /* loop until we send something or we give up on error */ | ||
223 | for ( ;; ) { | 238 | for ( ;; ) { |
224 | int ret; | 239 | ssize_t put = sendto(*ps, data, count, 0, addr, len); |
225 | fd_set fds; | 240 | if (put > 0) { |
226 | ssize_t put; | ||
227 | do put = sendto(sock, data, count, 0, addr, addr_len); | ||
228 | while (put < 0 && errno == EINTR); | ||
229 | if (put > 0) { | ||
230 | *sent = put; | 241 | *sent = put; |
231 | return IO_DONE; | 242 | return IO_DONE; |
232 | } | 243 | } |
233 | *sent = 0; | 244 | err = errno; |
234 | if (put < 0 && errno == EPIPE) return IO_CLOSED; | 245 | if (put == 0 || err == EPIPE) return IO_CLOSED; |
235 | if (put == 0 || errno != EAGAIN) return IO_USER; | 246 | if (err == EINTR) continue; |
236 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 247 | if (err != EAGAIN) return err; |
237 | FD_ZERO(&fds); | 248 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; |
238 | FD_SET(sock, &fds); | 249 | } |
239 | ret = sock_select(sock+1, NULL, &fds, NULL, tm); | 250 | return err; |
240 | if (ret == 0) return IO_TIMEOUT; | ||
241 | else if (ret < 0) break; | ||
242 | } | ||
243 | return IO_USER; | ||
244 | } | 251 | } |
245 | 252 | ||
246 | /*-------------------------------------------------------------------------*\ | 253 | /*-------------------------------------------------------------------------*\ |
247 | * Receive with timeout | 254 | * Receive with timeout |
248 | \*-------------------------------------------------------------------------*/ | 255 | \*-------------------------------------------------------------------------*/ |
249 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { | 256 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { |
250 | t_sock sock = *ps; | 257 | int err; |
251 | if (sock == SOCK_INVALID) return IO_CLOSED; | 258 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
252 | for ( ;; ) { | 259 | for ( ;; ) { |
253 | fd_set fds; | 260 | ssize_t taken = recv(*ps, data, count, 0); |
254 | int ret; | ||
255 | ssize_t taken; | ||
256 | do taken = read(sock, data, count); | ||
257 | while (taken < 0 && errno == EINTR); | ||
258 | if (taken > 0) { | 261 | if (taken > 0) { |
259 | *got = taken; | 262 | *got = taken; |
260 | return IO_DONE; | 263 | return IO_DONE; |
261 | } | 264 | } |
265 | err = errno; | ||
262 | *got = 0; | 266 | *got = 0; |
263 | if (taken == 0) return IO_CLOSED; | 267 | if (taken == 0) return IO_CLOSED; |
264 | if (errno != EAGAIN) return IO_USER; | 268 | if (err == EINTR) continue; |
265 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 269 | if (err != EAGAIN) return err; |
266 | FD_ZERO(&fds); | 270 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; |
267 | FD_SET(sock, &fds); | 271 | } |
268 | ret = sock_select(sock+1, &fds, NULL, NULL, tm); | 272 | return err; |
269 | if (ret == 0) return IO_TIMEOUT; | ||
270 | else if (ret < 0) break; | ||
271 | } | ||
272 | return IO_USER; | ||
273 | } | 273 | } |
274 | 274 | ||
275 | /*-------------------------------------------------------------------------*\ | 275 | /*-------------------------------------------------------------------------*\ |
276 | * Recvfrom with timeout | 276 | * Recvfrom with timeout |
277 | \*-------------------------------------------------------------------------*/ | 277 | \*-------------------------------------------------------------------------*/ |
278 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | 278 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, |
279 | SA *addr, socklen_t *addr_len, p_tm tm) { | 279 | SA *addr, socklen_t *len, p_tm tm) { |
280 | t_sock sock = *ps; | 280 | int err; |
281 | if (sock == SOCK_INVALID) return IO_CLOSED; | 281 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
282 | for ( ;; ) { | 282 | for ( ;; ) { |
283 | fd_set fds; | 283 | ssize_t taken = recvfrom(*ps, data, count, 0, addr, len); |
284 | int ret; | ||
285 | ssize_t taken; | ||
286 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
287 | while (taken < 0 && errno == EINTR); | ||
288 | if (taken > 0) { | 284 | if (taken > 0) { |
289 | *got = taken; | 285 | *got = taken; |
290 | return IO_DONE; | 286 | return IO_DONE; |
291 | } | 287 | } |
288 | err = errno; | ||
292 | *got = 0; | 289 | *got = 0; |
293 | if (taken == 0) return IO_CLOSED; | 290 | if (taken == 0) return IO_CLOSED; |
294 | if (errno != EAGAIN) return IO_USER; | 291 | if (err == EINTR) continue; |
295 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 292 | if (err != EAGAIN) return err; |
296 | FD_ZERO(&fds); | 293 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; |
297 | FD_SET(sock, &fds); | 294 | } |
298 | ret = sock_select(sock+1, &fds, NULL, NULL, tm); | 295 | return err; |
299 | if (ret == 0) return IO_TIMEOUT; | ||
300 | else if (ret < 0) break; | ||
301 | } | ||
302 | return IO_USER; | ||
303 | } | 296 | } |
304 | 297 | ||
305 | /*-------------------------------------------------------------------------*\ | 298 | /*-------------------------------------------------------------------------*\ |
@@ -321,29 +314,46 @@ void sock_setnonblocking(p_sock ps) { | |||
321 | } | 314 | } |
322 | 315 | ||
323 | /*-------------------------------------------------------------------------*\ | 316 | /*-------------------------------------------------------------------------*\ |
317 | * DNS helpers | ||
318 | \*-------------------------------------------------------------------------*/ | ||
319 | int sock_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { | ||
320 | *hp = gethostbyaddr(addr, len, AF_INET); | ||
321 | if (*hp) return IO_DONE; | ||
322 | else return h_errno; | ||
323 | } | ||
324 | |||
325 | int sock_gethostbyname(const char *addr, struct hostent **hp) { | ||
326 | *hp = gethostbyname(addr); | ||
327 | if (*hp) return IO_DONE; | ||
328 | else return h_errno; | ||
329 | } | ||
330 | |||
331 | /*-------------------------------------------------------------------------*\ | ||
324 | * Error translation functions | 332 | * Error translation functions |
333 | * Make sure important error messages are standard | ||
325 | \*-------------------------------------------------------------------------*/ | 334 | \*-------------------------------------------------------------------------*/ |
326 | const char *sock_hoststrerror(void) { | 335 | const char *sock_hoststrerror(int err) { |
327 | switch (h_errno) { | 336 | if (err <= 0) return io_strerror(err); |
328 | case HOST_NOT_FOUND: | 337 | switch (err) { |
329 | return "host not found"; | 338 | case HOST_NOT_FOUND: return "host_not_found"; |
330 | default: | 339 | default: return hstrerror(err); |
331 | return hstrerror(h_errno); | ||
332 | } | 340 | } |
333 | } | 341 | } |
334 | 342 | ||
335 | /* make sure important error messages are standard */ | 343 | const char *sock_strerror(int err) { |
336 | const char *sock_strerror(void) { | 344 | if (err <= 0) return io_strerror(err); |
337 | switch (errno) { | 345 | switch (err) { |
338 | case EADDRINUSE: | 346 | case EADDRINUSE: return "eaddrinuse"; |
339 | return "address already in use"; | 347 | case EACCES: return "eaccess"; |
340 | default: | 348 | case ECONNABORTED: return "econnaborted"; |
341 | return strerror(errno); | 349 | case ECONNREFUSED: return "econnrefused"; |
350 | case ECONNRESET: return "econnreset"; | ||
351 | case ETIMEDOUT: return "etimedout"; | ||
352 | default: return strerror(errno); | ||
342 | } | 353 | } |
343 | } | 354 | } |
344 | 355 | ||
345 | const char *sock_geterr(p_sock ps, int code) { | 356 | const char *sock_ioerror(p_sock ps, int err) { |
346 | (void) ps; | 357 | (void) ps; |
347 | (void) code; | 358 | return sock_strerror(err); |
348 | return sock_strerror(); | 359 | } |
349 | } | ||
diff --git a/test/httptest.lua b/test/httptest.lua index 5186bd5..1f4158a 100644 --- a/test/httptest.lua +++ b/test/httptest.lua | |||
@@ -19,7 +19,7 @@ http.TIMEOUT = 10 | |||
19 | 19 | ||
20 | local t = socket.gettime() | 20 | local t = socket.gettime() |
21 | 21 | ||
22 | host = host or "diego.student.dyn.cs.princeton.edu" | 22 | host = host or "diego.princeton.edu" |
23 | proxy = proxy or "http://localhost:3128" | 23 | proxy = proxy or "http://localhost:3128" |
24 | prefix = prefix or "/luasocket-test" | 24 | prefix = prefix or "/luasocket-test" |
25 | cgiprefix = cgiprefix or "/luasocket-test-cgi" | 25 | cgiprefix = cgiprefix or "/luasocket-test-cgi" |