//
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Net.Sockets;
using System.Transactions;
using System.Timers;
namespace System.ServiceModel.PeerResolvers
{
+#if false
[MonoTODO ("Implement cleanup and refresh")]
// FIXME: TransactionTimeout must be null by-default.
[ServiceBehavior (AutomaticSessionShutdown = true, ConcurrencyMode = ConcurrencyMode.Multiple,
public Guid RegistrationId { get; set; }
public PeerNodeAddress NodeAddress { get; set; }
}
+
+#else
+ [MonoTODO ("Implement cleanup and refresh")]
+ // FIXME: TransactionTimeout must be null by-default.
+ [ServiceBehavior (AutomaticSessionShutdown = true, ConcurrencyMode = ConcurrencyMode.Multiple,
+ InstanceContextMode = InstanceContextMode.Single, ReleaseServiceInstanceOnTransactionComplete = true,
+ TransactionIsolationLevel = IsolationLevel.Unspecified, /*TransactionTimeout = null, */
+ UseSynchronizationContext = false, ValidateMustUnderstand = true)]
+ public class CustomPeerResolverService : IPeerResolverContract
+ {
+ static ServiceHost localhost;
+
+ static void SetupCustomPeerResolverServiceHost ()
+ {
+ // launch peer resolver service locally only when it does not seem to be running ...
+ var t = new TcpListener (8931);
+ try {
+ t.Start ();
+ t.Stop ();
+ } catch {
+ return;
+ }
+ Console.WriteLine ("WARNING: it is running peer resolver service locally. This means, the node registration is valid only within this application domain...");
+ var host = new ServiceHost (new LocalPeerResolverService (TextWriter.Null));
+ host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().InstanceContextMode = InstanceContextMode.Single;
+ host.AddServiceEndpoint (typeof (ICustomPeerResolverContract), new BasicHttpBinding (), "http://localhost:8931");
+ localhost = host;
+ host.Open ();
+ }
+
+ ICustomPeerResolverClient client;
+ bool control_shape, opened;
+ TimeSpan refresh_interval, cleanup_interval;
+
+ public CustomPeerResolverService ()
+ {
+ client = ChannelFactory<ICustomPeerResolverClient>.CreateChannel (new BasicHttpBinding (), new EndpointAddress ("http://localhost:8931"));
+
+ refresh_interval = new TimeSpan (0, 10, 0);
+ cleanup_interval = new TimeSpan (0, 1, 0);
+ }
+
+ public TimeSpan CleanupInterval {
+ get { return cleanup_interval; }
+ set {
+ if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
+ throw new ArgumentOutOfRangeException (
+ "The interval is either zero or greater than max value.");
+ if (opened)
+ throw new InvalidOperationException ("The interval must be set before it is opened");
+
+ cleanup_interval = value;
+ }
+ }
+
+ public bool ControlShape {
+ get { return control_shape; }
+ set {
+ if (opened)
+ throw new InvalidOperationException ("The interval must be set before it is opened");
+ control_shape = value;
+ }
+ }
+
+ public TimeSpan RefreshInterval {
+ get { return refresh_interval; }
+ set {
+ if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
+ throw new ArgumentOutOfRangeException (
+ "The interval is either zero or greater than max value.");
+ if (opened)
+ throw new InvalidOperationException ("The interval must be set before it is opened");
+
+ refresh_interval = value;
+ }
+ }
+
+ [MonoTODO ("Do we have to unregister nodes here?")]
+ public virtual void Close ()
+ {
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed by a previous call to this method.");
+ client.Close ();
+ opened = false;
+
+ if (localhost != null) {
+ localhost.Close ();
+ localhost = null;
+ }
+ }
+
+ public virtual ServiceSettingsResponseInfo GetServiceSettings ()
+ {
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
+
+ return client.GetServiceSettings ();
+ }
+
+ public virtual void Open ()
+ {
+ if (localhost == null)
+ SetupCustomPeerResolverServiceHost ();
+
+ if ((CleanupInterval == TimeSpan.Zero) || (RefreshInterval == TimeSpan.Zero))
+ throw new ArgumentException ("Cleanup interval or refresh interval are set to a time span interval of zero.");
+
+ if (opened)
+ throw new InvalidOperationException ("The service has been started by a previous call to this method.");
+
+ opened = true;
+
+ client.Open ();
+ client.SetCustomServiceSettings (new PeerServiceSettingsInfo () { ControlMeshShape = control_shape, RefreshInterval = refresh_interval, CleanupInterval = cleanup_interval });
+ }
+
+ public virtual RefreshResponseInfo Refresh (RefreshInfo refreshInfo)
+ {
+ if (refreshInfo == null)
+ throw new ArgumentException ("Refresh info cannot be null.");
+
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
+
+ return client.Refresh (refreshInfo);
+ }
+
+ public virtual RegisterResponseInfo Register (RegisterInfo registerInfo)
+ {
+ if (registerInfo == null)
+ throw new ArgumentException ("Register info cannot be null.");
+
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
+
+ return client.Register (registerInfo);
+ }
+
+ public virtual RegisterResponseInfo Register (Guid clientId, string meshId, PeerNodeAddress address)
+ {
+ return Register (new RegisterInfo (clientId, meshId, address));
+ }
+
+ public virtual ResolveResponseInfo Resolve (ResolveInfo resolveInfo)
+ {
+ if (resolveInfo == null)
+ throw new ArgumentException ("Resolve info cannot be null.");
+
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
+
+ return client.Resolve (resolveInfo);
+ }
+
+ public virtual void Unregister (UnregisterInfo unregisterInfo)
+ {
+ if (unregisterInfo == null)
+ throw new ArgumentException ("Unregister info cannot be null.");
+
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
+
+ client.Unregister (unregisterInfo);
+ }
+
+ public virtual RegisterResponseInfo Update (UpdateInfo updateInfo)
+ {
+ if (updateInfo == null)
+ throw new ArgumentException ("Update info cannot be null.");
+
+ if (! opened)
+ throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
+
+ return client.Update (updateInfo);
+ }
+ }
+#endif
}
--- /dev/null
+//
+// LocalPeerResolverService.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if true
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.ServiceModel;
+using System.ServiceModel.PeerResolvers;
+
+namespace System.ServiceModel.PeerResolvers
+{
+ // This implementation of peer resolver should open up node
+ // registration to some extent, say, valid within the same machine.
+ //
+ // A correct implementation should be using something like zeroconf
+ // to register the local machine as a peer node.
+
+ class LocalPeerResolverService : ICustomPeerResolverContract
+ {
+ public LocalPeerResolverService (TextWriter log)
+ {
+ this.log = log ?? TextWriter.Null;
+ }
+
+ TextWriter log;
+ Dictionary<string,Mesh> mesh_map = new Dictionary<string,Mesh> ();
+
+ // CustomPeerResolverService delegation
+
+ // Open(), Close(), ControlShape, RefreshInterval, CleanupInterval
+
+ public bool ControlShape { get; set; }
+ public TimeSpan RefreshInterval { get; set; }
+ public TimeSpan CleanupInterval { get; set; }
+
+ // (internal) ICustomPeerResolverContract implementation
+
+ public PeerServiceSettingsInfo GetCustomServiceSettings ()
+ {
+ log.WriteLine ("REQUEST: GetCustomServiceSettings");
+ return new PeerServiceSettingsInfo () {
+ ControlMeshShape = this.ControlShape,
+ RefreshInterval = this.RefreshInterval,
+ CleanupInterval = this.CleanupInterval };
+ }
+
+ public void SetCustomServiceSettings (PeerServiceSettingsInfo info)
+ {
+ log.WriteLine ("REQUEST: SetCustomServiceSettings(ControlMeshShape:{0}, RefreshInterval:{1}, CleanupInterval:{2}", info.ControlMeshShape, info.RefreshInterval, info.CleanupInterval);
+ ControlShape = info.ControlMeshShape;
+ RefreshInterval = info.RefreshInterval;
+ CleanupInterval = info.CleanupInterval;
+ }
+
+ // IPeerResolverContract implementation
+
+ public ServiceSettingsResponseInfo GetServiceSettings ()
+ {
+ return new ServiceSettingsResponseInfo () { ControlMeshShape = this.ControlShape };
+ }
+
+ public RefreshResponseInfo Refresh (RefreshInfo refreshInfo)
+ {
+ var r = refreshInfo;
+ log.WriteLine ("REQUEST: Refresh (Mesh: {0}, Registraion: {1})", r.MeshId, r.RegistrationId);
+ var mesh = GetExistingMesh (r.MeshId);
+ var node = mesh.FirstOrDefault (n => n.RegistrationId == r.RegistrationId);
+ if (node == null)
+ return new RefreshResponseInfo () { Result = RefreshResult.RegistrationNotFound };
+ node.Refresh ();
+ return new RefreshResponseInfo () { Result = RefreshResult.Success, RegistrationLifetime = DateTime.Now - node.LastRefreshTime };
+ }
+
+ public RegisterResponseInfo Register (RegisterInfo registerInfo)
+ {
+ var r = registerInfo;
+ log.WriteLine ("REQUEST: Register (Mesh: {0}, Client: {1}, NodeAddress: endpoint {2})", r.MeshId, r.ClientId, r.NodeAddress.EndpointAddress);
+ Mesh mesh;
+ if (!mesh_map.TryGetValue (r.MeshId, out mesh)) {
+ mesh = new Mesh (r.MeshId);
+ mesh_map.Add (r.MeshId, mesh);
+ }
+ var node = RegisterNode (mesh, r.ClientId, r.NodeAddress);
+ return new RegisterResponseInfo () { RegistrationId = node.RegistrationId };
+ }
+
+ public ResolveResponseInfo Resolve (ResolveInfo resolveInfo)
+ {
+ var r = resolveInfo;
+ log.WriteLine ("REQUEST: Resolve (Mesh: {0}, Client: {1}, MaxAddresses: {2})", r.MeshId, r.ClientId, r.MaxAddresses);
+ Mesh mesh;
+ var rr = new ResolveResponseInfo ();
+ if (!mesh_map.TryGetValue (r.MeshId, out mesh))
+ return rr;
+ foreach (var node in mesh.TakeWhile (n => n.ClientId == r.ClientId)) {
+ rr.Addresses.Add (node.Address);
+ if (rr.Addresses.Count == r.MaxAddresses)
+ break;
+ }
+ return rr;
+ }
+
+ public void Unregister (UnregisterInfo unregisterInfo)
+ {
+ var u = unregisterInfo;
+ log.WriteLine ("REQUEST: Unregister (Mesh: {0}, Registration: {1})", u.MeshId, u.RegistrationId);
+ Mesh mesh = GetExistingMesh (u.MeshId);
+ lock (mesh) {
+ var node = mesh.GetRegisteredNode (u.RegistrationId);
+ mesh.Remove (node);
+ }
+ }
+
+ public RegisterResponseInfo Update (UpdateInfo updateInfo)
+ {
+ var u = updateInfo;
+ log.WriteLine ("REQUEST: Update (Mesh: {0}, Registration: {1}, NodeAddress:)", u.MeshId, u.RegistrationId, u.NodeAddress);
+ var mesh = GetExistingMesh (u.MeshId);
+ var node = mesh.GetRegisteredNode (u.RegistrationId);
+ node.Update (u.NodeAddress);
+ return new RegisterResponseInfo () { RegistrationId = node.RegistrationId };
+ }
+
+ Mesh GetExistingMesh (string meshId)
+ {
+ Mesh mesh;
+ if (!mesh_map.TryGetValue (meshId, out mesh))
+ throw new InvalidOperationException (String.Format ("Specified mesh {0} does not exist", meshId));
+ return mesh;
+ }
+
+ Node RegisterNode (Mesh mesh, Guid clientId, PeerNodeAddress addr)
+ {
+ lock (mesh) {
+ var node = new Node () { ClientId = clientId, Address = addr };
+ mesh.Add (node);
+ node.LastRefreshTime = DateTime.Now;
+ return node;
+ }
+ }
+ }
+
+ class Mesh : List<Node>
+ {
+ public Mesh (string id)
+ {
+ Id = id;
+ }
+
+ public string Id { get; private set; }
+
+ public Node GetRegisteredNode (Guid registrationId)
+ {
+ var node = this.FirstOrDefault (n => n.RegistrationId == registrationId);
+ if (node == null)
+ throw new InvalidOperationException (String.Format ("Node with registration Id {0} does not exist in the specified mesh {0}", registrationId, Id));
+ return node;
+ }
+ }
+
+ class Node
+ {
+ public Node ()
+ {
+ RegistrationId = Guid.NewGuid ();
+ }
+
+ public Guid RegistrationId { get; private set; }
+ public Guid ClientId { get; set; }
+ public PeerNodeAddress Address { get; set; }
+ public DateTime LastRefreshTime { get; set; }
+
+ public void Refresh ()
+ {
+ LastRefreshTime = DateTime.Now;
+ }
+
+ public void Update (PeerNodeAddress addr)
+ {
+ Address = addr;
+ LastRefreshTime = DateTime.Now;
+ }
+ }
+}
+#endif