- `CRSH_IDLE_TIMEOUT`: Timeout (in seconds) for the storage helper to wait
before exiting after client inactivity. If set to 0, the helper will stay up
indefinitely and never exit due to inactivity.
-- `CRSH_FORMAT_MAX`: Maximum version of the protocol greeting message format
- supported by the client as a positive integer. If not set, the storage helper
- must use the default value `1`.
Custom attributes from ccache's `remote_storage` configuration will also
provided as environment variables:
; put: key/value not stored
; remove: key/value not removed
<err> ::= 0x02 <msg> ; e.g. bad parameters, network/server errors
-<capabilities> ::= <cap_len> <cap_data>
-<cap_len> ::= <u8>
-<cap_data> ::= <cap>* ; <cap_len> entries
-<cap> ::= <cap0> ; currently only one capability is defined
-<cap0> ::= 0x00 ; get/put/remove/stop operations
```
-### Server greeting (server to client)
+### Capabilities
-In response to the client's startup parameters, the server sends a greeting to
-the client when the client has connected. The server must use the highest
-greeting message format that is supported by both sides. If the client's maximum
-greeting message format (`CRSH_FORMAT_MAX`) is lower than the lowest format the
-server supports, the server must close the connection.
+- 0x00: `get`/`put`/`remove` requests
+- 0x01: `info` request
-The client must verify server capabilities before sending any request.
-
-#### Greeting 1
-
-```
-<greeting_1> ::= 0x01 <capabilities>
-```
+### Server greeting (server to client)
-#### Greeting 2
+The server sends a greeting to the client when the client has connected. The
+client must verify protocol version and server capabilities before sending any
+request.
```
-<greeting_2> ::= 0x02 <capabilities> <server_identity> <diagnostics>
-<server_identity> ::= <msg> ; software name and version, etc.
-<diagnostics> ::= <diag_num> <diag>* ; <diag_num> diagnostics messages
-<diag_num> ::= <u8>
-<diag> ::= <msg> ; message to be logged by the client
+<greeting> ::= <protocol_ver> <capabilities>
+<protocol_ver> ::= 0x01 ; protocol version 1
+<capabilities> ::= <cap_len> <cap_data>
+<cap_len> ::= <u8>
+<cap_data> ::= <cap>* ; <cap_len> entries
+<cap> ::= <byte> ; see "Capabilities" above
```
### Requests (client to server with response from server)
-#### Get
+#### Get (capability 0x00)
Get a value from remote storage.
<get_response> ::= <ok> <value> | <noop> | <err>
```
-#### Put
+#### Put (capability 0x00)
Put a value in remote storage.
<put_response> ::= <ok> | <noop> | <err>
```
-#### Remove
+#### Remove (capability 0x00)
Remove a value from remote storage.
<remove_response> ::= <ok> | <noop> | <err>
```
-#### Stop
+#### Stop (always available)
Tell the server to shut down and exit. The server must terminate immediately
without waiting for ongoing client operations to finish.
```
Note that the connection might be closed before `<stop_response>` can be read.
+
+#### Info (capability 0x01)
+
+Get information about the helper.
+
+```
+<info_request> ::= 0x04
+<info_response> ::= <server_identity> <diagnostics>
+<server_identity> ::= <msg> ; software name and version, etc.
+<diagnostics> ::= <diag_num> <diag>* ; <diag_num> diagnostics messages
+<diag_num> ::= <u8>
+<diag> ::= <msg> ; message to be logged by the client
+```
constexpr uint8_t k_request_put = 0x01;
constexpr uint8_t k_request_remove = 0x02;
constexpr uint8_t k_request_stop = 0x03;
+constexpr uint8_t k_request_info = 0x04;
} // namespace
}
uint8_t
-Client::greeting_format() const
+Client::protocol_version() const
{
- return m_greeting_format;
-}
-
-const std::string&
-Client::server_identity() const
-{
- return m_server_identity;
-}
-
-const std::vector<std::string>&
-Client::diagnostics() const
-{
- return m_diagnostics;
+ return m_protocol_version;
}
const std::vector<Client::Capability>&
return receive_response_get();
}
+tl::expected<Client::InfoResponse, Client::Error>
+Client::info()
+{
+ if (!m_connected) {
+ return tl::unexpected(Error(Failure::error, "Not connected"));
+ }
+
+ m_request_start_time = std::chrono::steady_clock::now();
+
+ util::Bytes msg({k_request_info});
+ TRY(send_bytes(msg));
+
+ Client::InfoResponse response;
+
+ TRY_ASSIGN(uint8_t identity_len, receive_u8());
+ TRY_ASSIGN(auto identity_bytes, receive_bytes(identity_len));
+ response.server_identity.assign(
+ reinterpret_cast<const char*>(identity_bytes.data()), identity_len);
+
+ TRY_ASSIGN(uint8_t diag_num, receive_u8());
+ response.diagnostics.reserve(diag_num);
+ for (uint8_t i = 0; i < diag_num; ++i) {
+ TRY_ASSIGN(uint8_t msg_len, receive_u8());
+ TRY_ASSIGN(auto msg_bytes, receive_bytes(msg_len));
+ response.diagnostics.emplace_back(
+ reinterpret_cast<const char*>(msg_bytes.data()), msg_len);
+ }
+
+ return response;
+}
+
tl::expected<bool, Client::Error>
Client::put(std::span<const uint8_t> key,
std::span<const uint8_t> value,
if (m_connected) {
m_channel.close();
m_connected = false;
- m_greeting_format = 0;
+ m_protocol_version = 0;
m_capabilities.clear();
- m_server_identity.clear();
- m_diagnostics.clear();
}
}
tl::expected<void, Client::Error>
Client::read_greeting()
{
- TRY_ASSIGN(m_greeting_format, receive_u8());
- if (m_greeting_format != k_greeting_format_1
- && m_greeting_format != k_greeting_format_2) {
+ TRY_ASSIGN(m_protocol_version, receive_u8());
+ if (m_protocol_version != k_protocol_version) {
return tl::unexpected(
Error(Failure::error,
- FMT("Unsupported greeting format: {}", m_greeting_format)));
+ FMT("Unsupported protocol version: {}", m_protocol_version)));
}
TRY_ASSIGN(uint8_t cap_len, receive_u8());
m_capabilities.push_back(static_cast<Capability>(cap_byte));
}
- if (m_greeting_format == k_greeting_format_2) {
- TRY_ASSIGN(uint8_t identity_len, receive_u8());
- TRY_ASSIGN(auto identity_bytes, receive_bytes(identity_len));
- m_server_identity.assign(
- reinterpret_cast<const char*>(identity_bytes.data()), identity_len);
-
- TRY_ASSIGN(uint8_t diag_num, receive_u8());
- m_diagnostics.clear();
- m_diagnostics.reserve(diag_num);
- for (uint8_t i = 0; i < diag_num; ++i) {
- TRY_ASSIGN(uint8_t msg_len, receive_u8());
- TRY_ASSIGN(auto msg_bytes, receive_bytes(msg_len));
- m_diagnostics.emplace_back(
- reinterpret_cast<const char*>(msg_bytes.data()), msg_len);
- }
- }
-
return {};
}
class Client : util::NonCopyable
{
public:
- static constexpr uint8_t k_greeting_format_1 = 0x01;
- static constexpr uint8_t k_greeting_format_2 = 0x02;
- static constexpr uint8_t k_max_greeting_format = k_greeting_format_2;
+ static constexpr uint8_t k_protocol_version = 0x01;
enum class Capability : uint8_t {
- get_put_remove_stop = 0x00, // get/put/remove/stop operations
+ get_put_remove = 0x00, // get/put/remove operations
+ info = 0x01, // info operation
};
enum class Status : uint8_t {
}
};
+ struct InfoResponse
+ {
+ std::string server_identity;
+ std::vector<std::string> diagnostics;
+ };
+
struct PutFlags
{
bool overwrite = false; // bit 0 (LSB): overwrite existing value
~Client();
tl::expected<void, Error> connect(const std::string& path);
- uint8_t greeting_format() const;
+ uint8_t protocol_version() const;
const std::vector<Capability>& capabilities() const;
- const std::string& server_identity() const;
- const std::vector<std::string>& diagnostics() const;
bool has_capability(Capability cap) const;
tl::expected<std::optional<util::Bytes>, Error>
get(std::span<const uint8_t> key);
+
+ tl::expected<InfoResponse, Error> info();
+
tl::expected<bool, Error> put(std::span<const uint8_t> key,
std::span<const uint8_t> value,
PutFlags flags);
+
tl::expected<bool, Error> remove(std::span<const uint8_t> key);
+
tl::expected<void, Error> stop();
void close();
#else
util::BufferedIpcChannelClient<util::UnixSocketClient> m_channel;
#endif
- uint8_t m_greeting_format;
+ uint8_t m_protocol_version = 0;
std::vector<Capability> m_capabilities;
- std::string m_server_identity;
- std::vector<std::string> m_diagnostics;
bool m_connected = false;
std::chrono::milliseconds m_data_timeout;
std::chrono::milliseconds m_request_timeout;
to_string(Client::Capability capability)
{
switch (capability) {
- case Client::Capability::get_put_remove_stop:
- return "get_put_remove_stop";
+ case Client::Capability::get_put_remove:
+ return "get/put/remove";
+ case Client::Capability::info:
+ return "info";
}
return FMT("{}", static_cast<int>(capability));
}
std::string
generate_endpoint_name(
const Url& url,
- const std::vector<RemoteStorage::Backend::Attribute>& attributes,
- uint8_t max_greeting_format)
+ const std::vector<RemoteStorage::Backend::Attribute>& attributes)
{
static const uint8_t delimiter[1] = {0};
hash.hash(delimiter);
hash.hash(attr.value);
}
- hash.hash(delimiter);
- hash.hash(static_cast<int64_t>(max_greeting_format));
return FMT("storage-{}-{}", url.scheme(), util::format_base16(hash.digest()));
}
env_vars.emplace_back(FMT("CRSH_URL={}", url.str()));
env_vars.emplace_back(
FMT("CRSH_IDLE_TIMEOUT={}", idle_timeout.count() / 1000));
- env_vars.emplace_back(
- FMT("CRSH_FORMAT_MAX={}", Client::k_max_greeting_format));
env_vars.emplace_back(FMT("CRSH_NUM_ATTR={}", attributes.size()));
for (size_t i = 0; i < attributes.size(); ++i) {
}
return name == "CRSH_IPC_ENDPOINT" || name == "CRSH_URL"
- || name == "CRSH_IDLE_TIMEOUT" || name == "CRSH_FORMAT_MAX"
- || name == "CRSH_NUM_ATTR" || name.starts_with("CRSH_ATTR_KEY_")
+ || name == "CRSH_IDLE_TIMEOUT" || name == "CRSH_NUM_ATTR"
+ || name.starts_with("CRSH_ATTR_KEY_")
|| name.starts_with("CRSH_ATTR_VALUE_");
}
// No m_endpoint_lock_path needed since we won't spawn a helper.
} else {
// The common case:
- auto endpoint_name =
- generate_endpoint_name(url, attributes, Client::k_max_greeting_format);
+ auto endpoint_name = generate_endpoint_name(url, attributes);
#ifdef _WIN32
m_endpoint = FMT("{}ccache-{}", k_named_pipe_prefix, endpoint_name);
m_endpoint_lock_path = FMT("{}/{}", temp_dir, endpoint_name);
{
if (util::logging::enabled()) {
auto capabilities = util::join(m_client.capabilities(), " ");
- LOG("Storage helper: {} (format: {}, capabilities: {})",
- !m_client.server_identity().empty() ? m_client.server_identity()
- : "[unknown]",
- m_client.greeting_format(),
- capabilities);
- for (const auto& msg : m_client.diagnostics()) {
+ std::string server_identity = "[unknown]";
+ std::vector<std::string> diagnostics;
+ if (m_client.has_capability(Client::Capability::info)) {
+ auto info_result = m_client.info();
+ if (!info_result) {
+ LOG("Failed to get helper info: {}", info_result.error().message);
+ return tl::unexpected(Failure::error);
+ }
+ server_identity = std::move(info_result->server_identity);
+ diagnostics = std::move(info_result->diagnostics);
+ }
+ LOG("Storage helper: {} (capabilities: {})", server_identity, capabilities);
+ for (const auto& msg : diagnostics) {
LOG("Storage helper diagnostic: {}", msg);
}
}
- if (!m_client.has_capability(Client::Capability::get_put_remove_stop)) {
+ if (!m_client.has_capability(Client::Capability::get_put_remove)) {
LOG("Storage helper does not support capability {}",
- static_cast<int>(Client::Capability::get_put_remove_stop));
+ static_cast<int>(Client::Capability::get_put_remove));
return tl::unexpected(Failure::error);
}
Commands:
ping check if helper is reachable
+ info print helper info
get KEY -o FILE get a value and output to file
get KEY -o - get a value and output to stdout
put [--overwrite] KEY -i FILE put a value from file
PRINT(stream, USAGE_TEXT, program_name);
}
-int
+tl::expected<int, std::string>
cmd_get(Client& client, const std::vector<std::string>& args)
{
if (args.size() != 3 || args[1] != "-o") {
- PRINT(stderr, "Error: get requires: KEY -o OUTPUT\n");
- PRINT(stderr, " where OUTPUT is a file path or - for stdout\n");
- return 1;
+ return tl::unexpected("missing arguments");
}
auto key_result = util::parse_base16(args[0]);
if (!key_result) {
- PRINT(stderr, "Error: Invalid hex key: {}\n", key_result.error());
- return 1;
+ return tl::unexpected(FMT("invalid hex key: {}", key_result.error()));
}
const auto& key = *key_result;
const auto& output = args[2];
auto result = client.get(key);
if (!result) {
- PRINT(stderr, "Error: {}\n", result.error().message);
- return 1;
+ return tl::unexpected(result.error().message);
}
if (!*result) {
- PRINT(stderr, "Key not found: {}\n", util::format_base16(key));
+ PRINT(stdout, "Key not found: {}", util::format_base16(key));
return 2;
}
std::fwrite(value.data(), 1, value.size(), stdout);
} else {
if (auto r = util::write_file(output, value); !r) {
- PRINT(stderr, "Error writing to {}: {}", output, r.error());
- return 1;
+ return tl::unexpected(FMT("failed writing to {}: {}", output, r.error()));
}
}
return 0;
}
-int
+tl::expected<int, std::string>
+cmd_info(Client& client, const std::vector<std::string>& args)
+{
+ if (args.size() != 0) {
+ return tl::unexpected("info does not take any argument");
+ }
+
+ auto result = client.info();
+
+ if (!result) {
+ return tl::unexpected(result.error().message);
+ }
+
+ PRINT(stdout, "Server identity: {}\n", result->server_identity);
+ PRINT(stdout, "Capabilities: {}\n", util::join(client.capabilities(), " "));
+ return 0;
+}
+
+tl::expected<int, std::string>
cmd_put(Client& client, const std::vector<std::string>& args)
{
Client::PutFlags flags;
}
if (args.size() - start_idx != 3) {
- PRINT(stderr,
- "Error: put requires: [--overwrite] KEY -i INPUT\n"
- " or: [--overwrite] KEY -v VALUE\n"
- " where INPUT is a file path or - for stdin\n");
- return 1;
+ return tl::unexpected("missing arguments");
}
auto key_result = util::parse_base16(args[start_idx]);
if (!key_result) {
- PRINT(stderr, "Error: Invalid hex key: {}\n", key_result.error());
- return 1;
+ return tl::unexpected(FMT("invalid hex key: {}", key_result.error()));
}
const auto& key = *key_result;
const auto& mode = args[start_idx + 1];
if (input == "-") {
auto r = util::read_fd(STDIN_FILENO);
if (!r) {
- PRINT(stderr, "Error reading from stdin: {}", r.error());
- return 1;
+ return tl::unexpected(FMT("failed reading from stdin: {}", r.error()));
}
value = std::move(*r);
} else {
auto r = util::read_file<util::Bytes>(input);
if (!r) {
- PRINT(stderr, "Error reading from {}: {}", input, r.error());
- return 1;
+ return tl::unexpected(
+ FMT("failed reading from {}: {}", input, r.error()));
}
value = std::move(*r);
}
} else {
- PRINT(stderr, "Error: Unknown mode \"{}\". Use -v or -i\n", mode);
- return 1;
+ return tl::unexpected(FMT("unknown mode flag: {}", mode));
}
auto result = client.put(key, value, flags);
if (!result) {
- PRINT(stderr, "Error: {}\n", result.error().message);
- return 1;
+ return tl::unexpected(result.error().message);
}
if (*result) {
}
}
-int
+tl::expected<int, std::string>
cmd_remove(Client& client, const std::vector<std::string>& args)
{
if (args.size() != 1) {
- PRINT(stderr, "Error: remove requires exactly 1 argument: KEY\n");
- return 1;
+ return tl::unexpected("remove requires exactly 1 argument: KEY");
}
auto key_result = util::parse_base16(args[0]);
if (!key_result) {
- PRINT(stderr, "Error: Invalid hex key: {}\n", key_result.error());
- return 1;
+ return tl::unexpected(FMT("invalid hex key: {}", key_result.error()));
}
const auto& key = *key_result;
auto result = client.remove(key);
if (!result) {
- PRINT(stderr, "Error: {}\n", result.error().message);
- return 1;
+ return tl::unexpected(result.error().message);
}
if (*result) {
}
}
-int
+tl::expected<int, std::string>
cmd_stop(Client& client, const std::vector<std::string>& args)
{
if (!args.empty()) {
- PRINT(stderr, "Error: stop takes no arguments\n");
- return 1;
+ return tl::unexpected("stop takes no arguments");
}
auto result = client.stop();
if (!result) {
- PRINT(stderr, "Error: {}\n", result.error().message);
- return 1;
+ return tl::unexpected(result.error().message);
}
PRINT(stdout, "Helper stopped\n");
return 0;
}
-int
+tl::expected<int, std::string>
cmd_ping(const std::vector<std::string>& args)
{
if (!args.empty()) {
- PRINT(stderr, "Error: ping takes no arguments\n");
- return 1;
+ return tl::unexpected("ping takes no arguments");
}
// Connection and protocol verification already done in main.
} // namespace
+tl::expected<void, std::string>
+require_capability(const Client& client, Client::Capability capability)
+{
+ if (!client.has_capability(capability)) {
+ return tl::unexpected(
+ FMT("storage helper does not support capability \"{}\"",
+ to_string(capability)));
+ }
+ return {};
+}
+
+tl::expected<int, std::string>
+handle_command(Client& client,
+ const std::string& command,
+ const std::vector<std::string>& args)
+{
+ int result = 0;
+
+ if (command == "ping") {
+ TRY_ASSIGN(result, cmd_ping(args));
+ } else if (command == "get") {
+ TRY(require_capability(client, Client::Capability::get_put_remove));
+ TRY_ASSIGN(result, cmd_get(client, args));
+ } else if (command == "info") {
+ TRY(require_capability(client, Client::Capability::info));
+ TRY_ASSIGN(result, cmd_info(client, args));
+ } else if (command == "put") {
+ TRY(require_capability(client, Client::Capability::get_put_remove));
+ TRY_ASSIGN(result, cmd_put(client, args));
+ } else if (command == "remove") {
+ TRY(require_capability(client, Client::Capability::get_put_remove));
+ TRY_ASSIGN(result, cmd_remove(client, args));
+ } else if (command == "stop") {
+ TRY_ASSIGN(result, cmd_stop(client, args));
+ } else {
+ return tl::unexpected(FMT("Unknown command: {}", command));
+ }
+
+ return result;
+}
+
int
main(int argc, char* argv[])
{
#else
argv[1];
#endif
- const std::string command = argv[2];
-
- std::vector<std::string> cmd_args;
- for (int i = 3; i < argc; ++i) {
- cmd_args.push_back(argv[i]);
- }
Client client(k_data_timeout, k_request_timeout);
auto connect_result = client.connect(ipc_endpoint);
if (!connect_result) {
PRINT(stderr,
- "Failed to connect to {}: {}\n",
+ "Failed connecting to {}: {}\n",
ipc_endpoint,
connect_result.error().message);
return 1;
}
- if (!client.has_capability(Client::Capability::get_put_remove_stop)) {
- PRINT(stderr,
- "Helper does not support capability {}\n",
- to_string(Client::Capability::get_put_remove_stop));
- return 1;
+ const std::string command = argv[2];
+ std::vector<std::string> args;
+ for (int i = 3; i < argc; ++i) {
+ args.push_back(argv[i]);
}
- if (command == "ping") {
- return cmd_ping(cmd_args);
- } else if (command == "get") {
- return cmd_get(client, cmd_args);
- } else if (command == "put") {
- return cmd_put(client, cmd_args);
- } else if (command == "remove") {
- return cmd_remove(client, cmd_args);
- } else if (command == "stop") {
- return cmd_stop(client, cmd_args);
+ auto result = handle_command(client, command, args);
+ if (result) {
+ return *result;
} else {
- PRINT(stderr, "Unknown command: {}\n\n", command);
- print_usage(stderr, argv[0]);
+ PRINT(stderr, "Error: {}\n", result.error());
return 1;
}
}
namespace fs = util::filesystem;
-constexpr uint8_t CAP_GET_PUT_REMOVE_STOP = 0x00;
+constexpr uint8_t PROTOCOL_VERSION = 0x01;
+constexpr uint8_t CAP_GET_PUT_REMOVE = 0x00;
+constexpr uint8_t CAP_INFO = 0x01;
constexpr uint8_t STATUS_OK = 0x00;
constexpr uint8_t STATUS_NOOP = 0x01;
constexpr uint8_t REQ_PUT = 0x01;
constexpr uint8_t REQ_REMOVE = 0x02;
constexpr uint8_t REQ_STOP = 0x03;
+constexpr uint8_t REQ_INFO = 0x04;
constexpr uint8_t PUT_FLAG_OVERWRITE = 0x01;
class IpcServer
{
public:
- IpcServer(const std::string& endpoint,
- std::chrono::seconds idle_timeout,
- uint8_t greeting_format)
+ IpcServer(const std::string& endpoint, std::chrono::seconds idle_timeout)
: m_endpoint(endpoint),
m_idle_timeout(idle_timeout),
- m_last_activity(util::now()),
- m_greeting_format(greeting_format)
+ m_last_activity(util::now())
{
}
std::string m_endpoint;
std::chrono::seconds m_idle_timeout;
util::TimePoint m_last_activity;
- uint8_t m_greeting_format;
std::unordered_map<std::string, std::vector<uint8_t>> m_storage;
bool recv_exact(ConnHandle conn, uint8_t* buf, size_t count);
void send_data(ConnHandle conn, const uint8_t* data, size_t len);
void send_error(ConnHandle conn, const char* message);
void handle_get(ConnHandle conn);
+ void handle_info(ConnHandle conn);
void handle_put(ConnHandle conn);
void handle_remove(ConnHandle conn);
void handle_stop(ConnHandle conn);
}
}
+void
+IpcServer::handle_info(ConnHandle conn)
+{
+ log_msg("INFO");
+ const std::string_view identity = "ccache-storage-test";
+ std::vector<uint8_t> response;
+ response.push_back(static_cast<uint8_t>(identity.size()));
+ auto id_data = reinterpret_cast<const uint8_t*>(identity.data());
+ response.insert(response.end(), id_data, id_data + identity.size());
+ response.push_back(0); // 0 diagnostics
+ send_data(conn, response.data(), response.size());
+}
+
void
IpcServer::handle_put(ConnHandle conn)
{
void
IpcServer::handle_client(ConnHandle conn)
{
- if (m_greeting_format == 2) {
- const std::string_view identity = "ccache-storage-test";
- std::vector<uint8_t> greeting;
- greeting.push_back(0x02); // greeting_2
- greeting.push_back(1); // 1 capability
- greeting.push_back(CAP_GET_PUT_REMOVE_STOP);
- greeting.push_back(static_cast<uint8_t>(identity.size()));
- auto id_data = reinterpret_cast<const uint8_t*>(identity.data());
- greeting.insert(greeting.end(), id_data, id_data + identity.size());
- greeting.push_back(0); // 0 diagnostics
- send_data(conn, greeting.data(), greeting.size());
- } else {
- const uint8_t greeting[] = {0x01, 1, CAP_GET_PUT_REMOVE_STOP};
- send_data(conn, greeting, sizeof(greeting));
- }
+ uint8_t greeting[] = {PROTOCOL_VERSION, 2, CAP_GET_PUT_REMOVE, CAP_INFO};
+ send_data(conn, greeting, sizeof(greeting));
while (true) {
uint8_t request_type;
handle_get(conn);
break;
+ case REQ_INFO:
+ handle_info(conn);
+ break;
+
case REQ_PUT:
handle_put(conn);
break;
idle_timeout = *value;
}
- uint8_t greeting_format = 1;
- const char* format_max_env = std::getenv("CRSH_FORMAT_MAX");
- if (format_max_env) {
- auto client_format_max = util::parse_unsigned(format_max_env, 1, UINT8_MAX);
- if (!client_format_max) {
- fail(FMT("Invalid CRSH_FORMAT_MAX: {}", client_format_max.error()));
- }
- constexpr uint8_t server_format_max = 2;
- greeting_format = std::min<uint8_t>(*client_format_max, server_format_max);
- }
-
log_msg("Starting");
log_msg(FMT("IPC endpoint: {}", endpoint));
log_msg(FMT("URL: {}", url));
log_msg(FMT("Idle timeout: {}", idle_timeout));
- log_msg(FMT("Greeting format: {}", greeting_format));
- IpcServer helper(
- endpoint, std::chrono::seconds{idle_timeout}, greeting_format);
+ IpcServer helper(endpoint, std::chrono::seconds{idle_timeout});
helper.run();
log_msg("Shutdown complete");