
    =                     R   d Z ddlmZ ddlmZ ddlm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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ZdZdZej@                  jB                  ej@                  jD                  gZ# G d	 d
e$      Z% G d de$      Z& G d de$      Z'y)zLightweight websocket for IAP.    )absolute_import)division)unicode_literalsN)	platforms   i  c                       e Zd ZdZd Zy)SockOptzDClass that represents the options for the underlying socket library.c                 6    |i }d | _         g | _        || _        y N)timeoutsockoptsslopt)selfr   s     Flib/googlecloudsdk/api_lib/compute/iap_tunnel_lightweight_websocket.py__init__zSockOpt.__init__1   s#    ~f DLDLDK    N)__name__
__module____qualname____doc__r    r   r   r	   r	   .   s
    Lr   r	   c                   (    e Zd ZdZd Zd Zd Zd Zy)_FrameBufferzIClass that represents one single frame sent or received by the websocket.c                     || _         y r   )recv)r   recv_fns     r   r   z_FrameBuffer.__init__>   s	    DIr   c                    | j                  d      }|d   }t        j                  rt        |      }|dz	  dz  }|dz	  dz  }|dz	  dz  }|dz	  dz  }|dz  }|d   }t        j                  rt        |      }|dz	  dz  }	|d	z  }
||||||	|
fS )
z"Parse the header from the message.   r                        )r   sixPY2ord)r   headerb1finrsv1rsv2rsv3opcodeb2has_masklength_bitss              r   _recv_headerz_FrameBuffer._recv_headerA   s    YYq\F	B
wwr7b
'A+C7Q;D7Q;D7Q;D#XF	B
wwr7bQw{Ht)KtT68[AAr   c                     |dz  }|dk(  r*| j                  d      }t        j                  d|      d   S |dk(  r*| j                  d      }t        j                  d|      d   S |S )z"Parse the length from the message.r%   ~   r   !Hr      z!Q)r   structunpack)r   bitsr2   vs       r   _recv_lengthz_FrameBuffer._recv_lengthX   sg    +Kd
))A,a]]4#A&&		
))A,a]]4#A&&r   c           	          | j                         \  }}}}}}}|dk(  rt        d      | j                  |      }| j                  |      }	t	        j
                  |||||||	      S )zReceives the whole frame.r    z#Server should not mask the response)r3   	Exceptionr<   r   websocket_frame_utilsABNF)
r   r+   r,   r-   r.   r/   r1   r2   lengthpayloads
             r   
recv_framez_FrameBuffer.recv_framed   su     >B=N=N=P:S$dFHk1};<<{+FiiG %%c4tVX&-/ /r   N)r   r   r   r   r   r3   r<   rC   r   r   r   r   r   ;   s    QB.
/r   r   c                       e Zd ZdZ	 ddZd Zd Ze ej                  d      fdZ
e ej                  d      fdZd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zy)IapLightWeightWebsocketzvLightweight websocket created to send and receive data as fast as possible.

     This websocket implements rfc6455
  Nc                     || _         || _        || _        || _        || _        t        | j                        | _        d| _        d | _	        || _
        || _        t        j                         | _        y )NF)urlon_dataon_closeon_errorsockr   _recv_bytesframe_buffer	connectedget_mask_keysubprotocolsr)   	threadingLocksend_write_lock)r   rG   r)   rH   rI   rJ   rP   rK   s           r   r   z IapLightWeightWebsocket.__init__y   sk     DHDLDMDMDI$T%5%56DDN D$DDK
 %>>+Dr   c                     | j                   r| j                  st        j                  d      | j                  j                         S )zReceives data from the server.'Connection closed while receiving data.)rN   rK   websocket_exceptions"WebSocketConnectionClosedExceptionrM   rC   )r   s    r   r   zIapLightWeightWebsocket.recv   s<    >> CC
35 5 ''))r   c           	         |t         vrt        d      t        j                  dddd|d|      }| j                  r| j                  |_        |j                         }| j                  5  t        dt        dz         D ]  }	 | j                  r| j                  st        j                  d      | j                  j                  |      }|st        j                  d      t        |      |k7  rt        d      |c cddd       S  	 ddd       y# t        $ r}| j!                  ||       Y d}~d}~ww xY w# 1 sw Y   yxY w)	zSends data to the server.zInvalid opcoder    r   )r+   r,   r-   r.   r/   maskdataz%Connection closed while sending data.z$Packet was not sent in it's entiretyNattempt	exception)VALID_OPCODES
ValueErrorr?   r@   rO   formatrS   rangeWEBSOCKET_MAX_ATTEMPTSrN   rK   rV   rW   sendlenr>   _throw_or_wait_for_retry)r   rZ   r/   
frame_datar\   
bytes_sentes          r   rc   zIapLightWeightWebsocket.send   s6   ]"'((
 '++AAAf14IJ  $ 1 1j""$J 
		14q89'	Ftyy&II79 9yy~~j1*&II79 9 _
*BCC
 
	9 
	   	F

'
'1
'
E
E	F! 
	s=   )D:A9D:D:D:	D7D2-D:2D77D::E c                 2   | j                   rI| j                  r<	 | j                  ||       | j                  j                          d| _        d| _         yyy# t        j
                  t        j                  f$ r}| j                  |      s Y d}~yd}~ww xY w)zCloses the connection.NF)	rN   rK   
send_closecloserV   rW   socketerror_is_closed_connection_exceptionr   
close_codeclose_messagerh   s       r   rl   zIapLightWeightWebsocket.close   s    ~~$))

M2			 $~ #EEll  33A6
 7	s   :A #B:BBc                    | j                   rdt        j                  r|j                  d      }	 | j	                  t        j                  d|      |z   t        j                  j                         yy# t        j                  t        t        j                  t        j                   f$ r}| j#                  |      s Y d}~yd}~ww xY w)z4Sends a close message to the server but don't close.zlatin-1r6   N)rN   r&   r'   encoderc   r8   packr?   r@   OPCODE_CLOSErV   rW   OSErrorrm   rn   sslSSLErrorro   rp   s       r   rk   z"IapLightWeightWebsocket.send_close   s    ~~
 
%,,Y7		KKj)M9!&&33	5  #EEwllCLL*  33A6
 7	s   AA2 27C)C  Cc                    	 |j                  d| j                  i       |j                  d| j                  i        | j                  |fi | | j                  r| j
                  j                         dk(  rt        j                  d      | j                  t               | j                         }|j                  t        j                  j                  k(  r;| j!                  |j"                        }| j%                           | j&                  |  n&| j)                  |j"                  |j                         | j                  ryy# t*        $ r*}| j%                          | j'                  dd       |d}~wt,        $ rg}| j%                          | j/                  |       t1        j2                  |      }t1        j4                  |      }| j'                  ||       Y d}~yd}~ww xY w)z@Main method that will stay running while the connection is open.r)   rP   rU   )r   N)rq   rr   )updater)   rP   _connectrN   rK   filenorV   rW   _wait_for_socket_to_readyWEBSOCKET_RETRY_TIMEOUT_SECSr   r/   r?   r@   rv   _get_close_argsrZ   rl   rI   rH   KeyboardInterruptr>   rJ   websocket_utilsextract_error_codeextract_err_message)r   r   optionsframe
close_argsrh   
error_codemessages           r   run_foreverz#IapLightWeightWebsocket.run_forever   sy   )nnh,-nnnd&7&789dmmF&g&NN99#$GG79 9 	&&/K&L		<<055BBB++EJJ7*
**,
$--
$
,,uzz5<<
0 NN  
jjl
mmt4m8g )
jjl
mmA"55a8j33A6g
mmJ(()s%   EE
 
	G+%E88G+AG&&G+c                    t        t        |            }d}t        dt        dz         D ]p  }	 ||k  rW| j                  j                  ||d ||z
        }|dk(  r%| j                          t        j                  d      ||z  }||k  rW|j                         c S  y# t        $ r}| j                  ||       Y d}~d}~ww xY w)z5Internal implementation of recv called by recv_frame.r   r    NrU   r[   )
memoryview	bytearrayra   rb   rK   	recv_intorl   rV   rW   tobytesr>   re   )r   
buffersizeviewtotal_bytes_readr\   bytes_receivedrh   s          r   rL   z#IapLightWeightWebsocket._recv_bytes  s    i
+,D 2Q67D
 +99..t4D4E/F/9<L/LN.
 q JJL&II9; ;
n
,
 + ||~% 8&  D%%g%CCDs   AB
B	C'B??Cc                     || _         y r   )rO   )r   mask_keys     r   _set_mask_keyz%IapLightWeightWebsocket._set_mask_key"  s
     Dr   c                 Z   t        j                  di |}t        |      }| j                  r*t        j                  | j
                        \  }}}}|||f}	nMt        j                  | j
                  ||d      \  | _        }	t        j                  | j                  g|	i | d| _	        |	S )z)Connect method, doesn't follow redirects.NTr   )
