… | |
… | |
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.4 2007/08/28 17:08:12 pippijn Exp $"; |
8 | static 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 | |
14 | connection_vector connlist; |
15 | connection_vector connlist; |
15 | connection_t::callbacks connection_t::callback; |
16 | connection_t::callbacks connection_t::callback; |
16 | |
17 | |
17 | void |
18 | void |
… | |
… | |
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 | */ |
53 | connection_t * |
54 | connection_t * |
54 | connection_add (char const * const name, int fd, unsigned int flags, void (*read_handler) (connection_t *), void (*write_handler) (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 *)) |
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 | */ |
104 | connection_t * |
105 | connection_t * |
105 | connection_find (int fd) |
106 | connection_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 | */ |
136 | int |
137 | int |
137 | connection_count (void) |
138 | connection_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 | */ |
154 | void |
155 | void |
155 | connection_close (connection_t *cptr) |
156 | connection_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 | */ |
198 | static void |
199 | static void |
199 | empty_handler (connection_t *cptr) |
200 | empty_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 | */ |
217 | void |
218 | void |
218 | connection_close_soon (connection_t *cptr) |
219 | connection_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 | */ |
244 | void |
245 | void |
245 | connection_close_soon_children (connection_t *cptr) |
246 | connection_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 | */ |
279 | void |
278 | void |
280 | connection_close_all (void) |
279 | connection_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 | */ |
300 | connection_t * |
299 | 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 *)) |
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 *)) |
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 | */ |
391 | connection_t * |
390 | connection_t * |
392 | connection_open_listener_tcp (char const * const host, unsigned int port, void (*read_handler) (connection_t *)) |
391 | connection_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 | */ |
467 | connection_t * |
466 | connection_t * |
468 | connection_accept_tcp (connection_t *cptr, void (*read_handler) (connection_t *), void (*write_handler) (connection_t *)) |
467 | connection_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 | */ |
524 | void |
523 | void |
525 | connection_stats (void (*stats_cb) (char const * const , void *), void *privdata) |
524 | connection_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 | */ |
574 | void |
573 | void |
575 | connection_write (connection_t *to, char *format, ...) |
574 | connection_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 | */ |
605 | void |
604 | void |
606 | connection_write_raw (connection_t *to, char *data) |
605 | connection_t::write_raw (char *data) |
607 | { |
606 | { |
608 | sendq_add (to, data, strlen (data)); |
607 | sendq_add (this, data, strlen (data)); |
609 | } |
608 | } |