diff options
Diffstat (limited to 'src/usocket.c')
-rw-r--r-- | src/usocket.c | 334 |
1 files changed, 123 insertions, 211 deletions
diff --git a/src/usocket.c b/src/usocket.c index cf0458d..12a13a5 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
@@ -20,17 +20,10 @@ | |||
20 | 20 | ||
21 | #include "socket.h" | 21 | #include "socket.h" |
22 | 22 | ||
23 | static const char *sock_createstrerror(int err); | ||
24 | static const char *sock_bindstrerror(int err); | ||
25 | static const char *sock_connectstrerror(int err); | ||
26 | static const char *sock_acceptstrerror(int err); | ||
27 | static const char *sock_listenstrerror(int err); | ||
28 | |||
29 | /*-------------------------------------------------------------------------*\ | 23 | /*-------------------------------------------------------------------------*\ |
30 | * Initializes module | 24 | * Initializes module |
31 | \*-------------------------------------------------------------------------*/ | 25 | \*-------------------------------------------------------------------------*/ |
32 | int sock_open(void) | 26 | int sock_open(void) { |
33 | { | ||
34 | #if DOESNT_COMPILE_TRY_THIS | 27 | #if DOESNT_COMPILE_TRY_THIS |
35 | struct sigaction ignore; | 28 | struct sigaction ignore; |
36 | memset(&ignore, 0, sizeof(ignore)); | 29 | memset(&ignore, 0, sizeof(ignore)); |
@@ -45,16 +38,14 @@ int sock_open(void) | |||
45 | /*-------------------------------------------------------------------------*\ | 38 | /*-------------------------------------------------------------------------*\ |
46 | * Close module | 39 | * Close module |
47 | \*-------------------------------------------------------------------------*/ | 40 | \*-------------------------------------------------------------------------*/ |
48 | int sock_close(void) | 41 | int sock_close(void) { |
49 | { | ||
50 | return 1; | 42 | return 1; |
51 | } | 43 | } |
52 | 44 | ||
53 | /*-------------------------------------------------------------------------*\ | 45 | /*-------------------------------------------------------------------------*\ |
54 | * Close and inutilize socket | 46 | * Close and inutilize socket |
55 | \*-------------------------------------------------------------------------*/ | 47 | \*-------------------------------------------------------------------------*/ |
56 | void sock_destroy(p_sock ps) | 48 | void sock_destroy(p_sock ps) { |
57 | { | ||
58 | if (*ps != SOCK_INVALID) { | 49 | if (*ps != SOCK_INVALID) { |
59 | sock_setblocking(ps); | 50 | sock_setblocking(ps); |
60 | close(*ps); | 51 | close(*ps); |
@@ -63,23 +54,26 @@ void sock_destroy(p_sock ps) | |||
63 | } | 54 | } |
64 | 55 | ||
65 | /*-------------------------------------------------------------------------*\ | 56 | /*-------------------------------------------------------------------------*\ |
66 | * Select with int timeout in ms | 57 | * Select with timeout control |
67 | \*-------------------------------------------------------------------------*/ | 58 | \*-------------------------------------------------------------------------*/ |
68 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout) | 59 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) { |
69 | { | 60 | int ret; |
70 | struct timeval tv; | 61 | do { |
71 | tv.tv_sec = timeout / 1000; | 62 | struct timeval tv; |
72 | tv.tv_usec = (timeout % 1000) * 1000; | 63 | double t = tm_getretry(tm); |
73 | return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL); | 64 | tv.tv_sec = (int) t; |
65 | tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); | ||
66 | ret = select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL); | ||
67 | } while (ret < 0 && errno == EINTR); | ||
68 | return ret; | ||
74 | } | 69 | } |
75 | 70 | ||
76 | /*-------------------------------------------------------------------------*\ | 71 | /*-------------------------------------------------------------------------*\ |
77 | * Creates and sets up a socket | 72 | * Creates and sets up a socket |
78 | \*-------------------------------------------------------------------------*/ | 73 | \*-------------------------------------------------------------------------*/ |
79 | const char *sock_create(p_sock ps, int domain, int type, int protocol) | 74 | const char *sock_create(p_sock ps, int domain, int type, int protocol) { |
80 | { | ||
81 | t_sock sock = socket(domain, type, protocol); | 75 | t_sock sock = socket(domain, type, protocol); |
82 | if (sock == SOCK_INVALID) return sock_createstrerror(errno); | 76 | if (sock == SOCK_INVALID) return sock_strerror(); |
83 | *ps = sock; | 77 | *ps = sock; |
84 | return NULL; | 78 | return NULL; |
85 | } | 79 | } |
@@ -87,50 +81,49 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol) | |||
87 | /*-------------------------------------------------------------------------*\ | 81 | /*-------------------------------------------------------------------------*\ |
88 | * Connects or returns error message | 82 | * Connects or returns error message |
89 | \*-------------------------------------------------------------------------*/ | 83 | \*-------------------------------------------------------------------------*/ |
90 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) | 84 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) { |
91 | { | ||
92 | t_sock sock = *ps; | 85 | t_sock sock = *ps; |
93 | int err; | 86 | int err; |
94 | /* don't call on closed socket */ | 87 | /* don't call on closed socket */ |
95 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); | 88 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); |
96 | /* ask system to connect */ | 89 | /* ask system to connect */ |
97 | do err = connect(sock, addr, addr_len); | 90 | do err = connect(sock, addr, addr_len); |
98 | while (err < 0 && errno == EINTR); | 91 | while (err < 0 && errno == EINTR); |
99 | /* if no error, we're done */ | 92 | /* if no error, we're done */ |
100 | if (err == 0) return NULL; | 93 | if (err == 0) return NULL; |
101 | /* make sure the system is trying to connect */ | 94 | /* make sure the system is trying to connect */ |
102 | if (errno != EINPROGRESS) return sock_connectstrerror(errno); | 95 | if (errno != EINPROGRESS) return sock_strerror(); |
96 | /* optimize for timeout = 0 */ | ||
97 | if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); | ||
103 | /* wait for a timeout or for the system's answer */ | 98 | /* wait for a timeout or for the system's answer */ |
104 | for ( ;; ) { | 99 | for ( ;; ) { |
105 | fd_set rfds, wfds, efds; | 100 | fd_set rfds, wfds; |
106 | FD_ZERO(&rfds); FD_SET(sock, &rfds); | 101 | FD_ZERO(&rfds); FD_SET(sock, &rfds); |
107 | FD_ZERO(&wfds); FD_SET(sock, &wfds); | 102 | FD_ZERO(&wfds); FD_SET(sock, &wfds); |
108 | FD_ZERO(&efds); FD_SET(sock, &efds); | ||
109 | /* we run select to avoid busy waiting */ | 103 | /* we run select to avoid busy waiting */ |
110 | do err = sock_select(sock+1, &rfds, &wfds, &efds, tm_getretry(tm)); | 104 | err = sock_select(sock+1, &rfds, &wfds, NULL, tm); |
111 | while (err < 0 && errno == EINTR); | 105 | /* if there was an event, check what happened */ |
112 | /* if selects readable, try reading */ | ||
113 | if (err > 0) { | 106 | if (err > 0) { |
114 | char dummy; | 107 | char dummy; |
115 | /* recv will set errno to the value a blocking connect would set */ | 108 | /* recv will set errno to the value a blocking connect would set */ |
116 | if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) | 109 | if (err > 1 && FD_ISSET(sock, &rfds) && |
117 | return sock_connectstrerror(errno); | 110 | recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) |
111 | return sock_strerror(); | ||
118 | else | 112 | else |
119 | return NULL; | 113 | return NULL; |
120 | /* if no event happened, there was a timeout */ | 114 | /* if no event happened, there was a timeout */ |
121 | } else return io_strerror(IO_TIMEOUT); | 115 | } else if (err == 0) return io_strerror(IO_TIMEOUT); |
122 | } | 116 | } |
123 | return io_strerror(IO_TIMEOUT); /* can't get here */ | 117 | return sock_strerror(); |
124 | } | 118 | } |
125 | 119 | ||
126 | /*-------------------------------------------------------------------------*\ | 120 | /*-------------------------------------------------------------------------*\ |
127 | * Binds or returns error message | 121 | * Binds or returns error message |
128 | \*-------------------------------------------------------------------------*/ | 122 | \*-------------------------------------------------------------------------*/ |
129 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) | 123 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { |
130 | { | ||
131 | const char *err = NULL; | 124 | const char *err = NULL; |
132 | sock_setblocking(ps); | 125 | sock_setblocking(ps); |
133 | if (bind(*ps, addr, addr_len) < 0) err = sock_bindstrerror(errno); | 126 | if (bind(*ps, addr, addr_len) < 0) err = sock_strerror(); |
134 | sock_setnonblocking(ps); | 127 | sock_setnonblocking(ps); |
135 | return err; | 128 | return err; |
136 | } | 129 | } |
@@ -138,12 +131,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) | |||
138 | /*-------------------------------------------------------------------------*\ | 131 | /*-------------------------------------------------------------------------*\ |
139 | * | 132 | * |
140 | \*-------------------------------------------------------------------------*/ | 133 | \*-------------------------------------------------------------------------*/ |
141 | const char* sock_listen(p_sock ps, int backlog) | 134 | const char* sock_listen(p_sock ps, int backlog) { |
142 | { | ||
143 | const char *err = NULL; | 135 | const char *err = NULL; |
144 | sock_setblocking(ps); | 136 | sock_setblocking(ps); |
145 | if (listen(*ps, backlog)) | 137 | if (listen(*ps, backlog)) err = sock_strerror(); |
146 | err = sock_listenstrerror(errno); | ||
147 | sock_setnonblocking(ps); | 138 | sock_setnonblocking(ps); |
148 | return err; | 139 | return err; |
149 | } | 140 | } |
@@ -151,8 +142,7 @@ const char* sock_listen(p_sock ps, int backlog) | |||
151 | /*-------------------------------------------------------------------------*\ | 142 | /*-------------------------------------------------------------------------*\ |
152 | * | 143 | * |
153 | \*-------------------------------------------------------------------------*/ | 144 | \*-------------------------------------------------------------------------*/ |
154 | void sock_shutdown(p_sock ps, int how) | 145 | void sock_shutdown(p_sock ps, int how) { |
155 | { | ||
156 | sock_setblocking(ps); | 146 | sock_setblocking(ps); |
157 | shutdown(*ps, how); | 147 | shutdown(*ps, how); |
158 | sock_setnonblocking(ps); | 148 | sock_setnonblocking(ps); |
@@ -162,12 +152,11 @@ void sock_shutdown(p_sock ps, int how) | |||
162 | * Accept with timeout | 152 | * Accept with timeout |
163 | \*-------------------------------------------------------------------------*/ | 153 | \*-------------------------------------------------------------------------*/ |
164 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | 154 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, |
165 | socklen_t *addr_len, p_tm tm) | 155 | socklen_t *addr_len, p_tm tm) { |
166 | { | ||
167 | t_sock sock = *ps; | 156 | t_sock sock = *ps; |
168 | SA dummy_addr; | 157 | SA dummy_addr; |
169 | socklen_t dummy_len = sizeof(dummy_addr); | 158 | socklen_t dummy_len = sizeof(dummy_addr); |
170 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); | 159 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); |
171 | if (!addr) addr = &dummy_addr; | 160 | if (!addr) addr = &dummy_addr; |
172 | if (!addr_len) addr_len = &dummy_len; | 161 | if (!addr_len) addr_len = &dummy_len; |
173 | for (;;) { | 162 | for (;;) { |
@@ -179,14 +168,16 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | |||
179 | /* if result is valid, we are done */ | 168 | /* if result is valid, we are done */ |
180 | if (*pa != SOCK_INVALID) return NULL; | 169 | if (*pa != SOCK_INVALID) return NULL; |
181 | /* find out if we failed for a fatal reason */ | 170 | /* find out if we failed for a fatal reason */ |
182 | if (errno != EAGAIN && errno != ECONNABORTED) | 171 | /* if connection was aborted, we can try again if we have time */ |
183 | return sock_acceptstrerror(errno); | 172 | if (errno != EAGAIN && errno != ECONNABORTED) return sock_strerror(); |
173 | /* optimize for timeout = 0 case */ | ||
174 | if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); | ||
184 | /* call select to avoid busy-wait. */ | 175 | /* call select to avoid busy-wait. */ |
185 | FD_ZERO(&fds); | 176 | FD_ZERO(&fds); |
186 | FD_SET(sock, &fds); | 177 | FD_SET(sock, &fds); |
187 | do err = sock_select(sock+1, &fds, NULL, NULL, tm_getretry(tm)); | 178 | err = sock_select(sock+1, &fds, NULL, NULL, tm); |
188 | while (err < 0 && errno == EINTR); | ||
189 | if (err == 0) return io_strerror(IO_TIMEOUT); | 179 | if (err == 0) return io_strerror(IO_TIMEOUT); |
180 | else if (err < 0) return sock_strerror(); | ||
190 | } | 181 | } |
191 | return io_strerror(IO_TIMEOUT); /* can't get here */ | 182 | return io_strerror(IO_TIMEOUT); /* can't get here */ |
192 | } | 183 | } |
@@ -194,136 +185,136 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | |||
194 | /*-------------------------------------------------------------------------*\ | 185 | /*-------------------------------------------------------------------------*\ |
195 | * Send with timeout | 186 | * Send with timeout |
196 | \*-------------------------------------------------------------------------*/ | 187 | \*-------------------------------------------------------------------------*/ |
197 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | 188 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) |
198 | int timeout) | ||
199 | { | 189 | { |
200 | t_sock sock = *ps; | 190 | t_sock sock = *ps; |
201 | ssize_t put; | ||
202 | /* avoid making system calls on closed sockets */ | 191 | /* avoid making system calls on closed sockets */ |
203 | if (sock == SOCK_INVALID) return IO_CLOSED; | 192 | if (sock == SOCK_INVALID) return IO_CLOSED; |
204 | /* make sure we repeat in case the call was interrupted */ | 193 | /* loop until we send something or we give up on error */ |
205 | do put = send(sock, data, count, 0); | 194 | for ( ;; ) { |
206 | while (put < 0 && errno == EINTR); | ||
207 | /* deal with failure */ | ||
208 | if (put <= 0) { | ||
209 | int ret; | 195 | int ret; |
210 | fd_set fds; | 196 | fd_set fds; |
211 | /* in any case, nothing has been sent */ | 197 | ssize_t put; |
198 | /* make sure we repeat in case the call was interrupted */ | ||
199 | do put = send(sock, data, count, 0); | ||
200 | while (put < 0 && errno == EINTR); | ||
201 | /* if we sent something, get out */ | ||
202 | if (put > 0) { | ||
203 | *sent = put; | ||
204 | return IO_DONE; | ||
205 | } | ||
206 | /* deal with failure */ | ||
212 | *sent = 0; | 207 | *sent = 0; |
213 | /* only proceed to select if no error happened */ | ||
214 | if (errno != EAGAIN) return IO_ERROR; | ||
215 | /* optimize for the timeout = 0 case */ | ||
216 | if (timeout == 0) return IO_TIMEOUT; | ||
217 | /* here we know the connection has been closed */ | 208 | /* here we know the connection has been closed */ |
218 | if (errno == EPIPE) return IO_CLOSED; | 209 | if (put < 0 && errno == EPIPE) return IO_CLOSED; |
210 | /* send shouldn't return zero and we can only proceed if | ||
211 | * there was no serious error */ | ||
212 | if (put == 0 || errno != EAGAIN) return IO_USER; | ||
213 | /* optimize for the timeout = 0 case */ | ||
214 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | ||
219 | /* run select to avoid busy wait */ | 215 | /* run select to avoid busy wait */ |
220 | FD_ZERO(&fds); | 216 | FD_ZERO(&fds); |
221 | FD_SET(sock, &fds); | 217 | FD_SET(sock, &fds); |
222 | ret = sock_select(sock+1, NULL, &fds, NULL, timeout); | 218 | ret = sock_select(sock+1, NULL, &fds, NULL, tm); |
223 | if (ret == 0) return IO_TIMEOUT; | 219 | if (ret == 0) return IO_TIMEOUT; |
224 | else if (ret > 0 || errno == EINTR) return IO_RETRY; | 220 | if (ret < 0) return IO_USER; |
225 | else return IO_ERROR; | 221 | /* otherwise, try sending again */ |
226 | /* here we successfully sent something */ | 222 | } |
227 | } else { | ||
228 | *sent = put; | ||
229 | return IO_DONE; | ||
230 | } | ||
231 | } | 223 | } |
232 | 224 | ||
233 | /*-------------------------------------------------------------------------*\ | 225 | /*-------------------------------------------------------------------------*\ |
234 | * Sendto with timeout | 226 | * Sendto with timeout |
235 | \*-------------------------------------------------------------------------*/ | 227 | \*-------------------------------------------------------------------------*/ |
236 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | 228 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, |
237 | SA *addr, socklen_t addr_len, int timeout) | 229 | SA *addr, socklen_t addr_len, p_tm tm) |
238 | { | 230 | { |
239 | t_sock sock = *ps; | 231 | t_sock sock = *ps; |
240 | ssize_t put; | 232 | /* avoid making system calls on closed sockets */ |
241 | if (sock == SOCK_INVALID) return IO_CLOSED; | 233 | if (sock == SOCK_INVALID) return IO_CLOSED; |
242 | do put = sendto(sock, data, count, 0, addr, addr_len); | 234 | /* loop until we send something or we give up on error */ |
243 | while (put < 0 && errno == EINTR); | 235 | for ( ;; ) { |
244 | if (put <= 0) { | ||
245 | int ret; | 236 | int ret; |
246 | fd_set fds; | 237 | fd_set fds; |
238 | ssize_t put; | ||
239 | do put = sendto(sock, data, count, 0, addr, addr_len); | ||
240 | while (put < 0 && errno == EINTR); | ||
241 | if (put > 0) { | ||
242 | *sent = put; | ||
243 | return IO_DONE; | ||
244 | } | ||
247 | *sent = 0; | 245 | *sent = 0; |
248 | if (errno != EAGAIN) return IO_ERROR; | 246 | if (put < 0 && errno == EPIPE) return IO_CLOSED; |
249 | if (timeout == 0) return IO_TIMEOUT; | 247 | if (put == 0 || errno != EAGAIN) return IO_USER; |
250 | if (errno == EPIPE) return IO_CLOSED; | 248 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; |
251 | FD_ZERO(&fds); | 249 | FD_ZERO(&fds); |
252 | FD_SET(sock, &fds); | 250 | FD_SET(sock, &fds); |
253 | ret = sock_select(sock+1, NULL, &fds, NULL, timeout); | 251 | ret = sock_select(sock+1, NULL, &fds, NULL, tm); |
254 | if (ret == 0) return IO_TIMEOUT; | 252 | if (ret == 0) return IO_TIMEOUT; |
255 | else if (ret > 0 || errno == EINTR) return IO_RETRY; | 253 | if (ret < 0) return IO_USER; |
256 | else return IO_ERROR; | 254 | } |
257 | } else { | ||
258 | *sent = put; | ||
259 | return IO_DONE; | ||
260 | } | ||
261 | } | 255 | } |
262 | 256 | ||
263 | /*-------------------------------------------------------------------------*\ | 257 | /*-------------------------------------------------------------------------*\ |
264 | * Receive with timeout | 258 | * Receive with timeout |
265 | \*-------------------------------------------------------------------------*/ | 259 | \*-------------------------------------------------------------------------*/ |
266 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 260 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { |
267 | { | ||
268 | t_sock sock = *ps; | 261 | t_sock sock = *ps; |
269 | ssize_t taken; | ||
270 | if (sock == SOCK_INVALID) return IO_CLOSED; | 262 | if (sock == SOCK_INVALID) return IO_CLOSED; |
271 | do taken = read(sock, data, count); | 263 | for ( ;; ) { |
272 | while (taken < 0 && errno == EINTR); | ||
273 | if (taken <= 0) { | ||
274 | fd_set fds; | 264 | fd_set fds; |
275 | int ret; | 265 | int ret; |
266 | ssize_t taken; | ||
267 | do taken = read(sock, data, count); | ||
268 | while (taken < 0 && errno == EINTR); | ||
269 | if (taken > 0) { | ||
270 | *got = taken; | ||
271 | return IO_DONE; | ||
272 | } | ||
276 | *got = 0; | 273 | *got = 0; |
277 | if (taken == 0) return IO_CLOSED; | 274 | if (taken == 0) return IO_CLOSED; |
278 | if (errno != EAGAIN) return IO_ERROR; | 275 | if (errno != EAGAIN) return IO_USER; |
279 | if (timeout == 0) return IO_TIMEOUT; | 276 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; |
280 | FD_ZERO(&fds); | 277 | FD_ZERO(&fds); |
281 | FD_SET(sock, &fds); | 278 | FD_SET(sock, &fds); |
282 | ret = sock_select(sock+1, &fds, NULL, NULL, timeout); | 279 | ret = sock_select(sock+1, &fds, NULL, NULL, tm); |
283 | if (ret == 0) return IO_TIMEOUT; | 280 | if (ret == 0) return IO_TIMEOUT; |
284 | else if (ret > 0 || errno == EINTR) return IO_RETRY; | 281 | if (ret < 0) return IO_USER; |
285 | else return IO_ERROR; | 282 | } |
286 | } else { | ||
287 | *got = taken; | ||
288 | return IO_DONE; | ||
289 | } | ||
290 | } | 283 | } |
291 | 284 | ||
292 | /*-------------------------------------------------------------------------*\ | 285 | /*-------------------------------------------------------------------------*\ |
293 | * Recvfrom with timeout | 286 | * Recvfrom with timeout |
294 | \*-------------------------------------------------------------------------*/ | 287 | \*-------------------------------------------------------------------------*/ |
295 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | 288 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, |
296 | SA *addr, socklen_t *addr_len, int timeout) | 289 | SA *addr, socklen_t *addr_len, p_tm tm) { |
297 | { | ||
298 | t_sock sock = *ps; | 290 | t_sock sock = *ps; |
299 | ssize_t taken; | ||
300 | if (sock == SOCK_INVALID) return IO_CLOSED; | 291 | if (sock == SOCK_INVALID) return IO_CLOSED; |
301 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); | 292 | for ( ;; ) { |
302 | while (taken < 0 && errno == EINTR); | ||
303 | if (taken <= 0) { | ||
304 | fd_set fds; | 293 | fd_set fds; |
305 | int ret; | 294 | int ret; |
295 | ssize_t taken; | ||
296 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
297 | while (taken < 0 && errno == EINTR); | ||
298 | if (taken > 0) { | ||
299 | *got = taken; | ||
300 | return IO_DONE; | ||
301 | } | ||
306 | *got = 0; | 302 | *got = 0; |
307 | if (taken == 0) return IO_CLOSED; | 303 | if (taken == 0) return IO_CLOSED; |
308 | if (errno != EAGAIN) return IO_ERROR; | 304 | if (errno != EAGAIN) return IO_USER; |
309 | if (timeout == 0) return IO_TIMEOUT; | 305 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; |
310 | FD_ZERO(&fds); | 306 | FD_ZERO(&fds); |
311 | FD_SET(sock, &fds); | 307 | FD_SET(sock, &fds); |
312 | ret = sock_select(sock+1, &fds, NULL, NULL, timeout); | 308 | ret = sock_select(sock+1, &fds, NULL, NULL, tm); |
313 | if (ret == 0) return IO_TIMEOUT; | 309 | if (ret == 0) return IO_TIMEOUT; |
314 | else if (ret > 0 || errno == EINTR) return IO_RETRY; | 310 | if (ret < 0) return IO_USER; |
315 | else return IO_ERROR; | 311 | } |
316 | } else { | ||
317 | *got = taken; | ||
318 | return IO_DONE; | ||
319 | } | ||
320 | } | 312 | } |
321 | 313 | ||
322 | /*-------------------------------------------------------------------------*\ | 314 | /*-------------------------------------------------------------------------*\ |
323 | * Put socket into blocking mode | 315 | * Put socket into blocking mode |
324 | \*-------------------------------------------------------------------------*/ | 316 | \*-------------------------------------------------------------------------*/ |
325 | void sock_setblocking(p_sock ps) | 317 | void sock_setblocking(p_sock ps) { |
326 | { | ||
327 | int flags = fcntl(*ps, F_GETFL, 0); | 318 | int flags = fcntl(*ps, F_GETFL, 0); |
328 | flags &= (~(O_NONBLOCK)); | 319 | flags &= (~(O_NONBLOCK)); |
329 | fcntl(*ps, F_SETFL, flags); | 320 | fcntl(*ps, F_SETFL, flags); |
@@ -332,8 +323,7 @@ void sock_setblocking(p_sock ps) | |||
332 | /*-------------------------------------------------------------------------*\ | 323 | /*-------------------------------------------------------------------------*\ |
333 | * Put socket into non-blocking mode | 324 | * Put socket into non-blocking mode |
334 | \*-------------------------------------------------------------------------*/ | 325 | \*-------------------------------------------------------------------------*/ |
335 | void sock_setnonblocking(p_sock ps) | 326 | void sock_setnonblocking(p_sock ps) { |
336 | { | ||
337 | int flags = fcntl(*ps, F_GETFL, 0); | 327 | int flags = fcntl(*ps, F_GETFL, 0); |
338 | flags |= O_NONBLOCK; | 328 | flags |= O_NONBLOCK; |
339 | fcntl(*ps, F_SETFL, flags); | 329 | fcntl(*ps, F_SETFL, flags); |
@@ -342,98 +332,20 @@ void sock_setnonblocking(p_sock ps) | |||
342 | /*-------------------------------------------------------------------------*\ | 332 | /*-------------------------------------------------------------------------*\ |
343 | * Error translation functions | 333 | * Error translation functions |
344 | \*-------------------------------------------------------------------------*/ | 334 | \*-------------------------------------------------------------------------*/ |
345 | /* return error messages for the known errors reported by gethostbyname */ | 335 | const char *sock_hoststrerror(void) { |
346 | const char *sock_hoststrerror(void) | 336 | return hstrerror(h_errno); |
347 | { | ||
348 | switch (h_errno) { | ||
349 | case HOST_NOT_FOUND: return "host not found"; | ||
350 | case NO_ADDRESS: return "valid host but no ip found"; | ||
351 | case NO_RECOVERY: return "name server error"; | ||
352 | case TRY_AGAIN: return "name server unavailable, try again later"; | ||
353 | default: return "unknown error"; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | /* return error messages for the known errors reported by socket */ | ||
358 | static const char *sock_createstrerror(int err) | ||
359 | { | ||
360 | switch (err) { | ||
361 | case EPROTONOSUPPORT: return "protocol not supported"; | ||
362 | case EACCES: return "access denied"; | ||
363 | case EMFILE: return "process file table is full"; | ||
364 | case ENFILE: return "kernel file table is full"; | ||
365 | case EINVAL: return "unknown protocol or family"; | ||
366 | case ENOBUFS: return "insuffucient buffer space"; | ||
367 | default: return "unknown error"; | ||
368 | } | ||
369 | } | 337 | } |
370 | 338 | ||
371 | /* return error messages for the known errors reported by accept */ | 339 | /* make sure important error messages are standard */ |
372 | static const char *sock_acceptstrerror(int err) | 340 | const char *sock_strerror(void) { |
373 | { | 341 | switch (errno) { |
374 | switch (err) { | 342 | case EADDRINUSE: |
375 | case EAGAIN: return io_strerror(IO_RETRY); | 343 | return "address already in use"; |
376 | case EBADF: return "invalid descriptor"; | 344 | default: |
377 | case ENOBUFS: case ENOMEM: return "insuffucient buffer space"; | 345 | return strerror(errno); |
378 | case ENOTSOCK: return "descriptor not a socket"; | ||
379 | case EOPNOTSUPP: return "not supported"; | ||
380 | case EINTR: return "call interrupted"; | ||
381 | case ECONNABORTED: return "connection aborted"; | ||
382 | case EINVAL: return "not listening"; | ||
383 | case EMFILE: return "process file table is full"; | ||
384 | case ENFILE: return "kernel file table is full"; | ||
385 | case EFAULT: return "invalid memory address"; | ||
386 | default: return "unknown error"; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | |||
391 | /* return error messages for the known errors reported by bind */ | ||
392 | static const char *sock_bindstrerror(int err) | ||
393 | { | ||
394 | switch (err) { | ||
395 | case EBADF: return "invalid descriptor"; | ||
396 | case ENOTSOCK: return "descriptor not a socket"; | ||
397 | case EADDRNOTAVAIL: return "address unavailable in local host"; | ||
398 | case EADDRINUSE: return "address already in use"; | ||
399 | case EINVAL: return "already bound"; | ||
400 | case EACCES: return "access denied"; | ||
401 | case EFAULT: return "invalid memory address"; | ||
402 | case ENOMEM: return "out of memory"; | ||
403 | default: return "unknown error"; | ||
404 | } | 346 | } |
405 | } | 347 | } |
406 | 348 | ||
407 | /* return error messages for the known errors reported by listen */ | 349 | const char *sock_geterr(p_sock ps, int code) { |
408 | static const char *sock_listenstrerror(int err) | 350 | return sock_strerror(); |
409 | { | ||
410 | switch (err) { | ||
411 | case EADDRINUSE: return "local address already in use"; | ||
412 | case EBADF: return "invalid descriptor"; | ||
413 | case ENOTSOCK: return "descriptor not a socket"; | ||
414 | case EOPNOTSUPP: return "not supported"; | ||
415 | default: return "unknown error"; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | /* return error messages for the known errors reported by connect */ | ||
420 | static const char *sock_connectstrerror(int err) | ||
421 | { | ||
422 | switch (err) { | ||
423 | case EBADF: return "invalid descriptor"; | ||
424 | case EFAULT: return "invalid memory address"; | ||
425 | case ENOTSOCK: return "descriptor not a socket"; | ||
426 | case EADDRNOTAVAIL: return "address not available in local host"; | ||
427 | case EISCONN: return "already connected"; | ||
428 | case ECONNREFUSED: return "connection refused"; | ||
429 | case ETIMEDOUT: return io_strerror(IO_TIMEOUT); | ||
430 | case ENETUNREACH: return "network is unreachable"; | ||
431 | case EADDRINUSE: return "local address already in use"; | ||
432 | case EINPROGRESS: return "would block"; | ||
433 | case EALREADY: return "connect already in progress"; | ||
434 | case EAGAIN: return "not enough free ports"; | ||
435 | case EAFNOSUPPORT: return "address family not supported"; | ||
436 | case EPERM: return "broadcast not enabled or firewall block"; | ||
437 | default: return "unknown error"; | ||
438 | } | ||
439 | } | 351 | } |