From 6055a75f2f03a1f9e946a575febe58f1b3e9725c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Tigerstr=C3=B6m?= Date: Tue, 9 Jan 2024 01:47:36 +0100 Subject: [PATCH] gbn: complete handshake if client has completed it This fixes a bug where the server would not complete the handshake if the server restarted the handshake after sending it's SYN, which the client then received and then completed the handshake. This could previously happen if the server timedout when waiting for the clients SYN response, or if the client's SYNACK was lost due to packet loss. --- gbn/gbn_server.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/gbn/gbn_server.go b/gbn/gbn_server.go index 0f8116d..dc53ca9 100644 --- a/gbn/gbn_server.go +++ b/gbn/gbn_server.go @@ -84,6 +84,7 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo var n uint8 var resent bool +handshakeLoop: for { g.log.Debugf("Waiting for client SYN") select { @@ -111,6 +112,24 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo switch msg.(type) { case *PacketSYN: + + case *PacketSYNACK, *PacketData: + // If we receive a SYNACK or DATA packet after we have + // restarted the handshake, we can be sure that the + // client has received our SYN and has completed the + // handshake. We can therefore complete the handshake + // ourselves. + if resent { + g.log.Tracef("Received %T after restarting "+ + "handshake", msg) + g.timeoutManager.Received(msg) + + break handshakeLoop + } + + g.log.Tracef("Expected SYN, got %T", msg) + + continue default: g.log.Tracef("Expected SYN, got %T", msg) continue @@ -169,6 +188,8 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo switch msg.(type) { case *PacketSYNACK: + g.log.Debugf("Received SYNACK") + // Notify the timeout manager we've received the SYNACK // response from the counterparty. g.timeoutManager.Received(msg) @@ -185,8 +206,6 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo break } - g.log.Debugf("Received SYNACK") - // Set all variables that are dependent on the value of N that we get // from the client g.setN(n)