diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-15 06:11:53 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-15 06:11:53 +0000 |
| commit | 9a79d500eb3e015f5bf579aab714916d49c1f289 (patch) | |
| tree | db658e87a17e5417ec01ab4a1b0249bdaf2bd1d2 /src/usocket.c | |
| parent | 471334c3d07f398e4b0859c43276341a28b91504 (diff) | |
| download | luasocket-9a79d500eb3e015f5bf579aab714916d49c1f289.tar.gz luasocket-9a79d500eb3e015f5bf579aab714916d49c1f289.tar.bz2 luasocket-9a79d500eb3e015f5bf579aab714916d49c1f289.zip | |
Still need to fix windows. :o/
Diffstat (limited to 'src/usocket.c')
| -rw-r--r-- | src/usocket.c | 368 |
1 files changed, 189 insertions, 179 deletions
diff --git a/src/usocket.c b/src/usocket.c index 4e73a96..4d4f092 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
| @@ -14,6 +14,63 @@ | |||
| 14 | #include "socket.h" | 14 | #include "socket.h" |
| 15 | 15 | ||
| 16 | /*-------------------------------------------------------------------------*\ | 16 | /*-------------------------------------------------------------------------*\ |
| 17 | * Wait for readable/writable/connected socket with timeout | ||
| 18 | \*-------------------------------------------------------------------------*/ | ||
| 19 | #ifdef SOCK_POLL | ||
| 20 | #include <sys/poll.h> | ||
| 21 | |||
| 22 | #define WAITFD_R POLLIN | ||
| 23 | #define WAITFD_W POLLOUT | ||
| 24 | #define WAITFD_C (POLLIN|POLLOUT) | ||
| 25 | static int sock_waitfd(int fd, int sw, p_tm tm) { | ||
| 26 | int ret; | ||
| 27 | struct pollfd pfd; | ||
| 28 | pfd.fd = fd; | ||
| 29 | pfd.events = sw; | ||
| 30 | pfd.revents = 0; | ||
| 31 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | ||
| 32 | do ret = poll(&pfd, 1, (int)(tm_getretry(tm)*1e3)); | ||
| 33 | while (ret == -1 && errno == EINTR); | ||
| 34 | if (ret == -1) return errno; | ||
| 35 | if (ret == 0) return IO_TIMEOUT; | ||
| 36 | if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; | ||
| 37 | return IO_DONE; | ||
| 38 | } | ||
| 39 | #else | ||
| 40 | |||
| 41 | #define WAITFD_R 1 | ||
| 42 | #define WAITFD_W 2 | ||
| 43 | #define WAITFD_C (WAITFD_R|WAITFD_W) | ||
| 44 | |||
| 45 | static int sock_waitfd(int fd, int sw, p_tm tm) { | ||
| 46 | int ret; | ||
| 47 | fd_set rfds, wfds, *rp, *wp; | ||
| 48 | struct timeval tv, *tp; | ||
| 49 | double t; | ||
| 50 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | ||
| 51 | do { | ||
| 52 | /* must set bits within loop, because select may have modifed them */ | ||
| 53 | rp = wp = NULL; | ||
| 54 | if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rp = &rfds; } | ||
| 55 | if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(fd, &wfds); wp = &wfds; } | ||
| 56 | t = tm_getretry(tm); | ||
| 57 | tp = NULL; | ||
| 58 | if (t >= 0.0) { | ||
| 59 | tv.tv_sec = (int)t; | ||
| 60 | tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); | ||
| 61 | tp = &tv; | ||
| 62 | } | ||
| 63 | ret = select(fd+1, rp, wp, NULL, tp); | ||
| 64 | } while (ret == -1 && errno == EINTR); | ||
| 65 | if (ret == -1) return errno; | ||
| 66 | if (ret == 0) return IO_TIMEOUT; | ||
| 67 | if (sw == WAITFD_C && FD_ISSET(fd, &rfds)) return IO_CLOSED; | ||
| 68 | return IO_DONE; | ||
| 69 | } | ||
| 70 | #endif | ||
| 71 | |||
| 72 | |||
| 73 | /*-------------------------------------------------------------------------*\ | ||
| 17 | * Initializes module | 74 | * Initializes module |
| 18 | \*-------------------------------------------------------------------------*/ | 75 | \*-------------------------------------------------------------------------*/ |
| 19 | int sock_open(void) { | 76 | int sock_open(void) { |
| @@ -58,59 +115,19 @@ int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) { | |||
| 58 | /*-------------------------------------------------------------------------*\ | 115 | /*-------------------------------------------------------------------------*\ |
| 59 | * Creates and sets up a socket | 116 | * Creates and sets up a socket |
| 60 | \*-------------------------------------------------------------------------*/ | 117 | \*-------------------------------------------------------------------------*/ |
| 61 | const char *sock_create(p_sock ps, int domain, int type, int protocol) { | 118 | int sock_create(p_sock ps, int domain, int type, int protocol) { |
| 62 | t_sock sock = socket(domain, type, protocol); | 119 | *ps = socket(domain, type, protocol); |
| 63 | if (sock == SOCK_INVALID) return sock_strerror(); | 120 | if (*ps != SOCK_INVALID) return IO_DONE; |
| 64 | *ps = sock; | 121 | else return errno; |
| 65 | return NULL; | ||
| 66 | } | ||
| 67 | |||
| 68 | /*-------------------------------------------------------------------------*\ | ||
| 69 | * Connects or returns error message | ||
| 70 | \*-------------------------------------------------------------------------*/ | ||
| 71 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) { | ||
| 72 | t_sock sock = *ps; | ||
| 73 | int err; | ||
| 74 | /* don't call on closed socket */ | ||
| 75 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); | ||
| 76 | /* ask system to connect */ | ||
| 77 | do err = connect(sock, addr, addr_len); | ||
| 78 | while (err < 0 && errno == EINTR); | ||
| 79 | /* if no error, we're done */ | ||
| 80 | if (err == 0) return NULL; | ||
| 81 | /* make sure the system is trying to connect */ | ||
| 82 | if (errno != EINPROGRESS) return sock_strerror(); | ||
| 83 | /* optimize for timeout = 0 */ | ||
| 84 | if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); | ||
| 85 | /* wait for a timeout or for the system's answer */ | ||
| 86 | for ( ;; ) { | ||
| 87 | fd_set rfds, wfds; | ||
| 88 | FD_ZERO(&rfds); FD_SET(sock, &rfds); | ||
| 89 | FD_ZERO(&wfds); FD_SET(sock, &wfds); | ||
| 90 | /* we run select to avoid busy waiting */ | ||
| 91 | err = sock_select(sock+1, &rfds, &wfds, NULL, tm); | ||
| 92 | /* if there was an event, check what happened */ | ||
| 93 | if (err > 0) { | ||
| 94 | char dummy; | ||
| 95 | /* recv will set errno to the value a blocking connect would set */ | ||
| 96 | if (err > 1 && FD_ISSET(sock, &rfds) && | ||
| 97 | recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) | ||
| 98 | return sock_strerror(); | ||
| 99 | else | ||
| 100 | return NULL; | ||
| 101 | /* if no event happened, there was a timeout */ | ||
| 102 | } else if (err == 0) return io_strerror(IO_TIMEOUT); | ||
| 103 | } | ||
| 104 | return sock_strerror(); | ||
| 105 | } | 122 | } |
| 106 | 123 | ||
| 107 | /*-------------------------------------------------------------------------*\ | 124 | /*-------------------------------------------------------------------------*\ |
| 108 | * Binds or returns error message | 125 | * Binds or returns error message |
| 109 | \*-------------------------------------------------------------------------*/ | 126 | \*-------------------------------------------------------------------------*/ |
| 110 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { | 127 | int sock_bind(p_sock ps, SA *addr, socklen_t len) { |
| 111 | const char *err = NULL; | 128 | int err = IO_DONE; |
| 112 | sock_setblocking(ps); | 129 | sock_setblocking(ps); |
| 113 | if (bind(*ps, addr, addr_len) < 0) err = sock_strerror(); | 130 | if (bind(*ps, addr, len) < 0) err = errno; |
| 114 | sock_setnonblocking(ps); | 131 | sock_setnonblocking(ps); |
| 115 | return err; | 132 | return err; |
| 116 | } | 133 | } |
| @@ -118,10 +135,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { | |||
| 118 | /*-------------------------------------------------------------------------*\ | 135 | /*-------------------------------------------------------------------------*\ |
| 119 | * | 136 | * |
| 120 | \*-------------------------------------------------------------------------*/ | 137 | \*-------------------------------------------------------------------------*/ |
| 121 | const char* sock_listen(p_sock ps, int backlog) { | 138 | int sock_listen(p_sock ps, int backlog) { |
| 122 | const char *err = NULL; | 139 | int err = IO_DONE; |
| 123 | sock_setblocking(ps); | 140 | sock_setblocking(ps); |
| 124 | if (listen(*ps, backlog)) err = sock_strerror(); | 141 | if (listen(*ps, backlog)) err = errno; |
| 125 | sock_setnonblocking(ps); | 142 | sock_setnonblocking(ps); |
| 126 | return err; | 143 | return err; |
| 127 | } | 144 | } |
| @@ -136,37 +153,45 @@ void sock_shutdown(p_sock ps, int how) { | |||
| 136 | } | 153 | } |
| 137 | 154 | ||
| 138 | /*-------------------------------------------------------------------------*\ | 155 | /*-------------------------------------------------------------------------*\ |
| 156 | * Connects or returns error message | ||
| 157 | \*-------------------------------------------------------------------------*/ | ||
| 158 | int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { | ||
| 159 | int err; | ||
| 160 | /* avoid calling on closed sockets */ | ||
| 161 | if (*ps == SOCK_INVALID) return IO_CLOSED; | ||
| 162 | /* call connect until done or failed without being interrupted */ | ||
| 163 | do if (connect(*ps, addr, len) == 0) return IO_DONE; | ||
| 164 | while ((err = errno) == EINTR); | ||
| 165 | /* if connection failed immediately, return error code */ | ||
| 166 | if (err != EINPROGRESS && err != EAGAIN) return err; | ||
| 167 | /* wait until we have the result of the connection attempt or timeout */ | ||
| 168 | if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) { | ||
| 169 | /* finaly find out if we succeeded connecting */ | ||
| 170 | if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; | ||
| 171 | else return errno; | ||
| 172 | /* timed out or some weirder error */ | ||
| 173 | } else return err; | ||
| 174 | } | ||
| 175 | |||
| 176 | /*-------------------------------------------------------------------------*\ | ||
| 139 | * Accept with timeout | 177 | * Accept with timeout |
| 140 | \*-------------------------------------------------------------------------*/ | 178 | \*-------------------------------------------------------------------------*/ |
| 141 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | 179 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) { |
| 142 | socklen_t *addr_len, p_tm tm) { | 180 | SA daddr; |
| 143 | t_sock sock = *ps; | 181 | socklen_t dlen = sizeof(daddr); |
| 144 | SA dummy_addr; | 182 | int err; |
| 145 | socklen_t dummy_len = sizeof(dummy_addr); | 183 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
| 146 | if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); | 184 | if (!addr) addr = &daddr; |
| 147 | if (!addr) addr = &dummy_addr; | 185 | if (!len) len = &dlen; |
| 148 | if (!addr_len) addr_len = &dummy_len; | 186 | for ( ;; ) { |
| 149 | for (;;) { | 187 | if ((*pa = accept(*ps, addr, len)) != SOCK_INVALID) return IO_DONE; |
| 150 | int err; | 188 | err = errno; |
| 151 | fd_set fds; | 189 | if (err == EINTR) continue; |
| 152 | /* try to accept */ | 190 | if (err != EAGAIN && err != ECONNABORTED) return err; |
| 153 | do *pa = accept(sock, addr, addr_len); | 191 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 154 | while (*pa < 0 && errno == EINTR); | 192 | } |
| 155 | /* if result is valid, we are done */ | 193 | /* can't reach here */ |
| 156 | if (*pa != SOCK_INVALID) return NULL; | 194 | return err; |
| 157 | /* find out if we failed for a fatal reason */ | ||
| 158 | /* if connection was aborted, we can try again if we have time */ | ||
| 159 | if (errno != EAGAIN && errno != ECONNABORTED) return sock_strerror(); | ||
| 160 | /* optimize for timeout = 0 case */ | ||
| 161 | if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT); | ||
| 162 | /* call select to avoid busy-wait. */ | ||
| 163 | FD_ZERO(&fds); | ||
| 164 | FD_SET(sock, &fds); | ||
| 165 | err = sock_select(sock+1, &fds, NULL, NULL, tm); | ||
| 166 | if (err == 0) return io_strerror(IO_TIMEOUT); | ||
| 167 | else if (err < 0) break; | ||
| 168 | } | ||
| 169 | return sock_strerror(); | ||
| 170 | } | 195 | } |
| 171 | 196 | ||
| 172 | /*-------------------------------------------------------------------------*\ | 197 | /*-------------------------------------------------------------------------*\ |
| @@ -174,132 +199,100 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | |||
| 174 | \*-------------------------------------------------------------------------*/ | 199 | \*-------------------------------------------------------------------------*/ |
| 175 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) | 200 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) |
| 176 | { | 201 | { |
| 177 | t_sock sock = *ps; | 202 | int err; |
| 178 | /* avoid making system calls on closed sockets */ | 203 | /* avoid making system calls on closed sockets */ |
| 179 | if (sock == SOCK_INVALID) return IO_CLOSED; | 204 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
| 180 | /* loop until we send something or we give up on error */ | 205 | /* loop until we send something or we give up on error */ |
| 206 | *sent = 0; | ||
| 181 | for ( ;; ) { | 207 | for ( ;; ) { |
| 182 | int ret; | 208 | ssize_t put = send(*ps, data, count, 0); |
| 183 | fd_set fds; | 209 | /* if we sent anything, we are done */ |
| 184 | ssize_t put; | 210 | if (put > 0) { |
| 185 | /* make sure we repeat in case the call was interrupted */ | ||
| 186 | do put = send(sock, data, count, 0); | ||
| 187 | while (put < 0 && errno == EINTR); | ||
| 188 | /* if we sent something, get out */ | ||
| 189 | if (put > 0) { | ||
| 190 | *sent = put; | 211 | *sent = put; |
| 191 | return IO_DONE; | 212 | return IO_DONE; |
| 192 | } | 213 | } |
| 193 | /* deal with failure */ | 214 | err = errno; |
| 194 | *sent = 0; | 215 | /* send can't really return 0, but EPIPE means the connection was |
| 195 | /* here we know the connection has been closed */ | 216 | closed */ |
| 196 | if (put < 0 && errno == EPIPE) return IO_CLOSED; | 217 | if (put == 0 || err == EPIPE) return IO_CLOSED; |
| 197 | /* send shouldn't return zero and we can only proceed if | 218 | /* we call was interrupted, just try again */ |
| 198 | * there was no serious error */ | 219 | if (err == EINTR) continue; |
| 199 | if (put == 0 || errno != EAGAIN) return IO_USER; | 220 | /* if failed fatal reason, report error */ |
| 200 | /* optimize for the timeout = 0 case */ | 221 | if (err != EAGAIN) return err; |
| 201 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 222 | /* wait until we can send something or we timeout */ |
| 202 | /* run select to avoid busy wait */ | 223 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; |
| 203 | FD_ZERO(&fds); | 224 | } |
| 204 | FD_SET(sock, &fds); | 225 | /* can't reach here */ |
| 205 | ret = sock_select(sock+1, NULL, &fds, NULL, tm); | 226 | return err; |
| 206 | if (ret == 0) return IO_TIMEOUT; | ||
| 207 | else if (ret < 0) break; | ||
| 208 | /* otherwise, try sending again */ | ||
| 209 | } | ||
| 210 | return IO_USER; | ||
| 211 | } | 227 | } |
| 212 | 228 | ||
| 213 | /*-------------------------------------------------------------------------*\ | 229 | /*-------------------------------------------------------------------------*\ |
| 214 | * Sendto with timeout | 230 | * Sendto with timeout |
| 215 | \*-------------------------------------------------------------------------*/ | 231 | \*-------------------------------------------------------------------------*/ |
| 216 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | 232 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, |
| 217 | SA *addr, socklen_t addr_len, p_tm tm) | 233 | SA *addr, socklen_t len, p_tm tm) |
| 218 | { | 234 | { |
| 219 | t_sock sock = *ps; | 235 | int err; |
| 220 | /* avoid making system calls on closed sockets */ | 236 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
| 221 | if (sock == SOCK_INVALID) return IO_CLOSED; | 237 | *sent = 0; |
| 222 | /* loop until we send something or we give up on error */ | ||
| 223 | for ( ;; ) { | 238 | for ( ;; ) { |
| 224 | int ret; | 239 | ssize_t put = sendto(*ps, data, count, 0, addr, len); |
| 225 | fd_set fds; | 240 | if (put > 0) { |
| 226 | ssize_t put; | ||
| 227 | do put = sendto(sock, data, count, 0, addr, addr_len); | ||
| 228 | while (put < 0 && errno == EINTR); | ||
| 229 | if (put > 0) { | ||
| 230 | *sent = put; | 241 | *sent = put; |
| 231 | return IO_DONE; | 242 | return IO_DONE; |
| 232 | } | 243 | } |
| 233 | *sent = 0; | 244 | err = errno; |
| 234 | if (put < 0 && errno == EPIPE) return IO_CLOSED; | 245 | if (put == 0 || err == EPIPE) return IO_CLOSED; |
| 235 | if (put == 0 || errno != EAGAIN) return IO_USER; | 246 | if (err == EINTR) continue; |
| 236 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 247 | if (err != EAGAIN) return err; |
| 237 | FD_ZERO(&fds); | 248 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; |
| 238 | FD_SET(sock, &fds); | 249 | } |
| 239 | ret = sock_select(sock+1, NULL, &fds, NULL, tm); | 250 | return err; |
| 240 | if (ret == 0) return IO_TIMEOUT; | ||
| 241 | else if (ret < 0) break; | ||
| 242 | } | ||
| 243 | return IO_USER; | ||
| 244 | } | 251 | } |
| 245 | 252 | ||
| 246 | /*-------------------------------------------------------------------------*\ | 253 | /*-------------------------------------------------------------------------*\ |
| 247 | * Receive with timeout | 254 | * Receive with timeout |
| 248 | \*-------------------------------------------------------------------------*/ | 255 | \*-------------------------------------------------------------------------*/ |
| 249 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { | 256 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { |
| 250 | t_sock sock = *ps; | 257 | int err; |
| 251 | if (sock == SOCK_INVALID) return IO_CLOSED; | 258 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
| 252 | for ( ;; ) { | 259 | for ( ;; ) { |
| 253 | fd_set fds; | 260 | ssize_t taken = recv(*ps, data, count, 0); |
| 254 | int ret; | ||
| 255 | ssize_t taken; | ||
| 256 | do taken = read(sock, data, count); | ||
| 257 | while (taken < 0 && errno == EINTR); | ||
| 258 | if (taken > 0) { | 261 | if (taken > 0) { |
| 259 | *got = taken; | 262 | *got = taken; |
| 260 | return IO_DONE; | 263 | return IO_DONE; |
| 261 | } | 264 | } |
| 265 | err = errno; | ||
| 262 | *got = 0; | 266 | *got = 0; |
| 263 | if (taken == 0) return IO_CLOSED; | 267 | if (taken == 0) return IO_CLOSED; |
| 264 | if (errno != EAGAIN) return IO_USER; | 268 | if (err == EINTR) continue; |
| 265 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 269 | if (err != EAGAIN) return err; |
| 266 | FD_ZERO(&fds); | 270 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 267 | FD_SET(sock, &fds); | 271 | } |
| 268 | ret = sock_select(sock+1, &fds, NULL, NULL, tm); | 272 | return err; |
| 269 | if (ret == 0) return IO_TIMEOUT; | ||
| 270 | else if (ret < 0) break; | ||
| 271 | } | ||
| 272 | return IO_USER; | ||
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | /*-------------------------------------------------------------------------*\ | 275 | /*-------------------------------------------------------------------------*\ |
| 276 | * Recvfrom with timeout | 276 | * Recvfrom with timeout |
| 277 | \*-------------------------------------------------------------------------*/ | 277 | \*-------------------------------------------------------------------------*/ |
| 278 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | 278 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, |
| 279 | SA *addr, socklen_t *addr_len, p_tm tm) { | 279 | SA *addr, socklen_t *len, p_tm tm) { |
| 280 | t_sock sock = *ps; | 280 | int err; |
| 281 | if (sock == SOCK_INVALID) return IO_CLOSED; | 281 | if (*ps == SOCK_INVALID) return IO_CLOSED; |
| 282 | for ( ;; ) { | 282 | for ( ;; ) { |
| 283 | fd_set fds; | 283 | ssize_t taken = recvfrom(*ps, data, count, 0, addr, len); |
| 284 | int ret; | ||
| 285 | ssize_t taken; | ||
| 286 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
| 287 | while (taken < 0 && errno == EINTR); | ||
| 288 | if (taken > 0) { | 284 | if (taken > 0) { |
| 289 | *got = taken; | 285 | *got = taken; |
| 290 | return IO_DONE; | 286 | return IO_DONE; |
| 291 | } | 287 | } |
| 288 | err = errno; | ||
| 292 | *got = 0; | 289 | *got = 0; |
| 293 | if (taken == 0) return IO_CLOSED; | 290 | if (taken == 0) return IO_CLOSED; |
| 294 | if (errno != EAGAIN) return IO_USER; | 291 | if (err == EINTR) continue; |
| 295 | if (tm_get(tm) == 0.0) return IO_TIMEOUT; | 292 | if (err != EAGAIN) return err; |
| 296 | FD_ZERO(&fds); | 293 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 297 | FD_SET(sock, &fds); | 294 | } |
| 298 | ret = sock_select(sock+1, &fds, NULL, NULL, tm); | 295 | return err; |
| 299 | if (ret == 0) return IO_TIMEOUT; | ||
| 300 | else if (ret < 0) break; | ||
| 301 | } | ||
| 302 | return IO_USER; | ||
| 303 | } | 296 | } |
| 304 | 297 | ||
| 305 | /*-------------------------------------------------------------------------*\ | 298 | /*-------------------------------------------------------------------------*\ |
| @@ -321,29 +314,46 @@ void sock_setnonblocking(p_sock ps) { | |||
| 321 | } | 314 | } |
| 322 | 315 | ||
| 323 | /*-------------------------------------------------------------------------*\ | 316 | /*-------------------------------------------------------------------------*\ |
| 317 | * DNS helpers | ||
| 318 | \*-------------------------------------------------------------------------*/ | ||
| 319 | int sock_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { | ||
| 320 | *hp = gethostbyaddr(addr, len, AF_INET); | ||
| 321 | if (*hp) return IO_DONE; | ||
| 322 | else return h_errno; | ||
| 323 | } | ||
| 324 | |||
| 325 | int sock_gethostbyname(const char *addr, struct hostent **hp) { | ||
| 326 | *hp = gethostbyname(addr); | ||
| 327 | if (*hp) return IO_DONE; | ||
| 328 | else return h_errno; | ||
| 329 | } | ||
| 330 | |||
| 331 | /*-------------------------------------------------------------------------*\ | ||
| 324 | * Error translation functions | 332 | * Error translation functions |
| 333 | * Make sure important error messages are standard | ||
| 325 | \*-------------------------------------------------------------------------*/ | 334 | \*-------------------------------------------------------------------------*/ |
| 326 | const char *sock_hoststrerror(void) { | 335 | const char *sock_hoststrerror(int err) { |
| 327 | switch (h_errno) { | 336 | if (err <= 0) return io_strerror(err); |
| 328 | case HOST_NOT_FOUND: | 337 | switch (err) { |
| 329 | return "host not found"; | 338 | case HOST_NOT_FOUND: return "host_not_found"; |
| 330 | default: | 339 | default: return hstrerror(err); |
| 331 | return hstrerror(h_errno); | ||
| 332 | } | 340 | } |
| 333 | } | 341 | } |
| 334 | 342 | ||
| 335 | /* make sure important error messages are standard */ | 343 | const char *sock_strerror(int err) { |
| 336 | const char *sock_strerror(void) { | 344 | if (err <= 0) return io_strerror(err); |
| 337 | switch (errno) { | 345 | switch (err) { |
| 338 | case EADDRINUSE: | 346 | case EADDRINUSE: return "eaddrinuse"; |
| 339 | return "address already in use"; | 347 | case EACCES: return "eaccess"; |
| 340 | default: | 348 | case ECONNABORTED: return "econnaborted"; |
| 341 | return strerror(errno); | 349 | case ECONNREFUSED: return "econnrefused"; |
| 350 | case ECONNRESET: return "econnreset"; | ||
| 351 | case ETIMEDOUT: return "etimedout"; | ||
| 352 | default: return strerror(errno); | ||
| 342 | } | 353 | } |
| 343 | } | 354 | } |
| 344 | 355 | ||
| 345 | const char *sock_geterr(p_sock ps, int code) { | 356 | const char *sock_ioerror(p_sock ps, int err) { |
| 346 | (void) ps; | 357 | (void) ps; |
| 347 | (void) code; | 358 | return sock_strerror(err); |
| 348 | return sock_strerror(); | 359 | } |
| 349 | } | ||
