/* * Top level event loop for single-threaded operation. * UDP mode. */ static void tunnel_server_udp_single_threaded (struct context *top) { struct multi_context multi; top->mode = CM_TOP; context_clear_2 (top); /* initialize top-tunnel instance */ init_instance_handle_signals (top, top->es, CC_HARD_USR1_TO_HUP); if (IS_SIG (top)) return; /* initialize global multi_context object */ multi_init (&multi, top, false, MC_SINGLE_THREADED); /* initialize our cloned top object */ multi_top_init (&multi, top, true); /* initialize management interface */ init_management_callback_multi (&multi); /* finished with initialization */ initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */ /* per-packet event loop */ while (true) { perf_push (PERF_EVENT_LOOP); /* set up and do the io_wait() */ multi_get_timeout (&multi, &multi.top.c2.timeval); io_wait (&multi.top, p2mp_iow_flags (&multi)); MULTI_CHECK_SIG (&multi); /* check on status of coarse timers */ multi_process_per_second_timers (&multi); /* timeout? */ if (multi.top.c2.event_set_status == ES_TIMEOUT) { multi_process_timeout (&multi, MPP_PRE_SELECT|MPP_CLOSE_ON_SIGNAL); } else { /* process I/O */ multi_process_io_udp (&multi); MULTI_CHECK_SIG (&multi); } perf_pop (); } /* shut down management interface */ uninit_management_callback_multi (&multi); /* save ifconfig-pool */ multi_ifconfig_pool_persist (&multi, true); /* tear down tunnel instance (unless --persist-tun) */ multi_uninit (&multi); multi_top_free (&multi); close_instance (top); }
static struct multi_instance * multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int action) { const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; struct multi_instance *touched = mi; m->mpp_touched = &touched; dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_dispatch a=%s mi=" ptr_format, pract(action), (ptr_type)mi); switch (action) { case TA_TUN_READ: read_incoming_tun(&m->top); if (!IS_SIG(&m->top)) { multi_process_incoming_tun(m, mpp_flags); } break; case TA_SOCKET_READ: case TA_SOCKET_READ_RESIDUAL: ASSERT(mi); ASSERT(mi->context.c2.link_socket); set_prefix(mi); read_incoming_link(&mi->context); clear_prefix(); if (!IS_SIG(&mi->context)) { multi_process_incoming_link(m, mi, mpp_flags); if (!IS_SIG(&mi->context)) { stream_buf_read_setup(mi->context.c2.link_socket); } } break; case TA_TIMEOUT: multi_process_timeout(m, mpp_flags); break; case TA_TUN_WRITE: multi_process_outgoing_tun(m, mpp_flags); break; case TA_TUN_WRITE_TIMEOUT: multi_process_drop_outgoing_tun(m, mpp_flags); break; case TA_SOCKET_WRITE_READY: ASSERT(mi); multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags); break; case TA_SOCKET_WRITE: multi_tcp_process_outgoing_link(m, false, mpp_flags); break; case TA_SOCKET_WRITE_DEFERRED: multi_tcp_process_outgoing_link(m, true, mpp_flags); break; case TA_INITIAL: ASSERT(mi); multi_tcp_set_global_rw_flags(m, mi); multi_process_post(m, mi, mpp_flags); break; default: msg(M_FATAL, "MULTI TCP: multi_tcp_dispatch, unhandled action=%d", action); } m->mpp_touched = NULL; return touched; }