o b.@s$dZddlZddlmZddlmZmZmZmZddl m Z ddl m Z ddl mZddlmZGd d d Zee Gd d d ZeejejGd ddZddZddZefddZddZddZeejejGdddZGdddejZGdddejZd$d d!Z d%d"d#Z!dS)&zF Testing support for protocols -- loopback between client and server. N) implementer)defer interfacesmainprotocol)IAddress) deferLater)policies)failurec@s<eZdZdZdZdZddZddZdd ZeZ d d Z dS) _LoopbackQueuez Trivial wrapper around a list to give it an interface like a queue, which the addition of also sending notifications by way of a Deferred whenever the list has something added to it. NFcCs g|_dSN)_queueselfresz _LoopbackTransport._pollProducer)rr r! disconnectingr<rr.r4r5r6r9r;rArCr>rrrrr&9s r&cCs.|r|}|dur dS|||sdSdS)z L{identityPumpPolicy} is a policy which delivers each chunk of data written to the given queue as-is to the target. This isn't a particularly realistic policy. @see: L{loopbackAsync} N)r dataReceived)queuetargetr*rrridentityPumpPolicyjs    rIcCsDg}|r|}|dur n|||s|r |d|dSdS)z L{collapsingPumpPolicy} is a policy which collapses all outstanding chunks into a single string and delivers it to the target. @see: L{loopbackAsync} Nr0)rrrFr1)rGrHr*chunkrrrcollapsingPumpPolicyzs rKcCs8t}t}|t||t|t|||||S)a Establish a connection between C{server} and C{client} then transfer data between them until the connection is closed. This is often useful for testing a protocol. @param server: The protocol instance representing the server-side of this connection. @param client: The protocol instance representing the client-side of this connection. @param pumpPolicy: When either C{server} or C{client} writes to its transport, the string passed in is added to a queue of data for the other protocol. Eventually, C{pumpPolicy} will be called with one such queue and the corresponding protocol object. The pump policy callable is responsible for emptying the queue and passing the strings it contains to the given protocol's C{dataReceived} method. The signature of C{pumpPolicy} is C{(queue, protocol)}. C{queue} is an object with a C{get} method which will return the next string written to the transport, or L{None} if the transport has been disconnected, and which evaluates to C{True} if and only if there are more items to be retrieved via C{get}. @return: A L{Deferred} which fires when the connection has been closed and both sides have received notification of this. )r makeConnectionr&_loopbackAsyncBody)serverclient pumpPolicyserverToClientclientToServerrrr loopbackAsyncs rSc sfdd} d}}}||||}||||}|s3|s3t} | |_| |_| t||||| S|jr?d}||||n |jrJd}|||||rc|tt j |tt j t dSq)ak Transfer bytes from the output queue of each protocol to the input of the other. @param server: The protocol instance representing the server-side of this connection. @param serverToClient: The L{_LoopbackQueue} holding the server's output. @param client: The protocol instance representing the client-side of this connection. @param clientToServer: The L{_LoopbackQueue} holding the client's output. @param pumpPolicy: See L{loopbackAsync}. @return: A L{Deferred} which fires when the connection has been closed and both sides have received notification of this. cs,d}|r ||d}|r|s|j|S)NFT) transportr>)sourcer(rHsentrPrrpumps  z _loopbackAsyncBody..pumpFTN) rDeferredr addCallback_loopbackAsyncContinuer#connectionLostr FailurerCONNECTION_DONEsucceed) rNrQrOrRrPrXr# clientSent serverSentrrrWrrMs:      rMc Cs.d|_d|_ddlm}t|dt|||||S)Nrreactor)rtwisted.internetrdrrM)ignoredrNrQrOrRrPrdrrrr\s r\c@sneZdZdZdZdZdZdddZddZdd Z d d Z d d Z ddZ ddZ ddZddZddZdS) LoopbackRelayr0rNcCs||_||_dSr )rHlogFile)rrHrhrrrrs zLoopbackRelay.__init__cCs.|j||_|jr|jdt|dSdS)Nzloopback writing %s )bufferrhr.reprr,rrrr.s zLoopbackRelay.writecCs|d|dSr/)r.r1r2rrrr4"szLoopbackRelay.writeSequencecCs|jdkrdS|jr|j|jr,|jr |jdt|j|j}d|_|j||jdkr@d|_|j t t j dSdS)Nzloopback receiving %s r0rY) shouldLoser<rDrirhr.rjrHrFr]r r^rr_)rrirrr clearBuffer%s    zLoopbackRelay.clearBuffercCs|jdkr d|_dSdS)NrkrY)rlrrrrr55s  zLoopbackRelay.loseConnectioncCdSNloopbackrrrrrr;9zLoopbackRelay.getHostcCrnrorrrrrr9<rqzLoopbackRelay.getPeercCr'r rBr?rrrrA?rzLoopbackRelay.registerProducercCs d|_dSr rBrrrrrCBrz LoopbackRelay.unregisterProducercCsd|jjjdS)Nz Loopback())rH __class__rrrrr logPrefixEszLoopbackRelay.logPrefixr )rr r!rirlrEr<rr.r4rmr5r;r9rArCrtrrrrrgs  rgc@s$eZdZddZddZddZdS)LoopbackClientFactorycCsd|_t|_||_dSr) disconnectedrrZdeferredr)rrrrrrJs  zLoopbackClientFactory.__init__cCs|jSr )r)raddrrrr buildProtocolOr:z#LoopbackClientFactory.buildProtocolcCsd|_|jddS)NrY)rvrwr)r connectorreasonrrrclientConnectionLostRsz*LoopbackClientFactory.clientConnectionLostN)rr r!rryr|rrrrruIs ruc@seZdZddZddZdS) _FireOnClosecCstj|||t|_dSr )r ProtocolWrapperrrrZrw)rrfactoryrrrrXsz_FireOnClose.__init__cCstj|||jddSr )r r~r]rwr)rr{rrrr]\sz_FireOnClose.connectionLostN)rr r!rr]rrrrr}Ws r}Tcsddlm}tt}t||||_fdd|_|j ||ddt |}||_| d j ||j}|fdd|fdd|S) zBRun session between server and client protocol instances over TCP.rrccSr rrx serverWrapperrrhzloopbackTCP..z 127.0.0.1) interfacecjSr rwxrrrrncSr  stopListeningr serverPortrrro)rerdr WrappingFactoryrFactoryr}noisyry listenTCPru connectTCPr;portrwr[)rNrOrrrdfclientFrrrrr loopbackTCPas  rcst}ddlm}tt}t||||_ fdd|_ | ||t |}||_ | |||j}|fdd|fdd|S)zJRun session between server and client protocol instances over UNIX socket.rrccrr rrrrrr{rzloopbackUNIX..crr rrrrrrrcrr rrrrrrr)tempfilemktemprerdr rrrr}rry listenUNIXru connectUNIXrwr[)rNrOrpathrdrrrrrr loopbackUNIXss    r)rT)T)"r"rzope.interfacerrerrrrtwisted.internet.interfacesrtwisted.internet.taskrtwisted.protocolsr twisted.pythonr r r% ITransport IConsumerr&rIrKrSrMr\rg ClientFactoryrur~r}rrrrrrs0      0 &G 6