Merge branch 'master' of github.com:ZoneMinder/zoneminder

pull/4140/head^2
Isaac Connor 2025-01-03 13:54:47 -05:00
commit ef3055e638
6 changed files with 37 additions and 89 deletions

View File

@ -42,10 +42,6 @@ our @ISA = qw(ZoneMinder::Control);
use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);
our $username = '';
our $password = '';
our $realm = '';
sub new {
my $class = shift;
my $id = shift;
@ -54,12 +50,6 @@ sub new {
return $self;
}
sub credentials {
my $self = shift;
($username, $password) = @_;
}
sub open {
my $self = shift;
@ -80,30 +70,30 @@ sub open {
}
my $uri = URI->new($self->{Monitor}->{ControlAddress});
$realm = 'Login to ' . $self->{Monitor}->{ControlDevice};
$$self{realm} = 'Login to ' . $self->{Monitor}->{ControlDevice};
if ($self->{Monitor}->{ControlAddress}) {
if ( $uri->userinfo()) {
( $username, $password ) = $uri->userinfo() =~ /^(.*):(.*)$/;
@$self{'username', 'password'} = $uri->userinfo() =~ /^(.*):(.*)$/;
} else {
$username = $self->{Monitor}->{User};
$password = $self->{Monitor}->{Pass};
$$self{username} = $self->{Monitor}->{User};
$$self{password} = $self->{Monitor}->{Pass};
}
$$self{address} = $uri->host_port();
$self->{ua}->credentials($uri->host_port(), $realm, $username, $password);
$self->{ua}->credentials($uri->host_port(), @$self{'realm', 'username', 'password'});
# Testing seems to show that we need the username/password in each url as well as credentials
$$self{base_url} = $uri->canonical();
Debug('Using initial credentials for '.$uri->host_port().", $realm, $username, $password, base_url: $$self{base_url} auth:".$uri->authority());
Debug('Using initial credentials for '.$uri->host_port().join(',', '', @$self{'realm', 'username', 'password'}).", base_url: $$self{base_url} auth:".$uri->authority());
}
} elsif ( $self->{Monitor}{Path}) {
my $uri = URI->new($self->{Monitor}{Path});
Debug("Using Path for credentials: $self->{Monitor}{Path} " . $uri->userinfo());
if ( $uri->userinfo()) {
( $username, $password ) = $uri->userinfo() =~ /^(.*):(.*)$/;
@$self{'username', 'password'} = $uri->userinfo() =~ /^(.*):(.*)$/;
} else {
$username = $self->{Monitor}->{User};
$password = $self->{Monitor}->{Pass};
$uri->userinfo($username.':'.$password);
$$self{username} = $self->{Monitor}->{User};
$$self{password} = $self->{Monitor}->{Pass};
$uri->userinfo($$self{username}.':'.$$self{password});
}
$uri->scheme('http');
$uri->port(80);
@ -111,8 +101,8 @@ sub open {
$$self{base_url} = $uri->canonical();
$$self{address} = $uri->host_port();
Debug("User auth $username $password " . $uri->authority() . ' ' . $uri->host_port());
$self->{ua}->credentials($uri->host_port(), $realm, $username, $password);
Debug("User auth $$self{username} $$self{password} " . $uri->authority() . ' ' . $uri->host_port());
$self->{ua}->credentials($uri->host_port(), @$self{'realm', 'username', 'password');
chomp $$self{base_url};
Debug("Base_url is ".$$self{base_url});
} else {
@ -121,57 +111,17 @@ sub open {
my $url = $$self{base_url}.'cgi-bin/magicBox.cgi?action=getDeviceType';
# Detect REALM, has to be /cgi-bin/ptz.cgi because just / accepts no auth
my $res = $self->get($url);
my $res = $self->get_realm($url);
if ( $res->is_success ) {
$self->{state} = 'open';
return;
}
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 =~ /realm="([^"]+)"/i ) {
if ( $realm ne $1 ) {
$realm = $1;
Debug("Changing REALM to ($realm)");
$self->{ua}->credentials($$self{address}, $realm, $username, $password);
$res = $self->get($url);
if ( $res->is_success() ) {
$self->{state} = 'open';
return !undef;
} elsif ( $res->status_line eq '400 Bad Request' ) {
# In testing, this second request fails with Bad Request, I assume because we didn't actually give it a command.
$self->{state} = 'open';
return !undef;
} else {
Error('Authentication still failed after updating REALM' . $res->status_line);
$headers = $res->headers();
foreach my $k ( keys %$headers ) {
Debug("Header $k => $$headers{$k}");
} # end foreach
}
} else {
Error('Authentication failed, not a REALM problem');
}
} else {
Error('Failed to match realm in tokens');
} # end if
} else {
Debug('No headers line');
} # end if headers
return !undef;
} else {
Error("Failed to get $$self{base_url}cgi-bin/magicBox.cgi?action=getDeviceType ".$res->status_line());
Error("Failed to get $url ".$res->status_line());
} # end if $res->status_line() eq '401 Unauthorized'
$self->{state} = 'closed';
return undef;
}
sub close {
@ -179,15 +129,6 @@ sub close {
$self->{state} = 'closed';
}
sub get {
my $self = shift;
my $url = shift;
Debug("Getting $url");
my $response = $self->{ua}->get($url);
Debug('Response: '. $response->status_line . ' ' . $response->content);
return $response;
}
sub sendCmd {
my $self = shift;
my $cmd = shift;
@ -195,7 +136,7 @@ sub sendCmd {
$self->printMsg($cmd, 'Tx');
my $res = $self->{ua}->get($$self{base_url}.$cmd);
my $res = $self->get($$self{base_url}.$cmd);
if ( $res->is_success ) {
$result = !undef;
@ -203,14 +144,19 @@ sub sendCmd {
Info('Camera control: \''.$res->status_line().'\' for URL '.$$self{base_url}.$cmd);
# TODO: Add code to retrieve $res->message_decode or some such. Then we could do things like check the camera status.
} else {
# Have seen on some HikVision cams that whatever cookie LWP uses times out and it never refreshes, so we have to actually create a new LWP object.
$self->{ua} = LWP::UserAgent->new();
$self->{ua}->cookie_jar( {} );
$self->{ua}->credentials($$self{address}, $$self{realm}, $$self{username}, $$self{password});
# Try again
$res = $self->{ua}->get($$self{base_url}.$cmd);
$res = $self->get($$self{base_url}.$cmd);
if ( $res->is_success ) {
# Command to camera appears successful, write Info item to log
Info('Camera control 2: \''.$res->status_line().'\' for URL '.$$self{base_url}.$cmd);
} else {
Error('Camera control command FAILED: \''.$res->status_line().'\' for URL '.$$self{base_url}.$cmd);
$res = $self->{ua}->get('http://'.$self->{Monitor}->{ControlAddress}.'/'.$cmd);
$res = $self->get('http://'.$self->{Monitor}->{ControlAddress}.'/'.$cmd);
}
}
@ -447,7 +393,7 @@ sub set_config {
my $url = $$self{base_url}.'/cgi-bin/configManager.cgi?action=setConfig'.
join('&', map { $_.'='.uri_encode($$diff{$_}) } keys %$diff);
my $response = $self->{ua}->get($url);
my $response = $self->get($url);
Debug($response->content);
return $response->is_success();
}

View File

@ -60,12 +60,6 @@ my $DefaultFocusSpeed = 50; # Should be between 1 and 100
my $DefaultIrisSpeed = 50; # Should be between 1 and 100
my $uri;
sub credentials {
my $self = shift;
$$self{username} = shift;
$$self{password} = shift;
Debug("Setting credentials to $$self{username}/$$self{password}");
}
sub open {
my $self = shift;

View File

@ -1855,10 +1855,14 @@ void Monitor::UpdateFPS() {
last_camera_bytes = new_camera_bytes;
last_fps_time = now;
FPSeconds db_elapsed = now - last_status_time;
if (db_elapsed > Seconds(10)) {
std::string sql = stringtf(
"UPDATE LOW_PRIORITY Monitor_Status SET Status='Connected', CaptureFPS = %.2lf, CaptureBandwidth=%u, AnalysisFPS = %.2lf, UpdatedOn=NOW() WHERE MonitorId=%u",
new_capture_fps, new_capture_bandwidth, new_analysis_fps, id);
dbQueue.push(std::move(sql));
last_status_time = now;
}
} // now != last_fps_time
} // void Monitor::UpdateFPS()

View File

@ -569,6 +569,7 @@ class Monitor : public std::enable_shared_from_this<Monitor> {
State state;
SystemTimePoint start_time;
SystemTimePoint last_fps_time;
SystemTimePoint last_status_time;
SystemTimePoint last_analysis_fps_time;
SystemTimePoint auto_resume_time;
unsigned int last_motion_score;

View File

@ -192,7 +192,7 @@ bool VideoStore::open() {
video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
// Only set orientation if doing passthrough, otherwise the frame image will be rotated
Monitor::Orientation orientation = monitor->getOrientation();
if (orientation) {
if (orientation > 1) { // 1 is ROTATE_0
#if LIBAVCODEC_VERSION_CHECK(59, 37, 100, 37, 100)
int32_t* displaymatrix = static_cast<int32_t*>(av_malloc(sizeof(int32_t)*9));
Debug(3, "Have orientation %d", orientation);

View File

@ -90,9 +90,12 @@ class Filter extends ZM_Object {
$this->_querystring .= $term->querystring($objectname, $separator);
} # end foreach term
$this->_querystring .= $separator.urlencode($objectname.'[Query][sort_asc]').'='.$this->sort_asc();
$this->_querystring .= $separator.urlencode($objectname.'[Query][sort_field]').'='.$this->sort_field();
$this->_querystring .= $separator.urlencode($objectname.'[Query][skip_locked]').'='.$this->skip_locked();
$this->_querystring .= $separator.urlencode($objectname.'[Query][limit]').'='.$this->limit();
if ($this->sort_field())
$this->_querystring .= $separator.urlencode($objectname.'[Query][sort_field]').'='.$this->sort_field();
if ($this->skip_locked())
$this->_querystring .= $separator.urlencode($objectname.'[Query][skip_locked]').'='.$this->skip_locked();
if ($this->limit())
$this->_querystring .= $separator.urlencode($objectname.'[Query][limit]').'='.$this->limit();
if ( $this->Id() ) {
$this->_querystring .= $separator.$objectname.urlencode('[Id]').'='.$this->Id();
}