1 //
2 // ServiceRuntimeChannel.cs
3 //
4 // Author:
5 //	Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2007 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using System.ServiceModel.Channels;
32 using System.ServiceModel.Description;
33 using System.ServiceModel.Dispatcher;
34 using System.ServiceModel.MonoInternal;
35 
36 namespace System.ServiceModel.MonoInternal
37 {
38 #if DISABLE_REAL_PROXY
39 	// FIXME: this is a (similar) workaround for bug 571907.
40 	public
41 #endif
42 	class DuplexServiceRuntimeChannel : ServiceRuntimeChannel, IDuplexContextChannel, IInternalContextChannel
43 	{
DuplexServiceRuntimeChannel(IChannel channel, DispatchRuntime runtime)44 		public DuplexServiceRuntimeChannel (IChannel channel, DispatchRuntime runtime)
45 			: base (channel, runtime)
46 		{
47 			if (channel == null)
48 				throw new ArgumentNullException ("channel");
49 			// setup callback ClientRuntimeChannel.
50 			var crt = runtime.CallbackClientRuntime;
51 			if (crt == null)
52 				throw new InvalidOperationException ("The DispatchRuntime does not have CallbackClientRuntime");
53 			contract = ContractDescriptionGenerator.GetCallbackContract (runtime.Type, crt.CallbackClientType);
54 			client = new ClientRuntimeChannel (crt, contract, this.DefaultOpenTimeout, this.DefaultCloseTimeout, channel, null,
55 							   runtime.ChannelDispatcher.MessageVersion, this.RemoteAddress, null);
56 		}
57 
58 		ClientRuntimeChannel client;
59 		ContractDescription contract;
60 
61 		public override bool AllowOutputBatching {
62 			get { return client.AllowOutputBatching; }
63 			set { client.AllowOutputBatching = value; }
64 		}
65 
66 		public override TimeSpan OperationTimeout {
67 			get { return client.OperationTimeout; }
68 			set { client.OperationTimeout = value; }
69 		}
70 
71 		public bool AutomaticInputSessionShutdown {
72 			get { throw new NotImplementedException (); }
73 			set { throw new NotImplementedException (); }
74 		}
75 
76 		public InstanceContext CallbackInstance { get; set; }
77 
78 		public ContractDescription Contract {
79 			get { return contract; }
80 		}
81 
82 		public OperationContext Context {
83 			set {  }
84 		}
85 
86 		Action<TimeSpan> session_shutdown_delegate;
87 
CloseOutputSession(TimeSpan timeout)88 		public void CloseOutputSession (TimeSpan timeout)
89 		{
90 			throw new NotImplementedException ();
91 		}
92 
BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state)93 		public IAsyncResult BeginCloseOutputSession (TimeSpan timeout, AsyncCallback callback, object state)
94 		{
95 			if (session_shutdown_delegate == null)
96 				session_shutdown_delegate = new Action<TimeSpan> (CloseOutputSession);
97 			return session_shutdown_delegate.BeginInvoke (timeout, callback, state);
98 		}
99 
EndCloseOutputSession(IAsyncResult result)100 		public void EndCloseOutputSession (IAsyncResult result)
101 		{
102 			session_shutdown_delegate.EndInvoke (result);
103 		}
104 
105 		// proxy base implementation.
106 
BeginProcess(MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)107 		public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)
108 		{
109 			return client.BeginProcess (method, operationName, parameters, callback, asyncState);
110 		}
111 
EndProcess(MethodBase method, string operationName, object [] parameters, IAsyncResult result)112 		public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result)
113 		{
114 			return client.EndProcess (method, operationName, parameters, result);
115 		}
116 
Process(MethodBase method, string operationName, object [] parameters, OperationContext context)117 		public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context)
118 		{
119 			return client.Process (method, operationName, parameters, context);
120 		}
121 	}
122 
123 	// Its lifetime is per-session.
124 	// InputOrReplyRequestProcessor's lifetime is per-call.
125 #if DISABLE_REAL_PROXY
126 	// FIXME: this is a (similar) workaround for bug 571907.
127 	public
128 #endif
129 	class ServiceRuntimeChannel : CommunicationObject, IServiceChannel, IDisposable
130 	{
131 		IExtensionCollection<IContextChannel> extensions;
132 		readonly IChannel channel;
133 		readonly DispatchRuntime runtime;
134 
ServiceRuntimeChannel(IChannel channel, DispatchRuntime runtime)135 		public ServiceRuntimeChannel (IChannel channel, DispatchRuntime runtime)
136 		{
137 			this.channel = channel;
138 			this.runtime = runtime;
139 		}
140 
OnChannelClose(object o, EventArgs e)141 		void OnChannelClose (object o, EventArgs e)
142 		{
143 			Close ();
144 		}
145 
146 		#region IContextChannel
147 
148 		[MonoTODO]
149 		public virtual bool AllowOutputBatching { get; set; }
150 
151 		public IInputSession InputSession {
152 			get {
153 				var ch = channel as ISessionChannel<IInputSession>;
154 				if (ch != null)
155 					return ch.Session;
156 				var dch = channel as ISessionChannel<IDuplexSession>;
157 				return dch != null ? dch.Session : null;
158 			}
159 		}
160 
161 		public EndpointAddress LocalAddress {
162 			get {
163 				if (channel is IReplyChannel)
164 					return ((IReplyChannel) channel).LocalAddress;
165 				if (channel is IInputChannel)
166 					return ((IInputChannel) channel).LocalAddress;
167 				return null;
168 			}
169 		}
170 
171 		[MonoTODO]
172 		public virtual TimeSpan OperationTimeout { get; set; }
173 
174 		public IOutputSession OutputSession {
175 			get {
176 				var dch = channel as ISessionChannel<IDuplexSession>;
177 				return dch != null ? dch.Session : null;
178 			}
179 		}
180 
181 		public EndpointAddress RemoteAddress {
182 			get {
183 				if (channel is IDuplexChannel)
184 					return ((IDuplexChannel) channel).RemoteAddress;
185 				return null;
186 			}
187 		}
188 
189 		public string SessionId {
190 			get { return InputSession != null ? InputSession.Id : null; }
191 		}
192 
193 		#endregion
194 
195 		// CommunicationObject
196 		protected internal override TimeSpan DefaultOpenTimeout {
197 			get { return runtime.ChannelDispatcher.DefaultOpenTimeout; }
198 		}
199 
200 		protected internal override TimeSpan DefaultCloseTimeout {
201 			get { return runtime.ChannelDispatcher.DefaultCloseTimeout; }
202 		}
203 
OnAbort()204 		protected override void OnAbort ()
205 		{
206 			channel.Abort ();
207 		}
208 
209 		Action<TimeSpan> close_delegate;
210 
OnBeginClose( TimeSpan timeout, AsyncCallback callback, object state)211 		protected override IAsyncResult OnBeginClose (
212 			TimeSpan timeout, AsyncCallback callback, object state)
213 		{
214 			if (close_delegate == null)
215 				close_delegate = new Action<TimeSpan> (OnClose);
216 			return close_delegate.BeginInvoke (timeout, callback, state);
217 		}
218 
OnEndClose(IAsyncResult result)219 		protected override void OnEndClose (IAsyncResult result)
220 		{
221 			close_delegate.EndInvoke (result);
222 		}
223 
OnClose(TimeSpan timeout)224 		protected override void OnClose (TimeSpan timeout)
225 		{
226 			channel.Closing -= OnChannelClose;
227 		}
228 
OnBeginOpen( TimeSpan timeout, AsyncCallback callback, object state)229 		protected override IAsyncResult OnBeginOpen (
230 			TimeSpan timeout, AsyncCallback callback, object state)
231 		{
232 			return channel.BeginOpen (timeout, callback, state);
233 		}
234 
OnEndOpen(IAsyncResult result)235 		protected override void OnEndOpen (IAsyncResult result)
236 		{
237 			channel.EndOpen (result);
238 		}
239 
OnOpen(TimeSpan timeout)240 		protected override void OnOpen (TimeSpan timeout)
241 		{
242 			if (channel.State == CommunicationState.Created)
243 				channel.Open (timeout);
244 		}
245 
246 		// IChannel
247 		public T GetProperty<T> () where T : class
248 		{
249 			return channel.GetProperty<T> ();
250 		}
251 
252 		// IExtensibleObject<IContextChannel>
253 		public IExtensionCollection<IContextChannel> Extensions {
254 			get {
255 				if (extensions == null)
256 					extensions = new ExtensionCollection<IContextChannel> (this);
257 				return extensions;
258 			}
259 		}
260 
261 		public Uri ListenUri {
262 			get { return runtime.ChannelDispatcher.Listener.Uri; }
263 		}
264 
265 		#region IDisposable Members
266 
Dispose()267 		public void Dispose ()
268 		{
269 			Close ();
270 		}
271 
272 		#endregion
273 	}
274 }
275