Ejemplo n.º 1
0
CockpitConnectable *
cockpit_channel_parse_stream (CockpitChannel *self)
{
  CockpitConnectable *connectable;
  GSocketConnectable *address;
  gboolean local;
  gchar *name;

  address = parse_address (self, &name, &local);
  if (!address)
    return NULL;

  connectable = g_new0 (CockpitConnectable, 1);
  connectable->address = address;
  connectable->name = name;
  connectable->refs = 1;
  connectable->local = local;

  if (!parse_stream_options (self, connectable))
    {
      cockpit_connectable_unref (connectable);
      connectable = NULL;
    }

  return connectable;
}
Ejemplo n.º 2
0
static void
close_immediately (CockpitStream *self,
                   const gchar *problem)
{
  GError *error = NULL;
  GIOStream *io;

  if (self->priv->closed)
    return;

  if (problem)
    {
      g_free (self->priv->problem);
      self->priv->problem = g_strdup (problem);
    }

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

  self->priv->closed = TRUE;

  g_debug ("%s: closing stream%s%s", self->priv->name,
           self->priv->problem ? ": " : "",
           self->priv->problem ? self->priv->problem : "");

  if (self->priv->in_source)
    stop_input (self);
  if (self->priv->out_source)
    stop_output (self);

  if (self->priv->io)
    {
      io = self->priv->io;
      self->priv->io = NULL;

      if (self->priv->sig_accept_cert)
        {
          g_signal_handler_disconnect (io, self->priv->sig_accept_cert);
          self->priv->sig_accept_cert = 0;
        }

      g_io_stream_close (io, NULL, &error);
      if (error)
        {
          g_message ("%s: close failed: %s", self->priv->name, error->message);
          g_clear_error (&error);
        }
      g_object_unref (io);
    }

  g_debug ("%s: closed", self->priv->name);
  g_signal_emit (self, cockpit_stream_sig_close, 0, self->priv->problem);
}
Ejemplo n.º 3
0
static void
cockpit_http_client_unref (gpointer data)
{
  CockpitHttpClient *client = data;
  if (--client->refs == 0)
    {
      cockpit_http_client_reset (client);
      if (client->connectable)
        cockpit_connectable_unref (client->connectable);
      g_free (client->name);
      g_slice_free (CockpitHttpClient, client);
    }
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
0
static void
cockpit_web_socket_stream_prepare (CockpitChannel *channel)
{
  CockpitWebSocketStream *self = COCKPIT_WEB_SOCKET_STREAM (channel);
  CockpitConnectable *connectable = NULL;
  JsonObject *options;
  const gchar *path;
  gboolean started = FALSE;

  COCKPIT_CHANNEL_CLASS (cockpit_web_socket_stream_parent_class)->prepare (channel);

  if (self->closed)
    goto out;

  connectable = cockpit_channel_parse_stream (channel);
  if (!connectable)
    goto out;

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &path))
    {
      g_warning ("%s: bad \"path\" field in WebSocket stream request", self->origin);
      goto out;
    }
  else if (path == NULL || path[0] != '/')
    {
      g_warning ("%s: invalid or missing \"path\" field in WebSocket stream request", self->origin);
      goto out;
    }

  self->url = g_strdup_printf ("%s://%s%s", connectable->tls ? "wss" : "ws", connectable->name, path);
  self->origin = g_strdup_printf ("%s://%s", connectable->tls ? "https" : "http", connectable->name);

  /* Parsed elsewhere */
  self->binary = json_object_has_member (options, "binary");

  cockpit_connect_stream_full (connectable, NULL, on_socket_connect, g_object_ref (self));
  started = TRUE;

out:
  if (connectable)
    {
      cockpit_connectable_unref (connectable);
      if (!started)
        cockpit_channel_close (channel, "protocol-error");
    }
}
Ejemplo n.º 6
0
static void
cockpit_http_stream_prepare (CockpitChannel *channel)
{
  CockpitHttpStream *self = COCKPIT_HTTP_STREAM (channel);
  CockpitConnectable *connectable = NULL;
  const gchar *payload;
  const gchar *connection;
  JsonObject *options;
  const gchar *path;

  COCKPIT_CHANNEL_CLASS (cockpit_http_stream_parent_class)->prepare (channel);

  if (self->failed)
    goto out;

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "connection", NULL, &connection))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "bad \"connection\" field in HTTP stream request");
      goto out;
    }

  if (!cockpit_json_get_string (options, "path", "/", &path))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "bad \"path\" field in HTTP stream request");
      goto out;
    }

  /*
   * In http-stream1 the headers are sent as first message.
   * In http-stream2 the headers are in a control message.
   */
  if (cockpit_json_get_string (options, "payload", NULL, &payload) &&
      payload && g_str_equal (payload, "http-stream1"))
    {
      self->headers_inline = TRUE;
    }

  self->client = cockpit_http_client_ensure (connection);

  if (!self->client->connectable ||
      json_object_has_member (options, "unix") ||
      json_object_has_member (options, "port") ||
      json_object_has_member (options, "internal") ||
      json_object_has_member (options, "tls") ||
      json_object_has_member (options, "address"))
    {
      connectable = cockpit_connect_parse_stream (channel);
      if (!connectable)
        goto out;

      if (self->client->connectable)
        cockpit_connectable_unref (self->client->connectable);
      self->client->connectable = cockpit_connectable_ref (connectable);
    }

  self->name = g_strdup_printf ("%s://%s%s",
                                self->client->connectable->tls ? "https" : "http",
                                self->client->connectable->name, path);

  self->stream = cockpit_http_client_checkout (self->client);
  if (!self->stream)
    {
      self->stream = cockpit_stream_connect (self->name, self->client->connectable);
      self->sig_open = g_signal_connect (self->stream, "open", G_CALLBACK (on_stream_open), self);
    }

  /* Parsed elsewhere */
  self->binary = json_object_has_member (options, "binary");

  self->sig_read = g_signal_connect (self->stream, "read", G_CALLBACK (on_stream_read), self);
  self->sig_close = g_signal_connect (self->stream, "close", G_CALLBACK (on_stream_close), self);
  self->sig_rejected_cert = g_signal_connect (self->stream, "rejected-cert",
                                              G_CALLBACK (on_rejected_cert), self);

  /* Let the channel throttle the stream's input flow*/
  cockpit_flow_throttle (COCKPIT_FLOW (self->stream), COCKPIT_FLOW (self));

  /* Let the stream throtlte the channel peer's output flow */
  cockpit_flow_throttle (COCKPIT_FLOW (channel), COCKPIT_FLOW (self->stream));

  /* If not waiting for open */
  if (!self->sig_open)
    cockpit_channel_ready (channel, NULL);

out:
  if (connectable)
    cockpit_connectable_unref (connectable);
}