| File: | libsofia-sip-ua/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 |