[Bps-public-commit] r10937 - in Net-IMAP-Server: lib/Net/IMAP lib/Net/IMAP/Server lib/Net/IMAP/Server/Command
alexmv at bestpractical.com
alexmv at bestpractical.com
Tue Feb 26 01:12:58 EST 2008
Author: alexmv
Date: Tue Feb 26 01:12:58 2008
New Revision: 10937
Modified:
Net-IMAP-Server/ (props changed)
Net-IMAP-Server/lib/Net/IMAP/Server.pm
Net-IMAP-Server/lib/Net/IMAP/Server/Command/Starttls.pm
Net-IMAP-Server/lib/Net/IMAP/Server/Connection.pm
Log:
r28118 at zoq-fot-pik: chmrr | 2008-02-26 01:12:39 -0500
* Don't just ->cancel connections on print errors, throw back to the
top with a die
* Use new Net::Server::Coro SSL socket infrastrcture
* Idle timeouts and command limits
Modified: Net-IMAP-Server/lib/Net/IMAP/Server.pm
==============================================================================
--- Net-IMAP-Server/lib/Net/IMAP/Server.pm (original)
+++ Net-IMAP-Server/lib/Net/IMAP/Server.pm Tue Feb 26 01:12:58 2008
@@ -55,7 +55,7 @@
=cut
__PACKAGE__->mk_accessors(
- qw/connections port ssl_port auth_class model_class connection_class user group poll_every/
+ qw/connections port ssl_port auth_class model_class connection_class user group poll_every unauth_idle auth_idle unauth_commands/
);
=head2 new PARAMHASH
@@ -109,6 +109,23 @@
How often the current mailbox should be polled, in seconds; defaults
to 0, which means it will be polled after every client command.
+=item unauth_commands
+
+The number of commands before unauthenticated users are disconnected.
+The default is 10; set to zero to disable.
+
+=item unauth_idle
+
+How long, in seconds, to wait before disconnecting idle connections
+which have not authenticated yet. The default is 5 minutes; set to
+zero to disable (which is not advised).
+
+=item auth_idle
+
+How long, in seconds, to wait before disconnecting authentiated
+connections. By RFC specification, this B<must> be longer than 30
+minutes. The default is an hour; set to zero to disable.
+
=back
=cut
@@ -128,6 +145,9 @@
model_class => "Net::IMAP::Server::DefaultModel",
connection_class => "Net::IMAP::Server::Connection",
poll_every => 0,
+ unauth_idle => 5*60,
+ auth_idle => 60*60,
+ unauth_commands => 10,
@_,
connections => [],
}
@@ -193,7 +213,6 @@
io_handle => $handle,
server => $self,
);
- $Coro::current->prio(-4);
push @{ $self->connections }, $conn;
$conn->handle_lines;
}
Modified: Net-IMAP-Server/lib/Net/IMAP/Server/Command/Starttls.pm
==============================================================================
--- Net-IMAP-Server/lib/Net/IMAP/Server/Command/Starttls.pm (original)
+++ Net-IMAP-Server/lib/Net/IMAP/Server/Command/Starttls.pm Tue Feb 26 01:12:58 2008
@@ -31,12 +31,7 @@
$self->ok_completed;
- require Net::Server::Proto::SSL;
- my $handle = $self->connection->io_handle;
- $handle = tied(${$handle})->[0];
- IO::Socket::SSL->start_SSL( $handle,
- SSL_server => 1, );
- bless $handle, "Net::Server::Proto::SSL";
+ $self->connection->io_handle->start_SSL;
}
1;
Modified: Net-IMAP-Server/lib/Net/IMAP/Server/Connection.pm
==============================================================================
--- Net-IMAP-Server/lib/Net/IMAP/Server/Connection.pm (original)
+++ Net-IMAP-Server/lib/Net/IMAP/Server/Connection.pm Tue Feb 26 01:12:58 2008
@@ -10,7 +10,7 @@
use Net::IMAP::Server::Command;
__PACKAGE__->mk_accessors(
- qw(server io_handle _selected selected_read_only model pending temporary_messages temporary_sequence_map previous_exists untagged_expunge untagged_fetch ignore_flags last_poll)
+ qw(server io_handle _selected selected_read_only model pending temporary_messages temporary_sequence_map previous_exists untagged_expunge untagged_fetch ignore_flags last_poll commands timer coro)
);
=head1 NAME
@@ -36,10 +36,12 @@
state => "unauth",
untagged_expunge => [],
untagged_fetch => {},
- last_poll => time
+ last_poll => time,
+ commands => 0,
+ coro => $Coro::current,
}
);
- $self->greeting;
+ $self->update_timer;
return $self;
}
@@ -47,6 +49,12 @@
Returns the L<Net::IMAP::Server> that this connection is on.
+=head2 coro
+
+Returns the L<Coro> process associated with this connection. For
+things interacting with this conneciton, it will probably be the
+current coroutine, except for interactions coming from event loops.
+
=head2 io_handle
Returns the IO handle that can be used to read from or write to the
@@ -72,6 +80,7 @@
$self->{auth} = shift;
$self->server->{auth} = $self->{auth};
$self->server->model_class->require || warn $@;
+ $self->update_timer;
$self->model(
$self->server->model_class->new( { auth => $self->{auth} } ) );
}
@@ -118,17 +127,61 @@
sub handle_lines {
my $self = shift;
- while ( $self->io_handle and $_ = $self->io_handle->getline() ) {
- $self->handle_command($_);
- cede;
- }
+ $self->coro->prio(-4);
+ eval {
+ $self->greeting;
+ while ( $self->io_handle and $_ = $self->io_handle->getline() ) {
+ $self->handle_command($_);
+ $self->commands( $self->commands + 1 );
+ if ( $self->is_unauth
+ and $self->server->unauth_commands
+ and $self->commands >= $self->server->unauth_commands )
+ {
+ $self->out(
+ "* BYE Don't noodle around so much before logging in!");
+ $self->close;
+ last;
+ }
+ $self->update_timer;
+ cede;
+ }
- $self->log(
- "-(@{[$self]},@{[$self->auth ? $self->auth->user : '???']},@{[$self->is_selected ? $self->selected->full_path : 'unselected']}): Connection closed by remote host"
- );
- $self->close;
+ $self->log(
+ "-(@{[$self]},@{[$self->auth ? $self->auth->user : '???']},@{[$self->is_selected ? $self->selected->full_path : 'unselected']}): Connection closed by remote host"
+ );
+ $self->close;
+ };
+ my $err = $@;
+ warn $err
+ if $err and not( $err eq "Error printing\n" or $err eq "Timeout\n" );
+}
+
+=head2 update_timer
+
+Updates the inactivity timer.
+
+=cut
+
+sub update_timer {
+ my $self = shift;
+ $self->timer->stop if $self->timer;
+ $self->timer(undef);
+ my $timeout = sub {
+ eval { $self->out("* BYE Idle timeout; I fell asleep."); };
+ $self->coro->throw("Timeout\n");
+ $self->coro->ready;
+ };
+ if ( $self->is_unauth and $self->server->unauth_idle ) {
+ $self->timer( EV::timer $self->server->unauth_idle, 0, $timeout );
+ } elsif ( $self->server->auth_idle ) {
+ $self->timer( EV::timer $self->server->auth_idle, 0, $timeout );
+ }
}
+=head2 timer [EV watcher]
+
+Returns the L<EV> watcher in charge of the inactivity timer.
+
=head2 handle_command
Handles a single line from the client. This is not quite the same as
@@ -197,10 +250,10 @@
$self->server->connections(
[ grep { $_ ne $self } @{ $self->server->connections } ] );
if ( $self->io_handle ) {
- $self->log("Closing connection $self");
$self->io_handle->close;
$self->io_handle(undef);
}
+ $self->timer->stop if $self->timer;
$self->selected->close if $self->selected;
$self->model->close if $self->model;
}
@@ -273,9 +326,7 @@
sub is_encrypted {
my $self = shift;
- my $handle = $self->io_handle;
- $handle = tied( ${$handle} )->[0];
- return $handle->isa("IO::Socket::SSL");
+ return $self->io_handle->is_ssl;
}
=head2 poll
@@ -392,8 +443,7 @@
$ids{ @{$messages} + 0 }++;
}
}
- return
- grep {defined}
+ return grep {defined}
map { $messages->[ $_ - 1 ] } sort { $a <=> $b } keys %ids;
}
@@ -467,8 +517,7 @@
Sends the mesage to the client. If the client's connection has
dropped, or the send fails for whatever reason, L</close> the
-connection and then abort the coroutine; in which case, this function
-never returns!
+connection and then die, which is caught by L</handle_lines>.
=cut
@@ -482,15 +531,11 @@
);
} else {
$self->close;
-
- # Bail out; never returns
- $Coro::current->cancel;
+ die "Error printing\n";
}
} else {
$self->close;
-
- # Bail out; never returns
- $Coro::current->cancel;
+ die "Error printing\n";
}
}
More information about the Bps-public-commit
mailing list