Files
Tor/TorWebClient/TorClient/Proxy/Proxy.cs
Sean Kessler eacf2d72f6 Refactor the TorWeblient. It was found to be not working at all.
1) Tor.exe was updated.
2) There were found to socket handling issues in the Proxy class which was causing connectiion to be dropped.
   Also found were issues with the retrieval of the client parameters.

In short it's been overhauled and found to be working much better than ever.
2024-03-07 18:53:11 -05:00

357 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;
using System.Net.NetworkInformation;
using MarketData;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace Tor.Proxy
{
/// <summary>
/// A class containing the logic for the hosted HTTP proxy, which listens for connections to delegate to the tor network.
/// </summary>
[DebuggerStepThrough]
public sealed class Proxy : MarshalByRefObject, IDisposable
{
private readonly Client client;
private readonly object synchronize;
private List<Connection> connections;
private volatile bool disposed;
private int port;
private List<ConnectionProcessor> processors;
private Socket socket;
private volatile bool suppressDispose;
private Socks5Proxy webProxy;
/// <summary>
/// Initializes a new instance of the <see cref="Proxy"/> class.
/// </summary>
/// <param name="client">The client for which this object instance belongs.</param>
internal Proxy(Client client)
{
this.client = client;
this.connections = new List<Connection>();
this.webProxy = null;
this.port = 8182;
this.processors = new List<ConnectionProcessor>();
this.socket = null;
this.suppressDispose = false;
this.synchronize = new object();
this.Start();
}
/// <summary>
/// Finalizes an instance of the <see cref="Proxy"/> class.
/// </summary>
~Proxy()
{
Dispose(false);
}
#region Properties
/// <summary>
/// Gets the address of the proxy which can be used for manually creating <see cref="WebProxy"/> objects.
/// </summary>
public string Address
{
get { return string.Format("http://127.0.0.1:{0}", port); }
}
/// <summary>
/// Gets a value indicating whether the proxy socket is bound to the listen port.
/// </summary>
public bool IsRunning
{
get { lock (synchronize) return socket != null && socket.IsBound; }
}
/// <summary>
/// Gets or sets the port number which the client will listen on for HTTP proxy connections. This value defaults to 8182, but can be
/// changed depending on firewall restrictions. The port number must be available in order to host the HTTP proxy.
/// </summary>
public int Port
{
get { return port; }
set
{
if (port != value)
{
port = value;
Shutdown();
Start();
}
}
}
/// <summary>
/// Gets an <see cref="IWebProxy"/> which can be used in HTTP requests. This will be <c>null</c> if the proxy could not be hosted
/// on the specified port number.
/// </summary>
public IWebProxy WebProxy
{
get
{
if (disposed)
throw new ObjectDisposedException("this");
lock (synchronize)
return webProxy;
}
}
#endregion
#region System.IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
private void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
lock (synchronize)
{
suppressDispose = true;
foreach (ConnectionProcessor processor in processors)
processor.Dispose();
foreach (Connection connection in connections)
connection.Dispose();
connections.Clear();
processors.Clear();
}
Shutdown();
disposed = true;
}
}
#endregion
#region Tor.Net.ForwardSocket
/// <summary>
/// Called when the internal listener socket accepts a TCP connection.
/// </summary>
/// <param name="ar">The asynchronous result object for this callback.</param>
//private void OnSocketAccept(IAsyncResult ar)
//{
// try
// {
// if (client != null)
// {
// MDTrace.WriteLine(LogLevel.DEBUG,String.Format("INFO Accepting incoming..."));
// Socket accepted = socket.EndAccept(ar);
// MDTrace.WriteLine(LogLevel.DEBUG,String.Format("INFO Accepted connection:{0}->{1}",accepted.LocalEndPoint,accepted.RemoteEndPoint));
// Connection connection = new Connection(client, accepted, OnConnectionDisposed);
// lock (synchronize)
// {
// connections.Add(connection);
// MDTrace.WriteLine(LogLevel.DEBUG,String.Format("There are {0} connections.",connections.Count));
// }
// ConnectionProcessor processor = new ConnectionProcessor(client, connection, OnConnectionProcessorDisposed);
// lock (synchronize)
// {
// processors.Add(processor);
// }
// processor.Start();
// }
// }
// catch(Exception exception)
// {
// MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
// }
// try
// {
// if (socket != null)
// socket.BeginAccept(OnSocketAccept, socket);
// }
// catch
// {
// }
//}
private void OnSocketAccept(IAsyncResult ar)
{
try
{
Socket accepted = null;
if (client != null)
{
Task workerTask= Task.Factory.StartNew( () =>
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("INFO Accepting incoming..."));
accepted = socket.EndAccept(ar);
if (socket != null)socket.BeginAccept(OnSocketAccept, socket);
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("INFO Accepted connection:{0}->{1}",accepted.LocalEndPoint,accepted.RemoteEndPoint));
});
workerTask.ContinueWith((continuation) =>
{
Connection connection = new Connection(client, accepted, OnConnectionDisposed);
lock (synchronize)
{
connections.Add(connection);
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("There are {0} connections.",connections.Count));
}
ConnectionProcessor processor = new ConnectionProcessor(client, connection, OnConnectionProcessorDisposed);
lock (synchronize)
{
processors.Add(processor);
}
processor.Start();
//try
//{
// if (socket != null)
// socket.BeginAccept(OnSocketAccept, socket);
//}
//catch
//{
//}
});
}
}
catch(Exception exception)
{
MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
}
}
#endregion
#region Tor.Proxy.Connection
/// <summary>
/// Called when a connection has been disposed.
/// </summary>
/// <param name="connection">The connection which was disposed.</param>
private void OnConnectionDisposed(Connection connection)
{
if (connection == null || suppressDispose)
{
return;
}
lock (synchronize)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Removing 1 connection {0}:{1}. There are {2} active connections.",connection.Host,connection.Port,connections.Count-1));
connections.Remove(connection);
}
}
#endregion
#region Tor.Proxy.ConnectionProcessor
/// <summary>
/// Called when a connection processor has been disposed.
/// </summary>
/// <param name="processor">The connection processor which was disposed.</param>
private void OnConnectionProcessorDisposed(ConnectionProcessor processor)
{
if (processor == null || suppressDispose)
return;
lock (synchronize)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Disposing connection processor. There are {0} connection processors remaining.",processors.Count));
processors.Remove(processor);
}
}
#endregion
/// <summary>
/// Starts the proxy by creating a TCP listener on the specified proxy port number.
/// </summary>
private void Start()
{
if (disposed)
throw new ObjectDisposedException("this");
lock (synchronize)
{
if (socket != null)
return;
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
socket.Listen(30); // 25
socket.BeginAccept(OnSocketAccept, socket);
webProxy = new Socks5Proxy(client);
}
catch(Exception exception)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Proxy: Exception:{0}",exception.ToString()));
if (socket != null)
{
socket.Dispose();
socket = null;
}
}
}
}
/// <summary>
/// Shuts down the TCP listener, releasing any resources associated with it.
/// </summary>
private void Shutdown()
{
lock (synchronize)
{
if (socket == null)
return;
try
{
socket.Shutdown(SocketShutdown.Both);
}
catch { }
socket.Dispose();
socket = null;
webProxy = null;
}
}
}
}