aboutsummaryrefslogtreecommitdiff
path: root/src/usocket.c
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-24 00:18:19 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-24 00:18:19 +0000
commit0c9f420a3549df3fb331bb24157b65a3301641d4 (patch)
treee1b6ce40b55a77ed2bc20493f10f8239b7c00071 /src/usocket.c
parent42e0e74487ca62b58a8a1fa06580154c632b4942 (diff)
downloadluasocket-0c9f420a3549df3fb331bb24157b65a3301641d4.tar.gz
luasocket-0c9f420a3549df3fb331bb24157b65a3301641d4.tar.bz2
luasocket-0c9f420a3549df3fb331bb24157b65a3301641d4.zip
New accept/connect code.
Better error checking. Better tests. __tostring implemented.
Diffstat (limited to 'src/usocket.c')
-rw-r--r--src/usocket.c181
1 files changed, 118 insertions, 63 deletions
diff --git a/src/usocket.c b/src/usocket.c
index 5afa1bf..bece354 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -20,9 +20,11 @@
20 20
21#include "socket.h" 21#include "socket.h"
22 22
23static const char *sock_createstrerror(void); 23static const char *sock_createstrerror(int err);
24static const char *sock_bindstrerror(void); 24static const char *sock_bindstrerror(int err);
25static const char *sock_connectstrerror(void); 25static const char *sock_connectstrerror(int err);
26static const char *sock_acceptstrerror(int err);
27static const char *sock_listenstrerror(int err);
26 28
27/*-------------------------------------------------------------------------*\ 29/*-------------------------------------------------------------------------*\
28* Initializes module 30* Initializes module
@@ -46,19 +48,31 @@ int sock_open(void)
46void sock_destroy(p_sock ps) 48void sock_destroy(p_sock ps)
47{ 49{
48 if (*ps != SOCK_INVALID) { 50 if (*ps != SOCK_INVALID) {
51 sock_setblocking(ps);
49 close(*ps); 52 close(*ps);
50 *ps = SOCK_INVALID; 53 *ps = SOCK_INVALID;
51 } 54 }
52} 55}
53 56
54/*-------------------------------------------------------------------------*\ 57/*-------------------------------------------------------------------------*\
58* Select with int timeout in ms
59\*-------------------------------------------------------------------------*/
60int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout)
61{
62 struct timeval tv;
63 tv.tv_sec = timeout / 1000;
64 tv.tv_usec = (timeout % 1000) * 1000;
65 return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL);
66}
67
68/*-------------------------------------------------------------------------*\
55* Creates and sets up a socket 69* Creates and sets up a socket
56\*-------------------------------------------------------------------------*/ 70\*-------------------------------------------------------------------------*/
57const char *sock_create(p_sock ps, int domain, int type, int protocol) 71const char *sock_create(p_sock ps, int domain, int type, int protocol)
58{ 72{
59 int val = 1; 73 int val = 1;
60 t_sock sock = socket(domain, type, protocol); 74 t_sock sock = socket(domain, type, protocol);
61 if (sock == SOCK_INVALID) return sock_createstrerror(); 75 if (sock == SOCK_INVALID) return sock_createstrerror(errno);
62 *ps = sock; 76 *ps = sock;
63 sock_setnonblocking(ps); 77 sock_setnonblocking(ps);
64 setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); 78 setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
@@ -79,27 +93,22 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
79 /* if no error, we're done */ 93 /* if no error, we're done */
80 if (err == 0) return NULL; 94 if (err == 0) return NULL;
81 /* make sure the system is trying to connect */ 95 /* make sure the system is trying to connect */
82 if (errno != EINPROGRESS) return io_strerror(IO_ERROR); 96 if (errno != EINPROGRESS) return sock_connectstrerror(errno);
83 /* wait for a timeout or for the system's answer */ 97 /* wait for a timeout or for the system's answer */
84 for ( ;; ) { 98 for ( ;; ) {
85 struct timeval tv;
86 fd_set rfds, wfds, efds; 99 fd_set rfds, wfds, efds;
87 int timeout = tm_getretry(tm);
88 tv.tv_sec = timeout / 1000;
89 tv.tv_usec = (timeout % 1000) * 1000;
90 FD_ZERO(&rfds); FD_SET(sock, &rfds); 100 FD_ZERO(&rfds); FD_SET(sock, &rfds);
91 FD_ZERO(&wfds); FD_SET(sock, &wfds); 101 FD_ZERO(&wfds); FD_SET(sock, &wfds);
92 FD_ZERO(&efds); FD_SET(sock, &efds); 102 FD_ZERO(&efds); FD_SET(sock, &efds);
93 /* we run select to avoid busy waiting */ 103 /* we run select to avoid busy waiting */
94 err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL); 104 do err = sock_select(sock+1, &rfds, &wfds, &efds, tm_getretry(tm));
95 /* if select was interrupted, try again */ 105 while (err < 0 && errno == EINTR);
96 if (err < 0 && errno == EINTR) continue;
97 /* if selects readable, try reading */ 106 /* if selects readable, try reading */
98 if (err > 0) { 107 if (err > 0) {
99 char dummy; 108 char dummy;
100 /* recv will set errno to the value a blocking connect would set */ 109 /* recv will set errno to the value a blocking connect would set */
101 if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) 110 if (recv(sock, &dummy, 0, 0) < 0 && errno != EWOULDBLOCK)
102 return sock_connectstrerror(); 111 return sock_connectstrerror(errno);
103 else 112 else
104 return NULL; 113 return NULL;
105 /* if no event happened, there was a timeout */ 114 /* if no event happened, there was a timeout */
@@ -113,16 +122,24 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
113\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
114const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) 123const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
115{ 124{
116 if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); 125 const char *err = NULL;
117 else return NULL; 126 sock_setblocking(ps);
127 if (bind(*ps, addr, addr_len) < 0) err = sock_bindstrerror(errno);
128 sock_setnonblocking(ps);
129 return err;
118} 130}
119 131
120/*-------------------------------------------------------------------------*\ 132/*-------------------------------------------------------------------------*\
121* 133*
122\*-------------------------------------------------------------------------*/ 134\*-------------------------------------------------------------------------*/
123void sock_listen(p_sock ps, int backlog) 135const char* sock_listen(p_sock ps, int backlog)
124{ 136{
125 listen(*ps, backlog); 137 const char *err = NULL;
138 sock_setblocking(ps);
139 if (listen(*ps, backlog))
140 err = sock_listenstrerror(errno);
141 sock_setnonblocking(ps);
142 return err;
126} 143}
127 144
128/*-------------------------------------------------------------------------*\ 145/*-------------------------------------------------------------------------*\
@@ -130,35 +147,40 @@ void sock_listen(p_sock ps, int backlog)
130\*-------------------------------------------------------------------------*/ 147\*-------------------------------------------------------------------------*/
131void sock_shutdown(p_sock ps, int how) 148void sock_shutdown(p_sock ps, int how)
132{ 149{
150 sock_setblocking(ps);
133 shutdown(*ps, how); 151 shutdown(*ps, how);
152 sock_setnonblocking(ps);
134} 153}
135 154
136/*-------------------------------------------------------------------------*\ 155/*-------------------------------------------------------------------------*\
137* Accept with timeout 156* Accept with timeout
138\*-------------------------------------------------------------------------*/ 157\*-------------------------------------------------------------------------*/
139int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm) 158const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
159 socklen_t *addr_len, p_tm tm)
140{ 160{
141 t_sock sock = *ps; 161 t_sock sock = *ps;
142 SA dummy_addr; 162 SA dummy_addr;
143 socklen_t dummy_len = sizeof(dummy_addr); 163 socklen_t dummy_len = sizeof(dummy_addr);
144 if (sock == SOCK_INVALID) return IO_CLOSED; 164 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
145 if (!addr) addr = &dummy_addr; 165 if (!addr) addr = &dummy_addr;
146 if (!addr_len) addr_len = &dummy_len; 166 if (!addr_len) addr_len = &dummy_len;
147 for (;;) { 167 for (;;) {
148 int timeout = tm_getretry(tm); 168 int err;
149 struct timeval tv;
150 fd_set fds; 169 fd_set fds;
151 *pa = accept(sock, addr, addr_len); 170 *pa = accept(sock, addr, addr_len);
152 if (*pa != SOCK_INVALID) return IO_DONE; 171 /* if result is valid, we are done */
153 if (timeout == 0) return IO_TIMEOUT; 172 if (*pa != SOCK_INVALID) return NULL;
154 tv.tv_sec = timeout / 1000; 173 /* find out if we failed for a fatal reason */
155 tv.tv_usec = (timeout % 1000) * 1000; 174 if (errno != EWOULDBLOCK && errno != ECONNABORTED)
175 return sock_acceptstrerror(errno);
176 /* call select just to avoid busy-wait. */
156 FD_ZERO(&fds); 177 FD_ZERO(&fds);
157 FD_SET(sock, &fds); 178 FD_SET(sock, &fds);
158 /* call select just to avoid busy-wait. */ 179 do err = sock_select(sock+1, &fds, NULL, NULL, tm_getretry(tm));
159 select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL); 180 while (err < 0 && errno == EINTR);
181 if (err == 0) return io_strerror(IO_TIMEOUT);
160 } 182 }
161 return IO_TIMEOUT; /* can't get here */ 183 return io_strerror(IO_TIMEOUT); /* can't get here */
162} 184}
163 185
164/*-------------------------------------------------------------------------*\ 186/*-------------------------------------------------------------------------*\
@@ -176,18 +198,15 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
176 while (put < 0 && errno == EINTR); 198 while (put < 0 && errno == EINTR);
177 /* deal with failure */ 199 /* deal with failure */
178 if (put <= 0) { 200 if (put <= 0) {
179 struct timeval tv;
180 fd_set fds; 201 fd_set fds;
181 /* in any case, nothing has been sent */ 202 /* in any case, nothing has been sent */
182 *sent = 0; 203 *sent = 0;
183 /* here we know the connection has been closed */ 204 /* here we know the connection has been closed */
184 if (errno == EPIPE) return IO_CLOSED; 205 if (errno == EPIPE) return IO_CLOSED;
185 /* run select to avoid busy wait */ 206 /* run select to avoid busy wait */
186 tv.tv_sec = timeout / 1000;
187 tv.tv_usec = (timeout % 1000) * 1000;
188 FD_ZERO(&fds); 207 FD_ZERO(&fds);
189 FD_SET(sock, &fds); 208 FD_SET(sock, &fds);
190 if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) { 209 if (sock_select(sock+1, NULL, &fds, NULL, timeout) <= 0) {
191 /* here the call was interrupted. calling again might work */ 210 /* here the call was interrupted. calling again might work */
192 if (errno == EINTR) return IO_RETRY; 211 if (errno == EINTR) return IO_RETRY;
193 /* here there was no data before timeout */ 212 /* here there was no data before timeout */
@@ -213,15 +232,12 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
213 do put = sendto(sock, data, count, 0, addr, addr_len); 232 do put = sendto(sock, data, count, 0, addr, addr_len);
214 while (put < 0 && errno == EINTR); 233 while (put < 0 && errno == EINTR);
215 if (put <= 0) { 234 if (put <= 0) {
216 struct timeval tv;
217 fd_set fds; 235 fd_set fds;
218 *sent = 0; 236 *sent = 0;
219 if (errno == EPIPE) return IO_CLOSED; 237 if (errno == EPIPE) return IO_CLOSED;
220 tv.tv_sec = timeout / 1000;
221 tv.tv_usec = (timeout % 1000) * 1000;
222 FD_ZERO(&fds); 238 FD_ZERO(&fds);
223 FD_SET(sock, &fds); 239 FD_SET(sock, &fds);
224 if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) { 240 if (sock_select(sock+1, NULL, &fds, NULL, timeout) <= 0) {
225 if (errno == EINTR) return IO_RETRY; 241 if (errno == EINTR) return IO_RETRY;
226 else return IO_TIMEOUT; 242 else return IO_TIMEOUT;
227 } else return IO_DONE; 243 } else return IO_DONE;
@@ -242,16 +258,13 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
242 do taken = read(sock, data, count); 258 do taken = read(sock, data, count);
243 while (taken < 0 && errno == EINTR); 259 while (taken < 0 && errno == EINTR);
244 if (taken <= 0) { 260 if (taken <= 0) {
245 struct timeval tv;
246 fd_set fds; 261 fd_set fds;
247 int ret; 262 int ret;
248 *got = 0; 263 *got = 0;
249 if (taken == 0) return IO_CLOSED; 264 if (taken == 0) return IO_CLOSED;
250 tv.tv_sec = timeout / 1000;
251 tv.tv_usec = (timeout % 1000) * 1000;
252 FD_ZERO(&fds); 265 FD_ZERO(&fds);
253 FD_SET(sock, &fds); 266 FD_SET(sock, &fds);
254 ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); 267 ret = sock_select(sock+1, &fds, NULL, NULL, timeout);
255 if (ret < 0 && errno == EINTR) return IO_RETRY; 268 if (ret < 0 && errno == EINTR) return IO_RETRY;
256 if (ret == 0) return IO_TIMEOUT; 269 if (ret == 0) return IO_TIMEOUT;
257 else return IO_DONE; 270 else return IO_DONE;
@@ -273,16 +286,13 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
273 do taken = recvfrom(sock, data, count, 0, addr, addr_len); 286 do taken = recvfrom(sock, data, count, 0, addr, addr_len);
274 while (taken < 0 && errno == EINTR); 287 while (taken < 0 && errno == EINTR);
275 if (taken <= 0) { 288 if (taken <= 0) {
276 struct timeval tv;
277 fd_set fds; 289 fd_set fds;
278 int ret; 290 int ret;
279 *got = 0; 291 *got = 0;
280 if (taken == 0) return IO_CLOSED; 292 if (taken == 0) return IO_CLOSED;
281 tv.tv_sec = timeout / 1000;
282 tv.tv_usec = (timeout % 1000) * 1000;
283 FD_ZERO(&fds); 293 FD_ZERO(&fds);
284 FD_SET(sock, &fds); 294 FD_SET(sock, &fds);
285 ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); 295 ret = sock_select(sock+1, &fds, NULL, NULL, timeout);
286 if (ret < 0 && errno == EINTR) return IO_RETRY; 296 if (ret < 0 && errno == EINTR) return IO_RETRY;
287 if (ret == 0) return IO_TIMEOUT; 297 if (ret == 0) return IO_TIMEOUT;
288 else return IO_DONE; 298 else return IO_DONE;
@@ -315,53 +325,98 @@ void sock_setnonblocking(p_sock ps)
315/*-------------------------------------------------------------------------*\ 325/*-------------------------------------------------------------------------*\
316* Error translation functions 326* Error translation functions
317\*-------------------------------------------------------------------------*/ 327\*-------------------------------------------------------------------------*/
328/* return error messages for the known errors reported by gethostbyname */
318const char *sock_hoststrerror(void) 329const char *sock_hoststrerror(void)
319{ 330{
320 switch (h_errno) { 331 switch (h_errno) {
321 case HOST_NOT_FOUND: return "host not found"; 332 case HOST_NOT_FOUND: return "host not found";
322 case NO_ADDRESS: return "unable to resolve host name"; 333 case NO_ADDRESS: return "valid host but no ip found";
323 case NO_RECOVERY: return "name server error"; 334 case NO_RECOVERY: return "name server error";
324 case TRY_AGAIN: return "name server unavailable, try again later"; 335 case TRY_AGAIN: return "name server unavailable, try again later";
325 default: return "unknown error"; 336 default: return "unknown error";
326 } 337 }
327} 338}
328 339
329static const char *sock_createstrerror(void) 340/* return error messages for the known errors reported by socket */
341static const char *sock_createstrerror(int err)
330{ 342{
331 switch (errno) { 343 switch (err) {
344 case EPROTONOSUPPORT: return "protocol not supported";
332 case EACCES: return "access denied"; 345 case EACCES: return "access denied";
333 case EMFILE: return "descriptor table is full"; 346 case EMFILE: return "process file table is full";
334 case ENFILE: return "too many open files"; 347 case ENFILE: return "kernel file table is full";
348 case EINVAL: return "unknown protocol or family";
335 case ENOBUFS: return "insuffucient buffer space"; 349 case ENOBUFS: return "insuffucient buffer space";
336 default: return "unknown error"; 350 default: return "unknown error";
337 } 351 }
338} 352}
339 353
340static const char *sock_bindstrerror(void) 354/* return error messages for the known errors reported by accept */
355static const char *sock_acceptstrerror(int err)
341{ 356{
342 switch (errno) { 357 switch (err) {
358 case EWOULDBLOCK: return io_strerror(IO_RETRY);
343 case EBADF: return "invalid descriptor"; 359 case EBADF: return "invalid descriptor";
344 case EINVAL: return "socket already bound"; 360 case ENOBUFS: case ENOMEM: return "insuffucient buffer space";
345 case EACCES: return "access denied"; 361 case ENOTSOCK: return "descriptor not a socket";
346 case ENOTSOCK: return "not a socket descriptor"; 362 case EOPNOTSUPP: return "not supported";
363 case EINTR: return "call interrupted";
364 case ECONNABORTED: return "connection aborted";
365 case EINVAL: return "not listening";
366 case EMFILE: return "process file table is full";
367 case ENFILE: return "kernel file table is full";
368 case EFAULT: return "invalid memory address";
369 default: return "unknown error";
370 }
371}
372
373
374/* return error messages for the known errors reported by bind */
375static const char *sock_bindstrerror(int err)
376{
377 switch (err) {
378 case EBADF: return "invalid descriptor";
379 case ENOTSOCK: return "descriptor not a socket";
380 case EADDRNOTAVAIL: return "address unavailable in local host";
347 case EADDRINUSE: return "address already in use"; 381 case EADDRINUSE: return "address already in use";
348 case EADDRNOTAVAIL: return "address unavailable"; 382 case EINVAL: return "already bound";
383 case EACCES: return "access denied";
384 case EFAULT: return "invalid memory address";
349 case ENOMEM: return "out of memory"; 385 case ENOMEM: return "out of memory";
350 default: return "unknown error"; 386 default: return "unknown error";
351 } 387 }
352} 388}
353 389
354static const char *sock_connectstrerror(void) 390/* return error messages for the known errors reported by listen */
391static const char *sock_listenstrerror(int err)
355{ 392{
356 switch (errno) { 393 switch (err) {
394 case EADDRINUSE: return "local address already in use";
357 case EBADF: return "invalid descriptor"; 395 case EBADF: return "invalid descriptor";
358 case ENOTSOCK: return "not a socket descriptor"; 396 case ENOTSOCK: return "descriptor not a socket";
359 case EADDRNOTAVAIL: return "address not availabe"; 397 case EOPNOTSUPP: return "not supported";
360 case ETIMEDOUT: return "connection timed out"; 398 default: return "unknown error";
399 }
400}
401
402/* return error messages for the known errors reported by connect */
403static const char *sock_connectstrerror(int err)
404{
405 switch (err) {
406 case EBADF: return "invalid descriptor";
407 case EFAULT: return "invalid memory address";
408 case ENOTSOCK: return "descriptor not a socket";
409 case EADDRNOTAVAIL: return "address not available in local host";
410 case EISCONN: return "already connected";
361 case ECONNREFUSED: return "connection refused"; 411 case ECONNREFUSED: return "connection refused";
362 case EACCES: return "access denied"; 412 case ETIMEDOUT: return io_strerror(IO_TIMEOUT);
363 case ENETUNREACH: return "network is unreachable"; 413 case ENETUNREACH: return "network is unreachable";
364 case EADDRINUSE: return "address already in use"; 414 case EADDRINUSE: return "local address already in use";
415 case EINPROGRESS: return "would block";
416 case EALREADY: return "connect already in progress";
417 case EAGAIN: return "not enough free ports";
418 case EAFNOSUPPORT: return "address family not supported";
419 case EPERM: return "broadcast not enabled or firewall block";
365 default: return "unknown error"; 420 default: return "unknown error";
366 } 421 }
367} 422}