Fix sudden window drop bug (#465)

Fixes problem which caused drop of maxWindow to the size of
only one packet in case of only one packet hitting timeout.
This commit is contained in:
KonradStaniec 2022-01-21 14:48:01 +01:00 committed by GitHub
parent 45348e7664
commit 4e2b340af6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 2 deletions

View File

@ -469,8 +469,10 @@ proc checkTimeouts(socket: UtpSocket) {.async.} =
socket.sendBufferTracker.maxRemoteWindow, socket.sendBufferTracker.maxRemoteWindow,
newMaxWindow newMaxWindow
) )
else: elif (socket.sendBufferTracker.maxWindow < currentPacketSize):
# due to high delay window has shrunk below packet size
# which means that we cannot send more data
# reset it to fit at least one packet
debug "Reseting window size do fit a least one packet", debug "Reseting window size do fit a least one packet",
oldWindowSize = socket.sendBufferTracker.maxWindow, oldWindowSize = socket.sendBufferTracker.maxWindow,
newWindowSize = currentPacketSize newWindowSize = currentPacketSize

View File

@ -354,6 +354,72 @@ procSuite "Utp socket unit test":
await outgoingSocket.destroyWait() await outgoingSocket.destroyWait()
proc ackAllPacket(
socket: UtpSocket[TransportAddress],
queue: AsyncQueue[Packet],
initialRemoteSeq: uint16): Future[void] {.async.} =
try:
while true:
let sentPacket = await queue.get()
let ack = ackPacket(
initialRemoteSeq,
sentPacket.header.connectionId,
sentPacket.header.seqNr,
1024 * 1024,
1000'u32
)
await socket.processPacket(ack)
except CancelledError:
echo "foo"
asyncTest "Hitting RTO timeout with packets in flight should not decay window":
let q = newAsyncQueue[Packet]()
let initialRemoteSeq = 10'u16
# lot of data which will generate at least 5 packets
let bigDataTowWrite = generateByteArray(rng[], 10000)
let (outgoingSocket, initialPacket) = connectOutGoingSocket(initialRemoteSeq, q)
let acker = outgoingSocket.ackAllPacket(q, initialRemoteSeq)
let bytesWritten = await outgoingSocket.write(bigDataTowWrite)
check:
bytesWritten.get() == len(bigDataTowWrite)
await waitUntil(proc (): bool = outgoingSocket.numPacketsInOutGoingBuffer() == 0)
let maxWindowAfterSuccesfulSends = outgoingSocket.currentMaxWindowSize()
check:
# after processing a lot of data, our window size should be a lot bigger than our packet size
maxWindowAfterSuccesfulSends > uint32(outgoingSocket.getPacketSize())
# cancel acking process, next writes will for sure timeout
await acker.cancelAndWait()
# data which fits one packet and will timeout
let smallerData = generateByteArray(rng[], 100)
let bytesWritten1 = await outgoingSocket.write(smallerData)
# ignore standard sent packet
discard await q.get()
check:
bytesWritten1.get() == len(smallerData)
# ignore also first re-send
discard await q.get()
let maxWindowAfterTimeout = outgoingSocket.currentMaxWindowSize()
check:
# After standard timeout window should not decay and must be bigger than packet size
maxWindowAfterTimeout > uint32(outgoingSocket.getPacketSize())
maxWindowAfterTimeout == maxWindowAfterSuccesfulSends
await outgoingSocket.destroyWait()
asyncTest "Blocked writing futures should be properly finished when socket is closed": asyncTest "Blocked writing futures should be properly finished when socket is closed":
let q = newAsyncQueue[Packet]() let q = newAsyncQueue[Packet]()
let initialRemoteSeq = 10'u16 let initialRemoteSeq = 10'u16