1 //---------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //---------------------------------------------------------------------------- 4 5 namespace System.ServiceModel.Channels 6 { 7 using System.ServiceModel.Activation; 8 using System.Collections.Generic; 9 using System.Diagnostics; 10 using System.ServiceModel; 11 using System.Threading; 12 using System.ServiceModel.Diagnostics; 13 14 class SharedTcpTransportManager : TcpTransportManager, ITransportManagerRegistration 15 { 16 SharedConnectionListener listener; 17 ConnectionDemuxer connectionDemuxer; 18 HostNameComparisonMode hostNameComparisonMode; 19 Uri listenUri; 20 int queueId; 21 Guid token; 22 Func<Uri, int> onDuplicatedViaCallback; 23 bool demuxerCreated; 24 SharedTcpTransportManager(Uri listenUri, TcpChannelListener channelListener)25 public SharedTcpTransportManager(Uri listenUri, TcpChannelListener channelListener) 26 { 27 this.HostNameComparisonMode = channelListener.HostNameComparisonMode; 28 this.listenUri = listenUri; 29 30 // For port sharing, we apply all of the settings from channel listener to the transport manager. 31 this.ApplyListenerSettings(channelListener); 32 } 33 SharedTcpTransportManager(Uri listenUri)34 protected SharedTcpTransportManager(Uri listenUri) 35 { 36 this.listenUri = listenUri; 37 } 38 IsCompatible(TcpChannelListener channelListener)39 protected override bool IsCompatible(TcpChannelListener channelListener) 40 { 41 if (channelListener.HostedVirtualPath == null && !channelListener.PortSharingEnabled) 42 { 43 return false; 44 } 45 46 return base.IsCompatible(channelListener); 47 } 48 49 public HostNameComparisonMode HostNameComparisonMode 50 { 51 get 52 { 53 return this.hostNameComparisonMode; 54 } 55 set 56 { 57 HostNameComparisonModeHelper.Validate(value); 58 lock (base.ThisLock) 59 { 60 ThrowIfOpen(); 61 this.hostNameComparisonMode = value; 62 } 63 } 64 } 65 66 public Uri ListenUri 67 { 68 get 69 { 70 return this.listenUri; 71 } 72 } 73 OnOpen()74 internal override void OnOpen() 75 { 76 OnOpenInternal(0, Guid.Empty); 77 } 78 GetOnViaCallback()79 protected virtual Action<Uri> GetOnViaCallback() 80 { 81 return null; 82 } 83 84 // This method is called only for the first via of the current proxy. OnDuplicatedVia(Uri via)85 int OnDuplicatedVia(Uri via) 86 { 87 Action<Uri> onVia = GetOnViaCallback(); 88 if (onVia != null) 89 { 90 onVia(via); 91 } 92 93 if (!demuxerCreated) 94 { 95 lock (ThisLock) 96 { 97 if (listener == null) 98 { 99 // The listener has been stopped. 100 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationObjectAbortedException( 101 SR.GetString(SR.Sharing_ListenerProxyStopped))); 102 } 103 104 if (!demuxerCreated) 105 { 106 CreateConnectionDemuxer(); 107 demuxerCreated = true; 108 } 109 } 110 } 111 112 return this.ConnectionBufferSize; 113 } 114 CreateConnectionDemuxer()115 void CreateConnectionDemuxer() 116 { 117 IConnectionListener connectionListener = new BufferedConnectionListener(listener, MaxOutputDelay, ConnectionBufferSize); 118 if (DiagnosticUtility.ShouldUseActivity) 119 { 120 connectionListener = new TracingConnectionListener(connectionListener, this.ListenUri); 121 } 122 123 connectionDemuxer = new ConnectionDemuxer(connectionListener, 124 MaxPendingAccepts, MaxPendingConnections, ChannelInitializationTimeout, 125 IdleTimeout, MaxPooledConnections, 126 OnGetTransportFactorySettings, 127 OnGetSingletonMessageHandler, 128 OnHandleServerSessionPreamble, 129 OnDemuxerError); 130 connectionDemuxer.StartDemuxing(this.GetOnViaCallback()); 131 } 132 OnOpenInternal(int queueId, Guid token)133 internal void OnOpenInternal(int queueId, Guid token) 134 { 135 lock (ThisLock) 136 { 137 this.queueId = queueId; 138 this.token = token; 139 140 BaseUriWithWildcard path = new BaseUriWithWildcard(this.ListenUri, this.HostNameComparisonMode); 141 142 if (this.onDuplicatedViaCallback == null) 143 { 144 this.onDuplicatedViaCallback = new Func<Uri, int>(OnDuplicatedVia); 145 } 146 147 listener = new SharedConnectionListener(path, queueId, token, this.onDuplicatedViaCallback); 148 149 // Delay the creation of the demuxer on the first request. 150 } 151 } 152 CleanUp(bool aborting, TimeSpan timeout)153 protected void CleanUp(bool aborting, TimeSpan timeout) 154 { 155 lock (ThisLock) 156 { 157 if (listener != null) 158 { 159 if (!aborting) 160 { 161 listener.Stop(timeout); 162 } 163 else 164 { 165 listener.Abort(); 166 } 167 168 // The listener will be closed by the demuxer. 169 listener = null; 170 } 171 172 if (connectionDemuxer != null) 173 { 174 connectionDemuxer.Dispose(); 175 } 176 177 demuxerCreated = false; 178 } 179 } 180 Unregister()181 void Unregister() 182 { 183 TcpChannelListener.StaticTransportManagerTable.UnregisterUri(this.ListenUri, this.HostNameComparisonMode); 184 } 185 OnAbort()186 internal override void OnAbort() 187 { 188 CleanUp(true, TimeSpan.Zero); 189 Unregister(); 190 base.OnAbort(); 191 } 192 OnClose(TimeSpan timeout)193 internal override void OnClose(TimeSpan timeout) 194 { 195 CleanUp(false, timeout); 196 Unregister(); 197 } 198 OnSelecting(TcpChannelListener channelListener)199 protected virtual void OnSelecting(TcpChannelListener channelListener) 200 { 201 } 202 ITransportManagerRegistration.Select(TransportChannelListener channelListener)203 IList<TransportManager> ITransportManagerRegistration.Select(TransportChannelListener channelListener) 204 { 205 if (!channelListener.IsScopeIdCompatible(this.hostNameComparisonMode, this.listenUri)) 206 { 207 return null; 208 } 209 210 OnSelecting((TcpChannelListener)channelListener); 211 212 IList<TransportManager> result = null; 213 if (this.IsCompatible((TcpChannelListener)channelListener)) 214 { 215 result = new List<TransportManager>(); 216 result.Add(this); 217 } 218 return result; 219 } 220 } 221 } 222