/[svn]/ircd-hybrid-7.2/src/s_bsd_kqueue.c
ViewVC logotype

Annotation of /ircd-hybrid-7.2/src/s_bsd_kqueue.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 842 - (hide annotations)
Fri Feb 9 21:27:48 2007 UTC (13 years, 7 months ago) by adx
File MIME type: text/x-chdr
File size: 4913 byte(s)
+ fixed off-by-one which turned out to cause large memory overwrites
+ this is an old one, very hard to catch: 1) FreeBSD system, 2) a lot
  of clients (preferably 10K+), 3) exiting/reading from/writing to
  128+ clients at a time, 4) ircd version where the bug shows up clearly
  (on 7.3 WHOWASHASH gets corrupted, and somewhat later we have a core:
  whowas_add_history -> dlinkDelete)
        
This applies to ALL versions of hybrid since 7.0, but is known to 
disclose most noticeably under 7.3


1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * s_bsd_kqueue.c: FreeBSD kqueue compatible network routines.
4     *
5     * Originally by Adrian Chadd <adrian@creative.net.au>
6     * Copyright (C) 2005 Hybrid Development Team
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21     * USA
22     *
23 knight 31 * $Id$
24 adx 30 */
25    
26     #include "stdinc.h"
27     #include <sys/event.h>
28     #include "fdlist.h"
29     #include "ircd.h"
30     #include "memory.h"
31     #include "s_bsd.h"
32     #include "s_log.h"
33    
34     #define KE_LENGTH 128
35    
36     /* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
37    
38     #ifndef EV_SET
39     #define EV_SET(kevp, a, b, c, d, e, f) do { \
40     (kevp)->ident = (a); \
41     (kevp)->filter = (b); \
42     (kevp)->flags = (c); \
43     (kevp)->fflags = (d); \
44     (kevp)->data = (e); \
45     (kevp)->udata = (f); \
46     } while(0)
47     #endif
48    
49     static fde_t kqfd;
50     static struct kevent kq_fdlist[KE_LENGTH]; /* kevent buffer */
51     static int kqoff; /* offset into the buffer */
52     void init_netio(void);
53    
54     /*
55     * init_netio
56     *
57     * This is a needed exported function which will be called to initialise
58     * the network loop code.
59     */
60     void
61     init_netio(void)
62     {
63     int fd;
64    
65     if ((fd = kqueue()) < 0)
66     {
67     ilog(L_CRIT, "init_netio: Couldn't open kqueue fd!");
68     exit(115); /* Whee! */
69     }
70    
71     fd_open(&kqfd, fd, 0, "kqueue() file descriptor");
72     }
73    
74     /*
75     * Write a single update to the kqueue list.
76     */
77     static void
78     kq_update_events(int fd, int filter, int what)
79     {
80     static struct timespec zero_timespec = {0, 0};
81     struct kevent *kep = kq_fdlist + kqoff;
82    
83     EV_SET(kep, (uintptr_t) fd, (short) filter, what, 0, 0, NULL);
84    
85 adx 842 if (++kqoff == KE_LENGTH)
86 adx 30 {
87     kevent(kqfd.fd, kq_fdlist, kqoff, NULL, 0, &zero_timespec);
88     kqoff = 0;
89     }
90     }
91    
92     /*
93     * comm_setselect
94     *
95     * This is a needed exported function which will be called to register
96     * and deregister interest in a pending IO state for a given FD.
97     */
98     void
99     comm_setselect(fde_t *F, unsigned int type, PF *handler,
100     void *client_data, time_t timeout)
101     {
102     int new_events, diff;
103    
104     if ((type & COMM_SELECT_READ))
105     {
106     F->read_handler = handler;
107     F->read_data = client_data;
108     }
109    
110     if ((type & COMM_SELECT_WRITE))
111     {
112     F->write_handler = handler;
113     F->write_data = client_data;
114     }
115    
116     new_events = (F->read_handler ? COMM_SELECT_READ : 0) |
117     (F->write_handler ? COMM_SELECT_WRITE : 0);
118    
119     if (timeout != 0)
120     F->timeout = CurrentTime + (timeout / 1000);
121    
122     diff = new_events ^ F->evcache;
123    
124     if ((diff & COMM_SELECT_READ))
125     kq_update_events(F->fd, EVFILT_READ,
126     (new_events & COMM_SELECT_READ) ? EV_ADD : EV_DELETE);
127     if ((diff & COMM_SELECT_WRITE))
128     kq_update_events(F->fd, EVFILT_WRITE,
129     (new_events & COMM_SELECT_WRITE) ? EV_ADD : EV_DELETE);
130    
131     F->evcache = new_events;
132     }
133    
134     /*
135     * comm_select
136     *
137     * Called to do the new-style IO, courtesy of squid (like most of this
138     * new IO code). This routine handles the stuff we've hidden in
139     * comm_setselect and fd_table[] and calls callbacks for IO ready
140     * events.
141     */
142     void
143     comm_select(void)
144     {
145     int num, i;
146     static struct kevent ke[KE_LENGTH];
147     struct timespec poll_time;
148     PF *hdl;
149     fde_t *F;
150    
151     /*
152     * remember we are doing NANOseconds here, not micro/milli. God knows
153     * why jlemon used a timespec, but hey, he wrote the interface, not I
154     * -- Adrian
155     */
156     poll_time.tv_sec = 0;
157     poll_time.tv_nsec = SELECT_DELAY * 1000000;
158     num = kevent(kqfd.fd, kq_fdlist, kqoff, ke, KE_LENGTH, &poll_time);
159     kqoff = 0;
160    
161     set_time();
162    
163     if (num < 0)
164     {
165     #ifdef HAVE_USLEEP
166     usleep(50000); /* avoid 99% CPU in comm_select */
167     #endif
168     return;
169     }
170    
171     for (i = 0; i < num; i++)
172     {
173     F = lookup_fd(ke[i].ident);
174     if (F == NULL || !F->flags.open || (ke[i].flags & EV_ERROR))
175     continue;
176    
177     if (ke[i].filter == EVFILT_READ)
178     if ((hdl = F->read_handler) != NULL)
179     {
180     F->read_handler = NULL;
181     hdl(F, F->read_data);
182     if (!F->flags.open)
183     continue;
184     }
185    
186     if (ke[i].filter == EVFILT_WRITE)
187     if ((hdl = F->write_handler) != NULL)
188     {
189     F->write_handler = NULL;
190     hdl(F, F->write_data);
191     if (!F->flags.open)
192     continue;
193     }
194    
195     comm_setselect(F, 0, NULL, NULL, 0);
196     }
197     }

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28