1 | /* |
1 | /* |
2 | * connection.C: Connection and I/O management |
2 | * connection.C: Connection and I/O management |
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 | |
8 | static char const rcsid[] = "$Id: connection.C,v 1.3 2007/07/21 13:23:21 pippijn Exp $"; |
8 | static char const rcsid[] = "$Id: connection.C,v 1.4 2007/08/28 17:08:12 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 | |
13 | |
14 | #if 0 |
14 | connection_vector connlist; |
15 | static BlockHeap *sa_heap; |
15 | connection_t::callbacks connection_t::callback; |
16 | static BlockHeap *connection_heap; |
|
|
17 | #endif |
|
|
18 | |
|
|
19 | list_t connection_list; |
|
|
20 | |
16 | |
21 | void |
17 | void |
22 | init_netio (void) |
18 | init_netio (void) |
23 | { |
19 | { |
24 | #if 0 |
20 | #if 0 |
25 | connection_heap = BlockHeapCreate (sizeof (connection_t), 16); |
21 | connection_heap = BlockHeapCreate (sizeof (connection_t), 16); |
26 | sa_heap = BlockHeapCreate (sizeof (struct sockaddr_in), 16); |
22 | 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 |
23 | #endif |
34 | } |
24 | } |
35 | |
25 | |
36 | static int |
26 | static int |
37 | socket_setnonblocking (int sck) |
27 | socket_setnonblocking (int sck) |
… | |
… | |
59 | * |
49 | * |
60 | * side effects: |
50 | * side effects: |
61 | * a connection is added to the socket queue. |
51 | * a connection is added to the socket queue. |
62 | */ |
52 | */ |
63 | connection_t * |
53 | connection_t * |
64 | connection_add (const char *name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) |
54 | connection_add (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) |
65 | { |
55 | { |
66 | connection_t *cptr; |
56 | connection_t *cptr; |
67 | |
57 | |
68 | if ((cptr = connection_find (fd))) |
58 | if ((cptr = connection_find (fd))) |
69 | { |
59 | { |
70 | slog (LG_DEBUG, "connection_add(): connection %d is already registered as %s", fd, cptr->name); |
60 | slog (LG_DEBUG, "connection_add(): connection %d is already registered as %s", fd, cptr->name); |
71 | return NULL; |
61 | return NULL; |
72 | } |
62 | } |
73 | |
63 | |
74 | slog (LG_DEBUG, "connection_add(): adding connection '%s', fd=%d", name, fd); |
64 | slog (LG_DEBUG, "connection_add(): adding connection '%s', fd = %d", name, fd); |
75 | |
65 | |
76 | cptr = new connection_t; |
66 | cptr = new connection_t; |
77 | |
67 | |
78 | cptr->fd = fd; |
68 | cptr->fd = fd; |
79 | cptr->pollslot = -1; |
69 | cptr->pollslot = -1; |
… | |
… | |
92 | getpeername (cptr->fd, &cptr->saddr, &cptr->saddr_size); |
82 | getpeername (cptr->fd, &cptr->saddr, &cptr->saddr_size); |
93 | cptr->sa = (struct sockaddr_in *) &cptr->saddr; |
83 | cptr->sa = (struct sockaddr_in *) &cptr->saddr; |
94 | |
84 | |
95 | inet_ntop (AF_INET, &cptr->sa->sin_addr, cptr->hbuf, BUFSIZE); |
85 | inet_ntop (AF_INET, &cptr->sa->sin_addr, cptr->hbuf, BUFSIZE); |
96 | |
86 | |
97 | node_add (cptr, node_create (), &connection_list); |
87 | connlist.insert (cptr); |
98 | |
88 | |
99 | return cptr; |
89 | return cptr; |
100 | } |
90 | } |
101 | |
91 | |
102 | /* |
92 | /* |
… | |
… | |
113 | */ |
103 | */ |
114 | connection_t * |
104 | connection_t * |
115 | connection_find (int fd) |
105 | connection_find (int fd) |
116 | { |
106 | { |
117 | connection_t *cptr; |
107 | connection_t *cptr; |
118 | node_t *nptr; |
108 | connection_vector::iterator it = connlist.begin (); |
|
|
109 | connection_vector::iterator et = connlist.end (); |
119 | |
110 | |
120 | LIST_FOREACH (nptr, connection_list.head) |
111 | while (it != et) |
121 | { |
112 | { |
122 | cptr = static_cast<connection_t *> (nptr->data); |
113 | cptr = *it; |
123 | |
114 | |
124 | if (cptr->fd == fd) |
115 | if (cptr->fd == fd) |
125 | return cptr; |
116 | return cptr; |
|
|
117 | |
|
|
118 | ++it; |
126 | } |
119 | } |
127 | |
120 | |
128 | return NULL; |
121 | return NULL; |
129 | } |
122 | } |
130 | |
123 | |
131 | /* |
124 | /* |
… | |
… | |
141 | * none |
134 | * none |
142 | */ |
135 | */ |
143 | int |
136 | int |
144 | connection_count (void) |
137 | connection_count (void) |
145 | { |
138 | { |
146 | return LIST_LENGTH (&connection_list); |
139 | return connlist.size (); |
147 | } |
140 | } |
148 | |
141 | |
149 | /* |
142 | /* |
150 | * connection_close() |
143 | * connection_close() |
151 | * |
144 | * |
… | |
… | |
159 | * the connection is closed. |
152 | * the connection is closed. |
160 | */ |
153 | */ |
161 | void |
154 | void |
162 | connection_close (connection_t *cptr) |
155 | connection_close (connection_t *cptr) |
163 | { |
156 | { |
164 | node_t *nptr; |
157 | connection_vector::iterator it; |
165 | int errno1, errno2; |
158 | int errno1, errno2; |
166 | #ifdef SO_ERROR |
159 | #ifdef SO_ERROR |
167 | socklen_t len = sizeof (errno2); |
160 | socklen_t len = sizeof (errno2); |
168 | #endif |
161 | #endif |
169 | |
162 | |
170 | if (!cptr) |
163 | it = connlist.find (cptr); |
171 | { |
164 | if (it == connlist.end ()) |
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 | { |
165 | { |
179 | slog (LG_DEBUG, "connection_close(): connection %p is not registered!", cptr); |
166 | slog (LG_DEBUG, "connection_close(): connection %p is not registered!", cptr); |
180 | return; |
167 | return; |
181 | } |
168 | } |
182 | |
169 | |
183 | errno1 = errno; |
170 | errno1 = errno; |
184 | #ifdef SO_ERROR |
171 | #ifdef SO_ERROR |
185 | if (!getsockopt (cptr->fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) & len)) |
172 | if (!getsockopt (cptr->fd, SOL_SOCKET, SO_ERROR, (char *) &errno2, (socklen_t *) &len)) |
186 | { |
173 | { |
187 | if (errno2 != 0) |
174 | if (errno2 != 0) |
188 | errno1 = errno2; |
175 | errno1 = errno2; |
189 | } |
176 | } |
190 | #endif |
177 | #endif |
… | |
… | |
196 | cptr->close_handler (cptr); |
183 | cptr->close_handler (cptr); |
197 | |
184 | |
198 | /* close the fd */ |
185 | /* close the fd */ |
199 | close (cptr->fd); |
186 | close (cptr->fd); |
200 | |
187 | |
201 | node_del (nptr, &connection_list); |
188 | connlist.erase (cptr); |
202 | node_free (nptr); |
|
|
203 | |
189 | |
204 | sendqrecvq_free (cptr); |
190 | sendqrecvq_free (cptr); |
205 | |
191 | |
206 | delete cptr; |
192 | delete cptr; |
207 | } |
193 | } |
… | |
… | |
229 | * close_handler called |
215 | * close_handler called |
230 | */ |
216 | */ |
231 | void |
217 | void |
232 | connection_close_soon (connection_t *cptr) |
218 | connection_close_soon (connection_t *cptr) |
233 | { |
219 | { |
234 | if (cptr == NULL) |
|
|
235 | return; |
|
|
236 | cptr->flags |= CF_DEAD; |
220 | cptr->flags |= CF_DEAD; |
237 | /* these two cannot be NULL */ |
221 | /* these two cannot be NULL */ |
238 | cptr->read_handler = empty_handler; |
222 | cptr->read_handler = empty_handler; |
239 | cptr->write_handler = empty_handler; |
223 | cptr->write_handler = empty_handler; |
240 | cptr->recvq_handler = NULL; |
224 | cptr->recvq_handler = NULL; |
… | |
… | |
258 | * for all connections accepted on this listener |
242 | * for all connections accepted on this listener |
259 | */ |
243 | */ |
260 | void |
244 | void |
261 | connection_close_soon_children (connection_t *cptr) |
245 | connection_close_soon_children (connection_t *cptr) |
262 | { |
246 | { |
263 | node_t *n; |
247 | connection_vector::iterator it = connlist.begin (); |
|
|
248 | connection_vector::iterator et = connlist.end (); |
264 | connection_t *cptr2; |
249 | connection_t *cptr2; |
265 | |
250 | |
266 | if (cptr == NULL) |
251 | return_if_fail (cptr != NULL); |
267 | return; |
|
|
268 | |
252 | |
269 | if (CF_IS_LISTENING (cptr)) |
253 | if (CF_IS_LISTENING (cptr)) |
270 | { |
254 | { |
271 | LIST_FOREACH (n, connection_list.head) |
255 | while (it != et) |
272 | { |
256 | { |
273 | cptr2 = static_cast<connection_t *> (n->data); |
257 | cptr2 = *it; |
274 | if (cptr2->listener == cptr) |
258 | if (cptr2->listener == cptr) |
275 | connection_close_soon (cptr2); |
259 | connection_close_soon (cptr2); |
|
|
260 | ++it; |
276 | } |
261 | } |
277 | } |
262 | } |
|
|
263 | |
278 | connection_close_soon (cptr); |
264 | connection_close_soon (cptr); |
279 | } |
265 | } |
280 | |
266 | |
281 | /* |
267 | /* |
282 | * connection_close_all() |
268 | * connection_close_all() |
… | |
… | |
291 | * connection_close() called on all registered connections |
277 | * connection_close() called on all registered connections |
292 | */ |
278 | */ |
293 | void |
279 | void |
294 | connection_close_all (void) |
280 | connection_close_all (void) |
295 | { |
281 | { |
296 | node_t *n, *tn; |
282 | while (!connlist.empty ()) |
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); |
283 | connection_close (connlist.back ()); |
303 | } |
|
|
304 | } |
284 | } |
305 | |
285 | |
306 | /* |
286 | /* |
307 | * connection_open_tcp() |
287 | * connection_open_tcp() |
308 | * |
288 | * |
… | |
… | |
316 | * side effects: |
296 | * side effects: |
317 | * a TCP/IP connection is opened to the host, |
297 | * a TCP/IP connection is opened to the host, |
318 | * and interest is registered in read/write events. |
298 | * and interest is registered in read/write events. |
319 | */ |
299 | */ |
320 | connection_t * |
300 | connection_t * |
321 | connection_open_tcp (char *host, char *vhost, unsigned int port, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) |
301 | connection_open_tcp (char const * const host, char const * const vhost, unsigned int port, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) |
322 | { |
302 | { |
323 | connection_t *cptr; |
303 | connection_t *cptr; |
324 | char buf[BUFSIZE]; |
304 | char buf[BUFSIZE]; |
325 | struct hostent *hp; |
305 | struct hostent *hp; |
326 | struct sockaddr_in sa; |
306 | struct sockaddr_in sa; |
… | |
… | |
333 | slog (LG_ERROR, "connection_open_tcp(): unable to create socket."); |
313 | slog (LG_ERROR, "connection_open_tcp(): unable to create socket."); |
334 | return NULL; |
314 | return NULL; |
335 | } |
315 | } |
336 | |
316 | |
337 | /* Has the highest fd gotten any higher yet? */ |
317 | /* Has the highest fd gotten any higher yet? */ |
338 | if (s > claro_state.maxfd) |
318 | if (s > system_state.maxfd) |
339 | claro_state.maxfd = s; |
319 | system_state.maxfd = s; |
340 | |
320 | |
341 | snprintf (buf, BUFSIZE, "tcp connection: %s", host); |
321 | snprintf (buf, BUFSIZE, "tcp connection: %s", host); |
342 | |
322 | |
343 | if (vhost) |
323 | if (vhost) |
344 | { |
324 | { |
… | |
… | |
407 | * side effects: |
387 | * side effects: |
408 | * a TCP/IP connection is opened to the host, |
388 | * a TCP/IP connection is opened to the host, |
409 | * and interest is registered in read/write events. |
389 | * and interest is registered in read/write events. |
410 | */ |
390 | */ |
411 | connection_t * |
391 | connection_t * |
412 | connection_open_listener_tcp (char *host, unsigned int port, void (*read_handler) (connection_t *)) |
392 | connection_open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *)) |
413 | { |
393 | { |
414 | connection_t *cptr; |
394 | connection_t *cptr; |
415 | char buf[BUFSIZE]; |
395 | char buf[BUFSIZE]; |
416 | struct hostent *hp; |
396 | struct hostent *hp; |
417 | struct sockaddr_in sa; |
397 | struct sockaddr_in sa; |
… | |
… | |
424 | slog (LG_ERROR, "connection_open_listener_tcp(): unable to create socket."); |
404 | slog (LG_ERROR, "connection_open_listener_tcp(): unable to create socket."); |
425 | return NULL; |
405 | return NULL; |
426 | } |
406 | } |
427 | |
407 | |
428 | /* Has the highest fd gotten any higher yet? */ |
408 | /* Has the highest fd gotten any higher yet? */ |
429 | if (s > claro_state.maxfd) |
409 | if (s > system_state.maxfd) |
430 | claro_state.maxfd = s; |
410 | system_state.maxfd = s; |
431 | |
411 | |
432 | snprintf (buf, BUFSIZE, "listener: %s[%d]", host, port); |
412 | snprintf (buf, BUFSIZE, "listener: %s[%d]", host, port); |
433 | |
413 | |
434 | memset (&sa, 0, sizeof (sa)); |
414 | memset (&sa, 0, sizeof (sa)); |
435 | sa.sin_family = AF_INET; |
415 | sa.sin_family = AF_INET; |
… | |
… | |
496 | slog (LG_INFO, "connection_accept_tcp(): accept failed"); |
476 | slog (LG_INFO, "connection_accept_tcp(): accept failed"); |
497 | return NULL; |
477 | return NULL; |
498 | } |
478 | } |
499 | |
479 | |
500 | /* Has the highest fd gotten any higher yet? */ |
480 | /* Has the highest fd gotten any higher yet? */ |
501 | if (s > claro_state.maxfd) |
481 | if (s > system_state.maxfd) |
502 | claro_state.maxfd = s; |
482 | system_state.maxfd = s; |
503 | |
483 | |
504 | socket_setnonblocking (s); |
484 | socket_setnonblocking (s); |
505 | |
485 | |
506 | strlcpy (buf, "incoming connection", BUFSIZE); |
486 | strlcpy (buf, "incoming connection", BUFSIZE); |
507 | newptr = connection_add (buf, s, 0, read_handler, write_handler); |
487 | newptr = connection_add (buf, s, 0, read_handler, write_handler); |
… | |
… | |
540 | * |
520 | * |
541 | * side effects: |
521 | * side effects: |
542 | * callback function is called with a series of lines |
522 | * callback function is called with a series of lines |
543 | */ |
523 | */ |
544 | void |
524 | void |
545 | connection_stats (void (*stats_cb) (const char *, void *), void *privdata) |
525 | connection_stats (void (*stats_cb) (char const * const , void *), void *privdata) |
546 | { |
526 | { |
547 | node_t *n; |
|
|
548 | char buf[160]; |
527 | char buf[160]; |
549 | char buf2[20]; |
528 | char buf2[20]; |
|
|
529 | connection_vector::iterator it = connlist.begin (); |
|
|
530 | connection_vector::iterator et = connlist.end (); |
550 | |
531 | |
551 | LIST_FOREACH (n, connection_list.head) |
532 | while (it != et) |
552 | { |
533 | { |
553 | connection_t *c = (connection_t *) n->data; |
534 | connection_t *c = *it; |
554 | |
535 | |
555 | snprintf (buf, sizeof buf, "fd %-3d desc '%s'", c->fd, c->flags & CF_UPLINK ? "uplink" : c->flags & CF_LISTENING ? "listener" : "misc"); |
536 | 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) |
537 | if (c->listener != NULL) |
557 | { |
538 | { |
558 | snprintf (buf2, sizeof buf2, " listener %d", c->listener->fd); |
539 | snprintf (buf2, sizeof buf2, " listener %d", c->listener->fd); |
559 | strlcat (buf, buf2, sizeof buf); |
540 | strlcat (buf, buf2, sizeof buf); |
560 | } |
541 | } |
561 | if (c->flags & (CF_CONNECTING | CF_DEAD | CF_NONEWLINE | CF_SEND_EOF | CF_SEND_DEAD)) |
542 | if (c->flags & (CF_CONNECTING | CF_DEAD | CF_NONEWLINE | CF_SEND_EOF | CF_SEND_DEAD)) |
562 | { |
543 | { |
563 | strlcat (buf, " status", sizeof buf); |
544 | strlcat (buf, " status", sizeof buf); |
564 | if (c->flags & CF_CONNECTING) |
545 | if (c->flags & CF_CONNECTING) |
565 | strlcat (buf, " connecting", sizeof buf); |
546 | strlcat (buf, " connecting", sizeof buf); |
566 | if (c->flags & CF_DEAD) |
547 | if (c->flags & CF_DEAD) |
567 | strlcat (buf, " dead", sizeof buf); |
548 | strlcat (buf, " dead", sizeof buf); |
568 | if (c->flags & CF_NONEWLINE) |
549 | if (c->flags & CF_NONEWLINE) |
569 | strlcat (buf, " nonewline", sizeof buf); |
550 | strlcat (buf, " nonewline", sizeof buf); |
570 | if (c->flags & CF_SEND_DEAD) |
551 | if (c->flags & CF_SEND_DEAD) |
571 | strlcat (buf, " send_dead", sizeof buf); |
552 | strlcat (buf, " send_dead", sizeof buf); |
572 | else if (c->flags & CF_SEND_EOF) |
553 | else if (c->flags & CF_SEND_EOF) |
573 | strlcat (buf, " send_eof", sizeof buf); |
554 | strlcat (buf, " send_eof", sizeof buf); |
574 | } |
555 | } |
575 | stats_cb (buf, privdata); |
556 | stats_cb (buf, privdata); |
|
|
557 | |
|
|
558 | ++it; |
576 | } |
559 | } |
577 | } |
560 | } |
578 | |
561 | |
579 | /* |
562 | /* |
580 | * connection_write() |
563 | * connection_write() |
581 | * |
564 | * |
… | |
… | |
622 | void |
605 | void |
623 | connection_write_raw (connection_t *to, char *data) |
606 | connection_write_raw (connection_t *to, char *data) |
624 | { |
607 | { |
625 | sendq_add (to, data, strlen (data)); |
608 | sendq_add (to, data, strlen (data)); |
626 | } |
609 | } |
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 | */ |
|
|