private async Task CopyToAsync(IProxyServerUdpAssociateHandler src, IProxyServerUdpAssociateHandler dst) { try { byte[] buffer = new byte[64 * 1024]; while (true) { UdpReceiveFromResult result = await src.ReceiveFromAsync(buffer, 0, buffer.Length); await dst.SendToAsync(buffer, 0, result.BytesReceived, result.RemoteEndPoint); } } finally { Dispose(); } }
public async Task <int> UdpQueryAsync(byte[] request, int requestOffset, int requestCount, byte[] response, int responseOffset, int responseCount, EndPoint remoteEP, int timeout = 10000, int retries = 1, bool expBackoffTimeout = false, CancellationToken cancellationToken = default) { Task <UdpReceiveFromResult> recvTask = null; int timeoutValue = timeout; int retry = 0; while (retry < retries) //retry loop { if (expBackoffTimeout) { timeoutValue = timeout * (2 ^ retry); } retry++; if (cancellationToken.IsCancellationRequested) { return(await Task.FromCanceled <int>(cancellationToken)); //task cancelled } //send request await SendToAsync(request, requestOffset, requestCount, remoteEP); while (true) { //receive request if (recvTask == null) { recvTask = ReceiveFromAsync(response, responseOffset, responseCount); } //receive with timeout using (CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource()) { using (CancellationTokenRegistration ctr = cancellationToken.Register(delegate() { timeoutCancellationTokenSource.Cancel(); })) { if (await Task.WhenAny(recvTask, Task.Delay(timeoutValue, timeoutCancellationTokenSource.Token)) != recvTask) { break; //recv timed out } } timeoutCancellationTokenSource.Cancel(); //to stop delay task } UdpReceiveFromResult result = await recvTask; if ((remoteEP is DomainEndPoint) || remoteEP.Equals(result.RemoteEndPoint)) //in case remoteEP is domain end point then returned response will contain the resolved IP address so cant compare it together { //got response return(result.BytesReceived); } //recv task is complete; set recvTask to null so that another task is used to read next response packet recvTask = null; } } _udpSocket.Dispose(); throw new SocketException((int)SocketError.TimedOut); }
public async Task <UdpReceiveFromResult> ReceiveFromAsync(byte[] buffer, int offset, int count) { byte[] datagram = new byte[262 + count]; UdpReceiveFromResult result = await _udpSocket.ReceiveFromAsync(datagram); if (result.BytesReceived < 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.BytesReceived - dataOffset; if (dataSize > count) { dataSize = count; } Buffer.BlockCopy(datagram, dataOffset, buffer, offset, dataSize); if (_relayEP == null) { _relayEP = result.RemoteEndPoint; //set new relay ep } return(new UdpReceiveFromResult(dataSize, remoteEP)); }