diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-01 03:32:09 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-01 03:32:09 +0000 |
| commit | 7115c12fbc9aae1cd46fdf049697a27fb996181a (patch) | |
| tree | 2e918f54f729766701aabdef488a6461bc623da1 /src/usocket.c | |
| parent | 7aaba59909e8527190694285f56ca68772c97f6a (diff) | |
| download | luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.tar.gz luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.tar.bz2 luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.zip | |
Moving on to beta2.
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 | } |
