1 // ==++== 2 // 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // 5 // ==--== 6 //========================================================================== 7 // File: MessageSmuggler.cs 8 // 9 // Summary: Implements objects necessary to smuggle messages across 10 // AppDomains and determine when it's possible. 11 // 12 //========================================================================== 13 14 using System; 15 using System.Collections; 16 using System.IO; 17 using System.Runtime.Remoting; 18 using System.Runtime.Remoting.Channels; 19 using System.Runtime.Remoting.Messaging; 20 using System.Runtime.Remoting.Proxies; 21 22 23 namespace System.Runtime.Remoting.Messaging 24 { 25 26 internal class MessageSmuggler 27 { CanSmuggleObjectDirectly(Object obj)28 private static bool CanSmuggleObjectDirectly(Object obj) 29 { 30 if ((obj is String) || 31 (obj.GetType() == typeof(void)) || 32 obj.GetType().IsPrimitive) 33 { 34 return true; 35 } 36 37 return false; 38 } // CanSmuggleObjectDirectly 39 40 41 [System.Security.SecurityCritical] // auto-generated FixupArgs(Object[] args, ref ArrayList argsToSerialize)42 protected static Object[] FixupArgs(Object[] args, ref ArrayList argsToSerialize) 43 { 44 Object[] newArgs = new Object[args.Length]; 45 46 int total = args.Length; 47 for (int co = 0; co < total; co++) 48 { 49 newArgs[co] = FixupArg(args[co], ref argsToSerialize); 50 } 51 52 return newArgs; 53 } // FixupArgs 54 55 56 [System.Security.SecurityCritical] // auto-generated FixupArg(Object arg, ref ArrayList argsToSerialize)57 protected static Object FixupArg(Object arg, ref ArrayList argsToSerialize) 58 { 59 // This method examines an argument and sees if it can be smuggled in some form. 60 // If it can directly be smuggled (i.e. it is a primitive or string), we 61 // just return the same object. If it's a marshal by ref object, we 62 // see if we can smuggle the obj ref. If it's a primitive or string array, 63 // we can smuggle a cloned copy of the array. In all other cases, 64 // we add it to the list of args we want serialized, and return a 65 // placeholder element (SerializedArg). 66 67 if (arg == null) 68 return null; 69 70 int index; 71 72 // IMPORTANT!!! This should be done first because CanSmuggleObjectDirectly 73 // calls GetType() and that would slow this down. 74 MarshalByRefObject mbo = arg as MarshalByRefObject; 75 if (mbo != null) 76 { 77 // We can only try to smuggle objref's for actual CLR objects 78 // or for RemotingProxy's. 79 if (!RemotingServices.IsTransparentProxy(mbo) || 80 RemotingServices.GetRealProxy(mbo) is RemotingProxy) 81 { 82 ObjRef objRef = RemotingServices.MarshalInternal(mbo, null, null); 83 if (objRef.CanSmuggle()) 84 { 85 if (!RemotingServices.IsTransparentProxy(mbo)) 86 { 87 ServerIdentity srvId = (ServerIdentity)MarshalByRefObject.GetIdentity(mbo); 88 srvId.SetHandle(); 89 objRef.SetServerIdentity(srvId.GetHandle()); 90 objRef.SetDomainID(AppDomain.CurrentDomain.GetId()); 91 } 92 ObjRef smugObjRef = objRef.CreateSmuggleableCopy(); 93 smugObjRef.SetMarshaledObject(); 94 return new SmuggledObjRef(smugObjRef); 95 } 96 } 97 98 // Add this arg to list of one's to serialize and return a placeholder 99 // since we couldn't smuggle the objref. 100 if (argsToSerialize == null) 101 argsToSerialize = new ArrayList(); 102 index = argsToSerialize.Count; 103 argsToSerialize.Add(arg); 104 return new SerializedArg(index); 105 } 106 107 if (CanSmuggleObjectDirectly(arg)) 108 return arg; 109 110 // if this is a primitive array, we can just make a copy. 111 // (IMPORTANT: We can directly use this copy from the 112 // other app domain, there is no reason to make another 113 // copy once we are on the other side) 114 Array array = arg as Array; 115 if (array != null) 116 { 117 Type elementType = array.GetType().GetElementType(); 118 if (elementType.IsPrimitive || (elementType == typeof(String))) 119 return array.Clone(); 120 } 121 122 123 // Add this arg to list of one's to serialize and return a placeholder. 124 if (argsToSerialize == null) 125 argsToSerialize = new ArrayList(); 126 index = argsToSerialize.Count; 127 argsToSerialize.Add(arg); 128 return new SerializedArg(index); 129 } // FixupArg 130 131 132 [System.Security.SecurityCritical] // auto-generated UndoFixupArgs(Object[] args, ArrayList deserializedArgs)133 protected static Object[] UndoFixupArgs(Object[] args, ArrayList deserializedArgs) 134 { 135 Object[] newArgs = new Object[args.Length]; 136 int total = args.Length; 137 for (int co = 0; co < total; co++) 138 { 139 newArgs[co] = UndoFixupArg(args[co], deserializedArgs); 140 } 141 142 return newArgs; 143 } // UndoFixupArgs 144 145 146 [System.Security.SecurityCritical] // auto-generated UndoFixupArg(Object arg, ArrayList deserializedArgs)147 protected static Object UndoFixupArg(Object arg, ArrayList deserializedArgs) 148 { 149 SmuggledObjRef smuggledObjRef = arg as SmuggledObjRef; 150 if (smuggledObjRef != null) 151 { 152 // We call GetRealObject here ... that covers any 153 // special unmarshaling we need to do for _ComObject 154 return smuggledObjRef.ObjRef.GetRealObjectHelper(); 155 } 156 157 SerializedArg serializedArg = arg as SerializedArg; 158 if (serializedArg != null) 159 { 160 return deserializedArgs[serializedArg.Index]; 161 } 162 163 return arg; 164 } // UndoFixupArg 165 166 167 // returns number of entries added to argsToSerialize 168 [System.Security.SecurityCritical] // auto-generated StoreUserPropertiesForMethodMessage( IMethodMessage msg, ref ArrayList argsToSerialize)169 protected static int StoreUserPropertiesForMethodMessage( 170 IMethodMessage msg, 171 ref ArrayList argsToSerialize) 172 { 173 IDictionary properties = msg.Properties; 174 MessageDictionary dict = properties as MessageDictionary; 175 if (dict != null) 176 { 177 if (dict.HasUserData()) 178 { 179 int co = 0; 180 foreach (DictionaryEntry entry in dict.InternalDictionary) 181 { 182 if (argsToSerialize == null) 183 argsToSerialize = new ArrayList(); 184 argsToSerialize.Add(entry); 185 co++; 186 } 187 188 return co; 189 } 190 else 191 { 192 return 0; 193 } 194 } 195 else 196 { 197 // < 198 199 int co = 0; 200 foreach (DictionaryEntry entry in properties) 201 { 202 if (argsToSerialize == null) 203 argsToSerialize = new ArrayList(); 204 argsToSerialize.Add(entry); 205 co++; 206 } 207 208 return co; 209 } 210 } // StoreUserPropertiesForMethodMessage 211 212 213 // 214 // Helper classes used to smuggle transformed arguments 215 // 216 217 protected class SerializedArg 218 { 219 private int _index; 220 SerializedArg(int index)221 public SerializedArg(int index) 222 { 223 _index = index; 224 } 225 226 public int Index { get { return _index; } } 227 } 228 229 // 230 // end of Helper classes used to smuggle transformed arguments 231 // 232 233 } // class MessageSmuggler 234 235 236 237 // stores an object reference 238 internal class SmuggledObjRef 239 { 240 [System.Security.SecurityCritical] // auto-generated 241 ObjRef _objRef; 242 243 [System.Security.SecurityCritical] // auto-generated SmuggledObjRef(ObjRef objRef)244 public SmuggledObjRef(ObjRef objRef) 245 { 246 _objRef = objRef; 247 } 248 249 public ObjRef ObjRef 250 { 251 [System.Security.SecurityCritical] // auto-generated 252 get { return _objRef; } 253 } 254 } // SmuggledObjRef 255 256 257 258 259 260 internal class SmuggledMethodCallMessage : MessageSmuggler 261 { 262 private String _uri; 263 private String _methodName; 264 private String _typeName; 265 private Object[] _args; 266 267 private byte[] _serializedArgs = null; 268 #if false // This field isn't currently used 269 private Object[] _serializerSmuggledArgs = null; 270 #endif 271 272 // other things that might need to go through serializer 273 private SerializedArg _methodSignature = null; 274 private SerializedArg _instantiation = null; 275 private Object _callContext = null; // either a call id string or a SerializedArg pointing to CallContext object 276 277 private int _propertyCount = 0; // <n> = # of user properties in dictionary 278 // note: first <n> entries in _deserializedArgs will be the property entries 279 280 281 // always use this helper method to create 282 [System.Security.SecurityCritical] // auto-generated SmuggleIfPossible(IMessage msg)283 internal static SmuggledMethodCallMessage SmuggleIfPossible(IMessage msg) 284 { 285 IMethodCallMessage mcm = msg as IMethodCallMessage; 286 if (mcm == null) 287 return null; 288 289 return new SmuggledMethodCallMessage(mcm); 290 } 291 292 // hide default constructor SmuggledMethodCallMessage()293 private SmuggledMethodCallMessage(){} 294 295 [System.Security.SecurityCritical] // auto-generated SmuggledMethodCallMessage(IMethodCallMessage mcm)296 private SmuggledMethodCallMessage(IMethodCallMessage mcm) 297 { 298 _uri = mcm.Uri; 299 _methodName = mcm.MethodName; 300 _typeName = mcm.TypeName; 301 302 ArrayList argsToSerialize = null; 303 304 IInternalMessage iim = mcm as IInternalMessage; 305 306 // user properties (everything but special entries) 307 if ((iim == null) || iim.HasProperties()) 308 _propertyCount = StoreUserPropertiesForMethodMessage(mcm, ref argsToSerialize); 309 310 // generic instantiation information 311 if (mcm.MethodBase.IsGenericMethod) 312 { 313 Type[] inst = mcm.MethodBase.GetGenericArguments(); 314 if (inst != null && inst.Length > 0) 315 { 316 if (argsToSerialize == null) 317 argsToSerialize = new ArrayList(); 318 _instantiation = new SerializedArg(argsToSerialize.Count); 319 argsToSerialize.Add(inst); 320 } 321 } 322 323 // handle method signature 324 if (RemotingServices.IsMethodOverloaded(mcm)) 325 { 326 if (argsToSerialize == null) 327 argsToSerialize = new ArrayList(); 328 _methodSignature = new SerializedArg(argsToSerialize.Count); 329 argsToSerialize.Add(mcm.MethodSignature); 330 } 331 332 // handle call context 333 LogicalCallContext lcc = mcm.LogicalCallContext; 334 if (lcc == null) 335 { 336 _callContext = null; 337 } 338 else 339 if (lcc.HasInfo) 340 { 341 if (argsToSerialize == null) 342 argsToSerialize = new ArrayList(); 343 _callContext = new SerializedArg(argsToSerialize.Count); 344 argsToSerialize.Add(lcc); 345 } 346 else 347 { 348 // just smuggle the call id string 349 _callContext = lcc.RemotingData.LogicalCallID; 350 } 351 352 _args = FixupArgs(mcm.Args, ref argsToSerialize); 353 354 if (argsToSerialize != null) 355 { 356 //MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize, out _serializerSmuggledArgs); 357 MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize); 358 _serializedArgs = argStm.GetBuffer(); 359 } 360 361 } // SmuggledMethodCallMessage 362 363 364 // returns a list of the deserialized arguments 365 [System.Security.SecurityCritical] // auto-generated FixupForNewAppDomain()366 internal ArrayList FixupForNewAppDomain() 367 { 368 ArrayList deserializedArgs = null; 369 370 if (_serializedArgs != null) 371 { 372 deserializedArgs = 373 CrossAppDomainSerializer.DeserializeMessageParts( 374 new MemoryStream(_serializedArgs)); 375 //deserializedArgs = 376 // CrossAppDomainSerializer.DeserializeMessageParts( 377 // new MemoryStream(_serializedArgs), _serializerSmuggledArgs); 378 _serializedArgs = null; 379 } 380 381 return deserializedArgs; 382 } // FixupForNewAppDomain 383 384 385 internal String Uri { get { return _uri; } } 386 internal String MethodName { get { return _methodName; } } 387 internal String TypeName { get { return _typeName; } } 388 GetInstantiation(ArrayList deserializedArgs)389 internal Type[] GetInstantiation(ArrayList deserializedArgs) 390 { 391 if (_instantiation != null) 392 return (Type[])deserializedArgs[_instantiation.Index]; 393 else 394 return null; 395 } 396 GetMethodSignature(ArrayList deserializedArgs)397 internal Object[] GetMethodSignature(ArrayList deserializedArgs) 398 { 399 if (_methodSignature != null) 400 return (Object[])deserializedArgs[_methodSignature.Index]; 401 else 402 return null; 403 } 404 405 [System.Security.SecurityCritical] // auto-generated GetArgs(ArrayList deserializedArgs)406 internal Object[] GetArgs(ArrayList deserializedArgs) 407 { 408 return UndoFixupArgs(_args, deserializedArgs); 409 } // GetArgs 410 411 [System.Security.SecurityCritical] // auto-generated GetCallContext(ArrayList deserializedArgs)412 internal LogicalCallContext GetCallContext(ArrayList deserializedArgs) 413 { 414 if (_callContext == null) 415 { 416 return null; 417 } 418 if (_callContext is String) 419 { 420 LogicalCallContext callContext = new LogicalCallContext(); 421 callContext.RemotingData.LogicalCallID = (String)_callContext; 422 return callContext; 423 } 424 else 425 return (LogicalCallContext)deserializedArgs[((SerializedArg)_callContext).Index]; 426 } 427 428 internal int MessagePropertyCount 429 { 430 get { return _propertyCount; } 431 } 432 PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)433 internal void PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs) 434 { 435 for (int co = 0; co < _propertyCount; co++) 436 { 437 DictionaryEntry de = (DictionaryEntry)deserializedArgs[co]; 438 dict[de.Key] = de.Value; 439 } 440 } 441 442 } // class SmuggledMethodCallMessage 443 444 445 446 internal class SmuggledMethodReturnMessage : MessageSmuggler 447 { 448 private Object[] _args; 449 private Object _returnValue; 450 451 private byte[] _serializedArgs = null; 452 #if false // This field isn't currently used 453 private Object[] _serializerSmuggledArgs = null; 454 #endif 455 456 // other things that might need to go through serializer 457 private SerializedArg _exception = null; 458 private Object _callContext = null; // either a call id string or a SerializedArg pointing to CallContext object 459 460 private int _propertyCount; // <n> = # of user properties in dictionary 461 // note: first <n> entries in _deserializedArgs will be the property entries 462 463 464 // always use this helper method to create 465 [System.Security.SecurityCritical] // auto-generated SmuggleIfPossible(IMessage msg)466 internal static SmuggledMethodReturnMessage SmuggleIfPossible(IMessage msg) 467 { 468 IMethodReturnMessage mrm = msg as IMethodReturnMessage; 469 if (mrm == null) 470 return null; 471 472 return new SmuggledMethodReturnMessage(mrm); 473 } 474 475 // hide default constructor SmuggledMethodReturnMessage()476 private SmuggledMethodReturnMessage(){} 477 478 [System.Security.SecurityCritical] // auto-generated SmuggledMethodReturnMessage(IMethodReturnMessage mrm)479 private SmuggledMethodReturnMessage(IMethodReturnMessage mrm) 480 { 481 ArrayList argsToSerialize = null; 482 483 ReturnMessage retMsg = mrm as ReturnMessage; 484 485 // user properties (everything but special entries) 486 if ((retMsg == null) || retMsg.HasProperties()) 487 _propertyCount = StoreUserPropertiesForMethodMessage(mrm, ref argsToSerialize); 488 489 // handle exception 490 Exception excep = mrm.Exception; 491 if (excep != null) 492 { 493 if (argsToSerialize == null) 494 argsToSerialize = new ArrayList(); 495 _exception = new SerializedArg(argsToSerialize.Count); 496 argsToSerialize.Add(excep); 497 } 498 499 // handle call context 500 LogicalCallContext lcc = mrm.LogicalCallContext; 501 if (lcc == null) 502 { 503 _callContext = null; 504 } 505 else 506 if (lcc.HasInfo) 507 { 508 if (lcc.Principal != null) 509 lcc.Principal = null; 510 511 if (argsToSerialize == null) 512 argsToSerialize = new ArrayList(); 513 _callContext = new SerializedArg(argsToSerialize.Count); 514 argsToSerialize.Add(lcc); 515 } 516 else 517 { 518 // just smuggle the call id string 519 _callContext = lcc.RemotingData.LogicalCallID; 520 } 521 522 _returnValue = FixupArg(mrm.ReturnValue, ref argsToSerialize); 523 _args = FixupArgs(mrm.Args, ref argsToSerialize); 524 525 if (argsToSerialize != null) 526 { 527 MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize); 528 //MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize, out _serializerSmuggledArgs); 529 _serializedArgs = argStm.GetBuffer(); 530 } 531 532 } // SmuggledMethodReturnMessage 533 534 535 [System.Security.SecurityCritical] // auto-generated FixupForNewAppDomain()536 internal ArrayList FixupForNewAppDomain() 537 { 538 ArrayList deserializedArgs = null; 539 540 if (_serializedArgs != null) 541 { 542 deserializedArgs = 543 CrossAppDomainSerializer.DeserializeMessageParts( 544 new MemoryStream(_serializedArgs)); 545 //deserializedArgs = 546 // CrossAppDomainSerializer.DeserializeMessageParts( 547 // new MemoryStream(_serializedArgs), _serializerSmuggledArgs); 548 _serializedArgs = null; 549 } 550 551 return deserializedArgs; 552 } // FixupForNewAppDomain 553 554 [System.Security.SecurityCritical] // auto-generated GetReturnValue(ArrayList deserializedArgs)555 internal Object GetReturnValue(ArrayList deserializedArgs) 556 { 557 return UndoFixupArg(_returnValue, deserializedArgs); 558 } // GetReturnValue 559 560 [System.Security.SecurityCritical] // auto-generated GetArgs(ArrayList deserializedArgs)561 internal Object[] GetArgs(ArrayList deserializedArgs) 562 { 563 Object[] obj = UndoFixupArgs(_args, deserializedArgs); 564 return obj; 565 } // GetArgs 566 GetException(ArrayList deserializedArgs)567 internal Exception GetException(ArrayList deserializedArgs) 568 { 569 if (_exception != null) 570 return (Exception)deserializedArgs[_exception.Index]; 571 else 572 return null; 573 } // Exception 574 575 [System.Security.SecurityCritical] // auto-generated GetCallContext(ArrayList deserializedArgs)576 internal LogicalCallContext GetCallContext(ArrayList deserializedArgs) 577 { 578 if (_callContext == null) 579 { 580 return null; 581 } 582 if (_callContext is String) 583 { 584 LogicalCallContext callContext = new LogicalCallContext(); 585 callContext.RemotingData.LogicalCallID = (String)_callContext; 586 return callContext; 587 } 588 else 589 return (LogicalCallContext)deserializedArgs[((SerializedArg)_callContext).Index]; 590 } 591 592 internal int MessagePropertyCount 593 { 594 get { return _propertyCount; } 595 } 596 PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)597 internal void PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs) 598 { 599 for (int co = 0; co < _propertyCount; co++) 600 { 601 DictionaryEntry de = (DictionaryEntry)deserializedArgs[co]; 602 dict[de.Key] = de.Value; 603 } 604 } 605 606 } // class SmuggledMethodReturnMessage 607 608 609 } // namespace System.Runtime.Remoting.Messaging 610 611