o
    u]X'                  	   @   s   d 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
ZddlZdZdZdddddedddf	d	d
ZdddeddfddZdS )a|  
Helper functions for working with tor as a process.

:NO_TORRC:
  when provided as a torrc_path tor is ran with a blank configuration

:DEFAULT_INIT_TIMEOUT:
  number of seconds before we time out our attempt to start a tor instance

**Module Overview:**

::

  launch_tor             - starts up a tor process
  launch_tor_with_config - starts a tor process with a custom torrc
    Nz
<no torrc>Z   Ztord   FTc	                    sJ  t jj r dur tkrtdd nt jj	dkr+ dur) tkr)tdd t
jj| v rJt
j| r=td|  t
j| sItd|  nt jj| sWtd|  |dtfvrit
j|sitd| | gd}	}
|ru|	|7 }	|r|tkrtjd	d
dd }
|	d|
g7 }	n|	d|g7 }	|r|	dtt
 g7 }	d}zztj|	tjtjtjd}|r|jt jj| |j   rՇ fdd}ttj| t tj!  t"#d}t"#d}d}	 |j$% &dd' }|std| |r|| |(|}|(|}|rFt)|*d|krF|W W  rt+d |r5|r5|j$r,|j$  |j,r5|j,  |
rEzt
-|
 W S    Y S S |rd|. \}}d|vrdd|v rb|/dd ' }|}q   |rs|0  |1    r|t+d |r|r|j$r|j$  |j,r|j,  |
rzt
-|
 W w    Y w w )aM  
  Initializes a tor process. This blocks until initialization completes or we
  error out.

  If tor's data directory is missing or stale then bootstrapping will include
  making several requests to the directory authorities which can take a little
  while. Usually this is done in 50 seconds or so, but occasionally calls seem
  to get stuck, taking well over the default timeout.

  **To work to must log at NOTICE runlevel to stdout.** It does this by
  default, but if you have a 'Log' entry in your torrc then you'll also need
  'Log NOTICE stdout'.

  Note: The timeout argument does not work on Windows or when outside the
  main thread, and relies on the global state of the signal module.

  .. versionchanged:: 1.6.0
     Allowing the timeout argument to be a float.

  .. versionchanged:: 1.7.0
     Added the **close_output** argument.

  :param str tor_cmd: command for starting tor
  :param list args: additional arguments for tor
  :param str torrc_path: location of the torrc for us to use
  :param int completion_percent: percent of bootstrap completion at which
    this'll return
  :param functor init_msg_handler: optional functor that will be provided with
    tor's initialization stdout as we get it
  :param int timeout: time after which the attempt to start tor is aborted, no
    timeouts are applied if **None**
  :param bool take_ownership: asserts ownership over the tor process so it
    aborts if this python process terminates or a :class:`~stem.control.Controller`
    we establish to it disconnects
  :param bool close_output: closes tor's stdout and stderr streams when
    bootstrapping is complete if true
  :param str stdin: content to provide on stdin

  :returns: **subprocess.Popen** instance for the tor subprocess

  :raises: **OSError** if we either fail to create the tor process or reached a
    timeout without success
  Nz/You cannot launch tor with a timeout on WindowsZ_MainThreadz@Launching tor with a timeout can only be done in the main threadz+'%s' is a directory, not the tor executablez'%s' doesn't existzA'%s' isn't available on your system. Maybe it's not in your PATH?ztorrc doesn't exist (%s)zempty-torrc-Tprefixtext   -fZ__OwningControllerProcess)stdoutstdinstderrc                    s   t d  )Nz+reached a %i second timeout without success)OSError)Zsignumframetimeout ./usr/lib/python3/dist-packages/stem/process.pytimeout_handler   s   z#launch_tor.<locals>.timeout_handlerzBootstrapped ([0-9]+)%z\[(warn|err)\] (.*)$z	Timed outzutf-8replacezProcess terminated: %sr   zsee warnings abovez: )2stemutilsystemZ
is_windowsDEFAULT_INIT_TIMEOUTr   	threadingZcurrent_thread	__class____name__ospathsepisdirisfileZis_availableNO_TORRCexiststempfilemkstempstrgetpid
subprocessPopenPIPEr
   writeZ	str_toolsZ	_to_bytesclosesignalSIGALRM	setitimerITIMER_REALrecompiler	   readlinedecodestripsearchintgroupalarmr   removegroupssplitkillwait)tor_cmdargs
torrc_pathcompletion_percentinit_msg_handlerr   take_ownershipclose_outputr
   Zruntime_argsZ	temp_fileZtor_processr   Zbootstrap_lineZproblem_lineZlast_problemZ	init_lineZbootstrap_matchZproblem_matchZrunlevelmsgr   r   r   
launch_tor%   s   -









#


rF   c                 C   s  zt j|t jjjk}W n ty   d}Y nw d| v rIg d}t| d tr/| d g| d< d}	| d D ]
}
|
|v r?d}	 nq5|	sI| d d d}t	| 
 D ]\}}t|trc|d||f 7 }qQ|D ]
}|d||f 7 }qeqQ|rt|dd	gd
||||||d	S tjddd\}}z:t|d}|| W d
   n1 sw   Y  ddg}t|||||||W zt| t| W S    Y S zt| t| W w    Y w )a  
  Initializes a tor process, like :func:`~stem.process.launch_tor`, but with a
  customized configuration. This writes a temporary torrc to disk, launches
  tor, then deletes the torrc.

  For example...

  ::

    tor_process = stem.process.launch_tor_with_config(
      config = {
        'ControlPort': '2778',
        'Log': [
          'NOTICE stdout',
          'ERR file /tmp/tor_error_log',
        ],
      },
    )

  .. versionchanged:: 1.7.0
     Added the **close_output** argument.

  :param dict config: configuration options, such as "{'ControlPort': '9051'}",
    values can either be a **str** or **list of str** if for multiple values
  :param str tor_cmd: command for starting tor
  :param int completion_percent: percent of bootstrap completion at which
    this'll return
  :param functor init_msg_handler: optional functor that will be provided with
    tor's initialization stdout as we get it
  :param int timeout: time after which the attempt to start tor is aborted, no
    timeouts are applied if **None**
  :param bool take_ownership: asserts ownership over the tor process so it
    aborts if this python process terminates or a :class:`~stem.control.Controller`
    we establish to it disconnects
  :param bool close_output: closes tor's stdout and stderr streams when
    bootstrapping is complete if true

  :returns: **subprocess.Popen** instance for the tor subprocess

  :raises: **OSError** if we either fail to create the tor process or reached a
    timeout without success
  FZLog)zDEBUG stdoutzINFO stdoutNOTICE stdoutTrG    z%s %s
r   -N)r
   ztorrc-r   wZ__ReloadTorrcOnSIGHUP0)r   versionZget_system_tor_versionZRequirementZTORRC_VIA_STDINIOError
isinstancer%   appendlistitemsrF   r#   r$   openr*   r   r+   r9   )Zconfigr>   rA   rB   r   rC   rD   Z	use_stdinZstdout_optionsZ
has_stdoutZ
log_configZ
config_strkeyvaluesvalueZtorrc_descriptorr@   Z
torrc_filer?   r   r   r   launch_tor_with_config   sV   /


rV   )__doc__r   r0   r,   r'   r#   r   Zstem.prereqr   Zstem.util.str_toolsZstem.util.systemZstem.versionr!   r   rF   rV   r   r   r   r   <module>   s     (