File: | libsofia-sip-ua/su/su_select_port.c |
Warning: | line 600, 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 |