Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Commit 654720f

Browse files
committed
smaller memor usage for socks connect
1 parent 6d0d8f6 commit 654720f

File tree

5 files changed

+60
-66
lines changed

5 files changed

+60
-66
lines changed

src/Titanium.Web.Proxy/ProxySocket/Authentication/AuthMethod.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,8 @@ public AuthMethod(Socket server)
7474
/// <value>The socket connection with the proxy server.</value>
7575
protected Socket Server
7676
{
77-
get
78-
{
79-
return _server;
80-
}
81-
set
82-
{
83-
if (value == null)
84-
throw new ArgumentNullException();
85-
_server = value;
86-
}
77+
get => _server;
78+
set => _server = value ?? throw new ArgumentNullException();
8779
}
8880

8981
/// <summary>

src/Titanium.Web.Proxy/ProxySocket/Authentication/AuthUserPass.cs

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
2929
*/
3030

3131
using System;
32+
using System.Buffers;
3233
using System.Net.Sockets;
3334
using System.Text;
3435

@@ -56,15 +57,14 @@ public AuthUserPass(Socket server, string user, string pass) : base(server)
5657
/// Creates an array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.
5758
/// </summary>
5859
/// <returns>An array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.</returns>
59-
private byte[] GetAuthenticationBytes()
60+
private void GetAuthenticationBytes(Memory<byte> buffer)
6061
{
61-
byte[] buffer = new byte[3 + Username.Length + Password.Length];
62-
buffer[0] = 1;
63-
buffer[1] = (byte)Username.Length;
64-
Array.Copy(Encoding.ASCII.GetBytes(Username), 0, buffer, 2, Username.Length);
65-
buffer[Username.Length + 2] = (byte)Password.Length;
66-
Array.Copy(Encoding.ASCII.GetBytes(Password), 0, buffer, Username.Length + 3, Password.Length);
67-
return buffer;
62+
var span = buffer.Span;
63+
span[0] = 1;
64+
span[1] = (byte)Username.Length;
65+
Encoding.ASCII.GetBytes(Username).CopyTo(span.Slice(2));
66+
span[Username.Length + 2] = (byte)Password.Length;
67+
Encoding.ASCII.GetBytes(Password).CopyTo(span.Slice(Username.Length + 3));
6868
}
6969

7070
private int GetAuthenticationLength()
@@ -77,19 +77,28 @@ private int GetAuthenticationLength()
7777
/// </summary>
7878
public override void Authenticate()
7979
{
80-
if (Server.Send(GetAuthenticationBytes()) < GetAuthenticationLength())
80+
int length = GetAuthenticationLength();
81+
var buffer = ArrayPool<byte>.Shared.Rent(length);
82+
try
8183
{
82-
throw new SocketException(10054);
84+
GetAuthenticationBytes(buffer);
85+
if (Server.Send(buffer, 0, length, SocketFlags.None) < length)
86+
{
87+
throw new SocketException(10054);
88+
}
89+
}
90+
finally
91+
{
92+
ArrayPool<byte>.Shared.Return(buffer);
8393
}
8494

85-
;
86-
byte[] buffer = new byte[2];
8795
int received = 0;
8896
while (received != 2)
8997
{
9098
int recv = Server.Receive(buffer, received, 2 - received, SocketFlags.None);
9199
if (recv == 0)
92100
throw new SocketException(10054);
101+
93102
received += recv;
94103
}
95104

@@ -98,8 +107,6 @@ public override void Authenticate()
98107
Server.Close();
99108
throw new ProxyException("Username/password combination rejected.");
100109
}
101-
102-
return;
103110
}
104111

105112
/// <summary>
@@ -108,10 +115,11 @@ public override void Authenticate()
108115
/// <param name="callback">The method to call when the authentication is complete.</param>
109116
public override void BeginAuthenticate(HandShakeComplete callback)
110117
{
118+
int length = GetAuthenticationLength();
119+
Buffer = ArrayPool<byte>.Shared.Rent(length);
120+
GetAuthenticationBytes(Buffer);
111121
CallBack = callback;
112-
Server.BeginSend(GetAuthenticationBytes(), 0, GetAuthenticationLength(), SocketFlags.None,
113-
this.OnSent, Server);
114-
return;
122+
Server.BeginSend(Buffer, 0, length, SocketFlags.None, this.OnSent, Server);
115123
}
116124

