Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to provide DNS seeds #19

Merged
merged 2 commits into from
Jul 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ network:
# Supported value: IPv4, IPv6
- http://192.168.1.42:2828
- http://192.168.0.44:2828
dns:
# Supported value: FQDN seed
- seed.bosagora.io

################################################################################
## Quorum slices ##
Expand Down
31 changes: 21 additions & 10 deletions source/agora/common/Config.d
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ public struct Config
/// The administrator interface config
public AdminConfig admin;

/// The list of IPs / DNSes for use with network discovery
/// The list of IPs for use with network discovery
public immutable string[] network;

/// The list of DNS FQDN seeds for use with network discovery
public immutable string[] dns_seeds;

/// The quorum slice config
public immutable QuorumConfig[] quorums;

Expand Down Expand Up @@ -193,23 +196,31 @@ private Config parseConfigFileImpl (CommandLine cmdln)

Node root = Loader.fromFile(cmdln.config_path).load();

if (auto node = "network" in root)
enforce(root["network"].type == NodeType.sequence,
"`network` section must be a section");
else
throw new Exception("The 'network' section is mandatory and must specify at least one peer");
string[] parseSequence ( string section )
{
if (auto node = section in root)
enforce(root[section].type == NodeType.sequence,
format("`%s` section must be a sequence", section));
else
throw new Exception(
format("The '%s' section is mandatory and must " ~
"specify at least one item", section));

string[] network;
foreach (string address; root["network"])
network ~= address;
string[] result;
foreach (string item; root[section])
result ~= item;

return result;
}

enforce("node" in root, "The 'node' section is required");
enforce("quorum" in root, "The 'quorum' section is required");

Config conf =
{
node : parseNodeConfig(root["node"]),
network : assumeUnique(network),
network : assumeUnique(parseSequence("network")),
dns_seeds : assumeUnique(parseSequence("dns")),
quorums : assumeUnique(parseQuorumSection(root["quorum"]))
};

Expand Down
68 changes: 67 additions & 1 deletion source/agora/node/Network.d
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,12 @@ public class NetworkManager
/// but never added again if they're already in known_addresses
protected Set!Address todo_addresses;

/// DNS seeds
private const(string)[] dns_seeds;


/// Ctor
public this (in NodeConfig node_config, in string[] peers)
public this (in NodeConfig node_config, in string[] peers, in string[] dns_seeds)
in { assert(peers.length > 0, "No network option found"); }
do {
this.node_config = node_config;
Expand All @@ -78,12 +81,20 @@ public class NetworkManager
// the node communicating with itself
this.banned_addresses.put(
format("http://%s:%s", this.node_config.address, this.node_config.port));

this.dns_seeds = dns_seeds;
}

/// try to discover the network until we found
/// all the validator nodes from our quorum set.
public void discover ()
{
if (this.dns_seeds.length > 0)
{
logInfo("Resolving DNS from %s", this.dns_seeds);
this.addAddresses(resolveDNSSeeds(this.dns_seeds));
}

logInfo("Discovering from %s", this.todo_addresses.byKey());

while (!this.allPeersConnected())
Expand Down Expand Up @@ -242,3 +253,58 @@ public class NetworkManager

// check up to 10 addresses at once
private immutable MaxConnectingAddresses = 10;

/*******************************************************************************

Resolves IPs out of a list of DNS seeds

Params:
addresses = the set of DNS seeds

Returns:
The resolved set of IPs

*******************************************************************************/

private Set!Address resolveDNSSeeds (in string[] dns_seeds)
{
import std.conv;
import std.string;
import std.socket : getAddressInfo, AddressFamily, ProtocolType;

Set!Address resolved_ips;

foreach (host; dns_seeds)
try
{
logInfo("DNS: contacting seed '%s'..", host);
foreach (addr_info; getAddressInfo(host))
{
logTrace("DNS: checking address %s", addr_info);
if (addr_info.family != AddressFamily.INET &&
addr_info.family != AddressFamily.INET6)
{
logTrace("DNS: rejected non-IP family %s", addr_info.family);
continue;
}

// we only support TCP for now
if (addr_info.protocol != ProtocolType.TCP)
{
logTrace("DNS: rejected non-TCP node %s", addr_info);
continue;
}

// if the port is set to zero, assume default Boa port
auto ip = addr_info.address.to!string.replace(":0", ":2826");
logInfo("DNS: accepted IP %s", ip);
resolved_ips.put(ip);
}
}
catch (Exception ex)
{
logError("Error contacting DNS seed: %s", ex.message);
}

return resolved_ips;
}
2 changes: 1 addition & 1 deletion source/agora/node/Node.d
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class Node (Network) : API
public this (const Config config)
{
this.config = config;
this.network = new Network(config.node, config.network);
this.network = new Network(config.node, config.network, config.dns_seeds);
this.exception = new RestException(
400, Json("The query was incorrect"), string.init, int.init);
}
Expand Down
6 changes: 3 additions & 3 deletions source/agora/test/Base.d
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public class TestNetworkManager : NetworkManager
public TestAPI[PublicKey] apis;

/// Ctor
public this (NodeConfig config, in string[] peers)
public this (NodeConfig config, in string[] peers, in string[] dns_seeds)
{
super(config, peers);
super(config, peers, dns_seeds);
// NetworkManager assumes IP are used but we use pubkey
this.banned_addresses.put(config.key_pair.address.toString());
}
Expand Down Expand Up @@ -262,7 +262,7 @@ public NetworkT makeTestNetwork (NetworkT : TestNetworkManager)


auto net = new NetworkT(NodeConfig.init, node_configs.map!(
c => c.key_pair.address.toString()).array);
c => c.key_pair.address.toString()).array, null);

// Workaround https://issues.dlang.org/show_bug.cgi?id=20002
TestNetworkManager base_net = net;
Expand Down