|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//==========================================================================
// File: MessageSmuggler.cs
//
// Summary: Implements objects necessary to smuggle messages across
// AppDomains and determine when it's possible.
//
//==========================================================================
using System;
using System.Collections;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
namespace System.Runtime.Remoting.Messaging
{
internal class MessageSmuggler
{
private static bool CanSmuggleObjectDirectly(Object obj)
{
if ((obj is String) ||
(obj.GetType() == typeof(void)) ||
obj.GetType().IsPrimitive)
{
return true;
}
return false;
} // CanSmuggleObjectDirectly
[System.Security.SecurityCritical] // auto-generated
protected static Object[] FixupArgs(Object[] args, ref ArrayList argsToSerialize)
{
Object[] newArgs = new Object[args.Length];
int total = args.Length;
for (int co = 0; co < total; co++)
{
newArgs[co] = FixupArg(args[co], ref argsToSerialize);
}
return newArgs;
} // FixupArgs
[System.Security.SecurityCritical] // auto-generated
protected static Object FixupArg(Object arg, ref ArrayList argsToSerialize)
{
// This method examines an argument and sees if it can be smuggled in some form.
// If it can directly be smuggled (i.e. it is a primitive or string), we
// just return the same object. If it's a marshal by ref object, we
// see if we can smuggle the obj ref. If it's a primitive or string array,
// we can smuggle a cloned copy of the array. In all other cases,
// we add it to the list of args we want serialized, and return a
// placeholder element (SerializedArg).
if (arg == null)
return null;
int index;
// IMPORTANT!!! This should be done first because CanSmuggleObjectDirectly
// calls GetType() and that would slow this down.
MarshalByRefObject mbo = arg as MarshalByRefObject;
if (mbo != null)
{
// We can only try to smuggle objref's for actual CLR objects
// or for RemotingProxy's.
if (!RemotingServices.IsTransparentProxy(mbo) ||
RemotingServices.GetRealProxy(mbo) is RemotingProxy)
{
ObjRef objRef = RemotingServices.MarshalInternal(mbo, null, null);
if (objRef.CanSmuggle())
{
if (!RemotingServices.IsTransparentProxy(mbo))
{
ServerIdentity srvId = (ServerIdentity)MarshalByRefObject.GetIdentity(mbo);
srvId.SetHandle();
objRef.SetServerIdentity(srvId.GetHandle());
objRef.SetDomainID(AppDomain.CurrentDomain.GetId());
}
ObjRef smugObjRef = objRef.CreateSmuggleableCopy();
smugObjRef.SetMarshaledObject();
return new SmuggledObjRef(smugObjRef);
}
}
// Add this arg to list of one's to serialize and return a placeholder
// since we couldn't smuggle the objref.
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
index = argsToSerialize.Count;
argsToSerialize.Add(arg);
return new SerializedArg(index);
}
if (CanSmuggleObjectDirectly(arg))
return arg;
// if this is a primitive array, we can just make a copy.
// (IMPORTANT: We can directly use this copy from the
// other app domain, there is no reason to make another
// copy once we are on the other side)
Array array = arg as Array;
if (array != null)
{
Type elementType = array.GetType().GetElementType();
if (elementType.IsPrimitive || (elementType == typeof(String)))
return array.Clone();
}
// Add this arg to list of one's to serialize and return a placeholder.
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
index = argsToSerialize.Count;
argsToSerialize.Add(arg);
return new SerializedArg(index);
} // FixupArg
[System.Security.SecurityCritical] // auto-generated
protected static Object[] UndoFixupArgs(Object[] args, ArrayList deserializedArgs)
{
Object[] newArgs = new Object[args.Length];
int total = args.Length;
for (int co = 0; co < total; co++)
{
newArgs[co] = UndoFixupArg(args[co], deserializedArgs);
}
return newArgs;
} // UndoFixupArgs
[System.Security.SecurityCritical] // auto-generated
protected static Object UndoFixupArg(Object arg, ArrayList deserializedArgs)
{
SmuggledObjRef smuggledObjRef = arg as SmuggledObjRef;
if (smuggledObjRef != null)
{
// We call GetRealObject here ... that covers any
// special unmarshaling we need to do for _ComObject
return smuggledObjRef.ObjRef.GetRealObjectHelper();
}
SerializedArg serializedArg = arg as SerializedArg;
if (serializedArg != null)
{
return deserializedArgs[serializedArg.Index];
}
return arg;
} // UndoFixupArg
// returns number of entries added to argsToSerialize
[System.Security.SecurityCritical] // auto-generated
protected static int StoreUserPropertiesForMethodMessage(
IMethodMessage msg,
ref ArrayList argsToSerialize)
{
IDictionary properties = msg.Properties;
MessageDictionary dict = properties as MessageDictionary;
if (dict != null)
{
if (dict.HasUserData())
{
int co = 0;
foreach (DictionaryEntry entry in dict.InternalDictionary)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
argsToSerialize.Add(entry);
co++;
}
return co;
}
else
{
return 0;
}
}
else
{
// <
int co = 0;
foreach (DictionaryEntry entry in properties)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
argsToSerialize.Add(entry);
co++;
}
return co;
}
} // StoreUserPropertiesForMethodMessage
//
// Helper classes used to smuggle transformed arguments
//
protected class SerializedArg
{
private int _index;
public SerializedArg(int index)
{
_index = index;
}
public int Index { get { return _index; } }
}
//
// end of Helper classes used to smuggle transformed arguments
//
} // class MessageSmuggler
// stores an object reference
internal class SmuggledObjRef
{
[System.Security.SecurityCritical] // auto-generated
ObjRef _objRef;
[System.Security.SecurityCritical] // auto-generated
public SmuggledObjRef(ObjRef objRef)
{
_objRef = objRef;
}
public ObjRef ObjRef
{
[System.Security.SecurityCritical] // auto-generated
get { return _objRef; }
}
} // SmuggledObjRef
internal class SmuggledMethodCallMessage : MessageSmuggler
{
private String _uri;
private String _methodName;
private String _typeName;
private Object[] _args;
private byte[] _serializedArgs = null;
#if false // This field isn't currently used
private Object[] _serializerSmuggledArgs = null;
#endif
// other things that might need to go through serializer
private SerializedArg _methodSignature = null;
private SerializedArg _instantiation = null;
private Object _callContext = null; // either a call id string or a SerializedArg pointing to CallContext object
private int _propertyCount = 0; // <n> = # of user properties in dictionary
// note: first <n> entries in _deserializedArgs will be the property entries
// always use this helper method to create
[System.Security.SecurityCritical] // auto-generated
internal static SmuggledMethodCallMessage SmuggleIfPossible(IMessage msg)
{
IMethodCallMessage mcm = msg as IMethodCallMessage;
if (mcm == null)
return null;
return new SmuggledMethodCallMessage(mcm);
}
// hide default constructor
private SmuggledMethodCallMessage(){}
[System.Security.SecurityCritical] // auto-generated
private SmuggledMethodCallMessage(IMethodCallMessage mcm)
{
_uri = mcm.Uri;
_methodName = mcm.MethodName;
_typeName = mcm.TypeName;
ArrayList argsToSerialize = null;
IInternalMessage iim = mcm as IInternalMessage;
// user properties (everything but special entries)
if ((iim == null) || iim.HasProperties())
_propertyCount = StoreUserPropertiesForMethodMessage(mcm, ref argsToSerialize);
// generic instantiation information
if (mcm.MethodBase.IsGenericMethod)
{
Type[] inst = mcm.MethodBase.GetGenericArguments();
if (inst != null && inst.Length > 0)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
_instantiation = new SerializedArg(argsToSerialize.Count);
argsToSerialize.Add(inst);
}
}
// handle method signature
if (RemotingServices.IsMethodOverloaded(mcm))
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
_methodSignature = new SerializedArg(argsToSerialize.Count);
argsToSerialize.Add(mcm.MethodSignature);
}
// handle call context
LogicalCallContext lcc = mcm.LogicalCallContext;
if (lcc == null)
{
_callContext = null;
}
else
if (lcc.HasInfo)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
_callContext = new SerializedArg(argsToSerialize.Count);
argsToSerialize.Add(lcc);
}
else
{
// just smuggle the call id string
_callContext = lcc.RemotingData.LogicalCallID;
}
_args = FixupArgs(mcm.Args, ref argsToSerialize);
if (argsToSerialize != null)
{
//MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize, out _serializerSmuggledArgs);
MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize);
_serializedArgs = argStm.GetBuffer();
}
} // SmuggledMethodCallMessage
// returns a list of the deserialized arguments
[System.Security.SecurityCritical] // auto-generated
internal ArrayList FixupForNewAppDomain()
{
ArrayList deserializedArgs = null;
if (_serializedArgs != null)
{
deserializedArgs =
CrossAppDomainSerializer.DeserializeMessageParts(
new MemoryStream(_serializedArgs));
//deserializedArgs =
// CrossAppDomainSerializer.DeserializeMessageParts(
// new MemoryStream(_serializedArgs), _serializerSmuggledArgs);
_serializedArgs = null;
}
return deserializedArgs;
} // FixupForNewAppDomain
internal String Uri { get { return _uri; } }
internal String MethodName { get { return _methodName; } }
internal String TypeName { get { return _typeName; } }
internal Type[] GetInstantiation(ArrayList deserializedArgs)
{
if (_instantiation != null)
return (Type[])deserializedArgs[_instantiation.Index];
else
return null;
}
internal Object[] GetMethodSignature(ArrayList deserializedArgs)
{
if (_methodSignature != null)
return (Object[])deserializedArgs[_methodSignature.Index];
else
return null;
}
[System.Security.SecurityCritical] // auto-generated
internal Object[] GetArgs(ArrayList deserializedArgs)
{
return UndoFixupArgs(_args, deserializedArgs);
} // GetArgs
[System.Security.SecurityCritical] // auto-generated
internal LogicalCallContext GetCallContext(ArrayList deserializedArgs)
{
if (_callContext == null)
{
return null;
}
if (_callContext is String)
{
LogicalCallContext callContext = new LogicalCallContext();
callContext.RemotingData.LogicalCallID = (String)_callContext;
return callContext;
}
else
return (LogicalCallContext)deserializedArgs[((SerializedArg)_callContext).Index];
}
internal int MessagePropertyCount
{
get { return _propertyCount; }
}
internal void PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)
{
for (int co = 0; co < _propertyCount; co++)
{
DictionaryEntry de = (DictionaryEntry)deserializedArgs[co];
dict[de.Key] = de.Value;
}
}
} // class SmuggledMethodCallMessage
internal class SmuggledMethodReturnMessage : MessageSmuggler
{
private Object[] _args;
private Object _returnValue;
private byte[] _serializedArgs = null;
#if false // This field isn't currently used
private Object[] _serializerSmuggledArgs = null;
#endif
// other things that might need to go through serializer
private SerializedArg _exception = null;
private Object _callContext = null; // either a call id string or a SerializedArg pointing to CallContext object
private int _propertyCount; // <n> = # of user properties in dictionary
// note: first <n> entries in _deserializedArgs will be the property entries
// always use this helper method to create
[System.Security.SecurityCritical] // auto-generated
internal static SmuggledMethodReturnMessage SmuggleIfPossible(IMessage msg)
{
IMethodReturnMessage mrm = msg as IMethodReturnMessage;
if (mrm == null)
return null;
return new SmuggledMethodReturnMessage(mrm);
}
// hide default constructor
private SmuggledMethodReturnMessage(){}
[System.Security.SecurityCritical] // auto-generated
private SmuggledMethodReturnMessage(IMethodReturnMessage mrm)
{
ArrayList argsToSerialize = null;
ReturnMessage retMsg = mrm as ReturnMessage;
// user properties (everything but special entries)
if ((retMsg == null) || retMsg.HasProperties())
_propertyCount = StoreUserPropertiesForMethodMessage(mrm, ref argsToSerialize);
// handle exception
Exception excep = mrm.Exception;
if (excep != null)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
_exception = new SerializedArg(argsToSerialize.Count);
argsToSerialize.Add(excep);
}
// handle call context
LogicalCallContext lcc = mrm.LogicalCallContext;
if (lcc == null)
{
_callContext = null;
}
else
if (lcc.HasInfo)
{
if (lcc.Principal != null)
lcc.Principal = null;
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
_callContext = new SerializedArg(argsToSerialize.Count);
argsToSerialize.Add(lcc);
}
else
{
// just smuggle the call id string
_callContext = lcc.RemotingData.LogicalCallID;
}
_returnValue = FixupArg(mrm.ReturnValue, ref argsToSerialize);
_args = FixupArgs(mrm.Args, ref argsToSerialize);
if (argsToSerialize != null)
{
MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize);
//MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize, out _serializerSmuggledArgs);
_serializedArgs = argStm.GetBuffer();
}
} // SmuggledMethodReturnMessage
[System.Security.SecurityCritical] // auto-generated
internal ArrayList FixupForNewAppDomain()
{
ArrayList deserializedArgs = null;
if (_serializedArgs != null)
{
deserializedArgs =
CrossAppDomainSerializer.DeserializeMessageParts(
new MemoryStream(_serializedArgs));
//deserializedArgs =
// CrossAppDomainSerializer.DeserializeMessageParts(
// new MemoryStream(_serializedArgs), _serializerSmuggledArgs);
_serializedArgs = null;
}
return deserializedArgs;
} // FixupForNewAppDomain
[System.Security.SecurityCritical] // auto-generated
internal Object GetReturnValue(ArrayList deserializedArgs)
{
return UndoFixupArg(_returnValue, deserializedArgs);
} // GetReturnValue
[System.Security.SecurityCritical] // auto-generated
internal Object[] GetArgs(ArrayList deserializedArgs)
{
Object[] obj = UndoFixupArgs(_args, deserializedArgs);
return obj;
} // GetArgs
internal Exception GetException(ArrayList deserializedArgs)
{
if (_exception != null)
return (Exception)deserializedArgs[_exception.Index];
else
return null;
} // Exception
[System.Security.SecurityCritical] // auto-generated
internal LogicalCallContext GetCallContext(ArrayList deserializedArgs)
{
if (_callContext == null)
{
return null;
}
if (_callContext is String)
{
LogicalCallContext callContext = new LogicalCallContext();
callContext.RemotingData.LogicalCallID = (String)_callContext;
return callContext;
}
else
return (LogicalCallContext)deserializedArgs[((SerializedArg)_callContext).Index];
}
internal int MessagePropertyCount
{
get { return _propertyCount; }
}
internal void PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)
{
for (int co = 0; co < _propertyCount; co++)
{
DictionaryEntry de = (DictionaryEntry)deserializedArgs[co];
dict[de.Key] = de.Value;
}
}
} // class SmuggledMethodReturnMessage
} // namespace System.Runtime.Remoting.Messaging
|