aboutsummaryrefslogtreecommitdiff
path: root/src/wsocket.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/wsocket.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/wsocket.c')
-rw-r--r--src/wsocket.c215
1 files changed, 149 insertions, 66 deletions
diff --git a/src/wsocket.c b/src/wsocket.c
index f834503..f33e154 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -15,9 +15,11 @@
15 15
16#include "socket.h" 16#include "socket.h"
17 17
18static const char *sock_createstrerror(void); 18static const char *sock_createstrerror(int err);
19static const char *sock_bindstrerror(void); 19static const char *sock_bindstrerror(int err);
20static const char *sock_connectstrerror(void); 20static const char *sock_connectstrerror(int err);
21static const char *sock_acceptstrerror(int err);
22static const char *sock_listenstrerror(int err);
21 23
22/*-------------------------------------------------------------------------*\ 24/*-------------------------------------------------------------------------*\
23* Initializes module 25* Initializes module
@@ -36,11 +38,23 @@ int sock_open(void)
36} 38}
37 39
38/*-------------------------------------------------------------------------*\ 40/*-------------------------------------------------------------------------*\
41* Select with int timeout in ms
42\*-------------------------------------------------------------------------*/
43int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout)
44{
45 struct timeval tv;
46 tv.tv_sec = timeout / 1000;
47 tv.tv_usec = (timeout % 1000) * 1000;
48 return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL);
49}
50
51/*-------------------------------------------------------------------------*\
39* Close and inutilize socket 52* Close and inutilize socket
40\*-------------------------------------------------------------------------*/ 53\*-------------------------------------------------------------------------*/
41void sock_destroy(p_sock ps) 54void sock_destroy(p_sock ps)
42{ 55{
43 if (*ps != SOCK_INVALID) { 56 if (*ps != SOCK_INVALID) {
57 sock_setblocking(ps); /* close can take a long time on WIN32 */
44 closesocket(*ps); 58 closesocket(*ps);
45 *ps = SOCK_INVALID; 59 *ps = SOCK_INVALID;
46 } 60 }
@@ -51,7 +65,9 @@ void sock_destroy(p_sock ps)
51\*-------------------------------------------------------------------------*/ 65\*-------------------------------------------------------------------------*/
52void sock_shutdown(p_sock ps, int how) 66void sock_shutdown(p_sock ps, int how)
53{ 67{
68 sock_setblocking(ps);
54 shutdown(*ps, how); 69 shutdown(*ps, how);
70 sock_setnonblocking(ps);
55} 71}
56 72
57/*-------------------------------------------------------------------------*\ 73/*-------------------------------------------------------------------------*\
@@ -61,10 +77,11 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
61{ 77{
62 int val = 1; 78 int val = 1;
63 t_sock sock = socket(domain, type, protocol); 79 t_sock sock = socket(domain, type, protocol);
64 if (sock == SOCK_INVALID) return sock_createstrerror(); 80 if (sock == SOCK_INVALID)
81 return sock_createstrerror(WSAGetLastError());
65 *ps = sock; 82 *ps = sock;
66 sock_setnonblocking(ps);
67 setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); 83 setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
84 sock_setnonblocking(ps);
68 return NULL; 85 return NULL;
69} 86}
70 87
@@ -75,7 +92,6 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
75{ 92{
76 t_sock sock = *ps; 93 t_sock sock = *ps;
77 int err, timeout = tm_getretry(tm); 94 int err, timeout = tm_getretry(tm);
78 struct timeval tv;
79 fd_set efds, wfds; 95 fd_set efds, wfds;
80 /* don't call on closed socket */ 96 /* don't call on closed socket */
81 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); 97 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
@@ -84,27 +100,24 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
84 /* if no error, we're done */ 100 /* if no error, we're done */
85 if (err == 0) return NULL; 101 if (err == 0) return NULL;
86 /* make sure the system is trying to connect */ 102 /* make sure the system is trying to connect */
87 if (WSAGetLastError() != WSAEWOULDBLOCK) return sock_connectstrerror(); 103 err = WSAGetLastError();
104 if (err != WSAEWOULDBLOCK) return sock_connectstrerror(err);
88 /* wait for a timeout or for the system's answer */ 105 /* wait for a timeout or for the system's answer */
89 tv.tv_sec = timeout / 1000;
90 tv.tv_usec = (timeout % 1000) * 1000;
91 FD_ZERO(&wfds); FD_SET(sock, &wfds); 106 FD_ZERO(&wfds); FD_SET(sock, &wfds);
92 FD_ZERO(&efds); FD_SET(sock, &efds); 107 FD_ZERO(&efds); FD_SET(sock, &efds);
93 /* we run select to wait */ 108 /* we run select to wait */
94 err = select(0, NULL, &wfds, &efds, timeout >= 0? &tv: NULL); 109 err = sock_select(0, NULL, &wfds, &efds, timeout);
95 /* if select returned due to an event */ 110 /* if select returned due to an event */
96 if (err > 0 ) { 111 if (err > 0 ) {
97 /* if was in efds, we failed */ 112 /* if was in efds, we failed */
98 if (FD_ISSET(sock,&efds) || !FD_ISSET(sock,&wfds)) { 113 if (FD_ISSET(sock, &efds)) {
99 int why; 114 int why, len = sizeof(why);
100 int len = sizeof(why);
101 /* find out why we failed */ 115 /* find out why we failed */
102 getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len); 116 getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len);
103 WSASetLastError(why); 117 return sock_connectstrerror(why);
104 return sock_connectstrerror(); 118 /* otherwise it must be in wfds, so we succeeded */
105 /* if was in wfds, we succeeded */
106 } else return NULL; 119 } else return NULL;
107 /* if nothing happened, we timed out */ 120 /* if no event happened, we timed out */
108 } else return io_strerror(IO_TIMEOUT); 121 } else return io_strerror(IO_TIMEOUT);
109} 122}
110 123
@@ -113,44 +126,60 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
113\*-------------------------------------------------------------------------*/ 126\*-------------------------------------------------------------------------*/
114const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) 127const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
115{ 128{
116 if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); 129 const char *err = NULL;
117 else return NULL; 130 sock_setblocking(ps);
131 if (bind(*ps, addr, addr_len) < 0)
132 err = sock_bindstrerror(WSAGetLastError());
133 sock_setnonblocking(ps);
134 return err;
118} 135}
119 136
120/*-------------------------------------------------------------------------*\ 137/*-------------------------------------------------------------------------*\
121* 138*
122\*-------------------------------------------------------------------------*/ 139\*-------------------------------------------------------------------------*/
123void sock_listen(p_sock ps, int backlog) 140const char *sock_listen(p_sock ps, int backlog)
124{ 141{
125 listen(*ps, backlog); 142 const char *err = NULL;
143 sock_setblocking(ps);
144 if (listen(*ps, backlog) < 0)
145 err = sock_listenstrerror(WSAGetLastError());
146 sock_setnonblocking(ps);
147 return err;
126} 148}
127 149
128/*-------------------------------------------------------------------------*\ 150/*-------------------------------------------------------------------------*\
129* Accept with timeout 151* Accept with timeout
130\*-------------------------------------------------------------------------*/ 152\*-------------------------------------------------------------------------*/
131int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm) 153const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
154 socklen_t *addr_len, p_tm tm)
132{ 155{
133 t_sock sock = *ps; 156 t_sock sock = *ps;
134 SA dummy_addr; 157 SA dummy_addr;
135 socklen_t dummy_len = sizeof(dummy_addr); 158 socklen_t dummy_len = sizeof(dummy_addr);
136 if (sock == SOCK_INVALID) return IO_CLOSED; 159 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
137 if (!addr) addr = &dummy_addr; 160 if (!addr) addr = &dummy_addr;
138 if (!addr_len) addr_len = &dummy_len; 161 if (!addr_len) addr_len = &dummy_len;
139 for (;;) { 162 for (;;) {
163 fd_set rfds;
140 int timeout = tm_getretry(tm); 164 int timeout = tm_getretry(tm);
141 struct timeval tv; 165 int err;
142 fd_set fds; 166 /* try to get client socket */
143 *pa = accept(sock, addr, addr_len); 167 *pa = accept(sock, addr, addr_len);
144 if (*pa != SOCK_INVALID) return IO_DONE; 168 /* if return is valid, we are done */
145 if (timeout == 0) return IO_TIMEOUT; 169 if (*pa != SOCK_INVALID) return NULL;
146 tv.tv_sec = timeout / 1000; 170 /* optimization */
147 tv.tv_usec = (timeout % 1000) * 1000; 171 if (timeout == 0) return io_strerror(IO_TIMEOUT);
148 FD_ZERO(&fds); 172 /* otherwise find out why we failed */
149 FD_SET(sock, &fds); 173 err = WSAGetLastError();
150 /* call select just to avoid busy-wait. */ 174 /* if we failed because there was no connectoin, keep trying*/
151 select(0, &fds, NULL, NULL, timeout >= 0? &tv: NULL); 175 if (err != WSAEWOULDBLOCK) return sock_acceptstrerror(err);
176 /* call select to avoid busy wait */
177 FD_ZERO(&rfds);
178 FD_SET(sock, &rfds);
179 err = sock_select(0, &rfds, NULL, NULL, timeout);
180 if (err <= 0) return io_strerror(IO_TIMEOUT);
152 } 181 }
153 return IO_TIMEOUT; /* can't get here */ 182 return io_strerror(IO_TIMEOUT); /* can't get here */
154} 183}
155 184
156/*-------------------------------------------------------------------------*\ 185/*-------------------------------------------------------------------------*\
@@ -172,13 +201,10 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
172 *sent = 0; 201 *sent = 0;
173 /* run select to avoid busy wait */ 202 /* run select to avoid busy wait */
174 if (WSAGetLastError() == WSAEWOULDBLOCK) { 203 if (WSAGetLastError() == WSAEWOULDBLOCK) {
175 struct timeval tv;
176 fd_set fds; 204 fd_set fds;
177 tv.tv_sec = timeout / 1000;
178 tv.tv_usec = (timeout % 1000) * 1000;
179 FD_ZERO(&fds); 205 FD_ZERO(&fds);
180 FD_SET(sock, &fds); 206 FD_SET(sock, &fds);
181 ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); 207 ret = sock_select(0, NULL, &fds, NULL, timeout);
182 /* tell the caller to call us again because there is more data */ 208 /* tell the caller to call us again because there is more data */
183 if (ret > 0) return IO_DONE; 209 if (ret > 0) return IO_DONE;
184 /* tell the caller there was no data before timeout */ 210 /* tell the caller there was no data before timeout */
@@ -211,13 +237,10 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
211 *sent = 0; 237 *sent = 0;
212 /* run select to avoid busy wait */ 238 /* run select to avoid busy wait */
213 if (WSAGetLastError() == WSAEWOULDBLOCK) { 239 if (WSAGetLastError() == WSAEWOULDBLOCK) {
214 struct timeval tv;
215 fd_set fds; 240 fd_set fds;
216 tv.tv_sec = timeout / 1000;
217 tv.tv_usec = (timeout % 1000) * 1000;
218 FD_ZERO(&fds); 241 FD_ZERO(&fds);
219 FD_SET(sock, &fds); 242 FD_SET(sock, &fds);
220 ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); 243 ret = sock_select(0, NULL, &fds, NULL, timeout);
221 /* tell the caller to call us again because there is more data */ 244 /* tell the caller to call us again because there is more data */
222 if (ret > 0) return IO_DONE; 245 if (ret > 0) return IO_DONE;
223 /* tell the caller there was no data before timeout */ 246 /* tell the caller there was no data before timeout */
@@ -241,16 +264,13 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
241 if (sock == SOCK_INVALID) return IO_CLOSED; 264 if (sock == SOCK_INVALID) return IO_CLOSED;
242 taken = recv(sock, data, (int) count, 0); 265 taken = recv(sock, data, (int) count, 0);
243 if (taken <= 0) { 266 if (taken <= 0) {
244 struct timeval tv;
245 fd_set fds; 267 fd_set fds;
246 int ret; 268 int ret;
247 *got = 0; 269 *got = 0;
248 if (taken == 0) return IO_CLOSED; 270 if (taken == 0) return IO_CLOSED;
249 tv.tv_sec = timeout / 1000;
250 tv.tv_usec = (timeout % 1000) * 1000;
251 FD_ZERO(&fds); 271 FD_ZERO(&fds);
252 FD_SET(sock, &fds); 272 FD_SET(sock, &fds);
253 ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); 273 ret = sock_select(0, &fds, NULL, NULL, timeout);
254 if (ret > 0) return IO_DONE; 274 if (ret > 0) return IO_DONE;
255 else return IO_TIMEOUT; 275 else return IO_TIMEOUT;
256 } else { 276 } else {
@@ -270,16 +290,13 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
270 if (sock == SOCK_INVALID) return IO_CLOSED; 290 if (sock == SOCK_INVALID) return IO_CLOSED;
271 taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); 291 taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
272 if (taken <= 0) { 292 if (taken <= 0) {
273 struct timeval tv;
274 fd_set fds; 293 fd_set fds;
275 int ret; 294 int ret;
276 *got = 0; 295 *got = 0;
277 if (taken == 0) return IO_CLOSED; 296 if (taken == 0) return IO_CLOSED;
278 tv.tv_sec = timeout / 1000;
279 tv.tv_usec = (timeout % 1000) * 1000;
280 FD_ZERO(&fds); 297 FD_ZERO(&fds);
281 FD_SET(sock, &fds); 298 FD_SET(sock, &fds);
282 ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); 299 ret = sock_select(0, &fds, NULL, NULL, timeout);
283 if (ret > 0) return IO_DONE; 300 if (ret > 0) return IO_DONE;
284 else return IO_TIMEOUT; 301 else return IO_TIMEOUT;
285 } else { 302 } else {
@@ -309,51 +326,117 @@ void sock_setnonblocking(p_sock ps)
309/*-------------------------------------------------------------------------*\ 326/*-------------------------------------------------------------------------*\
310* Error translation functions 327* Error translation functions
311\*-------------------------------------------------------------------------*/ 328\*-------------------------------------------------------------------------*/
329/* return error messages for the known errors reported by gethostbyname */
312const char *sock_hoststrerror(void) 330const char *sock_hoststrerror(void)
313{ 331{
314 switch (WSAGetLastError()) { 332 switch (WSAGetLastError()) {
315 case HOST_NOT_FOUND: return "host not found"; 333 case WSANOTINITIALISED: return "not initialized";
316 case NO_ADDRESS: return "unable to resolve host name"; 334 case WSAENETDOWN: return "network is down";
317 case NO_RECOVERY: return "name server error"; 335 case WSAHOST_NOT_FOUND: return "host not found";
318 case TRY_AGAIN: return "name server unavailable, try again later."; 336 case WSATRY_AGAIN: return "name server unavailable, try again later";
337 case WSANO_RECOVERY: return "name server error";
338 case WSANO_DATA: return "host not found";
339 case WSAEINPROGRESS: return "another call in progress";
340 case WSAEFAULT: return "invalid memory address";
341 case WSAEINTR: return "call interrupted";
319 default: return "unknown error"; 342 default: return "unknown error";
320 } 343 }
321} 344}
322 345
323static const char *sock_createstrerror(void) 346/* return error messages for the known errors reported by socket */
347static const char *sock_createstrerror(int err)
324{ 348{
325 switch (WSAGetLastError()) { 349 switch (err) {
326 case WSANOTINITIALISED: return "not initialized"; 350 case WSANOTINITIALISED: return "not initialized";
327 case WSAENETDOWN: return "network is down"; 351 case WSAENETDOWN: return "network is down";
352 case WSAEAFNOSUPPORT: return "address family not supported";
353 case WSAEINPROGRESS: return "another call in progress";
328 case WSAEMFILE: return "descriptor table is full"; 354 case WSAEMFILE: return "descriptor table is full";
329 case WSAENOBUFS: return "insufficient buffer space"; 355 case WSAENOBUFS: return "insufficient buffer space";
356 case WSAEPROTONOSUPPORT: return "protocol not supported";
357 case WSAEPROTOTYPE: return "wrong protocol type";
358 case WSAESOCKTNOSUPPORT: return "socket type not supported by family";
330 default: return "unknown error"; 359 default: return "unknown error";
331 } 360 }
332} 361}
333 362
334static const char *sock_bindstrerror(void) 363/* return error messages for the known errors reported by accept */
364static const char *sock_acceptstrerror(int err)
335{ 365{
336 switch (WSAGetLastError()) { 366 switch (err) {
337 case WSANOTINITIALISED: return "not initialized"; 367 case WSANOTINITIALISED: return "not initialized";
338 case WSAENETDOWN: return "network is down"; 368 case WSAENETDOWN: return "network is down";
339 case WSAEADDRINUSE: return "address already in use"; 369 case WSAEFAULT: return "invalid memory address";
340 case WSAEINVAL: return "socket already bound"; 370 case WSAEINTR: return "call interrupted";
341 case WSAENOBUFS: return "too many connections"; 371 case WSAEINPROGRESS: return "another call in progress";
342 case WSAEFAULT: return "invalid address"; 372 case WSAEINVAL: return "not listening";
343 case WSAENOTSOCK: return "not a socket descriptor"; 373 case WSAEMFILE: return "descriptor table is full";
374 case WSAENOBUFS: return "insufficient buffer space";
375 case WSAENOTSOCK: return "descriptor not a socket";
376 case WSAEOPNOTSUPP: return "not supported";
377 case WSAEWOULDBLOCK: return "call would block";
344 default: return "unknown error"; 378 default: return "unknown error";
345 } 379 }
346} 380}
347 381
348static const char *sock_connectstrerror(void) 382/* return error messages for the known errors reported by bind */
383static const char *sock_bindstrerror(int err)
349{ 384{
350 switch (WSAGetLastError()) { 385 switch (err) {
351 case WSANOTINITIALISED: return "not initialized"; 386 case WSANOTINITIALISED: return "not initialized";
352 case WSAENETDOWN: return "network is down"; 387 case WSAENETDOWN: return "network is down";
388 case WSAEACCES: return "broadcast not enabled for socket";
353 case WSAEADDRINUSE: return "address already in use"; 389 case WSAEADDRINUSE: return "address already in use";
354 case WSAEADDRNOTAVAIL: return "address unavailable"; 390 case WSAEADDRNOTAVAIL: return "address not available in local host";
391 case WSAEFAULT: return "invalid memory address";
392 case WSAEINPROGRESS: return "another call in progress";
393 case WSAEINVAL: return "already bound";
394 case WSAENOBUFS: return "insuficient buffer space";
395 case WSAENOTSOCK: return "descriptor not a socket";
396 default: return "unknown error";
397 }
398
399}
400
401/* return error messages for the known errors reported by listen */
402static const char *sock_listenstrerror(int err)
403{
404 switch (err) {
405 case WSANOTINITIALISED: return "not initialized";
406 case WSAENETDOWN: return "network is down";
407 case WSAEADDRINUSE: return "local address already in use";
408 case WSAEINPROGRESS: return "another call in progress";
409 case WSAEINVAL: return "not bound";
410 case WSAEISCONN: return "already connected";
411 case WSAEMFILE: return "descriptor table is full";
412 case WSAENOBUFS: return "insuficient buffer space";
413 case WSAENOTSOCK: return "descriptor not a socket";
414 case WSAEOPNOTSUPP: return "not supported";
415 default: return "unknown error";
416 }
417}
418
419/* return error messages for the known errors reported by connect */
420static const char *sock_connectstrerror(int err)
421{
422 switch (err) {
423 case WSANOTINITIALISED: return "not initialized";
424 case WSAENETDOWN: return "network is down";
425 case WSAEADDRINUSE: return "local address already in use";
426 case WSAEINTR: return "call interrupted";
427 case WSAEINPROGRESS: return "another call in progress";
428 case WSAEALREADY: return "connect already in progress";
429 case WSAEADDRNOTAVAIL: return "invalid remote address";
430 case WSAEAFNOSUPPORT: return "address family not supported";
355 case WSAECONNREFUSED: return "connection refused"; 431 case WSAECONNREFUSED: return "connection refused";
432 case WSAEFAULT: return "invalid memory address";
433 case WSAEINVAL: return "socket is listening";
434 case WSAEISCONN: return "socket already connected";
356 case WSAENETUNREACH: return "network is unreachable"; 435 case WSAENETUNREACH: return "network is unreachable";
436 case WSAENOTSOCK: return "descriptor not a socket";
437 case WSAETIMEDOUT: return io_strerror(IO_TIMEOUT);
438 case WSAEWOULDBLOCK: return "would block";
439 case WSAEACCES: return "broadcast not enabled";
357 default: return "unknown error"; 440 default: return "unknown error";
358 } 441 }
359} 442}