2010-06-17 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / ChannelListenerBase_1.cs
1 //
2 // ChannelListenerBase.cs
3 //
4 // Author: Atsushi Enomoto (atsushi@ximian.com)
5 //
6 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 // 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 //
27 using System;
28 using System.Collections.Generic;
29 using System.ServiceModel;
30 using System.ServiceModel.Description;
31 using System.Threading;
32
33 namespace System.ServiceModel.Channels
34 {
35         internal abstract class InternalChannelListenerBase<TChannel>
36                 : ChannelListenerBase<TChannel>
37                 where TChannel : class, IChannel
38         {
39                 protected InternalChannelListenerBase (BindingContext context)
40                         : base (context.Binding)
41                 {
42                         // for ListenUriMode(.Unique), the URI uniqueness
43                         // should be assured by the derived types.
44                         listen_uri =
45                                 context.ListenUriRelativeAddress != null ?
46                                 new Uri (context.ListenUriBaseAddress, context.ListenUriRelativeAddress) :
47                                 context.ListenUriBaseAddress;
48                 }
49
50                 Uri listen_uri;
51                 Func<TimeSpan,TChannel> accept_channel_delegate;
52                 Func<TimeSpan,bool> wait_delegate;
53                 Action<TimeSpan> open_delegate, close_delegate;
54
55                 public MessageEncoder MessageEncoder { get; internal set; }
56
57                 public override Uri Uri {
58                         get { return listen_uri; }
59                 }
60
61                 protected Thread CurrentAsyncThread { get; private set; }
62                 protected IAsyncResult CurrentAsyncResult { get; private set; }
63
64                 protected override void OnAbort ()
65                 {
66                         if (CurrentAsyncThread != null)
67                                 CurrentAsyncThread.Abort (); // it is not beautiful but there is no other way to stop it.
68                 }
69
70                 protected override void OnClose (TimeSpan timeout)
71                 {
72                         if (CurrentAsyncThread != null)
73                                 if (!CancelAsync (timeout))
74                                         if (CurrentAsyncThread != null) // being careful
75                                                 CurrentAsyncThread.Abort (); // it is not beautiful but there is no other way to stop it.
76                 }
77
78                 // cancel ongoing async operations and return if it was 
79                 // completed successfully. If not, it will abort.
80                 public virtual bool CancelAsync (TimeSpan timeout)
81                 {
82                         return CurrentAsyncResult == null || CurrentAsyncResult.AsyncWaitHandle.WaitOne (timeout);
83                 }
84
85                 protected override IAsyncResult OnBeginAcceptChannel (
86                         TimeSpan timeout, AsyncCallback callback,
87                         object asyncState)
88                 {
89                         //if (CurrentAsyncResult != null)
90                         //      throw new InvalidOperationException ("Another AcceptChannel operation is in progress");
91
92                         ManualResetEvent wait = new ManualResetEvent (false);
93
94                         if (accept_channel_delegate == null)
95                                 accept_channel_delegate = new Func<TimeSpan,TChannel> (delegate (TimeSpan tout) {
96                                         wait.WaitOne (); // make sure that CurrentAsyncResult is set.
97                                         CurrentAsyncThread = Thread.CurrentThread;
98
99                                         try {
100                                                 return OnAcceptChannel (tout);
101                                         } finally {
102                                                 CurrentAsyncThread = null;
103                                                 CurrentAsyncResult = null;
104                                         }
105                                 });
106
107                         CurrentAsyncResult = accept_channel_delegate.BeginInvoke (timeout, callback, asyncState);
108                         wait.Set ();
109                         return CurrentAsyncResult;
110                 }
111
112                 protected override TChannel OnEndAcceptChannel (IAsyncResult result)
113                 {
114                         if (accept_channel_delegate == null)
115                                 throw new InvalidOperationException ("Async AcceptChannel operation has not started");
116                         // FIXME: what's wrong with this?
117                         //if (CurrentAsyncResult == null)
118                         //      throw new InvalidOperationException ("Async AcceptChannel operation has not started. Argument result was: " + result);
119                         return accept_channel_delegate.EndInvoke (result);
120                 }
121
122                 protected override IAsyncResult OnBeginWaitForChannel (
123                         TimeSpan timeout, AsyncCallback callback, object state)
124                 {
125                         if (wait_delegate == null)
126                                 wait_delegate = new Func<TimeSpan,bool> (OnWaitForChannel);
127                         return wait_delegate.BeginInvoke (timeout, callback, state);
128                 }
129
130                 protected override bool OnEndWaitForChannel (IAsyncResult result)
131                 {
132                         if (wait_delegate == null)
133                                 throw new InvalidOperationException ("Async WaitForChannel operation has not started");
134                         return wait_delegate.EndInvoke (result);
135                 }
136
137                 protected override IAsyncResult OnBeginOpen (TimeSpan timeout,
138                         AsyncCallback callback, object state)
139                 {
140                         if (open_delegate == null)
141                                 open_delegate = new Action<TimeSpan> (OnOpen);
142                         return open_delegate.BeginInvoke (timeout, callback, state);
143                 }
144
145                 protected override void OnEndOpen (IAsyncResult result)
146                 {
147                         if (open_delegate == null)
148                                 throw new InvalidOperationException ("Async Open operation has not started");
149                         open_delegate.EndInvoke (result);
150                 }
151
152                 protected override IAsyncResult OnBeginClose (TimeSpan timeout,
153                         AsyncCallback callback, object state)
154                 {
155                         if (close_delegate == null)
156                                 close_delegate = new Action<TimeSpan> (OnClose);
157                         return close_delegate.BeginInvoke (timeout, callback, state);
158                 }
159
160                 protected override void OnEndClose (IAsyncResult result)
161                 {
162                         if (close_delegate == null)
163                                 throw new InvalidOperationException ("Async Close operation has not started");
164                         close_delegate.EndInvoke (result);
165                 }
166         }
167
168         public abstract class ChannelListenerBase<TChannel>
169                 : ChannelListenerBase, IChannelListener<TChannel>, 
170                 IChannelListener,  ICommunicationObject
171                 where TChannel : class, IChannel
172         {
173                 IDefaultCommunicationTimeouts timeouts;
174
175                 protected ChannelListenerBase ()
176                         : this (DefaultCommunicationTimeouts.Instance)
177                 {
178                 }
179
180                 protected ChannelListenerBase (
181                         IDefaultCommunicationTimeouts timeouts)
182                 {
183                         if (timeouts == null)
184                                 throw new ArgumentNullException ("timeouts");
185                         this.timeouts = timeouts;
186                 }
187
188                 public TChannel AcceptChannel ()
189                 {
190                         return AcceptChannel (timeouts.ReceiveTimeout);
191                 }
192
193                 public TChannel AcceptChannel (TimeSpan timeout)
194                 {
195                         ThrowIfDisposedOrNotOpen ();
196                         return OnAcceptChannel (timeout);
197                 }
198
199                 public IAsyncResult BeginAcceptChannel (
200                         AsyncCallback callback, object asyncState)
201                 {
202                         return BeginAcceptChannel (
203                                 timeouts.ReceiveTimeout, callback, asyncState);
204                 }
205
206                 public IAsyncResult BeginAcceptChannel (TimeSpan timeout,
207                         AsyncCallback callback, object asyncState)
208                 {
209                         return OnBeginAcceptChannel (timeout, callback, asyncState);
210                 }
211
212                 public TChannel EndAcceptChannel (IAsyncResult result)
213                 {
214                         return OnEndAcceptChannel (result);
215                 }
216
217                 protected abstract TChannel OnAcceptChannel (TimeSpan timeout);
218
219                 protected abstract IAsyncResult OnBeginAcceptChannel (TimeSpan timeout,
220                         AsyncCallback callback, object asyncState);
221
222                 protected abstract TChannel OnEndAcceptChannel (IAsyncResult result);
223         }
224 }