117125
/// <summary>
@@ -124,12 +132,12 @@ private void OnSent(IAsyncResult ar)
124132
{
125133
if (Server.EndSend(ar) < GetAuthenticationLength())
126134
throw new SocketException(10054);
127-
Buffer = new byte[2];
135+
128136
Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, this.OnReceive, Server);
129137
}
130138
catch (Exception e)
131139
{
132-
CallBack(e);
140+
OnCallBack(e);
133141
}
134142
}
135143

@@ -144,37 +152,38 @@ private void OnReceive(IAsyncResult ar)
144152
int recv = Server.EndReceive(ar);
145153
if (recv <= 0)
146154
throw new SocketException(10054);
155+
147156
Received += recv;
148-
if (Received == Buffer.Length)
157+
if (Received == 2)
149158
if (Buffer[1] == 0)
150-
CallBack(null);
159+
OnCallBack(null);
151160
else
152161
throw new ProxyException("Username/password combination not accepted.");
153162
else
154-
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None,
163+
Server.BeginReceive(Buffer, Received, 2 - Received, SocketFlags.None,
155164
this.OnReceive, Server);
156165
}
157166
catch (Exception e)
158167
{
159-
CallBack(e);
168+
OnCallBack(e);
160169
}
161170
}
162171

172+
private void OnCallBack(Exception? exception)
173+
{
174+
ArrayPool<byte>.Shared.Return(Buffer);
175+
CallBack(exception);
176+
}
177+
163178
/// <summary>
164179
/// Gets or sets the username to use when authenticating with the proxy server.
165180
/// </summary>
166181
/// <value>The username to use when authenticating with the proxy server.</value>
167182
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
168183
private string Username
169184
{
170-
get
171-
{
172-
return _username;
173-
}
174-
set
175-
{
176-
_username = value ?? throw new ArgumentNullException();
177-
}
185+
get => _username;
186+
set => _username = value ?? throw new ArgumentNullException();
178187
}
179188

180189
/// <summary>
@@ -184,14 +193,8 @@ private string Username
184193
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
185194
private string Password
186195
{
187-
get
188-
{
189-
return _password;
190-
}
191-
set
192-
{
193-
_password = value ?? throw new ArgumentNullException();
194-
}
196+
get => _password;
197+
set => _password = value ?? throw new ArgumentNullException();
195198
}
196199

197200
// private variables

src/Titanium.Web.Proxy/ProxySocket/Socks4Handler.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
3030

3131
using System;
3232
using System.Buffers;
33+
using System.Diagnostics;
3334
using System.Net;
3435
using System.Net.Sockets;
3536
using System.Text;
@@ -68,8 +69,7 @@ private int GetHostPortBytes(string host, int port, Memory<byte> buffer)
6869
throw new ArgumentException(nameof(port));
6970

7071
int length = 10 + Username.Length + host.Length;
71-
if (buffer.Length < length)
72-
throw new ArgumentException(nameof(buffer));
72+
Debug.Assert(buffer.Length >= length);
7373

7474
var connect = buffer.Span;
7575
connect[0] = 4;
@@ -80,8 +80,8 @@ private int GetHostPortBytes(string host, int port, Memory<byte> buffer)
8080
var userNameArray = Encoding.ASCII.GetBytes(Username);
8181
userNameArray.CopyTo(connect.Slice(8));
8282
connect[8 + Username.Length] = 0;
83-
Encoding.ASCII.GetBytes(host).CopyTo(connect.Slice(9 + userNameArray.Length));
84-
connect[9 + Username.Length + host.Length] = 0;
83+
Encoding.ASCII.GetBytes(host).CopyTo(connect.Slice(9 + Username.Length));
84+
connect[length - 1] = 0;
8585
return length;
8686
}
8787

@@ -98,16 +98,15 @@ private int GetEndPointBytes(IPEndPoint remoteEP, Memory<byte> buffer)
9898
throw new ArgumentNullException(nameof(remoteEP));
9999

100100
int length = 9 + Username.Length;
101-
if (buffer.Length < length)
102-
throw new ArgumentException(nameof(buffer));
101+
Debug.Assert(buffer.Length >= length);
103102

104103
var connect = buffer.Span;
105104
connect[0] = 4;
106105
connect[1] = 1;
107106
PortToBytes(remoteEP.Port, connect.Slice(2));
108107
remoteEP.Address.GetAddressBytes().CopyTo(connect.Slice(4));
109108
Encoding.ASCII.GetBytes(Username).CopyTo(connect.Slice(8));
110-
connect[8 + Username.Length] = 0;
109+
connect[length - 1] = 0;
111110
return length;
112111
}
113112

@@ -123,7 +122,7 @@ private int GetEndPointBytes(IPEndPoint remoteEP, Memory<byte> buffer)
123122
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
124123
public override void Negotiate(string host, int port)
125124
{
126-
var buffer = ArrayPool<byte>.Shared.Rent(1024);
125+
var buffer = ArrayPool<byte>.Shared.Rent(10 + Username.Length + host.Length);
127126
try
128127
{
129128
int length = GetHostPortBytes(host, port, buffer);
@@ -145,7 +144,7 @@ public override void Negotiate(string host, int port)
145144
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
146145
public override void Negotiate(IPEndPoint remoteEP)
147146
{
148-
var buffer = ArrayPool<byte>.Shared.Rent(1024);
147+
var buffer = ArrayPool<byte>.Shared.Rent(9 + Username.Length);
149148
try
150149
{
151150
int length = GetEndPointBytes(remoteEP, buffer);
@@ -199,7 +198,7 @@ public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShak
199198
IPEndPoint proxyEndPoint, object state)
200199
{
201200
ProtocolComplete = callback;
202-
Buffer = ArrayPool<byte>.Shared.Rent(1024);
201+
Buffer = ArrayPool<byte>.Shared.Rent(10 + Username.Length + host.Length);
203202
BufferCount = GetHostPortBytes(host, port, Buffer);
204203
Server.BeginConnect(proxyEndPoint, OnConnect, Server);
205204
AsyncResult = new IAsyncProxyResult(state);
@@ -218,7 +217,7 @@ public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeC
218217
IPEndPoint proxyEndPoint, object state)
219218
{
220219
ProtocolComplete = callback;
221-
Buffer = ArrayPool<byte>.Shared.Rent(1024);
220+
Buffer = ArrayPool<byte>.Shared.Rent(9 + Username.Length);
222221
BufferCount = GetEndPointBytes(remoteEP, Buffer);
223222
Server.BeginConnect(proxyEndPoint, OnConnect, Server);
224223
AsyncResult = new IAsyncProxyResult(state);

src/Titanium.Web.Proxy/ProxySocket/Socks5Handler.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ private int GetEndPointBytes(IPEndPoint remoteEP, Memory<byte> buffer)
177177
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
178178
public override void Negotiate(string host, int port)
179179
{
180-
var buffer = ArrayPool<byte>.Shared.Rent(1024);
180+
var buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 10 + host.Length + Username.Length + Password.Length));
181181
try
182182
{
183183
Authenticate(buffer);
@@ -202,7 +202,7 @@ public override void Negotiate(string host, int port)
202202
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
203203
public override void Negotiate(IPEndPoint remoteEP)
204204
{
205-
var buffer = ArrayPool<byte>.Shared.Rent(1024);
205+
var buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 13 + Username.Length + Password.Length));
206206
try
207207
{
208208
Authenticate(buffer);
@@ -270,7 +270,7 @@ public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShak
270270
IPEndPoint proxyEndPoint, object state)
271271
{
272272
ProtocolComplete = callback;
273-
Buffer = ArrayPool<byte>.Shared.Rent(1024);
273+
Buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 10 + host.Length + Username.Length + Password.Length));
274274

275275
// first {ConnectOffset} bytes are reserved for authentication
276276
_handShakeLength = GetHostPortBytes(host, port, Buffer.AsMemory(ConnectOffset));
@@ -291,7 +291,7 @@ public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeC
291291
IPEndPoint proxyEndPoint, object state)
292292
{
293293
ProtocolComplete = callback;
294-
Buffer = ArrayPool<byte>.Shared.Rent(1024);
294+
Buffer = ArrayPool<byte>.Shared.Rent(Math.Max(258, 13 + Username.Length + Password.Length));
295295

296296
// first {ConnectOffset} bytes are reserved for authentication
297297
_handShakeLength = GetEndPointBytes(remoteEP, Buffer.AsMemory(ConnectOffset));
@@ -565,6 +565,6 @@ private string Password
565565

566566
// private variables
567567
/// <summary>Holds the value of the Password property.</summary>
568-
private string _password;
568+
private string _password = string.Empty;
569569
}
570570
}

src/Titanium.Web.Proxy/ProxySocket/SocksHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ protected string Username
197197
private Socket _server;
198198

199199
/// <summary>Holds the value of the Username property.</summary>
200-
private string _username;
200+
private string _username = string.Empty;
201201

202202
/// <summary>Holds the address of the method to call when the SOCKS protocol has been completed.</summary>
203203
protected HandShakeComplete ProtocolComplete;

0 commit comments

Comments
 (0)