Esempio 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);
}
Esempio n. 2
0
static void
mock_echo_channel_close (CockpitChannel *channel,
                         const gchar *problem)
{
  MockEchoChannel *self = (MockEchoChannel *)channel;
  self->close_called = TRUE;
  COCKPIT_CHANNEL_CLASS (mock_echo_channel_parent_class)->close (channel, problem);
}
Esempio n. 3
0
static void
mock_case_channel_class_init (MockCaseChannelClass *klass)
{
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = mock_case_channel_constructed;
  channel_class->recv = mock_case_channel_recv;
}
Esempio n. 4
0
static void
cockpit_echo_channel_class_init (CockpitEchoChannelClass *klass)
{
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);

  channel_class->prepare = cockpit_echo_channel_prepare;
  channel_class->recv = cockpit_echo_channel_recv;
  channel_class->done = cockpit_echo_channel_done;
}
Esempio n. 5
0
static void
cockpit_http_stream_close (CockpitChannel *channel,
                           const gchar *problem)
{
  CockpitHttpStream *self = COCKPIT_HTTP_STREAM (channel);

  if (problem)
    {
      self->failed = TRUE;
      self->state = FINISHED;
      COCKPIT_CHANNEL_CLASS (cockpit_http_stream_parent_class)->close (channel, problem);
    }
  else if (self->state == RELAY_DATA)
    {
      g_debug ("%s: relayed response", self->name);
      self->state = FINISHED;
      cockpit_channel_control (channel, "done", NULL);

      /* Save this for another round? */
      if (self->keep_alive)
        {
          if (self->sig_open)
            g_signal_handler_disconnect (self->stream, self->sig_open);
          g_signal_handler_disconnect (self->stream, self->sig_read);
          g_signal_handler_disconnect (self->stream, self->sig_close);
          g_signal_handler_disconnect (self->stream, self->sig_rejected_cert);
          cockpit_http_client_checkin (self->client, self->stream);
          cockpit_flow_throttle (COCKPIT_FLOW (self->stream), NULL);
          cockpit_flow_throttle (COCKPIT_FLOW (channel), NULL);
          g_object_unref (self->stream);
          self->stream = NULL;
        }

      COCKPIT_CHANNEL_CLASS (cockpit_http_stream_parent_class)->close (channel, NULL);
    }
  else if (self->state != FINISHED)
    {
      g_warn_if_reached ();
      self->failed = TRUE;
      self->state = FINISHED;
      COCKPIT_CHANNEL_CLASS (cockpit_http_stream_parent_class)->close (channel, "internal-error");
    }
}
static void
cockpit_channel_socket_class_init (CockpitChannelSocketClass *klass)
{
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->finalize = cockpit_channel_socket_finalize;

  channel_class->recv = cockpit_channel_socket_recv;
  channel_class->close = cockpit_channel_socket_close;
}
Esempio n. 7
0
static void
cockpit_fslist_class_init (CockpitFslistClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);

  gobject_class->dispose = cockpit_fslist_dispose;
  gobject_class->finalize = cockpit_fslist_finalize;

  channel_class->prepare = cockpit_fslist_prepare;
  channel_class->recv = cockpit_fslist_recv;
}
Esempio n. 8
0
static void
cockpit_text_stream_class_init (CockpitTextStreamClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);

  gobject_class->constructed = cockpit_text_stream_constructed;
  gobject_class->dispose = cockpit_text_stream_dispose;
  gobject_class->finalize = cockpit_text_stream_finalize;

  channel_class->recv = cockpit_text_stream_recv;
  channel_class->close = cockpit_text_stream_close;
}
Esempio n. 9
0
static void
cockpit_fswrite_class_init (CockpitFswriteClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);

  gobject_class->finalize = cockpit_fswrite_finalize;

  channel_class->prepare = cockpit_fswrite_prepare;
  channel_class->recv = cockpit_fswrite_recv;
  channel_class->eof = cockpit_fswrite_eof;
  channel_class->close = cockpit_fswrite_close;
}
Esempio n. 10
0
static void
cockpit_metrics_class_init (CockpitMetricsClass *klass)
{
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = cockpit_metrics_dispose;

  channel_class->recv = cockpit_metrics_recv;
  channel_class->close = cockpit_metrics_close;

  g_type_class_add_private (klass, sizeof (CockpitMetricsPrivate));
}
Esempio n. 11
0
static void
cockpit_internal_metrics_class_init (CockpitInternalMetricsClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  CockpitMetricsClass *metrics_class = COCKPIT_METRICS_CLASS (klass);
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);

  gobject_class->dispose = cockpit_internal_metrics_dispose;
  gobject_class->finalize = cockpit_internal_metrics_finalize;

  channel_class->prepare = cockpit_internal_metrics_prepare;
  metrics_class->tick = cockpit_internal_metrics_tick;
}
Esempio n. 12
0
static void
cockpit_metrics_close (CockpitChannel *channel,
                       const gchar *problem)
{
  CockpitMetrics *self = COCKPIT_METRICS (channel);

  if (self->priv->timeout)
    {
      g_source_remove (self->priv->timeout);
      self->priv->timeout = 0;
    }

  COCKPIT_CHANNEL_CLASS (cockpit_metrics_parent_class)->close (channel, problem);
}
Esempio n. 13
0
static void
cockpit_web_socket_stream_class_init (CockpitWebSocketStreamClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  CockpitChannelClass *channel_class = COCKPIT_CHANNEL_CLASS (klass);

  gobject_class->dispose = cockpit_web_socket_stream_dispose;
  gobject_class->finalize = cockpit_web_socket_stream_finalize;
  gobject_class->constructed = cockpit_web_socket_stream_constructed;

  channel_class->prepare = cockpit_web_socket_stream_prepare;
  channel_class->control = cockpit_web_socket_stream_control;
  channel_class->recv = cockpit_web_socket_stream_recv;
  channel_class->close = cockpit_web_socket_stream_close;
}
Esempio n. 14
0
static void
cockpit_web_socket_stream_close (CockpitChannel *channel,
                                 const gchar *problem)
{
  CockpitWebSocketStream *self = COCKPIT_WEB_SOCKET_STREAM (channel);

  self->closed = TRUE;
  if (self->client && web_socket_connection_get_ready_state (self->client) < WEB_SOCKET_STATE_CLOSING)
    {
      if (problem)
        web_socket_connection_close (self->client, WEB_SOCKET_CLOSE_ABNORMAL, problem);
      else
        web_socket_connection_close (self->client, WEB_SOCKET_CLOSE_NORMAL, "disconnected");
    }
  COCKPIT_CHANNEL_CLASS (cockpit_web_socket_stream_parent_class)->close (channel, problem);
}
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");
    }
}
Esempio n. 16
0
static void
cockpit_text_stream_close (CockpitChannel *channel,
                           const gchar *problem)
{
  CockpitTextStream *self = COCKPIT_TEXT_STREAM (channel);

  self->closing = TRUE;

  /*
   * If closed, call base class handler directly. Otherwise ask
   * our pipe to close first, which will come back here.
  */
  if (self->open)
    cockpit_pipe_close (self->pipe, problem);
  else
    COCKPIT_CHANNEL_CLASS (cockpit_text_stream_parent_class)->close (channel, problem);
}
Esempio n. 17
0
static void
cockpit_fswrite_close (CockpitChannel *channel,
                       const gchar *problem)
{
  CockpitFswrite *self = COCKPIT_FSWRITE (channel);

  if (self->fd != -1)
    close (self->fd);
  self->fd = -1;

  /* Cleanup in case of problem */
  if (problem)
    {
      if (self->tmp_path)
        unlink (self->tmp_path);
    }

  COCKPIT_CHANNEL_CLASS (cockpit_fswrite_parent_class)->close (channel, problem);
}
Esempio n. 18
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);
}
Esempio n. 19
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);
}
Esempio n. 20
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);
}
Esempio n. 21
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);
}
Esempio n. 22
0
static void
cockpit_echo_channel_prepare (CockpitChannel *channel)
{
  COCKPIT_CHANNEL_CLASS (cockpit_echo_channel_parent_class)->prepare (channel);
  cockpit_channel_ready (channel);
}