Ejemplo n.º 1
0
static gboolean
is_multicast_address (const gchar * host_name)
{
  GInetAddress *addr;
  GResolver *resolver = NULL;
  gboolean ret = FALSE;

  addr = g_inet_address_new_from_string (host_name);
  if (!addr) {
    GList *results;

    resolver = g_resolver_get_default ();
    results = g_resolver_lookup_by_name (resolver, host_name, NULL, NULL);
    if (!results)
      goto out;
    addr = G_INET_ADDRESS (g_object_ref (results->data));

    g_resolver_free_addresses (results);
  }
  g_assert (addr != NULL);

  ret = g_inet_address_get_is_multicast (addr);

out:
  if (resolver)
    g_object_unref (resolver);
  if (addr)
    g_object_unref (addr);
  return ret;
}
Ejemplo n.º 2
0
static gboolean
gst_multiudpsink_configure_client (GstMultiUDPSink * sink,
    GstUDPClient * client)
{
  GInetSocketAddress *saddr = G_INET_SOCKET_ADDRESS (client->addr);
  GInetAddress *addr = g_inet_socket_address_get_address (saddr);
  GSocketFamily family = g_socket_address_get_family (G_SOCKET_ADDRESS (saddr));
  GSocket *socket;
  GError *err = NULL;

  GST_DEBUG_OBJECT (sink, "configuring client %p", client);

  if (family == G_SOCKET_FAMILY_IPV6 && !sink->used_socket_v6)
    goto invalid_family;

  /* Select socket to send from for this address */
  if (family == G_SOCKET_FAMILY_IPV6 || !sink->used_socket)
    socket = sink->used_socket_v6;
  else
    socket = sink->used_socket;

  if (g_inet_address_get_is_multicast (addr)) {
    GST_DEBUG_OBJECT (sink, "we have a multicast client %p", client);
    if (sink->auto_multicast) {
      GST_DEBUG_OBJECT (sink, "autojoining group");
      if (!g_socket_join_multicast_group (socket, addr, FALSE,
              sink->multi_iface, &err))
        goto join_group_failed;
    }
    GST_DEBUG_OBJECT (sink, "setting loop to %d", sink->loop);
    g_socket_set_multicast_loopback (socket, sink->loop);
    GST_DEBUG_OBJECT (sink, "setting ttl to %d", sink->ttl_mc);
    g_socket_set_multicast_ttl (socket, sink->ttl_mc);
  } else {
    GST_DEBUG_OBJECT (sink, "setting unicast ttl to %d", sink->ttl);
    g_socket_set_ttl (socket, sink->ttl);
  }
  return TRUE;

  /* ERRORS */
join_group_failed:
  {
    gst_multiudpsink_stop (GST_BASE_SINK (sink));
    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
        ("Could not join multicast group: %s",
            err ? err->message : "unknown reason"));
    g_clear_error (&err);
    return FALSE;
  }
invalid_family:
  {
    gst_multiudpsink_stop (GST_BASE_SINK (sink));
    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
        ("Invalid address family (got %d)", family));
    return FALSE;
  }
}
Ejemplo n.º 3
0
gboolean
address_seems_public (GInetAddress *addr)
{
	return (g_inet_address_get_is_loopback (addr) == FALSE &&
	        g_inet_address_get_is_site_local (addr) == FALSE &&
	        g_inet_address_get_is_multicast (addr) == FALSE &&
	        g_inet_address_get_is_mc_link_local (addr) == FALSE &&
	        g_inet_address_get_is_mc_node_local (addr) == FALSE &&
	        g_inet_address_get_is_mc_site_local (addr) == FALSE &&
	        g_inet_address_get_is_mc_org_local (addr) == FALSE &&
	        g_inet_address_get_is_mc_global (addr) == FALSE);
}
Ejemplo n.º 4
0
static gboolean
gst_udpsrc_stop (GstBaseSrc * bsrc)
{
  GstUDPSrc *src;

  src = GST_UDPSRC (bsrc);

  GST_DEBUG ("stopping, closing sockets");

  if (src->used_socket) {
    if (src->auto_multicast
        &&
        g_inet_address_get_is_multicast (g_inet_socket_address_get_address
            (src->addr))) {
      GError *err = NULL;

      GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->host);

      if (!g_socket_leave_multicast_group (src->used_socket,
              g_inet_socket_address_get_address (src->addr), FALSE,
              src->multi_iface, &err)) {
        GST_ERROR_OBJECT (src, "Failed to leave multicast group: %s",
            err->message);
        g_clear_error (&err);
      }
    }

    if (src->close_socket || !src->external_socket) {
      GError *err = NULL;
      if (!g_socket_close (src->used_socket, &err)) {
        GST_ERROR_OBJECT (src, "Failed to close socket: %s", err->message);
        g_clear_error (&err);
      }
    }

    g_object_unref (src->used_socket);
    src->used_socket = NULL;
    g_object_unref (src->addr);
    src->addr = NULL;
  }

  return TRUE;
}
Ejemplo n.º 5
0
static gboolean
gst_udpsrc_close (GstUDPSrc * src)
{
  GST_DEBUG ("closing sockets");

  if (src->used_socket) {
    if (src->auto_multicast
        &&
        g_inet_address_get_is_multicast (g_inet_socket_address_get_address
            (src->addr))) {
      GError *err = NULL;

      GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->address);

      if (!g_socket_leave_multicast_group (src->used_socket,
              g_inet_socket_address_get_address (src->addr), FALSE,
              src->multi_iface, &err)) {
        GST_ERROR_OBJECT (src, "Failed to leave multicast group: %s",
            err->message);
        g_clear_error (&err);
      }
    }

    if (src->close_socket || !src->external_socket) {
      GError *err = NULL;
      if (!g_socket_close (src->used_socket, &err)) {
        GST_ERROR_OBJECT (src, "Failed to close socket: %s", err->message);
        g_clear_error (&err);
      }
    }

    g_object_unref (src->used_socket);
    src->used_socket = NULL;
    g_object_unref (src->addr);
    src->addr = NULL;
  }

  gst_udpsrc_reset_memory_allocator (src);

  gst_udpsrc_free_cancellable (src);

  return TRUE;
}
Ejemplo n.º 6
0
static gboolean
fill_address (const gchar * address, guint16 port, Addr * addr,
              gboolean is_multicast)
{
    GInetAddress *inet;

    inet = g_inet_address_new_from_string (address);
    if (inet == NULL)
        return FALSE;

    if (is_multicast != g_inet_address_get_is_multicast (inet)) {
        g_object_unref (inet);
        return FALSE;
    }

    addr->size = g_inet_address_get_native_size (inet);
    memcpy (addr->bytes, g_inet_address_to_bytes (inet), addr->size);
    g_object_unref (inet);
    addr->port = port;

    return TRUE;
}
Ejemplo n.º 7
0
static gboolean
gst_multiudpsink_configure_client (GstMultiUDPSink * sink,
    GstUDPClient * client)
{
  GInetSocketAddress *saddr = G_INET_SOCKET_ADDRESS (client->addr);
  GInetAddress *addr = g_inet_socket_address_get_address (saddr);
  GError *err = NULL;

  GST_DEBUG_OBJECT (sink, "configuring client %p", client);

  if (g_inet_address_get_is_multicast (addr)) {
    GST_DEBUG_OBJECT (sink, "we have a multicast client %p", client);
    if (sink->auto_multicast) {
      GST_DEBUG_OBJECT (sink, "autojoining group");
      if (!g_socket_join_multicast_group (sink->used_socket, addr, FALSE, NULL,
              &err))
        goto join_group_failed;
    }
    GST_DEBUG_OBJECT (sink, "setting loop to %d", sink->loop);
    g_socket_set_multicast_loopback (sink->used_socket, sink->loop);
    GST_DEBUG_OBJECT (sink, "setting ttl to %d", sink->ttl_mc);
    g_socket_set_multicast_ttl (sink->used_socket, sink->ttl_mc);
  } else {
    GST_DEBUG_OBJECT (sink, "setting unicast ttl to %d", sink->ttl);
    g_socket_set_ttl (sink->used_socket, sink->ttl);
  }
  return TRUE;

  /* ERRORS */
join_group_failed:
  {
    gst_multiudpsink_stop (GST_BASE_SINK (sink));
    GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
        ("Could not join multicast group: %s", err->message));
    g_clear_error (&err);
    return FALSE;
  }
}
Ejemplo n.º 8
0
/* create a socket for sending to remote machine */
static gboolean
gst_udpsrc_start (GstBaseSrc * bsrc)
{
  GstUDPSrc *src;
  GInetAddress *addr, *bind_addr;
  GSocketAddress *bind_saddr;
  GResolver *resolver;
  GError *err = NULL;

  src = GST_UDPSRC (bsrc);

  if (src->socket == NULL) {
    /* need to allocate a socket */
    GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->host, src->port);

    addr = g_inet_address_new_from_string (src->host);
    if (!addr) {
      GList *results;

      GST_DEBUG_OBJECT (src, "resolving IP address for host %s", src->host);
      resolver = g_resolver_get_default ();
      results =
          g_resolver_lookup_by_name (resolver, src->host, src->cancellable,
          &err);
      if (!results)
        goto name_resolve;
      addr = G_INET_ADDRESS (g_object_ref (results->data));

      g_resolver_free_addresses (results);
      g_object_unref (resolver);
    }
#ifndef GST_DISABLE_GST_DEBUG
    {
      gchar *ip = g_inet_address_to_string (addr);

      GST_DEBUG_OBJECT (src, "IP address for host %s is %s", src->host, ip);
      g_free (ip);
    }
#endif

    if ((src->used_socket =
            g_socket_new (g_inet_address_get_family (addr),
                G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
      goto no_socket;

    src->external_socket = FALSE;

    GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket);

    if (src->addr)
      g_object_unref (src->addr);
    src->addr =
        G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));

    GST_DEBUG_OBJECT (src, "binding on port %d", src->port);

    if (g_inet_address_get_is_multicast (addr))
      bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr));
    else
      bind_addr = G_INET_ADDRESS (g_object_ref (addr));

    g_object_unref (addr);

    bind_saddr = g_inet_socket_address_new (bind_addr, src->port);
    g_object_unref (bind_addr);
    if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err))
      goto bind_error;

    g_object_unref (bind_saddr);
  } else {
    GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket);
    /* we use the configured socket, try to get some info about it */
    src->used_socket = G_SOCKET (g_object_ref (src->socket));
    src->external_socket = TRUE;

    if (src->addr)
      g_object_unref (src->addr);
    src->addr =
        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
            &err));
    if (!src->addr)
      goto getsockname_error;
  }

#if GLIB_CHECK_VERSION (2, 35, 7)
  {
    gint val = 0;

    if (src->buffer_size != 0) {
      GError *opt_err = NULL;

      GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size);
      /* set buffer size, Note that on Linux this is typically limited to a
       * maximum of around 100K. Also a minimum of 128 bytes is required on
       * Linux. */
      if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF,
              src->buffer_size, &opt_err)) {
        GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
            ("Could not create a buffer of requested %d bytes: %s",
                src->buffer_size, opt_err->message));
        g_error_free (opt_err);
        opt_err = NULL;
      }
    }

    /* read the value of the receive buffer. Note that on linux this returns
     * 2x the value we set because the kernel allocates extra memory for
     * metadata. The default on Linux is about 100K (which is about 50K
     * without metadata) */
    if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val,
            NULL)) {
      GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val);
    } else {
      GST_DEBUG_OBJECT (src, "could not get udp buffer size");
    }
  }
#elif defined (SO_RCVBUF)
  {
    gint rcvsize, ret;
    socklen_t len;

    len = sizeof (rcvsize);
    if (src->buffer_size != 0) {
      rcvsize = src->buffer_size;

      GST_DEBUG_OBJECT (src, "setting udp buffer of %d bytes", rcvsize);
      /* set buffer size, Note that on Linux this is typically limited to a
       * maximum of around 100K. Also a minimum of 128 bytes is required on
       * Linux. */
      ret =
          setsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF,
          (void *) &rcvsize, len);
      if (ret != 0) {
        GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
            ("Could not create a buffer of requested %d bytes, %d: %s (%d)",
                rcvsize, ret, g_strerror (errno), errno));
      }
    }

    /* read the value of the receive buffer. Note that on linux this returns 2x the
     * value we set because the kernel allocates extra memory for metadata.
     * The default on Linux is about 100K (which is about 50K without metadata) */
    ret =
        getsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF,
        (void *) &rcvsize, &len);
    if (ret == 0)
      GST_DEBUG_OBJECT (src, "have udp buffer of %d bytes", rcvsize);
    else
      GST_DEBUG_OBJECT (src, "could not get udp buffer size");
  }
#else
  if (src->buffer_size != 0) {
    GST_WARNING_OBJECT (src, "don't know how to set udp buffer size on this "
        "OS. Consider upgrading your GLib to >= 2.35.7 and re-compiling the "
        "GStreamer udp plugin");
  }
#endif

  g_socket_set_broadcast (src->used_socket, TRUE);

  if (src->auto_multicast
      &&
      g_inet_address_get_is_multicast (g_inet_socket_address_get_address
          (src->addr))) {
    GST_DEBUG_OBJECT (src, "joining multicast group %s", src->host);
    if (!g_socket_join_multicast_group (src->used_socket,
            g_inet_socket_address_get_address (src->addr),
            FALSE, src->multi_iface, &err))
      goto membership;
  }

  /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
   * follows ss_family on both */
  {
    GInetSocketAddress *addr;
    guint16 port;

    addr =
        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
            &err));
    if (!addr)
      goto getsockname_error;

    port = g_inet_socket_address_get_port (addr);
    GST_DEBUG_OBJECT (src, "bound, on port %d", port);
    if (port != src->port) {
      src->port = port;
      GST_DEBUG_OBJECT (src, "notifying port %d", port);
      g_object_notify (G_OBJECT (src), "port");
    }
    g_object_unref (addr);
  }

  return TRUE;

  /* ERRORS */
name_resolve:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("Name resolval failed: %s", err->message));
    g_clear_error (&err);
    g_object_unref (resolver);
    return FALSE;
  }
no_socket:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
        ("no socket error: %s", err->message));
    g_clear_error (&err);
    g_object_unref (addr);
    return FALSE;
  }
bind_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("bind failed: %s", err->message));
    g_clear_error (&err);
    g_object_unref (bind_saddr);
    gst_udpsrc_stop (GST_BASE_SRC (src));
    return FALSE;
  }
membership:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("could add membership: %s", err->message));
    g_clear_error (&err);
    gst_udpsrc_stop (GST_BASE_SRC (src));
    return FALSE;
  }
getsockname_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("getsockname failed: %s", err->message));
    g_clear_error (&err);
    gst_udpsrc_stop (GST_BASE_SRC (src));
    return FALSE;
  }
}
Ejemplo n.º 9
0
void
gst_multiudpsink_remove (GstMultiUDPSink * sink, const gchar * host, gint port)
{
  GList *find;
  GstUDPClient udpclient;
  GstUDPClient *client;
  GTimeVal now;

  udpclient.host = (gchar *) host;
  udpclient.port = port;

  g_mutex_lock (&sink->client_lock);
  find = g_list_find_custom (sink->clients, &udpclient,
      (GCompareFunc) client_compare);
  if (!find)
    goto not_found;

  client = (GstUDPClient *) find->data;

  GST_DEBUG_OBJECT (sink, "found %d clients with host %s, port %d",
      client->refcount, host, port);

  client->refcount--;
  if (client->refcount == 0) {
    GInetSocketAddress *saddr = G_INET_SOCKET_ADDRESS (client->addr);
    GInetAddress *addr = g_inet_socket_address_get_address (saddr);
    GSocketFamily family =
        g_socket_address_get_family (G_SOCKET_ADDRESS (saddr));
    GSocket *socket;

    /* Select socket to send from for this address */
    if (family == G_SOCKET_FAMILY_IPV6 || !sink->used_socket)
      socket = sink->used_socket_v6;
    else
      socket = sink->used_socket;

    GST_DEBUG_OBJECT (sink, "remove client with host %s, port %d", host, port);

    g_get_current_time (&now);
    client->disconnect_time = GST_TIMEVAL_TO_TIME (now);

    if (socket && sink->auto_multicast
        && g_inet_address_get_is_multicast (addr)) {
      GError *err = NULL;

      if (!g_socket_leave_multicast_group (socket, addr, FALSE,
              sink->multi_iface, &err)) {
        GST_DEBUG_OBJECT (sink, "Failed to leave multicast group: %s",
            err->message);
        g_clear_error (&err);
      }
    }

    /* Unlock to emit signal before we delete the actual client */
    g_mutex_unlock (&sink->client_lock);
    g_signal_emit (G_OBJECT (sink),
        gst_multiudpsink_signals[SIGNAL_CLIENT_REMOVED], 0, host, port);
    g_mutex_lock (&sink->client_lock);

    sink->clients = g_list_delete_link (sink->clients, find);

    free_client (client);
  }
  g_mutex_unlock (&sink->client_lock);

  return;

  /* ERRORS */
not_found:
  {
    g_mutex_unlock (&sink->client_lock);
    GST_WARNING_OBJECT (sink, "client at host %s, port %d not found",
        host, port);
    return;
  }
}
/* create a socket for sending to remote machine */
static gboolean
gst_udpsrc_open (GstUDPSrc * src)
{
  GInetAddress *addr, *bind_addr;
  GSocketAddress *bind_saddr;
  GError *err = NULL;

  if (src->socket == NULL) {
    /* need to allocate a socket */
    GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->address,
        src->port);

    addr = gst_udpsrc_resolve (src, src->address);
    if (!addr)
      goto name_resolve;

    if ((src->used_socket =
            g_socket_new (g_inet_address_get_family (addr),
                G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
      goto no_socket;

    src->external_socket = FALSE;

    GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket);

    if (src->addr)
      g_object_unref (src->addr);
    src->addr =
        G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));

    GST_DEBUG_OBJECT (src, "binding on port %d", src->port);

    /* On Windows it's not possible to bind to a multicast address
     * but the OS will make sure to filter out all packets that
     * arrive not for the multicast address the socket joined.
     *
     * On Linux and others it is necessary to bind to a multicast
     * address to let the OS filter out all packets that are received
     * on the same port but for different addresses than the multicast
     * address
     */
#ifdef G_OS_WIN32
    if (g_inet_address_get_is_multicast (addr))
      bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr));
    else
#endif
      bind_addr = G_INET_ADDRESS (g_object_ref (addr));

    g_object_unref (addr);

    bind_saddr = g_inet_socket_address_new (bind_addr, src->port);
    g_object_unref (bind_addr);
    if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err))
      goto bind_error;

    g_object_unref (bind_saddr);
  } else {
    GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket);
    /* we use the configured socket, try to get some info about it */
    src->used_socket = G_SOCKET (g_object_ref (src->socket));
    src->external_socket = TRUE;

    if (src->addr)
      g_object_unref (src->addr);
    src->addr =
        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
            &err));
    if (!src->addr)
      goto getsockname_error;
  }

#if GLIB_CHECK_VERSION (2, 35, 7)
  {
    gint val = 0;

    if (src->buffer_size != 0) {
      GError *opt_err = NULL;

      GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size);
      /* set buffer size, Note that on Linux this is typically limited to a
       * maximum of around 100K. Also a minimum of 128 bytes is required on
       * Linux. */
      if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF,
              src->buffer_size, &opt_err)) {
        GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
            ("Could not create a buffer of requested %d bytes: %s",
                src->buffer_size, opt_err->message));
        g_error_free (opt_err);
        opt_err = NULL;
      }
    }

    /* read the value of the receive buffer. Note that on linux this returns
     * 2x the value we set because the kernel allocates extra memory for
     * metadata. The default on Linux is about 100K (which is about 50K
     * without metadata) */
    if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val,
            NULL)) {
      GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val);
    } else {
      GST_DEBUG_OBJECT (src, "could not get udp buffer size");
    }
  }
#elif defined (SO_RCVBUF)
  {
    gint rcvsize, ret;
    socklen_t len;

    len = sizeof (rcvsize);
    if (src->buffer_size != 0) {
      rcvsize = src->buffer_size;

      GST_DEBUG_OBJECT (src, "setting udp buffer of %d bytes", rcvsize);
      /* set buffer size, Note that on Linux this is typically limited to a
       * maximum of around 100K. Also a minimum of 128 bytes is required on
       * Linux. */
      ret =
          setsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF,
          (void *) &rcvsize, len);
      if (ret != 0) {
        GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
            ("Could not create a buffer of requested %d bytes, %d: %s (%d)",
                rcvsize, ret, g_strerror (errno), errno));
      }
    }

    /* read the value of the receive buffer. Note that on linux this returns 2x the
     * value we set because the kernel allocates extra memory for metadata.
     * The default on Linux is about 100K (which is about 50K without metadata) */
    ret =
        getsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF,
        (void *) &rcvsize, &len);
    if (ret == 0)
      GST_DEBUG_OBJECT (src, "have udp buffer of %d bytes", rcvsize);
    else
      GST_DEBUG_OBJECT (src, "could not get udp buffer size");
  }
#else
  if (src->buffer_size != 0) {
    GST_WARNING_OBJECT (src, "don't know how to set udp buffer size on this "
        "OS. Consider upgrading your GLib to >= 2.35.7 and re-compiling the "
        "GStreamer udp plugin");
  }
#endif

  g_socket_set_broadcast (src->used_socket, TRUE);

  if (src->auto_multicast
      &&
      g_inet_address_get_is_multicast (g_inet_socket_address_get_address
          (src->addr))) {
    GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address);
    if (!g_socket_join_multicast_group (src->used_socket,
            g_inet_socket_address_get_address (src->addr),
            FALSE, src->multi_iface, &err))
      goto membership;
  }

  /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
   * follows ss_family on both */
  {
    GInetSocketAddress *addr;
    guint16 port;

    addr =
        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
            &err));
    if (!addr)
      goto getsockname_error;

    port = g_inet_socket_address_get_port (addr);
    GST_DEBUG_OBJECT (src, "bound, on port %d", port);
    if (port != src->port) {
      src->port = port;
      GST_DEBUG_OBJECT (src, "notifying port %d", port);
      g_object_notify (G_OBJECT (src), "port");
    }
    g_object_unref (addr);
  }

  src->allocator = NULL;
  gst_allocation_params_init (&src->params);

  src->max_size = 0;

  return TRUE;

  /* ERRORS */
name_resolve:
  {
    return FALSE;
  }
no_socket:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
        ("no socket error: %s", err->message));
    g_clear_error (&err);
    g_object_unref (addr);
    return FALSE;
  }
bind_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("bind failed: %s", err->message));
    g_clear_error (&err);
    g_object_unref (bind_saddr);
    gst_udpsrc_close (src);
    return FALSE;
  }
membership:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("could add membership: %s", err->message));
    g_clear_error (&err);
    gst_udpsrc_close (src);
    return FALSE;
  }
getsockname_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("getsockname failed: %s", err->message));
    g_clear_error (&err);
    gst_udpsrc_close (src);
    return FALSE;
  }
}
Ejemplo n.º 11
0
/* create a socket for sending to remote machine */
static gboolean
gst_udpsrc_open (GstUDPSrc * src)
{
  GInetAddress *addr, *bind_addr;
  GSocketAddress *bind_saddr;
  GError *err = NULL;

  gst_udpsrc_create_cancellable (src);

  if (src->socket == NULL) {
    /* need to allocate a socket */
    GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->address,
        src->port);

    addr = gst_udpsrc_resolve (src, src->address);
    if (!addr)
      goto name_resolve;

    if ((src->used_socket =
            g_socket_new (g_inet_address_get_family (addr),
                G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
      goto no_socket;

    src->external_socket = FALSE;

    GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket);

    if (src->addr)
      g_object_unref (src->addr);
    src->addr =
        G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));

    GST_DEBUG_OBJECT (src, "binding on port %d", src->port);

    /* On Windows it's not possible to bind to a multicast address
     * but the OS will make sure to filter out all packets that
     * arrive not for the multicast address the socket joined.
     *
     * On Linux and others it is necessary to bind to a multicast
     * address to let the OS filter out all packets that are received
     * on the same port but for different addresses than the multicast
     * address
     */
#ifdef G_OS_WIN32
    if (g_inet_address_get_is_multicast (addr))
      bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr));
    else
