Giter Site home page Giter Site logo

Comments (6)

faithoflifedev avatar faithoflifedev commented on September 17, 2024

Hi @Viper-Bit ,

Per the WS-Discovery spec - https://en.wikipedia.org/wiki/WS-Discovery#:~:text=Web%20Services%20Dynamic%20Discovery%20(WS,255.250%20or%20FF02%3A%3AC.

"Web Services Dynamic Discovery (WS-Discovery) is a technical specification that defines a multicast discovery protocol to locate services on a local network. It operates over TCP and UDP port 3702 and uses IP multicast address 239.255.255.250 or FF02::C. As the name suggests, the actual communication between nodes is done using web services standards, notably SOAP-over-UDP."

Are you running the code on Windows, maybe the Windows firewall is blocking the connection. I don't think this is a code related issue.

from easy_onvif.

Viper-Bit avatar Viper-Bit commented on September 17, 2024

@faithoflifedev thx for answer,
with disabled firewall still get same result
i think dart have a problem to create dgram socket on windows with virtual adapters, i wrote a c++ WS-Discovery and use it as a dll in dart in same pc and everything works like charm.
and found similar issue in flutter repo #53477

from easy_onvif.

faithoflifedev avatar faithoflifedev commented on September 17, 2024

Thanks for the update @Viper-Bit, I tried the work-arounds suggested in #53477 and none worked for me on Windows 11.

Are you able to provide your c++ code and I can look at incorporating it into this package until a better solution is available?

from easy_onvif.

Viper-Bit avatar Viper-Bit commented on September 17, 2024

@faithoflifedev yes OfCourse,

onvif.cpp

#include "onvif.h"

char preferred_network_address[16];

int setSocketOptions(int socket) {
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 500000;
    int broadcast = 500;
    char loopch = 0;
    int status = 0;
    struct in_addr localInterface;

#ifdef _WIN32
    PMIB_IPADDRTABLE pIPAddrTable;
    DWORD dwSize = 0;
    DWORD dwRetVal = 0;
    IN_ADDR IPAddr;

    pIPAddrTable = (MIB_IPADDRTABLE*)malloc(sizeof(MIB_IPADDRTABLE));
    if (pIPAddrTable) {
        if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
            free(pIPAddrTable);
            pIPAddrTable = (MIB_IPADDRTABLE*)malloc(dwSize);
        }
        if (pIPAddrTable == NULL) {
            printf("Memory allocation failed for GetIpAddrTable\n");
            return -1;
        }
    }

    if ((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) != NO_ERROR) {
        printf("GetIpAddrTable failed with error %d\n", dwRetVal);
        return -1;
    }

    int p = 0;
    while (p < (int)pIPAddrTable->dwNumEntries) {
        IPAddr.S_un.S_addr = (u_long)pIPAddrTable->table[p].dwAddr;
        IPAddr.S_un.S_addr = (u_long)pIPAddrTable->table[p].dwMask;
        if (pIPAddrTable->table[p].dwAddr != inet_addr("127.0.0.1") && pIPAddrTable->table[p].dwMask == inet_addr("255.255.255.0")) {
            if (strlen(preferred_network_address) > 0) {
                localInterface.s_addr = inet_addr(preferred_network_address);
            }
            else {
                localInterface.s_addr = pIPAddrTable->table[p].dwAddr;
            }
            status = setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&localInterface, sizeof(localInterface));
            if (status < 0)
                printf("ip_multicast_if error");
            p = (int)pIPAddrTable->dwNumEntries;
        }
        p++;
    }

    if (pIPAddrTable) {
        free(pIPAddrTable);
        pIPAddrTable = NULL;
    }

    status = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&broadcast, sizeof(broadcast));
#else
    if (strlen(preferred_network_address) > 0) {
        localInterface.s_addr = inet_addr(preferred_network_address);
        status = setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&localInterface, sizeof(localInterface));
        if (status < 0)
            printf("ip_multicast_if error");
    }
    status = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (struct timeval*)&tv, sizeof(struct timeval));
#endif
    status = setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&loopch, sizeof(loopch));
    return 0;
}

int discovery(OnvifDiscoveryData* data, const char * probeMessage, int duration) {
#ifdef _WIN32
    WSADATA wsaData;
    int wsaStartup = WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

    sockaddr_in broadcast_address = {};

    int broadcast_message_length = strlen(probeMessage);
    int broadcast_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    setSocketOptions(broadcast_socket);

    memset((char*)&broadcast_address, 0, sizeof(broadcast_address));
    broadcast_address.sin_family = AF_INET;
    broadcast_address.sin_port = htons(3702);
    broadcast_address.sin_addr.s_addr = inet_addr("239.255.255.250");
    int status = sendto(broadcast_socket, probeMessage, broadcast_message_length, 0, (struct sockaddr*)&broadcast_address, sizeof(broadcast_address));
    if (status < 0) {
        //error
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(duration));
    int i = 0;
    bool loop = true;
    socklen_t address_size = sizeof(broadcast_address);
    while (loop) {
        int len = recvfrom(broadcast_socket, data->buf[i], sizeof(data->buf[i]), 0, (struct sockaddr*)&broadcast_address, &address_size);
        if (len > 0) {
            i++;
        }
        else {
            loop = false;
            if (len < 0) {
                //error
            }
        }
    }

#ifdef _WIN32
    closesocket(broadcast_socket);
    WSACleanup();
#else
    close(broadcast_socket);
#endif

    return i;
}

