mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-06 09:22:04 -04:00
* fix: schedule ONVIF subscription renewal for short and unreported lifetimes refs #5179 The Beward camera from #5165 grants a 60 second subscription and its RenewResponse carries no TerminationTime. Three things combined so that ZM renewed after every PullMessages that returned messages (61 renewals in 74 seconds of the reporter's log): - The renewal was scheduled a fixed ONVIF_RENEWAL_ADVANCE_SECONDS (60) before termination, which for a 60 second subscription is its creation time. ONVIFNextRenewalTime() now uses the smaller of that advance and half the remaining lifetime. - Renew() only logged a missing TerminationTime and left next_renewal_time in the past. assume_renewal_times() now schedules from the lifetime we asked for, capped at what the camera last granted (ONVIFAssumedLifetime()), so this camera renews every 30 seconds. - IsRenewalNeeded() was only checked after a response carrying messages, so a camera quiet for longer than its subscription was never renewed. It is now also checked after an empty (SOAP_EOF) poll. Since renewal is now checked after every poll, a camera that answers Renew with ActionNotSupported has renewal disabled rather than being asked again on each poll, matching the existing handling of unusable TerminationTimes. Tests cover the renewal time for long, short and very short subscriptions, and the assumed lifetime with no, smaller and larger previously granted lifetimes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: only disable ONVIF renewal for ActionNotSupported, keep sub-second grants refs #5179 Review follow-ups on the renewal scheduling change: - Renew() treated soap->error == 12 as ActionNotSupported, but 12 is gSOAP's generic SOAP_FAULT. With renewal now disabled on that path, a NotAuthorized or InvalidArgVal fault from Renew would have stopped renewal for good while marking the subscription healthy. ONVIFIsActionNotSupported() checks the fault subcode and string for ActionNotSupported (wsa: or ter:); any other fault now takes the existing cleanup and re-subscribe path. - granted_lifetime truncated the remaining time to whole seconds. A termination less than a second away stored 0, which reads as "never reported", so the next Renew without a TerminationTime assumed the full requested 300 seconds. ONVIFGrantedLifetime() rounds up instead. Tests cover ActionNotSupported subcodes and strings against other faults and non-fault results, and the granted lifetime for whole, fractional and sub-second remainders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: count an assumed ONVIF renewal lifetime from the request, not the response refs #5179 When a RenewResponse has no TerminationTime, assume_renewal_times() started the assumed lifetime when the response arrived, but the camera counts it from when it received the request. A slow response pushed the deadline and the next renewal later by the response time: with subscription_timeout=10 and a 6 second response, the camera's deadline was request+10 but the renewal was scheduled for request+11. In absolute renewal mode it also ignored the exact deadline that was sent. Renew() now records the time just before building the request and the deadline it asks for: request time plus subscription_timeout, or the absolute whole-second time it sends. ONVIFAssumedTermination() replaces ONVIFAssumedLifetime() and returns that deadline, capped at request time plus the lifetime the camera last granted. The renewal is scheduled from the request time; if the response arrived after it, it is already due and the next poll renews. Tests cover no, smaller and larger previous grants, an absolute deadline kept exactly, and the slow-response case from review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>