Instead of writing (and logging errors for) every parameter, one at a
time, send all fixed size data in a single struct, followed by all the
variable length data.
All are printf() formatter related. Even if a variable is e.g. a
'short', when used in an expression like '<variable> - 1' it is
promoted to an 'int'.
Closes#16
We now create a copy of the config for each client, and updates it
with the values passed from the client.
Since we're not actually cloning it (and e.g. strdup() all strings
etc) we can't call conf_destroy() to free it, but need to free just
the strings we've replaced.
Make both the server listening socket and the connecting client
sockets non-blocking.
Then, when reading the initial length of the setup packet, handle read
errors from partial reads separately.
Assume the client writes all four bytes of the 'length' field at once,
and bail out if we are unable to read those 4 bytes.
Limit the maximum setup packet size to 128K. This is to prevent
clients from pretending the setup packet is insanely large, causing us
to fail to malloc.
This is used when spawning the slave, to set its current working
directory just before we exec() the client.
In a regular foot instance, we set the cwd from getcwd().
In a foot server instance, each connecting client sends its cwd to the
server, and we use that.
* Client terminal initialization data is now received
asynchronously. To facilitate this, a couple of minor changes to the
protocol was made:
- The client now starts with sending a 4-byte unsigned integer
with the *total* size of the initialization data (*not*
including the size field itself.
- Strings (TERM variable + argv) are now sent NULL-terminated
* The server allocates a single buffer, and fills it
asynchronously. When full (as indicated by the initial 'total size'
integer), we parse it (taking care not to read outside boundaries
etc, and verifies the lengths (of the TERM variable and argv array)
indicated by the client matches the actual lengths of the strings
received.
* The server now ignores 'unexpected' data received from the client,
after the terminal has been instantiated.
When checking of a 'foot --server' instance is already running, we try
to connect to the UNIX socket we're planning on listening on.
In most cases, this will fail hard and fast. But under certain
circumstances, we can get stuck in connect() waiting for a connection
timeout.
Since it should be possible to establish a connection immediately *if*
there's someone actually listening on the socket, rely on the fact
that connect() will fail with a EINPROGRESS if a connection can *not*
be established immediately (and thus no one is listening on it).
In this mode, foot listens on a UNIX socket and creates terminal
windows when clients connect.
A connecting client sends argc/argv to the server, and the server
instantiates a new terminal window.
When the terminal window is closed, the exit code is sent back to the
client.