@@ -21,23 +21,27 @@ import ContainerizationExtras
2121import Dispatch
2222import Foundation
2323import Logging
24- import SendableProperty
24+ import Synchronization
2525import SystemConfiguration
2626import XPC
2727import vmnet
2828
2929/// Creates a vmnet network with reservation APIs.
3030@available ( macOS 26 , * )
3131public final class ReservedVmnetNetwork : Network {
32- @SendablePropertyUnchecked
33- private var _state : NetworkState
34- private let log : Logger
32+ private struct State {
33+ var networkState : NetworkState
34+ var network : vmnet_network_ref ?
35+ }
36+
37+ private struct NetworkInfo {
38+ let network : vmnet_network_ref
39+ let subnet : CIDRAddress
40+ let gateway : IPv4Address
41+ }
3542
36- @SendableProperty
37- private var network : vmnet_network_ref ?
38- @SendableProperty
39- private var interface : interface_ref ?
40- private let networkLock = NSLock ( )
43+ private let stateMutex : Mutex < State >
44+ private let log : Logger
4145
4246 /// Configure a bridge network that allows external system access using
4347 /// network address translation.
@@ -51,26 +55,33 @@ public final class ReservedVmnetNetwork: Network {
5155
5256 log. info ( " creating vmnet network " )
5357 self . log = log
54- _state = . created( configuration)
58+ let initialState = State ( networkState: . created( configuration) )
59+ stateMutex = Mutex ( initialState)
5560 log. info ( " created vmnet network " )
5661 }
5762
5863 public var state : NetworkState {
59- get async { _state }
64+ stateMutex . withLock { $0 . networkState }
6065 }
6166
6267 public nonisolated func withAdditionalData( _ handler: ( XPCMessage ? ) throws -> Void ) throws {
63- try networkLock . withLock {
64- try handler ( network. map { try Self . serialize_network_ref ( ref: $0) } )
68+ try stateMutex . withLock { state in
69+ try handler ( state . network. map { try Self . serialize_network_ref ( ref: $0) } )
6570 }
6671 }
6772
6873 public func start( ) async throws {
69- guard case . created( let configuration) = _state else {
70- throw ContainerizationError ( . invalidArgument, message: " cannot start network that is in \( _state. state) state " )
71- }
74+ try stateMutex. withLock { state in
75+ guard case . created( let configuration) = state. networkState else {
76+ throw ContainerizationError ( . invalidArgument, message: " cannot start network that is in \( state. networkState. state) state " )
77+ }
78+
79+ let networkInfo = try startNetwork ( configuration: configuration, log: log)
7280
73- try startNetwork ( configuration: configuration, log: log)
81+ let networkStatus = NetworkStatus ( address: networkInfo. subnet. description, gateway: networkInfo. gateway. description)
82+ state. networkState = NetworkState . running ( configuration, networkStatus)
83+ state. network = networkInfo. network
84+ }
7485 }
7586
7687 private static func serialize_network_ref( ref: vmnet_network_ref ) throws -> XPCMessage {
@@ -81,7 +92,7 @@ public final class ReservedVmnetNetwork: Network {
8192 return XPCMessage ( object: refObject)
8293 }
8394
84- private func startNetwork( configuration: NetworkConfiguration , log: Logger ) throws {
95+ private func startNetwork( configuration: NetworkConfiguration , log: Logger ) throws -> NetworkInfo {
8596 log. info (
8697 " starting vmnet network " ,
8798 metadata: [
@@ -125,7 +136,6 @@ public final class ReservedVmnetNetwork: Network {
125136 guard let network = vmnet_network_create ( vmnetConfiguration, & status) , status == . VMNET_SUCCESS else {
126137 throw ContainerizationError ( . unsupported, message: " failed to create vmnet network with status \( status) " )
127138 }
128- self . network = network
129139
130140 // retrieve the subnet since the caller may not have provided one
131141 var subnetAddr = in_addr ( )
@@ -137,7 +147,7 @@ public final class ReservedVmnetNetwork: Network {
137147 let upper = IPv4Address ( fromValue: lower. value + ~ maskValue)
138148 let runningSubnet = try CIDRAddress ( lower: lower, upper: upper)
139149 let runningGateway = IPv4Address ( fromValue: runningSubnet. lower. value + 1 )
140- self . _state = . running ( configuration , NetworkStatus ( address : runningSubnet . description , gateway : runningGateway . description ) )
150+
141151 log. info (
142152 " started vmnet network " ,
143153 metadata: [
@@ -146,5 +156,7 @@ public final class ReservedVmnetNetwork: Network {
146156 " cidr " : " \( runningSubnet) " ,
147157 ]
148158 )
159+
160+ return NetworkInfo ( network: network, subnet: runningSubnet, gateway: runningGateway)
149161 }
150162}
0 commit comments