public Task <SocketReceiveFromResult> ReceiveFromAsync(ArraySegment <byte> buffer)
 {
     return(_socket.ReceiveFromAsync(buffer, SocketFlags.None, SocketExtension.GetEndPointAnyFor(_socket.AddressFamily)));
 }
        public async Task <SocketReceiveFromResult> ReceiveFromAsync(ArraySegment <byte> buffer)
        {
            byte[] datagram = new byte[262 + buffer.Count];

            SocketReceiveFromResult result = await _udpSocket.ReceiveFromAsync(datagram, SocketFlags.None, SocketExtension.GetEndPointAnyFor(_udpSocket.AddressFamily));

            if (result.ReceivedBytes < 10)
            {
                throw new SocksProxyException("Incomplete SOCKS5 datagram was received.");
            }

            EndPoint remoteEP;

            switch ((SocksAddressType)datagram[3])
            {
            case SocksAddressType.IPv4Address:
            {
                byte[] address = new byte[4];
                Buffer.BlockCopy(datagram, 3 + 1, address, 0, 4);

                byte[] port = new byte[2];
                Buffer.BlockCopy(datagram, 3 + 1 + 4, port, 0, 2);
                Array.Reverse(port);

                remoteEP = new IPEndPoint(new IPAddress(address), BitConverter.ToUInt16(port, 0));
            }
            break;

            case SocksAddressType.IPv6Address:
            {
                byte[] address = new byte[16];
                Buffer.BlockCopy(datagram, 3 + 1, address, 0, 16);

                byte[] port = new byte[2];
                Buffer.BlockCopy(datagram, 3 + 1 + 16, port, 0, 2);
                Array.Reverse(port);

                remoteEP = new IPEndPoint(new IPAddress(address), BitConverter.ToUInt16(port, 0));
            }
            break;

            case SocksAddressType.DomainName:
            {
                int length = datagram[3 + 1];

                byte[] address = new byte[length];
                Buffer.BlockCopy(datagram, 3 + 1 + 1, address, 0, length);

                byte[] port = new byte[2];
                Buffer.BlockCopy(datagram, 3 + 1 + 1 + length, port, 0, 2);
                Array.Reverse(port);

                remoteEP = new DomainEndPoint(Encoding.ASCII.GetString(address), BitConverter.ToUInt16(port, 0));
            }
            break;

            default:
                throw new NotSupportedException("SocksAddressType not supported.");
            }

            int addressSize;

            switch (remoteEP.AddressFamily)
            {
            case AddressFamily.InterNetwork:
                addressSize = 4;
                break;

            case AddressFamily.InterNetworkV6:
                addressSize = 16;
                break;

            case AddressFamily.Unspecified:
                addressSize = 1 + (remoteEP as DomainEndPoint).Address.Length;
                break;

            default:
                throw new NotSupportedException("AddressFamily not supported.");
            }

            int dataOffset = 6 + addressSize;
            int dataSize   = result.ReceivedBytes - dataOffset;

            if (dataSize > buffer.Count)
            {
                dataSize = buffer.Count;
            }

            ArraySegment <byte> recvData = new ArraySegment <byte>(datagram, dataOffset, dataSize);

            recvData.CopyTo(buffer);

            if (_relayEP == null)
            {
                _relayEP = result.RemoteEndPoint; //set new relay ep
            }
            return(new SocketReceiveFromResult()
            {
                ReceivedBytes = dataSize, RemoteEndPoint = remoteEP
            });
        }