Пример #1
0
/*
 * Process an I/O event.
 */
static void
multi_process_io_udp (struct multi_context *m)
{
  const unsigned int status = m->top.c2.event_set_status;
  const unsigned int mpp_flags = m->top.c2.fast_io
    ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL)
    : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL);

#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

#ifdef ENABLE_MANAGEMENT
  if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE))
    {
      ASSERT (management);
      management_io (management);
    }
#endif

  /* UDP port ready to accept write */
  if (status & SOCKET_WRITE)
    {
      multi_process_outgoing_link (m, mpp_flags);
    }
  /* TUN device ready to accept write */
  else if (status & TUN_WRITE)
    {
      multi_process_outgoing_tun (m, mpp_flags);
    }
  /* Incoming data on UDP port */
  else if (status & SOCKET_READ)
    {
      read_incoming_link (&m->top);
      multi_release_io_lock (m);
      if (!IS_SIG (&m->top))
	multi_process_incoming_link (m, NULL, mpp_flags);
    }
  /* Incoming data on TUN device */
  else if (status & TUN_READ)
    {
      read_incoming_tun (&m->top);
      multi_release_io_lock (m);
      if (!IS_SIG (&m->top))
	multi_process_incoming_tun (m, mpp_flags);
    }
}
Пример #2
0
void
process_io (struct context *c)
{
  const unsigned int status = c->c2.event_set_status;

#ifdef ENABLE_MANAGEMENT
  if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE))
    {
      ASSERT (management);
      management_io (management);
    }
#endif

  /* TCP/UDP port ready to accept write */
  if (status & SOCKET_WRITE)
    {
      process_outgoing_link (c);
    }
  /* TUN device ready to accept write */
  else if (status & TUN_WRITE)
    {
      process_outgoing_tun (c);
    }
  /* Incoming data on TCP/UDP port */
  else if (status & SOCKET_READ)
    {
      read_incoming_link (c);
      if (!IS_SIG (c))
	process_incoming_link (c);
    }
  /* Incoming data on TUN device */
  else if (status & TUN_READ)
    {
      read_incoming_tun (c);
      if (!IS_SIG (c))
	process_incoming_tun (c);
    }
}
Пример #3
0
/**
 * Main event loop for OpenVPN in client mode, where only one VPN tunnel
 * is active.
 * @ingroup eventloop
 *
 * @param c - The context structure of the single active VPN tunnel.
 */
static void
tunnel_point_to_point(struct context *c)
{
    context_clear_2(c);

    /* set point-to-point mode */
    c->mode = CM_P2P;

    /* initialize tunnel instance */
    init_instance_handle_signals(c, c->es, CC_HARD_USR1_TO_HUP);
    if (IS_SIG(c))
    {
        return;
    }

    /* main event loop */
    while (true)
    {
        perf_push(PERF_EVENT_LOOP);

        /* process timers, TLS, etc. */
        pre_select(c);
        P2P_CHECK_SIG();

        /* set up and do the I/O wait */
        io_wait(c, p2p_iow_flags(c));
        P2P_CHECK_SIG();

        /* timeout? */
        if (c->c2.event_set_status == ES_TIMEOUT)
        {
            perf_pop();
            continue;
        }

        /* process the I/O which triggered select */
        process_io(c);
        P2P_CHECK_SIG();

        perf_pop();
    }

    uninit_management_callback();

    /* tear down tunnel instance (unless --persist-tun) */
    close_instance(c);
}
Пример #4
0
/**
 * OpenVPN's main init-run-cleanup loop.
 * @ingroup eventloop
 * 
 * This function contains the two outer OpenVPN loops.  Its structure is
 * as follows:
 *  - Once-per-process initialization.
 *  - Outer loop, run at startup and then once per \c SIGHUP:
 *    - Level 1 initialization
 *    - Inner loop, run at startup and then once per \c SIGUSR1:
 *      - Call event loop function depending on client or server mode:
 *        - \c tunnel_point_to_point()
 *        - \c tunnel_server()
 *    - Level 1 cleanup
 *  - Once-per-process cleanup.
 * 
 * @param argc - Commandline argument count.
 * @param argv - Commandline argument values.
 */
int
main (int argc, char *argv[])
{
  struct context c;

#if PEDANTIC
  fprintf (stderr, "Sorry, I was built with --enable-pedantic and I am incapable of doing any real work!\n");
  return 1;
#endif

  CLEAR (c);

  /* signify first time for components which can
     only be initialized once per program instantiation. */
  c.first_time = true;

  /* initialize program-wide statics */
  if (init_static ())
    {
      /*
       * This loop is initially executed on startup and then
       * once per SIGHUP.
       */
      do
	{
	  /* enter pre-initialization mode with regard to signal handling */
	  pre_init_signal_catch ();

	  /* zero context struct but leave first_time member alone */
	  context_clear_all_except_first_time (&c);

	  /* static signal info object */
	  CLEAR (siginfo_static);
	  c.sig = &siginfo_static;

	  /* initialize garbage collector scoped to context object */
	  gc_init (&c.gc);

	  /* initialize environmental variable store */
	  c.es = env_set_create (NULL);
#ifdef WIN32
	  env_set_add_win32 (c.es);
#endif

#ifdef ENABLE_MANAGEMENT
	  /* initialize management subsystem */
	  init_management (&c);
#endif

	  /* initialize options to default state */
	  init_options (&c.options, true);

	  /* parse command line options, and read configuration file */
	  parse_argv (&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);

#ifdef ENABLE_PLUGIN
	  /* plugins may contribute options configuration */
	  init_verb_mute (&c, IVM_LEVEL_1);
	  init_plugins (&c);
	  open_plugins (&c, true, OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE);
#endif

	  /* init verbosity and mute levels */
	  init_verb_mute (&c, IVM_LEVEL_1);

	  /* set dev options */
	  init_options_dev (&c.options);

	  /* openssl print info? */
	  if (print_openssl_info (&c.options))
	    break;

	  /* --genkey mode? */
	  if (do_genkey (&c.options))
	    break;

	  /* tun/tap persist command? */
	  if (do_persist_tuntap (&c.options))
	    break;

	  /* sanity check on options */
	  options_postprocess (&c.options);

	  /* show all option settings */
	  show_settings (&c.options);

	  /* print version number */
	  msg (M_INFO, "%s", title_string);

	  /* misc stuff */
	  pre_setup (&c.options);

	  /* test crypto? */
	  if (do_test_crypto (&c.options))
	    break;
	  
#ifdef ENABLE_MANAGEMENT
	  /* open management subsystem */
	  if (!open_management (&c))
	    break;
#endif

	  /* set certain options as environmental variables */
	  setenv_settings (c.es, &c.options);

	  /* finish context init */
	  context_init_1 (&c);

	  do
	    {
	      /* run tunnel depending on mode */
	      switch (c.options.mode)
		{
		case MODE_POINT_TO_POINT:
		  tunnel_point_to_point (&c);
		  break;
#if P2MP_SERVER
		case MODE_SERVER:
		  tunnel_server (&c);
		  break;
#endif
		default:
		  ASSERT (0);
		}

	      /* indicates first iteration -- has program-wide scope */
	      c.first_time = false;

	      /* any signals received? */
	      if (IS_SIG (&c))
		print_signal (c.sig, NULL, M_INFO);

	      /* pass restart status to management subsystem */
	      signal_restart_status (c.sig);
	    }
	  while (c.sig->signal_received == SIGUSR1);

	  uninit_options (&c.options);
	  gc_reset (&c.gc);
	}
      while (c.sig->signal_received == SIGHUP);
    }

  context_gc_free (&c);

  env_set_destroy (c.es);

#ifdef ENABLE_MANAGEMENT
  /* close management interface */
  close_management ();
#endif

  /* uninitialize program-wide statics */
  uninit_static ();

  openvpn_exit (OPENVPN_EXIT_STATUS_GOOD);  /* exit point */
  return 0;			            /* NOTREACHED */
}
Пример #5
0
/**
 * Main event loop for OpenVPN in UDP server mode.
 * @ingroup eventloop
 *
 * This function implements OpenVPN's main event loop for UDP server mode.
 *  At this time, OpenVPN does not yet support multithreading.  This
 * function's name is therefore slightly misleading.
 *
 * @param top - Top-level context structure.
 */
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);
}
Пример #6
0
/****************
 * Create notations and other stuff.  It is assumed that the stings in
 * STRLIST are already checked to contain only printable data and have
 * a valid NAME=VALUE format.
 */
