App-CamelPKI
view release on metacpan or search on metacpan
lib/App/CamelPKI/SysV/Apache.pm view on Meta::CPAN
} elsif ($k eq "-certification_chain") {
write_file($self->_ca_bundle_filename,
join("", map { $_->serialize } @$v));
} else {
throw App::CamelPKI::Error::Internal
("INCORRECT_ARGS",
-details => "Unknown named option $k");
}
}
}
=head2 is_operational()
Returns true if and only if the ad-hoc cryptographic material has been
added to this Web server using L</set_keys>.
=cut
# The above POD is ambiguous on purpose: ->is_operational may someday
# return true even if there is no CA chain available.
sub is_operational {
my ($self) = @_;
-r $self->_key_filename && -r $self->_certificate_filename &&
-r $self->_ca_bundle_filename;
}
=head2 certificate()
Returns the Web server's SSL certificate, as an instance of
L<App::CamelPKI::Certificate>.
=cut
sub certificate {
App::CamelPKI::Certificate->load(shift->_certificate_filename);
}
=head2 update_crl($crl)
Given $crl, an instance of L<App::CamelPKI::CRL>, verifies the signature
thereof and stores it into this Apache server if and only if it
matches one of the CAs previously installed using L</set_keys>'
C<-certificate_chain> named option, B<and> $crl is older than any CRL
previously added with I<update_crl()>. If these security checks are
successful and Apache is already running, it will be restarted so as
to take the new CRL into account immediately.
Note that a Web server works perfectly without a CRL, and therefore
calling I<update_crl> is optional. However, remember that CRLs have
expiration dates: once a CRL has been installed using this method, one
should plan for a suitable mechanism (e.g. a crontab entry) that will
download updated CRLs on a regular basis and submit them using
I<update_crl()>.
=cut
sub update_crl { "UNIMPLEMENTED" }
=head2 start(%opts)
Starts the daemon synchronously, meaning that I<start> will only
return control to its caller after ensuring that the Apache process
wrote its PID file and bound to its TCP port. I<start()> is
idempotent, and terminates immediately if the serveur is already up.
An L<App::CamelPKI::Error/App::CamelPKI::Error::OtherProcess> exception will be
thrown if the server doesn't answer within L</async_timeout> seconds.
An L<App::CamelPKI::Error/App::CamelPKI::Error::User> exception will be thrown
if one attempts to I<start()> the server before providing it with its
certificate and key with L</set_keys>.
Available named options are:
=over
=item I<< -strace => $strace_logfile >>
Starts Apache under the C<strace> debug command, storing all results
into $strace_logfile.
=item I<< -X => 1 >>
Starts Apache with the C<-X> option, which causes it to launch only
one worker and to not detach from the terminal.
=item I<< -gdb => 1 >>
=item I<< -gdb => $tty >>
Starts Apache under the GNU debugger attached to tty $tty (or the
current tty, if the value 1 is specified). Incompatible with
I<-strace>. If this option is specified, I<start()> will not time out
after L</async_timeout> seconds, but will instead wait an unlimited
amount of time for the server to come up.
=item I<< -exec => 1 >>
Don't fork a subprocess, use the C<exec> system call instead (see
L<perlfunc/exec>) to run Apache directly (or more usefully, some
combination of Apache and a debugger, according to the above named
options). The current UNIX process will turn into Apache, and the
I<start> method will therefore never return.
=back
=cut
sub start {
throw App::CamelPKI::Error::Internal("WRONG_NUMBER_ARGS")
unless (@_ % 2);
my ($self, %opts) = @_;
throw App::CamelPKI::Error::OtherProcess("Apache is wedged")
if ($self->is_wedged);
return if $self->is_started;
$self->_write_config_file();
my (@debugprecmd, @dashX);
my $timeout = 1;
if (defined(my $stracefile = delete $opts{-strace})) {
@debugprecmd = ("strace", -o => $stracefile,
qw(-f -s 2000));
} elsif (my $tty = delete $opts{-gdb}) {
@debugprecmd = ("gdb", ( ($tty eq "1") ? () : ("-tty=$tty") ),
"--args");
$timeout = 0;
}
if (delete $opts{-X}) { @dashX = qw(-X); }
my @fullcmdline =
(@debugprecmd,
$self->_apache_bin, @dashX, -f => $self->_config_filename);
if ($opts{-exec}) {
exec(@fullcmdline) or
throw App::CamelPKI::Error::OtherProcess("cannot exec() Apache",
-cmdline => \@fullcmdline);
} else {
# Double fork(), so we don't have to bother with zombies :
fork_and_do { fork_and_do {
exec @fullcmdline;
} };
}
if ($timeout) {
$self->_wait_for(sub { $self->is_started })
or throw App::CamelPKI::Error::OtherProcess("Cannot start Apache");
} else {
while(! $self->is_started) { sleep(1); }
};
return;
}
=head2 stop()
Stops the daemon synchronously, meaning that I<stop> will only return
control to its caller after ensuring that the Apache process whose PID
is in the PID file is terminated, and the TCP port is closed. Like
L</start>, this method is idempotent and returns immediately if the
server was already down.
An exception of class L<App::CamelPKI::Error/App::CamelPKI::Error::OtherProcess>
will be thrown if the server still hasn't stopped after
L</async_timeout> seconds.
Note that the "started" or "stopped" state is persisted to the
filesystem using the usual UNIX PID file mechanism; therefore it is
not necessary to use the same Perl object (or even the same process)
to L</start> and I<stop()> a given server.
=cut
sub stop {
my ($self) = @_;
throw App::CamelPKI::Error::OtherProcess("Apache is wedged")
if ($self->is_wedged);
return # Not wedged and not started means stopped
if ! defined(my $pid = $self->_process_ready);
kill TERM => $pid;
$self->_wait_for(sub { $self->is_stopped })
or throw App::CamelPKI::Error::OtherProcess("Cannot stop Apache");
return;
}
=head2 is_started()
Returns true iff the PID file currently contains the PID of a live
Apache process, B<and> one can connect to the TCP port.
=cut
sub is_started {
my ($self) = @_;
$self->_process_ready && $self->_port_ready;
}
=head2 is_stopped()
Returns true iff the PID file (if it exists at all) contains something
that is not the PID of a live Apache process, B<and> the TCP port is
closed.
=cut
sub is_stopped {
my ($self) = @_;
(! $self->_process_ready) && (! $self->_port_ready);
}
=head2 is_wedged()
Returns true iff neither L</is_stopped>, nor L</is_started> are true
(e.g. if the TCP port is taken, but not by us). One cannot call
L</start> or L</stop> against an instance of I<App::CamelPKI::SysV::Apache>
( run in 1.926 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )