static inline int multi_tcp_wait(const struct context *c, struct multi_tcp *mtcp) { int status; socket_set_listen_persistent(c->c2.link_socket, mtcp->es, MTCP_SOCKET); tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); #ifdef ENABLE_MANAGEMENT if (management) { management_socket_set(management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); } #endif #ifdef ENABLE_ASYNC_PUSH /* arm inotify watcher */ event_ctl(mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE); #endif status = event_wait(mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents); update_time(); mtcp->n_esr = 0; if (status > 0) { mtcp->n_esr = status; } return status; }
void io_wait_dowork (struct context *c, const unsigned int flags) { unsigned int socket = 0; unsigned int tuntap = 0; struct event_set_return esr[4]; /* These shifts all depend on EVENT_READ and EVENT_WRITE */ static int socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */ static int tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */ static int err_shift = 4; /* depends on ES_ERROR */ #ifdef ENABLE_MANAGEMENT static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ #endif /* * Decide what kind of events we want to wait for. */ event_reset (c->c2.event_set); /* * On win32 we use the keyboard or an event object as a source * of asynchronous signals. */ if (flags & IOW_WAIT_SIGNAL) wait_signal (c->c2.event_set, (void*)&err_shift); /* * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send * status from TCP/UDP port. Otherwise, wait for incoming data on * TUN/TAP device. */ if (flags & IOW_TO_LINK) { if (flags & IOW_SHAPER) { /* * If sending this packet would put us over our traffic shaping * quota, don't send -- instead compute the delay we must wait * until it will be OK to send the packet. */ #ifdef ENABLE_FEATURE_SHAPER int delay = 0; /* set traffic shaping delay in microseconds */ if (c->options.shaper) delay = max_int (delay, shaper_delay (&c->c2.shaper)); if (delay < 1000) { socket |= EVENT_WRITE; } else { shaper_soonest_event (&c->c2.timeval, delay); } #else /* ENABLE_FEATURE_SHAPER */ socket |= EVENT_WRITE; #endif /* ENABLE_FEATURE_SHAPER */ } else { socket |= EVENT_WRITE; } } else if (!((flags & IOW_FRAG) && TO_LINK_FRAG (c))) { if (flags & IOW_READ_TUN) tuntap |= EVENT_READ; } /* * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status * from device. Otherwise, wait for incoming data on TCP/UDP port. */ if (flags & IOW_TO_TUN) { tuntap |= EVENT_WRITE; } else { if (flags & IOW_READ_LINK) socket |= EVENT_READ; } /* * outgoing bcast buffer waiting to be sent? */ if (flags & IOW_MBUF) socket |= EVENT_WRITE; /* * Force wait on TUN input, even if also waiting on TCP/UDP output */ if (flags & IOW_READ_TUN_FORCE) tuntap |= EVENT_READ; /* * Configure event wait based on socket, tuntap flags. */ socket_set (c->c2.link_socket, c->c2.event_set, socket, (void*)&socket_shift, NULL); tun_set (c->c1.tuntap, c->c2.event_set, tuntap, (void*)&tun_shift, NULL); #ifdef ENABLE_MANAGEMENT if (management) management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL); #endif /* * Possible scenarios: * (1) tcp/udp port has data available to read * (2) tcp/udp port is ready to accept more data to write * (3) tun dev has data available to read * (4) tun dev is ready to accept more data to write * (5) we received a signal (handler sets signal_received) * (6) timeout (tv) expired */ c->c2.event_set_status = ES_ERROR; if (!c->sig->signal_received) { if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual (c->c2.link_socket)) { int status; #ifdef ENABLE_DEBUG if (check_debug_level (D_EVENT_WAIT)) show_wait_status (c); #endif /* * Wait for something to happen. */ status = event_wait (c->c2.event_set, &c->c2.timeval, esr, SIZE(esr)); check_status (status, "event_wait", NULL, NULL); if (status > 0) { int i; c->c2.event_set_status = 0; for (i = 0; i < status; ++i) { const struct event_set_return *e = &esr[i]; c->c2.event_set_status |= ((e->rwflags & 3) << *((int*)e->arg)); } } else if (status == 0) { c->c2.event_set_status = ES_TIMEOUT; } } else { c->c2.event_set_status = SOCKET_READ; } } /* 'now' should always be a reasonably up-to-date timestamp */ update_time (); /* set signal_received if a signal was received */ if (c->c2.event_set_status & ES_ERROR) get_signal (&c->sig->signal_received); dmsg (D_EVENT_WAIT, "I/O WAIT status=0x%04x", c->c2.event_set_status); }