2 // ClientSessionCache.cs: Client-side cache for re-using sessions
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // Copyright (C) 2006 Novell (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections;
32 namespace Mono.Security.Protocol.Tls {
34 internal class ClientSessionInfo : IDisposable {
36 // we keep this item valid for 3 minutes (if unused)
37 private const int ValidityInterval = 3 * 60;
39 private bool disposed;
40 private DateTime validuntil;
43 // see RFC2246 - Section 7
45 private byte[] masterSecret;
47 public ClientSessionInfo (string hostname, byte[] id)
60 public string HostName {
69 get { return (validuntil > DateTime.UtcNow); }
73 public void GetContext (Context context)
76 masterSecret = (byte[]) context.MasterSecret.Clone ();
79 public void SetContext (Context context)
82 context.MasterSecret = (byte[]) masterSecret.Clone ();
85 public void KeepAlive ()
88 validuntil = DateTime.UtcNow.AddSeconds (ValidityInterval);
91 public void Dispose ()
94 GC.SuppressFinalize (this);
97 private void Dispose (bool disposing)
100 validuntil = DateTime.MinValue;
104 if (masterSecret != null) {
105 Array.Clear (masterSecret, 0, masterSecret.Length);
112 private void CheckDisposed ()
115 string msg = Locale.GetText ("Cache session information were disposed.");
116 throw new ObjectDisposedException (msg);
121 // note: locking is aggressive but isn't used often (and we gain much more :)
122 internal class ClientSessionCache {
124 static Hashtable cache;
125 static object locker;
127 static ClientSessionCache ()
129 cache = new Hashtable ();
130 locker = new object ();
133 // note: we may have multiple connections with a host, so
134 // possibly multiple entries per host (each with a different
135 // id), so we do not use the host as the hashtable key
136 static public void Add (string host, byte[] id)
139 string uid = BitConverter.ToString (id);
140 ClientSessionInfo si = (ClientSessionInfo) cache[uid];
142 cache.Add (uid, new ClientSessionInfo (host, id));
143 } else if (si.HostName == host) {
144 // we already have this and it's still valid
145 // on the server, so we'll keep it a little longer
148 // it's very unlikely but the same session id
149 // could be used by more than one host. In this
150 // case we replace the older one with the new one
153 cache.Add (uid, new ClientSessionInfo (host, id));
158 // return the first session us
159 static public byte[] FromHost (string host)
162 foreach (ClientSessionInfo si in cache.Values) {
163 if (si.HostName == host) {
165 // ensure it's still valid when we really need it
175 // only called inside the lock
176 static private ClientSessionInfo FromContext (Context context)
181 byte[] id = context.SessionId;
182 if ((id == null) || (id.Length == 0))
185 // do we have a session cached for this host ?
186 string uid = BitConverter.ToString (id);
188 ClientSessionInfo si = (ClientSessionInfo) cache[uid];
192 // In the unlikely case of multiple hosts using the same
193 // session id, we just act like we do not know about it
194 if (context.ClientSettings.TargetHost != si.HostName)
197 // yes, so what's its status ?
208 static public bool SetContextInCache (Context context)
211 ClientSessionInfo csi = FromContext (context);
215 csi.GetContext (context);
221 static public bool SetContextFromCache (Context context)
224 ClientSessionInfo csi = FromContext (context);
228 csi.SetContext (context);