mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-11 07:10:36 +00:00
36792d4337
Lots and lots of places in the code had broken < operators because they are returning something like: foo < other.foo or bar < other.bar; but this breaks both the strict weak ordering requirements that are required for the "Compare" requirement for things like std::map/set/priority_queue. For example: a = {.foo=1, .bar=3} b = {.foo=3, .bar=1} does not have an ordering over a and b (both `a < b` and `b < a` are satisfied at the same time). This needs to be instead something like: foo < other.foo or (foo == other.foo and bar < other.bar) but that's a bit clunkier, and it is easier to use std::tie for tuple's built-in < comparison which does the right thing: std::tie(foo, bar) < std::tie(other.foo, other.bar) (Initially I noticed this in SockAddr/sockaddr_in6, but upon further investigation this extends to the major of multi-field `operator<`'s.) This fixes it by using std::tie (or something similar) everywhere we are doing multi-field inequalities.
109 lines
2.6 KiB
C++
109 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include "name.hpp"
|
|
#include "serialize.hpp"
|
|
|
|
#include <tuple>
|
|
#include <string_view>
|
|
|
|
#include "llarp/util/status.hpp"
|
|
|
|
namespace llarp::dns
|
|
{
|
|
using SRVTuple = std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string>;
|
|
|
|
struct SRVData
|
|
{
|
|
static constexpr size_t TARGET_MAX_SIZE = 200;
|
|
|
|
std::string service_proto; // service and protocol may as well be together
|
|
|
|
uint16_t priority;
|
|
uint16_t weight;
|
|
uint16_t port;
|
|
|
|
// target string for the SRV record to point to
|
|
// options:
|
|
// empty - refer to query name
|
|
// dot - authoritative "no such service available"
|
|
// any other .loki or .snode - target is that .loki or .snode
|
|
std::string target;
|
|
|
|
// do some basic validation on the target string
|
|
// note: this is not a conclusive, regex solution,
|
|
// but rather some sanity/safety checks
|
|
bool
|
|
IsValid() const;
|
|
|
|
SRVTuple
|
|
toTuple() const;
|
|
|
|
auto
|
|
toTupleRef() const
|
|
{
|
|
return std::tie(service_proto, priority, weight, port, target);
|
|
}
|
|
|
|
/// so we can put SRVData in a std::set
|
|
bool
|
|
operator<(const SRVData& other) const
|
|
{
|
|
return toTupleRef() < other.toTupleRef();
|
|
}
|
|
|
|
bool
|
|
operator==(const SRVData& other) const
|
|
{
|
|
return toTupleRef() == other.toTupleRef();
|
|
}
|
|
|
|
bool
|
|
BEncode(llarp_buffer_t*) const;
|
|
|
|
bool
|
|
BDecode(llarp_buffer_t*);
|
|
|
|
util::StatusObject
|
|
ExtractStatus() const;
|
|
|
|
static SRVData
|
|
fromTuple(SRVTuple tuple);
|
|
|
|
/* bind-like formatted string for SRV records in config file
|
|
*
|
|
* format:
|
|
* srv=service.proto priority weight port target
|
|
*
|
|
* exactly one space character between parts.
|
|
*
|
|
* target can be empty, in which case the space after port should
|
|
* be omitted. if this is the case, the target is
|
|
* interpreted as the .loki or .snode of the current context.
|
|
*
|
|
* if target is not empty, it must be either
|
|
* - simply a full stop (dot/period) OR
|
|
* - a name within the .loki or .snode subdomains. a target
|
|
* specified in this manner must not end with a full stop.
|
|
*/
|
|
bool
|
|
fromString(std::string_view srvString);
|
|
};
|
|
|
|
} // namespace llarp::dns
|
|
|
|
namespace std
|
|
{
|
|
template <>
|
|
struct hash<llarp::dns::SRVData>
|
|
{
|
|
size_t
|
|
operator()(const llarp::dns::SRVData& data) const
|
|
{
|
|
const std::hash<std::string> h_str{};
|
|
const std::hash<uint16_t> h_port{};
|
|
return h_str(data.service_proto) ^ (h_str(data.target) << 3) ^ (h_port(data.priority) << 5)
|
|
^ (h_port(data.weight) << 7) ^ (h_port(data.port) << 9);
|
|
}
|
|
};
|
|
} // namespace std
|