+
+
+/***** TRANSPORT PEERS definitions *****/
+
+static void transport_peers_debug(struct site *st, transport_peers *dst,
+ const char *didwhat,
+ int nargs, const struct comm_addr *args,
+ size_t stride) {
+ int i;
+ char *argp;
+
+ if (!(st->log_events & LOG_PEER_ADDRS))
+ return; /* an optimisation */
+
+ slog(st, LOG_PEER_ADDRS, "peers (%s) %s nargs=%d => npeers=%d",
+ (dst==&st->peers ? "data" :
+ dst==&st->setup_peers ? "setup" : "UNKNOWN"),
+ didwhat, nargs, dst->npeers);
+
+ for (i=0, argp=(void*)args;
+ i<nargs;
+ i++, (argp+=stride?stride:sizeof(*args))) {
+ const struct comm_addr *ca=(void*)argp;
+ slog(st, LOG_PEER_ADDRS, " args: addrs[%d]=%s",
+ i, ca->comm->addr_to_string(ca->comm->st,ca));
+ }
+ for (i=0; i<dst->npeers; i++) {
+ struct timeval diff;
+ timersub(tv_now,&dst->peers[i].last,&diff);
+ const struct comm_addr *ca=&dst->peers[i].addr;
+ slog(st, LOG_PEER_ADDRS, " peers: addrs[%d]=%s T-%ld.%06ld",
+ i, ca->comm->addr_to_string(ca->comm->st,ca),
+ (unsigned long)diff.tv_sec, (unsigned long)diff.tv_usec);
+ }
+}
+
+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 void transport_peers_expire(struct site *st, transport_peers *peers) {
+ /* peers must be sorted first */
+ int previous_peers=peers->npeers;
+ struct timeval oldest;
+ oldest.tv_sec = tv_now->tv_sec - st->mobile_peer_expiry;
+ oldest.tv_usec = tv_now->tv_usec;
+ while (peers->npeers>1 &&
+ timercmp(&peers->peers[peers->npeers-1].last, &oldest, <))
+ peers->npeers--;
+ if (peers->npeers != previous_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;
+
+ for (slot=0; slot<peers->npeers; slot++)
+ if (!memcmp(&peers->peers[slot].addr, addr, sizeof(*addr)))
+ goto found;
+
+ changed=1;
+ if (peers->npeers==st->transport_peers_max)
+ slot=st->transport_peers_max;
+ else
+ slot=peers->npeers++;
+
+ found:
+ peers->peers[slot].addr=*addr;
+ peers->peers[slot].last=*tv_now;
+
+ if (peers->npeers>1)
+ qsort(peers->peers, peers->npeers,
+ sizeof(*peers->peers), transport_peer_compar);
+
+ if (changed || peers->npeers!=1)
+ transport_peers_debug(st,peers,m, 1,addr,0);
+ transport_peers_expire(st, peers);
+}
+
+static bool_t transport_compute_setupinit_peers(struct site *st,
+ const struct comm_addr *configured_addr /* 0 if none or not found */) {
+
+ if (!configured_addr && !transport_peers_valid(&st->peers))
+ return False;
+
+ slog(st,LOG_SETUP_INIT,
+ (!configured_addr ? "using only %d old peer address(es)"
+ : "using configured address, and/or perhaps %d old peer address(es)"),
+ st->peers);
+
+ /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they
+ * have transport_peers_max==1. The effect is that this code
+ * always uses the configured address if supplied, or otherwise
+ * the existing data peer if one exists; this is as desired. */
+
+ transport_peers_copy(st,&st->setup_peers,&st->peers);
+
+ if (configured_addr)
+ transport_record_peer(st,&st->setup_peers,configured_addr,"setupinit");
+
+ assert(transport_peers_valid(&st->setup_peers));
+ return True;
+}
+
+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");
+}
+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");
+}
+
+static int transport_peers_valid(transport_peers *peers) {
+ return peers->npeers;
+}
+static void transport_peers_clear(struct site *st, transport_peers *peers) {
+ peers->npeers= 0;
+ transport_peers_debug(st,peers,"clear",0,0,0);
+}
+static void transport_peers_copy(struct site *st, transport_peers *dst,
+ const transport_peers *src) {
+ dst->npeers=src->npeers;
+ memcpy(dst->peers, src->peers, sizeof(*dst->peers) * dst->npeers);
+ transport_peers_debug(st,dst,"copy",
+ src->npeers, &src->peers->addr, sizeof(src->peers));
+}
+
+void transport_xmit(struct site *st, transport_peers *peers,
+ struct buffer_if *buf, bool_t candebug) {
+ int slot;
+ transport_peers_expire(st, peers);
+ 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);
+ }
+}
+
+/***** END of transport peers declarations *****/