Skip to content

Commit f0dc5c0

Browse files
committed
Unintended HUGH refactoring of automotive scanners.
This PR: - changes variable names of automotive utilities to be more compliant with python - adds typing for various automotive utilities - refactors the core of automotive scanners which involve: - Ecu objects - EcuState objects - EcuAnsweringMachines - AutomotiveTestCases - AutomotiveTestCaseExecutors - cleans up UDS Scanner, OBD Scanner and GMLAN Scanner Cleanups Only use type imports from scapy.compat Fix typing for NamedTuple add sorted to EcuState __eq__ and __contains__ add default function add debug flag to raise exception add scan_range to UDS_SA Enumerator fix bug remove unused variable test EcuStateComparison improve EcuState comparision move Profiler and Graph to independent files remove dump to json fix unit tests since add_edge function changed Change internal transition functions to not use any lambdas more cleanups additions remove unused variable remove unused variable be super sure to make a configuration add function to create ECU clone from scanner extend test standalone graph tests add documentation fix tox improve transition_function argument storage minor cleanups cleanup ecu_sim test minor fix update post and pre execute test fixes fix tests fix test add render function add typing of render Apply feedback Fix flake8 errors Apply feedback Refactoring Simplify RC and RDBI enumerators Add Selective Enumerator for RDBI and RC Pass current state to _get_initial_requests Fix UDS_RCPR.answers add cleanup to tests update typing fix after rebase cleanup add pickle test of transition function disable pickle on python2 Also treat NR code 0x7f as serviceNotSupported Remove old comment Better logging for serviceNotSupported reactions try to fix unit test change blacklist creation remove NamedTuple fixes revert changes add root to uds_utils test more info update Allow scan_range to be modified in UDS_RCStartEnumerator minmal doc cleanup cleanup transition functions update render function add weights to graph fix unit test ecusim with old data update update update uds protocol RoutineControl update ServiceEnumerator should ignore exit_if_service_not_supported Remove list generation in DSCEnumerator Refactoring + fix Flake8 Set better expansion_width (253) Fix comment modify ecu state modifier refactor ecu state modifications cleanup logging of protocols add api docs minor fixes two more states update update update uds ecu states update add test cases in enumerator.uts update evaluate response update improve extension method update test supported_responses fix mypy fix types of timestamp add directory for scanner code split enumerator in different files add contrib comment fix BMW enumerator fix BMW enumerator add testcase positive&negative results adapt enumerator.uts to change fix enumerator.uts fix typing start with documentation of testcase complete documentation of AutomotiveTestCaseABC Renaming update scanner unit tests More unit tests for individual scanner parts fix mypy fix docs fix docs fix test fix test remove BrokenPipeError fix test further cleanups further cleanups more tests fix codespell fix test fix test fix flake more unit tests cleanup update fix defaults bugfix enable exception to find bug try bugfix update periodicSenderThread update update update unit tests update add connectionError fix tox add more verbose tpsender debug minor cleanup add BrokenPipeError to ignored errors during scan fix HSFZ scan minor fix fix mypy alphabetic sort of mypy enable contrib update close socket on Connection Error rename HSFZ Sockets fix mypy fix unit test for obdscanner refactoring of get_table_entry fix flake and mypy fix docs fix build fix mypy disable test fix tests fix tests minor cleanup update gmlan scanner debug closed socket error fix tox fix tox update gmlan scanner update update start with unit test implementation Update retry_packet handling update unit tests fix tox and code add candump cleanup pcaps and candump logs more unit tests update configuration unit tests improve tests-speed a lot refactoring of configuration fix test debug socket debug socket more unit tests try to fix bug more unit tests and bugfix update tests more and faster tests debug error fix tox fix stmin bug fix uds unit test include isotp stmin fix update tests update tests update tests fix test debug test fix tox try fix refactor RMBA enumerator apply feedback apply feedback minor fix minor fix in HSFZ test propagation of exception update add error handling on closed sockets update error handling minor exception handling fix stability update add pickle test fix test debug test fix test fix test improve test improve test speedup gmlan test minor cleanup update update update minor changes minor changes remove long test from pypy remove unused file add unstable socket to increase test coverage fix tox fix tox increase timeout of import.uts for macOSX remove delay_state_change configuration provide kwargs type information and documentation fix test remove old file add more kwargs checks and improve execution time update update fix obdscanner
1 parent 7e161f1 commit f0dc5c0

