You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			315 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			315 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | //---------------------------------------------------------------- | ||
|  | // Copyright (c) Microsoft Corporation.  All rights reserved. | ||
|  | //---------------------------------------------------------------- | ||
|  | 
 | ||
|  | namespace System.ServiceModel.Discovery | ||
|  | { | ||
|  |     using System.Collections.ObjectModel; | ||
|  |     using System.Diagnostics.CodeAnalysis; | ||
|  |     using System.Runtime; | ||
|  |      | ||
|  |     abstract class ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel> : AsyncResult | ||
|  |     { | ||
|  |         readonly IDiscoveryServiceImplementation discoveryServiceImpl; | ||
|  |         readonly IMulticastSuppressionImplementation multicastSuppressionImpl; | ||
|  |         readonly ResolveCriteria resolveCriteria; | ||
|  |         readonly DiscoveryOperationContext context; | ||
|  |         readonly TimeoutHelper timeoutHelper; | ||
|  | 
 | ||
|  |         static AsyncCompletion onShouldRedirectResolveCompletedCallback = new AsyncCompletion(OnShouldRedirectResolveCompleted); | ||
|  |         static AsyncCompletion onSendProxyAnnouncementsCompletedCallback = new AsyncCompletion(OnSendProxyAnnouncementsCompleted); | ||
|  | 
 | ||
|  |         static AsyncCompletion onOnResolveCompletedCallback = new AsyncCompletion(OnOnResolveCompleted); | ||
|  |         static AsyncCompletion onSendResolveResponseCompletedCallback = new AsyncCompletion(OnSendResolveResponseCompleted); | ||
|  |         TResponseChannel responseChannel; | ||
|  | 
 | ||
|  |         [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] | ||
|  |         protected ResolveDuplexAsyncResult(TResolveMessage resolveMessage, | ||
|  |             IDiscoveryServiceImplementation discoveryServiceImpl, | ||
|  |             IMulticastSuppressionImplementation multicastSuppressionImpl, | ||
|  |             AsyncCallback callback, | ||
|  |             object state) | ||
|  |             : base(callback, state) | ||
|  |         { | ||
|  |             Fx.Assert(resolveMessage != null, "The resolveMessage must be non null."); | ||
|  |             Fx.Assert(discoveryServiceImpl != null, "The discoveryServiceImpl must be non null."); | ||
|  | 
 | ||
|  |             this.discoveryServiceImpl = discoveryServiceImpl; | ||
|  |             this.multicastSuppressionImpl = multicastSuppressionImpl; | ||
|  | 
 | ||
|  |             if (!this.Validate(resolveMessage)) | ||
|  |             { | ||
|  |                 this.Complete(true); | ||
|  |                 return; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 this.context = new DiscoveryOperationContext(OperationContext.Current); | ||
|  |                 this.resolveCriteria = this.GetResolveCriteria(resolveMessage); | ||
|  |                 this.timeoutHelper = new TimeoutHelper(this.resolveCriteria.Duration); | ||
|  |                 this.timeoutHelper.RemainingTime(); | ||
|  |                 this.Process(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         TResponseChannel ResponseChannel | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 if (this.responseChannel == null) | ||
|  |                 { | ||
|  |                     this.responseChannel = this.context.GetCallbackChannel<TResponseChannel>(); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 return this.responseChannel; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         protected DiscoveryOperationContext Context | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 return this.context; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         protected virtual bool Validate(TResolveMessage resolveMessage) | ||
|  |         { | ||
|  |             return (DiscoveryService.EnsureMessageId() && | ||
|  |                 DiscoveryService.EnsureReplyTo() && | ||
|  |                 this.ValidateContent(resolveMessage) && | ||
|  |                 this.EnsureNotDuplicate()); | ||
|  |         } | ||
|  | 
 | ||
|  |         protected abstract bool ValidateContent(TResolveMessage resolveMessage); | ||
|  | 
 | ||
|  |         protected abstract ResolveCriteria GetResolveCriteria(TResolveMessage resolveMessage); | ||
|  | 
 | ||
|  |         protected abstract IAsyncResult BeginSendResolveResponse( | ||
|  |             TResponseChannel responseChannel, | ||
|  |             DiscoveryMessageSequence discoveryMessageSequence,  | ||
|  |             EndpointDiscoveryMetadata matchingEndpoint,  | ||
|  |             AsyncCallback callback,  | ||
|  |             object state); | ||
|  |         protected abstract void EndSendResolveResponse(TResponseChannel responseChannel, IAsyncResult result); | ||
|  | 
 | ||
|  |         protected abstract IAsyncResult BeginSendProxyAnnouncement( | ||
|  |             TResponseChannel responseChannel, | ||
|  |             DiscoveryMessageSequence discoveryMessageSequence, | ||
|  |             EndpointDiscoveryMetadata proxyEndpointDiscoveryMetadata, | ||
|  |             AsyncCallback callback, | ||
|  |             object state); | ||
|  |         protected abstract void EndSendProxyAnnouncement(TResponseChannel responseChannel, IAsyncResult result); | ||
|  | 
 | ||
|  |         static bool OnShouldRedirectResolveCompleted(IAsyncResult result) | ||
|  |         { | ||
|  |             Collection<EndpointDiscoveryMetadata> redirectionEndpoints = null; | ||
|  | 
 | ||
|  |             ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel> thisPtr = | ||
|  |                 (ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel>)result.AsyncState; | ||
|  | 
 | ||
|  |             if (thisPtr.multicastSuppressionImpl.EndShouldRedirectResolve(result, out redirectionEndpoints)) | ||
|  |             { | ||
|  |                 return thisPtr.SendProxyAnnouncements(redirectionEndpoints); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 return thisPtr.ProcessResolveRequest(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         static bool OnSendProxyAnnouncementsCompleted(IAsyncResult result) | ||
|  |         { | ||
|  |             ProxyAnnouncementsSendAsyncResult.End(result); | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         static bool OnOnResolveCompleted(IAsyncResult result) | ||
|  |         { | ||
|  |             ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel> thisPtr = | ||
|  |                 (ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel>)result.AsyncState; | ||
|  | 
 | ||
|  |             EndpointDiscoveryMetadata matchingEndpoint = thisPtr.discoveryServiceImpl.EndResolve(result); | ||
|  | 
 | ||
|  |             return thisPtr.SendResolveResponse(matchingEndpoint); | ||
|  |         } | ||
|  | 
 | ||
|  |         static bool OnSendResolveResponseCompleted(IAsyncResult result) | ||
|  |         { | ||
|  |             ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel> thisPtr = | ||
|  |                 (ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel>)result.AsyncState; | ||
|  | 
 | ||
|  |             thisPtr.EndSendResolveResponse(thisPtr.ResponseChannel, result); | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         void Process() | ||
|  |         { | ||
|  |             if ((this.multicastSuppressionImpl != null) && (this.context.DiscoveryMode == ServiceDiscoveryMode.Adhoc)) | ||
|  |             { | ||
|  |                 if (this.SuppressResolveRequest()) | ||
|  |                 { | ||
|  |                     Complete(true); | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 if (this.ProcessResolveRequest()) | ||
|  |                 { | ||
|  |                     Complete(true); | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         bool SuppressResolveRequest() | ||
|  |         { | ||
|  |             IAsyncResult result = this.multicastSuppressionImpl.BeginShouldRedirectResolve( | ||
|  |                 this.resolveCriteria, | ||
|  |                 this.PrepareAsyncCompletion(onShouldRedirectResolveCompletedCallback), | ||
|  |                 this); | ||
|  | 
 | ||
|  |             return (result.CompletedSynchronously && OnShouldRedirectResolveCompleted(result)); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool SendProxyAnnouncements(Collection<EndpointDiscoveryMetadata> redirectionEndpoints) | ||
|  |         { | ||
|  |             if ((redirectionEndpoints == null) || (redirectionEndpoints.Count == 0)) | ||
|  |             { | ||
|  |                 return true; | ||
|  |             } | ||
|  | 
 | ||
|  |             IAsyncResult result = new ProxyAnnouncementsSendAsyncResult( | ||
|  |                 this, | ||
|  |                 redirectionEndpoints, | ||
|  |                 this.PrepareAsyncCompletion(onSendProxyAnnouncementsCompletedCallback), | ||
|  |                 this); | ||
|  | 
 | ||
|  |             return (result.CompletedSynchronously && OnSendProxyAnnouncementsCompleted(result)); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool ProcessResolveRequest() | ||
|  |         { | ||
|  |             IAsyncResult result = this.discoveryServiceImpl.BeginResolve( | ||
|  |                 resolveCriteria, | ||
|  |                 PrepareAsyncCompletion(onOnResolveCompletedCallback), | ||
|  |                 this); | ||
|  | 
 | ||
|  |             return (result.CompletedSynchronously && OnOnResolveCompleted(result)); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool SendResolveResponse(EndpointDiscoveryMetadata matchingEndpoint) | ||
|  |         { | ||
|  |             if (matchingEndpoint == null) | ||
|  |             { | ||
|  |                 return true; | ||
|  |             } | ||
|  | 
 | ||
|  |             IContextChannel contextChannel = (IContextChannel)this.ResponseChannel; | ||
|  |             IAsyncResult result = null; | ||
|  |             using (new OperationContextScope(contextChannel)) | ||
|  |             { | ||
|  |                 this.context.AddressDuplexResponseMessage(OperationContext.Current); | ||
|  | 
 | ||
|  |                 contextChannel.OperationTimeout = this.timeoutHelper.RemainingTime(); | ||
|  | 
 | ||
|  |                 result = this.BeginSendResolveResponse( | ||
|  |                     this.ResponseChannel, | ||
|  |                     this.discoveryServiceImpl.GetNextMessageSequence(), | ||
|  |                     matchingEndpoint, | ||
|  |                     this.PrepareAsyncCompletion(onSendResolveResponseCompletedCallback), | ||
|  |                     this); | ||
|  |             } | ||
|  | 
 | ||
|  |             return (result.CompletedSynchronously && OnSendResolveResponseCompleted(result)); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool EnsureNotDuplicate() | ||
|  |         { | ||
|  |             bool isDuplicate = this.discoveryServiceImpl.IsDuplicate(OperationContext.Current.IncomingMessageHeaders.MessageId); | ||
|  | 
 | ||
|  |             if (isDuplicate && TD.DuplicateDiscoveryMessageIsEnabled()) | ||
|  |             { | ||
|  |                 TD.DuplicateDiscoveryMessage( | ||
|  |                     this.context.EventTraceActivity, | ||
|  |                     ProtocolStrings.TracingStrings.Resolve, | ||
|  |                     OperationContext.Current.IncomingMessageHeaders.MessageId.ToString()); | ||
|  |             } | ||
|  | 
 | ||
|  |             return !isDuplicate; | ||
|  |         } | ||
|  | 
 | ||
|  |         IAsyncResult BeginSendProxyAnnouncement( | ||
|  |             EndpointDiscoveryMetadata proxyEndpoint, | ||
|  |             TimeSpan timeout, | ||
|  |             AsyncCallback callback, | ||
|  |             object state) | ||
|  |         { | ||
|  |             IAsyncResult result; | ||
|  |             IContextChannel contextChannel = (IContextChannel)this.ResponseChannel; | ||
|  |             using (new OperationContextScope(contextChannel)) | ||
|  |             { | ||
|  |                 this.context.AddressDuplexResponseMessage(OperationContext.Current); | ||
|  | 
 | ||
|  |                 contextChannel.OperationTimeout = timeout; | ||
|  | 
 | ||
|  |                 result = this.BeginSendProxyAnnouncement( | ||
|  |                     this.ResponseChannel, | ||
|  |                     this.discoveryServiceImpl.GetNextMessageSequence(), | ||
|  |                     proxyEndpoint, | ||
|  |                     callback, | ||
|  |                     state); | ||
|  |             } | ||
|  | 
 | ||
|  |             return result; | ||
|  |         } | ||
|  | 
 | ||
|  |         void EndSendProxyAnnouncement(IAsyncResult result) | ||
|  |         { | ||
|  |             this.EndSendProxyAnnouncement(this.ResponseChannel, result); | ||
|  |         } | ||
|  | 
 | ||
|  |         class ProxyAnnouncementsSendAsyncResult : RandomDelaySendsAsyncResult | ||
|  |         { | ||
|  |             ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel> resolveDuplexAsyncResult; | ||
|  |             Collection<EndpointDiscoveryMetadata> redirectionEndpoints; | ||
|  | 
 | ||
|  |             public ProxyAnnouncementsSendAsyncResult( | ||
|  |                 ResolveDuplexAsyncResult<TResolveMessage, TResponseChannel> resolveDuplexAsyncResult, | ||
|  |                 Collection<EndpointDiscoveryMetadata> redirectionEndpoints, | ||
|  |                 AsyncCallback callback, | ||
|  |                 object state) | ||
|  |                 : base( | ||
|  |                 redirectionEndpoints.Count, | ||
|  |                 resolveDuplexAsyncResult.context.MaxResponseDelay, | ||
|  |                 callback, | ||
|  |                 state) | ||
|  |             { | ||
|  |                 this.resolveDuplexAsyncResult = resolveDuplexAsyncResult; | ||
|  |                 this.redirectionEndpoints = redirectionEndpoints; | ||
|  |                 this.Start(this.resolveDuplexAsyncResult.timeoutHelper.RemainingTime()); | ||
|  |             } | ||
|  | 
 | ||
|  |             public static void End(IAsyncResult result) | ||
|  |             { | ||
|  |                 AsyncResult.End<ProxyAnnouncementsSendAsyncResult>(result); | ||
|  |             } | ||
|  | 
 | ||
|  |             protected override IAsyncResult OnBeginSend(int index, TimeSpan timeout, AsyncCallback callback, object state) | ||
|  |             { | ||
|  |                 return this.resolveDuplexAsyncResult.BeginSendProxyAnnouncement( | ||
|  |                     this.redirectionEndpoints[index], | ||
|  |                     timeout, | ||
|  |                     callback, | ||
|  |                     state); | ||
|  |             } | ||
|  | 
 | ||
|  |             protected override void OnEndSend(IAsyncResult result) | ||
|  |             { | ||
|  |                 this.resolveDuplexAsyncResult.EndSendProxyAnnouncement(result); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |