static void on_address_next (GObject *object, GAsyncResult *result, gpointer user_data) { CockpitStream *self = user_data; GSocketConnection *connection; GSocketAddress *address; GError *error = NULL; GSocket *sock; address = g_socket_address_enumerator_next_finish (G_SOCKET_ADDRESS_ENUMERATOR (object), result, &error); if (error) { set_problem_from_error (self, "couldn't resolve", error); g_error_free (error); close_immediately (self, NULL); } else if (address) { sock = g_socket_new (g_socket_address_get_family (address), G_SOCKET_TYPE_STREAM, 0, &error); if (sock) { g_socket_set_blocking (sock, FALSE); connection = g_socket_connection_factory_create_connection (sock); g_object_unref (sock); g_socket_connection_connect_async (connection, address, NULL, on_socket_connect, g_object_ref (self)); } if (error) { g_debug ("%s: couldn't open socket: %s", self->priv->name, error->message); g_clear_error (&self->priv->connect_error); self->priv->connect_error = error; } g_object_unref (address); } else { if (self->priv->connect_error) { set_problem_from_error (self, "couldn't connect", self->priv->connect_error); close_immediately (self, NULL); } else { g_message ("%s: no addresses found", self->priv->name); close_immediately (self, "not-found"); } } g_object_unref (self); }
/** * g_socket_listener_add_address: * @listener: a #GSocketListener * @address: a #GSocketAddress * @type: a #GSocketType * @protocol: a #GSocketProtocol * @source_object: (allow-none): Optional #GObject identifying this source * @effective_address: (out) (allow-none): location to store the address that was bound to, or %NULL. * @error: #GError for error reporting, or %NULL to ignore. * * Creates a socket of type @type and protocol @protocol, binds * it to @address and adds it to the set of sockets we're accepting * sockets from. * * Note that adding an IPv6 address, depending on the platform, * may or may not result in a listener that also accepts IPv4 * connections. For more deterministic behavior, see * g_socket_listener_add_inet_port(). * * @source_object will be passed out in the various calls * to accept to identify this particular source, which is * useful if you're listening on multiple addresses and do * different things depending on what address is connected to. * * If successful and @effective_address is non-%NULL then it will * be set to the address that the binding actually occurred at. This * is helpful for determining the port number that was used for when * requesting a binding to port 0 (ie: "any port"). This address, if * requested, belongs to the caller and must be freed. * * Returns: %TRUE on success, %FALSE on error. * * Since: 2.22 */ gboolean g_socket_listener_add_address (GSocketListener *listener, GSocketAddress *address, GSocketType type, GSocketProtocol protocol, GObject *source_object, GSocketAddress **effective_address, GError **error) { GSocketAddress *local_address; GSocketFamily family; GSocket *socket; if (!check_listener (listener, error)) return FALSE; family = g_socket_address_get_family (address); socket = g_socket_new (family, type, protocol, error); if (socket == NULL) return FALSE; g_socket_set_listen_backlog (socket, listener->priv->listen_backlog); if (!g_socket_bind (socket, address, TRUE, error) || !g_socket_listen (socket, error)) { g_object_unref (socket); return FALSE; } local_address = NULL; if (effective_address) { local_address = g_socket_get_local_address (socket, error); if (local_address == NULL) { g_object_unref (socket); return FALSE; } } if (!g_socket_listener_add_socket (listener, socket, source_object, error)) { if (local_address) g_object_unref (local_address); g_object_unref (socket); return FALSE; } if (effective_address) *effective_address = local_address; g_object_unref (socket); /* add_socket refs this */ return TRUE; }
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; } }
static GSocket * create_socket (GSocketClient *client, GSocketAddress *dest_address, GError **error) { GSocketFamily family; GSocket *socket; family = client->priv->family; if (family == G_SOCKET_FAMILY_INVALID && client->priv->local_address != NULL) family = g_socket_address_get_family (client->priv->local_address); if (family == G_SOCKET_FAMILY_INVALID) family = g_socket_address_get_family (dest_address); socket = g_socket_new (family, client->priv->type, client->priv->protocol, error); if (socket == NULL) return NULL; if (client->priv->local_address) { if (!g_socket_bind (socket, client->priv->local_address, FALSE, error)) { g_object_unref (socket); return NULL; } } if (client->priv->timeout) g_socket_set_timeout (socket, client->priv->timeout); return socket; }
static gboolean kms_sctp_connection_create_socket (KmsSCTPConnection * conn, gchar * host, gint port, GCancellable * cancellable, GError ** err) { GInetAddress *addr; /* look up name if we need to */ addr = g_inet_address_new_from_string (host); if (addr == NULL) { GResolver *resolver; GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, host, cancellable, err); if (results == NULL) { g_object_unref (resolver); return FALSE; } addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } if (G_UNLIKELY (GST_LEVEL_DEBUG <= _gst_debug_min)) { gchar *ip = g_inet_address_to_string (addr); GST_DEBUG ("IP address for host %s is %s", host, ip); g_free (ip); } conn->saddr = g_inet_socket_address_new (addr, port); g_object_unref (addr); conn->socket = g_socket_new (g_socket_address_get_family (conn->saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_SCTP, err); if (conn->socket == NULL) { g_clear_object (&conn->saddr); return FALSE; } /* create socket */ GST_DEBUG ("created SCTP socket for %s", host); return TRUE; }
/** * g_vfs_ftp_connection_listen_data_connection: * @conn: a connection * @error: %NULL or location to take potential errors * * Initiates a listening socket that the FTP server can connect to. To accept * connections and initialize data transfers, use * g_vfs_ftp_connection_accept_data_connection(). * This function supports what is known as "active FTP", while * g_vfs_ftp_connection_open_data_connection() is to be used for "passive FTP". * * Returns: the actual address the socket is listening on or %NULL on error **/ GSocketAddress * g_vfs_ftp_connection_listen_data_connection (GVfsFtpConnection *conn, GError ** error) { GSocketAddress *local, *addr; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (conn->data == NULL, NULL); g_vfs_ftp_connection_stop_listening (conn); local = g_socket_connection_get_local_address (conn->connection, error); if (local == NULL) return NULL; conn->listen_socket = g_socket_new (g_socket_address_get_family (local), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error); if (conn->listen_socket == NULL) return NULL; g_assert (G_IS_INET_SOCKET_ADDRESS (local)); addr = g_inet_socket_address_new (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (local)), 0); g_object_unref (local); if (!g_socket_bind (conn->listen_socket, addr, TRUE, error) || !g_socket_listen (conn->listen_socket, error) || !(local = g_socket_get_local_address (conn->listen_socket, error))) { g_object_unref (addr); g_vfs_ftp_connection_stop_listening (conn); return NULL; } g_object_unref (addr); return local; }
/* create a socket for sending to remote machine */ static void gst_sctp_base_sink_create_socket (GstSCTPBaseSink * self) { GSocketAddress *saddr; GResolver *resolver; GInetAddress *addr; GError *err = NULL; if (GST_OBJECT_FLAG_IS_SET (self, GST_SCTP_BASE_SINK_OPEN)) return; /* look up name if we need to */ addr = g_inet_address_new_from_string (self->priv->host); if (addr == NULL) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, self->priv->host, self->priv->cancellable, &err); if (results == NULL) goto name_resolve; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } if (G_UNLIKELY (GST_LEVEL_DEBUG <= _gst_debug_min)) { gchar *ip = g_inet_address_to_string (addr); GST_DEBUG_OBJECT (self, "IP address for host %s is %s", self->priv->host, ip); g_free (ip); } saddr = g_inet_socket_address_new (addr, self->priv->port); g_object_unref (addr); /* create sending client socket */ GST_DEBUG_OBJECT (self, "opening sending client socket to %s:%d", self->priv->host, self->priv->port); self->priv->socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_SCTP, &err); if (self->priv->socket == NULL) goto no_socket; #if defined (SCTP_INITMSG) { struct sctp_initmsg initmsg; memset (&initmsg, 0, sizeof (initmsg)); initmsg.sinit_num_ostreams = self->priv->num_ostreams; initmsg.sinit_max_instreams = self->priv->max_istreams; if (setsockopt (g_socket_get_fd (self->priv->socket), IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof (initmsg)) < 0) GST_ELEMENT_WARNING (self, RESOURCE, SETTINGS, (NULL), ("Could not configure SCTP socket: %s (%d)", g_strerror (errno), errno)); } #else GST_WARNING_OBJECT (self, "don't know how to configure the SCTP initiation " "parameters on this OS."); #endif GST_DEBUG_OBJECT (self, "opened sending client socket"); /* connect to server */ if (!g_socket_connect (self->priv->socket, saddr, self->priv->cancellable, &err)) goto connect_failed; g_object_unref (saddr); GST_OBJECT_FLAG_SET (self, GST_SCTP_BASE_SINK_OPEN); GST_DEBUG ("Created sctp socket"); return; no_socket: { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("Failed to create socket: %s", err->message)); g_clear_error (&err); g_object_unref (saddr); return; } name_resolve: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (self, "Cancelled name resolval"); } else { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("Failed to resolve host '%s': %s", self->priv->host, err->message)); } g_clear_error (&err); g_object_unref (resolver); return; } connect_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (self, "Cancelled connecting"); } else { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("Failed to connect to host '%s:%d': %s", self->priv->host, self->priv->port, err->message)); } g_clear_error (&err); g_object_unref (saddr); /* pretend we opened ok for proper cleanup to happen */ GST_OBJECT_FLAG_SET (self, GST_SCTP_BASE_SINK_OPEN); gst_sctp_base_sink_destroy_socket (self); return; } }
static GSocket * gst_switch_server_listen (GstSwitchServer *srv, gint port, gint *bound_port) { GError *err = NULL; GInetAddress *addr; GSocket *socket = NULL; GSocketAddress *saddr; GResolver *resolver; gchar *ip; *bound_port = 0; /* look up name if we need to */ addr = g_inet_address_new_from_string (srv->host); if (!addr) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, srv->host, srv->cancellable, &err); if (!results) goto resolve_no_name; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } ip = g_inet_address_to_string (addr); saddr = g_inet_socket_address_new (addr, port); g_object_unref (addr); /* create the server listener socket */ socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &err); if (!socket) goto socket_new_failed; /* bind it */ if (!g_socket_bind (socket, saddr, TRUE, &err)) goto socket_bind_failed; g_object_unref (saddr); /* listen on the socket */ g_socket_set_listen_backlog (socket, GST_SWITCH_SERVER_LISTEN_BACKLOG); if (!g_socket_listen (socket, &err)) goto socket_listen_failed; if (port == 0) { saddr = g_socket_get_local_address (socket, NULL); *bound_port = g_inet_socket_address_get_port ((GInetSocketAddress *) saddr); g_object_unref (saddr); } else { *bound_port = port; } INFO ("Listening on %s (%s:%d)", srv->host, ip, *bound_port); g_free (ip); //g_atomic_int_set (&srv->bound_port, bound_port); //g_object_notify (G_OBJECT (src), "bound-port"); return socket; /* Errors Handling */ resolve_no_name: { ERROR ("resolve: %s", err->message); g_object_unref (resolver); g_object_unref (addr); return NULL; } socket_new_failed: { ERROR ("new socket: %s", err->message); g_clear_error (&err); g_object_unref (saddr); g_free (ip); return NULL; } socket_bind_failed: { ERROR ("bind socket: %s", err->message); g_clear_error (&err); g_object_unref (saddr); g_free (ip); return NULL; } socket_listen_failed: { ERROR ("listen socket: %s", err->message); g_clear_error (&err); g_object_unref (saddr); g_free (ip); return NULL; } }
static gboolean gst_tcp_mix_src_listen (GstTCPMixSrc * src, GstTCPMixSrcPad * pad) { GError *err = NULL; GInetAddress *addr; GSocketAddress *saddr; GResolver *resolver; gint bound_port = 0; gchar *ip; /* look up name if we need to */ addr = g_inet_address_new_from_string (src->host); if (!addr) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, src->host, src->cancellable, &err); if (!results) goto resolve_no_name; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } /* get IP address */ ip = g_inet_address_to_string (addr); saddr = g_inet_socket_address_new (addr, src->server_port); g_object_unref (addr); /* create the server listener socket */ src->server_socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &err); if (!src->server_socket) goto socket_new_failed; /* bind it */ if (!g_socket_bind (src->server_socket, saddr, TRUE, &err)) goto socket_bind_failed; g_object_unref (saddr); g_socket_set_listen_backlog (src->server_socket, TCP_BACKLOG); if (!g_socket_listen (src->server_socket, &err)) goto socket_listen_failed; GST_OBJECT_FLAG_SET (src, GST_TCP_MIX_SRC_OPEN); if (src->server_port == 0) { saddr = g_socket_get_local_address (src->server_socket, NULL); bound_port = g_inet_socket_address_get_port ((GInetSocketAddress *) saddr); g_object_unref (saddr); } else { bound_port = src->server_port; } GST_DEBUG_OBJECT (src, "Listening on %s (%s:%d)", src->host, ip, bound_port); g_free (ip); g_atomic_int_set (&src->bound_port, bound_port); g_object_notify (G_OBJECT (src), "bound-port"); return TRUE; /* Handling Errors */ resolve_no_name: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled name resolval"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to resolve host '%s': %s", src->host, err->message)); } g_clear_error (&err); g_object_unref (resolver); return FALSE; } socket_new_failed: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to create socket: %s", err->message)); g_clear_error (&err); g_object_unref (saddr); return FALSE; } socket_bind_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled binding"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to bind on host '%s:%d': %s", src->host, src->server_port, err->message)); } g_clear_error (&err); g_object_unref (saddr); gst_tcp_mix_src_stop (src, pad); return FALSE; } socket_listen_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled listening"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to listen on host '%s:%d': %s", src->host, src->server_port, err->message)); } g_clear_error (&err); gst_tcp_mix_src_stop (src, pad); return FALSE; } }
/* create a socket for sending to remote machine */ static gboolean gst_multiudpsink_start (GstBaseSink * bsink) { GstMultiUDPSink *sink; GList *clients; GstUDPClient *client; GError *err = NULL; sink = GST_MULTIUDPSINK (bsink); sink->external_socket = FALSE; if (sink->socket) { GST_DEBUG_OBJECT (sink, "using configured socket"); if (g_socket_get_family (sink->socket) == G_SOCKET_FAMILY_IPV6) { sink->used_socket_v6 = G_SOCKET (g_object_ref (sink->socket)); sink->external_socket = TRUE; } else { sink->used_socket = G_SOCKET (g_object_ref (sink->socket)); sink->external_socket = TRUE; } } if (sink->socket_v6) { GST_DEBUG_OBJECT (sink, "using configured IPv6 socket"); g_return_val_if_fail (g_socket_get_family (sink->socket) != G_SOCKET_FAMILY_IPV6, FALSE); if (sink->used_socket_v6 && sink->used_socket_v6 != sink->socket_v6) { GST_ERROR_OBJECT (sink, "Provided different IPv6 sockets in socket and socket-v6 properties"); return FALSE; } sink->used_socket_v6 = G_SOCKET (g_object_ref (sink->socket_v6)); sink->external_socket = TRUE; } if (!sink->used_socket && !sink->used_socket_v6) { GSocketAddress *bind_addr; GInetAddress *bind_iaddr; if (sink->bind_address) { GSocketFamily family; bind_iaddr = g_inet_address_new_from_string (sink->bind_address); if (!bind_iaddr) { GList *results; GResolver *resolver; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, sink->bind_address, sink->cancellable, &err); if (!results) { g_object_unref (resolver); goto name_resolve; } bind_iaddr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port); g_object_unref (bind_iaddr); family = g_socket_address_get_family (G_SOCKET_ADDRESS (bind_addr)); if ((sink->used_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) { g_object_unref (bind_addr); goto no_socket; } g_socket_bind (sink->used_socket, bind_addr, TRUE, &err); if (err != NULL) goto bind_error; } else { /* create sender sockets if none available */ if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) goto no_socket; bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port); g_socket_bind (sink->used_socket, bind_addr, TRUE, &err); g_object_unref (bind_addr); g_object_unref (bind_iaddr); if (err != NULL) goto bind_error; if ((sink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) { GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s", err->message); g_clear_error (&err); } else { bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6); bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port); g_socket_bind (sink->used_socket_v6, bind_addr, TRUE, &err); g_object_unref (bind_addr); g_object_unref (bind_iaddr); if (err != NULL) goto bind_error; } } } #ifdef SO_SNDBUF { socklen_t len; gint sndsize, ret; len = sizeof (sndsize); if (sink->buffer_size != 0) { sndsize = sink->buffer_size; GST_DEBUG_OBJECT (sink, "setting udp buffer of %d bytes", sndsize); /* 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 (sink->used_socket) { ret = setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, len); if (ret != 0) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s", sndsize, ret, g_strerror (errno))); } } if (sink->used_socket_v6) { ret = setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, len); if (ret != 0) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s", sndsize, ret, g_strerror (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) */ if (sink->used_socket) { ret = getsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, &len); if (ret == 0) GST_DEBUG_OBJECT (sink, "have UDP buffer of %d bytes", sndsize); else GST_DEBUG_OBJECT (sink, "could not get UDP buffer size"); } if (sink->used_socket_v6) { ret = getsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, SO_SNDBUF, (void *) &sndsize, &len); if (ret == 0) GST_DEBUG_OBJECT (sink, "have UDPv6 buffer of %d bytes", sndsize); else GST_DEBUG_OBJECT (sink, "could not get UDPv6 buffer size"); } } #endif #ifdef SO_BINDTODEVICE if (sink->multi_iface) { if (sink->used_socket) { setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, SO_BINDTODEVICE, sink->multi_iface, strlen (sink->multi_iface)); } if (sink->used_socket_v6) { setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, SO_BINDTODEVICE, sink->multi_iface, strlen (sink->multi_iface)); } } #endif if (sink->used_socket) g_socket_set_broadcast (sink->used_socket, TRUE); if (sink->used_socket_v6) g_socket_set_broadcast (sink->used_socket_v6, TRUE); sink->bytes_to_serve = 0; sink->bytes_served = 0; gst_multiudpsink_setup_qos_dscp (sink, sink->used_socket); gst_multiudpsink_setup_qos_dscp (sink, sink->used_socket_v6); /* look for multicast clients and join multicast groups appropriately set also ttl and multicast loopback delivery appropriately */ for (clients = sink->clients; clients; clients = g_list_next (clients)) { client = (GstUDPClient *) clients->data; if (!gst_multiudpsink_configure_client (sink, client)) return FALSE; } return TRUE; /* ERRORS */ no_socket: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Could not create socket: %s", err->message)); g_clear_error (&err); return FALSE; } bind_error: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Failed to bind socket: %s", err->message)); g_clear_error (&err); return FALSE; } name_resolve: { GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL), ("Failed to resolve bind address %s: %s", sink->bind_address, err->message)); g_clear_error (&err); return FALSE; } }
static GstFlowReturn gst_multiudpsink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstMultiUDPSink *sink; GList *clients; GOutputVector *vec; GstMapInfo *map; guint n_mem, i; gsize size; GstMemory *mem; gint num, no_clients; GError *err = NULL; sink = GST_MULTIUDPSINK (bsink); n_mem = gst_buffer_n_memory (buffer); if (n_mem == 0) goto no_data; /* allocated on the stack, the max number of memory blocks is limited so this * should not cause stack overflows */ vec = sink->vec; map = sink->map; size = 0; for (i = 0; i < n_mem; i++) { mem = gst_buffer_get_memory (buffer, i); gst_memory_map (mem, &map[i], GST_MAP_READ); vec[i].buffer = map[i].data; vec[i].size = map[i].size; size += map[i].size; } sink->bytes_to_serve += size; /* grab lock while iterating and sending to clients, this should be * fast as UDP never blocks */ g_mutex_lock (&sink->client_lock); GST_LOG_OBJECT (bsink, "about to send %" G_GSIZE_FORMAT " bytes in %u blocks", size, n_mem); no_clients = 0; num = 0; for (clients = sink->clients; clients; clients = g_list_next (clients)) { GstUDPClient *client; GSocket *socket; GSocketFamily family; gint count; client = (GstUDPClient *) clients->data; no_clients++; GST_LOG_OBJECT (sink, "sending %" G_GSIZE_FORMAT " bytes to client %p", size, client); family = g_socket_address_get_family (G_SOCKET_ADDRESS (client->addr)); /* 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; count = sink->send_duplicates ? client->refcount : 1; while (count--) { gssize ret; ret = g_socket_send_message (socket, client->addr, vec, n_mem, NULL, 0, 0, sink->cancellable, &err); if (G_UNLIKELY (ret < 0)) { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) goto flushing; /* we continue after posting a warning, next packets might be ok * again */ if (size > UDP_MAX_SIZE) { GST_ELEMENT_WARNING (sink, RESOURCE, WRITE, ("Attempting to send a UDP packet larger than maximum size " "(%" G_GSIZE_FORMAT " > %d)", size, UDP_MAX_SIZE), ("Reason: %s", err ? err->message : "unknown reason")); } else { GST_ELEMENT_WARNING (sink, RESOURCE, WRITE, ("Error sending UDP packet"), ("Reason: %s", err ? err->message : "unknown reason")); } g_clear_error (&err); } else { num++; client->bytes_sent += ret; client->packets_sent++; sink->bytes_served += ret; } } } g_mutex_unlock (&sink->client_lock); /* unmap all memory again */ for (i = 0; i < n_mem; i++) { gst_memory_unmap (map[i].memory, &map[i]); gst_memory_unref (map[i].memory); } GST_LOG_OBJECT (sink, "sent %" G_GSIZE_FORMAT " bytes to %d (of %d) clients", size, num, no_clients); return GST_FLOW_OK; no_data: { return GST_FLOW_OK; } flushing: { GST_DEBUG ("we are flushing"); g_mutex_unlock (&sink->client_lock); g_clear_error (&err); /* unmap all memory */ for (i = 0; i < n_mem; i++) { gst_memory_unmap (map[i].memory, &map[i]); gst_memory_unref (map[i].memory); } return GST_FLOW_FLUSHING; } }
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; } }
/* set up server */ static gboolean gst_tcp_server_src_start (GstBaseSrc * bsrc) { GstTCPServerSrc *src = GST_TCP_SERVER_SRC (bsrc); GError *err = NULL; GInetAddress *addr; GSocketAddress *saddr; GResolver *resolver; /* look up name if we need to */ addr = g_inet_address_new_from_string (src->host); if (!addr) { GList *results; 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 saddr = g_inet_socket_address_new (addr, src->server_port); g_object_unref (addr); /* create the server listener socket */ src->server_socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &err); if (!src->server_socket) goto no_socket; GST_DEBUG_OBJECT (src, "opened receiving server socket"); /* bind it */ GST_DEBUG_OBJECT (src, "binding server socket to address"); if (!g_socket_bind (src->server_socket, saddr, TRUE, &err)) goto bind_failed; g_object_unref (saddr); GST_DEBUG_OBJECT (src, "listening on server socket"); g_socket_set_listen_backlog (src->server_socket, TCP_BACKLOG); if (!g_socket_listen (src->server_socket, &err)) goto listen_failed; GST_OBJECT_FLAG_SET (src, GST_TCP_SERVER_SRC_OPEN); return TRUE; /* ERRORS */ no_socket: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to create socket: %s", err->message)); g_clear_error (&err); g_object_unref (saddr); return FALSE; } name_resolve: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled name resolval"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to resolve host '%s': %s", src->host, err->message)); } g_clear_error (&err); g_object_unref (resolver); return FALSE; } bind_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled binding"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to bind on host '%s:%d': %s", src->host, src->server_port, err->message)); } g_clear_error (&err); g_object_unref (saddr); gst_tcp_server_src_stop (GST_BASE_SRC (src)); return FALSE; } listen_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled listening"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to listen on host '%s:%d': %s", src->host, src->server_port, err->message)); } g_clear_error (&err); gst_tcp_server_src_stop (GST_BASE_SRC (src)); return FALSE; } }