o
    h
]b                     @   s   d Z ddlmZ ddlZddlZddlZddlZddlZddlZ	ddl
Z	ddlZ	ddlmZ edZdZdZG dd	 d	eZG d
d deZG dd deZG dd deZG dd deZdddZdd ZdddZdd Zdd ZdS )a  
Supports communication with sockets speaking Tor protocols. This
allows us to send messages as basic strings, and receive responses as
:class:`~stem.response.ControlMessage` instances.

**This module only consists of low level components, and is not intended for
users.** See our `tutorials <../tutorials.html>`_ and `Control Module
<control.html>`_ if you're new to Stem and looking to get started.

With that aside, these can still be used for raw socket communication with
Tor...

::

  import stem
  import stem.connection
  import stem.socket

  if __name__ == '__main__':
    try:
      control_socket = stem.socket.ControlPort(port = 9051)
      stem.connection.authenticate(control_socket)
    except stem.SocketError as exc:
      print 'Unable to connect to tor on port 9051: %s' % exc
      sys.exit(1)
    except stem.connection.AuthenticationFailure as exc:
      print 'Unable to authenticate: %s' % exc
      sys.exit(1)

    print "Issuing 'GETINFO version' query...\n"
    control_socket.send('GETINFO version')
    print control_socket.recv()

::

  % python example.py
  Issuing 'GETINFO version' query...

  version=0.2.4.10-alpha-dev (git-8be6058d8f31e578)
  OK

**Module Overview:**

::

  BaseSocket - Thread safe socket.
    |- RelaySocket - Socket for a relay's ORPort.
    |  |- send - sends a message to the socket
    |  +- recv - receives a response from the socket
    |
    |- ControlSocket - Socket wrapper that speaks the tor control protocol.
    |  |- ControlPort - Control connection via a port.
    |  |- ControlSocketFile - Control connection via a local file socket.
    |  |
    |  |- send - sends a message to the socket
    |  +- recv - receives a ControlMessage from the socket
    |
    |- is_alive - reports if the socket is known to be closed
    |- is_localhost - returns if the socket is for the local system or not
    |- connection_time - timestamp when socket last connected or disconnected
    |- connect - connects a new socket
    |- close - shuts down the socket
    +- __enter__ / __exit__ - manages socket connection

  send_message - Writes a message to a control socket.
  recv_message - Reads a ControlMessage from a control socket.
  send_formatting - Performs the formatting expected from sent messages.
    )absolute_importN)logs   ^[a-zA-Z0-9]{3}[-+ ]z0Error while receiving a control message (%s): %s
   c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )
BaseSocketz@
  Thread safe socket, providing common socket functionality.
  c                 C   s0   d\| _ | _d| _d| _t | _t | _d S )N)NNFg        )_socket_socket_file	_is_alive_connection_time	threadingRLock
_send_lock
_recv_lockself r   -/usr/lib/python3/dist-packages/stem/socket.py__init__d   s
   
zBaseSocket.__init__c                 C      | j S )a  
    Checks if the socket is known to be closed. We won't be aware if it is
    until we either use it or have explicitily shut it down.

    In practice a socket derived from a port knows about its disconnection
    after failing to receive data, whereas socket file derived connections
    know after either sending or receiving data.

    This means that to have reliable detection for when we're disconnected
    you need to continually pull from the socket (which is part of what the
    :class:`~stem.control.BaseController` does).

    :returns: **bool** that's **True** if our socket is connected and **False**
      otherwise
    )r   r   r   r   r   is_alivep   s   zBaseSocket.is_alivec                 C      dS )z
    Returns if the connection is for the local system or not.

    :returns: **bool** that's **True** if the connection is for the local host
      and **False** otherwise
    Fr   r   r   r   r   is_localhost   s   zBaseSocket.is_localhostc                 C   r   )ae  
    Provides the unix timestamp for when our socket was either connected or
    disconnected. That is to say, the time we connected if we're currently
    connected and the time we disconnected if we're not connected.

    .. versionadded:: 1.3.0

    :returns: **float** for when we last connected or disconnected, zero if
      we've never connected
    )r	   r   r   r   r   connection_time   s   zBaseSocket.connection_timec              
   C   s   | j V |  r|   | j2 |  | _| jjdd| _d| _t		 | _
z|   W n tjy9   |   Y nw W d   n1 sDw   Y  W d   dS W d   dS 1 s\w   Y  dS )z
    Connects to a new socket, closing our previous one if we're already
    attached.

    :raises: :class:`stem.SocketError` if unable to make a socket
    Zrwb)modeTN)r   r   closer   _make_socketr   Zmakefiler   r   timer	   _connectstemSocketErrorr   r   r   r   connect   s$   

"zBaseSocket.connectc              	   C   s   | j [ |  }| jr+z	| jtj W n
 tjy   Y nw z| j  W n   Y | jr:z| j  W n   Y d| _d| _d| _	t

 | _|rV|   W d   dS W d   dS 1 saw   Y  dS )zM
    Shuts down the socket. If it's already closed then this is a no-op.
    NF)r   r   r   ZshutdownsocketZ	SHUT_RDWRerrorr   r   r   r   r	   _close)r   Z	is_changer   r   r   r      s4   

$"zBaseSocket.closec              	   C   st   | j - z|  st || j| j| W n tjy'   |  r&|    w W d   dS 1 s3w   Y  dS )z
    Send message in a thread safe manner. Handler is expected to be of the form...

    ::

      my_handler(socket, socket_file, message)
    N)r   r   r   SocketClosedr   r   r   )r   messagehandlerr   r   r   _send   s   	"zBaseSocket._sendc              	   C   s   | j : z| j| j}}|r|st |||W W  d   S  tjy<   |  r;| jdr;|   | j	   w 1 s@w   Y  dS )z
    Receives a message in a thread safe manner. Handler is expected to be of the form...

    ::

      my_handler(socket, socket_file)
    NF)
r   r   r   r   r#   r   r   acquirer   release)r   r%   Z	my_socketZmy_socket_filer   r   r   _recv   s   	

zBaseSocket._recvc                 C   r   )a}  
    The send lock is useful to classes that interact with us at a deep level
    because it's used to lock :func:`stem.socket.ControlSocket.connect` /
    :func:`stem.socket.BaseSocket.close`, and by extension our
    :func:`stem.socket.BaseSocket.is_alive` state changes.

    :returns: **threading.RLock** that governs sending messages to our socket
      and state changes
    )r   r   r   r   r   _get_send_lock)  s   zBaseSocket._get_send_lockc                 C   s   | S Nr   r   r   r   r   	__enter__6     zBaseSocket.__enter__c                 C   s   |    d S r+   )r   )r   Z	exit_typevalue	tracebackr   r   r   __exit__9  s   zBaseSocket.__exit__c                 C   r   )zQ
    Connection callback that can be overwritten by subclasses and wrappers.
    Nr   r   r   r   r   r   <     zBaseSocket._connectc                 C   r   )zT
    Disconnection callback that can be overwritten by subclasses and wrappers.
    Nr   r   r   r   r   r"   C  r1   zBaseSocket._closec                 C   s   t d)a  
    Constructs and connects new socket. This is implemented by subclasses.

    :returns: **socket.socket** for our configuration

    :raises:
      * :class:`stem.SocketError` if unable to make a socket
      * **NotImplementedError** if not implemented by a subclass
    zLUnsupported Operation: this should be implemented by the BaseSocket subclass)NotImplementedErrorr   r   r   r   r   J  s   zBaseSocket._make_socketN)__name__
__module____qualname____doc__r   r   r   r   r   r   r&   r)   r*   r,   r0   r   r"   r   r   r   r   r   r   _   s     
 ,*r   c                       sD   e Zd ZdZd fdd	Zdd Zdd
dZdd Zdd Z  Z	S )RelaySocketz
  `Link-level connection
  <https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt>`_ to a Tor
  relay.

  .. versionadded:: 1.7.0

  :var str address: address our socket connects to
  :var int port: ORPort our socket connects to
  	127.0.0.1Z#  Tc                    .   t t|   || _|| _|r|   dS dS )aE  
    RelaySocket constructor.

    :param str address: ip address of the relay
    :param int port: orport of the relay
    :param bool connect: connects to the socket if True, leaves it unconnected otherwise

    :raises: :class:`stem.SocketError` if connect is **True** and we're
      unable to establish a connection
    N)superr7   r   addressportr   r   r<   r=   r   	__class__r   r   r   d     zRelaySocket.__init__c                 C      |  |dd  dS )a  
    Sends a message to the relay's ORPort.

    :param str message: message to be formatted and sent to the socket

    :raises:
      * :class:`stem.SocketError` if a problem arises in using the socket
      * :class:`stem.SocketClosed` if the socket is known to be shut down
    c                 S   
   t ||S r+   )_write_to_socketssfmsgr   r   r   <lambda>     
 z"RelaySocket.send.<locals>.<lambda>Nr&   r   r$   r   r   r   sendw  s   zRelaySocket.sendNc                    s    fdd}|  |S )a  
    Receives a message from the relay.

    :param float timeout: maxiumum number of seconds to await a response, this
      blocks indefinitely if **None**

    :returns: bytes for the message received

    :raises:
      * :class:`stem.ProtocolError` the content from the socket is malformed
      * :class:`stem.SocketClosed` if the socket closes before we receive a complete message
    c              
      sv    d u r|   S | d |   z"z|   W W | d S  tjtjtjfy4   Y W | d d S w | d w )Nr      )recvZsetblockingZ
settimeoutr    timeoutsslZSSLErrorZSSLWantReadErrorrF   rG   rP   r   r   wrapped_recv  s   


z&RelaySocket.recv.<locals>.wrapped_recvr)   )r   rP   rT   r   rS   r   rO     s   
zRelaySocket.recvc                 C   
   | j dkS Nr8   r<   r   r   r   r   r        
zRelaySocket.is_localhostc              
   C   sT   zt  t jt j}|| j| jf t|W S  t jy) } zt	
|d }~ww r+   )r    AF_INETSOCK_STREAMr   r<   r=   rQ   Zwrap_socketr!   r   r   )r   Zrelay_socketexcr   r   r   r     s   
zRelaySocket._make_socket)r8   r9   Tr+   )
r3   r4   r5   r6   r   rM   rO   r   r   __classcell__r   r   r?   r   r7   X  s    
r7   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )ControlSocketaK  
  Wrapper for a socket connection that speaks the Tor control protocol. To the
  better part this transparently handles the formatting for sending and
  receiving complete messages.

  Callers should not instantiate this class directly, but rather use subclasses
  which are expected to implement the **_make_socket()** method.
  c                    s   t t|   d S r+   )r;   r^   r   r   r?   r   r   r     s   zControlSocket.__init__c                 C   rB   )a&  
    Formats and sends a message to the control socket. For more information see
    the :func:`~stem.socket.send_message` function.

    .. deprecated:: 1.7.0
       The **raw** argument was unhelpful and be removed. Use
       :func:`stem.socket.send_message` if you need this level of control
       instead.

    :param str message: message to be formatted and sent to the socket

    :raises:
      * :class:`stem.SocketError` if a problem arises in using the socket
      * :class:`stem.SocketClosed` if the socket is known to be shut down
    c                 S   rC   r+   )send_messagerE   r   r   r   rI     rJ   z$ControlSocket.send.<locals>.<lambda>NrK   rL   r   r   r   rM     s   zControlSocket.sendc                 C   s   |  dd S )a  
    Receives a message from the control socket, blocking until we've received
    one. For more information see the :func:`~stem.socket.recv_message` function.

    :returns: :class:`~stem.response.ControlMessage` for the message received

    :raises:
      * :class:`stem.ProtocolError` the content from the socket is malformed
      * :class:`stem.SocketClosed` if the socket closes before we receive a complete message
    c                 S   s   t |S r+   )recv_messagerR   r   r   r   rI     s    z$ControlSocket.recv.<locals>.<lambda>rU   r   r   r   r   rO     s   zControlSocket.recv)r3   r4   r5   r6   r   rM   rO   r]   r   r   r?   r   r^     s
    	r^   c                       sB   e Zd ZdZd fdd	Zdd Zd	d
 Zdd Zdd Z  Z	S )ControlPortz
  Control connection to tor. For more information see tor's ControlPort torrc
  option.

  :var str address: address our socket connects to
  :var int port: ControlPort our socket connects to
  r8   [#  Tc                    r:   )aT  
    ControlPort constructor.

    :param str address: ip address of the controller
    :param int port: port number of the controller
    :param bool connect: connects to the socket if True, leaves it unconnected otherwise

    :raises: :class:`stem.SocketError` if connect is **True** and we're
      unable to establish a connection
    N)r;   ra   r   r<   r=   r   r>   r?   r   r   r     rA   zControlPort.__init__c                 C   r   )z
    Provides the ip address our socket connects to.

    .. deprecated:: 1.7.0
       Use the **address** attribute instead.

    :returns: str with the ip address of our socket
    rX   r   r   r   r   get_address     
