[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