ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/connection.C
Revision: 1.7
Committed: Sun Sep 16 18:54:44 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +7 -2 lines
Log Message:
#defines to enum

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * connection.C: Connection and I/O management
3 pippijn 1.7 *
4     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5     * Rights to this code are as documented in COPYING.
6     *
7     *
8     * Portions of this file were derived from sources bearing the following license:
9 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
10 pippijn 1.4 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 pippijn 1.1 */
12    
13 pippijn 1.7 static char const rcsid[] = "$Id: connection.C,v 1.6 2007-09-05 11:23:15 pippijn Exp $";
14 pippijn 1.1
15     #include "atheme.h"
16     #include "internal.h"
17     #include "datastream.h"
18 pippijn 1.5 #include "connection.h"
19 pippijn 1.1
20 pippijn 1.6 connection_t::list_type connection_t::list;
21 pippijn 1.4 connection_t::callbacks connection_t::callback;
22 pippijn 1.1
23     void
24     init_netio (void)
25     {
26     #if 0
27     connection_heap = BlockHeapCreate (sizeof (connection_t), 16);
28     sa_heap = BlockHeapCreate (sizeof (struct sockaddr_in), 16);
29     #endif
30     }
31    
32     static int
33     socket_setnonblocking (int sck)
34     {
35     int flags;
36    
37     flags = fcntl (sck, F_GETFL, 0);
38     flags |= O_NONBLOCK;
39    
40     if (fcntl (sck, F_SETFL, flags))
41     return -1;
42    
43     return 0;
44     }
45    
46     /*
47 pippijn 1.5 * connection_t::create()
48 pippijn 1.1 *
49     * inputs:
50     * connection name, file descriptor, flag bitmask,
51     * read handler, write handler.
52     *
53     * outputs:
54     * a connection object for the connection information given.
55     *
56     * side effects:
57     * a connection is added to the socket queue.
58     */
59     connection_t *
60 pippijn 1.5 connection_t::create (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
61 pippijn 1.1 {
62     connection_t *cptr;
63    
64 pippijn 1.5 if ((cptr = connection_t::find (fd)))
65 pippijn 1.1 {
66 pippijn 1.5 slog (LG_DEBUG, "connection_t::create(): connection %d is already registered as %s", fd, cptr->name);
67 pippijn 1.1 return NULL;
68     }
69    
70 pippijn 1.5 slog (LG_DEBUG, "connection_t::create(): adding connection '%s', fd = %d", name, fd);
71 pippijn 1.1
72     cptr = new connection_t;
73    
74     cptr->fd = fd;
75     cptr->pollslot = -1;
76     cptr->flags = flags;
77     cptr->first_recv = NOW;
78     cptr->last_recv = NOW;
79    
80     cptr->read_handler = read_handler;
81     cptr->write_handler = write_handler;
82    
83     /* set connection name */
84     strlcpy (cptr->name, name, HOSTLEN);
85    
86     /* XXX */
87     cptr->saddr_size = sizeof (cptr->saddr);
88     getpeername (cptr->fd, &cptr->saddr, &cptr->saddr_size);
89     cptr->sa = (struct sockaddr_in *) &cptr->saddr;
90    
91     inet_ntop (AF_INET, &cptr->sa->sin_addr, cptr->hbuf, BUFSIZE);
92    
93 pippijn 1.6 connection_t::list.insert (cptr);
94 pippijn 1.1
95     return cptr;
96     }
97    
98     /*
99 pippijn 1.5 * connection_t::find()
100 pippijn 1.1 *
101     * inputs:
102     * the file descriptor to search by
103     *
104     * outputs:
105     * the connection_t object associated with that fd
106     *
107     * side effects:
108     * none
109     */
110     connection_t *
111 pippijn 1.5 connection_t::find (int fd)
112 pippijn 1.1 {
113     connection_t *cptr;
114 pippijn 1.6 connection_t::list_type::iterator it = connection_t::list.begin ();
115     connection_t::list_type::iterator et = connection_t::list.end ();
116 pippijn 1.1
117 pippijn 1.4 while (it != et)
118     {
119     cptr = *it;
120    
121     if (cptr->fd == fd)
122     return cptr;
123    
124     ++it;
125     }
126 pippijn 1.1
127     return NULL;
128     }
129    
130     /*
131 pippijn 1.5 * connection_t::count()
132 pippijn 1.1 *
133     * inputs:
134     * none
135     *
136     * outputs:
137     * number of connections tracked
138     *
139     * side effects:
140     * none
141     */
142     int
143 pippijn 1.5 connection_t::count (void)
144 pippijn 1.1 {
145 pippijn 1.6 return connection_t::list.size ();
146 pippijn 1.1 }
147    
148     /*
149     * connection_close()
150     *
151     * inputs:
152     * the connection being closed.
153     *
154     * outputs:
155     * none
156     *
157     * side effects:
158     * the connection is closed.
159     */
160     void
161 pippijn 1.5 connection_t::close ()
162 pippijn 1.1 {
163 pippijn 1.6 connection_t::list_type::iterator it;
164 pippijn 1.1 int errno1, errno2;
165     #ifdef SO_ERROR
166     socklen_t len = sizeof (errno2);
167     #endif
168    
169 pippijn 1.6 it = connection_t::list.find (this);
170     if (it == connection_t::list.end ())
171 pippijn 1.1 {
172 pippijn 1.5 slog (LG_DEBUG, "connection_close(): connection %p is not registered!", this);
173 pippijn 1.1 return;
174     }
175    
176     errno1 = errno;
177     #ifdef SO_ERROR
178 pippijn 1.5 if (!getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) &len))
179 pippijn 1.1 {
180     if (errno2 != 0)
181     errno1 = errno2;
182     }
183     #endif
184    
185     if (errno1)
186 pippijn 1.5 slog (flags & CF_UPLINK ? LG_ERROR : LG_INFO, "connection_close(): connection %s[%d] closed due to error %d (%s)", name, fd, errno1, strerror (errno1));
187 pippijn 1.1
188 pippijn 1.5 if (close_handler)
189     close_handler (this);
190 pippijn 1.1
191     /* close the fd */
192 pippijn 1.5 ::close (fd);
193 pippijn 1.1
194 pippijn 1.6 connection_t::list.erase (this);
195 pippijn 1.1
196 pippijn 1.5 sendqrecvq_free (this);
197 pippijn 1.1
198 pippijn 1.5 delete this;
199 pippijn 1.1 }
200    
201 pippijn 1.5 /* This one is only safe for use by connection_t::close_soon(),
202 pippijn 1.1 * it will cause infinite loops otherwise
203     */
204     static void
205     empty_handler (connection_t *cptr)
206     {
207     }
208    
209     /*
210     * connection_close_soon()
211     *
212     * inputs:
213     * the connection being closed.
214     *
215     * outputs:
216     * none
217     *
218     * side effects:
219     * the connection is marked to be closed soon
220     * handlers reset
221     * close_handler called
222     */
223     void
224 pippijn 1.5 connection_t::close_soon ()
225 pippijn 1.1 {
226 pippijn 1.5 flags |= CF_DEAD;
227 pippijn 1.1 /* these two cannot be NULL */
228 pippijn 1.5 read_handler = empty_handler;
229     write_handler = empty_handler;
230     recvq_handler = NULL;
231     if (close_handler)
232     close_handler (this);
233     close_handler = NULL;
234     listener = NULL;
235 pippijn 1.1 }
236    
237     /*
238     * connection_close_soon_children()
239     *
240     * inputs:
241     * a listener.
242     *
243     * outputs:
244     * none
245     *
246     * side effects:
247 pippijn 1.5 * close_soon() called on the connection itself and
248 pippijn 1.1 * for all connections accepted on this listener
249     */
250     void
251 pippijn 1.5 connection_t::close_soon_children ()
252 pippijn 1.1 {
253 pippijn 1.6 connection_t::list_type::iterator it = connection_t::list.begin ();
254     connection_t::list_type::iterator et = connection_t::list.end ();
255 pippijn 1.1 connection_t *cptr2;
256    
257 pippijn 1.5 if (is_listening ())
258 pippijn 1.1 {
259 pippijn 1.4 while (it != et)
260     {
261     cptr2 = *it;
262 pippijn 1.5 if (cptr2->listener == this)
263     cptr2->close_soon ();
264 pippijn 1.4 ++it;
265     }
266 pippijn 1.1 }
267 pippijn 1.4
268 pippijn 1.5 close_soon ();
269 pippijn 1.1 }
270    
271     /*
272 pippijn 1.5 * connection_t::close_all()
273 pippijn 1.1 *
274     * inputs:
275     * none
276     *
277     * outputs:
278     * none
279     *
280     * side effects:
281     * connection_close() called on all registered connections
282     */
283     void
284 pippijn 1.5 connection_t::close_all (void)
285 pippijn 1.1 {
286 pippijn 1.6 while (!connection_t::list.empty ())
287     connection_t::list.back ()->close ();
288 pippijn 1.1 }
289    
290     /*
291 pippijn 1.5 * connection_t::open_tcp()
292 pippijn 1.1 *
293     * inputs:
294     * hostname to connect to, vhost to use, port,
295     * read handler, write handler
296     *
297     * outputs:
298     * the connection_t on success, NULL on failure.
299     *
300     * side effects:
301     * a TCP/IP connection is opened to the host,
302     * and interest is registered in read/write events.
303     */
304     connection_t *
305 pippijn 1.5 connection_t::open_tcp (char const * const host, char const * const vhost, unsigned int port, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
306 pippijn 1.1 {
307     connection_t *cptr;
308     char buf[BUFSIZE];
309     struct hostent *hp;
310     struct sockaddr_in sa;
311     struct in_addr *in;
312     unsigned s;
313     unsigned int optval;
314    
315     if (!(s = socket (AF_INET, SOCK_STREAM, 0)))
316     {
317 pippijn 1.5 slog (LG_ERROR, "connection_t::open_tcp(): unable to create socket.");
318 pippijn 1.1 return NULL;
319     }
320    
321     /* Has the highest fd gotten any higher yet? */
322 pippijn 1.4 if (s > system_state.maxfd)
323     system_state.maxfd = s;
324 pippijn 1.1
325     snprintf (buf, BUFSIZE, "tcp connection: %s", host);
326    
327     if (vhost)
328     {
329     memset (&sa, 0, sizeof (sa));
330     sa.sin_family = AF_INET;
331    
332     if ((hp = gethostbyname (vhost)) == NULL)
333     {
334 pippijn 1.5 slog (LG_ERROR, "connection_t::open_tcp(): cant resolve vhost %s", vhost);
335     ::close (s);
336 pippijn 1.1 return NULL;
337     }
338    
339     in = (struct in_addr *) (hp->h_addr_list[0]);
340     sa.sin_addr.s_addr = in->s_addr;
341     sa.sin_port = 0;
342    
343     optval = 1;
344     setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof (optval));
345    
346     if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0)
347     {
348 pippijn 1.5 ::close (s);
349     slog (LG_ERROR, "connection_t::open_tcp(): unable to bind to vhost %s", vhost);
350 pippijn 1.1 return NULL;
351     }
352     }
353    
354     /* resolve it */
355     if ((hp = gethostbyname (host)) == NULL)
356     {
357 pippijn 1.5 slog (LG_ERROR, "connection_t::open_tcp(): unable to resolve %s", host);
358     ::close (s);
359 pippijn 1.1 return NULL;
360     }
361    
362     memset (&sa, '\0', sizeof (sa));
363     sa.sin_family = AF_INET;
364     sa.sin_port = htons (port);
365     memcpy (&sa.sin_addr, hp->h_addr, hp->h_length);
366    
367     socket_setnonblocking (s);
368    
369     if (connect (s, (struct sockaddr *) &sa, sizeof (sa)) == -1 && errno != EINPROGRESS && errno != EINTR)
370     {
371 pippijn 1.5 slog (LG_ERROR, "connection_t::open_tcp(): failed to connect to %s: %s", host, strerror (errno));
372     ::close (s);
373 pippijn 1.1 return NULL;
374     }
375    
376 pippijn 1.5 cptr = connection_t::create (buf, s, CF_CONNECTING, read_handler, write_handler);
377 pippijn 1.1
378     return cptr;
379     }
380    
381     /*
382 pippijn 1.5 * connection_t::open_listener_tcp()
383 pippijn 1.1 *
384     * inputs:
385     * host and port to listen on,
386     * accept handler
387     *
388     * outputs:
389     * the connection_t on success, NULL on failure.
390     *
391     * side effects:
392     * a TCP/IP connection is opened to the host,
393     * and interest is registered in read/write events.
394     */
395     connection_t *
396 pippijn 1.5 connection_t::open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *))
397 pippijn 1.1 {
398     connection_t *cptr;
399     char buf[BUFSIZE];
400     struct hostent *hp;
401     struct sockaddr_in sa;
402     struct in_addr *in;
403     unsigned s;
404     unsigned int optval;
405    
406     if (!(s = socket (AF_INET, SOCK_STREAM, 0)))
407     {
408 pippijn 1.5 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to create socket.");
409 pippijn 1.1 return NULL;
410     }
411    
412     /* Has the highest fd gotten any higher yet? */
413 pippijn 1.4 if (s > system_state.maxfd)
414     system_state.maxfd = s;
415 pippijn 1.1
416     snprintf (buf, BUFSIZE, "listener: %s[%d]", host, port);
417    
418     memset (&sa, 0, sizeof (sa));
419     sa.sin_family = AF_INET;
420    
421     if ((hp = gethostbyname (host)) == NULL)
422     {
423 pippijn 1.5 slog (LG_ERROR, "connection_t::open_listener_tcp(): cant resolve host %s", host);
424     ::close (s);
425 pippijn 1.1 return NULL;
426     }
427    
428     in = (struct in_addr *) (hp->h_addr_list[0]);
429     sa.sin_family = AF_INET;
430     sa.sin_addr.s_addr = in->s_addr;
431     sa.sin_port = htons (port);
432    
433     optval = 1;
434     setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof (optval));
435    
436     if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0)
437     {
438 pippijn 1.5 ::close (s);
439     slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to bind listener %s[%d], errno [%d]", host, port, errno);
440 pippijn 1.1 return NULL;
441     }
442    
443     socket_setnonblocking (s);
444    
445     /* XXX we need to have some sort of handling for SOMAXCONN */
446     if (listen (s, 5) < 0)
447     {
448 pippijn 1.5 ::close (s);
449     slog (LG_ERROR, "connection_t::open_listener_tcp(): error: %s", strerror (errno));
450 pippijn 1.1 return NULL;
451     }
452    
453 pippijn 1.5 cptr = connection_t::create (buf, s, CF_LISTENING, read_handler, NULL);
454 pippijn 1.1
455     return cptr;
456     }
457    
458     /*
459 pippijn 1.5 * connection_t::accept_tcp()
460 pippijn 1.1 *
461     * inputs:
462     * listener to accept from, read handler, write handler
463     *
464     * outputs:
465     * the connection_t on success, NULL on failure.
466     *
467     * side effects:
468     * a TCP/IP connection is accepted from the host,
469     * and interest is registered in read/write events.
470     */
471     connection_t *
472 pippijn 1.5 connection_t::accept_tcp (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
473 pippijn 1.1 {
474     char buf[BUFSIZE];
475     connection_t *newptr;
476     unsigned s;
477    
478     if (!(s = accept (cptr->fd, NULL, NULL)))
479     {
480 pippijn 1.5 slog (LG_INFO, "connection_t::accept_tcp(): accept failed");
481 pippijn 1.1 return NULL;
482     }
483    
484     /* Has the highest fd gotten any higher yet? */
485 pippijn 1.4 if (s > system_state.maxfd)
486     system_state.maxfd = s;
487 pippijn 1.1
488     socket_setnonblocking (s);
489    
490     strlcpy (buf, "incoming connection", BUFSIZE);
491 pippijn 1.5 newptr = connection_t::create (buf, s, 0, read_handler, write_handler);
492 pippijn 1.1 newptr->listener = cptr;
493     return newptr;
494     }
495    
496     /*
497     * connection_setselect()
498     *
499     * inputs:
500     * connection_t to register/deregister interest on,
501     * replacement handlers (NULL = no interest)
502     *
503     * outputs:
504     * none
505     *
506     * side effects:
507     * the handlers are changed for the connection_t.
508     */
509     void
510     connection_setselect (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
511     {
512     cptr->read_handler = read_handler;
513     cptr->write_handler = write_handler;
514     }
515    
516     /*
517 pippijn 1.5 * connection_t::stats()
518 pippijn 1.1 *
519     * inputs:
520     * callback function, data for callback function
521     *
522     * outputs:
523     * none
524     *
525     * side effects:
526     * callback function is called with a series of lines
527     */
528     void
529 pippijn 1.5 connection_t::stats (void (*stats_cb) (char const * const , void *), void *privdata)
530 pippijn 1.1 {
531     char buf[160];
532     char buf2[20];
533 pippijn 1.6 connection_t::list_type::iterator it = connection_t::list.begin ();
534     connection_t::list_type::iterator et = connection_t::list.end ();
535 pippijn 1.1
536 pippijn 1.4 while (it != et)
537     {
538     connection_t *c = *it;
539    
540     snprintf (buf, sizeof buf, "fd %-3d desc '%s'", c->fd, c->flags & CF_UPLINK ? "uplink" : c->flags & CF_LISTENING ? "listener" : "misc");
541     if (c->listener != NULL)
542     {
543     snprintf (buf2, sizeof buf2, " listener %d", c->listener->fd);
544     strlcat (buf, buf2, sizeof buf);
545     }
546     if (c->flags & (CF_CONNECTING | CF_DEAD | CF_NONEWLINE | CF_SEND_EOF | CF_SEND_DEAD))
547     {
548     strlcat (buf, " status", sizeof buf);
549     if (c->flags & CF_CONNECTING)
550     strlcat (buf, " connecting", sizeof buf);
551     if (c->flags & CF_DEAD)
552     strlcat (buf, " dead", sizeof buf);
553     if (c->flags & CF_NONEWLINE)
554     strlcat (buf, " nonewline", sizeof buf);
555     if (c->flags & CF_SEND_DEAD)
556     strlcat (buf, " send_dead", sizeof buf);
557     else if (c->flags & CF_SEND_EOF)
558     strlcat (buf, " send_eof", sizeof buf);
559     }
560     stats_cb (buf, privdata);
561    
562     ++it;
563     }
564 pippijn 1.1 }
565    
566     /*
567     * connection_write()
568     *
569     * inputs:
570     * connection_t to write to, format string, parameters
571     *
572     * outputs:
573     * none
574     *
575     * side effects:
576     * data is added to the connection_t sendq cache.
577     */
578     void
579 pippijn 1.5 connection_t::write (char *format, ...)
580 pippijn 1.1 {
581     char buf[BUFSIZE * 12];
582     va_list args;
583     unsigned int len;
584    
585     va_start (args, format);
586     vsnprintf (buf, BUFSIZE * 12, format, args);
587     va_end (args);
588    
589     len = strlen (buf);
590     buf[len++] = '\r';
591     buf[len++] = '\n';
592     buf[len] = '\0';
593    
594 pippijn 1.5 sendq_add (this, buf, len);
595 pippijn 1.1 }
596    
597     /*
598     * connection_write_raw()
599     *
600     * inputs:
601     * connection_t to write to, raw string to write
602     *
603     * outputs:
604     * none
605     *
606     * side effects:
607     * data is added to the connection_t sendq cache.
608     */
609     void
610 pippijn 1.5 connection_t::write_raw (char *data)
611 pippijn 1.1 {
612 pippijn 1.5 sendq_add (this, data, strlen (data));
613 pippijn 1.1 }