Commit 654720fd authored by Honfika's avatar Honfika

smaller memor usage for socks connect

parent 6d0d8f6d
...@@ -74,16 +74,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -74,16 +74,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <value>The socket connection with the proxy server.</value> /// <value>The socket connection with the proxy server.</value>
protected Socket Server protected Socket Server
{ {
get get => _server;
{ set => _server = value ?? throw new ArgumentNullException();
return _server;
}
set
{
if (value == null)
throw new ArgumentNullException();
_server = value;
}
} }
/// <summary> /// <summary>
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
*/ */
using System; using System;
using System.Buffers;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
...@@ -56,15 +57,14 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -56,15 +57,14 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// Creates an array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme. /// Creates an array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.
/// </summary> /// </summary>
/// <returns>An array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.</returns> /// <returns>An array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.</returns>
private byte[] GetAuthenticationBytes() private void GetAuthenticationBytes(Memory<byte> buffer)
{ {
byte[] buffer = new byte[3 + Username.Length + Password.Length]; var span = buffer.Span;
buffer[0] = 1; span[0] = 1;
buffer[1] = (byte)Username.Length; span[1] = (byte)Username.Length;
Array.Copy(Encoding.ASCII.GetBytes(Username), 0, buffer, 2, Username.Length); Encoding.ASCII.GetBytes(Username).CopyTo(span.Slice(2));
buffer[Username.Length + 2] = (byte)Password.Length; span[Username.Length + 2] = (byte)Password.Length;
Array.Copy(Encoding.ASCII.GetBytes(Password), 0, buffer, Username.Length + 3, Password.Length); Encoding.ASCII.GetBytes(Password).CopyTo(span.Slice(Username.Length + 3));
return buffer;
} }
private int GetAuthenticationLength() private int GetAuthenticationLength()
...@@ -77,19 +77,28 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -77,19 +77,28 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// </summary> /// </summary>
public override void Authenticate() public override void Authenticate()
{ {
if (Server.Send(GetAuthenticationBytes()) < GetAuthenticationLength()) int length = GetAuthenticationLength();
var buffer = ArrayPool<byte>.Shared.Rent(length);
try
{
GetAuthenticationBytes(buffer);
if (Server.Send(buffer, 0, length, SocketFlags.None) < length)
{ {
throw new SocketException(10054); throw new SocketException(10054);
} }
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
;
byte[] buffer = new byte[2];
int received = 0; int received = 0;
while (received != 2) while (received != 2)
{ {
int recv = Server.Receive(buffer, received, 2 - received, SocketFlags.None); int recv = Server.Receive(buffer, received, 2 - received, SocketFlags.None);
if (recv == 0) if (recv == 0)
throw new SocketException(10054); throw new SocketException(10054);
received += recv; received += recv;
} }
...@@ -98,8 +107,6 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -98,8 +107,6 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
Server.Close(); Server.Close();
throw new ProxyException("Username/password combination rejected."); throw new ProxyException("Username/password combination rejected.");
} }
return;
} }
/// <summary> /// <summary>
...@@ -108,10 +115,11 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -108,10 +115,11 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <param name="callback">The method to call when the authentication is complete.</param> /// <param name="callback">The method to call when the authentication is complete.</param>
public override void BeginAuthenticate(HandShakeComplete callback) public override void BeginAuthenticate(HandShakeComplete callback)
{ {
int length = GetAuthenticationLength();
Buffer = ArrayPool<byte>.Shared.Rent(length);
GetAuthenticationBytes(Buffer);
CallBack = callback; CallBack = callback;
Server.BeginSend(GetAuthenticationBytes(), 0, GetAuthenticationLength(), SocketFlags.None, Server.BeginSend(Buffer, 0, length, SocketFlags.None, this.OnSent, Server);
this.OnSent, Server);
return;
} }
/// <summary> /// <summary>
...@@ -124,12 +132,12 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -124,12 +132,12 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
{ {
if (Server.EndSend(ar) < GetAuthenticationLength()) if (Server.EndSend(ar) < GetAuthenticationLength())
throw new SocketException(10054); throw new SocketException(10054);
Buffer = new byte[2];
Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, this.OnReceive, Server); Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, this.OnReceive, Server);
} }
catch (Exception e) catch (Exception e)
{ {
CallBack(e); OnCallBack(e);
} }
} }
...@@ -144,20 +152,27 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -144,20 +152,27 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
int recv = Server.EndReceive(ar); int recv = Server.EndReceive(ar);
if (recv <= 0) if (recv <= 0)
throw new SocketException(10054); throw new SocketException(10054);
Received += recv; Received += recv;
if (Received == Buffer.Length) if (Received == 2)
if (Buffer[1] == 0) if (Buffer[1] == 0)
CallBack(null); OnCallBack(null);
else else
throw new ProxyException("Username/password combination not accepted."); throw new ProxyException("Username/password combination not accepted.");
else else
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, Server.BeginReceive(Buffer, Received, 2 - Received, SocketFlags.None,
this.OnReceive, Server); this.OnReceive, Server);
} }
catch (Exception e) catch (Exception e)
{ {
CallBack(e); OnCallBack(e);
}
} }
private void OnCallBack(Exception? exception)
{
ArrayPool<byte>.Shared.Return(Buffer);
CallBack(exception);
} }
/// <summary> /// <summary>
...@@ -167,14 +182,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -167,14 +182,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <exception cref="ArgumentNullException">The specified value is null.</exception> /// <exception cref="ArgumentNullException">The specified value is null.</exception>
private string Username private string Username
{ {
get get => _username;
{ set => _username = value ?? throw new ArgumentNullException();
return _username;
}
set
{
_username = value ?? throw new ArgumentNullException();
}
} }
/// <summary> /// <summary>
...@@ -184,14 +193,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication ...@@ -184,14 +193,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <exception cref="ArgumentNullException">The specified value is null.</exception> /// <exception cref="ArgumentNullException">The specified value is null.</exception>
private string Password private string Password
{ {
get get => _password;
{ set => _password = value ?? throw new ArgumentNullException();
return _password;
}
set
{
_password = value ?? throw new ArgumentNullException();
}
} }
// private variables // private variables
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
...@@ -68,8 +69,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -68,8 +69,7 @@ namespace Titanium.Web.Proxy.ProxySocket
throw new ArgumentException(nameof(port)); throw new ArgumentException(nameof(port));
int length = 10 + Username.Length + host.Length; int length = 10 + Username.Length + host.Length;
if (buffer.Length < length) Debug.Assert(buffer.Length >= length);
throw new ArgumentException(nameof(buffer));
var connect = buffer.Span; var connect = buffer.Span;
connect[0] = 4; connect[0] = 4;
...@@ -80,8 +80,8 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -80,8 +80,8 @@ namespace Titanium.Web.Proxy.ProxySocket
var userNameArray = Encoding.ASCII.GetBytes(Username); var userNameArray = Encoding.ASCII.GetBytes(Username);
userNameArray.CopyTo(connect.Slice(8)); userNameArray.CopyTo(connect.Slice(8));
connect[8 + Username.Length] = 0; connect[8 + Username.Length] = 0;
Encoding.ASCII.GetBytes(host).CopyTo(connect.Slice(9 + userNameArray.Length)); Encoding.ASCII.GetBytes(host).CopyTo(connect.Slice(9 + Username.Length));
connect[9 + Username.Length + host.Length] = 0; connect[length - 1] = 0;
return length; return length;
} }
...@@ -98,8 +98,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -98,8 +98,7 @@ namespace Titanium.Web.Proxy.ProxySocket
throw new ArgumentNullException(nameof(remoteEP)); throw new ArgumentNullException(nameof(remoteEP));
int length = 9 + Username.Length; int length = 9 + Username.Length;
if (buffer.Length < length) Debug.Assert(buffer.Length >= length);
throw new ArgumentException(nameof(buffer));
var connect = buffer.Span; var connect = buffer.Span;
connect[0] = 4; connect[0] = 4;
...@@ -107,7 +106,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -107,7 +106,7 @@ namespace Titanium.Web.Proxy.ProxySocket
PortToBytes(remoteEP.Port, connect.Slice(2)); PortToBytes(remoteEP.Port, connect.Slice(2));
remoteEP.Address.GetAddressBytes().CopyTo(connect.Slice(4)); remoteEP.Address.GetAddressBytes().CopyTo(connect.Slice(4));
Encoding.ASCII.GetBytes(Username).CopyTo(connect.Slice(8)); Encoding.ASCII.GetBytes(Username).CopyTo(connect.Slice(8));
connect[8 + Username.Length] = 0; connect[length - 1] = 0;
return length; return length;
} }
...@@ -123,7 +122,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -123,7 +122,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception> /// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public override void Negotiate(string host, int port) public override void Negotiate(string host, int port)
{ {
var buffer = ArrayPool<byte>.Shared.Rent(1024); var buffer = ArrayPool<byte>.Shared.Rent(10 + Username.Length + host.Length);
try try
{ {
int length = GetHostPortBytes(host, port, buffer); int length = GetHostPortBytes(host, port, buffer);
...@@ -145,7 +144,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -145,7 +144,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception> /// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public override void Negotiate(IPEndPoint remoteEP) public override void Negotiate(IPEndPoint remoteEP)
{ {
var buffer = ArrayPool<byte>.Shared.Rent(1024); var buffer = ArrayPool<byte>.Shared.Rent(9 + Username.Length);
try try
{ {
int length = GetEndPointBytes(remoteEP, buffer); int length = GetEndPointBytes(remoteEP, buffer);
...@@ -199,7 +198,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -199,7 +198,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state) IPEndPoint proxyEndPoint, object state)
{ {
ProtocolComplete = callback; ProtocolComplete = callback;
Buffer = ArrayPool<byte>.Shared.Rent(1024); Buffer = ArrayPool<byte>.Shared.Rent(10 + Username.Length + host.Length);
BufferCount = GetHostPortBytes(host, port, Buffer); BufferCount = GetHostPortBytes(host, port, Buffer);
Server.BeginConnect(proxyEndPoint, OnConnect, Server); Server.BeginConnect(proxyEndPoint, OnConnect, Server);
AsyncResult = new IAsyncProxyResult(state); AsyncResult = new IAsyncProxyResult(state);
...@@ -218,7 +217,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -218,7 +217,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state) IPEndPoint proxyEndPoint, object state)
{ {
ProtocolComplete = callback; ProtocolComplete = callback;
Buffer = ArrayPool<byte>.Shared.Rent(1024); Buffer = ArrayPool<byte>.Shared.Rent(9 + Username.Length);
BufferCount = GetEndPointBytes(remoteEP, Buffer); BufferCount = GetEndPointBytes(remoteEP, Buffer);
Server.BeginConnect(proxyEndPoint, OnConnect, Server); Server.BeginConnect(proxyEndPoint, OnConnect, Server);
AsyncResult = new IAsyncProxyResult(state); AsyncResult = new IAsyncProxyResult(state);
......
...@@ -177,7 +177,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -177,7 +177,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception> /// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
public override void Negotiate(string host, int port) public override void Negotiate(string host, int port)
{ {
var buffer = ArrayPool<byte>.Shared.Rent(1024); var buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 10 + host.Length + Username.Length + Password.Length));
try try
{ {
Authenticate(buffer); Authenticate(buffer);
...@@ -202,7 +202,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -202,7 +202,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception> /// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
public override void Negotiate(IPEndPoint remoteEP) public override void Negotiate(IPEndPoint remoteEP)
{ {
var buffer = ArrayPool<byte>.Shared.Rent(1024); var buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 13 + Username.Length + Password.Length));
try try
{ {
Authenticate(buffer); Authenticate(buffer);
...@@ -270,7 +270,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -270,7 +270,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state) IPEndPoint proxyEndPoint, object state)
{ {
ProtocolComplete = callback; ProtocolComplete = callback;
Buffer = ArrayPool<byte>.Shared.Rent(1024); Buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 10 + host.Length + Username.Length + Password.Length));
// first {ConnectOffset} bytes are reserved for authentication // first {ConnectOffset} bytes are reserved for authentication
_handShakeLength = GetHostPortBytes(host, port, Buffer.AsMemory(ConnectOffset)); _handShakeLength = GetHostPortBytes(host, port, Buffer.AsMemory(ConnectOffset));
...@@ -291,7 +291,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -291,7 +291,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state) IPEndPoint proxyEndPoint, object state)
{ {
ProtocolComplete = callback; ProtocolComplete = callback;
Buffer = ArrayPool<byte>.Shared.Rent(1024); Buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 13 + Username.Length + Password.Length));
// first {ConnectOffset} bytes are reserved for authentication // first {ConnectOffset} bytes are reserved for authentication
_handShakeLength = GetEndPointBytes(remoteEP, Buffer.AsMemory(ConnectOffset)); _handShakeLength = GetEndPointBytes(remoteEP, Buffer.AsMemory(ConnectOffset));
...@@ -565,6 +565,6 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -565,6 +565,6 @@ namespace Titanium.Web.Proxy.ProxySocket
// private variables // private variables
/// <summary>Holds the value of the Password property.</summary> /// <summary>Holds the value of the Password property.</summary>
private string _password; private string _password = string.Empty;
} }
} }
...@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.ProxySocket ...@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.ProxySocket
private Socket _server; private Socket _server;
/// <summary>Holds the value of the Username property.</summary> /// <summary>Holds the value of the Username property.</summary>
private string _username; private string _username = string.Empty;
/// <summary>Holds the address of the method to call when the SOCKS protocol has been completed.</summary> /// <summary>Holds the address of the method to call when the SOCKS protocol has been completed.</summary>
protected HandShakeComplete ProtocolComplete; protected HandShakeComplete ProtocolComplete;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment