U
    ¹êW[À6  ã                   @   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mZ ddlm	Z	m
Z
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mZ eeejejejƒG dd„ dej ƒƒZ!G dd„ dƒZ"eej#ƒG dd„ de"e!ƒƒZ$dS )z
UDP support for IOCP reactor
é    N)Úimplementer)ÚdeferÚaddressÚerrorÚ
interfaces)ÚisIPAddressÚisIPv6Address)ÚlogÚfailure)ÚERROR_IO_PENDING)ÚERROR_CONNECTION_REFUSED)ÚERROR_PORT_UNREACHABLE)ÚIReadWriteHandle)ÚiocpsupportÚabstractc                   @   sâ   e Zd ZdZejZejZdZ	dZ
d4d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d5dd„Zdd„ Zd d!„ Zd"d#„ Zd$d%„ Zd&d'„ Zd6d(d)„Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Z d2d3„ Z!dS )7ÚPortzÈ
    UDP port, listening for packets.

    @ivar addressFamily: L{socket.AF_INET} or L{socket.AF_INET6}, depending on
        whether this port is listening on an IPv4 address or an IPv6 address.
    FNÚ é    c                 C   sx   || _ || _|| _|| _|  ¡  d| _|  ¡  tj 	| |¡ t
 
| j| j¡}t | ¡ ¡}t|ƒ| _tt d¡ƒ| _dS )z>
        Initialize with a numeric port to listen on.
        NÚi)ÚportÚprotocolZreadBufferSizeÚ	interfaceÚ	setLogStrÚ_connectedAddrÚ_setAddressFamilyr   Ú
FileHandleÚ__init__ÚsocketÚaddressFamilyÚ
socketTypeÚ_iocpZ
maxAddrLenÚfilenoÚ	bytearrayÚaddressBufferÚstructZcalcsizeÚaddressLengthBuffer)Úselfr   Úprotor   ÚmaxPacketSizeÚreactorÚsktZaddrLen© r+   úB/usr/lib/python3/dist-packages/twisted/internet/iocpreactor/udp.pyr   *   s    
zPort.__init__c                 C   s@   t | jƒrtj| _n(t| jƒr(tj| _n| jr<t | jd¡‚dS )z8
        Resolve address family for the socket.
        znot an IPv4 or IPv6 addressN)	r   r   r   ÚAF_INET6r   r   ÚAF_INETr   ÚInvalidAddressError©r&   r+   r+   r,   r   @   s    



 ÿzPort._setAddressFamilyc                 C   s.   | j d k	rd| jj| j f S d| jjf S d S )Nz
<%s on %s>z<%s not connected>)Ú_realPortNumberr   Ú	__class__r0   r+   r+   r,   Ú__repr__M   s
    
ÿzPort.__repr__c                 C   s   | j S )z)
        Return a socket object.
        )r   r0   r+   r+   r,   Ú	getHandleU   s    zPort.getHandlec                 C   s   |   ¡  |  ¡  dS )zÐ
        Create and bind my socket, and begin listening on it.

        This is called on unserialization, and must be called after creating a
        server to begin listening on the specified port.
        N)Ú_bindSocketÚ_connectToProtocolr0   r+   r+   r,   ÚstartListening\   s    zPort.startListeningc                 C   s   | j  | j| j¡S ©N)r)   ÚcreateSocketr   r   r0   r+   r+   r,   r9   g   s    zPort.createSocketc              
   C   sš   z|   ¡ }| | j| jf¡ W n6 tjk
rT } zt | j| j|¡‚W 5 d }~X Y nX | ¡ d | _t	 
d|  | j¡| jf ¡ d| _|| _| jj| _d S )Né   z%s starting on %sT)r9   Zbindr   r   r   r   ZCannotListenErrorÚgetsocknamer1   r	   ÚmsgÚ_getLogPrefixr   Ú	connectedr!   ÚgetFileHandle)r&   r*   Úler+   r+   r,   r5   k   s    $
 ÿzPort._bindSocketc                 C   s$   | j  | ¡ |  ¡  | j | ¡ d S r8   )r   ZmakeConnectionZstartReadingr)   ZaddActiveHandler0   r+   r+   r,   r6   ~   s    zPort._connectToProtocolc                 C   s    | j r|  |||¡ |  ¡  d S r8   )ZreadingÚ
handleReadÚdoRead©r&   ÚrcÚdataÚevtr+   r+   r,   ÚcbRead„   s    zPort.cbReadc                 C   sŠ   |t jt jttfkr&| jr†| j ¡  n`|rHt 	dt j
 |d¡|f ¡ n>z(| j t|jd |… ƒt |j¡¡ W n   t ¡  Y nX d S )Nzerror in recvfrom -- %s (%s)zunknown error)ÚerrnoÚWSAECONNREFUSEDÚWSAECONNRESETr   r   r   r   ÚconnectionRefusedr	   r<   Z	errorcodeÚgetZdatagramReceivedÚbytesÚbuffr    ZmakesockaddrÚ	addr_buffÚerrrC   r+   r+   r,   rA   Š   s     
 ÿÿ
ÿzPort.handleReadc                 C   sn   t  | j| ¡}| jd  |_}| j |_}| j |_}t  	|  
¡ ||||¡\}}|rj|tkrj|  |||¡ d S ©Nr   )r    ZEventrG   Z_readBuffersrN   r#   rO   r%   Úaddr_len_buffZrecvfromr?   r   rA   )r&   rF   rN   rO   rR   rD   rE   r+   r+   r,   rB   š   s      ÿzPort.doReadc              
   C   sæ  | j r®|d| j fkst‚z| j |¡W S  tjk
r¨ } zb|jd }|tjkr`|  |¡ W Y ¢>S |tj	krvt 
d¡‚n"|tjtjttfkr–| j ¡  n‚ W 5 d}~X Y nX n4|dksºt‚t|d ƒsît|d ƒsî|d dkrît |d d¡‚t|d ƒr| jtjkrt |d d¡‚t|d ƒrF| jtjkrFt |d d¡‚z| j ||¡W S  tjk
rà } zh|jd }|tjkr–|  ||¡ W Y ¢@S |tj	kr®t 
d¡‚n"|tjtjttfkrÎW Y ¢
dS ‚ W 5 d}~X Y nX dS )z~
        Write a datagram.

        @param addr: should be a tuple (ip, port), can be None in connected
        mode.
        Nr   zmessage too longz<broadcast>z0write() only accepts IP addresses, not hostnamesz*IPv6 port write() called with IPv4 addressz*IPv4 port write() called with IPv6 address)r   ÚAssertionErrorr   Úsendr   ÚargsrH   ZWSAEINTRÚwriteZWSAEMSGSIZEZMessageLengthErrorrI   rJ   r   r   r   rK   r   r   r/   r   r-   r.   Zsendto)r&   ZdatagramÚaddrZseZnor+   r+   r,   rV   §   s`    



 ÿ
ÿþ ÿ ÿ

 ÿ
z
Port.writec                 C   s   |   d |¡|¡ d S )Nó    )rV   Újoin)r&   ÚseqrW   r+   r+   r,   ÚwriteSequenceÜ   s    zPort.writeSequencec                 C   sH   | j rtdƒ‚t|ƒs*t|ƒs*t |d¡‚||f| _ | j ||f¡ dS )z-
        'Connect' to remote server.
        z\already connected, reconnecting is not currently supported (talk to itamar if you want this)znot an IPv4 or IPv6 address.N)r   ÚRuntimeErrorr   r   r   r/   r   Úconnect)r&   Zhostr   r+   r+   r,   r]   à   s    ÿ ÿ
zPort.connectc                 C   s.   |   ¡  | j | ¡ | jr*| j d| j¡ d S rQ   )ZstopReadingr)   ZremoveActiveHandler>   Z	callLaterÚconnectionLostr0   r+   r+   r,   Ú_loseConnectionï   s    zPort._loseConnectionc                 C   s&   | j rt ¡  }| _nd }|  ¡  |S r8   )r>   r   ZDeferredÚdr_   )r&   Úresultr+   r+   r,   ÚstopListeningö   s
    zPort.stopListeningc                 C   s   t jdtdd |  ¡  d S )Nz-Please use stopListening() to disconnect porté   )Ú
stacklevel)ÚwarningsÚwarnÚDeprecationWarningrb   r0   r+   r+   r,   ÚloseConnectionÿ   s
     ÿzPort.loseConnectionc                 C   s^   t  d| j ¡ d| _tj | |¡ | j ¡  | j 	¡  | `| `
t| dƒrZ| j d¡ | `dS )z&
        Cleans up my socket.
        z(UDP Port %s Closed)Nr`   )r	   r<   r1   r   r   r^   r   ZdoStopr   Úcloser?   Úhasattrr`   Úcallback)r&   Úreasonr+   r+   r,   r^     s    


zPort.connectionLostc                 C   s   |   | j¡}d| | _dS )zP
        Initialize the C{logstr} attribute to be used by C{logPrefix}.
        z%s (UDP)N)r=   r   Úlogstr)r&   Ú	logPrefixr+   r+   r,   r     s    zPort.setLogStrc                 C   s   | j S )zK
        Returns the name of my class, to prefix log entries with.
        )rm   r0   r+   r+   r,   rn     s    zPort.logPrefixc                 C   sJ   | j  ¡ }| jt jkr$tjd|žŽ S | jt jkrFtjd|dd… žŽ S dS )z¬
        Return the local address of the UDP connection

        @returns: the local address of the UDP connection
        @rtype: L{IPv4Address} or L{IPv6Address}
        ÚUDPNrc   )ro   )ro   )r   r;   r   r.   r   ZIPv4Addressr-   ZIPv6Address©r&   rW   r+   r+   r,   ÚgetHost$  s
    
zPort.getHostc                 C   s   | j  t jt j|¡ dS )z«
        Set whether this port may broadcast. This is disabled by default.

        @param enabled: Whether the port may broadcast.
        @type enabled: L{bool}
        N)r   Ú
setsockoptÚ
SOL_SOCKETÚSO_BROADCAST)r&   Úenabledr+   r+   r,   ÚsetBroadcastAllowed2  s
      ÿzPort.setBroadcastAllowedc                 C   s   t  | j tjtj¡¡S )z“
        Checks if broadcast is currently allowed on this port.

        @return: Whether this port may broadcast.
        @rtype: L{bool}
        )ÚoperatorÚtruthr   Ú
getsockoptrs   rt   r0   r+   r+   r,   ÚgetBroadcastAllowed=  s    ÿzPort.getBroadcastAllowed)r   r   N)N)N)"Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r.   r   Z
SOCK_DGRAMr   ZdynamicReadBuffersr1   r   r   r3   r4   r7   r9   r5   r6   rG   rA   rB   rV   r[   r]   r_   rb   rh   r^   r   rn   rq   rv   rz   r+   r+   r+   r,   r      s<     ÿ

5	
r   c                   @   sl   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d„Zdd„ Zdd„ Zddd„ZdS )ÚMulticastMixinz,
    Implement multicast functionality.
    c                 C   s$   | j  t jt j¡}t  t d|¡¡S )Nz@i)r   ry   Ú
IPPROTO_IPÚIP_MULTICAST_IFZ	inet_ntoar$   Úpack)r&   r   r+   r+   r,   ÚgetOutgoingInterfaceO  s    z#MulticastMixin.getOutgoingInterfacec                 C   s   | j  |¡ | j¡S )z.
        Returns Deferred of success.
        )r)   ÚresolveÚaddCallbackÚ_setInterfacerp   r+   r+   r,   ÚsetOutgoingInterfaceT  s    z#MulticastMixin.setOutgoingInterfacec                 C   s"   t  |¡}| j  t jt j|¡ dS )Nr:   )r   Ú	inet_atonrr   r€   r   )r&   rW   r   r+   r+   r,   r†   [  s    
zMulticastMixin._setInterfacec                 C   s   | j  t jt j¡S r8   )r   ry   r€   ÚIP_MULTICAST_LOOPr0   r+   r+   r,   ÚgetLoopbackModea  s    
ÿzMulticastMixin.getLoopbackModec                 C   s*   t  dt |¡¡}| j tjtj|¡ d S )NÚb)r$   r‚   rw   rx   r   rr   r€   r‰   )r&   Úmoder+   r+   r,   ÚsetLoopbackModef  s    ÿzMulticastMixin.setLoopbackModec                 C   s   | j  t jt j¡S r8   )r   ry   r€   ÚIP_MULTICAST_TTLr0   r+   r+   r,   ÚgetTTLl  s    
ÿzMulticastMixin.getTTLc                 C   s$   t  d|¡}| j tjtj|¡ d S )NÚB)r$   r‚   r   rr   r€   rŽ   )r&   Zttlr+   r+   r,   ÚsetTTLq  s    zMulticastMixin.setTTLr   c                 C   s   | j  |¡ | j|d¡S )zF
        Join a multicast group. Returns Deferred of success.
        r:   ©r)   r„   r…   Ú
_joinAddr1©r&   rW   r   r+   r+   r,   Ú	joinGroupv  s     ÿzMulticastMixin.joinGroupc                 C   s   | j  |¡ | j||¡S r8   )r)   r„   r…   Ú
_joinAddr2)r&   rW   r   rY   r+   r+   r,   r“   ~  s     ÿzMulticastMixin._joinAddr1c              
   C   sˆ   t  |¡}t  |¡}|r t j}nt j}z| j  t j||| ¡ W nB t jk
r‚ } z"t tj	||f|j
žŽ ¡ W Y ¢S d }~X Y nX d S r8   )r   rˆ   ZIP_ADD_MEMBERSHIPZIP_DROP_MEMBERSHIPrr   r€   r   r
   ZFailureZMulticastJoinErrorrU   )r&   r   rW   rY   ÚcmdÚer+   r+   r,   r–   ƒ  s    

ÿzMulticastMixin._joinAddr2c                 C   s   | j  |¡ | j|d¡S )zD
        Leave multicast group, return Deferred of success.
        r   r’   r”   r+   r+   r,   Ú
leaveGroup‘  s     ÿzMulticastMixin.leaveGroupN)r   )r   )r{   r|   r}   r~   rƒ   r‡   r†   rŠ   r   r   r‘   r•   r“   r–   r™   r+   r+   r+   r,   r   I  s   
r   c                   @   s"   e Zd ZdZd
dd„Zdd	„ ZdS )ÚMulticastPortz.
    UDP Port that supports multicasting.
    r   r   NFc                 C   s   t  | |||||¡ || _d S r8   )r   r   ÚlistenMultiple)r&   r   r'   r   r(   r)   r›   r+   r+   r,   r      s    zMulticastPort.__init__c                 C   sB   t  | ¡}| jr>| tjtjd¡ ttdƒr>| tjtjd¡ |S )Nr:   ÚSO_REUSEPORT)	r   r9   r›   rr   r   rs   ZSO_REUSEADDRrj   rœ   )r&   r*   r+   r+   r,   r9   ¦  s    

zMulticastPort.createSocket)r   r   NF)r{   r|   r}   r~   r   r9   r+   r+   r+   r,   rš   š  s       ÿ
rš   )%r~   r   rw   r$   re   rH   Zzope.interfacer   Ztwisted.internetr   r   r   r   Ztwisted.internet.abstractr   r   Ztwisted.pythonr	   r
   Z"twisted.internet.iocpreactor.constr   r   r   Z'twisted.internet.iocpreactor.interfacesr   Ztwisted.internet.iocpreactorr   r    r   ZIListeningPortZIUDPTransportZISystemHandler   r   r   ZIMulticastTransportrš   r+   r+   r+   r,   Ú<module>   s(   ( ÿ  1Q