| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- #if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA_8_1
- #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
|