276 lines
8.5 KiB
Swift
276 lines
8.5 KiB
Swift
//
|
|
// ViewController.swift
|
|
// Example_OSX_App
|
|
//
|
|
// Created by Joseph Henry on 6/22/16.
|
|
// Copyright © 2016 ZeroTier Inc. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
class ViewController: NSViewController {
|
|
|
|
let zt = ZTSDK();
|
|
|
|
@IBOutlet weak var btnJoinNetwork: NSButton!
|
|
@IBOutlet weak var btnLeaveNetwork: NSButton!
|
|
@IBOutlet weak var txtNWID: NSTextField!
|
|
@IBOutlet weak var segmentAPISelector: NSSegmentedCell!
|
|
@IBOutlet weak var segmentProtocolSelector: NSSegmentedCell!
|
|
@IBOutlet weak var txtAddr: NSTextField!
|
|
@IBOutlet weak var txtPort: NSTextField!
|
|
@IBOutlet weak var btnConnect: NSButton!
|
|
@IBOutlet weak var btnBind: NSButton!
|
|
|
|
@IBOutlet weak var txtTX: NSTextField!
|
|
@IBOutlet weak var txtRX: NSTextField!
|
|
|
|
var serverPort:Int32 = 8080
|
|
var serverAddr:String = "0.0.0.0"
|
|
var sock:Int32 = -1
|
|
var accepted_sock:Int32 = -1
|
|
|
|
@IBAction func txtAddrChanged(sender: AnyObject) {
|
|
if(sender.stringValue != nil) {
|
|
serverAddr = sender.stringValue
|
|
}
|
|
}
|
|
@IBAction func txtPortChanged(sender: AnyObject) {
|
|
serverPort = sender.intValue
|
|
}
|
|
// Join a ZeroTier network
|
|
@IBAction func UI_JoinNetwork(sender: AnyObject) {
|
|
zt.join_network(txtNWID.stringValue);
|
|
}
|
|
// Leave a ZeroTier network
|
|
@IBAction func UI_LeaveNetwork(sender: AnyObject) {
|
|
zt.leave_network(txtNWID.stringValue);
|
|
}
|
|
// Select an API
|
|
var selectedShim:Int32 = 0
|
|
@IBAction func UI_SelectAPI(sender: AnyObject) {
|
|
selectedShim = sender.intValue // 0 = BSD-style, 1 = SOCKS5 Proxy, etc
|
|
}
|
|
// Select a protocol
|
|
// Protocol { TCP / UDP }
|
|
var selectedProtocol:Int32 = 0
|
|
@IBAction func UI_SelectProtocol(sender: AnyObject) {
|
|
switch sender.intValue
|
|
{
|
|
case 0:
|
|
selectedProtocol = SOCK_STREAM
|
|
case 1:
|
|
selectedProtocol = SOCK_DGRAM
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// CONNECT
|
|
var connect_thread : NSThread!
|
|
func attempt_connect()
|
|
{
|
|
// TCP
|
|
if(selectedProtocol == SOCK_STREAM)
|
|
{
|
|
sock = zt.socket(AF_INET, SOCK_STREAM, 0)
|
|
let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort))
|
|
let connect_err = zt.connect(sock, ztaddr)
|
|
|
|
print("connect_err = \(connect_err),\(errno)")
|
|
if connect_err < 0 {
|
|
let err = errno
|
|
print("Error connecting IPv4 socket \(err)")
|
|
return
|
|
}
|
|
}
|
|
|
|
// UDP
|
|
if(selectedProtocol == SOCK_DGRAM)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
// Connect to remote host on ZeroTier virtual network
|
|
@IBAction func UI_Connect(sender: AnyObject) {
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
|
|
self.connect_thread = NSThread(target:self, selector:#selector(ViewController.attempt_connect), object:nil)
|
|
self.connect_thread.start()
|
|
});
|
|
}
|
|
|
|
// BIND
|
|
var bind_thread : NSThread!
|
|
func attempt_bind()
|
|
{
|
|
sock = zt.socket(AF_INET, SOCK_STREAM, 0)
|
|
let ztaddr: ZTAddress = ZTAddress(AF_INET, serverAddr, Int16(serverPort))
|
|
let bind_err = zt.bind(sock, ztaddr)
|
|
|
|
print("bind_err = \(bind_err),\(errno)")
|
|
if bind_err < 0 {
|
|
let err = errno
|
|
print("Error binding IPv4 socket \(err)")
|
|
return
|
|
}
|
|
|
|
// Put socket into listening state
|
|
zt.listen(sock, 1);
|
|
|
|
// TCP
|
|
if(selectedProtocol == SOCK_STREAM) {
|
|
while(accepted_sock < 0) {
|
|
accepted_sock = zt.accept(sock, ztaddr)
|
|
}
|
|
print("accepted connection")
|
|
}
|
|
// UDP
|
|
if(selectedProtocol == SOCK_DGRAM) {
|
|
// nothing
|
|
}
|
|
}
|
|
|
|
// Bind a ZeroTier socket
|
|
@IBAction func UI_Bind(sender: AnyObject) {
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
|
|
self.bind_thread = NSThread(target:self, selector:#selector(ViewController.attempt_bind), object:nil)
|
|
self.bind_thread.start()
|
|
});
|
|
}
|
|
|
|
// TX
|
|
@IBOutlet weak var btnSend: NSButton!
|
|
@IBAction func UI_SendData(sender: AnyObject) {
|
|
// Use ordinary read/write calls on ZeroTier socket
|
|
// TCP
|
|
if(selectedProtocol == SOCK_STREAM)
|
|
{
|
|
write(sock, txtTX.description, txtTX.description.characters.count);
|
|
}
|
|
// UDP
|
|
if(selectedProtocol == SOCK_DGRAM)
|
|
{
|
|
// zt_sendto
|
|
}
|
|
}
|
|
|
|
// RX
|
|
@IBOutlet weak var btnReadData: NSButton!
|
|
@IBAction func UI_ReadData(sender: AnyObject) {
|
|
// Use ordinary read/write calls on ZeroTier socket
|
|
// TCP
|
|
if(selectedProtocol == SOCK_STREAM)
|
|
{
|
|
var buffer = [UInt8](count: 100, repeatedValue: 0)
|
|
read(accepted_sock, &buffer, 1024);
|
|
print(buffer)
|
|
|
|
}
|
|
// UDP
|
|
if(selectedProtocol == SOCK_DGRAM)
|
|
{
|
|
// zt_recvfrom
|
|
}
|
|
}
|
|
|
|
// Watch for incoming data
|
|
var rx_thread : NSThread!
|
|
func update_rx() {
|
|
while(true)
|
|
{
|
|
sleep(1)
|
|
dispatch_async(dispatch_get_main_queue()) {
|
|
let str_buf = [Int8](count: 16, repeatedValue: 0)
|
|
print("addr = ", String.fromCString(str_buf))
|
|
}
|
|
|
|
// TCP
|
|
if(selectedProtocol == SOCK_STREAM)
|
|
{
|
|
let len = 32
|
|
var buffer = [UInt8](count: len, repeatedValue: 0)
|
|
let n = read(accepted_sock, &buffer, len);
|
|
if(n > 0)
|
|
{
|
|
if let str = String(data: NSData(bytes: &buffer, length: len), encoding: NSUTF8StringEncoding) {
|
|
dispatch_async(dispatch_get_main_queue()) {
|
|
self.txtRX.stringValue = str
|
|
}
|
|
} else {
|
|
print("not a valid UTF-8 sequence")
|
|
}
|
|
}
|
|
}
|
|
// UDP
|
|
if(selectedProtocol == SOCK_DGRAM)
|
|
{
|
|
// zt_recvfrom
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Built-in SOCKS5 Proxy Server Test
|
|
func test_client_proxy_nsstream()
|
|
{
|
|
// For HTTP request
|
|
var buffer = [UInt8](count: 100, repeatedValue: 0)
|
|
let str = "GET / HTTP/1.0\r\n\r\n"
|
|
//let str = "Welcome to the machine"
|
|
print("strlen = %d\n", str.characters.count)
|
|
let encodedDataArray = [UInt8](str.utf8)
|
|
|
|
var inputStream:NSInputStream?
|
|
var outputStream:NSOutputStream?
|
|
|
|
// As usual, get our streams to our desired "local" address
|
|
NSStream.getStreamsToHostWithName(serverAddr, port: Int(serverPort), inputStream: &inputStream, outputStream: &outputStream)
|
|
|
|
// SOCKS Proxy config dictionary
|
|
let myDict:NSDictionary = [NSStreamSOCKSProxyHostKey : "0.0.0.0",
|
|
NSStreamSOCKSProxyPortKey : 1337,
|
|
NSStreamSOCKSProxyVersionKey : NSStreamSOCKSProxyVersion5]
|
|
|
|
// Give configuration to NSStreams
|
|
inputStream!.setProperty(myDict, forKey: NSStreamSOCKSProxyConfigurationKey)
|
|
outputStream!.setProperty(myDict, forKey: NSStreamSOCKSProxyConfigurationKey)
|
|
|
|
inputStream!.open()
|
|
outputStream!.open()
|
|
|
|
// TX
|
|
outputStream?.write(encodedDataArray, maxLength: encodedDataArray.count)
|
|
|
|
// RX
|
|
sleep(5)
|
|
inputStream?.read(&buffer, maxLength: 100)
|
|
print("buffer = \(buffer)\n")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
// Set initial UI values for demo
|
|
txtAddr.stringValue = serverAddr
|
|
txtPort.intValue = serverPort
|
|
txtNWID.stringValue = "8056c2e21c000001"
|
|
selectedProtocol = SOCK_STREAM // Just for selecting test mode. Not necessary for zt API
|
|
|
|
zt.start_service(".");
|
|
zt.join_network(txtNWID.stringValue);
|
|
|
|
// Update UI on RX of data
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
|
|
self.rx_thread = NSThread(target:self, selector:#selector(ViewController.update_rx), object:nil)
|
|
self.rx_thread.start()
|
|
});
|
|
}
|
|
|
|
override var representedObject: AnyObject? {
|
|
didSet {
|
|
// Update the view, if already loaded.
|
|
}
|
|
}
|
|
}
|
|
|