ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/src/listener.c
Revision: 2408
Committed: Thu Jul 18 19:57:58 2013 UTC (10 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 13768 byte(s)
Log Message:
- ioengine changes as of 18JUL13

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * listener.c: Listens on a port.
4     *
5     * Copyright (C) 2002 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26 michael 1011 #include "list.h"
27 michael 2396 #include "ioengine.h"
28 adx 30 #include "listener.h"
29     #include "client.h"
30     #include "irc_string.h"
31     #include "ircd.h"
32     #include "ircd_defs.h"
33     #include "s_bsd.h"
34     #include "numeric.h"
35 michael 1309 #include "conf.h"
36 adx 30 #include "send.h"
37     #include "memory.h"
38    
39    
40 michael 2396 static dlink_list listener_list;
41 adx 30
42 michael 2408 static void accept_connection(struct Event *);
43 michael 2407 static void listener_close(struct Listener *);
44 michael 2396
45 adx 30 static struct Listener *
46 michael 2407 make_listener(const int port, const struct irc_ssaddr *addr)
47 adx 30 {
48     struct Listener *listener = MyMalloc(sizeof(struct Listener));
49    
50 michael 2407 listener->fd_v4 = -1;
51     listener->fd_v6 = -1;
52     listener->port = port;
53 adx 30 memcpy(&listener->addr, addr, sizeof(struct irc_ssaddr));
54    
55     return listener;
56     }
57    
58 michael 2396 /** Deallocate a Listener structure.
59     * @param[in] listener Listener to be freed.
60     */
61     static void
62 michael 2406 listener_free(struct Listener *listener)
63 adx 30 {
64 michael 2396 assert(listener);
65     assert(listener->active == 0);
66     assert(listener->ref_count == 0);
67 adx 30
68     MyFree(listener);
69     }
70    
71     /*
72     * get_listener_name - return displayable listener name and port
73 michael 1242 * returns "host.foo.org/6667" for a given listener
74 adx 30 */
75     const char *
76 michael 1123 get_listener_name(const struct Listener *const listener)
77 adx 30 {
78     static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];
79    
80 michael 1123 snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name,
81     listener->name, listener->port);
82 michael 900 return buf;
83 adx 30 }
84    
85     /* show_ports()
86     *
87     * inputs - pointer to client to show ports to
88     * output - none
89     * side effects - send port listing to a client
90     */
91     void
92     show_ports(struct Client *source_p)
93     {
94 michael 900 char buf[6];
95 adx 30 char *p = NULL;
96     dlink_node *ptr;
97    
98 michael 2396 DLINK_FOREACH(ptr, listener_list.head)
99 adx 30 {
100     const struct Listener *listener = ptr->data;
101     p = buf;
102    
103 michael 2396 if (listener->flags & LISTENER_HIDDEN)
104     {
105 michael 1219 if (!HasUMode(source_p, UMODE_ADMIN))
106 adx 30 continue;
107     *p++ = 'H';
108     }
109    
110 michael 900 if (listener->flags & LISTENER_SERVER)
111     *p++ = 'S';
112 adx 30 if (listener->flags & LISTENER_SSL)
113     *p++ = 's';
114     *p = '\0';
115 michael 1834 sendto_one(source_p, form_str(RPL_STATSPLINE),
116 adx 30 me.name, source_p->name, 'P', listener->port,
117 michael 1219 HasUMode(source_p, UMODE_ADMIN) ? listener->name : me.name,
118 adx 30 listener->ref_count, buf,
119     listener->active ? "active" : "disabled");
120     }
121     }
122    
123     /*
124     * inetport - create a listener socket in the AF_INET or AF_INET6 domain,
125     * bind it to the port given in 'port' and listen to it
126     * returns true (1) if successful false (0) on error.
127     *
128     * If the operating system has a define for SOMAXCONN, use it, otherwise
129     * use HYBRID_SOMAXCONN
130     */
131     #ifdef SOMAXCONN
132     #define HYBRID_SOMAXCONN SOMAXCONN
133 michael 2396 #else
134     /** Maximum length of socket connection backlog. */
135     #define HYBRID_SOMAXCONN 64
136 adx 30 #endif
137    
138 michael 2408 /** Set or update socket options for \a listener.
139     * @param[in] listener Listener to determine socket option values.
140     * @param[in] fd File descriptor being updated.
141     * @return Non-zero on success, zero on failure.
142     */
143     static int
144     set_listener_options(struct Listener *listener, int fd)
145     {
146     /*
147     * Set the buffer sizes for the listener. Accepted connections
148     * inherit the accepting sockets settings for SO_RCVBUF S_SNDBUF
149     * The window size is set during the SYN ACK so setting it anywhere
150     * else has no effect whatsoever on the connection.
151     * NOTE: this must be set before listen is called
152     */
153     if (!os_set_sockbufs(fd, CLIENT_TCP_WINDOW, /* XXX */
154     CLIENT_TCP_WINDOW))
155     {
156     report_error(L_ALL, SETBUFS_ERROR_MSG, get_listener_name(listener), errno);
157     close(fd);
158     return 0;
159     }
160    
161     #ifdef NOTYET
162     /*
163     * Set the TOS bits - this is nonfatal if it doesn't stick.
164     */
165     if (!os_set_tos(fd,feature_int(is_server ? FEAT_TOS_SERVER : FEAT_TOS_CLIENT)))
166     report_error(L_ALL, TOS_ERROR_MSG, get_listener_name(listener), errno);
167     #endif
168     return 1;
169     }
170    
171 michael 2396 /** Open listening socket for \a listener.
172     * @param[in,out] listener Listener to make a socket for.
173     * @return Non-zero on success, zero on failure.
174     */
175 adx 30 static int
176 michael 2407 inetport(struct Listener *listener, int family)
177 adx 30 {
178 michael 2408 struct Socket *sock = NULL;
179 michael 2392 int fd = 0;
180 adx 30 struct irc_ssaddr lsin;
181     socklen_t opt = 1;
182    
183 michael 1123 memset(&lsin, 0, sizeof(lsin));
184     memcpy(&lsin, &listener->addr, sizeof(lsin));
185    
186     getnameinfo((struct sockaddr *)&lsin, lsin.ss_len, listener->name,
187     sizeof(listener->name), NULL, 0, NI_NUMERICHOST);
188    
189 adx 30 /*
190     * At first, open a new socket
191     */
192 michael 2407 if ((fd = os_socket(family, SOCK_STREAM)) == -1)
193 adx 30 {
194 michael 2407 report_error(L_ALL, SOCKET_ERROR_MSG, get_listener_name(listener), errno);
195 michael 2408 return -1;
196 adx 30 }
197    
198 michael 2407 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
199 adx 30 {
200 michael 2407 report_error(L_ALL, REUSEADDR_ERROR_MSG, get_listener_name(listener), errno);
201 michael 2392 close(fd);
202 michael 2408 return -1;
203 adx 30 }
204    
205     /*
206     * Bind a port to listen for new connections if port is non-null,
207     * else assume it is already open and try get something from it.
208     */
209     lsin.ss_port = htons(listener->port);
210    
211 michael 2407 if (bind(fd, (struct sockaddr *)&lsin, lsin.ss_len))
212 adx 30 {
213 michael 2407 report_error(L_ALL, BIND_ERROR_MSG, get_listener_name(listener), errno);
214 michael 2392 close(fd);
215 michael 2408 return -1;
216 adx 30 }
217    
218 michael 2392 if (!os_set_listen(fd, HYBRID_SOMAXCONN))
219 adx 30 {
220 michael 2407 report_error(L_ALL, LISTEN_ERROR_MSG, get_listener_name(listener), errno);
221 michael 2392 close(fd);
222 michael 2408 return -1;
223 adx 30 }
224    
225 michael 2408 if (!set_listener_options(listener, fd))
226     return -1;
227    
228     sock = (family == AF_INET) ? &listener->socket_v4 : &listener->socket_v6;
229    
230     if (!socket_add(sock, accept_connection, listener, SS_LISTENING, 0, fd))
231 michael 2392 {
232     /* Error should already have been reported to the logs */
233     close(fd);
234 michael 2408 return -1;
235 michael 2392 }
236 adx 30
237 michael 2408 return fd;
238 adx 30 }
239    
240     static struct Listener *
241 michael 2407 listener_find(const int port, const struct irc_ssaddr *addr)
242 adx 30 {
243 michael 2396 dlink_node *ptr = NULL;
244 adx 30
245 michael 2407 DLINK_FOREACH(ptr, listener_list.head)
246 adx 30 {
247 michael 2396 struct Listener *listener = ptr->data;
248 adx 30
249     if ((port == listener->port) &&
250     (!memcmp(addr, &listener->addr, sizeof(struct irc_ssaddr))))
251 michael 2396 return listener;
252 adx 30 }
253    
254 michael 2396 return NULL;
255 adx 30 }
256    
257     /*
258     * add_listener- create a new listener
259     * port - the port number to listen on
260     * vhost_ip - if non-null must contain a valid IP address string in
261     * the format "255.255.255.255"
262     */
263     void
264     add_listener(int port, const char *vhost_ip, unsigned int flags)
265     {
266 michael 2408 int okay = 0;
267     int new_listener = 0;
268     int fd;
269 adx 30 struct Listener *listener;
270     struct irc_ssaddr vaddr;
271     struct addrinfo hints, *res;
272     char portname[PORTNAMELEN + 1];
273 michael 2408 const struct sockaddr_in *v4;
274     const struct sockaddr_in6 *v6;
275 adx 30
276     /*
277 michael 2396 * If no or invalid port in conf line, don't bother
278 adx 30 */
279     if (!(port > 0 && port <= 0xFFFF))
280     return;
281    
282     memset(&vaddr, 0, sizeof(vaddr));
283 michael 2396 memset(&hints, 0, sizeof(hints));
284 adx 30
285     hints.ai_family = AF_UNSPEC;
286     hints.ai_socktype = SOCK_STREAM;
287     /* Get us ready for a bind() and don't bother doing dns lookup */
288     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
289    
290 michael 2396 snprintf(portname, sizeof(portname), "%d", port);
291 adx 30
292 michael 1669 if (!EmptyString(vhost_ip))
293 adx 30 {
294 michael 1123 if (getaddrinfo(vhost_ip, portname, &hints, &res))
295     return;
296 adx 30
297     assert(res != NULL);
298    
299 michael 2396 memcpy((struct sockaddr *)&vaddr, res->ai_addr, res->ai_addrlen);
300 adx 30 vaddr.ss_port = port;
301     vaddr.ss_len = res->ai_addrlen;
302 michael 1123 freeaddrinfo(res);
303 adx 30 }
304    
305 michael 2408 if (!(listener = listener_find(port, &vaddr)))
306 adx 30 {
307 michael 2408 new_listener = 1;
308     listener = make_listener(port, &vaddr);
309 adx 30 }
310 michael 2396
311 michael 2408 listener->active = 1;
312     listener->flags = flags;
313 adx 30
314 michael 2408 v4 = (const struct sockaddr_in *)&vaddr;
315     v6 = (const struct sockaddr_in6 *)&vaddr;
316 michael 2396
317 michael 2408 if ((listener->flags & LISTENER_IPV6) &&
318     (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr) || vaddr.ss.ss_family == AF_INET6))
319     {
320     if (listener->fd_v6 >= 0)
321     {
322     set_listener_options(listener, listener->fd_v6);
323     okay = 1;
324     }
325     else if ((fd = inetport(listener, AF_INET6)) >= 0)
326     {
327     listener->fd_v6 = fd;
328     okay = 1;
329     }
330     }
331     else if (listener->fd_v6 > -1)
332     {
333     close(listener->fd_v6);
334     socket_del(&listener->socket_v6);
335     listener->fd_v6 = -1;
336     }
337    
338     if ((listener->flags, LISTENER_IPV4) &&
339     (v4->sin_addr.s_addr == INADDR_NONE || vaddr.ss.ss_family == AF_INET))
340     {
341     if (listener->fd_v4 >= 0)
342     {
343     set_listener_options(listener, listener->fd_v4);
344     okay = 1;
345     }
346     else if ((fd = inetport(listener, AF_INET)) >= 0)
347     {
348     listener->fd_v4 = fd;
349     okay = 1;
350     }
351     }
352     else if (listener->fd_v4 > -1)
353     {
354     close(listener->fd_v4);
355     socket_del(&listener->socket_v4);
356     listener->fd_v4 = -1;
357     }
358    
359     if (!okay)
360     listener_free(listener);
361     else if (new_listener)
362     dlinkAdd(listener, &listener->node, &listener_list);
363 adx 30 }
364    
365 michael 2396 /** Mark all listeners as closing (inactive).
366     * This is done so unused listeners are closed after a rehash.
367 adx 30 */
368 michael 2396 void
369     listener_mark_closing(void)
370     {
371     dlink_node *ptr = NULL;
372    
373     DLINK_FOREACH(ptr, listener_list.head)
374 michael 2406 ((struct Listener *)ptr->data)->active = 0;
375 michael 2396 }
376    
377    
378     /** Close a single listener.
379     * @param[in] listener Listener to close.
380     */
381 adx 30 static void
382 michael 2406 listener_close(struct Listener *listener)
383 adx 30 {
384 michael 2396 assert(listener);
385     assert(listener->active == 0);
386     assert(listener->ref_count == 0);
387 adx 30
388 michael 2396 /*
389 michael 2408 * Remove from listener list
390 michael 2396 */
391     dlinkDelete(&listener->node, &listener_list);
392 adx 30
393 michael 2407 if (listener->fd_v4 > -1)
394     {
395     close(listener->fd_v4);
396     socket_del(&listener->socket_v4);
397     listener->fd_v4 = -1;
398     }
399 adx 30
400 michael 2407 if (listener->fd_v6 > -1)
401 michael 2396 {
402 michael 2407 close(listener->fd_v6);
403     socket_del(&listener->socket_v6);
404     listener->fd_v6 = -1;
405 michael 2396 }
406 adx 30
407 michael 2396 listener_free(listener);
408     }
409 adx 30
410 michael 2396 /** Close all inactive listeners. */
411     void
412     listener_close_marked(void)
413     {
414     dlink_node *ptr = NULL, *ptr_next = NULL;
415    
416     /*
417 michael 2408 * Close all 'extra' listening ports we have
418 michael 2396 */
419     DLINK_FOREACH_SAFE(ptr, ptr_next, listener_list.head)
420     {
421 michael 2406 struct Listener *listener = ptr->data;
422 michael 2396
423     if (!listener->active && !listener->ref_count)
424     listener_close(listener);
425     }
426 adx 30 }
427    
428 michael 2396 /** Dereference the listener previously associated with a client.
429     * @param[in] listener Listener to dereference.
430 adx 30 */
431 michael 2396 void
432 michael 2406 listener_release(struct Listener *listener)
433 adx 30 {
434 michael 2396 assert(listener);
435     assert(listener->ref_count > 0);
436 adx 30
437 michael 2396 if (--listener->ref_count == 0 && !listener->active)
438     listener_close(listener);
439 adx 30 }
440    
441 michael 2396
442 adx 30 #define TOOFAST_WARNING "ERROR :Trying to reconnect too fast.\r\n"
443     #define DLINE_WARNING "ERROR :You have been D-lined.\r\n"
444    
445     static void
446 michael 2392 accept_connection(struct Event *ev)
447 adx 30 {
448     static time_t last_oper_notice = 0;
449     struct irc_ssaddr addr;
450     int fd;
451     int pe;
452 michael 2392 struct Listener *listener = s_data(ev_socket(ev));
453 adx 30
454 michael 2392 assert(ev_socket(ev));
455     assert(s_data(ev_socket(ev)));
456    
457 adx 30 memset(&addr, 0, sizeof(addr));
458    
459 michael 2392 if (ev_type(ev) == ET_DESTROY) /* Being destroyed */
460     return;
461    
462     assert(ev_type(ev) == ET_ACCEPT || ev_type(ev) == ET_ERROR);
463    
464     /*
465     * There may be many reasons for error return, but
466 adx 30 * in otherwise correctly working environment the
467     * probable cause is running out of file descriptors
468     * (EMFILE, ENFILE or others?). The man pages for
469     * accept don't seem to list these as possible,
470     * although it's obvious that it may happen here.
471     * Thus no specific errors are tested at this
472     * point, just assume that connections cannot
473     * be accepted until some old is closed first.
474 michael 2392 *
475     * This piece of code implements multi-accept, based
476     * on the idea that poll/select can only be efficient,
477     * if we succeed in handling all available events,
478     * i.e. accept all pending connections.
479     *
480     * http://www.hpl.hp.com/techreports/2000/HPL-2000-174.html
481 adx 30 */
482 michael 2392 while (1)
483 adx 30 {
484 michael 2392 if ((fd = os_accept(s_fd(ev_socket(ev)), &addr)) == -1)
485     {
486     if (errno == EAGAIN ||
487     #ifdef EWOULDBLOCK
488     errno == EWOULDBLOCK)
489     #endif
490     return;
491     return;
492     }
493 michael 2407 #ifdef XXX___
494 adx 30 /*
495     * check for connection limit
496     */
497     if (number_fd > hard_fdlimit - 10)
498     {
499 michael 896 ++ServerStats.is_ref;
500 michael 563
501 adx 30 /*
502     * slow down the whining to opers bit
503     */
504     if ((last_oper_notice + 20) <= CurrentTime)
505     {
506 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
507     "All connections in use. (%s)",
508 adx 30 get_listener_name(listener));
509     last_oper_notice = CurrentTime;
510     }
511    
512     if (!(listener->flags & LISTENER_SSL))
513     send(fd, "ERROR :All connections in use\r\n", 32, 0);
514 michael 1001
515 adx 30 close(fd);
516 michael 2392 return;
517 adx 30 }
518 michael 2407 #endif
519 michael 563 /*
520     * Do an initial check we aren't connecting too fast or with too many
521     * from this IP...
522     */
523     if ((pe = conf_connect_allowed(&addr, addr.ss.ss_family)) != 0)
524 adx 30 {
525 michael 896 ++ServerStats.is_ref;
526    
527 adx 30 if (!(listener->flags & LISTENER_SSL))
528     switch (pe)
529     {
530     case BANNED_CLIENT:
531     send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
532     break;
533     case TOO_FAST:
534     send(fd, TOOFAST_WARNING, sizeof(TOOFAST_WARNING)-1, 0);
535     break;
536     }
537    
538     close(fd);
539     continue; /* drop the one and keep on clearing the queue */
540     }
541    
542 michael 896 ++ServerStats.is_ac;
543 michael 549 add_connection(listener, &addr, fd);
544 adx 30 }
545     }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision