public void ClusterMemberSettings_ComputeIntervals() { ClusterMemberSettings settings = new ClusterMemberSettings((MsgEP)"logical://foo"); settings.MasterBroadcastInterval = TimeSpan.FromSeconds(2); settings.MissingMasterCount = 3; settings.SlaveUpdateInterval = TimeSpan.FromSeconds(4); settings.MissingSlaveCount = 5; Assert.AreEqual(TimeSpan.FromSeconds(2 * 3), settings.MissingMasterInterval); Assert.AreEqual(TimeSpan.FromSeconds(4 * 5), settings.MissingSlaveInterval); }
public void ClusterMemberSettings_Equals() { ClusterMemberSettings s1, s2; s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); Assert.AreEqual(s1, s2); s1.ClusterBaseEP = "logical://foo"; Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.MasterBroadcastInterval = TimeSpan.FromMinutes(99); Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.SlaveUpdateInterval = TimeSpan.FromMinutes(99); Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.ElectionInterval = TimeSpan.FromMinutes(99); Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.MissingMasterCount = 99; Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.MissingSlaveCount = 99; Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.MasterBkInterval = TimeSpan.FromMinutes(99); Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.SlaveBkInterval = TimeSpan.FromMinutes(99); Assert.AreNotEqual(s1, s2); s1 = new ClusterMemberSettings((MsgEP)"logical://test"); s2 = new ClusterMemberSettings((MsgEP)"logical://test"); s1.BkInterval = TimeSpan.FromMinutes(99); Assert.AreNotEqual(s1, s2); }
public void ClusterMemberSettings_Default() { ClusterMemberSettings settings = new ClusterMemberSettings((MsgEP)"logical://test"); Assert.AreEqual((MsgEP)"logical://test", settings.ClusterBaseEP); Assert.AreEqual(ClusterMemberMode.Normal, settings.Mode); Assert.AreEqual(TimeSpan.FromSeconds(30), settings.MasterBroadcastInterval); Assert.AreEqual(TimeSpan.FromSeconds(30), settings.SlaveUpdateInterval); Assert.AreEqual(TimeSpan.FromSeconds(10), settings.ElectionInterval); Assert.AreEqual(2, settings.MissingMasterCount); Assert.AreEqual(2, settings.MissingSlaveCount); Assert.AreEqual(TimeSpan.FromSeconds(1), settings.MasterBkInterval); Assert.AreEqual(TimeSpan.FromSeconds(1), settings.SlaveBkInterval); Assert.AreEqual(TimeSpan.FromSeconds(1), settings.BkInterval); }
public void ClusterStatus_Serialize_ClusterStatus() { Dictionary <string, string> clusterProps = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); EnhancedMemoryStream ms = new EnhancedMemoryStream(); ClusterMemberSettings settings = new ClusterMemberSettings((MsgEP)"logical://test"); ClusterMemberStatus memberStatus; ClusterStatus status; status = new ClusterStatus((MsgEP)"logical://test/master"); status.LoadProperties(clusterProps); status.MasterProtocolCaps = unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF); memberStatus = new ClusterMemberStatus("logical://test/master", ClusterMemberState.Master, settings); memberStatus["setting1"] = "value1"; memberStatus["setting2"] = "value2"; status.Members.Add(memberStatus); memberStatus = new ClusterMemberStatus("logical://test/bar", ClusterMemberState.Slave, settings); memberStatus["setting3"] = "value3"; memberStatus["setting4"] = "value4"; status.Members.Add(memberStatus); status.Write(ms); ms.Position = 0; status = new ClusterStatus(ms); Assert.AreEqual((MsgEP)"logical://test/master", status.MasterEP); Assert.AreEqual(Helper.MachineName, status.MasterMachine); Assert.AreEqual(unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF), status.MasterProtocolCaps); Assert.AreEqual(2, status.Members.Count); memberStatus = status.Members[0]; Assert.AreEqual((MsgEP)"logical://test/master", memberStatus.InstanceEP); Assert.AreEqual(Helper.MachineName, memberStatus.MachineName); Assert.AreEqual(ClusterMemberState.Master, memberStatus.State); Assert.AreEqual(settings, memberStatus.Settings); Assert.AreEqual("value1", memberStatus["setting1"]); Assert.AreEqual("value2", memberStatus["setting2"]); memberStatus = status.Members[1]; Assert.AreEqual((MsgEP)"logical://test/bar", memberStatus.InstanceEP); Assert.AreEqual(Helper.MachineName, memberStatus.MachineName); Assert.AreEqual(ClusterMemberState.Slave, memberStatus.State); Assert.AreEqual(settings, memberStatus.Settings); Assert.AreEqual("value3", memberStatus["setting3"]); Assert.AreEqual("value4", memberStatus["setting4"]); }
public void ClusterMemberSettings_LoadFromClusterMemberStatus() { ClusterMemberStatus status; ClusterMemberSettings settings; string cfg; try { cfg = @" §ion Settings ClusterBaseEP = logical://test Mode = PreferSlave MasterBroadcastInterval = 10m SlaveUpdateInterval = 11m MissingMasterCount = 13 MissingSlaveCount = 20 MasterBkInterval = 14m SlaveBkInterval = 15m BkInterval = 16m ElectionInterval = 17m &endsection "; Config.SetConfig(cfg.Replace('&', '#')); settings = ClusterMemberSettings.LoadConfig("Settings"); status = new ClusterMemberStatus("logical://test/foo", ClusterMemberState.Slave, settings); settings = new ClusterMemberSettings(status); Assert.AreEqual((MsgEP)"logical://test", settings.ClusterBaseEP); Assert.AreEqual(ClusterMemberMode.PreferSlave, settings.Mode); Assert.AreEqual(TimeSpan.FromMinutes(10), settings.MasterBroadcastInterval); Assert.AreEqual(TimeSpan.FromMinutes(11), settings.SlaveUpdateInterval); Assert.AreEqual(13, settings.MissingMasterCount); Assert.AreEqual(20, settings.MissingSlaveCount); Assert.AreEqual(TimeSpan.FromMinutes(14), settings.MasterBkInterval); Assert.AreEqual(TimeSpan.FromMinutes(15), settings.SlaveBkInterval); Assert.AreEqual(TimeSpan.FromMinutes(16), settings.BkInterval); Assert.AreEqual(TimeSpan.FromMinutes(17), settings.ElectionInterval); } finally { Config.SetConfig(null); } }
public void ClusterStatus_Clone_ClusterStatus() { ClusterMemberSettings settings = new ClusterMemberSettings((MsgEP)"logical://test"); ClusterMemberStatus memberStatus; ClusterStatus input, output; input = new ClusterStatus((MsgEP)"logical://test/master"); input.ClusterTime = DateTime.UtcNow; input.MasterProtocolCaps = unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF); memberStatus = new ClusterMemberStatus("logical://test/master", ClusterMemberState.Master, settings); memberStatus["setting1"] = "value1"; memberStatus["setting2"] = "value2"; input.Members.Add(memberStatus); memberStatus = new ClusterMemberStatus("logical://test/bar", ClusterMemberState.Slave, settings); memberStatus["setting3"] = "value3"; memberStatus["setting4"] = "value4"; input.Members.Add(memberStatus); output = input.Clone(); Assert.AreNotSame(input, output); Assert.AreEqual((MsgEP)"logical://test/master", output.MasterEP); Assert.AreEqual(Helper.MachineName, output.MasterMachine); Assert.AreEqual(input.ClusterTime, output.ClusterTime); Assert.AreEqual(input.ReceiveTime, output.ReceiveTime); Assert.AreEqual(unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF), output.MasterProtocolCaps); Assert.AreEqual(2, output.Members.Count); memberStatus = output.Members[0]; Assert.AreEqual((MsgEP)"logical://test/master", memberStatus.InstanceEP); Assert.AreEqual(Helper.MachineName, memberStatus.MachineName); Assert.AreEqual(ClusterMemberState.Master, memberStatus.State); Assert.AreEqual(settings, memberStatus.Settings); Assert.AreEqual("value1", memberStatus["setting1"]); Assert.AreEqual("value2", memberStatus["setting2"]); memberStatus = output.Members[1]; Assert.AreEqual((MsgEP)"logical://test/bar", memberStatus.InstanceEP); Assert.AreEqual(Helper.MachineName, memberStatus.MachineName); Assert.AreEqual(ClusterMemberState.Slave, memberStatus.State); Assert.AreEqual(settings, memberStatus.Settings); Assert.AreEqual("value3", memberStatus["setting3"]); Assert.AreEqual("value4", memberStatus["setting4"]); }
public void ClusterStatus_Clone_ClusterMemberStatus() { ClusterMemberSettings settings = new ClusterMemberSettings((MsgEP)"logical://test"); ClusterMemberStatus input, output; input = new ClusterMemberStatus("logical://test/foo", ClusterMemberState.Master, settings); input["setting1"] = "value1"; input["setting2"] = "value2"; input.ProtocolCaps = unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF); output = input.Clone(); Assert.AreNotSame(input, output); Assert.AreEqual((MsgEP)"logical://test/foo", output.InstanceEP); Assert.AreEqual(Helper.MachineName, output.MachineName); Assert.AreEqual(unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF), output.ProtocolCaps); Assert.AreEqual(ClusterMemberState.Master, output.State); Assert.AreEqual(settings, output.Settings); Assert.AreEqual("value1", output["setting1"]); Assert.AreEqual("value2", output["setting2"]); }
public void ClusterStatus_Serialize_ClusterMemberStatus() { EnhancedMemoryStream ms = new EnhancedMemoryStream(); ClusterMemberSettings settings = new ClusterMemberSettings((MsgEP)"logical://test"); ClusterMemberStatus status; status = new ClusterMemberStatus("logical://test/foo", ClusterMemberState.Master, settings); status["setting1"] = "value1"; status["setting2"] = "value2"; status.ProtocolCaps = unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF); status.Write(ms); ms.Position = 0; status = new ClusterMemberStatus(ms); Assert.AreEqual((MsgEP)"logical://test/foo", status.InstanceEP); Assert.AreEqual(Helper.MachineName, status.MachineName); Assert.AreEqual(unchecked ((ClusterMemberProtocolCaps)0xFFFFFFFF), status.ProtocolCaps); Assert.AreEqual(ClusterMemberState.Master, status.State); Assert.AreEqual(settings, status.Settings); Assert.AreEqual("value1", status["setting1"]); Assert.AreEqual("value2", status["setting2"]); }
public void ClusterMemberSettings_LoadConfig() { ClusterMemberSettings settings; string cfg; try { // Verify that we actually load existing settings cfg = @" §ion Settings ClusterBaseEP = logical://test Mode = PreferMaster MasterBroadcastInterval = 10m SlaveUpdateInterval = 11m MissingMasterCount = 13 MissingSlaveCount = 20 MasterBkInterval = 14m SlaveBkInterval = 15m BkInterval = 16m ElectionInterval = 17m &endsection "; Config.SetConfig(cfg.Replace('&', '#')); settings = ClusterMemberSettings.LoadConfig("Settings"); Assert.AreEqual((MsgEP)"logical://test", settings.ClusterBaseEP); Assert.AreEqual(ClusterMemberMode.PreferMaster, settings.Mode); Assert.AreEqual(TimeSpan.FromMinutes(10), settings.MasterBroadcastInterval); Assert.AreEqual(TimeSpan.FromMinutes(11), settings.SlaveUpdateInterval); Assert.AreEqual(13, settings.MissingMasterCount); Assert.AreEqual(20, settings.MissingSlaveCount); Assert.AreEqual(TimeSpan.FromMinutes(14), settings.MasterBkInterval); Assert.AreEqual(TimeSpan.FromMinutes(15), settings.SlaveBkInterval); Assert.AreEqual(TimeSpan.FromMinutes(16), settings.BkInterval); Assert.AreEqual(TimeSpan.FromMinutes(17), settings.ElectionInterval); // Verify that settings not in the config are initialized // with the proper defaults cfg = @" §ion Settings ClusterBaseEP = logical://test &endsection "; Config.SetConfig(cfg.Replace('&', '#')); settings = ClusterMemberSettings.LoadConfig("Settings"); Assert.AreEqual((MsgEP)"logical://test", settings.ClusterBaseEP); Assert.AreEqual(ClusterMemberMode.Normal, settings.Mode); Assert.AreEqual(TimeSpan.FromSeconds(30), settings.MasterBroadcastInterval); Assert.AreEqual(TimeSpan.FromSeconds(30), settings.SlaveUpdateInterval); Assert.AreEqual(2, settings.MissingMasterCount); Assert.AreEqual(2, settings.MissingSlaveCount); Assert.AreEqual(TimeSpan.FromSeconds(1), settings.MasterBkInterval); Assert.AreEqual(TimeSpan.FromSeconds(1), settings.SlaveBkInterval); Assert.AreEqual(TimeSpan.FromSeconds(1), settings.BkInterval); Assert.AreEqual(TimeSpan.FromSeconds(10), settings.ElectionInterval); // Make sure we see an exception if the ClusterBaseEP setting is // not present. cfg = @" §ion Settings &endsection "; Config.SetConfig(cfg.Replace('&', '#')); try { settings = ClusterMemberSettings.LoadConfig("Settings"); Assert.Fail("Expected an ArgumentException"); } catch (Exception e) { Assert.IsInstanceOfType(e, typeof(ArgumentException)); } } finally { Config.SetConfig(null); } }
/// <summary> /// Associates the service handler with a message router by registering /// the necessary application message handlers. /// </summary> /// <param name="router">The message router.</param> /// <param name="keyPrefix">The configuration key prefix or (null to use <b>LillTek.Datacenter.AppStore</b>).</param> /// <param name="perfCounters">The application's performance counter set (or <c>null</c>).</param> /// <param name="perfPrefix">The string to prefix any performance counter names (or <c>null</c>).</param> /// <remarks> /// <para> /// Applications that expose performance counters will pass a non-<c>null</c> <b>perfCounters</b> /// instance. The service handler should add any counters it implements to this set. /// If <paramref name="perfPrefix" /> is not <c>null</c> then any counters added should prefix their /// names with this parameter. /// </para> /// </remarks> public void Start(MsgRouter router, string keyPrefix, PerfCounterSet perfCounters, string perfPrefix) { var config = new Config(keyPrefix != null ? keyPrefix : ConfigPrefix); // Make sure the syncLock is set early. this.syncLock = router.SyncRoot; // Make sure that the LillTek.Datacenter message types have been // registered with the LillTek.Messaging subsystem. LillTek.Datacenter.Global.RegisterMsgTypes(); // Verify the router parameter if (router == null) { throw new ArgumentNullException("router", "Router cannot be null."); } if (this.router != null) { throw new InvalidOperationException("This handler has already been started."); } // General initialization mode = config.Get <AppStoreMode>("Mode", AppStoreMode.Primary); primaryBroadcast = config.Get("PrimaryBroadcast", true); packageScanInterval = config.Get("PackageScanInterval", TimeSpan.FromMinutes(5)); primaryPollInterval = config.Get("PrimaryPollInterval", TimeSpan.FromMinutes(15)); primaryPollTime = SysTime.Now; onTransfer = new AsyncCallback(OnTransfer); downloads = new Dictionary <AppRef, PendingDownload>(); forceSync = false; cDownloads = 0; netFail = false; // Initialize the package folder packageFolder = new AppPackageFolder(syncLock, config.Get("PackageFolder", "Packages")); packageFolder.ChangeEvent += new MethodArg1Invoker(OnPackageFolderChange); packageScanTime = SysTime.Now; // Initialize the performance counters startTime = DateTime.UtcNow; perf = new Perf(perfCounters, perfPrefix); // Crank up the background task timer. bkTimer = new GatedTimer(new TimerCallback(OnBkTimer), null, config.Get("BkTaskInterval", TimeSpan.FromSeconds(1))); try { // Initialize the router this.router = router; // Join the cluster, initializing this instance's state. cluster = new ClusterMember(router, ClusterMemberSettings.LoadConfig(config.KeyPrefix + "Cluster")); cluster["Mode"] = this.mode.ToString(); cluster.ClusterStatusUpdate += new ClusterMemberEventHandler(OnClusterStatusUpdate); cluster.Start(); // Rather than calling cluster.JoinWait() which could take a really long // time, I'm going to sleep for two seconds. There are three scenarios: // // 1. This is the first Application Store instance. // // 2. Other instances are running but they haven't // organized into a cluster. // // 3. A cluster is already running. // // If #1 is the current situation, then it will take a very long time // for JoinWait() to return because we have to go through the entire // missed master broadcast and election periods. Since we're the only // instance, we could have started serving content well before this. // // #2 won't be very common but if it is the case, the worst thing // that will happen is that it will take a while to discover the // primary store. // // If #3 is the case, then two seconds should be long enough for the // master to send the instance a cluster update. Thread.Sleep(2000); // Register the message handlers via the cluster member // so that the endpoint used will be the member's instanceEP. cluster.AddTarget(this, AppStoreHandler.DynamicScope); } catch { if (packageFolder != null) { packageFolder.Dispose(); packageFolder = null; } if (bkTimer != null) { bkTimer.Dispose(); bkTimer = null; } router.Dispatcher.RemoveTarget(this); if (cluster != null) { cluster.Stop(); cluster = null; } throw; } }
/// <summary> /// Loads DNS client settings from a configuration section. /// </summary> /// <param name="keyPrefix">The configuration section key prefix (or <c>null</c>).</param> /// <remarks> /// <para> /// The settings will loaded are: /// </para> /// <div class="tablediv"> /// <table class="dtTABLE" cellspacing="0" ID="Table1"> /// <tr valign="top"> /// <th width="1">Setting</th> /// <th width="1">Default</th> /// <th width="90%">Description</th> /// </tr> /// <tr valign="top"> /// <td>Enabled</td> /// <td>true</td> /// <td> /// Indicates whether the dynamic DNS client should be enabled. /// </td> /// </tr> /// <tr valign="top"> /// <td>NetworkBinding</td> /// <td>ANY</td> /// <td> /// Specifies the <see cref="NetworkBinding" /> the DNS client /// should use for sending UDP host registration messages to the /// DNS servers. /// </td> /// </tr> /// <tr valign="top"> /// <td>Mode</td> /// <td>Cluster</td> /// <td> /// Controls how the client registers hosts with the DNS server. The possible values /// are <see cref="DynDnsMode.Udp" /> or <see cref="DynDnsMode.Cluster"/>. /// <see cref="DynDnsMode.Both" /> is not allowed for DNS clients. /// </td> /// </tr> /// <tr valign="top"> /// <td>SharedKey</td> /// <td>(see note)</td> /// <td> /// Shared symmetric encryption key used to decrypt UDP registration messages /// sent by DNS clients while in <see cref="DynDnsMode.Udp" /> mode. This /// key must match the shared key configured for the client. This defaults /// to a reasonable value. /// </td> /// </tr> /// <tr valign="top"> /// <td>Domain</td> /// <td>(see note)</td> /// <td> /// <para> /// Specifies the name server domain for the name server. If this is /// specified, the DNS client will periodically query DNS for the NS /// records for the domain and then use the IP addresses to send UDP /// host registration messages to the servers. /// </para> /// <para> /// This setting must be formatted as a network binding with a host name /// and port, such as <b>LILLTEK.NET:DYNAMIC-DNS</b>. /// </para> /// <note> /// One of <b>Domain</b> or <b>NameServer</b> must be specified when when <b>Mode=UDP</b>. /// If both settings are present, then <b>Domain</b> will be used. /// </note> /// </td> /// </tr> /// <tr valign="top"> /// <td>NameServer[#]</td> /// <td>(see note)</td> /// <td> /// <para> /// Specifies the network bindings for the DNS servers for the delivery /// of UDP host registration messages. These entries may include /// IP addresses or host names, but note that host name lookups are /// performed only once by the server, when it starts. /// </para> /// <note> /// One of <b>Domain</b> or <b>NameServer</b> must be specified when when <b>Mode=UDP</b>. /// If both settings are present, then <b>Domain</b> will be used. /// </note> /// </td> /// </tr> /// <tr valign="top"> /// <td>BkInterval</td> /// <td>1s</td> /// <td> /// Minimum interval for which background activities will be scheduled. /// </td> /// </tr> /// <tr valign="top"> /// <td>DomainRefreshInterval</td> /// <td>15m</td> /// <td> /// Interval at which DNS NS queries will be performed to refresh the list of /// name servers for the specified <b>Domain</b>. /// </td> /// </tr> /// <tr valign="top"> /// <td>UdpRegisterInterval</td> /// <td>60s</td> /// <td> /// Interval at which UDP host registration messages will be sent to the /// DNS servers when operating in <b>Mode=UDP</b>. /// </td> /// </tr> /// <tr valign="top"> /// <td>Host[#]</td> /// <td>(optional)</td> /// <td> /// <para> /// The set of static host entries to be returned by the DNS server. These /// entries are formatted as: /// </para> /// <code lang="none"> /// <host name> "," <ip or cname> [ "," <TTL> [ "," <host-mode> [ ";" "NAT" ] ] ] /// </code> /// <para> /// where <b>host name</b> is the DNS name being registered, <b>ip</b> or <b>cname</b> /// specifies the IP address or CNAME reference to the host, <b>TTL</b> is the optional /// time-to-live (TTL) to use for the entry in seconds, and <b>host-mode</b> is the optional /// host entry mode, one of <b>ADDRESS</b>, <b>ADDRESSLIST</b>, or <b>CNAME</b>. /// </para> /// <para> /// The <b>TTL</b> value defaults to -1 seconds (indicating that the server's default TTL /// will be used) and the <b>host-mode</b> defaults to <b>ADDRESS</b> for IP addresses or /// <b>CNAME</b> for CNAME references. You can also set <b>TTL=-1</b> to use the DNS server /// default for this. /// </para> /// <note> /// A host mode of <b>ADDRESS</b> or <b>ADDRESSLIST</b> can only be specified for IP /// addresses and <b>CNAME</b> can only be specified for CNAME entries. /// </note> /// </td> /// </tr> /// <tr valign="top"> /// <td>Cluster</td> /// <td>(see note)</td> /// <td> /// <b>Cluster</b> is a subsection in the configuration that /// that specifies the settings required to establish a cooperative /// cluster with the Dynamic DNS instances on the network while operating /// in CLUSTER mode. The client uses the <see cref="ClusterMember" /> class /// to perform the work necessary to join the cluster. The <b>ClusterBaseEP</b> /// setting is required. /// </td> /// </tr> /// </table> /// </div> /// </remarks> public DynDnsClientSettings(string keyPrefix) { Config config = new Config(keyPrefix); string[] list; List <DynDnsHostEntry> registrations; List <NetworkBinding> bindings; list = config.GetArray("Host"); registrations = new List <DynDnsHostEntry>(list.Length); for (int i = 0; i < list.Length; i++) { try { registrations.Add(DynDnsHostEntry.Parse(list[i])); } catch { SysLog.LogWarning("DynamicDnsClient: Error parsing host registration [{0}Host[{1}]={2}].", config.KeyPrefix, i, list[i]); } } this.Hosts = registrations.ToArray(); list = config.GetArray("NameServer"); bindings = new List <NetworkBinding>(list.Length); for (int i = 0; i < list.Length; i++) { try { bindings.Add(new NetworkBinding((list[i]))); } catch { SysLog.LogWarning("DynamicDnsClient: Error parsing name server binding [{0}NameServer[{1}]={2}].", config.KeyPrefix, i, list[i]); } } this.NameServers = bindings.ToArray(); this.Enabled = config.Get("Enabled", this.Enabled); if (this.Enabled) { this.NetworkBinding = config.Get("NetworkBinding", this.NetworkBinding); this.Mode = config.Get <DynDnsMode>("Mode", this.Mode); this.SharedKey = new SymmetricKey(config.Get("SharedKey", "aes:BcskocQ2W4aIGEemkPsy5dhAxuWllweKLVToK1NoYzg=:5UUVxRPml8L4WH82unR74A==")); this.Domain = config.Get("Domain", this.Domain); this.BkInterval = config.Get("BkInterval", this.BkInterval); this.DomainRefreshInterval = config.Get("DomainRefreshInterval", this.DomainRefreshInterval); this.UdpRegisterInterval = config.Get("UdpRegisterInterval", this.UdpRegisterInterval); if (this.Mode == DynDnsMode.Cluster) { this.Cluster = ClusterMemberSettings.LoadConfig(config.KeyPrefix + "Cluster"); } if (this.Mode == DynDnsMode.Both) { throw new FormatException("DynamicDnsClient: [Mode=BOTH] is not supported."); } if (this.Mode == DynDnsMode.Udp && this.Domain.IsAny && this.NameServers.Length == 0) { throw new FormatException("DynDnsClient: One of DOMAIN or NAMESERVER[#] must be specified when [Mode=UDP]."); } } }