SimpleTunnel/ClientTunnelConnection.swift
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
This file contains the ClientTunnelConnection class. The ClientTunnelConnection class handles the encapsulation and decapsulation of IP packets in the client side of the SimpleTunnel tunneling protocol. |
*/ |
import Foundation |
import SimpleTunnelServices |
import NetworkExtension |
// MARK: Protocols |
/// The delegate protocol for ClientTunnelConnection. |
protocol ClientTunnelConnectionDelegate { |
/// Handle the connection being opened. |
func tunnelConnectionDidOpen(_ connection: ClientTunnelConnection, configuration: [NSObject: AnyObject]) |
/// Handle the connection being closed. |
func tunnelConnectionDidClose(_ connection: ClientTunnelConnection, error: NSError?) |
} |
/// An object used to tunnel IP packets using the SimpleTunnel protocol. |
class ClientTunnelConnection: Connection { |
// MARK: Properties |
/// The connection delegate. |
let delegate: ClientTunnelConnectionDelegate |
/// The flow of IP packets. |
let packetFlow: NEPacketTunnelFlow |
// MARK: Initializers |
init(tunnel: ClientTunnel, clientPacketFlow: NEPacketTunnelFlow, connectionDelegate: ClientTunnelConnectionDelegate) { |
delegate = connectionDelegate |
packetFlow = clientPacketFlow |
let newConnectionIdentifier = arc4random() |
super.init(connectionIdentifier: Int(newConnectionIdentifier), parentTunnel: tunnel) |
} |
// MARK: Interface |
/// Open the connection by sending a "connection open" message to the tunnel server. |
func open() { |
guard let clientTunnel = tunnel as? ClientTunnel else { return } |
let properties = createMessagePropertiesForConnection(identifier, commandType: .open, extraProperties:[ |
TunnelMessageKey.TunnelType.rawValue: TunnelLayer.ip.rawValue as AnyObject |
]) |
clientTunnel.sendMessage(properties) { error in |
if let error = error { |
self.delegate.tunnelConnectionDidClose(self, error: error) |
} |
} |
} |
/// Handle packets coming from the packet flow. |
func handlePackets(_ packets: [Data], protocols: [NSNumber]) { |
guard let clientTunnel = tunnel as? ClientTunnel else { return } |
let properties = createMessagePropertiesForConnection(identifier, commandType: .packets, extraProperties:[ |
TunnelMessageKey.Packets.rawValue: packets as AnyObject, |
TunnelMessageKey.Protocols.rawValue: protocols as AnyObject |
]) |
clientTunnel.sendMessage(properties) { error in |
if let sendError = error { |
self.delegate.tunnelConnectionDidClose(self, error: sendError) |
return |
} |
// Read more packets. |
self.packetFlow.readPackets { inPackets, inProtocols in |
self.handlePackets(inPackets, protocols: inProtocols) |
} |
} |
} |
/// Make the initial readPacketsWithCompletionHandler call. |
func startHandlingPackets() { |
packetFlow.readPackets { inPackets, inProtocols in |
self.handlePackets(inPackets, protocols: inProtocols) |
} |
} |
// MARK: Connection |
/// Handle the event of the connection being established. |
override func handleOpenCompleted(_ resultCode: TunnelConnectionOpenResult, properties: [NSObject: AnyObject]) { |
guard resultCode == .success else { |
delegate.tunnelConnectionDidClose(self, error: SimpleTunnelError.badConnection as NSError) |
return |
} |
// Pass the tunnel network settings to the delegate. |
if let configuration = properties[TunnelMessageKey.Configuration.rawValue as NSString] as? [NSObject: AnyObject] { |
delegate.tunnelConnectionDidOpen(self, configuration: configuration) |
} |
else { |
delegate.tunnelConnectionDidOpen(self, configuration: [:]) |
} |
} |
/// Send packets to the virtual interface to be injected into the IP stack. |
override func sendPackets(_ packets: [Data], protocols: [NSNumber]) { |
packetFlow.writePackets(packets, withProtocols: protocols) |
} |
} |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-10-04