The RF-to-APRS-IS path does not consult the existing 25-second duplicate cache.
The cache is currently used only by the digipeater path.
As a result, one local iGate can upload the same RF packet more than once when
it first hears the original transmission and then hears the same packet again
after a digipeater has changed the path.
Example of one information field arriving through two paths:
STATION_Utils::isIn25SegHashBuffer() is called only from the digipeater
branch. APRS_IS_Utils::processLoRaPacket() uploads without consulting a
local duplicate cache.
Moving the existing check in front of both consumers would not solve the
problem: whichever consumer checks first would prevent the other destination
from processing the first valid reception.
Expected behavior
For one local node and one duplicate window:
the first valid reception may be uploaded once to APRS-IS;
the first relayable reception may be repeated once by the digipeater;
a later copy with a changed RF path must not be uploaded or repeated again
by that same node;
independent iGates remain independent and may each upload their own copy.
Proposed design
Use one bounded, expiring cache whose entries contain:
The RF path must not be included, and the information field must not be
trimmed. A single atomic-style operation such as claimDestination(fingerprint, destination) should return true only the first
time that destination claims the packet.
The APRS-IS claim should happen immediately before the effective upload, after
local message/query handling. The digipeater claim should happen only after
the packet has been found relayable, immediately before queueing the RF relay.
Tested implementation
A field-tested implementation using a 64-bit FNV-1a fingerprint, a 25-second
window, a bounded cache and per-destination bits is available here:
That fork also carries RXT, so its fingerprint removes the RF-only RXT trailer
before hashing. The generic upstream fix does not otherwise depend on RXT.
The implementation includes host tests for independent destination claims,
expiry, capacity bounds, exact whitespace preservation and millis()
wraparound. Field logs confirm that the direct packet is uploaded and the
returned digipeated copy is reported as locally skipped.
## Problem
The RF-to-APRS-IS path does not consult the existing 25-second duplicate cache.
The cache is currently used only by the digipeater path.
As a result, one local iGate can upload the same RF packet more than once when
it first hears the original transmission and then hears the same packet again
after a digipeater has changed the path.
Example of one information field arriving through two paths:
```text
F5ZQC-10>APLRG1,WIDE1-1:!L8f?,Nn&"# GLoRa APRS Batt=4.27V
F5ZQC-10>APLRG1,F4MLV-10*:!L8f?,Nn&"# GLoRa APRS Batt=4.27V
```
The source and information field are identical; only the RF path differs.
Both copies are currently eligible for upload by the same iGate.
## Cause
The main loop sends a received packet to APRS-IS before passing it to the
digipeater:
```cpp
APRS_IS_Utils::processLoRaPacket(packet);
DIGI_Utils::processLoRaPacket(packet);
```
`STATION_Utils::isIn25SegHashBuffer()` is called only from the digipeater
branch. `APRS_IS_Utils::processLoRaPacket()` uploads without consulting a
local duplicate cache.
Moving the existing check in front of both consumers would not solve the
problem: whichever consumer checks first would prevent the other destination
from processing the first valid reception.
## Expected behavior
For one local node and one duplicate window:
- the first valid reception may be uploaded once to APRS-IS;
- the first relayable reception may be repeated once by the digipeater;
- a later copy with a changed RF path must not be uploaded or repeated again
by that same node;
- independent iGates remain independent and may each upload their own copy.
## Proposed design
Use one bounded, expiring cache whose entries contain:
```cpp
struct PacketDedupEntry {
uint64_t fingerprint;
uint32_t firstSeenMs;
uint8_t destinations;
};
constexpr uint8_t DEDUP_DIGI = 1 << 0;
constexpr uint8_t DEDUP_APRSIS = 1 << 1;
```
The fingerprint should be based on:
```text
original source + exact information field
```
The RF path must not be included, and the information field must not be
trimmed. A single atomic-style operation such as
`claimDestination(fingerprint, destination)` should return true only the first
time that destination claims the packet.
The APRS-IS claim should happen immediately before the effective upload, after
local message/query handling. The digipeater claim should happen only after
the packet has been found relayable, immediately before queueing the RF relay.
## Tested implementation
A field-tested implementation using a 64-bit FNV-1a fingerprint, a 25-second
window, a bounded cache and per-destination bits is available here:
https://github.com/moricef/LoRa_APRS_iGate/commit/b1f96425651975813c277b4d18b550285ed29cae
That fork also carries RXT, so its fingerprint removes the RF-only RXT trailer
before hashing. The generic upstream fix does not otherwise depend on RXT.
The implementation includes host tests for independent destination claims,
expiry, capacity bounds, exact whitespace preservation and `millis()`
wraparound. Field logs confirm that the direct packet is uploaded and the
returned digipeated copy is reported as locally skipped.
<!-- github-sync-id:5595387966 -->
Hi, I asked the same question a few years ago and I got as response:
iGates should upload everything they hear, EVERYTHING.
APRS-IS has many ways to work with this tons of packets being uploaded and the deduplication is done on their servers.
Only Digipeaters should do the filtering of those packets being repeated.
PS: the reason is that igates will upload all and this will help to have all the path and info to analyze packets also
Hi, I asked the same question a few years ago and I got as response:
iGates should upload everything they hear, EVERYTHING.
APRS-IS has many ways to work with this tons of packets being uploaded and the deduplication is done on their servers.
Only Digipeaters should do the filtering of those packets being repeated.
PS: the reason is that igates will upload all and this will help to have all the path and info to analyze packets also
<!-- github-comment-id:5856912337 -->
Thank you for the clarification. I misunderstood the intended division of responsibility between IGates and APRS-IS duplicate filtering. After reviewing the APRS-IS server specification, I agree that IGates should upload every valid RF reception and leave duplicate suppression to the servers.
Sorry for the noise, and thank you again for the explanation. I’m closing this issue.
Hi Ricardo,
Thank you for the clarification. I misunderstood the intended division of responsibility between IGates and APRS-IS duplicate filtering. After reviewing the APRS-IS server specification, I agree that IGates should upload every valid RF reception and leave duplicate suppression to the servers.
Sorry for the noise, and thank you again for the explanation. I’m closing this issue.
<!-- github-comment-id:5857406302 -->
There is no problem on chasing on this topics! and thanks again on helping with this
I'm currently reviewing the PR you just pushed also
There is no problem on chasing on this topics! and thanks again on helping with this
I'm currently reviewing the PR you just pushed also
<!-- github-comment-id:5857437735 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
The RF-to-APRS-IS path does not consult the existing 25-second duplicate cache.
The cache is currently used only by the digipeater path.
As a result, one local iGate can upload the same RF packet more than once when
it first hears the original transmission and then hears the same packet again
after a digipeater has changed the path.
Example of one information field arriving through two paths:
The source and information field are identical; only the RF path differs.
Both copies are currently eligible for upload by the same iGate.
Cause
The main loop sends a received packet to APRS-IS before passing it to the
digipeater:
STATION_Utils::isIn25SegHashBuffer()is called only from the digipeaterbranch.
APRS_IS_Utils::processLoRaPacket()uploads without consulting alocal duplicate cache.
Moving the existing check in front of both consumers would not solve the
problem: whichever consumer checks first would prevent the other destination
from processing the first valid reception.
Expected behavior
For one local node and one duplicate window:
by that same node;
Proposed design
Use one bounded, expiring cache whose entries contain:
The fingerprint should be based on:
The RF path must not be included, and the information field must not be
trimmed. A single atomic-style operation such as
claimDestination(fingerprint, destination)should return true only the firsttime that destination claims the packet.
The APRS-IS claim should happen immediately before the effective upload, after
local message/query handling. The digipeater claim should happen only after
the packet has been found relayable, immediately before queueing the RF relay.
Tested implementation
A field-tested implementation using a 64-bit FNV-1a fingerprint, a 25-second
window, a bounded cache and per-destination bits is available here:
https://github.com/moricef/LoRa_APRS_iGate/commit/b1f96425651975813c277b4d18b550285ed29cae
That fork also carries RXT, so its fingerprint removes the RF-only RXT trailer
before hashing. The generic upstream fix does not otherwise depend on RXT.
The implementation includes host tests for independent destination claims,
expiry, capacity bounds, exact whitespace preservation and
millis()wraparound. Field logs confirm that the direct packet is uploaded and the
returned digipeated copy is reported as locally skipped.
Hi, I asked the same question a few years ago and I got as response:
iGates should upload everything they hear, EVERYTHING.
APRS-IS has many ways to work with this tons of packets being uploaded and the deduplication is done on their servers.
Only Digipeaters should do the filtering of those packets being repeated.
PS: the reason is that igates will upload all and this will help to have all the path and info to analyze packets also
Hi Ricardo,
Thank you for the clarification. I misunderstood the intended division of responsibility between IGates and APRS-IS duplicate filtering. After reviewing the APRS-IS server specification, I agree that IGates should upload every valid RF reception and leave duplicate suppression to the servers.
Sorry for the noise, and thank you again for the explanation. I’m closing this issue.
There is no problem on chasing on this topics! and thanks again on helping with this
I'm currently reviewing the PR you just pushed also