using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Tor.Config;
using Tor.Helpers;
namespace Tor
{
///
/// A class containing the configurations needed when launching a tor application executable.
///
[DebuggerStepThrough]
[Serializable]
public sealed class ClientCreateParams
{
private string defaultConfigurationFile;
private string configurationFile;
private string controlPassword;
private int controlPort;
private Dictionary overrides;
private string path;
///
/// Initializes a new instance of the class.
///
public ClientCreateParams() : this(null, 9051, "", null)
{
}
///
/// Initializes a new instance of the class.
///
/// The path to the application executable file.
public ClientCreateParams(string path) : this(path, 9051, "", null)
{
}
///
/// Initializes a new instance of the class.
///
/// The path to the application executable file.
/// The path to the configuration file.
public ClientCreateParams(string path, string configurationFile) : this(path, 9051, "", configurationFile)
{
}
///
/// Initializes a new instance of the class.
///
/// The path to the application executable file.
/// The port number which the application will listening on for control connections.
public ClientCreateParams(string path, int controlPort) : this(path, controlPort, "", null)
{
}
///
/// Initializes a new instance of the class.
///
/// The path to the application executable file.
/// The port number which the application will listening on for control connections.
/// The password used when authenticating with the control connection.
public ClientCreateParams(string path, int controlPort, string controlPassword) : this(path, controlPort, controlPassword, null)
{
}
///
/// Initializes a new instance of the class.
///
/// The path to the application executable file.
/// The port number which the application will listening on for control connections.
/// The password used when authenticating with the control connection.
/// The path to the configuration file.
public ClientCreateParams(string path, int controlPort, string controlPassword, string configurationFile)
{
this.configurationFile = configurationFile;
this.controlPassword = controlPassword;
this.controlPort = controlPort;
this.defaultConfigurationFile = null;
this.overrides = new Dictionary();
this.path = path;
}
#region Properties
///
/// Gets or sets the path to the configuration file containing the default values. A value of null
/// indicates that no default configuration file will be loaded.
///
public string DefaultConfigurationFile
{
get { return defaultConfigurationFile; }
set { defaultConfigurationFile = value; }
}
///
/// Gets or sets the path to the configuration file. A value of null indicates that no
/// configuration file will be loaded.
///
public string ConfigurationFile
{
get { return configurationFile; }
set { configurationFile = value; }
}
///
/// Gets or sets the password used when authenticating with the tor application on the control connection. A value of
/// null or blank indicates that no password has been configured.
///
public string ControlPassword
{
get { return controlPassword; }
set { controlPassword = value; }
}
///
/// Gets or sets the port number which the application will be listening on for control connections.
///
public int ControlPort
{
get { return controlPort; }
set { controlPort = value; }
}
///
/// Gets or sets the path to the application executable file.
///
public string Path
{
get { return path; }
set { path = value; }
}
#endregion
#region System.Object
///
/// Determines whether the specified , is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object obj)
{
ClientCreateParams compare = obj as ClientCreateParams;
if (compare == null)
return false;
return compare.configurationFile == configurationFile &&
compare.controlPassword == controlPassword &&
compare.controlPort == controlPort &&
compare.defaultConfigurationFile == defaultConfigurationFile &&
compare.path == path;
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + (defaultConfigurationFile != null ? defaultConfigurationFile.GetHashCode() : 0);
hash = hash * 23 + (configurationFile != null ? configurationFile.GetHashCode() : 0);
hash = hash * 23 + (controlPassword != null ? controlPassword.GetHashCode() : 0);
hash = hash * 23 + (controlPort);
hash = hash * 23 + (path != null ? path.GetHashCode() : 0);
return hash;
}
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
StringBuilder builder;
builder = new StringBuilder();
builder.Append("--ignore-missing-torrc ");
builder.Append("--allow-missing-torrc ");
builder.AppendFormat("--ControlPort {0}", controlPort);
/** TEMPORARY: DELETE LATER **/
builder.AppendFormat(" --SocksPort 9050");
if (!string.IsNullOrWhiteSpace(configurationFile))
builder.AppendFormat(" -f \"{0}\"", configurationFile);
if (!string.IsNullOrWhiteSpace(defaultConfigurationFile))
builder.AppendFormat(" --defaults-torrc \"{0}\"", defaultConfigurationFile);
foreach (KeyValuePair over in overrides)
{
string value = "";
ConfigurationAssocAttribute attribute = ReflectionHelper.GetAttribute(over.Key);
if (attribute == null)
continue;
if (over.Value != null)
value = ReflectionHelper.Convert(over.Value, typeof(string)) as string;
if (value == null)
value = "";
if (value.Contains(" "))
value = "\"" + value + "\"";
builder.AppendFormat(" --{0} {1}", attribute.Name, value);
}
return builder.ToString();
}
#endregion
///
/// Sets the value of a configuration supplied with the process arguments. Setting a configuration value within the create
/// parameters overrides any values stored in the configuration file. The control port can also be set using this method.
///
/// The configuration which should be overridden.
/// The value of the configuration. This should align with the type specified in the class.
public void SetConfig(ConfigurationNames configuration, object value)
{
ConfigurationAssocAttribute attribute = ReflectionHelper.GetAttribute(configuration);
if (attribute == null)
return;
if (value != null && !value.GetType().Equals(attribute.Type))
throw new ArgumentException("The value of this configuration should be of type " + attribute.Type, "value");
ConfigurationValidation validation = attribute.Validation;
if (validation != ConfigurationValidation.None)
{
if (validation.HasFlag(ConfigurationValidation.NonNull) && value == null)
throw new ArgumentNullException("value");
if (validation.HasFlag(ConfigurationValidation.NonZero) ||
validation.HasFlag(ConfigurationValidation.NonNegative) ||
validation.HasFlag(ConfigurationValidation.PortRange))
{
int converted = Convert.ToInt32(value);
if (validation.HasFlag(ConfigurationValidation.NonZero) && converted == 0)
throw new ArgumentOutOfRangeException("value", "The value of this configuration cannot be zero");
if (validation.HasFlag(ConfigurationValidation.NonNegative) && converted < 0)
throw new ArgumentOutOfRangeException("value", "The value of this configuration cannot be below zero");
if (validation.HasFlag(ConfigurationValidation.PortRange) && (converted <= 0 || short.MaxValue < converted))
throw new ArgumentOutOfRangeException("value", "The value of this configuration must be within a valid port range");
}
if (validation.HasFlag(ConfigurationValidation.SizeDivision))
{
double converted = Convert.ToDouble(value);
if (converted % 1024 != 0)
throw new ArgumentException("The value of this configuration must be divisible by 1024");
}
}
if (configuration == ConfigurationNames.ControlPort)
controlPort = Convert.ToInt32(value);
else
overrides[configuration] = value;
}
///
/// Validates the parameters assigned to the object, and throws relevant exceptions where necessary.
///
internal void ValidateParameters()
{
if (string.IsNullOrWhiteSpace(path))
throw new TorException("The path cannot be null or white-space");
if (controlPort <= 0 || short.MaxValue < controlPort)
throw new TorException("The control port number must be within a valid port range");
}
}
}