#endif
      bind_addr = G_INET_ADDRESS (g_object_ref (addr));

    g_object_unref (addr);

    bind_saddr = g_inet_socket_address_new (bind_addr, src->port);
    g_object_unref (bind_addr);
    if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err))
      goto bind_error;

    g_object_unref (bind_saddr);
    g_socket_set_multicast_loopback (src->used_socket, src->loop);
  } else {
    GInetSocketAddress *local_addr;

    GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket);
    /* we use the configured socket, try to get some info about it */
    src->used_socket = G_SOCKET (g_object_ref (src->socket));
    src->external_socket = TRUE;

    local_addr =
        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
            &err));
    if (!local_addr)
      goto getsockname_error;

    /* See above for the reasons. Without this we would behave different on
     * Windows and Linux, joining multicast groups below for provided sockets
     * on Linux but not on Windows
     */
#ifdef G_OS_WIN32
    addr = gst_udpsrc_resolve (src, src->address);
    if (!addr)
      goto name_resolve;

    if (!src->auto_multicast ||
        !g_inet_address_get_is_any (g_inet_socket_address_get_address
            (local_addr))
        || !g_inet_address_get_is_multicast (addr)) {
      g_object_unref (addr);
#endif
      if (src->addr)
        g_object_unref (src->addr);
      src->addr = local_addr;
#ifdef G_OS_WIN32
    } else {
      g_object_unref (local_addr);
      if (src->addr)
        g_object_unref (src->addr);
      src->addr =
          G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));
      g_object_unref (addr);
    }
#endif
  }

  {
    gint val = 0;

    if (src->buffer_size != 0) {
      GError *opt_err = NULL;

      GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size);
      /* set buffer size, Note that on Linux this is typically limited to a
       * maximum of around 100K. Also a minimum of 128 bytes is required on
       * Linux. */
      if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF,
              src->buffer_size, &opt_err)) {
        GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
            ("Could not create a buffer of requested %d bytes: %s",
                src->buffer_size, opt_err->message));
        g_error_free (opt_err);
        opt_err = NULL;
      }
    }

    /* read the value of the receive buffer. Note that on linux this returns
     * 2x the value we set because the kernel allocates extra memory for
     * metadata. The default on Linux is about 100K (which is about 50K
     * without metadata) */
    if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val,
            NULL)) {
      GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val);
    } else {
      GST_DEBUG_OBJECT (src, "could not get udp buffer size");
    }
  }

  g_socket_set_broadcast (src->used_socket, TRUE);

  if (src->auto_multicast
      &&
      g_inet_address_get_is_multicast (g_inet_socket_address_get_address
          (src->addr))) {
    GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address);
    if (!g_socket_join_multicast_group (src->used_socket,
            g_inet_socket_address_get_address (src->addr),
            FALSE, src->multi_iface, &err))
      goto membership;
  }

  /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
   * follows ss_family on both */
  {
    GInetSocketAddress *addr;
    guint16 port;

    addr =
        G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
            &err));
    if (!addr)
      goto getsockname_error;

    port = g_inet_socket_address_get_port (addr);
    GST_DEBUG_OBJECT (src, "bound, on port %d", port);
    if (port != src->port) {
      src->port = port;
      GST_DEBUG_OBJECT (src, "notifying port %d", port);
      g_object_notify (G_OBJECT (src), "port");
    }
    g_object_unref (addr);
  }

  src->allocator = NULL;
  gst_allocation_params_init (&src->params);

  src->max_size = 0;

  return TRUE;

  /* ERRORS */
name_resolve:
  {
    return FALSE;
  }
no_socket:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
        ("no socket error: %s", err->message));
    g_clear_error (&err);
    g_object_unref (addr);
    return FALSE;
  }
bind_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("bind failed: %s", err->message));
    g_clear_error (&err);
    g_object_unref (bind_saddr);
    gst_udpsrc_close (src);
    return FALSE;
  }
membership:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("could add membership: %s", err->message));
    g_clear_error (&err);
    gst_udpsrc_close (src);
    return FALSE;
  }
getsockname_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
        ("getsockname failed: %s", err->message));
    g_clear_error (&err);
    gst_udpsrc_close (src);
    return FALSE;
  }
}