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

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.6 2007-09-05 11:23:15 pippijn Exp $";
14
15 #include "atheme.h"
16 #include "internal.h"
17 #include "datastream.h"
18 #include "connection.h"
19
20 connection_t::list_type connection_t::list;
21 connection_t::callbacks connection_t::callback;
22
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 * connection_t::create()
48 *
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 connection_t::create (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
61 {
62 connection_t *cptr;
63
64 if ((cptr = connection_t::find (fd)))
65 {
66 slog (LG_DEBUG, "connection_t::create(): connection %d is already registered as %s", fd, cptr->name);
67 return NULL;
68 }
69
70 slog (LG_DEBUG, "connection_t::create(): adding connection '%s', fd = %d", name, fd);
71
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 connection_t::list.insert (cptr);
94
95 return cptr;
96 }
97
98 /*
99 * connection_t::find()
100 *
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 connection_t::find (int fd)
112 {
113 connection_t *cptr;
114 connection_t::list_type::iterator it = connection_t::list.begin ();
115 connection_t::list_type::iterator et = connection_t::list.end ();
116
117 while (it != et)
118 {
119 cptr = *it;
120
121 if (cptr->fd == fd)
122 return cptr;
123
124 ++it;
125 }
126
127 return NULL;
128 }
129
130 /*
131 * connection_t::count()
132 *
133 * inputs:
134 * none
135 *
136 * outputs:
137 * number of connections tracked
138 *
139 * side effects:
140 * none
141 */
142 int
143 connection_t::count (void)
144 {
145 return connection_t::list.size ();
146 }
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 connection_t::close ()
162 {
163 connection_t::list_type::iterator it;
164 int errno1, errno2;
165 #ifdef SO_ERROR
166 socklen_t len = sizeof (errno2);
167 #endif
168
169 it = connection_t::list.find (this);
170 if (it == connection_t::list.end ())
171 {
172 slog (LG_DEBUG, "connection_close(): connection %p is not registered!", this);
173 return;
174 }
175
176 errno1 = errno;
177 #ifdef SO_ERROR
178 if (!getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) &len))
179 {
180 if (errno2 != 0)
181 errno1 = errno2;
182 }
183 #endif
184
185 if (errno1)
186 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
188 if (close_handler)
189 close_handler (this);
190
191 /* close the fd */
192 ::close (fd);
193
194 connection_t::list.erase (this);
195
196 sendqrecvq_free (this);
197
198 delete this;
199 }
200
201 /* This one is only safe for use by connection_t::close_soon(),
202 * 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 connection_t::close_soon ()
225 {
226 flags |= CF_DEAD;
227 /* these two cannot be NULL */
228 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 }
236
237 /*
238 * connection_close_soon_children()
239 *
240 * inputs:
241 * a listener.
242 *
243 * outputs:
244 * none
245 *
246 * side effects:
247 * close_soon() called on the connection itself and
248 * for all connections accepted on this listener
249 */
250 void
251 connection_t::close_soon_children ()
252 {
253 connection_t::list_type::iterator it = connection_t::list.begin ();
254 connection_t::list_type::iterator et = connection_t::list.end ();
255 connection_t *cptr2;
256
257 if (is_listening ())
258 {
259 while (it != et)
260 {
261 cptr2 = *it;
262 if (cptr2->listener == this)
263 cptr2->close_soon ();
264 ++it;
265 }
266 }
267
268 close_soon ();
269 }
270
271 /*
272 * connection_t::close_all()
273 *
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 connection_t::close_all (void)
285 {
286 while (!connection_t::list.empty ())
287 connection_t::list.back ()->close ();
288 }
289
290 /*
291 * connection_t::open_tcp()
292 *
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 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 {
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 slog (LG_ERROR, "connection_t::open_tcp(): unable to create socket.");
318 return NULL;
319 }
320
321 /* Has the highest fd gotten any higher yet? */
322 if (s > system_state.maxfd)
323 system_state.maxfd = s;
324
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 slog (LG_ERROR, "connection_t::open_tcp(): cant resolve vhost %s", vhost);
335 ::close (s);
336 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 ::close (s);
349 slog (LG_ERROR, "connection_t::open_tcp(): unable to bind to vhost %s", vhost);
350 return NULL;
351 }
352 }
353
354 /* resolve it */
355 if ((hp = gethostbyname (host)) == NULL)
356 {
357 slog (LG_ERROR, "connection_t::open_tcp(): unable to resolve %s", host);
358 ::close (s);
359 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 slog (LG_ERROR, "connection_t::open_tcp(): failed to connect to %s: %s", host, strerror (errno));
372 ::close (s);
373 return NULL;
374 }
375
376 cptr = connection_t::create (buf, s, CF_CONNECTING, read_handler, write_handler);
377
378 return cptr;
379 }
380
381 /*
382 * connection_t::open_listener_tcp()
383 *
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 connection_t::open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *))
397 {
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 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to create socket.");
409 return NULL;
410 }
411
412 /* Has the highest fd gotten any higher yet? */
413 if (s > system_state.maxfd)
414 system_state.maxfd = s;
415
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 slog (LG_ERROR, "connection_t::open_listener_tcp(): cant resolve host %s", host);
424 ::close (s);
425 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 ::close (s);
439 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to bind listener %s[%d], errno [%d]", host, port, errno);
440 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 ::close (s);
449 slog (LG_ERROR, "connection_t::open_listener_tcp(): error: %s", strerror (errno));
450 return NULL;
451 }
452
453 cptr = connection_t::create (buf, s, CF_LISTENING, read_handler, NULL);
454
455 return cptr;
456 }
457
458 /*
459 * connection_t::accept_tcp()
460 *
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 connection_t::accept_tcp (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
473 {
474 char buf[BUFSIZE];
475 connection_t *newptr;
476 unsigned s;
477
478 if (!(s = accept (cptr->fd, NULL, NULL)))
479 {
480 slog (LG_INFO, "connection_t::accept_tcp(): accept failed");
481 return NULL;
482 }
483
484 /* Has the highest fd gotten any higher yet? */
485 if (s > system_state.maxfd)
486 system_state.maxfd = s;
487
488 socket_setnonblocking (s);
489
490 strlcpy (buf, "incoming connection", BUFSIZE);
491 newptr = connection_t::create (buf, s, 0, read_handler, write_handler);
492 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 * connection_t::stats()
518 *
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 connection_t::stats (void (*stats_cb) (char const * const , void *), void *privdata)
530 {
531 char buf[160];
532 char buf2[20];
533 connection_t::list_type::iterator it = connection_t::list.begin ();
534 connection_t::list_type::iterator et = connection_t::list.end ();
535
536 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 }
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 connection_t::write (char *format, ...)
580 {
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 sendq_add (this, buf, len);
595 }
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 connection_t::write_raw (char *data)
611 {
612 sendq_add (this, data, strlen (data));
613 }