9f3022762c8e2a23cde495235dd32d4c0165ebd1
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / InternalDuplexChannelListener.cs
1 //----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Runtime;
7     using System.ServiceModel.Diagnostics;
8
9     sealed class InternalDuplexChannelListener : DelegatingChannelListener<IDuplexChannel>
10     {
11         IChannelFactory<IOutputChannel> innerChannelFactory;
12         bool providesCorrelation;
13
14         internal InternalDuplexChannelListener(InternalDuplexBindingElement bindingElement, BindingContext context)
15             : base(context.Binding, context.Clone().BuildInnerChannelListener<IInputChannel>())
16         {
17             this.innerChannelFactory = context.BuildInnerChannelFactory<IOutputChannel>();
18             this.providesCorrelation = bindingElement.ProvidesCorrelation;
19         }
20
21         IOutputChannel GetOutputChannel(Uri to, TimeoutHelper timeoutHelper)
22         {
23             IOutputChannel channel = this.innerChannelFactory.CreateChannel(new EndpointAddress(to));
24             channel.Open(timeoutHelper.RemainingTime());
25             return channel;
26         }
27
28         protected override void OnAbort()
29         {
30             try
31             {
32                 this.innerChannelFactory.Abort();
33             }
34             finally
35             {
36                 base.OnAbort();
37             }
38         }
39
40         protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
41         {
42             return new ChainedCloseAsyncResult(timeout, callback, state, base.OnBeginClose, base.OnEndClose, this.innerChannelFactory);
43         }
44
45         protected override void OnEndClose(IAsyncResult result)
46         {
47             ChainedCloseAsyncResult.End(result);
48         }
49
50         protected override void OnClose(TimeSpan timeout)
51         {
52             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
53             base.OnClose(timeoutHelper.RemainingTime());
54             this.innerChannelFactory.Close(timeoutHelper.RemainingTime());
55         }
56
57         protected override void OnOpening()
58         {
59             base.OnOpening();
60             this.Acceptor = (IChannelAcceptor<IDuplexChannel>)(object)new CompositeDuplexChannelAcceptor(this, (IChannelListener<IInputChannel>)this.InnerChannelListener);
61         }
62
63         protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
64         {
65             return new ChainedOpenAsyncResult(timeout, callback, state, base.OnBeginOpen, base.OnEndOpen, this.innerChannelFactory);
66         }
67
68         protected override void OnEndOpen(IAsyncResult result)
69         {
70             ChainedOpenAsyncResult.End(result);
71         }
72
73         protected override void OnOpen(TimeSpan timeout)
74         {
75             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
76             base.OnOpen(timeoutHelper.RemainingTime());
77             this.innerChannelFactory.Open(timeoutHelper.RemainingTime());
78         }
79
80         public override T GetProperty<T>()
81         {
82             if (typeof(T) == typeof(IChannelFactory))
83             {
84                 return (T)(object)innerChannelFactory;
85             }
86
87             if (typeof(T) == typeof(ISecurityCapabilities) && !this.providesCorrelation)
88             {
89                 return InternalDuplexBindingElement.GetSecurityCapabilities<T>(base.GetProperty<ISecurityCapabilities>());
90             }
91
92             T baseProperty = base.GetProperty<T>();
93             if (baseProperty != null)
94             {
95                 return baseProperty;
96             }
97
98             return this.innerChannelFactory.GetProperty<T>();
99         }
100
101         sealed class CompositeDuplexChannelAcceptor : LayeredChannelAcceptor<IDuplexChannel, IInputChannel>
102         {
103             public CompositeDuplexChannelAcceptor(InternalDuplexChannelListener listener, IChannelListener<IInputChannel> innerListener)
104                 : base(listener, innerListener)
105             {
106             }
107
108             protected override IDuplexChannel OnAcceptChannel(IInputChannel innerChannel)
109             {
110                 return new ServerCompositeDuplexChannel((InternalDuplexChannelListener)ChannelManager, innerChannel);
111             }
112         }
113
114         sealed class ServerCompositeDuplexChannel : ChannelBase, IDuplexChannel
115         {
116             IInputChannel innerInputChannel;
117             TimeSpan sendTimeout;
118
119             public ServerCompositeDuplexChannel(InternalDuplexChannelListener listener, IInputChannel innerInputChannel)
120                 : base(listener)
121             {
122                 this.innerInputChannel = innerInputChannel;
123                 this.sendTimeout = listener.DefaultSendTimeout;
124             }
125
126             InternalDuplexChannelListener Listener
127             {
128                 get { return (InternalDuplexChannelListener)base.Manager; }
129             }
130
131             public EndpointAddress LocalAddress
132             {
133                 get { return this.innerInputChannel.LocalAddress; }
134             }
135
136             public EndpointAddress RemoteAddress
137             {
138                 get { return null; }
139             }
140
141             public Uri Via
142             {
143                 get { return null; }
144             }
145
146             public Message Receive()
147             {
148                 return this.Receive(this.DefaultReceiveTimeout);
149             }
150
151             public Message Receive(TimeSpan timeout)
152             {
153                 return InputChannel.HelpReceive(this, timeout);
154             }
155
156             public IAsyncResult BeginReceive(AsyncCallback callback, object state)
157             {
158                 return this.BeginReceive(this.DefaultReceiveTimeout, callback, state);
159             }
160
161             public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
162             {
163                 return InputChannel.HelpBeginReceive(this, timeout, callback, state);
164             }
165
166             public Message EndReceive(IAsyncResult result)
167             {
168                 return InputChannel.HelpEndReceive(result);
169             }
170
171             public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
172             {
173                 return this.innerInputChannel.BeginTryReceive(timeout, callback, state);
174             }
175
176             public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
177             {
178                 return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
179             }
180
181             public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
182             {
183                 return new SendAsyncResult(this, message, timeout, callback, state);
184             }
185
186             public bool EndTryReceive(IAsyncResult result, out Message message)
187             {
188                 return this.innerInputChannel.EndTryReceive(result, out message);
189             }
190
191             public void EndSend(IAsyncResult result)
192             {
193                 SendAsyncResult.End(result);
194             }
195
196             protected override void OnAbort()
197             {
198                 this.innerInputChannel.Abort();
199             }
200
201             protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
202             {
203                 return this.innerInputChannel.BeginClose(timeout, callback, state);
204             }
205
206             protected override void OnEndClose(IAsyncResult result)
207             {
208                 this.innerInputChannel.EndClose(result);
209             }
210
211             protected override void OnClose(TimeSpan timeout)
212             {
213                 if (this.innerInputChannel.State == CommunicationState.Opened)
214                     this.innerInputChannel.Close(timeout);
215             }
216
217             protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
218             {
219                 return this.innerInputChannel.BeginOpen(callback, state);
220             }
221
222             protected override void OnEndOpen(IAsyncResult result)
223             {
224                 this.innerInputChannel.EndOpen(result);
225             }
226
227             protected override void OnOpen(TimeSpan timeout)
228             {
229                 this.innerInputChannel.Open(timeout);
230             }
231
232             public bool TryReceive(TimeSpan timeout, out Message message)
233             {
234                 return this.innerInputChannel.TryReceive(timeout, out message);
235             }
236
237             public void Send(Message message)
238             {
239                 this.Send(message, this.DefaultSendTimeout);
240             }
241
242             public void Send(Message message, TimeSpan timeout)
243             {
244                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
245                 IOutputChannel outputChannel = ValidateStateAndGetOutputChannel(message, timeoutHelper);
246                 try
247                 {
248                     outputChannel.Send(message, timeoutHelper.RemainingTime());
249                     outputChannel.Close(timeoutHelper.RemainingTime());
250                 }
251                 finally
252                 {
253                     outputChannel.Abort();
254                 }
255             }
256
257             IOutputChannel ValidateStateAndGetOutputChannel(Message message, TimeoutHelper timeoutHelper)
258             {
259                 ThrowIfDisposedOrNotOpen();
260                 if (message == null)
261                 {
262                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
263                 }
264                 Uri to = message.Properties.Via;
265                 if (to == null)
266                 {
267                     to = message.Headers.To;
268                     if (to == null)
269                     {
270                         throw TraceUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageMustHaveViaOrToSetForSendingOnServerSideCompositeDuplexChannels)), message);
271                     }
272                     //Check for EndpointAddress.AnonymousUri is just redundant
273                     else if (to.Equals(EndpointAddress.AnonymousUri) || to.Equals(message.Version.Addressing.AnonymousUri))
274                     {
275                         throw TraceUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageToCannotBeAddressedToAnonymousOnServerSideCompositeDuplexChannels, to)), message);
276                     }
277                 }
278                 //Check for EndpointAddress.AnonymousUri is just redundant
279                 else if (to.Equals(EndpointAddress.AnonymousUri) || to.Equals(message.Version.Addressing.AnonymousUri))
280                 {
281                     throw TraceUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageViaCannotBeAddressedToAnonymousOnServerSideCompositeDuplexChannels, to)), message);
282                 }
283                 return this.Listener.GetOutputChannel(to, timeoutHelper);
284             }
285
286             class SendAsyncResult : AsyncResult
287             {
288                 IOutputChannel outputChannel;
289                 static AsyncCallback sendCompleteCallback = Fx.ThunkCallback(new AsyncCallback(SendCompleteCallback));
290                 TimeoutHelper timeoutHelper;
291
292                 public SendAsyncResult(ServerCompositeDuplexChannel outer, Message message, TimeSpan timeout, AsyncCallback callback, object state)
293                     : base(callback, state)
294                 {
295                     this.timeoutHelper = new TimeoutHelper(timeout);
296                     this.outputChannel = outer.ValidateStateAndGetOutputChannel(message, timeoutHelper);
297
298                     bool success = false;
299                     try
300                     {
301                         IAsyncResult result = outputChannel.BeginSend(message, timeoutHelper.RemainingTime(), sendCompleteCallback, this);
302                         if (result.CompletedSynchronously)
303                         {
304                             CompleteSend(result);
305                             this.Complete(true);
306                         }
307                         success = true;
308                     }
309                     finally
310                     {
311                         if (!success)
312                             this.outputChannel.Abort();
313                     }
314                 }
315
316                 void CompleteSend(IAsyncResult result)
317                 {
318                     try
319                     {
320                         outputChannel.EndSend(result);
321                         outputChannel.Close();
322                     }
323                     finally
324                     {
325                         outputChannel.Abort();
326                     }
327                 }
328
329                 internal static void End(IAsyncResult result)
330                 {
331                     AsyncResult.End<SendAsyncResult>(result);
332                 }
333
334                 static void SendCompleteCallback(IAsyncResult result)
335                 {
336                     if (result.CompletedSynchronously)
337                     {
338                         return;
339                     }
340
341                     SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
342
343                     Exception completionException = null;
344                     try
345                     {
346                         thisPtr.CompleteSend(result);
347                     }
348 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
349                     catch (Exception e)
350                     {
351                         if (Fx.IsFatal(e))
352                         {
353                             throw;
354                         }
355                         completionException = e;
356                     }
357                     thisPtr.Complete(false, completionException);
358                 }
359             }
360
361             public bool WaitForMessage(TimeSpan timeout)
362             {
363                 return innerInputChannel.WaitForMessage(timeout);
364             }
365
366             public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
367             {
368                 return innerInputChannel.BeginWaitForMessage(timeout, callback, state);
369             }
370
371             public bool EndWaitForMessage(IAsyncResult result)
372             {
373                 return innerInputChannel.EndWaitForMessage(result);
374             }
375         }
376     }
377 }