a
    kÄ#d-?  ã                   @   s   d dl Z d dlZd dlmZ d dlmZ d dlmZmZm	Z	m
Z
mZmZ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mZ d dlm  mZ d d
lmZmZm Z  d dl!m"Z" d dl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) e *e j+¡G dd„ dƒƒZ,dS )é    N)Úproduct)ÚEvent)ÚAnyÚUnionÚListÚOptionalÚDictÚCallableÚTypeÚcast)Úlog_automotive)ÚGraph)ÚScapy_Exception)ÚSuperSocket)Úmake_lined_tableÚSingleConversationSocket)ÚEcuStateÚEcuResponseÚEcu)Ú'AutomotiveTestCaseExecutorConfiguration)ÚAutomotiveTestCaseABCÚ_SocketUnionÚ_CleanupCallableÚStateGeneratorÚTestCaseGeneratorÚAutomotiveTestCasec                       sø   e Zd ZdZedd„ ƒZd1dd„Z‡ fdd„Zeej	d	d
„ ƒƒZ
edd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZdd„ Zdd„ Zd2dd„Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd3d#d$„Zd%d&„ Zd'd(„ Zd)d*„ Zd+d,„ Zd-d.„ Zed/d0„ ƒZ‡  ZS )4ÚAutomotiveTestCaseExecutoraÓ  
    Base class for different automotive scanners. This class handles
    the connection to a scan target, ensures the execution of all it's
    test cases, and stores the system state machine


    :param socket: A socket object to communicate with the scan target
    :param reset_handler: A function to reset the scan target
    :param reconnect_handler: In case the communication needs to be
                              established after a reset, provide a
                              reconnect function which returns a socket object
    :param test_cases: A list of TestCase instances or classes
    :param kwargs: Arguments for the internal
                   AutomotiveTestCaseExecutorConfiguration instance
    c                 C   s
   t dd�S )Né   )Úsession)r   ©Úself© r!   ú`/var/www/html/gsl.tools/lib/python3.9/site-packages/scapy/contrib/automotive/scanner/executor.pyÚ_initial_ecu_state1   s    z-AutomotiveTestCaseExecutor._initial_ecu_stateNc                 K   sd   t |tƒst|ƒ| _n|| _| j| _|| _|| _tƒ | _t	|pB| j
fi |¤Ž| _|  ¡  tƒ | _d S ©N)Ú
isinstancer   Úsocketr#   Útarget_stateÚreset_handlerÚreconnect_handlerÚlistÚcleanup_functionsr   Údefault_test_case_clssÚconfigurationÚvalidate_test_case_kwargsr   Ú_stop_scan_event)r    r&   r(   r)   Ú
test_casesÚkwargsr!   r!   r"   Ú__init__6   s    
ÿÿz#AutomotiveTestCaseExecutor.__init__c                    s–   t t| ƒ ¡ \}}}z
|d= W n ty0   Y n0 z
|d= W n tyN   Y n0 z
|d= W n tyl   Y n0 z
|d= W n tyŠ   Y n0 |||fS )Nr&   r(   r)   r/   )Úsuperr   Ú
__reduce__ÚKeyError)r    ÚfÚtÚd©Ú	__class__r!   r"   r4   S   s$    



z%AutomotiveTestCaseExecutor.__reduce__c                 C   s
   t ƒ ‚d S r$   )ÚNotImplementedErrorr   r!   r!   r"   r,   g   s    z1AutomotiveTestCaseExecutor.default_test_case_clssc                 C   s   | j jS r$   )r-   Ústate_graphr   r!   r!   r"   r<   m   s    z&AutomotiveTestCaseExecutor.state_graphc                    s:   ‡ fdd„ˆ j jD ƒ}tdd„ |D ƒˆ jgg dd„ d�S )z‰
        Returns all state paths. A path is represented by a list of EcuState
        objects.
        :return: A list of paths.
        c                    s(   g | ] }|ˆ j krt ˆ jˆ j |¡‘qS r!   )r#   r   Zdijkstrar<   )Ú.0Úsr   r!   r"   Ú
<listcomp>z   s   
þz:AutomotiveTestCaseExecutor.state_paths.<locals>.<listcomp>c                 S   s   g | ]}|r|‘qS r!   r!   ©r=   Úpr!   r!   r"   r?   ~   ó    c                 S   s   | d S )Néÿÿÿÿr!   )Úxr!   r!   r"   Ú<lambda>   rB   z8AutomotiveTestCaseExecutor.state_paths.<locals>.<lambda>©Úkey)r<   ÚnodesÚsortedr#   )r    Úpathsr!   r   r"   Ústate_pathsr   s    
ÿþz&AutomotiveTestCaseExecutor.state_pathsc                 C   s   dd„ | j D ƒS )z{
        Returns a list with all final states. A final state is the last
        state of a path.
        :return:
        c                 S   s   g | ]}|d  ‘qS )rC   r!   r@   r!   r!   r"   r?   ‰   rB   z;AutomotiveTestCaseExecutor.final_states.<locals>.<listcomp>)rK   r   r!   r!   r"   Úfinal_states�   s    z'AutomotiveTestCaseExecutor.final_statesc                 C   s   t dd„ t| jj| jƒD ƒƒS )Nc                 s   s   | ]\}}|  |¡V  qd S r$   )Úhas_completed)r=   r7   r>   r!   r!   r"   Ú	<genexpr>Ž   rB   z<AutomotiveTestCaseExecutor.scan_completed.<locals>.<genexpr>)Úallr   r-   r0   rL   r   r!   r!   r"   Úscan_completed‹   s    ÿz)AutomotiveTestCaseExecutor.scan_completedc                 C   s$   t  d¡ | jr|  ¡  | j| _d S )NzTarget reset)r   Úinfor(   r#   r'   r   r!   r!   r"   Úreset_target‘   s    
z'AutomotiveTestCaseExecutor.reset_targetc              
   C   sˆ   | j rtz| j ¡  W n0 tyD } zt d|¡ W Y d }~n
d }~0 0 t d¡ |   ¡ }t|tƒsnt|ƒ| _n|| _| jj	r„t
dƒ‚d S )Nz"Exception '%s' during socket.closezTarget reconnectz.Socket closed even after reconnect. Stop scan!)r)   r&   ÚcloseÚ	Exceptionr   Ú	exceptionrQ   r%   r   Úclosedr   )r    Úer&   r!   r!   r"   Ú	reconnect˜   s     ÿ

ÿz$AutomotiveTestCaseExecutor.reconnectc                 C   s  |  | j| j| j¡ z| j|jj }W n ty>   tƒ }Y n0 |rttt	|t
 
¡  ƒdƒ}| dd¡}t||ƒ|d< t d|jj|¡ |j| j| jfd| ji|¤Ž | | j| j| j¡ |  |¡ |  |¡ t|dƒ�r| ¡ }|du�rt d|jj|d	 |d
 |d ¡ dS )a°  
        This function ensures the correct execution of a testcase, including
        the pre_execute, execute and post_execute.
        Finally the testcase is asked if a new edge or a new testcase was
        generated.

        :param test_case: A test case to be executed
        :param kill_time: If set, this defines the maximum execution time for
                          the current test_case
        :return: None
        é   Zexecution_timei°  z!Execute test_case %s with args %sZ
stop_eventÚruntime_estimationNz/[i] Test_case %s: TODO %d, DONE %d, TOTAL %0.2fr   r   é   )Zpre_executer&   r'   r-   r:   Ú__name__r5   ÚdictÚmaxÚintÚtimeÚgetÚminr   ÚdebugÚexecuter/   Zpost_executeÚcheck_new_statesÚcheck_new_testcasesÚhasattrrZ   )r    Ú	test_caseÚ	kill_timeÚtest_case_kwargsZmax_execution_timeZcur_execution_timeZ
estimationr!   r!   r"   Úexecute_test_case¬   sD    ÿÿÿÿþÿ


üz,AutomotiveTestCaseExecutor.execute_test_casec                 C   s2   t |tƒr.| ¡ }|r.t d|¡ | j |¡ d S )NzTestcase generated %s)r%   r   Zget_generated_test_caser   rc   r-   Zadd_test_case)r    rh   Znew_test_caser!   r!   r"   rf   Ý   s
    
z.AutomotiveTestCaseExecutor.check_new_testcasesc                 C   sJ   t |tƒrF| | j| j¡}|rFt d|¡ | | j|¡}| j 	||¡ d S )NzEdge found %s)
r%   r   Zget_new_edger&   r-   r   rc   Zget_transition_functionr<   Zadd_edge)r    rh   ÚedgeÚtfr!   r!   r"   re   å   s    
z+AutomotiveTestCaseExecutor.check_new_statesc                 C   s4   | j jD ]&}t|tƒr| j |jj }| |¡ qd S r$   )r-   r0   r%   r   r:   r\   Zcheck_kwargs)r    rh   rj   r!   r!   r"   r.   î   s    
z4AutomotiveTestCaseExecutor.validate_test_case_kwargsc                 C   s   | j  ¡  d S r$   )r/   Úsetr   r!   r!   r"   Ú	stop_scanõ   s    z$AutomotiveTestCaseExecutor.stop_scanc                 C   sZ   g }| j jD ]0}t|dƒsq| ¡ }|d u r.q| |d ¡ qt|ƒrVt|ƒt|ƒ S dS )NrZ   r[   g        )r-   r0   rg   rZ   ÚappendÚlenÚsum)r    ÚprogressÚtcZestr!   r!   r"   rs   ù   s    
z#AutomotiveTestCaseExecutor.progressc           	      C   sò  | j  ¡  t ¡ |pd }t dt |¡ ¡ |t ¡ k�rÞd}t d|  ¡ ¡ t d| j¡ t	| j| j
jƒD �]X\}}t d|¡ |t ¡ k}|sž| j  ¡ r®t d¡  �qÊ|d }| |¡rÔt d	t|ƒ|¡ qnzèzJ|  |¡süt d
|¡ W W |  ¡  qnt dt|ƒ|¡ |  ||¡ d}W n� tttf�y° } zpt d|¡ | j
j�rR|‚t|tƒ�rrt d¡ | j ¡  tt| jƒj�rœ| jdu �rœt d¡ |‚W Y d}~n
d}~0 0 W |  ¡  qn|  ¡  0 qn|s.t d¡ �qÞq.|  ¡  |   ¡  dS )z|
        Executes all testcases for a given time.
        :param timeout: Time for execution.
        :return: None
        l   ÿÿ zSet kill_time to %sFz[i] Scan progress %0.2fz[i] Scan paths %szScan path %sz*Execution time exceeded. Terminating scan!rC   zState %s for %s completedzError entering path %szExecute %s for path %sTzException: %sz OSError occurred, closing socketNz$Socket went down. Need to leave scanz-Execute failure or scan completed. Exit scan!)!r/   Úclearr`   r   rc   ÚctimerQ   rs   rK   r   r-   r0   Úis_setrM   ÚreprÚenter_state_pathÚerrorÚcleanup_stateÚstrrk   ÚOSErrorÚ
