13269ba93b
Will need to do subclass-specific implementations in the next commit. This isn't because there will be multiple variations of the daemon protocol (whew!) but because different clients pick and choose different parts to use.
129 lines
3.5 KiB
C++
129 lines
3.5 KiB
C++
#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.)
|
|
*/
|
|
unsigned int 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<TrustedFlag> 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<std::string> daemonNixVersion;
|
|
|
|
/**
|
|
* Time this connection was established.
|
|
*/
|
|
std::chrono::time_point<std::chrono::steady_clock> 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,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 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,
|
|
};
|
|
}
|
|
|
|
virtual ~Connection();
|
|
|
|
virtual void closeWrite() = 0;
|
|
|
|
std::exception_ptr processStderr(Sink * sink = 0, Source * source = 0, bool flush = true);
|
|
};
|
|
|
|
/**
|
|
* A wrapper around Pool<RemoteStore::Connection>::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<RemoteStore::Connection>::Handle handle;
|
|
bool daemonException = false;
|
|
|
|
ConnectionHandle(Pool<RemoteStore::Connection>::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<void(Sink & sink)> fun);
|
|
};
|
|
|
|
}
|