Exemplo n.º 1
0
static void
cockpit_fswrite_prepare (CockpitChannel *channel)
{
  CockpitFswrite *self = COCKPIT_FSWRITE (channel);
  const gchar *problem = "protocol-error";
  JsonObject *options;
  gchar *actual_tag = NULL;

  COCKPIT_CHANNEL_CLASS (cockpit_fswrite_parent_class)->prepare (channel);

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &self->path))
    {
      g_warning ("invalid \"path\" option for fswrite1 channel");
      goto out;
    }
  else if (self->path == NULL || g_str_equal (self->path, ""))
    {
      g_warning ("missing \"path\" option for fswrite1 channel");
      goto out;
    }

  if (!cockpit_json_get_string (options, "tag", NULL, &self->expected_tag))
    {
      g_warning ("%s: invalid \"tag\" option for fswrite1 channel", self->path);
      goto out;
    }

  actual_tag = cockpit_get_file_tag (self->path);
  if (self->expected_tag && g_strcmp0 (self->expected_tag, actual_tag))
    {
      problem = "change-conflict";
      goto out;
    }

  // TODO - delay the opening until the first content message.  That
  // way, we don't create a useless temporary file (which might even
  // fail).

  for (int i = 1; i < 10000; i++)
    {
      self->tmp_path = g_strdup_printf ("%s.%d", self->path, i);
      self->fd = open (self->tmp_path, O_WRONLY | O_CREAT | O_EXCL, 0666);
      if (self->fd >= 0 || errno != EEXIST)
        break;
      g_free (self->tmp_path);
      self->tmp_path = NULL;
    }

  problem = NULL;
  if (self->fd < 0)
    close_with_errno (self, "couldn't open unique file", errno);
  else
    cockpit_channel_ready (channel);

out:
  g_free (actual_tag);
  if (problem)
      cockpit_channel_close (channel, problem);
}
Exemplo n.º 2
0
static void
on_web_socket_open (WebSocketConnection *connection,
                    gpointer user_data)
{
  CockpitWebSocketStream *self = COCKPIT_WEB_SOCKET_STREAM (user_data);
  CockpitChannel *channel = COCKPIT_CHANNEL (user_data);
  JsonObject *object;
  JsonObject *headers;
  GHashTableIter iter;
  gpointer key, value;

  headers = json_object_new ();

  g_hash_table_iter_init (&iter, web_socket_client_get_headers (WEB_SOCKET_CLIENT (self->client)));
  while (g_hash_table_iter_next (&iter, &key, &value))
    json_object_set_string_member (headers, key, value);

  object = json_object_new ();
  json_object_set_object_member (object, "headers", headers);

  cockpit_channel_control (channel, "response", object);
  json_object_unref (object);

  cockpit_channel_ready (channel, NULL);
}
Exemplo n.º 3
0
static void
on_stream_open (CockpitStream *stream,
                gpointer user_data)
{
  CockpitChannel *channel = user_data;
  cockpit_channel_ready (channel, NULL);
}
Exemplo n.º 4
0
static void
cockpit_text_stream_constructed (GObject *object)
{
  CockpitTextStream *self = COCKPIT_TEXT_STREAM (object);
  CockpitChannel *channel = COCKPIT_CHANNEL (self);
  GSocketAddress *address;
  const gchar *unix_path;
  const gchar **argv;
  const gchar **env;

  G_OBJECT_CLASS (cockpit_text_stream_parent_class)->constructed (object);

  unix_path = cockpit_channel_get_option (channel, "unix");
  argv = cockpit_channel_get_strv_option (channel, "spawn");

  if (argv == NULL && unix_path == NULL)
    {
      g_warning ("did not receive a unix or spawn option");
      g_idle_add_full (G_PRIORITY_DEFAULT, on_idle_protocol_error,
                       g_object_ref (channel), g_object_unref);
      return;
    }
  else if (argv != NULL && unix_path != NULL)
    {
      g_warning ("received both a unix and spawn option");
      g_idle_add_full (G_PRIORITY_DEFAULT, on_idle_protocol_error,
                       g_object_ref (channel), g_object_unref);
      return;
    }
  else if (unix_path)
    {
      self->name = unix_path;
      address = g_unix_socket_address_new (unix_path);
      self->pipe = cockpit_pipe_connect (self->name, address);
      g_object_unref (address);
    }
  else if (argv)
    {
      self->name = argv[0];
      env = cockpit_channel_get_strv_option (channel, "environ");
      if (cockpit_channel_get_bool_option (channel, "pty"))
        self->pipe = cockpit_pipe_pty (argv, env, NULL);
      else
        self->pipe = cockpit_pipe_spawn (argv, env, NULL);
    }

  self->sig_read = g_signal_connect (self->pipe, "read", G_CALLBACK (on_pipe_read), self);
  self->sig_close = g_signal_connect (self->pipe, "close", G_CALLBACK (on_pipe_close), self);
  self->open = TRUE;
  cockpit_channel_ready (channel);
}
static void
on_socket_open (WebSocketConnection *connection,
                gpointer user_data)
{
  CockpitChannel *channel = COCKPIT_CHANNEL (user_data);
  JsonObject *open;

  /*
   * Actually open the channel. We wait until the WebSocket is open
   * before doing this, so we don't receive messages from the bridge
   * before the websocket is open.
   */

  open = cockpit_channel_get_options (channel);
  cockpit_channel_control (channel, "open", open);

  /* Tell the channel we're ready */
  cockpit_channel_ready (channel, NULL);
}
Exemplo n.º 6
0
static void
cockpit_fswatch_prepare (CockpitChannel *channel)
{
  CockpitFswatch *self = COCKPIT_FSWATCH (channel);
  JsonObject *options;
  GError *error = NULL;
  const gchar *path;

  COCKPIT_CHANNEL_CLASS (cockpit_fswatch_parent_class)->prepare (channel);

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &path))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "invalid \"path\" option for fswatch channel");
      goto out;
    }
  else if (path == NULL || *path == 0)
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "missing \"path\" option for fswatch channel");
      goto out;
    }

  GFile *file = g_file_new_for_path (path);
  GFileMonitor *monitor = g_file_monitor (file, 0, NULL, &error);
  g_object_unref (file);

  if (monitor == NULL)
    {
      cockpit_channel_fail (channel, "internal-error", "%s: %s", self->path, error->message);
      goto out;
    }

  self->monitor = monitor;
  self->sig_changed = g_signal_connect (self->monitor, "changed", G_CALLBACK (on_changed), self);

  cockpit_channel_ready (channel, NULL);

out:
  g_clear_error (&error);
}
Exemplo n.º 7
0
static void
mock_case_channel_constructed (GObject *obj)
{
  MockCaseChannel *self = (MockCaseChannel *)obj;
  const gchar *payload = NULL;
  JsonObject *options;

  G_OBJECT_CLASS (mock_case_channel_parent_class)->constructed (obj);

  options = cockpit_channel_get_options (COCKPIT_CHANNEL (obj));
  if (!cockpit_json_get_string (options, "payload", NULL, &payload))
    g_assert_not_reached ();

  if (g_strcmp0 (payload, "upper") == 0)
    self->function = g_ascii_toupper;
  else if (g_strcmp0 (payload, "lower") == 0)
    self->function = g_ascii_tolower;
  else
    g_assert_not_reached ();

  cockpit_channel_ready (COCKPIT_CHANNEL (self));
}
Exemplo n.º 8
0
static void
cockpit_fslist_prepare (CockpitChannel *channel)
{
  CockpitFslist *self = COCKPIT_FSLIST (channel);
  const gchar *problem = "protocol-error";
  JsonObject *options;
  GError *error = NULL;
  GFile *file = NULL;
  gboolean watch;

  COCKPIT_CHANNEL_CLASS (cockpit_fslist_parent_class)->prepare (channel);

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &self->path))
    {
      g_warning ("invalid \"path\" option for fslist1 channel");
      goto out;
    }
  if (self->path == NULL || *(self->path) == 0)
    {
      g_warning ("missing \"path\" option for fslist1 channel");
      goto out;
    }

  if (!cockpit_json_get_bool (options, "watch", TRUE, &watch))
    {
      g_warning ("invalid \"watch\" option for fslist1 channel");
      goto out;
    }

  self->cancellable = g_cancellable_new ();

  file = g_file_new_for_path (self->path);
  g_file_enumerate_children_async (file,
                                   G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
                                   G_FILE_QUERY_INFO_NONE,
                                   G_PRIORITY_DEFAULT,
                                   self->cancellable,
                                   on_enumerator_ready,
                                   self);

  if (watch)
    {
      self->monitor = g_file_monitor_directory (file, 0, NULL, &error);
      if (self->monitor == NULL)
        {
          g_message ("%s: couldn't monitor directory: %s", self->path, error->message);
          options = cockpit_channel_close_options (channel);
          json_object_set_string_member (options, "message", error->message);
          problem = "internal-error";
          goto out;
        }

      self->sig_changed = g_signal_connect (self->monitor, "changed", G_CALLBACK (on_changed), self);
    }

  cockpit_channel_ready (channel);
  problem = NULL;

