1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 //+----------------------------------------------------------------------------
7 //
8 // Microsoft Windows
9 // File:        LifetimeServices.cs
10 //
11 // Contents:    Used to obtain a lease <
12 
13 
14 
15 //
16 //+----------------------------------------------------------------------------
17 
18 namespace System.Runtime.Remoting.Lifetime
19 
20 {
21     using System;
22     using System.Threading;
23     using System.Security;
24     using System.Security.Permissions;
25     using System.Runtime.Remoting.Contexts;
26     using System.Runtime.Remoting.Messaging;
27     using System.Globalization;
28 
29         //   access needs to be restricted
30         [System.Security.SecurityCritical]  // auto-generated_required
31         [System.Runtime.InteropServices.ComVisible(true)]
32         public sealed class LifetimeServices
33         {
34             // Set once boolean
35             private static bool s_isLeaseTime = false;
36             private static bool s_isRenewOnCallTime = false;
37             private static bool s_isSponsorshipTimeout = false;
38 
39             // Default values
40             private static long s_leaseTimeTicks = TimeSpan.FromMinutes(5).Ticks;
41             private static long s_renewOnCallTimeTicks = TimeSpan.FromMinutes(2).Ticks;
42             private static long s_sponsorshipTimeoutTicks = TimeSpan.FromMinutes(2).Ticks;
43             private static long s_pollTimeTicks = TimeSpan.FromMilliseconds(10000).Ticks;
44 
GetTimeSpan(ref long ticks)45             private static TimeSpan GetTimeSpan(ref long ticks)
46             {
47                 return TimeSpan.FromTicks(Volatile.Read(ref ticks));
48             }
49 
SetTimeSpan(ref long ticks, TimeSpan value)50             private static void SetTimeSpan(ref long ticks, TimeSpan value)
51             {
52                 Volatile.Write(ref ticks, value.Ticks);
53             }
54 
55             // Testing values
56             //private static TimeSpan s_leaseTimeTicks = TimeSpan.FromSeconds(20).Ticks;
57             //private static TimeSpan s_renewOnCallTimeTicks = TimeSpan.FromSeconds(20).Ticks;
58             //private static TimeSpan s_sponsorshipTimeoutTicks = TimeSpan.FromSeconds(20).Ticks;
59             //private static TimeSpan s_pollTimeTicks = TimeSpan.FromMilliseconds(10000).Ticks;
60 
61             private static Object s_LifetimeSyncObject = null;
62 
63             private static Object LifetimeSyncObject
64             {
65                 get
66                 {
67                     if (s_LifetimeSyncObject == null)
68                     {
69                         Object o = new Object();
70                         Interlocked.CompareExchange(ref s_LifetimeSyncObject, o, null);
71                     }
72                     return s_LifetimeSyncObject;
73                 }
74             }
75 
76             // This should have been a static class, but wasn't as of v3.5.  Clearly, this is
77             // broken.  We'll keep this in V4 for binary compat, but marked obsolete as error
78             // so migrated source code gets fixed.
79             [Obsolete("Do not create instances of the LifetimeServices class.  Call the static methods directly on this type instead", true)]
LifetimeServices()80             public LifetimeServices()
81             {
82                 // Should be a static type - this exists in V4 for binary compatiblity.
83             }
84 
85             // Initial Lease Time span for appdomain
86             public static TimeSpan LeaseTime
87             {
88                 get{ return GetTimeSpan(ref s_leaseTimeTicks); }
89 
90                 [System.Security.SecurityCritical]  // auto-generated
91                 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
92                 set
93                     {
94                         lock(LifetimeSyncObject)
95                             {
96                                 if (s_isLeaseTime)
97                                     throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_SetOnce", "LeaseTime"));
98 
99 
100                                 SetTimeSpan(ref s_leaseTimeTicks, value);
101                                 s_isLeaseTime = true;
102                             }
103                     }
104 
105             }
106 
107             // Initial renew on call time span for appdomain
108             public static TimeSpan RenewOnCallTime
109             {
110                 get{ return GetTimeSpan(ref s_renewOnCallTimeTicks); }
111                 [System.Security.SecurityCritical]  // auto-generated
112                 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
113                 set
114                     {
115                         lock(LifetimeSyncObject)
116                             {
117                                 if (s_isRenewOnCallTime)
118                                     throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_SetOnce", "RenewOnCallTime"));
119 
120 
121                                 SetTimeSpan(ref s_renewOnCallTimeTicks, value);
122                                 s_isRenewOnCallTime = true;
123                             }
124                     }
125 
126             }
127 
128 
129             // Initial sponsorshiptimeout for appdomain
130             public static TimeSpan SponsorshipTimeout
131 
132             {
133                 get{ return GetTimeSpan(ref s_sponsorshipTimeoutTicks); }
134                 [System.Security.SecurityCritical]  // auto-generated
135                 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
136                 set
137                     {
138                         lock(LifetimeSyncObject)
139                             {
140                                 if (s_isSponsorshipTimeout)
141                                     throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_SetOnce", "SponsorshipTimeout"));
142                                 SetTimeSpan(ref s_sponsorshipTimeoutTicks, value);
143                                 s_isSponsorshipTimeout = true;
144                             }
145                     }
146 
147             }
148 
149 
150             // Initial sponsorshiptimeout for appdomain
151             public static TimeSpan LeaseManagerPollTime
152 
153             {
154                 get{ return GetTimeSpan(ref s_pollTimeTicks); }
155                 [System.Security.SecurityCritical]  // auto-generated
156                 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
157                 set
158                     {
159                         lock(LifetimeSyncObject)
160                             {
161                                 SetTimeSpan(ref s_pollTimeTicks, value);
162                                 if (LeaseManager.IsInitialized())
163                                     LeaseManager.GetLeaseManager().ChangePollTime(value);
164                             }
165                     }
166 
167             }
168 
169 
170 
171             [System.Security.SecurityCritical]  // auto-generated
GetLeaseInitial(MarshalByRefObject obj)172             internal static ILease GetLeaseInitial(MarshalByRefObject obj)
173 
174             {
175                 ILease lease = null;
176                 LeaseManager leaseManager = LeaseManager.GetLeaseManager(LeaseManagerPollTime);
177                 lease = (ILease)leaseManager.GetLease(obj);
178                 if (lease == null)
179                     lease = CreateLease(obj);
180                 return lease;
181 
182             }
183 
184 
185             [System.Security.SecurityCritical]  // auto-generated
GetLease(MarshalByRefObject obj)186             internal static ILease GetLease(MarshalByRefObject obj)
187 
188             {
189                 ILease lease = null;
190                 LeaseManager leaseManager = LeaseManager.GetLeaseManager(LeaseManagerPollTime);
191                 lease = (ILease)leaseManager.GetLease(obj);
192                 return lease;
193 
194             }
195 
196 
197 
198 
199             //internal static ILease CreateLease(MarshalByRefObject obj, IMessageSink nextSink)
200 
201             [System.Security.SecurityCritical]  // auto-generated
CreateLease(MarshalByRefObject obj)202             internal static ILease CreateLease(MarshalByRefObject obj)
203 
204             {
205                 return CreateLease(LeaseTime, RenewOnCallTime, SponsorshipTimeout, obj);
206 
207             }
208 
209 
210             [System.Security.SecurityCritical]  // auto-generated
CreateLease(TimeSpan leaseTime, TimeSpan renewOnCallTime, TimeSpan sponsorshipTimeout, MarshalByRefObject obj )211             internal static ILease CreateLease(TimeSpan leaseTime,
212                                                TimeSpan renewOnCallTime,
213                                                TimeSpan sponsorshipTimeout,
214                                                MarshalByRefObject obj
215                                                )
216 
217             {
218                 // Will create leaseManager if not already created.
219                 LeaseManager.GetLeaseManager(LeaseManagerPollTime);
220                 return (ILease)(new Lease(leaseTime, renewOnCallTime, sponsorshipTimeout, obj));
221 
222             }
223 
224         }
225 
226 
227     [Serializable]
228     internal class LeaseLifeTimeServiceProperty : IContextProperty, IContributeObjectSink
229 
230     {
231 
232         public String Name
233 
234         {
235             [System.Security.SecurityCritical]  // auto-generated
236             get {return "LeaseLifeTimeServiceProperty";}
237 
238         }
239 
240 
241         [System.Security.SecurityCritical]  // auto-generated
IsNewContextOK(Context newCtx)242         public bool IsNewContextOK(Context newCtx)
243 
244         {
245             return true;
246 
247         }
248 
249 
250         [System.Security.SecurityCritical]  // auto-generated
Freeze(Context newContext)251         public void Freeze(Context newContext)
252 
253         {
254 
255         }
256 
257 
258         // Initiates the creation of a lease
259 
260         // Creates a sink for invoking a renew on call when an object is created.
261 
262         [System.Security.SecurityCritical]  // auto-generated
GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)263         public IMessageSink GetObjectSink(MarshalByRefObject obj,
264                                           IMessageSink nextSink)
265 
266         {
267             bool fServer;
268             ServerIdentity identity = (ServerIdentity)MarshalByRefObject.GetIdentity(obj, out fServer);
269             BCLDebug.Assert(identity != null, "[LifetimeServices.GetObjectSink] identity != null");
270 
271             // NOTE: Single Call objects do not have a lease associated with it because they last
272             // only for the duration of the call.
273             // Singleton objects on the other hand do have leases associated with them and they can
274             // be garbage collected.
275             if (identity.IsSingleCall())
276             {
277                 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, no lease SingleCall",obj,", NextSink "+nextSink);
278                 return nextSink;
279             }
280 
281 
282 
283             // Create lease. InitializeLifetimeService is a virtual method which can be overridded so that a lease with
284             // object specific properties can be created.
285             Object leaseObj = obj.InitializeLifetimeService();
286 
287 
288             BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, return from InitializeLifetimeService obj ",obj,", lease ",leaseObj);
289 
290 
291             // InitializeLifetimeService can return a lease in one of conditions:
292             // 1) the lease has a null state which specifies that no lease is to be created.
293             // 2) the lease has an initial state which specifies that InitializeLifeTimeService has created a new lease.
294             // 3) the lease has another state which indicates that the lease has already been created and registered.
295 
296 
297             if (leaseObj == null)
298                 {
299                     BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, no lease ",obj,", NextSink "+nextSink);
300                     return nextSink;
301                 }
302 
303             if (!(leaseObj is System.Runtime.Remoting.Lifetime.ILease))
304                 throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_ILeaseReturn", leaseObj));
305 
306             ILease ilease = (ILease)leaseObj;
307 
308             if (ilease.InitialLeaseTime.CompareTo(TimeSpan.Zero) <= 0)
309                 {
310                     // No lease
311                     {
312                         BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, no lease because InitialLeaseTime is Zero ",obj);
313                         if (ilease is System.Runtime.Remoting.Lifetime.Lease)
314                             {
315                                 ((Lease)ilease).Remove();
316                             }
317                         return nextSink;
318                     }
319                 }
320 
321 
322             Lease lease = null;
323             lock(identity)
324                 {
325                     if (identity.Lease != null)
326                         {
327                             // Lease already exists for object, object is being marsalled again
328                             BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, Lease already exists for object ",obj);
329                             lease = (Lease)identity.Lease;
330                             lease.Renew(lease.InitialLeaseTime); // Reset initial lease time
331                         }
332                     else
333                         {
334                             // New lease
335                             if (!(ilease is System.Runtime.Remoting.Lifetime.Lease))
336                                 {
337                                     // InitializeLifetimeService created its own ILease object
338                                     // Need to create a System.Runtime.Remoting.Lease object
339                                     BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, New Lease, lease not of type Lease  ",obj);
340                                     lease = (Lease)LifetimeServices.GetLeaseInitial(obj);
341                                     if (lease.CurrentState == LeaseState.Initial)
342                                         {
343                                             lease.InitialLeaseTime = ilease.InitialLeaseTime;
344                                             lease.RenewOnCallTime = ilease.RenewOnCallTime;
345                                             lease.SponsorshipTimeout = ilease.SponsorshipTimeout;
346                                         }
347                                 }
348                             else
349                                 {
350                                     // An object of Type Lease was created
351                                     BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, New Lease, lease is type Lease  ",obj);
352                                     lease = (Lease)ilease;
353                                 }
354 
355                             // Put lease in active state
356                             // Creation phase of lease is over, properties can no longer be set on lease.
357                             identity.Lease = lease; // Place lease into identity for object
358                             // If the object has been marshaled activate
359                             // the lease
360                             if (identity.ObjectRef != null)
361                             {
362                                 lease.ActivateLease();
363                             }
364                         }
365                 }
366 
367 
368             if (lease.RenewOnCallTime > TimeSpan.Zero)
369                 {
370                     // RenewOnCall create sink
371                     BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, lease created ",obj);
372                     return new LeaseSink(lease, nextSink);
373                 }
374             else
375                 {
376                     // No RenewOnCall so no sink created
377                     BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, No RenewOnCall so no sink created ",obj);
378                     return nextSink;
379                 }
380 
381         }
382 
383     }
384 
385 }
386 
387