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