File: | su/su_select_port.c |
Warning: | line 598, column 11 Array access (via field 'fds_bits') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||||
2 | * This file is part of the Sofia-SIP package | |||||
3 | * | |||||
4 | * Copyright (C) 2005 Nokia Corporation. | |||||
5 | * | |||||
6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> | |||||
7 | * | |||||
8 | * This library is free software; you can redistribute it and/or | |||||
9 | * modify it under the terms of the GNU Lesser General Public License | |||||
10 | * as published by the Free Software Foundation; either version 2.1 of | |||||
11 | * the License, or (at your option) any later version. | |||||
12 | * | |||||
13 | * This library is distributed in the hope that it will be useful, but | |||||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
16 | * Lesser General Public License for more details. | |||||
17 | * | |||||
18 | * You should have received a copy of the GNU Lesser General Public | |||||
19 | * License along with this library; if not, write to the Free Software | |||||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||||
21 | * 02110-1301 USA | |||||
22 | * | |||||
23 | */ | |||||
24 | ||||||
25 | /**@ingroup su_wait | |||||
26 | * @CFILE su_select_port.c | |||||
27 | * | |||||
28 | * Port implementation using select(). | |||||
29 | * | |||||
30 | * @author Pekka Pessi <Pekka.Pessi@nokia.com> | |||||
31 | * @author Kai Vehmanen <kai.vehmanen@nokia.com> | |||||
32 | * | |||||
33 | * @date Created: Fri Jan 26 17:56:34 2007 ppessi | |||||
34 | */ | |||||
35 | ||||||
36 | #include "config.h" | |||||
37 | ||||||
38 | #if HAVE_SELECT1 | |||||
39 | ||||||
40 | #define su_port_ssu_select_port_s su_select_port_s | |||||
41 | ||||||
42 | #include "sofia-sip/su.h" | |||||
43 | #include "su_port.h" | |||||
44 | #include "sofia-sip/su_alloc.h" | |||||
45 | ||||||
46 | #include <stdlib.h> | |||||
47 | #include <assert.h> | |||||
48 | #include <stdarg.h> | |||||
49 | #include <stdio.h> | |||||
50 | #include <string.h> | |||||
51 | #include <limits.h> | |||||
52 | #include <errno(*__errno_location ()).h> | |||||
53 | ||||||
54 | #if HAVE_WIN32 | |||||
55 | #error winsock select() not supported yet | |||||
56 | #else | |||||
57 | #if HAVE_SYS_SELECT_H1 | |||||
58 | #include <sys/select.h> | |||||
59 | #elif HAVE_SYS_TIME_H1 | |||||
60 | #include <sys/time.h> | |||||
61 | #endif | |||||
62 | ||||||
63 | #include <sys/types.h> | |||||
64 | #include <unistd.h> | |||||
65 | ||||||
66 | #ifndef __NFDBITS(8 * (int) sizeof (__fd_mask)) | |||||
67 | #define __NFDBITS(8 * (int) sizeof (__fd_mask)) (8 * sizeof (long int)) | |||||
68 | #endif | |||||
69 | ||||||
70 | #undef FDSETSIZE | |||||
71 | /* Size of fd set in bytes */ | |||||
72 | #define FDSETSIZE(n)(((n) + (8 * (int) sizeof (__fd_mask)) - 1) / (8 * (int) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask)) / 8)) (((n) + __NFDBITS(8 * (int) sizeof (__fd_mask)) - 1) / __NFDBITS(8 * (int) sizeof (__fd_mask)) * (__NFDBITS(8 * (int) sizeof (__fd_mask)) / 8)) | |||||
73 | #endif | |||||
74 | ||||||
75 | /** Port based on select(). */ | |||||
76 | ||||||
77 | struct su_select_port_s { | |||||
78 | su_socket_port_t sup_base[1]; | |||||
79 | ||||||
80 | #define sup_homesup_base->sup_base->sup_base->sup_home sup_base->sup_base->sup_base->sup_homesup_base->sup_base->sup_base->sup_home | |||||
81 | ||||||
82 | /** epoll fd */ | |||||
83 | int sup_epoll; | |||||
84 | unsigned sup_multishot; /**< Multishot operation? */ | |||||
85 | ||||||
86 | unsigned sup_registers; /** Counter incremented by | |||||
87 | su_port_register() or | |||||
88 | su_port_unregister() | |||||
89 | */ | |||||
90 | int sup_n_registrations; | |||||
91 | int sup_max_index; /**< Indexes are equal or smaller than this */ | |||||
92 | int sup_size_indices; /**< Size of allocated index table */ | |||||
93 | ||||||
94 | /** Structure containing registration data */ | |||||
95 | struct su_select_register { | |||||
96 | struct su_select_register *ser_next; /* Next in free list */ | |||||
97 | su_wakeup_f ser_cb; | |||||
98 | su_wakeup_arg_t*ser_arg; | |||||
99 | su_root_t *ser_root; | |||||
100 | int ser_id; /** registration identifier */ | |||||
101 | su_wait_t ser_wait[1]; | |||||
102 | } **sup_indices; | |||||
103 | ||||||
104 | int sup_maxfd, sup_allocfd; | |||||
105 | ||||||
106 | fd_set *sup_readfds, *sup_readfds2; | |||||
107 | fd_set *sup_writefds, *sup_writefds2; | |||||
108 | }; | |||||
109 | ||||||
110 | static void su_select_port_decref(su_port_t *self, | |||||
111 | int blocking, | |||||
112 | char const *who); | |||||
113 | static int su_select_port_register(su_port_t *self, | |||||
114 | su_root_t *root, | |||||
115 | su_wait_t *wait, | |||||
116 | su_wakeup_f callback, | |||||
117 | su_wakeup_arg_t *arg, | |||||
118 | int priority); | |||||
119 | static int su_select_port_unregister(su_port_t *port, | |||||
120 | su_root_t *root, | |||||
121 | su_wait_t *wait, | |||||
122 | su_wakeup_f callback, | |||||
123 | su_wakeup_arg_t *arg); | |||||
124 | static int su_select_port_deregister(su_port_t *self, int i); | |||||
125 | static int su_select_port_unregister_all(su_port_t *self, su_root_t *root); | |||||
126 | static int su_select_port_eventmask(su_port_t *self, | |||||
127 | int index, | |||||
128 | int socket, | |||||
129 | int events); | |||||
130 | static int su_select_port_multishot(su_port_t *self, int multishot); | |||||
131 | static int su_select_port_wait_events(su_port_t *self, su_duration_t tout); | |||||
132 | static char const *su_select_port_name(su_port_t const *self); | |||||
133 | ||||||
134 | su_port_vtable_t const su_select_port_vtable[1] = | |||||
135 | {{ | |||||
136 | /* su_vtable_size: */ sizeof su_select_port_vtable, | |||||
137 | su_pthread_port_lock, | |||||
138 | su_pthread_port_unlock, | |||||
139 | su_base_port_incref, | |||||
140 | su_select_port_decref, | |||||
141 | su_base_port_gsource, | |||||
142 | su_base_port_send, | |||||
143 | su_select_port_register, | |||||
144 | su_select_port_unregister, | |||||
145 | su_select_port_deregister, | |||||
146 | su_select_port_unregister_all, | |||||
147 | su_select_port_eventmask, | |||||
148 | su_base_port_run, | |||||
149 | su_base_port_break, | |||||
150 | su_base_port_step, | |||||
151 | su_pthread_port_thread, | |||||
152 | su_base_port_add_prepoll, | |||||
153 | su_base_port_remove_prepoll, | |||||
154 | su_base_port_timers, | |||||
155 | su_select_port_multishot, | |||||
156 | su_select_port_wait_events, | |||||
157 | su_base_port_getmsgs, | |||||
158 | su_base_port_getmsgs_from, | |||||
159 | su_select_port_name, | |||||
160 | su_base_port_start_shared, | |||||
161 | su_pthread_port_wait, | |||||
162 | su_pthread_port_execute, | |||||
163 | su_base_port_deferrable, | |||||
164 | su_base_port_max_defer, | |||||
165 | su_socket_port_wakeup, | |||||
166 | su_base_port_is_running, | |||||
167 | }}; | |||||
168 | ||||||
169 | static char const *su_select_port_name(su_port_t const *self) | |||||
170 | { | |||||
171 | return "select"; | |||||
172 | } | |||||
173 | ||||||
174 | static void su_select_port_decref(su_port_t *self, int blocking, char const *who) | |||||
175 | { | |||||
176 | (void)su_base_port_decref(self, blocking, who); | |||||
177 | } | |||||
178 | ||||||
179 | static void su_select_port_deinit(void *arg) | |||||
180 | { | |||||
181 | su_port_t *self = arg; | |||||
182 | ||||||
183 | SU_DEBUG_9(("%s(%p) called\n", "su_select_port_deinit", (void *)self))((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 9 ? (_su_llog((su_log_global ), 9, "su_select_port.c", (const char *)__func__, 183, "%s(%p) called\n" , "su_select_port_deinit", (void *)self)) : (void)0); | |||||
184 | ||||||
185 | su_socket_port_deinit(self->sup_base); | |||||
186 | } | |||||
187 | ||||||
188 | /** @internal | |||||
189 | * | |||||
190 | * Register a #su_wait_t object. The wait object, a callback function and | |||||
191 | * an argument pointer is stored in the port object. The callback function | |||||
192 | * will be called when the wait object is signaled. | |||||
193 | * | |||||
194 | * Please note if identical wait objects are inserted, only first one is | |||||
195 | * ever signalled. | |||||
196 | * | |||||
197 | * @param self pointer to port | |||||
198 | * @param root pointer to root object | |||||
199 | * @param waits pointer to wait object | |||||
200 | * @param callback callback function pointer | |||||
201 | * @param arg argument given to callback function when it is invoked | |||||
202 | * @param priority relative priority of the wait object | |||||
203 | * (0 is normal, 1 important, 2 realtime) | |||||
204 | * | |||||
205 | * @return | |||||
206 | * Positive index of the wait object, | |||||
207 | * or -1 upon an error. | |||||
208 | */ | |||||
209 | int su_select_port_register(su_port_t *self, | |||||
210 | su_root_t *root, | |||||
211 | su_wait_t *wait, | |||||
212 | su_wakeup_f callback, | |||||
213 | su_wakeup_arg_t *arg, | |||||
214 | int priority) | |||||
215 | { | |||||
216 | int i, j, n; | |||||
217 | struct su_select_register *ser; | |||||
218 | struct su_select_register **indices = self->sup_indices; | |||||
219 | int allocfd = self->sup_allocfd; | |||||
220 | fd_set *readfds = self->sup_readfds, *readfds2 = self->sup_readfds2; | |||||
221 | fd_set *writefds = self->sup_writefds, *writefds2 = self->sup_writefds2; | |||||
222 | ||||||
223 | assert(su_port_own_thread(self))((void) sizeof ((su_port_own_thread(self)) ? 1 : 0), __extension__ ({ if (su_port_own_thread(self)) ; else __assert_fail ("su_port_own_thread(self)" , "su_select_port.c", 223, __extension__ __PRETTY_FUNCTION__) ; })); | |||||
224 | ||||||
225 | n = self->sup_size_indices; | |||||
226 | ||||||
227 | if (n >= SU_WAIT_MAX(0x7fffffff)) | |||||
228 | return su_seterrno(ENOMEM12); | |||||
229 | ||||||
230 | self->sup_registers++; | |||||
231 | ||||||
232 | if (wait->fd >= allocfd) | |||||
233 | allocfd += __NFDBITS(8 * (int) sizeof (__fd_mask)); /* long at a time */ | |||||
234 | ||||||
235 | if (allocfd >= self->sup_allocfd) { | |||||
236 | size_t bytes = FDSETSIZE(allocfd)(((allocfd) + (8 * (int) sizeof (__fd_mask)) - 1) / (8 * (int ) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask)) / 8)); | |||||
237 | size_t bytes0 = FDSETSIZE(self->sup_allocfd)(((self->sup_allocfd) + (8 * (int) sizeof (__fd_mask)) - 1 ) / (8 * (int) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask )) / 8)); | |||||
238 | /* (Re)allocate fd_sets */ | |||||
239 | ||||||
240 | readfds = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, readfds, bytes); | |||||
241 | if (readfds) self->sup_readfds = readfds; | |||||
242 | readfds2 = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, readfds2, bytes); | |||||
243 | if (readfds2) self->sup_readfds2 = readfds2; | |||||
244 | if (!readfds || !readfds2) | |||||
245 | return -1; | |||||
246 | ||||||
247 | writefds = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, writefds, bytes); | |||||
248 | if (writefds) self->sup_writefds = writefds; | |||||
249 | writefds2 = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, writefds2, bytes); | |||||
250 | if (writefds2) self->sup_writefds2 = writefds2; | |||||
251 | if (!writefds || !writefds2) | |||||
252 | return -1; | |||||
253 | ||||||
254 | memset((char *)readfds + bytes0, 0, bytes - bytes0); | |||||
255 | memset((char *)writefds + bytes0, 0, bytes - bytes0); | |||||
256 | ||||||
257 | self->sup_allocfd = allocfd; | |||||
258 | } | |||||
259 | ||||||
260 | ser = indices[0]; | |||||
261 | ||||||
262 | if (!ser) { | |||||
263 | su_home_t *h = su_port_home(self); | |||||
264 | ||||||
265 | i = self->sup_max_index, j = i == 0 ? 15 : i + 16; | |||||
266 | ||||||
267 | if (j >= self->sup_size_indices) { | |||||
268 | /* Reallocate index table */ | |||||
269 | n = n < 1024 ? 2 * n : n + 1024; | |||||
270 | indices = su_realloc(h, indices, n * sizeof(indices[0])); | |||||
271 | if (!indices) | |||||
272 | return -1; | |||||
273 | self->sup_indices = indices; | |||||
274 | self->sup_size_indices = n; | |||||
275 | } | |||||
276 | ||||||
277 | /* Allocate registrations */ | |||||
278 | ser = su_zalloc(h, (j - i) * (sizeof *ser)); | |||||
279 | if (!ser) | |||||
280 | return -1; | |||||
281 | ||||||
282 | indices[0] = ser; | |||||
283 | ||||||
284 | for (i++; i <= j; i++) { | |||||
285 | ser->ser_id = i; | |||||
286 | ser->ser_next = i < j ? ser + 1 : NULL((void*)0); | |||||
287 | indices[i] = ser++; | |||||
288 | } | |||||
289 | ||||||
290 | self->sup_max_index = j; | |||||
291 | ||||||
292 | ser = indices[0]; | |||||
293 | } | |||||
294 | ||||||
295 | i = ser->ser_id; | |||||
296 | ||||||
297 | indices[0] = ser->ser_next; | |||||
298 | ||||||
299 | ser->ser_next = NULL((void*)0); | |||||
300 | *ser->ser_wait = *wait; | |||||
301 | ser->ser_cb = callback; | |||||
302 | ser->ser_arg = arg; | |||||
303 | ser->ser_root = root; | |||||
304 | ||||||
305 | if (wait->events & SU_WAIT_IN(0x001)) | |||||
306 | FD_SET(wait->fd, readfds)((void) (((readfds)->fds_bits)[((wait->fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((wait-> fd) % (8 * (int) sizeof (__fd_mask))))))); | |||||
307 | if (wait->events & SU_WAIT_OUT(0x004)) | |||||
308 | FD_SET(wait->fd, writefds)((void) (((writefds)->fds_bits)[((wait->fd) / (8 * (int ) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((wait-> fd) % (8 * (int) sizeof (__fd_mask))))))); | |||||
309 | ||||||
310 | if (wait->fd >= self->sup_maxfd) | |||||
311 | self->sup_maxfd = wait->fd + 1; | |||||
312 | ||||||
313 | self->sup_n_registrations++; | |||||
314 | ||||||
315 | return i; /* return index */ | |||||
316 | } | |||||
317 | ||||||
318 | static void su_select_port_update_maxfd(su_port_t *self) | |||||
319 | { | |||||
320 | int i; | |||||
321 | su_socket_t maxfd = 0; | |||||
322 | ||||||
323 | for (i = 1; i <= self->sup_max_index; i++) { | |||||
324 | if (!self->sup_indices[i]->ser_cb) | |||||
325 | continue; | |||||
326 | if (maxfd <= self->sup_indices[i]->ser_wait->fd) | |||||
327 | maxfd = self->sup_indices[i]->ser_wait->fd + 1; | |||||
328 | } | |||||
329 | ||||||
330 | self->sup_maxfd = maxfd; | |||||
331 | } | |||||
332 | ||||||
333 | /** Deregister a su_wait_t object. */ | |||||
334 | static int su_select_port_deregister0(su_port_t *self, int i, int destroy_wait) | |||||
335 | { | |||||
336 | struct su_select_register **indices = self->sup_indices; | |||||
337 | struct su_select_register *ser; | |||||
338 | ||||||
339 | ser = self->sup_indices[i]; | |||||
340 | if (ser == NULL((void*)0) || ser->ser_cb == NULL((void*)0)) { | |||||
341 | su_seterrno(ENOENT2); | |||||
342 | return -1; | |||||
343 | } | |||||
344 | ||||||
345 | assert(ser->ser_id == i)((void) sizeof ((ser->ser_id == i) ? 1 : 0), __extension__ ({ if (ser->ser_id == i) ; else __assert_fail ("ser->ser_id == i" , "su_select_port.c", 345, __extension__ __PRETTY_FUNCTION__) ; })); | |||||
346 | ||||||
347 | FD_CLR(ser->ser_wait->fd, self->sup_readfds)((void) (((self->sup_readfds)->fds_bits)[((ser->ser_wait ->fd) / (8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask ) (1UL << ((ser->ser_wait->fd) % (8 * (int) sizeof (__fd_mask))))))); | |||||
348 | FD_CLR(ser->ser_wait->fd, self->sup_writefds)((void) (((self->sup_writefds)->fds_bits)[((ser->ser_wait ->fd) / (8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask ) (1UL << ((ser->ser_wait->fd) % (8 * (int) sizeof (__fd_mask))))))); | |||||
349 | ||||||
350 | if (ser->ser_wait->fd + 1 >= self->sup_maxfd) | |||||
351 | self->sup_maxfd = 0; | |||||
352 | ||||||
353 | memset(ser, 0, sizeof *ser); | |||||
354 | ser->ser_id = i; | |||||
355 | ser->ser_next = indices[0], indices[0] = ser; | |||||
356 | ||||||
357 | self->sup_n_registrations--; | |||||
358 | self->sup_registers++; | |||||
359 | ||||||
360 | return i; | |||||
361 | } | |||||
362 | ||||||
363 | ||||||
364 | /** Unregister a su_wait_t object. | |||||
365 | * | |||||
366 | * The function su_select_port_unregister() unregisters a su_wait_t object. | |||||
367 | * The registration defined by the wait object, the callback function and | |||||
368 | * the argument pointer are removed from the port object. | |||||
369 | * | |||||
370 | * @param self - pointer to port object | |||||
371 | * @param root - pointer to root object | |||||
372 | * @param wait - pointer to wait object | |||||
373 | * @param callback - callback function pointer (may be NULL) | |||||
374 | * @param arg - argument given to callback function when it is invoked | |||||
375 | * (may be NULL) | |||||
376 | * | |||||
377 | * @deprecated Use su_select_port_deregister() instead. | |||||
378 | * | |||||
379 | * @return Nonzero index of the wait object, or -1 upon an error. | |||||
380 | */ | |||||
381 | int su_select_port_unregister(su_port_t *self, | |||||
382 | su_root_t *root, | |||||
383 | su_wait_t *wait, | |||||
384 | su_wakeup_f callback, /* XXX - ignored */ | |||||
385 | su_wakeup_arg_t *arg) | |||||
386 | { | |||||
387 | int i, I; | |||||
388 | ||||||
389 | struct su_select_register *ser; | |||||
390 | ||||||
391 | assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "su_select_port.c", 391, __extension__ __PRETTY_FUNCTION__); })); | |||||
392 | assert(su_port_own_thread(self))((void) sizeof ((su_port_own_thread(self)) ? 1 : 0), __extension__ ({ if (su_port_own_thread(self)) ; else __assert_fail ("su_port_own_thread(self)" , "su_select_port.c", 392, __extension__ __PRETTY_FUNCTION__) ; })); | |||||
393 | ||||||
394 | I = self->sup_max_index; | |||||
395 | ||||||
396 | for (i = 1; i <= I; i++) { | |||||
397 | ser = self->sup_indices[i]; | |||||
398 | ||||||
399 | if (ser->ser_cb && | |||||
400 | arg == ser->ser_arg && | |||||
401 | SU_WAIT_CMP(wait[0], ser->ser_wait[0])(((wait[0]).fd - (ser->ser_wait[0]).fd) ? ((wait[0]).fd - ( ser->ser_wait[0]).fd) : ((wait[0]).events - (ser->ser_wait [0]).events)) == 0) | |||||
402 | return su_select_port_deregister0(self, ser->ser_id, 0); | |||||
403 | } | |||||
404 | ||||||
405 | su_seterrno(ENOENT2); | |||||
406 | ||||||
407 | return -1; | |||||
408 | } | |||||
409 | ||||||
410 | /** Deregister a su_wait_t object. | |||||
411 | * | |||||
412 | * Deregisters a registration by index. The wait object, a callback | |||||
413 | * function and a argument are removed from the port object. The wait | |||||
414 | * object is destroyed. | |||||
415 | * | |||||
416 | * @param self - pointer to port object | |||||
417 | * @param i - registration index | |||||
418 | * | |||||
419 | * @return Index of the wait object, or -1 upon an error. | |||||
420 | */ | |||||
421 | int su_select_port_deregister(su_port_t *self, int i) | |||||
422 | { | |||||
423 | struct su_select_register *ser; | |||||
424 | ||||||
425 | if (i <= 0 || i > self->sup_max_index) | |||||
426 | return su_seterrno(EBADF9); | |||||
427 | ||||||
428 | ser = self->sup_indices[i]; | |||||
429 | if (!ser->ser_cb) | |||||
430 | return su_seterrno(EBADF9); | |||||
431 | ||||||
432 | return su_select_port_deregister0(self, i, 1); | |||||
433 | } | |||||
434 | ||||||
435 | ||||||
436 | /** @internal | |||||
437 | * Unregister all su_wait_t objects of given su_root_t instance. | |||||
438 | * | |||||
439 | * The function su_select_port_unregister_all() unregisters all su_wait_t | |||||
440 | * objects associated with given root object. | |||||
441 | * | |||||
442 | * @param self - pointer to port object | |||||
443 | * @param root - pointer to root object | |||||
444 | * | |||||
445 | * @return Number of wait objects removed. | |||||
446 | */ | |||||
447 | int su_select_port_unregister_all(su_port_t *self, su_root_t *root) | |||||
448 | { | |||||
449 | int i, I, n; | |||||
450 | ||||||
451 | struct su_select_register *ser; | |||||
452 | ||||||
453 | assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "su_select_port.c", 453, __extension__ __PRETTY_FUNCTION__); })); assert(root)((void) sizeof ((root) ? 1 : 0), __extension__ ({ if (root) ; else __assert_fail ("root", "su_select_port.c", 453, __extension__ __PRETTY_FUNCTION__); })); | |||||
454 | assert(su_port_own_thread(self))((void) sizeof ((su_port_own_thread(self)) ? 1 : 0), __extension__ ({ if (su_port_own_thread(self)) ; else __assert_fail ("su_port_own_thread(self)" , "su_select_port.c", 454, __extension__ __PRETTY_FUNCTION__) ; })); | |||||
455 | ||||||
456 | I = self->sup_max_index; | |||||
457 | ||||||
458 | for (i = 1, n = 0; i <= I; i++) { | |||||
459 | ser = self->sup_indices[i]; | |||||
460 | if (ser->ser_root != root) | |||||
461 | continue; | |||||
462 | su_select_port_deregister0(self, ser->ser_id, 0); | |||||
463 | n++; | |||||
464 | } | |||||
465 | ||||||
466 | return n; | |||||
467 | } | |||||
468 | ||||||
469 | /**Set mask for a registered event. @internal | |||||
470 | * | |||||
471 | * The function su_select_port_eventmask() sets the mask describing events | |||||
472 | * that can signal the registered callback. | |||||
473 | * | |||||
474 | * @param port pointer to port object | |||||
475 | * @param index registration index | |||||
476 | * @param socket socket | |||||
477 | * @param events new event mask | |||||
478 | * | |||||
479 | * @retval 0 when successful, | |||||
480 | * @retval -1 upon an error. | |||||
481 | */ | |||||
482 | int su_select_port_eventmask(su_port_t *self, | |||||
483 | int index, | |||||
484 | int socket, int events) | |||||
485 | { | |||||
486 | struct su_select_register *ser; | |||||
487 | ||||||
488 | if (index <= 0 || index > self->sup_max_index) | |||||
489 | return su_seterrno(EBADF9); | |||||
490 | ||||||
491 | ser = self->sup_indices[index]; | |||||
492 | if (!ser->ser_cb) | |||||
493 | return su_seterrno(EBADF9); | |||||
494 | ||||||
495 | if (self->sup_maxfd == 0) | |||||
496 | su_select_port_update_maxfd(self); | |||||
497 | ||||||
498 | if (socket >= self->sup_maxfd) | |||||
499 | return su_seterrno(EBADF9); | |||||
500 | ||||||
501 | if (su_wait_mask(ser->ser_wait, socket, events) < 0) | |||||
502 | return -1; | |||||
503 | ||||||
504 | assert(socket < self->sup_maxfd)((void) sizeof ((socket < self->sup_maxfd) ? 1 : 0), __extension__ ({ if (socket < self->sup_maxfd) ; else __assert_fail ( "socket < self->sup_maxfd", "su_select_port.c", 504, __extension__ __PRETTY_FUNCTION__); })); | |||||
505 | ||||||
506 | if (events & SU_WAIT_IN(0x001)) | |||||
507 | FD_SET(socket, self->sup_readfds)((void) (((self->sup_readfds)->fds_bits)[((socket) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ( (socket) % (8 * (int) sizeof (__fd_mask))))))); | |||||
508 | else | |||||
509 | FD_CLR(socket, self->sup_readfds)((void) (((self->sup_readfds)->fds_bits)[((socket) / (8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask) (1UL << ((socket) % (8 * (int) sizeof (__fd_mask))))))); | |||||
510 | ||||||
511 | if (events & SU_WAIT_OUT(0x004)) | |||||
512 | FD_SET(socket, self->sup_writefds)((void) (((self->sup_writefds)->fds_bits)[((socket) / ( 8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((socket) % (8 * (int) sizeof (__fd_mask))))))); | |||||
513 | else | |||||
514 | FD_CLR(socket, self->sup_writefds)((void) (((self->sup_writefds)->fds_bits)[((socket) / ( 8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask) (1UL << ((socket) % (8 * (int) sizeof (__fd_mask))))))); | |||||
515 | ||||||
516 | return 0; | |||||
517 | } | |||||
518 | ||||||
519 | /** @internal Enable multishot mode. | |||||
520 | * | |||||
521 | * Enables, disables or queries the multishot mode for the port. The | |||||
522 | * multishot mode determines how the events are scheduled by port. If | |||||
523 | * multishot mode is enabled, port serves all the sockets that have received | |||||
524 | * network events. If it is disabled, only first socket event is served. | |||||
525 | * | |||||
526 | * @param self pointer to port object | |||||
527 | * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query) | |||||
528 | * | |||||
529 | * @retval 0 multishot mode is disabled | |||||
530 | * @retval 1 multishot mode is enabled | |||||
531 | * @retval -1 an error occurred | |||||
532 | */ | |||||
533 | static | |||||
534 | int su_select_port_multishot(su_port_t *self, int multishot) | |||||
535 | { | |||||
536 | if (multishot < 0) | |||||
537 | return self->sup_multishot; | |||||
538 | else if (multishot == 0 || multishot == 1) | |||||
539 | return self->sup_multishot = multishot; | |||||
540 | else | |||||
541 | return (errno(*__errno_location ()) = EINVAL22), -1; | |||||
542 | } | |||||
543 | ||||||
544 | ||||||
545 | /** @internal | |||||
546 | * Wait (poll()) for wait objects in port. | |||||
547 | * | |||||
548 | * @param self pointer to port | |||||
549 | * @param tout timeout in milliseconds | |||||
550 | * | |||||
551 | * @return number of events handled | |||||
552 | */ | |||||
553 | static | |||||
554 | int su_select_port_wait_events(su_port_t *self, su_duration_t tout) | |||||
555 | { | |||||
556 | int j, n, events = 0; | |||||
557 | unsigned version = self->sup_registers; | |||||
558 | size_t bytes; | |||||
559 | struct timeval tv; | |||||
560 | fd_set *rset = NULL((void*)0), *wset = NULL((void*)0); | |||||
| ||||||
561 | ||||||
562 | if (self->sup_maxfd == 0) | |||||
563 | su_select_port_update_maxfd(self); | |||||
564 | ||||||
565 | bytes = FDSETSIZE(self->sup_maxfd)(((self->sup_maxfd) + (8 * (int) sizeof (__fd_mask)) - 1) / (8 * (int) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask )) / 8)); | |||||
566 | ||||||
567 | if (bytes) { | |||||
568 | rset = memcpy(self->sup_readfds2, self->sup_readfds, bytes); | |||||
569 | wset = memcpy(self->sup_writefds2, self->sup_writefds, bytes); | |||||
570 | } | |||||
571 | ||||||
572 | tv.tv_sec = tout / 1000; | |||||
573 | tv.tv_usec = (tout % 1000) * 1000; | |||||
574 | ||||||
575 | n = select(self->sup_maxfd, rset, wset, NULL((void*)0), &tv); | |||||
576 | ||||||
577 | if (n < 0) { | |||||
578 | SU_DEBUG_0(("su_select_port_wait_events(%p): %s (%d)\n",((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 0 ? (_su_llog((su_log_global ), 0, "su_select_port.c", (const char *)__func__, 579, "su_select_port_wait_events(%p): %s (%d)\n" , (void *)self, su_strerror(su_errno()), su_errno())) : (void )0) | |||||
579 | (void *)self, su_strerror(su_errno()), su_errno()))((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 0 ? (_su_llog((su_log_global ), 0, "su_select_port.c", (const char *)__func__, 579, "su_select_port_wait_events(%p): %s (%d)\n" , (void *)self, su_strerror(su_errno()), su_errno())) : (void )0); | |||||
580 | return 0; | |||||
581 | } | |||||
582 | else if (n == 0) | |||||
583 | return 0; | |||||
584 | ||||||
585 | for (j = 1; j <= self->sup_max_index; j++) { | |||||
586 | struct su_select_register *ser; | |||||
587 | su_root_magic_t *magic; | |||||
588 | int fd; | |||||
589 | ||||||
590 | ser = self->sup_indices[j]; | |||||
591 | if (!ser->ser_cb) | |||||
592 | continue; | |||||
593 | ||||||
594 | fd = ser->ser_wait->fd; | |||||
595 | ser->ser_wait->revents = 0; | |||||
596 | ||||||
597 | if (ser->ser_wait->events & SU_WAIT_IN(0x001)) | |||||
598 | if (FD_ISSET(fd, rset)((((rset)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask) ))] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)) ser->ser_wait->revents |= SU_WAIT_IN(0x001), n--; | |||||
| ||||||
599 | if (ser->ser_wait->events & SU_WAIT_OUT(0x004)) | |||||
600 | if (FD_ISSET(fd, wset)((((wset)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask) ))] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)) ser->ser_wait->revents |= SU_WAIT_OUT(0x004), n--; | |||||
601 | ||||||
602 | if (ser->ser_wait->revents) { | |||||
603 | magic = ser->ser_root ? su_root_magic(ser->ser_root) : NULL((void*)0); | |||||
604 | ser->ser_cb(magic, ser->ser_wait, ser->ser_arg); | |||||
605 | events++; | |||||
606 | if (version != self->sup_registers) | |||||
607 | /* Callback function used su_register()/su_deregister() */ | |||||
608 | return events; | |||||
609 | if (!self->sup_multishot) | |||||
610 | /* Callback function used su_register()/su_deregister() */ | |||||
611 | return events; | |||||
612 | } | |||||
613 | ||||||
614 | if (n == 0) | |||||
615 | break; | |||||
616 | } | |||||
617 | ||||||
618 | assert(n == 0)((void) sizeof ((n == 0) ? 1 : 0), __extension__ ({ if (n == 0 ) ; else __assert_fail ("n == 0", "su_select_port.c", 618, __extension__ __PRETTY_FUNCTION__); })); | |||||
619 | ||||||
620 | return events; | |||||
621 | } | |||||
622 | ||||||
623 | /** Create a port using epoll() or poll(). | |||||
624 | */ | |||||
625 | su_port_t *su_select_port_create(void) | |||||
626 | { | |||||
627 | su_port_t *self; | |||||
628 | ||||||
629 | self = su_home_new(sizeof *self); | |||||
630 | if (!self) | |||||
631 | return NULL((void*)0); | |||||
632 | ||||||
633 | if (su_home_destructor(su_port_home(self), su_select_port_deinit) < 0 || | |||||
634 | !(self->sup_indices = | |||||
635 | su_zalloc(su_port_home(self), | |||||
636 | (sizeof self->sup_indices[0]) * | |||||
637 | (self->sup_size_indices = __NFDBITS(8 * (int) sizeof (__fd_mask)))))) { | |||||
638 | su_home_unref(su_port_home(self)); | |||||
639 | return NULL((void*)0); | |||||
640 | } | |||||
641 | ||||||
642 | self->sup_multishot = SU_ENABLE_MULTISHOT_POLL1; | |||||
643 | ||||||
644 | if (su_socket_port_init(self->sup_base, su_select_port_vtable) < 0) | |||||
645 | return su_home_unref(su_port_home(self)), NULL((void*)0); | |||||
646 | ||||||
647 | return self; | |||||
648 | } | |||||
649 | ||||||
650 | int su_select_clone_start(su_root_t *parent, | |||||
651 | su_clone_r return_clone, | |||||
652 | su_root_magic_t *magic, | |||||
653 | su_root_init_f init, | |||||
654 | su_root_deinit_f deinit) | |||||
655 | { | |||||
656 | return su_pthreaded_port_start(su_select_port_create, | |||||
657 | parent, return_clone, magic, init, deinit); | |||||
658 | } | |||||
659 | ||||||
660 | ||||||
661 | #endif |