static gboolean on_transport_recv (CockpitTransport *transport, const gchar *channel, GBytes *payload, gpointer user_data) { CockpitWebService *self = user_data; WebSocketDataType data_type; CockpitSocket *socket; gchar *string; GBytes *prefix; if (!channel) return FALSE; /* Forward the message to the right socket */ socket = cockpit_socket_lookup_by_channel (&self->sockets, channel); if (socket && web_socket_connection_get_ready_state (socket->connection) == WEB_SOCKET_STATE_OPEN) { string = g_strdup_printf ("%s\n", channel); prefix = g_bytes_new_take (string, strlen (string)); data_type = GPOINTER_TO_INT (g_hash_table_lookup (socket->channels, channel)); web_socket_connection_send (socket->connection, data_type, prefix, payload); g_bytes_unref (prefix); return TRUE; } return FALSE; }
static void cockpit_channel_socket_recv (CockpitChannel *channel, GBytes *payload) { CockpitChannelSocket *self = COCKPIT_CHANNEL_SOCKET (channel); if (web_socket_connection_get_ready_state (self->socket) == WEB_SOCKET_STATE_OPEN) web_socket_connection_send (self->socket, self->data_type, NULL, payload); }
static gboolean on_transport_recv (CockpitTransport *transport, const gchar *channel, GBytes *payload, CockpitChannelSocket *chock) { if (channel && g_str_equal (channel, chock->channel)) { if (web_socket_connection_get_ready_state (chock->socket) == WEB_SOCKET_STATE_OPEN) web_socket_connection_send (chock->socket, chock->data_type, NULL, payload); return TRUE; } return FALSE; }
static gboolean process_ping (CockpitWebService *self, CockpitSocket *socket, JsonObject *options) { GBytes *payload; /* Respond to a ping without a channel, by saying "pong" */ json_object_set_string_member (options, "command", "pong"); payload = cockpit_json_write_bytes (options); if (web_socket_connection_get_ready_state (socket->connection) == WEB_SOCKET_STATE_OPEN) web_socket_connection_send (socket->connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload); g_bytes_unref (payload); return TRUE; }
static void on_web_socket_open (WebSocketConnection *connection, CockpitWebService *self) { CockpitSocket *socket; JsonArray *capabilities; GBytes *command; JsonObject *object; JsonObject *info; g_info ("New connection to session from %s", cockpit_creds_get_rhost (self->creds)); socket = cockpit_socket_lookup_by_connection (&self->sockets, connection); g_return_if_fail (socket != NULL); object = json_object_new (); json_object_set_string_member (object, "command", "init"); json_object_set_int_member (object, "version", 1); json_object_set_string_member (object, "channel-seed", socket->id); json_object_set_string_member (object, "host", "localhost"); json_object_set_string_member (object, "csrf-token", cockpit_creds_get_csrf_token (self->creds)); capabilities = json_array_new (); json_array_add_string_element (capabilities, "multi"); json_array_add_string_element (capabilities, "credentials"); json_array_add_string_element (capabilities, "binary"); json_object_set_array_member (object, "capabilities", capabilities); info = json_object_new (); json_object_set_string_member (info, "version", PACKAGE_VERSION); json_object_set_string_member (info, "build", COCKPIT_BUILD_INFO); json_object_set_object_member (object, "system", info); command = cockpit_json_write_bytes (object); json_object_unref (object); web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, command); g_bytes_unref (command); /* Do we have an authorize password? if so tell the frontend */ if (cockpit_creds_get_password (self->creds)) send_socket_hints (self, "credential", "password"); g_signal_connect (connection, "message", G_CALLBACK (on_web_socket_message), self); }
static void on_web_socket_noauth (WebSocketConnection *connection, gpointer data) { GBytes *payload; GBytes *prefix; g_debug ("closing unauthenticated web socket"); payload = cockpit_transport_build_control ("command", "init", "problem", "no-session", NULL); prefix = g_bytes_new_static ("\n", 1); web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, prefix, payload); web_socket_connection_close (connection, WEB_SOCKET_CLOSE_GOING_AWAY, "no-session"); g_bytes_unref (prefix); g_bytes_unref (payload); }
static void inbound_protocol_error (CockpitWebService *self, WebSocketConnection *connection, const gchar *problem) { GBytes *payload; if (problem == NULL) problem = "protocol-error"; if (web_socket_connection_get_ready_state (connection) == WEB_SOCKET_STATE_OPEN) { payload = cockpit_transport_build_control ("command", "close", "problem", problem, NULL); web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload); g_bytes_unref (payload); web_socket_connection_close (connection, WEB_SOCKET_CLOSE_SERVER_ERROR, problem); } }
static void on_echo_socket_message (WebSocketConnection *self, WebSocketDataType type, GBytes *message, gpointer user_data) { GByteArray *array = g_bytes_unref_to_array (g_bytes_ref (message)); GBytes *payload; guint i; /* Capitalize and relay back */ for (i = 0; i < array->len; i++) array->data[i] = g_ascii_toupper (array->data[i]); payload = g_byte_array_free_to_bytes (array); web_socket_connection_send (self, type, NULL, payload); g_bytes_unref (payload); }
static gboolean on_ping_time (gpointer user_data) { CockpitWebService *self = user_data; WebSocketConnection *connection; GHashTableIter iter; GBytes *payload; payload = cockpit_transport_build_control ("command", "ping", NULL); g_hash_table_iter_init (&iter, self->sockets.by_connection); while (g_hash_table_iter_next (&iter, (gpointer *)&connection, NULL)) { if (web_socket_connection_get_ready_state (connection) == WEB_SOCKET_STATE_OPEN) web_socket_connection_send (connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload); } g_bytes_unref (payload); return TRUE; }
static void cockpit_web_socket_stream_recv (CockpitChannel *channel, GBytes *message) { CockpitWebSocketStream *self = COCKPIT_WEB_SOCKET_STREAM (channel); WebSocketDataType type; WebSocketState state; /* Should never be called before cockpit_channel_ready() */ g_return_if_fail (self->client != NULL); state = web_socket_connection_get_ready_state (self->client); g_return_if_fail (state >= WEB_SOCKET_STATE_OPEN); if (state == WEB_SOCKET_STATE_OPEN) { type = self->binary ? WEB_SOCKET_DATA_BINARY : WEB_SOCKET_DATA_TEXT; web_socket_connection_send (self->client, type, NULL, message); } }
static void send_socket_hints (CockpitWebService *self, const gchar *name, const gchar *value) { CockpitSocket *socket; GHashTableIter iter; GBytes *payload; payload = cockpit_transport_build_control ("command", "hint", name, value, NULL); g_hash_table_iter_init (&iter, self->sockets.by_connection); while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&socket)) { if (web_socket_connection_get_ready_state (socket->connection) == WEB_SOCKET_STATE_OPEN) { web_socket_connection_send (socket->connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload); } } g_bytes_unref (payload); }
static gboolean on_transport_control (CockpitTransport *transport, const gchar *command, const gchar *channel, JsonObject *options, GBytes *payload, gpointer user_data) { const gchar *problem = "protocol-error"; CockpitWebService *self = user_data; CockpitSocket *socket = NULL; gboolean valid = FALSE; gboolean forward; if (!channel) { if (g_strcmp0 (command, "init") == 0) { problem = process_transport_init (self, transport, options); valid = (problem == NULL); } else if (!self->init_received) { g_message ("bridge did not send 'init' message first"); valid = FALSE; } else if (g_strcmp0 (command, "authorize") == 0) { valid = process_transport_authorize (self, transport, options); } else { g_debug ("received a %s unknown control command", command); valid = TRUE; } } else { socket = cockpit_socket_lookup_by_channel (&self->sockets, channel); /* Usually all control messages with a channel are forwarded */ forward = TRUE; if (g_strcmp0 (command, "close") == 0) { valid = process_close (self, socket, channel); } else { valid = TRUE; } if (forward) { /* Forward this message to the right websocket */ if (socket && web_socket_connection_get_ready_state (socket->connection) == WEB_SOCKET_STATE_OPEN) { web_socket_connection_send (socket->connection, WEB_SOCKET_DATA_TEXT, self->control_prefix, payload); } } } if (!valid) { outbound_protocol_error (self, transport, problem); } return TRUE; /* handled */ }