/** * @internal noPoll select implementation for the "add to" on fd set * operation. * * @param fds The socket descriptor to be added. * * @param fd_set The fd set where the socket descriptor will be added. */ nopoll_bool nopoll_io_wait_select_add_to (int fds, noPollCtx * ctx, noPollConn * conn, noPollPtr __fd_set) { noPollSelect * select = (noPollSelect *) __fd_set; if (fds < 0) { nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "received a non valid socket (%d), unable to add to the set", fds); return nopoll_false; } /* set the value */ FD_SET (fds, &(select->set)); /* update length */ select->length++; /* update max fds */ if (fds > select->max_fds) select->max_fds = fds; return nopoll_true; }
/** * @internal Function used to detected which connections has something * interesting to be notified. * */ nopoll_bool nopoll_loop_process (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) { int * conn_changed = (int *) user_data; /* check if the connection have something to notify */ if (ctx->io_engine->isset (ctx, conn->session, ctx->io_engine->io_object)) { /* call to notify action according to role */ switch (conn->role) { case NOPOLL_ROLE_CLIENT: case NOPOLL_ROLE_LISTENER: /* received data, notify */ nopoll_loop_process_data (ctx, conn); break; case NOPOLL_ROLE_MAIN_LISTENER: /* call to handle */ nopoll_conn_accept (ctx, conn); break; default: nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found connection with unknown role, closing and dropping"); nopoll_conn_shutdown (conn); break; } /* reduce connection changed */ (*conn_changed)--; } /* end if */ return (*conn_changed) == 0; }
/** * @internal Function used to init internal io wait mechanism... * * @param ctx The noPoll context to be initialized if it wasn't */ void nopoll_loop_init (noPollCtx * ctx) { if (ctx == NULL) return; /* grab the mutex for the following check */ if (ctx->io_engine == NULL) { ctx->io_engine = nopoll_io_get_engine (ctx, NOPOLL_IO_ENGINE_DEFAULT); if (ctx->io_engine == NULL) { nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to create IO wait engine, unable to implement wait call"); return; } } /* end if */ /* release the mutex */ return; }
/** * @internal Function used by nopoll_loop_wait to register all * connections into the io waiting object. */ nopoll_bool nopoll_loop_register (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) { /* do not add connections that aren't working */ if (! nopoll_conn_is_ok (conn)) { /* remove this connection from registry */ nopoll_ctx_unregister_conn (ctx, conn); return nopoll_false; /* keep foreach, don't stop */ } /* register the connection socket */ /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding socket id: %d", conn->session);*/ if (! ctx->io_engine->addto (conn->session, ctx, conn, ctx->io_engine->io_object)) { /* remove this connection from registry */ nopoll_ctx_unregister_conn (ctx, conn); nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Failed to add socket %d to the watching set", conn->session); } return nopoll_false; /* keep foreach, don't stop */ }
/** * @brief Allows to implement a wait over all connections registered * under the provided context during the provided timeout until * something is detected meaningful to the user, calling to the action * handler defined, optionally receving the user data pointer. * * @param ctx The context object where the wait will be implemented. * * @param timeout The timeout to wait for changes. If no changes * happens, the function returns. The function will block the caller * until a call to \ref nopoll_loop_stop is done in the case timeout * passed is 0. * * @return The function returns 0 when finished or -2 in the case ctx * is NULL or timeout is negative. */ int nopoll_loop_wait (noPollCtx * ctx, long timeout) { struct timeval start; struct timeval stop; struct timeval diff; long ellapsed; int wait_status; nopoll_return_val_if_fail (ctx, ctx, -2); nopoll_return_val_if_fail (ctx, timeout >= 0, -2); /* call to init io engine */ nopoll_loop_init (ctx); /* get as reference current time */ if (timeout > 0) #if defined(NOPOLL_OS_WIN32) nopoll_win32_gettimeofday (&start, NULL); #else gettimeofday (&start, NULL); #endif /* set to keep looping everything this function is called */ ctx->keep_looping = nopoll_true; while (ctx->keep_looping) { /* ok, now implement wait operation */ ctx->io_engine->clear (ctx, ctx->io_engine->io_object); /* add all connections */ /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding connections to watch: %d", ctx->conn_num); */ nopoll_ctx_foreach_conn (ctx, nopoll_loop_register, NULL); /* if (errno == EBADF) { */ /* detected some descriptor not properly * working, try to check them */ /* nopoll_ctx_foreach_conn (ctx, nopoll_loop_clean_descriptors, NULL); */ /* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found some descriptor is not valid (errno==%d)", errno); continue; */ /* } */ /* end if */ /* implement wait operation */ /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting for changes into %d connections", ctx->conn_num); */ wait_status = ctx->io_engine->wait (ctx, ctx->io_engine->io_object); /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting finished with result %d", wait_status); */ if (wait_status == -1) { nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received error from wait operation, error code was: %d", errno); break; } /* end if */ /* check how many connections changed and restart */ if (wait_status > 0) { /* check and call for connections with something * interesting */ nopoll_ctx_foreach_conn (ctx, nopoll_loop_process, &wait_status); } /* check to stop wait operation */ if (timeout > 0) { #if defined(NOPOLL_OS_WIN32) nopoll_win32_gettimeofday (&stop, NULL); #else gettimeofday (&stop, NULL); #endif nopoll_timeval_substract (&stop, &start, &diff); ellapsed = (diff.tv_sec * 1000000) + diff.tv_usec; if (ellapsed > timeout) break; } /* end if */ } /* end while */ /* release engine */ nopoll_io_release_engine (ctx->io_engine); ctx->io_engine = NULL; return 0; }