onvif.h

#ifndef ONVIF_H
#define ONVIF_H

#include <chrono>
#include <thread>
#include <cstring>


#ifdef _WIN32
#define LIBRARY_API __declspec(dllexport)
#include <ws2tcpip.h>
#include <iphlpapi.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")
#else
#define LIBRARY_API
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif

#ifdef __MINGW32__
#include <ws2tcpip.h>
#endif

#pragma pack (push, 1)
struct OnvifDiscoveryData {
    char buf[128][8192];
};
#pragma pack(pop)

#ifdef __cplusplus
extern "C" {
#endif

    LIBRARY_API int discovery(OnvifDiscoveryData* data, const char* probeMessage, int duration);

#ifdef __cplusplus
}
#endif

#endif

and dart side is:

import 'dart:ffi';
import 'dart:io';

import 'package:ffi/ffi.dart';

final Pointer<T> Function<T extends NativeType>(String symbolName) _lookup =
    () {
  if (Platform.isWindows) {
    return DynamicLibrary.open('onvif.dll').lookup;
  } else if (Platform.isLinux) {
    return DynamicLibrary.open('/usr/local/lib/libonvif.so').lookup;
  } else {
    throw UnimplementedError();
  }
}();

final _discoveryPtr = _lookup<
    NativeFunction<
        Int32 Function(
          Pointer<NativeType>,
          Pointer<NativeType>,
          Int32,
        )>>('discovery');
final _discovery = _discoveryPtr.asFunction<
    int Function(
      Pointer<NativeType>,
      Pointer<NativeType>,
      int,
    )>();

@Packed(1)
sealed class _OnvifDiscoveryData extends Struct {
  @Array<Int8>(128, 8192)
  external Array<Array<Int8>> buf;
}

const _probeMessage = '''
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
	<SOAP-ENV:Header>
		<a:Action SOAP-ENV:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>
		<a:MessageID>urn:uuid:2809d092-cb6c-476a-9a6f-7ee0123265d3</a:MessageID>
		<a:ReplyTo>
			<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
		</a:ReplyTo>
		<a:To SOAP-ENV:mustUnderstand="1">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>
	</SOAP-ENV:Header>
	<SOAP-ENV:Body>
		<p:Probe xmlns:p="http://schemas.xmlsoap.org/ws/2005/04/discovery">
			<d:Types xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:dp0="http://www.onvif.org/ver10/network/wsdl">dp0:NetworkVideoTransmitter</d:Types>
		</p:Probe>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
''';

Future<void> discovery([Duration duration = const Duration(seconds: 5)]) async {
  final data = calloc<_OnvifDiscoveryData>();

  final probeMessageData = _probeMessage.toNativeUtf8();

  final devices = _discovery(data, probeMessageData, duration.inMilliseconds);

  //for flutter _discovery cant be called in main thread (locks main thread for duration) so _discovery must be called from isolate
  /*
  final devices = await compute(
        (msg) {
      return _discovery(
        Pointer.fromAddress(msg['dataAddress'] as int),
        Pointer.fromAddress(msg['probeAddress'] as int),
        msg['duration'] as int,
      );
    },
    {
      'dataAddress': data.address,
      'probeAddress': probeMessageData.address,
      'duration': duration.inMilliseconds,
    },
  );
   */

  print('Found $devices Devices');
  for (var index = 0; index < devices; index++) {
    print(Pointer.fromAddress(data.address + index * 8192)
        .cast<Utf8>()
        .toDartString());
  }

  malloc.free(probeMessageData);
  calloc.free(data);
}

from easy_onvif.

faithoflifedev avatar faithoflifedev commented on September 17, 2024

Hi @Viper-Bit , as an update on this, I'm currently readying a new release with the above workaround for Windows OS included. It should be available in a day or two. Thanks for your help with this.

from easy_onvif.

faithoflifedev avatar faithoflifedev commented on September 17, 2024

Hi @Viper-Bit , I've just published the new package v2.1.3+1.

Please let me know if this resolves the issue for you, or if you need a better explanation on how to use the fix (see the known issues section of the README).

from easy_onvif.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.