File Coverage

blib/lib/Net/Server/POP3proxy.pm
Criterion Covered Total %
statement 15 304 4.9
branch 0 158 0.0
condition 0 30 0.0
subroutine 5 30 16.6
pod 3 21 14.2
total 23 543 4.2


line stmt bran cond sub pod time code
1             package Net::Server::POP3proxy;
2              
3 1     1   728 use strict;
  1         2  
  1         29  
4 1     1   18 use vars qw($VERSION);
  1         1  
  1         55  
5             $VERSION = '0.1';
6              
7 1     1   860 use POSIX;
  1         6997  
  1         5  
8 1     1   4143 use IO::Socket;
  1         29055  
  1         4  
9 1     1   1687 use IO::Select;
  1         1670  
  1         3582  
10              
11             # Constructor
12             # Parameters: Port, Error, Debug, Action
13             sub new {
14             # no need to check subclassing ... not public
15 0     0 1   my $proto = shift;
16              
17             # generate a clear hash for holding data
18             my $self = {
19             # default parameters
20             Port => 110,
21 0     0     Error => sub { die ($_[0]); },
22 0     0     Debug => sub { print gmtime() . ": " . $_[0] . "\n"; },
23 0     0     Action => sub { },
24 0           MaxSize => 0,
25             @_,
26              
27             # interal structures
28             write_buffer => {},
29             read_buffer => {},
30             write_sockets => new IO::Select,
31             read_sockets => new IO::Select,
32             listening_socket => undef,
33             client_peers => {},
34             server_peers => {},
35             waiting_user => {},
36             reading_multiline => {},
37             snarfing => {},
38             command_queue => {},
39             write_disconnect => {},
40             };
41              
42             # initialize class
43 0   0       my $class = ref($proto) || $proto;
44 0           $self = bless( $self, $class );
45              
46             # init the listening socket
47 0           $self->init();
48              
49 0           $self;
50             }
51              
52             # init the listening socket
53             sub init {
54 0     0 0   my ($self) = shift;
55             # create listening socket
56 0           $self->{listening_socket} = IO::Socket::INET->new(LocalPort => $self->{Port}, Listen => 5, Reuse => 1, Timeout => 5);
57 0 0         $self->error("Cannot create socket: $!") unless $self->{listening_socket};
58            
59 0           $self->debug("Created listening socket on port " . $self->{Port});
60            
61             # add it to readable sockets
62 0           $self->{read_sockets}->add($self->{listening_socket});
63             }
64              
65             sub canrecycle {
66 0     0 0   my $self = shift;
67            
68 0 0 0       if ($self->{read_sockets}->count() <= 1 && $self->{write_sockets}->count() == 0) {
69 0           return 1;
70             } else {
71 0           return 0;
72             }
73             }
74              
75             # this should be called in a while (1) loop to work through sockets
76             # main dispatcher
77             sub looper {
78 0     0 1   my $self = shift;
79              
80 0 0 0       return 0 unless ($self->{read_sockets}->count() || $self->{write_sockets}->count());
81            
82             # find out sockets to read and to write to
83 0           my ($toread, $towrite) = IO::Select->select($self->{read_sockets}, $self->{write_sockets},undef, 5);
84            
85             # first work on read sockets
86 0           foreach my $socket ( @$toread ) {
87             # check which type of socket we are working on:
88 0 0         if ($socket == $self->{listening_socket}) {
89             # initial communication
90 0           $self->minipop3_connect($socket);
91             } else {
92             # followup connection
93 0 0         if (defined $self->{client_peers}->{$socket}) {
    0          
94             # its a client which already has a server assotiated
95 0           $self->proxypop3_client2server($socket);
96             } elsif (defined $self->{server_peers}->{$socket}) {
97             # its a server communicating with the client
98 0           $self->proxypop3_server2client($socket);
99             } else {
100             # its a client communicating with minipop3
101 0           $self->minipop3_client2server($socket);
102             }
103             }
104            
105             # cleanup
106 0 0 0       unless ($socket && $socket->connected()) {
107 0           undef $socket;
108             }
109             }
110            
111             # next work on write sockets
112 0           foreach my $socket ( @$towrite ) {
113             # check if write buffer waits for something
114 0 0         if ($self->{write_buffer}->{$socket}) {
115 0           $self->write2socket($socket);
116             }
117              
118             # cleanup
119 0 0 0       unless ($socket && $socket->connected()) {
120 0           undef $socket;
121             }
122             }
123              
124             # cleanup
125 0           undef $toread; undef $towrite;
  0            
126              
127 0           1;
128             }
129              
130             # Basic write to socket function. Writes waiting data to a writing socket.
131             sub write2socket {
132 0     0 0   my ($self, $socket) = @_;
133            
134 0 0         return unless $self->{write_buffer}->{$socket};
135            
136             # write to socket
137 0 0         my $wrote = syswrite($socket, $self->{write_buffer}->{$socket}, length($self->{write_buffer}->{$socket})) or do {
138             # write failed
139 0           $self->debug("write to " . $socket->peerhost() . " failed");
140            
141             # clear writing buffer on socket
142 0           $self->{write_buffer}->{$socket} = "";
143            
144             # disconnect all assotiated stuff
145 0 0         if (defined $self->{client_peers}->{$socket}) {
    0          
146             # its a port of a client - so the client disconnects
147 0           $self->client_disconnect($socket);
148             } elsif (defined $self->{server_peers}->{$socket}) {
149             # its a port of a server - so a server is not reachable any more
150 0           $self->server_disconnect($socket);
151             } else {
152             # no assosiated port so only mini disconnect
153 0           $self->minipop3_quit($socket);
154             }
155             };
156            
157             # after a write - we have to flush the buffer (only if writte is buffer size)
158 0           substr($self->{write_buffer}->{$socket},0,$wrote,"");
159 0 0         if (length ($self->{write_buffer}->{$socket}) == 0) {
160 0           $self->{write_sockets}->remove($socket);
161              
162 0           undef $self->{write_buffer}->{$socket};
163              
164             # implicit disconnect after last write
165 0 0         if ($self->{write_disconnect}->{$socket}) {
166 0           $self->debug("executing pending disconnect for " . $socket->peerhost() . ".");
167            
168 0 0         if (defined $self->{client_peers}->{$socket}) {
    0          
169             # a client port - client disconnect
170 0           $self->client_disconnect($socket);
171             } elsif (defined $self->{server_peers}->{$socket}) {
172             # a server port - so server disconnect
173 0           $self->server_disconnect($socket);
174             } else {
175 0           $self->minipop3_quit($socket);
176             }
177             }
178            
179             }
180             }
181              
182             # Connection from a client to our proxy
183             sub minipop3_connect {
184 0     0 0   my ($self, $socket) = @_;
185            
186             # accept socket
187 0           my $new_sock = $socket->accept;
188 0 0         $self->{read_sockets}->add($new_sock) if $new_sock;
189 0 0         $self->error("Cannot accept new connection from client") unless $new_sock;
190              
191 0           $self->debug("Connection accepted from " . $new_sock->peerhost() . ".");
192              
193             # fill data
194 0           $self->{write_buffer}->{$new_sock} = undef; $self->{read_buffer}->{$new_sock} = undef;
  0            
195 0           $self->{write_disconnect}->{$new_sock} = 0;
196            
197             # write mini pop3 welcome
198 0           $self->preparewrite($new_sock,"+OK welcome to maxbounce pop3 proxy\x0D\x0A");
199             }
200              
201             sub minipop3_client2server {
202 0     0 0   my ($self, $socket) = @_;
203            
204 0           $self->debug("Receiving data from client -> proxy server");
205            
206             # get read data
207 0 0         $self->doread($socket) or $self->minipop3_quit($socket);
208              
209             # check if buffer is enough to run action
210 0           $self->minipop3_action($socket);
211             }
212              
213             sub minipop3_action {
214 0     0 0   my ($self, $socket) = @_;
215            
216 0 0         return unless $self->{read_buffer}->{$socket};
217            
218 0 0         if ($self->{read_buffer}->{$socket} =~ /\x0D\x0A?$/s) {
219 0           my @workbuffer = split (/\x0D\x0A?/,$self->{read_buffer}->{$socket});
220 0           undef $self->{read_buffer}->{$socket};
221              
222             # only an "enter"
223 0 0         if (@workbuffer == 0) {
224 0           $self->debug("client sent only empty line");
225 0           $self->preparewrite($socket,"-ERR empty command\x0D\x0A");
226             }
227            
228             # work the lines
229 0           foreach my $line ( @workbuffer ) {
230             # hanging x0A
231 0           $line =~ s/^\x0A//;
232              
233 0 0         if ($line =~ /^USER\s+([^\%]+)\%(.+)$/i) {
    0          
    0          
234 0           my ($remoteuser, $remotehost) = ($1,$2);
235 0           $self->debug("Got USER command from client: pop3 host $remotehost, username $remoteuser");
236            
237             # append port 110 if not included
238 0 0         if ($remotehost !~ /:\d+$/) {
239 0           $remotehost .= ":110";
240             }
241            
242             # open up a new socket to a pop server
243 0           my $remote = IO::Socket::INET->new(PeerAddr => $remotehost);
244 0 0         unless ($remote) {
245             # no connection possible
246 0           $self->debug("No connection to $remotehost");
247 0           $self->preparewrite($socket,"-ERR $remotehost is not reachable\x0D\x0A");
248             } else {
249 0           $self->debug("Connection to $remotehost ok");
250            
251            
252             # fill up datas
253 0           $self->{read_sockets}->add($remote);
254 0           $self->{client_peers}->{$socket} = $remote;
255 0           $self->{server_peers}->{$remote} = $socket;
256 0           $self->{waiting_user}->{$remote} = $remoteuser;
257 0           $self->{write_buffer}->{$remote} = undef; $self->{read_buffer}->{$remote} = undef;
  0            
258 0           $self->{reading_multiline}->{$remote} = 0; $self->{snarfing}->{$remote} = 0;
  0            
259 0           $self->{command_queue}->{$socket} = [];
260 0           $self->{write_disconnect}->{$remote} = 0;
261             }
262             } elsif ($line =~ /^QUIT/i) {
263             # quit request
264 0           $self->debug("Proxy client issues QUIT");
265 0           $self->minipop3_quit($socket);
266             } elsif ($line =~ /^SHUTDOWN/i) {
267             # shutdown all
268 0           $self->cleanup();
269             } else {
270             # wrong command
271 0           $self->debug("Proxy client issues wrong command");
272 0           $self->preparewrite($socket,"-ERR waiting for USER\x0D\x0A");
273             }
274             }
275            
276 0           undef @workbuffer;
277             } else {
278 0           $self->debug('... waiting for EOL');
279             }
280             }
281              
282             # close connection in minipop3 mode (not so ugly)
283             sub minipop3_quit {
284 0     0 0   my ($self,$socket) = @_;
285            
286 0           $self->debug("Connection to " . $socket->peerhost() . " closed (minipop3).");
287 0           $self->socketclose($socket);
288             }
289              
290             # communication from a client to a server / Command checkup and catcher
291             sub proxypop3_client2server {
292 0     0 0   my ($self,$socket) = @_;
293              
294 0           $self->debug("Receiving data from client -> pop server");
295            
296 0 0         $self->doread($socket) or $self->client_disconnect($socket);
297            
298 0           $self->proxypop3_client_action($socket);
299             }
300              
301             # a client socket dies or needs to be disconnected
302             sub client_disconnect {
303 0     0 0   my ($self,$socket) = @_;
304              
305             # is a server port assosiated ?
306 0 0         if (defined $self->{client_peers}->{$socket}) {
307             # is data pending ?
308 0 0         if ($self->{write_buffer}->{$self->{client_peers}->{$socket}}) {
309 0           $self->debug("Initiating clients assosiated server disconnect after next write");
310 0           $self->{write_disconnect}->{$self->{client_peers}->{$socket}} = 1;
311             } else {
312 0           $self->debug("Initiating clients assosiated server disconnect immediate");
313              
314 0           $self->socketclose($self->{client_peers}->{$socket});
315             }
316             }
317            
318 0           $self->debug("Disconnecting client connection to " . $socket->peerhost() . ".");
319 0           $self->socketclose($socket);
320             }
321              
322             # handle read data from client and make command checkup
323             sub proxypop3_client_action {
324 0     0 0   my ($self, $socket) = @_;
325            
326             # no action needed
327 0 0         return unless $self->{read_buffer}->{$socket};
328            
329             # check if empty line
330 0 0         if ($self->{read_buffer}->{$socket} =~ /\x0D\x0A?$/s) {
331 0           my @workbuffer = split (/\x0D\x0A?/,$self->{read_buffer}->{$socket});
332 0           $self->{read_buffer}->{$socket} = "";
333              
334             # empty line
335 0 0         if (@workbuffer == 0) {
336 0           $self->debug("Empty client command");
337 0           $self->preparewrite($socket,"-ERR empty command");
338             } else {
339             # only interested in one line command
340 0           my $line = $workbuffer[0];
341            
342             # hanging x0A
343 0           $line =~ s/^\x0A//;
344            
345             # the plain command
346 0           my ($command) = $line =~ /^(\S+)/;
347            
348             # disable AUTH requests
349 0 0 0       if ($command and $command =~ /^AUTH$/i) {
350 0           $self->preparewrite($socket,"-ERR Auth disabled\x0D\x0A");
351 0           return;
352             }
353              
354             # we are in proxy mode already, do not retry authentication!
355 0 0 0       if ($command and $command =~ /^USER/i) {
356 0           $self->preparewrite($socket,"-ERR Only one authentication can be done. Please restart\x0D\x0A");
357 0           return;
358             }
359            
360             # push command to stack
361 0 0         push (@{$self->{command_queue}->{$self->{client_peers}->{$socket}}}, $command) if $command;
  0            
362            
363 0           $self->debug("Client issues command '$command'.");
364 0           $self->preparewrite($self->{client_peers}->{$socket},"$line\x0D\x0A");
365             }
366             } else {
367             # new line missing
368 0           $self->debug('Client communication needs a newline to finish');
369             }
370             }
371              
372             # a server is communicating with the client
373             sub proxypop3_server2client {
374 0     0 0   my ($self,$socket) = @_;
375            
376 0           $self->debug("Receiving data from pop server -> client");
377            
378 0 0         $self->doread($socket) or $self->server_disconnect($socket);
379            
380 0           $self->proxypop3_server_action($socket);
381             }
382              
383             # all stuff if a server port disconnects
384             sub server_disconnect {
385 0     0 0   my ($self,$socket) = @_;
386            
387             # is a client assosiated with this communication
388 0 0         if (defined $self->{server_peers}->{$socket}) {
389 0 0         if ($self->{write_buffer}->{$self->{server_peers}->{$socket}}) {
390 0           $self->debug("Initiating server assosiated client disconnect after next write");
391 0           $self->{write_disconnect}->{$self->{server_peers}->{$socket}}=1;
392             } else {
393 0           $self->debug("Initiating server assosiated client disconnect immediate");
394              
395 0           $self->socketclose($self->{server_peers}->{$socket});
396             }
397             }
398            
399 0           $self->debug("Disconnecting server connection to " . $socket->peerhost() . ".");
400 0           $self->socketclose($socket);
401             }
402              
403             # work the server answers to see whats up in the mailbox and to catch mails
404             sub proxypop3_server_action {
405 0     0 0   my ($self, $socket) = @_;
406              
407 0 0         return unless ($self->{read_buffer}->{$socket});
408              
409             # is it a full answer?
410 0 0         if ($self->{read_buffer}->{$socket} =~ /\x0D\x0A?$/s) {
411             # split buffer
412 0           my @workbuffer = split (/\x0D\x0A?/,$self->{read_buffer}->{$socket});
413             # discard buffer
414 0           undef $self->{read_buffer}->{$socket};
415            
416 0           foreach my $line ( @workbuffer ) {
417             # hanging x0A
418 0           $line =~ s/^\x0A//;
419            
420             # response is a status reply and no multiline response
421 0 0 0       if (($line =~ /^(\+OK|-ERR)/i) && (! $self->{reading_multiline}->{$socket})) {
    0          
422 0           $self->debug("command response");
423              
424             # do we need to make a silent connect to the server?
425 0 0         if ($self->{waiting_user}->{$socket}) {
426             # first hello
427 0           $self->debug("Remote server alive, trying authenticate with user " . $self->{waiting_user}->{$socket} . ".");
428 0           $self->preparewrite($socket,"USER " . $self->{waiting_user}->{$socket} . "\x0D\x0A");
429              
430 0           undef $self->{waiting_user}->{$socket}; delete $self->{waiting_user}->{$socket};
  0            
431              
432             # no interest in going on server replies
433 0           last;
434             }
435            
436             # Response to a command (hopefully!)
437 0           my $command = shift @{$self->{command_queue}->{$socket}};
  0            
438            
439             # santity check
440 0 0         if ($self->{snarfing}->{$socket}) {
441 0           $self->error("Sanity: multiline not ready - error in snarfing");
442             }
443              
444             # positiv answer
445 0 0 0       if ((substr ($line, 0, 1) eq '+') && (defined $command)) {
446             # command TOP
447 0 0         if ($command =~ /^TOP$/i) {
448 0           $self->{snarfing}->{$socket} = 1;
449 0           next;
450             }
451            
452             # Command RETR (reply with original Status)
453 0 0         if ($command =~ /RETR/i) {
454 0           $self->{snarfing}->{$socket} = 2;
455 0           $self->preparewrite($self->{server_peers}->{$socket}, "+OK filtered message follows\x0D\x0A");
456 0           next;
457             }
458              
459             # Command CAPA (reply with original Status=
460 0 0         if ($command =~ /CAPA/i) {
461 0           $self->{snarfing}->{$socket} = 3;
462 0           $self->preparewrite($self->{server_peers}->{$socket}, "$line\x0D\x0A");
463 0           next;
464             }
465             }
466             } elsif ($line =~ /^\.$/) {
467 0           $self->debug("end ML");
468             # End of a multiline response
469              
470 0           $self->{reading_multiline}->{$socket} = 0;
471              
472             # we just catch a message
473 0 0         if ($self->{snarfing}->{$socket}) {
474            
475             # a RETR Request
476 0 0         if ($self->{snarfing}->{$socket} == 2) {
    0          
    0          
477 0 0         if (! defined ($self->{message}->{$socket})) {
478 0           $self->{message}->{$socket} = '';
479             }
480            
481 0 0 0       if (($self->{MaxSize} == 0) || (length ($self->{message}->{$socket}) < $self->{MaxSize})) {
482 0           $self->{message}->{$socket} = $self->{Action}($self->{message}->{$socket});
483             } else {
484 0           $self->debug("Message not filtered - too big");
485             }
486            
487 0           $self->debug("Returning RETR command / applying filter");
488            
489 0           $self->preparewrite($self->{server_peers}->{$socket},$self->{message}->{$socket});
490             # TOP Command will be dropped ( problem because we modify messages )
491             } elsif ($self->{snarfing}->{$socket} == 1) {
492 0           $self->{message}->{$socket} = ''; $self->{snarfing}->{$socket} = 0;
  0            
493            
494 0           $self->debug("Discard TOP command reply");
495 0           $self->preparewrite($self->{server_peers}->{$socket},"-ERR no TOP allowed\x0D\x0A");
496 0           next;
497             # CAPA Reply
498             } elsif ($self->{snarfing}->{$socket} == 3) {
499             # Strips out the TOP response, if any.
500 0           $self->{message}->{$socket} =~ s/TOP\x0D\x0A//sig;
501             # Strips out the SASL response, if any.
502 0           $self->{message}->{$socket} =~ s/SASL\x0D\x0A//sig;
503            
504 0           $self->debug("Return modified CAPA reply");
505 0           $self->preparewrite($self->{server_peers}->{$socket},$self->{message}->{$socket});
506             } else {
507 0           $self->error("Sanity: Another Snarfing Action code");
508             }
509            
510             # discard snarfing and message
511 0           undef $self->{message}->{$socket}; delete $self->{message}->{$socket};
  0            
512 0           $self->{snarfing}->{$socket} = 0;
513             }
514             } else {
515             # $self->debug("ML");
516              
517             # it must be a multiline
518 0           $self->{reading_multiline}->{$socket} = 1;
519             }
520            
521             # if in multiline snarfing - store message
522 0 0         if ($self->{snarfing}->{$socket}) {
523 0           $self->{message}->{$socket} .= $line . "\x0D\x0A";
524             } else {
525             # pipeline it to the client
526 0           $self->preparewrite($self->{server_peers}->{$socket}, "$line\x0D\x0A");
527             }
528             }
529             # free workbuffer
530 0           undef @workbuffer;
531             } else {
532             # new line missing
533 0           $self->debug('Server communication needs a newline to finish');
534             }
535             }
536              
537             # Cleanup means to kill all existing ports
538             sub cleanup {
539 0     0 1   my ($self, $force) = shift;
540            
541 0 0         if ($force) {
542 0           $self->debug("Forced shutdown");
543             }
544            
545             # gather all sockets
546 0           my @allwrite = $self->{write_sockets}->handles;
547            
548             # begin with the writing ones
549 0           foreach my $socket ( @allwrite ) {
550 0 0         unless ($force) {
551 0 0         if (defined $self->{client_peers}->{$socket}) {
    0          
552 0           $self->client_disconnect($socket);
553             } elsif (defined $self->{server_peers}->{$socket}) {
554 0           $self->server_disconnect($socket);
555             } else {
556 0           $self->minipop3_quit($socket);
557             }
558             } else {
559 0           $self->socketclose($socket);
560             }
561             }
562              
563             # Read sockets
564 0           my @allread = $self->{read_sockets}->handles;
565              
566             # now go to the reading ones
567 0           foreach my $socket ( @allread ) {
568 0 0         unless ($force) {
569 0 0         if (defined $self->{client_peers}->{$socket}) {
    0          
    0          
570 0           $self->client_disconnect($socket);
571             } elsif (defined $self->{server_peers}->{$socket}) {
572 0           $self->server_disconnect($socket);
573             } elsif ($socket == $self->{listening_socket}) {
574 0           $self->debug("Closing listening socket");
575 0           $self->socketclose($socket);
576             } else {
577 0           $self->minipop3_quit($socket);
578             }
579             } else {
580 0           $self->socketclose($socket);
581             }
582             }
583             }
584              
585             # put a write in the queue and enable writing
586             sub preparewrite {
587 0     0 0   my ($self,$socket,$message) = @_;
588            
589 0 0         if (ref($message) eq "SCALAR") {
590 0           $self->{write_buffer}->{$socket} .= $$message;
591             } else {
592 0           $self->{write_buffer}->{$socket} .= $message;
593             }
594 0 0         $self->{write_sockets}->add($socket) unless $self->{write_sockets}->exists($socket);
595             }
596              
597             # get a block for reading
598             sub doread {
599 0     0 0   my ($self, $socket) = @_;
600            
601 0 0         $self->{read_buffer}->{$socket} = '' unless ($self->{read_buffer}->{$socket});
602 0           return sysread($socket, $self->{read_buffer}->{$socket}, 4096, length($self->{read_buffer}->{$socket}));
603             }
604              
605             # debugging
606             sub debug {
607 0     0 0   my ($self, $msg) = @_;
608 0           $self->{Debug}($msg);
609             }
610              
611             # error
612             sub error {
613 0     0 0   my ($self, $msg) = @_;
614            
615 0           $self->cleanup();
616 0           $self->{Error}($msg);
617             }
618              
619             # Sub will clean all data assosiated with a socket
620             sub socketclose {
621 0     0 0   my ($self, $socket) = @_;
622              
623 0 0         return unless $socket;
624              
625 0           $self->{read_sockets}->remove($socket); $self->{write_sockets}->remove($socket);
  0            
626            
627             # clean all assosiated hashes
628 0 0         do { undef $self->{server_peers}->{$socket}; delete $self->{server_peers}->{$socket} } if (exists $self->{server_peers}->{$socket});
  0            
  0            
629 0 0         do { undef $self->{client_peers}->{$socket}; delete $self->{client_peers}->{$socket} } if (exists $self->{client_peers}->{$socket});
  0            
  0            
630 0 0         do { undef $self->{read_buffer}->{$socket}; delete $self->{read_buffer}->{$socket} } if (exists $self->{read_buffer}->{$socket});
  0            
  0            
631 0 0         do { undef $self->{write_buffer}->{$socket}; delete $self->{write_buffer}->{$socket} } if (exists $self->{write_buffer}->{$socket});
  0            
  0            
632 0 0         do { undef $self->{reading_multiline}->{$socket}; delete $self->{reading_multiline}->{$socket} } if (exists $self->{reading_multiline}->{$socket});
  0            
  0            
633 0 0         do { undef $self->{command_queue}->{$socket}; delete $self->{command_queue}->{$socket} } if (exists $self->{command_queue}->{$socket});
  0            
  0            
634 0 0         do { undef $self->{write_disconnect}->{$socket}; delete $self->{write_disconnect}->{$socket} } if (exists $self->{write_disconnect}->{$socket});
  0            
  0            
635 0 0         do { undef $self->{snarfing}->{$socket}; delete $self->{snarfing}->{$socket}} if (exists $self->{snarfing}->{$socket});
  0            
  0            
636 0 0         do { undef $self->{message}->{$socket}; delete $self->{message}->{$socket} } if (exists $self->{message}->{$socket});
  0            
  0            
637            
638             # close socket
639 0           $socket->shutdown(2);
640 0 0         $socket->close() if ($socket);
641             }
642              
643             sub DESTROY {
644 0     0     my $self = shift;
645            
646 0           $self->debug("Destroy");
647 0           $self->cleanup(1);
648             }
649              
650             # a positiv result - we are polite!
651             1;
652              
653             __END__