diff --git a/Message Encoding.go b/Message Encoding.go index 3fcc9e9..7d4a8dd 100644 --- a/Message Encoding.go +++ b/Message Encoding.go @@ -51,6 +51,11 @@ const ( ActionInfoStore = 3 // INFO_STORE Sender indicates storing provided data ) +// Actions in Response message +const ( + ActionSequenceLast = 0 // SEQUENCE_LAST Last response to the announcement in the sequence +) + // Features are sent as bit array in the Announcement message. const ( FeatureIPv4Listen = 0 // Sender listens on IPv4 @@ -726,9 +731,10 @@ createPacketLoop: hashesNotFound = nil } + raw[2] |= 1 << ActionSequenceLast // Indicate that no more responses will be sent in this sequence packetsRaw = append(packetsRaw, raw[:packetSize]) - if len(hash2Peers) == 0 && len(filesEmbed) == 0 && len(hashesNotFound) == 0 { + if len(hash2Peers) == 0 && len(filesEmbed) == 0 && len(hashesNotFound) == 0 { // this should always be the case here return } } diff --git a/Message Sequence.go b/Message Sequence.go index c33bdc1..41da2e4 100644 --- a/Message Sequence.go +++ b/Message Sequence.go @@ -124,4 +124,16 @@ func msgValidateSequence(raw *MessageRaw) (valid bool, rtt time.Duration) { return sequence.expires.After(time.Now()), rtt } -// TODO: Manual invalidation of sequence number from high-level (once information request is considered handled). +// msgInvalidateSequence invalidates the sequence number. +func msgInvalidateSequence(raw *MessageRaw) { + // Only Response + if raw.Command != CommandResponse { + return + } + + key := string(raw.SenderPublicKey.SerializeCompressed()) + strconv.FormatUint(uint64(raw.Sequence), 10) + + sequencesMutex.Lock() + delete(sequences, key) + sequencesMutex.Unlock() +} diff --git a/Network.go b/Network.go index d24ac31..0f507c6 100644 --- a/Network.go +++ b/Network.go @@ -174,6 +174,10 @@ func packetWorker(packets <-chan networkWire) { case CommandResponse: // Response if response, _ := msgDecodeResponse(raw); response != nil { + if (response.Actions & (1 << ActionSequenceLast)) > 0 { + msgInvalidateSequence(raw) + } + peer.cmdResponse(response) }