Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOCKET/TLS framer using message decode() #2129

Merged
merged 1 commit into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 11 additions & 27 deletions pymodbus/framer/socket_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,41 +72,25 @@ def frameProcessIncomingPacket(self, single, callback, slave, tid=None, **kwargs
The processed and decoded messages are pushed to the callback
function to process and send.
"""
def check_frame(self):
"""Check and decode the next frame."""
if not len(self._buffer) > self._hsize:
return False
(
self._header["tid"],
self._header["pid"],
self._header["len"],
self._header["uid"],
) = struct.unpack(">HHHB", self._buffer[0 : self._hsize])
if self._header["len"] < 2:
length = self._hsize + self._header["len"] -1
self._buffer = self._buffer[length:]
self._header = {"tid": 0, "pid": 0, "len": 0, "uid": 0}
elif len(self._buffer) - self._hsize + 1 >= self._header["len"]:
return True
Log.debug("Frame check failed, missing part of message!!")
return False

while True:
if not check_frame(self):
return
used_len, use_tid, dev_id, data = self.message_handler.decode(self._buffer)
if not data:
if not used_len:
return
self._buffer = self._buffer[used_len :]
continue
self._header["uid"] = dev_id
self._header["tid"] = use_tid
self._header["pid"] = 0
if not self._validate_slave_id(slave, single):
header_txt = self._header["uid"]
Log.debug("Not a valid slave id - {}, ignoring!!", header_txt)
Log.debug("Not a valid slave id - {}, ignoring!!", dev_id)
self.resetFrame()
return
length = self._hsize + self._header["len"] -1
data = self._buffer[self._hsize : length]
if (result := self.decoder.decode(data)) is None:
self.resetFrame()
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
length = self._hsize + self._header["len"] -1
self._buffer = self._buffer[length:]
self._buffer = self._buffer[used_len:]
self._header = {"tid": 0, "pid": 0, "len": 0, "uid": 0}
if tid and tid != result.transaction_id:
self.resetFrame()
Expand Down
52 changes: 24 additions & 28 deletions pymodbus/framer/tls_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, decoder, client=None):
"""
super().__init__(decoder, client)
self._hsize = 0x0
self.message_encoder = MessageTLS([0], True)
self.message_handler = MessageTLS([0], True)

def decode_data(self, data):
"""Decode data."""
Expand All @@ -47,38 +47,34 @@ def decode_data(self, data):
def frameProcessIncomingPacket(self, single, callback, slave, _tid=None, **kwargs):
"""Process new packet pattern."""
# no slave id for Modbus Security Application Protocol
def check_frame(self):
"""Check and decode the next frame."""
if len(self._buffer) > self._hsize:
# we have at least a complete message, continue
if len(self._buffer) - self._hsize >= 1:
return True
# we don't have enough of a message yet, wait
return False

if not len(self._buffer) > self._hsize:
return
if not check_frame(self):
Log.debug("Frame check failed, ignoring!!")
self.resetFrame()
return
if not self._validate_slave_id(slave, single):
Log.debug("Not in valid slave id - {}, ignoring!!", slave)
self.resetFrame()
return
data = self._buffer[self._hsize :]
if (result := self.decoder.decode(data)) is None:
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
self._buffer = b""
self._header = {}
callback(result) # defer or push to a thread?

while True:
used_len, use_tid, dev_id, data = self.message_handler.decode(self._buffer)
if not data:
if not used_len:
return
self._buffer = self._buffer[used_len :]
continue
self._header["uid"] = dev_id
self._header["tid"] = use_tid
self._header["pid"] = 0

if not self._validate_slave_id(slave, single):
Log.debug("Not in valid slave id - {}, ignoring!!", slave)
self.resetFrame()
return
if (result := self.decoder.decode(data)) is None:
raise ModbusIOException("Unable to decode request")
self.populateResult(result)
self._buffer = b""
self._header = {}
callback(result) # defer or push to a thread?

def buildPacket(self, message):
"""Create a ready to send modbus packet.

:param message: The populated request/response to send
"""
data = message.function_code.to_bytes(1,'big') + message.encode()
packet = self.message_encoder.encode(data, message.slave_id, message.transaction_id)
packet = self.message_handler.encode(data, message.slave_id, message.transaction_id)
return packet