Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / SharedConnectionListener.cs / 1 / SharedConnectionListener.cs
//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.ServiceModel; using System.ComponentModel; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Security.Principal; using System.ServiceModel.Diagnostics; using System.Threading; using System.ServiceProcess; using System.Security.AccessControl; using System.Reflection; using System.ServiceModel.Configuration; using System.Web.Hosting; using System.ServiceModel.Security; using System.ServiceModel.Activation; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.Remoting; using System.ServiceModel.Dispatcher; using System.ServiceModel.Description; using Utility = System.ServiceModel.Activation.Utility; sealed class SharedConnectionListener : IConnectionListener { BaseUriWithWildcard baseAddress; int queueId; Guid token; InputQueueconnectionQueue; SharedListenerProxy listenerProxy; WaitCallback reconnectCallback; object syncRoot = new object(); CommunicationState state; ManualResetEvent reconnectEvent; OnDuplicatedViaDelegate onDuplicatedViaCallback; internal SharedConnectionListener(BaseUriWithWildcard baseAddress, int queueId, Guid token, OnDuplicatedViaDelegate onDuplicatedViaCallback) { this.baseAddress = baseAddress; this.queueId = queueId; this.token = token; this.onDuplicatedViaCallback = onDuplicatedViaCallback; this.connectionQueue = new InputQueue (); this.state = CommunicationState.Created; this.reconnectEvent = new ManualResetEvent(true); // only attmptStart if doing TCP port sharing // for activation we need to wait for the service to start if it crashes before w3wp can hook up StartListen(false); } object ThisLock { get { return this.syncRoot; } } void IConnectionListener.Listen() { // No-op since we have already been started. } IAsyncResult IConnectionListener.BeginAccept(AsyncCallback callback, object state) { DiagnosticUtility.DebugAssert(connectionQueue != null, "The connectionQueue should not be null when BeginAccept is called."); Debug.Print("SharedConnectionListener.BeginAccept() connectionQueue.PendingCount: " + connectionQueue.PendingCount); return connectionQueue.BeginDequeue(TimeSpan.MaxValue, callback, state); } // Stop the proxy but do not close to let existing connections to be drained. public void Stop() { bool shouldWait = false; lock (ThisLock) { if (this.state == CommunicationState.Closing || this.state == CommunicationState.Closed) { return; } else if (this.state == CommunicationState.Opening) { shouldWait = true; } this.state = CommunicationState.Closing; } if (shouldWait) { this.reconnectEvent.WaitOne(); } if (listenerProxy != null) { listenerProxy.Close(); } } void Close() { lock (ThisLock) { if (this.state == CommunicationState.Closed) { return; } DiagnosticUtility.DebugAssert(this.state == CommunicationState.Closing, "The Stop method must be called first before calling Close."); this.state = CommunicationState.Closed; } if (connectionQueue != null) { connectionQueue.Close(); } if (this.reconnectEvent != null) { this.reconnectEvent.Close(); } } void OnConnectionAvailable(DuplicateConnectionAsyncResult result) { // Enqueue the context and dispatch it on a different thread. connectionQueue.EnqueueAndDispatch(result, null, false); } static string GetServiceName(bool isTcp) { return isTcp ? ListenerConstants.TcpPortSharingServiceName : ListenerConstants.NamedPipeActivationServiceName; } IConnection IConnectionListener.EndAccept(IAsyncResult result) { lock (ThisLock) { if (this.state != CommunicationState.Opening && this.state != CommunicationState.Opened) { return null; } DuplicateConnectionAsyncResult duplicateAsyncResult = connectionQueue.EndDequeue(result); DiagnosticUtility.DebugAssert(duplicateAsyncResult != null, "EndAccept: EndDequeue returned null."); // Finish the duplication. duplicateAsyncResult.CompleteOperation(); return duplicateAsyncResult.Connection; } } void OnListenerFaulted(bool shouldReconnect) { lock (ThisLock) { if (this.state == CommunicationState.Closing || this.state == CommunicationState.Closed) { return; } listenerProxy.Abort(); if (shouldReconnect) { this.state = CommunicationState.Opening; this.reconnectEvent.Reset(); } else { this.state = CommunicationState.Faulted; } } if (shouldReconnect) { if (reconnectCallback == null) { reconnectCallback = new WaitCallback(ReconnectCallback); } IOThreadScheduler.ScheduleCallback(reconnectCallback, this); } } void StartListen(bool isReconnecting) { listenerProxy = new SharedListenerProxy(this); if (isReconnecting) { // Signal the event so that we are safe to close. reconnectEvent.Set(); } listenerProxy.Open(isReconnecting); lock (ThisLock) { if (this.state == CommunicationState.Created || this.state == CommunicationState.Opening) { this.state = CommunicationState.Opened; } } } void ReconnectCallback(object state) { BackoffTimeoutHelper backoffHelper = new BackoffTimeoutHelper(TimeSpan.MaxValue, TimeSpan.FromMinutes(5), TimeSpan.FromSeconds(30)); // Looping until we can connect or when it's closed. while(this.state == CommunicationState.Opening) { bool success = false; try { StartListen(true); success = true; } catch (Exception exception) { if (DiagnosticUtility.IsFatal(exception)) { throw; } if (DiagnosticUtility.ShouldTraceError) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); } } // Add backoff when reconnect if (this.state == CommunicationState.Opening) { DiagnosticUtility.DebugAssert(!success, "The state should be Opened if it is successful."); backoffHelper.WaitAndBackoff(); } } } void IDisposable.Dispose() { Debug.Print("SharedConnectionListener.Dispose()"); Close(); } [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] class SharedListenerProxy : IConnectionDuplicator, IInputSessionShutdown { static byte[] drainBuffer; SharedConnectionListener parent; BaseUriWithWildcard baseAddress; int queueId; Guid token; bool isTcp; string serviceName; string listenerEndPoint; SecurityIdentifier listenerUniqueSid; SecurityIdentifier listenerUserSid; ChannelFactory channelFactory; IDuplexContextChannel controlSessionWithListener; IDisposable allowContext; string securityEventName; object syncRoot = new object(); int connectionBufferSize; OnDuplicatedViaDelegate onDuplicatedViaCallback; bool listenerClosed; bool closed; bool opened; public SharedListenerProxy(SharedConnectionListener parent) { this.parent = parent; this.baseAddress = parent.baseAddress; this.queueId = parent.queueId; this.token = parent.token; this.onDuplicatedViaCallback = parent.onDuplicatedViaCallback; this.isTcp = parent.baseAddress.BaseAddress.Scheme.Equals(Uri.UriSchemeNetTcp); this.securityEventName = Guid.NewGuid().ToString(); this.serviceName = SharedConnectionListener.GetServiceName(isTcp); } public void Open(bool isReconnecting) { Debug.Print("SharedListenerProxy.Open() isReconnecting: " + isReconnecting); if (this.closed) { return; } // Start the listener service this.listenerEndPoint = HandleServiceStart(isReconnecting); if (string.IsNullOrEmpty(listenerEndPoint)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException( SR.GetString(SR.Sharing_EmptyListenerEndpoint, this.serviceName))); } // Check it again after possible backoff if (this.closed) { return; } LookupListenerSid(); EventWaitHandle securityEvent = null; bool success = false; // Synchronize with Close so that we can ensure cleanness lock (ThisLock) { try { // Create the control proxy CreateControlProxy(); EventWaitHandleSecurity handleSecurity = new EventWaitHandleSecurity(); handleSecurity.AddAccessRule(new EventWaitHandleAccessRule(listenerUniqueSid, EventWaitHandleRights.Modify, AccessControlType.Allow)); bool createdNew; securityEvent = new EventWaitHandle(false, EventResetMode.ManualReset, ListenerConstants.GlobalPrefix + this.securityEventName, out createdNew, handleSecurity); if (!createdNew) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceSecurityFailed)))); } Register(); bool signalled = securityEvent.WaitOne(0, false); if (!signalled) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceSecurityFailed)))); } if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PortSharingListening, SR.GetString(SR.TraceCodePortSharingListening)); } this.opened = true; success = true; } finally { if (securityEvent != null) { securityEvent.Close(); } if (!success) { Cleanup(true); // Mark it as closed this.closed = true; } } } } public void Close() { Close(false); } void Close(bool isAborting) { lock (ThisLock) { if (this.closed) { return; } bool success = false; try { Cleanup(isAborting); success = true; } finally { if (!success && !isAborting) { // Abort it Close(true); } this.closed = true; } } if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PortSharingClosed, SR.GetString(SR.TraceCodePortSharingClosed)); } } void Cleanup(bool isAborting) { bool success = false; if (controlSessionWithListener != null) { if (!isAborting) { try { Unregister(); controlSessionWithListener.Close(ListenerConstants.RegistrationCloseTimeout); success = true; } catch (Exception exception) { if (DiagnosticUtility.IsFatal(exception)) { throw; } if (DiagnosticUtility.ShouldTraceError) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); } } } if (isAborting || !success) { controlSessionWithListener.Abort(); } } if (channelFactory != null) { success = false; if (!isAborting) { try { channelFactory.Close(ListenerConstants.RegistrationCloseTimeout); success = true; } catch(Exception exception) { if (DiagnosticUtility.IsFatal(exception)) { throw; } if (DiagnosticUtility.ShouldTraceError) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); } } } if (isAborting || !success) { channelFactory.Abort(); } } if (allowContext != null) { allowContext.Dispose(); } } public void Abort() { Close(true); } object ThisLock { get { return this.syncRoot; } } void Unregister() { Debug.Print("SharedListenerProxy.Unregister()"); ((IConnectionRegister)controlSessionWithListener).Unregister(); } void LookupListenerSid() { // SECURITY // now check with the SCM and get the LogonSid or ServiceSid and the Pid for the listener if (OSEnvironmentHelper.IsVistaOrGreater) { try { listenerUniqueSid = Utility.GetWindowsServiceSid(serviceName); Debug.Print("SharedListenerProxy.LookupListenerSid() listenerUniqueSid: " + listenerUniqueSid); } catch (Win32Exception exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceSidLookupFailure, exception.NativeErrorCode)), exception)); } } else { int listenerPid; try { listenerPid = Utility.GetPidForService(serviceName); Debug.Print("SharedListenerProxy.LookupListenerSid() listenerPid: " + listenerPid); } catch (Win32Exception exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceLookupFailure, exception.NativeErrorCode)), exception)); } try { listenerUserSid = Utility.GetUserSidForPid(listenerPid); Debug.Print("SharedListenerProxy.LookupListenerSid() listenerUserSid: " + listenerUserSid); } catch (Win32Exception exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerUserSidLookupFailure, exception.NativeErrorCode)), exception)); } try { listenerUniqueSid = Utility.GetLogonSidForPid(listenerPid); } catch (Win32Exception exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerLogonSidLookupFailure, exception.NativeErrorCode)), exception)); } } Debug.Print("SharedListenerProxy.LookupListenerSid() listenerUniqueSid: " + listenerUniqueSid); } void CreateControlProxy() { EndpointAddress epa = new EndpointAddress(Utility.FormatListenerEndpoint(this.serviceName, this.listenerEndPoint)); NamedPipeTransportBindingElement namedPipeBindingElement = new NamedPipeTransportBindingElement(); CustomBinding customBinding = new CustomBinding(namedPipeBindingElement); InstanceContext instanceContext = new InstanceContext(null, this, false); ChannelFactory registerChannelFactory = new DuplexChannelFactory (instanceContext, customBinding, epa); registerChannelFactory.Endpoint.Behaviors.Add(new SharedListenerProxyBehavior(this)); IConnectionRegister connectionRegister = registerChannelFactory.CreateChannel(); this.channelFactory = registerChannelFactory; this.controlSessionWithListener = connectionRegister as IDuplexContextChannel; } void Register() { Version version = Assembly.GetExecutingAssembly().GetName().Version; int myPid = Process.GetCurrentProcess().Id; HandleAllowDupHandlePermission(myPid); ListenerExceptionStatus status = ((IConnectionRegister)this.controlSessionWithListener).Register( version, myPid, this.baseAddress, this.queueId, this.token, this.securityEventName); Debug.Print("SharedListenerProxy.Register() Register returned status: " + status); if (status != ListenerExceptionStatus.Success) { switch (status) { case ListenerExceptionStatus.ConflictingRegistration: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerConflictingRegistration)))); case ListenerExceptionStatus.FailedToListen: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerFailedToListen)))); default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString("SharedManager" + status)))); } } } void HandleAllowDupHandlePermission(int myPid) { Debug.Print("SharedListenerProxy.HandleAllowDupHandlePermission() myPid: " + myPid); bool notNecessary = !OSEnvironmentHelper.IsVistaOrGreater && listenerUserSid.Equals(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null)); Debug.Print("SharedListenerProxy.HandleAllowDupHandlePermission() notNecessary(ServiceRunningAsLocalSystem): " + notNecessary); if (notNecessary) { return; } SecurityIdentifier myUserSid; try { myUserSid = Utility.GetUserSidForPid(myPid); } catch (Win32Exception exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerCurrentUserSidLookupFailure, exception.NativeErrorCode)), exception)); } Debug.Print("SharedListenerProxy.HandleAllowDupHandlePermission() myPid: " + myPid + " myUserSid: " + myUserSid.Value); notNecessary = !OSEnvironmentHelper.IsVistaOrGreater && myUserSid.Equals(listenerUserSid); Debug.Print("SharedListenerProxy.HandleAllowDupHandlePermission() notNecessary(RunningUnderTheSameAccount): " + notNecessary); if (notNecessary) { return; } try { allowContext = AllowHelper.TryAllow(listenerUniqueSid.Value); } catch (Win32Exception exception) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerAllowDupHandleFailed, listenerUniqueSid.Value)), exception)); } if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.DiagnosticTrace.TraceEvent(TraceEventType.Information, TraceCode.PortSharingDupHandleGranted, SR.GetString(SR.TraceCodePortSharingDupHandleGranted, serviceName, listenerUniqueSid.Value), null, null); } } IConnection BuildDuplicatedNamedPipeConnection(NamedPipeDuplicateContext duplicateContext, int connectionBufferSize) { if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.PortSharingDuplicatedPipe, SR.GetString(SR.TraceCodePortSharingDuplicatedPipe)); } PipeHandle duplicated = new PipeHandle(duplicateContext.Handle); PipeConnection pipeConnection = new PipeConnection(duplicated, connectionBufferSize, false, true); return new NamedPipeValidatingConnection(new PreReadConnection(pipeConnection, duplicateContext.ReadData), this); } IConnection BuildDuplicatedTcpConnection(TcpDuplicateContext duplicateContext, int connectionBufferSize) { if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.PortSharingDuplicatedSocket, SR.GetString(SR.TraceCodePortSharingDuplicatedSocket)); } Socket socket = new Socket(duplicateContext.SocketInformation); SocketConnection socketConnection = new SocketConnection(socket, connectionBufferSize, true); return new TcpValidatingConnection(new PreReadConnection(socketConnection, duplicateContext.ReadData), this); } bool ValidateUriRoute(Uri uri, IPAddress address, int port) { try { // Synchronize with Unregister. lock (ThisLock) { if (closed) { return false; } return ((IConnectionRegister)controlSessionWithListener).ValidateUriRoute(uri, address, port); } } catch (Exception exception) { if (DiagnosticUtility.ShouldTraceError) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); } if (exception is CommunicationException || exception is TimeoutException) { return false; } throw; } } class NamedPipeValidatingConnection : DelegatingConnection { SharedListenerProxy listenerProxy; bool initialValidation; public NamedPipeValidatingConnection(IConnection connection, SharedListenerProxy listenerProxy) : base(connection) { this.listenerProxy = listenerProxy; this.initialValidation = true; } public override bool Validate(Uri uri) { if (this.initialValidation) // optimization for first usage { this.initialValidation = false; return true; } return this.listenerProxy.ValidateUriRoute(uri, null, -1); } } class TcpValidatingConnection : DelegatingConnection { IPAddress ipAddress; int port; SharedListenerProxy listenerProxy; bool initialValidation; public TcpValidatingConnection(IConnection connection, SharedListenerProxy listenerProxy) : base(connection) { this.listenerProxy = listenerProxy; Socket socket = (Socket)connection.GetCoreTransport(); this.ipAddress = ((IPEndPoint)socket.LocalEndPoint).Address; this.port = ((IPEndPoint)socket.LocalEndPoint).Port; this.initialValidation = true; } public override bool Validate(Uri uri) { if (this.initialValidation) // optimization for first usage { this.initialValidation = false; return true; } return this.listenerProxy.ValidateUriRoute(uri, ipAddress, port); } } bool ReadEndpoint(string sharedMemoryName, out string listenerEndpoint) { try { if (SharedMemory.Read(sharedMemoryName, out listenerEndpoint)) { return true; } if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.DiagnosticTrace.TraceEvent(TraceEventType.Information, TraceCode.SharedManagerServiceEndpointNotExist, SR.GetString(SR.TraceCodeSharedManagerServiceEndpointNotExist, serviceName), null, null); } return false; } catch (Win32Exception exception) { // Wrap unexpected Win32Exception. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WrapEndpointReadingException(exception)); } } Exception WrapEndpointReadingException(Win32Exception exception) { string message; if (exception.NativeErrorCode == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND) { message = SR.GetString(SR.SharedEndpointReadNotFound, this.baseAddress.BaseAddress.ToString(), this.serviceName); } else if (exception.NativeErrorCode == UnsafeNativeMethods.ERROR_ACCESS_DENIED) { message = SR.GetString(SR.SharedEndpointReadDenied, this.baseAddress.BaseAddress.ToString()); } else { message = SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceEndpointReadFailure, exception.NativeErrorCode)); } return new CommunicationException(message, exception); } string HandleServiceStart(bool isReconnecting) { string listenerEndpoint = null; string sharedMemoryName = isTcp ? ListenerConstants.TcpSharedMemoryName : ListenerConstants.NamedPipeSharedMemoryName; serviceName = SharedConnectionListener.GetServiceName(isTcp); // Try to read the endpoint only if not reconnecting. if (!isReconnecting) { if (ReadEndpoint(sharedMemoryName, out listenerEndpoint)) { return listenerEndpoint; } } ServiceController service = new ServiceController(serviceName); try { ServiceControllerStatus serviceStatus = service.Status; Debug.Print("ListenerServiceHelper.HandleServiceStart() service serviceName: " + serviceName + " is in status serviceStatus: " + serviceStatus); if (isReconnecting) { if (serviceStatus == ServiceControllerStatus.Running) { try { string listenerEndPoint = SharedMemory.Read(sharedMemoryName); if (this.listenerEndPoint != listenerEndPoint) { // Service restarted. return listenerEndPoint; } } catch (Win32Exception exception) { Debug.Print("ListenerServiceHelper.HandleServiceStart() failed when reading the shared memory sharedMemoryName: " + sharedMemoryName + " exception: " + exception); if (DiagnosticUtility.ShouldTraceWarning) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning); } } // Wait for the service to exit the running state serviceStatus = ExitServiceStatus(service, 50, 50, ServiceControllerStatus.Running); } } if (serviceStatus != ServiceControllerStatus.Running) { if (!isReconnecting) { try { service.Start(); } catch (InvalidOperationException exception) { Win32Exception win32Exception = exception.InnerException as Win32Exception; if (win32Exception != null) { if (win32Exception.NativeErrorCode == UnsafeNativeMethods.ERROR_SERVICE_DISABLED) { // service is disabled in the SCM, be specific throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceStartFailureDisabled, serviceName)), exception)); } else if (win32Exception.NativeErrorCode != UnsafeNativeMethods.ERROR_SERVICE_ALREADY_RUNNING) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceStartFailure, win32Exception.NativeErrorCode)), exception)); } } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceStartFailureNoError)), exception)); } } } else if (serviceStatus != ServiceControllerStatus.StartPending) { if (serviceStatus == ServiceControllerStatus.StopPending) { serviceStatus = ExitServiceStatus(service, 50, 1000, serviceStatus); } if (serviceStatus == ServiceControllerStatus.Stopped) { serviceStatus = ExitServiceStatus(service, 50, 1000, serviceStatus); } } service.Refresh(); serviceStatus = service.Status; Debug.Print("ListenerServiceHelper.HandleServiceStart() service serviceName: " + serviceName + " is in status serviceStatus: " + serviceStatus); if (serviceStatus == ServiceControllerStatus.StartPending) { serviceStatus = ExitServiceStatus(service, 50, 50, ServiceControllerStatus.StartPending); } } Debug.Print("ListenerServiceHelper.HandleServiceStart() final, service serviceName: " + serviceName + " is in status serviceStatus: " + serviceStatus); if (serviceStatus != ServiceControllerStatus.Running) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString( SR.SharedManagerBase, serviceName, SR.GetString(SR.SharedManagerServiceStartFailureNoError)))); } } finally { service.Close(); } try { return SharedMemory.Read(sharedMemoryName); } catch (Win32Exception exception) { Debug.Print("ListenerServiceHelper.HandleServiceStart() final, failed when reading the shared memory sharedMemoryName: " + sharedMemoryName + " exception: " + exception); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WrapEndpointReadingException(exception)); } } ServiceControllerStatus ExitServiceStatus(ServiceController service, int pollMin, int pollMax, ServiceControllerStatus status) { Debug.Print("ListenerServiceHelper.ExitServiceStatus() pollMin: " + pollMin + " pollMax: " + pollMax + " exit serviceStatus: " + status); int poll = pollMin; BackoffTimeoutHelper backoffHelper = new BackoffTimeoutHelper(TimeSpan.MaxValue, TimeSpan.FromMilliseconds(pollMax), TimeSpan.FromMilliseconds(pollMin)); for (; ; ) { if (this.closed) { // Break from backoff return service.Status; } backoffHelper.WaitAndBackoff(); service.Refresh(); ServiceControllerStatus serviceStatus = service.Status; if (serviceStatus != status) { return serviceStatus; } } } void SendFault(IConnection connection, string faultCode) { try { if (drainBuffer == null) { drainBuffer = new byte[1024]; } // return fault and close connection InitialServerConnectionReader.SendFault(connection, faultCode, drainBuffer, ListenerConstants.SharedSendTimeout, ListenerConstants.SharedMaxDrainSize); } catch (Exception exception) { if (DiagnosticUtility.IsFatal(exception)) { throw; } if (DiagnosticUtility.ShouldTraceError) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); } } } bool HandleOnVia(DuplicateContext duplicateContext) { if (this.onDuplicatedViaCallback == null) { return true; } // This is synchronized so that only the first service initializes the transport manager etc. // Subsequent services are skipped here. lock (ThisLock) { if (this.onDuplicatedViaCallback == null) { return true; } int connectionBufferSize; if (this.onDuplicatedViaCallback != null) { try { onDuplicatedViaCallback(duplicateContext.Via, out connectionBufferSize); // We completed the initialization. this.connectionBufferSize = connectionBufferSize; this.onDuplicatedViaCallback = null; } catch (Exception e) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } string faultCode = null; if (e is ServiceActivationException) { faultCode = FramingEncodingString.ServiceActivationFailedFault; } else if (e is EndpointNotFoundException) { faultCode = FramingEncodingString.EndpointNotFoundFault; } IConnection connection = BuildConnectionFromData(duplicateContext, ConnectionOrientedTransportDefaults.ConnectionBufferSize); if (faultCode != null) { SendFault(connection, faultCode); return false; } else { connection.Abort(); if (e is CommunicationObjectAbortedException) { return false; } throw; } } } } return true; } IConnection BuildConnectionFromData(DuplicateContext duplicateContext, int connectionBufferSize) { if (isTcp) { return BuildDuplicatedTcpConnection((TcpDuplicateContext)duplicateContext, connectionBufferSize); } else { return BuildDuplicatedNamedPipeConnection((NamedPipeDuplicateContext)duplicateContext, connectionBufferSize); } } IAsyncResult IConnectionDuplicator.BeginDuplicate(DuplicateContext duplicateContext, AsyncCallback callback, object state) { try { DuplicateConnectionAsyncResult result; if (!HandleOnVia(duplicateContext)) { return new DuplicateConnectionAsyncResult(callback, state); } result = new DuplicateConnectionAsyncResult(BuildConnectionFromData(duplicateContext, this.connectionBufferSize), callback, state); parent.OnConnectionAvailable(result); return result; } catch (Exception exception) { if (DiagnosticUtility.ShouldTraceError) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); } throw; } } void IConnectionDuplicator.EndDuplicate(IAsyncResult result) { DuplicateConnectionAsyncResult.End(result); } void IInputSessionShutdown.ChannelFaulted(IDuplexContextChannel channel) { OnControlChannelShutdown(); } void IInputSessionShutdown.DoneReceiving(IDuplexContextChannel channel) { OnControlChannelShutdown(); } void OnControlChannelShutdown() { if (this.listenerClosed || !this.opened) { return; } lock (ThisLock) { if (this.listenerClosed || !this.opened) { return; } listenerClosed = true; } // Only reconnect in non-activation case. this.parent.OnListenerFaulted(queueId == 0); } class SharedListenerProxyBehavior : IEndpointBehavior { SharedListenerProxy proxy; public SharedListenerProxyBehavior(SharedListenerProxy proxy) { this.proxy = proxy; } public void Validate(ServiceEndpoint serviceEndpoint) { } public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher) { } public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior) { behavior.DispatchRuntime.InputSessionShutdownHandlers.Add(this.proxy); } } } class DuplicateConnectionAsyncResult : AsyncResult { IConnection connection; public DuplicateConnectionAsyncResult(IConnection connection, AsyncCallback callback, object state) : base(callback, state) { this.connection = connection; } public DuplicateConnectionAsyncResult(AsyncCallback callback, object state) : base(callback, state) { this.Complete(true); } public IConnection Connection { get { return this.connection; } } public void CompleteOperation() { Complete(false); } public static void End(IAsyncResult result) { AsyncResult.End (result); } } } class AllowHelper : MarshalByRefObject { // this is the real instance in the default AppDomain, otherwise it's a proxy static AllowHelper singleton; static Dictionary processWideRefCount; static object thisLock = new object(); static object ThisLock { get { return thisLock; } } public override object InitializeLifetimeService() { return null; } static void EnsureInitialized() { if (singleton != null) { return; } lock (ThisLock) { if (singleton != null) { return; } if (AppDomain.CurrentDomain.IsDefaultAppDomain()) { processWideRefCount = new Dictionary (); singleton = new AllowHelper(); } else { Guid rclsid = new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E"); Guid riid = new Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E"); ListenerUnsafeNativeMethods.ICorRuntimeHost corRuntimeHost; // this call returns S_FALSE when this call did not load the library // which must be our case since we're already in managed code const int S_FALSE = 1; int hresult = ListenerUnsafeNativeMethods.CorBindToRuntimeEx(IntPtr.Zero, IntPtr.Zero, 0, ref rclsid, ref riid, out corRuntimeHost); DiagnosticUtility.DebugAssert(hresult == S_FALSE, "AllowHelper..ctor() CorBindToRuntimeEx failed"); object defaultDomainAsObject; corRuntimeHost.GetDefaultDomain(out defaultDomainAsObject); AppDomain defaultDomain = (AppDomain)defaultDomainAsObject; if (!defaultDomain.IsDefaultAppDomain()) { DiagnosticUtility.DebugAssert("AllowHelper..ctor() GetDefaultDomain did not return the default domain!"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(true); } singleton = defaultDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(AllowHelper).FullName) as AllowHelper; } } } public static IDisposable TryAllow(string newSid) { EnsureInitialized(); singleton.TryAllowCore(newSid); return new RegistrationForAllow(singleton, newSid); } void TryAllowCore(string newSid) { // In DefaultAppDomain, need to initialize. EnsureInitialized(); lock (ThisLock) { RegistrationRefCount registration; if (!processWideRefCount.TryGetValue(newSid, out registration)) { registration = new RegistrationRefCount(newSid); } registration.AddRef(); } } void UndoAllow(string grantedSid) { lock (ThisLock) { RegistrationRefCount registration = processWideRefCount[grantedSid]; registration.RemoveRef(); } } // This type is not thread-safe. The caller needs to provide synchronization mechanism. class RegistrationRefCount { int refCount; string grantedSid; public RegistrationRefCount(string grantedSid) { this.grantedSid = grantedSid; } public void AddRef() { if (refCount == 0) { Utility.AddRightGrantedToAccount(new SecurityIdentifier(grantedSid), ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE); processWideRefCount.Add(grantedSid, this); } refCount++; } public void RemoveRef() { refCount--; if (refCount == 0) { Utility.RemoveRightGrantedToAccount(new SecurityIdentifier(grantedSid), ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE); processWideRefCount.Remove(grantedSid); } } } class RegistrationForAllow : IDisposable { string grantedSid; AllowHelper singleton; public RegistrationForAllow(AllowHelper singleton, string grantedSid) { this.singleton = singleton; this.grantedSid = grantedSid; } void IDisposable.Dispose() { singleton.UndoAllow(grantedSid); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- InheritablePropertyChangeInfo.cs
- JoinElimination.cs
- LoginDesignerUtil.cs
- DbProviderFactory.cs
- AnnotationResourceChangedEventArgs.cs
- UpdateRecord.cs
- FlowDocumentReader.cs
- Utils.cs
- DragDeltaEventArgs.cs
- ActivitySurrogate.cs
- ListViewDeleteEventArgs.cs
- SymbolMethod.cs
- IPAddress.cs
- MDIClient.cs
- SapiAttributeParser.cs
- COM2IManagedPerPropertyBrowsingHandler.cs
- WebPartManagerInternals.cs
- IisTraceListener.cs
- ProbeMatchesMessage11.cs
- SiteMapNode.cs
- InvokeMethodActivityDesigner.cs
- FrameworkContentElementAutomationPeer.cs
- GetPageNumberCompletedEventArgs.cs
- AnonymousIdentificationModule.cs
- SqlRetyper.cs
- SoapAttributeAttribute.cs
- Misc.cs
- TableStyle.cs
- _BufferOffsetSize.cs
- UpdatePanelTriggerCollection.cs
- HtmlTableCellCollection.cs
- MouseGestureValueSerializer.cs
- WmlLiteralTextAdapter.cs
- PropertyChangedEventManager.cs
- GlyphsSerializer.cs
- ImageCodecInfo.cs
- ListViewItemMouseHoverEvent.cs
- ObjectResult.cs
- ExtendedPropertyDescriptor.cs
- RelationshipDetailsRow.cs
- FilterException.cs
- XmlExpressionDumper.cs
- OutputCacheProfile.cs
- TextServicesDisplayAttribute.cs
- Model3DGroup.cs
- StringDictionaryEditor.cs
- SoapEnumAttribute.cs
- MatrixStack.cs
- ExpandCollapsePattern.cs
- StateChangeEvent.cs
- remotingproxy.cs
- CompoundFileStorageReference.cs
- UniqueEventHelper.cs
- TypeInitializationException.cs
- ControlEvent.cs
- DesignerTransaction.cs
- XslVisitor.cs
- ContainerControl.cs
- WebServiceErrorEvent.cs
- CommandEventArgs.cs
- CollectionTypeElement.cs
- FixedSOMPageElement.cs
- Separator.cs
- TimeStampChecker.cs
- ListViewItemMouseHoverEvent.cs
- TemplatePropertyEntry.cs
- TraceSource.cs
- ApplicationFileCodeDomTreeGenerator.cs
- InvalidAsynchronousStateException.cs
- AssemblyHash.cs
- DefaultMemberAttribute.cs
- CodeArgumentReferenceExpression.cs
- TabRenderer.cs
- HandledEventArgs.cs
- hwndwrapper.cs
- EditorZoneAutoFormat.cs
- WindowsFormsHelpers.cs
- CharEntityEncoderFallback.cs
- AccessDataSourceDesigner.cs
- PartManifestEntry.cs
- formatter.cs
- OpenTypeLayout.cs
- Material.cs
- LineProperties.cs
- BaseTemplateBuildProvider.cs
- WebPartMenuStyle.cs
- DataGridViewButtonCell.cs
- TdsParameterSetter.cs
- Crypto.cs
- StoryFragments.cs
- filewebresponse.cs
- UncommonField.cs
- Pair.cs
- OleDbCommandBuilder.cs
- AdornedElementPlaceholder.cs
- WeakReference.cs
- NullableFloatMinMaxAggregationOperator.cs
- RecognizerBase.cs
- HttpGetServerProtocol.cs
- RegistryConfigurationProvider.cs