2020-03-13 18:02:54 +01:00
|
|
|
#pragma once
|
2020-04-13 18:03:19 +02:00
|
|
|
#include "auth.h"
|
2020-05-12 20:33:59 +02:00
|
|
|
#include <string_view>
|
2020-03-13 18:02:54 +01:00
|
|
|
|
|
|
|
namespace lokimq {
|
|
|
|
|
|
|
|
class bt_dict;
|
|
|
|
struct ConnectionID;
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
template <typename... T>
|
2020-05-12 20:33:59 +02:00
|
|
|
bt_dict build_send(ConnectionID to, std::string_view cmd, T&&... opts);
|
2020-03-13 18:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Opaque data structure representing a connection which supports ==, !=, < and std::hash. For
|
|
|
|
/// connections to service node this is the service node pubkey (and you can pass a 32-byte string
|
|
|
|
/// anywhere a ConnectionID is called for). For non-SN remote connections you need to keep a copy
|
|
|
|
/// of the ConnectionID returned by connect_remote().
|
|
|
|
struct ConnectionID {
|
2020-04-26 17:12:04 +02:00
|
|
|
// Default construction; creates a ConnectionID with an invalid internal ID that will not match
|
|
|
|
// an actual connection.
|
|
|
|
ConnectionID() : ConnectionID(0) {}
|
|
|
|
// Construction from a service node pubkey
|
2020-03-13 18:02:54 +01:00
|
|
|
ConnectionID(std::string pubkey_) : id{SN_ID}, pk{std::move(pubkey_)} {
|
|
|
|
if (pk.size() != 32)
|
|
|
|
throw std::runtime_error{"Invalid pubkey: expected 32 bytes"};
|
|
|
|
}
|
2020-04-26 17:12:04 +02:00
|
|
|
// Construction from a service node pubkey
|
2020-05-12 20:33:59 +02:00
|
|
|
ConnectionID(std::string_view pubkey_) : ConnectionID(std::string{pubkey_}) {}
|
2020-04-26 17:12:04 +02:00
|
|
|
|
2020-03-13 18:02:54 +01:00
|
|
|
ConnectionID(const ConnectionID&) = default;
|
|
|
|
ConnectionID(ConnectionID&&) = default;
|
|
|
|
ConnectionID& operator=(const ConnectionID&) = default;
|
|
|
|
ConnectionID& operator=(ConnectionID&&) = default;
|
|
|
|
|
|
|
|
// Returns true if this is a ConnectionID (false for a default-constructed, invalid id)
|
|
|
|
explicit operator bool() const {
|
|
|
|
return id != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Two ConnectionIDs are equal if they are both SNs and have matching pubkeys, or they are both
|
2020-04-26 17:12:04 +02:00
|
|
|
// not SNs and have matching internal IDs and routes. (Pubkeys do not have to match for
|
|
|
|
// non-SNs).
|
2020-03-13 18:02:54 +01:00
|
|
|
bool operator==(const ConnectionID &o) const {
|
2020-04-26 17:12:04 +02:00
|
|
|
if (sn() && o.sn())
|
2020-03-13 18:02:54 +01:00
|
|
|
return pk == o.pk;
|
2020-04-26 17:12:04 +02:00
|
|
|
return id == o.id && route == o.route;
|
2020-03-13 18:02:54 +01:00
|
|
|
}
|
|
|
|
bool operator!=(const ConnectionID &o) const { return !(*this == o); }
|
|
|
|
bool operator<(const ConnectionID &o) const {
|
2020-04-26 17:12:04 +02:00
|
|
|
if (sn() && o.sn())
|
2020-03-13 18:02:54 +01:00
|
|
|
return pk < o.pk;
|
2020-04-26 17:12:04 +02:00
|
|
|
return id < o.id || (id == o.id && route < o.route);
|
2020-03-13 18:02:54 +01:00
|
|
|
}
|
2020-04-26 17:12:04 +02:00
|
|
|
|
2020-03-13 18:02:54 +01:00
|
|
|
// Returns true if this ConnectionID represents a SN connection
|
|
|
|
bool sn() const { return id == SN_ID; }
|
|
|
|
|
2020-04-26 17:12:04 +02:00
|
|
|
// Returns this connection's pubkey, if any. (Note that all curve connections have pubkeys, not
|
|
|
|
// only SNs).
|
2020-03-13 18:02:54 +01:00
|
|
|
const std::string& pubkey() const { return pk; }
|
2020-04-26 17:12:04 +02:00
|
|
|
|
|
|
|
// Returns a copy of the ConnectionID with the route set to empty.
|
|
|
|
ConnectionID unrouted() { return ConnectionID{id, pk, ""}; }
|
|
|
|
|
2020-03-13 18:02:54 +01:00
|
|
|
private:
|
|
|
|
ConnectionID(long long id) : id{id} {}
|
|
|
|
ConnectionID(long long id, std::string pubkey, std::string route = "")
|
|
|
|
: id{id}, pk{std::move(pubkey)}, route{std::move(route)} {}
|
|
|
|
|
|
|
|
constexpr static long long SN_ID = -1;
|
|
|
|
long long id = 0;
|
|
|
|
std::string pk;
|
|
|
|
std::string route;
|
|
|
|
friend class LokiMQ;
|
|
|
|
friend struct std::hash<ConnectionID>;
|
|
|
|
template <typename... T>
|
2020-05-12 20:33:59 +02:00
|
|
|
friend bt_dict detail::build_send(ConnectionID to, std::string_view cmd, T&&... opts);
|
2020-03-13 18:02:54 +01:00
|
|
|
friend std::ostream& operator<<(std::ostream& o, const ConnectionID& conn);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace lokimq
|
|
|
|
namespace std {
|
|
|
|
template <> struct hash<lokimq::ConnectionID> {
|
|
|
|
size_t operator()(const lokimq::ConnectionID &c) const {
|
1.1.0: invocation-time SN auth; failure responses
This replaces the recognition of SN status to be checked per-command
invocation rather than on connection. As this breaks the API quite
substantially, though doesn't really affect the functionality, it seems
suitable to bump the minor version.
This requires a fundamental shift in how the calling application tells
LokiMQ about service nodes: rather than using a callback invoked on
connection, the application now has to call set_active_sns() (or the
more efficient update_active_sns(), if changes are readily available) to
update the list whenever it changes. LokiMQ then keeps this list
internally and uses it when determining whether to invoke.
This release also brings better request responses on errors: when a
request fails, the data argument will now be set to the failure reason,
one of:
- TIMEOUT
- UNKNOWNCOMMAND
- NOT_A_SERVICE_NODE (the remote isn't running in SN mode)
- FORBIDDEN (auth level denies the request)
- FORBIDDEN_SN (SN required and the remote doesn't see us as a SN)
Some of these (UNKNOWNCOMMAND, NOT_A_SERVICE_NODE, FORBIDDEN) were
already sent by remotes, but there was no connection to a request and so
they would log a warning, but the request would have to time out.
These errors (minus TIMEOUT, plus NO_REPLY_TAG signalling that a command
is a request but didn't include a reply tag) are also sent in response
to regular commands, but they simply result in a log warning showing the
error type and the command that caused the failure when received.
2020-04-13 00:57:19 +02:00
|
|
|
return c.sn() ? lokimq::already_hashed{}(c.pk) :
|
2020-04-26 17:12:04 +02:00
|
|
|
std::hash<long long>{}(c.id) + std::hash<std::string>{}(c.route);
|
2020-03-13 18:02:54 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
|