Skip to content

Commit c925a25

Browse files
committed
Simplify response rejection.
1 parent eb84cfe commit c925a25

File tree

9 files changed

+79
-95
lines changed

9 files changed

+79
-95
lines changed

examples/message_parser.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def decode(self, message):
8080
print(f"{decoder.decoder.__class__.__name__}")
8181
print("-" * 80)
8282
try:
83-
_, pdu = decoder.processIncomingFrame(message)
83+
_, pdu = decoder.handleFrame(message, 0, 0)
8484
self.report(pdu)
8585
except Exception: # pylint: disable=broad-except
8686
self.check_errors(decoder, message)

pymodbus/framer/base.py

+17-33
Original file line numberDiff line numberDiff line change
@@ -63,40 +63,24 @@ def buildFrame(self, message: ModbusPDU) -> bytes:
6363
frame = self.encode(data, message.dev_id, message.transaction_id)
6464
return frame
6565

66-
def processIncomingFrame(self, data: bytes) -> tuple[int, ModbusPDU | None]:
67-
"""Process new packet pattern.
68-
69-
This takes in a new request packet, adds it to the current
70-
packet stream, and performs framing on it. That is, checks
71-
for complete messages, and once found, will process all that
72-
exist.
73-
"""
66+
def handleFrame(self, data: bytes, exp_devid: int, exp_tid: int) -> tuple[int, ModbusPDU | None]:
67+
"""Process incoming data."""
7468
used_len = 0
7569
while True:
76-
data_len, pdu = self._processIncomingFrame(data[used_len:])
70+
if used_len >= len(data):
71+
return used_len, None
72+
Log.debug("Processing: {}", data, ":hex")
73+
data_len, dev_id, tid, frame_data = self.decode(data)
7774
used_len += data_len
78-
if not data_len:
75+
if ( not frame_data
76+
or (exp_devid and dev_id != exp_devid)
77+
or (exp_tid and tid != exp_tid)
78+
):
79+
if data_len:
80+
continue
7981
return used_len, None
80-
if pdu:
81-
return used_len, pdu
82-
83-
def _processIncomingFrame(self, data: bytes) -> tuple[int, ModbusPDU | None]:
84-
"""Process new packet pattern.
85-
86-
This takes in a new request packet, adds it to the current
87-
packet stream, and performs framing on it. That is, checks
88-
for complete messages, and once found, will process all that
89-
exist.
90-
"""
91-
Log.debug("Processing: {}", data, ":hex")
92-
if not data:
93-
return 0, None
94-
used_len, dev_id, tid, frame_data = self.decode(data)
95-
if not frame_data:
96-
return used_len, None
97-
if (result := self.decoder.decode(frame_data)) is None:
98-
raise ModbusIOException("Unable to decode request")
99-
result.dev_id = dev_id
100-
result.transaction_id = tid
101-
Log.debug("Frame advanced, resetting header!!")
102-
return used_len, result
82+
if (pdu := self.decoder.decode(frame_data)) is None:
83+
raise ModbusIOException("Unable to decode request")
84+
pdu.dev_id = dev_id
85+
pdu.transaction_id = tid
86+
return used_len, pdu

pymodbus/transaction/transaction.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def sync_get_response(self, dev_id) -> ModbusPDU:
108108
continue
109109

110110
databuffer += data
111-
used_len, pdu = self.framer.processIncomingFrame(self.trace_packet(False, databuffer))
111+
used_len, pdu = self.framer.handleFrame(self.trace_packet(False, databuffer), 0, 0)
112112
databuffer = databuffer[used_len:]
113113
if pdu:
114114
if pdu.dev_id != dev_id:
@@ -214,7 +214,7 @@ def callback_disconnected(self, exc: Exception | None) -> None:
214214
def callback_data(self, data: bytes, addr: tuple | None = None) -> int:
215215
"""Handle received data."""
216216
self.last_pdu = self.last_addr = None
217-
used_len, pdu = self.framer.processIncomingFrame(self.trace_packet(False, data))
217+
used_len, pdu = self.framer.handleFrame(self.trace_packet(False, data), 0, 0)
218218
if pdu:
219219
self.last_pdu = self.trace_pdu(False, pdu)
220220
self.last_addr = addr

test/client/test_client_faulty_response.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,23 @@ def fixture_framer(self):
1919

2020
def test_ok_frame(self, framer):
2121
"""Test ok frame."""
22-
used_len, pdu = framer.processIncomingFrame(self.good_frame)
22+
used_len, pdu = framer.handleFrame(self.good_frame, 0, 0)
2323
assert pdu
2424
assert used_len == len(self.good_frame)
2525

2626
def test_1917_frame(self):
2727
"""Test invalid frame in issue 1917."""
2828
recv = b"\x01\x86\x02\x00\x01"
2929
framer = FramerRTU(DecodePDU(False))
30-
used_len, pdu = framer.processIncomingFrame(recv)
30+
used_len, pdu = framer.handleFrame(recv, 0, 0)
3131
assert not pdu
3232
assert not used_len
3333

3434
def test_faulty_frame1(self, framer):
3535
"""Test ok frame."""
3636
faulty_frame = b"\x00\x04\x00\x00\x00\x05\x00\x03\x0a\x00\x04"
3737
with pytest.raises(ModbusIOException):
38-
framer.processIncomingFrame(faulty_frame)
39-
used_len, pdu = framer.processIncomingFrame(self.good_frame)
38+
framer.handleFrame(faulty_frame, 0, 0)
39+
used_len, pdu = framer.handleFrame(self.good_frame, 0, 0)
4040
assert pdu
4141
assert used_len == len(self.good_frame)

test/framer/test_extras.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ def test_tcp_framer_transaction_half2(self):
4141
"""Test a half completed tcp frame transaction."""
4242
msg1 = b"\x00\x01\x12\x34\x00\x06\xff"
4343
msg2 = b"\x02\x01\x02\x00\x08"
44-
used_len, pdu = self._tcp.processIncomingFrame(msg1)
44+
used_len, pdu = self._tcp.handleFrame(msg1, 0, 0)
4545
assert not pdu
4646
assert not used_len
47-
used_len, pdu = self._tcp.processIncomingFrame(msg1+msg2)
47+
used_len, pdu = self._tcp.handleFrame(msg1+msg2, 0, 0)
4848
assert pdu
4949
assert used_len == len(msg1) + len(msg2)
5050
assert pdu.function_code.to_bytes(1,'big') + pdu.encode() == msg2
@@ -53,10 +53,10 @@ def test_tcp_framer_transaction_half3(self):
5353
"""Test a half completed tcp frame transaction."""
5454
msg1 = b"\x00\x01\x12\x34\x00\x06\xff\x02\x01\x02\x00"
5555
msg2 = b"\x08"
56-
used_len, pdu = self._tcp.processIncomingFrame(msg1)
56+
used_len, pdu = self._tcp.handleFrame(msg1, 0, 0)
5757
assert not pdu
5858
assert not used_len
59-
used_len, pdu = self._tcp.processIncomingFrame(msg1+msg2)
59+
used_len, pdu = self._tcp.handleFrame(msg1+msg2, 0, 0)
6060
assert pdu
6161
assert used_len == len(msg1) + len(msg2)
6262
assert pdu.function_code.to_bytes(1,'big') + pdu.encode() == msg1[7:] + msg2
@@ -65,34 +65,34 @@ def test_tcp_framer_transaction_short(self):
6565
"""Test that we can get back on track after an invalid message."""
6666
msg1 = b''
6767
msg2 = b"\x00\x01\x12\x34\x00\x06\xff\x02\x01\x02\x00\x08"
68-
used_len, pdu = self._tcp.processIncomingFrame(msg1)
68+
used_len, pdu = self._tcp.handleFrame(msg1, 0, 0)
6969
assert not pdu
7070
assert not used_len
71-
used_len, pdu = self._tcp.processIncomingFrame(msg1+msg2)
71+
used_len, pdu = self._tcp.handleFrame(msg1+msg2, 0, 0)
7272
assert pdu
7373
assert used_len == len(msg1) + len(msg2)
7474
assert pdu.function_code.to_bytes(1,'big') + pdu.encode() == msg2[7:]
7575

7676
def test_tls_incoming_packet(self):
7777
"""Framer tls incoming packet."""
7878
msg = b"\x00\x01\x12\x34\x00\x06\xff\x02\x01\x02\x00\x08"
79-
_, pdu = self._tls.processIncomingFrame(msg)
79+
_, pdu = self._tls.handleFrame(msg, 0, 0)
8080
assert pdu
8181

8282
def test_rtu_process_incoming_packets(self):
8383
"""Test rtu process incoming packets."""
8484
msg = b"\x00\x01\x00\x00\x00\x01\xfc\x1b"
85-
_, pdu = self._rtu.processIncomingFrame(msg)
85+
_, pdu = self._rtu.handleFrame(msg, 0, 0)
8686
assert pdu
8787

8888
def test_ascii_process_incoming_packets(self):
8989
"""Test ascii process incoming packet."""
9090
msg = b":F7031389000A60\r\n"
91-
_, pdu = self._ascii.processIncomingFrame(msg)
91+
_, pdu = self._ascii.handleFrame(msg, 0, 0)
9292
assert pdu
9393

9494
def test_rtu_decode_exception(self):
9595
"""Test that the RTU framer can decode errors."""
9696
msg = b"\x00\x90\x02\x9c\x01"
97-
_, pdu = self._rtu.processIncomingFrame(msg)
97+
_, pdu = self._rtu.handleFrame(msg, 0, 0)
9898
assert pdu

test/framer/test_framer.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -388,20 +388,20 @@ def test_framer_decode(self, test_framer):
388388
assert not res_data
389389

390390
@pytest.mark.parametrize(("is_server"), [False])
391-
async def test_processIncomingFrame_no(self, test_framer):
392-
"""Test processIncomingFrame."""
391+
async def test_handleFrame_no(self, test_framer):
392+
"""Test handleFrame."""
393393
msg = b"\x00\x01\x00\x00\x00\x01\xfc\x1b"
394-
with mock.patch.object(test_framer, "_processIncomingFrame") as mock_process:
395-
mock_process.side_effect = [(5, None), (0, None)]
396-
used_len, pdu = test_framer.processIncomingFrame(msg)
394+
with mock.patch.object(test_framer, "decode") as mock_process:
395+
mock_process.side_effect = [(5, 0, 0, None), (0, 0, 0, None)]
396+
used_len, pdu = test_framer.handleFrame(msg, 0, 0)
397397
assert used_len == 5
398398
assert not pdu
399399

400400
@pytest.mark.parametrize(("is_server"), [True])
401-
async def test_processIncomingFrame1(self, test_framer):
402-
"""Test processIncomingFrame."""
401+
async def test_handleFrame1(self, test_framer):
402+
"""Test handleFrame."""
403403
msg = b"\x00\x01\x00\x00\x00\x01\xfc\x1b"
404-
_, pdu = test_framer.processIncomingFrame(msg)
404+
_, pdu = test_framer.handleFrame(msg, 0, 0)
405405
assert pdu
406406

407407
@pytest.mark.parametrize(("is_server"), [True])
@@ -411,9 +411,9 @@ async def test_processIncomingFrame1(self, test_framer):
411411
(FramerType.RTU, b"\x00\x01\x00\x00\x00\x01\xfc\x1b"),
412412
(FramerType.ASCII, b":F7031389000A60\r\n"),
413413
])
414-
def test_processIncomingFrame2(self, test_framer, msg):
414+
def test_handleFrame2(self, test_framer, msg):
415415
"""Test a tcp frame transaction."""
416-
used_len, pdu = test_framer.processIncomingFrame(msg)
416+
used_len, pdu = test_framer.handleFrame(msg, 0, 0)
417417
assert pdu
418418
assert used_len == len(msg)
419419

@@ -425,16 +425,16 @@ def test_processIncomingFrame2(self, test_framer, msg):
425425
(FramerType.RTU, b"\x00\x01\x00\x00\x00\x01\xfc\x1b", 0, 0),
426426
(FramerType.ASCII, b":F7031389000A60\r\n", 0xf7, 0),
427427
])
428-
def test_processIncomingFrame_roundtrip(self, entry, test_framer, msg, dev_id, tid, half):
428+
def test_handleFrame_roundtrip(self, entry, test_framer, msg, dev_id, tid, half):
429429
"""Test a tcp frame transaction."""
430430
if half and entry != FramerType.TLS:
431431
data_len = int(len(msg) / 2)
432-
used_len, pdu = test_framer.processIncomingFrame(msg[:data_len])
432+
used_len, pdu = test_framer.handleFrame(msg[:data_len], 0, 0)
433433
assert not pdu
434434
assert not used_len
435-
used_len, result = test_framer.processIncomingFrame(msg)
435+
used_len, result = test_framer.handleFrame(msg, 0, 0)
436436
else:
437-
used_len, result = test_framer.processIncomingFrame(msg)
437+
used_len, result = test_framer.handleFrame(msg, 0, 0)
438438
assert used_len == len(msg)
439439
assert result
440440
assert result.dev_id == dev_id

test/framer/test_multidrop.py

+23-23
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,24 @@ def fixture_framer(self):
2020
def test_ok_frame(self, framer):
2121
"""Test ok frame."""
2222
serial_event = self.good_frame
23-
used_len, pdu = framer.processIncomingFrame(serial_event)
23+
used_len, pdu = framer.handleFrame(serial_event, 0, 0)
2424
assert pdu
2525
assert used_len == len(serial_event)
2626

2727
def test_ok_2frame(self, framer):
2828
"""Test ok frame."""
2929
serial_event = self.good_frame + self.good_frame
30-
used_len, pdu = framer.processIncomingFrame(serial_event)
30+
used_len, pdu = framer.handleFrame(serial_event, 0, 0)
3131
assert pdu
3232
assert used_len == len(self.good_frame)
33-
used_len, pdu = framer.processIncomingFrame(serial_event[used_len:])
33+
used_len, pdu = framer.handleFrame(serial_event[used_len:], 0, 0)
3434
assert pdu
3535
assert used_len == len(self.good_frame)
3636

3737
def test_bad_crc(self, framer):
3838
"""Test bad crc."""
3939
serial_event = b"\x02\x03\x00\x01\x00}\xd4\x19" # Manually mangled crc
40-
_, pdu = framer.processIncomingFrame(serial_event)
40+
_, pdu = framer.handleFrame(serial_event, 0, 0)
4141
assert not pdu
4242

4343
def test_big_split_response_frame_from_other_id(self, framer):
@@ -62,46 +62,46 @@ def test_big_split_response_frame_from_other_id(self, framer):
6262
data = b''
6363
for serial_event in serial_events:
6464
data += serial_event
65-
used_len, pdu = framer.processIncomingFrame(data)
65+
used_len, pdu = framer.handleFrame(data, 0, 0)
6666
assert not pdu
6767
assert not used_len
68-
used_len, pdu = framer.processIncomingFrame(data + final)
68+
used_len, pdu = framer.handleFrame(data + final, 0, 0)
6969
assert pdu
7070
assert used_len == len(data + final)
7171

7272
def test_split_frame(self, framer):
7373
"""Test split frame."""
74-
used_len, pdu = framer.processIncomingFrame(self.good_frame[:5])
74+
used_len, pdu = framer.handleFrame(self.good_frame[:5], 0, 0)
7575
assert not pdu
7676
assert not used_len
77-
used_len, pdu = framer.processIncomingFrame(self.good_frame)
77+
used_len, pdu = framer.handleFrame(self.good_frame, 0, 0)
7878
assert pdu
7979
assert used_len == len(self.good_frame)
8080

8181
def test_complete_frame_trailing_data_without_id(self, framer):
8282
"""Test trailing data."""
8383
garbage = b"\x05\x04\x03" # without id
8484
serial_event = garbage + self.good_frame
85-
used_len, pdu = framer.processIncomingFrame(serial_event)
85+
used_len, pdu = framer.handleFrame(serial_event, 0, 0)
8686
assert pdu
8787
assert used_len == len(serial_event)
8888

8989
def test_complete_frame_trailing_data_with_id(self, framer):
9090
"""Test trailing data."""
9191
garbage = b"\x05\x04\x03\x02\x01\x00" # with id
9292
serial_event = garbage + self.good_frame
93-
used_len, pdu = framer.processIncomingFrame(serial_event)
93+
used_len, pdu = framer.handleFrame(serial_event, 0, 0)
9494
assert pdu
9595
assert used_len == len(serial_event)
9696

9797
def test_split_frame_trailing_data_with_id(self, framer):
9898
"""Test split frame."""
9999
garbage = b"ABCDEF"
100100
serial_events = garbage + self.good_frame
101-
used_len, pdu = framer.processIncomingFrame(serial_events[:11])
101+
used_len, pdu = framer.handleFrame(serial_events[:11], 0, 0)
102102
assert not pdu
103103
serial_events = serial_events[used_len:]
104-
used_len, pdu = framer.processIncomingFrame(serial_events)
104+
used_len, pdu = framer.handleFrame(serial_events, 0, 0)
105105
assert pdu
106106
assert used_len == len(serial_events)
107107

@@ -114,10 +114,10 @@ def test_split_frame_trailing_data_with_id(self, framer):
114114
def test_coincidental(self, garbage, framer):
115115
"""Test conincidental."""
116116
serial_events = garbage + self.good_frame
117-
used_len, pdu = framer.processIncomingFrame(serial_events[:5])
117+
used_len, pdu = framer.handleFrame(serial_events[:5], 0, 0)
118118
assert not pdu
119119
serial_events = serial_events[used_len:]
120-
used_len, pdu = framer.processIncomingFrame(serial_events)
120+
used_len, pdu = framer.handleFrame(serial_events, 0, 0)
121121
assert pdu
122122
assert used_len == len(serial_events)
123123

@@ -129,15 +129,15 @@ def test_wrapped_frame(self, framer):
129129
# i.e. this probably represents a case where a command came for us, but we didn't get
130130
# to the serial buffer in time (some other co-routine or perhaps a block on the USB bus)
131131
# and the master moved on and queried another device
132-
_, pdu = framer.processIncomingFrame(serial_event)
132+
_, pdu = framer.handleFrame(serial_event, 0, 0)
133133
assert pdu
134134

135135
def test_frame_with_trailing_data(self, framer):
136136
"""Test trailing data."""
137137
garbage = b"\x05\x04\x03\x02\x01\x00"
138138
serial_event = self.good_frame + garbage
139139
# We should not respond in this case for identical reasons as test_wrapped_frame
140-
_, pdu = framer.processIncomingFrame(serial_event)
140+
_, pdu = framer.handleFrame(serial_event, 0, 0)
141141
assert pdu
142142

143143
def test_wrong_class(self):
@@ -150,19 +150,19 @@ def return_none(_data):
150150
framer = FramerAscii(DecodePDU(True))
151151
framer.decoder.decode = return_none
152152
with pytest.raises(ModbusIOException):
153-
framer.processIncomingFrame(b':1103007C00026E\r\n')
153+
framer.handleFrame(b':1103007C00026E\r\n', 0, 0)
154154

155155
def test_getFrameStart(self, framer):
156156
"""Test getFrameStart."""
157157
framer_ok = b"\x02\x03\x00\x01\x00\x7d\xd4\x18"
158-
_, pdu = framer.processIncomingFrame(framer_ok)
158+
_, pdu = framer.handleFrame(framer_ok, 0, 0)
159159
assert framer_ok[1:-2] == pdu.function_code.to_bytes(1,'big')+pdu.encode()
160160

161161
framer_2ok = framer_ok + framer_ok
162-
used_len, pdu = framer.processIncomingFrame(framer_2ok)
162+
used_len, pdu = framer.handleFrame(framer_2ok, 0, 0)
163163
assert pdu
164164
framer_2ok = framer_2ok[used_len:]
165-
used_len, pdu = framer.processIncomingFrame(framer_2ok)
165+
used_len, pdu = framer.handleFrame(framer_2ok, 0, 0)
166166
assert pdu
167167
assert used_len == len(framer_2ok)
168168

@@ -174,12 +174,12 @@ def test_rtu_split_frame(self, framer):
174174
b'\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99'
175175
b'\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99'
176176
b'\xaa\xbb\xcc\xdd\xee\xff\xe7\x65')
177-
used_len, pdu = framer.processIncomingFrame(msg1+msg2)
177+
used_len, pdu = framer.handleFrame(msg1+msg2, 0, 0)
178178
assert pdu
179179
assert used_len == len(msg1 + msg2)
180-
used_len, pdu = framer.processIncomingFrame(msg1)
180+
used_len, pdu = framer.handleFrame(msg1, 0, 0)
181181
assert not pdu
182182
assert not used_len
183-
used_len, pdu = framer.processIncomingFrame(msg1+msg2)
183+
used_len, pdu = framer.handleFrame(msg1+msg2, 0, 0)
184184
assert pdu
185185
assert used_len == len(msg1 + msg2)

0 commit comments

Comments
 (0)