U
    ¤�©jËm  ã                   @   sL  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	 ddl
mZmZmZmZmZmZ z2ddlZejejejejdœZeedƒoŽejZW n ek
r®   dZdZY nX d	d
lmZmZmZmZ dZ dZ!dZ"d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 )zGModule implementing low-level socket communication with MySQL servers.
é    N)ÚABCÚabstractmethod)Údeque)ÚAnyÚDequeÚListÚOptionalÚTupleÚUnion)ÚTLSv1úTLSv1.1úTLSv1.2úTLSv1.3ÚHAS_TLSv1_3Fé   )ÚInterfaceErrorÚNotSupportedErrorÚOperationalErrorÚProgrammingErroré2   iÿÿÿ é   é   )Ú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/network.pyÚ_strioerrorE   s    r    c                	   @   sP   e Zd ZdZed	ej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©ÚsockÚaddressÚpayloadÚpacket_numberÚcompressed_packet_numberr   c                 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   Úsende   s    	zNetworkBroker.send©r#   r$   r   c                 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   Úrecv�   s    zNetworkBroker.recv)NN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Úsocketr   Úbytesr   Úintr)   Ú	bytearrayr+   r   r   r   r   r!   M   s     úùr!   c                   @   s�   e Zd ZdZddœdd„Zddœdd„Zejeeddœd	d
„Z	deje
edœdd„Zdej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__c                 C   s   | j d d | _ dS ©zIncrement packet id.r   é   Nr9   r;   r   r   r   Ú_set_next_pktnrš   s    z"NetworkBrokerPlain._set_next_pktnr©r#   r$   Úpktr   c              
   C   sx   z|  |¡ W nd tk
rF } ztd|t|ƒfd�|‚W 5 d}~X Y n. tk
rr } ztdd�|‚W 5 d}~X Y nX dS )z!Write packet to the comm channel.é  ©r   ÚvaluesNiÖ  ©r   )ÚsendallÚIOErrorr   r    ÚAttributeError)r(   r#   r$   rA   r   r   r   r   Ú	_send_pktž   s     
ÿþzNetworkBrokerPlain._send_pktr   )r#   Úsizer   c                 C   sT   t |ƒ}t|ƒ}|rP| ||¡}|dkr:|dkr:tdd�‚||d… }||8 }q|S )z(Read `size` bytes from the comm channel.r   iÝ  rE   N)r3   Ú
memoryviewÚ	recv_intor   )r(   r#   rJ   rA   Zpkt_viewÚreadr   r   r   Ú_recv_chunk©   s    

zNetworkBrokerPlain._recv_chunkr"   c              
   C   s¾   |dkr|   ¡  n|| _t|ƒtkr†d}tt|ƒt ƒD ]@}|  ||dt d| j¡ |||t …  ¡ |   ¡  |t7 }q8||d… }|  ||t dt|ƒ¡dd… t d| j¡ | ¡ 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.
        Nr   ó   ÿÿÿú<Bú<Ié   )r?   r:   ÚlenÚMAX_PAYLOAD_LENGTHÚrangerI   ÚstructÚpack)r(   r#   r$   r%   r&   r'   ÚoffsetÚ_r   r   r   r)   µ   s6    
ÿþý
ÿþýzNetworkBrokerPlain.sendr*   c              
   C   sˆ   zJ| j |td�}t d|dd… d ¡d |d  }| _|| j ||d� W S  tk
r‚ } ztd|t|ƒfd�|‚W 5 d}~X Y nX dS )	z+Receive `one` packet from the MySQL server.©rJ   rQ   r   rR   ó    rB   rC   N)rN   ÚPACKET_HEADER_LENGTHrV   Úunpackr:   rG   r   r    )r(   r#   r$   ÚheaderZpayload_lenr   r   r   r   r+   á   s    þ 
ÿþzNetworkBrokerPlain.recv)r   )NN)r,   r-   r.   r/   r<   r?   r0   r   r1   rI   r2   r3   rN   r   r)   r+   r   r   r   r   r4   ”   s      úù,r4   c                       sÂ   e Zd ZdZddœ‡ fdd„Zeeeee dœdd„ƒZ	ddœd	d
„Z
ejeeddœ‡ fdd„Zdejeeee ee ddœ‡ fdd„Zejeeddœ‡ fdd„Zejeedœ‡ fdd„Z‡  ZS )ÚNetworkBrokerCompressedr5   Nr6   c                    s   t ƒ  ¡  d| _tƒ | _d S r7   )Úsuperr<   Ú_compressed_pktnrr   Ú_queue_readr;   ©Ú	__class__r   r   r<   ø   s    
z NetworkBrokerCompressed.__init__)r%   Úpktnrr   c                 C   s¢   g }t | ƒtkrpd}tt | ƒt ƒD ]>}| dt d|¡ | ||t …  ¡ |d d }|t7 }q$| |d… } | t dt | ƒ¡dd… t d|¡ |  ¡ |S )	z2Prepare a payload for sending to the MySQL server.r   rO   rP   r   r>   NrQ   rR   )rS   rT   rU   ÚappendrV   rW   )r%   re   ZpktsrX   rY   r   r   r   Ú_prepare_packetsý   s$    
ÿþÿ
&ÿz(NetworkBrokerCompressed._prepare_packetsc                 C   s   | j d d | _ dS r=   )ra   r;   r   r   r   Ú_set_next_compressed_pktnr  s    z2NetworkBrokerCompressed._set_next_compressed_pktnrr@   c                    s\   t  |¡}t dt|ƒ¡dd… t d| j¡ t dt|ƒ¡dd…  | }tƒ  |||¡S )z1Compress packet and write it to the comm channel.rQ   r   rR   rP   )ÚzlibÚcompressrV   rW   rS   ra   r`   rI   )r(   r#   r$   rA   Úcompressed_pktrc   r   r   rI     s    
ÿþýÿz!NetworkBrokerCompressed._send_pktr"   c           	   	      s  |dkr|   ¡  n|| _|dkr*|  ¡  n|| _tdƒ |  || j¡¡}t|ƒtt	 kr´d}t
t|ƒt ƒD ].}|  |||||t … ¡ |  ¡  |t7 }ql|  ||||d… ¡ nft|ƒtkrÐ|  |||¡ nJtƒ  ||t dt|ƒ¡dd… t d| j¡ t dd¡dd…  | ¡ 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.
        Nó    r   rQ   rR   rP   )r?   r:   rh   ra   r3   Újoinrg   rS   rT   r\   rU   rI   ÚMIN_COMPRESS_LENGTHr`   rV   rW   )	r(   r#   r$   r%   r&   r'   Zpayload_preprX   rY   rc   r   r   r)   &  s>    

  ÿ
ÿþýýzNetworkBrokerCompressed.send)r#   Úcompressed_pllÚuncompressed_pllr   c           	         s"  t ƒ j||d�}|dkr|ntt |¡ƒ}d}|t|ƒk �rt d|||t d … d ¡d }t| t|ƒ| krôt ƒ j|t	d�}t d|dd… d ¡d |d t d|dd… d ¡d   }| _
}t ƒ j||d�}||dkrè|nt |¡7 }| j |||t | … ¡ |t| 7 }q.d	S )
z&Handle reading of a compressed packet.rZ   r   rQ   r   r[   rR   r   r   N)r`   rN   r3   ri   Ú
decompressrS   rV   r]   r\   ÚCOMPRESSED_PACKET_HEADER_LENGTHra   rb   rf   )	r(   r#   ro   rp   rk   rA   rX   Zpllr^   rc   r   r   Ú_recv_compressed_pktc  s>    ÿý ÿþýüÿýz,NetworkBrokerCompressed._recv_compressed_pktr*   c              
      sÊ   | j s¨zhtƒ j|td�}t d|dd… d ¡d |d t d|dd… d ¡d   }| _}|  |||¡ 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.
        rZ   rQ   r   rR   r[   r   r   rB   rC   N)rb   r`   rN   rr   rV   r]   ra   rs   rG   r   r    Úpopleftr:   )r(   r#   r$   r^   ro   rp   r   rA   rc   r   r   r+   “  s0    ýü 
ÿþ

zNetworkBrokerCompressed.recv)NN)r,   r-   r.   r/   r<   Ústaticmethodr1   r2   r   rg   rh   r0   r   rI   r   r)   rs   r3   r+   Ú__classcell__r   r   rc   r   r_   õ   s,     úù>  þ0r_   c                
   @   s  e Zd ZdZddœdd„Zddœdd„Zddœdd	„Zddœd
d„Zddœdd„Ze	e
 ddœdd„Zeeddœdd„Zd!e	e e	e e	e e	e e	e e	ee  e	ee  edœdd„Zd"ee	e
 e	e
 ddœdd„Zedœdd„Zeddœdd„ƒZeeedœdd „ƒƒZdS )#ÚMySQLSocketz�MySQL socket communication interface.

    Examples:
        Subclasses: network.MySQLTCPSocket and network.MySQLUnixSocket.
    Nr6   c                 C   s   d| _ d| _d| _tƒ | _dS )zsNetwork layer where transactions are made with plain (uncompressed) packets
        is enabled by default.
        N)r#   Ú_connection_timeoutÚserver_hostr4   Ú
_netbrokerr;   r   r   r   r<   ¼  s    zMySQLSocket.__init__c                 C   s   t ƒ | _dS )zIEnable network layer where transactions are made with compressed packets.N)r_   rz   r;   r   r   r   Úswitch_to_compressed_modeÆ  s    z%MySQLSocket.switch_to_compressed_modec              	   C   s:   z| j  tj¡ | j  ¡  W n ttfk
r4   Y nX dS )z'Shut down the socket before closing it.N)r#   Úshutdownr0   Ú	SHUT_RDWRÚcloserH   ÚOSErrorr;   r   r   r   r|   Ê  s
    zMySQLSocket.shutdownc              	   C   s,   z| j  ¡  W n ttfk
r&   Y nX dS )zClose the socket.N)r#   r~   rH   r   r;   r   r   r   Úclose_connectionÒ  s    zMySQLSocket.close_connectionc                 C   s   |   ¡  d S ©N)r|   r;   r   r   r   Ú__del__Ù  s    zMySQLSocket.__del__)Útimeoutr   c                 C   s   || _ | jr| j |¡ dS )zSet the connection timeout.N)rx   r#   Ú
settimeout)r(   rƒ   r   r   r   Úset_connection_timeoutÜ  s    z"MySQLSocket.set_connection_timeout)Ússl_contextÚhostr   c              
   C   s  | j dk	st‚| j jdkr"tdƒ‚tdkr2tdƒ‚z|j| j |d�| _ W nÊ tk
rt } ztdƒ|‚W 5 d}~X Y n  tjt	fk
r² } zt
d| jt|ƒfd�|‚W 5 d}~X Y nb tjk
râ } zt
t|ƒƒ|‚W 5 d}~X Y n2 tk
�r } zt
t|ƒƒ|‚W 5 d}~X Y nX dS )a�  Upgrade an existing connection to TLS.

        Args:
            ssl_context (ssl.SSLContext): The SSL Context to be used.
            host (str): Server host name.

        Returns:
            None.

        Raises:
            ProgrammingError: If the transport does not expose the socket instance.
            NotSupportedError: If Python installation has no SSL support.
        Nr   z,SSL is not supported when using Unix socketsú&Python installation has no SSL support)Úserver_hostnamerB   rC   )r#   ÚAssertionErrorÚfamilyr   Ússlr   Úwrap_socketÚ	NameErrorÚSSLErrorrG   r   r$   r    ÚCertificateErrorr   ÚNotImplementedError)r(   r†   r‡   r   r   r   r   Úswitch_to_sslâ  s(     ÿþzMySQLSocket.switch_to_sslF)Ú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ƒ‚|dkr,g }|dkr8g }�zt|r¸|jdd� |d }t| }	t |	¡}
|dkrÀd	|kr†|
 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|
_|
 ¡  |�rBz|
 |¡ 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
�r’ } 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 )aÊ  Build a SSLContext.

        Args:
            ssl_ca: Certificate authority, opptional.
            ssl_cert: SSL certificate, optional.
            ssl_key: Private key, optional.
            ssl_verify_cert: Verify the SSL certificate if `True`.
            ssl_verify_identity: Verify host identity if `True`.
            tls_versions: TLS protocol versions, optional.
            tls_cipher_suites: Set of steps that helps to establish a secure connection.

        Returns:
            ssl_context (ssl.SSLContext): An SSL Context ready be used.

        Raises:
            NotSupportedError: Python installation has no SSL support.
            InterfaceError: Socket undefined or invalid ssl data.
        i   rE   Nrˆ   T)Úreverser   r   r   r   r   zInvalid CA Certificate: zInvalid Certificate/Key: ú:)r#   r   rŒ   r   Ú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_locationsrG   r�   Úload_cert_chainÚset_ciphersrm   rŽ   r‘   r�   r   )r(   r“   r”   r•   r–   r—   r˜   r™   Ztls_versionZssl_protocolÚcontextr   r   r   r   Úbuild_ssl_context  sf    



""üzMySQLSocket.build_ssl_context)r%   r&   r'   r   c                 C   s   | j j| j| j|||d�S )at  Send `payload` to the MySQL server.

        NOTE: if `payload` is an instance of `bytearray`, then `payload` might be
        changed by this method - `bytearray` is similar to passing a variable by
        reference.

        If you're sure you won't read `payload` after invoking `send()`,
        then you can use `bytearray.` Otherwise, you must use `bytes`.
        )r&   r'   )rz   r)   r#   r$   )r(   r%   r&   r'   r   r   r   r)   d  s    ûzMySQLSocket.sendc                 C   s   | j  | j| j¡S )z.Get packet from the MySQL server comm channel.)rz   r+   r#   r$   r;   r   r   r   r+   {  s    zMySQLSocket.recvc                 C   s   dS )zOpen the socket.Nr   r;   r   r   r   Úopen_connection  s    zMySQLSocket.open_connectionc                 C   s   dS )zGet the location of the socket.Nr   r;   r   r   r   r$   ƒ  s    zMySQLSocket.address)NNNFFNN)NN)r,   r-   r.   r/   r<   r{   r|   r€   r‚   r   r2   r…   r   r   r’   Úboolr   r®   r1   r)   r3   r+   r   r¯   Úpropertyr$   r   r   r   r   rw   µ  sN   
&       ø

÷a  üûrw   c                       s\   e Zd ZdZdeddœ‡ fdd„Zeedœdd	„ƒZddœd
d„Ze	e	ddœdd„Z
‡  ZS )ÚMySQLUnixSocketzpMySQL socket class using UNIX sockets.

    Opens a connection through the UNIX socket of the MySQL Server.
    ú/tmp/mysql.sockN)Úunix_socketr   c                    s   t ƒ  ¡  || _|| _d S r�   )r`   r<   r´   Ú_address)r(   r´   rc   r   r   r<   �  s    
zMySQLUnixSocket.__init__r6   c                 C   s   | j S r�   ©rµ   r;   r   r   r   r$   ”  s    zMySQLUnixSocket.addressc              
   C   s    z2t   t jt j¡| _| j | j¡ | j | j¡ W nh tk
rl } zt	d| j
t|ƒfd�|‚W 5 d }~X Y n0 tk
rš } zt	t|ƒƒ|‚W 5 d }~X Y nX d S )NiÒ  rC   )r0   ÚAF_UNIXÚSOCK_STREAMr#   r„   rx   Úconnectr´   rG   r   r$   r    Ú	Exceptionr   )r(   r   r   r   r   r¯   ˜  s     ý ÿþzMySQLUnixSocket.open_connection)ÚargsÚkwargsr   c                 O   s   t  dt¡ dS )zSwitch the socket to use SSL.z2SSL is disabled when using unix socket connectionsN)ÚwarningsÚwarnÚWarning)r(   r»   r¼   r   r   r   r’   ¨  s    þzMySQLUnixSocket.switch_to_ssl)r³   )r,   r-   r.   r/   r   r<   r±   r$   r¯   r   r’   rv   r   r   rc   r   r²   ‰  s    þr²   c                       sN   e Zd ZdZdeeeddœ‡ fdd„Zeed	œd
d„ƒZ	dd	œdd„Z
‡  ZS )ÚMySQLTCPSocketzYMySQL socket class using TCP/IP.

    Opens a TCP/IP connection to the MySQL Server.
    ú	127.0.0.1éê  FN)r‡   ÚportÚ
force_ipv6r   c                    s6   t ƒ  ¡  || _|| _|| _d| _|› d|› �| _d S )Nr   r›   )r`   r<   ry   Úserver_portrÄ   Ú_familyrµ   )r(   r‡   rÃ   rÄ   rc   r   r   r<   ¸  s    
zMySQLTCPSocket.__init__r6   c                 C   s   | j S r�   r¶   r;   r   r   r   r$   Å  s    zMySQLTCPSocket.addressc           	   
   C   s†  d}z�t  | j| jdt jt j¡}|D ]6}| jrD|d t jkrD|} q\|d t jkr$|} q\q$| jr~|d dkr~t	d| j› �ƒ‚|d dkr’|d }W n: t
k
rÎ } zt	d| jt|ƒfd�|‚W 5 d}~X Y nX |\| _}}}}z0t   | j||¡| _| j | j¡ | j |¡ W np t
k
�rP } z t	d| j| jt|ƒfd�|‚W 5 d}~X Y n2 tk
�r€ } ztt|ƒƒ|‚W 5 d}~X Y nX dS )z/Open the TCP/IP connection to the MySQL server.)NNNNNr   NzNo IPv6 address found for iÓ  rC   )r0   Úgetaddrinfory   rÅ   r¸   ÚSOL_TCPrÄ   ÚAF_INET6ÚAF_INETr   rG   r$   r    rÆ   r#   r„   rx   r¹   rº   r   r   )	r(   ZaddrinfoZ	addrinfosÚinfor   ÚsocktypeÚprotorY   Zsockaddrr   r   r   r¯   É  sZ    ÷
û ÿþýþùzMySQLTCPSocket.open_connection)rÁ   rÂ   F)r,   r-   r.   r/   r   r2   r°   r<   r±   r$   r¯   rv   r   r   rc   r   rÀ   ²  s      üûrÀ   )-r/   r0   rV   r½   ri   Úabcr   r   Úcollectionsr   Útypingr   r   r   r   r	   r
   rŒ   ÚPROTOCOL_TLSv1ÚPROTOCOL_TLSv1_1ÚPROTOCOL_TLSv1_2ÚPROTOCOL_TLSr�   Úhasattrr   ZTLS_V1_3_SUPPORTEDÚImportErrorÚerrorsr   r   r   r   rn   rT   r\   rr   rG   r   r    r!   r4   r_   rw   r²   rÀ   r   r   r   r   Ú<module>   s@    ü
Ga A U)