U
    
W[E                     @   sV  d Z ddlmZmZmZ ddlZzddlmZ W n e	k
rD   Y nX ddl
mZmZ ddlmZmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ G dd dZeejG dd deZeej ej!G dd dZ"dd Z#dd Z$G dd dZ%d&ddZ&e#e$ddfddZ'd d! Z(G d"d# d#eZ)d'd$d%Z*dS )(z0
Utilities and helpers for simulating a network
    )absolute_importdivisionprint_functionN)Error)implementerdirectlyProvides)TCP4ClientEndpointTCP4ServerEndpoint)FactoryProtocol)ConnectionRefusedError)Failure)error)
interfaces   )MemoryReactorClockc                   @   s$   e Zd Zdd Zdd Zdd ZdS )TLSNegotiationc                 C   s   || _ || _d| _|| _d S )NF)objconnectStatesentreadyToSend)selfr   r    r   4/usr/lib/python3/dist-packages/twisted/test/iosim.py__init__   s    zTLSNegotiation.__init__c                 C   s   d| j f S )NzTLSNegotiation(%r))r   r   r   r   r   __repr__&   s    zTLSNegotiation.__repr__c                 C   s"   | j |j st |_|  d S N)r   ZiosimVerifyNativeOpenSSLErrordisconnectReasonloseConnection)r   otherZtptr   r   r   pretendToVerify*   s    zTLSNegotiation.pretendToVerifyN)__name__
__module____qualname__r   r   r"   r   r   r   r   r      s   r   c                   @   s   e Zd ZdZdS )FakeAddressz]
    The default address type for the host and peer of L{FakeTransport}
    connections.
    N)r#   r$   r%   __doc__r   r   r   r   r&   4   s   r&   c                   @   s   e Zd ZdZee fddZdZdZ	dZ
edZdZdZdZd0d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%d& Z d'd( Z!d1d*d+Z"d,d- Z#d.d/ Z$dS )2FakeTransportz
    A wrapper around a file-like object to make it behave as a Transport.

    This doesn't actually stream the file to the attached protocol,
    and is thus useful mainly as a utility for debugging protocols.
    c                 C   s   t | S r   )next)Zcounterr   r   r   <lambda>G       zFakeTransport.<lambda>r   zConnection doneNc                 C   sH   || _ || _g | _|  | _|dkr*t }|| _|dkr>t }|| _dS )a  
        @param protocol: This transport will deliver bytes to this protocol.
        @type protocol: L{IProtocol} provider

        @param isServer: C{True} if this is the accepting side of the
            connection, C{False} if it is the connecting side.
        @type isServer: L{bool}

        @param hostAddress: The value to return from C{getHost}.  L{None}
            results in a new L{FakeAddress} being created to use as the value.
        @type hostAddress: L{IAddress} provider or L{None}

        @param peerAddress: The value to return from C{getPeer}.  L{None}
            results in a new L{FakeAddress} being created to use as the value.
        @type peerAddress: L{IAddress} provider or L{None}
        N)protocolisServerstream_nextserialserialr&   hostAddresspeerAddress)r   r,   r-   r1   r2   r   r   r   r   P   s    
zFakeTransport.__init__c                 C   s    d| j rdpd| j| jjjf S )NzFakeTransport<%s,%s,%s>SC)r-   r0   r,   	__class__r#   r   r   r   r   r   m   s
     zFakeTransport.__repr__c                 C   s2   | j r
d S | jd k	r"| j| n| j| d S r   )disconnectingtlstlsbufappendr.   )r   datar   r   r   writes   s
    
