diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm index 64e284278..e50449927 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm @@ -51,11 +51,21 @@ sub open { my $self = shift; $self->loadMonitor(); - if ( $self->{Monitor}->{ControlAddress} !~ /^\w+:\/\// ) { - # Has no scheme at the beginning, so won't parse as a URI - $self->{Monitor}->{ControlAddress} = 'http://'.$self->{Monitor}->{ControlAddress}; - } - $uri = URI->new($self->{Monitor}->{ControlAddress}); + + if ($self->{Monitor}->{ControlAddress} and ($self->{Monitor}->{ControlAddress} ne 'user:pass@ip')) { + Debug("Getting connection details from Control Address " . $self->{Monitor}->{ControlAddress}); + if ( $self->{Monitor}->{ControlAddress} !~ /^\w+:\/\// ) { + # Has no scheme at the beginning, so won't parse as a URI + $self->{Monitor}->{ControlAddress} = 'http://'.$self->{Monitor}->{ControlAddress}; + } + $uri = URI->new($self->{Monitor}->{ControlAddress}); + } elsif ($self->{Monitor}->{Path}) { + Debug("Getting connection details from Path " . $self->{Monitor}->{Path}); + $uri = URI->new($self->{Monitor}->{Path}); + $uri->scheme('http'); + $uri->port(80); + $uri->path(''); + } use LWP::UserAgent; $self->{ua} = LWP::UserAgent->new; @@ -64,6 +74,7 @@ sub open { $self->{state} = 'closed'; my ( $username, $password, $host ) = ( $uri->authority() =~ /^([^:]+):([^@]*)@(.+)$/ ); + Debug("Have username: $username password: $password host: $host from authority:" . $uri->authority()); $uri->userinfo(undef); @@ -75,40 +86,47 @@ sub open { # test auth my $res = $self->{ua}->get($uri->canonical().$url); - if ( $res->is_success ) { - if ( $res->content() ne "Properties.PTZ.PTZ=yes\n" ) { + if ($res->is_success) { + if ($res->content() ne "Properties.PTZ.PTZ=yes\n") { Warning('Response suggests that camera doesn\'t support PTZ. Content:('.$res->content().')'); } $self->{state} = 'open'; return; } + if ($res->status_line() eq '404 Not Found') { + #older style + $url = 'axis-cgi/com/ptz.cgi'; + $res = $self->{ua}->get($uri->canonical().$url); + Debug("Result from getting ".$uri->canonical().$url . ':' . $res->status_line()); + } - if ( $res->status_line() eq '401 Unauthorized' ) { - + if ($res->status_line() eq '401 Unauthorized') { my $headers = $res->headers(); foreach my $k ( keys %$headers ) { Debug("Initial Header $k => $$headers{$k}"); } if ( $$headers{'www-authenticate'} ) { - my ( $auth, $tokens ) = $$headers{'www-authenticate'} =~ /^(\w+)\s+(.*)$/; - if ( $tokens =~ /\w+="([^"]+)"/i ) { - if ( $realm ne $1 ) { - $realm = $1; - $self->{ua}->credentials($uri->host_port(), $realm, $username, $password); - $res = $self->{ua}->get($uri->canonical().$url); - if ( $res->is_success() ) { - Info("Auth succeeded after setting realm to $realm. You can set this value in the Control Device field to speed up connections and remove these log entries."); - $self->{state} = 'open'; - return; + foreach my $auth_header ( ref $$headers{'www-authenticate'} eq 'ARRAY' ? @{$$headers{'www-authenticate'}} : ($$headers{'www-authenticate'})) { + my ( $auth, $tokens ) = $auth_header =~ /^(\w+)\s+(.*)$/; + if ( $tokens =~ /\w+="([^"]+)"/i ) { + if ( $realm ne $1 ) { + $realm = $1; + $self->{ua}->credentials($uri->host_port(), $realm, $username, $password); + $res = $self->{ua}->get($uri->canonical().$url); + if ( $res->is_success() ) { + Info("Auth succeeded after setting realm to $realm. You can set this value in the Control Device field to speed up connections and remove these log entries."); + $self->{state} = 'open'; + return; + } + Error('Authentication still failed after updating REALM status: '.$res->status_line); + } else { + Error('Authentication failed, not a REALM problem'); } - Error('Authentication still failed after updating REALM status: '.$res->status_line); } else { - Error('Authentication failed, not a REALM problem'); - } - } else { - Error('Failed to match realm in tokens'); - } # end if + Error('Failed to match realm in tokens'); + } # end if + } # end foreach auth header } else { Debug('No headers line'); } # end if headers diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 7b3efad46..726685a7e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -413,12 +413,10 @@ sub Sql { $sql .= ' LIMIT 0,'.$filter_expr->{limit}; } if ($$self{LockRows}) { - $sql .= ' FOR UPDATE OF E' - } else { - $sql .= ' FOR SHARE OF E' - } - if ($filter_expr->{skip_locked}) { - $sql .= ' SKIP LOCKED'; + $sql .= ' FOR UPDATE'; + if ($filter_expr->{skip_locked}) { + $sql .= ' SKIP LOCKED'; + } } $self->{Sql} = $sql; } # end if has Sql diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index 5646fb897..d179534d4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -241,20 +241,26 @@ sub control { my $command = shift; my $process = shift; - if ( $command eq 'stop' or $command eq 'restart' ) { - if ( $process ) { - `/usr/bin/zmdc.pl stop $process -m $$monitor{Id}`; + if ($command eq 'stop' or $command eq 'restart') { + if ($process) { + ZoneMinder::General::runCommand("zmdc.pl stop $process -m $$monitor{Id}"); } else { - `/usr/bin/zmdc.pl stop zma -m $$monitor{Id}`; - `/usr/bin/zmdc.pl stop zmc -m $$monitor{Id}`; + if ($monitor->{Type} eq 'Local') { + ZoneMinder::General::runCommand('zmdc.pl stop zmc -d '.$monitor->{Device}); + } else { + ZoneMinder::General::runCommand('zmdc.pl stop zmc -m '.$monitor->{Id}); + } } } if ( $command eq 'start' or $command eq 'restart' ) { if ( $process ) { - `/usr/bin/zmdc.pl start $process -m $$monitor{Id}`; + ZoneMinder::General::runCommand("zmdc.pl start $process -m $$monitor{Id}"); } else { - `/usr/bin/zmdc.pl start zmc -m $$monitor{Id}`; - `/usr/bin/zmdc.pl start zma -m $$monitor{Id}`; + if ($monitor->{Type} eq 'Local') { + ZoneMinder::General::runCommand('zmdc.pl start zmc -d '.$monitor->{Device}); + } else { + ZoneMinder::General::runCommand('zmdc.pl start zmc -m '.$monitor->{Id}); + } } # end if } } # end sub control diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index fd927020f..c0cdf7235 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -1048,7 +1048,7 @@ sub executeCommand { Error("Command '$command' exited with status: $status"); return 0; } else { - zmSQLExecute('UPDATE `Events` SET `Executed` = 1 WHERE `Id` = ?', $Event->{Id}); + ZoneMinder::Database::zmSQLExecute('UPDATE `Events` SET `Executed` = 1 WHERE `Id` = ?', $Event->{Id}); } return 1; } diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 96235ccd3..1b4790bce 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -56,6 +56,7 @@ use constant START_DELAY => 30; # To give everything else time to start @EXTRA_PERL_LIB@ use ZoneMinder; use ZoneMinder::Storage; +use ZoneMinder::Monitor; use POSIX; use DBI; use autouse 'Data::Dumper'=>qw(Dumper); @@ -80,91 +81,75 @@ Info('Watchdog starting, pausing for '.START_DELAY.' seconds'); sleep(START_DELAY); my $dbh = zmDbConnect(); -my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors'; -my $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); while (!$zm_terminate) { - while ( ! ( $dbh and $dbh->ping() ) ) { - if ( ! ( $dbh = zmDbConnect() ) ) { + while (!($dbh and $dbh->ping())) { + if (!($dbh = zmDbConnect())) { sleep($Config{ZM_WATCH_CHECK_INTERVAL}); } } - my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () ) - or Fatal('Can\'t execute: '.$sth->errstr()); - while( my $monitor = $sth->fetchrow_hashref() ) { + foreach my $monitor (ZoneMinder::Monitor->find($Config{ZM_SERVER_ID} ? (ServerId=>$Config{ZM_SERVER_ID}) : ())) { next if $monitor->{Function} eq 'None'; next if $monitor->{Type} eq 'WebSite'; my $now = time(); my $restart = 0; - if (zmMemVerify($monitor)) { -# Check we have got an image recently - my $capture_time = zmGetLastWriteTime($monitor); - if (!defined($capture_time)) { -# Can't read from shared data - Debug('LastWriteTime is not defined.'); - zmMemInvalidate($monitor); - next; - } - Debug("Monitor $$monitor{Id} LastWriteTime is $capture_time."); - if (!$capture_time) { - my $startup_time = zmGetStartupTime($monitor); - if (($now - $startup_time) > $Config{ZM_WATCH_MAX_DELAY}) { - Warning( - "Restarting capture daemon for $$monitor{Name}, no image since startup. ". - "Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}" - ); - $restart = 1; - } else { - # We can't get the last capture time so can't be sure it's died, it might just be starting up. - zmMemInvalidate($monitor); - next; - } - } - if (!$restart) { - my $max_image_delay = ( - $monitor->{MaxFPS} - &&($monitor->{MaxFPS}>0) - &&($monitor->{MaxFPS}<1) - ) ? (3/$monitor->{MaxFPS}) - : $Config{ZM_WATCH_MAX_DELAY} - ; - my $image_delay = $now - $capture_time; - Debug("Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay"); - if ( $image_delay > $max_image_delay ) { - Warning("Restarting capture daemon for " - .$monitor->{Name}.", time since last capture $image_delay seconds ($now-$capture_time)" - ); - $restart = 1; - } - } # end if ! restart - } else { + + zmMemInvalidate($monitor); + if (!zmMemVerify($monitor)) { Info("Restarting capture daemon for $monitor->{Name}, shared data not valid"); - $restart = 1; + $monitor->control('restart'); + next; } - if ($restart) { - my $command; - if ($monitor->{Type} eq 'Local') { - $command = 'zmdc.pl restart zmc -d '.$monitor->{Device}; - } else { - $command = 'zmdc.pl restart zmc -m '.$monitor->{Id}; + # Check we have got an image recently + my $capture_time = zmGetLastWriteTime($monitor); + if (!defined($capture_time)) { + # Can't read from shared data + Warning('LastWriteTime is not defined.'); + next; + } + Debug("Monitor $$monitor{Id} LastWriteTime is $capture_time."); + if (!$capture_time) { + # We can't get the last capture time so can't be sure it's died, it might just be starting up. + my $startup_time = zmGetStartupTime($monitor); + if (($now - $startup_time) > $Config{ZM_WATCH_MAX_DELAY}) { + Warning( + "Restarting capture daemon for $$monitor{Name}, no image since startup. ". + "Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}" + ); + $monitor->control('restart'); } - runCommand($command); - } elsif ($monitor->{Function} ne 'Monitor') { -# Now check analysis daemon - $restart = 0; + next; + } + + my $max_image_delay = ( + $monitor->{MaxFPS} + &&($monitor->{MaxFPS}>0) + &&($monitor->{MaxFPS}<1) + ) ? (3/$monitor->{MaxFPS}) + : $Config{ZM_WATCH_MAX_DELAY} + ; + my $image_delay = $now - $capture_time; + Debug("Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay"); + if ($image_delay > $max_image_delay) { + Warning('Restarting capture daemon for '.$monitor->{Name}. + ", time since last capture $image_delay seconds ($now-$capture_time)"); + $monitor->control('restart'); + next; + } + + if ($monitor->{Function} ne 'Monitor') { + # Now check analysis thread # Check we have got an image recently my $image_time = zmGetLastReadTime($monitor); if (!defined($image_time)) { -# Can't read from shared data - $restart = 1; + # Can't read from shared data Error("Error reading shared data for $$monitor{Id} $$monitor{Name}"); + $monitor->control('restart'); + next; } elsif (!$image_time) { -# We can't get the last capture time so can't be sure it's died. - #$restart = 1; - Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero."); + Debug("Last analyse time for $$monitor{Id} $$monitor{Name} was zero."); } else { my $max_image_delay = ( $monitor->{MaxFPS} &&($monitor->{MaxFPS}>0) @@ -176,25 +161,14 @@ while (!$zm_terminate) { Debug("Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay"); if ($image_delay > $max_image_delay) { Warning("Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting," - ." time since last analysis $image_delay seconds ($now-$image_time)" - ); - $restart = 1; + ." time since last analysis $image_delay seconds ($now-$image_time)"); + $monitor->control('restart'); + next; } } - if ($restart) { - Info("Restarting analysis daemon for $$monitor{Id} $$monitor{Name}"); - my $command; - if ( $monitor->{Type} eq 'Local' ) { - $command = 'zmdc.pl restart zmc -d '.$monitor->{Device}; - } else { - $command = 'zmdc.pl restart zmc -m '.$monitor->{Id}; - } - runCommand($command); - } # end if restart } # end if check analysis daemon - # Prevent open handles building up if we have connect to shared memory - zmMemInvalidate($monitor); # Close our file handle to the zmc process we are about to end + } # end foreach monitor sleep($Config{ZM_WATCH_CHECK_INTERVAL}); diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 5255d3ab2..88ccd11d1 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -128,10 +128,10 @@ bool StreamBase::checkCommandQueue() { return true; } } else if ( connkey ) { - Warning("No sd in checkCommandQueue, comms not open?"); + Warning("No sd in checkCommandQueue, comms not open for connkey %06d?", connkey); } else { // Perfectly valid if only getting a snapshot - Debug(1, "No sd in checkCommandQueue, comms not open?"); + Debug(1, "No sd in checkCommandQueue, comms not open."); } return false; } // end bool StreamBase::checkCommandQueue() @@ -387,8 +387,8 @@ void StreamBase::openComms() { rem_addr.sun_family = AF_UNIX; last_comm_update = std::chrono::system_clock::now(); + Debug(3, "comms open at %s", loc_sock_path); } // end if connKey > 0 - Debug(3, "comms open at %s", loc_sock_path); } // end void StreamBase::openComms() void StreamBase::closeComms() { diff --git a/src/zmu.cpp b/src/zmu.cpp index ec4ae7b86..b85227fc4 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -482,7 +482,7 @@ int main(int argc, char *argv[]) { exit_zmu(-1); } if ( !ValidateAccess(user, mon_id, function) ) { - Error("Insufficient privileges for requested action"); + Error("Insufficient privileges for user %s for requested function %x", username, function); exit_zmu(-1); } } // end if auth @@ -497,6 +497,16 @@ int main(int argc, char *argv[]) { if ( verbose ) { printf("Monitor %u(%s)\n", monitor->Id(), monitor->Name()); } + + if (monitor->GetFunction() == Monitor::NONE) { + if (verbose) { + printf("Current state: None\n"); + } else { + printf("%d", Monitor::UNKNOWN); + } + exit_zmu(-1); + } + if ( !monitor->connect() ) { Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); exit_zmu(-1); diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index b252c292c..04bf66b7e 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -446,8 +446,10 @@ function streamFastRev(action) { function streamPrev(action) { if (action) { $j(".vjsMessage").remove(); - location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery); - return; + if (prevEventId != 0) { + location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery); + return; + } /* Ideally I'd like to get back to this style if ( vid && PrevEventDefVideoPath.indexOf("view_video") > 0 ) { @@ -619,8 +621,8 @@ function getNearEventsResponse(respObj, respText) { if (checkStreamForErrors('getNearEventsResponse', respObj)) { return; } - prevEventId = respObj.nearevents.PrevEventId; - nextEventId = respObj.nearevents.NextEventId; + prevEventId = parseInt(respObj.nearevents.PrevEventId); + nextEventId = parseInt(respObj.nearevents.NextEventId); prevEventStartTime = Date.parse(respObj.nearevents.PrevEventStartTime); nextEventStartTime = Date.parse(respObj.nearevents.NextEventStartTime); PrevEventDefVideoPath = respObj.nearevents.PrevEventDefVideoPath; diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 8a0f527c9..f290e1998 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -904,9 +904,10 @@ function initPage() { if (monitorType != 'WebSite') { if (streamMode == 'single') { - statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout); + statusCmdTimer = setTimeout(statusCmdQuery, 100); setInterval(watchdogCheck, statusRefreshTimeout*2, 'status'); } else { + streamCmdTimer = setTimeout(streamCmdQuery, 100); setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream'); } diff --git a/web/skins/classic/views/js/watch.js.php b/web/skins/classic/views/js/watch.js.php index ab09d6ca5..d7b108b6d 100644 --- a/web/skins/classic/views/js/watch.js.php +++ b/web/skins/classic/views/js/watch.js.php @@ -1,5 +1,5 @@ Refresh() ?>'; var monitorStreamReplayBuffer = StreamReplayBuffer() ?>; var monitorControllable = Controllable()?'true':'false' ?>; -var monIdx = ''; +var monIdx = ; var nextMid = ""; var mode = "";