summaryrefslogtreecommitdiff
path: root/Erika/Assets/ConsolePro/Remote/LiteNetLib/NetSocket.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Erika/Assets/ConsolePro/Remote/LiteNetLib/NetSocket.cs')
-rw-r--r--Erika/Assets/ConsolePro/Remote/LiteNetLib/NetSocket.cs455
1 files changed, 455 insertions, 0 deletions
diff --git a/Erika/Assets/ConsolePro/Remote/LiteNetLib/NetSocket.cs b/Erika/Assets/ConsolePro/Remote/LiteNetLib/NetSocket.cs
new file mode 100644
index 00000000..922c9bd2
--- /dev/null
+++ b/Erika/Assets/ConsolePro/Remote/LiteNetLib/NetSocket.cs
@@ -0,0 +1,455 @@
+#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
+#if !WINRT || UNITY_EDITOR
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace FlyingWormConsole3.LiteNetLib
+{
+ internal sealed class NetSocket
+ {
+ private Socket _udpSocketv4;
+ private Socket _udpSocketv6;
+ private NetEndPoint _localEndPoint;
+ private Thread _threadv4;
+ private Thread _threadv6;
+ private bool _running;
+ private readonly NetManager.OnMessageReceived _onMessageReceived;
+
+ private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse (NetConstants.MulticastGroupIPv6);
+ private static readonly bool IPv6Support;
+ private const int SocketReceivePollTime = 100000;
+ private const int SocketSendPollTime = 5000;
+
+ public NetEndPoint LocalEndPoint
+ {
+ get { return _localEndPoint; }
+ }
+
+ static NetSocket()
+ {
+ try
+ {
+ //Unity3d .NET 2.0 throws exception.
+ // IPv6Support = Socket.OSSupportsIPv6;
+ IPv6Support = false;
+ }
+ catch
+ {
+ IPv6Support = false;
+ }
+ }
+
+ public NetSocket(NetManager.OnMessageReceived onMessageReceived)
+ {
+ _onMessageReceived = onMessageReceived;
+ }
+
+ private void ReceiveLogic(object state)
+ {
+ Socket socket = (Socket)state;
+ EndPoint bufferEndPoint = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);
+ NetEndPoint bufferNetEndPoint = new NetEndPoint((IPEndPoint)bufferEndPoint);
+ byte[] receiveBuffer = new byte[NetConstants.PacketSizeLimit];
+
+ while (_running)
+ {
+ //wait for data
+ if (!socket.Poll(SocketReceivePollTime, SelectMode.SelectRead))
+ {
+ continue;
+ }
+
+ int result;
+
+ //Reading data
+ try
+ {
+ result = socket.ReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref bufferEndPoint);
+ if (!bufferNetEndPoint.EndPoint.Equals(bufferEndPoint))
+ {
+ bufferNetEndPoint = new NetEndPoint((IPEndPoint)bufferEndPoint);
+ }
+ }
+ catch (SocketException ex)
+ {
+ if (ex.SocketErrorCode == SocketError.ConnectionReset ||
+ ex.SocketErrorCode == SocketError.MessageSize)
+ {
+ //10040 - message too long
+ //10054 - remote close (not error)
+ //Just UDP
+ NetUtils.DebugWrite(ConsoleColor.DarkRed, "[R] Ingored error: {0} - {1}", (int)ex.SocketErrorCode, ex.ToString() );
+ continue;
+ }
+ NetUtils.DebugWriteError("[R]Error code: {0} - {1}", (int)ex.SocketErrorCode, ex.ToString());
+ _onMessageReceived(null, 0, (int)ex.SocketErrorCode, bufferNetEndPoint);
+ continue;
+ }
+
+ //All ok!
+ NetUtils.DebugWrite(ConsoleColor.Blue, "[R]Recieved data from {0}, result: {1}", bufferNetEndPoint.ToString(), result);
+ _onMessageReceived(receiveBuffer, result, 0, bufferNetEndPoint);
+ }
+ }
+
+ public bool Bind(int port, bool reuseAddress)
+ {
+ _udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ _udpSocketv4.Blocking = false;
+ _udpSocketv4.ReceiveBufferSize = NetConstants.SocketBufferSize;
+ _udpSocketv4.SendBufferSize = NetConstants.SocketBufferSize;
+ _udpSocketv4.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, NetConstants.SocketTTL);
+ if(reuseAddress)
+ _udpSocketv4.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+#if !NETCORE
+ _udpSocketv4.DontFragment = true;
+#endif
+
+ try
+ {
+ _udpSocketv4.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
+ }
+ catch (SocketException e)
+ {
+ NetUtils.DebugWriteError("Broadcast error: {0}", e.ToString());
+ }
+
+ if (!BindSocket(_udpSocketv4, new IPEndPoint(IPAddress.Any, port)))
+ {
+ return false;
+ }
+ _localEndPoint = new NetEndPoint((IPEndPoint)_udpSocketv4.LocalEndPoint);
+
+ _running = true;
+ _threadv4 = new Thread(ReceiveLogic);
+ _threadv4.Name = "SocketThreadv4(" + port + ")";
+ _threadv4.IsBackground = true;
+ _threadv4.Start(_udpSocketv4);
+
+ //Check IPv6 support
+ if (!IPv6Support)
+ return true;
+
+ //Use one port for two sockets
+ port = _localEndPoint.Port;
+
+ _udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
+ _udpSocketv6.Blocking = false;
+ _udpSocketv6.ReceiveBufferSize = NetConstants.SocketBufferSize;
+ _udpSocketv6.SendBufferSize = NetConstants.SocketBufferSize;
+ if (reuseAddress)
+ _udpSocketv6.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+
+ if (BindSocket(_udpSocketv6, new IPEndPoint(IPAddress.IPv6Any, port)))
+ {
+ _localEndPoint = new NetEndPoint((IPEndPoint)_udpSocketv6.LocalEndPoint);
+
+ try
+ {
+ _udpSocketv6.SetSocketOption(
+ SocketOptionLevel.IPv6,
+ SocketOptionName.AddMembership,
+ new IPv6MulticastOption(MulticastAddressV6));
+ }
+ catch(Exception)
+ {
+ // Unity3d throws exception - ignored
+ }
+
+ _threadv6 = new Thread(ReceiveLogic);
+ _threadv6.Name = "SocketThreadv6(" + port + ")";
+ _threadv6.IsBackground = true;
+ _threadv6.Start(_udpSocketv6);
+ }
+
+ return true;
+ }
+
+ private bool BindSocket(Socket socket, IPEndPoint ep)
+ {
+ try
+ {
+ socket.Bind(ep);
+ NetUtils.DebugWrite(ConsoleColor.Blue, "[B]Succesfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
+ }
+ catch (SocketException ex)
+ {
+ NetUtils.DebugWriteError("[B]Bind exception: {0}", ex.ToString());
+ //TODO: very temporary hack for iOS (Unity3D)
+ if (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
+ {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public bool SendBroadcast(byte[] data, int offset, int size, int port)
+ {
+ try
+ {
+ int result = _udpSocketv4.SendTo(data, offset, size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port));
+ if (result <= 0)
+ return false;
+ if (IPv6Support)
+ {
+ result = _udpSocketv6.SendTo(data, offset, size, SocketFlags.None, new IPEndPoint(MulticastAddressV6, port));
+ if (result <= 0)
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ NetUtils.DebugWriteError("[S][MCAST]" + ex);
+ return false;
+ }
+ return true;
+ }
+
+ public int SendTo(byte[] data, int offset, int size, NetEndPoint remoteEndPoint, ref int errorCode)
+ {
+ try
+ {
+ int result = 0;
+ if (remoteEndPoint.EndPoint.AddressFamily == AddressFamily.InterNetwork)
+ {
+ if (!_udpSocketv4.Poll(SocketSendPollTime, SelectMode.SelectWrite))
+ return -1;
+ result = _udpSocketv4.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint.EndPoint);
+ }
+ else if(IPv6Support)
+ {
+ if (!_udpSocketv6.Poll(SocketSendPollTime, SelectMode.SelectWrite))
+ return -1;
+ result = _udpSocketv6.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint.EndPoint);
+ }
+
+ NetUtils.DebugWrite(ConsoleColor.Blue, "[S]Send packet to {0}, result: {1}", remoteEndPoint.EndPoint, result);
+ return result;
+ }
+ catch (SocketException ex)
+ {
+ if (ex.SocketErrorCode != SocketError.MessageSize)
+ {
+ NetUtils.DebugWriteError("[S]" + ex);
+ }
+
+ errorCode = (int)ex.SocketErrorCode;
+ return -1;
+ }
+ catch (Exception ex)
+ {
+ NetUtils.DebugWriteError("[S]" + ex);
+ return -1;
+ }
+ }
+
+ private void CloseSocket(Socket s)
+ {
+#if NETCORE
+ s.Dispose();
+#else
+ s.Close();
+#endif
+ }
+
+ public void Close()
+ {
+ _running = false;
+
+ //Close IPv4
+ if (Thread.CurrentThread != _threadv4)
+ {
+ _threadv4.Join();
+ }
+ _threadv4 = null;
+ if (_udpSocketv4 != null)
+ {
+ CloseSocket(_udpSocketv4);
+ _udpSocketv4 = null;
+ }
+
+ //No ipv6
+ if (_udpSocketv6 == null)
+ return;
+
+ //Close IPv6
+ if (Thread.CurrentThread != _threadv6)
+ {
+ _threadv6.Join();
+ }
+ _threadv6 = null;
+ if (_udpSocketv6 != null)
+ {
+ CloseSocket(_udpSocketv6);
+ _udpSocketv6 = null;
+ }
+ }
+ }
+}
+#else
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.Networking;
+using Windows.Networking.Sockets;
+using Windows.Storage.Streams;
+
+namespace FlyingWormConsole3.LiteNetLib
+{
+ internal sealed class NetSocket
+ {
+ private DatagramSocket _datagramSocket;
+ private readonly Dictionary<NetEndPoint, IOutputStream> _peers = new Dictionary<NetEndPoint, IOutputStream>();
+ private readonly NetManager.OnMessageReceived _onMessageReceived;
+ private readonly byte[] _byteBuffer = new byte[NetConstants.PacketSizeLimit];
+ private readonly IBuffer _buffer;
+ private NetEndPoint _bufferEndPoint;
+ private NetEndPoint _localEndPoint;
+ private static readonly HostName BroadcastAddress = new HostName("255.255.255.255");
+ private static readonly HostName MulticastAddressV6 = new HostName(NetConstants.MulticastGroupIPv6);
+
+ public NetEndPoint LocalEndPoint
+ {
+ get { return _localEndPoint; }
+ }
+
+ public NetSocket(NetManager.OnMessageReceived onMessageReceived)
+ {
+ _onMessageReceived = onMessageReceived;
+ _buffer = _byteBuffer.AsBuffer();
+ }
+
+ private void OnMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
+ {
+ var result = args.GetDataStream().ReadAsync(_buffer, _buffer.Capacity, InputStreamOptions.None).AsTask().Result;
+ int length = (int)result.Length;
+ if (length <= 0)
+ return;
+
+ if (_bufferEndPoint == null ||
+ !_bufferEndPoint.HostName.IsEqual(args.RemoteAddress) ||
+ !_bufferEndPoint.PortStr.Equals(args.RemotePort))
+ {
+ _bufferEndPoint = new NetEndPoint(args.RemoteAddress, args.RemotePort);
+ }
+ _onMessageReceived(_byteBuffer, length, 0, _bufferEndPoint);
+ }
+
+ public bool Bind(int port, bool reuseAddress)
+ {
+ _datagramSocket = new DatagramSocket();
+ _datagramSocket.Control.InboundBufferSizeInBytes = NetConstants.SocketBufferSize;
+ _datagramSocket.Control.DontFragment = true;
+ _datagramSocket.Control.OutboundUnicastHopLimit = NetConstants.SocketTTL;
+ _datagramSocket.MessageReceived += OnMessageReceived;
+
+ try
+ {
+ _datagramSocket.BindServiceNameAsync(port.ToString()).AsTask().Wait();
+ _datagramSocket.JoinMulticastGroup(MulticastAddressV6);
+ _localEndPoint = new NetEndPoint(_datagramSocket.Information.LocalAddress, _datagramSocket.Information.LocalPort);
+ }
+ catch (Exception ex)
+ {
+ NetUtils.DebugWriteError("[B]Bind exception: {0}", ex.ToString());
+ return false;
+ }
+ return true;
+ }
+
+ public bool SendBroadcast(byte[] data, int offset, int size, int port)
+ {
+ var portString = port.ToString();
+ try
+ {
+ var outputStream =
+ _datagramSocket.GetOutputStreamAsync(BroadcastAddress, portString)
+ .AsTask()
+ .Result;
+ var writer = outputStream.AsStreamForWrite();
+ writer.Write(data, offset, size);
+ writer.Flush();
+
+ outputStream =
+ _datagramSocket.GetOutputStreamAsync(MulticastAddressV6, portString)
+ .AsTask()
+ .Result;
+ writer = outputStream.AsStreamForWrite();
+ writer.Write(data, offset, size);
+ writer.Flush();
+ }
+ catch (Exception ex)
+ {
+ NetUtils.DebugWriteError("[S][MCAST]" + ex);
+ return false;
+ }
+ return true;
+ }
+
+ public int SendTo(byte[] data, int offset, int length, NetEndPoint remoteEndPoint, ref int errorCode)
+ {
+ Task<uint> task = null;
+ try
+ {
+ IOutputStream writer;
+ if (!_peers.TryGetValue(remoteEndPoint, out writer))
+ {
+ writer =
+ _datagramSocket.GetOutputStreamAsync(remoteEndPoint.HostName, remoteEndPoint.PortStr)
+ .AsTask()
+ .Result;
+ _peers.Add(remoteEndPoint, writer);
+ }
+
+ task = writer.WriteAsync(data.AsBuffer(offset, length)).AsTask();
+ return (int)task.Result;
+ }
+ catch (Exception ex)
+ {
+ if (task?.Exception?.InnerExceptions != null)
+ {
+ ex = task.Exception.InnerException;
+ }
+ var errorStatus = SocketError.GetStatus(ex.HResult);
+ switch (errorStatus)
+ {
+ case SocketErrorStatus.MessageTooLong:
+ errorCode = 10040;
+ break;
+ default:
+ errorCode = (int)errorStatus;
+ NetUtils.DebugWriteError("[S " + errorStatus + "(" + errorCode + ")]" + ex);
+ break;
+ }
+
+ return -1;
+ }
+ }
+
+ internal void RemovePeer(NetEndPoint ep)
+ {
+ _peers.Remove(ep);
+ }
+
+ public void Close()
+ {
+ _datagramSocket.Dispose();
+ _datagramSocket = null;
+ ClearPeers();
+ }
+
+ internal void ClearPeers()
+ {
+ _peers.Clear();
+ }
+ }
+}
+#endif
+#endif