ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/listener.c
Revision: 1592
Committed: Sat Oct 27 21:02:32 2012 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/listener.c
File size: 11022 byte(s)
Log Message:
- Second time's the charm? Moving svnroot/ircd-hybrid-8 to
  svnroot/ircd-hybrid/trunk

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 adx 30 #include "listener.h"
28     #include "client.h"
29     #include "fdlist.h"
30     #include "irc_string.h"
31     #include "sprintf_irc.h"
32     #include "ircd.h"
33     #include "ircd_defs.h"
34     #include "s_bsd.h"
35     #include "numeric.h"
36 michael 1309 #include "conf.h"
37 adx 30 #include "send.h"
38     #include "memory.h"
39    
40     static PF accept_connection;
41    
42     static dlink_list ListenerPollList = { NULL, NULL, 0 };
43     static void close_listener(struct Listener *listener);
44    
45     static struct Listener *
46     make_listener(int port, struct irc_ssaddr *addr)
47     {
48     struct Listener *listener = MyMalloc(sizeof(struct Listener));
49    
50     listener->port = port;
51     memcpy(&listener->addr, addr, sizeof(struct irc_ssaddr));
52    
53     return listener;
54     }
55    
56     void
57     free_listener(struct Listener *listener)
58     {
59     assert(listener != NULL);
60    
61     dlinkDelete(&listener->listener_node, &ListenerPollList);
62     MyFree(listener);
63     }
64    
65     /*
66     * get_listener_name - return displayable listener name and port
67 michael 1242 * returns "host.foo.org/6667" for a given listener
68 adx 30 */
69     const char *
70 michael 1123 get_listener_name(const struct Listener *const listener)
71 adx 30 {
72     static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4];
73    
74 michael 1123 snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name,
75     listener->name, listener->port);
76 michael 900 return buf;
77 adx 30 }
78    
79     /* show_ports()
80     *
81     * inputs - pointer to client to show ports to
82     * output - none
83     * side effects - send port listing to a client
84     */
85     void
86     show_ports(struct Client *source_p)
87     {
88 michael 900 char buf[6];
89 adx 30 char *p = NULL;
90     dlink_node *ptr;
91    
92     DLINK_FOREACH(ptr, ListenerPollList.head)
93     {
94     const struct Listener *listener = ptr->data;
95     p = buf;
96    
97     if (listener->flags & LISTENER_HIDDEN) {
98 michael 1219 if (!HasUMode(source_p, UMODE_ADMIN))
99 adx 30 continue;
100     *p++ = 'H';
101     }
102    
103 michael 900 if (listener->flags & LISTENER_SERVER)
104     *p++ = 'S';
105 adx 30 if (listener->flags & LISTENER_SSL)
106     *p++ = 's';
107     *p = '\0';
108     sendto_one(source_p, form_str(RPL_STATSPLINE),
109     me.name, source_p->name, 'P', listener->port,
110 michael 1219 HasUMode(source_p, UMODE_ADMIN) ? listener->name : me.name,
111 adx 30 listener->ref_count, buf,
112     listener->active ? "active" : "disabled");
113     }
114     }
115    
116     /*
117     * inetport - create a listener socket in the AF_INET or AF_INET6 domain,
118     * bind it to the port given in 'port' and listen to it
119     * returns true (1) if successful false (0) on error.
120     *
121     * If the operating system has a define for SOMAXCONN, use it, otherwise
122     * use HYBRID_SOMAXCONN
123     */
124     #ifdef SOMAXCONN
125     #undef HYBRID_SOMAXCONN
126     #define HYBRID_SOMAXCONN SOMAXCONN
127     #endif
128    
129     static int
130     inetport(struct Listener *listener)
131     {
132     struct irc_ssaddr lsin;
133     socklen_t opt = 1;
134    
135 michael 1123 memset(&lsin, 0, sizeof(lsin));
136     memcpy(&lsin, &listener->addr, sizeof(lsin));
137    
138     getnameinfo((struct sockaddr *)&lsin, lsin.ss_len, listener->name,
139     sizeof(listener->name), NULL, 0, NI_NUMERICHOST);
140    
141 adx 30 /*
142     * At first, open a new socket
143     */
144     if (comm_open(&listener->fd, listener->addr.ss.ss_family, SOCK_STREAM, 0,
145     "Listener socket") == -1)
146     {
147     report_error(L_ALL, "opening listener socket %s:%s",
148     get_listener_name(listener), errno);
149     return 0;
150     }
151    
152     if (setsockopt(listener->fd.fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
153     {
154     report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s",
155     get_listener_name(listener), errno);
156     fd_close(&listener->fd);
157 michael 900 return 0;
158 adx 30 }
159    
160     /*
161     * Bind a port to listen for new connections if port is non-null,
162     * else assume it is already open and try get something from it.
163     */
164     lsin.ss_port = htons(listener->port);
165    
166     if (bind(listener->fd.fd, (struct sockaddr *)&lsin, lsin.ss_len))
167     {
168     report_error(L_ALL, "binding listener socket %s:%s",
169     get_listener_name(listener), errno);
170     fd_close(&listener->fd);
171 michael 900 return 0;
172 adx 30 }
173    
174     if (listen(listener->fd.fd, HYBRID_SOMAXCONN))
175     {
176     report_error(L_ALL, "listen failed for %s:%s",
177     get_listener_name(listener), errno);
178     fd_close(&listener->fd);
179 michael 900 return 0;
180 adx 30 }
181    
182     /* Listen completion events are READ events .. */
183    
184     accept_connection(&listener->fd, listener);
185     return 1;
186     }
187    
188     static struct Listener *
189     find_listener(int port, struct irc_ssaddr *addr)
190     {
191     dlink_node *ptr;
192     struct Listener *listener = NULL;
193     struct Listener *last_closed = NULL;
194    
195     DLINK_FOREACH(ptr, ListenerPollList.head)
196     {
197     listener = ptr->data;
198    
199     if ((port == listener->port) &&
200     (!memcmp(addr, &listener->addr, sizeof(struct irc_ssaddr))))
201     {
202     /* Try to return an open listener, otherwise reuse a closed one */
203     if (!listener->fd.flags.open)
204     last_closed = listener;
205     else
206     return (listener);
207     }
208     }
209    
210     return (last_closed);
211     }
212    
213     /*
214     * add_listener- create a new listener
215     * port - the port number to listen on
216     * vhost_ip - if non-null must contain a valid IP address string in
217     * the format "255.255.255.255"
218     */
219     void
220     add_listener(int port, const char *vhost_ip, unsigned int flags)
221     {
222     struct Listener *listener;
223     struct irc_ssaddr vaddr;
224     struct addrinfo hints, *res;
225     char portname[PORTNAMELEN + 1];
226     #ifdef IPV6
227     static short int pass = 0; /* if ipv6 and no address specified we need to
228     have two listeners; one for each protocol. */
229     #endif
230    
231     /*
232     * if no or invalid port in conf line, don't bother
233     */
234     if (!(port > 0 && port <= 0xFFFF))
235     return;
236    
237     memset(&vaddr, 0, sizeof(vaddr));
238    
239     /* Set up the hints structure */
240     memset(&hints, 0, sizeof(hints));
241     hints.ai_family = AF_UNSPEC;
242     hints.ai_socktype = SOCK_STREAM;
243     /* Get us ready for a bind() and don't bother doing dns lookup */
244     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
245    
246     #ifdef IPV6
247     if (ServerInfo.can_use_v6)
248     {
249 michael 1123 snprintf(portname, sizeof(portname), "%d", port);
250     getaddrinfo("::", portname, &hints, &res);
251 adx 30 vaddr.ss.ss_family = AF_INET6;
252     assert(res != NULL);
253    
254     memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
255     vaddr.ss_port = port;
256     vaddr.ss_len = res->ai_addrlen;
257 michael 1123 freeaddrinfo(res);
258 adx 30 }
259     else
260     #endif
261     {
262     struct sockaddr_in *v4 = (struct sockaddr_in*) &vaddr;
263     v4->sin_addr.s_addr = INADDR_ANY;
264     vaddr.ss.ss_family = AF_INET;
265     vaddr.ss_len = sizeof(struct sockaddr_in);
266     v4->sin_port = htons(port);
267     }
268    
269     snprintf(portname, PORTNAMELEN, "%d", port);
270    
271     if (vhost_ip)
272     {
273 michael 1123 if (getaddrinfo(vhost_ip, portname, &hints, &res))
274     return;
275 adx 30
276     assert(res != NULL);
277    
278     memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen);
279     vaddr.ss_port = port;
280     vaddr.ss_len = res->ai_addrlen;
281 michael 1123 freeaddrinfo(res);
282 adx 30 }
283     #ifdef IPV6
284     else if (pass == 0 && ServerInfo.can_use_v6)
285     {
286     /* add the ipv4 listener if we havent already */
287     pass = 1;
288     add_listener(port, "0.0.0.0", flags);
289     }
290     pass = 0;
291     #endif
292    
293     if ((listener = find_listener(port, &vaddr)))
294     {
295     listener->flags = flags;
296     if (listener->fd.flags.open)
297     return;
298     }
299     else
300     {
301     listener = make_listener(port, &vaddr);
302     dlinkAdd(listener, &listener->listener_node, &ListenerPollList);
303     listener->flags = flags;
304     }
305    
306     if (inetport(listener))
307     listener->active = 1;
308     else
309     close_listener(listener);
310     }
311    
312     /*
313     * close_listener - close a single listener
314     */
315     static void
316     close_listener(struct Listener *listener)
317     {
318     assert(listener != NULL);
319    
320     if (listener == NULL)
321     return;
322    
323     if (listener->fd.flags.open)
324     fd_close(&listener->fd);
325    
326     listener->active = 0;
327    
328     if (listener->ref_count)
329     return;
330    
331     free_listener(listener);
332     }
333    
334     /*
335     * close_listeners - close and free all listeners that are not being used
336     */
337     void
338     close_listeners(void)
339     {
340 michael 1123 dlink_node *ptr = NULL, *next_ptr = NULL;
341 adx 30
342     /* close all 'extra' listening ports we have */
343     DLINK_FOREACH_SAFE(ptr, next_ptr, ListenerPollList.head)
344     close_listener(ptr->data);
345     }
346    
347     #define TOOFAST_WARNING "ERROR :Trying to reconnect too fast.\r\n"
348     #define DLINE_WARNING "ERROR :You have been D-lined.\r\n"
349    
350     static void
351     accept_connection(fde_t *pfd, void *data)
352     {
353     static time_t last_oper_notice = 0;
354     struct irc_ssaddr addr;
355     int fd;
356     int pe;
357     struct Listener *listener = data;
358    
359     memset(&addr, 0, sizeof(addr));
360    
361     assert(listener != NULL);
362    
363     /* There may be many reasons for error return, but
364     * in otherwise correctly working environment the
365     * probable cause is running out of file descriptors
366     * (EMFILE, ENFILE or others?). The man pages for
367     * accept don't seem to list these as possible,
368     * although it's obvious that it may happen here.
369     * Thus no specific errors are tested at this
370     * point, just assume that connections cannot
371     * be accepted until some old is closed first.
372     */
373 michael 563 while ((fd = comm_accept(listener, &addr)) != -1)
374 adx 30 {
375     /*
376     * check for connection limit
377     */
378     if (number_fd > hard_fdlimit - 10)
379     {
380 michael 896 ++ServerStats.is_ref;
381 michael 563
382 adx 30 /*
383     * slow down the whining to opers bit
384     */
385     if ((last_oper_notice + 20) <= CurrentTime)
386     {
387     sendto_realops_flags(UMODE_ALL, L_ALL, "All connections in use. (%s)",
388     get_listener_name(listener));
389     last_oper_notice = CurrentTime;
390     }
391    
392     if (!(listener->flags & LISTENER_SSL))
393     send(fd, "ERROR :All connections in use\r\n", 32, 0);
394 michael 1001
395 adx 30 close(fd);
396     break; /* jump out and re-register a new io request */
397     }
398    
399 michael 563 /*
400     * Do an initial check we aren't connecting too fast or with too many
401     * from this IP...
402     */
403     if ((pe = conf_connect_allowed(&addr, addr.ss.ss_family)) != 0)
404 adx 30 {
405 michael 896 ++ServerStats.is_ref;
406    
407 adx 30 if (!(listener->flags & LISTENER_SSL))
408     switch (pe)
409     {
410     case BANNED_CLIENT:
411     send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
412     break;
413     case TOO_FAST:
414     send(fd, TOOFAST_WARNING, sizeof(TOOFAST_WARNING)-1, 0);
415     break;
416     }
417    
418     close(fd);
419     continue; /* drop the one and keep on clearing the queue */
420     }
421    
422 michael 896 ++ServerStats.is_ac;
423 michael 549 add_connection(listener, &addr, fd);
424 adx 30 }
425    
426     /* Re-register a new IO request for the next accept .. */
427     comm_setselect(&listener->fd, COMM_SELECT_READ, accept_connection,
428     listener, 0);
429     }

Properties

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