Skip to content

Commit

Permalink
gv: discovery interface selection
Browse files Browse the repository at this point in the history
Fixes #505
  • Loading branch information
yuhamag authored and EmmanuelP committed Feb 12, 2025
1 parent 516065b commit 2c5730c
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 16 deletions.
9 changes: 9 additions & 0 deletions src/arvcameratest.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static gboolean arv_option_show_version = FALSE;
static gboolean arv_option_gv_allow_broadcast_discovery_ack = FALSE;
static char *arv_option_gv_port_range = NULL;
static gboolean arv_option_native_buffers = FALSE;
static char *arv_option_gv_discovery_interface = NULL;

/* clang-format off */
static const GOptionEntry arv_option_entries[] =
Expand Down Expand Up @@ -227,6 +228,11 @@ static const GOptionEntry arv_option_entries[] =
&arv_option_gv_port_range, "GV port range",
"<min>-<max>"
},
{
"gv-discovery-interface", '\0', 0, G_OPTION_ARG_STRING,
&arv_option_gv_discovery_interface, "Discovery using the interface",
"<interface>"
},
{
"native-buffers", '\0', 0, G_OPTION_ARG_NONE,
&arv_option_native_buffers, "Enable native buffers",
Expand Down Expand Up @@ -506,6 +512,9 @@ main (int argc, char **argv)
if (arv_option_gv_allow_broadcast_discovery_ack)
arv_set_interface_flags ("GigEVision", ARV_GV_INTERFACE_FLAGS_ALLOW_BROADCAST_DISCOVERY_ACK);

if (arv_option_gv_discovery_interface)
arv_gv_interface_set_discovery_interface_name (arv_option_gv_discovery_interface);

arv_enable_interface ("Fake");

arv_debug_enable (arv_option_debug_domains);
Expand Down
119 changes: 108 additions & 11 deletions src/arvgvinterface.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ arv_gv_discover_socket_free (ArvGvDiscoverSocket *discover_socket)
}

