my @out;
push @out, $self->msg('constart', $call);
-ExtMsg::start_connect($call, "$main::root/connect/$lccall");
+my $fn = "$main::root/connect/$lccall";
+
+my $f = new IO::File $fn;
+if ($f) {
+ my @f = <$f>;
+ $f->close;
+ ExtMsg::start_connect($call, @f);
+} else {
+ push @out, $self->msg('e3', 'connect', $fn);
+}
return (1, @out);
# Store it here (but only if it isn't baddx)
my $t = (int ($main::systime/60)) * 60;
-return (1, $self->msg('dup')) if Spot::dup($freq, $spotted, $t, $line, $spotter);
my @spot = Spot::prepare($freq, $spotted, $t, $line, $spotter, $main::mycall);
+my $thing = Thingy::Dx->new(origin=>$main::mycall, group=>'DX', user=>$spotter);
+$thing->from_DXProt(spotdata=>\@spot);
if ($DXProt::baddx->in($spotted) || $freq =~ /^69/ || $localonly) {
if ($freq =~ /^69/) {
$self->badcount(($self->badcount||0) + 1);
}
-
- $self->dx_spot(undef, undef, @spot);
- return (1);
} else {
- if (@spot) {
- # store it
- Spot::add(@spot);
-
- # send orf to the users
- DXProt::send_dx_spot($self, DXProt::pc11($spotter, $freq, $spotted, $line), @spot);
- }
+ $thing->queue($self);
}
-
+push @out, $thing->gen_DXCommandmode($self);
return (1, @out);
my $c = $call;
my $addr;
- if ($c =~ /^Server\s+(\S+)$/) {
+ if ($c =~ /^Server\s+(.*)$/) {
$addr = $1;
+ $addr =~ s/\s+using.*$//;
$c = "Server";
} else {
$addr = "$r->{peerhost}/$r->{peerport}";
my $type = $dxchan->is_node ? "NODE" : "USER";\r
my $sort = " ";\r
if ($dxchan->is_node) {\r
- $sort = 'ANEA' if $dxchan->is_aranea;\r
$sort = "DXSP" if $dxchan->is_spider;\r
$sort = "CLX " if $dxchan->is_clx;\r
$sort = "DXNT" if $dxchan->is_dxnet;\r
$sort = "AR-C" if $dxchan->is_arcluster;\r
$sort = "AK1A" if $dxchan->is_ak1a;\r
}\r
+ $type = 'ANEA' if $dxchan->is_aranea;\r
my $name = $dxchan->user->name || " ";\r
my $ping = $dxchan->is_node && $dxchan != $main::me ? sprintf("%5.2f", $dxchan->pingave) : " ";\r
my $conn = $dxchan->conn;\r
}
}
if ($conn->{state} eq 'WC' && exists $conn->{cmd} && @{$conn->{cmd}} == 0) {
- $conn->to_connected($conn->{call}, 'O', $conn->{csort});
+ $conn->{state} = 'WH';
}
} elsif ($conn->{msg} =~ /\cJ/) {
my @lines = $conn->{msg} =~ /([^\cM\cJ]*)\cM?\cJ/g;
dbg("connect $conn->{cnum}: $msg") if $conn->{state} ne 'C' && isdbg('connect');
if ($conn->{state} eq 'C') {
&{$conn->{rproc}}($conn, $msg);
- } elsif ($conn->{state} eq 'WA' ) {
- my $uref = DXUser->get_current($conn->{call});
+ } elsif ($conn->{state} eq 'WH' ) {
+ # this is the first stage that we have a callsign
+ # do we have a hello?
$msg =~ s/[\r\n]+$//;
- if ($uref && $msg eq $uref->passwd) {
- my $sort = $conn->{csort};
- $sort = 'local' if $conn->{peerhost} eq "127.0.0.1";
- $conn->{usedpasswd} = 1;
- $conn->to_connected($conn->{call}, 'A', $sort);
- } else {
- $conn->send_now("Sorry");
- $conn->disconnect;
+ if ($msg =~ m{ROUTE,[0-9A-F,]+|HELLO}) {
+ # a possibly valid HELLO line, process it
+ $conn->new_channel($msg);
}
} 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->to_connected($conn->{call}, 'O', $conn->{csort});
+ $conn->{state} = 'WH';
}
}
}
}
}
-sub to_connected
-{
- my ($conn, $call, $dir, $sort) = @_;
- $conn->{state} = 'C';
- $conn->conns($call);
- delete $conn->{cmd};
- $conn->{timeout}->del if $conn->{timeout};
- delete $conn->{timeout};
- $conn->nolinger;
- &{$conn->{rproc}}($conn, "$dir$call|$sort");
-}
-
sub login
{
return \&new_channel;
$conn->disconnect();
}
Log('Aranea', "Incoming connection from $conn->{peerhost}");
- $conn->{outgoing} = 0;
+ $conn->{outbound} = 0;
$conn->{state} = 'WH'; # wait for return authorize
my $thing = $conn->{lastthing} = Thingy::Hello->new(origin=>$main::mycall, group=>'ROUTE');
+
$thing->send($conn, 'Aranea');
+ dbg("-> D $conn->{peerhost} $thing->{Aranea}") if isdbg('chan');
}
} else {
dbg("ExtMsg: error on accept ($!)") if isdbg('err');
}
}
-sub start_connect
+sub set_newchannel_rproc
{
- my $call = shift;
- my $fn = shift;
- my $conn = AMsg->new(\&new_channel);
- $conn->{outgoing} = 1;
- $conn->conns($call);
-
- my $f = new IO::File $fn;
- push @{$conn->{cmd}}, <$f>;
- $f->close;
- $conn->{state} = 'WC';
- $conn->_dotimeout($deftimeout);
- $conn->_docmd;
+ my $conn = shift;
+ $conn->{rproc} = \&new_channel;
+ $conn->{state} = 'WH';
}
#
sub new_channel
{
my ($conn, $msg) = @_;
+ my $call = $conn->{call} || $conn->{peerhost};
+
+ dbg("<- I $call $msg") if isdbg('chan');
+
my $thing = Aranea::input($msg);
- return unless defined $thing;
+ unless ($thing) {
+ dbg("Invalid thingy: $msg from $conn->{peerhost}");
+ $conn->send_now("Sorry");
+ $conn->disconnect;
+ return;
+ }
- my $call = $thing->{origin};
+ $call = $thing->{origin};
unless (is_callsign($call)) {
main::already_conn($conn, $call, DXM::msg($main::lang, "illcall", $call));
return;
my $user = DXUser->get_current($call);
my $dxchan = DXChannel->get($call);
if ($dxchan) {
- if ($main::bumpexisting) {
+ if ($main::bumpexisting && $call ne $main::mycall) {
my $ip = $conn->{peerhost} || 'unknown';
$dxchan->send_now('D', DXM::msg($main::lang, 'conbump', $call, $ip));
Log('DXCommand', "$call bumped off by $ip, disconnected");
$dxchan = Aranea->new($call, $conn, $user);
# check that the conn has a callsign
- $conn->conns($call) if $conn->isa('IntMsg');
+ $conn->conns($call);
# set callbacks
$conn->set_error(sub {main::error_handler($dxchan)});
$conn->set_rproc(sub {my ($conn,$msg) = @_; $dxchan->rec($msg)});
- $dxchan->rec($msg);
+ $conn->{state} = 'C';
+ delete $conn->{cmd};
+ $conn->{timeout}->del if $conn->{timeout};
+ delete $conn->{timeout};
+ $conn->nolinger;
+ $thing->handle($dxchan);
}
sub send
use Script;
use Verify;
use DXDupe;
+use Thingy;
use vars qw($VERSION $BRANCH);
$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
my $seqno = 0;
my $dayno = 0;
+my $daystart = 0;
sub init
{
$self->{metric} ||= 100;
$self->{lastping} = $main::systime;
- $self->state('init');
+ $self->state('normal');
$self->{pc50_t} = $main::systime;
# send info to all logged in thingies
# run a script send the output to the debug file
my $script = new Script(lc $call) || new Script('node_default');
$script->run($self) if $script;
- $self->send("Hello?");
}
#
sub normal
{
my ($self, $line) = @_;
-
-
+ my $thing = input($line);
+ $thing->queue($self) if $thing;
}
#
{
# calc day number
- $dayno = (gmtime($main::systime))[3];
+ my $d = (gmtime($main::systime))[3];
+ if ($d != $dayno) {
+ $dayno = $d;
+ $daystart = $main::systime - ($main::systime % 86400);
+ }
+}
+
+sub disconnect
+{
+ my $self = shift;
+ my $call = $self->call;
+
+ return if $self->{disconnecting}++;
+
+ # get rid of any PC16/17/19
+# eph_del_regex("^PC1[679]*$call");
+
+ # do routing stuff, remove me from routing table
+ my $node = Route::Node::get($call);
+ my @rout;
+ if ($node) {
+ @rout = $node->del($main::routeroot);
+
+ # and all my ephemera as well
+ for (@rout) {
+ my $c = $_->call;
+# eph_del_regex("^PC1[679].*$c");
+ }
+ }
+
+ RouteDB::delete_interface($call);
+
+ # unbusy and stop and outgoing mail
+ my $mref = DXMsg::get_busy($call);
+ $mref->stop_msg($call) if $mref;
+
+ # broadcast to all other nodes that all the nodes connected to via me are gone
+# $self->route_pc21($main::mycall, undef, @rout) if @rout;
+
+ # remove outstanding pings
+# delete $pings{$call};
+
+ # I was the last node visited
+ $self->user->node($main::mycall);
+
+ # send info to all logged in thingies
+ $self->tell_login('logoutn');
+
+ Log('Aranea', $call . " Disconnected");
+
+ $self->SUPER::disconnect;
}
#
my $from = shift;
my $date = ((($dayno << 1) | $ntpflag) << 18) | ($main::systime % 86400);
- my $r = "$mycall,$to," . sprintf('%06X%04X,0', $date, $seqno);
+ my $r = "$mycall,$to," . sprintf('%6X%04X,0', $date, $seqno);
$r .= ",$from" if $from;
$seqno++;
$seqno = 0 if $seqno > 0x0ffff;
return $r;
}
+#
+# decode the date time sequence group
+#
+
+sub decode_dts
+{
+ my $dts = shift;
+ my ($dt, $seqno) = map {hex} unpack "H6H4", $dts;
+ my $secs = $dt & 0x3FFFF;
+ $dt >>= 18;
+ my $day = $dt >> 1;
+ my $ntp = $dt & 1;
+ my $t;
+ if ($dayno == $day) {
+ $t = $daystart + $secs;
+ } elsif ($dayno < $day) {
+ $t = $daystart + (($day-$dayno) * 86400) + $secs;
+ } else {
+ $t = $daystart + (($dayno-$day) * 86400) + $secs;
+ }
+ return ($t, $seqno, $ntp);
+}
+
# subroutines to encode and decode values in lists
sub tencode
{
my $s = shift;
- $s =~ s/([\%=|,\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg;
+ $s =~ s/([\%=|,\'\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg;
+ $s = "'$s'" if $s =~ / /;
return $s;
}
sub tdecode
{
my $s = shift;
+ $s =~ s/^'(.*)'$/$1/;
$s =~ s/\%([0-9A-F][0-9A-F])/chr(hex($1))/eg;
return $s;
}
return "$head|$data";
}
+
+sub decode_input
+{
+ my $self = shift;
+ my $line = shift;
+ return ('I', $self->{call}, $line);
+}
+
sub input
{
my $line = shift;
my ($head, $data) = split /\|/, $line, 2;
return unless $head && $data;
+
my ($origin, $group, $dts, $hop, $user) = split /,/, $head;
- return if DXDupe::add("Ara,$origin,$dts", $dupeage);
- $hop++;
+ return if DXDupe::check("Ara,$origin,$dts", $dupeage);
+ my $err;
+ $err .= "incomplete header," unless $origin && defined $group && $dts && defined $hop;
my ($cmd, $rdata) = split /,/, $data, 2;
- my $class = 'Thingy::' . ucfirst $cmd;
+
+ # validate it further
+ $err .= "missing cmd or data," unless $cmd && $data;
+ $err .= "invalid command ($cmd)," unless $cmd =~ /^[A-Z][A-Z0-9]*$/;
+ $err .= "invalid group ($group)," unless $group =~ /^[-A-Z0-9\/:]{2,}$/;
+
+ my $class = 'Thingy::' . ucfirst(lc $cmd);
my $thing;
+ my ($t, $seqno, $ntp) = decode_dts($dts) unless $err;
+ $err .= "invalid date/seq," unless $t;
- # create the appropriate Thingy
- if (defined *$class) {
+ if ($err) {
+ chop $err;
+ dbg("Aranea input: $err");
+ } elsif ($class->can('new')) {
+ # create the appropriate Thingy
$thing = $class->new();
# reconstitute the header but wth hop increased by one
- $head = join(',', $origin, $group, $dts, $hop);
+ $head = join(',', $origin, $group, $dts, ++$hop);
$head .= ",$user" if $user;
$thing->{Aranea} = "$head|$data";
# store useful data
$thing->{origin} = $origin;
- $thing->{group} = $group;
- $thing->{time} = decode_dts($dts);
+ ($thing->{group}, $thing->{touser}) = split /:/, $group, 2;
+ $thing->{time} = $t;
$thing->{user} = $user if $user;
$thing->{hopsaway} = $hop;
- while (my ($k,$v) = split /,/, $rdata) {
- $thing->{$k} = tdecode($v);
+ for (split(/,/, $rdata)) {
+ if (/=/) {
+ my ($k,$v) = split /=/, $_, 2;
+ $thing->{$k} = tdecode($v);
+ } else {
+ $thing->{$_} = 1;
+ }
+ }
+
+ # post process the thing, this generally adds on semantic meaning
+ # does parameter checking etc. It also adds / prepares the thingy so
+ # this is compatible with older protocol and arranges data so
+ # that the filtering can still work.
+ if ($thing->can('from_Aranea')) {
+
+ # if a thing is ok then return that thing, otherwise return
+ # nothing
+ $thing = $thing->from_Aranea;
}
}
return $thing;
}
+# this is the DXChannel send
+# note that this does NOT send out stuff in same way as other DXChannels
+# it is just as it comes, no extra bits added (here)
+sub send # this is always later and always data
+{
+ my $self = shift;
+ my $conn = $self->{conn};
+ return unless $conn;
+ my $call = $self->{call};
+
+ for (@_) {
+# chomp;
+ my @lines = split /\n/;
+ for (@lines) {
+ $conn->send_later($_);
+ dbg("-> D $call $_") if isdbg('chan');
+ }
+ }
+ $self->{t} = $main::systime;
+}
+
+#
+# load of dummies for DXChannel broadcasts
+# these will go away in time?
+# These are all from PC protocol
+#
+
+sub dx_spot
+{
+ my $self = shift;
+ my $line = shift;
+ my $isolate = shift;
+ my ($filter, $hops);
+
+ if ($self->{spotsfilter}) {
+ ($filter, $hops) = $self->{spotsfilter}->it(@_);
+ return unless $filter;
+ }
+# send_prot_line($self, $filter, $hops, $isolate, $line);
+}
+
+sub wwv
+{
+ my $self = shift;
+ my $line = shift;
+ my $isolate = shift;
+ my ($filter, $hops);
+
+ if ($self->{wwvfilter}) {
+ ($filter, $hops) = $self->{wwvfilter}->it(@_);
+ return unless $filter;
+ }
+# send_prot_line($self, $filter, $hops, $isolate, $line)
+}
+
+sub wcy
+{
+ my $self = shift;
+ my $line = shift;
+ my $isolate = shift;
+ my ($filter, $hops);
+
+ if ($self->{wcyfilter}) {
+ ($filter, $hops) = $self->{wcyfilter}->it(@_);
+ return unless $filter;
+ }
+# send_prot_line($self, $filter, $hops, $isolate, $line) if $self->is_clx || $self->is_spider || $self->is_dxnet;
+}
+
+sub announce
+{
+ my $self = shift;
+ my $line = shift;
+ my $isolate = shift;
+ my $to = shift;
+ my $target = shift;
+ my $text = shift;
+ my ($filter, $hops);
+
+ if ($self->{annfilter}) {
+ ($filter, $hops) = $self->{annfilter}->it(@_);
+ return unless $filter;
+ }
+# send_prot_line($self, $filter, $hops, $isolate, $line) unless $_[1] eq $main::mycall;
+}
+
+sub chat
+{
+ goto &announce;
+}
+
1;
sub is_node
{
my $self = shift;
- return $self->{'sort'} =~ /[ACRSXW]/;
+ return $self->{'sort'} =~ /[ACRSX]/;
}
# is it an ak1a node ?
sub is_ak1a
use QSL;
use DB_File;
use VE7CC;
+use Thingy;
+use Thingy::Dx;
use strict;
use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase $maxerrors %nothereslug $maxbadcount $msgpolltime);
sub format_dx_spot
{
my $self = shift;
-
- my $t = ztime($_[2]);
+ my $spot = ref $_[0] ? shift : \@_;
+
+ my $t = ztime($spot->[2]);
my $loc = '';
my $clth = $self->{consort} eq 'local' ? 29 : 30;
- my $comment = substr $_[3], 0, $clth;
+ my $comment = substr $spot->[3], 0, $clth;
$comment .= ' ' x ($clth - length($comment));
if ($self->{user}->wantgrid) {
- my $ref = DXUser->get_current($_[4]);
+ my $ref = DXUser->get_current($spot->[4]);
if ($ref) {
$loc = $ref->qra || '';
$loc = ' ' . substr($loc, 0, 4) if $loc;
}
if ($self->{user}->wantdxitu) {
- $loc = ' ' . sprintf("%2d", $_[10]) if defined $_[10];
- $comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $_[8]) if defined $_[8];
+ $loc = ' ' . sprintf("%2d", $spot->[10]) if defined $spot->[10];
+ $comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $spot->[8]) if defined $spot->[8];
} elsif ($self->{user}->wantdxcq) {
- $loc = ' ' . sprintf("%2d", $_[11]) if defined $_[11];
- $comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $_[9]) if defined $_[9];
+ $loc = ' ' . sprintf("%2d", $spot->[11]) if defined $spot->[11];
+ $comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $spot->[9]) if defined $spot->[9];
} elsif ($self->{user}->wantusstate) {
- $loc = ' ' . $_[13] if $_[13];
- $comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . $_[12] if $_[12];
+ $loc = ' ' . $spot->[13] if $spot->[13];
+ $comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . $spot->[12] if $spot->[12];
}
- return sprintf "DX de %-7.7s%11.1f %-12.12s %-s $t$loc", "$_[4]:", $_[0], $_[1], $comment;
+ return sprintf "DX de %-7.7s%11.1f %-12.12s %-s $t$loc", "$spot->[4]:", $spot->[0], $spot->[1], $comment;
}
# send a dx spot
require Exporter;
@ISA = qw(Exporter);
-@EXPORT = qw(dbginit dbg dbgadd dbgsub dbglist dbgdump isdbg dbgclose confess croak cluck);
+@EXPORT = qw(dbginit dbg dbgadd dbgsub dbglist dbgdump dbglog isdbg dbgclose confess croak cluck);
use strict;
use vars qw(%dbglevel $fp $callback $cleandays $keepdays);
}
}
+sub dbglog
+{
+ my $sort = shift;
+ my $l = shift;
+ dbg($l);
+ DXLog::Log($sort, $l);
+}
1;
__END__
use Script;
use Investigate;
use RouteDB;
-
+use Thingy;
+use Thingy::Dx;
use strict;
$main::me->{metric} = 0;
$main::me->{pingave} = 0;
$main::me->{registered} = 1;
- $main::me->{version} = $main::version;
+ $main::me->{version} = 5251 + $main::version;
$main::me->{build} = $main::build;
}
$self->send(pc18());
}
-sub removepc90
-{
- $_[0] =~ s/^PC90\^[-A-Z0-9]+\^\d+\^//;
- $_[0] =~ s/^PC91\^[-A-Z0-9]+\^\d+\^[-A-Z0-9]+\^//;
-}
-
-#sub send
-#{
-# my $self = shift;
-# while (@_) {
-# my $line = shift;
-# $self->SUPER::send($line);
-# }
-#}
#
# This is the normal pcxx despatcher
{
my ($self, $line) = @_;
- # remove any incoming PC90 frames
- removepc90($line);
-
my @field = split /\^/, $line;
return unless @field;
# print join(',', @field), "\n";
-
# process PC frames, this will fail unless the frame starts PCnn
my ($pcno) = $field[0] =~ /^PC(\d\d)/; # just get the number
unless (defined $pcno && $pcno >= 10 && $pcno <= 99) {
return;
}
+ # decrement any hop fields at this point
+ if ($line =~ /\^H(\d\d?)\^?~?$/) {
+ my $hops = $1 - 1;
+ if ($hops < 0) {
+ dbg("PCPROT: zero hop count, dumped") if isdbg('chanerr');
+ return;
+ }
+ $line =~ s/\^H\d\d?(\^?~?)$/^H$hops$1/;
+ }
+
my $origin = $self->{call};
no strict 'subs';
my $sub = "handle_$pcno";
}
# remember a route to this node and also the node on which this user is
- RouteDB::update($_[6], $self->{call});
+ RouteDB::update($_[6], $origin);
# RouteDB::update($to, $_[6]);
# it is here and logged on
# RouteDB::update($_[6], $_[7]);
my @spot = Spot::prepare($_[1], $_[2], $d, $_[5], $_[6], $_[7]);
- # global spot filtering on INPUT
- if ($self->{inspotsfilter}) {
- my ($filter, $hops) = $self->{inspotsfilter}->it(@spot);
- unless ($filter) {
- dbg("PCPROT: Rejected by input spot filter") if isdbg('chanerr');
- return;
- }
- }
+
+ my $thing = Thingy::Dx->new(origin=>$main::mycall, group=>'DX');
+ $thing->from_DXProt(DXProt=>$line,spotdata=>\@spot);
+ $thing->queue($self);
# this goes after the input filtering, but before the add
# so that if it is input filtered, it isn't added to the dup
# list. This allows it to come in from a "legitimate" source
- if (Spot::dup($_[1], $_[2], $d, $_[5], $_[6])) {
- dbg("PCPROT: Duplicate Spot ignored\n") if isdbg('chanerr');
- return;
- }
-
- # add it
- Spot::add(@spot);
-
#
# @spot at this point contains:-
# freq, spotted call, time, text, spotter, spotted cc, spotters cc, orig node
return if $pcno == 26;
# send out the filtered spots
- send_dx_spot($self, $line, @spot) if @spot;
+# send_dx_spot($self, $line, @spot) if @spot;
}
# announces
# dos I want users from this channel?
unless ($self->user->wantpc16) {
- dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr');
+ dbg("PCPROT: don't send users to $origin") if isdbg('chanerr');
return;
}
# is it me?
return;
}
- RouteDB::update($ncall, $self->{call});
+ RouteDB::update($ncall, $origin);
# do we believe this call?
- unless ($ncall eq $self->{call} || $self->is_believed($ncall)) {
- if (my $ivp = Investigate::get($ncall, $self->{call})) {
+ unless ($ncall eq $origin || $self->is_believed($ncall)) {
+ if (my $ivp = Investigate::get($ncall, $origin)) {
$ivp->store_pcxx($pcno,$line,$origin,@_);
} else {
- dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr');
+ dbg("PCPROT: We don't believe $ncall on $origin") if isdbg('chanerr');
}
return;
}
$parent = Route::Node::get($_->[0]);
$dxchan = $parent->dxchan if $parent;
if ($dxchan && $dxchan ne $self) {
- dbg("PCPROT: PC19 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
+ dbg("PCPROT: PC19 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
$parent = undef;
}
if ($parent) {
$dxchan = $parent->dxchan;
if ($dxchan && $dxchan ne $self) {
- dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
+ dbg("PCPROT: PC16 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
return;
}
# do I want users from this channel?
unless ($self->user->wantpc16) {
- dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr');
+ dbg("PCPROT: don't send users to $origin") if isdbg('chanerr');
return;
}
if ($ncall eq $main::mycall) {
return;
}
- RouteDB::delete($ncall, $self->{call});
+ RouteDB::delete($ncall, $origin);
# do we believe this call?
- unless ($ncall eq $self->{call} || $self->is_believed($ncall)) {
- if (my $ivp = Investigate::get($ncall, $self->{call})) {
+ unless ($ncall eq $origin || $self->is_believed($ncall)) {
+ if (my $ivp = Investigate::get($ncall, $origin)) {
$ivp->store_pcxx($pcno,$line,$origin,@_);
} else {
- dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr');
+ dbg("PCPROT: We don't believe $ncall on $origin") if isdbg('chanerr');
}
return;
}
$dxchan = $parent->dxchan if $parent;
if ($dxchan && $dxchan ne $self) {
- dbg("PCPROT: PC17 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
+ dbg("PCPROT: PC17 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
return;
}
# record the type and version offered
if ($_[1] =~ /DXSpider Version: (\d+\.\d+) Build: (\d+\.\d+)/) {
- $self->version(53 + $1);
- $self->user->version(53 + $1);
+ $self->version(52.51 + $1);
+ $self->user->version(52.51 + $1);
$self->build(0 + $2);
$self->user->build(0 + $2);
unless ($self->is_spider) {
}
# first clear out any nodes on this dxchannel
- my $parent = Route::Node::get($self->{call});
+ my $parent = Route::Node::get($origin);
my @rout = $parent->del_nodes;
$self->route_pc21($origin, $line, @rout, $parent) if @rout;
$self->send_local_config();
my @rout;
# first get the INTERFACE node
- my $parent = Route::Node::get($self->{call});
+ my $parent = Route::Node::get($origin);
unless ($parent) {
- dbg("DXPROT: my parent $self->{call} has disappeared");
+ dbg("DXPROT: my parent $origin has disappeared");
$self->disconnect;
return;
}
# check that this PC19 isn't trying to alter the wrong dxchan
my $dxchan = DXChannel->get($call);
if ($dxchan && $dxchan != $self) {
- dbg("PCPROT: PC19 from $self->{call} trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr');
+ dbg("PCPROT: PC19 from $origin trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr');
next;
}
}
$user->sort('A') unless $user->is_node;
- RouteDB::update($call, $self->{call});
+ RouteDB::update($call, $origin);
# do we believe this call?
my $genline = "PC19^$here^$call^$conf^$ver^$_[-1]^";
- unless ($call eq $self->{call} || $self->is_believed($call)) {
- my $pt = $user->lastping($self->{call}) || 0;
- if ($pt+$investigation_int < $main::systime && !Investigate::get($call, $self->{call})) {
- my $ivp = Investigate->new($call, $self->{call});
+ unless ($call eq $origin || $self->is_believed($call)) {
+ my $pt = $user->lastping($origin) || 0;
+ if ($pt+$investigation_int < $main::systime && !Investigate::get($call, $origin)) {
+ my $ivp = Investigate->new($call, $origin);
$ivp->version($ver);
$ivp->here($here);
$ivp->store_pcxx($pcno,$genline,$origin,'PC19',$here,$call,$conf,$ver,$_[-1]);
} else {
- dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr');
+ dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr');
}
$user->put;
next;
} else {
# if he is directly connected or allowed then add him, otherwise store him up for later
- if ($call eq $self->{call} || $user->wantroutepc19) {
+ if ($call eq $origin || $user->wantroutepc19) {
my $new = Route->new($call); # throw away
if ($self->in_filter_route($new)) {
my $ar = $parent->add($call, $ver, $flags);
} else {
$pc19list{$call} = [] unless exists $pc19list{$call};
my $nl = $pc19list{$call};
- push @{$pc19list{$call}}, [$self->{call}, $ver, $flags] unless grep $_->[0] eq $self->{call}, @$nl;
+ push @{$pc19list{$call}}, [$origin, $ver, $flags] unless grep $_->[0] eq $origin, @$nl;
}
}
return;
}
- RouteDB::delete($call, $self->{call});
+ RouteDB::delete($call, $origin);
# check if we believe this
- unless ($call eq $self->{call} || $self->is_believed($call)) {
- if (my $ivp = Investigate::get($call, $self->{call})) {
+ unless ($call eq $origin || $self->is_believed($call)) {
+ if (my $ivp = Investigate::get($call, $origin)) {
$ivp->store_pcxx($pcno,$line,$origin,@_);
} else {
- dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr');
+ dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr');
}
return;
}
# this routing table manipulation, just remove it from the list and dump it
my @rout;
if (my $nl = $pc19list{$call}) {
- $pc19list{$call} = [ grep {$_->[0] ne $self->{call}} @$nl ];
+ $pc19list{$call} = [ grep {$_->[0] ne $origin} @$nl ];
delete $pc19list{$call} unless @{$pc19list{$call}};
} else {
- my $parent = Route::Node::get($self->{call});
+ my $parent = Route::Node::get($origin);
unless ($parent) {
- dbg("DXPROT: my parent $self->{call} has disappeared");
+ dbg("DXPROT: my parent $origin has disappeared");
$self->disconnect;
return;
}
my $dxchan = DXChannel->get($call);
if ($dxchan && $dxchan != $self) {
- dbg("PCPROT: PC21 from $self->{call} trying to alter locally connected $call, ignored!") if isdbg('chanerr');
+ dbg("PCPROT: PC21 from $origin trying to alter locally connected $call, ignored!") if isdbg('chanerr');
return;
}
my $pcno = shift;
my $line = shift;
my $origin = shift;
- if ($_[1] eq $self->{call}) {
+ if ($_[1] eq $origin) {
$self->disconnect(1);
} else {
dbg("PCPROT: came in on wrong channel") if isdbg('chanerr');
my $call = $_[1];
- RouteDB::update($call, $self->{call});
+ RouteDB::update($call, $origin);
my $node = Route::Node::get($call);
if ($node) {
- return unless $node->call eq $self->{call};
+ return unless $node->call eq $origin;
$node->usercount($_[2]);
# input filter if required
$tochan->{pingave} = $tochan->{pingave} + (($t - $tochan->{pingave}) / 6);
}
$tochan->{nopings} = $nopings; # pump up the timer
- if (my $ivp = Investigate::get($from, $self->{call})) {
+ if (my $ivp = Investigate::get($from, $origin)) {
$ivp->handle_ping;
}
} elsif (my $rref = Route::Node::get($r->{call})) {
- if (my $ivp = Investigate::get($from, $self->{call})) {
+ if (my $ivp = Investigate::get($from, $origin)) {
$ivp->handle_ping;
}
}
}
} else {
- RouteDB::update($from, $self->{call});
+ RouteDB::update($from, $origin);
if (eph_dup($line)) {
dbg("PCPROT: dup PC51 detected") if isdbg('chanerr');
$s =~ s/\^H(\d+)(\^~?)$/\^H$newhops$2/ if $newhops;
} else {
# simply decrement it
- $hops--;
+# $hops--; this is done on receipt now
return "" if !$hops;
$s =~ s/\^H(\d+)(\^~?)$/\^H$hops$2/ if $hops;
}
$pc50_interval = 14*60;
# the version of DX cluster (tm) software I am masquerading as
-$myprot_version = 5300;
+$myprot_version = 5251;
# default hopcount to use
$def_hopcount = 30;
# Request init string
sub pc18
{
- return "PC18^DXSpider Version: $main::version Build: $main::build^$DXProt::myprot_version^";
+ my $v = $DXProt::myprot_version + $main::version;
+ return "PC18^DXSpider Version: $main::version Build: $main::build^$v^";
}
#
delete $conn->{timeout};
$conn->nolinger;
&{$conn->{rproc}}($conn, "$dir$call|$sort");
- $conn->_send_file("$main::data/connected") unless $conn->{outgoing};
+ $conn->_send_file("$main::data/connected") unless $conn->{outbound};
}
sub new_client {
my $call = shift;
my $fn = shift;
my $conn = ExtMsg->new(\&main::new_channel);
- $conn->{outgoing} = 1;
+ $conn->{outbound} = 1;
$conn->conns($call);
-
- my $f = new IO::File $fn;
- push @{$conn->{cmd}}, <$f>;
- $f->close;
+ push @{$conn->{cmd}}, @_;
$conn->{state} = 'WC';
$conn->_dotimeout($deftimeout);
$conn->_docmd;
dbg("CONNECT $conn->{cnum} sort: $sort command: $line") if isdbg('connect');
if ($sort eq 'telnet') {
# this is a straight network connect
- my ($host, $port) = split /\s+/, $line;
+ my ($host, $port, $type) = split /\s+/, $line;
+ if ($type && ref($conn) ne $type) {
+ bless $conn, $type;
+ $conn->set_newchannel_rproc;
+ dbg("$conn->{cnum} to $host $port reblessed as $type") if isdbg('connect');
+ }
$port = 23 if !$port;
$r = $conn->connect($host, $port);
if ($r) {
dbg("Connected $conn->{cnum} to $host $port") if isdbg('connect');
+
} else {
dbg("***Connect $conn->{cnum} Failed to $host $port $!") if isdbg('connect');
}
my $key;
my $type = 'Dunno';
my $asc = '?';
+ my $data = ref $_[0] ? shift : \@_;
my $r = @keys > 0 ? 0 : 1;
foreach $key (@keys) {
if ($filter->{reject} && exists $filter->{reject}->{code}) {
$type = 'reject';
$asc = $filter->{reject}->{user};
- if (&{$filter->{reject}->{code}}(\@_)) {
+ if (&{$filter->{reject}->{code}}($data)) {
$r = 0;
last;
} else {
if ($filter->{accept} && exists $filter->{accept}->{code}) {
$type = 'accept';
$asc = $filter->{accept}->{user};
- if (&{$filter->{accept}->{code}}(\@_)) {
+ if (&{$filter->{accept}->{code}}($data)) {
$r = 1;
last;
} else {
my $hops = $self->{hops} if exists $self->{hops};
if (isdbg('filter')) {
- my $args = join '\',\'', map {defined $_ ? $_ : 'undef'} @_;
+ my $args = join '\',\'', map {defined $_ ? $_ : 'undef'} @$data;
my $true = $r ? "OK " : "REJ";
my $sort = $self->{sort};
my $dir = $self->{name} =~ /^in_/i ? "IN " : "OUT";
$out[4] =~ s/-\d+$//o;
# remove leading and trailing spaces
- $_[3] = unpad($_[3]);
+ unpad($out[3]);
# add the 'dxcc' country on the end for both spotted and spotter, then the cluster call
# Thingy handling
#
# This is the new fundamental protocol engine handler
+#
+# This is where all the new things (and eventually all the old things
+# as well) happen.
#
# $Id$
#
package Thingy;
-use vars qw($VERSION $BRANCH);
+use vars qw($VERSION $BRANCH @queue @permin @persec);
$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ || (0,0));
$main::build += $VERSION;
$main::branch += $BRANCH;
+@queue = (); # the input / processing queue
+
+#
+# these are set up using the Thingy->add_second_process($addr, $name)
+# and Thingy->add_minute_process($addr, $name)
+#
+# They replace the old cycle in cluster.pl
+#
+
+@persec = (); # this replaces the cycle in cluster.pl
+@permin = (); # this is an extra per minute cycle
+
+my $lastsec = time;
+my $lastmin = time;
+
use DXChannel;
use DXDebug;
sub send
{
my $thing = shift;
- my $chan = shift;
+ my $dxchan = shift;
my $class;
if (@_) {
$class = shift;
- } elsif ($chan->isa('DXChannel')) {
- $class = ref $chan;
+ } elsif ($dxchan->isa('DXChannel')) {
+ $class = ref $dxchan;
+ }
+
+ # do output filtering
+ if ($thing->can('out_filter')) {
+ return unless $thing->out_filter;
}
# generate the line which may (or not) be cached
} else {
no strict 'refs';
my $sub = "gen_$class";
- push @out, $thing->$sub() if $thing->can($sub);
+ push @out, $thing->$sub($dxchan) if $thing->can($sub);
+ }
+ $dxchan->send(@out) if @out;
+}
+
+# broadcast to all except @_
+sub broadcast
+{
+ my $thing = shift;
+ dbg("Thingy::broadcast: " . $thing->ascii) if isdbg('thing');
+
+ foreach my $dxchan (DXChannel::get_all()) {
+ next if $dxchan == $main::me;
+ next if grep $dxchan == $_, @_;
+ $thing->send($dxchan);
+ }
+}
+
+# queue this thing for processing
+sub queue
+{
+ my $thing = shift;
+ my $dxchan = shift;
+ $thing->{dxchan} = $dxchan->call;
+ push @queue, $thing;
+}
+
+# this is the main commutator loop. In due course it will
+# become the *only* commutator loop
+sub process
+{
+ my $thing;
+ while (@queue) {
+ $thing = shift @queue;
+ my $dxchan = DXChannel->get($thing->{dxchan});
+ if ($dxchan) {
+ if ($thing->can('in_filter')) {
+ next unless $thing->in_filter($dxchan);
+ }
+ $thing->handle($dxchan);
+ }
+ }
+
+ # per second and per minute processing
+ if ($main::systime != $lastsec) {
+ if ($main::systime >= $lastmin+60) {
+ foreach my $r (@permin) {
+ &{$r->[0]}();
+ }
+ $lastmin = $main::systime;
+ }
+ foreach my $r (@persec) {
+ &{$r->[0]}();
+ }
+ $lastsec = $main::systime;
}
- $chan->send(@out) if @out;
}
+sub add_minute_process
+{
+ my $pkg = shift;
+ my $addr = shift;
+ my $name = shift;
+ dbg('Adding $name to Thingy per minute queue');
+ push @permin, [$addr, $name];
+}
+
+sub add_second_process
+{
+ my $pkg = shift;
+ my $addr = shift;
+ my $name = shift;
+ dbg('Adding $name to Thingy per second queue');
+ push @persec, [$addr, $name];
+}
+
+sub ascii
+{
+ my $thing = shift;
+ my $dd = new Data::Dumper([$thing]);
+ $dd->Indent(0);
+ $dd->Terse(1);
+ $dd->Sortkeys(1);
+ $dd->Quotekeys($] < 5.005 ? 1 : 0);
+ return $dd->Dumpxs;
+}
1;
--- /dev/null
+#
+# Dx Thingy handling
+#
+# $Id$
+#
+# Copyright (c) 2005 Dirk Koopman G1TLH
+#
+
+use strict;
+
+package Thingy::Dx;
+
+use vars qw($VERSION $BRANCH);
+$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
+$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ || (0,0));
+$main::build += $VERSION;
+$main::branch += $BRANCH;
+
+use DXChannel;
+use DXDebug;
+use DXUtil;
+use Thingy;
+use Spot;
+
+use vars qw(@ISA);
+@ISA = qw(Thingy);
+
+sub gen_Aranea
+{
+ my $thing = shift;
+ unless ($thing->{Aranea}) {
+ my $sd = $thing->{spotdata};
+ my @items = (
+ f=>$sd->[0],
+ c=>$sd->[1],
+ );
+ push @items, ('b', $sd->[4]) unless $thing->{user};
+ push @items, ('st', sprintf("%X", $sd->[2] / 60), 'o', $sd->[7]) unless $sd->[7] eq $main::mycall;
+ push @items, ('i', $sd->[3]) if $sd->[3];
+ $thing->{Aranea} = Aranea::genmsg($thing, 'DX', @items);
+ }
+ return $thing->{Aranea};
+}
+
+sub from_Aranea
+{
+ my $thing = shift;
+ return unless $thing;
+ my $t = hex($thing->{st}) if exists $thing->{st};
+ $t ||= $thing->{time} / 60;
+ my @spot = Spot::prepare(
+ $thing->{f},
+ $thing->{c},
+ $t*60,
+ ($thing->{i} || ''),
+ ($thing->{b} || $thing->{fromuser} || $thing->{user} || $thing->{origin}),
+ ($thing->{o} || $thing->{origin}),
+ );
+ $thing->{spotdata} = \@spot;
+ return $thing;
+}
+
+sub gen_DXProt
+{
+ my $thing = shift;
+ unless ($thing->{DXProt}) {
+ my $sd = $thing->{spotdata};
+ my $hops = $thing->{hops} || DXProt::get_hops(11);
+ my $text = $sd->[3] || ' ';
+ $text =~ s/\^/%5E/g;
+ my $t = $sd->[2];
+ $thing->{DXProt} = sprintf "PC11^%.1f^$sd->[1]^%s^%s^$text^$sd->[4]^$sd->[7]^$hops^~", $sd->[0], cldate($t), ztime($t);
+ }
+ return $thing->{DXProt};
+}
+
+sub gen_DXCommandmode
+{
+ my $thing = shift;
+ my $dxchan = shift;
+
+ # these are always generated, never cached
+ return unless $dxchan->{dx};
+
+ my $buf;
+ if ($dxchan->{ve7cc}) {
+ $buf = VE7CC::dx_spot($dxchan, $thing->{spotdata});
+ } else {
+ $buf = $dxchan->format_dx_spot($thing->{spotdata});
+ $buf .= "\a\a" if $dxchan->{beep};
+ $buf =~ s/\%5E/^/g;
+ }
+ return $buf;
+}
+
+sub from_DXProt
+{
+ my $thing = shift;
+ while (@_) {
+ my $k = shift;
+ $thing->{$k} = shift;
+ }
+ ($thing->{hops}) = $thing->{DXProt} =~ /\^H(\d+)\^?~?$/ if exists $thing->{DXProt};
+ return $thing;
+}
+
+sub handle
+{
+ my $thing = shift;
+ my $dxchan = shift;
+
+ my $spot = $thing->{spotdata};
+ if (Spot::dup(@$spot[0..4])) {
+ dbg("PCPROT: Duplicate Spot ignored\n") if isdbg('chanerr');
+ return;
+ }
+
+ # add it
+ Spot::add(@$spot);
+
+ $thing->broadcast($dxchan);
+}
+
+sub in_filter
+{
+ my $thing = shift;
+ my $dxchan = shift;
+
+ # global spot filtering on INPUT
+ if ($dxchan->{inspotsfilter}) {
+ my ($filter, $hops) = $dxchan->{inspotsfilter}->it($thing->{spotdata});
+ unless ($filter) {
+ dbg("PCPROT: Rejected by input spot filter") if isdbg('chanerr');
+ return;
+ }
+ }
+ return 1;
+}
+
+sub out_filter
+{
+ my $thing = shift;
+ my $dxchan = shift;
+
+ # global spot filtering on INPUT
+ if ($dxchan->{inspotsfilter}) {
+ my ($filter, $hops) = $dxchan->{inspotsfilter}->it($thing->{spotdata});
+ unless ($filter) {
+ dbg("PCPROT: Rejected by input spot filter") if isdbg('chanerr');
+ return;
+ }
+ $thing->{hops} = $hops if $hops;
+ } elsif ($dxchan->{isolate}) {
+ return;
+ }
+ return 1;
+}
+1;
use Verify;
use Thingy;
-use vars qw(@ISA);
+use vars qw(@ISA $verify_on_login);
@ISA = qw(Thingy);
+$verify_on_login = 1; # make sure that a HELLO coming from
+ # the dxchan call is authentic
+
sub gen_Aranea
{
my $thing = shift;
unless ($thing->{Aranea}) {
- my $auth = $thing->{auth} = Verify->new($main::mycall, $main::systime);
- $thing->{Aranea} = Aranea::genmsg($thing, 'HELLO', sw=>'DXSpider',
+ my $s = sprintf "%X", int(rand() * 100000000);
+ my $auth = Verify->new("DXSp,$main::mycall,$s,$main::version,$main::build");
+ $thing->{Aranea} = Aranea::genmsg($thing, 'HELLO', sw=>'DXSp',
v=>$main::version,
b=>$main::build,
+ 's'=>$s,
auth=>$auth->challenge($main::me->user->passphrase)
);
}
return $thing->{Aranea};
}
-sub from_Aranea
+sub handle
{
- my $line = shift;
- my $thing = Aranea::input($line);
- return unless $thing;
+ my $thing = shift;
+ my $dxchan = shift;
+
+ # verify authenticity
+ if ($dxchan->call eq $thing->{origin}) {
+ if ($verify_on_login) {
+ my $pp = $dxchan->user->passphrase;
+ unless ($pp) {
+ dbglog('err', "Thingy::Hello::handle: verify on and $thing->{origin} has no passphrase");
+ $dxchan->disconnect;
+ return;
+ }
+ my $auth = Verify->new("DXSp,$thing->{origin},$thing->{s},$thing->{v},$thing->{b}");
+ unless ($auth->verify($thing->{auth}, $dxchan->user->passphrase)) {
+ dbglog('err', "Thingy::Hello::handle: verify on and $thing->{origin} failed auth check");
+ $dxchan->disconnect;
+ return;
+ }
+ }
+ if ($dxchan->{state} ne 'normal') {
+ $dxchan->start($dxchan->{conn}->{csort}, $dxchan->{conn}->{outbound} ? 'O' : 'A');
+ if ($dxchan->{outbound}) {
+ my $thing = Thingy::Hello->new(origin=>$main::mycall, group=>'ROUTE');
+ $thing->send($dxchan);
+ }
+ }
+ }
+ $thing->broadcast($dxchan);
}
1;
{
my $class = shift;
my $self = bless {}, ref($class) || $class;
- if (@_) {
- $self->newseed(@_);
- $self->newsalt;
- }
+ $self->newsalt(@_);
return $self;
}
-sub newseed
-{
- my $self = shift;
- return $self->{seed} = sha1_base64('RbG4tST2dYPWnh6bfAaq7pPSL04', @_);
-}
-
sub newsalt
{
my $self = shift;
- return $self->{salt} = substr sha1_base64($self->{seed}, rand, rand, rand), 0, 6;
+ return $self->{salt} = sha1_base64('RbG4tST2dYPWnh6bfAaq7pPSL04', @_);
}
sub challenge
{
my $self = shift;
- return $self->{salt} . sha1_base64($self->{salt}, $self->{seed}, @_);
+ my $p = substr(sha1_base64($self->{salt}, @_), -6, 6);
+ return $p;
}
sub verify
{
my $self = shift;
my $answer = shift;
- my $p = sha1_base64($self->{salt}, $self->{seed}, @_);
+ my $p = substr(sha1_base64($self->{salt}, @_), -6, 6);
return $p eq $answer;
}
-sub seed
-{
- my $self = shift;
- return @_ ? $self->{seed} = shift : $self->{seed};
-}
-
sub salt
{
my $self = shift;
@inqueue = (); # the main input queue, an array of hashes
$systime = 0; # the time now (in seconds)
-$version = "1.51"; # the version no of the software
+$version = "2.01"; # the version no of the software
$starttime = 0; # the starting time of the cluster
#@outstanding_connects = (); # list of outstanding connects
@listeners = (); # list of listeners
already_conn($conn, $call, DXM::msg($lang, 'concluster', $call, $main::mycall));
return;
}
- if ($bumpexisting) {
+ if ($bumpexisting && $call ne $main::mycall) {
my $ip = $conn->{peerhost} || 'unknown';
$dxchan->send_now('D', DXM::msg($lang, 'conbump', $call, $ip));
Log('DXCommand', "$call bumped off by $ip, disconnected");
Aranea->init();
# put in a DXCluster node for us here so we can add users and take them away
-$routeroot = Route::Node->new($mycall, $version*100+5300, Route::here($main::me->here)|Route::conf($main::me->conf));
+$routeroot = Route::Node->new($mycall, $version*100+5251, Route::here($main::me->here)|Route::conf($main::me->conf));
# make sure that there is a routing OUTPUT node default file
#unless (Filter::read_in('route', 'node_default', 0)) {
my $timenow = time;
DXChannel::process();
+ Thingy::process();
# $DB::trace = 0;
# do timed stuff, ongoing processing happens one a second
if ($timenow != $systime) {
+ rand(); # keep randomising to reduce (but not eliminate) predictability
reap if $zombies;
$systime = $timenow;
DXCron::process(); # do cron jobs