Пример #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 void
initialize_io (CockpitStream *self)
{
  GInputStream *is;
  GOutputStream *os;

  g_return_if_fail (self->priv->in_source == NULL);

  is = g_io_stream_get_input_stream (self->priv->io);
  os = g_io_stream_get_output_stream (self->priv->io);

  if (!G_IS_POLLABLE_INPUT_STREAM (is) ||
      !g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (is)) ||
      !G_IS_POLLABLE_OUTPUT_STREAM (os) ||
      !g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (os)))
    {
      g_warning ("%s: stream is not pollable", self->priv->name);
      close_immediately (self, "internal-error");
      return;
    }

  if (self->priv->connecting)
    {
      g_object_unref (self->priv->connecting);
      self->priv->connecting = NULL;
    }

  self->priv->in_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (is), NULL);
  g_source_set_name (self->priv->in_source, "stream-input");
  g_source_set_callback (self->priv->in_source, (GSourceFunc)dispatch_input, self, NULL);
  g_source_attach (self->priv->in_source, self->priv->context);

  start_output (self);
}
Пример #3
0
/**
 * g_pollable_output_stream_can_poll:
 * @stream: a #GPollableOutputStream.
 *
 * Checks if @stream is actually pollable. Some classes may implement
 * #GPollableOutputStream but have only certain instances of that
 * class be pollable. If this method returns %FALSE, then the behavior
 * of other #GPollableOutputStream methods is undefined.
 *
 * For any given stream, the value returned by this method is constant;
 * a stream cannot switch from pollable to non-pollable or vice versa.
 *
 * Returns: %TRUE if @stream is pollable, %FALSE if not.
 *
 * Since: 2.28
 */
gboolean
g_pollable_output_stream_can_poll (GPollableOutputStream *stream)
{
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE);

  return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->can_poll (stream);
}
Пример #4
0
/**
 * g_pollable_output_stream_create_source:
 * @stream: a #GPollableOutputStream.
 * @cancellable: (allow-none): a #GCancellable, or %NULL
 *
 * Creates a #GSource that triggers when @stream can be written, or
 * @cancellable is triggered or an error occurs. The callback on the
 * source is of the #GPollableSourceFunc type.
 *
 * As with g_pollable_output_stream_is_writable(), it is possible that
 * the stream may not actually be writable even after the source
 * triggers, so you should use g_pollable_output_stream_write_nonblocking()
 * rather than g_output_stream_write() from the callback.
 *
 * Returns: (transfer full): a new #GSource
 *
 * Since: 2.28
 */
GSource *
g_pollable_output_stream_create_source (GPollableOutputStream *stream,
					GCancellable          *cancellable)
{
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), NULL);

  return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
	  create_source (stream, cancellable);
}
Пример #5
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);
}
Пример #6
0
static void
initialize_io (CockpitStream *self)
{
  GInputStream *is;
  GOutputStream *os;

  g_return_if_fail (self->priv->in_source == NULL);

  is = g_io_stream_get_input_stream (self->priv->io);
  os = g_io_stream_get_output_stream (self->priv->io);

  if (!G_IS_POLLABLE_INPUT_STREAM (is) ||
      !g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (is)) ||
      !G_IS_POLLABLE_OUTPUT_STREAM (os) ||
      !g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (os)))
    {
      g_warning ("%s: stream is not pollable", self->priv->name);
      close_immediately (self, "internal-error");
      return;
    }

  if (self->priv->connecting)
    {
      cockpit_connectable_unref (self->priv->connecting);
      self->priv->connecting = NULL;
    }

  self->priv->in_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (is), NULL);
  g_source_set_name (self->priv->in_source, "stream-input");
  g_source_set_callback (self->priv->in_source, (GSourceFunc)dispatch_input, self, NULL);
  g_source_attach (self->priv->in_source, self->priv->context);

  if (G_IS_TLS_CONNECTION (self->priv->io))
    {
      self->priv->sig_accept_cert =  g_signal_connect (G_TLS_CONNECTION (self->priv->io),
                                                       "accept-certificate",
                                                       G_CALLBACK (on_rejected_certificate),
                                                       self);
    }
  else
    {
      self->priv->sig_accept_cert = 0;
    }

  start_output (self);

  g_signal_emit (self, cockpit_stream_sig_open, 0);
}
Пример #7
0
/**
 * g_pollable_source_new:
 * @pollable_stream: the stream associated with the new source
 *
 * Utility method for #GPollableInputStream and #GPollableOutputStream
 * implementations. Creates a new #GSource that expects a callback of
 * type #GPollableSourceFunc. The new source does not actually do
 * anything on its own; use g_source_add_child_source() to add other
 * sources to it to cause it to trigger.
 *
 * Return value: (transfer full): the new #GSource.
 *
 * Since: 2.28
 */
GSource *
g_pollable_source_new (GObject *pollable_stream)
{
  GSource *source;
  GPollableSource *pollable_source;

  g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (pollable_stream) ||
			G_IS_POLLABLE_OUTPUT_STREAM (pollable_stream), NULL);

  source = g_source_new (&pollable_source_funcs, sizeof (GPollableSource));
  g_source_set_name (source, "GPollableSource");
  pollable_source = (GPollableSource *)source;
  pollable_source->stream = g_object_ref (pollable_stream);

  return source;
}
Пример #8
0
/**
 * cockpit_web_response_new:
 * @io: the stream to send on
 * @path: the path resource or NULL
 * @query: the query string or NULL
 * @in_headers: input headers or NULL
 *
 * Create a new web response.
 *
 * The returned reference belongs to the caller. Additionally
 * once cockpit_web_response_complete() is called, an additional
 * reference is held until the response is sent and flushed.
 *
 * Returns: (transfer full): the new response, unref when done with it
 */
CockpitWebResponse *
cockpit_web_response_new (GIOStream *io,
                          const gchar *path,
                          const gchar *query,
                          GHashTable *in_headers)
{
  CockpitWebResponse *self;
  GOutputStream *out;
  const gchar *connection;

  /* Trying to be a somewhat performant here, avoiding properties */
  self = g_object_new (COCKPIT_TYPE_WEB_RESPONSE, NULL);
  self->io = g_object_ref (io);

  out = g_io_stream_get_output_stream (io);
  if (G_IS_POLLABLE_OUTPUT_STREAM (out))
    {
      self->out = (GPollableOutputStream *)out;
    }
  else
    {
      g_critical ("Cannot send web response over non-pollable output stream: %s",
                  G_OBJECT_TYPE_NAME (out));
    }

  self->full_path = g_strdup (path);
  self->path = self->full_path;
  self->query = g_strdup (query);
  if (self->path)
    self->logname = self->path;
  else
    self->logname = "response";

  self->keep_alive = TRUE;
  if (in_headers)
    {
      connection = g_hash_table_lookup (in_headers, "Connection");
      if (connection)
        self->keep_alive = g_str_equal (connection, "keep-alive");
    }

  return self;
}
Пример #9
0
/**
 * g_pollable_output_stream_write_nonblocking:
 * @stream: a #GPollableOutputStream
 * @buffer: (array length=count) (element-type guint8): a buffer to write
 *     data from
 * @count: the number of bytes you want to write
 * @cancellable: (allow-none): a #GCancellable, or %NULL
 * @error: #GError for error reporting, or %NULL to ignore.
 *
 * Attempts to write up to @count bytes from @buffer to @stream, as
 * with g_output_stream_write(). If @stream is not currently writable,
 * this will immediately return %G_IO_ERROR_WOULD_BLOCK, and you can
 * use g_pollable_output_stream_create_source() to create a #GSource
 * that will be triggered when @stream is writable.
 *
 * Note that since this method never blocks, you cannot actually
 * use @cancellable to cancel it. However, it will return an error
 * if @cancellable has already been cancelled when you call, which
 * may happen if you call this method after a source triggers due
 * to having been cancelled.
 *
 * Virtual: write_nonblocking
 * Return value: the number of bytes written, or -1 on error (including
 *   %G_IO_ERROR_WOULD_BLOCK).
 */
