+13Mar01=======================================================================
+1. implemented first cut at non blocking connect
+2. removed memory leakage in connects
10Mar01=======================================================================
1. minor changes to the admin manual to reflect differences in distibutions
thanks to pa3ezl (g0vgs)
'^l$', 'directory', 'directory',
'^ll$', 'directory', 'directory',
'^ll/(\d+)', 'directory $1', 'directory',
+ '^lm$', 'directory own', 'directory',
],
'm' => [
],
#
my $self = shift;
+
+# log out text
+if ($self->is_user && -e "$main::data/logout") {
+ open(I, "$main::data/logout") or confess;
+ my @in = <I>;
+ close(I);
+ $self->send_now('D', @in);
+ sleep(1);
+}
+
$self->state('bye');
return (1);
}
$dxchan->disconnect;
push @out, $self->msg('disc2', $call);
- } elsif (my $conn = Msg->call($call)) {
+ } elsif (my $conn = Msg->conns($call)) {
$conn->disconnect;
} else {
push @out, $self->msg('e10', $call);
$call = uc $call;
my $ref = DXChannel->get($call);
if ($ref) {
- @out = print_all_fields($self, $ref, "Channe Information $call");
+ @out = print_all_fields($self, $ref, "Channel Information $call");
} else {
return (0, "Channel: $call not found") if !$ref;
}
{
my $self = shift;
my $user = $self->{user};
- my $conn = $self->{conn};
my $call = $self->{call};
- $self->finish($conn);
+ $self->finish;
$user->close() if defined $user;
- $conn->disconnect() if $conn;
+ $self->{conn}->disconnect;
$self->del();
}
sub finish
{
my $self = shift;
- my $conn = shift;
my $call = $self->call;
# reset the redirection of messages back to 'normal' if we are the sysop
# I was the last node visited
$self->user->node($main::mycall);
- # log out text
- if ($conn && -e "$main::data/logout") {
- open(I, "$main::data/logout") or confess;
- my @in = <I>;
- close(I);
- $self->send_now('D', @in);
- sleep(1);
- }
-
-# if ($call eq $main::myalias) { # unset the channel if it is us really
-# my $node = DXNode->get($main::mycall);
-# $node->{dxchan} = 0;
-# }
-
# issue a pc17 to everybody interested
my $nchan = DXChannel->get($main::mycall);
my $pc17 = $nchan->pc17($self);
{
my $self = shift;
my $call = $self->call;
- my $conn = shift;
my $ref = DXCluster->get_exact($call);
# unbusy and stop and outgoing mail
{
my $conn = shift;
my $msg;
-
- while (@{$conn->{inqueue}}){
- $msg = shift @{$conn->{inqueue}};
- dbg('connect', $msg) unless $conn->{state} eq 'C';
-
- $msg =~ s/\xff\xfa.*\xff\xf0|\xff[\xf0-\xfe].//g; # remove telnet options
- $msg =~ s/[\x00-\x08\x0a-\x1f\x80-\x9f]/./g; # immutable CSI sequence + control characters
- if ($conn->{state} eq 'C') {
- &{$conn->{rproc}}($conn, "I$conn->{call}|$msg", $!);
- $! = 0;
- } elsif ($conn->{state} eq 'WL' ) {
- $msg = uc $msg;
- if (is_callsign($msg)) {
- &{$conn->{rproc}}($conn, "A$msg|telnet");
- _send_file($conn, "$main::data/connected");
- $conn->{state} = 'C';
- } else {
- $conn->send_now("Sorry $msg is an invalid callsign");
- $conn->disconnect;
- }
- } elsif ($conn->{state} eq 'WC') {
- if (exists $conn->{cmd} && @{$conn->{cmd}}) {
- $conn->_docmd($msg);
- if ($conn->{state} eq 'WC' && exists $conn->{cmd} && @{$conn->{cmd}} == 0) {
- $conn->{state} = 'C';
- &{$conn->{rproc}}($conn, "O$conn->{call}|telnet");
- delete $conn->{cmd};
- $conn->{timeout}->del_timer if $conn->{timeout};
- }
- }
+ if ($conn->{state} eq 'WC') {
+ if (exists $conn->{cmd}) {
+ if (@{$conn->{cmd}}) {
+ dbg('connect', $conn->{msg});
+ $conn->_docmd($conn->{msg});
+ }
}
- }
- if ($conn->{msg} && $conn->{state} eq 'WC' && exists $conn->{cmd} && @{$conn->{cmd}}) {
- dbg('connect', $conn->{msg});
- $conn->_docmd($conn->{msg});
if ($conn->{state} eq 'WC' && exists $conn->{cmd} && @{$conn->{cmd}} == 0) {
$conn->{state} = 'C';
&{$conn->{rproc}}($conn, "O$conn->{call}|telnet");
delete $conn->{cmd};
- $conn->{timeout}->del_timer if $conn->{timeout};
+ $conn->{timeout}->del if $conn->{timeout};
+ }
+ } elsif ($conn->{msg} =~ /\n/) {
+ my @lines = split /\r?\n/, $conn->{msg};
+ if ($conn->{msg} =~ /\n$/) {
+ delete $conn->{msg};
+ } else {
+ $conn->{msg} = pop @lines;
+ }
+ while (defined ($msg = shift @lines)) {
+ dbg('connect', $msg) unless $conn->{state} eq 'C';
+
+ $msg =~ s/\xff\xfa.*\xff\xf0|\xff[\xf0-\xfe].//g; # remove telnet options
+ $msg =~ s/[\x00-\x08\x0a-\x1f\x80-\x9f]/./g; # immutable CSI sequence + control characters
+
+ if ($conn->{state} eq 'C') {
+ &{$conn->{rproc}}($conn, "I$conn->{call}|$msg");
+ } elsif ($conn->{state} eq 'WL' ) {
+ $msg = uc $msg;
+ if (is_callsign($msg)) {
+ &{$conn->{rproc}}($conn, "A$msg|telnet");
+ _send_file($conn, "$main::data/connected");
+ $conn->{state} = 'C';
+ } else {
+ $conn->send_now("Sorry $msg is an invalid callsign");
+ $conn->disconnect;
+ }
+ } elsif ($conn->{state} eq 'WC') {
+ if (exists $conn->{cmd} && @{$conn->{cmd}}) {
+ $conn->_docmd($msg);
+ if ($conn->{state} eq 'WC' && exists $conn->{cmd} && @{$conn->{cmd}} == 0) {
+ $conn->{state} = 'C';
+ &{$conn->{rproc}}($conn, "O$conn->{call}|telnet");
+ delete $conn->{cmd};
+ $conn->{timeout}->del if $conn->{timeout};
+ }
+ }
+ }
}
}
}
my $conn = $server_conn->new($server_conn->{rproc});
$conn->{sock} = $sock;
- my $rproc = &{$server_conn->{rproc}} ($conn, $sock->peerhost(), $sock->peerport());
+ my ($rproc, $eproc) = &{$server_conn->{rproc}} ($conn, $conn->{peerhost} = $sock->peerhost(), $conn->{peerport} = $sock->peerport());
+ if ($eproc) {
+ $conn->{eproc} = $eproc;
+ set_event_handler ($sock, "error" => $eproc);
+ }
if ($rproc) {
$conn->{rproc} = $rproc;
my $callback = sub {$conn->_rcv};
my $conn = shift;
my $val = shift;
dbg('connect', "timeout set to $val");
- $conn->{timeout}->del_timer if $conn->{timeout};
- $conn->{timeout} = ExtMsg->new_timer($val, sub{ _timeout($conn); });
+ my $old = $conn->{timeout}->del if $conn->{timeout};
+ $conn->{timeout} = Timer->new($val, sub{ &_timeout($conn) });
$conn->{timeval} = $val;
}
$conn->{state} = 'C';
&{$conn->{rproc}}($conn, "O$conn->{call}|telnet");
delete $conn->{cmd};
- $conn->{timeout}->del_timer if $conn->{timeout};
+ $conn->{timeout}->del if $conn->{timeout};
}
sub _send_file
$f->close;
}
}
- $! = undef;
}
sub dequeue
{
my $conn = shift;
- my $msg;
-
- while ($msg = shift @{$conn->{inqueue}}){
- $msg =~ s/\%([2-9A-F][0-9A-F])/chr(hex($1))/eg;
- $msg =~ s/[\x00-\x08\x0a-\x1f\x80-\x9f]/./g; # immutable CSI sequence + control characters
- &{$conn->{rproc}}($conn, $msg, $!);
- $! = 0;
+
+ if ($conn->{msg} =~ /\n/) {
+ my @lines = split /\r?\n/, $conn->{msg};
+ if ($conn->{msg} =~ /\n$/) {
+ delete $conn->{msg};
+ } else {
+ $conn->{msg} = pop @lines;
+ }
+ for (@lines) {
+ if (defined $_) {
+ s/\%([0-9A-F][0-9A-F])/chr(hex($1))/eg;
+ s/[\x00-\x08\x0a-\x1f\x80-\x9f]/./g; # immutable CSI sequence + control characters
+ } else {
+ $_ = '';
+ }
+ &{$conn->{rproc}}($conn, $_);
+ }
}
}
+
use strict;
use IO::Select;
use IO::Socket;
-use Carp;
+use DXDebug;
+use Timer;
+use Errno qw(EWOULDBLOCK EAGAIN EINPROGRESS);
+use POSIX qw(F_GETFL F_SETFL O_NONBLOCK);
-use vars qw(%rd_callbacks %wt_callbacks $rd_handles $wt_handles $now @timerchain %conns);
+use vars qw(%rd_callbacks %wt_callbacks %er_callbacks $rd_handles $wt_handles $er_handles $now %conns $noconns);
%rd_callbacks = ();
%wt_callbacks = ();
+%er_callbacks = ();
$rd_handles = IO::Select->new();
$wt_handles = IO::Select->new();
-$now = time;
-@timerchain = ();
-
-my $blocking_supported = 0;
+$er_handles = IO::Select->new();
-BEGIN {
- # Checks if blocking is supported
- eval {
- require POSIX; POSIX->import(qw (F_SETFL O_NONBLOCK EAGAIN));
- };
- $blocking_supported = 1 unless $@;
-}
+$now = time;
#
#-----------------------------------------------------------------
timeval => 60,
};
+ $noconns++;
+ dbg('connll', "Connection created ($noconns)");
return bless $conn, $class;
}
+sub set_error
+{
+ my $conn = shift;
+ my $callback = shift;
+ $conn->{eproc} = $callback;
+ set_event_handler($conn->{sock}, error => $callback) if exists $conn->{sock};
+}
+
+sub blocking
+{
+ my $flags = fcntl ($_[0], F_GETFL, 0);
+ if ($_[1]) {
+ $flags &= ~O_NONBLOCK;
+ } else {
+ $flags |= O_NONBLOCK;
+ }
+ fcntl ($_[0], F_SETFL, $flags);
+}
+
# save it
sub conns
{
confess "changing $pkg->{call} to $call" if exists $pkg->{call} && $call ne $pkg->{call};
$pkg->{call} = $call;
$ref = $conns{$call} = $pkg;
+ dbg('connll', "Connection $call stored");
} else {
$ref = $conns{$call};
}
my @pid = grep {$_->{pid} == $pid} values %conns;
for (@pid) {
- if ($_->{rproc}) {
- &{$_->{rproc}}($_, undef, "$pid has gorn");
- } else {
- $_->disconnect;
- }
+ &{$_->{eproc}}($_, "$pid has gorn") if exists $_->{eproc};
+ $_->disconnect;
}
}
unless (ref $pkg) {
$conn = $pkg->new($rproc);
}
+ $conn->{peerhost} = $to_host;
+ $conn->{peerport} = $to_port;
+ $conn->{sort} = 'Outgoing';
# Create a new internet socket
- my $sock = IO::Socket::INET->new (
- PeerAddr => $to_host,
- PeerPort => $to_port,
- Proto => 'tcp',
- Reuse => 1,
- Timeout => $conn->{timeval} / 2);
-
+ my $sock = IO::Socket::INET->new();
return undef unless $sock;
-
+
+ my $proto = getprotobyname('tcp');
+ $sock->socket(AF_INET, SOCK_STREAM, $proto) or return undef;
+
+ blocking($sock, 0);
+ my $ip = gethostbyname($to_host);
+ my $r = $sock->connect($to_port, $ip);
+ unless ($r) {
+ return undef unless $! == EINPROGRESS;
+ }
+
$conn->{sock} = $sock;
if ($conn->{rproc}) {
sub disconnect {
my $conn = shift;
+ return if exists $conn->{disconnecting};
+
+ $conn->{disconnecting} = 1;
my $sock = delete $conn->{sock};
$conn->{state} = 'E';
delete $conn->{cmd};
- $conn->{timeout}->del_timer if $conn->{timeout};
+ delete $conn->{eproc};
+ delete $conn->{rproc};
+ $conn->{timeout}->del if $conn->{timeout};
# be careful to delete the correct one
- if (my $call = $conn->{call}) {
+ my $call;
+ if ($call = $conn->{call}) {
my $ref = $conns{$call};
delete $conns{$call} if $ref && $ref == $conn;
}
+ $call ||= 'unallocated';
+ dbg('connll', "Connection $call disconnected");
- set_event_handler ($sock, "read" => undef, "write" => undef);
+ set_event_handler ($sock, read => undef, write => undef, error => undef);
unless ($^O =~ /^MS/i) {
kill 'TERM', $conn->{pid} if exists $conn->{pid};
}
sub enqueue {
my $conn = shift;
- push (@{$conn->{outqueue}}, $_[0]);
+ push (@{$conn->{outqueue}}, defined $_[0] ? $_[0] : '');
}
sub _send {
# return to the event loop only after every message, or if it
# is likely to block in the middle of a message.
- $flush ? $conn->set_blocking() : $conn->set_non_blocking();
+ blocking($sock, $flush);
my $offset = (exists $conn->{send_offset}) ? $conn->{send_offset} : 0;
while (@$rq) {
# be called back eventually, and will resume sending
return 1;
} else { # Uh, oh
- delete $conn->{send_offset};
- $conn->handle_send_err($!);
+ &{$conn->{eproc}}($conn, $!) if exists $conn->{eproc};
$conn->disconnect;
return 0; # fail. Message remains in queue ..
}
set_event_handler ($sock, "write" => sub {$conn->_send(0)});
} else {
set_event_handler ($sock, "write" => undef);
+ if (exists $conn->{close_on_empty}) {
+ &{$conn->{eproc}}($conn, undef) if exists $conn->{eproc};
+ $conn->disconnect;
+ }
}
1; # Success
}
sub _err_will_block {
- if ($blocking_supported) {
- return ($_[0] == EAGAIN());
- }
- return 0;
-}
-sub set_non_blocking { # $conn->set_blocking
- if ($blocking_supported) {
- # preserve other fcntl flags
- my $flags = fcntl ($_[0], F_GETFL(), 0);
- fcntl ($_[0], F_SETFL(), $flags | O_NONBLOCK());
- }
-}
-sub set_blocking {
- if ($blocking_supported) {
- my $flags = fcntl ($_[0], F_GETFL(), 0);
- $flags &= ~O_NONBLOCK(); # Clear blocking, but preserve other flags
- fcntl ($_[0], F_SETFL(), $flags);
- }
+ return ($_[0] == EAGAIN || $_[0] == EWOULDBLOCK || $_[0] == EINPROGRESS);
}
-sub handle_send_err {
- # For more meaningful handling of send errors, subclass Msg and
- # rebless $conn.
- my ($conn, $err_msg) = @_;
- warn "Error while sending: $err_msg \n";
- set_event_handler ($conn->{sock}, "write" => undef);
+sub close_on_empty
+{
+ my $conn = shift;
+ $conn->{close_on_empty} = 1;
}
#-----------------------------------------------------------------
$self->{sock} = IO::Socket::INET->new (
LocalAddr => $my_host,
LocalPort => $my_port,
- Listen => 5,
+ Listen => SOMAXCONN,
Proto => 'tcp',
Reuse => 1);
die "Could not create socket: $! \n" unless $self->{sock};
sub dequeue
{
my $conn = shift;
- my $msg;
-
- while ($msg = shift @{$conn->{inqueue}}){
- &{$conn->{rproc}}($conn, $msg, $!);
- $! = 0;
+
+ if ($conn->{msg} =~ /\n/) {
+ my @lines = split /\r?\n/, $conn->{msg};
+ if ($conn->{msg} =~ /\n$/) {
+ delete $conn->{msg};
+ } else {
+ $conn->{msg} = pop @lines;
+ }
+ for (@lines) {
+ &{$conn->{rproc}}($conn, defined $_ ? $_ : '');
+ }
}
}
return unless defined($sock);
my @lines;
- $conn->set_non_blocking();
+ blocking($sock, 0);
$bytes_read = sysread ($sock, $msg, 1024, 0);
if (defined ($bytes_read)) {
if ($bytes_read > 0) {
- if ($msg =~ /\n/) {
- @lines = split /\r?\n/, $msg;
- if (@lines) {
- $lines[0] = $conn->{msg} . $lines[0] if exists $conn->{msg};
- } else {
- $lines[0] = $conn->{msg} if exists $conn->{msg};
- push @lines, '' unless @lines;
- }
- if ($msg =~ /\n$/) {
- delete $conn->{msg};
- } else {
- $conn->{msg} = pop @lines;
- }
- push @{$conn->{inqueue}}, @lines if @lines;
- } else {
- $conn->{msg} .= $msg;
- }
+ $conn->{msg} .= $msg;
}
} else {
if (_err_will_block($!)) {
FINISH:
if (defined $bytes_read && $bytes_read == 0) {
-# $conn->disconnect();
- &{$conn->{rproc}}($conn, undef, $!);
- delete $conn->{inqueue};
+ &{$conn->{eproc}}($conn, undef) if exists $conn->{eproc};
+ $conn->disconnect();
} else {
- $conn->dequeue;
+ $conn->dequeue if exists $conn->{msg};
}
}
my $sock = $server_conn->{sock}->accept();
my $conn = $server_conn->new($server_conn->{rproc});
$conn->{sock} = $sock;
- my $rproc = &{$server_conn->{rproc}} ($conn, $sock->peerhost(), $sock->peerport());
+ my ($rproc, $eproc) = &{$server_conn->{rproc}} ($conn, $conn->{peerhost} = $sock->peerhost(), $conn->{peerport} = $sock->peerport());
+ $conn->{sort} = 'Incoming';
+ if ($eproc) {
+ $conn->{eproc} = $eproc;
+ set_event_handler ($sock, "error" => $eproc);
+ }
if ($rproc) {
$conn->{rproc} = $rproc;
my $callback = sub {_rcv($conn)};
set_event_handler ($sock, "read" => $callback);
} else { # Login failed
+ &{$conn->{eproc}}($conn, undef) if exists $conn->{eproc};
$conn->disconnect();
}
}
$conn->{sock}->close;
}
+# close all clients (this is for forking really)
+sub close_all_clients
+{
+ for (values %conns) {
+ $_->disconnect;
+ }
+}
+
#----------------------------------------------------
# Event loop routines used by both client and server
$rd_handles->remove($handle);
}
}
-}
-
-sub new_timer
-{
- my ($pkg, $time, $proc, $recur) = @_;
- my $obj = ref($pkg);
- my $class = $obj || $pkg;
- my $self = bless { t=>$time + time, proc=>$proc }, $class;
- $self->{interval} = $time if $recur;
- push @timerchain, $self;
- return $self;
-}
-
-sub del_timer
-{
- my $self = shift;
- @timerchain = grep {$_ != $self} @timerchain;
+ if (exists $args{'error'}) {
+ $callback = $args{'error'};
+ if ($callback) {
+ $er_callbacks{$handle} = $callback;
+ $er_handles->add($handle);
+ } else {
+ delete $er_callbacks{$handle};
+ $er_handles->remove($handle);
+ }
+ }
}
sub event_loop {
my ($pkg, $loop_count, $timeout) = @_; # event_loop(1) to process events once
- my ($conn, $r, $w, $rset, $wset);
+ my ($conn, $r, $w, $e, $rset, $wset, $eset);
while (1) {
# Quit the loop if no handles left to process
last unless ($rd_handles->count() || $wt_handles->count());
- ($rset, $wset) =
- IO::Select->select ($rd_handles, $wt_handles, undef, $timeout);
+ ($rset, $wset) = IO::Select->select($rd_handles, $wt_handles, $er_handles, $timeout);
$now = time;
+ foreach $e (@$eset) {
+ &{$er_callbacks{$e}}($e) if exists $er_callbacks{$e};
+ }
foreach $r (@$rset) {
- &{$rd_callbacks{$r}} ($r) if exists $rd_callbacks{$r};
+ &{$rd_callbacks{$r}}($r) if exists $rd_callbacks{$r};
}
foreach $w (@$wset) {
&{$wt_callbacks{$w}}($w) if exists $wt_callbacks{$w};
}
- # handle things on the timer chain
- for (@timerchain) {
- if ($now >= $_->{t}) {
- &{$_->{proc}}();
- $_->{t} = $now + $_->{interval} if exists $_->{interval};
- }
- }
-
- # remove dead timers
- @timerchain = grep { $_->{t} > $now } @timerchain;
+ Timer::handler;
if (defined($loop_count)) {
last unless --$loop_count;
}
}
+sub DESTROY
+{
+ my $conn = shift;
+ my $call = $conn->{call} || 'unallocated';
+ dbg('connll', "Connection $call being destroyed ($noconns)");
+ $noconns--;
+}
+
1;
__END__
--- /dev/null
+#
+# Polled Timer handling
+#
+# This uses callbacks. BE CAREFUL!!!!
+#
+# $Id$
+#
+# Copyright (c) 2001 Dirk Koopman G1TLH
+#
+
+package Timer;
+
+use vars qw(@timerchain);
+
+@timerchain = ();
+
+sub new
+{
+ my ($pkg, $time, $proc, $recur) = @_;
+ my $obj = ref($pkg);
+ my $class = $obj || $pkg;
+ my $self = bless { t=>$time + time, proc=>$proc }, $class;
+ $self->{interval} = $time if $recur;
+ push @timerchain, $self;
+ return $self;
+}
+
+sub del
+{
+ my $self = shift;
+ my $old = delete $self->{proc};
+ @timerchain = grep {$_ != $self} @timerchain;
+ return $old;
+}
+
+sub handler
+{
+ my $now = time;
+
+ # handle things on the timer chain
+ for (@timerchain) {
+ if ($now >= $_->{t}) {
+ &{$_->{proc}}();
+ $_->{t} = $now + $_->{interval} if exists $_->{interval};
+ }
+ }
+}
+
+1;
dbg('chan', "-> D $call $mess\n");
$conn->send_now("D$call|$mess");
- sleep(1);
- dbg('chan', "-> Z $call bye\n");
- $conn->send_now("Z$call|bye"); # this will cause 'client' to disconnect
- sleep(1);
+ sleep(2);
$conn->disconnect;
}
+sub error_handler
+{
+ my $dxchan = shift;
+ $dxchan->disconnect;
+}
+
# handle incoming messages
sub rec
{
- my ($conn, $msg, $err) = @_;
+ my ($conn, $msg) = @_;
my $dxchan = DXChannel->get_by_cnum($conn); # get the dxconnnect object for this message
+ my ($sort, $call, $line) = DXChannel::decode_input(0, $msg);
+ return unless defined $sort;
- if (!defined $msg || (defined $err && $err)) {
- if ($dxchan) {
- if (defined $err) {
- $conn->disconnect;
- undef $conn;
- $dxchan->conn(undef);
- }
- $dxchan->disconnect;
- } elsif ($conn) {
- $conn->disconnect;
- }
- return;
- }
-
- # set up the basic channel info - this needs a bit more thought - there is duplication here
+ # set up the basic channel info
if (!defined $dxchan) {
- my ($sort, $call, $line) = DXChannel::decode_input(0, $msg);
- return unless defined $sort;
-
+
# is there one already connected to me - locally?
my $user = DXUser->get($call);
if ($sort ne 'O' && Msg->conns($call)) {
# is he locked out ?
if ($user->lockout) {
Log('DXCommand', "$call is locked out, disconnected");
- $conn->send_now("Z$call|bye"); # this will cause 'client' to disconnect
$conn->disconnect;
return;
}
# mark him up
$conn->conns($call) unless $sort eq 'O';
+ $conn->set_error(sub {error_handler($dxchan)});
# create the channel
$dxchan = DXCommandmode->new($call, $conn, $user) if $user->is_user;
use Listeners;
dbg('err', "starting listeners ...");
-push @listeners, IntMsg->new_server("$clusteraddr", $clusterport, \&login);
+my $conn = IntMsg->new_server($clusteraddr, $clusterport, \&login);
+$conn->conns("Server $clusteraddr/$clusterport");
+push @listeners, $conn;
dbg('err', "Internal port: $clusteraddr $clusterport");
for (@main::listen) {
- push @listeners, ExtMsg->new_server($_->[0], $_->[1], \&login);
+ $conn = ExtMsg->new_server($_->[0], $_->[1], \&login);
+ $conn->conns("Server $_->[0]/$_->[1]");
+ push @listeners, $conn;
dbg('err', "External Port: $_->[0] $_->[1]");
}
for (;;) {
# $DB::trace = 1;
- Msg->event_loop(1, 0.1);
+ Msg->event_loop(10, 0.001);
my $timenow = time;
process_inqueue(); # read in lines from the input queue and despatch them
# $DB::trace = 0;
sub cease
{
my $sendz = shift;
-# if ($conn && $sendz) {
-# $conn->send_now("Z$call|bye...");
-# }
+ $conn->disconnect if $conn;
endwin();
dbgclose();
print @_ if @_;
exit(0);
}
+$conn->set_error(sub{cease(0)});
+
unless ($DB::VERSION) {
$SIG{'INT'} = \&sig_term;