1/***********************************************************************
2*
3* event_tcp.c -- implementation of event-driven socket I/O.
4*
5* Copyright (C) 2001 Roaring Penguin Software Inc.
6*
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.
9*
10* LIC: GPL
11*
12***********************************************************************/
13
14static char const RCSID[] =
15"$Id$";
16
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>
24
25static void free_state(EventTcpState *state);
26
27typedef struct EventTcpConnectState_t {
28    int fd;
29    EventHandler *conn;
30    EventTcpConnectFunc f;
31    void *data;
32} EventTcpConnectState;
33
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***********************************************************************/
47static void
48handle_accept(EventSelector *es,
49	      int fd,
50	      unsigned int flags,
51	      void *data)
52{
53    int conn;
54    EventTcpAcceptFunc f;
55
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;
60
61    f(es, conn);
62}
63
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***********************************************************************/
77static void
78handle_connect(EventSelector *es,
79	      int fd,
80	      unsigned int flags,
81	      void *data)
82{
83    int error = 0;
84    socklen_t len = sizeof(error);
85    EventTcpConnectState *state = (EventTcpConnectState *) data;
86
87    EVENT_DEBUG(("tcp_handle_connect(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
88
89    /* Cancel writable event */
90    Event_DelHandler(es, state->conn);
91    state->conn = NULL;
92
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;
99    }
100
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;
106    }
107    if (error) {
108	errno = error;
109	state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);
110	free(state);
111	return;
112    }
113
114    /* It looks cool! */
115    state->f(es, fd, EVENT_TCP_FLAG_COMPLETE, state->data);
116    free(state);
117}
118
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***********************************************************************/
132EventHandler *
133EventTcp_CreateAcceptor(EventSelector *es,
134			int socket,
135			EventTcpAcceptFunc f)
136{
137    int flags;
138
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;
144    }
145    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
146	return NULL;
147    }
148
149    return Event_AddHandler(es, socket, EVENT_FLAG_READABLE,
150			    handle_accept, (void *) f);
151
152}
153
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***********************************************************************/
163static void
164free_state(EventTcpState *state)
165{
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);
171}
172
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***********************************************************************/
185static void
186handle_readable(EventSelector *es,
187		int fd,
188		unsigned int flags,
189		void *data)
190{
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;
196
197    EVENT_DEBUG(("tcp_handle_readable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
198
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;
206    }
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;
216	    }
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;
222	}
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;
231	}
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;
239	}
240
241	if (nread <= 0) {
242	    /* Error or EOF -- check for EAGAIN */
243	    if (nread < 0 && errno == EAGAIN) return;
244	}
245
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;
253	}
254	(state->f)(es, state->socket, state->buf, done, flag, state->data);
255	free_state(state);
256	return;
257    }
258}
259
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***********************************************************************/
272static void
273handle_writeable(EventSelector *es,
274		int fd,
275		unsigned int flags,
276		void *data)
277{
278    EventTcpState *state = (EventTcpState *) data;
279    int done = state->cur - state->buf;
280    int togo = state->len - done;
281    int n;
282
283    /* Timed out? */
284    if (flags & EVENT_FLAG_TIMEOUT) {
285	errno = ETIMEDOUT;
286	(state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,
287		   state->data);
288	free_state(state);
289	return;
290    }
291
292    /* togo had better not be zero here! */
293    n = write(fd, state->cur, togo);
294
295    EVENT_DEBUG(("tcp_handle_writeable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));
296    if (n <= 0) {
297	/* error */
298	if (state->f) {
299	    (state->f)(es, state->socket, state->buf, done,
300		       EVENT_TCP_FLAG_IOERROR,
301		       state->data);
302	} else {
303	    close(fd);
304	}
305	free_state(state);
306	return;
307    }
308    state->cur += n;
309    done += n;
310    if (done >= state->len) {
311	/* Written enough! */
312	if (state->f) {
313	    (state->f)(es, state->socket, state->buf, done,
314		       EVENT_TCP_FLAG_COMPLETE, state->data);
315	} else {
316	    close(fd);
317	}
318	free_state(state);
319	return;
320    }
321
322}
323
324/**********************************************************************
325* %FUNCTION: EventTcp_ReadBuf
326* %ARGUMENTS:
327*  es -- event selector
328*  socket -- socket to read from
329*  len -- maximum number of bytes to read
330*  delim -- delimiter at which to stop reading, or -1 if we should
331*           read exactly len bytes
332*  f -- function to call on EOF or when all bytes have been read
333*  timeout -- if non-zero, timeout in seconds after which we cancel
334*             operation.
335*  data -- extra data to pass to function f.
336* %RETURNS:
337*  A new EventTcpState token or NULL on error
338* %DESCRIPTION:
339*  Sets up a handler to fill a buffer from a socket.
340***********************************************************************/
341EventTcpState *
342EventTcp_ReadBuf(EventSelector *es,
343		 int socket,
344		 int len,
345		 int delim,
346		 EventTcpIOFinishedFunc f,
347		 int timeout,
348		 void *data)
349{
350    EventTcpState *state;
351    int flags;
352    struct timeval t;
353
354    EVENT_DEBUG(("EventTcp_ReadBuf(es=%p, socket=%d, len=%d, delim=%d, timeout=%d)\n", es, socket, len, delim, timeout));
355    if (len <= 0) return NULL;
356    if (socket < 0) return NULL;
357
358    /* Make sure socket is non-blocking */
359    flags = fcntl(socket, F_GETFL, 0);
360    if (flags == -1) {
361	return NULL;
362    }
363    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
364	return NULL;
365    }
366
367    state = malloc(sizeof(EventTcpState));
368    if (!state) return NULL;
369
370    memset(state, 0, sizeof(EventTcpState));
371
372    state->socket = socket;
373
374    state->buf = malloc(len);
375    if (!state->buf) {
376	free_state(state);
377	return NULL;
378    }
379
380    state->cur = state->buf;
381    state->len = len;
382    state->f = f;
383    state->es = es;
384
385    if (timeout <= 0) {
386	t.tv_sec = -1;
387	t.tv_usec = -1;
388    } else {
389	t.tv_sec = timeout;
390	t.tv_usec = 0;
391    }
392
393    state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_READABLE,
394					    t, handle_readable,
395					    (void *) state);
396    if (!state->eh) {
397	free_state(state);
398	return NULL;
399    }
400    state->data = data;
401    state->delim = delim;
402    EVENT_DEBUG(("EventTcp_ReadBuf() -> %p\n", state));
403
404    return state;
405}
406
407/**********************************************************************
408* %FUNCTION: EventTcp_WriteBuf
409* %ARGUMENTS:
410*  es -- event selector
411*  socket -- socket to read from
412*  buf -- buffer to write
413*  len -- number of bytes to write
414*  f -- function to call on EOF or when all bytes have been read
415*  timeout -- timeout after which to cancel operation
416*  data -- extra data to pass to function f.
417* %RETURNS:
418*  A new EventTcpState token or NULL on error
419* %DESCRIPTION:
420*  Sets up a handler to fill a buffer from a socket.
421***********************************************************************/
422EventTcpState *
423EventTcp_WriteBuf(EventSelector *es,
424		  int socket,
425		  char *buf,
426		  int len,
427		  EventTcpIOFinishedFunc f,
428		  int timeout,
429		  void *data)
430{
431    EventTcpState *state;
432    int flags;
433    struct timeval t;
434
435    EVENT_DEBUG(("EventTcp_WriteBuf(es=%p, socket=%d, len=%d, timeout=%d)\n", es, socket, len, timeout));
436    if (len <= 0) return NULL;
437    if (socket < 0) return NULL;
438
439    /* Make sure socket is non-blocking */
440    flags = fcntl(socket, F_GETFL, 0);
441    if (flags == -1) {
442	return NULL;
443    }
444    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
445	return NULL;
446    }
447
448    state = malloc(sizeof(EventTcpState));
449    if (!state) return NULL;
450
451    memset(state, 0, sizeof(EventTcpState));
452
453    state->socket = socket;
454
455    state->buf = malloc(len);
456    if (!state->buf) {
457	free_state(state);
458	return NULL;
459    }
460    memcpy(state->buf, buf, len);
461
462    state->cur = state->buf;
463    state->len = len;
464    state->f = f;
465    state->es = es;
466
467    if (timeout <= 0) {
468	t.tv_sec = -1;
469	t.tv_usec = -1;
470    } else {
471	t.tv_sec = timeout;
472	t.tv_usec = 0;
473    }
474
475    state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_WRITEABLE,
476					    t, handle_writeable,
477					    (void *) state);
478    if (!state->eh) {
479	free_state(state);
480	return NULL;
481    }
482
483    state->data = data;
484    state->delim = -1;
485    EVENT_DEBUG(("EventTcp_WriteBuf() -> %p\n", state));
486    return state;
487}
488
489/**********************************************************************
490* %FUNCTION: EventTcp_Connect
491* %ARGUMENTS:
492*  es -- event selector
493*  fd -- descriptor to connect
494*  addr -- address to connect to
495*  addrlen -- length of address
496*  f -- function to call with connected socket
497*  data -- extra data to pass to f
498* %RETURNS:
499*  Nothing
500* %DESCRIPTION:
501*  Does a non-blocking connect on fd
502***********************************************************************/
503void
504EventTcp_Connect(EventSelector *es,
505		 int fd,
506		 struct sockaddr const *addr,
507		 socklen_t addrlen,
508		 EventTcpConnectFunc f,
509		 int timeout,
510		 void *data)
511{
512    int flags;
513    int n;
514    EventTcpConnectState *state;
515    struct timeval t;
516
517    /* Make sure socket is non-blocking */
518    flags = fcntl(fd, F_GETFL, 0);
519    if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
520	f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
521	return;
522    }
523
524    n = connect(fd, addr, addrlen);
525    if (n < 0) {
526	if (errno != EINPROGRESS) {
527	    f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
528	    return;
529	}
530    }
531
532    if (n == 0) { /* Connect succeeded immediately */
533	f(es, fd, EVENT_TCP_FLAG_COMPLETE, data);
534	return;
535    }
536
537    state = malloc(sizeof(*state));
538    if (!state) {
539	f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
540	return;
541    }
542    state->f = f;
543    state->fd = fd;
544    state->data = data;
545
546    if (timeout <= 0) {
547	t.tv_sec = -1;
548	t.tv_usec = -1;
549    } else {
550	t.tv_sec = timeout;
551	t.tv_usec = 0;
552    }
553
554    state->conn = Event_AddHandlerWithTimeout(es, fd, EVENT_FLAG_WRITEABLE,
555					      t, handle_connect,
556					      (void *) state);
557    if (!state->conn) {
558	free(state);
559	f(es, fd, EVENT_TCP_FLAG_IOERROR, data);
560	return;
561    }
562}
563
564/**********************************************************************
565* %FUNCTION: EventTcp_CancelPending
566* %ARGUMENTS:
567*  s -- an EventTcpState
568* %RETURNS:
569*  Nothing
570* %DESCRIPTION:
571*  Cancels the pending event handler
572***********************************************************************/
573void
574EventTcp_CancelPending(EventTcpState *s)
575{
576    free_state(s);
577}
578