static ArvGvDiscoverSocketList *
arv_gv_discover_socket_list_new (void)
arv_gv_discover_socket_list_new (const char *discovery_interface)
{
ArvGvDiscoverSocketList *socket_list;
GSList *iter;
Expand All @@ -92,7 +92,7 @@ arv_gv_discover_socket_list_new (void)
return socket_list;

for (iface_iter = ifaces; iface_iter != NULL; iface_iter = iface_iter->next) {
ArvGvDiscoverSocket *discover_socket = g_new0 (ArvGvDiscoverSocket, 1);
ArvGvDiscoverSocket *discover_socket;
GSocketAddress *socket_address;
GSocketAddress *socket_broadcast;
GInetAddress *inet_address;
Expand All @@ -101,6 +101,12 @@ arv_gv_discover_socket_list_new (void)
char *inet_broadcast_string;
GError *error = NULL;
gint buffer_size = ARV_GV_INTERFACE_DISCOVERY_SOCKET_BUFFER_SIZE;

if (discovery_interface != NULL)
if (g_strcmp0 (discovery_interface, arv_network_interface_get_name (iface_iter->data)) != 0)
continue;

discover_socket = g_new0 (ArvGvDiscoverSocket, 1);
socket_address = g_socket_address_new_from_native (arv_network_interface_get_addr(iface_iter->data),
sizeof (struct sockaddr));
socket_broadcast = g_socket_address_new_from_native (arv_network_interface_get_broadaddr(iface_iter->data),
Expand Down Expand Up @@ -339,6 +345,9 @@ arv_gv_interface_device_infos_unref (ArvGvInterfaceDeviceInfos *infos)

typedef struct {
GHashTable *devices;

GMutex mutex;
char *discovery_interface;
} ArvGvInterfacePrivate;

struct _ArvGvInterface {
Expand All @@ -354,7 +363,7 @@ struct _ArvGvInterfaceClass {
G_DEFINE_TYPE_WITH_CODE (ArvGvInterface, arv_gv_interface, ARV_TYPE_INTERFACE, G_ADD_PRIVATE (ArvGvInterface))

static ArvGvInterfaceDeviceInfos *
_discover (GHashTable *devices, const char *device_id, gboolean allow_broadcast_discovery_ack)
_discover (GHashTable *devices, const char *device_id, gboolean allow_broadcast_discovery_ack, const char *discovery_interface)
{
ArvGvDiscoverSocketList *socket_list;
GSList *iter;
Expand All @@ -367,7 +376,7 @@ _discover (GHashTable *devices, const char *device_id, gboolean allow_broadcast_
if (devices != NULL)
g_hash_table_remove_all (devices);

socket_list = arv_gv_discover_socket_list_new ();
socket_list = arv_gv_discover_socket_list_new (discovery_interface);

if (socket_list->n_sockets < 1) {
arv_gv_discover_socket_list_free (socket_list);
Expand Down Expand Up @@ -484,8 +493,12 @@ static void
arv_gv_interface_discover (ArvGvInterface *gv_interface)
{
int flags = arv_interface_get_flags (ARV_INTERFACE(gv_interface));
char *discovery_interface;

_discover (gv_interface->priv->devices, NULL, flags & ARV_GV_INTERFACE_FLAGS_ALLOW_BROADCAST_DISCOVERY_ACK);
discovery_interface = arv_gv_interface_dup_discovery_interface_name();
_discover (gv_interface->priv->devices, NULL, flags & ARV_GV_INTERFACE_FLAGS_ALLOW_BROADCAST_DISCOVERY_ACK,
discovery_interface);
g_free (discovery_interface);
}

static GInetAddress *
Expand Down Expand Up @@ -553,6 +566,7 @@ arv_gv_interface_camera_locate (ArvGvInterface *gv_interface, GInetAddress *devi
GList *ifaces;
GList *iface_iter;
struct sockaddr_in device_sockaddr;
char *discovery_interface;

device_socket_address = g_inet_socket_address_new(device_address, ARV_GVCP_PORT);

Expand All @@ -563,7 +577,8 @@ arv_gv_interface_camera_locate (ArvGvInterface *gv_interface, GInetAddress *devi
for (iface_iter = ifaces; iface_iter != NULL; iface_iter = iface_iter->next) {
struct sockaddr_in *sa = (struct sockaddr_in*)arv_network_interface_get_addr(iface_iter->data);
struct sockaddr_in *mask = (struct sockaddr_in*)arv_network_interface_get_netmask(iface_iter->data);
if ((sa->sin_addr.s_addr & mask->sin_addr.s_addr) == (device_sockaddr.sin_addr.s_addr & mask->sin_addr.s_addr)) {
if ((sa->sin_addr.s_addr & mask->sin_addr.s_addr) ==
(device_sockaddr.sin_addr.s_addr & mask->sin_addr.s_addr)) {
GSocketAddress *socket_address = g_socket_address_new_from_native
(arv_network_interface_get_addr(iface_iter->data), sizeof(struct sockaddr));
GInetAddress *inet_address = g_object_ref(g_inet_socket_address_get_address
Expand All @@ -580,7 +595,9 @@ arv_gv_interface_camera_locate (ArvGvInterface *gv_interface, GInetAddress *devi
g_list_free_full (ifaces, (GDestroyNotify) arv_network_interface_free);
}

socket_list = arv_gv_discover_socket_list_new();
discovery_interface = arv_gv_interface_dup_discovery_interface_name();
socket_list = arv_gv_discover_socket_list_new (discovery_interface);
g_free (discovery_interface);

if (socket_list->n_sockets < 1) {
arv_gv_discover_socket_list_free (socket_list);
Expand Down Expand Up @@ -728,6 +745,7 @@ arv_gv_interface_open_device (ArvInterface *interface, const char *device_id, GE
{
ArvDevice *device;
ArvGvInterfaceDeviceInfos *device_infos;
char *discovery_interface;
GError *local_error = NULL;
int flags;

Expand All @@ -739,7 +757,11 @@ arv_gv_interface_open_device (ArvInterface *interface, const char *device_id, GE
}

flags = arv_interface_get_flags (interface);
device_infos = _discover (NULL, device_id, flags & ARV_GVCP_DISCOVERY_PACKET_FLAGS_ALLOW_BROADCAST_ACK);
discovery_interface = arv_gv_interface_dup_discovery_interface_name();
device_infos = _discover (NULL, device_id, flags & ARV_GVCP_DISCOVERY_PACKET_FLAGS_ALLOW_BROADCAST_ACK,
discovery_interface);
g_free (discovery_interface);

if (device_infos != NULL) {
GInetAddress *device_address;

Expand All @@ -758,6 +780,75 @@ arv_gv_interface_open_device (ArvInterface *interface, const char *device_id, GE
static ArvInterface *arv_gv_interface = NULL;
static GMutex arv_gv_interface_mutex;

static ArvInterface *
_get_instance (void)
{
if (arv_gv_interface == NULL)
arv_gv_interface = g_object_new (ARV_TYPE_GV_INTERFACE, NULL);

return ARV_INTERFACE (arv_gv_interface);
}

/*
* arv_gv_interface_set_discovery_interface_name:
* @discovery_interface: (nullable): name of the discovery network interface
*
* Set the name of discovery network interface. If discovery_interface is %NULL, a discovery will be performed on every
* interfaces, which is the default behaviour.
*
* A call to [[email protected]_device_list] may be necessary after the discovery interface has changed, in order to
* forget the previously discovered devices.
*/

void
arv_gv_interface_set_discovery_interface_name (const char *discovery_interface)
{
ArvInterface *interface;

g_mutex_lock (&arv_gv_interface_mutex);

interface = _get_instance();
if (interface != NULL) {
ArvGvInterfacePrivate *priv = ARV_GV_INTERFACE (interface)->priv;

g_mutex_lock (&priv->mutex);
g_clear_pointer (&priv->discovery_interface, g_free);
priv->discovery_interface = g_strdup (discovery_interface);
g_mutex_unlock (&priv->mutex);
}

g_mutex_unlock (&arv_gv_interface_mutex);
}

/*
* arv_gv_interface_dup_discovery_interface_name:
*
* Returns: the name of the interface used for device discovery, %NULL if discovery is performed on all the available
* interfaces.
*/

char *
arv_gv_interface_dup_discovery_interface_name (void)
{
ArvInterface *interface;
char *discovery_interface = NULL;

g_mutex_lock (&arv_gv_interface_mutex);

interface = _get_instance();
if (interface != NULL) {
ArvGvInterfacePrivate *priv = ARV_GV_INTERFACE (interface)->priv;

g_mutex_lock (&priv->mutex);
discovery_interface = g_strdup (priv->discovery_interface);
g_mutex_unlock (&priv->mutex);
}

g_mutex_unlock (&arv_gv_interface_mutex);

return discovery_interface;
}

/**
* arv_gv_interface_get_instance:
*
Expand All @@ -769,14 +860,15 @@ static GMutex arv_gv_interface_mutex;
ArvInterface *
arv_gv_interface_get_instance (void)
{
ArvInterface *gv_interface;

g_mutex_lock (&arv_gv_interface_mutex);

if (arv_gv_interface == NULL)
arv_gv_interface = g_object_new (ARV_TYPE_GV_INTERFACE, NULL);
gv_interface = _get_instance();

g_mutex_unlock (&arv_gv_interface_mutex);

return ARV_INTERFACE (arv_gv_interface);
return gv_interface;
}

void
Expand All @@ -799,6 +891,9 @@ arv_gv_interface_init (ArvGvInterface *gv_interface)

gv_interface->priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
(GDestroyNotify) arv_gv_interface_device_infos_unref);
g_mutex_init(&gv_interface->priv->mutex);
gv_interface->priv->discovery_interface = NULL;

}

static void
Expand All @@ -808,6 +903,8 @@ arv_gv_interface_finalize (GObject *object)

g_hash_table_unref (gv_interface->priv->devices);
gv_interface->priv->devices = NULL;
g_clear_pointer (&gv_interface->priv->discovery_interface, g_free);
g_mutex_clear (&gv_interface->priv->mutex);

G_OBJECT_CLASS (arv_gv_interface_parent_class)->finalize (object);
}
Expand Down
4 changes: 3 additions & 1 deletion src/arvgvinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ typedef enum {
#define ARV_TYPE_GV_INTERFACE (arv_gv_interface_get_type ())
ARV_API G_DECLARE_FINAL_TYPE (ArvGvInterface, arv_gv_interface, ARV, GV_INTERFACE, ArvInterface)

ARV_API ArvInterface * arv_gv_interface_get_instance (void);
ARV_API ArvInterface * arv_gv_interface_get_instance (void);
ARV_API void arv_gv_interface_set_discovery_interface_name (const char *discovery_interface);
ARV_API char * arv_gv_interface_dup_discovery_interface_name (void);

G_END_DECLS

Expand Down
4 changes: 2 additions & 2 deletions src/arvsystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
G_BEGIN_DECLS

ARV_API unsigned int arv_get_n_interfaces (void);
ARV_API ArvInterface* arv_get_interface (unsigned int index);
ARV_API ArvInterface* arv_get_interface_by_id (const char* interface_id);
ARV_API ArvInterface* arv_get_interface (unsigned int index);
ARV_API ArvInterface* arv_get_interface_by_id (const char* interface_id);
ARV_API const char * arv_get_interface_id (unsigned int index);
ARV_API const char * arv_get_interface_protocol (unsigned int index);
ARV_API void arv_enable_interface (const char *interface_id);
Expand Down
9 changes: 9 additions & 0 deletions src/arvtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static gboolean arv_option_gv_allow_broadcast_discovery_ack = FALSE;
static gboolean arv_option_show_time = FALSE;
static gboolean arv_option_show_version = FALSE;
static char *arv_option_gv_port_range = NULL;
static char *arv_option_gv_discovery_interface = NULL;

static const GOptionEntry arv_option_entries[] =
{
Expand Down Expand Up @@ -82,6 +83,11 @@ static const GOptionEntry arv_option_entries[] =
&arv_option_gv_port_range, "GV port range",
"<min>-<max>"
},
{
"gv-discovery-interface", '\0', 0, G_OPTION_ARG_STRING,
&arv_option_gv_discovery_interface, "Discovery using the interface",
"<interface>"
},
{
"debug", 'd', 0, G_OPTION_ARG_STRING,
&arv_option_debug_domains, NULL,
Expand Down Expand Up @@ -802,6 +808,9 @@ main (int argc, char **argv)
if (arv_option_gv_allow_broadcast_discovery_ack)
arv_set_interface_flags ("GigEVision", ARV_GV_INTERFACE_FLAGS_ALLOW_BROADCAST_DISCOVERY_ACK);

if (arv_option_gv_discovery_interface)
arv_gv_interface_set_discovery_interface_name (arv_option_gv_discovery_interface);

device_id = arv_option_device_address != NULL ?
arv_option_device_address :
(is_glob_pattern ? NULL : arv_option_device_selection);
Expand Down
25 changes: 25 additions & 0 deletions tests/fakegv.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,34 @@ static ArvCamera *camera = NULL;
static void
discovery_test (void)
{
ArvCamera *test_camera;
char *discovery_iface;
int n_devices;
int i;

arv_gv_interface_set_discovery_interface_name("not-an-iface");

arv_update_device_list();

discovery_iface = arv_gv_interface_dup_discovery_interface_name();
g_assert (discovery_iface != NULL);
g_assert_cmpstr("not-an-iface", ==, discovery_iface);
g_free (discovery_iface);

test_camera = arv_camera_new ("Aravis-GVTest", NULL);
g_assert (test_camera == NULL);

arv_gv_interface_set_discovery_interface_name(NULL);

arv_update_device_list();

discovery_iface = arv_gv_interface_dup_discovery_interface_name();
g_assert (discovery_iface == NULL);

test_camera = arv_camera_new ("Aravis-GVTest", NULL);
g_assert (ARV_IS_CAMERA(test_camera));
g_clear_object (&test_camera);

n_devices = arv_get_n_devices ();

for (i = 0; i < n_devices; i++) {
Expand Down
4 changes: 2 additions & 2 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if get_option('tests')
],
env:['DEBUGINFOD_URLS=', 'ARV_TEST_IGNORE_BUFFER='],
exclude_suites:['python'],
timeout_multiplier:10
timeout_multiplier:5
)

tests = [
Expand All @@ -36,7 +36,7 @@ if get_option('tests')
link_with: aravis_library,
dependencies: aravis_dependencies,
include_directories: [library_inc])
test (t[0], exe, suite: t[1])
test (t[0], exe, suite: t[1], timeout: 60)
endforeach

py_script_config_data = configuration_data ()
Expand Down

0 comments on commit 2c5730c

Please sign in to comment.