aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/inet.c7
-rw-r--r--src/io.h13
-rw-r--r--src/select.c2
-rw-r--r--src/timeout.c3
-rw-r--r--src/udp.h2
-rw-r--r--src/usocket.c18
-rw-r--r--src/wsocket.c453
7 files changed, 210 insertions, 288 deletions
diff --git a/src/inet.c b/src/inet.c
index 33191c3..e2afcdf 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -209,8 +209,8 @@ const char *inet_tryconnect(p_sock ps, const char *address,
209 memset(&remote, 0, sizeof(remote)); 209 memset(&remote, 0, sizeof(remote));
210 remote.sin_family = AF_INET; 210 remote.sin_family = AF_INET;
211 remote.sin_port = htons(port); 211 remote.sin_port = htons(port);
212 if (strcmp(address, "*")) { 212 if (strcmp(address, "*")) {
213 if (!strlen(address) || !inet_aton(address, &remote.sin_addr)) { 213 if (!inet_aton(address, &remote.sin_addr)) {
214 struct hostent *hp = NULL; 214 struct hostent *hp = NULL;
215 struct in_addr **addr; 215 struct in_addr **addr;
216 err = sock_gethostbyname(address, &hp); 216 err = sock_gethostbyname(address, &hp);
@@ -236,8 +236,7 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port)
236 local.sin_addr.s_addr = htonl(INADDR_ANY); 236 local.sin_addr.s_addr = htonl(INADDR_ANY);
237 local.sin_port = htons(port); 237 local.sin_port = htons(port);
238 local.sin_family = AF_INET; 238 local.sin_family = AF_INET;
239 if (strcmp(address, "*") && 239 if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
240 (!strlen(address) || !inet_aton(address, &local.sin_addr))) {
241 struct hostent *hp = NULL; 240 struct hostent *hp = NULL;
242 struct in_addr **addr; 241 struct in_addr **addr;
243 err = sock_gethostbyname(address, &hp); 242 err = sock_gethostbyname(address, &hp);
diff --git a/src/io.h b/src/io.h
index 22cf467..51801f6 100644
--- a/src/io.h
+++ b/src/io.h
@@ -24,18 +24,19 @@ enum {
24 IO_DONE = 0, /* operation completed successfully */ 24 IO_DONE = 0, /* operation completed successfully */
25 IO_TIMEOUT = -1, /* operation timed out */ 25 IO_TIMEOUT = -1, /* operation timed out */
26 IO_CLOSED = -2, /* the connection has been closed */ 26 IO_CLOSED = -2, /* the connection has been closed */
27 IO_CLIPPED = -3 /* maxium bytes count reached */ 27 IO_CLIPPED = -3, /* maxium bytes count reached */
28 IO_UNKNOWN = -4
28}; 29};
29 30
30/* interface to error message function */ 31/* interface to error message function */
31typedef const char *(*p_error) ( 32typedef const char *(*p_error) (
32 void *ctx, /* context needed by send */ 33 void *ctx, /* context needed by send */
33 int err /* error code */ 34 int err /* error code */
34); 35);
35 36
36/* interface to send function */ 37/* interface to send function */
37typedef int (*p_send) ( 38typedef int (*p_send) (
38 void *ctx, /* context needed by send */ 39 void *ctx, /* context needed by send */
39 const char *data, /* pointer to buffer with data to send */ 40 const char *data, /* pointer to buffer with data to send */
40 size_t count, /* number of bytes to send from buffer */ 41 size_t count, /* number of bytes to send from buffer */
41 size_t *sent, /* number of bytes sent uppon return */ 42 size_t *sent, /* number of bytes sent uppon return */
@@ -44,7 +45,7 @@ typedef int (*p_send) (
44 45
45/* interface to recv function */ 46/* interface to recv function */
46typedef int (*p_recv) ( 47typedef int (*p_recv) (
47 void *ctx, /* context needed by recv */ 48 void *ctx, /* context needed by recv */
48 char *data, /* pointer to buffer where data will be writen */ 49 char *data, /* pointer to buffer where data will be writen */
49 size_t count, /* number of bytes to receive into buffer */ 50 size_t count, /* number of bytes to receive into buffer */
50 size_t *got, /* number of bytes received uppon return */ 51 size_t *got, /* number of bytes received uppon return */
@@ -61,6 +62,6 @@ typedef struct t_io_ {
61typedef t_io *p_io; 62typedef t_io *p_io;
62 63
63void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); 64void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
64const char *io_strerror(int err); 65const char *io_strerror(int err);
65 66
66#endif /* IO_H */ 67#endif /* IO_H */ \ No newline at end of file
diff --git a/src/select.c b/src/select.c
index 3c01b06..a92a2c5 100644
--- a/src/select.c
+++ b/src/select.c
@@ -64,7 +64,7 @@ static int global_select(lua_State *L) {
64 tm_init(&tm, t, -1); 64 tm_init(&tm, t, -1);
65 max_fd = collect_fd(L, 2, max_fd, itab, &wset); 65 max_fd = collect_fd(L, 2, max_fd, itab, &wset);
66 ret = sock_select(max_fd+1, &rset, &wset, NULL, &tm); 66 ret = sock_select(max_fd+1, &rset, &wset, NULL, &tm);
67 if (ret > 0 || (ret == 0 && ndirty > 0)) { 67 if (ret > 0 || ndirty > 0) {
68 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); 68 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
69 return_fd(L, &wset, max_fd+1, itab, wtab, 0); 69 return_fd(L, &wset, max_fd+1, itab, wtab, 0);
70 make_assoc(L, rtab); 70 make_assoc(L, rtab);
diff --git a/src/timeout.c b/src/timeout.c
index 74ba968..66b98dd 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -192,7 +192,8 @@ int tm_lua_sleep(lua_State *L)
192 struct timespec t, r; 192 struct timespec t, r;
193 t.tv_sec = (int) n; 193 t.tv_sec = (int) n;
194 n -= t.tv_sec; 194 n -= t.tv_sec;
195 t.tv_nsec = (int) (n * 1000000000) % 1000000000; 195 t.tv_nsec = (int) (n * 1000000000);
196 if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999;
196 nanosleep(&t, &r); 197 nanosleep(&t, &r);
197#endif 198#endif
198 return 0; 199 return 0;
diff --git a/src/udp.h b/src/udp.h
index 0d8e5f4..f34c8ad 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -19,7 +19,7 @@
19#include "timeout.h" 19#include "timeout.h"
20#include "socket.h" 20#include "socket.h"
21 21
22#define UDP_DATAGRAMSIZE 576 22#define UDP_DATAGRAMSIZE 8192
23 23
24typedef struct t_udp_ { 24typedef struct t_udp_ {
25 t_sock sock; 25 t_sock sock;
diff --git a/src/usocket.c b/src/usocket.c
index 4d4f092..0cff17b 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -179,11 +179,11 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) {
179int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) { 179int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) {
180 SA daddr; 180 SA daddr;
181 socklen_t dlen = sizeof(daddr); 181 socklen_t dlen = sizeof(daddr);
182 int err;
183 if (*ps == SOCK_INVALID) return IO_CLOSED; 182 if (*ps == SOCK_INVALID) return IO_CLOSED;
184 if (!addr) addr = &daddr; 183 if (!addr) addr = &daddr;
185 if (!len) len = &dlen; 184 if (!len) len = &dlen;
186 for ( ;; ) { 185 for ( ;; ) {
186 int err;
187 if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE; 187 if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE;
188 err = errno; 188 err = errno;
189 if (err == EINTR) continue; 189 if (err == EINTR) continue;
@@ -191,7 +191,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) {
191 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; 191 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
192 } 192 }
193 /* can't reach here */ 193 /* can't reach here */
194 return err; 194 return IO_UNKNOWN;
195} 195}
196 196
197/*-------------------------------------------------------------------------*\ 197/*-------------------------------------------------------------------------*\
@@ -223,7 +223,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
223 if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; 223 if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
224 } 224 }
225 /* can't reach here */ 225 /* can't reach here */
226 return err; 226 return IO_UNKNOWN;
227} 227}
228 228
229/*-------------------------------------------------------------------------*\ 229/*-------------------------------------------------------------------------*\
@@ -247,7 +247,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
247 if (err != EAGAIN) return err; 247 if (err != EAGAIN) return err;
248 if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; 248 if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
249 } 249 }
250 return err; 250 return IO_UNKNOWN;
251} 251}
252 252
253/*-------------------------------------------------------------------------*\ 253/*-------------------------------------------------------------------------*\
@@ -269,7 +269,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
269 if (err != EAGAIN) return err; 269 if (err != EAGAIN) return err;
270 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; 270 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
271 } 271 }
272 return err; 272 return IO_UNKNOWN;
273} 273}
274 274
275/*-------------------------------------------------------------------------*\ 275/*-------------------------------------------------------------------------*\
@@ -292,7 +292,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
292 if (err != EAGAIN) return err; 292 if (err != EAGAIN) return err;
293 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; 293 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
294 } 294 }
295 return err; 295 return IO_UNKNOWN;
296} 296}
297 297
298/*-------------------------------------------------------------------------*\ 298/*-------------------------------------------------------------------------*\
@@ -345,10 +345,10 @@ const char *sock_strerror(int err) {
345 switch (err) { 345 switch (err) {
346 case EADDRINUSE: return "eaddrinuse"; 346 case EADDRINUSE: return "eaddrinuse";
347 case EACCES: return "eaccess"; 347 case EACCES: return "eaccess";
348 case ECONNABORTED: return "econnaborted";
349 case ECONNREFUSED: return "econnrefused"; 348 case ECONNREFUSED: return "econnrefused";
350 case ECONNRESET: return "econnreset"; 349 case ECONNABORTED: return "closed";
351 case ETIMEDOUT: return "etimedout"; 350 case ECONNRESET: return "closed";
351 case ETIMEDOUT: return "timedout";
352 default: return strerror(errno); 352 default: return strerror(errno);
353 } 353 }
354} 354}
diff --git a/src/wsocket.c b/src/wsocket.c
index a264452..d9da6fc 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -13,7 +13,6 @@
13 13
14/* WinSock doesn't have a strerror... */ 14/* WinSock doesn't have a strerror... */
15static const char *wstrerror(int err); 15static const char *wstrerror(int err);
16static int wisclosed(int err);
17 16
18/*-------------------------------------------------------------------------*\ 17/*-------------------------------------------------------------------------*\
19* Initializes module 18* Initializes module
@@ -39,14 +38,43 @@ int sock_close(void) {
39} 38}
40 39
41/*-------------------------------------------------------------------------*\ 40/*-------------------------------------------------------------------------*\
41* Wait for readable/writable/connected socket with timeout
42\*-------------------------------------------------------------------------*/
43#define WAITFD_R 1
44#define WAITFD_W 2
45#define WAITFD_E 4
46#define WAITFD_C (WAITFD_E|WAITFD_W)
47
48static int sock_waitfd(t_sock fd, int sw, p_tm tm) {
49 int ret;
50 fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
51 struct timeval tv, *tp = NULL;
52 double t;
53 if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
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 if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(fd, &efds); ep = &efds; }
57 if ((t = tm_get(tm)) >= 0.0) {
58 tv.tv_sec = (int) t;
59 tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
60 tp = &tv;
61 }
62 ret = select(0, rp, wp, ep, tp);
63 if (ret == -1) return WSAGetLastError();
64 if (ret == 0) return IO_TIMEOUT;
65 if (sw == WAITFD_C && FD_ISSET(fd, &efds)) return IO_CLOSED;
66 return IO_DONE;
67}
68
69/*-------------------------------------------------------------------------*\
42* Select with int timeout in ms 70* Select with int timeout in ms
43\*-------------------------------------------------------------------------*/ 71\*-------------------------------------------------------------------------*/
44int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) { 72int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
45 struct timeval tv; 73 struct timeval tv;
46 double t = tm_get(tm); 74 double t = tm_get(tm);
47 tv.tv_sec = (int) t; 75 tv.tv_sec = (int) t;
48 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); 76 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
49 return select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL); 77 return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
50} 78}
51 79
52/*-------------------------------------------------------------------------*\ 80/*-------------------------------------------------------------------------*\
@@ -72,62 +100,45 @@ void sock_shutdown(p_sock ps, int how) {
72/*-------------------------------------------------------------------------*\ 100/*-------------------------------------------------------------------------*\
73* Creates and sets up a socket 101* Creates and sets up a socket
74\*-------------------------------------------------------------------------*/ 102\*-------------------------------------------------------------------------*/
75const char *sock_create(p_sock ps, int domain, int type, int protocol) { 103int sock_create(p_sock ps, int domain, int type, int protocol) {
76 t_sock sock = socket(domain, type, protocol); 104 *ps = socket(domain, type, protocol);
77 if (sock == SOCK_INVALID) return sock_strerror(); 105 if (*ps != SOCK_INVALID) return IO_DONE;
78 *ps = sock; 106 else return WSAGetLastError();
79 return NULL;
80} 107}
81 108
82/*-------------------------------------------------------------------------*\ 109/*-------------------------------------------------------------------------*\
83* Connects or returns error message 110* Connects or returns error message
84\*-------------------------------------------------------------------------*/ 111\*-------------------------------------------------------------------------*/
85const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) { 112int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) {
86 t_sock sock = *ps;
87 int err; 113 int err;
88 fd_set efds, wfds;
89 /* don't call on closed socket */ 114 /* don't call on closed socket */
90 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); 115 if (*ps == SOCK_INVALID) return IO_CLOSED;
91 /* ask system to connect */ 116 /* ask system to connect */
92 err = connect(sock, addr, addr_len); 117 if (connect(*ps, addr, len) == 0) return IO_DONE;
93 /* if no error, we're done */
94 if (err == 0) return NULL;
95 /* make sure the system is trying to connect */ 118 /* make sure the system is trying to connect */
96 err = WSAGetLastError(); 119 err = WSAGetLastError();
97 if (err != WSAEWOULDBLOCK) return wstrerror(err); 120 if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
98 /* optimize for timeout=0 */ 121 /* we wait until something happens */
99 if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); 122 if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) {
100 /* wait for a timeout or for the system's answer */ 123 int len = sizeof(err);
101 FD_ZERO(&wfds); FD_SET(sock, &wfds); 124 /* give windows time to set the error (yes, disgusting) */
102 FD_ZERO(&efds); FD_SET(sock, &efds); 125 Sleep(0);
103 /* we run select to wait */ 126 /* find out why we failed */
104 err = sock_select(0, NULL, &wfds, &efds, tm); 127 getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
105 /* if select returned due to an event */ 128 /* we KNOW there was an error. if why is 0, we will return
106 if (err > 0) { 129 * "unknown error", but it's not really our fault */
107 /* if was in efds, we failed */ 130 return err > 0? err: IO_UNKNOWN;
108 if (FD_ISSET(sock, &efds)) { 131 /* here we deal with the case in which it worked, timedout or weird errors */
109 int why, len = sizeof(why); 132 } else return err;
110 /* give windows time to set the error (disgusting) */
111 Sleep(0);
112 /* find out why we failed */
113 getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len);
114 /* we KNOW there was an error. if why is 0, we will return
115 * "unknown error", but it's not really our fault */
116 return wstrerror(why);
117 /* otherwise it must be in wfds, so we succeeded */
118 } else return NULL;
119 /* if no event happened, we timed out */
120 } else if (err == 0) return io_strerror(IO_TIMEOUT);
121 return sock_strerror();
122} 133}
123 134
124/*-------------------------------------------------------------------------*\ 135/*-------------------------------------------------------------------------*\
125* Binds or returns error message 136* Binds or returns error message
126\*-------------------------------------------------------------------------*/ 137\*-------------------------------------------------------------------------*/
127const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { 138int sock_bind(p_sock ps, SA *addr, socklen_t len) {
128 const char *err = NULL; 139 int err = IO_DONE;
129 sock_setblocking(ps); 140 sock_setblocking(ps);
130 if (bind(*ps, addr, addr_len) < 0) err = sock_strerror(); 141 if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
131 sock_setnonblocking(ps); 142 sock_setnonblocking(ps);
132 return err; 143 return err;
133} 144}
@@ -135,10 +146,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
135/*-------------------------------------------------------------------------*\ 146/*-------------------------------------------------------------------------*\
136* 147*
137\*-------------------------------------------------------------------------*/ 148\*-------------------------------------------------------------------------*/
138const char *sock_listen(p_sock ps, int backlog) { 149int sock_listen(p_sock ps, int backlog) {
139 const char *err = NULL; 150 int err = IO_DONE;
140 sock_setblocking(ps); 151 sock_setblocking(ps);
141 if (listen(*ps, backlog) < 0) err = sock_strerror(); 152 if (listen(*ps, backlog) < 0) err = WSAGetLastError();
142 sock_setnonblocking(ps); 153 sock_setnonblocking(ps);
143 return err; 154 return err;
144} 155}
@@ -146,35 +157,25 @@ const char *sock_listen(p_sock ps, int backlog) {
146/*-------------------------------------------------------------------------*\ 157/*-------------------------------------------------------------------------*\
147* Accept with timeout 158* Accept with timeout
148\*-------------------------------------------------------------------------*/ 159\*-------------------------------------------------------------------------*/
149const char *sock_accept(p_sock ps, p_sock pa, SA *addr, 160int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) {
150 socklen_t *addr_len, p_tm tm) { 161 SA daddr;
151 t_sock sock = *ps; 162 socklen_t dlen = sizeof(daddr);
152 SA dummy_addr; 163 if (*ps == SOCK_INVALID) return IO_CLOSED;
153 socklen_t dummy_len = sizeof(dummy_addr); 164 if (!addr) addr = &daddr;
154 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); 165 if (!len) len = &dlen;
155 if (!addr) addr = &dummy_addr; 166 for ( ;; ) {
156 if (!addr_len) addr_len = &dummy_len;
157 for (;;) {
158 fd_set rfds;
159 int err; 167 int err;
160 /* try to get client socket */ 168 /* try to get client socket */
161 *pa = accept(sock, addr, addr_len); 169 if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE;
162 /* if return is valid, we are done */ 170 /* find out why we failed */
163 if (*pa != SOCK_INVALID) return NULL;
164 /* otherwise find out why we failed */
165 err = WSAGetLastError(); 171 err = WSAGetLastError();
166 /* if we failed because there was no connectoin, keep trying */ 172 /* if we failed because there was no connectoin, keep trying */
167 if (err != WSAEWOULDBLOCK) return wstrerror(err); 173 if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
168 /* optimize for the timeout=0 case */
169 if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
170 /* call select to avoid busy wait */ 174 /* call select to avoid busy wait */
171 FD_ZERO(&rfds); 175 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
172 FD_SET(sock, &rfds);
173 err = sock_select(0, &rfds, NULL, NULL, tm);
174 if (err == 0) return io_strerror(IO_TIMEOUT);
175 else if (err < 0) break;
176 } 176 }
177 return sock_strerror(); 177 /* can't reach here */
178 return IO_UNKNOWN;
178} 179}
179 180
180/*-------------------------------------------------------------------------*\ 181/*-------------------------------------------------------------------------*\
@@ -182,131 +183,93 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
182\*-------------------------------------------------------------------------*/ 183\*-------------------------------------------------------------------------*/
183int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) 184int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
184{ 185{
185 t_sock sock = *ps; 186 int err;
186 /* avoid making system calls on closed sockets */ 187 /* avoid making system calls on closed sockets */
187 if (sock == SOCK_INVALID) return IO_CLOSED; 188 if (*ps == SOCK_INVALID) return IO_CLOSED;
189 /* loop until we send something or we give up on error */
190 *sent = 0;
188 for ( ;; ) { 191 for ( ;; ) {
189 fd_set fds;
190 int ret, put;
191 /* try to send something */ 192 /* try to send something */
192 put = send(sock, data, (int) count, 0); 193 int put = send(*ps, data, (int) count, 0);
193 /* if we sent something, we are done */ 194 /* if we sent something, we are done */
194 if (put > 0) { 195 if (put > 0) {
195 *sent = put; 196 *sent = put;
196 return IO_DONE; 197 return IO_DONE;
197 } 198 }
198 /* deal with failure */ 199 /* deal with failure */
199 *sent = 0; 200 err = WSAGetLastError();
200 ret = WSAGetLastError();
201 /* check for connection closed */
202 if (wisclosed(ret)) return IO_CLOSED;
203 /* we can only proceed if there was no serious error */ 201 /* we can only proceed if there was no serious error */
204 if (ret != WSAEWOULDBLOCK) return IO_USER; 202 if (err != WSAEWOULDBLOCK) return err;
205 /* optimize for the timeout = 0 case */ 203 /* avoid busy wait */
206 if (tm_get(tm) == 0.0) return IO_TIMEOUT; 204 if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
207 /* run select to avoid busy wait */
208 FD_ZERO(&fds);
209 FD_SET(sock, &fds);
210 ret = sock_select(0, NULL, &fds, NULL, tm);
211 if (ret == 0) return IO_TIMEOUT;
212 else if (ret < 0) break;
213 } 205 }
214 return IO_USER; 206 /* can't reach here */
207 return IO_UNKNOWN;
215} 208}
216 209
217/*-------------------------------------------------------------------------*\ 210/*-------------------------------------------------------------------------*\
218* Sendto with timeout 211* Sendto with timeout
219\*-------------------------------------------------------------------------*/ 212\*-------------------------------------------------------------------------*/
220int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, 213int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
221 SA *addr, socklen_t addr_len, p_tm tm) 214 SA *addr, socklen_t len, p_tm tm)
222{ 215{
223 t_sock sock = *ps; 216 int err;
224 /* avoid making system calls on closed sockets */ 217 if (*ps == SOCK_INVALID) return IO_CLOSED;
225 if (sock == SOCK_INVALID) return IO_CLOSED; 218 *sent = 0;
226 for ( ;; ) { 219 for ( ;; ) {
227 fd_set fds; 220 int put = send(*ps, data, (int) count, 0);
228 int ret, put;
229 /* try to send something */
230 put = sendto(sock, data, (int) count, 0, addr, addr_len);
231 /* if we sent something, we are done */
232 if (put > 0) { 221 if (put > 0) {
233 *sent = put; 222 *sent = put;
234 return IO_DONE; 223 return IO_DONE;
235 } 224 }
236 /* deal with failure */ 225 err = WSAGetLastError();
237 *sent = 0; 226 if (err != WSAEWOULDBLOCK) return err;
238 ret = WSAGetLastError(); 227 if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err;
239 /* check for connection closed */
240 if (wisclosed(ret)) return IO_CLOSED;
241 /* we can only proceed if there was no serious error */
242 if (ret != WSAEWOULDBLOCK) return IO_USER;
243 /* optimize for the timeout = 0 case */
244 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
245 /* run select to avoid busy wait */
246 FD_ZERO(&fds);
247 FD_SET(sock, &fds);
248 ret = sock_select(0, NULL, &fds, NULL, tm);
249 if (ret == 0) return IO_TIMEOUT;
250 else if (ret < 0) break;
251 } 228 }
252 return IO_USER; 229 return IO_UNKNOWN;
253} 230}
254 231
255/*-------------------------------------------------------------------------*\ 232/*-------------------------------------------------------------------------*\
256* Receive with timeout 233* Receive with timeout
257\*-------------------------------------------------------------------------*/ 234\*-------------------------------------------------------------------------*/
258int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) 235int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
259{ 236 int err;
260 t_sock sock = *ps; 237 if (*ps == SOCK_INVALID) return IO_CLOSED;
261 if (sock == SOCK_INVALID) return IO_CLOSED; 238 *got = 0;
262 for ( ;; ) { 239 for ( ;; ) {
263 fd_set fds; 240 int taken = recv(*ps, data, (int) count, 0);
264 int ret, taken;
265 taken = recv(sock, data, (int) count, 0);
266 if (taken > 0) { 241 if (taken > 0) {
267 *got = taken; 242 *got = taken;
268 return IO_DONE; 243 return IO_DONE;
269 } 244 }
270 *got = 0; 245 if (taken == 0) return IO_CLOSED;
271 if (taken == 0 || wisclosed(ret = WSAGetLastError())) return IO_CLOSED; 246 err = WSAGetLastError();
272 if (ret != WSAEWOULDBLOCK) return IO_USER; 247 if (err != WSAEWOULDBLOCK) return err;
273 if (tm_get(tm) == 0.0) return IO_TIMEOUT; 248 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
274 FD_ZERO(&fds);
275 FD_SET(sock, &fds);
276 ret = sock_select(0, &fds, NULL, NULL, tm);
277 if (ret == 0) return IO_TIMEOUT;
278 else if (ret < 0) break;
279 } 249 }
280 return IO_TIMEOUT; 250 return IO_UNKNOWN;
281} 251}
282 252
283/*-------------------------------------------------------------------------*\ 253/*-------------------------------------------------------------------------*\
284* Recvfrom with timeout 254* Recvfrom with timeout
285\*-------------------------------------------------------------------------*/ 255\*-------------------------------------------------------------------------*/
286int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, 256int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
287 SA *addr, socklen_t *addr_len, p_tm tm) 257 SA *addr, socklen_t *len, p_tm tm) {
288{ 258 int err;
289 t_sock sock = *ps; 259 if (*ps == SOCK_INVALID) return IO_CLOSED;
290 if (sock == SOCK_INVALID) return IO_CLOSED; 260 *got = 0;
291 for ( ;; ) { 261 for ( ;; ) {
292 fd_set fds; 262 int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
293 int ret, taken;
294 taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
295 if (taken > 0) { 263 if (taken > 0) {
296 *got = taken; 264 *got = taken;
297 return IO_DONE; 265 return IO_DONE;
298 } 266 }
299 *got = 0; 267 if (taken == 0) return IO_CLOSED;
300 if (taken == 0 || wisclosed(ret = WSAGetLastError())) return IO_CLOSED; 268 err = WSAGetLastError();
301 if (ret != WSAEWOULDBLOCK) return IO_USER; 269 if (err != WSAEWOULDBLOCK) return err;
302 if (tm_get(tm) == 0.0) return IO_TIMEOUT; 270 if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err;
303 FD_ZERO(&fds);
304 FD_SET(sock, &fds);
305 ret = sock_select(0, &fds, NULL, NULL, tm);
306 if (ret == 0) return IO_TIMEOUT;
307 else if (ret < 0) break;
308 } 271 }
309 return IO_TIMEOUT; 272 return IO_UNKNOWN;
310} 273}
311 274
312/*-------------------------------------------------------------------------*\ 275/*-------------------------------------------------------------------------*\
@@ -326,138 +289,96 @@ void sock_setnonblocking(p_sock ps) {
326} 289}
327 290
328/*-------------------------------------------------------------------------*\ 291/*-------------------------------------------------------------------------*\
292* DNS helpers
293\*-------------------------------------------------------------------------*/
294int sock_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
295 *hp = gethostbyaddr(addr, len, AF_INET);
296 if (*hp) return IO_DONE;
297 else return h_errno;
298}
299
300int sock_gethostbyname(const char *addr, struct hostent **hp) {
301 *hp = gethostbyname(addr);
302 if (*hp) return IO_DONE;
303 else return h_errno;
304}
305
306/*-------------------------------------------------------------------------*\
329* Error translation functions 307* Error translation functions
330\*-------------------------------------------------------------------------*/ 308\*-------------------------------------------------------------------------*/
331const char *sock_hoststrerror(void) { 309const char *sock_hoststrerror(int err) {
332 int err = WSAGetLastError(); 310 if (err <= 0) return io_strerror(err);
333 switch (err) { 311 switch (err) {
334 case WSAHOST_NOT_FOUND: 312 case WSAHOST_NOT_FOUND: return "host_not_found";
335 return "host not found"; 313 default: return wstrerror(err);
336 default:
337 return wstrerror(err);
338 } 314 }
339} 315}
340 316
341const char *sock_strerror(void) { 317const char *sock_strerror(int err) {
342 int err = WSAGetLastError(); 318 if (err <= 0) return io_strerror(err);
343 switch (err) { 319 switch (err) {
344 case WSAEADDRINUSE: 320 case WSAEADDRINUSE: return "eaddrinuse";
345 return "address already in use"; 321 case WSAECONNREFUSED: return "econnrefused";
346 default: 322 case WSAECONNABORTED: return "closed";
347 return wstrerror(err); 323 case WSAECONNRESET: return "closed";
324 case WSAETIMEDOUT: return "timeout";
325 default: return wstrerror(err);
348 } 326 }
349} 327}
350 328
351const char *sock_geterr(p_sock ps, int code) { 329const char *sock_ioerror(p_sock ps, int err) {
352 (void) ps; 330 (void) ps;
353 (void) code; 331 return sock_strerror(err);
354 return sock_strerror();
355}
356
357int wisclosed(int err) {
358 switch (err) {
359 case WSAECONNRESET:
360 case WSAECONNABORTED:
361 case WSAESHUTDOWN:
362 case WSAENOTCONN:
363 return 1;
364 default:
365 return 0;
366 }
367} 332}
368 333
369static const char *wstrerror(int err) { 334static const char *wstrerror(int err) {
370 switch (err) { 335 switch (err) {
371 case WSAEINTR: 336 case WSAEINTR: return "Interrupted function call";
372 return "WSAEINTR: Interrupted function call"; 337 case WSAEACCES: return "Permission denied";
373 case WSAEACCES: 338 case WSAEFAULT: return "Bad address";
374 return "WSAEACCES: Permission denied"; 339 case WSAEINVAL: return "Invalid argument";
375 case WSAEFAULT: 340 case WSAEMFILE: return "Too many open files";
376 return "WSAEFAULT: Bad address"; 341 case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
377 case WSAEINVAL: 342 case WSAEINPROGRESS: return "Operation now in progress";
378 return "WSAEINVAL: Invalid argument"; 343 case WSAEALREADY: return "Operation already in progress";
379 case WSAEMFILE: 344 case WSAENOTSOCK: return "Socket operation on nonsocket";
380 return "WSAEMFILE: Too many open files"; 345 case WSAEDESTADDRREQ: return "Destination address required";
381 case WSAEWOULDBLOCK: 346 case WSAEMSGSIZE: return "Message too long";
382 return "WSAEWOULDBLOCK: Resource temporarily unavailable"; 347 case WSAEPROTOTYPE: return "Protocol wrong type for socket";
383 case WSAEINPROGRESS: 348 case WSAENOPROTOOPT: return "Bad protocol option";
384 return "WSAEINPROGRESS: Operation now in progress"; 349 case WSAEPROTONOSUPPORT: return "Protocol not supported";
385 case WSAEALREADY: 350 case WSAESOCKTNOSUPPORT: return "Socket type not supported";
386 return "WSAEALREADY: Operation already in progress"; 351 case WSAEOPNOTSUPP: return "Operation not supported";
387 case WSAENOTSOCK: 352 case WSAEPFNOSUPPORT: return "Protocol family not supported";
388 return "WSAENOTSOCK: Socket operation on nonsocket"; 353 case WSAEAFNOSUPPORT:
389 case WSAEDESTADDRREQ: 354 return "Address family not supported by protocol family";
390 return "WSAEDESTADDRREQ: Destination address required"; 355 case WSAEADDRINUSE: return "Address already in use";
391 case WSAEMSGSIZE: 356 case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
392 return "WSAEMSGSIZE: Message too long"; 357 case WSAENETDOWN: return "Network is down";
393 case WSAEPROTOTYPE: 358 case WSAENETUNREACH: return "Network is unreachable";
394 return "WSAEPROTOTYPE: Protocol wrong type for socket"; 359 case WSAENETRESET: return "Network dropped connection on reset";
395 case WSAENOPROTOOPT: 360 case WSAECONNABORTED: return "Software caused connection abort";
396 return "WSAENOPROTOOPT: Bad protocol option"; 361 case WSAECONNRESET: return "Connection reset by peer";
397 case WSAEPROTONOSUPPORT: 362 case WSAENOBUFS: return "No buffer space available";
398 return "WSAEPROTONOSUPPORT: Protocol not supported"; 363 case WSAEISCONN: return "Socket is already connected";
399 case WSAESOCKTNOSUPPORT: 364 case WSAENOTCONN: return "Socket is not connected";
400 return "WSAESOCKTNOSUPPORT: Socket type not supported"; 365 case WSAESHUTDOWN: return "Cannot send after socket shutdown";
401 case WSAEOPNOTSUPP: 366 case WSAETIMEDOUT: return "Connection timed out";
402 return "WSAEOPNOTSUPP: Operation not supported"; 367 case WSAECONNREFUSED: return "Connection refused";
403 case WSAEPFNOSUPPORT: 368 case WSAEHOSTDOWN: return "Host is down";
404 return "WSAEPFNOSUPPORT: Protocol family not supported"; 369 case WSAEHOSTUNREACH: return "No route to host";
405 case WSAEAFNOSUPPORT: 370 case WSAEPROCLIM: return "Too many processes";
406 return "WSAEAFNOSUPPORT: Address family not supported by " 371 case WSASYSNOTREADY: return "Network subsystem is unavailable";
407 "protocol family"; 372 case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
408 case WSAEADDRINUSE: 373 case WSANOTINITIALISED:
409 return "WSAEADDRINUSE: Address already in use"; 374 return "Successful WSAStartup not yet performed";
410 case WSAEADDRNOTAVAIL: 375 case WSAEDISCON: return "Graceful shutdown in progress";
411 return "WSAEADDRNOTAVAIL: Cannot assign requested address"; 376 case WSATYPE_NOT_FOUND: return "Class type not found";
412 case WSAENETDOWN: 377 case WSAHOST_NOT_FOUND: return "Host not found";
413 return "WSAENETDOWN: Network is down"; 378 case WSATRY_AGAIN: return "Nonauthoritative host not found";
414 case WSAENETUNREACH: 379 case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
415 return "WSAENETUNREACH: Network is unreachable"; 380 case WSANO_DATA: return "Valid name, no data record of requested type";
416 case WSAENETRESET: 381 case WSASYSCALLFAILURE: return "System call failure";
417 return "WSAENETRESET: Network dropped connection on reset"; 382 default: return "Unknown error";
418 case WSAECONNABORTED:
419 return "WSAECONNABORTED: Software caused connection abort";
420 case WSAECONNRESET:
421 return "WSAECONNRESET: Connection reset by peer";
422 case WSAENOBUFS:
423 return "WSAENOBUFS: No buffer space available";
424 case WSAEISCONN:
425 return "WSAEISCONN: Socket is already connected";
426 case WSAENOTCONN:
427 return "WSAENOTCONN: Socket is not connected";
428 case WSAESHUTDOWN:
429 return "WSAESHUTDOWN: Cannot send after socket shutdown";
430 case WSAETIMEDOUT:
431 return "WSAETIMEDOUT: Connection timed out";
432 case WSAECONNREFUSED:
433 return "WSAECONNREFUSED: Connection refused";
434 case WSAEHOSTDOWN:
435 return "WSAEHOSTDOWN: Host is down";
436 case WSAEHOSTUNREACH:
437 return "WSAEHOSTUNREACH: No route to host";
438 case WSAEPROCLIM:
439 return "WSAEPROCLIM: Too many processes";
440 case WSASYSNOTREADY:
441 return "WSASYSNOTREADY: Network subsystem is unavailable";
442 case WSAVERNOTSUPPORTED:
443 return "WSAVERNOTSUPPORTED: Winsock.dll version out of range";
444 case WSANOTINITIALISED:
445 return "WSANOTINITIALISED: Successful WSAStartup not yet performed";
446 case WSAEDISCON:
447 return "WSAEDISCON: Graceful shutdown in progress";
448 case WSATYPE_NOT_FOUND:
449 return "WSATYPE_NOT_FOUND: Class type not found";
450 case WSAHOST_NOT_FOUND:
451 return "WSAHOST_NOT_FOUND: Host not found";
452 case WSATRY_AGAIN:
453 return "WSATRY_AGAIN: Nonauthoritative host not found";
454 case WSANO_RECOVERY:
455 return "WSANO_RECOVERY: Nonrecoverable name lookup error";
456 case WSANO_DATA:
457 return "WSANO_DATA: Valid name, no data record of requested type";
458 case WSASYSCALLFAILURE:
459 return "WSASYSCALLFAILURE: System call failure";
460 default:
461 return "Unknown error";
462 } 383 }
463} 384}