static void
mk_notation_policy_etc (PKT_signature *sig,
			PKT_public_key *pk, PKT_public_key *pksk)
{
  const char *string;
  char *p = NULL;
  strlist_t pu = NULL;
  struct notation *nd = NULL;
  struct expando_args args;

  log_assert (sig->version >= 4);

  memset (&args, 0, sizeof(args));
  args.pk = pk;
  args.pksk = pksk;

  /* Notation data. */
  if (IS_SIG(sig) && opt.sig_notations)
    nd = opt.sig_notations;
  else if (IS_CERT(sig) && opt.cert_notations)
    nd = opt.cert_notations;

  if (nd)
    {
      struct notation *item;

      for (item = nd; item; item = item->next)
        {
          item->altvalue = pct_expando (item->value,&args);
          if (!item->altvalue)
            log_error (_("WARNING: unable to %%-expand notation "
                         "(too large).  Using unexpanded.\n"));
        }

      keygen_add_notations (sig, nd);

      for (item = nd; item; item = item->next)
        {
          xfree (item->altvalue);
          item->altvalue = NULL;
        }
    }

  /* Set policy URL. */
  if (IS_SIG(sig) && opt.sig_policy_url)
    pu = opt.sig_policy_url;
  else if (IS_CERT(sig) && opt.cert_policy_url)
    pu = opt.cert_policy_url;

  for (; pu; pu = pu->next)
    {
      string = pu->d;

      p = pct_expando (string, &args);
      if (!p)
        {
          log_error(_("WARNING: unable to %%-expand policy URL "
                      "(too large).  Using unexpanded.\n"));
          p = xstrdup(string);
        }

      build_sig_subpkt (sig, (SIGSUBPKT_POLICY
                              | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)),
                        p, strlen (p));

      xfree (p);
    }

  /* Preferred keyserver URL. */
  if (IS_SIG(sig) && opt.sig_keyserver_url)
    pu = opt.sig_keyserver_url;

  for (; pu; pu = pu->next)
    {
      string = pu->d;

      p = pct_expando (string, &args);
      if (!p)
        {
          log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
                       " (too large).  Using unexpanded.\n"));
          p = xstrdup (string);
        }

      build_sig_subpkt (sig, (SIGSUBPKT_PREF_KS
                              | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)),
                        p, strlen (p));
      xfree (p);
    }

  /* Set signer's user id.  */
  if (IS_SIG (sig) && !opt.flags.disable_signer_uid)
    {
      char *mbox;

      /* For now we use the uid which was used to locate the key.  */
      if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name)))
        {
          if (DBG_LOOKUP)
            log_debug ("setting Signer's UID to '%s'\n", mbox);
          build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox));
          xfree (mbox);
        }
      else if (opt.sender_list)
        {
          /* If a list of --sender was given we scan that list and use
           * the first one matching a user id of the current key.  */

          /* FIXME: We need to get the list of user ids for the PKSK
           * packet.  That requires either a function to look it up
           * again or we need to extend the key packet struct to link
           * to the primary key which in turn could link to the user
           * ids.  Too much of a change right now.  Let's take just
           * one from the supplied list and hope that the caller
           * passed a matching one.  */
          build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID,
                            opt.sender_list->d, strlen (opt.sender_list->d));
        }
    }
}
Пример #7
0
/****************
 * Create notations and other stuff.  It is assumed that the stings in
 * STRLIST are already checked to contain only printable data and have
 * a valid NAME=VALUE format.
 */
