rpc: dedup qso announcements

We may receive more than one copy of the same announcement because we may
share the same multiple subnets as the sending instance, or we may have more
than one IP on a subnet.  Either way, we don't want to spam the callbacks
with duplicate QSO announcements.  So, we keep a small circular buffer of
last NUM_QSO_DEDUP uuids that we received for each instance.

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
1 files changed, 47 insertions(+), 6 deletions(-)

M rpc/announce-track.c
M rpc/announce-track.c +47 -6
@@ 37,6 37,18 @@ 
 
 #include "announce-impl.h"
 
+/*
+ * Number of entries per instance to keep around for dedup'ing of QSO
+ * announcements.
+ *
+ * We may receive more than one copy of the same announcement because we may
+ * share the same multiple subnets as the sending instance, or we may have
+ * more than one IP on a subnet.  Either way, we don't want to spam the
+ * callbacks with duplicate QSO announcements.  So, we keep a small circular
+ * buffer of last NUM_QSO_DEDUP uuids that we received for each instance.
+ */
+#define NUM_QSO_DEDUP	4
+
 struct addr {
 	union xsockaddr addr;
 	uint64_t ts;

          
@@ 51,8 63,16 @@ struct instance {
 	/* the bulk of the data lives in the following sub-struct */
 	struct instance_info info;
 
+	struct str *hlog_version;
+
 	struct addr *addrs; /* announcement addresses & times */
 	/* TODO: RPC addresses & ports */
+
+	struct qso_dedup {
+		struct xuuid uuid;
+		enum announce_qso_msg_type type;
+	} qso_dedup[NUM_QSO_DEDUP];
+	size_t qso_dedup_next;
 };
 
 static struct rb_tree instances;

          
@@ 105,15 125,36 @@ static void invoke_callback(struct insta
 			    const struct announce_msg *msg)
 {
 	switch ((enum announce_msg_type) msg->major) {
-		case ANNOUNCE_QSO:
-			if (notify.qso) {
-				struct xuuid uuid;
+		case ANNOUNCE_QSO: {
+			const size_t next = inst->qso_dedup_next;
+			struct xuuid uuid;
+			size_t i;
+
+			if (!notify.qso)
+				return; /* no callback */
+
+			memcpy(uuid.raw, msg->u.qso.uuid, sizeof(uuid));
+
+			for (i = 0; i < ARRAY_LEN(inst->qso_dedup); i++) {
+				struct qso_dedup *d = &inst->qso_dedup[i];
 
-				memcpy(uuid.raw, msg->u.qso.uuid, sizeof(uuid));
+				if (xuuid_compare(&uuid, &d->uuid))
+					continue;
+
+				if (msg->minor != d->type)
+					continue;
+
+				return; /* ignore duplicate */
+			}
 
-				notify.qso(msg->minor, &inst->info, &uuid);
-			}
+			notify.qso(msg->minor, &inst->info, &uuid);
+
+			/* stash uuid & minor type for future dedup matching */
+			inst->qso_dedup[next].uuid = uuid;
+			inst->qso_dedup[next].type = msg->minor;
+			inst->qso_dedup_next = (next + 1) % NUM_QSO_DEDUP;
 			break;
+		}
 		case ANNOUNCE_LOC:
 			if (notify.loc)
 				notify.loc(msg->minor, &inst->info);