ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/connection.C
Revision: 1.8
Committed: Sat Sep 22 14:27:30 2007 UTC (16 years, 7 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +3 -1 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

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