Private/Invoke-BfdSessionLoop.ps1

function Invoke-BfdSessionLoop {
    param($S)
    $c = $S.Config
    $rx = $null; $tx = $null
    $clock = [Diagnostics.Stopwatch]::StartNew()
    $rand = [Random]::new()

    try {
        $bindIp = if ($c.LocalAddress) { [ipaddress]$c.LocalAddress } else { [ipaddress]::Any }
        $rx = [Net.Sockets.UdpClient]::new([Net.IPEndPoint]::new($bindIp, $c.ListenPort))
        for ($i = 0; $i -lt 20 -and -not $tx; $i++) {
            try { $tx = [Net.Sockets.UdpClient]::new([Net.IPEndPoint]::new($bindIp, $rand.Next(49152, 65535))) } catch { }
        }
        if (-not $tx) { throw 'Could not bind a source port in 49152-65535.' }
        $tx.Client.Ttl = 255
        $remote = [Net.IPEndPoint]::new([ipaddress]$c.RemoteAddress, $c.RemotePort)

        $myDisc = [uint32]$rand.Next(1, [int]::MaxValue)
        $yourDisc = [uint32]0
        $fsm = @{ State = 'Down'; Diag = 0 }
        $remoteMult = 0; $remoteDesiredTx = 1000000; $remoteRequiredRx = 1000000
        $lastRx = 0.0
        $replyFinal = $false
        $nextTx = 0.0
        $S.State = 'Down'
        $S.LocalDiscriminator = $myDisc

        $setState = {
            param($new, $newDiag)
            if ($new -ne $fsm.State) {
                $S.History.Enqueue(('{0:HH:mm:ss.fff} {1} -> {2}' -f (Get-Date), $fsm.State, $new))
                $dummy = $null
                while ($S.History.Count -gt 100) { $null = $S.History.TryDequeue([ref]$dummy) }
            }
            $fsm.State = $new; $fsm.Diag = $newDiag
            $S.State = $new
        }

        while (-not $S.Stop) {
            $now = $clock.Elapsed.TotalMilliseconds

            while ($rx.Available -gt 0) {
                $ep = [Net.IPEndPoint]::new([ipaddress]::Any, 0)
                $data = $rx.Receive([ref]$ep)
                if (-not $ep.Address.Equals($remote.Address) -or $data.Length -lt 24) { continue }
                $p = ConvertFrom-BfdControl $data
                if ($p.Version -ne 1 -or $p.DetectMult -eq 0 -or $p.MyDiscriminator -eq 0) { continue }
                if ($p.YourDiscriminator -ne 0 -and $p.YourDiscriminator -ne $myDisc) { continue }

                $S.Received++
                $lastRx = $now
                $yourDisc = $p.MyDiscriminator
                $remoteMult = $p.DetectMult
                $remoteDesiredTx = $p.DesiredMinTx
                $remoteRequiredRx = $p.RequiredMinRx
                $S.RemoteState = $p.State

                switch ($fsm.State) {
                    'Down' {
                        if ($p.State -eq 'Down') { & $setState 'Init' 0 }
                        elseif ($p.State -eq 'Init') { & $setState 'Up' 0 }
                    }
                    'Init' {
                        if ($p.State -in 'Init', 'Up') { & $setState 'Up' 0 }
                    }
                    'Up' {
                        if ($p.State -in 'Down', 'AdminDown') { & $setState 'Down' 3 }
                    }
                }
                if ($p.Poll) { $nextTx = 0; $replyFinal = $true }
            }

            if ($fsm.State -in 'Init', 'Up' -and $remoteMult -gt 0) {
                $detectMs = $remoteMult * [Math]::Max($c.RequiredMinRx, $remoteDesiredTx) / 1000.0
                if (($now - $lastRx) -gt $detectMs) { & $setState 'Down' 1; $yourDisc = 0 }
            }

            if (-not $S.Suppress -and $now -ge $nextTx) {
                $advTx = if ($fsm.State -eq 'Up') { $c.DesiredMinTx } else { [Math]::Max($c.DesiredMinTx, 1000000) }
                $pkt = New-BfdControl -State $fsm.State -Diagnostic $fsm.Diag -DetectMult $c.DetectMult -MyDiscriminator $myDisc `
                    -YourDiscriminator $yourDisc -DesiredMinTx $advTx -RequiredMinRx $c.RequiredMinRx -Final:$replyFinal
                $replyFinal = $false
                $null = $tx.Send($pkt, $pkt.Length, $remote)
                $S.Sent++
                $intervalUs = if ($fsm.State -eq 'Up') { [Math]::Max($c.DesiredMinTx, $remoteRequiredRx) } else { [Math]::Max($c.DesiredMinTx, 1000000) }
                $nextTx = $now + ($intervalUs / 1000.0) * (1 - 0.25 * $rand.NextDouble())
            }
            Start-Sleep -Milliseconds 5
        }

        $pkt = New-BfdControl -State AdminDown -Diagnostic 7 -DetectMult $c.DetectMult -MyDiscriminator $myDisc -YourDiscriminator $yourDisc
        $null = $tx.Send($pkt, $pkt.Length, $remote)
    }
    catch { $S.LastError = $_.Exception.Message }
    finally {
        if ($rx) { $rx.Dispose() }
        if ($tx) { $tx.Dispose() }
        $S.State = 'AdminDown'
    }
}