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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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)); }
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; }
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); }
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; }
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"); } }
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); }
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); }
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); }
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); }
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); }
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); }
static void cockpit_echo_channel_prepare (CockpitChannel *channel) { COCKPIT_CHANNEL_CLASS (cockpit_echo_channel_parent_class)->prepare (channel); cockpit_channel_ready (channel); }