13
|
1 ???using System; |
|
2 using System.Collections.Generic; |
|
3 using System.IO; |
|
4 using System.Reflection; |
|
5 using System.Reflection.Emit; |
|
6 using System.Runtime.Remoting; |
|
7 using System.Runtime.Remoting.Messaging; |
|
8 using System.Runtime.Remoting.Proxies; |
|
9 using System.Runtime.Serialization; |
|
10 using System.Threading; |
|
11 using UCIS.Util; |
|
12 using SysThreadPool = System.Threading.ThreadPool; |
|
13 |
|
14 //[assembly: InternalsVisibleToAttribute("UCIS.Remoting.Proxies")] |
|
15 |
|
16 namespace UCIS.Remoting { |
|
17 public class RemotingManager { |
|
18 Dictionary<UInt32, PendingRemoteCall> pendingCalls = new Dictionary<uint, PendingRemoteCall>(); |
|
19 Dictionary<Thread, UInt32> waitingCallThreads = new Dictionary<Thread, UInt32>(); |
|
20 Boolean Closed = false; |
|
21 |
|
22 IDictionary<String, Object> incomingCallContext = new Dictionary<String, Object>(); |
|
23 [ThreadStatic] |
|
24 static IDictionary<String, Object> currentCallContext; |
|
25 |
|
26 public event Action<String> OnDebugLog; |
|
27 public event Action<Exception> OnErrorLog; |
|
28 |
|
29 private void DebugLog(String text, params Object[] args) { |
|
30 if (OnDebugLog != null) OnDebugLog(String.Format(text, args)); |
|
31 } |
|
32 private void ErrorLog(Exception ex) { |
|
33 if (OnErrorLog != null) OnErrorLog(ex); |
|
34 } |
|
35 |
|
36 public Object LocalRoot { get; set; } |
|
37 |
|
38 public IDictionary<String, Object> CallContext { get { return incomingCallContext; } } |
|
39 public static IDictionary<String, Object> CurrentCallContext { get { return currentCallContext; } } |
|
40 |
|
41 public RemotingManager(PacketStream stream) : this(stream, null) { } |
|
42 public RemotingManager(PacketStream stream, Object localRoot) { |
|
43 this.stream = stream; |
|
44 this.LocalRoot = localRoot; |
|
45 stream.BeginReadPacketFast(ReceiveCallback, null); |
|
46 } |
|
47 |
|
48 #region I/O, multiplexing, encoding |
|
49 PacketStream stream; |
|
50 public PacketStream Stream { get { return stream; } } |
|
51 int streamIndex = 0; |
|
52 Dictionary<int, StreamChannel> streamChannels = new Dictionary<int, StreamChannel>(); |
|
53 |
|
54 class StreamChannel : QueuedPacketStream { |
|
55 public RemotingManager Manager { get; private set; } |
|
56 public int StreamID { get; private set; } |
|
57 public StreamChannel OtherSide { get; set; } |
|
58 |
|
59 public StreamChannel(RemotingManager conn, int sid) { |
|
60 this.Manager = conn; |
|
61 this.StreamID = sid; |
|
62 } |
|
63 |
|
64 internal void AddBuffer(Byte[] buffer, int offset, int count) { |
|
65 if (Closed) return; |
|
66 base.AddReadBufferCopy(buffer, offset, count); |
|
67 } |
|
68 |
|
69 public override bool CanRead { get { return !Closed; } } |
|
70 public override bool CanWrite { get { return !Closed; } } |
|
71 |
|
72 public override void Flush() { } |
|
73 |
|
74 public override void Write(byte[] buffer, int offset, int count) { |
|
75 if (Closed) throw new ObjectDisposedException("BaseStream", "The connection has been closed"); |
|
76 Manager.WriteStreamChannelPacket(StreamID ^ 0x4000, buffer, offset, count); |
|
77 } |
|
78 |
|
79 public override void Close() { |
|
80 StreamChannel other = OtherSide; |
|
81 MultiplexorClosed(); |
|
82 if (other != null) other.CloseInternal(); |
|
83 lock (Manager.streamChannels) Manager.streamChannels.Remove(StreamID); |
|
84 } |
|
85 public void CloseInternal() { |
|
86 MultiplexorClosed(); |
|
87 lock (Manager.streamChannels) Manager.streamChannels.Remove(StreamID); |
|
88 } |
|
89 internal void MultiplexorClosed() { |
|
90 base.Close(); |
|
91 OtherSide = null; |
|
92 } |
|
93 } |
|
94 |
|
95 private void ReceiveCallback(IAsyncResult ar) { |
|
96 if (ar.CompletedSynchronously) { |
|
97 SysThreadPool.QueueUserWorkItem(ReceiveCallbackA, ar); |
|
98 } else { |
|
99 ReceiveCallbackB(ar); |
|
100 } |
|
101 } |
|
102 private void ReceiveCallbackA(Object state) { |
|
103 ReceiveCallbackB((IAsyncResult)state); |
|
104 } |
|
105 private void ReceiveCallbackB(IAsyncResult ar) { |
|
106 try { |
|
107 ArraySegment<Byte> packet = stream.EndReadPacketFast(ar); |
|
108 Byte[] array = packet.Array; |
|
109 if (packet.Count < 2) throw new ArgumentOutOfRangeException("packet.Count", "Packet is too small"); |
|
110 int offset = packet.Offset; |
|
111 int sid = (array[offset + 0] << 8) | (array[offset + 1] << 0); |
|
112 if ((sid & 0x8000) != 0) { |
|
113 StreamChannel substr; |
|
114 if (streamChannels.TryGetValue(sid, out substr)) substr.AddBuffer(array, offset + 2, packet.Count - 2); |
|
115 } |
|
116 stream.BeginReadPacketFast(ReceiveCallback, null); |
|
117 if (sid == 0) { |
|
118 Object obj; |
|
119 using (MemoryStream ms = new MemoryStream(packet.Array, packet.Offset + 2, packet.Count - 2, false)) obj = Deserialize(ms); |
|
120 ReceiveObject(obj); |
|
121 } |
|
122 } catch (Exception ex) { |
|
123 Closed = true; |
|
124 stream.Close(); |
|
125 lock (ObjectReferencesByID) { |
|
126 ObjectReferencesByID.Clear(); |
|
127 RemoteObjectReferences.Clear(); |
|
128 } |
|
129 lock (pendingCalls) { |
|
130 foreach (PendingRemoteCall call in pendingCalls.Values) call.SetError(new InvalidOperationException("The connection has been closed")); |
|
131 pendingCalls.Clear(); |
|
132 } |
|
133 lock (streamChannels) { |
|
134 foreach (StreamChannel s in streamChannels.Values) s.MultiplexorClosed(); |
|
135 streamChannels.Clear(); |
|
136 } |
|
137 ErrorLog(ex); |
|
138 } |
|
139 } |
|
140 private void SendObject(Object obj) { |
|
141 if (Closed) throw new ObjectDisposedException("RemotingManager", "The connection has been closed"); |
|
142 using (MemoryStream ms = new MemoryStream()) { |
|
143 ms.WriteByte(0); |
|
144 ms.WriteByte(0); |
|
145 Serialize(ms, obj); |
|
146 lock (stream) ms.WriteTo(stream); |
|
147 } |
|
148 } |
|
149 |
|
150 private void WriteStreamChannelPacket(int sid, Byte[] buffer, int offset, int count) { |
|
151 Byte[] store = new Byte[count + 2]; |
|
152 store[0] = (Byte)(sid >> 8); |
|
153 store[1] = (Byte)(sid >> 0); |
|
154 Buffer.BlockCopy(buffer, offset, store, 2, count); |
|
155 lock (stream) stream.Write(store, 0, store.Length); |
|
156 } |
|
157 |
|
158 public PacketStream GetStreamPair(out PacketStream remote) { |
|
159 StreamChannel stream; |
|
160 int sid; |
|
161 lock (streamChannels) { |
|
162 if (Closed) throw new ObjectDisposedException("BaseStream", "Reading from the base stream failed"); |
|
163 while (true) { |
|
164 sid = Interlocked.Increment(ref streamIndex); |
|
165 if ((sid & 0xc000) != 0) streamIndex = sid = 0; |
|
166 sid |= 0x8000; |
|
167 if (!streamChannels.ContainsKey(sid)) break; |
|
168 } |
|
169 stream = new StreamChannel(this, sid); |
|
170 streamChannels.Add(sid, stream); |
|
171 } |
|
172 stream.OtherSide = (StreamChannel)SyncCall(new CreateStreamRequest() { StreamObject = stream, StreamID = sid | 0x4000 }); |
|
173 remote = stream.OtherSide; |
|
174 return stream; |
|
175 } |
|
176 #endregion |
|
177 |
|
178 #region Incoming call processing |
|
179 private void ReceiveObject(Object obj) { |
|
180 if (obj is ReferenceReleaseRequest) { |
|
181 ReferenceReleaseRequest req = (ReferenceReleaseRequest)obj; |
|
182 lock (ObjectReferencesByID) { |
|
183 RemoteObjectReference objref = (RemoteObjectReference)ObjectReferencesByID[req.ObjectID]; |
|
184 if (objref.Release(req.ReferenceCount) == 0) { |
|
185 ObjectReferencesByID.Remove(objref.ID); |
|
186 RemoteObjectReferences.Remove(objref); |
|
187 DebugLog("Release remoted object {0} with reference count {1}; {2} objects referenced", objref.ID, req.ReferenceCount, RemoteObjectReferences.Count); |
|
188 } |
|
189 } |
|
190 } else if (obj is SynchronousCall) { |
|
191 SynchronousCall sc = (SynchronousCall)obj; |
|
192 if (sc.IsResult) { |
|
193 PendingRemoteCall call; |
|
194 lock (pendingCalls) { |
|
195 call = pendingCalls[sc.CallID]; |
|
196 pendingCalls.Remove(call.ID); |
|
197 } |
|
198 call.SetResult(sc.Data); |
|
199 } else if (sc.HasPreviousCallID) { |
|
200 PendingRemoteCall call; |
|
201 lock (pendingCalls) call = pendingCalls[sc.PreviousCallID]; |
|
202 if (!call.SetNextCall(sc)) { |
|
203 ProcessRemoteCallRequest(sc); |
|
204 } |
|
205 } else { |
|
206 ProcessRemoteCallRequest(sc); |
|
207 } |
|
208 } else { |
|
209 throw new InvalidDataException("Unexpected object type"); |
|
210 } |
|
211 } |
|
212 |
|
213 private void ProcessRemoteCallRequest(SynchronousCall call) { |
|
214 UInt32 prevcallid; |
|
215 Boolean hasprevcallid; |
|
216 Thread currentThread = Thread.CurrentThread; |
|
217 lock (waitingCallThreads) { |
|
218 hasprevcallid = waitingCallThreads.TryGetValue(currentThread, out prevcallid); |
|
219 waitingCallThreads[currentThread] = call.CallID; |
|
220 } |
|
221 IDictionary<String, Object> prevCallContext = currentCallContext; |
|
222 currentCallContext = incomingCallContext; |
|
223 try { |
|
224 call.Data = ProcessRemoteCallRequestA(call.Data); |
|
225 } finally { |
|
226 currentCallContext = prevCallContext; |
|
227 lock (waitingCallThreads) { |
|
228 if (hasprevcallid) waitingCallThreads[currentThread] = prevcallid; |
|
229 else waitingCallThreads.Remove(currentThread); |
|
230 } |
|
231 } |
|
232 call.IsResult = true; |
|
233 SendObject(call); |
|
234 } |
|
235 |
|
236 private Object FixReturnType(Object value, Type expectedType) { |
|
237 if (value == null) return value; |
|
238 Type valueType = value.GetType(); |
|
239 if (valueType != expectedType) { |
|
240 if (valueType.IsArray) { |
|
241 Array retarray = value as Array; |
|
242 if (retarray != null) { |
|
243 if (!valueType.GetElementType().IsPublic && retarray.Rank == 1 && |
|
244 ( |
|
245 expectedType.IsArray || |
|
246 (expectedType.IsGenericType && (expectedType.GetGenericTypeDefinition() == typeof(IEnumerable<>) || expectedType.GetGenericTypeDefinition() == typeof(ICollection<>) || expectedType.GetGenericTypeDefinition() == typeof(IList<>))) |
|
247 ) |
|
248 ) { |
|
249 Type btype = expectedType.IsArray ? expectedType.GetElementType() : expectedType.GetGenericArguments()[0]; |
|
250 Array r = Array.CreateInstance(btype, retarray.Length); |
|
251 retarray.CopyTo(r, 0); |
|
252 value = r; |
|
253 } |
|
254 } |
|
255 } |
|
256 } |
|
257 return value; |
|
258 } |
|
259 private Object ProcessRemoteMethodCallRequestA(Object ret) { |
|
260 if (ret is DelegateCallRequest) { |
|
261 DelegateCallRequest call = (DelegateCallRequest)ret; |
|
262 Object target = call.Delegate; |
|
263 DebugLog("Remote delegate call on {0}", target); |
|
264 if (ReferenceEquals(target, null)) throw new NullReferenceException("target"); |
|
265 if (!(target is Delegate)) throw new InvalidCastException("target"); |
|
266 Object[] args = call.Arguments; |
|
267 return ((Delegate)target).DynamicInvoke(args); |
|
268 } else if (ret is MethodCallRequest) { |
|
269 MethodCallRequest call = (MethodCallRequest)ret; |
|
270 Object target = call.Object; |
|
271 if (ReferenceEquals(target, null)) throw new NullReferenceException("target"); |
|
272 Type intf = call.Type ?? target.GetType(); |
|
273 DebugLog("Remote call {0}.{1} on {2}", intf.FullName, call.MethodName, target); |
|
274 if (!intf.IsInstanceOfType(target)) throw new InvalidCastException("target"); |
|
275 MethodInfo meth; |
|
276 if (call.MethodSignature != null) { |
|
277 meth = intf.GetMethod(call.MethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, call.MethodSignature, null); |
|
278 } else { |
|
279 meth = intf.GetMethod(call.MethodName, BindingFlags.Instance | BindingFlags.Public); |
|
280 } |
|
281 if (meth == null) throw new NullReferenceException("method"); |
|
282 Object[] args = call.Arguments; |
|
283 Object retval; |
|
284 if (meth.Name == "GetType" && meth == typeof(Object).GetMethod("GetType", Type.EmptyTypes)) { |
|
285 if (target.GetType().IsPublic) retval = target.GetType(); |
|
286 else retval = intf; |
|
287 } else { |
|
288 retval = meth.Invoke(target, args); |
|
289 } |
|
290 //Todo: causes lots of redundant data transfers, do something about it! |
|
291 /*Object[] rargs = new Object[0]; |
|
292 for (int i = 0; i < args.Length; i++) { |
|
293 if (args[i] == null) continue; |
|
294 if (args[i].GetType().IsArray) { |
|
295 Array.Resize(ref rargs, i + 1); |
|
296 rargs[i] = args[i]; |
|
297 } |
|
298 } |
|
299 resp.ReturnArguments = rargs;*/ |
|
300 return FixReturnType(retval, meth.ReturnType); |
|
301 } else if (ret is PropertyAccessRequest) { |
|
302 PropertyAccessRequest call = (PropertyAccessRequest)ret; |
|
303 Object target = call.Object; |
|
304 if (ReferenceEquals(target, null)) throw new NullReferenceException("target"); |
|
305 Type intf = call.Type ?? target.GetType(); |
|
306 DebugLog("Remote property access {0}.{1} on {2}", intf.FullName, call.PropertyName, target); |
|
307 if (!intf.IsInstanceOfType(target)) throw new InvalidCastException("target"); |
|
308 PropertyInfo meth = intf.GetProperty(call.PropertyName, BindingFlags.Instance | BindingFlags.Public); |
|
309 if (meth == null) throw new NullReferenceException("property"); |
|
310 if (call.SetValue) { |
|
311 meth.SetValue(target, call.Value, null); |
|
312 return null; |
|
313 } else { |
|
314 return FixReturnType(meth.GetValue(target, null), meth.PropertyType); |
|
315 } |
|
316 } else { |
|
317 throw new InvalidDataException("Unexpected object type"); |
|
318 } |
|
319 } |
|
320 private Object ProcessRemoteCallRequestA(Object ret) { |
|
321 if (ret is DelegateCallRequest || ret is MethodCallRequest || ret is PropertyAccessRequest) { |
|
322 MethodCallResponse resp = new MethodCallResponse(); |
|
323 try { |
|
324 resp.ReturnValue = ProcessRemoteMethodCallRequestA(ret); |
|
325 } catch (Exception ex) { |
|
326 resp.Exception = ex; |
|
327 ErrorLog(ex); |
|
328 } |
|
329 return resp; |
|
330 } else if (ret is GetRootRequest) { |
|
331 DebugLog("Remote root request"); |
|
332 return LocalRoot; |
|
333 } else if (ret is ObjectCanCastToRequest) { |
|
334 ObjectCanCastToRequest ctr = (ObjectCanCastToRequest)ret; |
|
335 Type intf = ctr.Type; |
|
336 Object target = ctr.Object; |
|
337 DebugLog("Remote type check for {0} on {1}", intf.Name, target); |
|
338 return intf != null && intf.IsInstanceOfType(target); |
|
339 } else if (ret is CreateStreamRequest) { |
|
340 CreateStreamRequest csr = (CreateStreamRequest)ret; |
|
341 StreamChannel ss = new StreamChannel(this, csr.StreamID); |
|
342 ss.OtherSide = csr.StreamObject; |
|
343 lock (streamChannels) streamChannels.Add(csr.StreamID, ss); |
|
344 return ss; |
|
345 } else { |
|
346 throw new InvalidDataException("Unexpected object type"); |
|
347 } |
|
348 } |
|
349 #endregion |
|
350 |
|
351 #region Outgoing calls |
|
352 UInt32 callID = 0; |
|
353 private UInt32 AllocatePendingCallID(PendingRemoteCall call) { |
|
354 UInt32 cid; |
|
355 lock (pendingCalls) { |
|
356 while (true) { |
|
357 cid = ++callID; |
|
358 if (!pendingCalls.ContainsKey(cid)) break; |
|
359 Monitor.Wait(pendingCalls); |
|
360 } |
|
361 call.ID = cid; |
|
362 pendingCalls.Add(cid, call); |
|
363 } |
|
364 return cid; |
|
365 } |
|
366 private Object SyncCall(Object req) { |
|
367 UInt32 previousCall; |
|
368 Boolean hasPreviousCall; |
|
369 lock (waitingCallThreads) hasPreviousCall = waitingCallThreads.TryGetValue(Thread.CurrentThread, out previousCall); |
|
370 PendingRemoteCall pending = new PendingRemoteCall() { Completed = false, WaitHandle = new ManualResetEvent(false), CallData = req }; |
|
371 AllocatePendingCallID(pending); |
|
372 SynchronousCall call = new SynchronousCall() { IsResult = false, CallID = pending.ID, Data = req, HasPreviousCallID = false }; |
|
373 if (hasPreviousCall) { |
|
374 call.HasPreviousCallID = true; |
|
375 call.PreviousCallID = previousCall; |
|
376 } |
|
377 SendObject(call); |
|
378 while (true) { |
|
379 pending.WaitHandle.WaitOne(); |
|
380 if (pending.Completed) break; |
|
381 pending.WaitHandle.Reset(); |
|
382 if (pending.NextCall == null) throw new InvalidOperationException("Operation did not complete"); |
|
383 SynchronousCall sc = pending.NextCall.Value; |
|
384 pending.NextCall = null; |
|
385 ProcessRemoteCallRequest(sc); |
|
386 } |
|
387 pending.WaitHandle.Close(); |
|
388 if (pending.Error != null) throw pending.Error; |
|
389 return pending.Response; |
|
390 } |
|
391 private void AsyncCall(Object req) { |
|
392 UInt32 cid = AllocatePendingCallID(new PendingRemoteCall() { Completed = false, CallData = req }); |
|
393 SendObject(new SynchronousCall() { IsResult = false, CallID = cid, Data = req, HasPreviousCallID = false }); |
|
394 } |
|
395 |
|
396 public Object RemoteRoot { |
|
397 get { |
|
398 return SyncCall(new GetRootRequest()); |
|
399 } |
|
400 } |
|
401 |
|
402 public static void AsyncCall(Delegate f, params Object[] args) { |
|
403 IProxyBase proxy; |
|
404 if ((proxy = GetRealProxyForObject(f)) != null) { |
|
405 proxy.Manager.AsyncCall(new DelegateCallRequest() { Delegate = proxy, Arguments = args }); |
|
406 } else if ((proxy = GetRealProxyForObject(f.Target)) != null) { |
|
407 MethodCallRequest call = new MethodCallRequest() { Object = proxy, Type = f.Method.DeclaringType, MethodName = f.Method.Name, Arguments = args }; |
|
408 call.MethodSignature = ConvertMethodParameterTypeArray(f.Method); |
|
409 proxy.Manager.AsyncCall(call); |
|
410 } else { |
|
411 throw new InvalidOperationException("Delegate is not a proxy for a remote object"); |
|
412 } |
|
413 } |
|
414 |
|
415 private static Type[] ConvertMethodParameterTypeArray(MethodInfo method) { |
|
416 ParameterInfo[] parameters = method.GetParameters(); |
|
417 Type[] types = new Type[parameters.Length]; |
|
418 for (int i = 0; i < types.Length; i++) types[i] = parameters[i].ParameterType; |
|
419 return types; |
|
420 } |
|
421 private void ProxyCallCheckReturnType(Object value, Type type) { |
|
422 if (type == typeof(void)) return; |
|
423 if (type.IsInstanceOfType(value)) return; |
|
424 if (value == null && !type.IsValueType) return; |
|
425 throw new InvalidCastException("Type returned by remote procedure does not match expected type."); |
|
426 } |
|
427 private void ProxyCallFixReturnArguments(Object[] args, Object[] rargs) { |
|
428 if (rargs == null) return; |
|
429 for (int i = 0; i < rargs.Length; i++) { |
|
430 if (rargs[i] == null) continue; |
|
431 if (args[i] != null && args[i].GetType().IsArray) { |
|
432 ((Array)rargs[i]).CopyTo((Array)args[i], 0); |
|
433 } |
|
434 } |
|
435 } |
|
436 private Object ProxyMakeCallDelegate(DelegateProxy obj, Object[] args) { |
|
437 DelegateCallRequest call = new DelegateCallRequest() { Delegate = obj, Arguments = args }; |
|
438 MethodCallResponse resp = (MethodCallResponse)SyncCall(call); |
|
439 if (resp.Exception != null) throw new Exception("Remote exception", resp.Exception); |
|
440 ProxyCallFixReturnArguments(args, resp.ReturnArguments); |
|
441 ProxyCallCheckReturnType(resp.ReturnValue, obj.MethodSignature.ReturnType); |
|
442 return resp.ReturnValue; |
|
443 } |
|
444 private Object ProxyMakeCall(IProxyBase obj, MethodInfo method, Object[] args) { |
|
445 /*if (args.Length == 1 && method.ReturnType == typeof(void) && args[0] != null && args[0] is Delegate) { |
|
446 foreach (EventInfo ei in type.GetEvents()) { |
|
447 if (ei.EventHandlerType.IsInstanceOfType(args[0])) { |
|
448 if (method == ei.GetAddMethod()) { |
|
449 Console.WriteLine("ADD EVENT"); |
|
450 } else if (method == ei.GetRemoveMethod()) { |
|
451 Console.WriteLine("REMOVE EVENT"); |
|
452 } |
|
453 } |
|
454 } |
|
455 }*/ |
|
456 MethodCallRequest call = new MethodCallRequest() { Object = obj, Type = method.DeclaringType, MethodName = method.Name, Arguments = args }; |
|
457 call.MethodSignature = ConvertMethodParameterTypeArray(method); |
|
458 MethodCallResponse resp = (MethodCallResponse)SyncCall(call); |
|
459 if (resp.Exception != null) throw new Exception("Remote exception", resp.Exception); |
|
460 ProxyCallFixReturnArguments(args, resp.ReturnArguments); |
|
461 ProxyCallCheckReturnType(resp.ReturnValue, method.ReturnType); |
|
462 return resp.ReturnValue; |
|
463 } |
|
464 private Boolean ProxyCanCastTo(IProxyBase obj, Type type) { |
|
465 return (Boolean)SyncCall(new ObjectCanCastToRequest() { Object = obj, Type = type }); |
|
466 } |
|
467 private void ProxyReleaseObject(ProxyObjectReference objref) { |
|
468 if (objref == null) return; |
|
469 ProxyReleaseObject(objref, objref.RefCnt); |
|
470 } |
|
471 private void ProxyReleaseObject(ProxyObjectReference objref, int refcnt) { |
|
472 lock (ObjectReferencesByID) { |
|
473 int newrefcnt = objref.Release(refcnt); |
|
474 IObjectReferenceBase regobjref; |
|
475 if (newrefcnt <= 0 && ObjectReferencesByID.TryGetValue(objref.ID, out regobjref) && objref == regobjref) ObjectReferencesByID.Remove(objref.ID); |
|
476 } |
|
477 try { |
|
478 if (Closed) return; |
|
479 SendObject(new ReferenceReleaseRequest() { ObjectID = objref.RemoteID, ReferenceCount = refcnt }); |
|
480 } catch (Exception) { } //Assume the exception happened because the connection is closed. Otherwise memory leak... |
|
481 } |
|
482 |
|
483 class PendingRemoteCall { |
|
484 public UInt32 ID = 0; |
|
485 public ManualResetEvent WaitHandle = null; |
|
486 public Object Response = null; |
|
487 public Exception Error = null; |
|
488 public Boolean Completed = false; |
|
489 public SynchronousCall? NextCall = null; |
|
490 public Object CallData = null; |
|
491 |
|
492 public void SetError(Exception error) { |
|
493 this.Error = error; |
|
494 Completed = true; |
|
495 if (WaitHandle != null) WaitHandle.Set(); |
|
496 } |
|
497 public void SetResult(Object result) { |
|
498 this.Response = result; |
|
499 Completed = true; |
|
500 if (WaitHandle != null) WaitHandle.Set(); |
|
501 } |
|
502 public Boolean SetNextCall(SynchronousCall nextcall) { |
|
503 if (WaitHandle == null) return false; |
|
504 this.NextCall = nextcall; |
|
505 WaitHandle.Set(); |
|
506 return true; |
|
507 } |
|
508 } |
|
509 #endregion |
|
510 |
|
511 #region Object serialization support |
|
512 private void Serialize(Stream stream, Object obj) { |
|
513 BinaryWriter writer = new BinaryWriter(stream); |
|
514 Serialize(writer, obj); |
|
515 writer.Flush(); |
|
516 } |
|
517 private void Serialize(BinaryWriter writer, Object obj) { |
|
518 if (ReferenceEquals(obj, null)) { |
|
519 writer.Write((Byte)0); |
|
520 } else if (GetRealProxyForObject(obj) != null) { |
|
521 GetObjectData(obj, writer); |
|
522 } else { |
|
523 Type type = obj.GetType(); |
|
524 if (type == typeof(Boolean)) { |
|
525 writer.Write((Byte)1); |
|
526 writer.Write((Boolean)obj); |
|
527 } else if (type == typeof(Byte)) { |
|
528 writer.Write((Byte)2); |
|
529 writer.Write((Byte)obj); |
|
530 } else if (type == typeof(Char)) { |
|
531 writer.Write((Byte)3); |
|
532 writer.Write((Int16)obj); |
|
533 } else if (type == typeof(Decimal)) { |
|
534 writer.Write((Byte)4); |
|
535 writer.Write((Decimal)obj); |
|
536 } else if (type == typeof(Double)) { |
|
537 writer.Write((Byte)5); |
|
538 writer.Write((Double)obj); |
|
539 } else if (type == typeof(Int16)) { |
|
540 writer.Write((Byte)6); |
|
541 writer.Write((Int16)obj); |
|
542 } else if (type == typeof(Int32)) { |
|
543 writer.Write((Byte)7); |
|
544 writer.Write((Int32)obj); |
|
545 } else if (type == typeof(Int64)) { |
|
546 writer.Write((Byte)8); |
|
547 writer.Write((Int64)obj); |
|
548 } else if (type == typeof(SByte)) { |
|
549 writer.Write((Byte)9); |
|
550 writer.Write((SByte)obj); |
|
551 } else if (type == typeof(Single)) { |
|
552 writer.Write((Byte)10); |
|
553 writer.Write((Single)obj); |
|
554 } else if (type == typeof(String)) { |
|
555 writer.Write((Byte)11); |
|
556 writer.Write((String)obj); |
|
557 } else if (type == typeof(UInt16)) { |
|
558 writer.Write((Byte)12); |
|
559 writer.Write((UInt16)obj); |
|
560 } else if (type == typeof(UInt32)) { |
|
561 writer.Write((Byte)13); |
|
562 writer.Write((UInt32)obj); |
|
563 } else if (type == typeof(UInt64)) { |
|
564 writer.Write((Byte)14); |
|
565 writer.Write((UInt64)obj); |
14
|
566 } else if (type == typeof(DateTime)) { |
|
567 writer.Write((Byte)32); |
|
568 writer.Write((Int64)((DateTime)obj).ToBinary()); |
13
|
569 } else if (type.IsSubclassOf(typeof(Type))) { |
|
570 writer.Write((Byte)165); |
|
571 SerializeType(writer, (Type)obj); |
|
572 } else if (type.IsArray) { |
|
573 writer.Write((Byte)164); |
|
574 Array arr = (Array)obj; |
|
575 writer.Write((int)arr.Length); |
|
576 SerializeType(writer, type.GetElementType()); |
|
577 for (int i = 0; i < arr.Length; i++) { |
|
578 Serialize(writer, arr.GetValue(i)); |
|
579 } |
|
580 } else if (type.IsPrimitive) { |
|
581 throw new NotSupportedException(); |
|
582 } else if (typeof(Delegate).IsAssignableFrom(type) || type.IsMarshalByRef) { |
|
583 GetObjectData(obj, writer); |
|
584 } else if (obj is ISerializable) { |
|
585 SerializationInfo si = new SerializationInfo(type, new FormatterConverter()); |
|
586 ((ISerializable)obj).GetObjectData(si, new StreamingContext(StreamingContextStates.All)); |
14
|
587 writer.Write((Byte)128); |
13
|
588 SerializeType(writer, Type.GetType(si.FullTypeName + "," + si.AssemblyName)); |
|
589 writer.Write((int)si.MemberCount); |
|
590 foreach (SerializationEntry se in si) { |
|
591 writer.Write(se.Name); |
|
592 Serialize(writer, se.Value); |
|
593 } |
|
594 } else if (type.IsSerializable) { |
|
595 MemberInfo[] members = FormatterServices.GetSerializableMembers(type); |
|
596 Object[] values = FormatterServices.GetObjectData(obj, members); |
|
597 writer.Write((Byte)128); |
|
598 SerializeType(writer, type); |
14
|
599 writer.Write((int)members.Length); |
13
|
600 for (int i = 0; i < members.Length; i++) { |
14
|
601 writer.Write(members[i].Name); |
13
|
602 Serialize(writer, values[i]); |
|
603 } |
|
604 } else { |
|
605 GetObjectData(obj, writer); |
|
606 } |
|
607 } |
|
608 } |
|
609 private void SerializeType(BinaryWriter writer, Type t) { |
|
610 writer.Write(t.FullName); |
|
611 writer.Write(t.Assembly.FullName); |
|
612 } |
|
613 private Object Deserialize(Stream stream) { |
|
614 BinaryReader reader = new BinaryReader(stream); |
|
615 return Deserialize(reader); |
|
616 } |
|
617 private Object Deserialize(BinaryReader reader) { |
|
618 Byte t = reader.ReadByte(); |
|
619 if (t == 0) return null; |
|
620 if (t == 1) return reader.ReadBoolean(); |
|
621 if (t == 2) return reader.ReadByte(); |
|
622 if (t == 3) return (Char)reader.ReadInt16(); |
|
623 if (t == 4) return reader.ReadDecimal(); |
|
624 if (t == 5) return reader.ReadDouble(); |
|
625 if (t == 6) return reader.ReadInt16(); |
|
626 if (t == 7) return reader.ReadInt32(); |
|
627 if (t == 8) return reader.ReadInt64(); |
|
628 if (t == 9) return reader.ReadSByte(); |
|
629 if (t == 10) return reader.ReadSingle(); |
|
630 if (t == 11) return reader.ReadString(); |
|
631 if (t == 12) return reader.ReadUInt16(); |
|
632 if (t == 13) return reader.ReadUInt32(); |
|
633 if (t == 14) return reader.ReadUInt64(); |
14
|
634 if (t == 32) return DateTime.FromBinary(reader.ReadInt64()); |
13
|
635 if (t == 128) { |
|
636 Type type = DeserializeType(reader); |
14
|
637 int cnt = reader.ReadInt32(); |
|
638 Object inst; |
|
639 StreamingContext sc = new StreamingContext(StreamingContextStates.All); |
|
640 if (typeof(ISerializable).IsAssignableFrom(type) && type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, null) != null) { |
|
641 SerializationInfo si = new SerializationInfo(type, new FormatterConverter()); |
|
642 for (int i = 0; i < cnt; i++) { |
|
643 String name = reader.ReadString(); |
|
644 Object value = Deserialize(reader); |
|
645 si.AddValue(name, value); |
|
646 } |
|
647 inst = Activator.CreateInstance(type, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Object[] { si, sc }, null); |
|
648 } else if (type.IsSerializable) { |
|
649 inst = FormatterServices.GetUninitializedObject(type); |
|
650 List<MemberInfo> members = new List<MemberInfo>(); |
|
651 List<Object> values = new List<object>(); |
|
652 for (int i = 0; i < cnt; i++) { |
13
|
653 String mname = reader.ReadString(); |
|
654 Object value = Deserialize(reader); |
|
655 MemberInfo[] mms = type.GetMember(mname, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); |
|
656 if (mms.Length != 1) throw new InvalidOperationException(); |
|
657 members.Add(mms[0]); |
|
658 values.Add(value); |
14
|
659 } |
|
660 FormatterServices.PopulateObjectMembers(inst, members.ToArray(), values.ToArray()); |
|
661 } else { |
|
662 throw new InvalidOperationException("Type " + type.Name + " is not serializable"); |
13
|
663 } |
14
|
664 IObjectReference objref = inst as IObjectReference; |
|
665 if (objref != null) inst = objref.GetRealObject(sc); |
13
|
666 return inst; |
|
667 } |
|
668 if (t == 129 || t == 130 || t == 131) { |
|
669 return SetObjectData(t, reader); |
|
670 } |
|
671 if (t == 164) { |
|
672 int len = reader.ReadInt32(); |
|
673 Type type = DeserializeType(reader); Array arr = Array.CreateInstance(type, len); |
|
674 for (int i = 0; i < len; i++) arr.SetValue(Deserialize(reader), i); |
|
675 return arr; |
|
676 } |
|
677 if (t == 165) { |
|
678 return DeserializeType(reader); |
|
679 } |
|
680 throw new NotSupportedException(); |
|
681 } |
|
682 private Type DeserializeType(BinaryReader reader) { |
|
683 String name = reader.ReadString(); |
|
684 String aname = reader.ReadString(); |
|
685 Type t = Type.GetType(name + ", " + aname, false); |
|
686 if (t != null) return t; |
|
687 foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { |
|
688 t = assembly.GetType(name, false); |
|
689 if (t != null) return t; |
|
690 } |
|
691 return t; |
|
692 } |
|
693 |
|
694 Dictionary<UInt32, IObjectReferenceBase> ObjectReferencesByID = new Dictionary<uint, IObjectReferenceBase>(); |
|
695 List<RemoteObjectReference> RemoteObjectReferences = new List<RemoteObjectReference>(); |
|
696 uint remoteReferenceIndex = 0; |
|
697 void GetObjectData(object obj, BinaryWriter w) { |
|
698 IObjectReferenceBase rref = null; |
|
699 IProxyBase proxy = GetRealProxyForObject(obj); |
|
700 if (proxy != null && proxy.Manager == this) { |
|
701 rref = proxy.ObjectReference; |
|
702 w.Write((Byte)131); |
|
703 w.Write((UInt32)rref.RemoteID); |
|
704 } else { |
|
705 Boolean isDelegate = obj is Delegate; |
|
706 lock (ObjectReferencesByID) { |
|
707 foreach (IObjectReferenceBase objref in RemoteObjectReferences) { |
|
708 Object other = objref.Target; |
|
709 if (ReferenceEquals(other, obj) || (isDelegate && Delegate.Equals(other, obj))) { |
|
710 rref = objref; |
|
711 break; |
|
712 } |
|
713 } |
|
714 if (rref == null) { |
|
715 UInt32 objid; |
|
716 lock (ObjectReferencesByID) { |
|
717 while (true) { |
|
718 remoteReferenceIndex++; |
|
719 objid = remoteReferenceIndex; |
|
720 if ((objid & 0x80000000) != 0) { |
|
721 remoteReferenceIndex = 0; |
|
722 continue; |
|
723 } |
|
724 if (!ObjectReferencesByID.ContainsKey(objid)) break; |
|
725 Monitor.Wait(ObjectReferencesByID); |
|
726 } |
|
727 } |
|
728 rref = new RemoteObjectReference(objid, obj); |
|
729 ObjectReferencesByID.Add(objid, rref); |
|
730 RemoteObjectReferences.Add((RemoteObjectReference)rref); |
|
731 } |
|
732 rref.AddRef(); |
|
733 } |
|
734 if (isDelegate) { |
|
735 w.Write((Byte)130); |
|
736 w.Write((UInt32)rref.RemoteID); |
|
737 SerializeType(w, obj.GetType()); |
|
738 } else { |
|
739 w.Write((Byte)129); |
|
740 w.Write((UInt32)rref.RemoteID); |
|
741 } |
|
742 } |
|
743 } |
|
744 object SetObjectData(Byte t, BinaryReader r) { |
|
745 UInt32 objid = r.ReadUInt32(); |
|
746 Type deltype = null; |
|
747 if (t == 130) deltype = DeserializeType(r); |
|
748 lock (ObjectReferencesByID) { |
|
749 Object target = null; |
|
750 IObjectReferenceBase rref; |
|
751 if (ObjectReferencesByID.TryGetValue(objid, out rref)) target = rref.Target; |
|
752 if (t == 131) { |
|
753 if (target == null) throw new InvalidOperationException("Object not found"); |
|
754 } else { |
|
755 if (target == null) { |
|
756 if ((objid & 0x80000000) == 0) throw new InvalidOperationException("The Object ID is invalid"); |
|
757 IProxyBase proxy; |
|
758 if (t == 130) { |
|
759 proxy = CreateDelegateProxy(objid, deltype); |
|
760 } else { |
|
761 String[] iftypes = null; //(String[])info.GetValue("InterfaceTypes", typeof(String[])); |
|
762 proxy = CreateObjectProxy(objid, iftypes); |
|
763 } |
|
764 rref = proxy.ObjectReference; |
|
765 ObjectReferencesByID[objid] = rref; |
|
766 target = proxy.GetTransparentProxy(); |
|
767 } |
|
768 rref.AddRef(); |
|
769 } |
|
770 return target; |
|
771 } |
|
772 } |
|
773 #endregion |
|
774 |
|
775 #region RPC messages |
|
776 [Serializable] |
|
777 struct SynchronousCall { |
|
778 public UInt32 CallID; |
|
779 public Boolean IsResult; |
|
780 public Object Data; |
|
781 public Boolean HasPreviousCallID; |
|
782 public UInt32 PreviousCallID; |
|
783 } |
|
784 |
|
785 [Serializable] |
|
786 struct MethodCallRequest { |
|
787 public Object Object; |
|
788 public Type Type; |
|
789 public String MethodName; |
|
790 public Type[] MethodSignature; |
|
791 public Object[] Arguments; |
|
792 } |
|
793 [Serializable] |
|
794 struct MethodCallResponse { |
|
795 public Exception Exception; |
|
796 public Object ReturnValue; |
|
797 public Object[] ReturnArguments; |
|
798 } |
|
799 [Serializable] |
|
800 struct PropertyAccessRequest { |
|
801 public Object Object; |
|
802 public Type Type; |
|
803 public String PropertyName; |
|
804 public Boolean SetValue; |
|
805 public Object Value; |
|
806 } |
|
807 [Serializable] |
|
808 struct ReferenceReleaseRequest { |
|
809 public UInt32 ObjectID; |
|
810 public Int32 ReferenceCount; |
|
811 } |
|
812 [Serializable] |
|
813 struct GetRootRequest { |
|
814 } |
|
815 [Serializable] |
|
816 struct ObjectCanCastToRequest { |
|
817 public Object Object; |
|
818 public Type Type; |
|
819 } |
|
820 [Serializable] |
|
821 struct CreateStreamRequest { |
|
822 public StreamChannel StreamObject; |
|
823 public int StreamID; |
|
824 } |
|
825 [Serializable] |
|
826 struct DelegateCallRequest { |
|
827 public Object Delegate; |
|
828 public Object[] Arguments; |
|
829 } |
|
830 #endregion |
|
831 |
|
832 #region Proxy magic |
|
833 static IProxyBase GetRealProxyForObject(Object obj) { |
|
834 if (RemotingServices.IsTransparentProxy(obj)) return RemotingServices.GetRealProxy(obj) as FWProxy; |
|
835 IProxyBase obj_IProxyBase = obj as IProxyBase; |
|
836 if (obj_IProxyBase != null) return obj_IProxyBase; |
|
837 Delegate obj_Delegate = obj as Delegate; |
|
838 if (obj_Delegate != null) { |
|
839 DelegateProxy pb = obj_Delegate.Target as DelegateProxy; |
|
840 if (pb != null) return pb; |
|
841 } |
|
842 return null; |
|
843 } |
|
844 public static RemotingManager GetManagerForObjectProxy(Object obj) { |
|
845 IProxyBase prox = GetRealProxyForObject(obj); |
|
846 if (prox == null) return null; |
|
847 return prox.Manager; |
|
848 } |
|
849 |
|
850 interface IObjectReferenceBase { |
|
851 UInt32 ID { get; } |
|
852 Object Target { get; } |
|
853 int AddRef(); |
|
854 int RefCnt { get; } |
|
855 Boolean IsLocal { get; } |
|
856 UInt32 RemoteID { get; } |
|
857 } |
|
858 |
|
859 class RemoteObjectReference : IObjectReferenceBase { |
|
860 int refcnt = 0; |
|
861 public UInt32 ID { get; private set; } |
|
862 public Object Target { get; private set; } |
|
863 public int RefCnt { get { return refcnt; } } |
|
864 public int AddRef() { return Interlocked.Increment(ref refcnt); } |
|
865 public int Release(int count) { return Interlocked.Add(ref refcnt, -count); } |
|
866 public Boolean IsLocal { get { return true; } } |
|
867 public UInt32 RemoteID { get { return ID | 0x80000000; } } |
|
868 public RemoteObjectReference(UInt32 id, Object obj) { |
|
869 if ((id & 0x80000000) != 0) throw new InvalidOperationException("The Object ID is invalid"); |
|
870 this.ID = id; |
|
871 this.Target = obj; |
|
872 } |
|
873 } |
|
874 |
|
875 interface IProxyBase { |
|
876 RemotingManager Manager { get; } |
|
877 UInt32 ID { get; } |
|
878 ProxyObjectReference ObjectReference { get; } |
|
879 Object GetTransparentProxy(); |
|
880 } |
|
881 class ProxyObjectReference : IObjectReferenceBase { |
|
882 int refcnt = 0; |
|
883 WeakReference targetref; |
|
884 public UInt32 ID { get; private set; } |
|
885 public RemotingManager Manager { get; private set; } |
|
886 public Object Target { |
|
887 get { |
|
888 IProxyBase proxy = this.Proxy; |
|
889 if (proxy == null) return null; |
|
890 return proxy.GetTransparentProxy(); |
|
891 } |
|
892 } |
|
893 public IProxyBase Proxy { |
|
894 get { |
|
895 if (targetref == null) return null; |
|
896 return (IProxyBase)targetref.Target; |
|
897 } |
|
898 } |
|
899 public int RefCnt { get { return refcnt; } } |
|
900 public int AddRef() { |
|
901 int newcnt = Interlocked.Increment(ref refcnt); |
|
902 if (newcnt > 10000 && Interlocked.CompareExchange(ref refcnt, 1, newcnt) == newcnt) { |
|
903 Manager.ProxyReleaseObject(this, newcnt - 1); |
|
904 newcnt = 1; |
|
905 } |
|
906 return newcnt; |
|
907 } |
|
908 public int Release(int count) { return Interlocked.Add(ref refcnt, -count); } |
|
909 public Boolean IsLocal { get { return false; } } |
|
910 public UInt32 RemoteID { get { return ID & 0x7FFFFFFF; } } |
|
911 public ProxyObjectReference(IProxyBase proxy) { |
|
912 this.Manager = proxy.Manager; |
|
913 this.ID = proxy.ID; |
|
914 if ((ID & 0x80000000) == 0) throw new InvalidOperationException("The Object ID is invalid"); |
|
915 targetref = new WeakReference(proxy); |
|
916 } |
|
917 } |
|
918 class DelegateProxy : IProxyBase { |
|
919 public ProxyObjectReference ObjectReference { get; private set; } |
|
920 public RemotingManager Manager { get; private set; } |
|
921 public UInt32 ID { get; private set; } |
|
922 public Delegate Target { get; private set; } |
|
923 public MethodInfo MethodSignature { get; private set; } |
|
924 public Object GetTransparentProxy() { return Target; } |
|
925 |
|
926 public DelegateProxy(RemotingManager manager, UInt32 objid, MethodInfo methodinfo, Type delegateType, DynamicMethod methodBuilder) { |
|
927 this.Manager = manager; |
|
928 this.ID = objid; |
|
929 this.MethodSignature = methodinfo; |
|
930 Delegate mi = methodBuilder.CreateDelegate(delegateType, this); |
|
931 ObjectReference = new ProxyObjectReference(this); |
|
932 } |
|
933 ~DelegateProxy() { |
|
934 Manager.ProxyReleaseObject(ObjectReference); |
|
935 } |
|
936 private Object DoCall(Object[] args) { |
|
937 return Manager.ProxyMakeCallDelegate(this, args); |
|
938 } |
|
939 } |
|
940 class FWProxy : RealProxy, IRemotingTypeInfo, IProxyBase { |
|
941 public RemotingManager Manager { get; private set; } |
|
942 public UInt32 ID { get; private set; } |
|
943 public ProxyObjectReference ObjectReference { get; private set; } |
|
944 |
|
945 public FWProxy(RemotingManager manager, UInt32 objid) : base(typeof(MarshalByRefObject)) { |
|
946 this.Manager = manager; |
|
947 this.ID = objid; |
|
948 this.ObjectReference = new ProxyObjectReference(this); |
|
949 } |
|
950 |
|
951 ~FWProxy() { |
|
952 Manager.ProxyReleaseObject(ObjectReference); |
|
953 } |
|
954 |
|
955 public string TypeName { get; set; } |
|
956 |
|
957 public override IMessage Invoke(IMessage msg) { |
|
958 IMethodCallMessage methodCallMessage = msg as IMethodCallMessage; |
|
959 if (methodCallMessage != null) { |
|
960 Object r = Manager.ProxyMakeCall(this, (MethodInfo)methodCallMessage.MethodBase, methodCallMessage.Args); |
|
961 return new ReturnMessage(r, null, 0, null, methodCallMessage); |
|
962 } |
|
963 throw new NotImplementedException(); |
|
964 } |
|
965 |
|
966 public bool CanCastTo(Type fromType, object o) { |
|
967 if (fromType == typeof(ISerializable)) return false; |
|
968 return Manager.ProxyCanCastTo(this, fromType); |
|
969 } |
|
970 } |
|
971 class ProxyBase : IProxyBase { |
|
972 public RemotingManager Manager { get; private set; } |
|
973 public UInt32 ID { get; private set; } |
|
974 public ProxyObjectReference ObjectReference { get; private set; } |
|
975 public Object GetTransparentProxy() { return this; } |
|
976 |
|
977 public void Init(RemotingManager manager, UInt32 objid) { |
|
978 this.Manager = manager; |
|
979 this.ID = objid; |
|
980 this.ObjectReference = new ProxyObjectReference(this); |
|
981 } |
|
982 |
|
983 protected Object DoCall(RuntimeMethodHandle methodh, Object[] args) { |
|
984 MethodInfo meth = (MethodInfo)MethodInfo.GetMethodFromHandle(methodh); |
|
985 return Manager.ProxyMakeCall(this, meth, args); |
|
986 } |
|
987 |
|
988 ~ProxyBase() { |
|
989 Manager.ProxyReleaseObject(ObjectReference); |
|
990 } |
|
991 } |
|
992 |
|
993 private IProxyBase CreateDelegateProxy(UInt32 objid, Type deltype) { |
|
994 MethodInfo newMethod = deltype.GetMethod("Invoke"); |
|
995 ParameterInfo[] parameters = newMethod.GetParameters(); |
|
996 Type[] mparams = ArrayUtil.Merge(new Type[1] { typeof(DelegateProxy) }, Array.ConvertAll(parameters, delegate(ParameterInfo pi) { return pi.ParameterType; })); |
|
997 DynamicMethod methodBuilder = new DynamicMethod(String.Empty, newMethod.ReturnType, mparams, typeof(DelegateProxy)); |
|
998 ILGenerator ilGenerator = methodBuilder.GetILGenerator(); |
|
999 GenerateProxyMethodCode(ilGenerator, parameters, newMethod.ReturnType, typeof(DelegateProxy), "DoCall", null); |
|
1000 return new DelegateProxy(this, objid, newMethod, deltype, methodBuilder); |
|
1001 } |
|
1002 |
|
1003 private IProxyBase CreateObjectProxy(UInt32 objid, String[] typeNames) { |
|
1004 DebugLog("Create proxy for remote object {0}", objid); |
|
1005 IProxyBase proxy; |
|
1006 if (true) { |
|
1007 proxy = new FWProxy(this, objid); |
|
1008 } else { |
|
1009 Type[] types = new Type[typeNames.Length]; |
|
1010 int j = 0; |
|
1011 for (int i = 0; i < typeNames.Length; i++) { |
|
1012 Type t = Type.GetType(typeNames[i], false); |
|
1013 if (t == null || !t.IsInterface) continue; |
|
1014 types[j] = t; |
|
1015 j++; |
|
1016 } |
|
1017 Array.Resize(ref types, j); |
|
1018 Type proxyType = GetProxyType(types); |
|
1019 proxy = (ProxyBase)Activator.CreateInstance(proxyType); |
|
1020 ((ProxyBase)proxy).Init(this, objid); |
|
1021 } |
|
1022 return proxy; |
|
1023 } |
|
1024 |
|
1025 private static ModuleBuilder moduleBuilder = null; |
|
1026 private static Dictionary<String, Type> proxyCache = null; |
|
1027 private static Type GetProxyType(Type[] interfaceTypes) { |
|
1028 Type proxyType; |
|
1029 String key = String.Join("&", Array.ConvertAll(interfaceTypes, delegate(Type t) { return t.Name; })); |
|
1030 lock (typeof(RemotingManager)) if (proxyCache == null) proxyCache = new Dictionary<String, Type>(); |
|
1031 lock (proxyCache) { |
|
1032 if (!proxyCache.TryGetValue(key, out proxyType)) { |
|
1033 proxyType = GenerateProxyType(key, interfaceTypes); |
|
1034 proxyCache.Add(key, proxyType); |
|
1035 } |
|
1036 } |
|
1037 return proxyType; |
|
1038 } |
|
1039 private static Type GenerateProxyType(String name, Type[] interfaceTypes) { |
|
1040 lock (typeof(RemotingManager)) { |
|
1041 if (moduleBuilder == null) { |
|
1042 AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("UCIS.Remoting.Proxies"), AssemblyBuilderAccess.Run); |
|
1043 moduleBuilder = assembly.DefineDynamicModule("UCIS.Remoting.Proxies", false); |
|
1044 } |
|
1045 } |
|
1046 TypeBuilder typeBuilder = moduleBuilder.DefineType( |
|
1047 name.Length == 0 ? "UndefinedProxy" : name, //mono does not like types with no name! |
|
1048 TypeAttributes.NotPublic | TypeAttributes.Sealed, |
|
1049 typeof(ProxyBase), |
|
1050 interfaceTypes); |
|
1051 foreach (Type interfaceType in interfaceTypes) { |
|
1052 foreach (MethodInfo method in interfaceType.GetMethods()) { |
|
1053 GenerateProxyMethod(typeBuilder, method); |
|
1054 } |
|
1055 } |
|
1056 return typeBuilder.CreateType(); |
|
1057 } |
|
1058 private static void GenerateProxyMethod(TypeBuilder typeBuilder, MethodInfo newMethod) { |
|
1059 if (newMethod.IsGenericMethod) newMethod = newMethod.GetGenericMethodDefinition(); |
|
1060 ParameterInfo[] parameters = newMethod.GetParameters(); |
|
1061 Type[] parameterTypes = Array.ConvertAll(parameters, delegate(ParameterInfo parameter) { return parameter.ParameterType; }); |
|
1062 |
|
1063 MethodBuilder methodBuilder = typeBuilder.DefineMethod( |
|
1064 "Impl_" + newMethod.DeclaringType.Name + "_" + newMethod.Name, |
|
1065 MethodAttributes.Public | MethodAttributes.Virtual, |
|
1066 newMethod.ReturnType, |
|
1067 parameterTypes); |
|
1068 typeBuilder.DefineMethodOverride(methodBuilder, newMethod); |
|
1069 |
|
1070 if (newMethod.IsGenericMethod) { |
|
1071 methodBuilder.DefineGenericParameters(Array.ConvertAll(newMethod.GetGenericArguments(), delegate(Type type) { return type.Name; })); |
|
1072 } |
|
1073 |
|
1074 ILGenerator ilGenerator = methodBuilder.GetILGenerator(); |
|
1075 GenerateProxyMethodCode(ilGenerator, parameters, newMethod.ReturnType, typeof(ProxyBase), "DoCall", newMethod); |
|
1076 } |
|
1077 private static void GenerateProxyMethodCode(ILGenerator ilGenerator, ParameterInfo[] parameters, Type returnType, Type baseType, String baseMethod, MethodInfo methodRef) { |
|
1078 LocalBuilder localBuilder = ilGenerator.DeclareLocal(typeof(Object[])); |
|
1079 ilGenerator.Emit(OpCodes.Ldc_I4, parameters.Length); |
|
1080 ilGenerator.Emit(OpCodes.Newarr, typeof(Object)); |
|
1081 ilGenerator.Emit(OpCodes.Stloc, localBuilder); |
|
1082 for (int i = 0; i < parameters.Length; i++) { |
|
1083 if (parameters[i].ParameterType.IsByRef) continue; |
|
1084 ilGenerator.Emit(OpCodes.Ldloc, localBuilder); |
|
1085 ilGenerator.Emit(OpCodes.Ldc_I4, i); |
|
1086 ilGenerator.Emit(OpCodes.Ldarg, i + 1); |
|
1087 if (parameters[i].ParameterType.IsValueType) ilGenerator.Emit(OpCodes.Box, parameters[i].ParameterType); |
|
1088 ilGenerator.Emit(OpCodes.Stelem_Ref); |
|
1089 } |
|
1090 ilGenerator.Emit(OpCodes.Ldarg_0); |
|
1091 if (methodRef != null) ilGenerator.Emit(OpCodes.Ldtoken, methodRef); |
|
1092 ilGenerator.Emit(OpCodes.Ldloc, localBuilder); |
|
1093 ilGenerator.Emit(OpCodes.Call, baseType.GetMethod(baseMethod, BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic)); |
|
1094 if (returnType == typeof(void)) { |
|
1095 ilGenerator.Emit(OpCodes.Pop); |
|
1096 } else if (returnType.IsValueType) { |
|
1097 ilGenerator.Emit(OpCodes.Unbox_Any, returnType); |
|
1098 } |
|
1099 ilGenerator.Emit(OpCodes.Ret); |
|
1100 } |
|
1101 #endregion |
|
1102 } |
|
1103 } |