zControlPort.get_addressc                 C   r   )z
    Provides the port our socket connects to.

    .. deprecated:: 1.7.0
       Use the **port** attribute instead.

    :returns: int with the port of our socket
    )r=   r   r   r   r   get_port  rd   zControlPort.get_portc                 C   rV   rW   rX   r   r   r   r   r     rY   zControlPort.is_localhostc              
   C   sN   zt  t jt j}|| j| jf |W S  t jy& } zt|d }~ww r+   )	r    rZ   r[   r   r<   r=   r!   r   r   r   Zcontrol_socketr\   r   r   r   r     s   
zControlPort._make_socket)r8   rb   T)
r3   r4   r5   r6   r   rc   re   r   r   r]   r   r   r?   r   ra     s    ra   c                       s:   e Zd ZdZd fdd	Zdd Zdd	 Zd
d Z  ZS )ControlSocketFilez
  Control connection to tor. For more information see tor's ControlSocket torrc
  option.

  :var str path: filesystem path of the socket we connect to
  /var/run/tor/controlTc                    s(   t t|   || _|r|   dS dS )a7  
    ControlSocketFile constructor.

    :param str socket_path: path where the control socket is located
    :param bool connect: connects to the socket if True, leaves it unconnected otherwise

    :raises: :class:`stem.SocketError` if connect is **True** and we're
      unable to establish a connection
    N)r;   rg   r   pathr   )r   ri   r   r?   r   r   r   %  s
   zControlSocketFile.__init__c                 C   r   )z
    Provides the path our socket connects to.

    .. deprecated:: 1.7.0
       Use the **path** attribute instead.

    :returns: str with the path for our control socket
    )ri   r   r   r   r   get_socket_path6  rd   z!ControlSocketFile.get_socket_pathc                 C   r   )NTr   r   r   r   r   r   B  r-   zControlSocketFile.is_localhostc              
   C   sH   zt  t jt j}|| j |W S  t jy# } zt|d }~ww r+   )r    ZAF_UNIXr[   r   ri   r!   r   r   rf   r   r   r   r   E  s   
zControlSocketFile._make_socket)rh   T)	r3   r4   r5   r6   r   rj   r   r   r]   r   r   r?   r   rg     s    rg   Fc                 C   sX   |st |}t| | t r*|dd }d|v rdnd}td||f  dS dS )a  
  Sends a message to the control socket, adding the expected formatting for
  single verses multi-line messages. Neither message type should contain an
  ending newline (if so it'll be treated as a multi-line message with a blank
  line at the end). If the message doesn't contain a newline then it's sent
  as...

  ::

    <message>\r\n

  and if it does contain newlines then it's split on ``\n`` and sent as...

  ::

    +<line 1>\r\n
    <line 2>\r\n
    <line 3>\r\n
    .\r\n

  :param file control_file: file derived from the control socket (see the
    socket's makefile() method for more information)
  :param str message: message to be sent on the control socket
  :param bool raw: leaves the message formatting untouched, passing it to the
    socket as-is

  :raises:
    * :class:`stem.SocketError` if a problem arises in using the socket
    * :class:`stem.SocketClosed` if the socket is known to be shut down
  

 zSent to tor:%s%sN)send_formattingrD   r   
