Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / rp-l2tp / libevent / event_tcp.c
blob14259989576491d598d4a2d82b798904690951e6
1 /***********************************************************************
3 * event_tcp.c -- implementation of event-driven socket I/O.
5 * Copyright (C) 2001 Roaring Penguin Software Inc.
7 * This program may be distributed according to the terms of the GNU
8 * General Public License, version 2 or (at your option) any later version.
10 * LIC: GPL
12 ***********************************************************************/
14 static char const RCSID[] =
15 "$Id: event_tcp.c,v 1.1.48.1 2005/08/08 12:05:25 honor Exp $";
17 #include "event_tcp.h"
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
25 static void free_state(EventTcpState *state);
27 typedef struct EventTcpConnectState_t {
28 int fd;
29 EventHandler *conn;
30 EventTcpConnectFunc f;
31 void *data;
32 } EventTcpConnectState;
34 /**********************************************************************
35 * %FUNCTION: handle_accept
36 * %ARGUMENTS:
37 * es -- event selector
38 * fd -- socket
39 * flags -- ignored
40 * data -- the accept callback function
41 * %RETURNS:
42 * Nothing
43 * %DESCRIPTION:
44 * Calls accept; if a connection arrives, calls the accept callback
45 * function with connected descriptor
46 ***********************************************************************/
47 static void
48 handle_accept(EventSelector *es,
49 int fd,
50 unsigned int flags,
51 void *data)
53 int conn;
54 EventTcpAcceptFunc f;
56 EVENT_DEBUG(("tcp_handle_accept(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
57 conn = accept(fd, NULL, NULL);
58 if (conn < 0) return;
59 f = (EventTcpAcceptFunc) data;
61 f(es, conn);
64 /**********************************************************************
65 * %FUNCTION: handle_connect
66 * %ARGUMENTS:
67 * es -- event selector
68 * fd -- socket
69 * flags -- ignored
70 * data -- the accept callback function
71 * %RETURNS:
72 * Nothing
73 * %DESCRIPTION:
74 * Calls accept; if a connection arrives, calls the accept callback
75 * function with connected descriptor
76 ***********************************************************************/
77 static void
78 handle_connect(EventSelector *es,
79 int fd,
80 unsigned int flags,
81 void *data)
83 int error = 0;
84 socklen_t len = sizeof(error);
85 EventTcpConnectState *state = (EventTcpConnectState *) data;
87 EVENT_DEBUG(("tcp_handle_connect(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
89 /* Cancel writable event */
90 Event_DelHandler(es, state->conn);
91 state->conn = NULL;
93 /* Timeout? */
94 if (flags & EVENT_FLAG_TIMEOUT) {
95 errno = ETIMEDOUT;
96 state->f(es, fd, EVENT_TCP_FLAG_TIMEOUT, state->data);
97 free(state);
98 return;
101 /* Check for pending error */
102 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
103 state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);
104 free(state);
105 return;
107 if (error) {
108 errno = error;
109 state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);
110 free(state);
111 return;
114 /* It looks cool! */
115 state->f(es, fd, EVENT_TCP_FLAG_COMPLETE, state->data);
116 free(state);
119 /**********************************************************************
120 * %FUNCTION: EventTcp_CreateAcceptor
121 * %ARGUMENTS:
122 * es -- event selector
123 * socket -- listening socket
124 * f -- function to call when a connection is accepted
125 * data -- extra data to pass to f.
126 * %RETURNS:
127 * An event handler on success, NULL on failure.
128 * %DESCRIPTION:
129 * Sets up an accepting socket and calls "f" whenever a new
130 * connection arrives.
131 ***********************************************************************/
132 EventHandler *
133 EventTcp_CreateAcceptor(EventSelector *es,
134 int socket,
135 EventTcpAcceptFunc f)
137 int flags;
139 EVENT_DEBUG(("EventTcp_CreateAcceptor(es=%p, socket=%d)\n", es, socket));
140 /* Make sure socket is non-blocking */
141 flags = fcntl(socket, F_GETFL, 0);
142 if (flags == -1) {
143 return NULL;
145 if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
146 return NULL;
149 return Event_AddHandler(es, socket, EVENT_FLAG_READABLE,
150 handle_accept, (void *) f);
154 /**********************************************************************
155 * %FUNCTION: free_state
156 * %ARGUMENTS:
157 * state -- EventTcpState to free
158 * %RETURNS:
159 * Nothing
160 * %DESCRIPTION:
161 * Frees all state associated with the TcpEvent.
162 ***********************************************************************/
163 static void
164 free_state(EventTcpState *state)
166 if (!state) return;
167 EVENT_DEBUG(("tcp_free_state(state=%p)\n", state));
168 if (state->buf) free(state->buf);
169 if (state->eh) Event_DelHandler(state->es, state->eh);
170 free(state);
173 /**********************************************************************
174 * %FUNCTION: handle_readable
175 * %ARGUMENTS:
176 * es -- event selector
177 * fd -- the readable socket
178 * flags -- ignored
179 * data -- the EventTcpState object
180 * %RETURNS:
181 * Nothing
182 * %DESCRIPTION:
183 * Continues to fill buffer. Calls callback when done.
184 ***********************************************************************/
185 static void
186 handle_readable(EventSelector *es,
187 int fd,
188 unsigned int flags,
189 void *data)
191 EventTcpState *state = (EventTcpState *) data;
192 int done = state->cur - state->buf;
193 int togo = state->len - done;
194 int nread = 0;
195 int flag;
197 EVENT_DEBUG(("tcp_handle_readable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
199 /* Timed out? */
200 if (flags & EVENT_FLAG_TIMEOUT) {
201 errno = ETIMEDOUT;
202 (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,
203 state->data);
204 free_state(state);
205 return;
207 if (state->delim < 0) {
208 /* Not looking for a delimiter */
209 /* togo had better not be zero here! */
210 nread = read(fd, state->cur, togo);
211 if (nread <= 0) {
212 /* Change connection reset to EOF if we have read at least
213 one char */
214 if (nread < 0 && errno == ECONNRESET && done > 0) {
215 nread = 0;
217 flag = (nread) ? EVENT_TCP_FLAG_IOERROR : EVENT_TCP_FLAG_EOF;
218 /* error or EOF */
219 (state->f)(es, state->socket, state->buf, done, flag, state->data);
220 free_state(state);
221 return;
223 state->cur += nread;
224 done += nread;
225 if (done >= state->len) {
226 /* Read enough! */
227 (state->f)(es, state->socket, state->buf, done,
228 EVENT_TCP_FLAG_COMPLETE, state->data);
229 free_state(state);
230 return;
232 } else {
233 /* Looking for a delimiter */
234 while ( (togo > 0) && (nread = read(fd, state->cur, 1)) == 1) {
235 togo--;
236 done++;
237 state->cur++;
238 if (*(state->cur - 1) == state->delim) break;
241 if (nread <= 0) {
242 /* Error or EOF -- check for EAGAIN */
243 if (nread < 0 && errno == EAGAIN) return;
246 /* Some other error, or EOF, or delimiter, or read enough */
247 if (nread < 0) {
248 flag = EVENT_TCP_FLAG_IOERROR;
249 } else if (nread == 0) {
250 flag = EVENT_TCP_FLAG_EOF;
251 } else {
252 flag = EVENT_TCP_FLAG_COMPLETE;
254 (state->f)(es, state->socket, state->buf, done, flag, state->data);
255 free_state(state);
256 return;
260 /**********************************************************************
261 * %FUNCTION: handle_writeable
262 * %ARGUMENTS:
263 * es -- event selector
264 * fd -- the writeable socket
265 * flags -- ignored
266 * data -- the EventTcpState object
267 * %RETURNS:
268 * Nothing
269 * %DESCRIPTION:
270 * Continues to fill buffer. Calls callback when done.
271 ***********************************************************************/
272 static void
273 handle_writeable(EventSelector *es,
274 int fd,
275 unsigned int flags,
276 void *data)
278 EventTcpState *state = (EventTcpState *) data;
279 int done = state->cur - state->buf;
280 int togo = state->len - done;
281 int n;
283 /* Timed out? */
284 if (flags & EVENT_FLAG_TIMEOUT) {
285 errno = ETIMEDOUT;
286 if (state->f) {
287 (state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,
288 state->data);
289 } else {
290 close(fd);
292 free_state(state);
293 return;
296 /* togo had better not be zero here! */
297 n = write(fd, state->cur, togo);
299 EVENT_DEBUG(("tcp_handle_writeable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
300 if (n <= 0) {
301 /* error */
302 if (state->f) {
303 (state->f)(es, state->socket, state->buf, done,
304 EVENT_TCP_FLAG_IOERROR,
305 state->data);
306 } else {
307 close(fd);
309 free_state(state);
310 return;
312 state->cur += n;
313 done += n;
314 if (done >= state->len) {
315 /* Written enough! */
316 if (state->f) {
317 (state->f)(es, state->socket, state->buf, done,
318 EVENT_TCP_FLAG_COMPLETE, state->data);
319 } else {
320 close(fd);
322 free_state(state);
323 return;
328 /**********************************************************************
329 * %FUNCTION: EventTcp_ReadBuf
330 * %ARGUMENTS:
331 * es -- event selector
332 * socket -- socket to read from
333 * len -- maximum number of bytes to read
334 * delim -- delimiter at which to stop reading, or -1 if we should
335 * read exactly len bytes
336 * f -- function to call on EOF or when all bytes have been read
337 * timeout -- if non-zero, timeout in seconds after which we cancel
338 * operation.
339 * data -- extra data to pass to function f.
340 * %RETURNS:
341 * A new EventTcpState token or NULL on error
342 * %DESCRIPTION:
343 * Sets up a handler to fill a buffer from a socket.
344 ***********************************************************************/
345 EventTcpState *
346 EventTcp_ReadBuf(EventSelector *es,
347 int socket,
348 int len,
349 int delim,
350 EventTcpIOFinishedFunc f,
351 int timeout,
352 void *data)
354 EventTcpState *state;
355 int flags;
356 struct timeval t;
358 EVENT_DEBUG(("EventTcp_ReadBuf(es=%p, socket=%d, len=%d, delim=%d, timeout=%d)\n", es, socket, len, delim, timeout));
359 if (len <= 0) return NULL;
360 if (socket < 0) return NULL;
362 /* Make sure socket is non-blocking */
363 flags = fcntl(socket, F_GETFL, 0);
364 if (flags == -1) {
365 return NULL;
367 if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
368 return NULL;
371 state = malloc(sizeof(EventTcpState));
372 if (!state) return NULL;
374 memset(state, 0, sizeof(EventTcpState));
376 state->socket = socket;
378 state->buf = malloc(len);
379 if (!state->buf) {
380 free_state(state);
381 return NULL;
384 state->cur = state->buf;
385 state->len = len;
386 state->f = f;
387 state->es = es;
389 if (timeout <= 0) {
390 t.tv_sec = -1;
391 t.tv_usec = -1;
392 } else {
393 t.tv_sec = timeout;
394 t.tv_usec = 0;
397 state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_READABLE,
398 t, handle_readable,
399 (void *) state);
400 if (!state->eh) {
401 free_state(state);
402 return NULL;
404 state->data = data;
405 state->delim = delim;
406 EVENT_DEBUG(("EventTcp_ReadBuf() -> %p\n", state));
408 return state;
411 /**********************************************************************
412 * %FUNCTION: EventTcp_WriteBuf
413 * %ARGUMENTS:
414 * es -- event selector
415 * socket -- socket to read from
416 * buf -- buffer to write
417 * len -- number of bytes to write
418 * f -- function to call on EOF or when all bytes have been read
419 * timeout -- timeout after which to cancel operation
420 * data -- extra data to pass to function f.
421 * %RETURNS:
422 * A new EventTcpState token or NULL on error
423 * %DESCRIPTION:
424 * Sets up a handler to fill a buffer from a socket.
425 ***********************************************************************/
426 EventTcpState *
427 EventTcp_WriteBuf(EventSelector *es,
428 int socket,
429 char *buf,
430 int len,
431 EventTcpIOFinishedFunc f,
432 int timeout,
433 void *data)
435 EventTcpState *state;
436 int flags;
437 struct timeval t;
439 EVENT_DEBUG(("EventTcp_WriteBuf(es=%p, socket=%d, len=%d, timeout=%d)\n", es, socket, len, timeout));
440 if (len <= 0) return NULL;
441 if (socket < 0) return NULL;
443 /* Make sure socket is non-blocking */
444 flags = fcntl(socket, F_GETFL, 0);
445 if (flags == -1) {
446 return NULL;
448 if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
449 return NULL;
452 state = malloc(sizeof(EventTcpState));
453 if (!state) return NULL;
455 memset(state, 0, sizeof(EventTcpState));
457 state->socket = socket;
459 state->buf = malloc(len);
460 if (!state->buf) {
461 free_state(state);
462 return NULL;
464 memcpy(state->buf, buf, len);
466 state->cur = state->buf;
467 state->len = len;
468 state->f = f;
469 state->es = es;
471 if (timeout <= 0) {
472 t.tv_sec = -1;
473 t.tv_usec = -1;
474 } else {
475 t.tv_sec = timeout;
476 t.tv_usec = 0;
479 state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_WRITEABLE,
480 t, handle_writeable,
481 (void *) state);
482 if (!state->eh) {
483 free_state(state);
484 return NULL;
487 state->data = data;
488 state->delim = -1;
489 EVENT_DEBUG(("EventTcp_WriteBuf() -> %p\n", state));
490 return state;
493 /**********************************************************************
494 * %FUNCTION: EventTcp_Connect
495 * %ARGUMENTS:
496 * es -- event selector
497 * fd -- descriptor to connect
498 * addr -- address to connect to
499 * addrlen -- length of address
500 * f -- function to call with connected socket
501 * data -- extra data to pass to f
502 * %RETURNS:
503 * Nothing
504 * %DESCRIPTION:
505 * Does a non-blocking connect on fd
506 ***********************************************************************/
507 void
508 EventTcp_Connect(EventSelector *es,
509 int fd,
510 struct sockaddr const *addr,
511 socklen_t addrlen,
512 EventTcpConnectFunc f,
513 int timeout,
514 void *data)
516 int flags;
517 int n;
518 EventTcpConnectState *state;
519 struct timeval t;
521 /* Make sure socket is non-blocking */
522 flags = fcntl(fd, F_GETFL, 0);
523 if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
524 f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
525 return;
528 n = connect(fd, addr, addrlen);
529 if (n < 0) {
530 if (errno != EINPROGRESS) {
531 f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
532 return;
536 if (n == 0) { /* Connect succeeded immediately */
537 f(es, fd, EVENT_TCP_FLAG_COMPLETE, data);
538 return;
541 state = malloc(sizeof(*state));
542 if (!state) {
543 f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
544 return;
546 state->f = f;
547 state->fd = fd;
548 state->data = data;
550 if (timeout <= 0) {
551 t.tv_sec = -1;
552 t.tv_usec = -1;
553 } else {
554 t.tv_sec = timeout;
555 t.tv_usec = 0;
558 state->conn = Event_AddHandlerWithTimeout(es, fd, EVENT_FLAG_WRITEABLE,
559 t, handle_connect,
560 (void *) state);
561 if (!state->conn) {
562 free(state);
563 f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
564 return;
568 /**********************************************************************
569 * %FUNCTION: EventTcp_CancelPending
570 * %ARGUMENTS:
571 * s -- an EventTcpState
572 * %RETURNS:
573 * Nothing
574 * %DESCRIPTION:
575 * Cancels the pending event handler
576 ***********************************************************************/
577 void
578 EventTcp_CancelPending(EventTcpState *s)
580 free_state(s);