U
    ¤�©j`a  ã                   @   sL  d Z ddgZddlZddlZddlZz"ddlZejejejej	dœZ
W n ek
r^   dZY nX ddlmZmZ ddlmZ ddlmZmZmZmZmZ d	d
lmZmZmZmZ d	dlmZmZmZm Z  ddl!m"Z"m#Z# e$e%dœdd„Z&G dd„ deƒZ'G dd„ de'ƒZ(G dd„ de(ƒZ)G dd„ deƒZ*G dd„ de*ƒZ+G dd„ de*ƒZ,dS )zFModule implementing low-level socket communication with MySQL servers.ÚMySQLTcpSocketÚMySQLUnixSocketé    N)ÚTLSv1úTLSv1.1úTLSv1.2úTLSv1.3)ÚABCÚabstractmethod)Údeque)ÚAnyÚDequeÚListÚOptionalÚTupleé   )ÚInterfaceErrorÚNotSupportedErrorÚOperationalErrorÚProgrammingError)ÚCOMPRESSED_PACKET_HEADER_LENGTHÚMAX_PAYLOAD_LENGTHÚMIN_COMPRESS_LENGTHÚPACKET_HEADER_LENGTHé   )ÚStreamWriterÚopen_connection)ÚerrÚreturnc                 C   s    | j st| ƒS | j › d| j› �S )z`Reformat the IOError error message.

    This function reformats the IOError error message.
    ú )ÚerrnoÚstrÚstrerror)r   © r"   ú?/tmp/pip-unpacked-wheel-d6bt0v6z/mysql/connector/aio/network.pyÚ_strioerrorG   s    r$   c                	   @   sN   e Zd ZdZed	eeeee	 ee	 ddœdd„ƒZ
eejeedœdd„ƒZdS )
ÚNetworkBrokeraP  Broker class interface.

    The network object is a broker used as a delegate by a socket object. Whenever the
    socket wants to deliver or get packets to or from the MySQL server it needs to rely
    on its network broker (netbroker).

    The netbroker sends `payloads` and receives `packets`.

    A packet is a bytes sequence, it has a header and body (referred to as payload).
    The first `PACKET_HEADER_LENGTH` or `COMPRESSED_PACKET_HEADER_LENGTH`
    (as appropriate) bytes correspond to the `header`, the remaining ones represent the
    `payload`.

    The maximum payload length allowed to be sent per packet to the server is
    `MAX_PAYLOAD_LENGTH`. When  `send` is called with a payload whose length is greater
    than `MAX_PAYLOAD_LENGTH` the netbroker breaks it down into packets, so the caller
    of `send` can provide payloads of arbitrary length.

    Finally, data received by the netbroker comes directly from the server, expect to
    get a packet for each call to `recv`. The received packet contains a header and
    payload, the latter respecting `MAX_PAYLOAD_LENGTH`.
    N©ÚwriterÚaddressÚpayloadÚpacket_numberÚcompressed_packet_numberr   c                 Ã   s   dS )aó  Send `payload` to the MySQL server.

        If provided a payload whose length is greater than `MAX_PAYLOAD_LENGTH`, it is
        broken down into packets.

        Args:
            sock: Object holding the socket connection.
            address: Socket's location.
            payload: Packet's body to send.
            packet_number: Sequence id (packet ID) to attach to the header when sending
                           plain packets.
            compressed_packet_number: Same as `packet_number` but used when sending
                                      compressed packets.

        Raises:
            :class:`OperationalError`: If something goes wrong while sending packets to
                                       the MySQL server.
        Nr"   )Úselfr'   r(   r)   r*   r+   r"   r"   r#   Úwriteg   s    	zNetworkBroker.write©Úreaderr(   r   c                 Ã   s   dS )a)  Get the next available packet from the MySQL server.

        Args:
            sock: Object holding the socket connection.
            address: Socket's location.

        Returns:
            packet: A packet from the MySQL server.

        Raises:
            :class:`OperationalError`: If something goes wrong while receiving packets
                                       from the MySQL server.
            :class:`InterfaceError`: If something goes wrong while receiving packets
                                     from the MySQL server.
        Nr"   )r,   r/   r(   r"   r"   r#   Úreadƒ   s    zNetworkBroker.read)NN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r	   r   r    Úbytesr   Úintr-   ÚasyncioÚStreamReaderÚ	bytearrayr0   r"   r"   r"   r#   r%   O   s     úùr%   c                   @   s°   e Zd ZdZddœdd„Zeeeeef dœdd„ƒZ	de
e dd	œd
d„Zeeeddœdd„Zdejeedœdd„Zdeeee
e e
e ddœdd„Zejeedœdd„ZdS )ÚNetworkBrokerPlainú,Broker class for MySQL socket communication.N©r   c                 C   s
   d| _ d S ©Néÿÿÿÿ©Ú_pktnr©r,   r"   r"   r#   Ú__init__™   s    zNetworkBrokerPlain.__init__©Úpktr   c                 C   sB   t | ƒtk rtdƒ‚t d| dd… d ¡d | d  }}||fS )ú-Recover the header information from a packet.ú3Can't recover header info from an incomplete packetú<Ir   é   ó    )Úlenr   Ú
ValueErrorÚstructÚunpack)rD   ÚpllÚseqidr"   r"   r#   Ú
get_headerœ   s    þzNetworkBrokerPlain.get_header©Únext_idr   c                 C   s0   |dkr|  j d7  _ n|| _ |  j d;  _ dS ©z:Set the given packet id, if any, else increment packet id.Nr   é   r?   ©r,   rR   r"   r"   r#   Ú_set_next_pktnr©   s    z"NetworkBrokerPlain._set_next_pktnr©r'   r(   rD   r   c              
   Ã   s†   z|  |¡ | ¡ I dH  W nd tk
rT } ztd|t|ƒfd�|‚W 5 d}~X Y n. tk
r€ } ztdd�|‚W 5 d}~X Y nX dS )z!Write packet to the comm channel.Né  ©r   ÚvaluesiÖ  ©r   )r-   ZdrainÚIOErrorr   r$   ÚAttributeError)r,   r'   r(   rD   r   r"   r"   r#   Ú
_write_pkt±   s    
 
ÿþzNetworkBrokerPlain._write_pktr   )r/   Úsizer   c                 Ã   sH   t dƒ}t|ƒ|k rD| |t|ƒ ¡I dH }|s:tdd�‚||7 }q|S )z(Read `size` bytes from the comm channel.ó    NiÝ  r[   )r9   rJ   r0   r   )r,   r/   r_   rD   Úchunkr"   r"   r#   Ú_read_chunk½   s    

zNetworkBrokerPlain._read_chunkr&   c              
   Ã   s°   |   |¡ d}tt|ƒt ƒD ]F}|  ||dt d| j¡ |||t …  ¡I dH  |   ¡  |t7 }q|  ||t dt|ƒ| ¡dd… t d| j¡ ||d…  ¡I dH  dS )z¤Send payload to the MySQL server.

        If provided a payload whose length is greater than `MAX_PAYLOAD_LENGTH`, it is
        broken down into packets.
        r   ó   ÿÿÿú<BNrG   rH   )rV   ÚrangerJ   r   r^   rL   Úpackr@   )r,   r'   r(   r)   r*   r+   ÚoffsetÚ_r"   r"   r#   r-   É   s.    
ÿþý

ÿ
þýzNetworkBrokerPlain.writer.   c              
   Ã   s|   z>| j |td�I dH }|  |¡\}| _|| j ||d�I dH  W S  tk
rv } ztd|t|ƒfd�|‚W 5 d}~X Y nX dS )z+Receive `one` packet from the MySQL server.©r_   NrX   rY   )rb   r   rP   r@   r\   r   r$   )r,   r/   r(   ÚheaderZpayload_lenr   r"   r"   r#   r0   ï   s     
ÿþzNetworkBrokerPlain.read)N)r   )NN)r1   r2   r3   r4   rB   Ústaticmethodr5   r   r6   rP   r   rV   r   r    r^   r7   r8   r9   rb   r-   r0   r"   r"   r"   r#   r:   –   s.    ÿ þ  úù&r:   c                       sâ   e Zd ZdZddœ‡ fdd„Zeeeee dœdd„ƒZ	eee
eeef d	œd
d„ƒZdee ddœdd„Zeeeddœ‡ fdd„Zdeeeee ee ddœ‡ fdd„Zejeddœ‡ fdd„Zejeedœ‡ fdd„Z‡  ZS )ÚNetworkBrokerCompressedr;   Nr<   c                    s   t ƒ  ¡  d| _tƒ | _d S r=   )ÚsuperrB   Ú_compressed_pktnrr
   Ú_queue_readrA   ©Ú	__class__r"   r#   rB     s    
z NetworkBrokerCompressed.__init__)r)   Úpktnrr   c                 C   s–   d}g }t t| ƒt ƒD ]>}| dt d|¡ | ||t …  ¡ |d d }|t7 }q| t dt| ƒ| ¡dd… t d|¡ | |d…  ¡ |S )	z2Prepare a payload for sending to the MySQL server.r   rc   rd   r   rT   rG   rH   N)re   rJ   r   ÚappendrL   rf   )r)   rr   rg   Zpktsrh   r"   r"   r#   Ú_prepare_packets  s(    
ÿþÿ

ÿ
þÿz(NetworkBrokerCompressed._prepare_packetsrC   c                 C   sb   t | ƒtk rtdƒ‚t d| dd… d ¡d | d t d| dd… d ¡d   }}}|||fS )rE   rF   rG   r   rH   rI   é   é   )rJ   r   rK   rL   rM   )rD   Úcompressed_pllrO   Úuncompressed_pllr"   r"   r#   rP   !  s    ý
z"NetworkBrokerCompressed.get_headerrQ   c                 C   s0   |dkr|  j d7  _ n|| _ |  j d;  _ dS rS   )rn   rU   r"   r"   r#   Ú_set_next_compressed_pktnr/  s    z2NetworkBrokerCompressed._set_next_compressed_pktnrrW   c                 ƒ   sb   t  |¡}t dt|ƒ¡dd… t d| j¡ t dt|ƒ¡dd…  | }tƒ  |||¡I dH S )z1Compress packet and write it to the comm channel.rG   r   rH   rd   N)ÚzlibÚcompressrL   rf   rJ   rn   rm   r^   )r,   r'   r(   rD   Úcompressed_pktrp   r"   r#   r^   7  s    
ÿþýÿz"NetworkBrokerCompressed._write_pktr&   c           	   	   ƒ   s  |   |¡ |  |¡ tdƒ |  || j¡¡}t|ƒtt kr¤d}t	t|ƒt ƒD ]4}|  
|||||t … ¡I dH  |  ¡  |t7 }qP|  
||||d… ¡I dH  nrt|ƒtkrÆ|  
|||¡I dH  nPtƒ  
||t dt|ƒ¡dd… t d| j¡ t dd¡dd…  | ¡I dH  dS )z¼Send `payload` as compressed packets to the MySQL server.

        If provided a payload whose length is greater than `MAX_PAYLOAD_LENGTH`, it is
        broken down into packets.
        r`   r   NrG   rH   rd   )rV   ry   r9   Újoinrt   r@   rJ   r   r   re   r^   r   rm   rL   rf   rn   )	r,   r'   r(   r)   r*   r+   Zpayload_preprg   rh   rp   r"   r#   r-   B  s6    

  ÿ

ÿþýýzNetworkBrokerCompressed.write)r/   rw   r   c           	      ƒ   sî   t t tƒ j||d�I dH ¡ƒ}d}|t|ƒk rêt d|||t d … d ¡d }t| t|ƒ| krÀtƒ j|t	d�I dH }|  
|¡\}| _}tƒ j||d�I dH }||dkr´|nt |¡7 }| j |||t | … ¡ |t| 7 }q$dS )z&Handle reading of a compressed packet.ri   Nr   rG   r   rI   )r9   rz   Ú
decompressrm   rb   rJ   rL   rM   r   r   rP   rn   ro   rs   )	r,   r/   rw   rD   rg   rN   rj   rx   r|   rp   r"   r#   Ú_read_compressed_pkty  s:    ÿ ÿþ ÿ	üÿýz,NetworkBrokerCompressed._read_compressed_pktr.   c              
   ƒ   sÈ   | j s¦zftƒ j|td�I dH }|  |¡\}| _}|dkrX| j  tƒ j||d�I dH ¡ n|  ||¡I dH  W n8 tk
r¤ } zt	d|t
|ƒfd�|‚W 5 d}~X Y nX | j s°dS | j  ¡ }|d | _|S )z{Receive `one` or `several` packets from the MySQL server, enqueue them, and
        return the packet at the head.
        ri   Nr   rX   rY   rH   )ro   rm   rb   r   rP   rn   rs   r   r\   r   r$   Úpopleftr@   )r,   r/   r(   rj   rw   rx   r   rD   rp   r"   r#   r0   ¡  s8     ÿ	üÿ 
ÿþ

zNetworkBrokerCompressed.read)N)NN)r1   r2   r3   r4   rB   rk   r5   r6   r   rt   r   rP   r   ry   r   r    r^   r-   r7   r8   r   r9   r0   Ú__classcell__r"   r"   rp   r#   rl      s.     úù8 þ(rl   c                
   @   s  e Zd ZdZddœdd„Zeedœdd„ƒZee	ddœd	d
„ƒZ
ddœdd„Zedœdd„Zeddœdd„Zddœdd„Zejddœdd„Zd eee ee ddœdd„Zedœdd„Zdddddg g fee ee ee ee ee eee  eee  ejdœdd„ZdS )!ÚMySQLSocketz�MySQL socket communication interface.

    Examples:
        Subclasses: network.MySQLTCPSocket and network.MySQLUnixSocket.
    Nr<   c                 C   s*   d| _ d| _d| _d| _tƒ | _d| _dS )zsNetwork layer where transactions are made with plain (uncompressed) packets
        is enabled by default.
        NF)Ú_readerÚ_writerÚ_connection_timeoutÚ_addressr:   Ú
_netbrokerÚ_is_connectedrA   r"   r"   r#   rB   Ð  s    zMySQLSocket.__init__c                 C   s   | j S )zSocket location.)r†   rA   r"   r"   r#   r(   Û  s    zMySQLSocket.address©Úkwargsr   c                 Ë   s   dS )zOpen the socket.Nr"   ©r,   rŠ   r"   r"   r#   r   à  s    zMySQLSocket.open_connectionc                 Ã   sB   | j r8| j  ¡  | j jdk	r(| j j ¡  | j  ¡ I dH  d| _dS )zClose the connection.NF)r„   ÚcloseÚ	transportÚabortZwait_closedrˆ   rA   r"   r"   r#   Úclose_connectionä  s    
zMySQLSocket.close_connectionc                 C   s   | j S )zˆCheck if the socket is connected.

        Return:
            bool: Returns `True` if the socket is connected to MySQL server.
        )rˆ   rA   r"   r"   r#   Úis_connectedî  s    zMySQLSocket.is_connected)Útimeoutr   c                 C   s
   || _ dS )zSet the connection timeout.N)r…   )r,   r‘   r"   r"   r#   Úset_connection_timeoutö  s    z"MySQLSocket.set_connection_timeoutc                 C   s   t ƒ | _dS )zIEnable network layer where transactions are made with compressed packets.N)rl   r‡   rA   r"   r"   r#   Úswitch_to_compressed_modeú  s    z%MySQLSocket.switch_to_compressed_mode)Ússl_contextr   c                 Ã   sD   | j dk	st‚| j j d¡}|jdkr.tdƒ‚| j  |¡I dH  dS )a?  Upgrade an existing stream-based connection to TLS.

        The `start_tls()` method from `asyncio.streams.StreamWriter` is only available
        in Python 3.11. This method is used as a workaround.

        The MySQL TLS negotiation happens in the middle of the TCP connection.
        Therefore, passing a socket to open connection will cause it to negotiate
        TLS on an existing connection.

        Args:
            ssl_context: The SSL Context to be used.

        Raises:
            RuntimeError: If the transport does not expose the socket instance.
        NÚsocketr   z,SSL is not supported when using Unix sockets)r„   ÚAssertionErrorr�   Zget_extra_infoÚfamilyr   Z	start_tls)r,   r”   r•   r"   r"   r#   Úswitch_to_sslþ  s
    
zMySQLSocket.switch_to_ssl)r)   r*   r+   r   c                 Ã   s$   | j j| j| j|||d�I dH  dS )z!Send packets to the MySQL server.)r*   r+   N)r‡   r-   r„   r(   )r,   r)   r*   r+   r"   r"   r#   r-     s    ûzMySQLSocket.writec                 Ã   s   | j  | j| j¡I dH S )z#Read packets from the MySQL server.N)r‡   r0   rƒ   r(   rA   r"   r"   r#   r0   &  s    zMySQLSocket.readF)Ússl_caÚssl_certÚssl_keyÚssl_verify_certÚssl_verify_identityÚtls_versionsÚtls_cipher_suitesr   c                 C   s  | j stdd�‚tdkr tdƒ‚�zt|r |jdd� |d }t| }	t |	¡}
|dkr¨d	|krn|
 jtjO  _d
|kr†|
 jtj	O  _d|kr¨|
 jtj
O  _nt ¡ }
||
_|r¼tj|
_n|rÊtj|
_ntj|
_|
 ¡  |�r*z|
 |¡ W n: ttjfk
�r( } ztd|› �ƒ|‚W 5 d}~X Y nX |�r|z|
 ||¡ W n: ttjfk
�rz } ztd|› �ƒ|‚W 5 d}~X Y nX |�r’|
 d |¡¡ |
W S  tk
�rÄ } ztdƒ|‚W 5 d}~X Y n> tttjtjfk
�r  } ztt|ƒƒ|‚W 5 d}~X Y nX dS )zBuild a SSLContext.i   r[   Nz&Python installation has no SSL supportT)Úreverser   r   r   r   r   zInvalid CA Certificate: zInvalid Certificate/Key: ú:)rƒ   r   ÚsslÚRuntimeErrorÚsortÚTLS_VERSIONSÚ
SSLContextÚoptionsÚOP_NO_TLSv1_2ÚOP_NO_TLSv1_1ÚOP_NO_TLSv1Úcreate_default_contextÚcheck_hostnameÚCERT_REQUIREDÚverify_modeÚCERT_OPTIONALÚ	CERT_NONEÚload_default_certsÚload_verify_locationsr\   ÚSSLErrorÚload_cert_chainÚset_ciphersr}   Ú	NameErrorr   ÚNotImplementedErrorÚCertificateErrorr    )r,   r™   rš   r›   rœ   r�   rž   rŸ   Ztls_versionZssl_protocolÚcontextr   r"   r"   r#   Úbuild_ssl_context*  s^    



""üzMySQLSocket.build_ssl_context)NN)r1   r2   r3   r4   rB   Úpropertyr    r(   r	   r   r   r�   Úboolr�   r6   r’   r“   r¢   r¦   r˜   r5   r   r-   r9   r0   r   rº   r"   r"   r"   r#   r‚   É  sJ   
  üûø

÷r‚   c                       s<   e Zd ZdZdeeedœ‡ fdd„Zedd	œd
d„Z	‡  Z
S )r   z�MySQL socket class using TCP/IP.

    Args:
        host: MySQL host name.
        port: MySQL port.
        force_ipv6: Force IPv6 usage.
    ú	127.0.0.1éê  F)ÚhostÚportÚ
force_ipv6c                    s0   t ƒ  ¡  || _|| _|| _|› d|› �| _d S )Nr¡   )rm   rB   Ú_hostÚ_portZ_force_ipv6r†   )r,   r¿   rÀ   rÁ   rp   r"   r#   rB   z  s
    
zMySQLTcpSocket.__init__Nr‰   c                 Ë   s0   t f | j| jdœ|—ŽI dH \| _| _d| _dS )zOpen TCP/IP connection.)r¿   rÀ   NT)r   rÂ   rÃ   rƒ   r„   rˆ   r‹   r"   r"   r#   r   ƒ  s     ÿÿzMySQLTcpSocket.open_connection)r½   r¾   F)r1   r2   r3   r4   r    r6   r¼   rB   r   r   r�   r"   r"   rp   r#   r   q  s   	     ÿ  ÿ	c                       s8   e Zd ZdZd
edœ‡ fdd„Zeddœdd	„Z‡  ZS )r   zbMySQL socket class using UNIX sockets.

    Args:
        unix_socket: UNIX socket file path.
    ú/tmp/mysql.sock)Úunix_socketc                    s   t ƒ  ¡  || _d S )N)rm   rB   r†   )r,   rÅ   rp   r"   r#   rB   ’  s    
zMySQLUnixSocket.__init__Nr‰   c                 Ë   s.   t jf d| ji|—ŽI dH \| _| _d| _dS )zOpen UNIX socket connection.ÚpathNT)r7   Zopen_unix_connectionr†   rƒ   r„   rˆ   r‹   r"   r"   r#   r   –  s    ÿÿ
ýzMySQLUnixSocket.open_connection)rÄ   )	r1   r2   r3   r4   r    rB   r   r   r�   r"   r"   rp   r#   r   ‹  s   )-r4   Ú__all__r7   rL   rz   r¢   ÚPROTOCOL_TLSv1ÚPROTOCOL_TLSv1_1ÚPROTOCOL_TLSv1_2ÚPROTOCOL_TLSr¥   ÚImportErrorÚabcr   r	   Úcollectionsr
   Útypingr   r   r   r   r   Úerrorsr   r   r   r   Únetworkr   r   r   r   Úutilsr   r   r\   r    r$   r%   r:   rl   r‚   r   r   r"   r"   r"   r#   Ú<module>   s8   ü

Gj J )