1 /*
2  *  ircd-ratbox: A slightly useful ircd.
3  *  ports.c: Solaris ports 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-2004,2008 ircd-ratbox development team
9  *  Copyright (C) 2005 Edward Brocklesby.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
24  *  USA
25  *
26  *  $Id: ports.c 26286 2008-12-10 23:28:53Z androsyn $
27  */
28 
29 #include <libratbox_config.h>
30 #include <ratbox_lib.h>
31 #include <commio-int.h>
32 #include <event-int.h>
33 #if defined(HAVE_PORT_H) && (HAVE_PORT_CREATE)
34 
35 #include <port.h>
36 
37 #define PE_LENGTH	128
38 
39 static int pe;
40 static struct timespec zero_timespec;
41 
42 static port_event_t *pelst;	/* port buffer */
43 static int pemax;		/* max structs to buffer */
44 
45 int
rb_setup_fd_ports(rb_fde_t * F)46 rb_setup_fd_ports(rb_fde_t *F)
47 {
48 	return 0;
49 }
50 
51 /*
52  * rb_init_netio
53  *
54  * This is a needed exported function which will be called to initialise
55  * the network loop code.
56  */
57 
58 int
rb_init_netio_ports(void)59 rb_init_netio_ports(void)
60 {
61 	if((pe = port_create()) < 0)
62 	{
63 		return errno;
64 	}
65 	pemax = getdtablesize();
66 	pelst = rb_malloc(sizeof(port_event_t) * pemax);
67 	zero_timespec.tv_sec = 0;
68 	zero_timespec.tv_nsec = 0;
69 	rb_set_time();
70 	return 0;
71 }
72 
73 /*
74  * rb_setselect
75  *
76  * This is a needed exported function which will be called to register
77  * and deregister interest in a pending IO state for a given FD.
78  */
79 void
rb_setselect_ports(rb_fde_t * F,unsigned int type,PF * handler,void * client_data)80 rb_setselect_ports(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
81 {
82 	lrb_assert(IsFDOpen(F));
83 	int old_flags = F->pflags;
84 
85 	if(type & RB_SELECT_READ)
86 	{
87 		F->read_handler = handler;
88 		F->read_data = client_data;
89 	}
90 	if(type & RB_SELECT_WRITE)
91 	{
92 		F->write_handler = handler;
93 		F->write_data = client_data;
94 	}
95 	F->pflags = 0;
96 
97 	if(F->read_handler != NULL)
98 		F->pflags = POLLIN;
99 	if(F->write_handler != NULL)
100 		F->pflags |= POLLOUT;
101 
102 	if(old_flags == 0 && F->pflags == 0)
103 		return;
104 	else if(F->pflags <= 0)
105 	{
106 		port_dissociate(pe, PORT_SOURCE_FD, F->fd);
107 		return;
108 	}
109 
110 	port_associate(pe, PORT_SOURCE_FD, F->fd, F->pflags, F);
111 
112 }
113 
114 /*
115  * rb_select
116  *
117  * Called to do the new-style IO, courtesy of squid (like most of this
118  * new IO code). This routine handles the stuff we've hidden in
119  * rb_setselect and fd_table[] and calls callbacks for IO ready
120  * events.
121  */
122 
123 int
rb_select_ports(long delay)124 rb_select_ports(long delay)
125 {
126 	int i, fd;
127 	int nget = 1;
128 	struct timespec poll_time;
129 	struct timespec *p = NULL;
130 	struct ev_entry *ev;
131 
132 	if(delay >= 0)
133 	{
134 		poll_time.tv_sec = delay / 1000;
135 		poll_time.tv_nsec = (delay % 1000) * 1000000;
136 		p = &poll_time;
137 	}
138 
139 
140 	i = port_getn(pe, pelst, pemax, &nget, p);
141 	rb_set_time();
142 
143 	if(i == -1)
144 		return RB_OK;
145 
146 	for(i = 0; i < nget; i++)
147 	{
148 		if(pelst[i].portev_source == PORT_SOURCE_FD)
149 		{
150 			fd = pelst[i].portev_object;
151 			PF *hdl = NULL;
152 			rb_fde_t *F = pelst[i].portev_user;
153 			if((pelst[i].portev_events & (POLLIN | POLLHUP | POLLERR)) && (hdl = F->read_handler))
154 			{
155 				F->read_handler = NULL;
156 				hdl(F, F->read_data);
157 			}
158 			if((pelst[i].portev_events & (POLLOUT | POLLHUP | POLLERR)) && (hdl = F->write_handler))
159 			{
160 				F->write_handler = NULL;
161 				hdl(F, F->write_data);
162 			}
163 		} else if(pelst[i].portev_source == PORT_SOURCE_TIMER)
164 		{
165 			ev = (struct ev_entry *)pelst[i].portev_user;
166 			rb_run_event(ev);
167 		}
168 	}
169 	return RB_OK;
170 }
171 
172 int
rb_ports_supports_event(void)173 rb_ports_supports_event(void)
174 {
175 	return 1;
176 };
177 
178 void
rb_ports_init_event(void)179 rb_ports_init_event(void)
180 {
181 	return;
182 }
183 
184 int
rb_ports_sched_event(struct ev_entry * event,int when)185 rb_ports_sched_event(struct ev_entry *event, int when)
186 {
187 	timer_t *id;
188 	struct sigevent ev;
189 	port_notify_t not;
190 	struct itimerspec ts;
191 
192 	event->comm_ptr = rb_malloc(sizeof(timer_t));
193 	id = event->comm_ptr;
194 
195 	memset(&ev, 0, sizeof(ev));
196 	ev.sigev_notify = SIGEV_PORT;
197 	ev.sigev_value.sival_ptr = &not;
198 
199 	memset(&not, 0, sizeof(not));
200 	not.portnfy_port = pe;
201 	not.portnfy_user = event;
202 
203 	if(timer_create(CLOCK_REALTIME, &ev, id) < 0)
204 	{
205 		rb_lib_log("timer_create: %s\n", strerror(errno));
206 		return 0;
207 	}
208 
209 	memset(&ts, 0, sizeof(ts));
210 	ts.it_value.tv_sec = when;
211 	ts.it_value.tv_nsec = 0;
212 	if(event->frequency != 0)
213 		ts.it_interval = ts.it_value;
214 
215 	if(timer_settime(*id, 0, &ts, NULL) < 0)
216 	{
217 		rb_lib_log("timer_settime: %s\n", strerror(errno));
218 		return 0;
219 	}
220 	return 1;
221 }
222 
223 void
rb_ports_unsched_event(struct ev_entry * event)224 rb_ports_unsched_event(struct ev_entry *event)
225 {
226 	timer_delete(*((timer_t *) event->comm_ptr));
227 	rb_free(event->comm_ptr);
228 	event->comm_ptr = NULL;
229 }
230 #else /* ports not supported */
231 
232 int
rb_ports_supports_event(void)233 rb_ports_supports_event(void)
234 {
235 	errno = ENOSYS;
236 	return 0;
237 }
238 
239 void
rb_ports_init_event(void)240 rb_ports_init_event(void)
241 {
242 	return;
243 }
244 
245 int
rb_ports_sched_event(struct ev_entry * event,int when)246 rb_ports_sched_event(struct ev_entry *event, int when)
247 {
248 	errno = ENOSYS;
249 	return -1;
250 }
251 
252 void
rb_ports_unsched_event(struct ev_entry * event)253 rb_ports_unsched_event(struct ev_entry *event)
254 {
255 	return;
256 }
257 
258 int
rb_init_netio_ports(void)259 rb_init_netio_ports(void)
260 {
261 	return ENOSYS;
262 }
263 
264 void
rb_setselect_ports(rb_fde_t * F,unsigned int type,PF * handler,void * client_data)265 rb_setselect_ports(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
266 {
267 	errno = ENOSYS;
268 	return;
269 }
270 
271 int
rb_select_ports(long delay)272 rb_select_ports(long delay)
273 {
274 	errno = ENOSYS;
275 	return -1;
276 }
277 
278 int
rb_setup_fd_ports(rb_fde_t * F)279 rb_setup_fd_ports(rb_fde_t *F)
280 {
281 	errno = ENOSYS;
282 	return -1;
283 }
284 
285 
286 #endif
287