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