/** * Might call `svc_destroy(up7->xprt)`. * * @param[in] up7 Upstream LDM-7. * @retval 0 Success. */ static int up7_run( Up7* const up7) { const int sock = up7->xprt->xp_sock; int status; struct pollfd fds; fds.fd = sock; fds.events = POLLRDNORM; pthread_cleanup_push(funcCancelled, "up7_run"); int initCancelState; (void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &initCancelState); for (;;) { udebug("up7_run(): Calling poll()"); status = poll(&fds, 1, -1); // `-1` => indefinite timeout int cancelState; // (void)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelState); if (0 > status) { svc_destroy(up7->xprt); break; } if ((fds.revents & POLLERR) || (fds.revents & POLLNVAL)) { status = EIO; break; } if (fds.revents & POLLHUP) { status = 0; break; } if (fds.revents & POLLRDNORM) { udebug("up7_run(): Calling svc_getreqsock()"); svc_getreqsock(sock); // calls `ldmprog_7()` } if (!FD_ISSET(sock, &svc_fdset)) { /* * The connection to the receiver was closed by the RPC layer => * `svc_destroy(up7->xprt)` was called. */ up7->xprt = NULL; // so others don't try to destroy it status = 0; break; } (void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelState); } /* * In order to play nice with the caller, the cancelability state is * reverted to its value on entry. */ (void)pthread_setcancelstate(initCancelState, &initCancelState); pthread_cleanup_pop(0); udebug("up7_run(): Returning %d", status); return status; }
/** * Run an RPC server on a single socket (similar to svc_run(3RPC)). Runs until: * 1) The socket gets closed; or * 2) The timeout expires without any activity; or * 3) as_shouldSwitch() returns true; or * 4) An error occurs. * <p> * This function uses the "log" module to accumulate messages. * * @param sock The connected socket. * @param timeout The maximum amount of time to wait with no activity * on the socket in seconds. * * @retval 0 Success. as_shouldSwitch() is true. * @retval EBADF The socket isn't open. * @retval EINVAL Invalid timeout value. * @retval ECONNRESET RPC layer closed socket. The RPC layer also * destroyed the associated SVCXPRT structure; * therefore, that object must not be subsequently * dereferenced. * @retval ETIMEDOUT "timeout" time passed without any activity on * the socket. */ int one_svc_run( const int sock, const unsigned timeout) { timestampt canonicalTimeout; timestampt selectTimeout; fd_set fds; canonicalTimeout.tv_sec = timeout; canonicalTimeout.tv_usec = 0; selectTimeout = canonicalTimeout; FD_ZERO(&fds); FD_SET(sock, &fds); for (;;) { fd_set readFds = fds; timestampt before; int selectStatus; (void)set_timestamp(&before); selectStatus = select(sock+1, &readFds, 0, 0, &selectTimeout); (void)exitIfDone(0); /* handles SIGTERM reception */ if (selectStatus == 0) return ETIMEDOUT; if (selectStatus > 0) { /* * The socket is ready for reading. The following statement calls * `ldmprog_5()`, `ldmprog_6()`, or `ldmprog_7()`. */ svc_getreqsock(sock); (void)exitIfDone(0); if (!FD_ISSET(sock, &svc_fdset)) { /* * The RPC layer closed the socket and destroyed the associated * SVCXPRT structure. */ log_add("one_svc_run(): RPC layer closed connection"); return ECONNRESET; } if (as_shouldSwitch()) /* always false for upstream LDM-s */ return 0; selectTimeout = canonicalTimeout; /* reset select(2) timeout */ } /* socket is read-ready */ else { if (errno != EINTR) { log_errno(); log_add("one_svc_run(): select() error on socket %d", sock); return errno; } { timestampt after; timestampt diff; (void)set_timestamp(&after); /* * Adjust select(2) timeout. */ diff = diff_timestamp(&after, &before); selectTimeout = diff_timestamp(&canonicalTimeout, &diff); } } /* select() returned -1 */ } /* indefinite loop */ return 0; // Eclipse wants to see a return }