From 8b90bb0e8b31aa0081f9a67ebd2e87837f779381 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 21 Jun 2016 10:56:57 -0700 Subject: [PATCH] improved API path handling --- docs/unity3d_osx_zt_sdk.md | 12 +- .../UserInterfaceState.xcuserstate | Bin 64671 -> 49840 bytes .../Assets/ZeroTierNetworkInterface.cs | 323 ++++++++++++++++++ .../Unity3D/Assets/ZeroTierSockets_Demo.cs | 7 +- 4 files changed, 333 insertions(+), 9 deletions(-) create mode 100755 integrations/Unity3D/Assets/ZeroTierNetworkInterface.cs diff --git a/docs/unity3d_osx_zt_sdk.md b/docs/unity3d_osx_zt_sdk.md index 64a1fe4..e71839c 100644 --- a/docs/unity3d_osx_zt_sdk.md +++ b/docs/unity3d_osx_zt_sdk.md @@ -12,14 +12,14 @@ Our implementation currently intends to be the bare minimum required to get your - `Join(nwid)`: Joins a ZeroTier virtual network - `Leave(nwid)`: Leaves a ZeroTier virtual network -- `Socket(family, type, protocol)`: Creates a ZeroTier-administered socket +- `Socket(family, type, protocol)`: Creates a ZeroTier-administered socket (returns an `fd`) - `Bind(fd, addr, port)`: Binds to that socket on the address and port given - `Listen(fd, backlog)`: Puts a socket into a listening state - `Accept(fd)`: Accepts an incoming connection - `Connect(fd, addr, port)`: Connects to an endpoint associated with the given `fd` - `Write(fd, buf, len)`: Sends data to the endpoint associated with the given `fd` - `Read(fd, buf, len)`: Receives data from an endpoint associated with the given `fd` -- `CLose(fd)`: Closes a connection with an endpoint +- `CLose(fd)`: Closes a connection to an endpoint *** ## Adding ZeroTier to your Unity app @@ -46,13 +46,16 @@ public class Example public void example_server() { + zt = new ZeroTierNetworkInterface (); // Start interface + zt.Join("565799d8f6e1c11a"); // Join your network + Thread connectThread = new Thread(() => { // Create ZeroTier-administered socket int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); zt.Bind(sock, "0.0.0.0", 8000); zt.Listen(sock, 1); - // Accept() client connection + // Accept client connection int accept_sock = -1; while(accept_res < 0) { accept_sock = zt.Accept(sock); @@ -81,6 +84,9 @@ public class Example public void example_client() { + zt = new ZeroTierNetworkInterface (); + zt.Join("565799d8f6e1c11a"); + Thread connectThread = new Thread(() => { // Create ZeroTier-administered socket int sock = zt.Socket ((int)AddressFamily.InterNetwork, (int)SocketType.Stream, (int)ProtocolType.Unspecified); diff --git a/integrations/Apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.xcworkspace/xcuserdata/Joseph.xcuserdatad/UserInterfaceState.xcuserstate b/integrations/Apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.xcworkspace/xcuserdata/Joseph.xcuserdatad/UserInterfaceState.xcuserstate index 794599c6b02e97faf65eba79f3fb29e6bada8f9e..b1e27ce96672c3c6a2c12bf882570811f7b33422 100644 GIT binary patch literal 49840 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 hxujTrG?^;Y~>|NnL){|iW?wp;)J literal 64671 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 diff --git a/integrations/Unity3D/Assets/ZeroTierNetworkInterface.cs b/integrations/Unity3D/Assets/ZeroTierNetworkInterface.cs new file mode 100755 index 0000000..d56fe67 --- /dev/null +++ b/integrations/Unity3D/Assets/ZeroTierNetworkInterface.cs @@ -0,0 +1,323 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.Networking; + +using System; +using System.Collections; +using System.Runtime.InteropServices; +using System.Threading; +using System.Net.Sockets; +using System.Net; +using System.IO; +using System.Collections.Generic; + +// TODO: +/* + * check for mem leaks surrounding managed/unmanaged barrier + * find root of 2X buffer size requirement issue + * check that cross-thread oprations are handled correctly + * check that .IsRunning() doesn't bork the entire system anymore + * Allow max packet size configuration + * Handle exceptions from unmanaged code + * */ + +// Provides a bare-bones interface to ZeroTier-administered sockets +public class ZeroTierNetworkInterface { + + // ZeroTier background thread + protected Thread ztThread; + protected List connections = new List (); + protected int MaxPacketSize; + + // Only allow one network at a time for BETA + protected bool joined_to_network = false; + protected string nwid = ""; + + // Platform-specific paths and bundle/libary names + #if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX + const string DLL_PATH = "ZeroTierSDK_Unity3D_OSX"; + protected string rpc_path = "/Library/Application\\ Support/ZeroTier/SDK/"; + #endif + #if UNITY_IOS || UNITY_IPHONE + const string DLL_PATH = "ZeroTierSDK_Unity3D_iOS"; + protected string rpc_path = "ZeroTier/One/"; + #endif + #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + const string DLL_PATH = "ZeroTierSDK_Unity3D_WIN"; + protected string rpc_path = ""; + #endif + #if UNITY_STANDALONE_LINUX + const string DLL_PATH = "ZeroTierSDK_Unity3D_LINUX"; + protected string rpc_path = ""; + #endif + #if UNITY_ANDROID + const string DLL_PATH = "ZeroTierSDK_Unity3D_ANDROID"; + protected string rpc_path = "ZeroTier/One/"; + #endif + +#region DLL Imports + // ZeroTier service / debug initialization + [DllImport (DLL_PATH)] + public static extern void SetDebugFunction( IntPtr fp ); + [DllImport (DLL_PATH)] + private static extern int unity_start_service(string path); + + // Connection calls + [DllImport (DLL_PATH)] + protected static extern int zt_socket(int family, int type, int protocol); + + [DllImport (DLL_PATH)] + unsafe protected static extern int zt_bind(int sockfd, System.IntPtr addr, int addrlen); + [DllImport (DLL_PATH)] + unsafe protected static extern int zt_connect(int sockfd, System.IntPtr addr, int addrlen); + + [DllImport (DLL_PATH)] + protected static extern int zt_accept(int sockfd); + [DllImport (DLL_PATH)] + protected static extern int zt_listen(int sockfd, int backlog); + [DllImport (DLL_PATH)] + protected static extern int zt_close(int sockfd); + + // RX / TX + [DllImport (DLL_PATH)] + unsafe protected static extern int zt_recv(int sockfd, [In, Out] IntPtr buf, int len); + [DllImport (DLL_PATH)] + unsafe protected static extern int zt_send(int sockfd, IntPtr buf, int len); + [DllImport (DLL_PATH)] + unsafe protected static extern int zt_set_nonblock(int sockfd); + + // ZT Thread controls + [DllImport (DLL_PATH)] + protected static extern bool zt_is_running(); + [DllImport (DLL_PATH)] + protected static extern void zt_terminate(); + + // ZT Network controls + [DllImport (DLL_PATH)] + protected static extern bool zt_join_network(string nwid); + [DllImport (DLL_PATH)] + protected static extern void zt_leave_network(string nwid); +#endregion + + // Interop structures + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)] + public struct sockaddr { + /// u_short->unsigned short + public ushort sa_family; + /// char[14] + [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=14)] + public string sa_data; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void MyDelegate(string str); + + // Debug output callback + static void CallBackFunction(string str) { + Debug.Log("ZeroTier: " + str); + } + + + // Returns a path for RPC communications to the service + private string rpcCommPath() + { + if(rpc_path != "" && nwid != "") { + return rpc_path + "nc_" + nwid; + } + return ""; + } + + // Thread which starts the ZeroTier service + protected void zt_service_thread() + { + // Set up debug callback + MyDelegate callback_delegate = new MyDelegate( CallBackFunction ); + IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate); + SetDebugFunction( intptr_delegate ); + Debug.Log ("RPC = " + rpcCommPath()); + // Start service + unity_start_service(rpcCommPath()); + /* This new instance will communicate via a named pipe, so any + * API calls (ZeroTier.Connect(), ZeroTier.Send(), etc) will be sent to the service + * via this pipe. + */ + } + + // Returns the nwid of the network you're currently connected to + public string GetNetworkID() { + return nwid; + } + + // Returns whether you're currently connected to a network + public bool IsConnected() { + return nwid != ""; + } + + // Start the ZeroTier service + protected void Init() + { + ztThread = new Thread(() => { + try { + zt_service_thread(); + } catch(Exception e) { + Debug.Log(e.Message.ToString()); + } + }); + ztThread.IsBackground = true; // Allow the thread to be aborted safely + ztThread.Start(); + } + + // Initialize the ZeroTier service with a given path + public ZeroTierNetworkInterface(string nwid) + { + this.nwid = nwid; + Init(); + } + + // Initialize the ZeroTier service + public ZeroTierNetworkInterface() + { + Init(); + } + + // Initialize the ZeroTier service + // Use the GlobalConfig to set things like the max packet size + /* + public ZeroTierNetworkInterface(GlobalConfig gConfig) + { + MaxPacketSize = gConfig.MaxPacketSize; // TODO: Do something with this! + Init(); + } + */ + +#region Network Handling + // Joins a ZeroTier virtual network + public bool JoinNetwork(string nwid) + { + if(!joined_to_network) { + zt_join_network(nwid); + return true; + } + return false; + } + + // Leaves a ZeroTier virtual network + public bool LeaveNetwork(string nwid) + { + if(!joined_to_network) { + return false; + } + else { + zt_leave_network(nwid); + return true; + } + } +#endregion + + // Creates a new ZeroTier-administered socket + public int Socket(int family, int type, int protocol) + { + return zt_socket (family, type, protocol); + } + + // Binds to a specific address + public int Bind(int fd, string addr, int port) + { + GCHandle sockaddr_ptr = ZeroTierUtils.Generate_unmananged_sockaddr(addr + ":" + port); + IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); + int addrlen = Marshal.SizeOf (pSockAddr); + return zt_bind (fd, pSockAddr, addrlen); + } + + // Listens for an incoming connection request + public int Listen(int fd, int backlog) + { + return zt_listen(fd, backlog); + } + + // Accepts an incoming connection + public int Accept(int fd) + { + return zt_accept (fd); + } + + // Closes a connection + public int Close(int fd) + { + return Close (fd); + } + + // Connects to a remote host + public int Connect(int fd, string addr, int port) + { + GCHandle sockaddr_ptr = ZeroTierUtils.Generate_unmananged_sockaddr(addr + ":" + port); + IntPtr pSockAddr = sockaddr_ptr.AddrOfPinnedObject (); + int addrlen = Marshal.SizeOf (pSockAddr); + return zt_connect (fd, pSockAddr, addrlen); + } + + public int Read(int fd, ref char[] buf, int len) + { + GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); + IntPtr ptr = handle.AddrOfPinnedObject(); + int bytes_read = zt_recv (fd, ptr, len*2); + string str = Marshal.PtrToStringAuto(ptr); + //Marshal.Copy (ptr, buf, 0, bytes_read); + buf = Marshal.PtrToStringAnsi(ptr).ToCharArray(); + return bytes_read; + } + + public int Write(int fd, char[] buf, int len) + { + GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); + IntPtr ptr = handle.AddrOfPinnedObject(); + //error = 0; + int bytes_written; + // FIXME: Sending a length of 2X the buffer size seems to fix the object pinning issue + if((bytes_written = zt_send(fd, ptr, len*2)) < 0) { + //error = (byte)bytes_written; + } + return bytes_written; + } + +#region Service-Related calls + // Returns whether the ZeroTier service is currently running + public bool IsRunning() + { + return zt_is_running (); + } + + // Terminates the ZeroTier service + public void Terminate() + { + zt_terminate (); + } +#endregion +} diff --git a/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs b/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs index 60dfdb4..8c81b1a 100644 --- a/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs +++ b/integrations/Unity3D/Assets/ZeroTierSockets_Demo.cs @@ -186,12 +186,7 @@ public class ZeroTierSockets_Demo : MonoBehaviour input.text = "Welcome to the machine"; // Create new instance of ZeroTier in separate thread - zt = new ZeroTierLLAPI ("/Users/Joseph/utest2/nc_565799d8f6e1c11a"); - - /* This new instance will communicate via a named pipe, so any - * API calls (ZeroTier.Connect(), ZeroTier.Send(), etc) will be sent to the service - * via this pipe. - */ + zt = new ZeroTierNetworkInterface (); } // Terminate the ZeroTier service when the application quits