Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Mike Perry
Tor
Commits
4b266c6e
Commit
4b266c6e
authored
May 15, 2011
by
Robert Ransom
Browse files
Implement __OwningControllerProcess option
Implements part of feature 3049.
parent
c714a098
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/common/Makefile.am
View file @
4b266c6e
...
...
@@ -12,11 +12,11 @@ libor_extra_source=
endif
libor_a_SOURCES
=
address.c log.c util.c compat.c container.c mempool.c
\
memarea.c util_codedigest.c
$(libor_extra_source)
memarea.c util_codedigest.c
procmon.c
$(libor_extra_source)
libor_crypto_a_SOURCES
=
crypto.c aes.c tortls.c torgzip.c
libor_event_a_SOURCES
=
compat_libevent.c
noinst_HEADERS
=
address.h torlog.h crypto.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h ciphers.inc compat_libevent.h tortls_states.h
noinst_HEADERS
=
address.h torlog.h crypto.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h
procmon.h
ciphers.inc compat_libevent.h tortls_states.h
common_sha1.i
:
$(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
if
test
"@SHA1SUM@"
!=
none
;
then
\
...
...
src/common/procmon.c
0 → 100644
View file @
4b266c6e
/**
* \file procmon.c
* \brief Process-termination monitor functions
**/
#include
"procmon.h"
#include
"util.h"
#ifdef HAVE_EVENT2_EVENT_H
#include
<event2/event.h>
#else
#include
<event.h>
#endif
#ifdef HAVE_SIGNAL_H
#include
<signal.h>
#endif
#ifdef HAVE_ERRNO_H
#include
<errno.h>
#endif
#ifdef MS_WINDOWS
#include
<windows.h>
/* Windows does not define pid_t, but _getpid() returns an int. */
typedef
int
pid_t
;
#endif
/* Define to 1 if process-termination monitors on this OS and Libevent
version must poll for process termination themselves. */
#define PROCMON_POLLS 1
/* Currently we need to poll in some way on all systems. */
#ifdef PROCMON_POLLS
static
void
tor_process_monitor_poll_cb
(
int
unused1
,
short
unused2
,
void
*
procmon_
);
#endif
/* This struct may contain pointers into the original process
* specifier string, but it should *never* contain anything which
* needs to be freed. */
struct
parsed_process_specifier_t
{
pid_t
pid
;
};
/** Parse the process specifier given in <b>process_spec</b> into
* *<b>ppspec</b>. Return 0 on success; return -1 and store an error
* message into *<b>msg</b> on failure. The caller must not free the
* returned error message. */
static
int
parse_process_specifier
(
const
char
*
process_spec
,
struct
parsed_process_specifier_t
*
ppspec
,
const
char
**
msg
)
{
long
pid_l
;
int
pid_ok
=
0
;
char
*
pspec_next
;
/* If we're lucky, long will turn out to be large enough to hold a
* PID everywhere that Tor runs. */
pid_l
=
tor_parse_long
(
process_spec
,
0
,
1
,
LONG_MAX
,
&
pid_ok
,
&
pspec_next
);
/* Reserve room in the ‘process specifier’ for additional
* (platform-specific) identifying information beyond the PID, to
* make our process-existence checks a bit less racy in a future
* version. */
if
((
*
pspec_next
!=
0
)
&&
(
*
pspec_next
!=
' '
)
&&
(
*
pspec_next
!=
':'
))
{
pid_ok
=
0
;
}
ppspec
->
pid
=
(
pid_t
)(
pid_l
);
if
(
!
pid_ok
||
(
pid_l
!=
(
long
)(
ppspec
->
pid
)))
{
*
msg
=
"invalid PID"
;
goto
err
;
}
return
0
;
err:
return
-
1
;
}
struct
tor_process_monitor_t
{
/** Log domain for warning messages. */
log_domain_mask_t
log_domain
;
/** All systems: The best we can do in general is poll for the
* process's existence by PID periodically, and hope that the kernel
* doesn't reassign the same PID to another process between our
* polls. */
pid_t
pid
;
#ifdef MS_WINDOWS
/** Windows-only: Should we poll hproc? If false, poll pid
* instead. */
int
poll_hproc
;
/** Windows-only: Get a handle to the process (if possible) and
* periodically check whether the process we have a handle to has
* ended. */
HANDLE
hproc
;
/* XXX023 We can and should have Libevent watch hproc for us,
* if/when some version of Libevent 2.x can be told to do so. */
#endif
/* XXX023 On Linux, we can and should receive the 22nd
* (space-delimited) field (‘starttime’) of /proc/$PID/stat from the
* owning controller and store it, and poll once in a while to see
* whether it has changed -- if so, the kernel has *definitely*
* reassigned the owning controller's PID and we should exit. On
* FreeBSD, we can do the same trick using either the 8th
* space-delimited field of /proc/$PID/status on the seven FBSD
* systems whose admins have mounted procfs, or the start-time field
* of the process-information structure returned by kvmgetprocs() on
* any system. The latter is ickier. */
/* XXX023 On FreeBSD (and possibly other kqueue systems), we can and
* should arrange to receive EVFILT_PROC NOTE_EXIT notifications for
* pid, so we don't have to do such a heavyweight poll operation in
* order to avoid the PID-reassignment race condition. (We would
* still need to poll our own kqueue periodically until some version
* of Libevent 2.x learns to receive these events for us.) */
/** A Libevent event structure, to either poll for the process's
* existence or receive a notification when the process ends. */
struct
event
*
e
;
/** A callback to be called when the process ends. */
tor_procmon_callback_t
cb
;
void
*
cb_arg
;
/**< A user-specified pointer to be passed to cb. */
};
/** Verify that the process specifier given in <b>process_spec</b> is
* syntactically valid. Return 0 on success; return -1 and store an
* error message into *<b>msg</b> on failure. The caller must not
* free the returned error message. */
int
tor_validate_process_specifier
(
const
char
*
process_spec
,
const
char
**
msg
)
{
struct
parsed_process_specifier_t
ppspec
;
tor_assert
(
msg
!=
NULL
);
*
msg
=
NULL
;
return
parse_process_specifier
(
process_spec
,
&
ppspec
,
msg
);
}
#ifdef HAVE_EVENT2_EVENT_H
#define PERIODIC_TIMER_FLAGS EV_PERSIST
#else
#define PERIODIC_TIMER_FLAGS (0)
#endif
static
const
struct
timeval
poll_interval_tv
=
{
15
,
0
};
/** Create a process-termination monitor for the process specifier
* given in <b>process_spec</b>. Return a newly allocated
* tor_process_monitor_t on success; return NULL and store an error
* message into *<b>msg</b> on failure. The caller must not free
* the returned error message.
*
* When the monitored process terminates, call
* <b>cb</b>(<b>cb_arg</b>).
*/
tor_process_monitor_t
*
tor_process_monitor_new
(
struct
event_base
*
base
,
const
char
*
process_spec
,
log_domain_mask_t
log_domain
,
tor_procmon_callback_t
cb
,
void
*
cb_arg
,
const
char
**
msg
)
{
tor_process_monitor_t
*
procmon
=
tor_malloc
(
sizeof
(
tor_process_monitor_t
));
struct
parsed_process_specifier_t
ppspec
;
tor_assert
(
msg
!=
NULL
);
*
msg
=
NULL
;
if
(
procmon
==
NULL
)
{
*
msg
=
"out of memory"
;
goto
err
;
}
procmon
->
log_domain
=
log_domain
;
if
(
parse_process_specifier
(
process_spec
,
&
ppspec
,
msg
))
goto
err
;
procmon
->
pid
=
ppspec
.
pid
;
#ifdef MS_WINDOWS
procmon
->
hproc
=
OpenProcess
(
PROCESS_QUERY_INFORMATION
|
SYNCHRONIZE
,
FALSE
,
procmon
->
pid
);
if
(
procmon
->
hproc
!=
NULL
)
{
procmon
->
poll_hproc
=
1
;
log_info
(
procmon
->
log_domain
,
"Successfully opened handle to process %d; "
"monitoring it."
,
(
int
)(
procmon
->
pid
));
}
else
{
/* If we couldn't get a handle to the process, we'll try again the
* first time we poll. */
log_info
(
procmon
->
log_domain
,
"Failed to open handle to process %d; will "
"try again later."
,
(
int
)(
procmon
->
pid
));
}
#endif
procmon
->
cb
=
cb
;
procmon
->
cb_arg
=
cb_arg
;
#ifdef PROCMON_POLLS
procmon
->
e
=
tor_event_new
(
base
,
-
1
/* no FD */
,
PERIODIC_TIMER_FLAGS
,
tor_process_monitor_poll_cb
,
procmon
);
/* Note: If you port this file to plain Libevent 2, check that
* procmon->e is non-NULL. We don't need to here because
* tor_evtimer_new never returns NULL. */
evtimer_add
(
procmon
->
e
,
&
poll_interval_tv
);
#else
#error OOPS?
#endif
return
procmon
;
err:
tor_process_monitor_free
(
procmon
);
return
NULL
;
}
#ifdef PROCMON_POLLS
/** Libevent callback to poll for the existence of the process
* monitored by <b>procmon_</b>. */
static
void
tor_process_monitor_poll_cb
(
int
unused1
,
short
unused2
,
void
*
procmon_
)
{
tor_process_monitor_t
*
procmon
=
(
tor_process_monitor_t
*
)(
procmon_
);
int
its_dead_jim
;
(
void
)
unused1
;
(
void
)
unused2
;
tor_assert
(
procmon
!=
NULL
);
#ifdef MS_WINDOWS
if
(
procmon
->
poll_hproc
)
{
DWORD
exit_code
;
if
(
!
GetExitCodeProcess
(
procmon
->
hproc
,
&
exit_code
))
{
char
*
errmsg
=
format_win32_error
(
GetLastError
());
log_warn
(
procmon
->
log_domain
,
"Error
\"
%s
\"
occurred while polling "
"handle for monitored process %d; assuming it's dead."
errmsg
,
procmon
->
pid
);
tor_free
(
errmsg
);
its_dead_jim
=
1
;
}
else
{
its_dead_jim
=
(
exit_code
!=
STILL_ACTIVE
);
}
}
else
{
/* All we can do is try to open the process, and look at the error
* code if it fails again. */
procmon
->
hproc
=
OpenProcess
(
PROCESS_QUERY_INFORMATION
|
SYNCHRONIZE
,
FALSE
,
procmon
->
pid
);
if
(
procmon
->
hproc
!=
NULL
)
{
log_info
(
procmon
->
log_domain
,
"Successfully opened handle to monitored "
"process %d."
,
procmon
->
pid
);
its_dead_jim
=
0
;
procmon
->
poll_hproc
=
1
;
}
else
{
DWORD
err_code
=
GetLastError
();
char
*
errmsg
=
format_win32_error
(
err_code
);
/* When I tested OpenProcess's error codes on Windows 7, I
* received error code 5 (ERROR_ACCESS_DENIED) for PIDs of
* existing processes that I could not open and error code 87
* (ERROR_INVALID_PARAMETER) for PIDs that were not in use.
* Since the nonexistent-process error code is sane, I'm going
* to assume that all errors other than ERROR_INVALID_PARAMETER
* mean that the process we are monitoring is still alive. */
its_dead_jim
=
(
err_code
==
ERROR_INVALID_PARAMETER
);
if
(
!
its_dead_jim
)
log_info
(
procmon
->
log_domain
,
"Failed to open handle to monitored "
"process %d, and error code %d (%s) is not 'invalid "
"parameter' -- assuming the process is still alive."
,
procmon
->
pid
,
err_code
,
err_msg
);
tor_free
(
err_msg
);
}
}
#else
/* Unix makes this part easy, if a bit racy. */
its_dead_jim
=
kill
(
procmon
->
pid
,
0
);
its_dead_jim
=
its_dead_jim
&&
(
errno
==
ESRCH
);
#endif
log
(
its_dead_jim
?
LOG_NOTICE
:
LOG_INFO
,
procmon
->
log_domain
,
"Monitored process %d is %s."
,
(
int
)
procmon
->
pid
,
its_dead_jim
?
"dead"
:
"still alive"
);
if
(
its_dead_jim
)
{
procmon
->
cb
(
procmon
->
cb_arg
);
#ifndef HAVE_EVENT2_EVENT_H
}
else
{
evtimer_add
(
procmon
->
e
,
&
poll_interval_tv
);
#endif
}
}
#endif
/** Free the process-termination monitor <b>procmon</b>. */
void
tor_process_monitor_free
(
tor_process_monitor_t
*
procmon
)
{
if
(
procmon
==
NULL
)
return
;
#ifdef MS_WINDOWS
if
(
procmon
->
hproc
!=
NULL
)
CloseHandle
(
procmon
->
hproc
);
#endif
if
(
procmon
->
e
!=
NULL
)
tor_event_free
(
procmon
->
e
);
tor_free
(
procmon
);
}
src/common/procmon.h
0 → 100644
View file @
4b266c6e
/**
* \file procmon.h
* \brief Headers for procmon.c
**/
#ifndef TOR_PROCMON_H
#define TOR_PROCMON_H
#include
"compat.h"
#include
"compat_libevent.h"
#include
"torlog.h"
typedef
struct
tor_process_monitor_t
tor_process_monitor_t
;
typedef
void
(
*
tor_procmon_callback_t
)(
void
*
);
int
tor_validate_process_specifier
(
const
char
*
process_spec
,
const
char
**
msg
);
tor_process_monitor_t
*
tor_process_monitor_new
(
struct
event_base
*
base
,
const
char
*
process_spec
,
log_domain_mask_t
log_domain
,
tor_procmon_callback_t
cb
,
void
*
cb_arg
,
const
char
**
msg
);
void
tor_process_monitor_free
(
tor_process_monitor_t
*
procmon
);
#endif
src/or/config.c
View file @
4b266c6e
...
...
@@ -38,6 +38,8 @@
#include
<shlobj.h>
#endif
#include
"procmon.h"
/** Enumeration of types which option values can take */
typedef
enum
config_type_t
{
CONFIG_TYPE_STRING
=
0
,
/**< An arbitrary string. */
...
...
@@ -393,6 +395,7 @@ static config_var_t _option_vars[] = {
VAR
(
"__LeaveStreamsUnattached"
,
BOOL
,
LeaveStreamsUnattached
,
"0"
),
VAR
(
"__HashedControlSessionPassword"
,
LINELIST
,
HashedControlSessionPassword
,
NULL
),
VAR
(
"__OwningControllerProcess"
,
STRING
,
OwningControllerProcess
,
NULL
),
V
(
MinUptimeHidServDirectoryV2
,
INTERVAL
,
"24 hours"
),
V
(
_UsingTestNetworkDefaults
,
BOOL
,
"0"
),
...
...
@@ -1229,6 +1232,11 @@ options_act(or_options_t *old_options)
return
-
1
;
}
if
(
monitor_owning_controller_process
(
options
->
OwningControllerProcess
))
{
log_warn
(
LD_CONFIG
,
"Error monitoring owning controller process"
);
return
-
1
;
}
/* reload keys as needed for rendezvous services. */
if
(
rend_service_load_keys
()
<
0
)
{
log_warn
(
LD_GENERAL
,
"Error loading rendezvous service keys"
);
...
...
@@ -3446,6 +3454,16 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
if
(
options
->
OwningControllerProcess
)
{
const
char
*
validate_pspec_msg
=
NULL
;
if
(
tor_validate_process_specifier
(
options
->
OwningControllerProcess
,
&
validate_pspec_msg
))
{
tor_asprintf
(
msg
,
"Bad OwningControllerProcess: %s"
,
validate_pspec_msg
);
return
-
1
;
}
}
if
(
options
->
ControlListenAddress
)
{
int
all_are_local
=
1
;
config_line_t
*
ln
;
...
...
src/or/control.c
View file @
4b266c6e
...
...
@@ -32,6 +32,8 @@
#include
"routerlist.h"
#include
"routerparse.h"
#include
"procmon.h"
/** Yield true iff <b>s</b> is the state of a control_connection_t that has
* finished authentication and is accepting commands. */
#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN)
...
...
@@ -3779,6 +3781,90 @@ init_cookie_authentication(int enabled)
return
0
;
}
/** A copy of the process specifier of Tor's owning controller, or
* NULL if this Tor instance is not currently owned by a process. */
static
char
*
owning_controller_process_spec
=
NULL
;
/** A process-termination monitor for Tor's owning controller, or NULL
* if this Tor instance is not currently owned by a process. */
static
tor_process_monitor_t
*
owning_controller_process_monitor
=
NULL
;
/** Process-termination monitor callback for Tor's owning controller
* process. */
static
void
owning_controller_procmon_cb
(
void
*
unused
)
{
int
shutdown_slowly
=
server_mode
(
get_options
());
(
void
)
unused
;
log_notice
(
LD_CONTROL
,
"Owning controller process has vanished -- "
"%s."
,
shutdown_slowly
?
"shutting down"
:
"exiting now"
);
/* XXXX This chunk of code should be a separate function, called
* here and by process_signal(SIGINT). */
if
(
!
shutdown_slowly
)
{
tor_cleanup
();
exit
(
0
);
}
/* XXXX This will close all listening sockets except control-port
* listeners. Perhaps we should close those too. */
hibernate_begin_shutdown
();
}
/** Set <b>process_spec</b> as Tor's owning controller process.
* Return 0 on success, -1 on failure. */
int
monitor_owning_controller_process
(
const
char
*
process_spec
)
{
const
char
*
msg
;
tor_assert
((
owning_controller_process_spec
==
NULL
)
==
(
owning_controller_process_monitor
==
NULL
));
if
(
owning_controller_process_spec
!=
NULL
)
{
if
((
process_spec
!=
NULL
)
&&
!
strcmp
(
process_spec
,
owning_controller_process_spec
))
{
/* Same process -- return now, instead of disposing of and
* recreating the process-termination monitor. */
return
0
;
}
/* We are currently owned by a process, and we should no longer be
* owned by it. Free the process-termination monitor. */
tor_process_monitor_free
(
owning_controller_process_monitor
);
owning_controller_process_monitor
=
NULL
;
tor_free
(
owning_controller_process_spec
);
owning_controller_process_spec
=
NULL
;
}
tor_assert
((
owning_controller_process_spec
==
NULL
)
&&
(
owning_controller_process_monitor
==
NULL
));
if
(
process_spec
==
NULL
)
return
0
;
owning_controller_process_spec
=
tor_strdup
(
process_spec
);
owning_controller_process_monitor
=
tor_process_monitor_new
(
tor_libevent_get_base
(),
owning_controller_process_spec
,
LD_CONTROL
,
owning_controller_procmon_cb
,
NULL
,
&
msg
);
if
(
owning_controller_process_monitor
==
NULL
)
{
log_warn
(
LD_CONTROL
,
"Couldn't create process-termination monitor for "
"owning controller: %s"
,
msg
);
return
-
1
;
}
return
0
;
}
/** Convert the name of a bootstrapping phase <b>s</b> into strings
* <b>tag</b> and <b>summary</b> suitable for display by the controller. */
static
int
...
...
src/or/control.h
View file @
4b266c6e
...
...
@@ -70,6 +70,8 @@ smartlist_t *decode_hashed_passwords(config_line_t *passwords);
void
disable_control_logging
(
void
);
void
enable_control_logging
(
void
);
int
monitor_owning_controller_process
(
const
char
*
process_spec
);
void
control_event_bootstrap
(
bootstrap_status_t
status
,
int
progress
);
void
control_event_bootstrap_problem
(
const
char
*
warn
,
int
reason
);
...
...
src/or/or.h
View file @
4b266c6e
...
...
@@ -2669,6 +2669,11 @@ typedef struct {
int
DisablePredictedCircuits
;
/**< Boolean: does Tor preemptively
* make circuits in the background (0),
* or not (1)? */
/** Process specifier for a controller that ‘owns’ this Tor
* instance. Tor will terminate if its owning controller does. */
char
*
OwningControllerProcess
;
int
ShutdownWaitLength
;
/**< When we get a SIGINT and we're a server, how
* long do we wait before exiting? */
char
*
SafeLogging
;
/**< Contains "relay", "1", "0" (meaning no scrubbing). */
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment