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);
}
Exemple #6
0
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);
    }
}
Exemple #8
0
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 */
}