#537 close sessions on receiving an ESTABLISH packet to allow for retries

This commit is contained in:
Mikayla Fischler 2024-08-24 14:46:58 -04:00
parent 0ab2d57b66
commit b3be2d4bfc
14 changed files with 134 additions and 112 deletions

View File

@ -520,7 +520,7 @@ function coordinator.comms(version, nic, sv_watchdog)
if self.sv_r_seq_num == nil then if self.sv_r_seq_num == nil then
self.sv_r_seq_num = packet.scada_frame.seq_num() + 1 self.sv_r_seq_num = packet.scada_frame.seq_num() + 1
elseif self.sv_r_seq_num ~= packet.scada_frame.seq_num() then elseif self.sv_r_seq_num ~= packet.scada_frame.seq_num() then
log.warning("sequence out-of-order: last = " .. self.sv_r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) log.warning("sequence out-of-order: next = " .. self.sv_r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
return false return false
elseif self.sv_linked and src_addr ~= self.sv_addr then elseif self.sv_linked and src_addr ~= self.sv_addr then
log.debug("received packet from unknown computer " .. src_addr .. " while linked; channel in use by another system?") log.debug("received packet from unknown computer " .. src_addr .. " while linked; channel in use by another system?")

View File

@ -106,7 +106,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
local function _handle_packet(pkt) local function _handle_packet(pkt)
-- check sequence number -- check sequence number
if self.r_seq_num ~= pkt.scada_frame.seq_num() then if self.r_seq_num ~= pkt.scada_frame.seq_num() then
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) log.warning(log_header .. "sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
return return
else else
self.r_seq_num = pkt.scada_frame.seq_num() + 1 self.r_seq_num = pkt.scada_frame.seq_num() + 1
@ -186,6 +186,10 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
elseif pkt.type == MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == MGMT_TYPE.ESTABLISH then
-- something is wrong, kill the session
_close()
log.warning(log_header .. "terminated session due to an unexpected ESTABLISH packet")
else else
log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type)
end end

View File

@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer")
local sounder = require("coordinator.sounder") local sounder = require("coordinator.sounder")
local threads = require("coordinator.threads") local threads = require("coordinator.threads")
local COORDINATOR_VERSION = "v1.5.5" local COORDINATOR_VERSION = "v1.5.6"
local CHUNK_LOAD_DELAY_S = 30.0 local CHUNK_LOAD_DELAY_S = 30.0

View File

@ -610,7 +610,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
if self.api.r_seq_num == nil then if self.api.r_seq_num == nil then
self.api.r_seq_num = packet.scada_frame.seq_num() + 1 self.api.r_seq_num = packet.scada_frame.seq_num() + 1
elseif self.api.r_seq_num ~= packet.scada_frame.seq_num() then elseif self.api.r_seq_num ~= packet.scada_frame.seq_num() then
log.warning("sequence out-of-order (API): last = " .. self.api.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) log.warning("sequence out-of-order (API): next = " .. self.api.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
return return
elseif self.api.linked and (src_addr ~= self.api.addr) then elseif self.api.linked and (src_addr ~= self.api.addr) then
log.debug("received packet from unknown computer " .. src_addr .. " while linked (API expected " .. self.api.addr .. log.debug("received packet from unknown computer " .. src_addr .. " while linked (API expected " .. self.api.addr ..
@ -697,25 +697,25 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
else else
log.debug("received coordinator establish allow without facility configuration") log.debug("received coordinator establish allow without facility configuration")
end end
elseif est_ack == ESTABLISH_ACK.DENY then else
if self.api.last_est_ack ~= est_ack then if self.api.last_est_ack ~= est_ack then
if est_ack == ESTABLISH_ACK.DENY then
log.info("coordinator connection denied") log.info("coordinator connection denied")
end
elseif est_ack == ESTABLISH_ACK.COLLISION then elseif est_ack == ESTABLISH_ACK.COLLISION then
if self.api.last_est_ack ~= est_ack then
log.info("coordinator connection denied due to collision") log.info("coordinator connection denied due to collision")
end
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
if self.api.last_est_ack ~= est_ack then
log.info("coordinator comms version mismatch") log.info("coordinator comms version mismatch")
end
elseif est_ack == ESTABLISH_ACK.BAD_API_VERSION then elseif est_ack == ESTABLISH_ACK.BAD_API_VERSION then
if self.api.last_est_ack ~= est_ack then
log.info("coordinator api version mismatch") log.info("coordinator api version mismatch")
end
else else
log.debug("coordinator SCADA_MGMT establish packet reply unsupported") log.debug("coordinator SCADA_MGMT establish packet reply unsupported")
end end
end
-- unlink
self.api.addr = comms.BROADCAST
self.api.linked = false
end
self.api.last_est_ack = est_ack self.api.last_est_ack = est_ack
end end
@ -730,7 +730,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
if self.sv.r_seq_num == nil then if self.sv.r_seq_num == nil then
self.sv.r_seq_num = packet.scada_frame.seq_num() + 1 self.sv.r_seq_num = packet.scada_frame.seq_num() + 1
elseif self.sv.r_seq_num ~= packet.scada_frame.seq_num() then elseif self.sv.r_seq_num ~= packet.scada_frame.seq_num() then
log.warning("sequence out-of-order (SVR): last = " .. self.sv.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) log.warning("sequence out-of-order (SVR): next = " .. self.sv.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
return return
elseif self.sv.linked and (src_addr ~= self.sv.addr) then elseif self.sv.linked and (src_addr ~= self.sv.addr) then
log.debug("received packet from unknown computer " .. src_addr .. " while linked (SVR expected " .. self.sv.addr .. log.debug("received packet from unknown computer " .. src_addr .. " while linked (SVR expected " .. self.sv.addr ..
@ -831,21 +831,23 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
else else
iocontrol.report_link_state(LINK_STATE.SV_LINK_ONLY, self.sv.addr, nil) iocontrol.report_link_state(LINK_STATE.SV_LINK_ONLY, self.sv.addr, nil)
end end
elseif est_ack == ESTABLISH_ACK.DENY then else
if self.sv.last_est_ack ~= est_ack then if self.sv.last_est_ack ~= est_ack then
if est_ack == ESTABLISH_ACK.DENY then
log.info("supervisor connection denied") log.info("supervisor connection denied")
end
elseif est_ack == ESTABLISH_ACK.COLLISION then elseif est_ack == ESTABLISH_ACK.COLLISION then
if self.sv.last_est_ack ~= est_ack then
log.info("supervisor connection denied due to collision") log.info("supervisor connection denied due to collision")
end
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
if self.sv.last_est_ack ~= est_ack then
log.info("supervisor comms version mismatch") log.info("supervisor comms version mismatch")
end
else else
log.debug("supervisor SCADA_MGMT establish packet reply unsupported") log.debug("supervisor SCADA_MGMT establish packet reply unsupported")
end end
end
-- unlink
self.sv.addr = comms.BROADCAST
self.sv.linked = false
end
self.sv.last_est_ack = est_ack self.sv.last_est_ack = est_ack
end end

View File

@ -20,7 +20,7 @@ local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local threads = require("pocket.threads") local threads = require("pocket.threads")
local POCKET_VERSION = "v0.11.6-alpha" local POCKET_VERSION = "v0.11.7-alpha"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -833,7 +833,7 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog)
if self.r_seq_num == nil then if self.r_seq_num == nil then
self.r_seq_num = packet.scada_frame.seq_num() + 1 self.r_seq_num = packet.scada_frame.seq_num() + 1
elseif self.r_seq_num ~= packet.scada_frame.seq_num() then elseif self.r_seq_num ~= packet.scada_frame.seq_num() then
log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) log.warning("sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
return return
elseif self.linked and (src_addr ~= self.sv_addr) then elseif self.linked and (src_addr ~= self.sv_addr) then
log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr .. log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr ..

View File

@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer") local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads") local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "v1.8.5" local R_PLC_VERSION = "v1.8.6"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -444,7 +444,7 @@ function rtu.comms(version, nic, conn_watchdog)
if self.r_seq_num == nil then if self.r_seq_num == nil then
self.r_seq_num = packet.scada_frame.seq_num() + 1 self.r_seq_num = packet.scada_frame.seq_num() + 1
elseif self.r_seq_num ~= packet.scada_frame.seq_num() then elseif self.r_seq_num ~= packet.scada_frame.seq_num() then
log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) log.warning("sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num())
return return
elseif rtu_state.linked and (src_addr ~= self.sv_addr) then elseif rtu_state.linked and (src_addr ~= self.sv_addr) then
log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr .. log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr ..

View File

@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
local sps_rtu = require("rtu.dev.sps_rtu") local sps_rtu = require("rtu.dev.sps_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local RTU_VERSION = "v1.10.5" local RTU_VERSION = "v1.10.6"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE

View File

@ -53,7 +53,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
-- print a log message to the terminal as long as the UI isn't running -- print a log message to the terminal as long as the UI isn't running
local function println(message) if not fp_ok then util.println_ts(message) end end local function println(message) if not fp_ok then util.println_ts(message) end end
local log_header = "crdn_session(" .. id .. "): " local log_tag = "crdn_session(" .. id .. "): "
local self = { local self = {
units = facility.get_units(), units = facility.get_units(),
@ -184,7 +184,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
local function _handle_packet(pkt) local function _handle_packet(pkt)
-- check sequence number -- check sequence number
if self.r_seq_num ~= pkt.scada_frame.seq_num() then if self.r_seq_num ~= pkt.scada_frame.seq_num() then
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) log.warning(log_tag .. "sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
return return
else else
self.r_seq_num = pkt.scada_frame.seq_num() + 1 self.r_seq_num = pkt.scada_frame.seq_num() + 1
@ -205,7 +205,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
self.last_rtt = srv_now - srv_start self.last_rtt = srv_now - srv_start
if self.last_rtt > 750 then if self.last_rtt > 750 then
log.warning(log_header .. "COORD KEEP_ALIVE round trip time > 750ms (" .. self.last_rtt .. "ms)") log.warning(log_tag .. "COORD KEEP_ALIVE round trip time > 750ms (" .. self.last_rtt .. "ms)")
end end
-- log.debug(log_header .. "COORD RTT = " .. self.last_rtt .. "ms") -- log.debug(log_header .. "COORD RTT = " .. self.last_rtt .. "ms")
@ -213,13 +213,17 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
databus.tx_crd_rtt(self.last_rtt) databus.tx_crd_rtt(self.last_rtt)
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_tag .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == MGMT_TYPE.ESTABLISH then
-- something is wrong, kill the session
_close()
log.warning(log_tag .. "terminated session due to an unexpected ESTABLISH packet")
else else
log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) log.debug(log_tag .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type)
end end
elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_CRDN then elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_CRDN then
---@cast pkt crdn_frame ---@cast pkt crdn_frame
@ -252,7 +256,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
_send(CRDN_TYPE.FAC_CMD, { cmd, table.unpack(facility.auto_start(config)) }) _send(CRDN_TYPE.FAC_CMD, { cmd, table.unpack(facility.auto_start(config)) })
else else
log.debug(log_header .. "CRDN auto start (with configuration) packet length mismatch") log.debug(log_tag .. "CRDN auto start (with configuration) packet length mismatch")
end end
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
facility.ack_all() facility.ack_all()
@ -261,25 +265,25 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
if pkt.length == 2 then if pkt.length == 2 then
_send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_waste_product(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_waste_product(pkt.data[2]) })
else else
log.debug(log_header .. "CRDN set waste mode packet length mismatch") log.debug(log_tag .. "CRDN set waste mode packet length mismatch")
end end
elseif cmd == FAC_COMMAND.SET_PU_FB then elseif cmd == FAC_COMMAND.SET_PU_FB then
if pkt.length == 2 then if pkt.length == 2 then
_send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2]) })
else else
log.debug(log_header .. "CRDN set pu fallback packet length mismatch") log.debug(log_tag .. "CRDN set pu fallback packet length mismatch")
end end
elseif cmd == FAC_COMMAND.SET_SPS_LP then elseif cmd == FAC_COMMAND.SET_SPS_LP then
if pkt.length == 2 then if pkt.length == 2 then
_send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_sps_low_power(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_sps_low_power(pkt.data[2]) })
else else
log.debug(log_header .. "CRDN set sps low power packet length mismatch") log.debug(log_tag .. "CRDN set sps low power packet length mismatch")
end end
else else
log.debug(log_header .. "CRDN facility command unknown") log.debug(log_tag .. "CRDN facility command unknown")
end end
else else
log.debug(log_header .. "CRDN facility command packet length mismatch") log.debug(log_tag .. "CRDN facility command packet length mismatch")
end end
elseif pkt.type == CRDN_TYPE.UNIT_BUILDS then elseif pkt.type == CRDN_TYPE.UNIT_BUILDS then
-- acknowledgement to coordinator receiving builds -- acknowledgement to coordinator receiving builds
@ -307,13 +311,13 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
if pkt.length == 3 then if pkt.length == 3 then
out_queue.push_data(SV_Q_DATA.SET_BURN, data) out_queue.push_data(SV_Q_DATA.SET_BURN, data)
else else
log.debug(log_header .. "CRDN unit command burn rate missing option") log.debug(log_tag .. "CRDN unit command burn rate missing option")
end end
elseif cmd == UNIT_COMMAND.SET_WASTE then elseif cmd == UNIT_COMMAND.SET_WASTE then
if (pkt.length == 3) and (type(pkt.data[3]) == "number") and (pkt.data[3] > 0) and (pkt.data[3] <= 4) then if (pkt.length == 3) and (type(pkt.data[3]) == "number") and (pkt.data[3] > 0) and (pkt.data[3] <= 4) then
unit.set_waste_mode(pkt.data[3]) unit.set_waste_mode(pkt.data[3])
else else
log.debug(log_header .. "CRDN unit command set waste missing/invalid option") log.debug(log_tag .. "CRDN unit command set waste missing/invalid option")
end end
elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then
unit.ack_all() unit.ack_all()
@ -322,32 +326,32 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
if pkt.length == 3 then if pkt.length == 3 then
unit.ack_alarm(pkt.data[3]) unit.ack_alarm(pkt.data[3])
else else
log.debug(log_header .. "CRDN unit command ack alarm missing alarm id") log.debug(log_tag .. "CRDN unit command ack alarm missing alarm id")
end end
elseif cmd == UNIT_COMMAND.RESET_ALARM then elseif cmd == UNIT_COMMAND.RESET_ALARM then
if pkt.length == 3 then if pkt.length == 3 then
unit.reset_alarm(pkt.data[3]) unit.reset_alarm(pkt.data[3])
else else
log.debug(log_header .. "CRDN unit command reset alarm missing alarm id") log.debug(log_tag .. "CRDN unit command reset alarm missing alarm id")
end end
elseif cmd == UNIT_COMMAND.SET_GROUP then elseif cmd == UNIT_COMMAND.SET_GROUP then
if (pkt.length == 3) and (type(pkt.data[3]) == "number") and (pkt.data[3] >= 0) and (pkt.data[3] <= 4) then if (pkt.length == 3) and (type(pkt.data[3]) == "number") and (pkt.data[3] >= 0) and (pkt.data[3] <= 4) then
facility.set_group(unit.get_id(), pkt.data[3]) facility.set_group(unit.get_id(), pkt.data[3])
_send(CRDN_TYPE.UNIT_CMD, { cmd, uid, pkt.data[3] }) _send(CRDN_TYPE.UNIT_CMD, { cmd, uid, pkt.data[3] })
else else
log.debug(log_header .. "CRDN unit command set group missing group id") log.debug(log_tag .. "CRDN unit command set group missing group id")
end end
else else
log.debug(log_header .. "CRDN unit command unknown") log.debug(log_tag .. "CRDN unit command unknown")
end end
else else
log.debug(log_header .. "CRDN unit command invalid") log.debug(log_tag .. "CRDN unit command invalid")
end end
else else
log.debug(log_header .. "CRDN unit command packet length mismatch") log.debug(log_tag .. "CRDN unit command packet length mismatch")
end end
else else
log.debug(log_header .. "handler received unexpected SCADA_CRDN packet type " .. pkt.type) log.debug(log_tag .. "handler received unexpected SCADA_CRDN packet type " .. pkt.type)
end end
end end
end end
@ -370,7 +374,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
_close() _close()
_send_mgmt(MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println("connection to coordinator " .. id .. " closed by server") println("connection to coordinator " .. id .. " closed by server")
log.info(log_header .. "session closed by server") log.info(log_tag .. "session closed by server")
end end
-- iterate the session -- iterate the session
@ -437,14 +441,14 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
_send(CRDN_TYPE.FAC_BUILDS, { facility.get_build(cmd.val.type) }) _send(CRDN_TYPE.FAC_BUILDS, { facility.get_build(cmd.val.type) })
end end
else else
log.error(log_header .. "unsupported data command received in in_queue (this is a bug)", true) log.error(log_tag .. "unsupported data command received in in_queue (this is a bug)", true)
end end
end end
end end
-- max 100ms spent processing queue -- max 100ms spent processing queue
if util.time() - handle_start > 100 then if util.time() - handle_start > 100 then
log.warning(log_header .. "exceeded 100ms queue process limit") log.warning(log_tag .. "exceeded 100ms queue process limit")
break break
end end
end end
@ -452,7 +456,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
-- exit if connection was closed -- exit if connection was closed
if not self.connected then if not self.connected then
println("connection to coordinator closed by remote host") println("connection to coordinator closed by remote host")
log.info(log_header .. "session closed by remote host") log.info(log_tag .. "session closed by remote host")
return self.connected return self.connected
end end

View File

@ -58,7 +58,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
-- print a log message to the terminal as long as the UI isn't running -- print a log message to the terminal as long as the UI isn't running
local function println(message) if not fp_ok then util.println_ts(message) end end local function println(message) if not fp_ok then util.println_ts(message) end end
local log_header = "plc_session(" .. id .. "): " local log_tag = "plc_session(" .. id .. "): "
local self = { local self = {
commanded_state = false, commanded_state = false,
@ -184,7 +184,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.sDB.max_op_temp_H2O = max_burn * 2 * (JOULES_PER_MB * heat_cap ^ -1) + BASE_BOIL_TEMP self.sDB.max_op_temp_H2O = max_burn * 2 * (JOULES_PER_MB * heat_cap ^ -1) + BASE_BOIL_TEMP
self.sDB.max_op_temp_Na = max_burn * (JOULES_PER_MB * heat_cap ^ -1) + BASE_BOIL_TEMP self.sDB.max_op_temp_Na = max_burn * (JOULES_PER_MB * heat_cap ^ -1) + BASE_BOIL_TEMP
log.info(util.sprintf(log_header .. "computed maximum operational temperatures %.3fK (H2O) and %.3fK (Na)", log.info(util.sprintf(log_tag .. "computed maximum operational temperatures %.3fK (H2O) and %.3fK (Na)",
self.sDB.max_op_temp_H2O, self.sDB.max_op_temp_Na)) self.sDB.max_op_temp_H2O, self.sDB.max_op_temp_Na))
end end
@ -289,12 +289,12 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
_copy_status(pkt.data[7]) _copy_status(pkt.data[7])
self.received_status_cache = true self.received_status_cache = true
else else
log.error(log_header .. "RPLC status packet reactor data length mismatch") log.error(log_tag .. "RPLC status packet reactor data length mismatch")
end end
end end
end end
else else
log.debug(log_header .. "RPLC status packet invalid") log.debug(log_tag .. "RPLC status packet invalid")
end end
end end
@ -341,7 +341,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
if pkt.length == 1 then if pkt.length == 1 then
return pkt.data[1] return pkt.data[1]
else else
log.debug(log_header .. "RPLC ACK length mismatch") log.debug(log_tag .. "RPLC ACK length mismatch")
return nil return nil
end end
end end
@ -351,7 +351,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
local function _handle_packet(pkt) local function _handle_packet(pkt)
-- check sequence number -- check sequence number
if self.r_seq_num ~= pkt.scada_frame.seq_num() then if self.r_seq_num ~= pkt.scada_frame.seq_num() then
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) log.warning(log_tag .. "sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
return return
else else
self.r_seq_num = pkt.scada_frame.seq_num() + 1 self.r_seq_num = pkt.scada_frame.seq_num() + 1
@ -362,7 +362,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
---@cast pkt rplc_frame ---@cast pkt rplc_frame
-- check reactor ID -- check reactor ID
if pkt.id ~= reactor_id then if pkt.id ~= reactor_id then
log.warning(log_header .. "discarding RPLC packet with ID not matching reactor ID: reactor " .. reactor_id .. " != " .. pkt.id) log.warning(log_tag .. "discarding RPLC packet with ID not matching reactor ID: reactor " .. reactor_id .. " != " .. pkt.id)
return return
end end
@ -375,7 +375,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
if pkt.length >= 5 then if pkt.length >= 5 then
_handle_status(pkt) _handle_status(pkt)
else else
log.debug(log_header .. "RPLC status packet length mismatch") log.debug(log_tag .. "RPLC status packet length mismatch")
end end
elseif pkt.type == RPLC_TYPE.MEK_STRUCT then elseif pkt.type == RPLC_TYPE.MEK_STRUCT then
-- received reactor structure, record it -- received reactor structure, record it
@ -385,7 +385,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.received_struct = true self.received_struct = true
out_queue.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, reactor_id) out_queue.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, reactor_id)
else else
log.debug(log_header .. "RPLC struct packet length mismatch") log.debug(log_tag .. "RPLC struct packet length mismatch")
end end
elseif pkt.type == RPLC_TYPE.MEK_BURN_RATE then elseif pkt.type == RPLC_TYPE.MEK_BURN_RATE then
-- burn rate acknowledgement -- burn rate acknowledgement
@ -393,7 +393,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
if ack then if ack then
self.acks.burn_rate = true self.acks.burn_rate = true
elseif ack == false then elseif ack == false then
log.debug(log_header .. "burn rate update failed!") log.debug(log_tag .. "burn rate update failed!")
end end
-- send acknowledgement to coordinator -- send acknowledgement to coordinator
@ -408,7 +408,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
if ack then if ack then
self.sDB.control_state = true self.sDB.control_state = true
elseif ack == false then elseif ack == false then
log.debug(log_header .. "enable failed!") log.debug(log_tag .. "enable failed!")
end end
-- send acknowledgement to coordinator -- send acknowledgement to coordinator
@ -424,7 +424,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.acks.disable = true self.acks.disable = true
self.sDB.control_state = false self.sDB.control_state = false
elseif ack == false then elseif ack == false then
log.debug(log_header .. "disable failed!") log.debug(log_tag .. "disable failed!")
end end
elseif pkt.type == RPLC_TYPE.RPS_SCRAM then elseif pkt.type == RPLC_TYPE.RPS_SCRAM then
-- manual SCRAM acknowledgement -- manual SCRAM acknowledgement
@ -433,7 +433,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.acks.scram = true self.acks.scram = true
self.sDB.control_state = false self.sDB.control_state = false
elseif ack == false then elseif ack == false then
log.debug(log_header .. "manual SCRAM failed!") log.debug(log_tag .. "manual SCRAM failed!")
end end
-- send acknowledgement to coordinator -- send acknowledgement to coordinator
@ -449,7 +449,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.acks.ascram = true self.acks.ascram = true
self.sDB.control_state = false self.sDB.control_state = false
elseif ack == false then elseif ack == false then
log.debug(log_header .. " automatic SCRAM failed!") log.debug(log_tag .. " automatic SCRAM failed!")
end end
elseif pkt.type == RPLC_TYPE.RPS_STATUS then elseif pkt.type == RPLC_TYPE.RPS_STATUS then
-- RPS status packet received, copy data -- RPS status packet received, copy data
@ -459,10 +459,10 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
-- copied in RPS status data OK -- copied in RPS status data OK
else else
-- error copying RPS status data -- error copying RPS status data
log.error(log_header .. "failed to parse RPS status packet data") log.error(log_tag .. "failed to parse RPS status packet data")
end end
else else
log.debug(log_header .. "RPLC RPS status packet length mismatch") log.debug(log_tag .. "RPLC RPS status packet length mismatch")
end end
elseif pkt.type == RPLC_TYPE.RPS_ALARM then elseif pkt.type == RPLC_TYPE.RPS_ALARM then
-- RPS alarm -- RPS alarm
@ -472,10 +472,10 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
-- copied in RPS status data OK -- copied in RPS status data OK
else else
-- error copying RPS status data -- error copying RPS status data
log.error(log_header .. "failed to parse RPS alarm status data") log.error(log_tag .. "failed to parse RPS alarm status data")
end end
else else
log.debug(log_header .. "RPLC RPS alarm packet length mismatch") log.debug(log_tag .. "RPLC RPS alarm packet length mismatch")
end end
elseif pkt.type == RPLC_TYPE.RPS_RESET then elseif pkt.type == RPLC_TYPE.RPS_RESET then
-- RPS reset acknowledgement -- RPS reset acknowledgement
@ -485,7 +485,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.sDB.rps_tripped = false self.sDB.rps_tripped = false
self.sDB.rps_trip_cause = "ok" self.sDB.rps_trip_cause = "ok"
elseif ack == false then elseif ack == false then
log.debug(log_header .. "RPS reset failed") log.debug(log_tag .. "RPS reset failed")
end end
-- send acknowledgement to coordinator -- send acknowledgement to coordinator
@ -498,7 +498,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
-- RPS auto control reset acknowledgement -- RPS auto control reset acknowledgement
local ack = _get_ack(pkt) local ack = _get_ack(pkt)
if not ack then if not ack then
log.debug(log_header .. "RPS auto reset failed") log.debug(log_tag .. "RPS auto reset failed")
end end
elseif pkt.type == RPLC_TYPE.AUTO_BURN_RATE then elseif pkt.type == RPLC_TYPE.AUTO_BURN_RATE then
if pkt.length == 1 then if pkt.length == 1 then
@ -506,18 +506,18 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
if ack == PLC_AUTO_ACK.FAIL then if ack == PLC_AUTO_ACK.FAIL then
self.acks.burn_rate = false self.acks.burn_rate = false
log.debug(log_header .. "RPLC automatic burn rate set fail") log.debug(log_tag .. "RPLC automatic burn rate set fail")
elseif ack == PLC_AUTO_ACK.DIRECT_SET_OK or ack == PLC_AUTO_ACK.RAMP_SET_OK or ack == PLC_AUTO_ACK.ZERO_DIS_OK then elseif ack == PLC_AUTO_ACK.DIRECT_SET_OK or ack == PLC_AUTO_ACK.RAMP_SET_OK or ack == PLC_AUTO_ACK.ZERO_DIS_OK then
self.acks.burn_rate = true self.acks.burn_rate = true
else else
self.acks.burn_rate = false self.acks.burn_rate = false
log.debug(log_header .. "RPLC automatic burn rate ack unknown") log.debug(log_tag .. "RPLC automatic burn rate ack unknown")
end end
else else
log.debug(log_header .. "RPLC automatic burn rate ack packet length mismatch") log.debug(log_tag .. "RPLC automatic burn rate ack packet length mismatch")
end end
else else
log.debug(log_header .. "handler received unsupported RPLC packet type " .. pkt.type) log.debug(log_tag .. "handler received unsupported RPLC packet type " .. pkt.type)
end end
elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then
---@cast pkt mgmt_frame ---@cast pkt mgmt_frame
@ -530,7 +530,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
self.last_rtt = srv_now - srv_start self.last_rtt = srv_now - srv_start
if self.last_rtt > 750 then if self.last_rtt > 750 then
log.warning(log_header .. "PLC KEEP_ALIVE round trip time > 750ms (" .. self.last_rtt .. "ms)") log.warning(log_tag .. "PLC KEEP_ALIVE round trip time > 750ms (" .. self.last_rtt .. "ms)")
end end
-- log.debug(log_header .. "PLC RTT = " .. self.last_rtt .. "ms") -- log.debug(log_header .. "PLC RTT = " .. self.last_rtt .. "ms")
@ -538,13 +538,17 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
databus.tx_plc_rtt(reactor_id, self.last_rtt) databus.tx_plc_rtt(reactor_id, self.last_rtt)
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_tag .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == MGMT_TYPE.ESTABLISH then
-- something is wrong, kill the session
_close()
log.warning(log_tag .. "terminated session due to an unexpected ESTABLISH packet")
else else
log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) log.debug(log_tag .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type)
end end
end end
end end
@ -639,7 +643,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
_close() _close()
_send_mgmt(MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println("connection to reactor " .. reactor_id .. " PLC closed by server") println("connection to reactor " .. reactor_id .. " PLC closed by server")
log.info(log_header .. "session closed by server") log.info(log_tag .. "session closed by server")
end end
-- iterate the session -- iterate the session
@ -696,7 +700,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
_send(RPLC_TYPE.RPS_AUTO_RESET, {}) _send(RPLC_TYPE.RPS_AUTO_RESET, {})
end end
else else
log.error(log_header .. "unsupported command received in in_queue (this is a bug)", true) log.error(log_tag .. "unsupported command received in in_queue (this is a bug)", true)
end end
elseif message.qtype == mqueue.TYPE.DATA then elseif message.qtype == mqueue.TYPE.DATA then
-- instruction with body -- instruction with body
@ -745,14 +749,14 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
end end
end end
else else
log.error(log_header .. "unsupported data command received in in_queue (this is a bug)", true) log.error(log_tag .. "unsupported data command received in in_queue (this is a bug)", true)
end end
end end
end end
-- max 100ms spent processing queue -- max 100ms spent processing queue
if util.time() - handle_start > 100 then if util.time() - handle_start > 100 then
log.warning(log_header .. "exceeded 100ms queue process limit") log.warning(log_tag .. "exceeded 100ms queue process limit")
break break
end end
end end
@ -760,7 +764,7 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue,
-- exit if connection was closed -- exit if connection was closed
if not self.connected then if not self.connected then
println("connection to reactor " .. reactor_id .. " PLC closed by remote host") println("connection to reactor " .. reactor_id .. " PLC closed by remote host")
log.info(log_header .. "session closed by remote host") log.info(log_tag .. "session closed by remote host")
return self.connected return self.connected
end end

View File

@ -40,7 +40,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
-- print a log message to the terminal as long as the UI isn't running -- print a log message to the terminal as long as the UI isn't running
local function println(message) if not fp_ok then util.println_ts(message) end end local function println(message) if not fp_ok then util.println_ts(message) end end
local log_header = "pdg_session(" .. id .. "): " local log_tag = "pdg_session(" .. id .. "): "
local self = { local self = {
-- connection properties -- connection properties
@ -95,7 +95,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
local function _handle_packet(pkt) local function _handle_packet(pkt)
-- check sequence number -- check sequence number
if self.r_seq_num ~= pkt.scada_frame.seq_num() then if self.r_seq_num ~= pkt.scada_frame.seq_num() then
log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) log.warning(log_tag .. "sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
return return
else else
self.r_seq_num = pkt.scada_frame.seq_num() + 1 self.r_seq_num = pkt.scada_frame.seq_num() + 1
@ -116,7 +116,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
self.last_rtt = srv_now - srv_start self.last_rtt = srv_now - srv_start
if self.last_rtt > 750 then if self.last_rtt > 750 then
log.warning(log_header .. "PDG KEEP_ALIVE round trip time > 750ms (" .. self.last_rtt .. "ms)") log.warning(log_tag .. "PDG KEEP_ALIVE round trip time > 750ms (" .. self.last_rtt .. "ms)")
end end
-- log.debug(log_header .. "PDG RTT = " .. self.last_rtt .. "ms") -- log.debug(log_header .. "PDG RTT = " .. self.last_rtt .. "ms")
@ -124,11 +124,15 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
databus.tx_pdg_rtt(id, self.last_rtt) databus.tx_pdg_rtt(id, self.last_rtt)
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_tag .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == MGMT_TYPE.ESTABLISH then
-- something is wrong, kill the session
_close()
log.warning(log_tag .. "terminated session due to an unexpected ESTABLISH packet")
elseif pkt.type == MGMT_TYPE.DIAG_TONE_GET then elseif pkt.type == MGMT_TYPE.DIAG_TONE_GET then
-- get the state of alarm tones -- get the state of alarm tones
_send_mgmt(MGMT_TYPE.DIAG_TONE_GET, facility.get_alarm_tones()) _send_mgmt(MGMT_TYPE.DIAG_TONE_GET, facility.get_alarm_tones())
@ -145,13 +149,13 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
local allow_testing, test_tone_states = facility.diag_set_test_tone(pkt.data[1], pkt.data[2]) local allow_testing, test_tone_states = facility.diag_set_test_tone(pkt.data[1], pkt.data[2])
_send_mgmt(MGMT_TYPE.DIAG_TONE_SET, { allow_testing, test_tone_states }) _send_mgmt(MGMT_TYPE.DIAG_TONE_SET, { allow_testing, test_tone_states })
else else
log.debug(log_header .. "SCADA diag tone set packet data type mismatch") log.debug(log_tag .. "SCADA diag tone set packet data type mismatch")
end end
else else
log.debug(log_header .. "SCADA diag tone set packet length mismatch") log.debug(log_tag .. "SCADA diag tone set packet length mismatch")
end end
else else
log.debug(log_header .. "DIAG_TONE_SET is blocked without HMAC for security") log.debug(log_tag .. "DIAG_TONE_SET is blocked without HMAC for security")
end end
if not valid then _send_mgmt(MGMT_TYPE.DIAG_TONE_SET, { false }) end if not valid then _send_mgmt(MGMT_TYPE.DIAG_TONE_SET, { false }) end
@ -168,18 +172,18 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
local allow_testing, test_alarm_states = facility.diag_set_test_alarm(pkt.data[1], pkt.data[2]) local allow_testing, test_alarm_states = facility.diag_set_test_alarm(pkt.data[1], pkt.data[2])
_send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { allow_testing, test_alarm_states }) _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { allow_testing, test_alarm_states })
else else
log.debug(log_header .. "SCADA diag alarm set packet data type mismatch") log.debug(log_tag .. "SCADA diag alarm set packet data type mismatch")
end end
else else
log.debug(log_header .. "SCADA diag alarm set packet length mismatch") log.debug(log_tag .. "SCADA diag alarm set packet length mismatch")
end end
else else
log.debug(log_header .. "DIAG_ALARM_SET is blocked without HMAC for security") log.debug(log_tag .. "DIAG_ALARM_SET is blocked without HMAC for security")
end end
if not valid then _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { false }) end if not valid then _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { false }) end
else else
log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) log.debug(log_tag .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type)
end end
end end
end end
@ -205,7 +209,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
_close() _close()
_send_mgmt(MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println("connection to pocket diag session " .. id .. " closed by server") println("connection to pocket diag session " .. id .. " closed by server")
log.info(log_header .. "session closed by server") log.info(log_tag .. "session closed by server")
end end
-- iterate the session -- iterate the session
@ -236,7 +240,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
-- max 100ms spent processing queue -- max 100ms spent processing queue
if util.time() - handle_start > 100 then if util.time() - handle_start > 100 then
log.warning(log_header .. "exceeded 100ms queue process limit") log.warning(log_tag .. "exceeded 100ms queue process limit")
break break
end end
end end
@ -244,7 +248,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout,
-- exit if connection was closed -- exit if connection was closed
if not self.connected then if not self.connected then
println("connection to pocket diag session " .. id .. " closed by remote host") println("connection to pocket diag session " .. id .. " closed by remote host")
log.info(log_header .. "session closed by remote host") log.info(log_tag .. "session closed by remote host")
return self.connected return self.connected
end end

View File

@ -242,7 +242,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad
local function _handle_packet(pkt) local function _handle_packet(pkt)
-- check sequence number -- check sequence number
if self.r_seq_num ~= pkt.scada_frame.seq_num() then if self.r_seq_num ~= pkt.scada_frame.seq_num() then
log.warning(log_tag .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) log.warning(log_tag .. "sequence out-of-order: next = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num())
return return
else else
self.r_seq_num = pkt.scada_frame.seq_num() + 1 self.r_seq_num = pkt.scada_frame.seq_num() + 1
@ -283,6 +283,10 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad
elseif pkt.type == MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == MGMT_TYPE.ESTABLISH then
-- something is wrong, kill the session
_close()
log.warning(log_tag .. "terminated session due to an unexpected ESTABLISH packet")
elseif pkt.type == MGMT_TYPE.RTU_ADVERT then elseif pkt.type == MGMT_TYPE.RTU_ADVERT then
-- RTU advertisement -- RTU advertisement
log.debug(log_tag .. "received updated advertisement") log.debug(log_tag .. "received updated advertisement")

View File

@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.5.0" local SUPERVISOR_VERSION = "v1.5.1"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts