| @@ -0,0 +1,165 @@ | ||
| #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER || UNITY_PS4 || UNITY_PSM | ||
| using System; | ||
| using System.Net; | ||
| using System.Net.Sockets; | ||
| using UdpKit; | ||
|
|
||
| class DotNetSocket : UdpPlatformSocket { | ||
| string error; | ||
| Socket socket; | ||
| DotNetPlatform platform; | ||
| EndPoint recvEndPoint; | ||
| UdpEndPoint endpoint; | ||
|
|
||
| public override UdpPlatform Platform { | ||
| get { return platform; } | ||
| } | ||
|
|
||
| public DotNetSocket(DotNetPlatform platform) { | ||
| this.platform = platform; | ||
|
|
||
| try { | ||
| socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); | ||
| socket.Blocking = false; | ||
|
|
||
| SetConnReset(socket); | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| } | ||
|
|
||
| recvEndPoint = new IPEndPoint(IPAddress.Any, 0); | ||
| } | ||
|
|
||
| public override string Error { | ||
| get { return error; } | ||
| } | ||
|
|
||
| public override bool IsBound { | ||
| get { return socket != null && socket.IsBound; } | ||
| } | ||
|
|
||
| public override UdpEndPoint EndPoint { | ||
| get { | ||
| VerifyIsBound(); | ||
| return endpoint; | ||
| } | ||
| } | ||
|
|
||
| public override bool Broadcast { | ||
| get { | ||
| VerifyIsBound(); | ||
|
|
||
| try { | ||
| error = null; | ||
| return socket.EnableBroadcast; | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| return false; | ||
| } | ||
| } | ||
| set { | ||
| VerifyIsBound(); | ||
|
|
||
| try { | ||
| socket.EnableBroadcast = value; | ||
| } | ||
| catch (SocketException exn) { | ||
| error = null; | ||
| HandleSocketException(exn); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public override void Close() { | ||
| VerifyIsBound(); | ||
|
|
||
| try { | ||
| error = null; | ||
| socket.Close(); | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| } | ||
| } | ||
|
|
||
| public override void Bind(UdpEndPoint ep) { | ||
| try { | ||
| error = null; | ||
| socket.Bind(DotNetPlatform.ConvertEndPoint(ep)); | ||
|
|
||
| endpoint = DotNetPlatform.ConvertEndPoint(socket.LocalEndPoint); | ||
|
|
||
| UdpLog.Info("Socket bound to {0}", endpoint); | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| } | ||
| } | ||
|
|
||
| public override bool RecvPoll() { | ||
| return RecvPoll(0); | ||
| } | ||
|
|
||
| public override bool RecvPoll(int timeoutInMs) { | ||
| try { | ||
| return socket.Poll(timeoutInMs * 1000, SelectMode.SelectRead); | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| public override int RecvFrom(byte[] buffer, int bufferSize, ref UdpEndPoint endpoint) { | ||
| try { | ||
| int bytesReceived = socket.ReceiveFrom(buffer, 0, bufferSize, SocketFlags.None, ref recvEndPoint); | ||
|
|
||
| if (bytesReceived > 0) { | ||
| endpoint = DotNetPlatform.ConvertEndPoint(recvEndPoint); | ||
| return bytesReceived; | ||
| } | ||
| else { | ||
| return -1; | ||
| } | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| return -1; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| public override int SendTo(byte[] buffer, int bytesToSend, UdpEndPoint endpoint) { | ||
| try { | ||
| return socket.SendTo(buffer, 0, bytesToSend, SocketFlags.None, DotNetPlatform.ConvertEndPoint(endpoint)); | ||
| } | ||
| catch (SocketException exn) { | ||
| HandleSocketException(exn); | ||
| return -1; | ||
| } | ||
| } | ||
|
|
||
| void HandleSocketException(SocketException exn) { | ||
| error = exn.ErrorCode + ": " + exn.SocketErrorCode.ToString(); | ||
| } | ||
|
|
||
| void VerifyIsBound() { | ||
| if (IsBound == false) { | ||
| throw new InvalidOperationException(); | ||
| } | ||
| } | ||
|
|
||
| static void SetConnReset(Socket s) { | ||
| try { | ||
| const uint IOC_IN = 0x80000000; | ||
| const uint IOC_VENDOR = 0x18000000; | ||
| uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; | ||
| s.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null); | ||
| } | ||
| catch { } | ||
| } | ||
|
|
||
| } | ||
| #endif |
| @@ -0,0 +1,77 @@ | ||
| #if (UNITY_ANDROID || UNITY_IPHONE) && !UNITY_EDITOR | ||
| using UnityEngine; | ||
| using System.Collections; | ||
| using System.Runtime.InteropServices; | ||
| using System.Security; | ||
| using System; | ||
| using UdpKit; | ||
|
|
||
| public static class NativePInvoke { | ||
| #if UNITY_ANDROID | ||
| public const string DLL_NAME = "udpkit_android"; | ||
| #elif UNITY_IPHONE | ||
| public const string DLL_NAME = "__Internal"; | ||
| #else | ||
| public const string DLL_NAME = null; | ||
| #endif | ||
|
|
||
| public const int UDPKIT_SOCKET_OK = 0; | ||
| public const int UDPKIT_SOCKET_ERROR = -1; | ||
| public const int UDPKIT_SOCKET_NOTVALID = -2; | ||
| public const int UDPKIT_SOCKET_NODATA = -3; | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern IntPtr CreateSocket(); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 Bind(IntPtr socket, UdpEndPoint.Native addr); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 BroadcastEnable(IntPtr socket); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 BroadcastDisable(IntPtr socket); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 SendTo(IntPtr socket, byte[] buffer, int size, UdpEndPoint.Native addr); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 RecvFrom(IntPtr socket, [In,Out] byte[] buffer, int size, [Out] out UdpEndPoint.Native addr); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 RecvPoll(IntPtr socket, int timeout); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 GetEndPoint(IntPtr socket, [Out] out UdpEndPoint.Native addr); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern Int32 Close(IntPtr socket); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| static extern IntPtr PlatformName(); | ||
| public static string PlatformName_Wrapper() { return Marshal.PtrToStringAnsi(PlatformName()); } | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| static extern IntPtr Error(); | ||
| public static string Error_Wrapper() { return Marshal.PtrToStringAnsi(Error()); } | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern UInt32 GetPrecisionTime(); | ||
|
|
||
| [DllImport(DLL_NAME)] | ||
| [SuppressUnmanagedCodeSecurity] | ||
| public static extern UInt32 GetBroadcastAddress(); | ||
| } | ||
| #endif |
| @@ -0,0 +1,84 @@ | ||
| #if (UNITY_ANDROID || UNITY_IPHONE) && !UNITY_EDITOR | ||
| using UdpKit; | ||
| using UnityEngine; | ||
| using System.Collections; | ||
|
|
||
| public class NativePlatform : UdpKit.UdpPlatform { | ||
| static readonly object timeLock = new object(); | ||
|
|
||
| public override UdpKit.UdpPlatformSocket CreateSocket() { | ||
| return new NativeSocket(this); | ||
| } | ||
|
|
||
| public override UdpKit.UdpIPv4Address GetBroadcastAddress() { | ||
| #if UNITY_IPHONE | ||
| var addr = NativePInvoke.GetBroadcastAddress(); | ||
| return new UdpKit.UdpIPv4Address((byte) (addr >> 0), (byte) (addr >> 8), (byte) (addr >> 16), (byte) (addr >> 24)); | ||
| #elif UNITY_ANDROID | ||
| return Android.GetBroadcastAddress(); | ||
| #else | ||
| return new UdpKit.UdpIPv4Address(255, 255, 255, 255); | ||
| #endif | ||
| } | ||
|
|
||
| public override UdpIPv4Address[] ResolveHostAddresses(string host) { | ||
| return new UdpIPv4Address[0]; | ||
| } | ||
|
|
||
| public override System.Collections.Generic.List<UdpKit.UdpPlatformInterface> GetNetworkInterfaces() { | ||
| return new System.Collections.Generic.List<UdpKit.UdpPlatformInterface>(); | ||
| } | ||
|
|
||
| public override uint GetPrecisionTime() { | ||
| lock (timeLock) { | ||
| return NativePInvoke.GetPrecisionTime(); | ||
| } | ||
| } | ||
|
|
||
| public override bool SupportsBroadcast { | ||
| get { return true; } | ||
| } | ||
|
|
||
| public override bool SupportsMasterServer { | ||
| get { return true; } | ||
| } | ||
|
|
||
| #if UNITY_ANDROID | ||
| static class Android { | ||
| static AndroidJavaObject androidMulticastLock; | ||
|
|
||
| public static UdpIPv4Address GetBroadcastAddress () { | ||
| AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity"); | ||
| AndroidJavaObject wifi = activity.Call<AndroidJavaObject>("getSystemService", "wifi"); | ||
| AndroidJavaObject dhcp = wifi.Call<AndroidJavaObject>("getDhcpInfo"); | ||
|
|
||
| int dhcp_ip = dhcp.Get<int>("ipAddress"); | ||
| int dhcp_mask = dhcp.Get<int>("netmask"); | ||
| int broadcast = (dhcp_ip & dhcp_mask) | ~dhcp_mask; | ||
| byte[] quads = new byte[4]; | ||
|
|
||
| for (int k = 0; k < 4; k++) { | ||
| quads[k] = (byte) ((broadcast >> k * 8) & 0xFF); | ||
| } | ||
|
|
||
| return new UdpIPv4Address(quads[0], quads[1], quads[2], quads[3]); | ||
| } | ||
|
|
||
| public static void AcquireMulticastLock () { | ||
| AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity"); | ||
| AndroidJavaObject wifi = activity.Call<AndroidJavaObject>("getSystemService", "wifi"); | ||
| androidMulticastLock = wifi.Call<AndroidJavaObject>("createMulticastLock", "udpkit"); | ||
| androidMulticastLock.Call("acquire"); | ||
| } | ||
|
|
||
| public static void ReleaseMulticastLock () { | ||
| if (androidMulticastLock != null) { | ||
| androidMulticastLock.Call("release"); | ||
| androidMulticastLock.Dispose(); | ||
| androidMulticastLock = null; | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
| } | ||
| #endif |
| @@ -0,0 +1,127 @@ | ||
| #if (UNITY_ANDROID || UNITY_IPHONE) && !UNITY_EDITOR | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using UdpKit; | ||
|
|
||
| public class NativeSocket : UdpKit.UdpPlatformSocket { | ||
| NativePlatform platform; | ||
|
|
||
| IntPtr socket; | ||
| bool broadcast; | ||
|
|
||
| public override bool Broadcast { | ||
| get { | ||
| return broadcast; | ||
| } | ||
| set { | ||
| if (value) { | ||
| NativePInvoke.BroadcastEnable(socket); | ||
| } | ||
| else { | ||
| NativePInvoke.BroadcastDisable(socket); | ||
| } | ||
|
|
||
| broadcast = value; | ||
| } | ||
| } | ||
|
|
||
| public override UdpEndPoint EndPoint { | ||
| get { | ||
| UdpEndPoint.Native ep = default(UdpEndPoint.Native); | ||
|
|
||
| if (NativePInvoke.GetEndPoint(socket, out ep) == NativePInvoke.UDPKIT_SOCKET_OK) { | ||
| return ep.AsManaged; | ||
| } | ||
|
|
||
| return UdpEndPoint.Any; | ||
| } | ||
| } | ||
|
|
||
| public override string Error { | ||
| get { return NativePInvoke.Error_Wrapper(); } | ||
| } | ||
|
|
||
| public override bool IsBound { | ||
| get { return EndPoint != UdpEndPoint.Any; } | ||
| } | ||
|
|
||
| public override UdpKit.UdpPlatform Platform { | ||
| get { return platform; } | ||
| } | ||
|
|
||
| public NativeSocket(NativePlatform p) { | ||
| platform = p; | ||
| broadcast = false; | ||
| socket = NativePInvoke.CreateSocket(); | ||
| } | ||
|
|
||
| public override void Bind(UdpKit.UdpEndPoint ep) { | ||
| CheckResult(NativePInvoke.Bind(socket, ep.AsNative)); | ||
| } | ||
|
|
||
| public override void Close() { | ||
| CheckResult(NativePInvoke.Close(socket)); | ||
| socket = IntPtr.Zero; | ||
| } | ||
|
|
||
| public override int RecvFrom(byte[] buffer, int bufferSize, ref UdpKit.UdpEndPoint endpoint) { | ||
| var sender = default(UdpEndPoint.Native); | ||
| var bytesReceived = NativePInvoke.RecvFrom(socket, buffer, bufferSize, out sender); | ||
|
|
||
| if (bytesReceived > 0) { | ||
| endpoint = sender.AsManaged; | ||
| } | ||
|
|
||
| if (bytesReceived < 0) { | ||
| UdpLog.Error(Error); | ||
| bytesReceived = -1; | ||
| } | ||
|
|
||
| return bytesReceived; | ||
| } | ||
|
|
||
| public override bool RecvPoll(int timeout) { | ||
| return CheckResult(NativePInvoke.RecvPoll(socket, timeout)); | ||
| } | ||
|
|
||
| public override bool RecvPoll() { | ||
| return RecvPoll(0); | ||
| } | ||
|
|
||
| public override int SendTo(byte[] buffer, int bytesToSend, UdpKit.UdpEndPoint endpoint) { | ||
| var bytesSent = NativePInvoke.SendTo(socket, buffer, bytesToSend, endpoint.AsNative); | ||
|
|
||
| if (bytesSent >= 0) { | ||
| return bytesSent; | ||
| } | ||
|
|
||
| UdpLog.Error(Error); | ||
| return -1; | ||
| } | ||
|
|
||
| bool CheckResult(int result) { | ||
| if (result == NativePInvoke.UDPKIT_SOCKET_OK) { | ||
| return true; | ||
| } | ||
|
|
||
| if (result == NativePInvoke.UDPKIT_SOCKET_ERROR) { | ||
| UdpLog.Error(Error); | ||
| UdpLog.Error(System.Environment.StackTrace); | ||
| return false; | ||
| } | ||
|
|
||
| if (result == NativePInvoke.UDPKIT_SOCKET_NOTVALID) { | ||
| UdpLog.Error("Invalid socket pointer: {0}", socket); | ||
| return false; | ||
| } | ||
|
|
||
| if (result == NativePInvoke.UDPKIT_SOCKET_NODATA) { | ||
| return false; | ||
| } | ||
|
|
||
| throw new Exception(string.Format("Unknown return code: {0}", result)); | ||
| } | ||
| } | ||
| #endif |
| @@ -0,0 +1,70 @@ | ||
| #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER || UNITY_PS4 || UNITY_PSM || UNITY_WP8 | ||
| #define USE_DOTNET | ||
| #endif | ||
|
|
||
| using UnityEngine; | ||
| using System.Collections; | ||
| using UdpKit; | ||
|
|
||
| #if USE_DOTNET | ||
| using System.Diagnostics; | ||
| #endif | ||
|
|
||
| public class NullPlatform : UdpPlatform { | ||
| #if USE_DOTNET | ||
| class PrecisionTimer { | ||
| static readonly long start = Stopwatch.GetTimestamp(); | ||
| static readonly double freq = 1.0 / (double)Stopwatch.Frequency; | ||
|
|
||
| internal static uint GetCurrentTime() { | ||
| long diff = Stopwatch.GetTimestamp() - start; | ||
| double seconds = (double)diff * freq; | ||
| return (uint)(seconds * 1000.0); | ||
| } | ||
| } | ||
| #elif (UNITY_ANDROID || UNITY_IPHONE) && !UNITY_EDITOR | ||
| readonly object timeLock = new object(); | ||
| #endif | ||
|
|
||
| public NullPlatform() { | ||
| GetPrecisionTime(); | ||
| } | ||
|
|
||
| public override UdpPlatformSocket CreateSocket() { | ||
| return new NullSocket(this); | ||
| } | ||
|
|
||
| public override UdpIPv4Address GetBroadcastAddress() { | ||
| return UdpIPv4Address.Broadcast; | ||
| } | ||
|
|
||
| public override System.Collections.Generic.List<UdpPlatformInterface> GetNetworkInterfaces() { | ||
| return new System.Collections.Generic.List<UdpPlatformInterface>(); | ||
| } | ||
|
|
||
| public override uint GetPrecisionTime() { | ||
| #if USE_DOTNET | ||
| return PrecisionTimer.GetCurrentTime(); | ||
| #elif (UNITY_ANDROID || UNITY_IPHONE) && !UNITY_EDITOR | ||
| lock (timeLock) { | ||
| return NativePInvoke.GetPrecisionTime(); | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| public override UdpIPv4Address[] ResolveHostAddresses(string host) { | ||
| return new UdpIPv4Address[0]; | ||
| } | ||
|
|
||
| public override bool SupportsBroadcast { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool SupportsMasterServer { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool IsNull { | ||
| get { return true; } | ||
| } | ||
| } |
| @@ -0,0 +1,55 @@ | ||
| using UnityEngine; | ||
| using System.Collections; | ||
| using UdpKit; | ||
|
|
||
| public class NullSocket : UdpPlatformSocket { | ||
| NullPlatform platform; | ||
|
|
||
| public NullSocket(NullPlatform p) { | ||
| platform = p; | ||
| } | ||
|
|
||
| public override void Bind(UdpEndPoint ep) { | ||
|
|
||
| } | ||
|
|
||
| public override bool Broadcast { | ||
| get; | ||
| set; | ||
| } | ||
|
|
||
| public override void Close() { | ||
| } | ||
|
|
||
| public override UdpEndPoint EndPoint { | ||
| get { return UdpEndPoint.Any; } | ||
| } | ||
|
|
||
| public override string Error { | ||
| get { return ""; } | ||
| } | ||
|
|
||
| public override bool IsBound { | ||
| get { return true; } | ||
| } | ||
|
|
||
| public override UdpPlatform Platform { | ||
| get { return platform; } | ||
| } | ||
|
|
||
| public override int RecvFrom(byte[] buffer, int bufferSize, ref UdpEndPoint remoteEndpoint) { | ||
| return 0; | ||
| } | ||
|
|
||
| public override bool RecvPoll(int timeout) { | ||
| return false; | ||
| } | ||
|
|
||
| public override bool RecvPoll() { | ||
| return false; | ||
| } | ||
|
|
||
| public override int SendTo(byte[] buffer, int bytesToSend, UdpEndPoint endpoint) { | ||
| return bytesToSend; | ||
| } | ||
| } |
| @@ -0,0 +1,44 @@ | ||
| #if UNITY_WP8 && !UNITY_EDITOR | ||
| using UnityEngine; | ||
| using System.Collections; | ||
|
|
||
| public class Wp8Interface : UdpKit.UdpPlatformInterface { | ||
| readonly UdpKit.UdpIPv4Address[] unicast; | ||
| readonly UdpKit.UdpIPv4Address[] gateway; | ||
| readonly UdpKit.UdpIPv4Address[] multicast; | ||
|
|
||
| public Wp8Interface(UdpKit.UdpIPv4Address address) { | ||
| unicast = new UdpKit.UdpIPv4Address[1] { address }; | ||
|
|
||
| address.Byte0 = 1; | ||
| gateway = new UdpKit.UdpIPv4Address[1] { address }; | ||
|
|
||
| address.Byte0 = 255; | ||
| multicast = new UdpKit.UdpIPv4Address[2] { UdpKit.UdpIPv4Address.Broadcast, address }; | ||
| } | ||
|
|
||
| public override UdpKit.UdpIPv4Address[] GatewayAddresses { | ||
| get { return gateway; } | ||
| } | ||
|
|
||
| public override UdpKit.UdpLinkType LinkType { | ||
| get { return UdpKit.UdpLinkType.Unknown; } | ||
| } | ||
|
|
||
| public override UdpKit.UdpIPv4Address[] MulticastAddresses { | ||
| get { return multicast; } | ||
| } | ||
|
|
||
| public override string Name { | ||
| get { return "UNKNOWN"; } | ||
| } | ||
|
|
||
| public override byte[] PhysicalAddress { | ||
| get { return new byte[0]; } | ||
| } | ||
|
|
||
| public override UdpKit.UdpIPv4Address[] UnicastAddresses { | ||
| get { return unicast; } | ||
| } | ||
| } | ||
| #endif |
| @@ -0,0 +1,65 @@ | ||
| #if UNITY_WP8 && !UNITY_EDITOR | ||
| using System.Diagnostics; | ||
|
|
||
| public class Wp8Platform : UdpKit.UdpPlatform { | ||
| class PrecisionTimer { | ||
| static readonly long start = Stopwatch.GetTimestamp(); | ||
| static readonly double freq = 1.0 / (double)Stopwatch.Frequency; | ||
|
|
||
| internal static uint GetCurrentTime() { | ||
| long diff = Stopwatch.GetTimestamp() - start; | ||
| double seconds = (double)diff * freq; | ||
| return (uint)(seconds * 1000.0); | ||
| } | ||
| } | ||
|
|
||
| public Wp8Platform() { | ||
| GetPrecisionTime(); | ||
| } | ||
|
|
||
| public override UdpKit.UdpPlatformSocket CreateSocket() { | ||
| return new Wp8Socket(this); | ||
| } | ||
|
|
||
| public override UdpKit.UdpIPv4Address GetBroadcastAddress() { | ||
| return UdpKit.UdpIPv4Address.Broadcast; | ||
| } | ||
|
|
||
| public override System.Collections.Generic.List<UdpKit.UdpPlatformInterface> GetNetworkInterfaces() { | ||
| var result = new System.Collections.Generic.List<UdpKit.UdpPlatformInterface>(); | ||
|
|
||
| foreach (var addr in UdpKit.Wp8Platform.GetIpAddresses()) { | ||
| try { | ||
| var ipv4 = UdpKit.UdpIPv4Address.Parse(addr); | ||
|
|
||
| if (ipv4.IsPrivate) { | ||
| result.Add(new Wp8Interface(ipv4)); | ||
| } | ||
| } | ||
| catch { } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| public override uint GetPrecisionTime() { | ||
| return PrecisionTimer.GetCurrentTime(); | ||
| } | ||
|
|
||
| public override UdpKit.UdpIPv4Address[] ResolveHostAddresses(string host) { | ||
| return new UdpKit.UdpIPv4Address[0]; | ||
| } | ||
|
|
||
| public override bool SupportsBroadcast { | ||
| get { return false; } | ||
| } | ||
|
|
||
| public override bool SupportsMasterServer { | ||
| get { return true; } | ||
| } | ||
|
|
||
| public override bool IsNull { | ||
| get { return false; } | ||
| } | ||
| } | ||
| #endif |
| @@ -0,0 +1,87 @@ | ||
| #if UNITY_WP8 && !UNITY_EDITOR | ||
| using System.Net; | ||
|
|
||
| public class Wp8Socket : UdpKit.UdpPlatformSocket { | ||
| Wp8Platform platform; | ||
|
|
||
| UdpKit.Wp8Socket socket; | ||
| UdpKit.UdpEndPoint endpoint; | ||
|
|
||
| public Wp8Socket(Wp8Platform p) { | ||
| socket = new UdpKit.Wp8Socket(BoltLog.Warn, 8192); | ||
| platform = p; | ||
| } | ||
|
|
||
| public override void Bind(UdpKit.UdpEndPoint ep) { | ||
| socket.Bind(ep.Port.ToString()); | ||
| } | ||
|
|
||
| public override bool Broadcast { | ||
| get { return false; } | ||
| set { } | ||
| } | ||
|
|
||
| public override void Close() { | ||
| socket.Close(); | ||
| } | ||
|
|
||
| public override UdpKit.UdpEndPoint EndPoint { | ||
| get { return UdpKit.UdpEndPoint.Parse("0.0.0.0:" + socket.LocalPort); } | ||
| } | ||
|
|
||
| public override string Error { | ||
| get { return ""; } | ||
| } | ||
|
|
||
| public override bool IsBound { | ||
| get { return socket.IsBound; } | ||
| } | ||
|
|
||
| public override UdpKit.UdpPlatform Platform { | ||
| get { return platform; } | ||
| } | ||
|
|
||
| public override int RecvFrom(byte[] buffer, int bufferSize, ref UdpKit.UdpEndPoint remoteEndpoint) { | ||
| var host = ""; | ||
| var port = ""; | ||
| var bytes = socket.RecvFrom(buffer, bufferSize, ref host, ref port); | ||
|
|
||
| if (bytes > 0 && host != null && port != null) { | ||
| remoteEndpoint = UdpKit.UdpEndPoint.Parse(host + ":" + port); | ||
| return bytes; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| public override bool RecvPoll(int timeout) { | ||
| return socket.RecvPoll(timeout); | ||
| } | ||
|
|
||
| public override bool RecvPoll() { | ||
| return RecvPoll(0); | ||
| } | ||
|
|
||
| public override int SendTo(byte[] buffer, int bytesToSend, UdpKit.UdpEndPoint endpoint) { | ||
| return socket.SendTo(buffer, bytesToSend, endpoint.Address.ToString(), endpoint.Port.ToString()); | ||
| } | ||
|
|
||
| #pragma warning disable 618 | ||
| static UdpKit.UdpEndPoint ConvertEndPoint(EndPoint endpoint) { | ||
| return ConvertEndPoint((IPEndPoint)endpoint); | ||
| } | ||
|
|
||
| static UdpKit.UdpEndPoint ConvertEndPoint(IPEndPoint endpoint) { | ||
| return new UdpKit.UdpEndPoint(new UdpKit.UdpIPv4Address(endpoint.Address.Address), (ushort)endpoint.Port); | ||
| } | ||
|
|
||
| static UdpKit.UdpIPv4Address ConvertAddress(IPAddress address) { | ||
| return new UdpKit.UdpIPv4Address(address.Address); | ||
| } | ||
|
|
||
| static IPEndPoint ConvertEndPoint(UdpKit.UdpEndPoint endpoint) { | ||
| return new IPEndPoint(new IPAddress(new byte[] { endpoint.Address.Byte3, endpoint.Address.Byte2, endpoint.Address.Byte1, endpoint.Address.Byte0 }), endpoint.Port); | ||
| } | ||
| #pragma warning restore 618 | ||
| } | ||
| #endif |
| @@ -0,0 +1,345 @@ | ||
| #if BOLT_UPNP_SUPPORT && UNITY_STANDALONE | ||
| using Mono.Nat; | ||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using System.Net; | ||
| using UdpKit; | ||
| using UnityEngine; | ||
|
|
||
| namespace BoltInternal { | ||
| public class StandaloneNatCommunicator : BoltInternal.NatCommunicator { | ||
|
|
||
| class NatPortMappingChanged { | ||
| public NatDeviceState Device; | ||
| public NatPortMapping Mapping; | ||
| } | ||
|
|
||
| class NatPortMapping : Bolt.IPortMapping { | ||
| public volatile int External; | ||
| public volatile int Internal; | ||
| public volatile Bolt.NatPortMappingStatus Status; | ||
|
|
||
| ushort Bolt.IPortMapping.External { | ||
| get { return (ushort)External; } | ||
| } | ||
|
|
||
| ushort Bolt.IPortMapping.Internal { | ||
| get { return (ushort)Internal; } | ||
| } | ||
|
|
||
| Bolt.NatPortMappingStatus Bolt.IPortMapping.Status { | ||
| get { return Status; } | ||
| } | ||
|
|
||
| public NatPortMapping Clone() { | ||
| return (NatPortMapping)MemberwiseClone(); | ||
| } | ||
|
|
||
| public override int GetHashCode() { | ||
| return External ^ Internal; | ||
| } | ||
|
|
||
| public override bool Equals(object obj) { | ||
| var that = obj as NatPortMapping; | ||
| if (that != null) { | ||
| return this.Internal == that.Internal && this.External == that.External; | ||
| } | ||
| else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| public override string ToString() { | ||
| return string.Format("[PortMapping External={0} Internal={1} Status={2}]", External, Internal, Status); | ||
| } | ||
|
|
||
|
|
||
| } | ||
|
|
||
| class NatDeviceState : Bolt.INatDevice { | ||
| public volatile INatDevice Nat; | ||
| public volatile IPAddress ExternalAddress; | ||
| public volatile Dictionary<int, NatPortMapping> PortMappings = new Dictionary<int, NatPortMapping>(); | ||
|
|
||
| string Bolt.INatDevice.DeviceType { | ||
| get { lock (syncLock) { return Nat.DeviceType; } } | ||
| } | ||
|
|
||
| UdpIPv4Address Bolt.INatDevice.PublicAddress { | ||
| get { lock (syncLock) { return ExternalAddress == null ? UdpIPv4Address.Any : UdpIPv4Address.Parse(ExternalAddress.ToString()); } } | ||
| } | ||
|
|
||
| UdpIPv4Address Bolt.INatDevice.LocalAddress { | ||
| get { lock (syncLock) { return UdpIPv4Address.Parse(Nat.LocalAddress.ToString()); } } | ||
| } | ||
|
|
||
| IEnumerable<Bolt.IPortMapping> Bolt.INatDevice.Ports { | ||
| get { lock (syncLock) { return PortMappings.Values.Cast<Bolt.IPortMapping>().ToArray(); } } | ||
| } | ||
|
|
||
| public override string ToString() { | ||
| return string.Format("[NatDevice Local={0} Public={1}]", ((Bolt.INatDevice)this).LocalAddress, ((Bolt.INatDevice)this).PublicAddress); | ||
| } | ||
| } | ||
|
|
||
| class BoltLogTextWriter : TextWriter { | ||
| public override System.Text.Encoding Encoding { | ||
| get { return System.Text.Encoding.UTF8; } | ||
| } | ||
|
|
||
| public override void WriteLine(string value) { | ||
| BoltLog.Info("UPnP: " + value); | ||
| } | ||
|
|
||
| public override void WriteLine(string format, params object[] args) { | ||
| BoltLog.Info("UPnP: " + format, args); | ||
| } | ||
| } | ||
|
|
||
| static readonly object syncLock = new object(); | ||
| static List<NatDeviceState> deviceList = new List<NatDeviceState>(); | ||
| static Queue<NatPortMappingChanged> portChanges = new Queue<NatPortMappingChanged>(); | ||
| static Dictionary<int, NatPortMapping> portList = new Dictionary<int, NatPortMapping>(); | ||
|
|
||
| static StandaloneNatCommunicator() { | ||
| NatUtility.DeviceLost += NatUtility_DeviceLost; | ||
| NatUtility.DeviceFound += NatUtility_DeviceFound; | ||
| } | ||
|
|
||
| public override bool IsEnabled { | ||
| get { return NatUtility.IsEnabled; } | ||
| } | ||
|
|
||
| public override bool NextPortStatusChange(out Bolt.INatDevice device, out Bolt.IPortMapping mapping) { | ||
| lock (syncLock) { | ||
| if (portChanges.Count > 0) { | ||
| var change = portChanges.Dequeue(); | ||
|
|
||
| device = change.Device; | ||
| mapping = change.Mapping; | ||
| return true; | ||
| } | ||
| else { | ||
| device = null; | ||
| mapping = null; | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public override void OpenPort(int port) { | ||
| UpdatePort(Bolt.NatPortMappingStatus.Open, port); | ||
| } | ||
|
|
||
| public override void ClosePort(int port) { | ||
| UpdatePort(Bolt.NatPortMappingStatus.Closed, port); | ||
| } | ||
|
|
||
| void UpdatePort(Bolt.NatPortMappingStatus status, int port) { | ||
| if (port < 1 || port > ushort.MaxValue) { | ||
| throw new System.ArgumentOutOfRangeException("port"); | ||
| } | ||
|
|
||
| lock (syncLock) { | ||
| NatPortMapping mapping = new NatPortMapping { Status = status, Internal = port, External = port }; | ||
|
|
||
| if (portList.ContainsKey(port)) { | ||
| portList.Remove(port); | ||
| } | ||
|
|
||
| portList.Add(port, mapping); | ||
| } | ||
| } | ||
|
|
||
| public override IEnumerable<Bolt.INatDevice> NatDevices { | ||
| get { lock (syncLock) { return deviceList.Cast<Bolt.INatDevice>().ToArray(); } } | ||
| } | ||
|
|
||
| public override void Update() { | ||
| lock (syncLock) { | ||
| foreach (var mp in portList.Values) { | ||
| foreach (var dev in deviceList) { | ||
| NatPortMapping devMp; | ||
|
|
||
| if (dev.PortMappings.TryGetValue(mp.External, out devMp)) { | ||
| if (devMp.Status != mp.Status) { | ||
| switch (mp.Status) { | ||
| case Bolt.NatPortMappingStatus.Open: NatUtility_OpenPort(dev, devMp.External); break; | ||
| case Bolt.NatPortMappingStatus.Closed: NatUtility_ClosePort(dev, devMp.External); break; | ||
| } | ||
| } | ||
| } | ||
| else { | ||
| devMp = mp.Clone(); | ||
| devMp.Status = Bolt.NatPortMappingStatus.Unknown; | ||
| dev.PortMappings.Add(devMp.External, devMp); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public override void Disable(bool async) { | ||
| lock (syncLock) { | ||
| portList = new Dictionary<int, NatPortMapping>(); | ||
| deviceList = new List<NatDeviceState>(); | ||
|
|
||
| NatUtility.ShutdownThread(async); | ||
|
|
||
| BoltLog.Info("UPnP Disabled"); | ||
| } | ||
| } | ||
|
|
||
| public override void Enable() { | ||
| lock (syncLock) { | ||
| //NatUtility.Logger = new BoltLogTextWriter(); | ||
| NatUtility.StartDiscovery(); | ||
| BoltLog.Info("UPnP Enabled"); | ||
| } | ||
| } | ||
|
|
||
| static void NatUtility_DeviceFound(object sender, DeviceEventArgs e) { | ||
| lock (syncLock) { | ||
| foreach (var device in deviceList) { | ||
| if (device.Equals(e.Device)) { | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| NatDeviceState deviceState; | ||
| deviceState = new NatDeviceState { Nat = e.Device }; | ||
| deviceState.PortMappings = new Dictionary<int, NatPortMapping>(); | ||
| deviceList.Add(deviceState); | ||
|
|
||
| BoltLog.Info("Found {0}", deviceState); | ||
|
|
||
| NatUtility_FindPublicAddress(deviceState); | ||
| } | ||
| } | ||
|
|
||
| static void NatUtility_DeviceLost(object sender, DeviceEventArgs e) { | ||
| lock (syncLock) { | ||
| for (int i = 0; i < deviceList.Count; ++i) { | ||
| if (deviceList[i].Equals(e.Device)) { | ||
| deviceList.RemoveAt(i); | ||
| i -= 1; | ||
| } | ||
| } | ||
|
|
||
| BoltLog.Info("Lost NAT device at {0}", e.Device.LocalAddress); | ||
| } | ||
| } | ||
|
|
||
| static void NatUtility_FindPublicAddress(NatDeviceState device) { | ||
| lock (syncLock) { | ||
| device.Nat.BeginGetExternalIP(ar => { | ||
| lock (syncLock) { | ||
| try { | ||
| device.ExternalAddress = device.Nat.EndGetExternalIP(ar); | ||
| BoltLog.Info("Found external address of {0}", device); | ||
| } | ||
| catch (Exception exn) { | ||
| BoltLog.Exception(exn); | ||
| } | ||
| } | ||
| }, null); | ||
| } | ||
| } | ||
|
|
||
| static void NatUtility_OpenPort_Finish(NatDeviceState device, int port) { | ||
| try { | ||
| var natMapping = device.PortMappings.Values.FirstOrDefault(p => p.Internal == port && p.External == port); | ||
| if (natMapping != null) { | ||
| // set this port as open | ||
| natMapping.Status = Bolt.NatPortMappingStatus.Open; | ||
|
|
||
| // tell user about this | ||
| portChanges.Enqueue(new NatPortMappingChanged { Device = device, Mapping = natMapping.Clone() }); | ||
|
|
||
| // meep | ||
| BoltLog.Info("Changed {0} on {1}", natMapping, device); | ||
| } | ||
| else { | ||
| BoltLog.Warn("Received incorrect port mapping result from {0}", device); | ||
| } | ||
| } | ||
| catch (Exception exn) { | ||
| BoltLog.Exception(exn); | ||
| } | ||
| } | ||
|
|
||
| static void NatUtility_OpenPort(NatDeviceState device, int port) { | ||
| lock (syncLock) { | ||
| Mapping mapping = new Mapping(Protocol.Udp, port, port); | ||
| device.Nat.BeginCreatePortMap(mapping, ar => { | ||
| lock (syncLock) { | ||
| try { | ||
| device.Nat.EndCreatePortMap(ar); | ||
|
|
||
| // finish this | ||
| NatUtility_OpenPort_Finish(device, port); | ||
| } | ||
| catch (MappingException exn) { | ||
| if (exn.ErrorCode == 718) { | ||
| NatUtility_OpenPort_Finish(device, port); | ||
| } | ||
| else { | ||
| BoltLog.Exception(exn); | ||
| } | ||
| } | ||
| catch (Exception exn) { | ||
| BoltLog.Exception(exn); | ||
| } | ||
| } | ||
| }, null); | ||
| } | ||
| } | ||
|
|
||
| static void ClosePortMapping(NatDeviceState device, int port) { | ||
| var natMapping = device.PortMappings.Values.FirstOrDefault(p => p.Internal == port && p.External == port); | ||
| if (natMapping != null) { | ||
| // set this port as open | ||
| natMapping.Status = Bolt.NatPortMappingStatus.Closed; | ||
|
|
||
| // tell user about this | ||
| portChanges.Enqueue(new NatPortMappingChanged { Device = device, Mapping = natMapping.Clone() }); | ||
|
|
||
| // meep | ||
| BoltLog.Info("Changed {0} on {1}", natMapping, device); | ||
| } | ||
| else { | ||
| BoltLog.Warn("Received incorrect port mapping result from {0}", device); | ||
| } | ||
| } | ||
|
|
||
| static void NatUtility_ClosePort(NatDeviceState device, int port) { | ||
| lock (syncLock) { | ||
| Mapping mapping = new Mapping(Protocol.Udp, port, port); | ||
| device.Nat.BeginDeletePortMap(mapping, ar => { | ||
| lock (syncLock) { | ||
| try { | ||
| device.Nat.EndDeletePortMap(ar); | ||
| ClosePortMapping(device, port); | ||
| } | ||
| catch (MappingException exn) { | ||
| if (exn.ErrorCode == 714) { | ||
| ClosePortMapping(device, port); | ||
| } | ||
| else { | ||
| BoltLog.Exception(exn); | ||
| } | ||
| } | ||
| catch (Exception exn) { | ||
| BoltLog.Exception(exn); | ||
| } | ||
| } | ||
| }, null); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
| #endif |