o
    ¯b\6  ã                   @   sø   d 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 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mZ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)ÚOptional)Úimplementer)ÚaddressÚdeferÚerrorÚ
interfaces)ÚisIPAddressÚisIPv6Address)ÚabstractÚiocpsupport)ÚERROR_CONNECTION_REFUSEDÚERROR_IO_PENDINGÚERROR_PORT_UNREACHABLE)ÚIReadWriteHandle)ÚfailureÚlogc                   @   sö   e Zd ZU dZejZejZdZ	dZ
ee ed< d6dd„Zd	d
„ Zdef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d7dd„Zd d!„ Zd"d#„ Zd$d%„ Zd&d'„ Zd(d)„ Zd7d*d+„Z d,d-„ Z!d.d/„ Z"d0d1„ Z#d2d3„ Z$d4d5„ Z%dS )8Ú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Ú_realPortNumberÚ é    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ÚprotocolÚreadBufferSizeÚ	interfaceÚ	setLogStrÚ_connectedAddrÚ_setAddressFamilyr
   Ú
FileHandleÚ__init__ÚsocketÚaddressFamilyÚ
socketTypeÚ_iocpÚ
maxAddrLenÚfilenoÚ	bytearrayÚaddressBufferÚstructÚcalcsizeÚaddressLengthBuffer)Úselfr   Úprotor   ÚmaxPacketSizeÚreactorÚsktÚaddrLen© r1   úB/usr/lib/python3/dist-packages/twisted/internet/iocpreactor/udp.pyr   2   s   
zPort.__init__c                 C   sD   t | jƒrtj| _dS t| jƒrtj| _dS | 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+   r1   r1   r2   r   F   s   

ÿÿzPort._setAddressFamilyÚreturnc                 C   s2   | j d urd| jj› d| j › d�S d| jj› d�S )Nú<z on ú>z not connected>)r   r   Ú	__class__r6   r1   r1   r2   Ú__repr__S   s   
zPort.__repr__c                 C   ó   | j S )z)
        Return a socket object.
        )r    r6   r1   r1   r2   Ú	getHandleY   ó   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Ú_connectToProtocolr6   r1   r1   r2   ÚstartListening_   s   zPort.startListeningc                 C   s   | j  | j| j¡S ©N)r.   ÚcreateSocketr!   r"   r6   r1   r1   r2   rC   i   ó   zPort.createSocketc              
   C   sŽ   z|   ¡ }| | j| jf¡ W n ty$ } z	t | j| j|¡‚d }~ww | ¡ d | _t	 
d|  | j¡| jf ¡ d| _|| _| jj| _d S )Né   z%s starting on %sT)rC   Úbindr   r   ÚOSErrorr   ÚCannotListenErrorÚgetsocknamer   r   ÚmsgÚ_getLogPrefixr   Ú	connectedr    r%   ÚgetFileHandle)r+   r/   Úler1   r1   r2   r?   l   s    €ÿÿÿzPort._bindSocketc                 C   s$   | j  | ¡ |  ¡  | j | ¡ d S rB   )r   ÚmakeConnectionÚstartReadingr.   ÚaddActiveHandler6   r1   r1   r2   r@   €   s   zPort._connectToProtocolc                 C   s$   | j r|  |||¡ |  ¡  d S d S rB   )ÚreadingÚ
handleReadÚdoRead©r+   ÚrcÚdataÚevtr1   r1   r2   ÚcbRead…   s   þzPort.cbReadc                 C   s˜   |t jt jttfv r| jr| j ¡  d S d S |r(t 	dt j
 |d¡|f ¡ d S z| j t|jd |… ƒt |j¡¡ W d S  tyK   t ¡  Y d S w )Nzerror in recvfrom -- %s (%s)zunknown error)ÚerrnoÚWSAECONNREFUSEDÚWSAECONNRESETr   r   r   r   ÚconnectionRefusedr   rJ   Ú	errorcodeÚgetÚdatagramReceivedÚbytesÚbuffr#   ÚmakesockaddrÚ	addr_buffÚBaseExceptionÚerrrU   r1   r1   r2   rS   Š   s,   üÿÿÿ
ÿÿzPort.handleReadc                 C   sv   t  | j| ¡}| jd  |_}| j |_}| j |_}t  	|  
¡ ||||¡\}}|r7|tkr9|  |||¡ d S d S d S ©Nr   )r#   ÚEventrY   Ú_readBuffersrb   r'   rd   r*   Úaddr_len_buffÚrecvfromrM   r   rS   )r+   rX   rb   rd   rj   rV   rW   r1   r1   r2   rT       s   ÿÿzPort.doReadc              
   C   sÌ  | j rW|d| j fv sJ ‚z| j |¡W S  tyV } z7|jd }|tjkr0|  |¡W  Y d}~S |tjkr:t	 
d¡‚|tjtjttfv rJ| j ¡  n‚ W Y d}~dS d}~ww |dks]J ‚t|d ƒswt|d ƒsw|d dkrwt	 |d d¡‚t|d ƒr‹| jtjkr‹t	 |d d¡‚t|d ƒrŸ| jtjkrŸt	 |d d¡‚z| j ||¡W S  tyå } z2|jd }|tjkrÅ|  ||¡W  Y d}~S |tjkrÏt	 
d¡‚|tjtjttfv ràW Y d}~dS ‚ d}~ww )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   r    ÚsendrG   ÚargsrZ   ÚWSAEINTRÚwriteÚWSAEMSGSIZEr   ÚMessageLengthErrorr[   r\   r   r   r   r]   r   r	   r5   r!   r3   r4   Úsendto)r+   ÚdatagramÚaddrÚseÚnor1   r1   r2   ro   ­   sp   



üþ€ô
ÿ
þÿÿÿ



ü	€ïz
Port.writec                 C   s   |   d |¡|¡ d S )Nó    )ro   Újoin)r+   Úseqrt   r1   r1   r2   Ú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   r5   r    Úconnect)r+   Úhostr   r1   r1   r2   r|   ñ   s   ÿ
zPort.connectc                 C   s2   |   ¡  | j | ¡ | jr| j d| j¡ d S d S rg   )ÚstopReadingr.   ÚremoveActiveHandlerL   Ú	callLaterÚconnectionLostr6   r1   r1   r2   Ú_loseConnectionÿ   s
   ÿzPort._loseConnectionc                 C   s&   | j rt ¡  }| _nd }|  ¡  |S rB   )rL   r   ÚDeferredÚdr‚   )r+   Úresultr1   r1   r2   Ú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ÚDeprecationWarningr†   r6   r1   r1   r2   ÚloseConnection  s   ýzPort.loseConnectionc                 C   sb   t  d| j ¡ d| _tj | |¡ | j ¡  | j 	¡  | `| `
t| dƒr/| j d¡ | `dS dS )z&
        Cleans up my socket.
        z(UDP Port %s Closed)Nr„   )r   rJ   r   r
   r   r�   r   ÚdoStopr    ÚcloserM   Úhasattrr„   Úcallback)r+   Úreasonr1   r1   r2   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)rK   r   Úlogstr)r+   Ú	logPrefixr1   r1   r2   r   $  s   zPort.setLogStrc                 C   r<   )zK
        Returns the name of my class, to prefix log entries with.
        )r’   r6   r1   r1   r2   r“   +  r>   zPort.logPrefixc                 C   sR   | j  ¡ }| jt jkrtjdg|¢R Ž S | jt jkr'tjdg|dd… ¢R Ž 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}
        ÚUDPNr‡   )r    rI   r!   r4   r   ÚIPv4Addressr3   ÚIPv6Address©r+   rt   r1   r1   r2   ÚgetHost1  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+   Úenabledr1   r1   r2   ÚsetBroadcastAllowed>  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}
        )Úboolr    Ú
getsockoptrš   r›   r6   r1   r1   r2   ÚgetBroadcastAllowedG  s   zPort.getBroadcastAllowed)r   r   NrB   )&Ú__name__Ú
__module__Ú__qualname__Ú__doc__r    r4   r!   Ú
SOCK_DGRAMr"   ÚdynamicReadBuffersr   r   ÚintÚ__annotations__r   r   Ústrr;   r=   rA   rC   r?   r@   rY   rS   rT   ro   rz   r|   r‚   r†   rŒ   r�   r   r“   r˜   r�   r    r1   r1   r1   r2   r      s:   
 


A
	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    rŸ   Ú
IPPROTO_IPÚIP_MULTICAST_IFÚ	inet_ntoar(   Úpack)r+   r   r1   r1   r2   ÚgetOutgoingInterfaceV  s   z#MulticastMixin.getOutgoingInterfacec                 C   s   | j  |¡ | j¡S )z.
        Returns Deferred of success.
        )r.   ÚresolveÚaddCallbackÚ_setInterfacer—   r1   r1   r2   ÚsetOutgoingInterfaceZ  s   z#MulticastMixin.setOutgoingInterfacec                 C   s"   t  |¡}| j  t jt j|¡ dS )NrE   )r    Ú	inet_atonr™   r«   r¬   )r+   rt   r   r1   r1   r2   r²   `  s   
zMulticastMixin._setInterfacec                 C   ó   | j  t jt j¡S rB   )r    rŸ   r«   ÚIP_MULTICAST_LOOPr6   r1   r1   r2   ÚgetLoopbackModee  rD   zMulticastMixin.getLoopbackModec                 C   s(   t  dt|ƒ¡}| j tjtj|¡ d S )NÚb)r(   r®   rž   r    r™   r«   r¶   )r+   Úmoder1   r1   r2   ÚsetLoopbackModeh  s   zMulticastMixin.setLoopbackModec                 C   rµ   rB   )r    rŸ   r«   ÚIP_MULTICAST_TTLr6   r1   r1   r2   ÚgetTTLl  rD   zMulticastMixin.getTTLc                 C   s$   t  d|¡}| j tjtj|¡ d S )NÚB)r(   r®   r    r™   r«   r»   )r+   Úttlr1   r1   r2   ÚsetTTLo  s   zMulticastMixin.setTTLr   c                 C   ó   | j  |¡ | j|d¡S )zF
        Join a multicast group. Returns Deferred of success.
        rE   ©r.   r°   r±   Ú
_joinAddr1©r+   rt   r   r1   r1   r2   Ú	joinGroups  ó   zMulticastMixin.joinGroupc                 C   s   | j  |¡ | j||¡S rB   )r.   r°   r±   Ú
_joinAddr2)r+   rt   r   rx   r1   r1   r2   rÂ   y  s   zMulticastMixin._joinAddr1c              
   C   s„   t  |¡}t  |¡}|rt j}nt j}z| j  t j||| ¡ W d S  tyA } zt t	j
||g|j¢R Ž ¡W  Y d }~S d }~ww rB   )r    r´   ÚIP_ADD_MEMBERSHIPÚIP_DROP_MEMBERSHIPr™   r«   rG   r   ÚFailurer   ÚMulticastJoinErrorrm   )r+   r   rt   rx   ÚcmdÚer1   r1   r2   rÆ   |  s   

(€ÿzMulticastMixin._joinAddr2c                 C   rÀ   )zD
        Leave multicast group, return Deferred of success.
        r   rÁ   rÃ   r1   r1   r2   Ú
leaveGroupˆ  rÅ   zMulticastMixin.leaveGroupN)r   )r¡   r¢   r£   r¤   r¯   r³   r²   r·   rº   r¼   r¿   rÄ   rÂ   rÆ   rÍ   r1   r1   r1   r2   rª   Q  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 rB   )r   r   ÚlistenMultiple)r+   r   r,   r   r-   r.   rÏ   r1   r1   r2   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 )NrE   ÚSO_REUSEPORT)	r   rC   rÏ   r™   r    rš   ÚSO_REUSEADDRr�   rÐ   )r+   r/   r1   r1   r2   rC   ¡  s   

zMulticastPort.createSocket)r   r   NF)r¡   r¢   r£   r¤   r   rC   r1   r1   r1   r2   rÎ   �  s    
ùrÎ   )&r¤   rZ   r    r(   r‰   Útypingr   Úzope.interfacer   Útwisted.internetr   r   r   r   Útwisted.internet.abstractr   r	   Útwisted.internet.iocpreactorr
   r   r#   Ú"twisted.internet.iocpreactor.constr   r   r   Ú'twisted.internet.iocpreactor.interfacesr   Útwisted.pythonr   r   ÚIListeningPortÚIUDPTransportÚISystemHandler   r   rª   ÚIMulticastTransportrÎ   r1   r1   r1   r2   Ú<module>   s2   ü  1>