ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/connection.C
Revision: 1.3
Committed: Sat Jul 21 13:23:21 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
- added rcsid to some files
- more documentation tweaks
- made most protocol commands local to phandler.C
- added ircd metadata (inspircd only for now)
- added inspircd swhois support

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