1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * s_bsd_poll.c: POSIX poll() 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
23 * USA
24 *
25 * $Id: poll.c 26092 2008-09-19 15:13:52Z androsyn $
26 */
27 #include <libratbox_config.h>
28 #include <ratbox_lib.h>
29 #include <commio-int.h>
30
31 #if defined(HAVE_POLL) && (HAVE_SYS_POLL_H)
32 #include <sys/poll.h>
33
34
35 /* I hate linux -- adrian */
36 #ifndef POLLRDNORM
37 #define POLLRDNORM POLLIN
38 #endif
39 #ifndef POLLWRNORM
40 #define POLLWRNORM POLLOUT
41 #endif
42
43 struct _pollfd_list
44 {
45 struct pollfd *pollfds;
46 int maxindex; /* highest FD number */
47 int allocated; /* number of pollfds allocated */
48 };
49
50 typedef struct _pollfd_list pollfd_list_t;
51
52 static pollfd_list_t pollfd_list;
53
54 int
rb_setup_fd_poll(rb_fde_t * F)55 rb_setup_fd_poll(rb_fde_t *F)
56 {
57 return 0;
58 }
59
60
61 /*
62 * rb_init_netio
63 *
64 * This is a needed exported function which will be called to initialise
65 * the network loop code.
66 */
67 int
rb_init_netio_poll(void)68 rb_init_netio_poll(void)
69 {
70 int fd;
71 pollfd_list.pollfds = rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd)));
72 pollfd_list.allocated = rb_getmaxconnect();
73 for(fd = 0; fd < rb_getmaxconnect(); fd++)
74 {
75 pollfd_list.pollfds[fd].fd = -1;
76 }
77 pollfd_list.maxindex = 0;
78 return 0;
79 }
80
81 static void
resize_pollarray(int fd)82 resize_pollarray(int fd)
83 {
84 if(rb_unlikely(fd >= pollfd_list.allocated))
85 {
86 int x, old_value = pollfd_list.allocated;
87 pollfd_list.allocated += 1024;
88 pollfd_list.pollfds =
89 rb_realloc(pollfd_list.pollfds,
90 pollfd_list.allocated * (sizeof(struct pollfd)));
91 memset(&pollfd_list.pollfds[old_value + 1], 0, sizeof(struct pollfd) * 1024);
92 for(x = old_value + 1; x < pollfd_list.allocated; x++)
93 {
94 pollfd_list.pollfds[x].fd = -1;
95 }
96 }
97 }
98
99 /*
100 * rb_setselect
101 *
102 * This is a needed exported function which will be called to register
103 * and deregister interest in a pending IO state for a given FD.
104 */
105 void
rb_setselect_poll(rb_fde_t * F,unsigned int type,PF * handler,void * client_data)106 rb_setselect_poll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
107 {
108 if(F == NULL)
109 return;
110
111 if(type & RB_SELECT_READ)
112 {
113 F->read_handler = handler;
114 F->read_data = client_data;
115 if(handler != NULL)
116 F->pflags |= POLLRDNORM;
117 else
118 F->pflags &= ~POLLRDNORM;
119 }
120 if(type & RB_SELECT_WRITE)
121 {
122 F->write_handler = handler;
123 F->write_data = client_data;
124 if(handler != NULL)
125 F->pflags |= POLLWRNORM;
126 else
127 F->pflags &= ~POLLWRNORM;
128 }
129 resize_pollarray(F->fd);
130
131 if(F->pflags <= 0)
132 {
133 pollfd_list.pollfds[F->fd].events = 0;
134 pollfd_list.pollfds[F->fd].fd = -1;
135 if(F->fd == pollfd_list.maxindex)
136 {
137 while(pollfd_list.maxindex >= 0
138 && pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
139 pollfd_list.maxindex--;
140 }
141 }
142 else
143 {
144 pollfd_list.pollfds[F->fd].events = F->pflags;
145 pollfd_list.pollfds[F->fd].fd = F->fd;
146 if(F->fd > pollfd_list.maxindex)
147 pollfd_list.maxindex = F->fd;
148 }
149
150 }
151
152 /* int rb_select(unsigned long delay)
153 * Input: The maximum time to delay.
154 * Output: Returns -1 on error, 0 on success.
155 * Side-effects: Deregisters future interest in IO and calls the handlers
156 * if an event occurs for an FD.
157 * Comments: Check all connections for new connections and input data
158 * that is to be processed. Also check for connections with data queued
159 * and whether we can write it out.
160 * Called to do the new-style IO, courtesy of squid (like most of this
161 * new IO code). This routine handles the stuff we've hidden in
162 * rb_setselect and fd_table[] and calls callbacks for IO ready
163 * events.
164 */
165
166 int
rb_select_poll(long delay)167 rb_select_poll(long delay)
168 {
169 int num;
170 int fd;
171 int ci;
172 PF *hdl;
173 void *data;
174 struct pollfd *pfd;
175 int revents;
176
177 num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay);
178 rb_set_time();
179 if(num < 0)
180 {
181 if(!rb_ignore_errno(errno))
182 return RB_OK;
183 else
184 return RB_ERROR;
185 }
186 if(num == 0)
187 return RB_OK;
188
189 /* XXX we *could* optimise by falling out after doing num fds ... */
190 for(ci = 0; ci < pollfd_list.maxindex + 1; ci++)
191 {
192 rb_fde_t *F;
193 pfd = &pollfd_list.pollfds[ci];
194
195 revents = pfd->revents;
196 fd = pfd->fd;
197 if(revents == 0 || fd == -1)
198 continue;
199
200 F = rb_find_fd(fd);
201 if(F == NULL)
202 continue;
203
204 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
205 {
206 hdl = F->read_handler;
207 data = F->read_data;
208 F->read_handler = NULL;
209 F->read_data = NULL;
210 if(hdl)
211 hdl(F, data);
212 }
213
214 if(IsFDOpen(F) && (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)))
215 {
216 hdl = F->write_handler;
217 data = F->write_data;
218 F->write_handler = NULL;
219 F->write_data = NULL;
220 if(hdl)
221 hdl(F, data);
222 }
223
224 if(F->read_handler == NULL)
225 rb_setselect_poll(F, RB_SELECT_READ, NULL, NULL);
226 if(F->write_handler == NULL)
227 rb_setselect_poll(F, RB_SELECT_WRITE, NULL, NULL);
228
229 }
230 return 0;
231 }
232
233 #else /* poll not supported */
234 int
rb_init_netio_poll(void)235 rb_init_netio_poll(void)
236 {
237 errno = ENOSYS;
238 return -1;
239 }
240
241 void
rb_setselect_poll(rb_fde_t * F,unsigned int type,PF * handler,void * client_data)242 rb_setselect_poll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
243 {
244 errno = ENOSYS;
245 return;
246 }
247
248 int
rb_select_poll(long delay)249 rb_select_poll(long delay)
250 {
251 errno = ENOSYS;
252 return -1;
253 }
254
255 int
rb_setup_fd_poll(rb_fde_t * F)256 rb_setup_fd_poll(rb_fde_t *F)
257 {
258 errno = ENOSYS;
259 return -1;
260 }
261
262 #endif
263