is_tracingreplacerstriptrace)control_filer$   rawlog_messageZmsg_divr   r   r   r_   N  s    
r_   c              
   C   s   z|  tjj| |   W d S  tjy5 } zt	d|  t
|dkr,t|t|d }~w tyE   t	d tdw )NzFailed to send: %sz[Errno 32] Broken pipez$Failed to send: file has been closedzfile has been closed)writer   util	str_toolsZ	_to_bytesflushr    r!   r   infostrr#   r   AttributeError)Zsocket_filer$   r\   r   r   r   rD   y  s   



rD   c                 C   s  d\}}}	 z|   }W n1 ty   ttd  td tjt	fy= } zttdd| f  t|d}~ww |sLttd  td	t
|sdttd
dt| f  td|ds|ttd
dt| f  td|dd |dd |dd }}}	tj rtjj|}tjj|}|r|dkrt| tjj|||	fg||dS g t d}}}||7 }|dkr||||	f n|dkr||||	f tt| tjj|t||dS |dkrpt|	}
	 z
|   }||7 }W n% tjy* } zttdd|tt|f f  t|d}~ww |dsFttd
dtt| f  td|dkrLn|dd }|dr^|dd }|
d| 7 }
q|||t|
f nttd
d| f  td|tjj|f q) a  
  Pulls from a control socket until we either have a complete message or
  encounter a problem.

  :param file control_file: file derived from the control socket (see the
    socket's makefile() method for more information)

  :returns: :class:`~stem.response.ControlMessage` read from the socket

  :raises:
    * :class:`stem.ProtocolError` the content from the socket is malformed
    * :class:`stem.SocketClosed` if the socket closes before we receive
      a complete message
  )NNTT)r#   socket file has been closedr}   r#   zreceived exception "%s"N)r#   zempty socket contentzReceived empty socket content.ProtocolErrorz#malformed status code/divider, "%s"z2Badly formatted reply line: beginning is malformed   
zno CRLF linebreak, "%s"zAll lines should end with CRLF      rm   )
arrived_atF-+z^received an exception while mid-way through a data reply (exception: "%s", read content: "%s")z/CRLF linebreaks missing from a data reply, "%s"s   .
s   ..rN      
z$"%s" isn't a recognized divider typez"Unrecognized divider type '%s': %s)readliner|   r   rz   	ERROR_MSGr   r#   r    r!   
ValueErrorMESSAGE_PREFIXmatchescaper~   endswithZprereqZis_python_3rw   rx   _to_unicode
_log_traceresponseZControlMessage	bytearrayappendbytes
startswithwarn)rs   r   Zparsed_contentZraw_contentZ
first_lineliner\   Zstatus_codeZdividerZcontentZcontent_blockr   r   r   r`     s|   

	





(

$
 

r`   c                 C   s,   |  dd} d| v rd|  dd S | d S )a  
  Performs the formatting expected from sent control messages. For more
  information see the :func:`~stem.socket.send_message` function.

  :param str message: message to be formatted

  :returns: **str** of the message wrapped by the formatting expected from
    controllers
  rk   rl   z+%s
.
)rp   )r$   r   r   r   rn     s   rn   c                 C   s   t  sd S tjj| dd }|d}t	r2t
|t	kr2d|d t	 dt
|t	  g }t
|dkrAt d|  d S t d|dd  d S )	Nr   r   rl   z... %i more lines...   zReceived from tor:
%szReceived from tor: %sz\n)r   ro   r   rw   rx   r   rp   rq   splitTRUNCATE_LOGSlenjoinrr   )r   ru   Zlog_message_linesr   r   r   r   (  s   
$r   )Fr+   )r6   Z
__future__r   rer    rQ   r
   r   Zstem.prereqr   Zstem.responseZstem.util.str_toolsZ	stem.utilr   compiler   r   r   objectr   r7   r^   ra   rg   r_   rD   r`   rn   r   r   r   r   r   <module>   s2   E
 zV/@
1+
{