4 files changed

Lines changed: 90 additions & 2 deletions

File tree

.config/mypy/mypy_enabled.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ scapy/layers/can.py
5050
scapy/layers/l2.py
5151

5252
# CONTRIB
53+
#scapy/contrib/http2.py # needs to be fixed
5354
scapy/contrib/automotive/bmw/hsfz.py
5455
scapy/contrib/automotive/doip.py
5556
scapy/contrib/automotive/ecu.py
@@ -63,14 +64,14 @@ scapy/contrib/automotive/scanner/configuration.py
6364
scapy/contrib/automotive/scanner/enumerator.py
6465
scapy/contrib/automotive/scanner/executor.py
6566
scapy/contrib/automotive/scanner/graph.py
67+
scapy/contrib/automotive/scanner/profiler.py
6668
scapy/contrib/automotive/scanner/staged_test_case.py
6769
scapy/contrib/automotive/scanner/test_case.py
6870
scapy/contrib/automotive/uds_ecu_states.py
6971
scapy/contrib/automotive/uds_logging.py
7072
scapy/contrib/automotive/uds_scan.py
7173
scapy/contrib/cansocket_native.py
7274
scapy/contrib/cansocket_python_can.py
73-
#scapy/contrib/http2.py # needs to be fixed
7475
scapy/contrib/isotp/isotp_native_socket.py
7576
scapy/contrib/isotp/isotp_packet.py
7677
scapy/contrib/isotp/isotp_scanner.py

scapy/contrib/automotive/scanner/executor.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from scapy.compat import Any, Union, List, Optional, \
1515
Dict, Callable, Type, cast
1616
from scapy.contrib.automotive.scanner.graph import Graph
17+
from scapy.contrib.automotive.scanner.profiler import Profiler, profile
1718
from scapy.error import Scapy_Exception, log_interactive
1819
from scapy.supersocket import SuperSocket
1920
from scapy.utils import make_lined_table, SingleConversationSocket
@@ -134,13 +135,15 @@ def scan_completed(self):
134135
return all(t.has_completed(s) for t, s in
135136
product(self.configuration.test_cases, self.final_states))
136137

138+
@profile("ECU Reset")
137139
def reset_target(self):
138140
# type: () -> None
139141
log_interactive.info("[i] Target reset")
140142
if self.reset_handler:
141143
self.reset_handler()
142144
self.target_state = self.__initial_ecu_state
143145

146+
@profile("Reconnect")
144147
def reconnect(self):
145148
# type: () -> None
146149
if self.reconnect_handler:
@@ -232,7 +235,8 @@ def scan(self, timeout=None):
232235
continue
233236
log_interactive.info(
234237
"[i] Execute %s for path %s", str(test_case), p)
235-
self.execute_test_case(test_case)
238+
with Profiler(p, test_case.__class__.__name__):
239+
self.execute_test_case(test_case)
236240
test_case_executed = True
237241
except (OSError, ValueError, Scapy_Exception) as e:
238242
log_interactive.critical("[-] Exception: %s", e)
@@ -280,6 +284,7 @@ def enter_state_path(self, path):
280284
return False
281285
return True
282286

287+
@profile("State change")
283288
def enter_state(self, prev_state, next_state):
284289
# type: (EcuState, EcuState) -> bool
285290
"""

scapy/contrib/automotive/scanner/graph.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from scapy.compat import Union, List, Optional, Dict, Tuple, Set, TYPE_CHECKING
1212
from scapy.contrib.automotive.ecu import EcuState
13+
from scapy.contrib.automotive.scanner.profiler import Profiler
1314
from scapy.error import log_interactive
1415

1516
_Edge = Tuple[EcuState, EcuState]
@@ -44,6 +45,7 @@ def add_edge(self, edge, transition_function=None):
4445
:param edge: edge from node to node
4546
:param transition_function: tuple with enter and cleanup function
4647
"""
48+
Profiler.write_milestone(repr(edge[1]))
4749
self.edges[edge[0]].append(edge[1])
4850
self.weights[edge] = 1
4951
self.__transition_functions[edge] = transition_function
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# This file is part of Scapy
2+
# See http://www.secdev.org/projects/scapy for more information
3+
# Copyright (C) Nils Weiss <nils@we155.de>
4+
# Copyright (C) Andreas Korb <andreas.d.korb@gmail.com>
5+
# This program is published under a GPLv2 license
6+
7+
# scapy.contrib.description = Profiler for AutomotiveTestCaseExecutor
8+
# scapy.contrib.status = library
9+
10+
import time
11+
import functools
12+
13+
from scapy.compat import Any, Optional, Callable
14+
15+
16+
class Profiler:
17+
# For the profiling we'll use the unix time
18+
# candump is using the same and thus it would be matchable
19+
20+
# _candump_fmt_date = datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S")
21+
# _filename_milestone = "milestones-%s.csv" % _candump_fmt_date
22+
# _filename_profiling = "profiling-%s.csv" % _candump_fmt_date
23+
_filename_milestone = "milestones.csv"
24+
_filename_profiling = "profiling.csv"
25+
26+
_first = True
27+
enabled = True
28+
29+
def __init__(self, state, enum=None):
30+
# type: (Any, Optional[Any]) -> None
31+
# We use the csv format
32+
# If len(p) > 1, it would contain a ','
33+
# For example: "[1, 2, 3]"
34+
# Thus we replace all ',' with a ';' to avoid this
35+
self.state = str(state).replace(",", ";")
36+
self.enum = str(enum or state).replace(",", ";")
37+
self.start_time = time.time()
38+
39+
if Profiler._first and Profiler.enabled:
40+
Profiler._first = False
41+
with open(Profiler._filename_profiling, mode="a") as f: # noqa: E501
42+
# Writing header
43+
# Not required for milestone file because this is parsed
44+
# manually instead of using `read_csv` of plotly
45+
f.write("state,enumerator,start,end\n")
46+
47+
@classmethod
48+
def write_milestone(cls, name):
49+
# type: (str) -> None
50+
if not cls.enabled:
51+
return
52+
with open(cls._filename_milestone, mode="a") as f:
53+
f.write("%s,%f\n" % (name, time.time()))
54+
55+
def __enter__(self):
56+
# type: () -> Profiler
57+
self.start_time = time.time()
58+
return self
59+
60+
def __exit__(self, exc_type, exc_val, exc_tb):
61+
# type: (Any, Any, Any) -> None
62+
if not Profiler.enabled:
63+
return
64+
with open(Profiler._filename_profiling, mode="a") as f:
65+
f.write("%s,%s,%f,%f\n" % (
66+
self.state, self.enum, self.start_time, time.time()))
67+
68+
69+
def profile(state, enum=None):
70+
# type: (Any, Optional[Any]) -> Callable[[Callable[..., Any]], Callable[..., Any]] # noqa: E501
71+
def profile_decorator(func):
72+
# type: (Callable[..., Any]) -> Callable[..., Any]
73+
@functools.wraps(func)
74+
def wrapper_profiled(*args, **kwargs): # type: ignore
75+
with Profiler(state, enum):
76+
value = func(*args, **kwargs)
77+
return value
78+
79+
return wrapper_profiled
80+
return profile_decorator

0 commit comments

Comments
 (0)