/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef WIN32
#include "config-win32.h"
#else
#include "config.h"
#endif
#include "syshead.h"
#include "init.h"
#include "forward.h"
#include "multi.h"
#include "memdbg.h"
#include "forward-inline.h"
#define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL (c, process_signal_p2p, c);
static bool
process_signal_p2p (struct context *c)
{
remap_signal (c);
return process_signal (c);
}
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;
init_management_callback_p2p (c);
/* 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);
}
#undef PROCESS_SIGNAL_P2P
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
{
/* 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 (&c.gc);
#ifdef ENABLE_MANAGEMENT
/* initialize management subsystem */
init_management (&c);
#endif
/* initialize options to default state */
init_options (&c.options);
/* parse command line options, and read configuration file */
parse_argv (&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
/* 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, c.first_time);
/* 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);
#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 */
}