1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 // Implementation of CallContext ... currently leverages off
7 // the LocalDataStore facility.
8 namespace System.Runtime.Remoting.Messaging{
9 
10     using System.Threading;
11     using System.Runtime.Remoting;
12     using System.Security.Principal;
13     using System.Collections;
14     using System.Runtime.Serialization;
15     using System.Security.Permissions;
16     // This class exposes the API for the users of call context. All methods
17     // in CallContext are static and operate upon the call context in the Thread.
18     // NOTE: CallContext is a specialized form of something that behaves like
19     // TLS for method calls. However, since the call objects may get serialized
20     // and deserialized along the path, it is tough to guarantee identity
21     // preservation.
22     // The LogicalCallContext class has all the actual functionality. We have
23     // to use this scheme because Remoting message sinks etc do need to have
24     // the distinction between the call context on the physical thread and
25     // the call context that the remoting message actually carries. In most cases
26     // they will operate on the message's call context and hence the latter
27     // exposes the same set of methods as instance methods.
28 
29     // Only statics does not need to marked with the serializable attribute
30     [System.Security.SecurityCritical]  // auto-generated_required
31     [Serializable]
32     [System.Runtime.InteropServices.ComVisible(true)]
33     public sealed class CallContext
34     {
CallContext()35         private CallContext()
36         {
37         }
38 
39 #if MONO
SetCurrentCallContext(LogicalCallContext ctx)40         internal static object SetCurrentCallContext (LogicalCallContext ctx)
41         {
42             return null;
43         }
44 #endif
45 
46         // Sets the given logical call context object on the thread.
47         // Returns the previous one.
SetLogicalCallContext( LogicalCallContext callCtx)48         internal static LogicalCallContext SetLogicalCallContext(
49             LogicalCallContext callCtx)
50         {
51             ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
52             LogicalCallContext prev = ec.LogicalCallContext;
53             ec.LogicalCallContext = callCtx;
54             return prev;
55         }
56 
57         /*=========================================================================
58         ** Frees a named data slot.
59         =========================================================================*/
60         [System.Security.SecurityCritical]  // auto-generated
FreeNamedDataSlot(String name)61         public static void FreeNamedDataSlot(String name)
62         {
63             ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
64             ec.LogicalCallContext.FreeNamedDataSlot(name);
65             ec.IllogicalCallContext.FreeNamedDataSlot(name);
66         }
67 
68         /*=========================================================================
69         ** Get data on the logical call context
70         =========================================================================*/
71         [System.Security.SecurityCritical]  // auto-generated
LogicalGetData(String name)72         public static Object LogicalGetData(String name)
73         {
74             return Thread.CurrentThread.GetExecutionContextReader().LogicalCallContext.GetData(name);
75         }
76 
77         /*=========================================================================
78         ** Get data on the illogical call context
79         =========================================================================*/
IllogicalGetData(String name)80         private static Object IllogicalGetData(String name)
81         {
82             return Thread.CurrentThread.GetExecutionContextReader().IllogicalCallContext.GetData(name);
83         }
84 
85         internal static IPrincipal Principal
86         {
87             [System.Security.SecurityCritical]  // auto-generated
88             get
89             {
90                 return Thread.CurrentThread.GetExecutionContextReader().LogicalCallContext.Principal;
91             }
92 
93             [System.Security.SecurityCritical]  // auto-generated
94             set
95             {
96                 Thread.CurrentThread.
97                     GetMutableExecutionContext().LogicalCallContext.Principal = value;
98             }
99         }
100 
101         public static Object HostContext
102         {
103             [System.Security.SecurityCritical]  // auto-generated
104             get
105             {
106                 ExecutionContext.Reader ec = Thread.CurrentThread.GetExecutionContextReader();
107 
108                 Object hC = ec.IllogicalCallContext.HostContext;
109                 if (hC == null)
110                     hC = ec.LogicalCallContext.HostContext;
111                 return hC;
112             }
113             [System.Security.SecurityCritical]  // auto-generated_required
114             set
115             {
116                 ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
117                 if (value is ILogicalThreadAffinative)
118                 {
119                     ec.IllogicalCallContext.HostContext = null;
120                     ec.LogicalCallContext.HostContext = value;
121                 }
122                 else
123                 {
124                     ec.IllogicalCallContext.HostContext = value;
125                     ec.LogicalCallContext.HostContext = null;
126                 }
127             }
128         }
129 
130         // <
131 
132 
133         [System.Security.SecurityCritical]  // auto-generated
GetData(String name)134         public static Object GetData(String name)
135         {
136             Object o = LogicalGetData(name);
137             if (o == null)
138             {
139                 return IllogicalGetData(name);
140             }
141             else
142             {
143                 return o;
144             }
145         }
146 
147         [System.Security.SecurityCritical]  // auto-generated
SetData(String name, Object data)148         public static void SetData(String name, Object data)
149         {
150             if (data is ILogicalThreadAffinative)
151             {
152                 LogicalSetData(name, data);
153             }
154             else
155             {
156                 ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
157                 ec.LogicalCallContext.FreeNamedDataSlot(name);
158                 ec.IllogicalCallContext.SetData(name, data);
159             }
160         }
161         [System.Security.SecurityCritical]  // auto-generated
LogicalSetData(String name, Object data)162         public static void LogicalSetData(String name, Object data)
163         {
164             ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
165             ec.IllogicalCallContext.FreeNamedDataSlot(name);
166             ec.LogicalCallContext.SetData(name, data);
167         }
168 
169 
170         [System.Security.SecurityCritical]  // auto-generated
GetHeaders()171         public static Header[] GetHeaders()
172         {
173             // Header is mutable, so we need to get these from a mutable ExecutionContext
174             LogicalCallContext lcc =  Thread.CurrentThread.GetMutableExecutionContext().LogicalCallContext;
175             return lcc.InternalGetHeaders();
176         } // GetHeaders
177 
178         [System.Security.SecurityCritical]  // auto-generated
SetHeaders(Header[] headers)179         public static void SetHeaders(Header[] headers)
180         {
181             LogicalCallContext lcc =  Thread.CurrentThread.GetMutableExecutionContext().LogicalCallContext;
182             lcc.InternalSetHeaders(headers);
183         } // SetHeaders
184 
185     } // class CallContext
186 
187 [System.Runtime.InteropServices.ComVisible(true)]
188     public interface ILogicalThreadAffinative
189     {
190     }
191 
192     internal class IllogicalCallContext
193     {
194         private Hashtable m_Datastore;
195         private Object m_HostContext;
196 
197         internal struct Reader
198         {
199             IllogicalCallContext m_ctx;
200 
ReaderSystem.Runtime.Remoting.Messaging.IllogicalCallContext.Reader201             public Reader(IllogicalCallContext ctx) { m_ctx = ctx; }
202 
203             public bool IsNull { get { return m_ctx == null; } }
204 
205             [System.Security.SecurityCritical]
GetDataSystem.Runtime.Remoting.Messaging.IllogicalCallContext.Reader206             public Object GetData(String name) { return IsNull ? null : m_ctx.GetData(name); }
207 
208             public Object HostContext { get { return IsNull ? null : m_ctx.HostContext; } }
209         }
210 
211         private Hashtable Datastore
212         {
213             get
214             {
215                 if (null == m_Datastore)
216                 {
217                     // The local store has not yet been created for this thread.
218                     m_Datastore = new Hashtable();
219                 }
220                 return m_Datastore;
221             }
222         }
223 
224         internal Object HostContext
225         {
226             get
227             {
228                 return m_HostContext;
229             }
230             set
231             {
232                 m_HostContext = value;
233             }
234         }
235 
236         internal bool HasUserData
237         {
238             get { return ((m_Datastore != null) && (m_Datastore.Count > 0));}
239         }
240 
241         /*=========================================================================
242         ** Frees a named data slot.
243         =========================================================================*/
FreeNamedDataSlot(String name)244         public void FreeNamedDataSlot(String name)
245         {
246             Datastore.Remove(name);
247         }
248 
GetData(String name)249         public Object GetData(String name)
250         {
251             return Datastore[name];
252         }
253 
SetData(String name, Object data)254         public void SetData(String name, Object data)
255         {
256             Datastore[name] = data;
257         }
258 
CreateCopy()259         public IllogicalCallContext CreateCopy()
260         {
261             IllogicalCallContext ilcc = new IllogicalCallContext();
262             ilcc.HostContext = this.HostContext;
263             if (HasUserData)
264             {
265                 IDictionaryEnumerator de = this.m_Datastore.GetEnumerator();
266 
267                 while (de.MoveNext())
268                 {
269                     ilcc.Datastore[(String)de.Key] = de.Value;
270                 }
271             }
272             return ilcc;
273         }
274     }
275 
276     // This class handles the actual call context functionality. It leverages on the
277     // implementation of local data store ... except that the local store manager is
278     // not static. That is to say, allocating a slot in one call context has no effect
279     // on another call contexts. Different call contexts are entirely unrelated.
280 
281     [System.Security.SecurityCritical]  // auto-generated_required
282     [Serializable]
283     [System.Runtime.InteropServices.ComVisible(true)]
284     public sealed class LogicalCallContext : ISerializable, ICloneable
285     {
286         // Private static data
287         private static Type s_callContextType = typeof(LogicalCallContext);
288         private const string s_CorrelationMgrSlotName = "System.Diagnostics.Trace.CorrelationManagerSlot";
289 
290         /*=========================================================================
291         ** Data accessed from managed code that needs to be defined in
292         ** LogicalCallContextObject  to maintain alignment between the two classes.
293         ** DON'T CHANGE THESE UNLESS YOU MODIFY LogicalContextObject in vm\object.h
294         =========================================================================*/
295 
296         // Private member data
297         private Hashtable m_Datastore;
298         private CallContextRemotingData m_RemotingData = null;
299         private CallContextSecurityData m_SecurityData = null;
300         private Object m_HostContext = null;
301         private bool m_IsCorrelationMgr = false;
302 
303         // _sendHeaders is for Headers that should be sent out on the next call.
304         // _recvHeaders are for Headers that came from a response.
305         private Header[] _sendHeaders = null;
306         private Header[] _recvHeaders = null;
307 
308 
LogicalCallContext()309         internal LogicalCallContext()
310         {
311         }
312 
313         internal struct Reader
314         {
315             LogicalCallContext m_ctx;
316 
ReaderSystem.Runtime.Remoting.Messaging.LogicalCallContext.Reader317             public Reader(LogicalCallContext ctx) { m_ctx = ctx; }
318 
319             public bool IsNull { get { return m_ctx == null; } }
320             public bool HasInfo { get { return IsNull ? false : m_ctx.HasInfo; } }
321 
CloneSystem.Runtime.Remoting.Messaging.LogicalCallContext.Reader322             public LogicalCallContext Clone() { return (LogicalCallContext)m_ctx.Clone(); }
323 
324             public IPrincipal Principal { get { return IsNull ? null : m_ctx.Principal; } }
325 
326             [System.Security.SecurityCritical]
GetDataSystem.Runtime.Remoting.Messaging.LogicalCallContext.Reader327             public Object GetData(String name) { return IsNull ? null : m_ctx.GetData(name); }
328 
329             public Object HostContext { get { return IsNull ? null : m_ctx.HostContext; } }
330         }
331 
332         [System.Security.SecurityCritical]  // auto-generated
LogicalCallContext(SerializationInfo info, StreamingContext context)333         internal LogicalCallContext(SerializationInfo info, StreamingContext context)
334         {
335             SerializationInfoEnumerator e = info.GetEnumerator();
336             while (e.MoveNext())
337             {
338                 if (e.Name.Equals("__RemotingData"))
339                 {
340                     m_RemotingData = (CallContextRemotingData) e.Value;
341                 }
342                 else if (e.Name.Equals("__SecurityData"))
343                 {
344                     if (context.State == StreamingContextStates.CrossAppDomain)
345                     {
346                         m_SecurityData = (CallContextSecurityData) e.Value;
347                     }
348                     else
349                     {
350                         BCLDebug.Assert(false, "Security data should only be serialized in cross appdomain case.");
351                     }
352                 }
353                 else if (e.Name.Equals("__HostContext"))
354                 {
355                     m_HostContext = e.Value;
356                 }
357                 else if (e.Name.Equals("__CorrelationMgrSlotPresent"))
358                 {
359                     m_IsCorrelationMgr = (bool)e.Value;
360                 }
361                 else
362                 {
363                     Datastore[e.Name] = e.Value;
364                 }
365 
366             }
367         }
368 
369         [System.Security.SecurityCritical]  // auto-generated_required
GetObjectData(SerializationInfo info, StreamingContext context)370         public void GetObjectData(SerializationInfo info, StreamingContext context)
371         {
372             if (info == null)
373                 throw new ArgumentNullException("info");
374             info.SetType(s_callContextType);
375             if (m_RemotingData != null)
376             {
377                 info.AddValue("__RemotingData", m_RemotingData);
378             }
379             if (m_SecurityData != null)
380             {
381                 if (context.State == StreamingContextStates.CrossAppDomain)
382                 {
383                     info.AddValue("__SecurityData", m_SecurityData);
384                 }
385             }
386             if (m_HostContext != null)
387             {
388                 info.AddValue("__HostContext", m_HostContext);
389             }
390             if (m_IsCorrelationMgr)
391             {
392                 info.AddValue("__CorrelationMgrSlotPresent", m_IsCorrelationMgr);
393             }
394             if (HasUserData)
395             {
396                 IDictionaryEnumerator de = m_Datastore.GetEnumerator();
397 
398                 while (de.MoveNext())
399                 {
400                     info.AddValue((String)de.Key, de.Value);
401                 }
402             }
403 
404         }
405 
406 
407         // ICloneable::Clone
408         // Used to create a deep copy of the call context when an async
409         // call starts.
410 
411         // <
412 
413 
414 
415         [System.Security.SecuritySafeCritical] // overrides public transparent member
Clone()416         public Object Clone()
417         {
418             LogicalCallContext lc = new LogicalCallContext();
419             if (m_RemotingData != null)
420                 lc.m_RemotingData = (CallContextRemotingData)m_RemotingData.Clone();
421             if (m_SecurityData != null)
422                 lc.m_SecurityData = (CallContextSecurityData)m_SecurityData.Clone();
423             if (m_HostContext != null)
424                 lc.m_HostContext = m_HostContext;
425             lc.m_IsCorrelationMgr = m_IsCorrelationMgr;
426             if (HasUserData)
427             {
428                 IDictionaryEnumerator de = m_Datastore.GetEnumerator();
429 
430                 if (!m_IsCorrelationMgr)
431                 {
432                     while (de.MoveNext())
433                     {
434                         lc.Datastore[(String)de.Key] = de.Value;
435                     }
436                 }
437                 else
438                 {
439                     while (de.MoveNext())
440                     {
441                         String key = (String)de.Key;
442 
443                         // Deep clone "System.Diagnostics.Trace.CorrelationManagerSlot"
444                         if (key.Equals(s_CorrelationMgrSlotName))
445                         {
446                             lc.Datastore[key] = ((ICloneable)de.Value).Clone();
447                         }
448                         else
449                             lc.Datastore[key] = de.Value;
450                     }
451                 }
452             }
453             return lc;
454         }
455 
456         // Used to do a (limited) merge the call context from a returning async call
457         [System.Security.SecurityCritical]  // auto-generated
Merge(LogicalCallContext lc)458         internal void Merge(LogicalCallContext lc)
459         {
460             // we ignore the RemotingData & SecurityData
461             // and only merge the user sections of the two call contexts
462             // the idea being that if the original call had any
463             // identity/remoting callID that should remain unchanged
464 
465             // If we have a non-null callContext and it is not the same
466             // as the one on the current thread (can happen in x-context async)
467             // and there is any userData in the callContext, do the merge
468             if ((lc != null) && (this != lc) && lc.HasUserData)
469             {
470                 IDictionaryEnumerator de = lc.Datastore.GetEnumerator();
471 
472                 while (de.MoveNext())
473                 {
474                     Datastore[(String)de.Key] = de.Value;
475                 }
476             }
477         }
478 
479         public bool HasInfo
480         {
481             [System.Security.SecurityCritical]  // auto-generated
482             get
483             {
484                 bool fInfo = false;
485 
486                 // Set the flag to true if there is either remoting data, or
487                 // security data or user data
488                 if(
489                     (m_RemotingData != null &&  m_RemotingData.HasInfo) ||
490                     (m_SecurityData != null &&  m_SecurityData.HasInfo) ||
491                     (m_HostContext != null) ||
492                     HasUserData
493                   )
494                 {
495                     fInfo = true;
496                 }
497 
498                 return fInfo;
499             }
500         }
501 
502         private bool HasUserData
503         {
504             get { return ((m_Datastore != null) && (m_Datastore.Count > 0));}
505         }
506 
507         internal CallContextRemotingData RemotingData
508         {
509             get
510             {
511                 if (m_RemotingData == null)
512                     m_RemotingData = new CallContextRemotingData();
513 
514                 return m_RemotingData;
515             }
516         }
517 
518         internal CallContextSecurityData SecurityData
519         {
520             get
521             {
522                 if (m_SecurityData == null)
523                     m_SecurityData = new CallContextSecurityData();
524 
525                 return m_SecurityData;
526             }
527         }
528 
529         internal Object HostContext
530         {
531             get
532             {
533                 return m_HostContext;
534             }
535             set
536             {
537                 m_HostContext = value;
538             }
539         }
540 
541         private Hashtable Datastore
542         {
543             get
544             {
545                 if (null == m_Datastore)
546                 {
547                     // The local store has not yet been created for this thread.
548                     m_Datastore = new Hashtable();
549                 }
550                 return m_Datastore;
551             }
552         }
553 
554         // This is used for quick access to the current principal when going
555         // between appdomains.
556         internal IPrincipal Principal
557         {
558             get
559             {
560                 // This MUST not fault in the security data object if it doesn't exist.
561                 if (m_SecurityData != null)
562                     return m_SecurityData.Principal;
563 
564                 return null;
565             } // get
566 
567             [System.Security.SecurityCritical]  // auto-generated
568             set
569             {
570                 SecurityData.Principal = value;
571             } // set
572         } // Principal
573 
574         /*=========================================================================
575         ** Frees a named data slot.
576         =========================================================================*/
577         [System.Security.SecurityCritical]  // auto-generated
FreeNamedDataSlot(String name)578         public void FreeNamedDataSlot(String name)
579         {
580             Datastore.Remove(name);
581         }
582 
583         [System.Security.SecurityCritical]  // auto-generated
GetData(String name)584         public Object GetData(String name)
585         {
586             return Datastore[name];
587         }
588 
589         [System.Security.SecurityCritical]  // auto-generated
SetData(String name, Object data)590         public void SetData(String name, Object data)
591         {
592             Datastore[name] = data;
593             if (name.Equals(s_CorrelationMgrSlotName))
594                 m_IsCorrelationMgr = true;
595         }
596 
InternalGetOutgoingHeaders()597         private Header[] InternalGetOutgoingHeaders()
598         {
599             Header[] outgoingHeaders = _sendHeaders;
600             _sendHeaders = null;
601 
602             // A new remote call is being made, so we null out the
603             //   current received headers so these can't be confused
604             //   with a response from the next call.
605             _recvHeaders = null;
606 
607             return outgoingHeaders;
608         } // InternalGetOutgoingHeaders
609 
610 
InternalSetHeaders(Header[] headers)611         internal void InternalSetHeaders(Header[] headers)
612         {
613             _sendHeaders = headers;
614             _recvHeaders = null;
615         } // InternalSetHeaders
616 
617 
InternalGetHeaders()618         internal Header[] InternalGetHeaders()
619         {
620             // If _sendHeaders is currently set, we always want to return them.
621             if (_sendHeaders != null)
622                 return _sendHeaders;
623 
624             // Either _recvHeaders is non-null and those are the ones we want to
625             //   return, or there are no currently set headers, so we'll return
626             //    null.
627             return _recvHeaders;
628         } // InternalGetHeaders
629 
630         // Nulls out the principal if its not serializable.
631         // Since principals do flow for x-appdomain cases
632         // we need to handle this behaviour both during invoke
633         // and response
634         [System.Security.SecurityCritical]  // auto-generated
RemovePrincipalIfNotSerializable()635         internal IPrincipal RemovePrincipalIfNotSerializable()
636         {
637             IPrincipal currentPrincipal = this.Principal;
638             // If the principal is not serializable, we need to
639             //   null it out.
640             if (currentPrincipal != null)
641             {
642                 if (!currentPrincipal.GetType().IsSerializable)
643                     this.Principal = null;
644             }
645             return currentPrincipal;
646         }
647 
648         // Takes outgoing headers and inserts them
649         [System.Security.SecurityCritical]  // auto-generated
PropagateOutgoingHeadersToMessage(IMessage msg)650         internal void PropagateOutgoingHeadersToMessage(IMessage msg)
651         {
652             Header[] headers = InternalGetOutgoingHeaders();
653 
654             if (headers != null)
655             {
656                 BCLDebug.Assert(msg != null, "Why is the message null?");
657 
658                 IDictionary properties = msg.Properties;
659                 BCLDebug.Assert(properties != null, "Why are the properties null?");
660 
661                 foreach (Header header in headers)
662                 {
663                     // add header to the message dictionary
664                     if (header != null)
665                     {
666                         // The header key is composed from its name and namespace.
667 
668                         String name = GetPropertyKeyForHeader(header);
669 
670                         properties[name] = header;
671                     }
672                 }
673             }
674         } // PropagateOutgoingHeadersToMessage
675 
676         // Retrieve key to use for header.
GetPropertyKeyForHeader(Header header)677         internal static String GetPropertyKeyForHeader(Header header)
678         {
679             if (header == null)
680                 return null;
681 
682             if (header.HeaderNamespace != null)
683                 return header.Name + ", " + header.HeaderNamespace;
684             else
685                 return header.Name;
686         } // GetPropertyKeyForHeader
687 
688         // Take headers out of message and stores them in call context
689         [System.Security.SecurityCritical]  // auto-generated
PropagateIncomingHeadersToCallContext(IMessage msg)690         internal void PropagateIncomingHeadersToCallContext(IMessage msg)
691         {
692             BCLDebug.Assert(msg != null, "Why is the message null?");
693 
694             // If it's an internal message, we can quickly tell if there are any
695             //   headers.
696             IInternalMessage iim = msg as IInternalMessage;
697             if (iim != null)
698             {
699                 if (!iim.HasProperties())
700                 {
701                     // If there are no properties just return immediately.
702                     return;
703                 }
704             }
705 
706             IDictionary properties = msg.Properties;
707             BCLDebug.Assert(properties != null, "Why are the properties null?");
708 
709             IDictionaryEnumerator e = (IDictionaryEnumerator) properties.GetEnumerator();
710 
711             // cycle through the properties to get a count of the headers
712             int count = 0;
713             while (e.MoveNext())
714             {
715                 String key = (String)e.Key;
716                 if (!key.StartsWith("__", StringComparison.Ordinal))
717                 {
718                     // We don't want to have to check for special values, so we
719                     //   blanketly state that header names can't start with
720                     //   double underscore.
721                     if (e.Value is Header)
722                         count++;
723                 }
724             }
725 
726             // If there are headers, create array and set it to the received header property
727             Header[] headers = null;
728             if (count > 0)
729             {
730                 headers = new Header[count];
731 
732                 count = 0;
733                 e.Reset();
734                 while (e.MoveNext())
735                 {
736                     String key = (String)e.Key;
737                     if (!key.StartsWith("__", StringComparison.Ordinal))
738                     {
739                         Header header = e.Value as Header;
740                         if (header != null)
741                             headers[count++] = header;
742                     }
743                 }
744             }
745 
746             _recvHeaders = headers;
747             _sendHeaders = null;
748         } // PropagateIncomingHeadersToCallContext
749     } // class LogicalCallContext
750 
751 
752 
753     [Serializable]
754     internal class CallContextSecurityData : ICloneable
755     {
756         // This is used for the special getter/setter for security related
757         // info in the callContext.
758         IPrincipal _principal;
759         // <
760         internal IPrincipal Principal
761         {
762             get {return _principal;}
763             set {_principal = value;}
764         }
765 
766         // Checks if there is any useful data to be serialized
767         internal bool HasInfo
768         {
769             get
770             {
771                 return (null != _principal);
772             }
773 
774         }
775 
Clone()776         public Object Clone()
777         {
778             CallContextSecurityData sd = new CallContextSecurityData();
779             sd._principal = _principal;
780             return sd;
781         }
782 
783     }
784 
785     [Serializable]
786     internal class CallContextRemotingData : ICloneable
787     {
788         // This is used for the special getter/setter for remoting related
789         // info in the callContext.
790         String _logicalCallID;
791 
792         internal String LogicalCallID
793         {
794             get  {return _logicalCallID;}
795             set  {_logicalCallID = value;}
796         }
797 
798         // Checks if there is any useful data to be serialized
799         internal bool HasInfo
800         {
801             get
802             {
803                 // Keep this updated if we add more stuff to remotingData!
804                 return (_logicalCallID!=null);
805             }
806         }
807 
Clone()808         public Object Clone()
809         {
810             CallContextRemotingData rd = new CallContextRemotingData();
811             rd.LogicalCallID = LogicalCallID;
812             return rd;
813         }
814     }
815  }
816