lumeohq / onvif-rs

A native Rust ONVIF client library.
MIT License
114 stars 61 forks source link

advertised device mgmt uri not expected #77

Closed wiseman closed 1 year ago

wiseman commented 3 years ago

I have a "Hikvision Compatible Outdoor 8MP PTZ PoE IP Camera Speed Dome, Pan Tilt 18xOptical Zoom 30x Digital Zoom with 165ft IR Night Vsion, Motion Detect,WDR,IP66,PTZ IP Camera(4818X-IZ)", and examples/camera.rs fails with this:

$ ./target/debug/examples/camera get-hostname --uri http://192.168.1.200:80/
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value:
"advertised device mgmt uri http://192.168.1.200:80/Device not expected http://192.168.1.200/onvif/device_service"', onvif/examples/camera.rs:404:45
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

if I comment out the code that performs that check, it seems to work:

$ ./target/debug/examples/camera get-hostname --uri http://192.168.1.200:80/
IPNC
$ ./target/debug/examples/camera get-system-date-and-time --uri http://192.168.1.200:80/
Ok(
    GetSystemDateAndTimeResponse {
        system_date_and_time: SystemDateTime {
            date_time_type: Ntp,
            daylight_savings: false,
            time_zone: Some(
                TimeZone {
                    tz: "CST-8",
                },
            ),
# etc.
arunkd13 commented 2 years ago

There is an option called '--service-path' that you can pass from the command line. Use like

$ ./target/debug/examples/camera get-hostname --uri http://192.168.1.200:80/ --service-path=Device

abigagli commented 1 year ago

The problem is due to the fact that the URI in the reply contains :80 after the hostname and that doesn't match with the URI provided through the command line. Now even if you explicitly specify the port using --uri 192.168.1.200:80 when you invoke it, the Url parser will silently remove the :80 since that's the default for the http scheme..

I found the following change to onvif/examples/camera.rs to be sufficient to make it work (i.e. comparing Url instances instead of strings)

@@ -121,7 +121,9 @@ impl Clients {
             );
             match s.namespace.as_str() {
                 "http://www.onvif.org/ver10/device/wsdl" => {
-                    if s.x_addr != devicemgmt_uri.as_str() {
+                    let advertised_uri =
+                        Url::parse(s.x_addr.as_ref()).map_err(|e| e.to_string())?;
+                    if advertised_uri != devicemgmt_uri {
                         return Err(format!(
                             "advertised device mgmt uri {} not expected {}",
                             &s.x_addr, &devicemgmt_uri

I can probably fork and PR this, but it doesn't seem like PRs are going through, aren't they?

EDIT: Just found out there's already #101 exactly for this, from last December..

DmitrySamoylov commented 1 year ago

This should be fixed in https://github.com/lumeohq/onvif-rs/pull/105 (the other PR failed CI checks, so hasn't been merged).

Right now, I don't have a camera that outputs a URL with the port number to test it, so feel free to comment here if it worked or not.

abigagli commented 1 year ago

Confirming it now works. Thanks.