ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/connection.C
(Generate patch)

Comparing ermyth/src/connection.C (file contents):
Revision 1.4 by pippijn, Tue Aug 28 17:08:12 2007 UTC vs.
Revision 1.5 by pippijn, Thu Aug 30 19:56:24 2007 UTC

3 * Rights to this code are documented in doc/pod/license.pod. 3 * Rights to this code are documented in doc/pod/license.pod.
4 * 4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) 5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */ 6 */
7 7
8static char const rcsid[] = "$Id: connection.C,v 1.4 2007/08/28 17:08:12 pippijn Exp $"; 8static char const rcsid[] = "$Id: connection.C,v 1.5 2007/08/30 19:56:24 pippijn Exp $";
9 9
10#include "atheme.h" 10#include "atheme.h"
11#include "internal.h" 11#include "internal.h"
12#include "datastream.h" 12#include "datastream.h"
13#include "connection.h"
13 14
14connection_vector connlist; 15connection_vector connlist;
15connection_t::callbacks connection_t::callback; 16connection_t::callbacks connection_t::callback;
16 17
17void 18void
36 37
37 return 0; 38 return 0;
38} 39}
39 40
40/* 41/*
41 * connection_add() 42 * connection_t::create()
42 * 43 *
43 * inputs: 44 * inputs:
44 * connection name, file descriptor, flag bitmask, 45 * connection name, file descriptor, flag bitmask,
45 * read handler, write handler. 46 * read handler, write handler.
46 * 47 *
49 * 50 *
50 * side effects: 51 * side effects:
51 * a connection is added to the socket queue. 52 * a connection is added to the socket queue.
52 */ 53 */
53connection_t * 54connection_t *
54connection_add (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) 55connection_t::create (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
55{ 56{
56 connection_t *cptr; 57 connection_t *cptr;
57 58
58 if ((cptr = connection_find (fd))) 59 if ((cptr = connection_t::find (fd)))
59 { 60 {
60 slog (LG_DEBUG, "connection_add(): connection %d is already registered as %s", fd, cptr->name); 61 slog (LG_DEBUG, "connection_t::create(): connection %d is already registered as %s", fd, cptr->name);
61 return NULL; 62 return NULL;
62 } 63 }
63 64
64 slog (LG_DEBUG, "connection_add(): adding connection '%s', fd = %d", name, fd); 65 slog (LG_DEBUG, "connection_t::create(): adding connection '%s', fd = %d", name, fd);
65 66
66 cptr = new connection_t; 67 cptr = new connection_t;
67 68
68 cptr->fd = fd; 69 cptr->fd = fd;
69 cptr->pollslot = -1; 70 cptr->pollslot = -1;
88 89
89 return cptr; 90 return cptr;
90} 91}
91 92
92/* 93/*
93 * connection_find() 94 * connection_t::find()
94 * 95 *
95 * inputs: 96 * inputs:
96 * the file descriptor to search by 97 * the file descriptor to search by
97 * 98 *
98 * outputs: 99 * outputs:
100 * 101 *
101 * side effects: 102 * side effects:
102 * none 103 * none
103 */ 104 */
104connection_t * 105connection_t *
105connection_find (int fd) 106connection_t::find (int fd)
106{ 107{
107 connection_t *cptr; 108 connection_t *cptr;
108 connection_vector::iterator it = connlist.begin (); 109 connection_vector::iterator it = connlist.begin ();
109 connection_vector::iterator et = connlist.end (); 110 connection_vector::iterator et = connlist.end ();
110 111
120 121
121 return NULL; 122 return NULL;
122} 123}
123 124
124/* 125/*
125 * connection_count() 126 * connection_t::count()
126 * 127 *
127 * inputs: 128 * inputs:
128 * none 129 * none
129 * 130 *
130 * outputs: 131 * outputs:
132 * 133 *
133 * side effects: 134 * side effects:
134 * none 135 * none
135 */ 136 */
136int 137int
137connection_count (void) 138connection_t::count (void)
138{ 139{
139 return connlist.size (); 140 return connlist.size ();
140} 141}
141 142
142/* 143/*
150 * 151 *
151 * side effects: 152 * side effects:
152 * the connection is closed. 153 * the connection is closed.
153 */ 154 */
154void 155void
155connection_close (connection_t *cptr) 156connection_t::close ()
156{ 157{
157 connection_vector::iterator it; 158 connection_vector::iterator it;
158 int errno1, errno2; 159 int errno1, errno2;
159#ifdef SO_ERROR 160#ifdef SO_ERROR
160 socklen_t len = sizeof (errno2); 161 socklen_t len = sizeof (errno2);
161#endif 162#endif
162 163
163 it = connlist.find (cptr); 164 it = connlist.find (this);
164 if (it == connlist.end ()) 165 if (it == connlist.end ())
165 { 166 {
166 slog (LG_DEBUG, "connection_close(): connection %p is not registered!", cptr); 167 slog (LG_DEBUG, "connection_close(): connection %p is not registered!", this);
167 return; 168 return;
168 } 169 }
169 170
170 errno1 = errno; 171 errno1 = errno;
171#ifdef SO_ERROR 172#ifdef SO_ERROR
172 if (!getsockopt (cptr->fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) &len)) 173 if (!getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) &len))
173 { 174 {
174 if (errno2 != 0) 175 if (errno2 != 0)
175 errno1 = errno2; 176 errno1 = errno2;
176 } 177 }
177#endif 178#endif
178 179
179 if (errno1) 180 if (errno1)
180 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)); 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));
181 182
182 if (cptr->close_handler) 183 if (close_handler)
183 cptr->close_handler (cptr); 184 close_handler (this);
184 185
185 /* close the fd */ 186 /* close the fd */
186 close (cptr->fd); 187 ::close (fd);
187 188
188 connlist.erase (cptr); 189 connlist.erase (this);
189 190
190 sendqrecvq_free (cptr); 191 sendqrecvq_free (this);
191 192
192 delete cptr; 193 delete this;
193} 194}
194 195
195/* This one is only safe for use by connection_close_soon(), 196/* This one is only safe for use by connection_t::close_soon(),
196 * it will cause infinite loops otherwise 197 * it will cause infinite loops otherwise
197 */ 198 */
198static void 199static void
199empty_handler (connection_t *cptr) 200empty_handler (connection_t *cptr)
200{ 201{
213 * the connection is marked to be closed soon 214 * the connection is marked to be closed soon
214 * handlers reset 215 * handlers reset
215 * close_handler called 216 * close_handler called
216 */ 217 */
217void 218void
218connection_close_soon (connection_t *cptr) 219connection_t::close_soon ()
219{ 220{
220 cptr->flags |= CF_DEAD; 221 flags |= CF_DEAD;
221 /* these two cannot be NULL */ 222 /* these two cannot be NULL */
222 cptr->read_handler = empty_handler; 223 read_handler = empty_handler;
223 cptr->write_handler = empty_handler; 224 write_handler = empty_handler;
224 cptr->recvq_handler = NULL; 225 recvq_handler = NULL;
225 if (cptr->close_handler) 226 if (close_handler)
226 cptr->close_handler (cptr); 227 close_handler (this);
227 cptr->close_handler = NULL; 228 close_handler = NULL;
228 cptr->listener = NULL; 229 listener = NULL;
229} 230}
230 231
231/* 232/*
232 * connection_close_soon_children() 233 * connection_close_soon_children()
233 * 234 *
236 * 237 *
237 * outputs: 238 * outputs:
238 * none 239 * none
239 * 240 *
240 * side effects: 241 * side effects:
241 * connection_close_soon() called on the connection itself and 242 * close_soon() called on the connection itself and
242 * for all connections accepted on this listener 243 * for all connections accepted on this listener
243 */ 244 */
244void 245void
245connection_close_soon_children (connection_t *cptr) 246connection_t::close_soon_children ()
246{ 247{
247 connection_vector::iterator it = connlist.begin (); 248 connection_vector::iterator it = connlist.begin ();
248 connection_vector::iterator et = connlist.end (); 249 connection_vector::iterator et = connlist.end ();
249 connection_t *cptr2; 250 connection_t *cptr2;
250 251
251 return_if_fail (cptr != NULL); 252 if (is_listening ())
252
253 if (CF_IS_LISTENING (cptr))
254 { 253 {
255 while (it != et) 254 while (it != et)
256 { 255 {
257 cptr2 = *it; 256 cptr2 = *it;
258 if (cptr2->listener == cptr) 257 if (cptr2->listener == this)
259 connection_close_soon (cptr2); 258 cptr2->close_soon ();
260 ++it; 259 ++it;
261 } 260 }
262 } 261 }
263 262
264 connection_close_soon (cptr); 263 close_soon ();
265} 264}
266 265
267/* 266/*
268 * connection_close_all() 267 * connection_t::close_all()
269 * 268 *
270 * inputs: 269 * inputs:
271 * none 270 * none
272 * 271 *
273 * outputs: 272 * outputs:
275 * 274 *
276 * side effects: 275 * side effects:
277 * connection_close() called on all registered connections 276 * connection_close() called on all registered connections
278 */ 277 */
279void 278void
280connection_close_all (void) 279connection_t::close_all (void)
281{ 280{
282 while (!connlist.empty ()) 281 while (!connlist.empty ())
283 connection_close (connlist.back ()); 282 connlist.back ()->close ();
284} 283}
285 284
286/* 285/*
287 * connection_open_tcp() 286 * connection_t::open_tcp()
288 * 287 *
289 * inputs: 288 * inputs:
290 * hostname to connect to, vhost to use, port, 289 * hostname to connect to, vhost to use, port,
291 * read handler, write handler 290 * read handler, write handler
292 * 291 *
296 * side effects: 295 * side effects:
297 * a TCP/IP connection is opened to the host, 296 * a TCP/IP connection is opened to the host,
298 * and interest is registered in read/write events. 297 * and interest is registered in read/write events.
299 */ 298 */
300connection_t * 299connection_t *
301connection_open_tcp (char const * const host, char const * const vhost, unsigned int port, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) 300connection_t::open_tcp (char const * const host, char const * const vhost, unsigned int port, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
302{ 301{
303 connection_t *cptr; 302 connection_t *cptr;
304 char buf[BUFSIZE]; 303 char buf[BUFSIZE];
305 struct hostent *hp; 304 struct hostent *hp;
306 struct sockaddr_in sa; 305 struct sockaddr_in sa;
308 unsigned s; 307 unsigned s;
309 unsigned int optval; 308 unsigned int optval;
310 309
311 if (!(s = socket (AF_INET, SOCK_STREAM, 0))) 310 if (!(s = socket (AF_INET, SOCK_STREAM, 0)))
312 { 311 {
313 slog (LG_ERROR, "connection_open_tcp(): unable to create socket."); 312 slog (LG_ERROR, "connection_t::open_tcp(): unable to create socket.");
314 return NULL; 313 return NULL;
315 } 314 }
316 315
317 /* Has the highest fd gotten any higher yet? */ 316 /* Has the highest fd gotten any higher yet? */
318 if (s > system_state.maxfd) 317 if (s > system_state.maxfd)
325 memset (&sa, 0, sizeof (sa)); 324 memset (&sa, 0, sizeof (sa));
326 sa.sin_family = AF_INET; 325 sa.sin_family = AF_INET;
327 326
328 if ((hp = gethostbyname (vhost)) == NULL) 327 if ((hp = gethostbyname (vhost)) == NULL)
329 { 328 {
330 slog (LG_ERROR, "connection_open_tcp(): cant resolve vhost %s", vhost); 329 slog (LG_ERROR, "connection_t::open_tcp(): cant resolve vhost %s", vhost);
331 close (s); 330 ::close (s);
332 return NULL; 331 return NULL;
333 } 332 }
334 333
335 in = (struct in_addr *) (hp->h_addr_list[0]); 334 in = (struct in_addr *) (hp->h_addr_list[0]);
336 sa.sin_addr.s_addr = in->s_addr; 335 sa.sin_addr.s_addr = in->s_addr;
339 optval = 1; 338 optval = 1;
340 setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof (optval)); 339 setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof (optval));
341 340
342 if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0) 341 if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0)
343 { 342 {
344 close (s); 343 ::close (s);
345 slog (LG_ERROR, "connection_open_tcp(): unable to bind to vhost %s", vhost); 344 slog (LG_ERROR, "connection_t::open_tcp(): unable to bind to vhost %s", vhost);
346 return NULL; 345 return NULL;
347 } 346 }
348 } 347 }
349 348
350 /* resolve it */ 349 /* resolve it */
351 if ((hp = gethostbyname (host)) == NULL) 350 if ((hp = gethostbyname (host)) == NULL)
352 { 351 {
353 slog (LG_ERROR, "connection_open_tcp(): unable to resolve %s", host); 352 slog (LG_ERROR, "connection_t::open_tcp(): unable to resolve %s", host);
354 close (s); 353 ::close (s);
355 return NULL; 354 return NULL;
356 } 355 }
357 356
358 memset (&sa, '\0', sizeof (sa)); 357 memset (&sa, '\0', sizeof (sa));
359 sa.sin_family = AF_INET; 358 sa.sin_family = AF_INET;
362 361
363 socket_setnonblocking (s); 362 socket_setnonblocking (s);
364 363
365 if (connect (s, (struct sockaddr *) &sa, sizeof (sa)) == -1 && errno != EINPROGRESS && errno != EINTR) 364 if (connect (s, (struct sockaddr *) &sa, sizeof (sa)) == -1 && errno != EINPROGRESS && errno != EINTR)
366 { 365 {
367 slog (LG_ERROR, "connection_open_tcp(): failed to connect to %s: %s", host, strerror (errno)); 366 slog (LG_ERROR, "connection_t::open_tcp(): failed to connect to %s: %s", host, strerror (errno));
368 close (s); 367 ::close (s);
369 return NULL; 368 return NULL;
370 } 369 }
371 370
372 cptr = connection_add (buf, s, CF_CONNECTING, read_handler, write_handler); 371 cptr = connection_t::create (buf, s, CF_CONNECTING, read_handler, write_handler);
373 372
374 return cptr; 373 return cptr;
375} 374}
376 375
377/* 376/*
378 * connection_open_listener_tcp() 377 * connection_t::open_listener_tcp()
379 * 378 *
380 * inputs: 379 * inputs:
381 * host and port to listen on, 380 * host and port to listen on,
382 * accept handler 381 * accept handler
383 * 382 *
387 * side effects: 386 * side effects:
388 * a TCP/IP connection is opened to the host, 387 * a TCP/IP connection is opened to the host,
389 * and interest is registered in read/write events. 388 * and interest is registered in read/write events.
390 */ 389 */
391connection_t * 390connection_t *
392connection_open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *)) 391connection_t::open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *))
393{ 392{
394 connection_t *cptr; 393 connection_t *cptr;
395 char buf[BUFSIZE]; 394 char buf[BUFSIZE];
396 struct hostent *hp; 395 struct hostent *hp;
397 struct sockaddr_in sa; 396 struct sockaddr_in sa;
399 unsigned s; 398 unsigned s;
400 unsigned int optval; 399 unsigned int optval;
401 400
402 if (!(s = socket (AF_INET, SOCK_STREAM, 0))) 401 if (!(s = socket (AF_INET, SOCK_STREAM, 0)))
403 { 402 {
404 slog (LG_ERROR, "connection_open_listener_tcp(): unable to create socket."); 403 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to create socket.");
405 return NULL; 404 return NULL;
406 } 405 }
407 406
408 /* Has the highest fd gotten any higher yet? */ 407 /* Has the highest fd gotten any higher yet? */
409 if (s > system_state.maxfd) 408 if (s > system_state.maxfd)
414 memset (&sa, 0, sizeof (sa)); 413 memset (&sa, 0, sizeof (sa));
415 sa.sin_family = AF_INET; 414 sa.sin_family = AF_INET;
416 415
417 if ((hp = gethostbyname (host)) == NULL) 416 if ((hp = gethostbyname (host)) == NULL)
418 { 417 {
419 slog (LG_ERROR, "connection_open_listener_tcp(): cant resolve host %s", host); 418 slog (LG_ERROR, "connection_t::open_listener_tcp(): cant resolve host %s", host);
420 close (s); 419 ::close (s);
421 return NULL; 420 return NULL;
422 } 421 }
423 422
424 in = (struct in_addr *) (hp->h_addr_list[0]); 423 in = (struct in_addr *) (hp->h_addr_list[0]);
425 sa.sin_family = AF_INET; 424 sa.sin_family = AF_INET;
429 optval = 1; 428 optval = 1;
430 setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof (optval)); 429 setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof (optval));
431 430
432 if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0) 431 if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0)
433 { 432 {
434 close (s); 433 ::close (s);
435 slog (LG_ERROR, "connection_open_listener_tcp(): unable to bind listener %s[%d], errno [%d]", host, port, errno); 434 slog (LG_ERROR, "connection_t::open_listener_tcp(): unable to bind listener %s[%d], errno [%d]", host, port, errno);
436 return NULL; 435 return NULL;
437 } 436 }
438 437
439 socket_setnonblocking (s); 438 socket_setnonblocking (s);
440 439
441 /* XXX we need to have some sort of handling for SOMAXCONN */ 440 /* XXX we need to have some sort of handling for SOMAXCONN */
442 if (listen (s, 5) < 0) 441 if (listen (s, 5) < 0)
443 { 442 {
444 close (s); 443 ::close (s);
445 slog (LG_ERROR, "connection_open_listener_tcp(): error: %s", strerror (errno)); 444 slog (LG_ERROR, "connection_t::open_listener_tcp(): error: %s", strerror (errno));
446 return NULL; 445 return NULL;
447 } 446 }
448 447
449 cptr = connection_add (buf, s, CF_LISTENING, read_handler, NULL); 448 cptr = connection_t::create (buf, s, CF_LISTENING, read_handler, NULL);
450 449
451 return cptr; 450 return cptr;
452} 451}
453 452
454/* 453/*
455 * connection_accept_tcp() 454 * connection_t::accept_tcp()
456 * 455 *
457 * inputs: 456 * inputs:
458 * listener to accept from, read handler, write handler 457 * listener to accept from, read handler, write handler
459 * 458 *
460 * outputs: 459 * outputs:
463 * side effects: 462 * side effects:
464 * a TCP/IP connection is accepted from the host, 463 * a TCP/IP connection is accepted from the host,
465 * and interest is registered in read/write events. 464 * and interest is registered in read/write events.
466 */ 465 */
467connection_t * 466connection_t *
468connection_accept_tcp (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) 467connection_t::accept_tcp (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *))
469{ 468{
470 char buf[BUFSIZE]; 469 char buf[BUFSIZE];
471 connection_t *newptr; 470 connection_t *newptr;
472 unsigned s; 471 unsigned s;
473 472
474 if (!(s = accept (cptr->fd, NULL, NULL))) 473 if (!(s = accept (cptr->fd, NULL, NULL)))
475 { 474 {
476 slog (LG_INFO, "connection_accept_tcp(): accept failed"); 475 slog (LG_INFO, "connection_t::accept_tcp(): accept failed");
477 return NULL; 476 return NULL;
478 } 477 }
479 478
480 /* Has the highest fd gotten any higher yet? */ 479 /* Has the highest fd gotten any higher yet? */
481 if (s > system_state.maxfd) 480 if (s > system_state.maxfd)
482 system_state.maxfd = s; 481 system_state.maxfd = s;
483 482
484 socket_setnonblocking (s); 483 socket_setnonblocking (s);
485 484
486 strlcpy (buf, "incoming connection", BUFSIZE); 485 strlcpy (buf, "incoming connection", BUFSIZE);
487 newptr = connection_add (buf, s, 0, read_handler, write_handler); 486 newptr = connection_t::create (buf, s, 0, read_handler, write_handler);
488 newptr->listener = cptr; 487 newptr->listener = cptr;
489 return newptr; 488 return newptr;
490} 489}
491 490
492/* 491/*
508 cptr->read_handler = read_handler; 507 cptr->read_handler = read_handler;
509 cptr->write_handler = write_handler; 508 cptr->write_handler = write_handler;
510} 509}
511 510
512/* 511/*
513 * connection_stats() 512 * connection_t::stats()
514 * 513 *
515 * inputs: 514 * inputs:
516 * callback function, data for callback function 515 * callback function, data for callback function
517 * 516 *
518 * outputs: 517 * outputs:
520 * 519 *
521 * side effects: 520 * side effects:
522 * callback function is called with a series of lines 521 * callback function is called with a series of lines
523 */ 522 */
524void 523void
525connection_stats (void (*stats_cb) (char const * const , void *), void *privdata) 524connection_t::stats (void (*stats_cb) (char const * const , void *), void *privdata)
526{ 525{
527 char buf[160]; 526 char buf[160];
528 char buf2[20]; 527 char buf2[20];
529 connection_vector::iterator it = connlist.begin (); 528 connection_vector::iterator it = connlist.begin ();
530 connection_vector::iterator et = connlist.end (); 529 connection_vector::iterator et = connlist.end ();
570 * 569 *
571 * side effects: 570 * side effects:
572 * data is added to the connection_t sendq cache. 571 * data is added to the connection_t sendq cache.
573 */ 572 */
574void 573void
575connection_write (connection_t *to, char *format, ...) 574connection_t::write (char *format, ...)
576{ 575{
577 char buf[BUFSIZE * 12]; 576 char buf[BUFSIZE * 12];
578 va_list args; 577 va_list args;
579 unsigned int len; 578 unsigned int len;
580 579
585 len = strlen (buf); 584 len = strlen (buf);
586 buf[len++] = '\r'; 585 buf[len++] = '\r';
587 buf[len++] = '\n'; 586 buf[len++] = '\n';
588 buf[len] = '\0'; 587 buf[len] = '\0';
589 588
590 sendq_add (to, buf, len); 589 sendq_add (this, buf, len);
591} 590}
592 591
593/* 592/*
594 * connection_write_raw() 593 * connection_write_raw()
595 * 594 *
601 * 600 *
602 * side effects: 601 * side effects:
603 * data is added to the connection_t sendq cache. 602 * data is added to the connection_t sendq cache.
604 */ 603 */
605void 604void
606connection_write_raw (connection_t *to, char *data) 605connection_t::write_raw (char *data)
607{ 606{
608 sendq_add (to, data, strlen (data)); 607 sendq_add (this, data, strlen (data));
609} 608}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines