mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-09-13 05:38:05 -04:00
The control daemon filled its log with
failed to decode the reply to CoaxialControlIO.control: malformed JSON
on every lightOn, while the light itself still worked. Three faults in this
module compounding, all mine.
Nothing ever logged out. close() was inherited from Dahua_RPC, which only sets
a flag, so every login abandoned a session. The camera counts connections and
reclaims them slowly, and zmcontrol keeps one object for the life of the daemon
while Dahua_RPC re-logins whenever the camera times the session out - the log
shows that happening every half hour. Each one leaked a slot until the camera
answered global.login with "too many connections!", which it is still doing
here hours later.
login() then made a transient failure permanent. It cleared session and
mask_key up front, so a login that failed left the object with no key. Several
Dahua_RPC callers re-login on error and carry on without checking the result,
so every later command was sent unmasked, came back masked, and failed to
base64-decode. The logged error therefore described the symptom two steps
downstream of the cause and never mentioned the session at all.
So:
- logout() gives the session back, and close() calls it
- login() releases the previous session before taking another
- rpc_call refuses to send on the masked channel with no key, and says the
session is gone rather than emitting an unreadable decode error
- a login refused for "too many connections" is reported as that
global.logout, with no parameters on the ordinary Request channel, confirmed
against the camera's own web bundle rather than guessed.
Tested: 5 new assertions that a Request with no key returns undef and puts
nothing on the wire, while Login, OutsideCmd and the key exchange - which
legitimately have no key yet - are still sent. Perl suite 15 files / 266
assertions.
Not yet verified against the camera: it is still refusing logins with "too many
connections" from the sessions already leaked, so the logout path could not be
exercised end to end. It needs a retry once the camera has reclaimed them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvTCzCbvGt8xKQRNCSA7o8