2009-07-31 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.Threading;
31
32 namespace System.ServiceModel.Channels
33 {
34         internal abstract class InternalChannelListenerBase<TChannel>
35                 : ChannelListenerBase<TChannel>
36                 where TChannel : class, IChannel
37         {
38                 protected InternalChannelListenerBase ()
39                         : base ()
40                 {
41                 }
42
43                 protected InternalChannelListenerBase (IDefaultCommunicationTimeouts timeouts)
44                         : base (timeouts)
45                 {
46                 }
47
48                 Func<TimeSpan,TChannel> accept_channel_delegate;
49                 Func<TimeSpan,bool> wait_delegate;
50                 Action<TimeSpan> open_delegate, close_delegate;
51
52                 protected Thread CurrentAsyncThread { get; private set; }
53                 protected IAsyncResult CurrentAsyncResult { get; private set; }
54
55                 protected override void OnAbort ()
56                 {
57                         if (CurrentAsyncThread != null)
58                                 CurrentAsyncThread.Abort (); // it is not beautiful but there is no other way to stop it.
59                 }
60
61                 protected override void OnClose (TimeSpan timeout)
62                 {
63                         if (CurrentAsyncThread != null)
64                                 if (!CancelAsync (timeout))
65                                         if (CurrentAsyncThread != null) // being careful
66                                                 CurrentAsyncThread.Abort (); // it is not beautiful but there is no other way to stop it.
67                 }
68
69                 // cancel ongoing async operations and return if it was 
70                 // completed successfully. If not, it will abort.
71                 public virtual bool CancelAsync (TimeSpan timeout)
72                 {
73                         return CurrentAsyncResult == null || CurrentAsyncResult.AsyncWaitHandle.WaitOne (timeout);
74                 }
75
76                 protected override IAsyncResult OnBeginAcceptChannel (
77                         TimeSpan timeout, AsyncCallback callback,
78                         object asyncState)
79                 {
80                         //if (CurrentAsyncResult != null)
81                         //      throw new InvalidOperationException ("Another AcceptChannel operation is in progress");
82
83                         ManualResetEvent wait = new ManualResetEvent (false);
84
85                         if (accept_channel_delegate == null)
86                                 accept_channel_delegate = new Func<TimeSpan,TChannel> (delegate (TimeSpan tout) {
87                                         wait.WaitOne (); // make sure that CurrentAsyncResult is set.
88                                         CurrentAsyncThread = Thread.CurrentThread;
89
90                                         try {
91                                                 return OnAcceptChannel (tout);
92                                         } finally {
93                                                 CurrentAsyncThread = null;
94                                                 CurrentAsyncResult = null;
95                                         }
96                                 });
97
98                         CurrentAsyncResult = accept_channel_delegate.BeginInvoke (timeout, callback, asyncState);
99                         wait.Set ();
100                         return CurrentAsyncResult;
101                 }
102
103                 protected override TChannel OnEndAcceptChannel (IAsyncResult result)
104                 {
105                         if (accept_channel_delegate == null)
106                                 throw new InvalidOperationException ("Async AcceptChannel operation has not started");
107                         // FIXME: what's wrong with this?
108                         //if (CurrentAsyncResult == null)
109                         //      throw new InvalidOperationException ("Async AcceptChannel operation has not started. Argument result was: " + result);
110                         return accept_channel_delegate.EndInvoke (result);
111                 }
112
113                 protected override IAsyncResult OnBeginWaitForChannel (
114                         TimeSpan timeout, AsyncCallback callback, object state)
115                 {
116                         if (wait_delegate == null)
117                                 wait_delegate = new Func<TimeSpan,bool> (OnWaitForChannel);
118                         return wait_delegate.BeginInvoke (timeout, callback, state);
119                 }
120
121                 protected override bool OnEndWaitForChannel (IAsyncResult result)
122                 {
123                         if (wait_delegate == null)
124                                 throw new InvalidOperationException ("Async WaitForChannel operation has not started");
125                         return wait_delegate.EndInvoke (result);
126                 }
127
128                 protected override IAsyncResult OnBeginOpen (TimeSpan timeout,
129                         AsyncCallback callback, object state)
130                 {
131                         if (open_delegate == null)
132                                 open_delegate = new Action<TimeSpan> (OnOpen);
133                         return open_delegate.BeginInvoke (timeout, callback, state);
134                 }
135
136                 protected override void OnEndOpen (IAsyncResult result)
137                 {
138                         if (open_delegate == null)
139                                 throw new InvalidOperationException ("Async Open operation has not started");
140                         open_delegate.EndInvoke (result);
141                 }
142
143                 protected override IAsyncResult OnBeginClose (TimeSpan timeout,
144                         AsyncCallback callback, object state)
145                 {
146                         if (close_delegate == null)
147                                 close_delegate = new Action<TimeSpan> (OnClose);
148                         return close_delegate.BeginInvoke (timeout, callback, state);
149                 }
150
151                 protected override void OnEndClose (IAsyncResult result)
152                 {
153                         if (close_delegate == null)
154                                 throw new InvalidOperationException ("Async Close operation has not started");
155                         close_delegate.EndInvoke (result);
156                 }
157         }
158
159         public abstract class ChannelListenerBase<TChannel>
160                 : ChannelListenerBase, IChannelListener<TChannel>, 
161                 IChannelListener,  ICommunicationObject
162                 where TChannel : class, IChannel
163         {
164                 IDefaultCommunicationTimeouts timeouts;
165
166                 protected ChannelListenerBase ()
167                         : this (DefaultCommunicationTimeouts.Instance)
168                 {
169                 }
170
171                 protected ChannelListenerBase (
172                         IDefaultCommunicationTimeouts timeouts)
173                 {
174                         if (timeouts == null)
175                                 throw new ArgumentNullException ("timeouts");
176                         this.timeouts = timeouts;
177                 }
178
179                 public TChannel AcceptChannel ()
180                 {
181                         return AcceptChannel (timeouts.ReceiveTimeout);
182                 }
183
184                 public TChannel AcceptChannel (TimeSpan timeout)
185                 {
186                         ThrowIfDisposedOrNotOpen ();
187                         return OnAcceptChannel (timeout);
188                 }
189
190                 public IAsyncResult BeginAcceptChannel (
191                         AsyncCallback callback, object asyncState)
192                 {
193                         return BeginAcceptChannel (
194                                 timeouts.ReceiveTimeout, callback, asyncState);
195                 }
196
197                 public IAsyncResult BeginAcceptChannel (TimeSpan timeout,
198                         AsyncCallback callback, object asyncState)
199                 {
200                         return OnBeginAcceptChannel (timeout, callback, asyncState);
201                 }
202
203                 public TChannel EndAcceptChannel (IAsyncResult result)
204                 {
205                         return OnEndAcceptChannel (result);
206                 }
207
208                 protected abstract TChannel OnAcceptChannel (TimeSpan timeout);
209
210                 protected abstract IAsyncResult OnBeginAcceptChannel (TimeSpan timeout,
211                         AsyncCallback callback, object asyncState);
212
213                 protected abstract TChannel OnEndAcceptChannel (IAsyncResult result);
214         }
215 }