Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ class EndpointFlowProtocol<LinkageType: InboundDataLinkage>: ProtocolInstanceCon

public func setApplicationError(_ applicationError: UInt64, applicationErrorReason: String) {
if let metadata: ProtocolMetadata<QUICProtocol> = self.getMetadata() {
metadata.perProtocolMetadata?.quicConnectionMetadata?.applicationError = applicationError
metadata.perProtocolMetadata?.quicConnectionMetadata?.applicationErrorReason = applicationErrorReason
metadata.connectionMetadata?.applicationError = applicationError
metadata.connectionMetadata?.applicationErrorReason = applicationErrorReason
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions Sources/SwiftNetwork/Protocols/Frame.swift
Original file line number Diff line number Diff line change
Expand Up @@ -708,11 +708,14 @@ public struct Frame: ~Copyable {

#if !NETWORK_EMBEDDED
public mutating func setMetadata(metadata: AbstractProtocolMetadata?, isInput: Bool, isComplete: Bool) {
if let metadata = metadata as? ProtocolMetadata<IPProtocol>, let ipMetadata = metadata.perProtocolMetadata {
ecnFlag = ipMetadata.ecnFlag
dscpValue = ipMetadata.dscpValue
serviceClass = ipMetadata.serviceClass
fragmentationOverride = ipMetadata.fragmentationEnabled
if let metadata = metadata as? ProtocolMetadata<IPProtocol> {
metadata.withPerProtocolMetadata { ipMetadata in
guard let ipMetadata else { return }
ecnFlag = ipMetadata.ecnFlag
dscpValue = ipMetadata.dscpValue
serviceClass = ipMetadata.serviceClass
fragmentationOverride = ipMetadata.fragmentationEnabled
}
}

if protocolMetadatas.isEmpty {
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftNetwork/Protocols/HarnessProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ public class UpperHarness<LinkageType: InboundDataLinkage>: UpperHarnessProtocol

public func setApplicationError(_ applicationError: UInt64, applicationErrorReason: String) {
if let metadata: ProtocolMetadata<QUICProtocol> = self.getMetadata() {
metadata.perProtocolMetadata?.quicConnectionMetadata?.applicationError = applicationError
metadata.perProtocolMetadata?.quicConnectionMetadata?.applicationErrorReason = applicationErrorReason
metadata.connectionMetadata?.applicationError = applicationError
metadata.connectionMetadata?.applicationErrorReason = applicationErrorReason
}
}

Expand Down
6 changes: 4 additions & 2 deletions Sources/SwiftNetwork/Protocols/IPProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1060,8 +1060,10 @@ public struct IPProtocol: NetworkProtocol {
#if !NETWORK_EMBEDDED
internal static func _staticMetadata(ecnFlag: ECN) -> ProtocolMetadata<IPProtocol> {
let metadata = IPProtocol.definition.protocolMetadata()
metadata.perProtocolMetadata?.ecnFlag = ecnFlag
metadata.perProtocolMetadata?.isStatic = true
metadata.mutablePerProtocolMetadata { ipMetadata in
ipMetadata?.ecnFlag = ecnFlag
ipMetadata?.isStatic = true
}
return metadata
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftNetwork/Protocols/ProtocolDefinition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public struct ProtocolIdentifier: Hashable, Sendable {
@available(Network 0.1.0, *)
public protocol NetworkProtocol: Sendable {
associatedtype Options: PerProtocolOptions
associatedtype Metadata: PerProtocolMetadata
associatedtype Metadata: PerProtocolMetadata & ~Copyable

init()
func newPerProtocolOptions() -> Options?
Expand Down
57 changes: 37 additions & 20 deletions Sources/SwiftNetwork/Protocols/ProtocolMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ internal import Synchronization

@_spi(ProtocolProvider)
@available(Network 0.1.0, *)
public protocol PerProtocolMetadata: Equatable {
func isEqual(to: Self, for: ProtocolCompareMode) -> Bool
public protocol PerProtocolMetadata: ~Copyable, Equatable {
func isEqual(to: borrowing Self, for: ProtocolCompareMode) -> Bool
#if NETWORK_PRIVATE
var cProtocolDefinition: nw_protocol_definition_t? { get }
#endif
Expand Down Expand Up @@ -62,24 +62,31 @@ public class AbstractProtocolMetadata: PerProtocolMetadata {
public final class ProtocolMetadata<P: NetworkProtocol>: AbstractProtocolMetadata, @unchecked Sendable {
private let lock = NetworkMutex(())
private var _perProtocolMetadata: P.Metadata? = nil
public var perProtocolMetadata: P.Metadata? {
get {
lock.withLock { _ in
_perProtocolMetadata
}
}
set {
lock.withLock { _ in
_perProtocolMetadata = newValue
}
}

public func withPerProtocolMetadata<R>(_ body: (borrowing P.Metadata?) -> R) -> R {
lock.withLock { _ in body(_perProtocolMetadata) }
}

public func mutablePerProtocolMetadata<R>(_ body: (inout P.Metadata?) -> R) -> R {
lock.withLock { _ in body(&_perProtocolMetadata) }
}

#if NETWORK_PRIVATE
public override var cProtocolDefinition: nw_protocol_definition_t? { perProtocolMetadata?.cProtocolDefinition }
public override var cProtocolDefinition: nw_protocol_definition_t? {
withPerProtocolMetadata { metadata in
switch metadata {
case .none: return nil
case .some(let protocolMetadata): return protocolMetadata.cProtocolDefinition
}
}
}
#endif

init(protocolIdentifier: ProtocolIdentifier, perProtocolMetadata: P.Metadata?, messageIdentifier: SystemUUID) {
init(
protocolIdentifier: ProtocolIdentifier,
perProtocolMetadata: consuming P.Metadata?,
messageIdentifier: SystemUUID
) {
_perProtocolMetadata = perProtocolMetadata
super.init(protocolIdentifier: protocolIdentifier, messageIdentifier: messageIdentifier)
}
Expand All @@ -88,12 +95,22 @@ public final class ProtocolMetadata<P: NetworkProtocol>: AbstractProtocolMetadat
guard self.protocolIdentifier == other.protocolIdentifier else {
return false
}
if let lh = self.perProtocolMetadata, let rh = other.perProtocolMetadata {
return lh.isEqual(to: rh, for: compareMode)
} else if self.perProtocolMetadata == nil, other.perProtocolMetadata == nil {
return true
return withPerProtocolMetadata { lhMetadata in
other.withPerProtocolMetadata { rhMetadata in
switch lhMetadata {
case .some(let lhVal):
switch rhMetadata {
case .some(let rhVal): return lhVal.isEqual(to: rhVal, for: compareMode)
case .none: return false
}
case .none:
switch rhMetadata {
case .some: return false
case .none: return true
}
}
}
}
return false
}

public override func isEqual(to other: AbstractProtocolMetadata, for compareMode: ProtocolCompareMode) -> Bool {
Expand Down
69 changes: 54 additions & 15 deletions Sources/SwiftNetwork/Protocols/QUICStreamProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public struct QUICStreamProtocol: NetworkProtocol {

// QUICStreamMetadata -

public final class QUICStreamMetadata: PerProtocolMetadata {
public struct QUICStreamMetadata: ~Copyable, PerProtocolMetadata {

var streamID: UInt64 = 0

Expand All @@ -295,15 +295,27 @@ public struct QUICStreamProtocol: NetworkProtocol {

public init() {}

public func isEqual(to other: QUICStreamMetadata, for: ProtocolCompareMode) -> Bool {
public func isEqual(to other: borrowing QUICStreamMetadata, for: ProtocolCompareMode) -> Bool {
true
}

func deepCopy() -> Self {
self
var explicitCopy = QUICStreamMetadata()
explicitCopy.streamID = self.streamID
explicitCopy.datagramFlowID = self.datagramFlowID
explicitCopy.applicationError = self.applicationError
explicitCopy.reliableSize = self.reliableSize
#if !NETWORK_EMBEDDED
explicitCopy.setApplicationErrorHandler = self.setApplicationErrorHandler
#endif
explicitCopy.quicConnectionMetadata = self.quicConnectionMetadata
explicitCopy.usableDatagramFrameSize = self.usableDatagramFrameSize
explicitCopy.streamType = self.streamType
explicitCopy.isDatagramFlow = self.isDatagramFlow
return explicitCopy
}

static public func == (lhs: QUICStreamMetadata, rhs: QUICStreamMetadata) -> Bool {
static public func == (lhs: borrowing QUICStreamMetadata, rhs: borrowing QUICStreamMetadata) -> Bool {
if lhs.streamID == rhs.streamID && lhs.datagramFlowID == rhs.datagramFlowID
&& lhs.applicationError == rhs.applicationError
&& lhs.quicConnectionMetadata == rhs.quicConnectionMetadata
Expand All @@ -329,7 +341,7 @@ public struct QUICStreamProtocol: NetworkProtocol {
}
}

func setConnectionMetadata(connectionMetadata: QUICConnectionProtocol.QUICConnectionMetadata) {
mutating func setConnectionMetadata(connectionMetadata: QUICConnectionProtocol.QUICConnectionMetadata) {
mutex.withLock { _ in
self.quicConnectionMetadata = connectionMetadata
}
Expand All @@ -344,7 +356,7 @@ public struct QUICStreamProtocol: NetworkProtocol {
}
}

func setApplicationError(handler: @escaping QUICMetadataSetterHandler) {
mutating func setApplicationError(handler: @escaping QUICMetadataSetterHandler) {
mutex.withLock { _ in
self.setApplicationErrorHandler = handler
}
Expand Down Expand Up @@ -413,16 +425,43 @@ extension ProtocolOptions<QUICProtocol> {
}

extension ProtocolMetadata<QUICProtocol> {
public var streamID: UInt64? { perProtocolMetadata?.streamID }
public var datagramFlowID: UInt64? { perProtocolMetadata?.datagramFlowID }
public internal(set) var streamID: UInt64? {
get { mutablePerProtocolMetadata { $0?.streamID } }
set {
mutablePerProtocolMetadata {
guard let newValue else { return }
$0?.streamID = newValue
}
}
}
public var applicationError: UInt64? {
get { perProtocolMetadata?.applicationError }
set { perProtocolMetadata?.applicationError = newValue }
get { mutablePerProtocolMetadata { $0?.applicationError } }
set { mutablePerProtocolMetadata { $0?.applicationError = newValue } }
}
public var isBidirectional: Bool {
!isDatagram && (mutablePerProtocolMetadata { $0?.streamType == .bidirectional })
}
public var isUnidirectional: Bool {
!isDatagram && (mutablePerProtocolMetadata { $0?.streamType == .unidirectional })
}
public internal(set) var connectionMetadata: QUICConnectionProtocol.QUICConnectionMetadata? {
get { mutablePerProtocolMetadata { $0?.quicConnectionMetadata } }
set { mutablePerProtocolMetadata { $0?.quicConnectionMetadata = newValue } }
}
public internal(set) var streamType: QUICStreamType {
get { mutablePerProtocolMetadata { $0?.streamType ?? .bidirectional } }
set { mutablePerProtocolMetadata { $0?.streamType = newValue } }
}
public internal(set) var datagramFlowID: UInt64? {
get { mutablePerProtocolMetadata { $0?.datagramFlowID } }
set { mutablePerProtocolMetadata { $0?.datagramFlowID = newValue } }
}
public internal(set) var usableDatagramFrameSize: UInt16 {
get { mutablePerProtocolMetadata { $0?.usableDatagramFrameSize ?? 0 } }
set { mutablePerProtocolMetadata { $0?.usableDatagramFrameSize = newValue } }
}
public var isDatagram: Bool { perProtocolMetadata?.isDatagramFlow ?? false }
public var isBidirectional: Bool { !isDatagram && perProtocolMetadata?.streamType == .bidirectional }
public var isUnidirectional: Bool { !isDatagram && perProtocolMetadata?.streamType == .unidirectional }
public var connectionMetadata: QUICConnectionProtocol.QUICConnectionMetadata? {
perProtocolMetadata?.quicConnectionMetadata
public internal(set) var isDatagram: Bool {
get { mutablePerProtocolMetadata { $0?.isDatagramFlow ?? false } }
set { mutablePerProtocolMetadata { $0?.isDatagramFlow = newValue } }
}
}
29 changes: 12 additions & 17 deletions Sources/SwiftNetwork/QUIC/QUICConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2471,18 +2471,18 @@ public final class QUICConnection: ManyToManyApplicationStreamProtocol,

if case .allFlows = flowID {
let metadata = QUICProtocol.metadata()
metadata.perProtocolMetadata?.quicConnectionMetadata = self.connectionMetadata
metadata.connectionMetadata = self.connectionMetadata
return metadata as? ProtocolMetadata<P>
}

if let datagramFlow = secondaryFlow(for: flowID) {
let metadata = QUICProtocol.metadata()
metadata.perProtocolMetadata?.datagramFlowID = datagramFlow.flowID
metadata.perProtocolMetadata?.usableDatagramFrameSize = UInt16(
metadata.datagramFlowID = datagramFlow.flowID
metadata.usableDatagramFrameSize = UInt16(
datagramFlow.usableDatagramSize
)
metadata.perProtocolMetadata?.isDatagramFlow = true
metadata.perProtocolMetadata?.quicConnectionMetadata = self.connectionMetadata
metadata.isDatagram = true
metadata.connectionMetadata = self.connectionMetadata
return metadata as? ProtocolMetadata<P>
}

Expand All @@ -2493,11 +2493,11 @@ public final class QUICConnection: ManyToManyApplicationStreamProtocol,
}

let metadata = QUICProtocol.metadata()
metadata.perProtocolMetadata = stream.streamMetadata
metadata.perProtocolMetadata?.quicConnectionMetadata = self.connectionMetadata
metadata.perProtocolMetadata?.streamID = streamID.value
//metadata.perProtocolMetadata = stream.streamMetadata
metadata.connectionMetadata = self.connectionMetadata
metadata.streamID = streamID.value
if let streamType = stream.streamType {
metadata.perProtocolMetadata?.streamType = streamType
metadata.streamType = streamType
}
return metadata as? ProtocolMetadata<P>
}
Expand Down Expand Up @@ -2590,7 +2590,7 @@ public final class QUICConnection: ManyToManyApplicationStreamProtocol,
streamID = nil
}

stream.streamMetadata.quicConnectionMetadata = self.connectionMetadata
stream.streamMetadata.connectionMetadata = self.connectionMetadata
stream.setup(streamID: streamID, logPrefixer: logPrefixer)

if let remoteTransportParameters {
Expand Down Expand Up @@ -5376,7 +5376,7 @@ extension QUICConnection {
// create all the missing streams and flows. All will be left invalid until payload or application
// triggers a transition to active
let newStream = QUICStreamInstance(parent: self, inbound: true)
newStream.streamMetadata.quicConnectionMetadata = self.connectionMetadata
newStream.streamMetadata.connectionMetadata = self.connectionMetadata

let newFlowIdentifier = newStream.identifier
multiplexedFlows[newFlowIdentifier] = newStream
Expand All @@ -5388,12 +5388,7 @@ extension QUICConnection {
)
newStream.unidirectional = newStreamID.isUnidirectional

let abstractMetadata: AbstractProtocolMetadata = ProtocolMetadata<QUICStreamProtocol>(
protocolIdentifier: QUICStreamProtocol.identifier,
perProtocolMetadata: newStream.streamMetadata,
messageIdentifier: SystemUUID(insecure: true)
)
deliverNewInboundFlowEvent(newStream.reference, flowMetadata: abstractMetadata)
deliverNewInboundFlowEvent(newStream.reference, flowMetadata: newStream.streamMetadata)

log.debug(
"set stream \(newStreamID.description) for flow \(newFlowIdentifier.debugDescription)"
Expand Down
6 changes: 5 additions & 1 deletion Sources/SwiftNetwork/QUIC/QUICStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,11 @@ public final class QUICStreamInstance: MultiplexedStreamFlow<QUICConnection>,
{
private(set) var streamID: QUICStreamID?
var logPrefix: String = ""
var streamMetadata = QUICStreamProtocol.QUICStreamMetadata()
var streamMetadata = ProtocolMetadata<QUICStreamProtocol>(
protocolIdentifier: QUICStreamProtocol.identifier,
perProtocolMetadata: QUICStreamProtocol.QUICStreamMetadata(),
messageIdentifier: SystemUUID(insecure: true)
)

@_optimize(speed)
override public var reference: ProtocolInstanceReference {
Expand Down
6 changes: 4 additions & 2 deletions Sources/SwiftNetwork/QUIC/QUICStreamID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ internal import Logging
internal import os
#endif

enum QUICStreamType: CustomStringConvertible {
@_spi(Essentials)
@available(Network 0.1.0, *)
public enum QUICStreamType: CustomStringConvertible {
case bidirectional
case unidirectional

var description: String {
public var description: String {
switch self {
case .bidirectional: return "bidirectional"
case .unidirectional: return "unidirectional"
Expand Down
Loading