diff --git a/src/arvgvdevice.c b/src/arvgvdevice.c index 2c5a7cbcc..2f3a66670 100644 --- a/src/arvgvdevice.c +++ b/src/arvgvdevice.c @@ -1983,11 +1983,17 @@ arv_gv_device_constructed (GObject *object) char *address_string; guint32 capabilities; guint32 device_mode; + GInetAddress *any_address; + int socket_fd; + struct ifaddrs *addrs, *iap; + struct sockaddr_in *sa; + char buf[32]; + char interface_name[32]; - G_OBJECT_CLASS (arv_gv_device_parent_class)->constructed (object); + G_OBJECT_CLASS (arv_gv_device_parent_class)->constructed (object); if (!G_IS_INET_ADDRESS (priv->interface_address) || - !G_IS_INET_ADDRESS (priv->device_address)) { + !G_IS_INET_ADDRESS (priv->device_address)) { arv_device_take_init_error (ARV_DEVICE (object), g_error_new (ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_INVALID_PARAMETER, "Invalid interface or device address")); return; @@ -2010,18 +2016,51 @@ arv_gv_device_constructed (GObject *object) io_data->socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, NULL); - io_data->interface_address = arv_socket_bind_with_range (io_data->socket, priv->interface_address, 0, + // we have to grab the interface name + if (getifaddrs (&addrs) <0) { + arv_device_take_init_error (ARV_DEVICE (object), + g_error_new (ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_NOT_CONNECTED, + "Couldn't get available interfaces")); + return; + } + + for (iap = addrs; iap != NULL; iap = iap->ifa_next) { + if ((iap->ifa_flags & IFF_UP) != 0 && + (iap->ifa_flags & IFF_POINTOPOINT) == 0 && + (iap->ifa_addr != NULL) && + (iap->ifa_addr->sa_family == AF_INET)) { + + sa = (struct sockaddr_in *)(iap->ifa_addr); + inet_ntop(iap->ifa_addr->sa_family, (void *)&(sa->sin_addr), buf, sizeof(buf)); + if (!strcmp(g_inet_address_to_string (priv->interface_address), buf)) { + sprintf(interface_name, "%s", iap->ifa_name); + } + } + } + + freeifaddrs (addrs); + + socket_fd = g_socket_get_fd(io_data->socket); + if (setsockopt (socket_fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, strlen (interface_name)) == 0) { + any_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); + io_data->interface_address = arv_socket_bind_with_range (io_data->socket, any_address, 0, + FALSE, &local_error); + g_object_unref (any_address); + } else { + io_data->interface_address = arv_socket_bind_with_range (io_data->socket, priv->interface_address, 0, FALSE, &local_error); + } + if (io_data->interface_address == NULL) { if (local_error == NULL) local_error = g_error_new (ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_UNKNOWN, - "Unknown error trying to bind device interface"); + "Unknown error trying to bind device interface"); arv_device_take_init_error (ARV_DEVICE (gv_device), local_error); - return; } + io_data->buffer = g_malloc (ARV_GV_DEVICE_BUFFER_SIZE); io_data->gvcp_n_retries = ARV_GV_DEVICE_GVCP_N_RETRIES_DEFAULT; io_data->gvcp_timeout_ms = ARV_GV_DEVICE_GVCP_TIMEOUT_MS_DEFAULT; diff --git a/src/arvgvinterface.c b/src/arvgvinterface.c index 85b24d901..69aa69759 100644 --- a/src/arvgvinterface.c +++ b/src/arvgvinterface.c @@ -95,18 +95,22 @@ arv_gv_discover_socket_list_new (void) ArvGvDiscoverSocket *discover_socket = g_new0 (ArvGvDiscoverSocket, 1); GSocketAddress *socket_address; GSocketAddress *socket_broadcast; + GInetAddress *any_address; GInetAddress *inet_address; GInetAddress *inet_broadcast; char *inet_address_string; char *inet_broadcast_string; GError *error = NULL; gint buffer_size = ARV_GV_INTERFACE_DISCOVERY_SOCKET_BUFFER_SIZE; + int socket_fd; + const char *interface_name; + 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), sizeof (struct sockaddr)); inet_address = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (socket_address)); - inet_broadcast = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (socket_broadcast)); + inet_broadcast = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (socket_broadcast)); inet_address_string = g_inet_address_to_string (inet_address); inet_broadcast_string = g_inet_address_to_string (inet_broadcast); arv_info_interface ("[GvDiscoverSocket::new] Add interface %s (%s)", inet_address_string, inet_broadcast_string); @@ -118,23 +122,31 @@ arv_gv_discover_socket_list_new (void) G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, NULL); arv_socket_set_recv_buffer_size (g_socket_get_fd (discover_socket->socket), buffer_size); - - discover_socket->interface_address = arv_socket_bind_with_range (discover_socket->socket, inet_address, - 0, FALSE, &error); - - g_object_unref (socket_address); - g_object_unref (socket_broadcast); - - if (G_IS_INET_SOCKET_ADDRESS (discover_socket->interface_address)) { - socket_list->sockets = g_slist_prepend (socket_list->sockets, discover_socket); - socket_list->n_sockets++; - } else { - arv_warning_interface ("Failed to bind discovery socket: %s", - error != NULL ? error->message : "Unknown reason"); - arv_gv_discover_socket_free (discover_socket); - } - } - g_list_free_full (ifaces, (GDestroyNotify) arv_network_interface_free); + interface_name = arv_network_interface_get_name (iface_iter->data); + socket_fd = g_socket_get_fd(discover_socket->socket); + if (setsockopt (socket_fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, strlen (interface_name)) == 0) { + any_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); + discover_socket->interface_address = arv_socket_bind_with_range (discover_socket->socket, any_address, + 0, FALSE, &error); + g_object_unref (any_address); + } else { + discover_socket->interface_address = arv_socket_bind_with_range (discover_socket->socket, inet_address, + 0, FALSE, &error); + + g_object_unref (socket_address); + g_object_unref (socket_broadcast); + + if (G_IS_INET_SOCKET_ADDRESS (discover_socket->interface_address)) { + socket_list->sockets = g_slist_prepend (socket_list->sockets, discover_socket); + socket_list->n_sockets++; + } else { + arv_warning_interface ("Failed to bind discovery socket: %s", + error != NULL ? error->message : "Unknown reason"); + arv_gv_discover_socket_free (discover_socket); + } + } + } + g_list_free_full (ifaces, (GDestroyNotify) arv_network_interface_free); socket_list->poll_fds = g_new (GPollFD, socket_list->n_sockets); for (i = 0, iter = socket_list->sockets; iter != NULL; i++, iter = iter->next) { @@ -812,4 +824,4 @@ arv_gv_interface_class_init (ArvGvInterfaceClass *gv_interface_class) interface_class->update_device_list = arv_gv_interface_update_device_list; interface_class->open_device = arv_gv_interface_open_device; -} +} \ No newline at end of file