static void
mk_notation_policy_etc( PKT_signature *sig,
			PKT_public_key *pk, PKT_secret_key *sk )
{
    const char *string;
    char *s=NULL;
    STRLIST pu=NULL;
    struct notation *nd=NULL;
    struct expando_args args;

    assert(sig->version>=4);

    memset(&args,0,sizeof(args));
    args.pk=pk;
    args.sk=sk;

    /* notation data */
    if(IS_SIG(sig) && opt.sig_notations)
      nd=opt.sig_notations;
    else if( IS_CERT(sig) && opt.cert_notations )
      nd=opt.cert_notations;

    if(nd)
      {
	struct notation *i;

	for(i=nd;i;i=i->next)
	  {
	    i->altvalue=pct_expando(i->value,&args);
	    if(!i->altvalue)
	      log_error(_("WARNING: unable to %%-expand notation "
			  "(too large).  Using unexpanded.\n"));
	  }

	keygen_add_notations(sig,nd);

	for(i=nd;i;i=i->next)
	  {
	    xfree(i->altvalue);
	    i->altvalue=NULL;
	  }
      }

    /* set policy URL */
    if( IS_SIG(sig) && opt.sig_policy_url )
      pu=opt.sig_policy_url;
    else if( IS_CERT(sig) && opt.cert_policy_url )
      pu=opt.cert_policy_url;

    for(;pu;pu=pu->next)
      {
        string = pu->d;

	s=pct_expando(string,&args);
	if(!s)
	  {
	    log_error(_("WARNING: unable to %%-expand policy URL "
			"(too large).  Using unexpanded.\n"));
	    s=xstrdup(string);
	  }

	build_sig_subpkt(sig,SIGSUBPKT_POLICY|
			 ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
			 s,strlen(s));

	xfree(s);
      }

    /* preferred keyserver URL */
    if( IS_SIG(sig) && opt.sig_keyserver_url )
      pu=opt.sig_keyserver_url;

    for(;pu;pu=pu->next)
      {
        string = pu->d;

	s=pct_expando(string,&args);
	if(!s)
	  {
	    log_error(_("WARNING: unable to %%-expand preferred keyserver URL"
			" (too large).  Using unexpanded.\n"));
	    s=xstrdup(string);
	  }

	build_sig_subpkt(sig,SIGSUBPKT_PREF_KS|
			 ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
			 s,strlen(s));

	xfree(s);
      }
}
Пример #8
0
/****************
 * Create a notation.  It is assumed that the stings in STRLIST
 * are already checked to contain only printable data and have a valid
 * NAME=VALUE format.
 */
