<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>stem.control — Stem 1.1.0 documentation</title> <link rel="stylesheet" href="../../_static/haiku.css" type="text/css" /> <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> <link rel="stylesheet" href="../../_static/print.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../../', VERSION: '1.1.0', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../../_static/jquery.js"></script> <script type="text/javascript" src="../../_static/underscore.js"></script> <script type="text/javascript" src="../../_static/doctools.js"></script> <script type="text/javascript" src="../../_static/theme_extras.js"></script> <link rel="shortcut icon" href="../../_static/favicon.png"/> <link rel="top" title="Stem 1.1.0 documentation" href="../../index.html" /> <link rel="up" title="stem" href="../stem.html" /> </head> <body> <div class="header"><img class="rightlogo" src="../../_static/logo.png" alt="Logo"/><h1 class="heading"><a href="../../index.html"> <span>Stem Docs</span></a></h1> <h2 class="heading"><span>stem.control</span></h2> </div> <div class="topnav"> <p> <ul id="navbar"> <li><a href="../../index.html">Home</a></li> <li><a href="../../tutorials.html">Tutorials</a> <ul> <li><a href="../../tutorials/the_little_relay_that_could.html">Hello World</a></li> <li><a href="../../tutorials/to_russia_with_love.html">Client Usage</a></li> <li><a href="../../tutorials/tortoise_and_the_hare.html">Event Listening</a></li> <li><a href="../../tutorials/mirror_mirror_on_the_wall.html">Tor Descriptors</a></li> <li><a href="../../tutorials/east_of_the_sun.html">Utilities</a></li> <li><a href="../../tutorials/double_double_toil_and_trouble.html">Examples</a></li> </ul> </li> <li><a href="../../api.html">API</a> <ul> <li><a href="../../api/control.html">stem.control</a></li> <li><a href="../../api/connection.html">stem.connection</a></li> <li><a href="../../api/socket.html">stem.socket</a></li> <li><a href="../../api/process.html">stem.process</a></li> <li><a href="../../api/response.html">stem.response</a></li> <li><a href="../../api/exit_policy.html">stem.exit_policy</a></li> <li><a href="../../api/version.html">stem.version</a></li> <li><a href="../../api.html#descriptors">Descriptors</a></li> <li><a href="../../api.html#utilities">Utilities</a></li> </ul> </li> <li><a href="https://trac.torproject.org/projects/tor/wiki/doc/stem">Development</a> <ul> <li><a href="../../faq.html">FAQ</a></li> <li><a href="../../change_log.html">Change Log</a></li> <li><a href="https://trac.torproject.org/projects/tor/wiki/doc/stem/bugs">Bug Tracker</a></li> <li><a href="../../download.html">Download</a></li> </ul> </li> </ul> </p> </div> <div class="content"> <h1>Source code for stem.control</h1><div class="highlight"><pre> <span class="c"># Copyright 2011-2013, Damian Johnson and The Tor Project</span> <span class="c"># See LICENSE for licensing information</span> <span class="sd">"""</span> <span class="sd">Classes for interacting with the tor control socket.</span> <span class="sd">Controllers are a wrapper around a :class:`~stem.socket.ControlSocket`,</span> <span class="sd">retaining many of its methods (connect, close, is_alive, etc) in addition to</span> <span class="sd">providing its own for interacting at a higher level.</span> <span class="sd">**Module Overview:**</span> <span class="sd">::</span> <span class="sd"> Controller - General controller class intended for direct use</span> <span class="sd"> | |- from_port - Provides a Controller based on a port connection.</span> <span class="sd"> | +- from_socket_file - Provides a Controller based on a socket file connection.</span> <span class="sd"> |</span> <span class="sd"> |- authenticate - authenticates this controller with tor</span> <span class="sd"> |</span> <span class="sd"> |- get_info - issues a GETINFO query for a parameter</span> <span class="sd"> |- get_version - provides our tor version</span> <span class="sd"> |- get_exit_policy - provides our exit policy</span> <span class="sd"> |- get_socks_listeners - provides where tor is listening for SOCKS connections</span> <span class="sd"> |- get_protocolinfo - information about the controller interface</span> <span class="sd"> |- get_user - provides the user tor is running as</span> <span class="sd"> |- get_pid - provides the pid of our tor process</span> <span class="sd"> |</span> <span class="sd"> |- get_microdescriptor - querying the microdescriptor for a relay</span> <span class="sd"> |- get_microdescriptors - provides all presently available microdescriptors</span> <span class="sd"> |- get_server_descriptor - querying the server descriptor for a relay</span> <span class="sd"> |- get_server_descriptors - provides all presently available server descriptors</span> <span class="sd"> |- get_network_status - querying the router status entry for a relay</span> <span class="sd"> |- get_network_statuses - provides all preently available router status entries</span> <span class="sd"> |</span> <span class="sd"> |- get_conf - gets the value of a configuration option</span> <span class="sd"> |- get_conf_map - gets the values of multiple configuration options</span> <span class="sd"> |- set_conf - sets the value of a configuration option</span> <span class="sd"> |- reset_conf - reverts configuration options to their default values</span> <span class="sd"> |- set_options - sets or resets the values of multiple configuration options</span> <span class="sd"> |</span> <span class="sd"> |- add_event_listener - attaches an event listener to be notified of tor events</span> <span class="sd"> |- remove_event_listener - removes a listener so it isn't notified of further events</span> <span class="sd"> |</span> <span class="sd"> |- is_caching_enabled - true if the controller has enabled caching</span> <span class="sd"> |- set_caching - enables or disables caching</span> <span class="sd"> |- clear_cache - clears any cached results</span> <span class="sd"> |</span> <span class="sd"> |- load_conf - loads configuration information as if it was in the torrc</span> <span class="sd"> |- save_conf - saves configuration information to the torrc</span> <span class="sd"> |</span> <span class="sd"> |- is_feature_enabled - checks if a given controller feature is enabled</span> <span class="sd"> |- enable_feature - enables a controller feature that has been disabled by default</span> <span class="sd"> |</span> <span class="sd"> |- get_circuit - provides an active circuit</span> <span class="sd"> |- get_circuits - provides a list of active circuits</span> <span class="sd"> |- new_circuit - create new circuits</span> <span class="sd"> |- extend_circuit - create new circuits and extend existing ones</span> <span class="sd"> |- repurpose_circuit - change a circuit's purpose</span> <span class="sd"> |- close_circuit - close a circuit</span> <span class="sd"> |</span> <span class="sd"> |- get_streams - provides a list of active streams</span> <span class="sd"> |- attach_stream - attach a stream to a circuit</span> <span class="sd"> |- close_stream - close a stream</span> <span class="sd"> |</span> <span class="sd"> |- signal - sends a signal to the tor client</span> <span class="sd"> |- is_geoip_unavailable - true if we've discovered our geoip db to be unavailable</span> <span class="sd"> +- map_address - maps one address to another such that connections to the original are replaced with the other</span> <span class="sd"> BaseController - Base controller class asynchronous message handling</span> <span class="sd"> |- msg - communicates with the tor process</span> <span class="sd"> |- is_alive - reports if our connection to tor is open or closed</span> <span class="sd"> |- is_authenticated - checks if we're authenticated to tor</span> <span class="sd"> |- connect - connects or reconnects to tor</span> <span class="sd"> |- close - shuts down our connection to the tor process</span> <span class="sd"> |- get_socket - provides the socket used for control communication</span> <span class="sd"> |- get_latest_heartbeat - timestamp for when we last heard from tor</span> <span class="sd"> |- add_status_listener - notifies a callback of changes in our status</span> <span class="sd"> |- remove_status_listener - prevents further notification of status changes</span> <span class="sd"> +- __enter__ / __exit__ - manages socket connection</span> <span class="sd">.. data:: State (enum)</span> <span class="sd"> Enumeration for states that a controller can have.</span> <span class="sd"> ========== ===========</span> <span class="sd"> State Description</span> <span class="sd"> ========== ===========</span> <span class="sd"> **INIT** new control connection</span> <span class="sd"> **RESET** received a reset/sighup signal</span> <span class="sd"> **CLOSED** control connection closed</span> <span class="sd"> ========== ===========</span> <span class="sd">.. data:: EventType (enum)</span> <span class="sd"> Known types of events that the</span> <span class="sd"> :func:`~stem.control.Controller.add_event_listener` method of the</span> <span class="sd"> :class:`~stem.control.Controller` can listen for.</span> <span class="sd"> The most frequently listened for event types tend to be the logging events</span> <span class="sd"> (**DEBUG**, **INFO**, **NOTICE**, **WARN**, and **ERR**), bandwidth usage</span> <span class="sd"> (**BW**), and circuit or stream changes (**CIRC** and **STREAM**).</span> <span class="sd"> Enums are mapped to :class:`~stem.response.events.Event` subclasses as</span> <span class="sd"> follows...</span> <span class="sd"> ===================== ===========</span> <span class="sd"> EventType Event Class</span> <span class="sd"> ===================== ===========</span> <span class="sd"> **ADDRMAP** :class:`stem.response.events.AddrMapEvent`</span> <span class="sd"> **AUTHDIR_NEWDESCS** :class:`stem.response.events.AuthDirNewDescEvent`</span> <span class="sd"> **BUILDTIMEOUT_SET** :class:`stem.response.events.BuildTimeoutSetEvent`</span> <span class="sd"> **BW** :class:`stem.response.events.BandwidthEvent`</span> <span class="sd"> **CIRC** :class:`stem.response.events.CircuitEvent`</span> <span class="sd"> **CIRC_MINOR** :class:`stem.response.events.CircMinorEvent`</span> <span class="sd"> **CLIENTS_SEEN** :class:`stem.response.events.ClientsSeenEvent`</span> <span class="sd"> **CONF_CHANGED** :class:`stem.response.events.ConfChangedEvent`</span> <span class="sd"> **DEBUG** :class:`stem.response.events.LogEvent`</span> <span class="sd"> **DESCCHANGED** :class:`stem.response.events.DescChangedEvent`</span> <span class="sd"> **ERR** :class:`stem.response.events.LogEvent`</span> <span class="sd"> **GUARD** :class:`stem.response.events.GuardEvent`</span> <span class="sd"> **INFO** :class:`stem.response.events.LogEvent`</span> <span class="sd"> **NEWCONSENSUS** :class:`stem.response.events.NewConsensusEvent`</span> <span class="sd"> **NEWDESC** :class:`stem.response.events.NewDescEvent`</span> <span class="sd"> **NOTICE** :class:`stem.response.events.LogEvent`</span> <span class="sd"> **NS** :class:`stem.response.events.NetworkStatusEvent`</span> <span class="sd"> **ORCONN** :class:`stem.response.events.ORConnEvent`</span> <span class="sd"> **SIGNAL** :class:`stem.response.events.SignalEvent`</span> <span class="sd"> **STATUS_CLIENT** :class:`stem.response.events.StatusEvent`</span> <span class="sd"> **STATUS_GENERAL** :class:`stem.response.events.StatusEvent`</span> <span class="sd"> **STATUS_SERVER** :class:`stem.response.events.StatusEvent`</span> <span class="sd"> **STREAM** :class:`stem.response.events.StreamEvent`</span> <span class="sd"> **STREAM_BW** :class:`stem.response.events.StreamBwEvent`</span> <span class="sd"> **WARN** :class:`stem.response.events.LogEvent`</span> <span class="sd"> ===================== ===========</span> <span class="sd">"""</span> <span class="kn">import</span> <span class="nn">io</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">Queue</span> <span class="kn">import</span> <span class="nn">StringIO</span> <span class="kn">import</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="nn">time</span> <span class="kn">import</span> <span class="nn">stem.descriptor.microdescriptor</span> <span class="kn">import</span> <span class="nn">stem.descriptor.reader</span> <span class="kn">import</span> <span class="nn">stem.descriptor.router_status_entry</span> <span class="kn">import</span> <span class="nn">stem.descriptor.server_descriptor</span> <span class="kn">import</span> <span class="nn">stem.exit_policy</span> <span class="kn">import</span> <span class="nn">stem.response</span> <span class="kn">import</span> <span class="nn">stem.response.events</span> <span class="kn">import</span> <span class="nn">stem.socket</span> <span class="kn">import</span> <span class="nn">stem.util.connection</span> <span class="kn">import</span> <span class="nn">stem.util.enum</span> <span class="kn">import</span> <span class="nn">stem.util.str_tools</span> <span class="kn">import</span> <span class="nn">stem.util.system</span> <span class="kn">import</span> <span class="nn">stem.util.tor_tools</span> <span class="kn">import</span> <span class="nn">stem.version</span> <span class="kn">from</span> <span class="nn">stem</span> <span class="kn">import</span> <span class="n">UNDEFINED</span><span class="p">,</span> <span class="n">CircStatus</span><span class="p">,</span> <span class="n">Signal</span> <span class="kn">from</span> <span class="nn">stem.util</span> <span class="kn">import</span> <span class="n">log</span> <span class="c"># state changes a control socket can have</span> <span class="n">State</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">(</span><span class="s">"INIT"</span><span class="p">,</span> <span class="s">"RESET"</span><span class="p">,</span> <span class="s">"CLOSED"</span><span class="p">)</span> <span class="n">EventType</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">enum</span><span class="o">.</span><span class="n">UppercaseEnum</span><span class="p">(</span> <span class="s">"CIRC"</span><span class="p">,</span> <span class="s">"STREAM"</span><span class="p">,</span> <span class="s">"ORCONN"</span><span class="p">,</span> <span class="s">"BW"</span><span class="p">,</span> <span class="s">"DEBUG"</span><span class="p">,</span> <span class="s">"INFO"</span><span class="p">,</span> <span class="s">"NOTICE"</span><span class="p">,</span> <span class="s">"WARN"</span><span class="p">,</span> <span class="s">"ERR"</span><span class="p">,</span> <span class="s">"NEWDESC"</span><span class="p">,</span> <span class="s">"ADDRMAP"</span><span class="p">,</span> <span class="s">"AUTHDIR_NEWDESCS"</span><span class="p">,</span> <span class="s">"DESCCHANGED"</span><span class="p">,</span> <span class="s">"STATUS_GENERAL"</span><span class="p">,</span> <span class="s">"STATUS_CLIENT"</span><span class="p">,</span> <span class="s">"STATUS_SERVER"</span><span class="p">,</span> <span class="s">"GUARD"</span><span class="p">,</span> <span class="s">"NS"</span><span class="p">,</span> <span class="s">"STREAM_BW"</span><span class="p">,</span> <span class="s">"CLIENTS_SEEN"</span><span class="p">,</span> <span class="s">"NEWCONSENSUS"</span><span class="p">,</span> <span class="s">"BUILDTIMEOUT_SET"</span><span class="p">,</span> <span class="s">"SIGNAL"</span><span class="p">,</span> <span class="s">"CONF_CHANGED"</span><span class="p">,</span> <span class="s">"CIRC_MINOR"</span><span class="p">,</span> <span class="p">)</span> <span class="c"># Configuration options that are fetched by a special key. The keys are</span> <span class="c"># lowercase to make case insensitive lookups easier.</span> <span class="n">MAPPED_CONFIG_KEYS</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"hiddenservicedir"</span><span class="p">:</span> <span class="s">"HiddenServiceOptions"</span><span class="p">,</span> <span class="s">"hiddenserviceport"</span><span class="p">:</span> <span class="s">"HiddenServiceOptions"</span><span class="p">,</span> <span class="s">"hiddenserviceversion"</span><span class="p">:</span> <span class="s">"HiddenServiceOptions"</span><span class="p">,</span> <span class="s">"hiddenserviceauthorizeclient"</span><span class="p">:</span> <span class="s">"HiddenServiceOptions"</span><span class="p">,</span> <span class="s">"hiddenserviceoptions"</span><span class="p">:</span> <span class="s">"HiddenServiceOptions"</span> <span class="p">}</span> <span class="c"># unchangeable GETINFO parameters</span> <span class="n">CACHEABLE_GETINFO_PARAMS</span> <span class="o">=</span> <span class="p">(</span> <span class="s">'version'</span><span class="p">,</span> <span class="s">'config-file'</span><span class="p">,</span> <span class="s">'exit-policy/default'</span><span class="p">,</span> <span class="s">'fingerprint'</span><span class="p">,</span> <span class="s">'config/names'</span><span class="p">,</span> <span class="s">'config/defaults'</span><span class="p">,</span> <span class="s">'info/names'</span><span class="p">,</span> <span class="s">'events/names'</span><span class="p">,</span> <span class="s">'features/names'</span><span class="p">,</span> <span class="s">'process/descriptor-limit'</span><span class="p">,</span> <span class="p">)</span> <span class="c"># GETCONF parameters we shouldn't cache. This includes hidden service</span> <span class="c"># perameters due to the funky way they're set and retrieved (for instance,</span> <span class="c"># 'SETCONF HiddenServiceDir' effects 'GETCONF HiddenServiceOptions').</span> <span class="n">UNCACHEABLE_GETCONF_PARAMS</span> <span class="o">=</span> <span class="p">(</span> <span class="s">'hiddenserviceoptions'</span><span class="p">,</span> <span class="s">'hiddenservicedir'</span><span class="p">,</span> <span class="s">'hiddenserviceport'</span><span class="p">,</span> <span class="s">'hiddenserviceversion'</span><span class="p">,</span> <span class="s">'hiddenserviceauthorizeclient'</span><span class="p">,</span> <span class="s">'hiddenserviceoptions'</span><span class="p">,</span> <span class="p">)</span> <span class="c"># number of sequential attempts before we decide that the Tor geoip database</span> <span class="c"># is unavailable</span> <span class="n">GEOIP_FAILURE_THRESHOLD</span> <span class="o">=</span> <span class="mi">5</span> <span class="n">SERVER_DESCRIPTORS_UNSUPPORTED</span> <span class="o">=</span> <span class="s">"Tor is presently not configured to retrieve </span><span class="se">\</span> <span class="s">server descriptors. As of Tor version 0.2.3.25 it downloads microdescriptors </span><span class="se">\</span> <span class="s">instead unless you set 'UseMicrodescriptors 0' in your torrc."</span> <div class="viewcode-block" id="BaseController"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController">[docs]</a><span class="k">class</span> <span class="nc">BaseController</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Controller for the tor process. This is a minimal base class for other</span> <span class="sd"> controllers, providing basic process communication and event listing. Don't</span> <span class="sd"> use this directly - subclasses like the :class:`~stem.control.Controller`</span> <span class="sd"> provide higher level functionality.</span> <span class="sd"> It's highly suggested that you don't interact directly with the</span> <span class="sd"> :class:`~stem.socket.ControlSocket` that we're constructed from - use our</span> <span class="sd"> wrapper methods instead.</span> <span class="sd"> """</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">control_socket</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span> <span class="o">=</span> <span class="n">control_socket</span> <span class="bp">self</span><span class="o">.</span><span class="n">_msg_lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># tuples of the form (callback, spawn_thread)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners_lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span> <span class="c"># queues where incoming messages are directed</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reply_queue</span> <span class="o">=</span> <span class="n">Queue</span><span class="o">.</span><span class="n">Queue</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_queue</span> <span class="o">=</span> <span class="n">Queue</span><span class="o">.</span><span class="n">Queue</span><span class="p">()</span> <span class="c"># thread to continually pull from the control socket</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span> <span class="o">=</span> <span class="bp">None</span> <span class="c"># thread to pull from the _event_queue and call handle_event</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_notice</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Event</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span> <span class="o">=</span> <span class="bp">None</span> <span class="c"># saves our socket's prior _connect() and _close() methods so they can be</span> <span class="c"># called along with ours</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket_connect</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">_connect</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket_close</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">_close</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">_connect</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_connect</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">_close</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_close</span> <span class="bp">self</span><span class="o">.</span><span class="n">_last_heartbeat</span> <span class="o">=</span> <span class="mf">0.0</span> <span class="c"># timestamp for when we last heard from tor</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_authenticated</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="bp">self</span><span class="o">.</span><span class="n">_launch_threads</span><span class="p">()</span> <div class="viewcode-block" id="BaseController.msg"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.msg">[docs]</a> <span class="k">def</span> <span class="nf">msg</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Sends a message to our control socket and provides back its reply.</span> <span class="sd"> :param str message: message to be formatted and sent to tor</span> <span class="sd"> :returns: :class:`~stem.response.ControlMessage` with the response</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ProtocolError` the content from the socket is</span> <span class="sd"> malformed</span> <span class="sd"> * :class:`stem.SocketError` if a problem arises in using the</span> <span class="sd"> socket</span> <span class="sd"> * :class:`stem.SocketClosed` if the socket is shut down</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_msg_lock</span><span class="p">:</span> <span class="c"># If our _reply_queue isn't empty then one of a few things happened...</span> <span class="c">#</span> <span class="c"># - Our connection was closed and probably re-restablished. This was</span> <span class="c"># in reply to pulling for an asynchronous event and getting this is</span> <span class="c"># expected - ignore it.</span> <span class="c">#</span> <span class="c"># - Pulling for asynchronous events produced an error. If this was a</span> <span class="c"># ProtocolError then it's a tor bug, and if a non-closure SocketError</span> <span class="c"># then it was probably a socket glitch. Deserves an INFO level log</span> <span class="c"># message.</span> <span class="c">#</span> <span class="c"># - This is a leftover response for a msg() call. We can't tell who an</span> <span class="c"># exception was earmarked for, so we only know that this was the case</span> <span class="c"># if it's a ControlMessage. This should not be possible and indicates</span> <span class="c"># a stem bug. This deserves a NOTICE level log message since it</span> <span class="c"># indicates that one of our callers didn't get their reply.</span> <span class="k">while</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reply_queue</span><span class="o">.</span><span class="n">empty</span><span class="p">():</span> <span class="k">try</span><span class="p">:</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reply_queue</span><span class="o">.</span><span class="n">get_nowait</span><span class="p">()</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">SocketClosed</span><span class="p">):</span> <span class="k">pass</span> <span class="c"># this is fine</span> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">):</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">"Tor provided a malformed message (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">response</span><span class="p">)</span> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span><span class="p">):</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">"Socket experienced a problem (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">response</span><span class="p">)</span> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">ControlMessage</span><span class="p">):</span> <span class="n">log</span><span class="o">.</span><span class="n">notice</span><span class="p">(</span><span class="s">"BUG: the msg() function failed to deliver a response: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="p">)</span> <span class="k">except</span> <span class="n">Queue</span><span class="o">.</span><span class="n">Empty</span><span class="p">:</span> <span class="c"># the empty() method is documented to not be fully reliable so this</span> <span class="c"># isn't entirely surprising</span> <span class="k">break</span> <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reply_queue</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="c"># If the message we received back had an exception then re-raise it to the</span> <span class="c"># caller. Otherwise return the response.</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span><span class="p">):</span> <span class="k">raise</span> <span class="n">response</span> <span class="k">else</span><span class="p">:</span> <span class="c"># I really, really don't like putting hooks into this method, but</span> <span class="c"># this is the most reliable method I can think of for taking actions</span> <span class="c"># immediately after successfully authenticating to a connection.</span> <span class="k">if</span> <span class="n">message</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"AUTHENTICATE"</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">_post_authentication</span><span class="p">()</span> <span class="k">return</span> <span class="n">response</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">SocketClosed</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="c"># If the recv() thread caused the SocketClosed then we could still be</span> <span class="c"># in the process of closing. Calling close() here so that we can</span> <span class="c"># provide an assurance to the caller that when we raise a SocketClosed</span> <span class="c"># exception we are shut down afterward for realz.</span> <span class="bp">self</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="k">raise</span> <span class="n">exc</span> </div> <div class="viewcode-block" id="BaseController.is_alive"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.is_alive">[docs]</a> <span class="k">def</span> <span class="nf">is_alive</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Checks if our socket is currently connected. This is a pass-through for our</span> <span class="sd"> socket's :func:`~stem.socket.ControlSocket.is_alive` method.</span> <span class="sd"> :returns: **bool** that's **True** if our socket is connected and **False** otherwise</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">is_alive</span><span class="p">()</span> </div> <div class="viewcode-block" id="BaseController.is_authenticated"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.is_authenticated">[docs]</a> <span class="k">def</span> <span class="nf">is_authenticated</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Checks if our socket is both connected and authenticated.</span> <span class="sd"> :returns: **bool** that's **True** if our socket is authenticated to tor</span> <span class="sd"> and **False** otherwise</span> <span class="sd"> """</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_authenticated</span> <span class="k">return</span> <span class="bp">False</span> </div> <div class="viewcode-block" id="BaseController.connect"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.connect">[docs]</a> <span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Reconnects our control socket. This is a pass-through for our socket's</span> <span class="sd"> :func:`~stem.socket.ControlSocket.connect` method.</span> <span class="sd"> :raises: :class:`stem.SocketError` if unable to make a socket</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> </div> <div class="viewcode-block" id="BaseController.close"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.close">[docs]</a> <span class="k">def</span> <span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Closes our socket connection. This is a pass-through for our socket's</span> <span class="sd"> :func:`~stem.socket.ControlSocket.close` method.</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> </div> <div class="viewcode-block" id="BaseController.get_socket"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.get_socket">[docs]</a> <span class="k">def</span> <span class="nf">get_socket</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the socket used to speak with the tor process. Communicating with</span> <span class="sd"> the socket directly isn't advised since it may confuse this controller.</span> <span class="sd"> :returns: :class:`~stem.socket.ControlSocket` we're communicating with</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span> </div> <div class="viewcode-block" id="BaseController.get_latest_heartbeat"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.get_latest_heartbeat">[docs]</a> <span class="k">def</span> <span class="nf">get_latest_heartbeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the unix timestamp for when we last heard from tor. This is zero</span> <span class="sd"> if we've never received a message.</span> <span class="sd"> :returns: float for the unix timestamp of when we last heard from tor</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_last_heartbeat</span> </div> <div class="viewcode-block" id="BaseController.add_status_listener"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.add_status_listener">[docs]</a> <span class="k">def</span> <span class="nf">add_status_listener</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">spawn</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Notifies a given function when the state of our socket changes. Functions</span> <span class="sd"> are expected to be of the form...</span> <span class="sd"> ::</span> <span class="sd"> my_function(controller, state, timestamp)</span> <span class="sd"> The state is a value from the :data:`stem.control.State` enum. Functions</span> <span class="sd"> **must** allow for new values. The timestamp is a float for the unix time</span> <span class="sd"> when the change occurred.</span> <span class="sd"> This class only provides **State.INIT** and **State.CLOSED** notifications.</span> <span class="sd"> Subclasses may provide others.</span> <span class="sd"> If spawn is **True** then the callback is notified via a new daemon thread.</span> <span class="sd"> If **False** then the notice is under our locks, within the thread where</span> <span class="sd"> the change occurred. In general this isn't advised, especially if your</span> <span class="sd"> callback could block for a while.</span> <span class="sd"> :param function callback: function to be notified when our state changes</span> <span class="sd"> :param bool spawn: calls function via a new thread if **True**, otherwise</span> <span class="sd"> it's part of the connect/close method call</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners_lock</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">callback</span><span class="p">,</span> <span class="n">spawn</span><span class="p">))</span> </div> <div class="viewcode-block" id="BaseController.remove_status_listener"><a class="viewcode-back" href="../../api/control.html#stem.control.BaseController.remove_status_listener">[docs]</a> <span class="k">def</span> <span class="nf">remove_status_listener</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Stops listener from being notified of further events.</span> <span class="sd"> :param function callback: function to be removed from our listeners</span> <span class="sd"> :returns: **bool** that's **True** if we removed one or more occurrences of</span> <span class="sd"> the callback, **False** otherwise</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners_lock</span><span class="p">:</span> <span class="n">new_listeners</span><span class="p">,</span> <span class="n">is_changed</span> <span class="o">=</span> <span class="p">[],</span> <span class="bp">False</span> <span class="k">for</span> <span class="n">listener</span><span class="p">,</span> <span class="n">spawn</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners</span><span class="p">:</span> <span class="k">if</span> <span class="n">listener</span> <span class="o">!=</span> <span class="n">callback</span><span class="p">:</span> <span class="n">new_listeners</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">listener</span><span class="p">,</span> <span class="n">spawn</span><span class="p">))</span> <span class="k">else</span><span class="p">:</span> <span class="n">is_changed</span> <span class="o">=</span> <span class="bp">True</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners</span> <span class="o">=</span> <span class="n">new_listeners</span> <span class="k">return</span> <span class="n">is_changed</span> </div> <span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span> <span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exit_type</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">traceback</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="k">def</span> <span class="nf">_handle_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event_message</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Callback to be overwritten by subclasses for event listening. This is</span> <span class="sd"> notified whenever we receive an event from the control socket.</span> <span class="sd"> :param stem.response.ControlMessage event_message: message received from</span> <span class="sd"> the control socket</span> <span class="sd"> """</span> <span class="k">pass</span> <span class="k">def</span> <span class="nf">_connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">_launch_threads</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_notify_status_listeners</span><span class="p">(</span><span class="n">State</span><span class="o">.</span><span class="n">INIT</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket_connect</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_authenticated</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">def</span> <span class="nf">_close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c"># Our is_alive() state is now false. Our reader thread should already be</span> <span class="c"># awake from recv() raising a closure exception. Wake up the event thread</span> <span class="c"># too so it can end.</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_notice</span><span class="o">.</span><span class="n">set</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_authenticated</span> <span class="o">=</span> <span class="bp">False</span> <span class="c"># joins on our threads if it's safe to do so</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span><span class="p">):</span> <span class="k">if</span> <span class="n">t</span> <span class="ow">and</span> <span class="n">t</span><span class="o">.</span><span class="n">is_alive</span><span class="p">()</span> <span class="ow">and</span> <span class="n">threading</span><span class="o">.</span><span class="n">current_thread</span><span class="p">()</span> <span class="o">!=</span> <span class="n">t</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_notify_status_listeners</span><span class="p">(</span><span class="n">State</span><span class="o">.</span><span class="n">CLOSED</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket_close</span><span class="p">()</span> <span class="k">def</span> <span class="nf">_post_authentication</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c"># actions to be taken after we have a newly authenticated connection</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_authenticated</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">def</span> <span class="nf">_notify_status_listeners</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Informs our status listeners that a state change occurred.</span> <span class="sd"> :param stem.control.State state: state change that has occurred</span> <span class="sd"> """</span> <span class="c"># Any changes to our is_alive() state happen under the send lock, so we</span> <span class="c"># need to have it to ensure it doesn't change beneath us.</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">_get_send_lock</span><span class="p">():</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners_lock</span><span class="p">:</span> <span class="c"># States imply that our socket is either alive or not, which may not</span> <span class="c"># hold true when multiple events occur in quick succession. For</span> <span class="c"># instance, a sighup could cause two events (State.RESET for the sighup</span> <span class="c"># and State.CLOSE if it causes tor to crash). However, there's no</span> <span class="c"># guarantee of the order in which they occur, and it would be bad if</span> <span class="c"># listeners got the State.RESET last, implying that we were alive.</span> <span class="n">expect_alive</span> <span class="o">=</span> <span class="bp">None</span> <span class="k">if</span> <span class="n">state</span> <span class="ow">in</span> <span class="p">(</span><span class="n">State</span><span class="o">.</span><span class="n">INIT</span><span class="p">,</span> <span class="n">State</span><span class="o">.</span><span class="n">RESET</span><span class="p">):</span> <span class="n">expect_alive</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">elif</span> <span class="n">state</span> <span class="o">==</span> <span class="n">State</span><span class="o">.</span><span class="n">CLOSED</span><span class="p">:</span> <span class="n">expect_alive</span> <span class="o">=</span> <span class="bp">False</span> <span class="n">change_timestamp</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="k">if</span> <span class="n">expect_alive</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">expect_alive</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="k">return</span> <span class="k">for</span> <span class="n">listener</span><span class="p">,</span> <span class="n">spawn</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_status_listeners</span><span class="p">:</span> <span class="k">if</span> <span class="n">spawn</span><span class="p">:</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"</span><span class="si">%s</span><span class="s"> notification"</span> <span class="o">%</span> <span class="n">state</span> <span class="n">args</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="n">change_timestamp</span><span class="p">)</span> <span class="n">notice_thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span> <span class="o">=</span> <span class="n">listener</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="n">args</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">)</span> <span class="n">notice_thread</span><span class="o">.</span><span class="n">setDaemon</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="n">notice_thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> <span class="k">else</span><span class="p">:</span> <span class="n">listener</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="n">change_timestamp</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_launch_threads</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Initializes daemon threads. Threads can't be reused so we need to recreate</span> <span class="sd"> them if we're restarted.</span> <span class="sd"> """</span> <span class="c"># In theory concurrent calls could result in multiple start() calls on a</span> <span class="c"># single thread, which would cause an unexpected exception. Best be safe.</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">_get_send_lock</span><span class="p">():</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_loop</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"Tor Listener"</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span><span class="o">.</span><span class="n">setDaemon</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reader_thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_loop</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"Event Notifier"</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span><span class="o">.</span><span class="n">setDaemon</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> <span class="k">def</span> <span class="nf">_reader_loop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Continually pulls from the control socket, directing the messages into</span> <span class="sd"> queues based on their type. Controller messages come in two varieties...</span> <span class="sd"> * Responses to messages we've sent (GETINFO, SETCONF, etc).</span> <span class="sd"> * Asynchronous events, identified by a status code of 650.</span> <span class="sd"> """</span> <span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="k">try</span><span class="p">:</span> <span class="n">control_message</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_socket</span><span class="o">.</span><span class="n">recv</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_last_heartbeat</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="k">if</span> <span class="n">control_message</span><span class="o">.</span><span class="n">content</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s">"650"</span><span class="p">:</span> <span class="c"># asynchronous message, adds to the event queue and wakes up its handler</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">control_message</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_notice</span><span class="o">.</span><span class="n">set</span><span class="p">()</span> <span class="k">else</span><span class="p">:</span> <span class="c"># response to a msg() call</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reply_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">control_message</span><span class="p">)</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="c"># Assume that all exceptions belong to the reader. This isn't always</span> <span class="c"># true, but the msg() call can do a better job of sorting it out.</span> <span class="c">#</span> <span class="c"># Be aware that the msg() method relies on this to unblock callers.</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reply_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">exc</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_event_loop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Continually pulls messages from the _event_queue and sends them to our</span> <span class="sd"> handle_event callback. This is done via its own thread so subclasses with a</span> <span class="sd"> lengthy handle_event implementation don't block further reading from the</span> <span class="sd"> socket.</span> <span class="sd"> """</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">event_message</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_queue</span><span class="o">.</span><span class="n">get_nowait</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_handle_event</span><span class="p">(</span><span class="n">event_message</span><span class="p">)</span> <span class="k">except</span> <span class="n">Queue</span><span class="o">.</span><span class="n">Empty</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="k">break</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_notice</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_notice</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span> </div> <div class="viewcode-block" id="Controller"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller">[docs]</a><span class="k">class</span> <span class="nc">Controller</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Communicates with a control socket. This is built on top of the</span> <span class="sd"> BaseController and provides a more user friendly API for library users.</span> <span class="sd"> """</span> <span class="nd">@staticmethod</span> <div class="viewcode-block" id="Controller.from_port"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.from_port">[docs]</a> <span class="k">def</span> <span class="nf">from_port</span><span class="p">(</span><span class="n">address</span> <span class="o">=</span> <span class="s">"127.0.0.1"</span><span class="p">,</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">9051</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Constructs a :class:`~stem.socket.ControlPort` based Controller.</span> <span class="sd"> :param str address: ip address of the controller</span> <span class="sd"> :param int port: port number of the controller</span> <span class="sd"> :returns: :class:`~stem.control.Controller` attached to the given port</span> <span class="sd"> :raises: :class:`stem.SocketError` if we're unable to establish a connection</span> <span class="sd"> """</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_ipv4_address</span><span class="p">(</span><span class="n">address</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Invalid IP address: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">address</span><span class="p">)</span> <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_port</span><span class="p">(</span><span class="n">port</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Invalid port: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">port</span><span class="p">)</span> <span class="n">control_port</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">ControlPort</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span> <span class="k">return</span> <span class="n">Controller</span><span class="p">(</span><span class="n">control_port</span><span class="p">)</span> </div> <span class="nd">@staticmethod</span> <div class="viewcode-block" id="Controller.from_socket_file"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.from_socket_file">[docs]</a> <span class="k">def</span> <span class="nf">from_socket_file</span><span class="p">(</span><span class="n">path</span> <span class="o">=</span> <span class="s">"/var/run/tor/control"</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Constructs a :class:`~stem.socket.ControlSocketFile` based Controller.</span> <span class="sd"> :param str path: path where the control socket is located</span> <span class="sd"> :returns: :class:`~stem.control.Controller` attached to the given socket file</span> <span class="sd"> :raises: :class:`stem.SocketError` if we're unable to establish a connection</span> <span class="sd"> """</span> <span class="n">control_socket</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">ControlSocketFile</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">return</span> <span class="n">Controller</span><span class="p">(</span><span class="n">control_socket</span><span class="p">)</span> </div> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">control_socket</span><span class="p">):</span> <span class="nb">super</span><span class="p">(</span><span class="n">Controller</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">control_socket</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_caching_enabled</span> <span class="o">=</span> <span class="bp">True</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span> <span class="o">=</span> <span class="p">{}</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache_lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span> <span class="c"># mapping of event types to their listeners</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span> <span class="o">=</span> <span class="p">{}</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners_lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span> <span class="c"># number of sequential 'GETINFO ip-to-country/*' lookups that have failed</span> <span class="bp">self</span><span class="o">.</span><span class="n">_geoip_failure_count</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="o">.</span><span class="n">_enabled_features</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">def</span> <span class="nf">_sighup_listener</span><span class="p">(</span><span class="n">event</span><span class="p">):</span> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">signal</span> <span class="o">==</span> <span class="n">Signal</span><span class="o">.</span><span class="n">RELOAD</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">clear_cache</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">_notify_status_listeners</span><span class="p">(</span><span class="n">State</span><span class="o">.</span><span class="n">RESET</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">add_event_listener</span><span class="p">(</span><span class="n">_sighup_listener</span><span class="p">,</span> <span class="n">EventType</span><span class="o">.</span><span class="n">SIGNAL</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_confchanged_listener</span><span class="p">(</span><span class="n">event</span><span class="p">):</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">():</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">(</span><span class="nb">dict</span><span class="p">((</span><span class="n">k</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">config</span><span class="p">),</span> <span class="s">"getconf"</span><span class="p">)</span> <span class="k">if</span> <span class="s">"exitpolicy"</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">({</span><span class="s">"exitpolicy"</span><span class="p">:</span> <span class="bp">None</span><span class="p">})</span> <span class="bp">self</span><span class="o">.</span><span class="n">add_event_listener</span><span class="p">(</span><span class="n">_confchanged_listener</span><span class="p">,</span> <span class="n">EventType</span><span class="o">.</span><span class="n">CONF_CHANGED</span><span class="p">)</span> <div class="viewcode-block" id="Controller.connect"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.connect">[docs]</a> <span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="nb">super</span><span class="p">(</span><span class="n">Controller</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">clear_cache</span><span class="p">()</span> </div> <div class="viewcode-block" id="Controller.close"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.close">[docs]</a> <span class="k">def</span> <span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c"># making a best-effort attempt to quit before detaching the socket</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_alive</span><span class="p">():</span> <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"QUIT"</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="k">pass</span> <span class="bp">self</span><span class="o">.</span><span class="n">clear_cache</span><span class="p">()</span> <span class="nb">super</span><span class="p">(</span><span class="n">Controller</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> </div> <div class="viewcode-block" id="Controller.authenticate"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.authenticate">[docs]</a> <span class="k">def</span> <span class="nf">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> A convenience method to authenticate the controller. This is just a</span> <span class="sd"> pass-through to :func:`stem.connection.authenticate`.</span> <span class="sd"> """</span> <span class="kn">import</span> <span class="nn">stem.connection</span> <span class="n">stem</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.get_info"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_info">[docs]</a> <span class="k">def</span> <span class="nf">get_info</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">,</span> <span class="n">get_bytes</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Queries the control socket for the given GETINFO option. If provided a</span> <span class="sd"> default then that's returned if the GETINFO option is undefined or the</span> <span class="sd"> call fails for any reason (error response, control port closed, initiated,</span> <span class="sd"> etc).</span> <span class="sd"> :param str,list params: GETINFO option or options to be queried</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :param bool get_bytes: provides **bytes** values rather than a **str** under python 3.x</span> <span class="sd"> :returns:</span> <span class="sd"> Response depends upon how we were called as follows...</span> <span class="sd"> * **str** with the response if our param was a **str**</span> <span class="sd"> * **dict** with the 'param => response' mapping if our param was a **list**</span> <span class="sd"> * default if one was provided and our call failed</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails and we weren't</span> <span class="sd"> provided a default response</span> <span class="sd"> * :class:`stem.InvalidArguments` if the 'params' requested was</span> <span class="sd"> invalid</span> <span class="sd"> * :class:`stem.ProtocolError` if the geoip database is known to be</span> <span class="sd"> unavailable</span> <span class="sd"> """</span> <span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="n">reply</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="p">(</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)):</span> <span class="n">is_multiple</span> <span class="o">=</span> <span class="bp">False</span> <span class="n">params</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">params</span><span class="p">])</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">params</span><span class="p">:</span> <span class="k">return</span> <span class="p">{}</span> <span class="n">is_multiple</span> <span class="o">=</span> <span class="bp">True</span> <span class="n">params</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">params</span><span class="p">)</span> <span class="c"># check for cached results</span> <span class="n">from_cache</span> <span class="o">=</span> <span class="p">[</span><span class="n">param</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">]</span> <span class="n">cached_results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache_map</span><span class="p">(</span><span class="n">from_cache</span><span class="p">,</span> <span class="s">"getinfo"</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">cached_results</span><span class="p">:</span> <span class="n">user_expected_key</span> <span class="o">=</span> <span class="n">_case_insensitive_lookup</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="n">reply</span><span class="p">[</span><span class="n">user_expected_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">cached_results</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="n">params</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">user_expected_key</span><span class="p">)</span> <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span> <span class="k">if</span> <span class="n">param</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'ip-to-country/'</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_geoip_unavailable</span><span class="p">():</span> <span class="c"># the geoip database already looks to be unavailable - abort the request</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"Tor geoip database is unavailable"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> <span class="c"># if everything was cached then short circuit making the query</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">params</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">trace</span><span class="p">(</span><span class="s">"GETINFO </span><span class="si">%s</span><span class="s"> (cache fetch)"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">reply</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span> <span class="k">if</span> <span class="n">is_multiple</span><span class="p">:</span> <span class="k">return</span> <span class="n">reply</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">reply</span><span class="o">.</span><span class="n">values</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="k">try</span><span class="p">:</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"GETINFO </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">params</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"GETINFO"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="n">response</span><span class="o">.</span><span class="n">_assert_matches</span><span class="p">(</span><span class="n">params</span><span class="p">)</span> <span class="c"># usually we want unicode values under python 3.x</span> <span class="k">if</span> <span class="n">stem</span><span class="o">.</span><span class="n">prereq</span><span class="o">.</span><span class="n">is_python_3</span><span class="p">()</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">get_bytes</span><span class="p">:</span> <span class="n">response</span><span class="o">.</span><span class="n">entries</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">k</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">str_tools</span><span class="o">.</span><span class="n">_to_unicode</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="k">for</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="n">reply</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">entries</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">():</span> <span class="n">to_cache</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="n">key</span> <span class="o">=</span> <span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="c"># make case insensitive</span> <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">CACHEABLE_GETINFO_PARAMS</span><span class="p">:</span> <span class="n">to_cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="k">elif</span> <span class="n">key</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'ip-to-country/'</span><span class="p">):</span> <span class="c"># both cache-able and means that we should reset the geoip failure count</span> <span class="n">to_cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="bp">self</span><span class="o">.</span><span class="n">_geoip_failure_count</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">(</span><span class="n">to_cache</span><span class="p">,</span> <span class="s">"getinfo"</span><span class="p">)</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">"GETINFO </span><span class="si">%s</span><span class="s"> (runtime: </span><span class="si">%0.4f</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span><span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">params</span><span class="p">),</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start_time</span><span class="p">))</span> <span class="k">if</span> <span class="n">is_multiple</span><span class="p">:</span> <span class="k">return</span> <span class="n">reply</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">reply</span><span class="o">.</span><span class="n">values</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="c"># bump geoip failure count if...</span> <span class="c"># * we're caching results</span> <span class="c"># * this was soley a geoip lookup</span> <span class="c"># * we've never had a successful geoip lookup (failure count isn't -1)</span> <span class="n">is_geoip_request</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">params</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span> <span class="nb">list</span><span class="p">(</span><span class="n">params</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'ip-to-country/'</span><span class="p">)</span> <span class="k">if</span> <span class="n">is_geoip_request</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">()</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_geoip_failure_count</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_geoip_failure_count</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_geoip_unavailable</span><span class="p">():</span> <span class="n">log</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s">"Tor's geoip database is unavailable."</span><span class="p">)</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">"GETINFO </span><span class="si">%s</span><span class="s"> (failed: </span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span><span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">params</span><span class="p">),</span> <span class="n">exc</span><span class="p">))</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_version"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_version">[docs]</a> <span class="k">def</span> <span class="nf">get_version</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> A convenience method to get tor version that current controller is</span> <span class="sd"> connected to.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`~stem.version.Version` of the tor instance that we're</span> <span class="sd"> connected to</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if unable to query the version</span> <span class="sd"> * **ValueError** if unable to parse the version</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="n">version</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache</span><span class="p">(</span><span class="s">"version"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">version</span><span class="p">:</span> <span class="n">version</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"version"</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">({</span><span class="s">"version"</span><span class="p">:</span> <span class="n">version</span><span class="p">})</span> <span class="k">return</span> <span class="n">version</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_exit_policy"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_exit_policy">[docs]</a> <span class="k">def</span> <span class="nf">get_exit_policy</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Effective ExitPolicy for our relay. This accounts for</span> <span class="sd"> ExitPolicyRejectPrivate and default policies.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`~stem.exit_policy.ExitPolicy` of the tor instance that</span> <span class="sd"> we're connected to</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if unable to query the policy</span> <span class="sd"> * **ValueError** if unable to parse the policy</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_msg_lock</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">config_policy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache</span><span class="p">(</span><span class="s">"exit_policy"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">config_policy</span><span class="p">:</span> <span class="n">policy</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">"ExitPolicyRejectPrivate"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"1"</span><span class="p">:</span> <span class="n">policy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">"reject private:*"</span><span class="p">)</span> <span class="n">public_addr</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"address"</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">public_addr</span><span class="p">:</span> <span class="n">policy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">"reject </span><span class="si">%s</span><span class="s">:*"</span> <span class="o">%</span> <span class="n">public_addr</span><span class="p">)</span> <span class="k">for</span> <span class="n">policy_line</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">"ExitPolicy"</span><span class="p">,</span> <span class="n">multiple</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span> <span class="n">policy</span> <span class="o">+=</span> <span class="n">policy_line</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">","</span><span class="p">)</span> <span class="n">policy</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"exit-policy/default"</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">","</span><span class="p">)</span> <span class="n">config_policy</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">exit_policy</span><span class="o">.</span><span class="n">get_config_policy</span><span class="p">(</span><span class="n">policy</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">({</span><span class="s">"exit_policy"</span><span class="p">:</span> <span class="n">config_policy</span><span class="p">})</span> <span class="k">return</span> <span class="n">config_policy</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_socks_listeners"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_socks_listeners">[docs]</a> <span class="k">def</span> <span class="nf">get_socks_listeners</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the SOCKS **(address, port)** tuples that tor has open.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: list of **(address, port)** tuples for the available SOCKS</span> <span class="sd"> listeners</span> <span class="sd"> :raises: :class:`stem.ControllerError` if unable to determine the listeners</span> <span class="sd"> and no default was provided</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="n">proxy_addrs</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">try</span><span class="p">:</span> <span class="k">for</span> <span class="n">listener</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"net/listeners/socks"</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">():</span> <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">listener</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'"'</span><span class="p">)</span> <span class="ow">and</span> <span class="n">listener</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'"'</span><span class="p">)):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"'GETINFO net/listeners/socks' responses are expected to be quoted: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">listener</span><span class="p">)</span> <span class="k">elif</span> <span class="ow">not</span> <span class="s">':'</span> <span class="ow">in</span> <span class="n">listener</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"'GETINFO net/listeners/socks' had a listener without a colon: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">listener</span><span class="p">)</span> <span class="n">listener</span> <span class="o">=</span> <span class="n">listener</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c"># strip quotes</span> <span class="n">addr</span><span class="p">,</span> <span class="n">port</span> <span class="o">=</span> <span class="n">listener</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">':'</span><span class="p">)</span> <span class="n">proxy_addrs</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">addr</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">:</span> <span class="c"># tor version is old (pre-tor-0.2.2.26-beta), use get_conf() instead</span> <span class="n">socks_port</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">'SocksPort'</span><span class="p">)</span> <span class="k">for</span> <span class="n">listener</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">'SocksListenAddress'</span><span class="p">,</span> <span class="n">multiple</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span> <span class="k">if</span> <span class="s">':'</span> <span class="ow">in</span> <span class="n">listener</span><span class="p">:</span> <span class="n">addr</span><span class="p">,</span> <span class="n">port</span> <span class="o">=</span> <span class="n">listener</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">':'</span><span class="p">)</span> <span class="n">proxy_addrs</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">addr</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="k">else</span><span class="p">:</span> <span class="n">proxy_addrs</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">listener</span><span class="p">,</span> <span class="n">socks_port</span><span class="p">))</span> <span class="c"># validate that address/ports are valid, and convert ports to ints</span> <span class="k">for</span> <span class="n">addr</span><span class="p">,</span> <span class="n">port</span> <span class="ow">in</span> <span class="n">proxy_addrs</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_ipv4_address</span><span class="p">(</span><span class="n">addr</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"Invalid address for a SOCKS listener: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">addr</span><span class="p">)</span> <span class="k">elif</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">is_valid_port</span><span class="p">(</span><span class="n">port</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"Invalid port for a SOCKS listener: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">port</span><span class="p">)</span> <span class="k">return</span> <span class="p">[(</span><span class="n">addr</span><span class="p">,</span> <span class="nb">int</span><span class="p">(</span><span class="n">port</span><span class="p">))</span> <span class="k">for</span> <span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span> <span class="ow">in</span> <span class="n">proxy_addrs</span><span class="p">]</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_protocolinfo"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_protocolinfo">[docs]</a> <span class="k">def</span> <span class="nf">get_protocolinfo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> A convenience method to get the protocol info of the controller.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`~stem.response.protocolinfo.ProtocolInfoResponse` provided by tor</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ProtocolError` if the PROTOCOLINFO response is</span> <span class="sd"> malformed</span> <span class="sd"> * :class:`stem.SocketError` if problems arise in establishing or</span> <span class="sd"> using the socket</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="kn">import</span> <span class="nn">stem.connection</span> <span class="k">try</span><span class="p">:</span> <span class="k">return</span> <span class="n">stem</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">get_protocolinfo</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_user"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_user">[docs]</a> <span class="k">def</span> <span class="nf">get_user</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the user tor is running as. This often only works if tor is</span> <span class="sd"> running locally. Also, most of its checks are platform dependent, and hence</span> <span class="sd"> are not entirely reliable.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: str with the username tor is running as</span> <span class="sd"> """</span> <span class="n">user</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache</span><span class="p">(</span><span class="s">"user"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">user</span><span class="p">:</span> <span class="n">user</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"process/user"</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">user</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_socket</span><span class="p">()</span><span class="o">.</span><span class="n">is_localhost</span><span class="p">():</span> <span class="n">pid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_pid</span><span class="p">(</span><span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">pid</span><span class="p">:</span> <span class="n">user</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">system</span><span class="o">.</span><span class="n">get_user</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span> <span class="k">if</span> <span class="n">user</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">({</span><span class="s">"user"</span><span class="p">:</span> <span class="n">user</span><span class="p">})</span> <span class="k">return</span> <span class="n">user</span> <span class="k">elif</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_socket</span><span class="p">()</span><span class="o">.</span><span class="n">is_localhost</span><span class="p">():</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Unable to resolve tor's user"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Tor isn't running locally"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_pid"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_pid">[docs]</a> <span class="k">def</span> <span class="nf">get_pid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the process id of tor. This often only works if tor is running</span> <span class="sd"> locally. Also, most of its checks are platform dependent, and hence are not</span> <span class="sd"> entirely reliable.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: int with our process' pid</span> <span class="sd"> :raises: **ValueError** if unable to determine the pid and no default was</span> <span class="sd"> provided</span> <span class="sd"> """</span> <span class="n">pid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache</span><span class="p">(</span><span class="s">"pid"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">pid</span><span class="p">:</span> <span class="n">getinfo_pid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"process/pid"</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">getinfo_pid</span> <span class="ow">and</span> <span class="n">getinfo_pid</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span> <span class="n">pid</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">getinfo_pid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">pid</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_socket</span><span class="p">()</span><span class="o">.</span><span class="n">is_localhost</span><span class="p">():</span> <span class="n">pid_file_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">"PidFile"</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">pid_file_path</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">pid_file_path</span><span class="p">)</span> <span class="k">as</span> <span class="n">pid_file</span><span class="p">:</span> <span class="n">pid_file_contents</span> <span class="o">=</span> <span class="n">pid_file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">if</span> <span class="n">pid_file_contents</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span> <span class="n">pid</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">pid_file_contents</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">pid</span><span class="p">:</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">system</span><span class="o">.</span><span class="n">get_pid_by_name</span><span class="p">(</span><span class="s">'tor'</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">pid</span><span class="p">:</span> <span class="n">control_socket</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_socket</span><span class="p">()</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">control_socket</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">ControlPort</span><span class="p">):</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">system</span><span class="o">.</span><span class="n">get_pid_by_port</span><span class="p">(</span><span class="n">control_socket</span><span class="o">.</span><span class="n">get_port</span><span class="p">())</span> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">control_socket</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">ControlSocketFile</span><span class="p">):</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">system</span><span class="o">.</span><span class="n">get_pid_by_open_file</span><span class="p">(</span><span class="n">control_socket</span><span class="o">.</span><span class="n">get_socket_path</span><span class="p">())</span> <span class="k">if</span> <span class="n">pid</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">({</span><span class="s">"pid"</span><span class="p">:</span> <span class="n">pid</span><span class="p">})</span> <span class="k">return</span> <span class="n">pid</span> <span class="k">elif</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_socket</span><span class="p">()</span><span class="o">.</span><span class="n">is_localhost</span><span class="p">():</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Unable to resolve tor's pid"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Tor isn't running locally"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_microdescriptor"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_microdescriptor">[docs]</a> <span class="k">def</span> <span class="nf">get_microdescriptor</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relay</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the microdescriptor for the relay with the given fingerprint or</span> <span class="sd"> nickname. If the relay identifier could be either a fingerprint *or*</span> <span class="sd"> nickname then it's queried as a fingerprint.</span> <span class="sd"> :param str relay: fingerprint or nickname of the relay to be queried</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`~stem.descriptor.microdescriptor.Microdescriptor` for the given relay</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if unable to query the descriptor</span> <span class="sd"> * **ValueError** if **relay** doesn't conform with the pattern for being</span> <span class="sd"> a fingerprint or nickname</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="k">if</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">relay</span><span class="p">):</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"md/id/</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">relay</span> <span class="k">elif</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_nickname</span><span class="p">(</span><span class="n">relay</span><span class="p">):</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"md/name/</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">relay</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"'</span><span class="si">%s</span><span class="s">' isn't a valid fingerprint or nickname"</span> <span class="o">%</span> <span class="n">relay</span><span class="p">)</span> <span class="n">desc_content</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">get_bytes</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span> <span class="k">return</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">microdescriptor</span><span class="o">.</span><span class="n">Microdescriptor</span><span class="p">(</span><span class="n">desc_content</span><span class="p">)</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_microdescriptors"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_microdescriptors">[docs]</a> <span class="k">def</span> <span class="nf">get_microdescriptors</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides an iterator for all of the microdescriptors that tor presently</span> <span class="sd"> knows about.</span> <span class="sd"> **Tor does not expose this information via the control protocol**</span> <span class="sd"> (:trac:`8323`). Until it does this reads the microdescriptors from disk,</span> <span class="sd"> and hence won't work remotely or if we lack read permissions.</span> <span class="sd"> :param list default: items to provide if the query fails</span> <span class="sd"> :returns: iterates over</span> <span class="sd"> :class:`~stem.descriptor.microdescriptor.Microdescriptor` for relays in</span> <span class="sd"> the tor network</span> <span class="sd"> :raises: :class:`stem.ControllerError` if unable to query tor and no</span> <span class="sd"> default was provided</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">data_directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">"DataDirectory"</span><span class="p">)</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">OperationFailed</span><span class="p">(</span><span class="n">message</span> <span class="o">=</span> <span class="s">"Unable to determine the data directory (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">exc</span><span class="p">)</span> <span class="n">cached_descriptor_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">data_directory</span><span class="p">,</span> <span class="s">"cached-microdescs"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">data_directory</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">OperationFailed</span><span class="p">(</span><span class="n">message</span> <span class="o">=</span> <span class="s">"Data directory reported by tor doesn't exist (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">data_directory</span><span class="p">)</span> <span class="k">elif</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">cached_descriptor_path</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">OperationFailed</span><span class="p">(</span><span class="n">message</span> <span class="o">=</span> <span class="s">"Data directory doens't contain cached microescriptors (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">cached_descriptor_path</span><span class="p">)</span> <span class="k">with</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">reader</span><span class="o">.</span><span class="n">DescriptorReader</span><span class="p">([</span><span class="n">cached_descriptor_path</span><span class="p">])</span> <span class="k">as</span> <span class="n">reader</span><span class="p">:</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span> <span class="c"># It shouldn't be possible for these to be something other than</span> <span class="c"># microdescriptors but as the saying goes: trust but verify.</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">desc</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">microdescriptor</span><span class="o">.</span><span class="n">Microdescriptor</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">OperationFailed</span><span class="p">(</span><span class="n">message</span> <span class="o">=</span> <span class="s">"BUG: Descriptor reader provided non-microdescriptor content (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="nb">type</span><span class="p">(</span><span class="n">desc</span><span class="p">))</span> <span class="k">yield</span> <span class="n">desc</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">default</span><span class="p">:</span> <span class="k">yield</span> <span class="n">entry</span> </div> <div class="viewcode-block" id="Controller.get_server_descriptor"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_server_descriptor">[docs]</a> <span class="k">def</span> <span class="nf">get_server_descriptor</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relay</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the server descriptor for the relay with the given fingerprint or</span> <span class="sd"> nickname. If the relay identifier could be either a fingerprint *or*</span> <span class="sd"> nickname then it's queried as a fingerprint.</span> <span class="sd"> **As of Tor version 0.2.3.25 relays no longer get server descriptors by</span> <span class="sd"> default.** It's advised that you use microdescriptors instead, but if you</span> <span class="sd"> really need server descriptors then you can get them by setting</span> <span class="sd"> 'UseMicrodescriptors 0'.</span> <span class="sd"> :param str relay: fingerprint or nickname of the relay to be queried</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`~stem.descriptor.server_descriptor.RelayDescriptor` for the given relay</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if unable to query the descriptor</span> <span class="sd"> * **ValueError** if **relay** doesn't conform with the pattern for being</span> <span class="sd"> a fingerprint or nickname</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="k">if</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">relay</span><span class="p">):</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"desc/id/</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">relay</span> <span class="k">elif</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_nickname</span><span class="p">(</span><span class="n">relay</span><span class="p">):</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"desc/name/</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">relay</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"'</span><span class="si">%s</span><span class="s">' isn't a valid fingerprint or nickname"</span> <span class="o">%</span> <span class="n">relay</span><span class="p">)</span> <span class="n">desc_content</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">get_bytes</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span> <span class="k">return</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">server_descriptor</span><span class="o">.</span><span class="n">RelayDescriptor</span><span class="p">(</span><span class="n">desc_content</span><span class="p">)</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_server_descriptors_available</span><span class="p">():</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="n">SERVER_DESCRIPTORS_UNSUPPORTED</span><span class="p">)</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_server_descriptors"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_server_descriptors">[docs]</a> <span class="k">def</span> <span class="nf">get_server_descriptors</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides an iterator for all of the server descriptors that tor presently</span> <span class="sd"> knows about.</span> <span class="sd"> **As of Tor version 0.2.3.25 relays no longer get server descriptors by</span> <span class="sd"> default.** It's advised that you use microdescriptors instead, but if you</span> <span class="sd"> really need server descriptors then you can get them by setting</span> <span class="sd"> 'UseMicrodescriptors 0'.</span> <span class="sd"> :param list default: items to provide if the query fails</span> <span class="sd"> :returns: iterates over</span> <span class="sd"> :class:`~stem.descriptor.server_descriptor.RelayDescriptor` for relays in</span> <span class="sd"> the tor network</span> <span class="sd"> :raises: :class:`stem.ControllerError` if unable to query tor and no</span> <span class="sd"> default was provided</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="c"># TODO: We should iterate over the descriptors as they're read from the</span> <span class="c"># socket rather than reading the whole thing into memory.</span> <span class="c">#</span> <span class="c"># https://trac.torproject.org/8248</span> <span class="n">desc_content</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"desc/all-recent"</span><span class="p">,</span> <span class="n">get_bytes</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">desc_content</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_server_descriptors_available</span><span class="p">():</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="n">SERVER_DESCRIPTORS_UNSUPPORTED</span><span class="p">)</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">server_descriptor</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">desc_content</span><span class="p">)):</span> <span class="k">yield</span> <span class="n">desc</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">default</span><span class="p">:</span> <span class="k">yield</span> <span class="n">entry</span> </div> <span class="k">def</span> <span class="nf">_is_server_descriptors_available</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Checks to see if tor server descriptors should be available or not.</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_version</span><span class="p">()</span> <span class="o"><</span> <span class="n">stem</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">Requirement</span><span class="o">.</span><span class="n">MICRODESCRIPTOR_IS_DEFAULT</span> <span class="ow">or</span> \ <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">'UseMicrodescriptors'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="o">==</span> <span class="s">'0'</span> <div class="viewcode-block" id="Controller.get_network_status"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_network_status">[docs]</a> <span class="k">def</span> <span class="nf">get_network_status</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relay</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the router status entry for the relay with the given fingerprint</span> <span class="sd"> or nickname. If the relay identifier could be either a fingerprint *or*</span> <span class="sd"> nickname then it's queried as a fingerprint.</span> <span class="sd"> :param str relay: fingerprint or nickname of the relay to be queried</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3`</span> <span class="sd"> for the given relay</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if unable to query the descriptor</span> <span class="sd"> * **ValueError** if **relay** doesn't conform with the pattern for being</span> <span class="sd"> a fingerprint or nickname</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="c"># TODO: It would be great to add support for v3 router status entries. This</span> <span class="c"># is pending...</span> <span class="c">#</span> <span class="c"># https://trac.torproject.org/7953</span> <span class="k">try</span><span class="p">:</span> <span class="k">if</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">relay</span><span class="p">):</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"ns/id/</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">relay</span> <span class="k">elif</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_nickname</span><span class="p">(</span><span class="n">relay</span><span class="p">):</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"ns/name/</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">relay</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"'</span><span class="si">%s</span><span class="s">' isn't a valid fingerprint or nickname"</span> <span class="o">%</span> <span class="n">relay</span><span class="p">)</span> <span class="n">desc_content</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">get_bytes</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span> <span class="k">return</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV3</span><span class="p">(</span><span class="n">desc_content</span><span class="p">)</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_network_statuses"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_network_statuses">[docs]</a> <span class="k">def</span> <span class="nf">get_network_statuses</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides an iterator for all of the router status entries that tor</span> <span class="sd"> presently knows about.</span> <span class="sd"> :param list default: items to provide if the query fails</span> <span class="sd"> :returns: iterates over</span> <span class="sd"> :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` for</span> <span class="sd"> relays in the tor network</span> <span class="sd"> :raises: :class:`stem.ControllerError` if unable to query tor and no</span> <span class="sd"> default was provided</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="c"># TODO: We should iterate over the descriptors as they're read from the</span> <span class="c"># socket rather than reading the whole thing into memory.</span> <span class="c">#</span> <span class="c"># https://trac.torproject.org/8248</span> <span class="n">desc_content</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"ns/all"</span><span class="p">,</span> <span class="n">get_bytes</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span> <span class="n">desc_iterator</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">_parse_file</span><span class="p">(</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">desc_content</span><span class="p">),</span> <span class="bp">True</span><span class="p">,</span> <span class="n">entry_class</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">descriptor</span><span class="o">.</span><span class="n">router_status_entry</span><span class="o">.</span><span class="n">RouterStatusEntryV3</span><span class="p">,</span> <span class="p">)</span> <span class="k">for</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">desc_iterator</span><span class="p">:</span> <span class="k">yield</span> <span class="n">desc</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">default</span><span class="p">:</span> <span class="k">yield</span> <span class="n">entry</span> </div> <div class="viewcode-block" id="Controller.get_conf"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_conf">[docs]</a> <span class="k">def</span> <span class="nf">get_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">param</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">,</span> <span class="n">multiple</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Queries the current value for a configuration option. Some configuration</span> <span class="sd"> options (like the ExitPolicy) can have multiple values. This provides a</span> <span class="sd"> **list** with all of the values if **multiple** is **True**. Otherwise this</span> <span class="sd"> will be a **str** with the first value.</span> <span class="sd"> If provided with a **default** then that is provided if the configuration</span> <span class="sd"> option was unset or the query fails (invalid configuration option, error</span> <span class="sd"> response, control port closed, initiated, etc).</span> <span class="sd"> If the configuration value is unset and no **default** was given then this</span> <span class="sd"> provides **None** if **multiple** was **False** and an empty list if it was</span> <span class="sd"> **True**.</span> <span class="sd"> :param str param: configuration option to be queried</span> <span class="sd"> :param object default: response if the option is unset or the query fails</span> <span class="sd"> :param bool multiple: if **True** then provides a list with all of the</span> <span class="sd"> present values (this is an empty list if the config option is unset)</span> <span class="sd"> :returns:</span> <span class="sd"> Response depends upon how we were called as follows...</span> <span class="sd"> * **str** with the configuration value if **multiple** was **False**,</span> <span class="sd"> **None** if it was unset</span> <span class="sd"> * **list** with the response strings if multiple was **True**</span> <span class="sd"> * default if one was provided and the configuration option was either</span> <span class="sd"> unset or our call failed</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails and we weren't</span> <span class="sd"> provided a default response</span> <span class="sd"> * :class:`stem.InvalidArguments` if the configuration option</span> <span class="sd"> requested was invalid</span> <span class="sd"> """</span> <span class="c"># Config options are case insensitive and don't contain whitespace. Using</span> <span class="c"># strip so the following check will catch whitespace-only params.</span> <span class="n">param</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">param</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> <span class="k">if</span> <span class="n">default</span> <span class="o">!=</span> <span class="n">UNDEFINED</span> <span class="k">else</span> <span class="bp">None</span> <span class="n">entries</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf_map</span><span class="p">(</span><span class="n">param</span><span class="p">,</span> <span class="n">default</span><span class="p">,</span> <span class="n">multiple</span><span class="p">)</span> <span class="k">return</span> <span class="n">_case_insensitive_lookup</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">param</span><span class="p">,</span> <span class="n">default</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.get_conf_map"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_conf_map">[docs]</a> <span class="k">def</span> <span class="nf">get_conf_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">,</span> <span class="n">multiple</span> <span class="o">=</span> <span class="bp">True</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Similar to :func:`~stem.control.Controller.get_conf` but queries multiple</span> <span class="sd"> configuration options, providing back a mapping of those options to their</span> <span class="sd"> values.</span> <span class="sd"> There are three use cases for GETCONF:</span> <span class="sd"> 1. a single value is provided (e.g. **ControlPort**)</span> <span class="sd"> 2. multiple values are provided for the option (e.g. **ExitPolicy**)</span> <span class="sd"> 3. a set of options that weren't necessarily requested are returned (for</span> <span class="sd"> instance querying **HiddenServiceOptions** gives **HiddenServiceDir**,</span> <span class="sd"> **HiddenServicePort**, etc)</span> <span class="sd"> The vast majority of the options fall into the first two categories, in</span> <span class="sd"> which case calling :func:`~stem.control.Controller.get_conf` is sufficient.</span> <span class="sd"> However, for batch queries or the special options that give a set of values</span> <span class="sd"> this provides back the full response. As of tor version 0.2.1.25</span> <span class="sd"> **HiddenServiceOptions** was the only option that falls into the third</span> <span class="sd"> category.</span> <span class="sd"> :param str,list params: configuration option(s) to be queried</span> <span class="sd"> :param object default: value for the mappings if the configuration option</span> <span class="sd"> is either undefined or the query fails</span> <span class="sd"> :param bool multiple: if **True** then the values provided are lists with</span> <span class="sd"> all of the present values</span> <span class="sd"> :returns:</span> <span class="sd"> **dict** of the 'config key => value' mappings. The value is a...</span> <span class="sd"> * **str** if **multiple** is **False**, **None** if the configuration</span> <span class="sd"> option is unset</span> <span class="sd"> * **list** if **multiple** is **True**</span> <span class="sd"> * the **default** if it was set and the value was either undefined or our</span> <span class="sd"> lookup failed</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails and we weren't provided</span> <span class="sd"> a default response</span> <span class="sd"> * :class:`stem.InvalidArguments` if the configuration option requested</span> <span class="sd"> was invalid</span> <span class="sd"> """</span> <span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="n">reply</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="p">(</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)):</span> <span class="n">params</span> <span class="o">=</span> <span class="p">[</span><span class="n">params</span><span class="p">]</span> <span class="c"># remove strings which contain only whitespace</span> <span class="n">params</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">entry</span><span class="p">:</span> <span class="n">entry</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="n">params</span><span class="p">)</span> <span class="k">if</span> <span class="n">params</span> <span class="o">==</span> <span class="p">[]:</span> <span class="k">return</span> <span class="p">{}</span> <span class="c"># translate context sensitive options</span> <span class="n">lookup_params</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">MAPPED_CONFIG_KEYS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">entry</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">params</span><span class="p">])</span> <span class="c"># check for cached results</span> <span class="n">from_cache</span> <span class="o">=</span> <span class="p">[</span><span class="n">param</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">lookup_params</span><span class="p">]</span> <span class="n">cached_results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache_map</span><span class="p">(</span><span class="n">from_cache</span><span class="p">,</span> <span class="s">"getconf"</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">cached_results</span><span class="p">:</span> <span class="n">user_expected_key</span> <span class="o">=</span> <span class="n">_case_insensitive_lookup</span><span class="p">(</span><span class="n">lookup_params</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="n">reply</span><span class="p">[</span><span class="n">user_expected_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">cached_results</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="n">lookup_params</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">user_expected_key</span><span class="p">)</span> <span class="c"># if everything was cached then short circuit making the query</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">lookup_params</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">trace</span><span class="p">(</span><span class="s">"GETCONF </span><span class="si">%s</span><span class="s"> (cache fetch)"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">reply</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_conf_dict_to_response</span><span class="p">(</span><span class="n">reply</span><span class="p">,</span> <span class="n">default</span><span class="p">,</span> <span class="n">multiple</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"GETCONF </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">' '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">lookup_params</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"GETCONF"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="n">reply</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">entries</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">():</span> <span class="n">to_cache</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">k</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">UNCACHEABLE_GETCONF_PARAMS</span><span class="p">:</span> <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">to_cache</span><span class="p">:</span> <span class="k">del</span> <span class="n">to_cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">(</span><span class="n">to_cache</span><span class="p">,</span> <span class="s">"getconf"</span><span class="p">)</span> <span class="c"># Maps the entries back to the parameters that the user requested so the</span> <span class="c"># capitalization matches (ie, if they request "exitpolicy" then that</span> <span class="c"># should be the key rather than "ExitPolicy"). When the same</span> <span class="c"># configuration key is provided multiple times this determines the case</span> <span class="c"># based on the first and ignores the rest.</span> <span class="c">#</span> <span class="c"># This retains the tor provided camel casing of MAPPED_CONFIG_KEYS</span> <span class="c"># entries since the user didn't request those by their key, so we can't</span> <span class="c"># be sure what they wanted.</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">reply</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="n">MAPPED_CONFIG_KEYS</span><span class="o">.</span><span class="n">values</span><span class="p">():</span> <span class="n">user_expected_key</span> <span class="o">=</span> <span class="n">_case_insensitive_lookup</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">key</span> <span class="o">!=</span> <span class="n">user_expected_key</span><span class="p">:</span> <span class="n">reply</span><span class="p">[</span><span class="n">user_expected_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">reply</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="k">del</span> <span class="n">reply</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">"GETCONF </span><span class="si">%s</span><span class="s"> (runtime: </span><span class="si">%0.4f</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span><span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">lookup_params</span><span class="p">),</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start_time</span><span class="p">))</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_conf_dict_to_response</span><span class="p">(</span><span class="n">reply</span><span class="p">,</span> <span class="n">default</span><span class="p">,</span> <span class="n">multiple</span><span class="p">)</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">"GETCONF </span><span class="si">%s</span><span class="s"> (failed: </span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span><span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">lookup_params</span><span class="p">),</span> <span class="n">exc</span><span class="p">))</span> <span class="k">if</span> <span class="n">default</span> <span class="o">!=</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">return</span> <span class="nb">dict</span><span class="p">((</span><span class="n">param</span><span class="p">,</span> <span class="n">default</span><span class="p">)</span> <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> </div> <span class="k">def</span> <span class="nf">_get_conf_dict_to_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config_dict</span><span class="p">,</span> <span class="n">default</span><span class="p">,</span> <span class="n">multiple</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Translates a dictionary of 'config key => [value1, value2...]' into the</span> <span class="sd"> return value of :func:`~stem.control.Controller.get_conf_map`, taking into</span> <span class="sd"> account what the caller requested.</span> <span class="sd"> """</span> <span class="n">return_dict</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">values</span> <span class="ow">in</span> <span class="n">config_dict</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="k">if</span> <span class="n">values</span> <span class="o">==</span> <span class="p">[]:</span> <span class="c"># config option was unset</span> <span class="k">if</span> <span class="n">default</span> <span class="o">!=</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="n">return_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">default</span> <span class="k">else</span><span class="p">:</span> <span class="n">return_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">multiple</span> <span class="k">else</span> <span class="bp">None</span> <span class="k">else</span><span class="p">:</span> <span class="n">return_dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">values</span> <span class="k">if</span> <span class="n">multiple</span> <span class="k">else</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">return</span> <span class="n">return_dict</span> <div class="viewcode-block" id="Controller.set_conf"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.set_conf">[docs]</a> <span class="k">def</span> <span class="nf">set_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">param</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Changes the value of a tor configuration option. Our value can be any of</span> <span class="sd"> the following...</span> <span class="sd"> * a string to set a single value</span> <span class="sd"> * a list of strings to set a series of values (for instance the ExitPolicy)</span> <span class="sd"> * None to either set the value to 0/NULL</span> <span class="sd"> :param str param: configuration option to be set</span> <span class="sd"> :param str,list value: value to set the parameter to</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> * :class:`stem.InvalidArguments` if configuration options</span> <span class="sd"> requested was invalid</span> <span class="sd"> * :class:`stem.InvalidRequest` if the configuration setting is</span> <span class="sd"> impossible or if there's a syntax error in the configuration values</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">set_options</span><span class="p">({</span><span class="n">param</span><span class="p">:</span> <span class="n">value</span><span class="p">},</span> <span class="bp">False</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.reset_conf"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.reset_conf">[docs]</a> <span class="k">def</span> <span class="nf">reset_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">params</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Reverts one or more parameters to their default values.</span> <span class="sd"> :param str params: configuration option to be reset</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> * :class:`stem.InvalidArguments` if configuration options requested was invalid</span> <span class="sd"> * :class:`stem.InvalidRequest` if the configuration setting is</span> <span class="sd"> impossible or if there's a syntax error in the configuration values</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">set_options</span><span class="p">(</span><span class="nb">dict</span><span class="p">([(</span><span class="n">entry</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">params</span><span class="p">]),</span> <span class="bp">True</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.set_options"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.set_options">[docs]</a> <span class="k">def</span> <span class="nf">set_options</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">reset</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Changes multiple tor configuration options via either a SETCONF or</span> <span class="sd"> RESETCONF query. Both behave identically unless our value is None, in which</span> <span class="sd"> case SETCONF sets the value to 0 or NULL, and RESETCONF returns it to its</span> <span class="sd"> default value. This accepts str, list, or None values in a similar fashion</span> <span class="sd"> to :func:`~stem.control.Controller.set_conf`. For example...</span> <span class="sd"> ::</span> <span class="sd"> my_controller.set_options({</span> <span class="sd"> "Nickname": "caerSidi",</span> <span class="sd"> "ExitPolicy": ["accept *:80", "accept *:443", "reject *:*"],</span> <span class="sd"> "ContactInfo": "caerSidi-exit@someplace.com",</span> <span class="sd"> "Log": None,</span> <span class="sd"> })</span> <span class="sd"> The params can optionally be a list of key/value tuples, though the only</span> <span class="sd"> reason this type of argument would be useful is for hidden service</span> <span class="sd"> configuration (those options are order dependent).</span> <span class="sd"> :param dict,list params: mapping of configuration options to the values</span> <span class="sd"> we're setting it to</span> <span class="sd"> :param bool reset: issues a RESETCONF, returning **None** values to their</span> <span class="sd"> defaults if **True**</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> * :class:`stem.InvalidArguments` if configuration options</span> <span class="sd"> requested was invalid</span> <span class="sd"> * :class:`stem.InvalidRequest` if the configuration setting is</span> <span class="sd"> impossible or if there's a syntax error in the configuration values</span> <span class="sd"> """</span> <span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="c"># constructs the SETCONF or RESETCONF query</span> <span class="n">query_comp</span> <span class="o">=</span> <span class="p">[</span><span class="s">"RESETCONF"</span> <span class="k">if</span> <span class="n">reset</span> <span class="k">else</span> <span class="s">"SETCONF"</span><span class="p">]</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span> <span class="n">params</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">for</span> <span class="n">param</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span> <span class="n">query_comp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s">=</span><span class="se">\"</span><span class="si">%s</span><span class="se">\"</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">param</span><span class="p">,</span> <span class="n">value</span><span class="o">.</span><span class="n">strip</span><span class="p">()))</span> <span class="k">elif</span> <span class="n">value</span><span class="p">:</span> <span class="n">query_comp</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="s">"</span><span class="si">%s</span><span class="s">=</span><span class="se">\"</span><span class="si">%s</span><span class="se">\"</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">param</span><span class="p">,</span> <span class="n">val</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span> <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">value</span><span class="p">])</span> <span class="k">else</span><span class="p">:</span> <span class="n">query_comp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">param</span><span class="p">)</span> <span class="n">query</span> <span class="o">=</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">query_comp</span><span class="p">)</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">query</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s"> (runtime: </span><span class="si">%0.4f</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start_time</span><span class="p">))</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">():</span> <span class="n">to_cache</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">param</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span> <span class="n">param</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="p">(</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)):</span> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="n">value</span><span class="p">]</span> <span class="n">to_cache</span><span class="p">[</span><span class="n">param</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="k">if</span> <span class="n">param</span> <span class="o">==</span> <span class="s">"exitpolicy"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">({</span><span class="s">"exitpolicy"</span><span class="p">:</span> <span class="bp">None</span><span class="p">})</span> <span class="bp">self</span><span class="o">.</span><span class="n">_set_cache</span><span class="p">(</span><span class="n">to_cache</span><span class="p">,</span> <span class="s">"getconf"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s"> (failed, code: </span><span class="si">%s</span><span class="s">, message: </span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">))</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">"552"</span><span class="p">:</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"Unrecognized option: Unknown option '"</span><span class="p">):</span> <span class="n">key</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">[</span><span class="mi">37</span><span class="p">:</span><span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">"</span><span class="se">\'</span><span class="s">"</span><span class="p">,</span> <span class="mi">37</span><span class="p">)]</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="p">[</span><span class="n">key</span><span class="p">])</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">elif</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="ow">in</span> <span class="p">(</span><span class="s">"513"</span><span class="p">,</span> <span class="s">"553"</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"Returned unexpected status code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.add_event_listener"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.add_event_listener">[docs]</a> <span class="k">def</span> <span class="nf">add_event_listener</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">listener</span><span class="p">,</span> <span class="o">*</span><span class="n">events</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Directs further tor controller events to a given function. The function is</span> <span class="sd"> expected to take a single argument, which is a</span> <span class="sd"> :class:`~stem.response.events.Event` subclass. For instance the following</span> <span class="sd"> would print the bytes sent and received by tor over five seconds...</span> <span class="sd"> ::</span> <span class="sd"> import time</span> <span class="sd"> from stem.control import Controller, EventType</span> <span class="sd"> def print_bw(event):</span> <span class="sd"> print "sent: %i, received: %i" % (event.written, event.read)</span> <span class="sd"> with Controller.from_port(port = 9051) as controller:</span> <span class="sd"> controller.authenticate()</span> <span class="sd"> controller.add_event_listener(print_bw, EventType.BW)</span> <span class="sd"> time.sleep(5)</span> <span class="sd"> If a new control connection is initialized then this listener will be</span> <span class="sd"> reattached.</span> <span class="sd"> :param functor listener: function to be called when an event is received</span> <span class="sd"> :param stem.control.EventType events: event types to be listened for</span> <span class="sd"> :raises: :class:`stem.ProtocolError` if unable to set the events</span> <span class="sd"> """</span> <span class="c"># first checking that tor supports these event types</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners_lock</span><span class="p">:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_authenticated</span><span class="p">():</span> <span class="k">for</span> <span class="n">event_type</span> <span class="ow">in</span> <span class="n">events</span><span class="p">:</span> <span class="n">event_version</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">events</span><span class="o">.</span><span class="n">EVENT_TYPE_TO_CLASS</span><span class="p">[</span><span class="n">event_type</span><span class="p">]</span><span class="o">.</span><span class="n">_VERSION_ADDED</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_version</span><span class="p">()</span> <span class="o"><</span> <span class="n">event_version</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="mi">552</span><span class="p">,</span> <span class="s">"</span><span class="si">%s</span><span class="s"> event requires Tor version </span><span class="si">%s</span><span class="s"> or later"</span> <span class="o">%</span> <span class="p">(</span><span class="n">event_type</span><span class="p">,</span> <span class="n">event_version</span><span class="p">))</span> <span class="k">for</span> <span class="n">event_type</span> <span class="ow">in</span> <span class="n">events</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">event_type</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">listener</span><span class="p">)</span> <span class="n">failed_events</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_attach_listeners</span><span class="p">()[</span><span class="mi">1</span><span class="p">]</span> <span class="c"># restricted the failures to just things we requested</span> <span class="n">failed_events</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">failed_events</span><span class="p">)</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">events</span><span class="p">))</span> <span class="k">if</span> <span class="n">failed_events</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"SETEVENTS rejected </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">failed_events</span><span class="p">))</span> </div> <div class="viewcode-block" id="Controller.remove_event_listener"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.remove_event_listener">[docs]</a> <span class="k">def</span> <span class="nf">remove_event_listener</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">listener</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Stops a listener from being notified of further tor events.</span> <span class="sd"> :param stem.control.EventListener listener: listener to be removed</span> <span class="sd"> :raises: :class:`stem.ProtocolError` if unable to set the events</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners_lock</span><span class="p">:</span> <span class="n">event_types_changed</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">for</span> <span class="n">event_type</span><span class="p">,</span> <span class="n">event_listeners</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="k">if</span> <span class="n">listener</span> <span class="ow">in</span> <span class="n">event_listeners</span><span class="p">:</span> <span class="n">event_listeners</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">listener</span><span class="p">)</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">event_listeners</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="n">event_types_changed</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="p">[</span><span class="n">event_type</span><span class="p">]</span> <span class="k">if</span> <span class="n">event_types_changed</span><span class="p">:</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"SETEVENTS </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"SETEVENTS received unexpected response</span><span class="se">\n</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="p">)</span> </div> <span class="k">def</span> <span class="nf">_get_cache</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">param</span><span class="p">,</span> <span class="n">namespace</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Queries our request cache for the given key.</span> <span class="sd"> :param str param: key to be queried</span> <span class="sd"> :param str namespace: namespace in which to check for the key</span> <span class="sd"> :returns: cached value corresponding to key or **None** if the key wasn't found</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cache_map</span><span class="p">([</span><span class="n">param</span><span class="p">],</span> <span class="n">namespace</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">param</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_get_cache_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">namespace</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Queries our request cache for multiple entries.</span> <span class="sd"> :param list params: keys to be queried</span> <span class="sd"> :param str namespace: namespace in which to check for the keys</span> <span class="sd"> :returns: **dict** of 'param => cached value' pairs of keys present in cache</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache_lock</span><span class="p">:</span> <span class="n">cached_values</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">():</span> <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span> <span class="k">if</span> <span class="n">namespace</span><span class="p">:</span> <span class="n">cache_key</span> <span class="o">=</span> <span class="s">"</span><span class="si">%s</span><span class="s">.</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">namespace</span><span class="p">,</span> <span class="n">param</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">cache_key</span> <span class="o">=</span> <span class="n">param</span> <span class="k">if</span> <span class="n">cache_key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span><span class="p">:</span> <span class="n">cached_values</span><span class="p">[</span><span class="n">param</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span><span class="p">[</span><span class="n">cache_key</span><span class="p">]</span> <span class="k">return</span> <span class="n">cached_values</span> <span class="k">def</span> <span class="nf">_set_cache</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">namespace</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Sets the given request cache entries. If the new cache value is **None**</span> <span class="sd"> then it is removed from our cache.</span> <span class="sd"> :param dict params: **dict** of 'cache_key => value' pairs to be cached</span> <span class="sd"> :param str namespace: namespace for the keys</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache_lock</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_caching_enabled</span><span class="p">():</span> <span class="k">return</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">params</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="k">if</span> <span class="n">namespace</span><span class="p">:</span> <span class="n">cache_key</span> <span class="o">=</span> <span class="s">"</span><span class="si">%s</span><span class="s">.</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">namespace</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">cache_key</span> <span class="o">=</span> <span class="n">key</span> <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> <span class="k">if</span> <span class="n">cache_key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span><span class="p">:</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span><span class="p">[</span><span class="n">cache_key</span><span class="p">]</span> <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span><span class="p">[</span><span class="n">cache_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <div class="viewcode-block" id="Controller.is_caching_enabled"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.is_caching_enabled">[docs]</a> <span class="k">def</span> <span class="nf">is_caching_enabled</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> **True** if caching has been enabled, **False** otherwise.</span> <span class="sd"> :returns: bool to indicate if caching is enabled</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_caching_enabled</span> </div> <div class="viewcode-block" id="Controller.set_caching"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.set_caching">[docs]</a> <span class="k">def</span> <span class="nf">set_caching</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">enabled</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Enables or disables caching of information retrieved from tor.</span> <span class="sd"> :param bool enabled: **True** to enable caching, **False** to disable it</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_caching_enabled</span> <span class="o">=</span> <span class="n">enabled</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_caching_enabled</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">clear_cache</span><span class="p">()</span> </div> <div class="viewcode-block" id="Controller.clear_cache"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.clear_cache">[docs]</a> <span class="k">def</span> <span class="nf">clear_cache</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Drops any cached results.</span> <span class="sd"> """</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache_lock</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_request_cache</span> <span class="o">=</span> <span class="p">{}</span> <span class="bp">self</span><span class="o">.</span><span class="n">_geoip_failure_count</span> <span class="o">=</span> <span class="mi">0</span> </div> <div class="viewcode-block" id="Controller.load_conf"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.load_conf">[docs]</a> <span class="k">def</span> <span class="nf">load_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">configtext</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Sends the configuration text to Tor and loads it as if it has been read from</span> <span class="sd"> the torrc.</span> <span class="sd"> :param str configtext: the configuration text</span> <span class="sd"> :raises: :class:`stem.ControllerError` if the call fails</span> <span class="sd"> """</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"LOADCONF</span><span class="se">\n</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">configtext</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="ow">in</span> <span class="p">(</span><span class="s">"552"</span><span class="p">,</span> <span class="s">"553"</span><span class="p">):</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">"552"</span> <span class="ow">and</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"Invalid config file: Failed to parse/validate config: Unknown option"</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="p">[</span><span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">[</span><span class="mi">70</span><span class="p">:</span><span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">'.'</span><span class="p">,</span> <span class="mi">70</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]])</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">elif</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"+LOADCONF Received unexpected response</span><span class="se">\n</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">response</span><span class="p">))</span> </div> <div class="viewcode-block" id="Controller.save_conf"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.save_conf">[docs]</a> <span class="k">def</span> <span class="nf">save_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Saves the current configuration options into the active torrc file.</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> * :class:`stem.OperationFailed` if the client is unable to save</span> <span class="sd"> the configuration file</span> <span class="sd"> """</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"SAVECONF"</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">elif</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">"551"</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">OperationFailed</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"SAVECONF returned unexpected response code"</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.is_feature_enabled"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.is_feature_enabled">[docs]</a> <span class="k">def</span> <span class="nf">is_feature_enabled</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">feature</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Checks if a control connection feature is enabled. These features can be</span> <span class="sd"> enabled using :func:`~stem.control.Controller.enable_feature`.</span> <span class="sd"> :param str feature: feature to be checked</span> <span class="sd"> :returns: **True** if feature is enabled, **False** otherwise</span> <span class="sd"> """</span> <span class="n">feature</span> <span class="o">=</span> <span class="n">feature</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span> <span class="k">if</span> <span class="n">feature</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_enabled_features</span><span class="p">:</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">else</span><span class="p">:</span> <span class="c"># check if this feature is on by default</span> <span class="n">defaulted_version</span> <span class="o">=</span> <span class="bp">None</span> <span class="k">if</span> <span class="n">feature</span> <span class="o">==</span> <span class="s">"EXTENDED_EVENTS"</span><span class="p">:</span> <span class="n">defaulted_version</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">Requirement</span><span class="o">.</span><span class="n">FEATURE_EXTENDED_EVENTS</span> <span class="k">elif</span> <span class="n">feature</span> <span class="o">==</span> <span class="s">"VERBOSE_NAMES"</span><span class="p">:</span> <span class="n">defaulted_version</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">Requirement</span><span class="o">.</span><span class="n">FEATURE_VERBOSE_NAMES</span> <span class="k">if</span> <span class="n">defaulted_version</span><span class="p">:</span> <span class="n">our_version</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_version</span><span class="p">(</span><span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">our_version</span> <span class="ow">and</span> <span class="n">our_version</span> <span class="o">>=</span> <span class="n">defaulted_version</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_enabled_features</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">feature</span><span class="p">)</span> <span class="k">return</span> <span class="n">feature</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_enabled_features</span> </div> <div class="viewcode-block" id="Controller.enable_feature"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.enable_feature">[docs]</a> <span class="k">def</span> <span class="nf">enable_feature</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">features</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Enables features that are disabled by default to maintain backward</span> <span class="sd"> compatibility. Once enabled, a feature cannot be disabled and a new</span> <span class="sd"> control connection must be opened to get a connection with the feature</span> <span class="sd"> disabled. Feature names are case-insensitive.</span> <span class="sd"> The following features are currently accepted:</span> <span class="sd"> * EXTENDED_EVENTS - Requests the extended event syntax</span> <span class="sd"> * VERBOSE_NAMES - Replaces ServerID with LongName in events and GETINFO results</span> <span class="sd"> :param str,list features: a single feature or a list of features to be enabled</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> * :class:`stem.InvalidArguments` if features passed were invalid</span> <span class="sd"> """</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">features</span><span class="p">,</span> <span class="p">(</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)):</span> <span class="n">features</span> <span class="o">=</span> <span class="p">[</span><span class="n">features</span><span class="p">]</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"USEFEATURE </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">features</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">"552"</span><span class="p">:</span> <span class="n">invalid_feature</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"Unrecognized feature </span><span class="se">\"</span><span class="s">"</span><span class="p">):</span> <span class="n">invalid_feature</span> <span class="o">=</span> <span class="p">[</span><span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">[</span><span class="mi">22</span><span class="p">:</span><span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">"</span><span class="se">\"</span><span class="s">"</span><span class="p">,</span> <span class="mi">22</span><span class="p">)]]</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="n">invalid_feature</span><span class="p">)</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"USEFEATURE provided an invalid response code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_enabled_features</span> <span class="o">+=</span> <span class="p">[</span><span class="n">entry</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">features</span><span class="p">]</span> </div> <div class="viewcode-block" id="Controller.get_circuit"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_circuit">[docs]</a> <span class="k">def</span> <span class="nf">get_circuit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">circuit_id</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides a circuit presently available from tor.</span> <span class="sd"> :param int circuit_id: circuit to be fetched</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: :class:`stem.response.events.CircuitEvent` for the given circuit</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> * **ValueError** if the circuit doesn't exist</span> <span class="sd"> An exception is only raised if we weren't provided a default response.</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="k">for</span> <span class="n">circ</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_circuits</span><span class="p">():</span> <span class="k">if</span> <span class="n">circ</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">circuit_id</span><span class="p">:</span> <span class="k">return</span> <span class="n">circ</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"Tor presently does not have a circuit with the id of '</span><span class="si">%s</span><span class="s">'"</span> <span class="o">%</span> <span class="n">circuit_id</span><span class="p">)</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.get_circuits"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_circuits">[docs]</a> <span class="k">def</span> <span class="nf">get_circuits</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides tor's currently available circuits.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: **list** of :class:`stem.response.events.CircuitEvent` for our circuits</span> <span class="sd"> :raises: :class:`stem.ControllerError` if the call fails and no default was provided</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="n">circuits</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"circuit-status"</span><span class="p">)</span> <span class="k">for</span> <span class="n">circ</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span> <span class="n">circ_message</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">recv_message</span><span class="p">(</span><span class="n">StringIO</span><span class="o">.</span><span class="n">StringIO</span><span class="p">(</span><span class="s">"650 CIRC "</span> <span class="o">+</span> <span class="n">circ</span> <span class="o">+</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"EVENT"</span><span class="p">,</span> <span class="n">circ_message</span><span class="p">,</span> <span class="n">arrived_at</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">circuits</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">circ_message</span><span class="p">)</span> <span class="k">return</span> <span class="n">circuits</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.new_circuit"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.new_circuit">[docs]</a> <span class="k">def</span> <span class="nf">new_circuit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">purpose</span> <span class="o">=</span> <span class="s">"general"</span><span class="p">,</span> <span class="n">await_build</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Requests a new circuit. If the path isn't provided, one is automatically</span> <span class="sd"> selected.</span> <span class="sd"> :param list,str path: one or more relays to make a circuit through</span> <span class="sd"> :param str purpose: "general" or "controller"</span> <span class="sd"> :param bool await_build: blocks until the circuit is built if **True**</span> <span class="sd"> :returns: str of the circuit id of the newly created circuit</span> <span class="sd"> :raises: :class:`stem.ControllerError` if the call fails</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">extend_circuit</span><span class="p">(</span><span class="s">'0'</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">purpose</span><span class="p">,</span> <span class="n">await_build</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.extend_circuit"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.extend_circuit">[docs]</a> <span class="k">def</span> <span class="nf">extend_circuit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">circuit_id</span> <span class="o">=</span> <span class="s">"0"</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">purpose</span> <span class="o">=</span> <span class="s">"general"</span><span class="p">,</span> <span class="n">await_build</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Either requests the creation of a new circuit or extends an existing one.</span> <span class="sd"> When called with a circuit value of zero (the default) a new circuit is</span> <span class="sd"> created, and when non-zero the circuit with that id is extended. If the</span> <span class="sd"> path isn't provided, one is automatically selected.</span> <span class="sd"> A python interpreter session used to create circuits could look like this...</span> <span class="sd"> ::</span> <span class="sd"> >>> control.extend_circuit('0', ["718BCEA286B531757ACAFF93AE04910EA73DE617", "30BAB8EE7606CBD12F3CC269AE976E0153E7A58D", "2765D8A8C4BBA3F89585A9FFE0E8575615880BEB"])</span> <span class="sd"> 19</span> <span class="sd"> >>> control.extend_circuit('0')</span> <span class="sd"> 20</span> <span class="sd"> >>> print control.get_info('circuit-status')</span> <span class="sd"> 20 EXTENDED $718BCEA286B531757ACAFF93AE04910EA73DE617=KsmoinOK,$649F2D0ACF418F7CFC6539AB2257EB2D5297BAFA=Eskimo BUILD_FLAGS=NEED_CAPACITY PURPOSE=GENERAL TIME_CREATED=2012-12-06T13:51:11.433755</span> <span class="sd"> 19 BUILT $718BCEA286B531757ACAFF93AE04910EA73DE617=KsmoinOK,$30BAB8EE7606CBD12F3CC269AE976E0153E7A58D=Pascal1,$2765D8A8C4BBA3F89585A9FFE0E8575615880BEB=Anthracite PURPOSE=GENERAL TIME_CREATED=2012-12-06T13:50:56.969938</span> <span class="sd"> :param str circuit_id: id of a circuit to be extended</span> <span class="sd"> :param list,str path: one or more relays to make a circuit through, this is</span> <span class="sd"> required if the circuit id is non-zero</span> <span class="sd"> :param str purpose: "general" or "controller"</span> <span class="sd"> :param bool await_build: blocks until the circuit is built if **True**</span> <span class="sd"> :returns: str of the circuit id of the created or extended circuit</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.InvalidRequest` if one of the parameters were invalid</span> <span class="sd"> * :class:`stem.CircuitExtensionFailed` if we were waiting for the circuit</span> <span class="sd"> to build but it failed</span> <span class="sd"> * :class:`stem.ControllerError` if the call fails</span> <span class="sd"> """</span> <span class="c"># Attaches a temporary listener for CIRC events if we'll be waiting for it</span> <span class="c"># to build. This is icky, but we can't reliably do this via polling since</span> <span class="c"># we then can't get the failure if it can't be created.</span> <span class="n">circ_queue</span><span class="p">,</span> <span class="n">circ_listener</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="bp">None</span> <span class="k">if</span> <span class="n">await_build</span><span class="p">:</span> <span class="n">circ_queue</span> <span class="o">=</span> <span class="n">Queue</span><span class="o">.</span><span class="n">Queue</span><span class="p">()</span> <span class="k">def</span> <span class="nf">circ_listener</span><span class="p">(</span><span class="n">event</span><span class="p">):</span> <span class="n">circ_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">add_event_listener</span><span class="p">(</span><span class="n">circ_listener</span><span class="p">,</span> <span class="n">EventType</span><span class="o">.</span><span class="n">CIRC</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="c"># we might accidently get integer circuit ids</span> <span class="n">circuit_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">circuit_id</span><span class="p">)</span> <span class="k">if</span> <span class="n">path</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">circuit_id</span> <span class="o">==</span> <span class="s">'0'</span><span class="p">:</span> <span class="n">path_opt_version</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">Requirement</span><span class="o">.</span><span class="n">EXTENDCIRCUIT_PATH_OPTIONAL</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_version</span><span class="p">()</span> <span class="o">>=</span> <span class="n">path_opt_version</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="mi">512</span><span class="p">,</span> <span class="s">"EXTENDCIRCUIT requires the path prior to version </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">path_opt_version</span><span class="p">)</span> <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="n">circuit_id</span><span class="p">]</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="p">(</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)):</span> <span class="n">path</span> <span class="o">=</span> <span class="p">[</span><span class="n">path</span><span class="p">]</span> <span class="k">if</span> <span class="n">path</span><span class="p">:</span> <span class="n">args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">","</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">))</span> <span class="k">if</span> <span class="n">purpose</span><span class="p">:</span> <span class="n">args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">"purpose=</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">purpose</span><span class="p">)</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"EXTENDCIRCUIT </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">args</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="ow">in</span> <span class="p">(</span><span class="s">'512'</span><span class="p">,</span> <span class="s">'552'</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">elif</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"EXTENDCIRCUIT returned unexpected response code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"EXTENDED "</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"EXTENDCIRCUIT response invalid:</span><span class="se">\n</span><span class="si">%s</span><span class="s">"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="n">new_circuit</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">await_build</span><span class="p">:</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="n">circ</span> <span class="o">=</span> <span class="n">circ_queue</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="k">if</span> <span class="n">circ</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">new_circuit</span><span class="p">:</span> <span class="k">if</span> <span class="n">circ</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">CircStatus</span><span class="o">.</span><span class="n">BUILT</span><span class="p">:</span> <span class="k">break</span> <span class="k">elif</span> <span class="n">circ</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">CircStatus</span><span class="o">.</span><span class="n">FAILED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">CircuitExtensionFailed</span><span class="p">(</span><span class="s">"Circuit failed to be created: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">circ</span><span class="o">.</span><span class="n">reason</span><span class="p">,</span> <span class="n">circ</span><span class="p">)</span> <span class="k">elif</span> <span class="n">circ</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">CircStatus</span><span class="o">.</span><span class="n">CLOSED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">CircuitExtensionFailed</span><span class="p">(</span><span class="s">"Circuit was closed prior to build"</span><span class="p">,</span> <span class="n">circ</span><span class="p">)</span> <span class="k">return</span> <span class="n">new_circuit</span> <span class="k">finally</span><span class="p">:</span> <span class="k">if</span> <span class="n">circ_listener</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">remove_event_listener</span><span class="p">(</span><span class="n">circ_listener</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.repurpose_circuit"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.repurpose_circuit">[docs]</a> <span class="k">def</span> <span class="nf">repurpose_circuit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">circuit_id</span><span class="p">,</span> <span class="n">purpose</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Changes a circuit's purpose. Currently, two purposes are recognized...</span> <span class="sd"> * general</span> <span class="sd"> * controller</span> <span class="sd"> :param str circuit_id: id of the circuit whose purpose is to be changed</span> <span class="sd"> :param str purpose: purpose (either "general" or "controller")</span> <span class="sd"> :raises: :class:`stem.InvalidArguments` if the circuit doesn't exist or if the purpose was invalid</span> <span class="sd"> """</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"SETCIRCUITPURPOSE </span><span class="si">%s</span><span class="s"> purpose=</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">circuit_id</span><span class="p">,</span> <span class="n">purpose</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">"552"</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"SETCIRCUITPURPOSE returned unexpected response code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.close_circuit"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.close_circuit">[docs]</a> <span class="k">def</span> <span class="nf">close_circuit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">circuit_id</span><span class="p">,</span> <span class="n">flag</span> <span class="o">=</span> <span class="s">''</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Closes the specified circuit.</span> <span class="sd"> :param str circuit_id: id of the circuit to be closed</span> <span class="sd"> :param str flag: optional value to modify closing, the only flag available</span> <span class="sd"> is "IfUnused" which will not close the circuit unless it is unused</span> <span class="sd"> :raises: :class:`stem.InvalidArguments` if the circuit is unknown</span> <span class="sd"> :raises: :class:`stem.InvalidRequest` if not enough information is provided</span> <span class="sd"> """</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"CLOSECIRCUIT </span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">circuit_id</span><span class="p">,</span> <span class="n">flag</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="ow">in</span> <span class="p">(</span><span class="s">'512'</span><span class="p">,</span> <span class="s">'552'</span><span class="p">):</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"Unknown circuit "</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="p">[</span><span class="n">circuit_id</span><span class="p">])</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"CLOSECIRCUIT returned unexpected response code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.get_streams"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.get_streams">[docs]</a> <span class="k">def</span> <span class="nf">get_streams</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides the list of streams tor is currently handling.</span> <span class="sd"> :param object default: response if the query fails</span> <span class="sd"> :returns: list of :class:`stem.response.events.StreamEvent` objects</span> <span class="sd"> :raises: :class:`stem.ControllerError` if the call fails and no default was</span> <span class="sd"> provided</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="n">streams</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_info</span><span class="p">(</span><span class="s">"stream-status"</span><span class="p">)</span> <span class="k">for</span> <span class="n">stream</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span> <span class="n">message</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">recv_message</span><span class="p">(</span><span class="n">StringIO</span><span class="o">.</span><span class="n">StringIO</span><span class="p">(</span><span class="s">"650 STREAM "</span> <span class="o">+</span> <span class="n">stream</span> <span class="o">+</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"EVENT"</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">arrived_at</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">streams</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="k">return</span> <span class="n">streams</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="k">if</span> <span class="n">default</span> <span class="o">==</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exc</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> </div> <div class="viewcode-block" id="Controller.attach_stream"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.attach_stream">[docs]</a> <span class="k">def</span> <span class="nf">attach_stream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream_id</span><span class="p">,</span> <span class="n">circuit_id</span><span class="p">,</span> <span class="n">exiting_hop</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Attaches a stream to a circuit.</span> <span class="sd"> Note: Tor attaches streams to circuits automatically unless the</span> <span class="sd"> __LeaveStreamsUnattached configuration variable is set to "1"</span> <span class="sd"> :param str stream_id: id of the stream that must be attached</span> <span class="sd"> :param str circuit_id: id of the circuit to which it must be attached</span> <span class="sd"> :param int exiting_hop: hop in the circuit where traffic should exit</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.InvalidRequest` if the stream or circuit id were unrecognized</span> <span class="sd"> * :class:`stem.UnsatisfiableRequest` if the stream isn't in a state where it can be attached</span> <span class="sd"> * :class:`stem.OperationFailed` if the stream couldn't be attached for any other reason</span> <span class="sd"> """</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"ATTACHSTREAM </span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">stream_id</span><span class="p">,</span> <span class="n">circuit_id</span><span class="p">)</span> <span class="k">if</span> <span class="n">exiting_hop</span><span class="p">:</span> <span class="n">query</span> <span class="o">+=</span> <span class="s">" HOP=</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">exiting_hop</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">query</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">'552'</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">elif</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">'551'</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">OperationFailed</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">elif</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">'555'</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">UnsatisfiableRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"ATTACHSTREAM returned unexpected response code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.close_stream"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.close_stream">[docs]</a> <span class="k">def</span> <span class="nf">close_stream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream_id</span><span class="p">,</span> <span class="n">reason</span> <span class="o">=</span> <span class="n">stem</span><span class="o">.</span><span class="n">RelayEndReason</span><span class="o">.</span><span class="n">MISC</span><span class="p">,</span> <span class="n">flag</span> <span class="o">=</span> <span class="s">''</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Closes the specified stream.</span> <span class="sd"> :param str stream_id: id of the stream to be closed</span> <span class="sd"> :param stem.RelayEndReason reason: reason the stream is closing</span> <span class="sd"> :param str flag: not currently used</span> <span class="sd"> :raises: :class:`stem.InvalidArguments` if the stream or reason are not recognized</span> <span class="sd"> :raises: :class:`stem.InvalidRequest` if the stream and/or reason are missing</span> <span class="sd"> """</span> <span class="c"># there's a single value offset between RelayEndReason.index_of() and the</span> <span class="c"># value that tor expects since tor's value starts with the index of one</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"CLOSESTREAM </span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">stream_id</span><span class="p">,</span> <span class="n">stem</span><span class="o">.</span><span class="n">RelayEndReason</span><span class="o">.</span><span class="n">index_of</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">flag</span><span class="p">))</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="ow">in</span> <span class="p">(</span><span class="s">'512'</span><span class="p">,</span> <span class="s">'552'</span><span class="p">):</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"Unknown stream "</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="p">[</span><span class="n">stream_id</span><span class="p">])</span> <span class="k">elif</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">"Unrecognized reason "</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="p">[</span><span class="n">reason</span><span class="p">])</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidRequest</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"CLOSESTREAM returned unexpected response code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.signal"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.signal">[docs]</a> <span class="k">def</span> <span class="nf">signal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">signal</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Sends a signal to the Tor client.</span> <span class="sd"> :param stem.Signal signal: type of signal to be sent</span> <span class="sd"> :raises: :class:`stem.InvalidArguments` if signal provided wasn't recognized</span> <span class="sd"> """</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"SIGNAL </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">signal</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="s">"552"</span><span class="p">:</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">InvalidArguments</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">,</span> <span class="n">response</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="p">[</span><span class="n">signal</span><span class="p">])</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"SIGNAL response contained unrecognized status code: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </div> <div class="viewcode-block" id="Controller.is_geoip_unavailable"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.is_geoip_unavailable">[docs]</a> <span class="k">def</span> <span class="nf">is_geoip_unavailable</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Provides **True** if we've concluded hat our geoip database is unavailable,</span> <span class="sd"> **False** otherwise. This is determined by having our 'GETINFO</span> <span class="sd"> ip-to-country/\*' lookups fail so this will default to **False** if we</span> <span class="sd"> aren't making those queries.</span> <span class="sd"> Geoip failures will be untracked if caching is disabled.</span> <span class="sd"> :returns: **bool** to indicate if we've concluded our geoip database to be</span> <span class="sd"> unavailable or not</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_geoip_failure_count</span> <span class="o">>=</span> <span class="n">GEOIP_FAILURE_THRESHOLD</span> </div> <div class="viewcode-block" id="Controller.map_address"><a class="viewcode-back" href="../../api/control.html#stem.control.Controller.map_address">[docs]</a> <span class="k">def</span> <span class="nf">map_address</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mapping</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Map addresses to replacement addresses. Tor replaces subseqent connections</span> <span class="sd"> to the original addresses with the replacement addresses.</span> <span class="sd"> If the original address is a null address, i.e., one of "0.0.0.0", "::0", or</span> <span class="sd"> "." Tor picks an original address itself and returns it in the reply. If the</span> <span class="sd"> original address is already mapped to a different address the mapping is</span> <span class="sd"> removed.</span> <span class="sd"> :param dict mapping: mapping of original addresses to replacement addresses</span> <span class="sd"> :raises:</span> <span class="sd"> * :class:`stem.InvalidRequest` if the addresses are malformed</span> <span class="sd"> * :class:`stem.OperationFailed` if Tor couldn't fulfill the request</span> <span class="sd"> :returns: **dict** with 'original -> replacement' address mappings</span> <span class="sd"> """</span> <span class="n">mapaddress_arg</span> <span class="o">=</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">"</span><span class="si">%s</span><span class="s">=</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="ow">in</span> <span class="n">mapping</span><span class="o">.</span><span class="n">items</span><span class="p">()])</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"MAPADDRESS </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">mapaddress_arg</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"MAPADDRESS"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">return</span> <span class="n">response</span><span class="o">.</span><span class="n">entries</span> </div> <span class="k">def</span> <span class="nf">_post_authentication</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="nb">super</span><span class="p">(</span><span class="n">Controller</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_post_authentication</span><span class="p">()</span> <span class="c"># try to re-attach event listeners to the new instance</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners_lock</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">failed_events</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_attach_listeners</span><span class="p">()[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">failed_events</span><span class="p">:</span> <span class="c"># remove our listeners for these so we don't keep failing</span> <span class="k">for</span> <span class="n">event_type</span> <span class="ow">in</span> <span class="n">failed_events</span><span class="p">:</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="p">[</span><span class="n">event_type</span><span class="p">]</span> <span class="n">logging_id</span> <span class="o">=</span> <span class="s">"stem.controller.event_reattach-</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">"-"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">failed_events</span><span class="p">)</span> <span class="n">log</span><span class="o">.</span><span class="n">log_once</span><span class="p">(</span><span class="n">logging_id</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">WARN</span><span class="p">,</span> <span class="s">"We were unable to re-attach our event listeners to the new tor instance for: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">failed_events</span><span class="p">))</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s">"Unable to issue the SETEVENTS request to re-attach our listeners (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">exc</span><span class="p">)</span> <span class="c"># issue TAKEOWNERSHIP if we're the owning process for this tor instance</span> <span class="n">owning_pid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_conf</span><span class="p">(</span><span class="s">"__OwningControllerProcess"</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">owning_pid</span> <span class="o">==</span> <span class="nb">str</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">())</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_socket</span><span class="p">()</span><span class="o">.</span><span class="n">is_localhost</span><span class="p">():</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"TAKEOWNERSHIP"</span><span class="p">)</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"SINGLELINE"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="c"># Now that tor is tracking our ownership of the process via the control</span> <span class="c"># connection, we can stop having it check for us via our pid.</span> <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">reset_conf</span><span class="p">(</span><span class="s">"__OwningControllerProcess"</span><span class="p">)</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ControllerError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s">"We were unable to reset tor's __OwningControllerProcess configuration. It will continue to periodically check if our pid exists. (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">exc</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">log</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s">"We were unable assert ownership of tor through TAKEOWNERSHIP, despite being configured to be the owning process through __OwningControllerProcess. (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">response</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_handle_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event_message</span><span class="p">):</span> <span class="n">stem</span><span class="o">.</span><span class="n">response</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s">"EVENT"</span><span class="p">,</span> <span class="n">event_message</span><span class="p">,</span> <span class="n">arrived_at</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners_lock</span><span class="p">:</span> <span class="k">for</span> <span class="n">event_type</span><span class="p">,</span> <span class="n">event_listeners</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="k">if</span> <span class="n">event_type</span> <span class="o">==</span> <span class="n">event_message</span><span class="o">.</span><span class="n">type</span><span class="p">:</span> <span class="k">for</span> <span class="n">listener</span> <span class="ow">in</span> <span class="n">event_listeners</span><span class="p">:</span> <span class="n">listener</span><span class="p">(</span><span class="n">event_message</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_attach_listeners</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Attempts to subscribe to the self._event_listeners events from tor. This is</span> <span class="sd"> a no-op if we're not presently authenticated.</span> <span class="sd"> :returns: tuple of the form (set_events, failed_events)</span> <span class="sd"> :raises: :class:`stem.ControllerError` if unable to make our request to tor</span> <span class="sd"> """</span> <span class="n">set_events</span><span class="p">,</span> <span class="n">failed_events</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span> <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners_lock</span><span class="p">:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_authenticated</span><span class="p">():</span> <span class="c"># try to set them all</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"SETEVENTS </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="n">set_events</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span> <span class="k">else</span><span class="p">:</span> <span class="c"># One of the following likely happened...</span> <span class="c">#</span> <span class="c"># * Our user attached listeners before having an authenticated</span> <span class="c"># connection, so we couldn't check if we met the version</span> <span class="c"># requirement.</span> <span class="c">#</span> <span class="c"># * User attached listeners to one tor instance, then connected us to</span> <span class="c"># an older tor instancce.</span> <span class="c">#</span> <span class="c"># * Some other controller hiccup (far less likely).</span> <span class="c">#</span> <span class="c"># See if we can set some subset of our events.</span> <span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event_listeners</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">"SETEVENTS </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">set_events</span> <span class="o">+</span> <span class="p">[</span><span class="n">event</span><span class="p">]))</span> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">is_ok</span><span class="p">():</span> <span class="n">set_events</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">failed_events</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="k">return</span> <span class="p">(</span><span class="n">set_events</span><span class="p">,</span> <span class="n">failed_events</span><span class="p">)</span> </div> <span class="k">def</span> <span class="nf">_parse_circ_path</span><span class="p">(</span><span class="n">path</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Parses a circuit path as a list of **(fingerprint, nickname)** tuples. Tor</span> <span class="sd"> circuit paths are defined as being of the form...</span> <span class="sd"> ::</span> <span class="sd"> Path = LongName *("," LongName)</span> <span class="sd"> LongName = Fingerprint [ ( "=" / "~" ) Nickname ]</span> <span class="sd"> example:</span> <span class="sd"> $999A226EBED397F331B612FE1E4CFAE5C1F201BA=piyaz</span> <span class="sd"> ... *unless* this is prior to tor version 0.2.2.1 with the VERBOSE_NAMES</span> <span class="sd"> feature turned off (or before version 0.1.2.2 where the feature was</span> <span class="sd"> introduced). In that case either the fingerprint or nickname in the tuple</span> <span class="sd"> will be **None**, depending on which is missing.</span> <span class="sd"> ::</span> <span class="sd"> Path = ServerID *("," ServerID)</span> <span class="sd"> ServerID = Nickname / Fingerprint</span> <span class="sd"> example:</span> <span class="sd"> $E57A476CD4DFBD99B4EE52A100A58610AD6E80B9,hamburgerphone,PrivacyRepublic14</span> <span class="sd"> :param str path: circuit path to be parsed</span> <span class="sd"> :returns: list of **(fingerprint, nickname)** tuples, fingerprints do not have a proceeding '$'</span> <span class="sd"> :raises: :class:`stem.ProtocolError` if the path is malformed</span> <span class="sd"> """</span> <span class="k">if</span> <span class="n">path</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="k">return</span> <span class="p">[</span><span class="n">_parse_circ_entry</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">','</span><span class="p">)]</span> <span class="k">except</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="c"># include the path with the exception</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">exc</span><span class="p">,</span> <span class="n">path</span><span class="p">))</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="p">[]</span> <span class="k">def</span> <span class="nf">_parse_circ_entry</span><span class="p">(</span><span class="n">entry</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Parses a single relay's 'LongName' or 'ServerID'. See the</span> <span class="sd"> :func:`~_stem.control._parse_circ_path` function for more information.</span> <span class="sd"> :param str entry: relay information to be parsed</span> <span class="sd"> :returns: **(fingerprint, nickname)** tuple</span> <span class="sd"> :raises: :class:`stem.ProtocolError` if the entry is malformed</span> <span class="sd"> """</span> <span class="k">if</span> <span class="s">'='</span> <span class="ow">in</span> <span class="n">entry</span><span class="p">:</span> <span class="c"># common case</span> <span class="n">fingerprint</span><span class="p">,</span> <span class="n">nickname</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'='</span><span class="p">)</span> <span class="k">elif</span> <span class="s">'~'</span> <span class="ow">in</span> <span class="n">entry</span><span class="p">:</span> <span class="c"># this is allowed for by the spec, but I've never seen it used</span> <span class="n">fingerprint</span><span class="p">,</span> <span class="n">nickname</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'~'</span><span class="p">)</span> <span class="k">elif</span> <span class="n">entry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s">'$'</span><span class="p">:</span> <span class="c"># old style, fingerprint only</span> <span class="n">fingerprint</span><span class="p">,</span> <span class="n">nickname</span> <span class="o">=</span> <span class="n">entry</span><span class="p">,</span> <span class="bp">None</span> <span class="k">else</span><span class="p">:</span> <span class="c"># old style, nickname only</span> <span class="n">fingerprint</span><span class="p">,</span> <span class="n">nickname</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">entry</span> <span class="k">if</span> <span class="n">fingerprint</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_fingerprint</span><span class="p">(</span><span class="n">fingerprint</span><span class="p">,</span> <span class="bp">True</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"Fingerprint in the circuit path is malformed (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">fingerprint</span><span class="p">)</span> <span class="n">fingerprint</span> <span class="o">=</span> <span class="n">fingerprint</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="c"># strip off the leading '$'</span> <span class="k">if</span> <span class="n">nickname</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">stem</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">tor_tools</span><span class="o">.</span><span class="n">is_valid_nickname</span><span class="p">(</span><span class="n">nickname</span><span class="p">):</span> <span class="k">raise</span> <span class="n">stem</span><span class="o">.</span><span class="n">ProtocolError</span><span class="p">(</span><span class="s">"Nickname in the circuit path is malformed (</span><span class="si">%s</span><span class="s">)"</span> <span class="o">%</span> <span class="n">nickname</span><span class="p">)</span> <span class="k">return</span> <span class="p">(</span><span class="n">fingerprint</span><span class="p">,</span> <span class="n">nickname</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_case_insensitive_lookup</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">UNDEFINED</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Makes a case insensitive lookup within a list or dictionary, providing the</span> <span class="sd"> first matching entry that we come across.</span> <span class="sd"> :param list,dict entries: list or dictionary to be searched</span> <span class="sd"> :param str key: entry or key value to look up</span> <span class="sd"> :param object default: value to be returned if the key doesn't exist</span> <span class="sd"> :returns: case insensitive match or default if one was provided and key wasn't found</span> <span class="sd"> :raises: **ValueError** if no such value exists</span> <span class="sd"> """</span> <span class="k">if</span> <span class="n">entries</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">entries</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">entries</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="k">if</span> <span class="n">k</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> <span class="k">return</span> <span class="n">v</span> <span class="k">else</span><span class="p">:</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">:</span> <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> <span class="k">return</span> <span class="n">entry</span> <span class="k">if</span> <span class="n">default</span> <span class="o">!=</span> <span class="n">UNDEFINED</span><span class="p">:</span> <span class="k">return</span> <span class="n">default</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"key '</span><span class="si">%s</span><span class="s">' doesn't exist in dict: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">entries</span><span class="p">))</span> </pre></div> </div> <div class="bottomnav"> </div> <div class="footer"> </div> </body> </html>