# routing, this must go out here to prevent race condx
my $pkg = shift;
my $call = shift;
- my @rout = $main::routeroot->add_user($call, Route::here(1));
+ my $uref = Route::User::get($call) || Route::User->new($call);
+ $uref->here(1);
+ $uref->conf(0);
+ $main::routeroot->add_user($uref);
# ALWAYS output the user
- my $ref = Route::User::get($call);
- $main::me->route_pc16($main::mycall, undef, $main::routeroot, $ref) if $ref;
+ $main::me->route_pc16($main::mycall, undef, $main::routeroot, $uref);
return $self;
}
{
do "$main::data/hop_table.pl" if -e "$main::data/hop_table.pl";
confess $@ if $@;
+
+ my $user = DXUser->get($main::mycall);
+ $DXProt::myprot_version += $main::version*100;
+ $main::me = DXProt->SUPER::alloc($main::mycall, 0, $user);
+ $main::me->{here} = 1;
+ $main::me->{state} = "indifferent";
+ $main::me->{sort} = 'S'; # S for spider
+ $main::me->{priv} = 9;
+ $main::me->{metric} = 0;
+ $main::me->{pingave} = 0;
+ $main::me->{registered} = 1;
+ $main::me->{version} = $main::version;
+ $main::me->{build} = $main::build;
}
#
# add this node to the table, the values get filled in later
my $pkg = shift;
my $call = shift;
- $main::routeroot->add($call, '5000', Route::here(1)) if $call ne $main::mycall;
+ my $uref = Route::Node::get($call) || Route::Node->new($call);
+ $uref->here(1);
+ $uref->conf(0);
+ $uref->version(5000);
+ $main::routeroot->link_node($uref, $self);
return $self;
}
# now do it properly for actions
my $node = Route::Node::get($ncall) || Route::Node::new($ncall);
+ $node->newroute(1);
# find each of the entries (or create new ones)
my @refs;
next;
}
$ref->here($ehere); # might as well set this here
- $ref->lastheard($main::systime);
+ $ref->lastseen($main::systime);
push @refs, $ref;
}
push @adduser, $node->add_user($_) for @au;
}
-
$self->route_pc21($origin, $line, @delnode) if @delnode;
$self->route_pc19($origin, $line, @addnode) if @addnode;
$self->route_pc17($origin, $line, @deluser) if @deluser;
if ($self->{newroute}) {
my @nodes = $self->{isolate} ? ($main::routeroot) : grep { $_->call ne $main::mycall && $_ != $self && !$_->{isolate} } DXChannel::get_all_nodes();
my @users = DXChannel::get_all_users();
- $self->send_route($main::mycall, \&pc59c, @nodes+@users+1, (grep { Route::get($_) } $main::routeroot, @nodes, @users));
+ $self->send_route($main::mycall, \&pc59, @nodes+@users+4, 'C', 0, $main::mycall, (grep { Route::get($_) } $main::routeroot, @nodes, @users));
} else {
# send our nodes
if ($self->{isolate}) {
# do routing stuff, remove me from routing table
my $node = Route::Node::get($call);
my @rout;
+ my @rusers;
if ($node) {
- @rout = $node->del($main::routeroot);
+
+ # remove the route from this node and return a list
+ # of nodes that have become orphanned as a result.
+ push @rout, $main::routeroot->remove_route($node, $self);
+
+ # remove all consequently orphanned users from these nodes
+ push @rusers, $_->unlink_all_users for @rout;
- # and all my ephemera as well
+ # remove all my ephemera as well
for (@rout) {
my $c = $_->call;
eph_del_regex("^PC1[679].*$c");
}
}
- # remove them from the pc19list as well
- while (my ($k,$v) = each %pc19list) {
- my @l = grep {$_->[0] ne $call} @{$pc19list{$k}};
- if (@l) {
- $pc19list{$k} = \@l;
- } else {
- delete $pc19list{$k};
- }
-
- # and the ephemera
- eph_del_regex("^PC1[679].*$k");
- }
-
# 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
unless ($pc39flag && $pc39flag == 2) {
$self->route_pc21($main::mycall, undef, @rout) if @rout;
+ $self->route_pc59('D', 0, $main::mycall, $node);
}
+ # delete all the unwanted nodes
+ $_->delete for @rout, @rusers;
+
# remove outstanding pings
delete $pings{$call};
# deal with non routing parameters
unless (ref $r && $r->isa('Route')) {
push @rin, $r;
- $no++;
next;
}
my $origin = shift;
my $line = shift;
- # @_ - 2 because we start with [ACD], hexstamp
- broadcast_route($self, $origin, \&pc59, $line, scalar @_ - 2, @_);
+ broadcast_route($self, $origin, \&pc59, $line, scalar @_, @_);
}
sub in_filter_route
my $r = shift;
return $self ? 2 : 0 unless ref $self;
return ($self->{flags} & 2) ? 1 : 0 unless defined $r;
- $self->{flags} = (($self->{flags} & ~2) | ($r ? 2 : 0));
+ $self->{flags} &= ~2;
+ $self->{flags} |= $r ? 2 : 0;
return $r ? 1 : 0;
}
my $r = shift;
return $self ? 1 : 0 unless ref $self;
return ($self->{flags} & 1) ? 1 : 0 unless defined $r;
- $self->{flags} = (($self->{flags} & ~1) | ($r ? 1 : 0));
+ $self->{flags} &= ~1;
+ $self->{flags} |= $r ? 1 : 0;
return $r ? 1 : 0;
}
users => '0,Users,parray',
usercount => '0,User Count',
version => '0,Version',
+ newroute => '0,New Routing?,yesno',
);
$filterdef = $Route::filterdef;
{
my ($self, $neighbour, $dxchan) = @_;
- my $r = $self->is_empty('dxchan');
+ my $r = $neighbour->is_empty('dxchan');
$self->_addlist('nodes', $neighbour);
$neighbour->_addlist('nodes', $self);
- $self->_addlist('dxchan', $dxchan);
$neighbour->_addlist('dxchan', $dxchan);
- return $r ? ($self) : ();
+ return $r ? ($neighbour) : ();
}
# unlink a node from a neighbour and remove any
my ($self, $neighbour, $dxchan) = @_;
$self->_dellist('nodes', $neighbour);
$neighbour->_dellist('nodes', $self);
- $self->_dellist('dxchan', $dxchan);
- $neighbour->_dellist('dxchan', $dxchan);
- return $self->is_empty('dxchan') ? ($self) : ();
+ $neighbour->_dellist('dxchan', $dxchan) if $dxchan;
+ return $neighbour->is_empty('dxchan') ? ($neighbour) : ();
+}
+
+sub remove_route
+{
+ my ($self, $neighbour, $dxchan) = @_;
+
+ # cut the dxchan link
+ # cut the node link
+ my @rout;
+ push @rout, $self->unlink_node($neighbour, $dxchan);
+ dbg("Orphanning $neighbour->{call}") if isdbg('routelow');
+
+ # then run down the tree removing this dxchan link from
+ # all the referenced nodes that use this interface
+ my %visited;
+ my @in = map { Route::Node::get($_) } $neighbour->nodes;
+ foreach my $r (@in) {
+ next unless $r;
+ next if $visited{$r->call};
+ my ($o) = $r->del_dxchan($self);
+ if ($o) {
+ dbg("Orphanning $_->{call}") if isdbg('routelow');
+ push @rout, $o;
+ }
+ push @in, map{ Route::Node::get($_) } $r->nodes;
+ $visited{$r->call} = $r;
+ }
+
+ # in @rout there should be a list of orphaned (in dxchan terms)
+ # nodes. Now go thru and make sure that all their links are
+ # broken (they should be, but this is to check).
+
+ foreach my $r (@rout) {
+ my @nodes = map { Route::Node::get($_)} $r->nodes;
+ for (@nodes) {
+ next unless $_;
+ dbg("Orphaned node $_->{call}: breaking link to $_->{call}") if isdbg('routelow');
+ $r->unlink_node($_);
+ }
+ }
+ return @rout;
}
# add a user to this node
return $uref->is_empty('nodes') ? ($uref) : ();
}
+# add a single dxchan link
+sub add_dxchan
+{
+ my ($self, $dxchan) = @_;
+ return $self->_addlist('dxchan', $dxchan);
+}
+
+# remove a single dxchan link
+sub del_dxchan
+{
+ my ($self, $dxchan) = @_;
+ return $self->_dellist('dxchan', $dxchan);
+}
+
sub usercount
{
my $self = shift;
sub unlink_all_users
{
my $self = shift;
- foreach my $u (${$self->{nodes}}) {
+ my @rout;
+ foreach my $u (${$self->{users}}) {
my $uref = Route::User::get($u);
- $self->unlink_user($uref) if $uref;
+ push @rout, $self->del_user($uref) if $uref;
}
+ return @rout;
}
sub new
my $self = $pkg->SUPER::new($call);
$self->{dxchan} = ref $pkg ? [ $pkg->{call} ] : [ ];
- $self->{version} = shift;
- $self->{flags} = shift;
+ $self->{version} = shift || 5000;
+ $self->{flags} = shift || Route::here(1);
$self->{users} = [];
$self->{nodes} = [];
- $self->{lid} = 0;
$list{$call} = $self;
dbg("creating Route::Node $self->{call}") if isdbg('routelow');
my $pkg = shift;
my $call = uc shift;
my $ncall = uc shift;
- my $flags = shift;
+ my $flags = shift || Route::here(1);
confess "already have $call in $pkg" if $list{$call};
my $self = $pkg->SUPER::new($call);
use DXProtVars;
use DXProtout;
use DXProt;
-use QXProt;
use DXMsg;
use DXCron;
use DXConnect;
# create the channel
- if ($user->wantnp) {
- if ($user->passphrase && $main::me->user->passphrase) {
- $dxchan = QXProt->new($call, $conn, $user);
- } else {
- unless ($user->passphrase) {
- Log('DXCommand', "$call using NP but has no passphrase");
- dbg("$call using NP but has no passphrase");
- }
- unless ($main::me->user->passphrase) {
- Log('DXCommand', "$main::mycall using NP but has no passphrase");
- dbg("$main::mycall using NP but has no passphrase");
- }
- already_conn($conn, $call, "Need to exchange passphrases");
- return;
- }
- } elsif ($user->is_node) {
+ if ($user->is_node) {
$dxchan = DXProt->new($call, $conn, $user);
} elsif ($user->is_user) {
$dxchan = DXCommandmode->new($call, $conn, $user);
# initialise the protocol engine
dbg("Start Protocol Engines ...");
DXProt->init();
-QXProt->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);
+$routeroot->version($version*100+5300);
+$routeroot->here($main::me->here || 1);
+$routeroot->conf($main::me->conf || 0);
+$routeroot->add_dxchan($me);
+$routeroot->lastseen(time);
# make sure that there is a routing OUTPUT node default file
#unless (Filter::read_in('route', 'node_default', 0)) {
DXCron::process(); # do cron jobs
DXCommandmode::process(); # process ongoing command mode stuff
DXProt::process(); # process ongoing ak1a pcxx stuff
- QXProt::process();
DXConnect::process();
DXMsg::process();
DXDb::process();