chiark / gitweb /
site: Provide transport_record_peers to cope with multiple addresses
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 28 Jun 2014 16:11:07 +0000 (17:11 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 5 Oct 2014 20:06:28 +0000 (21:06 +0100)
This is a complete replacement of transport_record_peer by this new
function.  The semantics are similar to the old function, except that
the new one copes with multiple addresses at once (ensuring that they
arrive, in order, at the front of the array).  It now needs its
caller to call transport_peers_expire.

We provide a convenience function transport_expire_record_peers for
the various call sites that want to call expire and then record.

As yet, there are no callers of transport_record_peers which pass
naddrs!=1 so there is no overall functional change.

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

diff --git a/site.c b/site.c
index 8d6787d..9b07980 100644 (file)
--- a/site.c
+++ b/site.c
@@ -2092,13 +2092,9 @@ static void transport_peers_debug(struct site *st, transport_peers *dst,
     }
 }
 
-static int transport_peer_compar(const void *av, const void *bv) {
-    const transport_peer *a=av;
-    const transport_peer *b=bv;
-    /* put most recent first in the array */
-    if (timercmp(&a->last, &b->last, <)) return +1;
-    if (timercmp(&a->last, &b->last, >)) return -11;
-    return 0;
+static bool_t transport_addrs_equal(const struct comm_addr *a,
+                                   const struct comm_addr *b) {
+    return !memcmp(a,b,sizeof(*a));
 }
 
 static void transport_peers_expire(struct site *st, transport_peers *peers) {
@@ -2114,31 +2110,67 @@ static void transport_peers_expire(struct site *st, transport_peers *peers) {
        transport_peers_debug(st,peers,"expire", 0,0,0);
 }
 
-static void transport_record_peer(struct site *st, transport_peers *peers,
-                                 const struct comm_addr *addr, const char *m) {
-    int slot, changed=0;
+static bool_t transport_peer_record_one(struct site *st, transport_peers *peers,
+                                       const struct comm_addr *ca,
+                                       const struct timeval *tv) {
+    /* returns false if output is full */
+    int search;
 
-    for (slot=0; slot<peers->npeers; slot++)
-       if (!memcmp(&peers->peers[slot].addr, addr, sizeof(*addr)))
-           goto found;
+    if (peers->npeers >= st->transport_peers_max)
+       return 0;
 
-    changed=1;
-    if (peers->npeers==st->transport_peers_max)
-       slot=st->transport_peers_max-1;
-    else
-       slot=peers->npeers++;
+    for (search=0; search<peers->npeers; search++)
+       if (transport_addrs_equal(&peers->peers[search].addr, ca))
+           return 1;
+
+    peers->peers[peers->npeers].addr = *ca;
+    peers->peers[peers->npeers].last = *tv;
+    peers->npeers++;
+    return 1;
+}
+
+static void transport_record_peers(struct site *st, transport_peers *peers,
+                                  const struct comm_addr *addrs, int naddrs,
+                                  const char *m) {
+    /* We add addrs into peers.  The new entries end up at the front
+     * and displace entries towards the end (perhaps even off the
+     * end).  Any existing matching entries are moved up to the front.
+     *
+     * Caller must first call transport_peers_expire. */
+
+    if (naddrs==1 && peers->npeers>=1 &&
+       transport_addrs_equal(&addrs[0], &peers->peers[0].addr)) {
+       /* optimisation, also avoids debug for trivial updates */
+       peers->peers[0].last = *tv_now;
+       return;
+    }
 
- found:
-    peers->peers[slot].addr=*addr;
-    peers->peers[slot].last=*tv_now;
+    int old_npeers=peers->npeers;
+    transport_peer old_peers[old_npeers];
+    COPY_ARRAY(old_peers,peers->peers,old_npeers);
 
-    if (peers->npeers>1)
-       qsort(peers->peers, peers->npeers,
-             sizeof(*peers->peers), transport_peer_compar);
+    peers->npeers=0;
+    int i;
+    for (i=0; i<naddrs; i++) {
+       if (!transport_peer_record_one(st,peers, &addrs[i], tv_now))
+           break;
+    }
+    for (i=0; i<old_npeers; i++) {
+       const transport_peer *old=&old_peers[i];
+       if (!transport_peer_record_one(st,peers, &old->addr, &old->last))
+           break;
+    }
 
-    if (changed || peers->npeers!=1)
-       transport_peers_debug(st,peers,m, 1,addr,0);
-    transport_peers_expire(st, peers);
+    transport_peers_debug(st,peers,m, naddrs,addrs,0);
+}
+
+static void transport_expire_record_peers(struct site *st,
+                                         transport_peers *peers,
+                                         const struct comm_addr *addrs,
+                                         int naddrs, const char *m) {
+    /* Convenience function */
+    transport_peers_expire(st,peers);
+    transport_record_peers(st,peers,addrs,naddrs,m);
 }
 
 static bool_t transport_compute_setupinit_peers(struct site *st,
@@ -2162,13 +2194,15 @@ static bool_t transport_compute_setupinit_peers(struct site *st,
      * one exists; this is as desired. */
 
     transport_peers_copy(st,&st->setup_peers,&st->peers);
+    transport_peers_expire(st,&st->setup_peers);
 
     if (incoming_packet_addr)
-       transport_record_peer(st,&st->setup_peers,incoming_packet_addr,
-                             "incoming");
+       transport_record_peers(st,&st->setup_peers,
+                              incoming_packet_addr,1, "incoming");
 
     if (configured_addr)
-       transport_record_peer(st,&st->setup_peers,configured_addr,"setupinit");
+       transport_record_peers(st,&st->setup_peers,
+                              configured_addr,1, "setupinit");
 
     assert(transport_peers_valid(&st->setup_peers));
     return True;
@@ -2176,11 +2210,11 @@ static bool_t transport_compute_setupinit_peers(struct site *st,
 
 static void transport_setup_msgok(struct site *st, const struct comm_addr *a) {
     if (st->peer_mobile)
-       transport_record_peer(st,&st->setup_peers,a,"setupmsg");
+       transport_expire_record_peers(st,&st->setup_peers,a,1,"setupmsg");
 }
 static void transport_data_msgok(struct site *st, const struct comm_addr *a) {
     if (st->peer_mobile)
-       transport_record_peer(st,&st->peers,a,"datamsg");
+       transport_expire_record_peers(st,&st->peers,a,1,"datamsg");
 }
 
 static int transport_peers_valid(transport_peers *peers) {
@@ -2199,14 +2233,14 @@ static void transport_peers_copy(struct site *st, transport_peers *dst,
 }
 
 static void transport_resolve_complete(struct site *st,
-                                      const struct comm_addr *ca_use) {
-    transport_record_peer(st,&st->peers,ca_use,"resolved data");
-    transport_record_peer(st,&st->setup_peers,ca_use,"resolved setup");
+                                      const struct comm_addr *ca) {
+    transport_expire_record_peers(st,&st->peers,ca,1,"resolved data");
+    transport_expire_record_peers(st,&st->setup_peers,ca,1,"resolved setup");
 }
 
 static void transport_resolve_complete_tardy(struct site *st,
-                                            const struct comm_addr *ca_use) {
-    transport_record_peer(st,&st->peers,ca_use,"resolved tardily");
+                                            const struct comm_addr *ca) {
+    transport_expire_record_peers(st,&st->peers,ca,1,"resolved tardily");
 }
 
 static void transport_peers__copy_by_mask(transport_peer *out, int *nout_io,