diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-18 00:04:20 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-18 00:04:20 +0000 |
commit | c8d58798f0b0c789df5c566494112f81ac302432 (patch) | |
tree | 40c52eab0a4bf92636ebe13027d165f0b8452bb1 /src/usocket.c | |
parent | 02ef4e7daae6bef629dcb568052755fb85ed2efc (diff) | |
download | luasocket-c8d58798f0b0c789df5c566494112f81ac302432.tar.gz luasocket-c8d58798f0b0c789df5c566494112f81ac302432.tar.bz2 luasocket-c8d58798f0b0c789df5c566494112f81ac302432.zip |
Trying to get connect-with-timeout to work. Darwin works...
Diffstat (limited to 'src/usocket.c')
-rw-r--r-- | src/usocket.c | 163 |
1 files changed, 77 insertions, 86 deletions
diff --git a/src/usocket.c b/src/usocket.c index 9fcf4e8..acac852 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
@@ -46,50 +46,59 @@ void sock_destroy(p_sock ps) | |||
46 | /*-------------------------------------------------------------------------*\ | 46 | /*-------------------------------------------------------------------------*\ |
47 | * Creates and sets up a socket | 47 | * Creates and sets up a socket |
48 | \*-------------------------------------------------------------------------*/ | 48 | \*-------------------------------------------------------------------------*/ |
49 | const char *sock_create(p_sock ps, int domain, int type, int protocol) | 49 | int sock_create(p_sock ps, int domain, int type, int protocol) |
50 | { | 50 | { |
51 | int val = 1; | 51 | int val = 1; |
52 | t_sock sock = socket(domain, type, protocol); | 52 | t_sock sock = socket(domain, type, protocol); |
53 | if (sock == SOCK_INVALID) return sock_createstrerror(); | 53 | if (sock == SOCK_INVALID) return IO_ERROR; |
54 | *ps = sock; | 54 | *ps = sock; |
55 | sock_setnonblocking(ps); | 55 | sock_setnonblocking(ps); |
56 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); | 56 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); |
57 | return NULL; | 57 | return IO_DONE; |
58 | } | 58 | } |
59 | 59 | ||
60 | /*-------------------------------------------------------------------------*\ | 60 | /*-------------------------------------------------------------------------*\ |
61 | * Connects or returns error message | 61 | * Connects or returns error message |
62 | \*-------------------------------------------------------------------------*/ | 62 | \*-------------------------------------------------------------------------*/ |
63 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) | 63 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) |
64 | { | 64 | { |
65 | t_sock sock = *ps; | 65 | t_sock sock = *ps; |
66 | if (sock == SOCK_INVALID) return "closed"; | 66 | if (sock == SOCK_INVALID) return IO_CLOSED; |
67 | /* if connect fails, we have to find out why */ | ||
67 | if (connect(sock, addr, addr_len) < 0) { | 68 | if (connect(sock, addr, addr_len) < 0) { |
68 | struct timeval tv; | 69 | struct timeval tv; |
69 | fd_set wfds, efds; | 70 | fd_set rfds, efds, wfds; |
70 | int err; | 71 | int err; |
72 | /* make sure the system is trying to connect */ | ||
73 | if (errno != EINPROGRESS) return IO_ERROR; | ||
71 | tv.tv_sec = timeout / 1000; | 74 | tv.tv_sec = timeout / 1000; |
72 | tv.tv_usec = (timeout % 1000) * 1000; | 75 | tv.tv_usec = (timeout % 1000) * 1000; |
73 | FD_ZERO(&wfds); FD_ZERO(&efds); | 76 | FD_ZERO(&rfds); FD_SET(sock, &rfds); |
74 | FD_SET(sock, &wfds); FD_SET(sock, &efds); | 77 | FD_ZERO(&wfds); FD_SET(sock, &wfds); |
75 | do err = select(sock+1, NULL, &wfds, &efds, timeout >= 0 ? &tv : NULL); | 78 | FD_ZERO(&efds); FD_SET(sock, &efds); |
76 | while (err < 0 && errno == EINTR); | 79 | /* we run select to avoid busy waiting */ |
77 | if (err <= 0) return "timeout"; | 80 | err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL); |
78 | if (FD_ISSET(sock, &efds)) { | 81 | /* if select was interrupted, ask the user to retry */ |
82 | if (err < 0 && errno == EINTR) return IO_RETRY; | ||
83 | /* if selects readable, try reading */ | ||
84 | if (err > 0) { | ||
79 | char dummy; | 85 | char dummy; |
80 | recv(sock, &dummy, 0, 0); | 86 | /* try reading so that errno is set */ |
81 | return sock_connectstrerror(); | 87 | if (recv(sock, &dummy, 0, 0) < 0) return IO_ERROR; |
82 | } else return NULL; | 88 | return IO_DONE; |
83 | } else return NULL; | 89 | /* if no event happened, there was a timeout */ |
90 | } else return IO_TIMEOUT; | ||
91 | /* otherwise connection succeeded */ | ||
92 | } else return IO_DONE; | ||
84 | } | 93 | } |
85 | 94 | ||
86 | /*-------------------------------------------------------------------------*\ | 95 | /*-------------------------------------------------------------------------*\ |
87 | * Binds or returns error message | 96 | * Binds or returns error message |
88 | \*-------------------------------------------------------------------------*/ | 97 | \*-------------------------------------------------------------------------*/ |
89 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) | 98 | int sock_bind(p_sock ps, SA *addr, socklen_t addr_len) |
90 | { | 99 | { |
91 | if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); | 100 | if (bind(*ps, addr, addr_len) < 0) return IO_ERROR; |
92 | else return NULL; | 101 | else return IO_DONE; |
93 | } | 102 | } |
94 | 103 | ||
95 | /*-------------------------------------------------------------------------*\ | 104 | /*-------------------------------------------------------------------------*\ |
@@ -115,25 +124,24 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | |||
115 | int timeout) | 124 | int timeout) |
116 | { | 125 | { |
117 | t_sock sock = *ps; | 126 | t_sock sock = *ps; |
118 | struct timeval tv; | ||
119 | SA dummy_addr; | 127 | SA dummy_addr; |
120 | socklen_t dummy_len; | 128 | socklen_t dummy_len; |
121 | fd_set fds; | ||
122 | int err; | ||
123 | if (sock == SOCK_INVALID) return IO_CLOSED; | 129 | if (sock == SOCK_INVALID) return IO_CLOSED; |
124 | tv.tv_sec = timeout / 1000; | ||
125 | tv.tv_usec = (timeout % 1000) * 1000; | ||
126 | FD_ZERO(&fds); | ||
127 | FD_SET(sock, &fds); | ||
128 | *pa = SOCK_INVALID; | ||
129 | do err = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
130 | while (err < 0 && errno == EINTR); | ||
131 | if (err <= 0) return IO_TIMEOUT; | ||
132 | if (!addr) addr = &dummy_addr; | 130 | if (!addr) addr = &dummy_addr; |
133 | if (!addr_len) addr_len = &dummy_len; | 131 | if (!addr_len) addr_len = &dummy_len; |
134 | *pa = accept(sock, addr, addr_len); | 132 | *pa = accept(sock, addr, addr_len); |
135 | if (*pa == SOCK_INVALID) return IO_ERROR; | 133 | if (*pa == SOCK_INVALID) { |
136 | else return IO_DONE; | 134 | struct timeval tv; |
135 | fd_set fds; | ||
136 | tv.tv_sec = timeout / 1000; | ||
137 | tv.tv_usec = (timeout % 1000) * 1000; | ||
138 | FD_ZERO(&fds); | ||
139 | FD_SET(sock, &fds); | ||
140 | /* just call select to avoid busy-wait. doesn't really matter | ||
141 | * what happens. the caller will choose to retry or not */ | ||
142 | select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL); | ||
143 | return IO_RETRY; | ||
144 | } else return IO_DONE; | ||
137 | } | 145 | } |
138 | 146 | ||
139 | /*-------------------------------------------------------------------------*\ | 147 | /*-------------------------------------------------------------------------*\ |
@@ -144,32 +152,31 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | |||
144 | { | 152 | { |
145 | t_sock sock = *ps; | 153 | t_sock sock = *ps; |
146 | ssize_t put; | 154 | ssize_t put; |
147 | int ret; | ||
148 | /* avoid making system calls on closed sockets */ | 155 | /* avoid making system calls on closed sockets */ |
149 | if (sock == SOCK_INVALID) return IO_CLOSED; | 156 | if (sock == SOCK_INVALID) return IO_CLOSED; |
150 | /* make sure we repeat in case the call was interrupted */ | 157 | /* make sure we repeat in case the call was interrupted */ |
151 | do put = write(sock, data, count); | 158 | do put = send(sock, data, count, 0); |
152 | while (put <= 0 && errno == EINTR); | 159 | while (put < 0 && errno == EINTR); |
153 | /* deal with failure */ | 160 | /* deal with failure */ |
154 | if (put <= 0) { | 161 | if (put <= 0) { |
162 | struct timeval tv; | ||
163 | fd_set fds; | ||
155 | /* in any case, nothing has been sent */ | 164 | /* in any case, nothing has been sent */ |
156 | *sent = 0; | 165 | *sent = 0; |
166 | /* here we know the connection has been closed */ | ||
167 | if (errno == EPIPE) return IO_CLOSED; | ||
157 | /* run select to avoid busy wait */ | 168 | /* run select to avoid busy wait */ |
158 | if (errno != EPIPE) { | 169 | tv.tv_sec = timeout / 1000; |
159 | struct timeval tv; | 170 | tv.tv_usec = (timeout % 1000) * 1000; |
160 | fd_set fds; | 171 | FD_ZERO(&fds); |
161 | tv.tv_sec = timeout / 1000; | 172 | FD_SET(sock, &fds); |
162 | tv.tv_usec = (timeout % 1000) * 1000; | 173 | if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) { |
163 | FD_ZERO(&fds); | 174 | /* here the call was interrupted. calling again might work */ |
164 | FD_SET(sock, &fds); | 175 | if (errno == EINTR) return IO_RETRY; |
165 | do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ?&tv : NULL); | 176 | /* here there was no data before timeout */ |
166 | while (ret < 0 && errno == EINTR); | ||
167 | /* tell the caller to call us again because there is more data */ | ||
168 | if (ret > 0) return IO_DONE; | ||
169 | /* tell the caller there was no data before timeout */ | ||
170 | else return IO_TIMEOUT; | 177 | else return IO_TIMEOUT; |
171 | /* here we know the connection has been closed */ | 178 | /* here we didn't send anything, but now we can */ |
172 | } else return IO_CLOSED; | 179 | } else return IO_DONE; |
173 | /* here we successfully sent something */ | 180 | /* here we successfully sent something */ |
174 | } else { | 181 | } else { |
175 | *sent = put; | 182 | *sent = put; |
@@ -185,33 +192,22 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
185 | { | 192 | { |
186 | t_sock sock = *ps; | 193 | t_sock sock = *ps; |
187 | ssize_t put; | 194 | ssize_t put; |
188 | int ret; | ||
189 | /* avoid making system calls on closed sockets */ | ||
190 | if (sock == SOCK_INVALID) return IO_CLOSED; | 195 | if (sock == SOCK_INVALID) return IO_CLOSED; |
191 | /* make sure we repeat in case the call was interrupted */ | ||
192 | do put = sendto(sock, data, count, 0, addr, addr_len); | 196 | do put = sendto(sock, data, count, 0, addr, addr_len); |
193 | while (put <= 0 && errno == EINTR); | 197 | while (put < 0 && errno == EINTR); |
194 | /* deal with failure */ | ||
195 | if (put <= 0) { | 198 | if (put <= 0) { |
196 | /* in any case, nothing has been sent */ | 199 | struct timeval tv; |
200 | fd_set fds; | ||
197 | *sent = 0; | 201 | *sent = 0; |
198 | /* run select to avoid busy wait */ | 202 | if (errno == EPIPE) return IO_CLOSED; |
199 | if (errno != EPIPE) { | 203 | tv.tv_sec = timeout / 1000; |
200 | struct timeval tv; | 204 | tv.tv_usec = (timeout % 1000) * 1000; |
201 | fd_set fds; | 205 | FD_ZERO(&fds); |
202 | tv.tv_sec = timeout / 1000; | 206 | FD_SET(sock, &fds); |
203 | tv.tv_usec = (timeout % 1000) * 1000; | 207 | if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) { |
204 | FD_ZERO(&fds); | 208 | if (errno == EINTR) return IO_RETRY; |
205 | FD_SET(sock, &fds); | ||
206 | do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL); | ||
207 | while (ret < 0 && errno == EINTR); | ||
208 | /* tell the caller to call us again because there is more data */ | ||
209 | if (ret > 0) return IO_DONE; | ||
210 | /* tell the caller there was no data before timeout */ | ||
211 | else return IO_TIMEOUT; | 209 | else return IO_TIMEOUT; |
212 | /* here we know the connection has been closed */ | 210 | } else return IO_DONE; |
213 | } else return IO_CLOSED; | ||
214 | /* here we successfully sent something */ | ||
215 | } else { | 211 | } else { |
216 | *sent = put; | 212 | *sent = put; |
217 | return IO_DONE; | 213 | return IO_DONE; |
@@ -220,11 +216,6 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
220 | 216 | ||
221 | /*-------------------------------------------------------------------------*\ | 217 | /*-------------------------------------------------------------------------*\ |
222 | * Receive with timeout | 218 | * Receive with timeout |
223 | * Here we exchanged the order of the calls to write and select | ||
224 | * The idea is that the outer loop (whoever is calling sock_send) | ||
225 | * will call the function again if we didn't time out, so we can | ||
226 | * call write and then select only if it fails. | ||
227 | * Should speed things up! | ||
228 | \*-------------------------------------------------------------------------*/ | 219 | \*-------------------------------------------------------------------------*/ |
229 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 220 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
230 | { | 221 | { |
@@ -232,7 +223,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | |||
232 | ssize_t taken; | 223 | ssize_t taken; |
233 | if (sock == SOCK_INVALID) return IO_CLOSED; | 224 | if (sock == SOCK_INVALID) return IO_CLOSED; |
234 | do taken = read(sock, data, count); | 225 | do taken = read(sock, data, count); |
235 | while (taken <= 0 && errno == EINTR); | 226 | while (taken < 0 && errno == EINTR); |
236 | if (taken <= 0) { | 227 | if (taken <= 0) { |
237 | struct timeval tv; | 228 | struct timeval tv; |
238 | fd_set fds; | 229 | fd_set fds; |
@@ -243,10 +234,10 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | |||
243 | tv.tv_usec = (timeout % 1000) * 1000; | 234 | tv.tv_usec = (timeout % 1000) * 1000; |
244 | FD_ZERO(&fds); | 235 | FD_ZERO(&fds); |
245 | FD_SET(sock, &fds); | 236 | FD_SET(sock, &fds); |
246 | do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 237 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
247 | while (ret < 0 && errno == EINTR); | 238 | if (ret < 0 && errno == EINTR) return IO_RETRY; |
248 | if (ret > 0) return IO_DONE; | 239 | if (ret == 0) return IO_TIMEOUT; |
249 | else return IO_TIMEOUT; | 240 | else return IO_DONE; |
250 | } else { | 241 | } else { |
251 | *got = taken; | 242 | *got = taken; |
252 | return IO_DONE; | 243 | return IO_DONE; |
@@ -263,7 +254,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
263 | ssize_t taken; | 254 | ssize_t taken; |
264 | if (sock == SOCK_INVALID) return IO_CLOSED; | 255 | if (sock == SOCK_INVALID) return IO_CLOSED; |
265 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); | 256 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); |
266 | while (taken <= 0 && errno == EINTR); | 257 | while (taken < 0 && errno == EINTR); |
267 | if (taken <= 0) { | 258 | if (taken <= 0) { |
268 | struct timeval tv; | 259 | struct timeval tv; |
269 | fd_set fds; | 260 | fd_set fds; |
@@ -274,10 +265,10 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
274 | tv.tv_usec = (timeout % 1000) * 1000; | 265 | tv.tv_usec = (timeout % 1000) * 1000; |
275 | FD_ZERO(&fds); | 266 | FD_ZERO(&fds); |
276 | FD_SET(sock, &fds); | 267 | FD_SET(sock, &fds); |
277 | do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 268 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
278 | while (ret < 0 && errno == EINTR); | 269 | if (ret < 0 && errno == EINTR) return IO_RETRY; |
279 | if (ret > 0) return IO_DONE; | 270 | if (ret == 0) return IO_TIMEOUT; |
280 | else return IO_TIMEOUT; | 271 | else return IO_DONE; |
281 | } else { | 272 | } else { |
282 | *got = taken; | 273 | *got = taken; |
283 | return IO_DONE; | 274 | return IO_DONE; |