Skip to content

Conversation

Copy link

Copilot AI commented Dec 5, 2025

Cameras reject CreatePullPointSubscription with SubscribeCreationFailedFault when they hit their concurrent subscription limit (typically 1-5). Stale subscriptions from crashed ZoneMinder sessions don't auto-expire on many cameras, causing persistent failures.

Changes to src/zm_monitor_onvif.cpp

Retry logic with delays

  • Initial 2s delay before first subscription attempt to allow stale subscriptions to expire
  • Retry loop: 3 attempts with 3s delays between failures
  • SOAP context properly reset between retries

Improved fault detection and messaging

  • Detect SubscribeCreationFailedFault in both fault string and detail
  • On detection, log specific guidance: max subscriptions reached, stale subscriptions exist, auto-expiry not supported
  • Error messages include attempt counter (e.g., "attempt 2/3")
  • Bounds checking on SOAP_STRINGS array access (prevents buffer overflow when rc >= 13)

Cleanup fixes

  • Removed invalid unsubscribe attempt on failed subscriptions (was trying to use empty response.SubscriptionReference.Address)

Example flow

// Before: Direct call, fails immediately on stale subscription
proxyEvent.CreatePullPointSubscription(&request, response);  // SOAP_FAULT

// After: Retries with delays
for (attempt = 1; attempt <= 3; attempt++) {
  if (attempt > 1) {
    sleep(3s);  // Allow camera to expire previous subscription
    // Reset SOAP context
  }
  rc = proxyEvent.CreatePullPointSubscription(&request, response);
  if (rc == SOAP_OK) break;
  // Log "SubscribeCreationFailedFault: camera at max subscriptions..."
}

Cameras that work on first attempt see only 2s additional latency. Cameras with subscription conflicts get automatic recovery instead of permanent failure.

Original prompt

Problem

When subscribing to ONVIF events using gsoap's CreatePullPointSubscription, some cameras fail with the fault wsnt:SubscribeCreationFailedFault. This typically occurs when:

  1. The camera has reached its maximum number of concurrent pull point subscriptions - Most cameras have a limit (often 1-5) on concurrent subscriptions
  2. Stale subscriptions from previous sessions weren't properly cleaned up - If ZoneMinder crashes or exits unexpectedly, subscriptions remain on the camera
  3. The camera doesn't automatically expire old subscriptions - Some cameras don't respect the TerminationTime parameter

Current Behavior

In src/zm_monitor_onvif.cpp, the start() method (lines 74-199):

  • Directly calls CreatePullPointSubscription without checking for existing subscriptions
  • When subscription fails, attempts to unsubscribe using response.SubscriptionReference.Address which is invalid/empty on failure (lines 125-127)
  • Cleans up the local soap context but doesn't attempt to remove stale subscriptions from the camera

Solution Requirements

Implement a robust subscription management system that:

  1. Before creating a new subscription, attempt to clean up any stale subscriptions on the camera
  2. Add retry logic - If CreatePullPointSubscription fails with SubscribeCreationFailedFault:
    • Wait a short delay (e.g., 2-5 seconds)
    • Retry the subscription attempt (up to 2-3 times)
  3. Improve error handling - Provide more detailed logging about subscription failures
  4. Track subscription state - Store subscription reference addresses to enable proper cleanup

Implementation Details

Changes needed in src/zm_monitor_onvif.cpp:

  1. In the ONVIF class (header in src/zm_monitor.h lines 330-363):

    • Add a method to attempt cleanup of stale subscriptions: void cleanup_stale_subscriptions()
    • Add retry logic with configurable attempts and delay
  2. In the start() method:

    • Before calling CreatePullPointSubscription, add a small delay to allow any previous subscription to expire
    • Wrap the subscription call in a retry loop (2-3 attempts with 2-5 second delays between attempts)
    • Detect specific SubscribeCreationFailedFault and provide better error messages
    • On failure, suggest potential causes to the user (max subscriptions reached, credentials issue, etc.)
  3. Error Detection:

    • Check soap_fault_detail(soap) for specific ONVIF fault codes
    • Differentiate between SubscribeCreationFailedFault and other errors
    • Log the specific fault subcode if available

Key Code Locations

File: src/zm_monitor_onvif.cpp

  • Line 97: proxyEvent.CreatePullPointSubscription(&request, response) - Add retry wrapper here
  • Lines 106-131: Error handling - Improve to detect specific faults
  • Lines 125-127: Fix invalid unsubscribe attempt on failed subscription

File: src/zm_monitor.h

  • Lines 338-348: ONVIF class private members - Add subscription tracking
  • Lines 352-363: ONVIF class public methods - Add cleanup method declaration

Testing Considerations

The solution should:

  • Not break existing working ONVIF subscriptions
  • Gracefully handle cameras that don't have the subscription limit issue
  • Provide clear error messages to help diagnose camera-specific issues
  • Not introduce excessive delays for cameras that work on the first attempt (keep initial retry delay reasonable, e.g., 2 seconds)

Additional Notes

  • The ONVIF specification doesn't provide a standard way to list all subscriptions without knowing their addresses
  • The best approach is to add retry logic with delays, allowing old subscriptions to expire
  • Some cameras may require a 10-60 second delay before accepting a new subscription after the previous one ends
  • Consider making retry attempts and delays configurable via Monitor settings in the future

This pull request was created as a result of the following prompt from Copilot chat.

Problem

When subscribing to ONVIF events using gsoap's CreatePullPointSubscription, some cameras fail with the fault wsnt:SubscribeCreationFailedFault. This typically occurs when:

  1. The camera has reached its maximum number of concurrent pull point subscriptions - Most cameras have a limit (often 1-5) on concurrent subscriptions
  2. Stale subscriptions from previous sessions weren't properly cleaned up - If ZoneMinder crashes or exits unexpectedly, subscriptions remain on the camera
  3. The camera doesn't automatically expire old subscriptions - Some cameras don't respect the TerminationTime parameter

Current Behavior

In src/zm_monitor_onvif.cpp, the start() method (lines 74-199):

  • Directly calls CreatePullPointSubscription without checking for existing subscriptions
  • When subscription fails, attempts to unsubscribe using response.SubscriptionReference.Address which is invalid/empty on failure (lines 125-127)
  • Cleans up the local soap context but doesn't attempt to remove stale subscriptions from the camera

Solution Requirements

Implement a robust subscription management system that:

  1. Before creating a new subscription, attempt to clean up any stale subscriptions on the camera
  2. Add retry logic - If CreatePullPointSubscription fails with SubscribeCreationFailedFault:
    • Wait a short delay (e.g., 2-5 seconds)
    • Retry the subscription attempt (up to 2-3 times)
  3. Improve error handling - Provide more detailed logging about subscription failures
  4. Track subscription state - Store subscription reference addresses to enable proper cleanup

Implementation Details

Changes needed in src/zm_monitor_onvif.cpp:

  1. In the ONVIF class (header in src/zm_monitor.h lines 330-363):

    • Add a method to attempt cleanup of stale subscriptions: void cleanup_stale_subscriptions()
    • Add retry logic with configurable attempts and delay
  2. In the start() method:

    • Before calling CreatePullPointSubscription, add a small delay to allow any previous subscription to expire
    • Wrap the subscription call in a retry loop (2-3 attempts with 2-5 second delays between attempts)
    • Detect specific SubscribeCreationFailedFault and provide better error messages
    • On failure, suggest potential causes to the user (max subscriptions reached, credentials issue, etc.)
  3. Error Detection:

    • Check soap_fault_detail(soap) for specific ONVIF fault codes
    • Differentiate between SubscribeCreationFailedFault and other errors
    • Log the specific fault subcode if available

Key Code Locations

File: src/zm_monitor_onvif.cpp

  • Line 97: proxyEvent.CreatePullPointSubscription(&request, response) - Add retry wrapper here
  • Lines 106-131: Error handling - Improve to detect specific faults
  • Lines 125-127: Fix invalid unsubscribe attempt on failed subscription

File: src/zm_monitor.h

  • Lines 338-348: ONVIF class private members - Add subscription tracking
  • Lines 352-363: ONVIF class public methods - Add cleanup method declaration

Testing Considerations

The solution should:

  • Not break existing working ONVIF subscriptions
  • Gracefully handle cameras that don't have the subscription limit issue
  • Provide clear error messages to help diagnose camera-specific issues
  • Not introduce excessive delays for cameras that work on the first attempt (keep initial retry delay reasonable, e.g., 2 seconds)

Additional Notes

  • The ONVIF specification doesn't provide a standard way to list all subscriptions without knowing their addresses
  • The best approach is to add retry logic with delays, allowing old subscriptions to expire
  • Some cameras may require a 10-60 second delay before accepting a new subscription after the previous one ends
  • Consider making retry attempts and delays configurable via Monitor settings in the future

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 4 commits December 5, 2025 18:45
Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
… search

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix subscription failures in CreatePullPointSubscription Add retry logic for ONVIF CreatePullPointSubscription failures Dec 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants