diff options
author | Přemysl Eric Janouch <p@janouch.name> | 2022-08-08 04:39:20 +0200 |
---|---|---|
committer | Přemysl Eric Janouch <p@janouch.name> | 2022-09-05 14:26:00 +0200 |
commit | 1639235a48dbed75c2563c9a497b41c31a2a1bae (patch) | |
tree | 18193b72fa47e6bcac1358289ac9c36ed00c70ac /xF.c | |
parent | 2160d037943ef0a3adbf4c6e30a91ee0f205c3f3 (diff) | |
download | xK-1639235a48dbed75c2563c9a497b41c31a2a1bae.tar.gz xK-1639235a48dbed75c2563c9a497b41c31a2a1bae.tar.xz xK-1639235a48dbed75c2563c9a497b41c31a2a1bae.zip |
Start X11 and web frontends for xC
For this, we needed a wire protocol. After surveying available options,
it was decided to implement an XDR-like protocol code generator
in portable AWK. It now has two backends, per each of:
- xF, the X11 frontend, is in C, and is meant to be the primary
user interface in the future.
- xP, the web frontend, relies on a protocol proxy written in Go,
and is meant for use on-the-go (no pun intended).
They are very much work-in-progress proofs of concept right now,
and the relay protocol is certain to change.
Diffstat (limited to 'xF.c')
-rw-r--r-- | xF.c | 172 |
1 files changed, 172 insertions, 0 deletions
@@ -0,0 +1,172 @@ +/* + * xF.c: a toothless IRC client frontend + * + * Copyright (c) 2022, Přemysl Eric Janouch <p@janouch.name> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "config.h" +#define PROGRAM_NAME "xF" + +#include "common.c" +#include "xC-proto.c" + +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/keysym.h> +#include <X11/XKBlib.h> +#include <X11/Xft/Xft.h> + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static struct +{ + bool polling; + struct connector connector; + int socket; +} +g; + +static void +on_connector_connecting (void *user_data, const char *address) +{ + (void) user_data; + print_status ("connecting to %s...", address); +} + +static void +on_connector_error (void *user_data, const char *error) +{ + (void) user_data; + print_status ("connection failed: %s", error); +} + +static void +on_connector_failure (void *user_data) +{ + (void) user_data; + exit_fatal ("giving up"); +} + +static void +on_connector_connected (void *user_data, int socket, const char *hostname) +{ + (void) user_data; + (void) hostname; + g.polling = false; + g.socket = socket; +} + +static void +protocol_test (const char *host, const char *port) +{ + struct poller poller = {}; + poller_init (&poller); + + connector_init (&g.connector, &poller); + g.connector.on_connecting = on_connector_connecting; + g.connector.on_error = on_connector_error; + g.connector.on_connected = on_connector_connected; + g.connector.on_failure = on_connector_failure; + + connector_add_target (&g.connector, host, port); + + g.polling = true; + while (g.polling) + poller_run (&poller); + + connector_free (&g.connector); + + struct str s = str_make (); + str_pack_u32 (&s, 0); + struct relay_command_message m = {}; + m.data.hello.command = RELAY_COMMAND_HELLO; + m.data.hello.version = RELAY_VERSION; + if (!relay_command_message_serialize (&m, &s)) + exit_fatal ("serialization failed"); + + uint32_t len = htonl (s.len - sizeof len); + memcpy (s.str, &len, sizeof len); + if (errno = 0, write (g.socket, s.str, s.len) != (ssize_t) s.len) + exit_fatal ("short send or error: %s", strerror (errno)); + + char buf[1 << 20] = ""; + while (errno = 0, read (g.socket, &len, sizeof len) == sizeof len) + { + len = ntohl (len); + if (errno = 0, read (g.socket, buf, MIN (len, sizeof buf)) != len) + exit_fatal ("short read or error: %s", strerror (errno)); + + struct msg_unpacker r = msg_unpacker_make (buf, len); + struct relay_event_message m = {}; + if (!relay_event_message_deserialize (&m, &r)) + exit_fatal ("deserialization failed"); + if (msg_unpacker_get_available (&r)) + exit_fatal ("trailing data"); + + printf ("event: %d\n", m.data.event); + relay_event_message_free (&m); + } + exit_fatal ("short read or error: %s", strerror (errno)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +int +main (int argc, char *argv[]) +{ + static const struct opt opts[] = + { + { 'h', "help", NULL, 0, "display this help and exit" }, + { 'V', "version", NULL, 0, "output version information and exit" }, + { 0, NULL, NULL, 0, NULL } + }; + + struct opt_handler oh = opt_handler_make (argc, argv, opts, + "HOST:PORT", "X11 frontend for xC."); + + int c; + while ((c = opt_handler_get (&oh)) != -1) + switch (c) + { + case 'h': + opt_handler_usage (&oh, stdout); + exit (EXIT_SUCCESS); + case 'V': + printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); + exit (EXIT_SUCCESS); + default: + print_error ("wrong options"); + opt_handler_usage (&oh, stderr); + exit (EXIT_FAILURE); + } + + argc -= optind; + argv += optind; + if (argc != 1) + { + opt_handler_usage (&oh, stderr); + exit (EXIT_FAILURE); + } + opt_handler_free (&oh); + + char *address = xstrdup (argv[0]); + const char *port = NULL, *host = tokenize_host_port (address, &port); + if (!port) + exit_fatal ("missing port number/service name"); + + // TODO: Actually implement an X11-based user interface. + protocol_test (host, port); + return 0; +} |