#include "remote-store.hh" #include "worker-protocol.hh" #include "pool.hh" namespace nix { /** * Bidirectional connection (send and receive) used by the Remote Store * implementation. * * Contains `Source` and `Sink` for actual communication, along with * other information learned when negotiating the connection. */ struct RemoteStore::Connection { /** * Send with this. */ FdSink to; /** * Receive with this. */ FdSource from; /** * Worker protocol version used for the connection. * * Despite its name, I think it is actually the maximum version both * sides support. (If the maximum doesn't exist, we would fail to * establish a connection and produce a value of this type.) */ WorkerProto::Version daemonVersion; /** * Whether the remote side trusts us or not. * * 3 values: "yes", "no", or `std::nullopt` for "unknown". * * Note that the "remote side" might not be just the end daemon, but * also an intermediary forwarder that can make its own trusting * decisions. This would be the intersection of all their trust * decisions, since it takes only one link in the chain to start * denying operations. */ std::optional remoteTrustsUs; /** * The version of the Nix daemon that is processing our requests. * * Do note, it may or may not communicating with another daemon, * rather than being an "end" `LocalStore` or similar. */ std::optional daemonNixVersion; /** * Time this connection was established. */ std::chrono::time_point startTime; /** * Coercion to `WorkerProto::ReadConn`. This makes it easy to use the * factored out worker protocol searlizers with a * `RemoteStore::Connection`. * * The worker protocol connection types are unidirectional, unlike * this type. */ operator WorkerProto::ReadConn () { return WorkerProto::ReadConn { .from = from, .version = daemonVersion, }; } /** * Coercion to `WorkerProto::WriteConn`. This makes it easy to use the * factored out worker protocol searlizers with a * `RemoteStore::Connection`. * * The worker protocol connection types are unidirectional, unlike * this type. */ operator WorkerProto::WriteConn () { return WorkerProto::WriteConn { .to = to, .version = daemonVersion, }; } virtual ~Connection(); virtual void closeWrite() = 0; std::exception_ptr processStderr(Sink * sink = 0, Source * source = 0, bool flush = true); }; /** * A wrapper around Pool::Handle that marks * the connection as bad (causing it to be closed) if a non-daemon * exception is thrown before the handle is closed. Such an exception * causes a deviation from the expected protocol and therefore a * desynchronization between the client and daemon. */ struct RemoteStore::ConnectionHandle { Pool::Handle handle; bool daemonException = false; ConnectionHandle(Pool::Handle && handle) : handle(std::move(handle)) { } ConnectionHandle(ConnectionHandle && h) : handle(std::move(h.handle)) { } ~ConnectionHandle(); RemoteStore::Connection & operator * () { return *handle; } RemoteStore::Connection * operator -> () { return &*handle; } void processStderr(Sink * sink = 0, Source * source = 0, bool flush = true); void withFramedSink(std::function fun); }; }