]> jfr.im git - irc/rqf/shadowircd.git/blob - libcharybdis/select.c
[svn] - the new plan:
[irc/rqf/shadowircd.git] / libcharybdis / select.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * select.c: select() compatible network routines.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
8 * Copyright (C) 2002-2005 ircd-ratbox development team
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 * $Id: select.c 390 2005-12-07 18:46:56Z nenolod $
26 */
27
28 #include "config.h"
29
30 #include "libcharybdis.h"
31
32 #if HARD_FDLIMIT_ >= FD_SETSIZE
33 #error HARD_FDLIMIT_ must be less than FD_SETSIZE(try using poll instead of select)
34 #endif
35 /*
36 * Note that this is only a single list - multiple lists is kinda pointless
37 * under select because the list size is a function of the highest FD :-)
38 * -- adrian
39 */
40
41 fd_set select_readfds;
42 fd_set select_writefds;
43
44 /*
45 * You know, I'd rather have these local to comm_select but for some
46 * reason my gcc decides that I can't modify them at all..
47 * -- adrian
48 */
49 fd_set tmpreadfds;
50 fd_set tmpwritefds;
51
52 static void select_update_selectfds(int fd, short event, PF * handler);
53
54 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
55 /* Private functions */
56
57 /*
58 * set and clear entries in the select array ..
59 */
60 static void
61 select_update_selectfds(int fd, short event, PF * handler)
62 {
63 /* Update the read / write set */
64 if(event & COMM_SELECT_READ)
65 {
66 if(handler)
67 FD_SET(fd, &select_readfds);
68 else
69 FD_CLR(fd, &select_readfds);
70 }
71 if(event & COMM_SELECT_WRITE)
72 {
73 if(handler)
74 FD_SET(fd, &select_writefds);
75 else
76 FD_CLR(fd, &select_writefds);
77 }
78 }
79
80
81 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
82 /* Public functions */
83
84
85 /*
86 * init_netio
87 *
88 * This is a needed exported function which will be called to initialise
89 * the network loop code.
90 */
91 void
92 init_netio(void)
93 {
94 FD_ZERO(&select_readfds);
95 FD_ZERO(&select_writefds);
96 }
97
98 /*
99 * comm_setselect
100 *
101 * This is a needed exported function which will be called to register
102 * and deregister interest in a pending IO state for a given FD.
103 */
104 void
105 comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
106 void *client_data, time_t timeout)
107 {
108 fde_t *F = &fd_table[fd];
109 s_assert(fd >= 0);
110 s_assert(F->flags.open);
111
112 if(type & COMM_SELECT_READ)
113 {
114 F->read_handler = handler;
115 F->read_data = client_data;
116 select_update_selectfds(fd, COMM_SELECT_READ, handler);
117 }
118 if(type & COMM_SELECT_WRITE)
119 {
120 F->write_handler = handler;
121 F->write_data = client_data;
122 select_update_selectfds(fd, COMM_SELECT_WRITE, handler);
123 }
124 if(timeout)
125 F->timeout = CurrentTime + (timeout / 1000);
126 }
127
128 /*
129 * Check all connections for new connections and input data that is to be
130 * processed. Also check for connections with data queued and whether we can
131 * write it out.
132 */
133
134 /*
135 * comm_select
136 *
137 * Do IO events
138 */
139
140 int
141 comm_select(unsigned long delay)
142 {
143 int num;
144 int fd;
145 PF *hdl;
146 fde_t *F;
147 struct timeval to;
148
149 /* Copy over the read/write sets so we don't have to rebuild em */
150 memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set));
151 memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set));
152
153 for (;;)
154 {
155 to.tv_sec = 0;
156 to.tv_usec = delay * 1000;
157 num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
158 if(num >= 0)
159 break;
160 if(ignoreErrno(errno))
161 continue;
162 set_time();
163 /* error! */
164 return -1;
165 /* NOTREACHED */
166 }
167 set_time();
168
169 if(num == 0)
170 return 0;
171
172 /* XXX we *could* optimise by falling out after doing num fds ... */
173 for (fd = 0; fd < highest_fd + 1; fd++)
174 {
175 F = &fd_table[fd];
176
177 if(FD_ISSET(fd, &tmpreadfds))
178 {
179 hdl = F->read_handler;
180 F->read_handler = NULL;
181 if(hdl)
182 hdl(fd, F->read_data);
183 }
184
185 if(F->flags.open == 0)
186 continue; /* Read handler closed us..go on */
187
188 if(FD_ISSET(fd, &tmpwritefds))
189 {
190 hdl = F->write_handler;
191 F->write_handler = NULL;
192 if(hdl)
193 hdl(fd, F->write_data);
194 }
195
196 if(F->read_handler == NULL)
197 select_update_selectfds(fd, COMM_SELECT_READ, NULL);
198 if(F->write_handler == NULL)
199 select_update_selectfds(fd, COMM_SELECT_WRITE, NULL);
200 }
201 return 0;
202 }
203