Install tinc as a service under Windows (MinGW). Remove cleanup_and_exit(),

either exit() directly on errors or let main_loop() shutdown gracefully.
This commit is contained in:
Guus Sliepen 2003-08-02 20:50:38 +00:00
parent 7c34122af7
commit f08fc359a0
9 changed files with 410 additions and 175 deletions

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: logger.c,v 1.1.2.8 2003/07/29 22:59:00 guus Exp $
$Id: logger.c,v 1.1.2.9 2003/08/02 20:50:38 guus Exp $
*/
#include "system.h"
@ -71,6 +71,7 @@ void logger(int priority, const char *format, ...) {
fprintf(logfile, "%ld %s[%d]: ", time(NULL), logident, logpid);
vfprintf(logfile, format, ap);
fprintf(logfile, "\n");
fflush(logfile);
break;
case LOGMODE_SYSLOG:
#ifdef HAVE_SYSLOG_H

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.c,v 1.35.4.195 2003/07/29 22:59:00 guus Exp $
$Id: net.c,v 1.35.4.196 2003/08/02 20:50:38 guus Exp $
*/
#include "system.h"
@ -42,6 +42,7 @@
#include "xalloc.h"
bool do_purge = false;
volatile bool running;
time_t now = 0;
@ -280,7 +281,7 @@ static void check_network_activity(fd_set * f)
/*
this is where it all happens...
*/
void main_loop(void)
int main_loop(void)
{
fd_set fset;
struct timeval tv;
@ -294,7 +295,9 @@ void main_loop(void)
last_config_check = now;
srand(now);
for(;;) {
running = true;
while(running) {
now = time(NULL);
tv.tv_sec = 1 + (rand() & 7); /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
@ -310,7 +313,7 @@ void main_loop(void)
strerror(errno));
cp_trace();
dump_connections();
return;
return 1;
}
continue;
@ -379,7 +382,7 @@ void main_loop(void)
if(!read_server_config()) {
logger(LOG_ERR, _("Unable to reread configuration file, exitting."));
exit(1);
return 1;
}
/* Close connections to hosts that have a changed or deleted host config file */
@ -405,8 +408,8 @@ void main_loop(void)
/* Try to make outgoing connections */
try_outgoing_connections();
continue;
}
}
return 0;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.h,v 1.9.4.68 2003/07/29 22:59:00 guus Exp $
$Id: net.h,v 1.9.4.69 2003/08/02 20:50:38 guus Exp $
*/
#ifndef __TINC_NET_H__
@ -135,7 +135,7 @@ extern bool setup_network_connections(void);
extern void setup_outgoing_connection(struct outgoing_t *);
extern void try_outgoing_connections(void);
extern void close_network_connections(void);
extern void main_loop(void);
extern int main_loop(void);
extern void terminate_connection(struct connection_t *, bool);
extern void flush_queue(struct node_t *);
extern bool read_rsa_public_key(struct connection_t *);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: process.c,v 1.1.2.60 2003/07/31 14:24:19 guus Exp $
$Id: process.c,v 1.1.2.61 2003/08/02 20:50:38 guus Exp $
*/
#include "system.h"
@ -43,6 +43,7 @@ extern char *identname;
extern char *pidfilename;
extern char **g_argv;
extern bool use_logfile;
extern volatile bool running;
sigset_t emptysigset;
@ -70,24 +71,154 @@ static int fcloseall(void)
}
#endif
/*
Close network connections, and terminate neatly
*/
void cleanup_and_exit(int c)
{
cp();
#ifdef HAVE_MINGW
extern char *identname;
extern char *program_name;
extern char **g_argv;
close_network_connections();
static SC_HANDLE manager = NULL;
static SC_HANDLE service = NULL;
static SERVICE_STATUS status = {0};
static SERVICE_STATUS_HANDLE statushandle = 0;
ifdebug(CONNECTIONS)
dump_device_stats();
bool install_service(void) {
char command[4096] = "";
char **argp;
logger(LOG_NOTICE, _("Terminating"));
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!manager) {
logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
return false;
}
closelogger();
exit(c);
if(!strchr(program_name, '\\')) {
GetCurrentDirectory(sizeof(command), command);
strncat(command, "\\", sizeof(command));
}
strncat(command, program_name, sizeof(command));
for(argp = g_argv + 1; *argp; argp++) {
strncat(command, " ", sizeof(command));
strncat(command, *argp, sizeof(command));
}
service = CreateService(manager, identname, identname,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
command, "NDIS", NULL, NULL, NULL, NULL);
if(!service) {
logger(LOG_ERR, _("Could not create %s service: %s"), identname, winerror(GetLastError()));
return false;
}
logger(LOG_INFO, _("%s service installed"), identname);
if(!StartService(service, 0, NULL))
logger(LOG_WARNING, _("Could not start %s service: %s"), identname, winerror(GetLastError()));
else
logger(LOG_INFO, _("%s service started"), identname);
return true;
}
bool remove_service(void) {
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!manager) {
logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
return false;
}
service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
if(!service) {
logger(LOG_ERR, _("Could not open %s service: %s"), identname, winerror(GetLastError()));
return false;
}
if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
logger(LOG_ERR, _("Could not stop %s service: %s"), identname, winerror(GetLastError()));
else
logger(LOG_INFO, _("%s service stopped"), identname);
if(!DeleteService(service)) {
logger(LOG_ERR, _("Could not remove %s service: %s"), identname, winerror(GetLastError()));
return false;
}
logger(LOG_INFO, _("%s service removed"), identname);
return true;
}
DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
switch(request) {
case SERVICE_CONTROL_STOP:
logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_STOP");
running = false;
break;
case SERVICE_CONTROL_SHUTDOWN:
logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_SHUTDOWN");
running = false;
break;
default:
logger(LOG_WARNING, _("Got unexpected request %d"), request);
return ERROR_CALL_NOT_IMPLEMENTED;
}
return NO_ERROR;
}
VOID WINAPI run_service(DWORD argc, LPTSTR* argv)
{
int err = 1;
extern int main2(int argc, char **argv);
status.dwServiceType = SERVICE_WIN32;
status.dwCurrentState = SERVICE_RUNNING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL);
if (!statushandle) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
err = 1;
} else {
SetServiceStatus(statushandle, &status);
err = main2(argc, argv);
status.dwCurrentState = SERVICE_STOPPED;
status.dwWin32ExitCode = err;
SetServiceStatus(statushandle, &status);
}
return;
}
bool init_service(void) {
SERVICE_TABLE_ENTRY services[] = {
{identname, run_service},
{NULL, NULL}
};
if(!StartServiceCtrlDispatcher(services)) {
if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
return false;
}
else
logger(LOG_ERR, _("System call `%s' failed: %s"), "StartServiceCtrlDispatcher", winerror(GetLastError()));
}
return true;
}
#endif
#ifndef HAVE_MINGW
/*
check for an existing tinc for this net, and write pid to pidfile
@ -151,9 +282,11 @@ bool kill_other(int signal)
fprintf(stderr, _("Removing stale lock file.\n"));
remove_pid(pidfilename);
}
#endif
return true;
#else
return remove_service();
#endif
}
/*
@ -170,14 +303,14 @@ bool detach(void)
#ifndef HAVE_MINGW
if(!write_pidfile())
return false;
#endif
/* If we succeeded in doing that, detach */
closelogger();
#endif
#ifdef HAVE_FORK
if(do_detach) {
#ifndef HAVE_MINGW
if(daemon(0, 0)) {
fprintf(stderr, _("Couldn't detach from terminal: %s"),
strerror(errno));
@ -188,8 +321,11 @@ bool detach(void)
if(!write_pid(pidfilename))
return false;
}
#else
if(!statushandle)
exit(install_service());
#endif
}
openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
@ -312,14 +448,13 @@ bool execute_script(const char *name, char **envp)
static RETSIGTYPE sigterm_handler(int a)
{
logger(LOG_NOTICE, _("Got TERM signal"));
cleanup_and_exit(0);
running = false;
}
static RETSIGTYPE sigquit_handler(int a)
{
logger(LOG_NOTICE, _("Got QUIT signal"));
cleanup_and_exit(0);
running = false;
}
static RETSIGTYPE fatal_signal_square(int a)

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: process.h,v 1.1.2.18 2003/07/30 21:52:41 guus Exp $
$Id: process.h,v 1.1.2.19 2003/08/02 20:50:38 guus Exp $
*/
#ifndef __TINC_PROCESS_H__
@ -31,6 +31,5 @@ extern void setup_signals(void);
extern bool execute_script(const char *, char **);
extern bool detach(void);
extern bool kill_other(int);
extern void cleanup_and_exit(int) __attribute__ ((__noreturn__));
#endif /* __TINC_PROCESS_H__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: tincd.c,v 1.10.4.79 2003/07/30 11:50:45 guus Exp $
$Id: tincd.c,v 1.10.4.80 2003/08/02 20:50:38 guus Exp $
*/
#include "system.h"
@ -77,7 +77,8 @@ char *identname = NULL; /* program name for syslog */
char *pidfilename = NULL; /* pid file location */
char *logfilename = NULL; /* log file location */
char **g_argv; /* a copy of the cmdline arguments */
char **environment; /* A pointer to the environment on startup */
int exitstatus = 0;
static struct option const long_options[] = {
{"config", required_argument, NULL, 'c'},
@ -119,11 +120,9 @@ static void usage(bool status)
" --version Output version information and exit.\n\n"));
printf(_("Report bugs to tinc@nl.linux.org.\n"));
}
exit(status);
}
static void parse_options(int argc, char **argv, char **envp)
static bool parse_options(int argc, char **argv)
{
int r;
int option_index = 0;
@ -178,10 +177,13 @@ static void parse_options(int argc, char **argv, char **envp)
fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"),
optarg);
usage(true);
return false;
}
}
} else
kill_tincd = SIGTERM;
#else
kill_tincd = 1;
#endif
break;
@ -197,6 +199,7 @@ static void parse_options(int argc, char **argv, char **envp)
fprintf(stderr, _("Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n"),
optarg);
usage(true);
return false;
}
generate_keys &= ~7; /* Round it to bytes */
@ -228,11 +231,14 @@ static void parse_options(int argc, char **argv, char **envp)
case '?':
usage(true);
return false;
default:
break;
}
}
return true;
}
/* This function prettyprints the key generation process */
@ -354,7 +360,7 @@ static void make_names(void)
}
}
int main(int argc, char **argv, char **envp)
int main(int argc, char **argv)
{
program_name = argv[0];
@ -362,8 +368,9 @@ int main(int argc, char **argv, char **envp)
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
environment = envp;
parse_options(argc, argv, envp);
if(!parse_options(argc, argv))
return 1;
make_names();
if(show_version) {
@ -378,11 +385,13 @@ int main(int argc, char **argv, char **envp)
return 0;
}
if(show_help)
if(show_help) {
usage(false);
return 0;
}
if(kill_tincd)
exit(!kill_other(kill_tincd));
return !kill_other(kill_tincd);
openlogger("tinc", LOGMODE_STDERR);
@ -412,31 +421,48 @@ int main(int argc, char **argv, char **envp)
if(generate_keys) {
read_server_config();
exit(!keygen(generate_keys));
return !keygen(generate_keys);
}
if(!read_server_config())
exit(1);
return 1;
if(lzo_init() != LZO_E_OK) {
logger(LOG_ERR, _("Error initializing LZO compressor!"));
exit(1);
return 1;
}
#ifdef HAVE_MINGW
if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", strerror(errno));
exit(1);
logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError()));
return 1;
}
if(!do_detach || !init_service())
return main2(argc, argv);
else
return 1;
}
int main2(int argc, char **argv)
{
#endif
if(!detach())
exit(1);
return 1;
for(;;) {
if(setup_network_connections()) {
main_loop();
cleanup_and_exit(1);
int status;
status = main_loop();
close_network_connections();
ifdebug(CONNECTIONS)
dump_device_stats();
logger(LOG_NOTICE, _("Terminating"));
return status;
}
logger(LOG_ERR, _("Unrecoverable error"));
@ -447,7 +473,7 @@ int main(int argc, char **argv, char **envp)
sleep(maxtimeout);
} else {
logger(LOG_ERR, _("Not restarting."));
exit(1);
return 1;
}
}
}