gssize
g_pollable_output_stream_write_nonblocking (GPollableOutputStream  *stream,
					    const void             *buffer,
					    gsize                   count,
					    GCancellable           *cancellable,
					    GError                **error)
{
  gssize res;

  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), -1);
  g_return_val_if_fail (buffer != NULL, 0);

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return -1;

  if (count == 0)
    return 0;

  if (((gssize) count) < 0)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
		   _("Too large count value passed to %s"), G_STRFUNC);
      return -1;
    }

  if (cancellable)
    g_cancellable_push_current (cancellable);

  res = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
    write_nonblocking (stream, buffer, count, error);

  if (cancellable)
    g_cancellable_pop_current (cancellable);

  return res;
}
Пример #10
0
static void
test_pollable_cancellation (NiceAddress *addr)
{
  NiceAgent *agent;
  guint stream_id;
  GIOStream *io_stream;
  GInputStream *input_stream;
  GOutputStream *output_stream;
  GPollableInputStream *pollable_input_stream;
  GPollableOutputStream *pollable_output_stream;
  guint8 buf[65536];
  GError *error = NULL;
  GSource *stream_source;
  GCancellable *cancellable;

  agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245);
  nice_agent_add_local_address (agent, addr);

  /* Add a stream. */
  stream_id = nice_agent_add_stream (agent, 1);

  /* Try building an I/O stream around it. */
  io_stream = nice_agent_get_io_stream (agent, stream_id, 1);
  g_assert (G_IS_IO_STREAM (io_stream));
  g_assert (NICE_IS_IO_STREAM (io_stream));

  /* Grab the input and output streams. */
  input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream));
  g_assert (G_IS_POLLABLE_INPUT_STREAM (input_stream));
  pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream);

  output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream));
  g_assert (G_IS_POLLABLE_OUTPUT_STREAM (output_stream));
  pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream);

  /* Check the non-blocking read() and write() return immediately if called with
   * a cancelled cancellable. */
  cancellable = g_cancellable_new ();
  g_cancellable_cancel (cancellable);

  g_assert (
      g_pollable_input_stream_read_nonblocking (pollable_input_stream,
          buf, sizeof (buf), cancellable, &error) == -1);
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
  g_clear_error (&error);

  g_assert (
      g_pollable_output_stream_write_nonblocking (pollable_output_stream,
          buf, sizeof (buf), cancellable, &error) == -1);
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
  g_clear_error (&error);

  g_object_unref (cancellable);

  /* Check the GSources invoke a callback when run with the cancellable
   * cancelled. */
  cancellable = g_cancellable_new ();
  stream_source =
      g_pollable_input_stream_create_source (pollable_input_stream,
          cancellable);

  check_pollable_source_cancellation (stream_source, cancellable);

  g_source_unref (stream_source);
  g_object_unref (cancellable);

  /* And for the output stream. */
  cancellable = g_cancellable_new ();
  stream_source =
      g_pollable_output_stream_create_source (pollable_output_stream,
          cancellable);

  check_pollable_source_cancellation (stream_source, cancellable);

  g_object_unref (io_stream);
  g_source_unref (stream_source);
  g_object_unref (cancellable);
  g_object_unref (agent);
}
Пример #11
0
static void
test_pollable_properties (NiceAddress *addr)
{
  NiceAgent *agent;
  guint stream_id;
  GIOStream *io_stream;
  GInputStream *input_stream;
  GOutputStream *output_stream;
  GPollableInputStream *pollable_input_stream;
  GPollableOutputStream *pollable_output_stream;
  guint8 buf[65536];
  GError *error = NULL;
  GSource *stream_source;

  agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245);
  nice_agent_add_local_address (agent, addr);

  /* Add a stream. */
  stream_id = nice_agent_add_stream (agent, 1);

  /* Try building an I/O stream around it. */
  io_stream = nice_agent_get_io_stream (agent, stream_id, 1);
  g_assert (G_IS_IO_STREAM (io_stream));
  g_assert (NICE_IS_IO_STREAM (io_stream));

  /* Check the input stream’s properties. */
  input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream));
  g_assert (G_IS_POLLABLE_INPUT_STREAM (input_stream));
  pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream);

  g_assert (g_pollable_input_stream_can_poll (pollable_input_stream));
  g_assert (!g_pollable_input_stream_is_readable (pollable_input_stream));

  g_assert (
      g_pollable_input_stream_read_nonblocking (pollable_input_stream,
          buf, sizeof (buf), NULL, &error) == -1);
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
  g_clear_error (&error);

  stream_source =
      g_pollable_input_stream_create_source (pollable_input_stream, NULL);
  g_assert (stream_source != NULL);
  g_source_unref (stream_source);

  /* Check the output stream’s properties. */
  output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream));
  g_assert (G_IS_POLLABLE_OUTPUT_STREAM (output_stream));
  pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream);

  g_assert (g_pollable_output_stream_can_poll (pollable_output_stream));
  g_assert (!g_pollable_output_stream_is_writable (pollable_output_stream));

  g_assert (
      g_pollable_output_stream_write_nonblocking (pollable_output_stream,
          buf, sizeof (buf), NULL, &error) == -1);
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
  g_clear_error (&error);

  stream_source =
      g_pollable_output_stream_create_source (pollable_output_stream, NULL);
  g_assert (stream_source != NULL);
  g_source_unref (stream_source);

  /* Remove the component and check that the I/O streams close. */
  nice_agent_remove_stream (agent, stream_id);

  g_assert (!g_pollable_input_stream_is_readable (pollable_input_stream));
  g_assert (!g_pollable_output_stream_is_writable (pollable_output_stream));

  g_assert (
      g_pollable_input_stream_read_nonblocking (pollable_input_stream,
          buf, sizeof (buf), NULL, &error) == 0);
  g_assert_no_error (error);

  g_assert (
      g_pollable_output_stream_write_nonblocking (pollable_output_stream,
          buf, sizeof (buf), NULL, &error) == -1);
  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
  g_clear_error (&error);

  g_object_unref (io_stream);
  g_object_unref (agent);
}
Пример #12
0
static void
g_tls_connection_base_set_property (GObject      *object,
				    guint         prop_id,
				    const GValue *value,
				    GParamSpec   *pspec)
{
  GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object);
  GInputStream *istream;
  GOutputStream *ostream;
  gboolean system_certdb;
  GTlsBackend *backend;

  switch (prop_id)
    {
    case PROP_BASE_IO_STREAM:
      if (tls->base_io_stream)
	{
	  g_object_unref (tls->base_io_stream);
	  tls->base_istream = NULL;
	  tls->base_ostream = NULL;
	}
      tls->base_io_stream = g_value_dup_object (value);
      if (!tls->base_io_stream)
	return;

      istream = g_io_stream_get_input_stream (tls->base_io_stream);
      ostream = g_io_stream_get_output_stream (tls->base_io_stream);

      if (G_IS_POLLABLE_INPUT_STREAM (istream) &&
	  g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (istream)))
	{
	  tls->base_istream = G_POLLABLE_INPUT_STREAM (istream);
	  tls->tls_istream = g_tls_input_stream_base_new (tls);
	}
      if (G_IS_POLLABLE_OUTPUT_STREAM (ostream) &&
	  g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (ostream)))
	{
	  tls->base_ostream = G_POLLABLE_OUTPUT_STREAM (ostream);
	  tls->tls_ostream = g_tls_output_stream_base_new (tls);
	}
      break;

    case PROP_REQUIRE_CLOSE_NOTIFY:
      tls->require_close_notify = g_value_get_boolean (value);
      break;

    case PROP_REHANDSHAKE_MODE:
      tls->rehandshake_mode = g_value_get_enum (value);
      break;

    case PROP_USE_SYSTEM_CERTDB:
      system_certdb = g_value_get_boolean (value);
      if (system_certdb != tls->is_system_certdb)
        {
          g_clear_object (&tls->database);
          if (system_certdb)
            {
              backend = g_tls_backend_get_default ();
              tls->database = g_tls_backend_get_default_database (backend);
            }
          tls->is_system_certdb = system_certdb;
	  tls->database_is_unset = FALSE;
        }
      break;

    case PROP_DATABASE:
      g_clear_object (&tls->database);
      tls->database = g_value_dup_object (value);
      tls->is_system_certdb = FALSE;
      tls->database_is_unset = FALSE;
      break;

    case PROP_CERTIFICATE:
      if (tls->certificate)
	g_object_unref (tls->certificate);
      tls->certificate = g_value_dup_object (value);
      break;

    case PROP_INTERACTION:
      g_clear_object (&tls->interaction);
      tls->interaction = g_value_dup_object (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}