chiark / gitweb /
site: transport peers: Delete or demote unsuitable peers addresses
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 28 Jun 2014 14:32:19 +0000 (15:32 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 5 Oct 2014 20:06:28 +0000 (21:06 +0100)
If comm signals that the address is unuseable (ie we have no IPv4 or
IPv6 interface or routing), delete the address.  Or, if we are mobile,
demote it to the end of the list (since we might gain appropriate
routing in the future).

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
site.c

diff --git a/site.c b/site.c
index 2e514c2..8d6787d 100644 (file)
--- a/site.c
+++ b/site.c
@@ -2209,15 +2209,63 @@ static void transport_resolve_complete_tardy(struct site *st,
     transport_record_peer(st,&st->peers,ca_use,"resolved tardily");
 }
 
+static void transport_peers__copy_by_mask(transport_peer *out, int *nout_io,
+                                         unsigned mask,
+                                         const transport_peers *inp) {
+    /* out and in->peers may be the same region, or nonoverlapping */
+    const transport_peer *in=inp->peers;
+    int slot;
+    for (slot=0; slot<inp->npeers; slot++) {
+       if (!(mask & (1U << slot)))
+           continue;
+       if (!(out==in && slot==*nout_io))
+           COPY_OBJ(out[*nout_io], in[slot]);
+       (*nout_io)++;
+    }
+}
+
 void transport_xmit(struct site *st, transport_peers *peers,
                    struct buffer_if *buf, bool_t candebug) {
     int slot;
     transport_peers_expire(st, peers);
+    unsigned failed=0; /* bitmask */
+    assert(MAX_MOBILE_PEERS_MAX < sizeof(unsigned)*CHAR_BIT);
+
+    int nfailed=0;
     for (slot=0; slot<peers->npeers; slot++) {
        transport_peer *peer=&peers->peers[slot];
        if (candebug)
            dump_packet(st, buf, &peer->addr, False);
-       peer->addr.comm->sendmsg(peer->addr.comm->st, buf, &peer->addr);
+       bool_t ok =
+           peer->addr.comm->sendmsg(peer->addr.comm->st, buf, &peer->addr);
+       if (!ok) {
+           failed |= 1U << slot;
+           nfailed++;
+       }
+       if (ok && !st->peer_mobile)
+           break;
+    }
+    /* Now we need to demote/delete failing addrs: if we are mobile we
+     * merely demote them; otherwise we delete them. */
+    if (st->local_mobile) {
+       unsigned expected = ((1U << nfailed)-1) << (peers->npeers-nfailed);
+       /* `expected' has all the failures at the end already */
+       if (failed != expected) {
+           int fslot=0;
+           transport_peer failedpeers[nfailed];
+           transport_peers__copy_by_mask(failedpeers, &fslot, failed,peers);
+           assert(fslot == nfailed);
+           int wslot=0;
+           transport_peers__copy_by_mask(peers->peers,&wslot,~failed,peers);
+           assert(wslot+nfailed == peers->npeers);
+           COPY_ARRAY(peers->peers+wslot, failedpeers, nfailed);
+       }
+    } else {
+       if (failed && peers->npeers > 1) {
+           int wslot=0;
+           transport_peers__copy_by_mask(peers->peers,&wslot,~failed,peers);
+           peers->npeers=wslot;
+       }
     }
 }