mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Old Swift and new Swift runtimes and overlays need to coexist in the same process. This means there must not be any classes which have the same ObjC runtime name in old and new, because the ObjC runtime doesn't like name collisions. When possible without breaking source compatibility, classes were renamed in Swift, which results in a different ObjC name. Public classes were renamed only on the ObjC side using the @_objcRuntimeName attribute. This is similar to the work done in pull request #19295. That only renamed @objc classes. This renames all of the others, since even pure Swift classes still get an ObjC name. rdar://problem/46646438
303 lines
9.7 KiB
Swift
303 lines
9.7 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2018 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
import _SwiftNetworkOverlayShims
|
|
|
|
/// An NWInterface object represents an instance of a network interface of a specific
|
|
/// type, such as a Wi-Fi or Cellular interface.
|
|
@available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *)
|
|
public struct NWInterface : Hashable, CustomDebugStringConvertible {
|
|
|
|
public var debugDescription: String {
|
|
return self.name
|
|
}
|
|
|
|
public static func ==(lhs: NWInterface, rhs: NWInterface) -> Bool {
|
|
return lhs.index == rhs.index && lhs.name == rhs.name
|
|
}
|
|
|
|
public func hash(into hasher: inout Hasher) {
|
|
hasher.combine(self.index)
|
|
hasher.combine(self.name)
|
|
}
|
|
|
|
/// Interface types represent the underlying media for a network link
|
|
public enum InterfaceType {
|
|
/// A virtual or otherwise unknown interface type
|
|
case other
|
|
/// A Wi-Fi link
|
|
case wifi
|
|
/// A Cellular link
|
|
case cellular
|
|
/// A Wired Ethernet link
|
|
case wiredEthernet
|
|
/// The Loopback Interface
|
|
case loopback
|
|
|
|
internal var nw : nw_interface_type_t {
|
|
switch self {
|
|
case .wifi:
|
|
return Network.nw_interface_type_wifi
|
|
case .cellular:
|
|
return Network.nw_interface_type_cellular
|
|
case .wiredEthernet:
|
|
return Network.nw_interface_type_wired
|
|
case .loopback:
|
|
return Network.nw_interface_type_loopback
|
|
case .other:
|
|
return Network.nw_interface_type_other
|
|
}
|
|
}
|
|
|
|
internal init(_ nw: nw_interface_type_t) {
|
|
switch nw {
|
|
case Network.nw_interface_type_wifi:
|
|
self = .wifi
|
|
case Network.nw_interface_type_cellular:
|
|
self = .cellular
|
|
case Network.nw_interface_type_wired:
|
|
self = .wiredEthernet
|
|
case Network.nw_interface_type_loopback:
|
|
self = .loopback
|
|
default:
|
|
self = .other
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The interface type.
|
|
public let type: InterfaceType
|
|
|
|
/// The name of the interface, such as "en0"
|
|
public let name: String
|
|
|
|
/// The kernel index of the interface
|
|
public let index: Int
|
|
|
|
internal let nw: nw_interface_t
|
|
|
|
internal init(_ nw: nw_interface_t) {
|
|
self.nw = nw
|
|
self.type = NWInterface.InterfaceType(nw_interface_get_type(nw))
|
|
self.name = String(cString: nw_interface_get_name(nw))
|
|
self.index = Int(nw_interface_get_index(nw))
|
|
}
|
|
|
|
internal init?(_ index: Int) {
|
|
guard let nw = nw_interface_create_with_index(UInt32(index)) else {
|
|
return nil
|
|
}
|
|
self.init(nw)
|
|
}
|
|
|
|
internal init?(_ name: String) {
|
|
guard let nw = nw_interface_create_with_name(name) else {
|
|
return nil
|
|
}
|
|
self.init(nw)
|
|
}
|
|
}
|
|
|
|
/// An NWPath object represents a snapshot of network path state. This state
|
|
/// represents the known information about the local interface and routes that may
|
|
/// be used to send and receive data. If the network path for a connection changes
|
|
/// due to interface characteristics, addresses, or other attributes, a new NWPath
|
|
/// object will be generated. Note that the differences in the path attributes may not
|
|
/// be visible through public accessors, and these changes should be treated merely
|
|
/// as an indication that something about the network has changed.
|
|
@available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *)
|
|
public struct NWPath : Equatable, CustomDebugStringConvertible {
|
|
|
|
public var debugDescription: String {
|
|
return String(describing: self.nw)
|
|
}
|
|
|
|
/// An NWPath status indicates if there is a usable route available upon which to send and receive data.
|
|
public enum Status {
|
|
/// The path has a usable route upon which to send and receive data
|
|
case satisfied
|
|
/// The path does not have a usable route. This may be due to a network interface being down, or due to system policy.
|
|
case unsatisfied
|
|
/// The path does not currently have a usable route, but a connection attempt will trigger network attachment.
|
|
case requiresConnection
|
|
}
|
|
|
|
public let status: NWPath.Status
|
|
|
|
/// A list of all interfaces currently available to this path
|
|
public let availableInterfaces: [NWInterface]
|
|
|
|
/// Checks if the path uses an NWInterface that is considered to be expensive
|
|
///
|
|
/// Cellular interfaces are considered expensive. WiFi hotspots from an iOS device are considered expensive. Other
|
|
/// interfaces may appear as expensive in the future.
|
|
public let isExpensive : Bool
|
|
public let supportsIPv4 : Bool
|
|
public let supportsIPv6 : Bool
|
|
public let supportsDNS : Bool
|
|
|
|
/// Check the local endpoint set on a path. This will be nil for paths
|
|
/// from an NWPathMonitor. For paths from an NWConnection, this will
|
|
/// be set to the local address and port in use by the connection.
|
|
public let localEndpoint: NWEndpoint?
|
|
|
|
/// Check the remote endpoint set on a path. This will be nil for paths
|
|
/// from an NWPathMonitor. For paths from an NWConnection, this will
|
|
/// be set to the remote address and port in use by the connection.
|
|
public let remoteEndpoint: NWEndpoint?
|
|
|
|
/// Checks if the path uses an NWInterface with the specified type
|
|
public func usesInterfaceType(_ type: NWInterface.InterfaceType) -> Bool {
|
|
if let path = self.nw {
|
|
return nw_path_uses_interface_type(path, type.nw)
|
|
}
|
|
return false
|
|
}
|
|
|
|
internal let nw: nw_path_t?
|
|
|
|
internal init(_ path: nw_path_t?) {
|
|
var interfaces = [NWInterface]()
|
|
var local: NWEndpoint? = nil
|
|
var remote: NWEndpoint? = nil
|
|
if let path = path {
|
|
let nwstatus = nw_path_get_status(path)
|
|
switch (nwstatus) {
|
|
case Network.nw_path_status_satisfied:
|
|
self.status = .satisfied
|
|
case Network.nw_path_status_satisfiable:
|
|
self.status = .requiresConnection
|
|
default:
|
|
self.status = .unsatisfied
|
|
}
|
|
self.isExpensive = nw_path_is_expensive(path)
|
|
self.supportsDNS = nw_path_has_dns(path)
|
|
self.supportsIPv4 = nw_path_has_ipv4(path)
|
|
self.supportsIPv6 = nw_path_has_ipv6(path)
|
|
|
|
nw_path_enumerate_interfaces(path, { (interface) in
|
|
interfaces.append(NWInterface(interface))
|
|
return true
|
|
})
|
|
|
|
if let nwlocal = nw_path_copy_effective_local_endpoint(path) {
|
|
local = NWEndpoint(nwlocal)
|
|
}
|
|
if let nwremote = nw_path_copy_effective_remote_endpoint(path) {
|
|
remote = NWEndpoint(nwremote)
|
|
}
|
|
} else {
|
|
self.status = .unsatisfied
|
|
self.isExpensive = false
|
|
self.supportsDNS = false
|
|
self.supportsIPv4 = false
|
|
self.supportsIPv6 = false
|
|
}
|
|
self.availableInterfaces = interfaces
|
|
self.nw = path
|
|
self.localEndpoint = local
|
|
self.remoteEndpoint = remote
|
|
}
|
|
|
|
public static func ==(lhs: NWPath, rhs: NWPath) -> Bool {
|
|
if let lnw = lhs.nw, let rnw = rhs.nw {
|
|
return nw_path_is_equal(lnw, rnw)
|
|
}
|
|
return lhs.nw == nil && rhs.nw == nil
|
|
}
|
|
}
|
|
|
|
/// The NWPathMonitor allows the caller to fetch the current global path (or
|
|
/// a path restricted to a specific network interface type). The path for the monitor
|
|
/// is an observable property that will be updated upon each network change.
|
|
/// Paths generated by a path monitor are not specific to a given endpoint, and
|
|
/// will not have the localEndpoint or remoteEndpoint properties set.
|
|
/// The paths will watch the state of multiple interfaces, and allows the
|
|
/// application to enumerate the available interfaces for use in creating connections
|
|
/// or listeners bound to specific interfaces.
|
|
// NOTE: older overlays had Network.NWPathMonitor as the ObjC name.
|
|
// The two must coexist, so it was renamed. The old name must not be
|
|
// used in the new runtime. _TtC7Network14_NWPathMonitor is the
|
|
// mangled name for Network._NWPathMonitor.
|
|
@_objcRuntimeName(_TtC7Network14_NWPathMonitor)
|
|
@available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *)
|
|
public final class NWPathMonitor {
|
|
|
|
/// Access the current network path tracked by the monitor
|
|
public var currentPath = NWPath(nil)
|
|
fileprivate let nw : nw_path_monitor_t
|
|
|
|
/// Set a block to be called when the network path changes
|
|
private var _pathUpdateHandler: ((_ newPath: NWPath) -> Void)?
|
|
public var pathUpdateHandler: ((_ newPath: NWPath) -> Void)? {
|
|
set {
|
|
self._pathUpdateHandler = newValue
|
|
}
|
|
get {
|
|
return self._pathUpdateHandler
|
|
}
|
|
}
|
|
|
|
/// Start the path monitor and set a queue on which path updates
|
|
/// will be delivered.
|
|
/// Start should only be called once on a monitor, and multiple calls to start will
|
|
/// be ignored.
|
|
public func start(queue: DispatchQueue) {
|
|
self._queue = queue
|
|
nw_path_monitor_set_queue(self.nw, queue)
|
|
nw_path_monitor_start(self.nw)
|
|
}
|
|
|
|
/// Cancel the path monitor, after which point no more path updates will
|
|
/// be delivered.
|
|
public func cancel() {
|
|
nw_path_monitor_cancel(self.nw)
|
|
}
|
|
|
|
private var _queue: DispatchQueue?
|
|
|
|
/// Get queue used for delivering the pathUpdateHandler block.
|
|
/// If the path monitor has not yet been started, the queue will be nil. Once the
|
|
/// path monitor has been started, the queue will be valid.
|
|
public var queue: DispatchQueue? {
|
|
get {
|
|
return self._queue
|
|
}
|
|
}
|
|
|
|
|
|
/// Create a network path monitor to monitor overall network state for the
|
|
/// system. This allows enumeration of all interfaces that are available for
|
|
/// general use by the application.
|
|
public init() {
|
|
self.nw = nw_path_monitor_create()
|
|
nw_path_monitor_set_update_handler(self.nw) { (newPath) in
|
|
self.currentPath = NWPath(newPath)
|
|
if let handler = self._pathUpdateHandler {
|
|
handler(self.currentPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Create a network path monitor that watches a single interface type.
|
|
public init(requiredInterfaceType: NWInterface.InterfaceType) {
|
|
self.nw = nw_path_monitor_create_with_type(requiredInterfaceType.nw)
|
|
nw_path_monitor_set_update_handler(self.nw) { (newPath) in
|
|
self.currentPath = NWPath(newPath)
|
|
if let handler = self._pathUpdateHandler {
|
|
handler(self.currentPath)
|
|
}
|
|
}
|
|
}
|
|
}
|