U
    ¹êW[¯N  ã                   @   sØ  d Z ddlZddlZddlZddlZddlmZmZ ddlm	Z	m
Z
mZmZmZ ddlmZ ddlmZmZ ddlmZmZmZmZmZmZmZ ddl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- ddl)m.Z. zddl/m0Z1 W n e2k
r6   dZ1Y nX e-ej3e.ej4iZ5ee(e	j6e	j7ƒG dd„ de&j8eeƒƒZ9e1dk	r„ee9e	j:ƒ G dd„ deee9ƒZ;G dd„ de9ƒZ<G dd„ deƒZee	j=ƒG dd„ deeƒƒZ>dS )z
TCP support for IOCP reactor
é    N)ÚimplementerÚclassImplements)Ú
interfacesÚerrorÚaddressÚmainÚdefer)ÚProtocol)Ú	_LogOwnerÚisIPv6Address)Ú_SocketCloserÚ	ConnectorÚ_AbortingMixinÚ_BaseBaseClientÚ_BaseTCPClientÚ_resolveIPv6Ú_getsockname)ÚlogÚfailureÚreflect)Ú_PY3ÚnativeString)ÚiocpsupportÚabstract)ÚIReadWriteHandle)ÚERROR_IO_PENDING)ÚSO_UPDATE_CONNECT_CONTEXT)ÚSO_UPDATE_ACCEPT_CONTEXT)ÚERROR_CONNECTION_REFUSED)ÚERROR_NETWORK_UNREACHABLE)ÚstartTLSc                   @   sº   e Zd ZdZdZd+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dd„ Zdd„ Zdd„ Zedk	rŒd,dd „Zd!d"„ Zd#d$„ Zd-d%d&„Zd'd(„ Zd)d*„ ZdS ).Ú
ConnectionzÞ
    @ivar TLS: C{False} to indicate the connection is in normal TCP mode,
        C{True} to indicate that TLS has been started and that operations must
        be routed through the L{TLSMemoryBIOProtocol} instance.
    FNc                 C   s&   t j | |¡ || _|j| _|| _d S ©N)r   Ú
FileHandleÚ__init__ÚsocketÚfilenoÚgetFileHandleÚprotocol)ÚselfÚsockÚprotoÚreactor© r-   úB/usr/lib/python3/dist-packages/twisted/internet/iocpreactor/tcp.pyr$   3   s    zConnection.__init__c                 C   s   | j S r"   )r%   ©r)   r-   r-   r.   Ú	getHandle:   s    zConnection.getHandlec                 C   s@   t |tƒrn$t |tƒr t|ƒ}ntdt|ƒ ƒ‚| j |¡ dS )z`
        @param rbuffer: Data received.
        @type rbuffer: L{bytes} or L{bytearray}
        z%data must be bytes or bytearray, not N)Ú
isinstanceÚbytesÚ	bytearrayÚ	TypeErrorÚtyper(   ÚdataReceived)r)   Zrbufferr-   r-   r.   r6   >   s    


ÿzConnection.dataReceivedc                 C   s   t  |  ¡ ||¡S r"   )Ú_iocpZrecvr'   )r)   ZbufflistÚevtr-   r-   r.   ÚreadFromHandleO   s    zConnection.readFromHandlec                 C   s(   t |ƒ}t |  ¡ |d| j…  ¡ |¡S )zŽ
        Send C{buff} to current file handle using C{_iocp.send}. The buffer
        sent is limited to a size of C{self.SEND_LIMIT}.
        r   )Ú
memoryviewr7   Úsendr'   Z
SEND_LIMITÚtobytes)r)   Úbuffr8   Z	writeViewr-   r-   r.   ÚwriteToHandleS   s
    
 ÿzConnection.writeToHandlec                 C   sr   z| j  d¡ W n t jk
r&   Y nX t | jd ¡}|rnz| ¡  W n&   t ¡ }t	 
¡  |  |¡ Y nX d S )Né   )r%   Zshutdownr   r   ÚIHalfCloseableProtocolr(   ZwriteConnectionLostr   ÚFailurer   ÚerrÚconnectionLost)r)   ÚpÚfr-   r-   r.   Ú_closeWriteConnection]   s    z Connection._closeWriteConnectionc                 C   sR   t  | jd ¡}|rDz| ¡  W qN   t ¡  |  t ¡ ¡ Y qNX n
|  |¡ d S r"   )	r   r@   r(   ÚreadConnectionLostr   rB   rC   r   rA   )r)   ÚreasonrD   r-   r-   r.   rG   l   s    zConnection.readConnectionLostc                 C   sX   | j r
d S tj | |¡ |d kp,| tj¡ }|  |¡ | j}| `| `	| `
| |¡ d S r"   )Údisconnectedr   r#   rC   Zcheckr   ZConnectionAbortedÚ_closeSocketr(   r%   r'   )r)   rH   ZisCleanr(   r-   r-   r.   rC   x   s    ÿ
zConnection.connectionLostc                 C   s   | j S )zN
        Return the prefix to log with when I own the logging thread.
        )Úlogstrr/   r-   r-   r.   Ú	logPrefix†   s    zConnection.logPrefixc                 C   s   t  | j tjtj¡¡S r"   )ÚoperatorÚtruthr%   Ú
getsockoptÚIPPROTO_TCPÚTCP_NODELAYr/   r-   r-   r.   ÚgetTcpNoDelay   s    ÿzConnection.getTcpNoDelayc                 C   s   | j  t jt j|¡ d S r"   )r%   Ú
setsockoptrP   rQ   ©r)   Úenabledr-   r-   r.   ÚsetTcpNoDelay’   s    zConnection.setTcpNoDelayc                 C   s   t  | j tjtj¡¡S r"   )rM   rN   r%   rO   Ú
SOL_SOCKETÚSO_KEEPALIVEr/   r-   r-   r.   ÚgetTcpKeepAlive–   s    ÿzConnection.getTcpKeepAlivec                 C   s   | j  t jt j|¡ d S r"   )r%   rS   rW   rX   rT   r-   r-   r.   ÚsetTcpKeepAlive›   s    zConnection.setTcpKeepAliveTc                 C   s   t | ||tjƒ dS )z9
            @see: L{ITLSTransport.startTLS}
            N)Ú	_startTLSr   r#   )r)   ZcontextFactoryZnormalr-   r-   r.   r        s    zConnection.startTLSc                 C   s0   | j r
dS | jr| j |¡ ntj | |¡ dS )zò
        Write some data, either directly to the underlying handle or, if TLS
        has been started, to the L{TLSMemoryBIOProtocol} for it to encrypt and
        send.

        @see: L{twisted.internet.interfaces.ITransport.write}
        N)rI   ÚTLSr(   Úwriter   r#   )r)   Údatar-   r-   r.   r]   §   s
    zConnection.writec                 C   s0   | j r
dS | jr| j |¡ ntj | |¡ dS )zú
        Write some data, either directly to the underlying handle or, if TLS
        has been started, to the L{TLSMemoryBIOProtocol} for it to encrypt and
        send.

        @see: L{twisted.internet.interfaces.ITransport.writeSequence}
        N)rI   r\   r(   ÚwriteSequencer   r#   )r)   Ziovecr-   r-   r.   r_   ·   s
    zConnection.writeSequencec                 C   s0   | j r| jr,| js,| j ¡  ntj | |¡ dS )z®
        Close the underlying handle or, if TLS has been started, first shut it
        down.

        @see: L{twisted.internet.interfaces.ITransport.loseConnection}
        N)r\   Ú	connectedÚdisconnectingr(   ÚloseConnectionr   r#   )r)   rH   r-   r-   r.   rb   Ç   s    zConnection.loseConnectionc                 C   s*   | j r| j ||¡ ntj | ||¡ dS )zc
        Register a producer.

        If TLS is enabled, the TLS connection handles this.
        N)r\   r(   ÚregisterProducerr   r#   )r)   ZproducerZ	streamingr-   r-   r.   rc   Õ   s    zConnection.registerProducerc                 C   s"   | j r| j ¡  ntj | ¡ dS )ze
        Unregister a producer.

        If TLS is enabled, the TLS connection handles this.
        N)r\   r(   ÚunregisterProducerr   r#   r/   r-   r-   r.   rd   å   s    zConnection.unregisterProducer)N)T)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r\   r$   r0   r6   r9   r>   rF   rG   rC   rL   rR   rV   rY   rZ   r[   r    r]   r_   rb   rc   rd   r-   r-   r-   r.   r!   (   s,   



r!   c                   @   sT   e Zd ZdZejZejZdZ	e
Zdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ ZdS )ÚClientzº
    @ivar _tlsClientDefault: Always C{True}, indicating that this is a client
        connection, and by default when TLS is negotiated this class will act as
        a TLS client.
    Tc                 C   s*   |d krd}|| _ t | |||||¡ d S )N)Ú r   )r,   r   r$   )r)   ÚhostÚportÚbindAddressÚ	connectorr,   r-   r-   r.   r$     s    ÿzClient.__init__c                 C   s   | j  | j| j¡S )zd
        Create a socket registered with the IOCP reactor.

        @see: L{_BaseTCPClient}
        )r,   ÚcreateSocketÚaddressFamilyÚ
socketTyper/   r-   r-   r.   ÚcreateInternetSocket
  s    zClient.createInternetSocketc                 C   s   | ` | `dS )z–
        Clean up potentially circular references to the socket and to its
        C{getFileHandle} method.

        @see: L{_BaseBaseClient}
        N)r%   r'   r/   r-   r-   r.   Ú_collectSocketDetails  s    zClient._collectSocketDetailsc                 C   s   | j  | ¡ dS )z^
        Remove the active handle from the reactor.

        @see: L{_BaseBaseClient}
        N)r,   ÚremoveActiveHandler/   r-   r-   r.   Ú_stopReadingAndWriting  s    zClient._stopReadingAndWritingc              	   C   s²   |r0t  ||¡}|  t |tj |d¡f¡¡ n~| j tj	t
t d| j ¡ ¡¡ | j |  ¡ ¡| _d| _|  | j¡}|d | _| jd krštƒ | _|  ¡  n| j | ¡ |  ¡  d S )NzUnknown errorÚPTz,client)ÚconnectExErrorsÚgetZfailIfNotConnectedr   ZgetConnectErrorÚerrnoÚ	errorcoder%   rS   rW   r   ÚstructÚpackr&   rn   ÚbuildProtocolÚgetPeerr(   r`   Ú_getLogPrefixrK   r	   rb   ÚmakeConnectionÚstartReading)r)   Úrcr^   r8   rL   r-   r-   r.   Ú	cbConnect&  s&    
ÿ
 þ


zClient.cbConnectc                 C   sf   t | dƒsd S tjst‚| j | ¡ t | j| ¡}t | j	 
¡ | j|¡}|rb|tkrb|  |d|¡ d S )Nrn   r   )Úhasattrr7   Zhave_connectexÚAssertionErrorr,   ÚaddActiveHandleÚEventrƒ   Zconnectr%   r&   ZrealAddressr   )r)   r8   r‚   r-   r-   r.   Ú	doConnectB  s    

zClient.doConnectN)re   rf   rg   rh   r%   ÚAF_INETrp   ÚSOCK_STREAMrq   Ú_tlsClientDefaultr!   Z_commonConnectionr$   rr   rs   ru   rƒ   rˆ   r-   r-   r-   r.   ri   õ   s   		
	ri   c                   @   s4   e Zd ZdZdZdd„ Zdd„ Zdd„ Zd	d
„ ZdS )ÚServeraV  
    Serverside socket-stream connection class.

    I am a serverside network connection transport; a socket which came from an
    accept() on a server.

    @ivar _tlsClientDefault: Always C{False}, indicating that this is a server
        connection, and by default when TLS is negotiated this class will act as
        a TLS server.
    Fc                 C   sp   t  | |||¡ || _|| _|| _|  | j¡}d||| jjf | _d| jj	j
| j| jjf | _d| _|  ¡  dS )a  
        Server(sock, protocol, client, server, sessionno)

        Initialize me with a socket, a protocol, a descriptor for my peer (a
        tuple of host, port describing the other end of the connection), an
        instance of Port, and a session number.
        z%s,%s,%sz<%s #%s on %s>TN)r!   r$   Ú
serverAddrÚ
clientAddrÚ	sessionnor   r(   rk   rK   Ú	__class__re   rl   Úrepstrr`   r   )r)   r*   r(   rŽ   r   r   r,   rL   r-   r-   r.   r$   `  s    
 ÿzServer.__init__c                 C   s   | j S )z=
        A string representation of this connection.
        )r‘   r/   r-   r-   r.   Ú__repr__t  s    zServer.__repr__c                 C   s   | j S )zW
        Returns an IPv4Address.

        This indicates the server's address.
        )r   r/   r-   r-   r.   ÚgetHost{  s    zServer.getHostc                 C   s   | j S )zW
        Returns an IPv4Address.

        This indicates the client's address.
        )rŽ   r/   r-   r-   r.   r~   „  s    zServer.getPeerN)	re   rf   rg   rh   r‹   r$   r’   r“   r~   r-   r-   r-   r.   rŒ   Q  s   	rŒ   c                   @   s   e Zd Zdd„ ZdS )r   c                 C   s   t | j| j| j| | jƒS r"   )ri   rk   rl   rm   r,   r/   r-   r-   r.   Ú_makeTransport  s    ÿzConnector._makeTransportN)re   rf   rg   r”   r-   r-   r-   r.   r   Ž  s   r   c                   @   s    e Zd ZdZdZdZejZej	Z
ejZdZdZdZddd„Zd	d
„ Zdd„ Ze ej¡fdd„ZeZdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z dS )ÚPortFr   NÚTCPé2   rj   c                 C   s:   || _ || _|| _|| _|| _t|ƒr6tj| _t	j
| _d S r"   )rl   ÚfactoryÚbacklogÚ	interfacer,   r   r%   ÚAF_INET6rp   r   ZIPv6AddressÚ_addressType)r)   rl   r˜   r™   rš   r,   r-   r-   r.   r$   ª  s    zPort.__init__c                 C   s6   | j d k	r d| j| jj| j f S d| j| jjf S d S )Nz<%s of %s on %s>z<%s of %s (not listening)>)Ú_realPortNumberr   r˜   r/   r-   r-   r.   r’   µ  s    
þÿzPort.__repr__c              
   C   s  zH| j  | j| j¡}| jtjkr0t| j| jƒ}n| j| jf}| 	|¡ W n6 tj
k
r~ } zt
 | j| j|¡‚W 5 d }~X Y nX t | ¡ ¡| _| ¡ d | _t d|  | j¡| jf ¡ | j ¡  | | j¡ d| _d| _| j  | ¡ || _| jj| _|  ¡  d S )Nr?   z%s starting on %sTF)r,   ro   rp   rq   r%   r›   r   rš   rl   Zbindr   ZCannotListenErrorr7   Z
maxAddrLenr&   ÚaddrLenZgetsocknamer   r   Úmsgr   r˜   ZdoStartZlistenr™   r`   rI   r†   r'   ÚdoAccept)r)   ZsktZaddrÚler-   r-   r.   ÚstartListening¿  s.    
ÿ$ÿ

zPort.startListeningc                 C   s2   d| _ | jr.t ¡ | _| j d| j|¡ | jS dS )zæ
        Stop accepting connections on this port.

        This will shut down my socket and call self.connectionLost().
        It returns a deferred which will fire successfully when the
        port is actually closed.
        Tr   N)ra   r`   r   ZDeferredÚdeferredr,   Z	callLaterrC   )r)   ZconnDoner-   r-   r.   rb   ß  s
    
zPort.loseConnectionc                 C   s   t  d| j| jf ¡ dS )z.
        Log message for closing port
        z(%s Port %s Closed)N)r   rŸ   Ú_typer   r/   r-   r-   r.   Ú_logConnectionLostMsgð  s    zPort._logConnectionLostMsgc                 C   s¨   |   ¡  d| _d}t| dƒr&| j}| `d| _| j | ¡ d| _|  d¡ | `	| `
z| j ¡  W n,   d| _|dk	r„| t ¡ ¡ n‚ Y nX d| _|dk	r¤| d¡ dS )z'
        Cleans up the socket.
        Nr£   TF)r¥   r   r„   r£   rI   r,   rt   r`   rJ   r%   r'   r˜   ZdoStopra   Zerrbackr   rA   Úcallback)r)   rH   Údr-   r-   r.   rC   ÷  s,    

zPort.connectionLostc                 C   s   t  | jj¡S )zK
        Returns the name of my class, to prefix log entries with.
        )r   Zqualr˜   r   r/   r-   r-   r.   rL     s    zPort.logPrefixc                 C   s   | j dt| jƒžŽ S )zf
        Returns an IPv4Address or IPv6Address.

        This indicates the server's address.
        r–   )r–   )rœ   r   r%   r/   r-   r-   r.   r“     s    zPort.getHostc                 C   s$   |   ||¡ | js | js |  ¡  d S r"   )ÚhandleAcceptra   rI   r    )r)   r‚   r^   r8   r-   r-   r.   ÚcbAccept'  s    zPort.cbAcceptc           
   	   C   sŽ  | j s| jrdS |r4t dtj |d¡|f ¡ dS |j t	j
tt d| j	 ¡ ¡¡ t |j ¡ |j¡\}}}tsšt|d ƒ|d f}t|d ƒ|d f}|| jks¨t‚d|d krÞt|d  d¡d ƒ}|d |d d|f}d|d krt|d  d¡d ƒ}|d |d d|f}| j | jd
|žŽ ¡}|d krB|j ¡  nD| j}|d | _t|j|| jd|žŽ | jd|žŽ || jƒ}	| |	¡ d	S d S )NFz*Could not accept new connection -- %s (%s)zunknown errorrv   r   r?   ú%r–   T)r–   )r–   )r–   ) ra   rI   r   rŸ   ry   rz   rx   ÚnewsktrS   r%   rW   r   r{   r|   r&   r7   Zget_accept_addrsr=   r   r   rp   r…   ÚintÚsplitr˜   r}   rœ   Úcloser   rŒ   r,   r€   )
r)   r‚   r8   ZfamilyZlAddrZrAddrZscoper(   ÚsZ	transportr-   r-   r.   r¨   -  sP    ÿ þÿ
ÿ

 ý
zPort.handleAcceptc                 C   st   t  | j| ¡}td| jd  ƒ |_}| j | j| j	¡ |_
}t  | j ¡ | ¡ ||¡}|rp|tkrp|  ||¡ d S )Né   é   )r7   r‡   r©   r3   rž   r=   r,   ro   rp   rq   r«   Zacceptr%   r&   r   r¨   )r)   r8   r=   r«   r‚   r-   r-   r.   r    ^  s    
ÿ
zPort.doAccept)r—   rj   N)!re   rf   rg   r`   rI   ra   r%   r‰   rp   rŠ   rq   r   ZIPv4Addressrœ   r   r   r¤   r$   r’   r¢   r   rA   r   ZCONNECTION_DONErb   ZstopListeningr¥   rC   rL   r“   r©   r¨   r    r-   r-   r-   r.   r•   •  s*   

  	1r•   )?rh   r%   rM   ry   r{   Zzope.interfacer   r   Ztwisted.internetr   r   r   r   r   Ztwisted.internet.protocolr	   Ztwisted.internet.abstractr
   r   Ztwisted.internet.tcpr   r   ZTCPConnectorr   r   r   r   r   Ztwisted.pythonr   r   r   Ztwisted.python.compatr   r   Ztwisted.internet.iocpreactorr   r7   r   Z'twisted.internet.iocpreactor.interfacesr   Z"twisted.internet.iocpreactor.constr   r   r   r   r   Ztwisted.internet._newtlsr    r[   ÚImportErrorZWSAECONNREFUSEDZWSAENETUNREACHrw   ZITCPTransportZISystemHandler#   r!   ZITLSTransportri   rŒ   ZIListeningPortr•   r-   r-   r-   r.   Ú<module>   sH    $
  þÿ G
\=