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 }