* Copyright (C) 2013 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include "websocket.h"
static WebSocketConnection *web_socket = NULL;
static GString *buffer = NULL;
static GMainLoop *loop = NULL;
static void
on_release_buffer (gpointer user_data)
{
if (buffer == NULL)
buffer = user_data;
else
g_string_free (user_data, TRUE);
}
static gboolean
on_input_data (GIOChannel *channel,
GIOCondition cond,
gpointer user_data)
{
GError *error = NULL;
GIOStatus status;
GBytes *msg;
gsize line;
if (buffer == NULL)
buffer = g_string_sized_new (1024);
status = g_io_channel_read_line_string (channel, buffer, &line, &error);
switch (status)
{
case G_IO_STATUS_ERROR:
g_critical ("Failed to read input: %s", error->message);
g_error_free (error);
g_main_loop_quit (loop);
return FALSE;
case G_IO_STATUS_EOF:
web_socket_connection_close (web_socket, WEB_SOCKET_CLOSE_GOING_AWAY, "going away");
return FALSE;
case G_IO_STATUS_AGAIN:
return TRUE;
case G_IO_STATUS_NORMAL:
msg = g_bytes_new_with_free_func (buffer->str, line, on_release_buffer, buffer);
buffer = NULL;
web_socket_connection_send (web_socket, WEB_SOCKET_DATA_TEXT, NULL, msg);
g_bytes_unref (msg);
return TRUE;
default:
g_assert_not_reached ();
}
}
static void
on_web_socket_open (WebSocketConnection *ws,
gpointer unused)
{
GIOChannel *channel;
g_printerr ("WebSocket: opened %s with %s\n",
web_socket_connection_get_protocol (ws),
web_socket_connection_get_url (ws));
channel = g_io_channel_unix_new (0);
g_io_add_watch (channel, G_IO_IN, on_input_data, NULL);
g_io_channel_unref (channel);
}
static void
on_web_socket_message (WebSocketConnection *ws,
WebSocketDataType type,
GBytes *message)
{
const gchar *data;
gsize len;
g_printerr ("WebSocket: message 0x%x\n", (int)type);
data = g_bytes_get_data (message, &len);
g_print ("%.*s\n", (int)len, data);
}
static void
on_web_socket_close (WebSocketConnection *ws)
{
gushort code;
code = web_socket_connection_get_close_code (ws);
if (code != 0)
g_printerr ("WebSocket: close: %d %s\n", code,
web_socket_connection_get_close_data (ws));
else
g_printerr ("WebSocket: close\n");
g_main_loop_quit (loop);
}
int
main (int argc,
char *argv[])
{
GOptionContext *options;
gchar **protocols = NULL;
gchar *origin = NULL;
GError *error = NULL;
GOptionEntry entries[] = {
{ "origin", 0, 0, G_OPTION_ARG_STRING, &origin, "Web Socket Origin", "url" },
{ "protocol", 0, 0, G_OPTION_ARG_STRING_ARRAY, &protocols, "Web Socket Protocols", "proto" },
{ NULL }
};
signal (SIGPIPE, SIG_IGN);
options = g_option_context_new ("URL");
g_option_context_add_main_entries (options, entries, NULL);
if (!g_option_context_parse (options, &argc, &argv, &error))
{
g_printerr ("frob-websocket: %s\n", error->message);
return 2;
}
if (argc != 2)
{
g_printerr ("frob-websocket: specify the url to connect to\n");
return 2;
}
loop = g_main_loop_new (NULL, FALSE);
web_socket = web_socket_client_new (argv[1], origin, (const gchar **)protocols);
g_signal_connect (web_socket, "open", G_CALLBACK (on_web_socket_open), NULL);
g_signal_connect (web_socket, "message", G_CALLBACK (on_web_socket_message), NULL);
g_signal_connect (web_socket, "close", G_CALLBACK (on_web_socket_close), NULL);
g_main_loop_run (loop);
g_option_context_free (options);
g_object_unref (web_socket);
g_free (origin);
if (buffer)
g_string_free (buffer, TRUE);
g_strfreev (protocols);
return 0;
}