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 794599c..b1e27ce 100644
Binary files a/integrations/Apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.xcworkspace/xcuserdata/Joseph.xcuserdatad/UserInterfaceState.xcuserstate and b/integrations/Apple/ZeroTierSDK_Apple/ZeroTierSDK_Apple.xcodeproj/project.xcworkspace/xcuserdata/Joseph.xcuserdatad/UserInterfaceState.xcuserstate differ
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