websocket_http_utils
proxy_infor	   rK   	parse_urlrG   connectwebsocket_handshake	handshakerN   )
r   ssl_optr   proxyr   hostnameportresource_addrss
             r   r}   z IapLightWeightWebsocket._connect%  s     ++6g6EgG yy$8$B$B488$L!hhx(e-55dhh6:<di##DIIAAADNLr   c                 b   | j                  |      rt        j                  d      |t        j                  u r#|j
                  d   t        j                  k7  r|y|t        j                  u rBt        j                  |      }|||t        j                  k7  s|t        j                  k7  r|yy)zIDecides if we throw or if we ignore the exception because it's retriable.z*Connection closed while waiting for retry.r   N)ro   rV   rW   rx   ry   argsSSL_ERROR_WANT_WRITErm   rn   r   r   errnoEAGAINEWOULDBLOCK)r   rh   r   s      r   !_throw_on_non_retriable_exceptionz9IapLightWeightWebsocket._throw_on_non_retriable_exception5  s     ++A. CC
68 8CLL 
c..	. 
/	
fll	"55a8j			u||	#zU5F5F'F (G 
r   c                     | j                  |       |t        k  r?| j                  r3| j                  j                         dk7  r| j	                  t
               y|)zEWait for the websocket to be ready we don't retry too much too quick.r{   N)r   rb   rK   r~   r   r   )r   r\   r]   s      r   re   z0IapLightWeightWebsocket._throw_or_wait_for_retryH  sJ    **95 	((TYY		b 
$$%ABor   c                 <   | j                   j                         ry	 t        j                  | j                   gdd|      }y# t        $ rD}t	        j
                  |      }t        |t              rd|v rt        j                  d       d}~wt        t        j                  f$ rv}t        j                  j                         s |t        u r|j                  dk7  r |t        j                  u r#|j                   t         j"                  k7  r Y d}~yY d}~yd}~ww xY w)z@Wait for socket to be ready and treat some special errors cases.Nr   zarguments 1-3 must be sequencesz4Connection closed while waiting for socket to ready.i6'  )rK   pendingselect	TypeErrorr   r   
isinstancestrrV   rW   rw   rn   r   OperatingSystem	IsWindowswinerrorr   ENOTSOCK)r   r   r   rh   r   s        r   r   z1IapLightWeightWebsocket._wait_for_socket_to_readyT  s     yy
--RW
5a 	33A6g 
G
>'I"EEBD 	DV\\"  &&002	
g1::.	
fll	qww%..8  9	s$   #A 	D
?B		D%A'DDc                 V   |t         j                  u ry|t        u r|j                  t        j                  k(  ry|t
        j                  u r"|j                  d   t
        j                  k(  ryyt        j                  |      }|t        j                  k(  s|t        j                  k(  ryy)zAMethod to identify if the exception is of closed connection type.Tr   F)rV   rW   rw   r   EBADFrx   ry   r   SSL_ERROR_EOFr   r   ENOTCONNEPIPE)r   r]   r   s      r   ro   z7IapLightWeightWebsocket._is_closed_connection_exceptions  s    (KKK	g	)//U[["@ 	cll	" 
	c//	/  #55i@j 
u~~	%u{{)Br   c                     |r[t        |      dk\  rLdt        j                  |dd       z  t        j                  |dd       z   }|dd  j                  d      }||gS y y )Nr      r   r    zutf-8)rd   r&   byte2intdecode)r   rZ   codereasons       r   r   z'IapLightWeightWebsocket._get_close_args  sa    D	Q3<<Qq	**S\\$q)-DDdABxw'fF^ tr   r   )r   r   r   r   r   r   rc   CLOSE_STATUS_NORMALr&   brl   rk   r   rL   r   r}   r   re   r   ro   r   r   r   r   rE   rE   s   sx     ,8*!FF 1b	  #6USUU2Y .)@D8! &
>,r   rE   )(r   
__future__r   r   r   r   r   rm   rx   r8   rQ   googlecloudsdk.core.utilr   r&   websocket._abnf_abnfr?   websocket._exceptions_exceptionsrV   websocket._handshake
_handshaker   websocket._http_httpr   websocket._utils_utilsr   r   rb   r   r@   rv   OPCODE_BINARYr^   objectr	   r   rE   r   r   r   <module>r      s    % '  '    
   . 
 / 4 2 . *    ++,,
f 
5/6 5/pZf Zr   