Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Sources/SwiftNetwork/Protocols/BridgeProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public struct DatagramDrops: Equatable {
}
}

public typealias BridgeObserveFirstByteHandler = ((UInt8) -> Void)?

@_spi(Essentials)
@available(Network 0.1.0, *)
public struct BridgeDatagramProtocol: NetworkProtocol {
Expand All @@ -75,6 +77,7 @@ public struct BridgeDatagramProtocol: NetworkProtocol {

public struct BridgeOptions: PerProtocolOptions {
public var linkDelay: NetworkDuration = .zero
public var observeFirstByteHandler: BridgeObserveFirstByteHandler = nil
var datagramDrops: DatagramDrops?

init() {}
Expand All @@ -96,6 +99,10 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
self == other
}

static public func == (lhs: BridgeOptions, rhs: BridgeOptions) -> Bool {
lhs.linkDelay == rhs.linkDelay && lhs.datagramDrops == rhs.datagramDrops
}

var isDefault: Bool {
self == BridgeOptions()
}
Expand Down Expand Up @@ -142,6 +149,7 @@ public struct BridgeDatagramProtocol: NetworkProtocol {

var linkDelay: NetworkDuration = .zero
var datagramDrops: DatagramDrops? = nil
var observeFirstByteHandler: BridgeObserveFirstByteHandler = nil

private var timerSet = false
func deliverInboundDataAvailableEvent() {
Expand Down Expand Up @@ -183,6 +191,7 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
{
self.linkDelay = bridgeOptions.linkDelay
self.datagramDrops = bridgeOptions.datagramDrops
self.observeFirstByteHandler = bridgeOptions.observeFirstByteHandler
}
#endif

Expand Down Expand Up @@ -275,6 +284,14 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
datagrams = remainingDatagrams
}
log.datapath("forwarding \(datagrams.count) datagrams to port: \(remotePort)")
if let observeFirstByteHandler {
datagrams.iterateMutableFrames { frame in
if let bytes = frame.bytes, bytes.byteCount > 0 {
observeFirstByteHandler(bytes[0])
}
return true
}
}
remoteInstance.incomingFrames.add(frames: datagrams)
remoteInstance.deliverInboundDataAvailableEvent()
}
Expand Down Expand Up @@ -323,6 +340,11 @@ extension ProtocolOptions<BridgeDatagramProtocol> {
set { perProtocolOptions!.linkDelay = newValue }
}

public var observeFirstByteHandler: BridgeObserveFirstByteHandler {
get { perProtocolOptions!.observeFirstByteHandler }
set { perProtocolOptions!.observeFirstByteHandler = newValue }
}

public var datagramDrops: DatagramDrops? {
get { perProtocolOptions!.datagramDrops }
set { perProtocolOptions!.datagramDrops = newValue }
Expand Down
9 changes: 7 additions & 2 deletions Tests/SwiftNetworkTests/QUICTestHarness.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ final class QUICTestHarness {
serverDrops: DatagramDrops? = nil,
timeout: TimeInterval = 5.0,
clientOptions: ProtocolOptions<QUICProtocol> = QUICProtocol.options(),
serverOptions: ProtocolOptions<QUICProtocol> = QUICProtocol.options()
serverOptions: ProtocolOptions<QUICProtocol> = QUICProtocol.options(),
bridgeObserveFirstByteHandler: BridgeObserveFirstByteHandler = nil
) throws(NetworkError) {
var clientConnected = false
var serverConnected = false
Expand Down Expand Up @@ -167,6 +168,7 @@ final class QUICTestHarness {

let clientBridge = BridgeDatagramProtocol.instance(context: self.context)
let clientBridgeOptions = BridgeDatagramProtocol.options()
clientBridgeOptions.observeFirstByteHandler = bridgeObserveFirstByteHandler
clientBridgeOptions.setProtocolInstance(clientBridge)
clientBridgeOptions.linkDelay = clientLinkDelay
clientBridgeOptions.datagramDrops = clientDrops
Expand Down Expand Up @@ -194,6 +196,7 @@ final class QUICTestHarness {

let serverBridge = BridgeDatagramProtocol.instance(context: self.context)
let serverBridgeOptions = BridgeDatagramProtocol.options()
serverBridgeOptions.observeFirstByteHandler = bridgeObserveFirstByteHandler
serverBridgeOptions.setProtocolInstance(serverBridge)
serverBridgeOptions.linkDelay = serverLinkDelay
serverBridgeOptions.datagramDrops = serverDrops
Expand Down Expand Up @@ -914,6 +917,7 @@ final class QUICTestHarness {
extraServerCIDs: [(QUICConnectionID, QUICStatelessResetToken)] = .init(),
afterHandshake: ((QUICTestHarness) -> Void)? = nil, // Block to run after handshake is complete
afterData: ((QUICTestHarness) -> Void)? = nil, // Block to run after handshake is complete
bridgeObserveFirstByteHandler: BridgeObserveFirstByteHandler = nil
) {
// Start with the handshake
Logger.test.debug("Test phase: Handshake")
Expand All @@ -933,7 +937,8 @@ final class QUICTestHarness {
serverDrops: serverDrops,
timeout: timeout,
clientOptions: clientOptions,
serverOptions: serverOptions
serverOptions: serverOptions,
bridgeObserveFirstByteHandler: bridgeObserveFirstByteHandler
)
} catch {
if expectHandshakeError == nil {
Expand Down
21 changes: 15 additions & 6 deletions Tests/SwiftNetworkTests/SwiftNetworkQUICSpinBitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ final class SwiftNetworkQUICSpinBitTests: NetTestCase {
// it from the server.

var hasSpinBit = true
var observedSpinBitValues: Set<Bool> = []
let observeFirstByteHandler: BridgeObserveFirstByteHandler = { firstByte in
guard (firstByte & 0xC0) == 0x40 else { return }
observedSpinBitValues.insert((firstByte & 0x20) != 0)
}
QUICTestHarness().runQUICTest(
dataBlock: Array("Hello World!".utf8),
afterHandshake: { harness in
Expand Down Expand Up @@ -89,13 +94,17 @@ final class SwiftNetworkQUICSpinBitTests: NetTestCase {
let expectation = XCTestExpectation(description: "Wait to validate spin bit")
harness.context.async {
defer { expectation.fulfill() }

let clientSpinBit = harness.state?.clientInstance.currentPath?.spinValue ?? false
let serverSpinBit = harness.state?.serverInstance.currentPath?.spinValue ?? false
XCTAssertFalse(clientSpinBit, "Client should have the spin bit set to false")
XCTAssertTrue(serverSpinBit, "Server should have the spin bit set to true")
XCTAssertFalse(
observedSpinBitValues.isEmpty,
"BridgeDatagramProtocol should have observed short-header packets with spin bit values"
)
XCTAssertTrue(
observedSpinBitValues.contains(true),
"BridgeDatagramProtocol should have observed at least one packet with spin bit set"
)
}
}
},
bridgeObserveFirstByteHandler: observeFirstByteHandler
)
}

Expand Down
Loading