aboutsummaryrefslogtreecommitdiffstats
path: root/include/proto.h
blob: 4df52a6505ee24fd4a238202f11677d21192b7c0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* The client/server wire, and where sessions live.
 *
 * Frames are `u8 type, u32 length (big endian), payload`. Deliberately dull:
 * the interesting protocol is the JSON control channel (M3) that rides on
 * MSG_CMD, and it speaks the same vocabulary as the headless driver.
 */
#ifndef SLOSH_PROTO_H
#define SLOSH_PROTO_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

/* MSG_HELLO and MSG_RESIZE carry u16 cols, u16 rows, and since the graphics
 * fix two more: u16 cell_w, u16 cell_h, the client's cell size in pixels.
 * A four-byte payload is still accepted and means "I did not say", which is
 * what an older client sends and what a terminal that reports no pixel size
 * leads to. */
enum {
  MSG_HELLO = 1,  /* client -> server: u16 cols, rows[, cell_w, cell_h] */
  MSG_INPUT = 2,  /* client -> server: raw bytes from the terminal */
  MSG_RESIZE = 3, /* client -> server: u16 cols, rows[, cell_w, cell_h] */
  MSG_DETACH = 4, /* client -> server: leave, but keep running */
  MSG_OUTPUT = 5, /* server -> client: bytes for the terminal */
  MSG_EXIT = 6,   /* server -> client: u8 reason */
  MSG_CMD = 7,    /* client -> server: one JSON line */
  MSG_REPLY = 8,  /* server -> client: one JSON line */
};

enum {
  EXIT_SESSION_ENDED = 0, /* the last pane closed */
  EXIT_DETACHED = 1,      /* the user detached */
  EXIT_REPLACED = 2, /* legacy: retained so new clients speak to old servers */
};

typedef struct {
  uint8_t type;
  uint8_t *data;
  uint32_t len;
} msg_t;

/* Incremental framing: feed bytes, take whole messages out. */
typedef struct {
  uint8_t *buf;
  size_t len, cap;
  uint8_t *msg; /* the payload handed to the caller, lifted out of buf */
  size_t msg_cap;
} msg_reader_t;

void msg_reader_init(msg_reader_t *r);
void msg_reader_free(msg_reader_t *r);
void msg_reader_feed(msg_reader_t *r, const uint8_t *data, size_t len);
/* Returns true and fills `out` (data points into the reader's buffer, valid
 * until the next call) when a whole message is available. */
bool msg_reader_next(msg_reader_t *r, msg_t *out);

/* One frame is a type byte and a 32-bit big-endian length, then the payload.
 * The server frames into its own queue (it cannot afford to block on a client
 * that has stopped reading), so the size is not private to proto.c. */
#define MSG_HDR 5

/* Blocking send of one frame. Returns 0 on success, -1 if the peer is gone.
 * For the client, which has nothing else to be doing while it writes. */
int msg_send(int fd, uint8_t type, const void *data, size_t len);

/* $XDG_RUNTIME_DIR/slosh/<name>.sock, or /tmp/slosh-<uid>/<name>.sock.
 * Creates the directory (0700). Returns 0 on success. */
int session_socket_path(const char *name, char *out, size_t cap);
int session_log_path(const char *name, char *out, size_t cap);
/* Names of live sessions (sockets that answer). Caller frees each and the
 * array. Returns the count. */
size_t session_list(char ***out_names);

#endif /* SLOSH_PROTO_H */