📄 multi.c
字号:
&dest, &c->c2.to_tun, DEV_TYPE_TAP); if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) { /* check for broadcast */ if (m->enable_c2c) { if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) { multi_bcast (m, &c->c2.to_tun, mt->pending); } else /* try client-to-client routing */ { mi = multi_get_instance_by_virtual_addr (m, &dest, false); /* if dest addr is a known client, route to it */ if (mi) { multi_unicast (m, &c->c2.to_tun, mi); register_activity (c); c->c2.to_tun.len = 0; } } } /* learn source address */ multi_learn_addr (m, mt->pending, &src, 0); } else { c->c2.to_tun.len = 0; } } /* postprocess and set wakeup */ multi_process_post (mt, mt->pending); clear_prefix (); } gc_free (&gc);}/* * Process packets in the TUN/TAP interface -> TCP/UDP socket direction, * i.e. server -> client direction. */static voidmulti_process_incoming_tun (struct multi_thread *mt){ struct gc_arena gc = gc_new (); struct multi_context *m = mt->multi; if (BLEN (&mt->top.c2.buf) > 0) { unsigned int mroute_flags; struct mroute_addr src, dest; const int dev_type = TUNNEL_TYPE (mt->top.c1.tuntap);#ifdef MULTI_DEBUG_EVENT_LOOP printf ("TUN -> UDP [%d]\n", BLEN (&mt->top.c2.buf));#endif ASSERT (!mt->pending); /* * Route an incoming tun/tap packet to * the appropriate multi_instance object. */ mroute_flags = mroute_extract_addr_from_packet (&src, &dest, &mt->top.c2.buf, dev_type); if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) { struct context *c; /* broadcast or multicast dest addr? */ if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) { /* for now, treat multicast as broadcast */ multi_bcast (m, &mt->top.c2.buf, NULL); } else { mt->pending = multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN); if (mt->pending) { set_prefix (mt->pending); /* get instance context */ c = &mt->pending->context; /* transfer packet pointer from top-level context buffer to instance */ c->c2.buf = mt->top.c2.buf; /* encrypt in instance context */ process_incoming_tun (c); /* postprocess and set wakeup */ multi_process_post (mt, mt->pending); clear_prefix (); } } } } gc_free (&gc);}/* * Process a possible client-to-client/bcast/mcast message in the * queue. */struct multi_instance *multi_bcast_instance (struct multi_context *m){ struct mbuf_item item; if (mbuf_extract_item_lock (m->mbuf, &item, true)) { set_prefix (item.instance); item.instance->context.c2.buf = item.buffer->buf; encrypt_sign (&item.instance->context, true); mbuf_free_buf (item.buffer); mbuf_extract_item_unlock (m->mbuf);#ifdef MULTI_DEBUG msg (D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST");#endif clear_prefix (); return item.instance; } else { return NULL; }}/* * Send a packet to TCP/UDP socket. */static inline voidmulti_process_outgoing_link (struct multi_thread *mt){ struct multi_instance *mi; if (mt->pending) { mi = mt->pending;#ifdef MULTI_DEBUG_EVENT_LOOP printf ("%s -> UDP [U] l=%d f=%d\n", id(mi), mi->context.c2.to_link.len, mi->context.c2.fragment ? mi->context.c2.fragment->outgoing.len : -1);#endif } else { mi = multi_bcast_instance (mt->multi);#ifdef MULTI_DEBUG_EVENT_LOOP printf ("%s -> UDP [B] len=%d frag=%d\n", id(mi), mi ? mi->context.c2.to_link.len : -1, (mi && mi->context.c2.fragment) ? mi->context.c2.fragment->outgoing.len : -1);#endif } if (mi) { set_prefix (mi); process_outgoing_link (&mi->context); multi_process_post (mt, mi); clear_prefix (); }}/* * Send a packet to TUN/TAP interface. */static inline voidmulti_process_outgoing_tun (struct multi_thread *mt){ struct multi_instance *mi = mt->pending; ASSERT (mi);#ifdef MULTI_DEBUG_EVENT_LOOP printf ("%s -> TUN len=%d\n", id(mi), mi->context.c2.to_tun.len);#endif set_prefix (mi); process_outgoing_tun (&mi->context); multi_process_post (mt, mi); clear_prefix ();}/* * Process an I/O event. */voidmulti_process_io (struct multi_thread *mt){ const unsigned int status = mt->top.c2.event_set_status;#ifdef MULTI_DEBUG_EVENT_LOOP char buf[16]; buf[0] = 0; if (status & SOCKET_READ) strcat (buf, "SR/"); else if (status & SOCKET_WRITE) strcat (buf, "SW/"); else if (status & TUN_READ) strcat (buf, "TR/"); else if (status & TUN_WRITE) strcat (buf, "TW/"); printf ("IO %s\n", buf);#endif /* TCP/UDP port ready to accept write */ if (status & SOCKET_WRITE) { multi_process_outgoing_link (mt); } /* TUN device ready to accept write */ else if (status & TUN_WRITE) { multi_process_outgoing_tun (mt); } /* Incoming data on TCP/UDP port */ else if (status & SOCKET_READ) { read_incoming_link (&mt->top); if (!IS_SIG (&mt->top)) multi_process_incoming_link (mt); } /* Incoming data on TUN device */ else if (status & TUN_READ) { read_incoming_tun (&mt->top); if (!IS_SIG (&mt->top)) multi_process_incoming_tun (mt); }}/* * Called when an I/O wait times out. Usually means that a particular * client instance object needs timer-based service. */static inline voidmulti_process_timeout (struct multi_thread *mt){#ifdef MULTI_DEBUG_EVENT_LOOP printf ("%s -> TIMEOUT\n", id(mt->earliest_wakeup));#endif /* instance marked for wakeup? */ if (mt->earliest_wakeup) { set_prefix (mt->earliest_wakeup); multi_process_post (mt, mt->earliest_wakeup); mt->earliest_wakeup = NULL; clear_prefix (); }}/* * Check for signals. */#define TNUS_SIG() \ if (IS_SIG (&thread->top)) \ { \ if (thread->top.sig->signal_received == SIGUSR2) \ { \ struct status_output *so = status_open (NULL, 0, M_INFO); \ multi_print_status (thread->multi, so); \ status_close (so); \ thread->top.sig->signal_received = 0; \ continue; \ } \ break; \ }/* * The idea of struct multi_thread is that multiple threads could handle * the event loop simultaneously. */static struct multi_thread *multi_thread_init (struct multi_context *multi, const struct context *top){ struct multi_thread *thread; ALLOC_OBJ_CLEAR (thread, struct multi_thread); thread->multi = multi; inherit_context_thread (&thread->top, top); thread->context_buffers = thread->top.c2.buffers = init_context_buffers (&top->c2.frame); return thread;}static voidmulti_thread_free (struct multi_thread *thread){ close_context (&thread->top, -1); free_context_buffers (thread->context_buffers); free (thread);}/* * Return the io_wait() flags appropriate for * a point-to-multipoint tunnel. */static inline unsigned intp2mp_iow_flags (const struct multi_thread *mt){ unsigned int flags = 0; if (mt->pending) { if (TUN_OUT (&mt->pending->context)) flags |= IOW_TO_TUN; if (LINK_OUT (&mt->pending->context)) flags |= IOW_TO_LINK; } else if (mbuf_defined (mt->multi->mbuf)) flags |= IOW_MBUF; else flags |= IOW_READ; return flags;}static inline voidprocess_per_second_timers (struct multi_thread *thread){ if (thread->per_second_trigger != now) { /* possibly reap instances/routes in vhash */ multi_reap_process (thread->multi); /* possibly print to status log */ if (thread->top.c1.status_output) { if (status_trigger (thread->top.c1.status_output)) multi_print_status (thread->multi, thread->top.c1.status_output); } thread->per_second_trigger = now; }}/* * Top level event loop for single-threaded operation. * UDP mode. */static voidtunnel_server_single_threaded_udp (struct context *top){ struct multi_context multi; struct multi_thread *thread; top->mode = CM_TOP; context_clear_2 (top); /* initialize top-tunnel instance */ init_instance (top); if (IS_SIG (top)) return; /* initialize global multi_context object */ multi_init (&multi, top); /* initialize a single multi_thread object */ thread = multi_thread_init (&multi, top); /* per-packet event loop */ while (true) { /* set up and do the io_wait() */ multi_get_timeout (thread, &thread->top.c2.timeval); io_wait (&thread->top, p2mp_iow_flags (thread)); TNUS_SIG (); /* check on status of coarse timers */ process_per_second_timers (thread); /* timeout? */ if (thread->top.c2.event_set_status == ES_TIMEOUT) { multi_process_timeout (thread); } else { /* process the I/O which triggered select */ multi_process_io (thread); TNUS_SIG (); } } /* tear down tunnel instance (unless --persist-tun) */ multi_thread_free (thread); close_instance (top); multi_uninit (&multi); top->first_time = false;}/* * Top level event loop for single-threaded operation. * TCP mode. */static voidtunnel_server_single_threaded_tcp (struct context *top){ //struct multi_context multi; //struct multi_thread *thread; msg (M_FATAL, "Sorry, TCP support in server mode is not finished yet");}/* * Top level event loop for single-threaded operation. */voidtunnel_server_single_threaded (struct context *top){ ASSERT (top->options.mode == MODE_SERVER); switch (top->options.proto) { case PROTO_UDPv4: tunnel_server_single_threaded_udp (top); break; case PROTO_TCPv4_SERVER: tunnel_server_single_threaded_tcp (top); break; default: ASSERT (0); }}#ifdef USE_PTHREAD/* * NOTE: multi-threaded mode is not finished yet. */voidtunnel_server_multi_threaded (struct context *top){ ASSERT (top->options.n_threads >= 2); openvpn_thread_init (); tunnel_server_single_threaded (top); openvpn_thread_cleanup ();}#endif#elsestatic void dummy(void) {}#endif /* P2MP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -