o
    ]i;                     @   s  d dl Z d dlZd dl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
mZmZmZmZ ddlmZ ddlmZ eeZdZdZd	Zd
ZdZede jdZdedefddZde de de defddZ!G dd dZ"G dd dZ#G dd de#e"e j$Z%G dd de#e jZ&ee%e&f Z'G dd  d Z(eedd!fd"eg ef d#e)e e*f dee  dee  d$e*d%e*d&eeeej+f  d'e de)e(ef fd(d)Z,dS )*    N)Callable)AnyOptionalTypeVarUnioncast   )stun)random_transaction_idi  iX  i   i   i   
_ProtocolT)bounddatareturnc                 C   s   | d d@ dkS )Nr      @    )r   r   r   ?/home/ubuntu/.local/lib/python3.10/site-packages/aioice/turn.pyis_channel_data      r   usernamerealmpasswordc                 C   s    t d| ||gd S )N:utf8)hashlibmd5joinencodedigest)r   r   r   r   r   r   make_integrity_key   s    r   c                   @   sP   e Zd ZU eeegdf ed< ejed< deddfddZ	dedefdd	Z
dS )
TurnStreamMixinNdatagram_received	transportr   r   c                 C   s   t | dsd| _|  j|7  _t| jdkrctd| jdd \}}|t|7 }t| jr4d| }nd| }t| j|k rAd S | j	d}| 
| jd| | | j|d  | _t| jdksd S d S )Nbuffer       !HHr      peername)hasattrr#   lenstructunpackr	   padding_lengthr   r"   get_extra_infor!   )selfr   _lengthfull_lengthaddrr   r   r   data_received%   s   


zTurnStreamMixin.data_receivedc                 C   s"   t t|}|r|t|7 }|S N)r	   r-   r*   bytes)r/   r   paddingr   r   r   _padded8   s   zTurnStreamMixin._padded)__name__
__module____qualname__r   r6   r   __annotations__asyncioBaseTransportr4   r8   r   r   r   r   r    !   s
   
 
r    c                   @   s  e Zd ZU eegdf ed< deeef de	e de	e dededdfd	d
Z
dedeeef ddfddZdeeef fddZdeddfddZdejddfddZdeeef deeef ddfddZd+ddZdeddfddZdejdeejeeef f fd d!Zdejdeejeeef f fd"d#Zdedeeef ddfd$d%Zd&ejdeeef ddfd'd(Zdejddfd)d*ZdS ),TurnClientMixinN_sendserverr   r   lifetimechannel_refresh_timer   c                 C   sj   i | _ i | _i | _i | _d| _|| _d | _|| _d | _|| _	d | _
d | _d | _d | _|| _i | _|| _d S )Ni @  )channel_refresh_atchannel_to_peerpeer_connect_waiterspeer_to_channelchannel_numberrC   integrity_keyrB   noncer   receiverr   refresh_taskrelayed_addressrA   transactionsr   )r/   rA   r   r   rB   rC   r   r   r   __init__C   s$   
zTurnClientMixin.__init__rH   r3   c                    sN   t jt jjt jjd}||jd< ||jd< | |I d H  t	d|| d S )Nmessage_methodmessage_classzCHANNEL-NUMBERzXOR-PEER-ADDRESSzTURN channel bound %d %s)
r	   MessageMethodCHANNEL_BINDClassREQUEST
attributesrequest_with_retryloggerinfo)r/   rH   r3   requestr   r   r   channel_bind`   s   

zTurnClientMixin.channel_bindc                    s   t jt jjt jjd}| j|jd< t|jd< | 	|I dH \}}|jd }|jd | _
td| j
| t| || _| j
S )z+
        Create a TURN allocation.
        rP   LIFETIMEzREQUESTED-TRANSPORTNzXOR-RELAYED-ADDRESSz2TURN allocation created %s (expires in %d seconds))r	   rS   rT   ALLOCATErV   rW   rB   rX   UDP_TRANSPORTrY   rM   rZ   r[   r=   create_taskrefreshrL   )r/   r\   responser0   time_to_expiryr   r   r   connecti   s    

zTurnClientMixin.connectexcc                 C   s,   t d| | | jd ur| j| d S d S )Nz%s connection_lost(%s))rZ   debugrK   connection_lost)r/   rf   r   r   r   rh      s   
zTurnClientMixin.connection_lostr"   c                 C   s   t d| | || _d S )Nz%s connection_made(%s))rZ   rg   r"   )r/   r"   r   r   r   connection_made   s   
zTurnClientMixin.connection_mader   c           	      C   s  t t|}t|dkrAt|rAtd|dd \}}t||d kr?| jd ur?| j|}|r?|dd|  }| j	|| d S zt
|}td| || W n
 tyZ   Y d S w |jt
jjksi|jt
jjkr|j| jv r}| j|j }||| d S d S d S )Nr%   r&   r   z
%s < %s %s)r   r6   r*   r   r+   r,   rK   rE   getr!   r	   parse_messagerZ   rg   
ValueErrorrR   rV   RESPONSEERRORtransaction_idrN   response_received)	r/   r   r3   channelr1   peer_addresspayloadmessagetransactionr   r   r   r!      s,   

z!TurnClientMixin.datagram_receivedc                    s~   | j r| j   d| _ tjtjjtjjd}d|jd< z
| 	|I dH  W n
 tj
y0   Y nw td| j | j  dS )z-
        Delete the TURN allocation.
        NrP   r   r^   zTURN allocation deleted %s)rL   cancelr	   rS   rT   REFRESHrV   rW   rX   rY   TransactionErrorrZ   r[   rM   r"   closer/   r\   r   r   r   delete   s   

zTurnClientMixin.deleterd   c                    sj   	 t d| I dH  tjtjjtjjd}| j|j	d< | 
|I dH \}}|j	d }td| j| q)z;
        Periodically refresh the TURN allocation.
        Tg?NrP   r^   z4TURN allocation refreshed %s (expires in %d seconds))r=   sleepr	   rS   rT   rw   rV   rW   rB   rX   rY   rZ   r[   rM   )r/   rd   r\   rc   r0   r   r   r   rb      s   
zTurnClientMixin.refreshr\   c                    sf   |j | jvs	J | jr| | t|| j| }|| j|j < z| I dH W | j|j = S | j|j = w )zE
        Execute a STUN transaction and return the response.
        N)ro   rN   rI   $_TurnClientMixin__add_authenticationr	   TransactionrA   run)r/   r\   ru   r   r   r   r\      s   
zTurnClientMixin.requestc              
      s   z|  |I dH \}}W ||fS  tjy} } z`|jjd d }d|jjv ro| jduro| jduro|dkr;d|jjv sD|dkro| jduro|jjd | _|dkrV|jjd | _t	| j| j| j| _
t |_|  |I dH \}}n W Y d}~||fS d}~ww )z
        Execute a STUN transaction and return the response.

        On recoverable errors it will retry the request.
        Nz
ERROR-CODEr   NONCEi  REALMi  )r\   r	   TransactionFailedrc   rX   r   r   r   rJ   r   rI   r
   ro   )r/   r\   rc   r3   e
error_coder   r   r   rY      s0   


z"TurnClientMixin.request_with_retryc                    s  || j v rt }| }| j | | |I dH  | j|}t }|du rbg | j |< | j}|  jd7  _| 	||I dH  || j
 | j|< || j|< || j|< | j |D ]}|d qYn|| j| krz| 	||I dH  || j
 | j|< td|t|}| ||  dS )zA
        Send data to a remote host via the TURN server.
        Nr   r&   )rF   r=   get_event_loopcreate_futureappendrG   rj   timerH   r]   rC   rD   rE   pop
set_resultr+   packr*   r@   )r/   r   r3   loopwaiterrq   nowheaderr   r   r   	send_data  s0   




zTurnClientMixin.send_datart   c                 C   s"   t d| || | t| dS )z9
        Send a STUN message to the TURN server.
        z
%s > %s %sN)rZ   rg   r@   r6   )r/   rt   r3   r   r   r   	send_stun-  s   zTurnClientMixin.send_stunc                 C   s4   | j |jd< | j|jd< | j|jd< || j d S )NUSERNAMEr   r   )r   rX   rJ   r   add_message_integrityrI   rz   r   r   r   __add_authentication4  s   z$TurnClientMixin.__add_authenticationr   N)r9   r:   r;   r   r6   r<   tuplestrintr   rO   r]   re   	Exceptionrh   r=   r>   ri   r   r!   r{   rb   r	   rS   r\   rY   r   r   r}   r   r   r   r   r?   @   sF   
 

	&


% 'r?   c                   @   <   e Zd ZU dZejed< deddfddZde	fdd	Z
dS )
TurnClientTcpProtocolz.
    Protocol for handling TURN over TCP.
    r"   r   r   Nc                 C   s   | j | | d S r5   )r"   writer8   r/   r   r   r   r   r@   B  s   zTurnClientTcpProtocol._sendc                 C      dS )Nzturn/tcpr   r/   r   r   r   __repr__E     zTurnClientTcpProtocol.__repr__)r9   r:   r;   __doc__r=   	Transportr<   r6   r@   r   r   r   r   r   r   r   ;  
   
 
r   c                   @   r   )
TurnClientUdpProtocolz.
    Protocol for handling TURN over UDP.
    r"   r   r   Nc                 C   s   | j | d S r5   )r"   sendtor   r   r   r   r@   P  r   zTurnClientUdpProtocol._sendc                 C   r   )Nzturn/udpr   r   r   r   r   r   S  r   zTurnClientUdpProtocol.__repr__)r9   r:   r;   r   r=   DatagramTransportr<   r6   r@   r   r   r   r   r   r   r   I  r   r   c                   @   sv   e Zd ZdZdeddfddZdddZdd	ed
edefddZ	de
deeef ddfddZdejddfddZdS )TurnTransportzH
    Behaves like a Datagram transport, but uses a TURN allocation.
    inner_protocolr   Nc                 C   s   || _ d | _d S r5   )_TurnTransport__inner_protocol_TurnTransport__relayed_address)r/   r   r   r   r   rO   _  s   
zTurnTransport.__init__c                 C   s   t | j  dS )z
        Close the transport.

        After the TURN allocation has been deleted, the protocol's
        `connection_lost()` method will be called with None as its argument.
        N)r=   ra   r   r{   r   r   r   r   ry   c  s   zTurnTransport.closenamedefaultc                 C   s(   |dkr| j jdS |dkr| jS |S )z
        Return optional transport information.

        - `'related_address'`: the related address
        - `'sockname'`: the relayed address
        related_addresssockname)r   r"   r.   r   )r/   r   r   r   r   r   r.   l  s
   zTurnTransport.get_extra_infor   r3   c                 C   s   t | j|| dS )z~
        Sends the `data` bytes to the remote peer given `addr`.

        This will bind a TURN channel as necessary.
        N)r=   ra   r   r   )r/   r   r3   r   r   r   r   y  s   zTurnTransport.sendtoprotocolc                    s2   | j  I d H | _|| j _|ttj|  d S r5   )r   re   r   rK   ri   r   r=   r   )r/   r   r   r   r   _connect  s   zTurnTransport._connectr   r5   )r9   r:   r;   r   TurnClientProtocolrO   ry   r   r   r.   r6   r   r   r   r=   DatagramProtocolr   r   r   r   r   r   Z  s    
	r   udpprotocol_factoryserver_addrrB   rC   sslr"   c                    s   t  }|dkr$|j fddd d |dI dH \}	}
n&|j fddd	I dH \}	}
|	d
}|durJ|tjtjt	 z|  }t
|
}||I dH  W ||fS  tyj   |	   w )z7
    Create datagram connection relayed over TURN.
    tcpc                         t  dS N)r   r   rB   rC   )r   r   rC   rB   r   r   r   r   r   <lambda>      z&create_turn_endpoint.<locals>.<lambda>r   r   )hostportr   Nc                      r   r   )r   r   r   r   r   r     r   )remote_addrsocket)r=   r   create_connectioncreate_datagram_endpointr.   
setsockoptr   
SOL_SOCKET	SO_RCVBUFUDP_SOCKET_BUFFER_SIZEr   r   r   ry   )r   r   r   r   rB   rC   r   r"   r   inner_transportr   sockr   turn_transportr   r   r   create_turn_endpoint  s2   

r   )-r=   r   loggingr   r   r+   r   collections.abcr   typingr   r   r   r   r    r	   utilsr
   	getLoggerr9   rZ   DEFAULT_CHANNEL_REFRESH_TIMEDEFAULT_ALLOCATION_LIFETIMETCP_TRANSPORTr`   r   r   r   r6   boolr   r   r   r    r?   Protocolr   r   r   r   r   r   
SSLContextr   r   r   r   r   <module>   sd    
 |5


	