Skip to content

Commit b7c5d90

Browse files
Merge branch 'master' of github.com:ZoneMinder/zoneminder
2 parents 931bc2c + 2ffab6b commit b7c5d90

File tree

10 files changed

+489
-224
lines changed

10 files changed

+489
-224
lines changed

src/zm_monitor_onvif.cpp

Lines changed: 131 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,10 @@ ONVIF::~ONVIF() {
8686
_wsnt__UnsubscribeResponse wsnt__UnsubscribeResponse;
8787

8888
bool use_wsa = parent->soap_wsa_compl;
89-
const char *RequestMessageID = nullptr;
9089

9190
if (use_wsa) {
92-
RequestMessageID = soap_wsa_rand_uuid(soap);
93-
if (soap_wsa_request(soap, RequestMessageID, response.SubscriptionReference.Address, "UnsubscribeRequest") == SOAP_OK) {
94-
Debug(2, "ONVIF: WS-Addressing headers set for Unsubscribe");
91+
if (do_wsa_request(response.SubscriptionReference.Address, "UnsubscribeRequest")) {
9592
proxyEvent.Unsubscribe(response.SubscriptionReference.Address, nullptr, &wsnt__Unsubscribe, wsnt__UnsubscribeResponse);
96-
} else {
97-
Error("ONVIF: Couldn't set WS-Addressing headers for Unsubscribe. RequestMessageID=%s; TO=%s; Request=UnsubscribeRequest. Error %i %s, %s",
98-
RequestMessageID, response.SubscriptionReference.Address, soap->error, soap_fault_string(soap), soap_fault_detail(soap));
9993
}
10094
} else {
10195
// No WS-Addressing, just unsubscribe
@@ -154,20 +148,14 @@ void ONVIF::start() {
154148
// Try to create subscription with digest authentication first
155149
set_credentials(soap);
156150

157-
const char *RequestMessageID = nullptr;
158151
bool use_wsa = parent->soap_wsa_compl;
159152

160-
if (use_wsa) {
161-
RequestMessageID = soap_wsa_rand_uuid(soap);
162-
if (soap_wsa_request(soap, RequestMessageID, proxyEvent.soap_endpoint, "CreatePullPointSubscriptionRequest") != SOAP_OK) {
163-
Error("ONVIF: Couldn't set WS-Addressing headers. RequestMessageID=%s; TO=%s; Request=CreatePullPointSubscriptionRequest. Error %i %s, %s",
164-
RequestMessageID, proxyEvent.soap_endpoint, soap->error, soap_fault_string(soap), soap_fault_detail(soap));
165-
soap_destroy(soap);
166-
soap_end(soap);
167-
soap_free(soap);
168-
soap = nullptr;
169-
return;
170-
}
153+
if (use_wsa && !do_wsa_request(proxyEvent.soap_endpoint, "CreatePullPointSubscriptionRequest")) {
154+
soap_destroy(soap);
155+
soap_end(soap);
156+
soap_free(soap);
157+
soap = nullptr;
158+
return;
171159
}
172160

173161
Debug(1, "ONVIF: Creating PullPoint subscription at endpoint: %s", proxyEvent.soap_endpoint);
@@ -198,15 +186,10 @@ void ONVIF::start() {
198186
// Set credentials with plain auth
199187
set_credentials(soap);
200188

201-
if (use_wsa) {
202-
RequestMessageID = soap_wsa_rand_uuid(soap);
203-
if (soap_wsa_request(soap, RequestMessageID, proxyEvent.soap_endpoint, "CreatePullPointSubscriptionRequest") != SOAP_OK) {
204-
Error("ONVIF: Couldn't set WS-Addressing headers on retry. RequestMessageID=%s; TO=%s",
205-
RequestMessageID, proxyEvent.soap_endpoint);
206-
soap_free(soap);
207-
soap = nullptr;
208-
return;
209-
}
189+
if (use_wsa && !do_wsa_request(proxyEvent.soap_endpoint, "CreatePullPointSubscriptionRequest")) {
190+
soap_free(soap);
191+
soap = nullptr;
192+
return;
210193
}
211194

212195
rc = proxyEvent.CreatePullPointSubscription(&request, response);
@@ -287,15 +270,9 @@ void ONVIF::start() {
287270
//Empty the stored messages
288271
set_credentials(soap);
289272

290-
if (use_wsa) {
291-
RequestMessageID = soap_wsa_rand_uuid(soap);
292-
if (soap_wsa_request(soap, RequestMessageID, response.SubscriptionReference.Address, "PullMessageRequest") != SOAP_OK) {
293-
Error("ONVIF: Couldn't set WS-Addressing headers for initial pull. RequestMessageID=%s; TO=%s; Request=PullMessageRequest. Error %i %s, %s",
294-
RequestMessageID, response.SubscriptionReference.Address, soap->error, soap_fault_string(soap), soap_fault_detail(soap));
295-
healthy = false;
296-
return;
297-
}
298-
Debug(2, "ONVIF: WS-Addressing headers set for initial pull");
273+
if (use_wsa && !do_wsa_request(response.SubscriptionReference.Address, "PullMessageRequest")) {
274+
healthy = false;
275+
return;
299276
}
300277

301278
if ((proxyEvent.PullMessages(response.SubscriptionReference.Address, nullptr, &tev__PullMessages, tev__PullMessagesResponse) != SOAP_OK) &&
@@ -308,36 +285,11 @@ void ONVIF::start() {
308285
healthy = true;
309286
}
310287

311-
// we renew the current subscription .........
312-
if (use_wsa) {
313-
set_credentials(soap);
314-
RequestMessageID = soap_wsa_rand_uuid(soap);
315-
if (soap_wsa_request(soap, RequestMessageID, response.SubscriptionReference.Address, "RenewRequest") == SOAP_OK) {
316-
Debug(2, "ONVIF: WS-Addressing headers set for Renew");
317-
if (proxyEvent.Renew(response.SubscriptionReference.Address, nullptr, &wsnt__Renew, wsnt__RenewResponse) != SOAP_OK) {
318-
Error("ONVIF: Couldn't do initial Renew ! Error %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
319-
if (soap->error==12) {//ActionNotSupported
320-
healthy = true;
321-
} else {
322-
healthy = false;
323-
}
324-
} else {
325-
Debug(2, "ONVIF: Good Initial Renew %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
326-
healthy = true;
327-
// Update renewal times from initial renew response
328-
if (wsnt__RenewResponse.TerminationTime != 0) {
329-
update_renewal_times(wsnt__RenewResponse.TerminationTime);
330-
}
331-
}
332-
} else {
333-
Error("ONVIF: Couldn't set WS-Addressing headers for Renew. RequestMessageID=%s; TO=%s; Request=RenewRequest Error %i %s, %s",
334-
RequestMessageID,
335-
response.SubscriptionReference.Address,
336-
soap->error,
337-
soap_fault_string(soap),
338-
soap_fault_detail(soap));
339-
healthy = false;
340-
} // end renew
288+
// Perform initial renewal of the subscription
289+
if (use_wsa) { // Only if WS-Addressing is enabled
290+
if (!Renew()) {
291+
Debug(1, "ONVIF: Initial renewal failed, but continuing");
292+
}
341293
}
342294
} // end else (success block)
343295
#else
@@ -349,17 +301,12 @@ void ONVIF::WaitForMessage() {
349301
#ifdef WITH_GSOAP
350302
set_credentials(soap);
351303

352-
const char *RequestMessageID = nullptr;
353304
bool use_wsa = parent->soap_wsa_compl;
354305

355306
if (use_wsa) {
356-
RequestMessageID = soap_wsa_rand_uuid(soap);
357-
if (soap_wsa_request(soap, RequestMessageID, response.SubscriptionReference.Address, "PullMessageRequest") != SOAP_OK) {
358-
Error("ONVIF: Couldn't set WS-Addressing headers. RequestMessageID=%s; TO=%s; Request=PullMessageRequest. Error %i %s, %s",
359-
RequestMessageID, response.SubscriptionReference.Address, soap->error, soap_fault_string(soap), soap_fault_detail(soap));
307+
if (!do_wsa_request(response.SubscriptionReference.Address, "PullMessageRequest")) {
360308
return;
361309
}
362-
Debug(2, "ONVIF: WS-Addressing headers set successfully");
363310
} else {
364311
Debug(2, "ONVIF: WS-Addressing disabled, not sending addressing headers");
365312
}
@@ -567,77 +514,12 @@ void ONVIF::WaitForMessage() {
567514
} // end foreach msg
568515
} // end scope for lock
569516

570-
// Check if renewal is needed (only renew 10 seconds before termination)
571-
SystemTimePoint now = std::chrono::system_clock::now();
572-
bool renewal_needed = false;
573-
574-
// Check if we have valid renewal times set
575-
if (!is_renewal_tracking_initialized()) {
576-
// No renewal tracking set up yet, always renew (backward compatibility)
577-
Debug(2, "ONVIF: No renewal tracking initialized, performing renewal");
578-
renewal_needed = true;
579-
} else if (now >= next_renewal_time) {
580-
// Time to renew
581-
auto seconds_overdue = std::chrono::duration_cast<std::chrono::seconds>(
582-
now - next_renewal_time).count();
583-
Debug(2, "ONVIF: Subscription renewal needed (overdue by %ld seconds)", seconds_overdue);
584-
renewal_needed = true;
585-
} else {
586-
// Not yet time to renew
587-
auto seconds_until_renewal = std::chrono::duration_cast<std::chrono::seconds>(
588-
next_renewal_time - now).count();
589-
Debug(2, "ONVIF: Subscription renewal not yet needed (renews in %ld seconds)",
590-
seconds_until_renewal);
591-
renewal_needed = false;
592-
}
593-
594-
// Only renew if needed
595-
if (renewal_needed) {
596-
// we renew the current subscription .........
597-
set_credentials(soap);
598-
wsnt__Renew.TerminationTime = &subscription_timeout;
599-
if (use_wsa) {
600-
RequestMessageID = soap_wsa_rand_uuid(soap);
601-
if (soap_wsa_request(soap, RequestMessageID, response.SubscriptionReference.Address, "RenewRequest") == SOAP_OK) {
602-
Debug(2, "ONVIF: WS-Addressing headers set for Renew");
603-
if (proxyEvent.Renew(response.SubscriptionReference.Address, nullptr, &wsnt__Renew, wsnt__RenewResponse) != SOAP_OK) {
604-
Error("ONVIF: Couldn't do Renew! Error %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
605-
if (soap->error==12) {//ActionNotSupported
606-
healthy = true;
607-
} else {
608-
healthy = false;
609-
}
610-
} else {
611-
Debug(2, "ONVIF: Good Renew %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
612-
healthy = true;
613-
// Update renewal times from renew response
614-
if (wsnt__RenewResponse.TerminationTime != 0) {
615-
update_renewal_times(wsnt__RenewResponse.TerminationTime);
616-
}
617-
}
618-
} else {
619-
Error("ONVIF: Couldn't set WS-Addressing headers for Renew. RequestMessageID=%s; TO=%s; Request=RenewRequest. Error %i %s, %s",
620-
RequestMessageID, response.SubscriptionReference.Address, soap->error, soap_fault_string(soap), soap_fault_detail(soap));
621-
healthy = false;
622-
} // end renew
623-
} else {
624-
if (proxyEvent.Renew(response.SubscriptionReference.Address, nullptr, &wsnt__Renew, wsnt__RenewResponse) != SOAP_OK) {
625-
Error("ONVIF: Couldn't do Renew! Error %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
626-
if (soap->error==12) {//ActionNotSupported
627-
healthy = true;
628-
} else {
629-
healthy = false;
630-
}
631-
} else {
632-
Debug(2, "ONVIF: Good Renew %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
633-
healthy = true;
634-
// Update renewal times from renew response
635-
if (wsnt__RenewResponse.TerminationTime != 0) {
636-
update_renewal_times(wsnt__RenewResponse.TerminationTime);
637-
}
638-
}
517+
// Renew subscription if needed
518+
if (IsRenewalNeeded()) {
519+
if (!Renew()) {
520+
Warning("ONVIF: Failed to renew subscription");
639521
}
640-
} // end if renewal_needed
522+
}
641523
} // end if SOAP OK/NOT OK
642524
#endif
643525
return;
@@ -812,6 +694,112 @@ bool ONVIF::is_renewal_tracking_initialized() const {
812694
return next_renewal_time.time_since_epoch().count() != 0;
813695
}
814696

697+
// Perform ONVIF subscription renewal
698+
// Returns true if renewal succeeded or is not supported, false on error
699+
bool ONVIF::Renew() {
700+
#ifdef WITH_GSOAP
701+
set_credentials(soap);
702+
wsnt__Renew.TerminationTime = &subscription_timeout;
703+
704+
bool use_wsa = parent->soap_wsa_compl;
705+
706+
if (use_wsa && !do_wsa_request(response.SubscriptionReference.Address, "RenewRequest")) {
707+
healthy = false;
708+
return false;
709+
}
710+
711+
if (proxyEvent.Renew(response.SubscriptionReference.Address, nullptr, &wsnt__Renew, wsnt__RenewResponse) != SOAP_OK) {
712+
Error("ONVIF: Couldn't do Renew! Error %i %s, %s", soap->error, soap_fault_string(soap), soap_fault_detail(soap));
713+
if (soap->error == 12) { // ActionNotSupported
714+
Debug(2, "ONVIF: Renew not supported by device, continuing without renewal");
715+
healthy = true;
716+
return true; // Not a fatal error
717+
} else {
718+
healthy = false;
719+
return false;
720+
}
721+
}
722+
723+
Debug(2, "ONVIF: Subscription renewed successfully");
724+
healthy = true;
725+
726+
// Update renewal times from renew response
727+
if (wsnt__RenewResponse.TerminationTime != 0) {
728+
update_renewal_times(wsnt__RenewResponse.TerminationTime);
729+
}
730+
731+
return true;
732+
#else
733+
return false;
734+
#endif
735+
}
736+
737+
// Check if subscription renewal is needed
738+
// Returns true if renewal should be performed now, false if not yet needed
739+
bool ONVIF::IsRenewalNeeded() const {
740+
#ifdef WITH_GSOAP
741+
// Check if we have valid renewal times set
742+
if (!is_renewal_tracking_initialized()) {
743+
// No renewal tracking set up yet, always renew (backward compatibility)
744+
Debug(2, "ONVIF: No renewal tracking initialized, performing renewal");
745+
return true;
746+
}
747+
748+
SystemTimePoint now = std::chrono::system_clock::now();
749+
750+
if (now >= next_renewal_time) {
751+
// Time to renew
752+
auto seconds_overdue = std::chrono::duration_cast<std::chrono::seconds>(
753+
now - next_renewal_time).count();
754+
Debug(2, "ONVIF: Subscription renewal needed (overdue by %ld seconds)", seconds_overdue);
755+
return true;
756+
}
757+
758+
// Not yet time to renew
759+
auto seconds_until_renewal = std::chrono::duration_cast<std::chrono::seconds>(
760+
next_renewal_time - now).count();
761+
Debug(2, "ONVIF: Subscription renewal not yet needed (renews in %ld seconds)",
762+
seconds_until_renewal);
763+
return false;
764+
#else
765+
return false;
766+
#endif
767+
}
768+
769+
// Setup WS-Addressing headers for SOAP request
770+
// This helper method encapsulates the common pattern of setting up WS-Addressing
771+
// headers for SOAP requests, eliminating code duplication across the class.
772+
//
773+
// Parameters:
774+
// address - The target endpoint address (TO header)
775+
// action - The SOAP action name for the request
776+
//
777+
// Returns:
778+
// true - WS-Addressing headers were successfully set
779+
// false - Failed to set headers (error logged), or invalid parameters
780+
//
781+
// Note: This method assumes the soap context is already initialized.
782+
bool ONVIF::do_wsa_request(const char* address, const char* action) {
783+
#ifdef WITH_GSOAP
784+
if (!soap || !address || !action) {
785+
Error("ONVIF: Invalid parameters for WS-Addressing request");
786+
return false;
787+
}
788+
789+
const char* RequestMessageID = soap_wsa_rand_uuid(soap);
790+
if (soap_wsa_request(soap, RequestMessageID, address, action) != SOAP_OK) {
791+
Error("ONVIF: Couldn't set WS-Addressing headers. RequestMessageID=%s; TO=%s; Request=%s. Error %i %s, %s",
792+
RequestMessageID, address, action, soap->error, soap_fault_string(soap), soap_fault_detail(soap));
793+
return false;
794+
}
795+
796+
Debug(2, "ONVIF: WS-Addressing headers set for %s", action);
797+
return true;
798+
#else
799+
return false;
800+
#endif
801+
}
802+
815803
//ONVIF Set Credentials
816804
void ONVIF::set_credentials(struct soap *soap) {
817805
soap_wsse_delete_Security(soap);

src/zm_monitor_onvif.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ class ONVIF {
8585
int get_retry_delay(); // Calculate exponential backoff delay
8686
void update_renewal_times(time_t termination_time); // Update subscription renewal tracking times
8787
bool is_renewal_tracking_initialized() const; // Check if renewal tracking has been set up
88+
bool Renew(); // Perform subscription renewal, returns true on success
89+
bool IsRenewalNeeded() const; // Check if subscription renewal is needed now
90+
bool do_wsa_request(const char* address, const char* action); // Setup WS-Addressing headers for SOAP request
8891
#endif
8992
std::unordered_map<std::string, std::string> alarms;
9093
std::mutex alarms_mutex;

web/ajax/event.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
ZM\Debug("No filter");
136136
}
137137

138-
if ( $exportFile = exportEvents(
138+
if ( $exportFile = downloadEvents(
139139
$exportIds,
140140
$exportFileName,
141141
$exportFormat,
@@ -148,7 +148,7 @@
148148
));
149149

150150
} else {
151-
ajaxError('Export Failed');
151+
ajaxError('Download generation Failed');
152152
}
153153
break;
154154
}

0 commit comments

Comments
 (0)