Mercurial > luasocket
comparison src/usocket.c @ 0:4b915342e2a8
LuaSocket 2.0.2 + CMake build description.
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Tue, 26 Aug 2008 18:40:01 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4b915342e2a8 |
---|---|
1 /*=========================================================================*\ | |
2 * Socket compatibilization module for Unix | |
3 * LuaSocket toolkit | |
4 * | |
5 * The code is now interrupt-safe. | |
6 * The penalty of calling select to avoid busy-wait is only paid when | |
7 * the I/O call fail in the first place. | |
8 * | |
9 * RCS ID: $Id: usocket.c,v 1.38 2007/10/13 23:55:20 diego Exp $ | |
10 \*=========================================================================*/ | |
11 #include <string.h> | |
12 #include <signal.h> | |
13 | |
14 #include "socket.h" | |
15 | |
16 /*-------------------------------------------------------------------------*\ | |
17 * Wait for readable/writable/connected socket with timeout | |
18 \*-------------------------------------------------------------------------*/ | |
19 #ifdef SOCKET_POLL | |
20 #include <sys/poll.h> | |
21 | |
22 #define WAITFD_R POLLIN | |
23 #define WAITFD_W POLLOUT | |
24 #define WAITFD_C (POLLIN|POLLOUT) | |
25 int socket_waitfd(p_socket ps, int sw, p_timeout tm) { | |
26 int ret; | |
27 struct pollfd pfd; | |
28 pfd.fd = *ps; | |
29 pfd.events = sw; | |
30 pfd.revents = 0; | |
31 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | |
32 do { | |
33 int t = (int)(timeout_getretry(tm)*1e3); | |
34 ret = poll(&pfd, 1, t >= 0? t: -1); | |
35 } while (ret == -1 && errno == EINTR); | |
36 if (ret == -1) return errno; | |
37 if (ret == 0) return IO_TIMEOUT; | |
38 if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; | |
39 return IO_DONE; | |
40 } | |
41 #else | |
42 | |
43 #define WAITFD_R 1 | |
44 #define WAITFD_W 2 | |
45 #define WAITFD_C (WAITFD_R|WAITFD_W) | |
46 | |
47 int socket_waitfd(p_socket ps, int sw, p_timeout tm) { | |
48 int ret; | |
49 fd_set rfds, wfds, *rp, *wp; | |
50 struct timeval tv, *tp; | |
51 double t; | |
52 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | |
53 do { | |
54 /* must set bits within loop, because select may have modifed them */ | |
55 rp = wp = NULL; | |
56 if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; } | |
57 if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } | |
58 t = timeout_getretry(tm); | |
59 tp = NULL; | |
60 if (t >= 0.0) { | |
61 tv.tv_sec = (int)t; | |
62 tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); | |
63 tp = &tv; | |
64 } | |
65 ret = select(*ps+1, rp, wp, NULL, tp); | |
66 } while (ret == -1 && errno == EINTR); | |
67 if (ret == -1) return errno; | |
68 if (ret == 0) return IO_TIMEOUT; | |
69 if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED; | |
70 return IO_DONE; | |
71 } | |
72 #endif | |
73 | |
74 | |
75 /*-------------------------------------------------------------------------*\ | |
76 * Initializes module | |
77 \*-------------------------------------------------------------------------*/ | |
78 int socket_open(void) { | |
79 /* instals a handler to ignore sigpipe or it will crash us */ | |
80 signal(SIGPIPE, SIG_IGN); | |
81 return 1; | |
82 } | |
83 | |
84 /*-------------------------------------------------------------------------*\ | |
85 * Close module | |
86 \*-------------------------------------------------------------------------*/ | |
87 int socket_close(void) { | |
88 return 1; | |
89 } | |
90 | |
91 /*-------------------------------------------------------------------------*\ | |
92 * Close and inutilize socket | |
93 \*-------------------------------------------------------------------------*/ | |
94 void socket_destroy(p_socket ps) { | |
95 if (*ps != SOCKET_INVALID) { | |
96 socket_setblocking(ps); | |
97 close(*ps); | |
98 *ps = SOCKET_INVALID; | |
99 } | |
100 } | |
101 | |
102 /*-------------------------------------------------------------------------*\ | |
103 * Select with timeout control | |
104 \*-------------------------------------------------------------------------*/ | |
105 int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, | |
106 p_timeout tm) { | |
107 int ret; | |
108 do { | |
109 struct timeval tv; | |
110 double t = timeout_getretry(tm); | |
111 tv.tv_sec = (int) t; | |
112 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); | |
113 /* timeout = 0 means no wait */ | |
114 ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL); | |
115 } while (ret < 0 && errno == EINTR); | |
116 return ret; | |
117 } | |
118 | |
119 /*-------------------------------------------------------------------------*\ | |
120 * Creates and sets up a socket | |
121 \*-------------------------------------------------------------------------*/ | |
122 int socket_create(p_socket ps, int domain, int type, int protocol) { | |
123 *ps = socket(domain, type, protocol); | |
124 if (*ps != SOCKET_INVALID) return IO_DONE; | |
125 else return errno; | |
126 } | |
127 | |
128 /*-------------------------------------------------------------------------*\ | |
129 * Binds or returns error message | |
130 \*-------------------------------------------------------------------------*/ | |
131 int socket_bind(p_socket ps, SA *addr, socklen_t len) { | |
132 int err = IO_DONE; | |
133 socket_setblocking(ps); | |
134 if (bind(*ps, addr, len) < 0) err = errno; | |
135 socket_setnonblocking(ps); | |
136 return err; | |
137 } | |
138 | |
139 /*-------------------------------------------------------------------------*\ | |
140 * | |
141 \*-------------------------------------------------------------------------*/ | |
142 int socket_listen(p_socket ps, int backlog) { | |
143 int err = IO_DONE; | |
144 socket_setblocking(ps); | |
145 if (listen(*ps, backlog)) err = errno; | |
146 socket_setnonblocking(ps); | |
147 return err; | |
148 } | |
149 | |
150 /*-------------------------------------------------------------------------*\ | |
151 * | |
152 \*-------------------------------------------------------------------------*/ | |
153 void socket_shutdown(p_socket ps, int how) { | |
154 socket_setblocking(ps); | |
155 shutdown(*ps, how); | |
156 socket_setnonblocking(ps); | |
157 } | |
158 | |
159 /*-------------------------------------------------------------------------*\ | |
160 * Connects or returns error message | |
161 \*-------------------------------------------------------------------------*/ | |
162 int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { | |
163 int err; | |
164 /* avoid calling on closed sockets */ | |
165 if (*ps == SOCKET_INVALID) return IO_CLOSED; | |
166 /* call connect until done or failed without being interrupted */ | |
167 do if (connect(*ps, addr, len) == 0) return IO_DONE; | |
168 while ((err = errno) == EINTR); | |
169 /* if connection failed immediately, return error code */ | |
170 if (err != EINPROGRESS && err != EAGAIN) return err; | |
171 /* zero timeout case optimization */ | |
172 if (timeout_iszero(tm)) return IO_TIMEOUT; | |
173 /* wait until we have the result of the connection attempt or timeout */ | |
174 err = socket_waitfd(ps, WAITFD_C, tm); | |
175 if (err == IO_CLOSED) { | |
176 if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; | |
177 else return errno; | |
178 } else return err; | |
179 } | |
180 | |
181 /*-------------------------------------------------------------------------*\ | |
182 * Accept with timeout | |
183 \*-------------------------------------------------------------------------*/ | |
184 int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { | |
185 SA daddr; | |
186 socklen_t dlen = sizeof(daddr); | |
187 if (*ps == SOCKET_INVALID) return IO_CLOSED; | |
188 if (!addr) addr = &daddr; | |
189 if (!len) len = &dlen; | |
190 for ( ;; ) { | |
191 int err; | |
192 if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; | |
193 err = errno; | |
194 if (err == EINTR) continue; | |
195 if (err != EAGAIN && err != ECONNABORTED) return err; | |
196 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; | |
197 } | |
198 /* can't reach here */ | |
199 return IO_UNKNOWN; | |
200 } | |
201 | |
202 /*-------------------------------------------------------------------------*\ | |
203 * Send with timeout | |
204 \*-------------------------------------------------------------------------*/ | |
205 int socket_send(p_socket ps, const char *data, size_t count, | |
206 size_t *sent, p_timeout tm) | |
207 { | |
208 int err; | |
209 *sent = 0; | |
210 /* avoid making system calls on closed sockets */ | |
211 if (*ps == SOCKET_INVALID) return IO_CLOSED; | |
212 /* loop until we send something or we give up on error */ | |
213 for ( ;; ) { | |
214 long put = (long) send(*ps, data, count, 0); | |
215 /* if we sent anything, we are done */ | |
216 if (put > 0) { | |
217 *sent = put; | |
218 return IO_DONE; | |
219 } | |
220 err = errno; | |
221 /* send can't really return 0, but EPIPE means the connection was | |
222 closed */ | |
223 if (put == 0 || err == EPIPE) return IO_CLOSED; | |
224 /* we call was interrupted, just try again */ | |
225 if (err == EINTR) continue; | |
226 /* if failed fatal reason, report error */ | |
227 if (err != EAGAIN) return err; | |
228 /* wait until we can send something or we timeout */ | |
229 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; | |
230 } | |
231 /* can't reach here */ | |
232 return IO_UNKNOWN; | |
233 } | |
234 | |
235 /*-------------------------------------------------------------------------*\ | |
236 * Sendto with timeout | |
237 \*-------------------------------------------------------------------------*/ | |
238 int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, | |
239 SA *addr, socklen_t len, p_timeout tm) | |
240 { | |
241 int err; | |
242 *sent = 0; | |
243 if (*ps == SOCKET_INVALID) return IO_CLOSED; | |
244 for ( ;; ) { | |
245 long put = (long) sendto(*ps, data, count, 0, addr, len); | |
246 if (put > 0) { | |
247 *sent = put; | |
248 return IO_DONE; | |
249 } | |
250 err = errno; | |
251 if (put == 0 || err == EPIPE) return IO_CLOSED; | |
252 if (err == EINTR) continue; | |
253 if (err != EAGAIN) return err; | |
254 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; | |
255 } | |
256 return IO_UNKNOWN; | |
257 } | |
258 | |
259 /*-------------------------------------------------------------------------*\ | |
260 * Receive with timeout | |
261 \*-------------------------------------------------------------------------*/ | |
262 int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { | |
263 int err; | |
264 *got = 0; | |
265 if (*ps == SOCKET_INVALID) return IO_CLOSED; | |
266 for ( ;; ) { | |
267 long taken = (long) recv(*ps, data, count, 0); | |
268 if (taken > 0) { | |
269 *got = taken; | |
270 return IO_DONE; | |
271 } | |
272 err = errno; | |
273 if (taken == 0) return IO_CLOSED; | |
274 if (err == EINTR) continue; | |
275 if (err != EAGAIN) return err; | |
276 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; | |
277 } | |
278 return IO_UNKNOWN; | |
279 } | |
280 | |
281 /*-------------------------------------------------------------------------*\ | |
282 * Recvfrom with timeout | |
283 \*-------------------------------------------------------------------------*/ | |
284 int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, | |
285 SA *addr, socklen_t *len, p_timeout tm) { | |
286 int err; | |
287 *got = 0; | |
288 if (*ps == SOCKET_INVALID) return IO_CLOSED; | |
289 for ( ;; ) { | |
290 long taken = (long) recvfrom(*ps, data, count, 0, addr, len); | |
291 if (taken > 0) { | |
292 *got = taken; | |
293 return IO_DONE; | |
294 } | |
295 err = errno; | |
296 if (taken == 0) return IO_CLOSED; | |
297 if (err == EINTR) continue; | |
298 if (err != EAGAIN) return err; | |
299 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; | |
300 } | |
301 return IO_UNKNOWN; | |
302 } | |
303 | |
304 /*-------------------------------------------------------------------------*\ | |
305 * Put socket into blocking mode | |
306 \*-------------------------------------------------------------------------*/ | |
307 void socket_setblocking(p_socket ps) { | |
308 int flags = fcntl(*ps, F_GETFL, 0); | |
309 flags &= (~(O_NONBLOCK)); | |
310 fcntl(*ps, F_SETFL, flags); | |
311 } | |
312 | |
313 /*-------------------------------------------------------------------------*\ | |
314 * Put socket into non-blocking mode | |
315 \*-------------------------------------------------------------------------*/ | |
316 void socket_setnonblocking(p_socket ps) { | |
317 int flags = fcntl(*ps, F_GETFL, 0); | |
318 flags |= O_NONBLOCK; | |
319 fcntl(*ps, F_SETFL, flags); | |
320 } | |
321 | |
322 /*-------------------------------------------------------------------------*\ | |
323 * DNS helpers | |
324 \*-------------------------------------------------------------------------*/ | |
325 int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { | |
326 *hp = gethostbyaddr(addr, len, AF_INET); | |
327 if (*hp) return IO_DONE; | |
328 else if (h_errno) return h_errno; | |
329 else if (errno) return errno; | |
330 else return IO_UNKNOWN; | |
331 } | |
332 | |
333 int socket_gethostbyname(const char *addr, struct hostent **hp) { | |
334 *hp = gethostbyname(addr); | |
335 if (*hp) return IO_DONE; | |
336 else if (h_errno) return h_errno; | |
337 else if (errno) return errno; | |
338 else return IO_UNKNOWN; | |
339 } | |
340 | |
341 /*-------------------------------------------------------------------------*\ | |
342 * Error translation functions | |
343 * Make sure important error messages are standard | |
344 \*-------------------------------------------------------------------------*/ | |
345 const char *socket_hoststrerror(int err) { | |
346 if (err <= 0) return io_strerror(err); | |
347 switch (err) { | |
348 case HOST_NOT_FOUND: return "host not found"; | |
349 default: return hstrerror(err); | |
350 } | |
351 } | |
352 | |
353 const char *socket_strerror(int err) { | |
354 if (err <= 0) return io_strerror(err); | |
355 switch (err) { | |
356 case EADDRINUSE: return "address already in use"; | |
357 case EISCONN: return "already connected"; | |
358 case EACCES: return "permission denied"; | |
359 case ECONNREFUSED: return "connection refused"; | |
360 case ECONNABORTED: return "closed"; | |
361 case ECONNRESET: return "closed"; | |
362 case ETIMEDOUT: return "timeout"; | |
363 default: return strerror(errno); | |
364 } | |
365 } | |
366 | |
367 const char *socket_ioerror(p_socket ps, int err) { | |
368 (void) ps; | |
369 return socket_strerror(err); | |
370 } |