zFakeTransport.writec                 C   s   | j r| js| j   d S r   producerstreamingProducerresumeProducingr   r   r   r   _checkProducer~   s    zFakeTransport._checkProducerc                 C   s   || _ || _|s|  dS )z.
        From abstract.FileDescriptor
        Nr<   )r   r=   Z	streamingr   r   r   registerProducer   s    zFakeTransport.registerProducerc                 C   s
   d | _ d S r   )r=   r   r   r   r   unregisterProducer   s    z FakeTransport.unregisterProducerc                 C   s   |    |   d S r   )rB   r    r   r   r   r   stopConsuming   s    zFakeTransport.stopConsumingc                 C   s   |  d| d S )Nr+   )r;   join)r   Ziovecr   r   r   writeSequence   s    zFakeTransport.writeSequencec                 C   s
   d| _ d S NTr6   r   r   r   r   r       s    zFakeTransport.loseConnectionc                 C   s
   d| _ dS )zp
        For the time being, this is the same as loseConnection; no buffered
        data will be lost.
        TNrG   r   r   r   r   abortConnection   s    zFakeTransport.abortConnectionc                 C   s,   | j d k	rt }n| j}| jt| d S r   )r7   r   r   r,   ZconnectionLostr   )r   errr   r   r   reportDisconnect   s    
zFakeTransport.reportDisconnectc                 C   s   dS )zM
        Identify this transport/event source to the logging system.
        Ziosimr   r   r   r   r   	logPrefix   s    zFakeTransport.logPrefixc                 C   s   | j S r   )r2   r   r   r   r   getPeer   s    zFakeTransport.getPeerc                 C   s   | j S r   )r1   r   r   r   r   getHost   s    zFakeTransport.getHostc                 C   s   d S r   r   r   r   r   r   r?      s    zFakeTransport.resumeProducingc                 C   s   d S r   r   r   r   r   r   pauseProducing   s    zFakeTransport.pauseProducingc                 C   s   |    d S r   )r    r   r   r   r   stopProducing   s    zFakeTransport.stopProducingTc                 C   s    | j |A }t||| _g | _d S r   )r-   r   r7   r8   )r   ZcontextFactoryZbeNormalr   r   r   r   startTLS   s    
zFakeTransport.startTLSc                 C   sH   | j }|rg | _ d|S | jdk	r@| jjr:d| j_| jS dS ndS dS )z
        Get the pending writes from this transport, clearing them from the
        pending buffer.

        @return: the bytes written with C{transport.write}
        @rtype: L{bytes}
        r+   NT)r.   rD   r7   r   r   )r   r3   r   r   r   getOutBuffer   s    

zFakeTransport.getOutBufferc                 C   st   t |trd| jd k	st| jjrZ| j||  d | _| jd  }| _| | t| t	j
 qpd| j_n| j| d S rF   )
isinstancer   r7   AssertionErrorr   r"   r8   rE   r   r   ZISSLTransportr   r,   ZdataReceived)r   Zbufbr   r   r   bufferReceived   s    


zFakeTransport.bufferReceived)NN)T)%r#   r$   r%   r'   staticmethod	itertoolscountr/   closedr6   disconnectedr   ZConnectionDoner   r=   r>   r7   r   r   r;   r@   rA   rB   rC   rE   r    rH   rJ   rK   rL   rM   r?   rN   rO   rP   rQ   rU   r   r   r   r   r(   =   s:   




	r(   c                 C   s   t | ddS )z
    Create and return a new in-memory transport hooked up to the given protocol.

    @param clientProtocol: The client protocol to use.
    @type clientProtocol: L{IProtocol} provider

    @return: The transport.
    @rtype: L{FakeTransport}
    Fr-   r(   )clientProtocolr   r   r   makeFakeClient  s    
r^   c                 C   s   t | ddS )z
    Create and return a new in-memory transport hooked up to the given protocol.

    @param serverProtocol: The server protocol to use.
    @type serverProtocol: L{IProtocol} provider

    @return: The transport.
    @rtype: L{FakeTransport}
    Tr[   r\   )serverProtocolr   r   r   makeFakeServer  s    
r`   c                   @   s,   e Zd ZdZdd Zd
ddZdddZd	S )IOPumpz
    Utility to pump data between clients and servers for protocol testing.

    Perhaps this is a utility worthy of being in protocol.py?
    c                 C   s"   || _ || _|| _|| _|| _d S r   )clientserverclientIOserverIOdebug)r   rb   rc   rd   re   rf   r   r   r   r   &  s
    zIOPump.__init__Fc                 C   s6   d}t dD ]}| |r d}q q2qds2td|S )zk
        Pump until there is no more input or output.

        Returns whether any data was moved.
        Fi  Tr   zToo long)rangepumprS   )r   rf   resultxr   r   r   flush.  s    
zIOPump.flushc                 C   s,  | j s
|rtd | j }| j }| j  | j  | j sD|rttd |r`tdt|  |rttdt|  |r| j| |r| j| |s|rdS | jjr| jj	s| j s|rtd d| j_	d| j_| j
  dS | jjr(| jj	s(| j s|r
td d| j_	d| j_| j
  dS dS )	zX
        Move data back and forth.

        Returns whether any data was moved.
        z
-- GLUG --.zC: zS: Tz* Cz* SF)rf   printre   rQ   rd   r@   reprrU   r6   rZ   rJ   )r   rf   ZsDataZcDatar   r   r   rh   ?  sF    








zIOPump.pumpN)F)F)r#   r$   r%   r'   r   rk   rh   r   r   r   r   ra      s   
ra   FTc                 C   s4   |  | | | t|| |||}|r0|  |S )aN  
    Create a new L{IOPump} connecting two protocols.

    @param serverProtocol: The protocol to use on the accepting side of the
        connection.
    @type serverProtocol: L{IProtocol} provider

    @param serverTransport: The transport to associate with C{serverProtocol}.
    @type serverTransport: L{FakeTransport}

    @param clientProtocol: The protocol to use on the initiating side of the
        connection.
    @type clientProtocol: L{IProtocol} provider

    @param clientTransport: The transport to associate with C{clientProtocol}.
    @type clientTransport: L{FakeTransport}

    @param debug: A flag indicating whether to log information about what the
        L{IOPump} is doing.
    @type debug: L{bool}

    @param greet: Should the L{IOPump} be L{flushed <IOPump.flush>} once before
        returning to put the protocols into their post-handshake or
        post-server-greeting state?
    @type greet: L{bool}

    @return: An L{IOPump} which connects C{serverProtocol} and
        C{clientProtocol} and delivers bytes between them when it is pumped.
    @rtype: L{IOPump}
    )ZmakeConnectionra   rk   )r_   serverTransportr]   clientTransportrf   greetrh   r   r   r   connectk  s     

    rr   c           
   	   C   s4   | }|  }||}||}	||t ||	||||fS )a  
    Connect a given server and client class to each other.

    @param ServerClass: a callable that produces the server-side protocol.
    @type ServerClass: 0-argument callable returning L{IProtocol} provider.

    @param ClientClass: like C{ServerClass} but for the other side of the
        connection.
    @type ClientClass: 0-argument callable returning L{IProtocol} provider.

    @param clientTransportFactory: a callable that produces the transport which
        will be attached to the protocol returned from C{ClientClass}.
    @type clientTransportFactory: callable taking (L{IProtocol}) and returning
        L{FakeTransport}

    @param serverTransportFactory: a callable that produces the transport which
        will be attached to the protocol returned from C{ServerClass}.
    @type serverTransportFactory: callable taking (L{IProtocol}) and returning
        L{FakeTransport}

    @param debug: Should this dump an escaped version of all traffic on this
        connection to stdout for inspection?
    @type debug: L{bool}

    @param greet: Should the L{IOPump} be L{flushed <IOPump.flush>} once before
        returning to put the protocols into their post-handshake or
        post-server-greeting state?
    @type greet: L{bool}

    @return: the client protocol, the server protocol, and an L{IOPump} which,
        when its C{pump} and C{flush} methods are called, will move data
        between the created client and server protocol instances.
    @rtype: 3-L{tuple} of L{IProtocol}, L{IProtocol}, L{IOPump}
    )rr   )
ZServerClassZClientClassZclientTransportFactoryZserverTransportFactoryrf   rq   csZcioZsior   r   r   connectedServerAndClient  s
    &ru   c                 C   s2   | \}}}}}|\}}}	}
||kr*||fS dS dS )a'  
    Should the client and server described by the arguments be connected to
    each other, i.e. do their port numbers match?

    @param clientInfo: the args for connectTCP
    @type clientInfo: L{tuple}

    @param serverInfo: the args for listenTCP
    @type serverInfo: L{tuple}

    @return: If they do match, return factories for the client and server that
        should connect; otherwise return L{None}, indicating they shouldn't be
        connected.
    @rtype: L{None} or 2-L{tuple} of (L{ClientFactory},
        L{IProtocolFactory})
    Nr   )
clientInfo
serverInfoZ
clientHostZ
clientPortclientFactoryZclientTimeoutZclientBindAddressZ
serverPortserverFactoryZserverBacklogZserverInterfacer   r   r   _factoriesShouldConnect  s    
rz   c                   @   s4   e Zd ZdZdd Zd
ddZee fddZd	S )ConnectionCompleterz
    A L{ConnectionCompleter} can cause synthetic TCP connections established by
    L{MemoryReactor.connectTCP} and L{MemoryReactor.listenTCP} to succeed or
    fail.
    c                 C   s
   || _ dS )z
        Create a L{ConnectionCompleter} from a L{MemoryReactor}.

        @param memoryReactor: The reactor to attach to.
        @type memoryReactor: L{MemoryReactor}
        N)_reactor)r   memoryReactorr   r   r   r     s    zConnectionCompleter.__init__Fc                 C   s   | j }t|jD ]~\}}|jD ]n}t||}|r|j| |j| |\}}|d}	|d}
t	|
}t
|	}t|
||	||    S qqdS )a  
        Complete a single TCP connection established on this
        L{ConnectionCompleter}'s L{MemoryReactor}.

        @param debug: A flag; whether to dump output from the established
            connection to stdout.
        @type debug: L{bool}

        @return: a pump for the connection, or L{None} if no connection could
            be established.
        @rtype: L{IOPump} or L{None}
        N)r|   	enumerate
tcpClientsZ
tcpServersrz   remove
connectorspopZbuildProtocolr`   r^   rr   )r   rf   r}   Z	clientIdxrv   rw   Z	factoriesrx   ry   r]   r_   ro   rp   r   r   r   succeedOnce  s"    



 zConnectionCompleter.succeedOncec                 C   s(   | j jdd | j jd| dS )z
        Fail a single TCP connection established on this
        L{ConnectionCompleter}'s L{MemoryReactor}.

        @param reason: the reason to provide that the connection failed.
        @type reason: L{Failure}
        r      N)r|   r   r   ZclientConnectionFailedr   )r   reasonr   r   r   failOnce  s     zConnectionCompleter.failOnceN)F)	r#   r$   r%   r'   r   r   r   r   r   r   r   r   r   r{     s   

r{   c                 C   s8   t  }t|dd}t|d}|tt |t|fS )a  
    Create an endpoint that can be fired on demand.

    @param debug: A flag; whether to dump output from the established
        connection to stdout.
    @type debug: L{bool}

    @return: A client endpoint, and an object that will cause one of the
        L{Deferred}s returned by that client endpoint.
    @rtype: 2-L{tuple} of (L{IStreamClientEndpoint}, L{ConnectionCompleter})
    z0.0.0.0i  )r   r   r	   Zlistenr
   ZforProtocolr   r{   )rf   ZreactorZclientEndpointZserverEndpointr   r   r   connectableEndpoint  s
    
r   )FT)F)+r'   Z
__future__r   r   r   rW   ZOpenSSL.SSLr   r   ImportErrorZzope.interfacer   r   Ztwisted.internet.endpointsr   r	   Ztwisted.internet.protocolr
   r   Ztwisted.internet.errorr   Ztwisted.python.failurer   Ztwisted.internetr   r   Zproto_helpersr   r   ZIAddressobjectr&   Z
ITransportZITLSTransportr(   r^   r`   ra   rr   ru   rz   r{   r   r   r   r   r   <module>   sH    FL   
- 
.<