ValueErrorr   rU   r%   r&   rS   r   r   rV   r)   ÚcriticalrR   )	r    Útimeoutri   Ztest_case_executedrA   rh   Ú	terminateZfinal_staterW   r!   r!   r"   Úscan  sx    

ÿÿ
ÿ
ÿí
ÿ
ÿ
ÿÿÿzAutomotiveTestCaseExecutor.scanc                 C   sz   |d | j krtdƒ‚|  ¡  |  ¡  t|ƒdkr6dS |dd… D ]2}| j|f}| j|Ž sB| j |¡ |  	¡   dS qBdS )zý
        Resets and reconnects to a target and applies all transition functions
        to traversal a given path.
        :param path: Path to be applied to the scan target.
        :return: True, if all transition functions could be executed.
        r   z9Initial state of path not equal reset state of the targetr   TNF)
r#   r   rR   rX   rq   r'   Úenter_stater<   Zdownrate_edger{   )r    ÚpathÚ
next_staterl   r!   r!   r"   ry   D  s    ÿ

z+AutomotiveTestCaseExecutor.enter_state_pathc           	      C   s€   ||f}| j  |¡}|du r,t d|¡ dS |\}}}|| j| j|ƒ}|rl|| _|durh|  j|g7  _dS t d|¡ dS dS )aJ  
        Obtains a transition function from the system state graph and executes
        it. On success, the cleanup function is added for a later cleanup of
        the new state.
        :param prev_state: Current state
        :param next_state: Desired state
        :return: True, if state could be changed successful
        NzNo transition function for %sFTzTransition for edge %s failed)	r<   Zget_transition_tuple_for_edger   rz   r&   r-   r'   r+   rQ   )	r    Z
prev_stater…   rl   ÚfuncsZ
trans_funcZtrans_kwargsÚ
clean_funcZstate_changedr!   r!   r"   rƒ   ^  s     


ÿz&AutomotiveTestCaseExecutor.enter_statec                 C   s|   | j D ]h}t|ƒsqz"|| j| jƒs4t dt|ƒ¡ W q ttt	fyl } zt 
d|¡ W Y d}~qd}~0 0 qtƒ | _ dS )zf
        Executes all collected cleanup functions from a traversed path
        :return: None
        zCleanup function %s failedzException during cleanup: %sN)r+   Úcallabler&   r-   r   rQ   rx   r}   r~   r   r   r*   )r    r6   rW   r!   r!   r"   r{   |  s    
ÿ$z(AutomotiveTestCaseExecutor.cleanup_statec                 C   s   | j jD ]}| ¡  qd S r$   )r-   r0   Úshow)r    r7   r!   r!   r"   Úshow_testcasesŽ  s    z)AutomotiveTestCaseExecutor.show_testcasesc                 C   sR   t ƒ }| jjD ]0}| jjD ]"}|t|ƒ|jj| |¡fg7 }qqt	|dd„ ƒ d S )Nc                 S   s   | d | d | d fS )Nr   r   r[   r!   )Útupr!   r!   r"   rE   ™  rB   zBAutomotiveTestCaseExecutor.show_testcases_status.<locals>.<lambda>)
r*   r-   r0   r<   rH   rx   r:   r\   rM   r   )r    Údatar7   r>   r!   r!   r"   Úshow_testcases_status“  s
    "z0AutomotiveTestCaseExecutor.show_testcases_statusc                 C   s0   t ƒ }| jjD ]}||j7 }q|jtjd� |S )ac  
        Returns a sorted list of supported responses, gathered from all
        enumerators. The sort is done in a way
        to provide the best possible results, if this list of supported
        responses is used to simulate an real world Ecu with the
        EcuAnsweringMachine object.
        :return: A sorted list of EcuResponse objects
        rF   )r*   r-   r0   Úsupported_responsesÚsortr   Zsort_key_func)r    rŽ   rt   r!   r!   r"   rŽ   ›  s
    z.AutomotiveTestCaseExecutor.supported_responses)NNN)N)N)r\   Ú
__module__Ú__qualname__Ú__doc__Úpropertyr#   r2   r4   ÚabcÚabstractmethodr,   r<   rK   rL   rP   rR   rX   rk   rf   re   r.   ro   rs   r‚   ry   rƒ   r{   rŠ   r�   rŽ   Ú__classcell__r!   r!   r9   r"   r      sF   
   û



	

1	
>r   )-r”   r`   Ú	itertoolsr   Ú	threadingr   Zscapy.compatr   r   r   r   r   r	   r
   r   Zscapy.contrib.automotiver   Z&scapy.contrib.automotive.scanner.graphr   Zscapy.errorr   Zscapy.supersocketr   Zscapy.utilsr   r   Zscapy.libs.sixZlibsÚsixZscapy.contrib.automotive.ecur   r   r   Z.scapy.contrib.automotive.scanner.configurationr   Z*scapy.contrib.automotive.scanner.test_caser   r   r   r   r   r   Úadd_metaclassÚABCMetar   r!   r!   r!   r"   Ú<module>	   s   ( 
