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
/// <value>The socket connection with the proxy server.</value>
protected Socket Server
{
get
{
return _server;
}
set
{
if (value == null)
throw new ArgumentNullException();
_server = value;
}
get => _server;
set => _server = value ?? throw new ArgumentNullException();
}
/// <summary>
......
......@@ -29,6 +29,7 @@
*/
using System;
using System.Buffers;
using System.Net.Sockets;
using System.Text;
......@@ -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.
/// </summary>
/// <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];
buffer[0] = 1;
buffer[1] = (byte)Username.Length;
Array.Copy(Encoding.ASCII.GetBytes(Username), 0, buffer, 2, Username.Length);
buffer[Username.Length + 2] = (byte)Password.Length;
Array.Copy(Encoding.ASCII.GetBytes(Password), 0, buffer, Username.Length + 3, Password.Length);
return buffer;
var span = buffer.Span;
span[0] = 1;
span[1] = (byte)Username.Length;
Encoding.ASCII.GetBytes(Username).CopyTo(span.Slice(2));
span[Username.Length + 2] = (byte)Password.Length;
Encoding.ASCII.GetBytes(Password).CopyTo(span.Slice(Username.Length + 3));
}
private int GetAuthenticationLength()
......@@ -77,19 +77,28 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// </summary>
public override void Authenticate()
{
if (Server.Send(GetAuthenticationBytes()) < GetAuthenticationLength())
int length = GetAuthenticationLength();
var buffer = ArrayPool<byte>.Shared.Rent(length);
try
{
throw new SocketException(10054);
GetAuthenticationBytes(buffer);
if (Server.Send(buffer, 0, length, SocketFlags.None) < length)
{
throw new SocketException(10054);
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
;
byte[] buffer = new byte[2];
int received = 0;
while (received != 2)
{
int recv = Server.Receive(buffer, received, 2 - received, SocketFlags.None);
if (recv == 0)
throw new SocketException(10054);
received += recv;
}
......@@ -98,8 +107,6 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
Server.Close();
throw new ProxyException("Username/password combination rejected.");
}
return;
}
/// <summary>
......@@ -108,10 +115,11 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <param name="callback">The method to call when the authentication is complete.</param>
public override void BeginAuthenticate(HandShakeComplete callback)
{
int length = GetAuthenticationLength();
Buffer = ArrayPool<byte>.Shared.Rent(length);
GetAuthenticationBytes(Buffer);
CallBack = callback;
Server.BeginSend(GetAuthenticationBytes(), 0, GetAuthenticationLength(), SocketFlags.None,
this.OnSent, Server);
return;
Server.BeginSend(Buffer, 0, length, SocketFlags.None, this.OnSent, Server);
}
/// <summary>
......@@ -124,12 +132,12 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
{
if (Server.EndSend(ar) < GetAuthenticationLength())
throw new SocketException(10054);
Buffer = new byte[2];
Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, this.OnReceive, Server);
}
catch (Exception e)
{
CallBack(e);
OnCallBack(e);
}
}
......@@ -144,22 +152,29 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
int recv = Server.EndReceive(ar);
if (recv <= 0)
throw new SocketException(10054);
Received += recv;
if (Received == Buffer.Length)
if (Received == 2)
if (Buffer[1] == 0)
CallBack(null);
OnCallBack(null);
else
throw new ProxyException("Username/password combination not accepted.");
else
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None,
Server.BeginReceive(Buffer, Received, 2 - Received, SocketFlags.None,
this.OnReceive, Server);
}
catch (Exception e)
{
CallBack(e);
OnCallBack(e);
}
}
private void OnCallBack(Exception? exception)
{
ArrayPool<byte>.Shared.Return(Buffer);
CallBack(exception);
}
/// <summary>
/// Gets or sets the username to use when authenticating with the proxy server.
/// </summary>
......@@ -167,14 +182,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
private string Username
{
get
{
return _username;
}
set
{
_username = value ?? throw new ArgumentNullException();
}
get => _username;
set => _username = value ?? throw new ArgumentNullException();
}
/// <summary>
......@@ -184,14 +193,8 @@ namespace Titanium.Web.Proxy.ProxySocket.Authentication
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
private string Password
{
get
{
return _password;
}
set
{
_password = value ?? throw new ArgumentNullException();
}
get => _password;
set => _password = value ?? throw new ArgumentNullException();
}
// private variables
......
......@@ -30,6 +30,7 @@
using System;
using System.Buffers;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
......@@ -68,8 +69,7 @@ namespace Titanium.Web.Proxy.ProxySocket
throw new ArgumentException(nameof(port));
int length = 10 + Username.Length + host.Length;
if (buffer.Length < length)
throw new ArgumentException(nameof(buffer));
Debug.Assert(buffer.Length >= length);
var connect = buffer.Span;
connect[0] = 4;
......@@ -80,8 +80,8 @@ namespace Titanium.Web.Proxy.ProxySocket
var userNameArray = Encoding.ASCII.GetBytes(Username);
userNameArray.CopyTo(connect.Slice(8));
connect[8 + Username.Length] = 0;
Encoding.ASCII.GetBytes(host).CopyTo(connect.Slice(9 + userNameArray.Length));
connect[9 + Username.Length + host.Length] = 0;
Encoding.ASCII.GetBytes(host).CopyTo(connect.Slice(9 + Username.Length));
connect[length - 1] = 0;
return length;
}
......@@ -98,8 +98,7 @@ namespace Titanium.Web.Proxy.ProxySocket
throw new ArgumentNullException(nameof(remoteEP));
int length = 9 + Username.Length;
if (buffer.Length < length)
throw new ArgumentException(nameof(buffer));
Debug.Assert(buffer.Length >= length);
var connect = buffer.Span;
connect[0] = 4;
......@@ -107,7 +106,7 @@ namespace Titanium.Web.Proxy.ProxySocket
PortToBytes(remoteEP.Port, connect.Slice(2));
remoteEP.Address.GetAddressBytes().CopyTo(connect.Slice(4));
Encoding.ASCII.GetBytes(Username).CopyTo(connect.Slice(8));
connect[8 + Username.Length] = 0;
connect[length - 1] = 0;
return length;
}
......@@ -123,7 +122,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
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
{
int length = GetHostPortBytes(host, port, buffer);
......@@ -145,7 +144,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public override void Negotiate(IPEndPoint remoteEP)
{
var buffer = ArrayPool<byte>.Shared.Rent(1024);
var buffer = ArrayPool<byte>.Shared.Rent(9 + Username.Length);
try
{
int length = GetEndPointBytes(remoteEP, buffer);
......@@ -199,7 +198,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state)
{
ProtocolComplete = callback;
Buffer = ArrayPool<byte>.Shared.Rent(1024);
Buffer = ArrayPool<byte>.Shared.Rent(10 + Username.Length + host.Length);
BufferCount = GetHostPortBytes(host, port, Buffer);
Server.BeginConnect(proxyEndPoint, OnConnect, Server);
AsyncResult = new IAsyncProxyResult(state);
......@@ -218,7 +217,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state)
{
ProtocolComplete = callback;
Buffer = ArrayPool<byte>.Shared.Rent(1024);
Buffer = ArrayPool<byte>.Shared.Rent(9 + Username.Length);
BufferCount = GetEndPointBytes(remoteEP, Buffer);
Server.BeginConnect(proxyEndPoint, OnConnect, Server);
AsyncResult = new IAsyncProxyResult(state);
......
......@@ -177,7 +177,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
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
{
Authenticate(buffer);
......@@ -202,7 +202,7 @@ namespace Titanium.Web.Proxy.ProxySocket
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
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
{
Authenticate(buffer);
......@@ -270,7 +270,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state)
{
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
_handShakeLength = GetHostPortBytes(host, port, Buffer.AsMemory(ConnectOffset));
......@@ -291,7 +291,7 @@ namespace Titanium.Web.Proxy.ProxySocket
IPEndPoint proxyEndPoint, object state)
{
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
_handShakeLength = GetEndPointBytes(remoteEP, Buffer.AsMemory(ConnectOffset));
......@@ -565,6 +565,6 @@ namespace Titanium.Web.Proxy.ProxySocket
// private variables
/// <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
private Socket _server;
/// <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>
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