Init
This commit is contained in:
304
TorWebClient/TorClient/Controller/Connection/Connection.cs
Normal file
304
TorWebClient/TorClient/Controller/Connection/Connection.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.IO;
|
||||
|
||||
namespace Tor.Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// A class containing methods for interacting with a control connection for a tor application.
|
||||
/// </summary>
|
||||
internal sealed class Connection : IDisposable
|
||||
{
|
||||
private readonly static string EOL = "\r\n";
|
||||
private readonly Client client;
|
||||
|
||||
private volatile bool disposed;
|
||||
private StreamReader reader;
|
||||
private Socket socket;
|
||||
private NetworkStream stream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Connection"/> class.
|
||||
/// </summary>
|
||||
/// <param name="client">The client hosting the control connection.</param>
|
||||
public Connection(Client client)
|
||||
{
|
||||
this.client = client;
|
||||
this.disposed = false;
|
||||
this.reader = null;
|
||||
this.socket = null;
|
||||
this.stream = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="Connection"/> class.
|
||||
/// </summary>
|
||||
~Connection()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
if (reader != null)
|
||||
{
|
||||
reader.Dispose();
|
||||
reader = null;
|
||||
}
|
||||
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Dispose();
|
||||
stream = null;
|
||||
}
|
||||
|
||||
if (socket != null)
|
||||
{
|
||||
if (socket.Connected)
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
|
||||
socket.Dispose();
|
||||
socket = null;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates the connection by sending the password to the control port.
|
||||
/// </summary>
|
||||
/// <param name="password">The password used for authentication.</param>
|
||||
/// <returns><c>true</c> if the authentication succeeds; otherwise, <c>false</c>.</returns>
|
||||
public bool Authenticate(string password)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException("this");
|
||||
|
||||
if (password == null)
|
||||
password = "";
|
||||
|
||||
if (Write("authenticate \"{0}\"", password))
|
||||
{
|
||||
ConnectionResponse response = Read();
|
||||
|
||||
if (response.Success)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the control port hosted by the client.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the connection succeeds; otherwise, <c>false</c>.</returns>
|
||||
public bool Connect()
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException("this");
|
||||
|
||||
try
|
||||
{
|
||||
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
socket.Connect(client.GetClientAddress(), client.GetControlPort());
|
||||
|
||||
stream = new NetworkStream(socket, false);
|
||||
stream.ReadTimeout = 2000;
|
||||
|
||||
reader = new StreamReader(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (reader != null)
|
||||
{
|
||||
reader.Dispose();
|
||||
reader = null;
|
||||
}
|
||||
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Dispose();
|
||||
stream = null;
|
||||
}
|
||||
|
||||
if (socket != null)
|
||||
{
|
||||
if (socket.Connected)
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
|
||||
socket.Dispose();
|
||||
socket = null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a response buffer from the control connection. This method is blocking with a receive timeout of 500ms.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="ConnectionResponse"/> containing the response information.</returns>
|
||||
public ConnectionResponse Read()
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException("this");
|
||||
if (socket == null || stream == null || reader == null)
|
||||
return new ConnectionResponse(StatusCode.Unknown);
|
||||
|
||||
try
|
||||
{
|
||||
string line = reader.ReadLine();
|
||||
|
||||
if (line == null)
|
||||
return new ConnectionResponse(StatusCode.Unknown);
|
||||
|
||||
if (line.Length < 3)
|
||||
return new ConnectionResponse(StatusCode.Unknown);
|
||||
|
||||
int code;
|
||||
|
||||
if (!int.TryParse(line.Substring(0, 3), out code))
|
||||
return new ConnectionResponse(StatusCode.Unknown);
|
||||
|
||||
line = line.Substring(3);
|
||||
|
||||
if (line.Length == 0)
|
||||
return new ConnectionResponse((StatusCode)code, new List<string>() { "" });
|
||||
|
||||
if (line[0] != '+' && line[0] != '-')
|
||||
{
|
||||
if (line[0] == ' ')
|
||||
line = line.Substring(1);
|
||||
|
||||
return new ConnectionResponse((StatusCode)code, new List<string>() { line });
|
||||
}
|
||||
|
||||
char id = line[0];
|
||||
|
||||
List<string> responses = new List<string>();
|
||||
responses.Add(line.Substring(1));
|
||||
|
||||
try
|
||||
{
|
||||
for (line = reader.ReadLine(); line != null; line = reader.ReadLine())
|
||||
{
|
||||
string temp1 = line.Trim();
|
||||
string temp2 = temp1;
|
||||
|
||||
if (temp1.Length == 0)
|
||||
continue;
|
||||
if (id == '-' && temp2.Length > 3 && temp2[3] == ' ')
|
||||
break;
|
||||
|
||||
if (temp1.Length > 3 && id != '+')
|
||||
temp1 = temp1.Substring(4);
|
||||
|
||||
responses.Add(temp1);
|
||||
|
||||
if (id == '+' && ".".Equals(temp1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return new ConnectionResponse((StatusCode)code, responses);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ConnectionResponse(StatusCode.Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a command to the connection and flushes the buffer to the control port.
|
||||
/// </summary>
|
||||
/// <param name="command">The command to write to the connection.</param>
|
||||
/// <returns><c>true</c> if the command is dispatched successfully; otherwise, <c>false</c>.</returns>
|
||||
public bool Write(string command)
|
||||
{
|
||||
if (command == null)
|
||||
throw new ArgumentNullException("command");
|
||||
|
||||
if (!command.EndsWith(EOL))
|
||||
command += EOL;
|
||||
|
||||
return Write(Encoding.ASCII.GetBytes(command));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a command to the connection and flushes the buffer to the control port.
|
||||
/// </summary>
|
||||
/// <param name="command">The command to write to the connection.</param>
|
||||
/// <param name="parameters">An optional collection of parameters to serialize into the command.</param>
|
||||
/// <returns><c>true</c> if the command is dispatched successfully; otherwise, <c>false</c>.</returns>
|
||||
public bool Write(string command, params object[] parameters)
|
||||
{
|
||||
if (command == null)
|
||||
throw new ArgumentNullException("command");
|
||||
|
||||
command = string.Format(command, parameters);
|
||||
|
||||
if (!command.EndsWith(EOL))
|
||||
command += EOL;
|
||||
|
||||
return Write(Encoding.ASCII.GetBytes(command));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a command to the connection and flushes the buffer to the control port.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer containing the command data.</param>
|
||||
/// <returns><c>true</c> if the command is dispatched successfully; otherwise, <c>false</c>.</returns>
|
||||
public bool Write(byte[] buffer)
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException("this");
|
||||
if (buffer == null || buffer.Length == 0)
|
||||
throw new ArgumentNullException("buffer");
|
||||
if (socket == null || stream == null || reader == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
stream.Write(buffer, 0, buffer.Length);
|
||||
stream.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user