mirror of https://github.com/status-im/nim-eth.git
Update timestamp and ackNr on packet resend (#444)
* Update timestamp and ackNr on packet resend
This commit is contained in:
parent
b4066a5688
commit
09959d2a3f
|
@ -9,7 +9,7 @@
|
||||||
import
|
import
|
||||||
std/[monotimes],
|
std/[monotimes],
|
||||||
faststreams,
|
faststreams,
|
||||||
stew/[endians2, results, objects], bearssl,
|
stew/[endians2, results, objects, arrayops], bearssl,
|
||||||
../p2p/discoveryv5/random2
|
../p2p/discoveryv5/random2
|
||||||
|
|
||||||
export results
|
export results
|
||||||
|
@ -56,9 +56,11 @@ type
|
||||||
# https://github.com/bittorrent/libutp/blob/master/utp_utils.cpp, to check all the
|
# https://github.com/bittorrent/libutp/blob/master/utp_utils.cpp, to check all the
|
||||||
# timing assumptions on different platforms
|
# timing assumptions on different platforms
|
||||||
proc getMonoTimeTimeStamp*(): uint32 =
|
proc getMonoTimeTimeStamp*(): uint32 =
|
||||||
|
# TODO
|
||||||
# this value is equivalent of:
|
# this value is equivalent of:
|
||||||
# uint32((Moment.now() - Moment.init(0, Microseconds)).microseconds())
|
# uint32((Moment.now() - Moment.init(0, Microseconds)).microseconds())
|
||||||
# on macOs
|
# on macOs
|
||||||
|
# so we we can use moment here and return (Moment, uint32) tuple from this function
|
||||||
let time = getMonoTime()
|
let time = getMonoTime()
|
||||||
cast[uint32](time.ticks() div 1000)
|
cast[uint32](time.ticks() div 1000)
|
||||||
|
|
||||||
|
@ -136,6 +138,14 @@ proc decodePacket*(bytes: openArray[byte]): Result[Packet, string] =
|
||||||
|
|
||||||
ok(Packet(header: header, payload: payload))
|
ok(Packet(header: header, payload: payload))
|
||||||
|
|
||||||
|
proc modifyTimeStampAndAckNr*(packetBytes: var seq[byte], newTimestamp: uint32, newAckNr: uint16) =
|
||||||
|
## Modifies timestamp and ack nr of already encoded packets. Those fields should be
|
||||||
|
## filled right before sending, so when re-sending the packet we would like to update
|
||||||
|
## it without decoding and re-encoding the packet once again
|
||||||
|
doAssert(len(packetBytes) >= minimalHeaderSize)
|
||||||
|
packetBytes[4..7] = toBytesBE(newTimestamp)
|
||||||
|
packetBytes[18..19] = toBytesBE(newAckNr)
|
||||||
|
|
||||||
# connectionId - should be random not already used number
|
# connectionId - should be random not already used number
|
||||||
# bufferSize - should be pre configured initial buffer size for socket
|
# bufferSize - should be pre configured initial buffer size for socket
|
||||||
# SYN packets are special, and should have the receive ID in the connid field,
|
# SYN packets are special, and should have the receive ID in the connid field,
|
||||||
|
|
|
@ -357,9 +357,16 @@ proc sendAck(socket: UtpSocket): Future[void] =
|
||||||
|
|
||||||
# Should be called before sending packet
|
# Should be called before sending packet
|
||||||
proc setSend(s: UtpSocket, p: var OutgoingPacket): seq[byte] =
|
proc setSend(s: UtpSocket, p: var OutgoingPacket): seq[byte] =
|
||||||
|
let currentMoment = Moment.now()
|
||||||
|
let currentTimeStamp = getMonoTimeTimeStamp()
|
||||||
|
|
||||||
inc p.transmissions
|
inc p.transmissions
|
||||||
p.needResend = false
|
p.needResend = false
|
||||||
p.timeSent = Moment.now()
|
p.timeSent = currentMoment
|
||||||
|
# all bytearrays in outgoing buffer should be properly encoded utp packets
|
||||||
|
# so it is safe to directly modify fields
|
||||||
|
modifyTimeStampAndAckNr(p.packetBytes, currentTimeStamp, s.ackNr)
|
||||||
|
|
||||||
return p.packetBytes
|
return p.packetBytes
|
||||||
|
|
||||||
proc flushPackets(socket: UtpSocket) {.async.} =
|
proc flushPackets(socket: UtpSocket) {.async.} =
|
||||||
|
|
|
@ -12,4 +12,5 @@ import
|
||||||
./test_discv5_protocol,
|
./test_discv5_protocol,
|
||||||
./test_buffer,
|
./test_buffer,
|
||||||
./test_utp_socket,
|
./test_utp_socket,
|
||||||
./test_utp_router
|
./test_utp_router,
|
||||||
|
./test_clock_drift_calculator
|
||||||
|
|
|
@ -46,3 +46,19 @@ suite "Utp packets encoding/decoding":
|
||||||
packet.header.wndSize == 1048576
|
packet.header.wndSize == 1048576
|
||||||
packet.header.seqNr == 16807
|
packet.header.seqNr == 16807
|
||||||
packet.header.ackNr == 1
|
packet.header.ackNr == 1
|
||||||
|
|
||||||
|
test "Modify timestamp of encoded packet":
|
||||||
|
let synPacket = synPacket(5, 10, 20)
|
||||||
|
let initialTimestamp = synPacket.header.timestamp
|
||||||
|
let initialAckNr = synPacket.header.ackNr
|
||||||
|
let modifiedTimeStamp = initialTimestamp + 120324
|
||||||
|
let modifiedAckNr = initialAckNr + 20
|
||||||
|
var encoded = encodePacket(synPacket)
|
||||||
|
modifyTimeStampAndAckNr(encoded, modifiedTimeStamp, modifiedAckNr)
|
||||||
|
|
||||||
|
let decoded = decodePacket(encoded)
|
||||||
|
|
||||||
|
check:
|
||||||
|
decoded.isOk()
|
||||||
|
decoded.get().header.timestamp == modifiedTimeStamp
|
||||||
|
decoded.get().header.ackNr == modifiedAckNr
|
||||||
|
|
|
@ -1214,3 +1214,51 @@ procSuite "Utp socket unit test":
|
||||||
socketAck.header.timestampDiff > 0
|
socketAck.header.timestampDiff > 0
|
||||||
|
|
||||||
await outgoingSocket.destroyWait()
|
await outgoingSocket.destroyWait()
|
||||||
|
|
||||||
|
asyncTest "Re-sent packet should have updated timestamps and ack numbers":
|
||||||
|
let q = newAsyncQueue[Packet]()
|
||||||
|
let initalRemoteSeqNr = 10'u16
|
||||||
|
|
||||||
|
let (outgoingSocket, initialPacket) = connectOutGoingSocket(initalRemoteSeqNr, q)
|
||||||
|
|
||||||
|
let writeResult = await outgoingSocket.write(@[1'u8])
|
||||||
|
|
||||||
|
check:
|
||||||
|
writeResult.isOk()
|
||||||
|
|
||||||
|
let firstSend = await q.get()
|
||||||
|
|
||||||
|
let secondSend = await q.get()
|
||||||
|
|
||||||
|
check:
|
||||||
|
# there was sometime between resend but no packet from remote
|
||||||
|
# so timestamp should be updated but not ackNr
|
||||||
|
secondSend.header.timestamp > firstSend.header.timestamp
|
||||||
|
firstSend.header.ackNr == secondSend.header.ackNr
|
||||||
|
|
||||||
|
let dataP1 =
|
||||||
|
dataPacket(
|
||||||
|
initalRemoteSeqNr,
|
||||||
|
initialPacket.header.connectionId,
|
||||||
|
initialPacket.header.seqNr,
|
||||||
|
testBufferSize,
|
||||||
|
@[1'u8],
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
await outgoingSocket.processPacket(dataP1)
|
||||||
|
|
||||||
|
let ack = await q.get()
|
||||||
|
|
||||||
|
check:
|
||||||
|
ack.header.pType == ST_STATE
|
||||||
|
|
||||||
|
let thirdSend = await q.get()
|
||||||
|
|
||||||
|
check:
|
||||||
|
# as there was some incoming data between resend, both timestamp and ackNr
|
||||||
|
# should be updated
|
||||||
|
thirdSend.header.timestamp > secondSend.header.timestamp
|
||||||
|
thirdSend.header.ackNr > secondSend.header.ackNr
|
||||||
|
|
||||||
|
await outgoingSocket.destroyWait()
|
||||||
|
|
Loading…
Reference in New Issue