mirror of
https://github.com/naruxde/revpipyload.git
synced 2025-11-08 15:13:52 +01:00
Use struct module for net commands, send files with length, replace SD with WD
The struct module is more efficient than int.from_bytes. piCtory and ReplaceIO file length in the first 4 bytes of transmission Replaced SD with WD cmd, which will write one request, no buffer
This commit is contained in:
@@ -3,22 +3,24 @@
|
||||
__author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2018 Sven Sager"
|
||||
__license__ = "GPLv3"
|
||||
import proginit
|
||||
|
||||
import socket
|
||||
from fcntl import ioctl
|
||||
from shared.ipaclmanager import IpAclManager
|
||||
from struct import unpack, pack
|
||||
from threading import Event, Thread
|
||||
from timeit import default_timer
|
||||
|
||||
import proginit
|
||||
from shared.ipaclmanager import IpAclManager
|
||||
|
||||
# Hashvalues
|
||||
HASH_NULL = b'\x00' * 16
|
||||
HASH_FAIL = b'\xff' * 16
|
||||
HASH_NULL = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
HASH_FAIL = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
|
||||
HASH_PICT = HASH_FAIL
|
||||
HASH_RPIO = HASH_NULL
|
||||
|
||||
|
||||
class RevPiSlave(Thread):
|
||||
|
||||
"""RevPi PLC-Server.
|
||||
|
||||
Diese Klasste stellt den RevPi PLC-Server zur verfuegung und akzeptiert
|
||||
@@ -59,7 +61,7 @@ class RevPiSlave(Thread):
|
||||
def check_connectedacl(self):
|
||||
"""Prueft bei neuen ACLs bestehende Verbindungen."""
|
||||
for dev in self._th_dev:
|
||||
ip, port = dev._addr
|
||||
ip, port = dev._addr
|
||||
level = self.__ipacl.get_acllevel(ip)
|
||||
if level < 0:
|
||||
# Verbindung killen
|
||||
@@ -172,7 +174,6 @@ class RevPiSlave(Thread):
|
||||
|
||||
|
||||
class RevPiSlaveDev(Thread):
|
||||
|
||||
"""Klasse um eine RevPiModIO Verbindung zu verwalten.
|
||||
|
||||
Diese Klasste stellt die Funktionen zur Verfuegung um Daten ueber das
|
||||
@@ -195,7 +196,6 @@ class RevPiSlaveDev(Thread):
|
||||
self._devcon, self._addr = devcon
|
||||
self._evt_exit = Event()
|
||||
self.got_replace_ios = False
|
||||
self._writeerror = False
|
||||
|
||||
# Sicherheitsbytes
|
||||
self.ey_dict = {}
|
||||
@@ -222,13 +222,12 @@ class RevPiSlaveDev(Thread):
|
||||
|
||||
buff_size = 2048
|
||||
dirty = True
|
||||
netcmd = bytearray()
|
||||
buff_block = bytearray(buff_size)
|
||||
buff_recv = bytearray()
|
||||
while not self._evt_exit.is_set():
|
||||
# Laufzeitberechnung starten
|
||||
ot = default_timer()
|
||||
netcmd.clear()
|
||||
buff_recv.clear()
|
||||
|
||||
# Meldung erhalten
|
||||
try:
|
||||
@@ -237,27 +236,27 @@ class RevPiSlaveDev(Thread):
|
||||
count = self._devcon.recv_into(buff_block, recv_len)
|
||||
if count == 0:
|
||||
raise IOError("lost network connection")
|
||||
netcmd += buff_block[:count]
|
||||
buff_recv += buff_block[:count]
|
||||
recv_len -= count
|
||||
|
||||
# Unpack ist schneller als Direktzugriff oder Umwandlung
|
||||
netcmd = unpack("=c2sHH8sc", buff_recv)
|
||||
except Exception as e:
|
||||
proginit.logger.exception(e)
|
||||
proginit.logger.error(e)
|
||||
break
|
||||
|
||||
# Wenn Meldung ungültig ist aussteigen
|
||||
if netcmd[0:1] != b'\x01' or netcmd[-1:] != b'\x17':
|
||||
if netcmd != b'':
|
||||
proginit.logger.error(
|
||||
"net cmd not valid {0}".format(netcmd)
|
||||
)
|
||||
if netcmd[0] != b'\x01' or netcmd[5] != b'\x17':
|
||||
proginit.logger.error("net cmd not valid {0}".format(netcmd))
|
||||
break
|
||||
|
||||
cmd = netcmd[1:3]
|
||||
cmd = netcmd[1]
|
||||
if cmd == b'DA':
|
||||
# Processabbild übertragen
|
||||
# bCMiiii00000000b = 16
|
||||
# b CM ii ii 00000000 b = 16
|
||||
|
||||
position = int.from_bytes(netcmd[3:5], byteorder="little")
|
||||
length = int.from_bytes(netcmd[5:7], byteorder="little")
|
||||
position = netcmd[2]
|
||||
length = netcmd[3]
|
||||
|
||||
fh_proc.seek(position)
|
||||
try:
|
||||
@@ -266,44 +265,72 @@ class RevPiSlaveDev(Thread):
|
||||
proginit.logger.error("error while send read data")
|
||||
break
|
||||
|
||||
elif cmd == b'SD':
|
||||
elif cmd == b'WD':
|
||||
# Ausgänge setzen, wenn acl es erlaubt
|
||||
# bCMiiiic0000000b = 16
|
||||
# b CM ii ii c0000000 b = 16
|
||||
|
||||
# Berechtigung prüfen und ggf. trennen
|
||||
if self._acl < 1:
|
||||
self._devcon.sendall(b'\x18')
|
||||
break
|
||||
|
||||
position = int.from_bytes(netcmd[3:5], byteorder="little")
|
||||
length = int.from_bytes(netcmd[5:7], byteorder="little")
|
||||
control = netcmd[7:8]
|
||||
position = netcmd[2]
|
||||
length = netcmd[3]
|
||||
|
||||
# Datenblock schreiben
|
||||
buff_recv.clear()
|
||||
try:
|
||||
while length > 0:
|
||||
count = self._devcon.recv_into(buff_block, min(length, buff_size))
|
||||
if count == 0:
|
||||
raise IOError("lost network connection")
|
||||
buff_recv += buff_block[:count]
|
||||
length -= count
|
||||
except Exception:
|
||||
proginit.logger.error("error while recv data for wd write")
|
||||
break
|
||||
|
||||
fh_proc.seek(position)
|
||||
fh_proc.write(buff_recv)
|
||||
|
||||
# Record separator character
|
||||
self._devcon.sendall(b'\x1e')
|
||||
|
||||
elif cmd == b'FD':
|
||||
# Ausgänge gepuffert setzen, deutlich schneller als SD
|
||||
# b CM ii ii 00000000 b = 16
|
||||
|
||||
# Berechtigung prüfen und ggf. trennen
|
||||
if self._acl < 1:
|
||||
self._devcon.sendall(b'\x18')
|
||||
break
|
||||
|
||||
buff_recv.clear()
|
||||
counter = netcmd[2]
|
||||
try:
|
||||
while counter > 0:
|
||||
count = self._devcon.recv_into(buff_block, min(counter, buff_size))
|
||||
if count == 0:
|
||||
raise IOError("lost network connection")
|
||||
buff_recv += buff_block[:count]
|
||||
counter -= count
|
||||
except Exception:
|
||||
proginit.logger.error("error while recv data for fd write")
|
||||
break
|
||||
|
||||
# Header: ppllbuff
|
||||
index = 0
|
||||
while index < netcmd[2]:
|
||||
position, length = unpack("=HH", buff_recv[index: index + 4])
|
||||
index += 4
|
||||
|
||||
if control == b'\x1d' and length > 0:
|
||||
# Empfange Datenblock zu schreiben nach Meldung
|
||||
buff_recv.clear()
|
||||
try:
|
||||
while length > 0:
|
||||
count = self._devcon.recv_into(buff_block, min(length, buff_size))
|
||||
if count == 0:
|
||||
raise IOError("lost network connection")
|
||||
buff_recv += buff_block[:count]
|
||||
length -= count
|
||||
except Exception:
|
||||
proginit.logger.error("error while recv data to write")
|
||||
self._writeerror = True
|
||||
break
|
||||
fh_proc.seek(position)
|
||||
fh_proc.write(buff_recv)
|
||||
fh_proc.write(buff_recv[index:index + length])
|
||||
|
||||
# Record seperator character
|
||||
if control == b'\x1c':
|
||||
# Bestätige Schreibvorgang aller Datenblöcke
|
||||
if self._writeerror:
|
||||
self._devcon.sendall(b'\xff')
|
||||
else:
|
||||
self._devcon.sendall(b'\x1e')
|
||||
self._writeerror = False
|
||||
index += length
|
||||
|
||||
# Record separator character
|
||||
self._devcon.sendall(b'\x1e')
|
||||
|
||||
elif cmd == b'\x06\x16':
|
||||
# Just sync
|
||||
@@ -311,13 +338,9 @@ class RevPiSlaveDev(Thread):
|
||||
|
||||
elif cmd == b'CF':
|
||||
# Socket konfigurieren
|
||||
# bCMii0000000000b = 16
|
||||
# b CM ii xx 00000000 b = 16
|
||||
|
||||
try:
|
||||
timeoutms = int.from_bytes(netcmd[3:5], byteorder="little")
|
||||
except Exception:
|
||||
proginit.logger.error("can not convert timeout value")
|
||||
break
|
||||
timeoutms = netcmd[2]
|
||||
|
||||
if 0 < timeoutms <= 65535:
|
||||
self._deadtime = timeoutms / 1000
|
||||
@@ -326,7 +349,7 @@ class RevPiSlaveDev(Thread):
|
||||
"set socket timeout to {0}".format(self._deadtime)
|
||||
)
|
||||
|
||||
# Record seperator character
|
||||
# Record separator character
|
||||
self._devcon.sendall(b'\x1e')
|
||||
else:
|
||||
proginit.logger.error("timeout value must be 0 to 65535")
|
||||
@@ -335,16 +358,16 @@ class RevPiSlaveDev(Thread):
|
||||
|
||||
elif cmd == b'EY':
|
||||
# Bytes bei Verbindungsabbruch schreiben
|
||||
# bCMiiiix0000000b = 16
|
||||
# b CM ii ii x0000000 b = 16
|
||||
|
||||
# Berechtigung prüfen und ggf. trennen
|
||||
if self._acl < 1:
|
||||
self._devcon.sendall(b'\x18')
|
||||
break
|
||||
|
||||
position = int.from_bytes(netcmd[3:5], byteorder="little")
|
||||
length = int.from_bytes(netcmd[5:7], byteorder="little")
|
||||
control = netcmd[7:8]
|
||||
position = netcmd[2]
|
||||
length = netcmd[3]
|
||||
control = netcmd[4][0]
|
||||
|
||||
ok_byte = b'\xff' if self.__doerror else b'\x1e'
|
||||
|
||||
@@ -352,7 +375,6 @@ class RevPiSlaveDev(Thread):
|
||||
# Alle Dirtybytes löschen
|
||||
self.ey_dict = {}
|
||||
|
||||
# Record seperator character
|
||||
self._devcon.sendall(ok_byte)
|
||||
proginit.logger.info("cleared all dirty bytes")
|
||||
|
||||
@@ -362,7 +384,6 @@ class RevPiSlaveDev(Thread):
|
||||
if position in self.ey_dict:
|
||||
del self.ey_dict[position]
|
||||
|
||||
# Record seperator character
|
||||
self._devcon.sendall(ok_byte)
|
||||
proginit.logger.info(
|
||||
"cleared dirty bytes on position {0}"
|
||||
@@ -386,7 +407,6 @@ class RevPiSlaveDev(Thread):
|
||||
|
||||
self.ey_dict[position] = bytes(buff_recv)
|
||||
|
||||
# Record seperator character
|
||||
self._devcon.sendall(ok_byte)
|
||||
proginit.logger.info(
|
||||
"got dirty bytes to write on error on position {0}"
|
||||
@@ -401,17 +421,18 @@ class RevPiSlaveDev(Thread):
|
||||
)
|
||||
try:
|
||||
with open(proginit.pargs.configrsc, "rb") as fh_pic:
|
||||
# Komplette piCtory Datei senden
|
||||
self._devcon.sendall(fh_pic.read())
|
||||
# Komplette piCtory Datei lesen
|
||||
buff = fh_pic.read()
|
||||
|
||||
self._devcon.sendall(pack("=I", len(buff)) + buff)
|
||||
except Exception as e:
|
||||
proginit.logger.error(
|
||||
"error on pictory transfair: {0}".format(e)
|
||||
)
|
||||
break
|
||||
else:
|
||||
# End-of-Transmission character immer senden
|
||||
self._devcon.sendall(b'\x04')
|
||||
continue
|
||||
|
||||
# Laufzeitberechnung überspringen
|
||||
continue
|
||||
|
||||
elif cmd == b'PH':
|
||||
# piCtory md5 Hashwert senden (16 Byte)
|
||||
@@ -427,20 +448,25 @@ class RevPiSlaveDev(Thread):
|
||||
"".format(proginit.pargs.configrsc)
|
||||
)
|
||||
replace_ios = proginit.conf["DEFAULT"].get("replace_ios", "")
|
||||
try:
|
||||
if HASH_RPIO != HASH_NULL and replace_ios:
|
||||
if HASH_RPIO != HASH_NULL and replace_ios:
|
||||
try:
|
||||
with open(replace_ios, "rb") as fh:
|
||||
# Komplette replace_io Datei senden
|
||||
self._devcon.sendall(fh.read())
|
||||
except Exception as e:
|
||||
proginit.logger.error(
|
||||
"error on replace_io transfair: {0}".format(e)
|
||||
)
|
||||
break
|
||||
# Komplette replace_io Datei lesen
|
||||
buff = fh.read()
|
||||
|
||||
self._devcon.sendall(pack("=I", len(buff)) + buff)
|
||||
except Exception as e:
|
||||
proginit.logger.error(
|
||||
"error on replace_io transfair: {0}".format(e)
|
||||
)
|
||||
break
|
||||
|
||||
else:
|
||||
# End-of-Transmission character immer senden
|
||||
self._devcon.sendall(b'\x04')
|
||||
continue
|
||||
# Nulllänge senden, damit client weiter machen kann
|
||||
self._devcon.sendall(b'\x00\x00\x00\x00')
|
||||
|
||||
# Laufzeitberechnung überspringen
|
||||
continue
|
||||
|
||||
elif cmd == b'RH':
|
||||
# Replace_IOs md5 Hashwert senden (16 Byte)
|
||||
@@ -459,10 +485,10 @@ class RevPiSlaveDev(Thread):
|
||||
|
||||
elif cmd == b'IC':
|
||||
# Net-IOCTL ausführen
|
||||
# bCMiiiiii000000b = 16
|
||||
# b CM xx ii iiii0000 b = 16
|
||||
|
||||
request = int.from_bytes(netcmd[3:7], byteorder="little")
|
||||
length = int.from_bytes(netcmd[7:9], byteorder="little")
|
||||
request = unpack("=I4x", netcmd[4])[0]
|
||||
length = netcmd[3]
|
||||
|
||||
buff_recv.clear()
|
||||
try:
|
||||
@@ -503,13 +529,13 @@ class RevPiSlaveDev(Thread):
|
||||
|
||||
elif proginit.pargs.developermode and cmd == b'DV':
|
||||
# Development options
|
||||
# bCMc00000000000b = 16
|
||||
# b CM ii ii c0000000 b = 16
|
||||
if self._acl < 9:
|
||||
# Spezieller ACL-Wert für Entwicklung
|
||||
self._devcon.sendall(b'\x18')
|
||||
break
|
||||
|
||||
c = netcmd[3:4]
|
||||
c = netcmd[4][0]
|
||||
if c == b'a':
|
||||
# CMD a = Switch ACL to 0
|
||||
self._acl = 0
|
||||
@@ -517,7 +543,7 @@ class RevPiSlaveDev(Thread):
|
||||
self._devcon.sendall(b'\x1e')
|
||||
elif c == b'b':
|
||||
# CMD b = Aktiviert/Deaktiviert den Fehlermodus
|
||||
if netcmd[4:5] == b'\x01':
|
||||
if netcmd[4][1] == b'\x01':
|
||||
self.__doerror = True
|
||||
proginit.logger.warning("DV: set do_error")
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user