U
    W[d`                     @   s<  d Z ddlmZmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlmZmZmZmZmZmZ ddlmZ G dd	 d	ZG d
d deejZG dd deejZG dd deZG dd deZG dd dejZG dd dejZG dd dejZ G dd dejZ!e"eds$de_#de _#e$eds8de!_#dS )zG
Tests for implementations of L{IReactorUDP} and L{IReactorMulticast}.
    )divisionabsolute_import)unittest)
intToBytes)DeferredgatherResultsmaybeDeferred)protocolreactorerrordefer
interfacesudp)runtimec                   @   s0   e Zd ZdZdZdZdd Zdd Zdd ZdS )	Mixinr   Nc                 C   s
   g | _ d S N)packetsself r   7/usr/lib/python3/dist-packages/twisted/test/test_udp.py__init__   s    zMixin.__init__c                 C   s,   d| _ | jd k	r(| jd  }| _|d  d S N   )startedstartedDeferredcallbackr   dr   r   r   startProtocol   s    
zMixin.startProtocolc                 C   s
   d| _ d S r   )stoppedr   r   r   r   stopProtocol#   s    zMixin.stopProtocol)	__name__
__module____qualname__r   r    r   r   r   r!   r   r   r   r   r      s   r   c                   @   s   e Zd ZdZdZdd ZdS )ServerNr   c                 C   s6   | j ||f | jd k	r2| jd  }| _|d  d S r   r   appendpacketReceivedr   )r   dataaddrr   r   r   r   datagramReceived,   s    
zServer.datagramReceived)r"   r#   r$   r(   refusedr+   r   r   r   r   r%   '   s   r%   c                   @   s,   e Zd ZdZdZdd Zdd Zdd ZdS )	ClientNr   c                 C   s2   | j | | jd k	r.| jd  }| _|d  d S r   r&   )r   r)   r   r   r   r   r+   9   s    
zClient.datagramReceivedc                 C   s,   | j d k	r"| j d  }| _ || || _d S r   )r   errbackfailure)r   r/   r   r   r   r   connectionFailed?   s    

zClient.connectionFailedc                 C   s2   | j d k	r(| j d  }| _ |td d| _d S NZyupr   r   r.   r   ConnectionRefusedErrorr,   r   r   r   r   connectionRefusedE   s    
zClient.connectionRefused)r"   r#   r$   r(   r,   r+   r0   r4   r   r   r   r   r-   4   s
   r-   c                   @   s   e Zd Zdd ZdS )
GoodClientc                 C   s2   | j d k	r(| j d  }| _ |td d| _d S r1   r2   r   r   r   r   r4   N   s    
zGoodClient.connectionRefusedN)r"   r#   r$   r4   r   r   r   r   r5   L   s   r5   c                   @   s   e Zd ZdZdS )BadClientErrorzf
    Raised by BadClient at the end of every datagramReceived call to try and
    screw stuff up.
    N)r"   r#   r$   __doc__r   r   r   r   r6   V   s   r6   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )	BadClientz
    A DatagramProtocol which always raises an exception from datagramReceived.
    Used to test error handling behavior in the reactor for that method.
    Nc                 C   s
   || _ dS )ze
        Set the Deferred which will be called back when datagramReceived is
        called.
        N)r   r   r   r   r   setDeferrede   s    zBadClient.setDeferredc                 C   s.   | j d k	r"| j d  }| _ || tdd S )NzApplication code is very buggy!)r   r   r6   )r   bytesr*   r   r   r   r   r+   m   s    

zBadClient.datagramReceived)r"   r#   r$   r7   r   r9   r+   r   r   r   r   r8   ^   s   r8   c                   @   sT   e 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S )UDPTestsc                    s<   t  }t  }|_tjd|dd  fdd}||S )zu
        The C{type} of the host address of a listening L{DatagramProtocol}'s
        transport is C{"UDP"}.
        r   	127.0.0.1Z	interfacec                    s      }|jd   S )NZUDP)getHostassertEqualtypestopListening)ignoredr*   pr   r   r   	cbStarted   s    z+UDPTests.test_oldAddress.<locals>.cbStartedr%   r   r   r   r
   	listenUDPaddCallback)r   serverr   rE   r   rC   r   test_oldAddressw   s
    zUDPTests.test_oldAddressc                    sR   t  t  }_tjddd  fdd}fdd}|||S )z
        The L{DatagramProtocol}'s C{startProtocol} and C{stopProtocol}
        methods are called when its transports starts and stops listening,
        respectively.
        r   r<   r=   c                    s$    jd  jd   S )Nr   r   )r?   r   r    rA   rB   port1r   rI   r   r   rE      s    z*UDPTests.test_startStop.<locals>.cbStartedc                    s     jd d S r   )r?   r    rK   )r   rI   r   r   	cbStopped   s    z*UDPTests.test_startStop.<locals>.cbStoppedrF   )r   r   rE   rN   r   rL   r   test_startStop   s    zUDPTests.test_startStopc                    sF   t  t  }_tjddd}dd   fdd}| |S )zr
        Re-listening with the same L{DatagramProtocol} re-invokes the
        C{startProtocol} callback.
        r   r<   r=   c                 S   s   |  S r   rA   )rB   portr   r   r   rE      s    z'UDPTests.test_rebind.<locals>.cbStartedc                    s*   t   }_tjddd}| |S Nr   r<   r=   )r   r   r   r
   rG   rH   )rB   r   rD   rE   rI   r   r   rN      s    z'UDPTests.test_rebind.<locals>.cbStoppedrF   )r   r   rD   rN   r   rS   r   test_rebind   s    zUDPTests.test_rebindc                    sX   t  t  }_tjddd  fdd}||  fdd}|| |S )z
        A L{CannotListenError} exception is raised when attempting to bind a
        second protocol instance to an already bound port
        r   r<   r=   c                    s>      j  t }jtjtj  j	|dd d S )Nr<   r=   )
r?   r>   	transportr%   assertRaisesr   ZCannotListenErrorr
   rG   rQ   )rB   Zserver2rQ   r   rI   r   r   rE      s      z*UDPTests.test_bindError.<locals>.cbStartedc                    s      S r   rP   rK   rQ   r   r   
cbFinished   s    z+UDPTests.test_bindError.<locals>.cbFinishedrF   )r   r   rE   rY   r   rW   r   test_bindError   s    

zUDPTests.test_bindErrorc                    s   t  t  }_tjdddt  t   _ fdd}||} fdd}||  fdd	}|| fd
d}|| |S )z
        Datagrams can be sent with the transport's C{write} method and
        received via the C{datagramReceived} callback method.
        r   r<   r=   c                    s   t jd dd_S rR   )r
   rG   port2rK   )clientclientStartedr   r   r   cbServerStarted   s    z2UDPTests.test_sendPackets.<locals>.cbServerStartedc                    s   j dj  j j  }j  }t  }_j d|j|jf ddd|j|jffg fdd tj	 d |gdd	S )
Nr<      hello)   a)   bN   cc                    s6   r2t   }_|  jjd  |S d S Nr   )r   r   r(   rH   rU   writepop)rB   ZnextClientWrite)cbClientSendr\   clientWritesrI   r   r   rf      s
    
zHUDPTests.test_sendPackets.<locals>.cbClientStarted.<locals>.cbClientSendTZfireOnOneErrback)
rU   connectr>   rQ   r   r   r(   rd   hostDeferredList)rB   cAddrsAddrZ
serverSend)r\   rI   )rf   rg   r   cbClientStarted   s$    



z2UDPTests.test_sendPackets.<locals>.cbClientStartedc                    s`    j  }j  } jd|j|jffg |j|jf}jd|fd|fd|fg d S )Nr_   r`   ra   rb   )rU   r>   r?   r   rj   rQ   )rB   rl   rm   Z
clientAddrr\   r   rI   r   r   cbSendsFinished   s    

z2UDPTests.test_sendPackets.<locals>.cbSendsFinishedc                    s$   t jt  jt jjgddS NTrh   )r   rk   r   rA   r[   rK   )rM   r   r   r   rY     s    
z-UDPTests.test_sendPackets.<locals>.cbFinished)r%   r   r   r   r
   rG   r5   rH   )r   serverStartedr^   r   rn   rp   rY   r   )r\   r]   rM   r   rI   r   test_sendPackets   s    



zUDPTests.test_sendPacketsc                    s   t   t  } _tjd ddt t  }_tjdddtj||gdd} fdd}|| fdd	}|| |S )
z
        A L{ConnectionRefusedError} exception is raised when a connection
        attempt is actively refused by the other end.

        Note: This test assumes no one is listening on port 80 UDP.
        r   r<   r=   Trh   c                    sZ   t   } _ jdd tdD ]&} jt| jt|d q$|t	j
S )Nr<   P   
   )r<   rt   )r   r   r   rU   ri   rangerd   r   assertFailurer   r3   )rB   r4   iro   r   r   rE   "  s    z2UDPTests.test_connectionRefused.<locals>.cbStartedc                    s"   t jt  jt jgddS rq   )r   rk   r   rA   rK   )rQ   r[   r   r   rY   0  s    

z3UDPTests.test_connectionRefused.<locals>.cbFinished)	r5   r   r   r   r
   rG   r%   rk   rH   )r   r]   rr   r   rE   rY   r   )r\   rQ   r[   r   rI   r   test_connectionRefused  s    

zUDPTests.test_connectionRefusedc                 C   sV   t  }tjd|dd}| tj|jjdd |jdd | t|jjdd |	 S )a   
        A call to the transport's connect method fails with an
        L{InvalidAddressError} when a non-IP address is passed as the host
        value.

        A call to a transport's connect method fails with a L{RuntimeError}
        when the transport is already connected.
        r   r<   r=   Z	localhostrt   )
r5   r
   rG   rV   r   ZInvalidAddressErrorrU   ri   RuntimeErrorrA   )r   r\   rQ   r   r   r   test_badConnect:  s    	  zUDPTests.test_badConnectc                    s   t  fdd}| t tjdddfdd}|   tt	dg  fd	d
  S )zr
        When datagramReceived raises an exception it is logged but the port
        is not disconnected.
        c                    s*     t} t|ddt|f  dS )z
            Flush the exceptions which the reactor should have logged and make
            sure they're actually there.
               z'Incorrectly found %d errors, expected 2N)flushLoggedErrorsr6   r?   len)ignZerrsr   r   r   cbCompletedU  s    
z8UDPTests.test_datagramReceivedError.<locals>.cbCompletedr   r<   r=   c                    s   t j fddS )z
            Disconnect the port we started and pass on whatever was given to us
            in case it was a Failure.
            c                    s    S r   r   r   resultr   r   <lambda>f      zHUDPTests.test_datagramReceivedError.<locals>.cbCleanup.<locals>.<lambda>)r   r   rA   addBothr   rX   r   r   	cbCleanupa  s    z6UDPTests.test_datagramReceivedError.<locals>.cbCleanup<   c                     s   s(z d W n     Y nX jdd td} t }| j	| j
jf  fdd}fdd}||| |j td	|jtd
 dS )a6  
            Send one packet to the listening BadClient.  Set up a 0.1 second
            timeout to do re-transmits in case the packet is dropped.  When two
            packets have been received by the BadClient, stop sending and let
            the finalDeferred's callbacks do some assertions.
            zNot enough packets receivedNzUDP Protocol lost its transportr   c                    s:      |  tdkr0td jd n  dS )z
                A packet arrived.  Cancel the timeout for it, record it, and
                maybe finish the test.
                r|   r   N)Zcancelr'   r~   r
   	callLaterr   )packet)finalDeferredmakeAttemptsucceededAttemptstimeoutCallr   r   cbPacketReceived  s
    
zRUDPTests.test_datagramReceivedError.<locals>.makeAttempt.<locals>.cbPacketReceivedc                    s
      dS )a  
                The packet wasn't received quickly enough.  Try sending another
                one.  It doesn't matter if the packet for which this was the
                timeout eventually arrives: makeAttempt throws away the
                Deferred on which this function is the errback, so when
                datagramReceived callbacks, so it won't be on this Deferred, so
                it won't raise an AlreadyCalledError.
                Nr   )err)r   r   r   ebPacketTimeout  s    	zQUDPTests.test_datagramReceivedError.<locals>.makeAttempt.<locals>.ebPacketTimeoutg?z&Timed out in testDatagramReceivedError)Zfailr.   ZfailIfIdenticalrU   r   re   r   r   r9   rd   rj   rQ   ZaddCallbacksZ
addErrbackr
   r   r   TimeoutError)r   ZpacketDeferredr   r   )r*   attemptsr\   r   r   r   r   )r   r   r   v  s*    
 z8UDPTests.test_datagramReceivedError.<locals>.makeAttempt)
r   r   rH   r8   r
   rG   r   r>   listrv   )r   r   r   r   )r*   r   r\   r   r   rQ   r   r   r   test_datagramReceivedErrorN  s    


7z#UDPTests.test_datagramReceivedErrorc                 C   sR   G dd d}t dt }| |_|dd | | jg}| t|d dS )ai  
        C{'<broadcast>'} is an alternative way to say C{'255.255.255.255'}
        ({socket.gethostbyname("<broadcast>")} returns C{'255.255.255.255'}),
        so because it becomes a valid IP address, no deprecation warning about
        passing hostnames to L{twisted.internet.udp.Port.write} needs to be
        emitted by C{write()} in this case.
        c                   @   s   e Zd Zdd ZdS )z6UDPTests.test_NoWarningOnBroadcast.<locals>.fakeSocketc                 S   s   d S r   r   )r   ZfooZbarr   r   r   sendto  s    z=UDPTests.test_NoWarningOnBroadcast.<locals>.fakeSocket.sendtoN)r"   r#   r$   r   r   r   r   r   
fakeSocket  s   r   r   s   test)z<broadcast>i  N)	r   ZPortr%   Zsocketrd   ZflushWarningstest_NoWarningOnBroadcastr?   r~   )r   r   rD   warningsr   r   r   r     s    z"UDPTests.test_NoWarningOnBroadcastN)r"   r#   r$   rJ   rO   rT   rZ   rs   ry   r{   r   r   r   r   r   r   r;   u   s   K+cr;   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ReactorShutdownInteractionTestsz!Test reactor shutdown interactionc                 C   s    t  | _tjd| jdd| _dS )zStart a UDP portr   r<   r=   N)r%   rI   r
   rG   rQ   r   r   r   r   setUp  s    z%ReactorShutdownInteractionTests.setUpc                 C   s
   | j  S )zStop the UDP port)rQ   rA   r   r   r   r   tearDown  s    z(ReactorShutdownInteractionTests.tearDownc                    sh   t   t   }j_ fdd}|| fdd} | jjddjj jf  S )z0Test reactor shutdown while in a recvfrom() loopc                    s    j j  td jd  d S rc   )rI   rU   ZconnectionLostr
   r   r   rK   Zfinishedr   r   r   pktRece  s    zQReactorShutdownInteractionTests.testShutdownFromDatagramReceived.<locals>.pktRecec                    s       d S r   )r}   rK   r   r   r   flushErrors  s    zUReactorShutdownInteractionTests.testShutdownFromDatagramReceived.<locals>.flushErrorss@                                                                   r<   )	r   r   rI   r(   rH   rU   rd   r>   rQ   )r   prr   r   r   r   r    testShutdownFromDatagramReceived  s    

z@ReactorShutdownInteractionTests.testShutdownFromDatagramReceivedN)r"   r#   r$   r7   r   r   r   r   r   r   r   r     s   r   c                   @   s~   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	e
j rZe
j sZde	_dd Zdd Ze
j rzde_dS )MulticastTestsc                 C   sN   t  | _t | _td| j| _td| j| _| jj	d| jj
 j d S )Nr   r<   )r%   rI   r-   r\   r
   listenMulticastrM   r[   rU   ri   r>   rQ   r   r   r   r   r     s     zMulticastTests.setUpc                 C   s   t t| jjt| jjgS r   )r   r   rM   rA   r[   r   r   r   r   r     s    

zMulticastTests.tearDownc                 C   sF   | j | jfD ]4}| |j d |jd | |j d qd S )Nr   r|   )r\   rI   r?   rU   ZgetTTLZsetTTL)r   or   r   r   testTTL	  s    zMulticastTests.testTTLc                    sx    jj d jj  jjd} fdd}||  fdd}|| fdd}|| |S )	zv
        Test that after loopback mode has been set, multicast packets are
        delivered to their sender.
        r   225.0.0.250c                    s(   t   }j_jjdd jf |S )Nr_   r   r   rI   r(   rU   rd   rQ   rB   r   r*   r   r   r   cbJoined  s    z.MulticastTests.test_loopback.<locals>.cbJoinedc                    sf    tjjd jjd  jj d jjdd jf t	 }t
d|jd  |S )Nr   r   r_   r   )r?   r~   rI   r   rU   ZsetLoopbackModegetLoopbackModerd   rQ   r   r
   r   r   r   r   r   r   cbPacket  s    z.MulticastTests.test_loopback.<locals>.cbPacketc                    s     t jjd d S r   )r?   r~   rI   r   rK   r   r   r   
cbNoPacket+  s    z0MulticastTests.test_loopback.<locals>.cbNoPacket)r?   rI   rU   r   r>   	joinGrouprH   )r   joinedr   r   r   r   r   r   test_loopback  s    



zMulticastTests.test_loopbackc                    sj      jj d    jj d  jjd} jjd}t||g} fdd}|| |S )zK
        Test C{getOutgoingInterface} and C{setOutgoingInterface}.
        z0.0.0.0r<   c                    s,      jj d    jj d d S )Nr<   )r?   r\   rU   getOutgoingInterfacerI   rK   r   r   r   cbInterfaces?  s    
 
 z3MulticastTests.test_interface.<locals>.cbInterfaces)r?   r\   rU   r   rI   ZsetOutgoingInterfacer   rH   )r   d1d2r   r   r   r   r   test_interface2  s    
 
 
zMulticastTests.test_interfacec                    sT    j jd} fdd}||  fdd}||  fdd}|| |S )zE
        Test that multicast a group can be joined and left.
        r   c                    s    j jdS Nr   )r\   rU   
leaveGrouprK   r   r   r   clientJoinedN  s    z3MulticastTests.test_joinLeave.<locals>.clientJoinedc                    s    j jdS r   )rI   rU   r   rK   r   r   r   
clientLeftR  s    z1MulticastTests.test_joinLeave.<locals>.clientLeftc                    s    j jdS r   )rI   rU   r   rK   r   r   r   serverJoinedV  s    z3MulticastTests.test_joinLeave.<locals>.serverJoined)r\   rU   r   rH   )r   r   r   r   r   r   r   r   test_joinLeaveH  s    


zMulticastTests.test_joinLeavec                 C   s   |  | jjdtjS )z
        Test that an attempt to join an address which is not a multicast
        address fails with L{error.MulticastJoinError}.
        r<   )rw   r\   rU   r   r   ZMulticastJoinErrorr   r   r   r   test_joinFailure]  s    zMulticastTests.test_joinFailurez2Windows' UDP multicast is not yet fully supported.c                    sv   t  tdjj  jjd} fdd}|| fdd}|| fdd}|| |S )	zn
        Test that a multicast group can be joined and messages sent to and
        received from it.
        r   r   c                    s&   t   }j_jdd jf |S )N   hello worldr   r   r   )r*   cr   r   r   r   w  s    z/MulticastTests.test_multicast.<locals>.cbJoinedc                    s      jjd d d d S Nr   r   )r?   rI   r   rK   r   r   r   r   }  s    z/MulticastTests.test_multicast.<locals>.cbPacketc                    s    t j}| fdd |S )Nc                    s    S r   r   r   passthroughr   r   r     r   z@MulticastTests.test_multicast.<locals>.cleanup.<locals>.<lambda>)r   rA   rH   r   r   )rD   r   r   cleanup  s    
z.MulticastTests.test_multicast.<locals>.cleanup)r%   r
   r   rI   rU   r>   r   rH   )r   r   r   r   r   r   )r*   r   rD   r   r   test_multicastl  s    


zMulticastTests.test_multicastc                    s   t   tjd dd jt  tjdddtjjg} fdd}|	|  fdd}|	| fd	d
}|
| |S )z
        Test that multiple sockets can listen on the same multicast port and
        that they both receive multicast messages directed to that address.
        r   T)ZlistenMultipler   c                    s6   t   } _t   }_ jdf t||gS )Nr   )r   r(   rU   rd   r   )rB   r   r   )firstClientportnosecondClienttheGroupr   r   r     s    z5MulticastTests.test_multiListen.<locals>.serverJoinedc                    s0     jd d d  jd d d d S r   )r?   r   rK   )r   r   r   r   r   
gotPackets  s    z3MulticastTests.test_multiListen.<locals>.gotPacketsc                    s.   t tjtjg}| fdd |S )Nc                    s    S r   r   r   r   r   r   r     r   zBMulticastTests.test_multiListen.<locals>.cleanup.<locals>.<lambda>)r   r   rA   rH   r   )	firstPort
secondPortr   r   r     s    z0MulticastTests.test_multiListen.<locals>.cleanup)r%   r
   r   r>   rQ   r   rI   rU   r   rH   r   )r   r   r   r   r   r   )r   r   r   r   r   r   r   r   test_multiListen  s2      
  


zMulticastTests.test_multiListenzjon non-linux platforms it appears multiple processes can listen, but not multiple sockets in same process?N)r"   r#   r$   r   r   r   r   r   r   r   r   platformZ	isWindowsZisVistaskipr   r   r   r   r   r   r     s   
"	)
r   Nz!This reactor does not support UDPz'This reactor does not support multicast)%r7   Z
__future__r   r   Ztwisted.trialr   Ztwisted.python.compatr   Ztwisted.internet.deferr   r   r   Ztwisted.internetr	   r
   r   r   r   r   Ztwisted.pythonr   r   ZDatagramProtocolr%   ZConnectedDatagramProtocolr-   r5   	Exceptionr6   r8   ZTestCaser;   r   r   ZIReactorUDPr   ZIReactorMulticastr   r   r   r   <module>   s.    
  S1 C