/** * g_pollable_source_new_full: * @pollable_stream: (type GObject): the stream associated with the * new source * @child_source: (allow-none): optional child source to attach * @cancellable: (allow-none): optional #GCancellable to attach * * Utility method for #GPollableInputStream and #GPollableOutputStream * implementations. Creates a new #GSource, as with * g_pollable_source_new(), but also attaching @child_source (with a * dummy callback), and @cancellable, if they are non-%NULL. * * Return value: (transfer full): the new #GSource. * * Since: 2.34 */ GSource * g_pollable_source_new_full (gpointer pollable_stream, GSource *child_source, GCancellable *cancellable) { GSource *source; g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (pollable_stream) || G_IS_POLLABLE_OUTPUT_STREAM (pollable_stream), NULL); source = g_pollable_source_new (pollable_stream); if (child_source) { g_source_set_dummy_callback (child_source); g_source_add_child_source (source, child_source); } if (cancellable) { GSource *cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (source, cancellable_source); g_source_unref (cancellable_source); } return source; }
static GSource * nice_output_stream_create_source (GPollableOutputStream *stream, GCancellable *cancellable) { NiceOutputStreamPrivate *priv = NICE_OUTPUT_STREAM (stream)->priv; GSource *component_source = NULL; NiceComponent *component = NULL; NiceStream *_stream = NULL; NiceAgent *agent; /* owned */ component_source = g_pollable_source_new (G_OBJECT (stream)); if (cancellable) { GSource *cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (component_source, cancellable_source); g_source_unref (cancellable_source); } /* Closed streams cannot have sources. */ if (g_output_stream_is_closed (G_OUTPUT_STREAM (stream))) return component_source; /* Has the agent disappeared? */ agent = g_weak_ref_get (&priv->agent_ref); if (agent == NULL) return component_source; agent_lock (); /* Grab the socket for this component. */ if (!agent_find_component (agent, priv->stream_id, priv->component_id, &_stream, &component)) { g_warning ("Could not find component %u in stream %u", priv->component_id, priv->stream_id); goto done; } if (component->tcp_writable_cancellable) { GSource *cancellable_source = g_cancellable_source_new (component->tcp_writable_cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (component_source, cancellable_source); g_source_unref (cancellable_source); } done: agent_unlock (); g_object_unref (agent); return component_source; }
GSource * _g_fd_source_new (int fd, gushort events, GCancellable *cancellable) { GSource *source; FDSource *fd_source; source = g_source_new (&fd_source_funcs, sizeof (FDSource)); fd_source = (FDSource *)source; fd_source->pollfd.fd = fd; fd_source->pollfd.events = events; g_source_add_poll (source, &fd_source->pollfd); if (cancellable) { GSource *cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (source, cancellable_source); g_source_unref (cancellable_source); } return source; }
/** * message_queue_source_new: * @queue: the queue to check * @destroy_message: (nullable): function to free a message, or %NULL * @cancellable: (nullable): a #GCancellable, or %NULL * * Create a new #MessageQueueSource, a type of #GSource which dispatches for * each message queued to it. * * If a callback function of type #MessageQueueSourceFunc is connected to the * returned #GSource using g_source_set_callback(), it will be invoked for each * message, with the message passed as its first argument. It is responsible for * freeing the message. If no callback is set, messages are automatically freed * as they are queued. * * Returns: (transfer full): a new #MessageQueueSource */ GSource * message_queue_source_new (GAsyncQueue *queue, GDestroyNotify destroy_message, GCancellable *cancellable) { GSource *source; /* alias of @message_queue_source */ MessageQueueSource *message_queue_source; /* alias of @source */ g_return_val_if_fail (queue != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); source = g_source_new (&message_queue_source_funcs, sizeof (MessageQueueSource)); message_queue_source = (MessageQueueSource *) source; /* The caller can overwrite this name with something more useful later. */ g_source_set_name (source, "MessageQueueSource"); message_queue_source->queue = g_async_queue_ref (queue); message_queue_source->destroy_message = destroy_message; /* Add a cancellable source. */ if (cancellable != NULL) { GSource *cancellable_source; cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (source, cancellable_source); g_source_unref (cancellable_source); } return source; }
GSource * g_tls_connection_base_create_source (GTlsConnectionBase *tls, GIOCondition condition, GCancellable *cancellable) { GSource *source, *cancellable_source; GTlsConnectionBaseSource *tls_source; source = g_source_new (&tls_source_funcs, sizeof (GTlsConnectionBaseSource)); g_source_set_name (source, "GTlsConnectionBaseSource"); tls_source = (GTlsConnectionBaseSource *)source; tls_source->tls = g_object_ref (tls); tls_source->condition = condition; if (condition & G_IO_IN) tls_source->stream = G_OBJECT (tls->tls_istream); else if (condition & G_IO_OUT) tls_source->stream = G_OBJECT (tls->tls_ostream); tls_source->op_waiting = (gboolean) -1; tls_source->io_waiting = (gboolean) -1; tls_source_sync (tls_source); if (cancellable) { cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (source, cancellable_source); g_source_unref (cancellable_source); } return source; }
static void nice_component_init (NiceComponent *component) { g_atomic_int_inc (&n_components_created); nice_debug ("Created NiceComponent (%u created, %u destroyed)", n_components_created, n_components_destroyed); component->id = 0; component->state = NICE_COMPONENT_STATE_DISCONNECTED; component->restart_candidate = NULL; component->tcp = NULL; component->agent = NULL; component->stream = NULL; g_mutex_init (&component->io_mutex); g_queue_init (&component->pending_io_messages); component->io_callback_id = 0; component->own_ctx = g_main_context_new (); component->stop_cancellable = g_cancellable_new (); component->stop_cancellable_source = g_cancellable_source_new (component->stop_cancellable); g_source_set_dummy_callback (component->stop_cancellable_source); g_source_attach (component->stop_cancellable_source, component->own_ctx); component->ctx = g_main_context_ref (component->own_ctx); /* Start off with a fresh main context and all I/O paused. This * will be updated when nice_agent_attach_recv() or nice_agent_recv_messages() * are called. */ nice_component_set_io_context (component, NULL); nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL); g_queue_init (&component->queued_tcp_packets); }
/** * nice_component_source_new: * @agent: a #NiceAgent * @stream_id: The stream's id * @component_id: The component's number * @pollable_stream: a #GPollableInputStream or #GPollableOutputStream to pass * to dispatched callbacks * @cancellable: (allow-none): a #GCancellable, or %NULL * * Create a new #ComponentSource, a type of #GSource which proxies poll events * from all sockets in the given @component. * * A callback function of type #GPollableSourceFunc must be connected to the * returned #GSource using g_source_set_callback(). @pollable_stream is passed * to all callbacks dispatched from the #GSource, and a reference is held on it * by the #GSource. * * The #GSource will automatically update to poll sockets as they’re added to * the @component (e.g. during peer discovery). * * Returns: (transfer full): a new #ComponentSource; unref with g_source_unref() */ GSource * nice_component_input_source_new (NiceAgent *agent, guint stream_id, guint component_id, GPollableInputStream *pollable_istream, GCancellable *cancellable) { ComponentSource *component_source; g_assert (G_IS_POLLABLE_INPUT_STREAM (pollable_istream)); component_source = (ComponentSource *) g_source_new (&component_source_funcs, sizeof (ComponentSource)); g_source_set_name ((GSource *) component_source, "ComponentSource"); component_source->component_socket_sources_age = 0; component_source->pollable_stream = g_object_ref (pollable_istream); g_weak_ref_init (&component_source->agent_ref, agent); component_source->stream_id = stream_id; component_source->component_id = component_id; /* Add a cancellable source. */ if (cancellable != NULL) { GSource *cancellable_source; cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source ((GSource *) component_source, cancellable_source); g_source_unref (cancellable_source); } return (GSource *) component_source; }
static void tls_source_sync (GTlsConnectionBaseSource *tls_source) { GTlsConnectionBase *tls = tls_source->tls; gboolean io_waiting, op_waiting; /* Was the source destroyed earlier in this main context iteration? */ if (g_source_is_destroyed ((GSource *) tls_source)) return; g_mutex_lock (&tls->op_mutex); if (((tls_source->condition & G_IO_IN) && tls->reading) || ((tls_source->condition & G_IO_OUT) && tls->writing) || (tls->handshaking && !tls->need_finish_handshake)) op_waiting = TRUE; else op_waiting = FALSE; if (!op_waiting && !tls->need_handshake && !tls->need_finish_handshake) io_waiting = TRUE; else io_waiting = FALSE; g_mutex_unlock (&tls->op_mutex); if (op_waiting == tls_source->op_waiting && io_waiting == tls_source->io_waiting) return; tls_source->op_waiting = op_waiting; tls_source->io_waiting = io_waiting; if (tls_source->child_source) { g_source_remove_child_source ((GSource *)tls_source, tls_source->child_source); g_source_unref (tls_source->child_source); } if (op_waiting) tls_source->child_source = g_cancellable_source_new (tls->waiting_for_op); else if (io_waiting && G_IS_POLLABLE_INPUT_STREAM (tls_source->stream)) tls_source->child_source = g_pollable_input_stream_create_source (tls->base_istream, NULL); else if (io_waiting && G_IS_POLLABLE_OUTPUT_STREAM (tls_source->stream)) tls_source->child_source = g_pollable_output_stream_create_source (tls->base_ostream, NULL); else tls_source->child_source = g_timeout_source_new (0); g_source_set_dummy_callback (tls_source->child_source); g_source_add_child_source ((GSource *)tls_source, tls_source->child_source); }
GSource * soup_message_io_get_source (SoupMessage *msg, GCancellable *cancellable, SoupMessageSourceFunc callback, gpointer user_data) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; GSource *base_source, *source; SoupMessageSource *message_source; if (!io) { base_source = g_timeout_source_new (0); } else if (io->paused) { base_source = NULL; } else if (io->async_close_wait) { base_source = g_cancellable_source_new (io->async_close_wait); } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) { GPollableInputStream *istream; if (io->body_istream) istream = G_POLLABLE_INPUT_STREAM (io->body_istream); else istream = G_POLLABLE_INPUT_STREAM (io->istream); base_source = g_pollable_input_stream_create_source (istream, cancellable); } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) { GPollableOutputStream *ostream; if (io->body_ostream) ostream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream); else ostream = G_POLLABLE_OUTPUT_STREAM (io->ostream); base_source = g_pollable_output_stream_create_source (ostream, cancellable); } else base_source = g_timeout_source_new (0); source = g_source_new (&message_source_funcs, sizeof (SoupMessageSource)); g_source_set_name (source, "SoupMessageSource"); message_source = (SoupMessageSource *)source; message_source->msg = g_object_ref (msg); message_source->paused = io && io->paused; if (base_source) { g_source_set_dummy_callback (base_source); g_source_add_child_source (source, base_source); g_source_unref (base_source); } g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL); return source; }
static GSource * g_unix_input_stream_pollable_create_source (GPollableInputStream *stream, GCancellable *cancellable) { GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream); GSource *inner_source, *cancellable_source, *pollable_source; pollable_source = g_pollable_source_new (G_OBJECT (stream)); inner_source = g_unix_fd_source_new (unix_stream->priv->fd, G_IO_IN); g_source_set_dummy_callback (inner_source); g_source_add_child_source (pollable_source, inner_source); g_source_unref (inner_source); if (cancellable) { cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (pollable_source, cancellable_source); g_source_unref (cancellable_source); } return pollable_source; }
static GSource * g_socket_output_stream_pollable_create_source (GPollableOutputStream *pollable, GCancellable *cancellable) { GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable); GSource *socket_source, *pollable_source; pollable_source = g_pollable_source_new (G_OBJECT (output_stream)); socket_source = g_socket_create_source (output_stream->priv->socket, G_IO_OUT, cancellable); g_source_set_dummy_callback (socket_source); g_source_add_child_source (pollable_source, socket_source); g_source_unref (socket_source); return pollable_source; }
static GSource * soup_content_sniffer_stream_create_source (GPollableInputStream *stream, GCancellable *cancellable) { SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (stream); GSource *base_source, *pollable_source; if (sniffer->priv->error || (!sniffer->priv->sniffing && sniffer->priv->buffer)) base_source = g_timeout_source_new (0); else base_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (G_FILTER_INPUT_STREAM (stream)->base_stream), cancellable); g_source_set_dummy_callback (base_source); pollable_source = g_pollable_source_new (G_OBJECT (stream)); g_source_add_child_source (pollable_source, base_source); g_source_unref (base_source); return pollable_source; }
static GSource * nice_input_stream_create_source (GPollableInputStream *stream, GCancellable *cancellable) { NiceInputStreamPrivate *priv = NICE_INPUT_STREAM (stream)->priv; GSource *component_source = NULL; NiceAgent *agent; /* owned */ /* Closed streams cannot have sources. */ if (g_input_stream_is_closed (G_INPUT_STREAM (stream))) goto dummy_source; /* Has the agent disappeared? */ agent = g_weak_ref_get (&priv->agent_ref); if (agent == NULL) goto dummy_source; component_source = component_input_source_new (agent, priv->stream_id, priv->component_id, stream, cancellable); g_object_unref (agent); return component_source; dummy_source: component_source = g_pollable_source_new (G_OBJECT (stream)); if (cancellable) { GSource *cancellable_source = g_cancellable_source_new (cancellable); g_source_set_dummy_callback (cancellable_source); g_source_add_child_source (component_source, cancellable_source); g_source_unref (cancellable_source); } return component_source; }
int main(void) { NiceAgent *lagent = NULL, *ragent = NULL; GThread *stun_thread = NULL; NiceAddress baseaddr; GSource *src; int sock; global_cancellable = g_cancellable_new (); src = g_cancellable_source_new (global_cancellable); g_source_set_dummy_callback (src); g_source_attach (src, NULL); sock = listen_socket (&stun_port); if (sock == -1) { g_assert_not_reached (); } stun_thread = g_thread_new ("listen for STUN requests", stun_thread_func, GINT_TO_POINTER (sock)); // Once the the thread is forked, we want to listen for a signal // that the socket was opened successfully g_mutex_lock (stun_thread_mutex_ptr); g_cond_wait (stun_thread_signal_ptr, stun_thread_mutex_ptr); lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL); g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL); g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); g_object_set (G_OBJECT (lagent), "upnp", USE_UPNP, NULL); g_object_set (G_OBJECT (ragent), "upnp", USE_UPNP, NULL); g_object_set (G_OBJECT (lagent), "stun-server", "127.0.0.1", NULL); g_object_set (G_OBJECT (lagent), "stun-server-port", stun_port, NULL); g_object_set_data (G_OBJECT (lagent), "other-agent", ragent); g_object_set_data (G_OBJECT (ragent), "other-agent", lagent); g_assert (nice_address_set_from_string (&baseaddr, "127.0.0.1")); nice_agent_add_local_address (lagent, &baseaddr); nice_agent_add_local_address (ragent, &baseaddr); g_signal_connect(G_OBJECT(lagent), "candidate-gathering-done", G_CALLBACK(cb_candidate_gathering_done), LEFT_AGENT); g_signal_connect(G_OBJECT(ragent), "candidate-gathering-done", G_CALLBACK(cb_candidate_gathering_done), RIGHT_AGENT); g_signal_connect(G_OBJECT(lagent), "component-state-changed", G_CALLBACK(cb_component_state_changed), LEFT_AGENT); g_signal_connect(G_OBJECT(ragent), "component-state-changed", G_CALLBACK(cb_component_state_changed), RIGHT_AGENT); standard_test (lagent, ragent); bad_credentials_test (lagent, ragent); bad_candidate_test (lagent, ragent); new_candidate_test (lagent, ragent); // Do this to make sure the STUN thread exits exit_stun_thread = TRUE; drop_stun_packets = TRUE; send_dummy_data (); g_object_add_weak_pointer (G_OBJECT (lagent), (gpointer *) &lagent); g_object_add_weak_pointer (G_OBJECT (ragent), (gpointer *) &ragent); g_object_unref (lagent); g_object_unref (ragent); g_thread_join (stun_thread); g_object_unref (global_cancellable); g_source_destroy (src); g_source_unref (src); WAIT_UNTIL_UNSET (lagent, NULL); WAIT_UNTIL_UNSET (ragent, NULL); return 0; }
static gboolean component_source_prepare (GSource *source, gint *timeout_) { ComponentSource *component_source = (ComponentSource *) source; NiceAgent *agent; NiceComponent *component; GSList *parentl, *childl; agent = g_weak_ref_get (&component_source->agent_ref); if (!agent) return FALSE; /* Needed due to accessing the Component. */ agent_lock (); if (!agent_find_component (agent, component_source->stream_id, component_source->component_id, NULL, &component)) goto done; if (component->socket_sources_age == component_source->component_socket_sources_age) goto done; /* If the age has changed, either * - one or more new socket has been prepended * - old sockets have been removed */ /* Add the new child sources. */ for (parentl = component->socket_sources; parentl; parentl = parentl->next) { SocketSource *parent_socket_source = parentl->data; SocketSource *child_socket_source; if (parent_socket_source->socket->fileno == NULL) continue; /* Iterating the list of socket sources every time isn't a big problem * because the number of pairs is limited ~100 normally, so there will * rarely be more than 10. */ childl = g_slist_find_custom (component_source->socket_sources, parent_socket_source->socket, _find_socket_source); /* If we have reached this state, then all sources new sources have been * added, because they are always prepended. */ if (childl) break; child_socket_source = g_slice_new0 (SocketSource); child_socket_source->socket = parent_socket_source->socket; child_socket_source->source = g_socket_create_source (child_socket_source->socket->fileno, G_IO_IN, NULL); g_source_set_dummy_callback (child_socket_source->source); g_source_add_child_source (source, child_socket_source->source); g_source_unref (child_socket_source->source); component_source->socket_sources = g_slist_prepend (component_source->socket_sources, child_socket_source); } for (childl = component_source->socket_sources; childl;) { SocketSource *child_socket_source = childl->data; GSList *next = childl->next; parentl = g_slist_find_custom (component->socket_sources, child_socket_source->socket, _find_socket_source); /* If this is not a currently used socket, remove the relevant source */ if (!parentl) { g_source_remove_child_source (source, child_socket_source->source); g_slice_free (SocketSource, child_socket_source); component_source->socket_sources = g_slist_delete_link (component_source->socket_sources, childl); } childl = next; } /* Update the age. */ component_source->component_socket_sources_age = component->socket_sources_age; done: agent_unlock_and_emit (agent); g_object_unref (agent); /* We can’t be sure if the ComponentSource itself needs to be dispatched until * poll() is called on all the child sources. */ return FALSE; }