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rt	|d dt|d r| jtjkrt	|d dz| j||W S  ty } z2|jd }|tjkr| ||W  Y d}~S |tjkrt	
d|tjtjttfv rW 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>