예제 #1
0
/**
 * 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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #5
0
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;
}
예제 #6
0
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);
}
예제 #7
0
/**
 * 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;
}
예제 #8
0
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);
}
예제 #9
0
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;
}
예제 #10
0
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;
}
예제 #13
0
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;
}
예제 #14
0
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;
}
예제 #15
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;
}