static void
mk_notation_and_policy( PKT_signature *sig,
			PKT_public_key *pk, PKT_secret_key *sk )
{
    const char *string;
    char *s=NULL;
    byte *buf;
    unsigned n1, n2;
    STRLIST nd=NULL,pu=NULL;
    struct expando_args args;

    memset(&args,0,sizeof(args));
    args.pk=pk;
    args.sk=sk;

    /* notation data */
    if(IS_SIG(sig) && opt.sig_notation_data)
      {
	if(sig->version<4)
	  log_info("can't put notation data into v3 signatures\n");
	else
	  nd=opt.sig_notation_data;
      }
    else if( IS_CERT(sig) && opt.cert_notation_data )
      {
	if(sig->version<4)
	  log_info("can't put notation data into v3 key signatures\n");
	else
	  nd=opt.cert_notation_data;
      }

    for( ; nd; nd = nd->next ) {
        char *expanded;

        string = nd->d;
	s = strchr( string, '=' );
	if( !s )
	  BUG(); /* we have already parsed this */
	n1 = s - string;
	s++;

	expanded=pct_expando(s,&args);
	if(!expanded)
	  {
	    log_error(_("WARNING: unable to %%-expand notation "
			"(too large).  Using unexpanded.\n"));
	    expanded=m_strdup(s);
	  }

	n2 = strlen(expanded);
	buf = m_alloc( 8 + n1 + n2 );
	buf[0] = 0x80; /* human readable */
	buf[1] = buf[2] = buf[3] = 0;
	buf[4] = n1 >> 8;
	buf[5] = n1;
	buf[6] = n2 >> 8;
	buf[7] = n2;
	memcpy(buf+8, string, n1 );
	memcpy(buf+8+n1, expanded, n2 );
	build_sig_subpkt( sig, SIGSUBPKT_NOTATION
			  | ((nd->flags & 1)? SIGSUBPKT_FLAG_CRITICAL:0),
			  buf, 8+n1+n2 );
	m_free(expanded);
	m_free(buf);
    }

    if(opt.show_notation)
      show_notation(sig,0);

    /* set policy URL */
    if( IS_SIG(sig) && opt.sig_policy_url )
      {
	if(sig->version<4)
	  log_info("can't put a policy URL into v3 signatures\n");
	else
	  pu=opt.sig_policy_url;
      }
    else if( IS_CERT(sig) && opt.cert_policy_url )
      {
	if(sig->version<4)
	  log_info("can't put a policy URL into v3 key signatures\n");
	else
	  pu=opt.cert_policy_url;
      }

    for(;pu;pu=pu->next)
      {
        string = pu->d;

	s=pct_expando(string,&args);
	if(!s)
	  {
	    log_error(_("WARNING: unable to %%-expand policy url "
			"(too large).  Using unexpanded.\n"));
	    s=m_strdup(string);
	  }

	build_sig_subpkt(sig,SIGSUBPKT_POLICY|
			 ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
			 s,strlen(s));

	m_free(s);
      }

    if(opt.show_policy_url)
      show_policy_url(sig,0);
}
Пример #9
0
/*
 * Top level event loop for single-threaded operation.
 * TCP mode.
 */
void
tunnel_server_tcp(struct context *top)
{
    struct multi_context multi;
    int status;

    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, true, MC_SINGLE_THREADED);

    /* initialize our cloned top object */
    multi_top_init(&multi, top);

    /* initialize management interface */
    init_management_callback_multi(&multi);

    /* finished with initialization */
    initialization_sequence_completed(top, ISC_SERVER); /* --mode server --proto tcp-server */

#ifdef ENABLE_ASYNC_PUSH
    multi.top.c2.inotify_fd = inotify_init();
    if (multi.top.c2.inotify_fd < 0)
    {
        msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error");
    }
#endif

    /* per-packet event loop */
    while (true)
    {
        perf_push(PERF_EVENT_LOOP);

        /* wait on tun/socket list */
        multi_get_timeout(&multi, &multi.top.c2.timeval);
        status = multi_tcp_wait(&multi.top, multi.mtcp);
        MULTI_CHECK_SIG(&multi);

        /* check on status of coarse timers */
        multi_process_per_second_timers(&multi);

        /* timeout? */
        if (status > 0)
        {
            /* process the I/O which triggered select */
            multi_tcp_process_io(&multi);
            MULTI_CHECK_SIG(&multi);
        }
        else if (status == 0)
        {
            multi_tcp_action(&multi, NULL, TA_TIMEOUT, false);
        }

        perf_pop();
    }

#ifdef ENABLE_ASYNC_PUSH
    close(top->c2.inotify_fd);
#endif

    /* 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);
}
Пример #10
0
static void
multi_tcp_process_io(struct multi_context *m)
{
    struct multi_tcp *mtcp = m->mtcp;
    int i;

    for (i = 0; i < mtcp->n_esr; ++i)
    {
        struct event_set_return *e = &mtcp->esr[i];

        /* incoming data for instance? */
        if (e->arg >= MTCP_N)
        {
            struct multi_instance *mi = (struct multi_instance *) e->arg;
            if (mi)
            {
                if (e->rwflags & EVENT_WRITE)
                {
                    multi_tcp_action(m, mi, TA_SOCKET_WRITE_READY, false);
                }
                else if (e->rwflags & EVENT_READ)
                {
                    multi_tcp_action(m, mi, TA_SOCKET_READ, false);
                }
            }
        }
        else
        {
#ifdef ENABLE_MANAGEMENT
            if (e->arg == MTCP_MANAGEMENT)
            {
                ASSERT(management);
                management_io(management);
            }
            else
#endif
            /* incoming data on TUN? */
            if (e->arg == MTCP_TUN)
            {
                if (e->rwflags & EVENT_WRITE)
                {
                    multi_tcp_action(m, NULL, TA_TUN_WRITE, false);
                }
                else if (e->rwflags & EVENT_READ)
                {
                    multi_tcp_action(m, NULL, TA_TUN_READ, false);
                }
            }
            /* new incoming TCP client attempting to connect? */
            else if (e->arg == MTCP_SOCKET)
            {
                struct multi_instance *mi;
                ASSERT(m->top.c2.link_socket);
                socket_reset_listen_persistent(m->top.c2.link_socket);
                mi = multi_create_instance_tcp(m);
                if (mi)
                {
                    multi_tcp_action(m, mi, TA_INITIAL, false);
                }
            }
            /* signal received? */
            else if (e->arg == MTCP_SIG)
            {
                get_signal(&m->top.sig->signal_received);
            }
#ifdef ENABLE_ASYNC_PUSH
            else if (e->arg == MTCP_FILE_CLOSE_WRITE)
            {
                multi_process_file_closed(m, MPP_PRE_SELECT | MPP_RECORD_TOUCH);
            }
#endif
        }
        if (IS_SIG(&m->top))
        {
            break;
        }
    }
    mtcp->n_esr = 0;

    /*
     * Process queued mbuf packets destined for TCP socket
     */
    {
        struct multi_instance *mi;
        while (!IS_SIG(&m->top) && (mi = mbuf_peek(m->mbuf)) != NULL)
        {
            multi_tcp_action(m, mi, TA_SOCKET_WRITE, true);
        }
    }
}
Пример #11
0
static void
multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll)
{
    bool tun_input_pending = false;

    do
    {
        dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_action a=%s p=%d",
             pract(action),
             poll);

        /*
         * If TA_SOCKET_READ_RESIDUAL, it means we still have pending
         * input packets which were read by a prior TCP recv.
         *
         * Otherwise do a "lite" wait, which means we wait with 0 timeout
         * on I/O events only related to the current instance, not
         * the big list of events.
         *
         * On our first pass, poll will be false because we already know
         * that input is available, and to call io_wait would be redundant.
         */
        if (poll && action != TA_SOCKET_READ_RESIDUAL)
        {
            const int orig_action = action;
            action = multi_tcp_wait_lite(m, mi, action, &tun_input_pending);
            if (action == TA_UNDEF)
            {
                msg(M_FATAL, "MULTI TCP: I/O wait required blocking in multi_tcp_action, action=%d", orig_action);
            }
        }

        /*
         * Dispatch the action
         */
        {
            struct multi_instance *touched = multi_tcp_dispatch(m, mi, action);

            /*
             * Signal received or TCP connection
             * reset by peer?
             */
            if (touched && IS_SIG(&touched->context))
            {
                if (mi == touched)
                {
                    mi = NULL;
                }
                multi_close_instance_on_signal(m, touched);
            }
        }

        /*
         * If dispatch produced any pending output
         * for a particular instance, point to
         * that instance.
         */
        if (m->pending)
        {
            mi = m->pending;
        }

        /*
         * Based on the effects of the action,
         * such as generating pending output,
         * possibly transition to a new action state.
         */
        action = multi_tcp_post(m, mi, action);

        /*
         * If we are finished processing the original action,
         * check if we have any TUN input.  If so, transition
         * our action state to processing this input.
         */
        if (tun_input_pending && action == TA_UNDEF)
        {
            action = TA_TUN_READ;
            mi = NULL;
            tun_input_pending = false;
            poll = false;
        }
        else
        {
            poll = true;
        }

    } while (action != TA_UNDEF);
}
Пример #12
0
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;
}