out:
  g_clear_error (&error);
  if (file)
    g_object_unref (file);
  if (problem)
    cockpit_channel_close (channel, problem);
}
Exemplo n.º 9
0
static void
cockpit_internal_metrics_prepare (CockpitChannel *channel)
{
  CockpitInternalMetrics *self = COCKPIT_INTERNAL_METRICS (channel);
  JsonObject *options;
  JsonArray *metrics;
  int i;

  COCKPIT_CHANNEL_CLASS (cockpit_internal_metrics_parent_class)->prepare (channel);

  options = cockpit_channel_get_options (channel);

  /* "instances" option */
  if (!cockpit_json_get_strv (options, "instances", NULL, (gchar ***)&self->instances))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "invalid \"instances\" option (not an array of strings)");
      return;
    }

  /* "omit-instances" option */
  if (!cockpit_json_get_strv (options, "omit-instances", NULL, (gchar ***)&self->omit_instances))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "invalid \"omit-instances\" option (not an array of strings)");
      return;
    }

  /* "metrics" option */
  self->n_metrics = 0;
  if (!cockpit_json_get_array (options, "metrics", NULL, &metrics))
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "invalid \"metrics\" option was specified (not an array)");
      return;
    }
  if (metrics)
    self->n_metrics = json_array_get_length (metrics);

  self->metrics = g_new0 (MetricInfo, self->n_metrics);
  for (i = 0; i < self->n_metrics; i++)
    {
      MetricInfo *info = &self->metrics[i];
      if (!convert_metric_description (self, json_array_get_element (metrics, i), info, i))
        return;
      if (!info->desc)
        {
          cockpit_channel_close (channel, "not-supported");
          return;
        }
    }

  /* "interval" option */
  if (!cockpit_json_get_int (options, "interval", 1000, &self->interval))
    {
      cockpit_channel_fail (channel, "protocol-error", "invalid \"interval\" option");
      return;
    }
  else if (self->interval <= 0 || self->interval > G_MAXINT)
    {
      cockpit_channel_fail (channel, "protocol-error",
                            "invalid \"interval\" value: %" G_GINT64_FORMAT, self->interval);
      return;
    }

  self->need_meta = TRUE;

  cockpit_metrics_metronome (COCKPIT_METRICS (self), self->interval);
  cockpit_channel_ready (channel, NULL);
}
Exemplo n.º 10
0
static void
mock_echo_channel_constructed (GObject *obj)
{
  G_OBJECT_CLASS (mock_echo_channel_parent_class)->constructed (obj);
  cockpit_channel_ready (COCKPIT_CHANNEL (obj));
}
Exemplo n.º 11
0
static void
on_files_listed (GObject *source_object,
                 GAsyncResult *res,
                 gpointer user_data)
{
  GError *error = NULL;
  JsonObject *options;
  GList *files;

  files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source_object), res, &error);
  if (error)
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          CockpitFslist *self = COCKPIT_FSLIST (user_data);
          g_message ("%s: couldn't process files %s", COCKPIT_FSLIST(user_data)->path, error->message);
          options = cockpit_channel_close_options (COCKPIT_CHANNEL (self));
          json_object_set_string_member (options, "message", error->message);
          cockpit_channel_close (COCKPIT_CHANNEL (self), "internal-error");
        }
      g_clear_error (&error);
      return;
    }

  CockpitFslist *self = COCKPIT_FSLIST (user_data);

  if (files == NULL)
    {
      g_clear_object (&self->cancellable);
      g_object_unref (source_object);

      cockpit_channel_ready (COCKPIT_CHANNEL (self));

      if (self->monitor == NULL)
        {
          cockpit_channel_control (COCKPIT_CHANNEL (self), "done", NULL);
          cockpit_channel_close (COCKPIT_CHANNEL (self), NULL);
        }
      return;
    }

  for (GList *l = files; l; l = l->next)
    {
      GFileInfo *info = G_FILE_INFO (l->data);
      JsonObject *msg;
      GBytes *msg_bytes;

      msg = json_object_new ();
      json_object_set_string_member (msg, "event", "present");
      json_object_set_string_member
        (msg, "path", g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME));
      json_object_set_string_member
        (msg, "type", cockpit_file_type_to_string (g_file_info_get_file_type (info)));
      msg_bytes = cockpit_json_write_bytes (msg);
      json_object_unref (msg);
      cockpit_channel_send (COCKPIT_CHANNEL(self), msg_bytes, FALSE);
      g_bytes_unref (msg_bytes);
    }

  g_list_free_full (files, g_object_unref);

  g_file_enumerator_next_files_async (G_FILE_ENUMERATOR (source_object),
                                      10,
                                      G_PRIORITY_DEFAULT,
                                      self->cancellable,
                                      on_files_listed,
                                      self);
}
Exemplo n.º 12
0
static void
cockpit_echo_channel_prepare (CockpitChannel *channel)
{
  COCKPIT_CHANNEL_CLASS (cockpit_echo_channel_parent_class)->prepare (channel);
  cockpit_channel_ready (channel);
}
Exemplo n.º 13
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);
}