Skip to content

Commit 60afc2e

Browse files
authored
Merge pull request #41 from apple/agnosticdev/SpinBitVariance
SwiftQUIC: Fix variance in Spin Bit testing
2 parents 6fb079f + 2c404e9 commit 60afc2e

3 files changed

Lines changed: 44 additions & 8 deletions

File tree

Sources/SwiftNetwork/Protocols/BridgeProtocol.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public struct DatagramDrops: Equatable {
6666
}
6767
}
6868

69+
public typealias BridgeObserveFirstByteHandler = ((UInt8) -> Void)?
70+
6971
@_spi(Essentials)
7072
@available(Network 0.1.0, *)
7173
public struct BridgeDatagramProtocol: NetworkProtocol {
@@ -75,6 +77,7 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
7577

7678
public struct BridgeOptions: PerProtocolOptions {
7779
public var linkDelay: NetworkDuration = .zero
80+
public var observeFirstByteHandler: BridgeObserveFirstByteHandler = nil
7881
var datagramDrops: DatagramDrops?
7982

8083
init() {}
@@ -96,6 +99,10 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
9699
self == other
97100
}
98101

102+
static public func == (lhs: BridgeOptions, rhs: BridgeOptions) -> Bool {
103+
lhs.linkDelay == rhs.linkDelay && lhs.datagramDrops == rhs.datagramDrops
104+
}
105+
99106
var isDefault: Bool {
100107
self == BridgeOptions()
101108
}
@@ -142,6 +149,7 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
142149

143150
var linkDelay: NetworkDuration = .zero
144151
var datagramDrops: DatagramDrops? = nil
152+
var observeFirstByteHandler: BridgeObserveFirstByteHandler = nil
145153

146154
private var timerSet = false
147155
func deliverInboundDataAvailableEvent() {
@@ -183,6 +191,7 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
183191
{
184192
self.linkDelay = bridgeOptions.linkDelay
185193
self.datagramDrops = bridgeOptions.datagramDrops
194+
self.observeFirstByteHandler = bridgeOptions.observeFirstByteHandler
186195
}
187196
#endif
188197

@@ -275,6 +284,14 @@ public struct BridgeDatagramProtocol: NetworkProtocol {
275284
datagrams = remainingDatagrams
276285
}
277286
log.datapath("forwarding \(datagrams.count) datagrams to port: \(remotePort)")
287+
if let observeFirstByteHandler {
288+
datagrams.iterateMutableFrames { frame in
289+
if let bytes = frame.bytes, bytes.byteCount > 0 {
290+
observeFirstByteHandler(bytes[0])
291+
}
292+
return true
293+
}
294+
}
278295
remoteInstance.incomingFrames.add(frames: datagrams)
279296
remoteInstance.deliverInboundDataAvailableEvent()
280297
}
@@ -323,6 +340,11 @@ extension ProtocolOptions<BridgeDatagramProtocol> {
323340
set { perProtocolOptions!.linkDelay = newValue }
324341
}
325342

343+
public var observeFirstByteHandler: BridgeObserveFirstByteHandler {
344+
get { perProtocolOptions!.observeFirstByteHandler }
345+
set { perProtocolOptions!.observeFirstByteHandler = newValue }
346+
}
347+
326348
public var datagramDrops: DatagramDrops? {
327349
get { perProtocolOptions!.datagramDrops }
328350
set { perProtocolOptions!.datagramDrops = newValue }

Tests/SwiftNetworkTests/QUICTestHarness.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ final class QUICTestHarness {
138138
serverDrops: DatagramDrops? = nil,
139139
timeout: TimeInterval = 5.0,
140140
clientOptions: ProtocolOptions<QUICProtocol> = QUICProtocol.options(),
141-
serverOptions: ProtocolOptions<QUICProtocol> = QUICProtocol.options()
141+
serverOptions: ProtocolOptions<QUICProtocol> = QUICProtocol.options(),
142+
bridgeObserveFirstByteHandler: BridgeObserveFirstByteHandler = nil
142143
) throws(NetworkError) {
143144
var clientConnected = false
144145
var serverConnected = false
@@ -167,6 +168,7 @@ final class QUICTestHarness {
167168

168169
let clientBridge = BridgeDatagramProtocol.instance(context: self.context)
169170
let clientBridgeOptions = BridgeDatagramProtocol.options()
171+
clientBridgeOptions.observeFirstByteHandler = bridgeObserveFirstByteHandler
170172
clientBridgeOptions.setProtocolInstance(clientBridge)
171173
clientBridgeOptions.linkDelay = clientLinkDelay
172174
clientBridgeOptions.datagramDrops = clientDrops
@@ -194,6 +196,7 @@ final class QUICTestHarness {
194196

195197
let serverBridge = BridgeDatagramProtocol.instance(context: self.context)
196198
let serverBridgeOptions = BridgeDatagramProtocol.options()
199+
serverBridgeOptions.observeFirstByteHandler = bridgeObserveFirstByteHandler
197200
serverBridgeOptions.setProtocolInstance(serverBridge)
198201
serverBridgeOptions.linkDelay = serverLinkDelay
199202
serverBridgeOptions.datagramDrops = serverDrops
@@ -914,6 +917,7 @@ final class QUICTestHarness {
914917
extraServerCIDs: [(QUICConnectionID, QUICStatelessResetToken)] = .init(),
915918
afterHandshake: ((QUICTestHarness) -> Void)? = nil, // Block to run after handshake is complete
916919
afterData: ((QUICTestHarness) -> Void)? = nil, // Block to run after handshake is complete
920+
bridgeObserveFirstByteHandler: BridgeObserveFirstByteHandler = nil
917921
) {
918922
// Start with the handshake
919923
Logger.test.debug("Test phase: Handshake")
@@ -933,7 +937,8 @@ final class QUICTestHarness {
933937
serverDrops: serverDrops,
934938
timeout: timeout,
935939
clientOptions: clientOptions,
936-
serverOptions: serverOptions
940+
serverOptions: serverOptions,
941+
bridgeObserveFirstByteHandler: bridgeObserveFirstByteHandler
937942
)
938943
} catch {
939944
if expectHandshakeError == nil {

Tests/SwiftNetworkTests/SwiftNetworkQUICSpinBitTests.swift

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ final class SwiftNetworkQUICSpinBitTests: NetTestCase {
6060
// it from the server.
6161

6262
var hasSpinBit = true
63+
var observedSpinBitValues: Set<Bool> = []
64+
let observeFirstByteHandler: BridgeObserveFirstByteHandler = { firstByte in
65+
guard (firstByte & 0xC0) == 0x40 else { return }
66+
observedSpinBitValues.insert((firstByte & 0x20) != 0)
67+
}
6368
QUICTestHarness().runQUICTest(
6469
dataBlock: Array("Hello World!".utf8),
6570
afterHandshake: { harness in
@@ -89,13 +94,17 @@ final class SwiftNetworkQUICSpinBitTests: NetTestCase {
8994
let expectation = XCTestExpectation(description: "Wait to validate spin bit")
9095
harness.context.async {
9196
defer { expectation.fulfill() }
92-
93-
let clientSpinBit = harness.state?.clientInstance.currentPath?.spinValue ?? false
94-
let serverSpinBit = harness.state?.serverInstance.currentPath?.spinValue ?? false
95-
XCTAssertFalse(clientSpinBit, "Client should have the spin bit set to false")
96-
XCTAssertTrue(serverSpinBit, "Server should have the spin bit set to true")
97+
XCTAssertFalse(
98+
observedSpinBitValues.isEmpty,
99+
"BridgeDatagramProtocol should have observed short-header packets with spin bit values"
100+
)
101+
XCTAssertTrue(
102+
observedSpinBitValues.contains(true),
103+
"BridgeDatagramProtocol should have observed at least one packet with spin bit set"
104+
)
97105
}
98-
}
106+
},
107+
bridgeObserveFirstByteHandler: observeFirstByteHandler
99108
)
100109
}
101110

0 commit comments

Comments
 (0)