ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/connection.C
Revision: 1.6
Committed: Wed Sep 5 11:23:15 2007 UTC (16 years, 8 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

# Content
1 /*
2 * connection.C: Connection and I/O management
3 * Rights to this code are documented in doc/pod/license.pod.
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7
8 static char const rcsid[] = "$Id: connection.C,v 1.5 2007-08-30 19:56:24 pippijn Exp $";
9
10 #include "atheme.h"
11 #include "internal.h"
12 #include "datastream.h"
13 #include "connection.h"
14
15 connection_t::list_type connection_t::list;
16 connection_t::callbacks connection_t::callback;
17
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 * connection_t::create()
43 *
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 connection_t::create (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
56 {
57 connection_t *cptr;
58
59 if ((cptr = connection_t::find (fd)))
60 {
61 slog (LG_DEBUG, "connection_t::create(): connection %d is already registered as %s", fd, cptr->name);
62 return NULL;
63 }
64
65 slog (LG_DEBUG, "connection_t::create(): adding connection '%s', fd = %d", name, fd);
66
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 connection_t::list.insert (cptr);
89
90 return cptr;
91 }
92
93 /*
94 * connection_t::find()
95 *
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 connection_t::find (int fd)
107 {
108 connection_t *cptr;
109 connection_t::list_type::iterator it = connection_t::list.begin ();
110 connection_t::list_type::iterator et = connection_t::list.end ();
111
112 while (it != et)
113 {
114 cptr = *it;
115
116 if (cptr->fd == fd)
117 return cptr;
118
119 ++it;
120 }
121
122 return NULL;
123 }
124
125 /*
126 * connection_t::count()
127 *
128 * inputs:
129 * none
130 *
131 * outputs:
132 * number of connections tracked
133 *
134 * side effects:
135 * none
136 */
137 int
138 connection_t::count (void)
139 {
140 return connection_t::list.size ();
141 }
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 connection_t::close ()
157 {
158 connection_t::list_type::iterator it;
159 int errno1, errno2;
160 #ifdef SO_ERROR
161 socklen_t len = sizeof (errno2);
162 #endif
163
164 it = connection_t::list.find (this);
165 if (it == connection_t::list.end ())
166 {
167 slog (LG_DEBUG, "connection_close(): connection %p is not registered!", this);
168 return;
169 }
170
171 errno1 = errno;
172 #ifdef SO_ERROR
173 if (!getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) &len))
174 {
175 if (errno2 != 0)
176 errno1 = errno2;
177 }
178 #endif
179
180 if (errno1)
181 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
183 if (close_handler)
184 close_handler (this);
185
186 /* close the fd */
187 ::close (fd);
188
189 connection_t::list.erase (this);
190
191 sendqrecvq_free (this);
192
193 delete this;
194 }
195
196 /* This one is only safe for use by connection_t::close_soon(),
197 * 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 connection_t::close_soon ()
220 {
221 flags |= CF_DEAD;
222 /* these two cannot be NULL */
223 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 }
231
232 /*
233 * connection_close_soon_children()
234 *
235 * inputs:
236 * a listener.
237 *
238 * outputs:
239 * none
240 *
241 * side effects:
242 * close_soon() called on the connection itself and
243 * for all connections accepted on this listener
244 */
245 void
246 connection_t::close_soon_children ()
247 {
248 connection_t::list_type::iterator it = connection_t::list.begin ();
249 connection_t::list_type::iterator et = connection_t::list.end ();
250 connection_t *cptr2;
251
252 if (is_listening ())
253 {
254 while (it != et)
255 {
256 cptr2 = *it;
257 if (cptr2->listener == this)
258 cptr2->close_soon ();
259 ++it;
260 }
261 }
262
263 close_soon ();
264 }
265
266 /*
267 * connection_t::close_all()
268 *
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 connection_t::close_all (void)
280 {
281 while (!connection_t::list.empty ())
282 connection_t::list.back ()->close ();
283 }
284
285 /*
286 * connection_t::open_tcp()
287 *
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 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 {
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 slog (LG_ERROR, "connection_t::open_tcp(): unable to create socket.");
313 return NULL;
314 }
315
316 /* Has the highest fd gotten any higher yet? */
317 if (s > system_state.maxfd)
318 system_state.maxfd = s;
319
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 slog (LG_ERROR, "connection_t::open_tcp(): cant resolve vhost %s", vhost);
330 ::close (s);
331 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 ::close (s);
344 slog (LG_ERROR, "connection_t::open_tcp(): unable to bind to vhost %s", vhost);
345 return NULL;
346 }
347 }
348
349 /* resolve it */
350 if ((hp = gethostbyname (host)) == NULL)
351 {
352 slog (LG_ERROR, "connection_t::open_tcp(): unable to resolve %s", host);
353 ::close (s);
354 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 slog (LG_ERROR, "connection_t::open_tcp(): failed to connect to %s: %s", host, strerror (errno));
367 ::close (s);
368 return NULL;
369 }
370
371 cptr = connection_t::create (buf, s, CF_CONNECTING, read_handler, write_handler);
372
373 return cptr;
374 }
375
376 /*
377 * connection_t::open_listener_tcp()
378 *
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 connection_t::open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *))
392 {
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 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to create socket.");
404 return NULL;
405 }
406
407 /* Has the highest fd gotten any higher yet? */
408 if (s > system_state.maxfd)
409 system_state.maxfd = s;
410
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 slog (LG_ERROR, "connection_t::open_listener_tcp(): cant resolve host %s", host);
419 ::close (s);
420 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 ::close (s);
434 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to bind listener %s[%d], errno [%d]", host, port, errno);
435 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 ::close (s);
444 slog (LG_ERROR, "connection_t::open_listener_tcp(): error: %s", strerror (errno));
445 return NULL;
446 }
447
448 cptr = connection_t::create (buf, s, CF_LISTENING, read_handler, NULL);
449
450 return cptr;
451 }
452
453 /*
454 * connection_t::accept_tcp()
455 *
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 connection_t::accept_tcp (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
468 {
469 char buf[BUFSIZE];
470 connection_t *newptr;
471 unsigned s;
472
473 if (!(s = accept (cptr->fd, NULL, NULL)))
474 {
475 slog (LG_INFO, "connection_t::accept_tcp(): accept failed");
476 return NULL;
477 }
478
479 /* Has the highest fd gotten any higher yet? */
480 if (s > system_state.maxfd)
481 system_state.maxfd = s;
482
483 socket_setnonblocking (s);
484
485 strlcpy (buf, "incoming connection", BUFSIZE);
486 newptr = connection_t::create (buf, s, 0, read_handler, write_handler);
487 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 * connection_t::stats()
513 *
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 connection_t::stats (void (*stats_cb) (char const * const , void *), void *privdata)
525 {
526 char buf[160];
527 char buf2[20];
528 connection_t::list_type::iterator it = connection_t::list.begin ();
529 connection_t::list_type::iterator et = connection_t::list.end ();
530
531 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 }
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 connection_t::write (char *format, ...)
575 {
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 sendq_add (this, buf, len);
590 }
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 connection_t::write_raw (char *data)
606 {
607 sendq_add (this, data, strlen (data));
608 }