ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/connection.C
Revision: 1.6
Committed: Wed Sep 5 11:23:15 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +16 -16 lines
Log Message:
removed GPLed code and put license back to BSD

File Contents

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