Code:
/ FXUpdate3074 / FXUpdate3074 / 1.1 / DEVDIV / depot / DevDiv / releases / whidbey / QFE / ndp / fx / src / xsp / System / Web / State / OutOfProcStateClientManager.cs / 3 / OutOfProcStateClientManager.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.SessionState { using System.Collections; using System.Configuration; using System.Web.Configuration; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Web; using System.Web.Caching; using System.Web.Util; using System.Xml; using System.Collections.Specialized; using System.Configuration.Provider; using System.Globalization; using System.Web.Management; using System.Web.Hosting; internal sealed class OutOfProcSessionStateStore : SessionStateStoreProviderBase { internal static readonly IntPtr INVALID_SOCKET = UnsafeNativeMethods.INVALID_HANDLE_VALUE; internal static readonly int WHIDBEY_MAJOR_VERSION = 2; internal const int STATE_NETWORK_TIMEOUT_DEFAULT = 10; // in sec static string s_uribase; static int s_networkTimeout; #pragma warning disable 0649 static ReadWriteSpinLock s_lock; #pragma warning restore 0649 static bool s_oneTimeInited; static StateServerPartitionInfo s_singlePartitionInfo; static PartitionManager s_partitionManager; static bool s_usePartition; static EventHandler s_onAppDomainUnload; // We keep these info because we don't want to hold on to the config object. static string s_configPartitionResolverType; static string s_configStateConnectionString; static string s_configStateConnectionStringFileName; static int s_configStateConnectionStringLineNumber; // Per request info IPartitionResolver _partitionResolver; StateServerPartitionInfo _partitionInfo; internal override void Initialize(string name, NameValueCollection config, IPartitionResolver partitionResolver) { _partitionResolver = partitionResolver; Initialize(name, config); } public override void Initialize(string name, NameValueCollection config) { if (String.IsNullOrEmpty(name)) name = "State Server Session State Provider"; base.Initialize(name, config); if (!s_oneTimeInited) { s_lock.AcquireWriterLock(); try { if (!s_oneTimeInited) { OneTimeInit(); } } finally { s_lock.ReleaseWriterLock(); } } if (!s_usePartition) { // For single partition, the connection info won't change from request to request Debug.Assert(s_partitionManager == null); _partitionInfo = s_singlePartitionInfo; } } void OneTimeInit() { SessionStateSection config = RuntimeConfig.GetAppConfig().SessionState; s_configPartitionResolverType = config.PartitionResolverType; s_configStateConnectionString = config.StateConnectionString; s_configStateConnectionStringFileName = config.ElementInformation.Properties["stateConnectionString"].Source; s_configStateConnectionStringLineNumber = config.ElementInformation.Properties["stateConnectionString"].LineNumber; if (_partitionResolver == null) { String stateConnectionString = config.StateConnectionString; SessionStateModule.ReadConnectionString(config, ref stateConnectionString, "stateConnectionString"); s_singlePartitionInfo = (StateServerPartitionInfo)CreatePartitionInfo(stateConnectionString); } else { s_usePartition = true; s_partitionManager = new PartitionManager(new CreatePartitionInfo(CreatePartitionInfo)); } s_networkTimeout = (int)config.StateNetworkTimeout.TotalSeconds; string appId = HttpRuntime.AppDomainAppIdInternal; string idHash = MachineKeySection.HashAndBase64EncodeString(appId); // Make sure that we have a absolute URI, some hosts(Cassini) don't provide this. if (appId.StartsWith("/", StringComparison.Ordinal)) { s_uribase = appId + "(" + idHash + ")/"; } else { s_uribase = "/" + appId + "(" + idHash + ")/"; } // We only need to do this in one instance s_onAppDomainUnload = new EventHandler(OnAppDomainUnload); Thread.GetDomain().DomainUnload += s_onAppDomainUnload; s_oneTimeInited = true; } void OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs) { Debug.Trace("OutOfProcSessionStateStore", "OnAppDomainUnload called"); Thread.GetDomain().DomainUnload -= s_onAppDomainUnload; if (_partitionResolver == null) { if (s_singlePartitionInfo != null) { s_singlePartitionInfo.Dispose(); } } else { if (s_partitionManager != null) { s_partitionManager.Dispose(); } } } internal IPartitionInfo CreatePartitionInfo(string stateConnectionString) { string server; int port; int hr; try { /* * stateConnection string has the following format: * * "tcpip=: " */ string [] parts = stateConnectionString.Split(new char[] {'='}); if (parts.Length != 2 || parts[0] != "tcpip") { throw new ArgumentException("stateConnectionString"); } parts = parts[1].Split(new char[] {':'}); if (parts.Length != 2) { throw new ArgumentException("stateConnectionString"); } server = parts[0]; port = (int) System.UInt16.Parse(parts[1], CultureInfo.InvariantCulture); // At v1, we won't accept server name that has non-ascii characters for (int i = 0; i < server.Length; ++i) { if (server[i] > 0x7F) { throw new ArgumentException("stateConnectionString"); } } } catch { if (s_usePartition) { throw new HttpException( SR.GetString(SR.Error_parsing_state_server_partition_resolver_string, s_configPartitionResolverType)); } else { throw new ConfigurationErrorsException( SR.GetString(SR.Invalid_value_for_sessionstate_stateConnectionString, s_configStateConnectionString), s_configStateConnectionStringFileName, s_configStateConnectionStringLineNumber); } } hr = UnsafeNativeMethods.SessionNDConnectToService(server); if (hr != 0) { throw CreateConnectionException(server, port, hr); } return new StateServerPartitionInfo(new ResourcePool(new TimeSpan(0, 0, 5), int.MaxValue), server, port); } internal static HttpException CreateConnectionException(string server, int port, int hr) { if (s_usePartition) { return new HttpException( SR.GetString(SR.Cant_make_session_request_partition_resolver, s_configPartitionResolverType, server, port.ToString(CultureInfo.InvariantCulture)), hr); } else { return new HttpException( SR.GetString(SR.Cant_make_session_request), hr); } } public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) { return false; } public override void Dispose() { } public override void InitializeRequest(HttpContext context) { if (s_usePartition) { // For multiple partition case, the connection info can change from request to request Debug.Assert(_partitionResolver != null); _partitionInfo = null; } } void MakeRequest( UnsafeNativeMethods.StateProtocolVerb verb, String id, UnsafeNativeMethods.StateProtocolExclusive exclusiveAccess, int extraFlags, int timeout, int lockCookie, byte[] buf, int cb, int networkTimeout, out UnsafeNativeMethods.SessionNDMakeRequestResults results) { int hr; string uri; OutOfProcConnection conn = null; HandleRef socketHandle; bool checkVersion = false; Debug.Assert(timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES"); SessionIDManager.CheckIdLength(id, true /* throwOnFail */); if (_partitionInfo == null) { Debug.Assert(s_partitionManager != null); Debug.Assert(_partitionResolver != null); _partitionInfo = (StateServerPartitionInfo)s_partitionManager.GetPartition(_partitionResolver, id); // If its still null, we give up if (_partitionInfo == null) { throw new HttpException(SR.GetString(SR.Bad_partition_resolver_connection_string, "PartitionManager")); } } // Need to make sure we dispose the connection if anything goes wrong try { conn = (OutOfProcConnection)_partitionInfo.RetrieveResource(); if (conn != null) { socketHandle = new HandleRef(this, conn._socketHandle.Handle); } else { socketHandle = new HandleRef(this, INVALID_SOCKET); } if (_partitionInfo.StateServerVersion == -1) { // We don't need locking here because it's okay to have two // requests initializing s_stateServerVersion. checkVersion = true; } Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "Calling MakeRequest, " + "socket=" + (IntPtr)socketHandle.Handle + "verb=" + verb + " id=" + id + " exclusiveAccess=" + exclusiveAccess + " timeout=" + timeout + " buf=" + ((buf != null) ? "non-null" : "null") + " cb=" + cb + " checkVersion=" + checkVersion + " extraFlags=" + extraFlags); // Have to UrlEncode id because it may contain non-URL-safe characters uri = HttpUtility.UrlEncode(s_uribase + id); hr = UnsafeNativeMethods.SessionNDMakeRequest( socketHandle, _partitionInfo.Server, _partitionInfo.Port, networkTimeout, verb, uri, exclusiveAccess, extraFlags, timeout, lockCookie, buf, cb, checkVersion, out results); Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "MakeRequest returned: " + "hr=" + hr + " socket=" + (IntPtr)results.socket + " httpstatus=" + results.httpStatus + " timeout=" + results.timeout + " contentlength=" + results.contentLength + " uri=" + (IntPtr)results.content + " lockCookie=" + results.lockCookie + " lockDate=" + string.Format("{0:x}", results.lockDate) + " lockAge=" + results.lockAge + " stateServerMajVer=" + results.stateServerMajVer + " actionFlags=" + results.actionFlags); if (conn != null) { if (results.socket == INVALID_SOCKET) { conn.Detach(); conn = null; } else if (results.socket != socketHandle.Handle) { // The original socket is no good. We've got a new one. // Pleae conn._socketHandle = new HandleRef(this, results.socket); } } else if (results.socket != INVALID_SOCKET) { conn = new OutOfProcConnection(results.socket); } if (conn != null) { _partitionInfo.StoreResource(conn); } } catch { // We just need to dispose the connection if anything bad happened if (conn != null) { conn.Dispose(); } throw; } if (hr != 0) { HttpException e = CreateConnectionException(_partitionInfo.Server, _partitionInfo.Port, hr); string phase = null; switch (results.lastPhase) { case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Initialization: phase = SR.GetString(SR.State_Server_detailed_error_phase0); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Connecting: phase = SR.GetString(SR.State_Server_detailed_error_phase1); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.SendingRequest: phase = SR.GetString(SR.State_Server_detailed_error_phase2); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.ReadingResponse: phase = SR.GetString(SR.State_Server_detailed_error_phase3); break; default: Debug.Assert(false, "Unknown results.lastPhase: " + results.lastPhase); break; } WebBaseEvent.RaiseSystemEvent(SR.GetString( SR.State_Server_detailed_error, phase, "0x" + hr.ToString("X08", CultureInfo.InvariantCulture), cb.ToString(CultureInfo.InvariantCulture)), this, WebEventCodes.WebErrorOtherError, WebEventCodes.StateServerConnectionError, e); throw e; } if (results.httpStatus == 400) { if (s_usePartition) { throw new HttpException( SR.GetString(SR.Bad_state_server_request_partition_resolver, s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture))); } else { throw new HttpException( SR.GetString(SR.Bad_state_server_request)); } } if (checkVersion) { _partitionInfo.StateServerVersion = results.stateServerMajVer; if (_partitionInfo.StateServerVersion < WHIDBEY_MAJOR_VERSION) { // We won't work with versions lower than Whidbey if (s_usePartition) { throw new HttpException( SR.GetString(SR.Need_v2_State_Server_partition_resolver, s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture))); } else { throw new HttpException( SR.GetString(SR.Need_v2_State_Server)); } } } } internal SessionStateStoreData DoGet(HttpContext context, String id, UnsafeNativeMethods.StateProtocolExclusive exclusiveAccess, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { SessionStateStoreData item = null; UnmanagedMemoryStream stream; int contentLength; UnsafeNativeMethods.SessionNDMakeRequestResults results; // Set default return values locked = false; lockId = null; lockAge = TimeSpan.Zero; actionFlags = 0; results.content = IntPtr.Zero; try { MakeRequest(UnsafeNativeMethods.StateProtocolVerb.GET, id, exclusiveAccess, 0, 0, 0, null, 0, s_networkTimeout, out results); switch (results.httpStatus) { case 200: /* item found, deserialize it */ contentLength = results.contentLength; if (contentLength > 0) { unsafe { stream = new UnmanagedMemoryStream((byte*)results.content, contentLength); } item = SessionStateUtility.Deserialize(context, stream); stream.Close(); lockId = results.lockCookie; actionFlags = (SessionStateActions) results.actionFlags; } break; case 423: /* state locked, return lock information */ if (0 <= results.lockAge) { if (results.lockAge < Sec.ONE_YEAR) { lockAge = new TimeSpan(0, 0, results.lockAge); } else { lockAge = TimeSpan.Zero; } } else { DateTime now = DateTime.Now; if (0 < results.lockDate && results.lockDate < now.Ticks) { lockAge = now - new DateTime(results.lockDate); } else { lockAge = TimeSpan.Zero; } } locked = true; lockId = results.lockCookie; Debug.Assert((results.actionFlags & (int)SessionStateActions.InitializeItem) == 0, "(results.actionFlags & (int)SessionStateActions.InitializeItem) == 0; uninitialized item cannot be locked"); break; } } finally { if (results.content != IntPtr.Zero) { UnsafeNativeMethods.SessionNDFreeBody(new HandleRef(this, results.content)); } } return item; } public override SessionStateStoreData GetItem(HttpContext context, String id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { Debug.Trace("OutOfProcSessionStateStore", "Calling Get, id=" + id); return DoGet(context, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, out locked, out lockAge, out lockId, out actionFlags); } public override SessionStateStoreData GetItemExclusive(HttpContext context, String id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { Debug.Trace("OutOfProcSessionStateStore", "Calling GetExlusive, id=" + id); return DoGet(context, id, UnsafeNativeMethods.StateProtocolExclusive.ACQUIRE, out locked, out lockAge, out lockId, out actionFlags); } public override void ReleaseItemExclusive(HttpContext context, String id, object lockId) { Debug.Assert(lockId != null, "lockId != null"); UnsafeNativeMethods.SessionNDMakeRequestResults results; int lockCookie = (int)lockId; Debug.Trace("OutOfProcSessionStateStore", "Calling ReleaseExclusive, id=" + id); MakeRequest(UnsafeNativeMethods.StateProtocolVerb.GET, id, UnsafeNativeMethods.StateProtocolExclusive.RELEASE, 0, 0, lockCookie, null, 0, s_networkTimeout, out results); } public override void SetAndReleaseItemExclusive(HttpContext context, String id, SessionStateStoreData item, object lockId, bool newItem) { UnsafeNativeMethods.SessionNDMakeRequestResults results; byte[] buf; int length; int lockCookie; Debug.Assert(item.Items != null, "item.Items != null"); Debug.Assert(item.StaticObjects != null, "item.StaticObjects != null"); Debug.Trace("OutOfProcSessionStateStore", "Calling Set, id=" + id + " sessionItems=" + item.Items + " timeout=" + item.Timeout); try { SessionStateUtility.SerializeStoreData(item, 0, out buf, out length); } catch { if (!newItem) { ((SessionStateStoreProviderBase)this).ReleaseItemExclusive(context, id, lockId); } throw; } // Save it to the store if (lockId == null) { lockCookie = 0; } else { lockCookie = (int)lockId; } MakeRequest(UnsafeNativeMethods.StateProtocolVerb.PUT, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, 0, item.Timeout, lockCookie, buf, length, s_networkTimeout, out results); } public override void RemoveItem(HttpContext context, String id, object lockId, SessionStateStoreData item) { Debug.Assert(lockId != null, "lockId != null"); Debug.Trace("OutOfProcSessionStateStore", "Calling Remove, id=" + id); UnsafeNativeMethods.SessionNDMakeRequestResults results; int lockCookie = (int)lockId; MakeRequest(UnsafeNativeMethods.StateProtocolVerb.DELETE, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, 0, 0, lockCookie, null, 0, s_networkTimeout, out results); } public override void ResetItemTimeout(HttpContext context, String id) { UnsafeNativeMethods.SessionNDMakeRequestResults results; Debug.Trace("OutOfProcSessionStateStore", "Calling ResetTimeout, id=" + id); MakeRequest(UnsafeNativeMethods.StateProtocolVerb.HEAD, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, 0, 0, 0, null, 0, s_networkTimeout, out results); } public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout) { Debug.Assert(timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES"); return SessionStateUtility.CreateLegitStoreData(context, null, null, timeout); } public override void CreateUninitializedItem(HttpContext context, String id, int timeout) { UnsafeNativeMethods.SessionNDMakeRequestResults results; byte[] buf; int length; Debug.Trace("OutOfProcSessionStateStore", "Calling CreateUninitializedItem, id=" + id + " timeout=" + timeout); // Create an empty item SessionStateUtility.SerializeStoreData(CreateNewStoreData(context, timeout), 0, out buf, out length); // Save it to the store MakeRequest(UnsafeNativeMethods.StateProtocolVerb.PUT, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, (int)SessionStateItemFlags.Uninitialized, timeout, 0, buf, length, s_networkTimeout, out results); } // Called during EndRequest event public override void EndRequest(HttpContext context) { } class StateServerPartitionInfo : PartitionInfo { string _server; int _port; int _stateServerVersion; internal StateServerPartitionInfo(ResourcePool rpool, string server, int port) : base(rpool) { _server = server; _port = port; _stateServerVersion = -1; Debug.Trace("PartitionInfo", "Created a new info, server=" + server + ", port=" + port); } internal string Server { get { return _server; } } internal int Port { get { return _port; } } internal int StateServerVersion { get { return _stateServerVersion; } set { _stateServerVersion = value; } } protected override string TracingPartitionString { get { return Server + ":" + Port; } } } class OutOfProcConnection : IDisposable { internal HandleRef _socketHandle; internal OutOfProcConnection(IntPtr socket) { Debug.Assert(socket != OutOfProcSessionStateStore.INVALID_SOCKET, "socket != OutOfProcSessionStateStore.INVALID_SOCKET"); _socketHandle = new HandleRef(this, socket); PerfCounters.IncrementCounter(AppPerfCounter.SESSION_STATE_SERVER_CONNECTIONS); } ~OutOfProcConnection() { Dispose(false); } public void Dispose() { Debug.Trace("ResourcePool", "Disposing OutOfProcConnection"); Dispose(true); System.GC.SuppressFinalize(this); } private void Dispose(bool dummy) { if (_socketHandle.Handle != OutOfProcSessionStateStore.INVALID_SOCKET) { UnsafeNativeMethods.SessionNDCloseConnection(_socketHandle); _socketHandle = new HandleRef(this, OutOfProcSessionStateStore.INVALID_SOCKET); PerfCounters.DecrementCounter(AppPerfCounter.SESSION_STATE_SERVER_CONNECTIONS); } } internal void Detach() { _socketHandle = new HandleRef(this, OutOfProcSessionStateStore.INVALID_SOCKET); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.SessionState { using System.Collections; using System.Configuration; using System.Web.Configuration; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Web; using System.Web.Caching; using System.Web.Util; using System.Xml; using System.Collections.Specialized; using System.Configuration.Provider; using System.Globalization; using System.Web.Management; using System.Web.Hosting; internal sealed class OutOfProcSessionStateStore : SessionStateStoreProviderBase { internal static readonly IntPtr INVALID_SOCKET = UnsafeNativeMethods.INVALID_HANDLE_VALUE; internal static readonly int WHIDBEY_MAJOR_VERSION = 2; internal const int STATE_NETWORK_TIMEOUT_DEFAULT = 10; // in sec static string s_uribase; static int s_networkTimeout; #pragma warning disable 0649 static ReadWriteSpinLock s_lock; #pragma warning restore 0649 static bool s_oneTimeInited; static StateServerPartitionInfo s_singlePartitionInfo; static PartitionManager s_partitionManager; static bool s_usePartition; static EventHandler s_onAppDomainUnload; // We keep these info because we don't want to hold on to the config object. static string s_configPartitionResolverType; static string s_configStateConnectionString; static string s_configStateConnectionStringFileName; static int s_configStateConnectionStringLineNumber; // Per request info IPartitionResolver _partitionResolver; StateServerPartitionInfo _partitionInfo; internal override void Initialize(string name, NameValueCollection config, IPartitionResolver partitionResolver) { _partitionResolver = partitionResolver; Initialize(name, config); } public override void Initialize(string name, NameValueCollection config) { if (String.IsNullOrEmpty(name)) name = "State Server Session State Provider"; base.Initialize(name, config); if (!s_oneTimeInited) { s_lock.AcquireWriterLock(); try { if (!s_oneTimeInited) { OneTimeInit(); } } finally { s_lock.ReleaseWriterLock(); } } if (!s_usePartition) { // For single partition, the connection info won't change from request to request Debug.Assert(s_partitionManager == null); _partitionInfo = s_singlePartitionInfo; } } void OneTimeInit() { SessionStateSection config = RuntimeConfig.GetAppConfig().SessionState; s_configPartitionResolverType = config.PartitionResolverType; s_configStateConnectionString = config.StateConnectionString; s_configStateConnectionStringFileName = config.ElementInformation.Properties["stateConnectionString"].Source; s_configStateConnectionStringLineNumber = config.ElementInformation.Properties["stateConnectionString"].LineNumber; if (_partitionResolver == null) { String stateConnectionString = config.StateConnectionString; SessionStateModule.ReadConnectionString(config, ref stateConnectionString, "stateConnectionString"); s_singlePartitionInfo = (StateServerPartitionInfo)CreatePartitionInfo(stateConnectionString); } else { s_usePartition = true; s_partitionManager = new PartitionManager(new CreatePartitionInfo(CreatePartitionInfo)); } s_networkTimeout = (int)config.StateNetworkTimeout.TotalSeconds; string appId = HttpRuntime.AppDomainAppIdInternal; string idHash = MachineKeySection.HashAndBase64EncodeString(appId); // Make sure that we have a absolute URI, some hosts(Cassini) don't provide this. if (appId.StartsWith("/", StringComparison.Ordinal)) { s_uribase = appId + "(" + idHash + ")/"; } else { s_uribase = "/" + appId + "(" + idHash + ")/"; } // We only need to do this in one instance s_onAppDomainUnload = new EventHandler(OnAppDomainUnload); Thread.GetDomain().DomainUnload += s_onAppDomainUnload; s_oneTimeInited = true; } void OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs) { Debug.Trace("OutOfProcSessionStateStore", "OnAppDomainUnload called"); Thread.GetDomain().DomainUnload -= s_onAppDomainUnload; if (_partitionResolver == null) { if (s_singlePartitionInfo != null) { s_singlePartitionInfo.Dispose(); } } else { if (s_partitionManager != null) { s_partitionManager.Dispose(); } } } internal IPartitionInfo CreatePartitionInfo(string stateConnectionString) { string server; int port; int hr; try { /* * stateConnection string has the following format: * * "tcpip=: " */ string [] parts = stateConnectionString.Split(new char[] {'='}); if (parts.Length != 2 || parts[0] != "tcpip") { throw new ArgumentException("stateConnectionString"); } parts = parts[1].Split(new char[] {':'}); if (parts.Length != 2) { throw new ArgumentException("stateConnectionString"); } server = parts[0]; port = (int) System.UInt16.Parse(parts[1], CultureInfo.InvariantCulture); // At v1, we won't accept server name that has non-ascii characters for (int i = 0; i < server.Length; ++i) { if (server[i] > 0x7F) { throw new ArgumentException("stateConnectionString"); } } } catch { if (s_usePartition) { throw new HttpException( SR.GetString(SR.Error_parsing_state_server_partition_resolver_string, s_configPartitionResolverType)); } else { throw new ConfigurationErrorsException( SR.GetString(SR.Invalid_value_for_sessionstate_stateConnectionString, s_configStateConnectionString), s_configStateConnectionStringFileName, s_configStateConnectionStringLineNumber); } } hr = UnsafeNativeMethods.SessionNDConnectToService(server); if (hr != 0) { throw CreateConnectionException(server, port, hr); } return new StateServerPartitionInfo(new ResourcePool(new TimeSpan(0, 0, 5), int.MaxValue), server, port); } internal static HttpException CreateConnectionException(string server, int port, int hr) { if (s_usePartition) { return new HttpException( SR.GetString(SR.Cant_make_session_request_partition_resolver, s_configPartitionResolverType, server, port.ToString(CultureInfo.InvariantCulture)), hr); } else { return new HttpException( SR.GetString(SR.Cant_make_session_request), hr); } } public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) { return false; } public override void Dispose() { } public override void InitializeRequest(HttpContext context) { if (s_usePartition) { // For multiple partition case, the connection info can change from request to request Debug.Assert(_partitionResolver != null); _partitionInfo = null; } } void MakeRequest( UnsafeNativeMethods.StateProtocolVerb verb, String id, UnsafeNativeMethods.StateProtocolExclusive exclusiveAccess, int extraFlags, int timeout, int lockCookie, byte[] buf, int cb, int networkTimeout, out UnsafeNativeMethods.SessionNDMakeRequestResults results) { int hr; string uri; OutOfProcConnection conn = null; HandleRef socketHandle; bool checkVersion = false; Debug.Assert(timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES"); SessionIDManager.CheckIdLength(id, true /* throwOnFail */); if (_partitionInfo == null) { Debug.Assert(s_partitionManager != null); Debug.Assert(_partitionResolver != null); _partitionInfo = (StateServerPartitionInfo)s_partitionManager.GetPartition(_partitionResolver, id); // If its still null, we give up if (_partitionInfo == null) { throw new HttpException(SR.GetString(SR.Bad_partition_resolver_connection_string, "PartitionManager")); } } // Need to make sure we dispose the connection if anything goes wrong try { conn = (OutOfProcConnection)_partitionInfo.RetrieveResource(); if (conn != null) { socketHandle = new HandleRef(this, conn._socketHandle.Handle); } else { socketHandle = new HandleRef(this, INVALID_SOCKET); } if (_partitionInfo.StateServerVersion == -1) { // We don't need locking here because it's okay to have two // requests initializing s_stateServerVersion. checkVersion = true; } Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "Calling MakeRequest, " + "socket=" + (IntPtr)socketHandle.Handle + "verb=" + verb + " id=" + id + " exclusiveAccess=" + exclusiveAccess + " timeout=" + timeout + " buf=" + ((buf != null) ? "non-null" : "null") + " cb=" + cb + " checkVersion=" + checkVersion + " extraFlags=" + extraFlags); // Have to UrlEncode id because it may contain non-URL-safe characters uri = HttpUtility.UrlEncode(s_uribase + id); hr = UnsafeNativeMethods.SessionNDMakeRequest( socketHandle, _partitionInfo.Server, _partitionInfo.Port, networkTimeout, verb, uri, exclusiveAccess, extraFlags, timeout, lockCookie, buf, cb, checkVersion, out results); Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "MakeRequest returned: " + "hr=" + hr + " socket=" + (IntPtr)results.socket + " httpstatus=" + results.httpStatus + " timeout=" + results.timeout + " contentlength=" + results.contentLength + " uri=" + (IntPtr)results.content + " lockCookie=" + results.lockCookie + " lockDate=" + string.Format("{0:x}", results.lockDate) + " lockAge=" + results.lockAge + " stateServerMajVer=" + results.stateServerMajVer + " actionFlags=" + results.actionFlags); if (conn != null) { if (results.socket == INVALID_SOCKET) { conn.Detach(); conn = null; } else if (results.socket != socketHandle.Handle) { // The original socket is no good. We've got a new one. // Pleae conn._socketHandle = new HandleRef(this, results.socket); } } else if (results.socket != INVALID_SOCKET) { conn = new OutOfProcConnection(results.socket); } if (conn != null) { _partitionInfo.StoreResource(conn); } } catch { // We just need to dispose the connection if anything bad happened if (conn != null) { conn.Dispose(); } throw; } if (hr != 0) { HttpException e = CreateConnectionException(_partitionInfo.Server, _partitionInfo.Port, hr); string phase = null; switch (results.lastPhase) { case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Initialization: phase = SR.GetString(SR.State_Server_detailed_error_phase0); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Connecting: phase = SR.GetString(SR.State_Server_detailed_error_phase1); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.SendingRequest: phase = SR.GetString(SR.State_Server_detailed_error_phase2); break; case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.ReadingResponse: phase = SR.GetString(SR.State_Server_detailed_error_phase3); break; default: Debug.Assert(false, "Unknown results.lastPhase: " + results.lastPhase); break; } WebBaseEvent.RaiseSystemEvent(SR.GetString( SR.State_Server_detailed_error, phase, "0x" + hr.ToString("X08", CultureInfo.InvariantCulture), cb.ToString(CultureInfo.InvariantCulture)), this, WebEventCodes.WebErrorOtherError, WebEventCodes.StateServerConnectionError, e); throw e; } if (results.httpStatus == 400) { if (s_usePartition) { throw new HttpException( SR.GetString(SR.Bad_state_server_request_partition_resolver, s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture))); } else { throw new HttpException( SR.GetString(SR.Bad_state_server_request)); } } if (checkVersion) { _partitionInfo.StateServerVersion = results.stateServerMajVer; if (_partitionInfo.StateServerVersion < WHIDBEY_MAJOR_VERSION) { // We won't work with versions lower than Whidbey if (s_usePartition) { throw new HttpException( SR.GetString(SR.Need_v2_State_Server_partition_resolver, s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture))); } else { throw new HttpException( SR.GetString(SR.Need_v2_State_Server)); } } } } internal SessionStateStoreData DoGet(HttpContext context, String id, UnsafeNativeMethods.StateProtocolExclusive exclusiveAccess, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { SessionStateStoreData item = null; UnmanagedMemoryStream stream; int contentLength; UnsafeNativeMethods.SessionNDMakeRequestResults results; // Set default return values locked = false; lockId = null; lockAge = TimeSpan.Zero; actionFlags = 0; results.content = IntPtr.Zero; try { MakeRequest(UnsafeNativeMethods.StateProtocolVerb.GET, id, exclusiveAccess, 0, 0, 0, null, 0, s_networkTimeout, out results); switch (results.httpStatus) { case 200: /* item found, deserialize it */ contentLength = results.contentLength; if (contentLength > 0) { unsafe { stream = new UnmanagedMemoryStream((byte*)results.content, contentLength); } item = SessionStateUtility.Deserialize(context, stream); stream.Close(); lockId = results.lockCookie; actionFlags = (SessionStateActions) results.actionFlags; } break; case 423: /* state locked, return lock information */ if (0 <= results.lockAge) { if (results.lockAge < Sec.ONE_YEAR) { lockAge = new TimeSpan(0, 0, results.lockAge); } else { lockAge = TimeSpan.Zero; } } else { DateTime now = DateTime.Now; if (0 < results.lockDate && results.lockDate < now.Ticks) { lockAge = now - new DateTime(results.lockDate); } else { lockAge = TimeSpan.Zero; } } locked = true; lockId = results.lockCookie; Debug.Assert((results.actionFlags & (int)SessionStateActions.InitializeItem) == 0, "(results.actionFlags & (int)SessionStateActions.InitializeItem) == 0; uninitialized item cannot be locked"); break; } } finally { if (results.content != IntPtr.Zero) { UnsafeNativeMethods.SessionNDFreeBody(new HandleRef(this, results.content)); } } return item; } public override SessionStateStoreData GetItem(HttpContext context, String id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { Debug.Trace("OutOfProcSessionStateStore", "Calling Get, id=" + id); return DoGet(context, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, out locked, out lockAge, out lockId, out actionFlags); } public override SessionStateStoreData GetItemExclusive(HttpContext context, String id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags) { Debug.Trace("OutOfProcSessionStateStore", "Calling GetExlusive, id=" + id); return DoGet(context, id, UnsafeNativeMethods.StateProtocolExclusive.ACQUIRE, out locked, out lockAge, out lockId, out actionFlags); } public override void ReleaseItemExclusive(HttpContext context, String id, object lockId) { Debug.Assert(lockId != null, "lockId != null"); UnsafeNativeMethods.SessionNDMakeRequestResults results; int lockCookie = (int)lockId; Debug.Trace("OutOfProcSessionStateStore", "Calling ReleaseExclusive, id=" + id); MakeRequest(UnsafeNativeMethods.StateProtocolVerb.GET, id, UnsafeNativeMethods.StateProtocolExclusive.RELEASE, 0, 0, lockCookie, null, 0, s_networkTimeout, out results); } public override void SetAndReleaseItemExclusive(HttpContext context, String id, SessionStateStoreData item, object lockId, bool newItem) { UnsafeNativeMethods.SessionNDMakeRequestResults results; byte[] buf; int length; int lockCookie; Debug.Assert(item.Items != null, "item.Items != null"); Debug.Assert(item.StaticObjects != null, "item.StaticObjects != null"); Debug.Trace("OutOfProcSessionStateStore", "Calling Set, id=" + id + " sessionItems=" + item.Items + " timeout=" + item.Timeout); try { SessionStateUtility.SerializeStoreData(item, 0, out buf, out length); } catch { if (!newItem) { ((SessionStateStoreProviderBase)this).ReleaseItemExclusive(context, id, lockId); } throw; } // Save it to the store if (lockId == null) { lockCookie = 0; } else { lockCookie = (int)lockId; } MakeRequest(UnsafeNativeMethods.StateProtocolVerb.PUT, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, 0, item.Timeout, lockCookie, buf, length, s_networkTimeout, out results); } public override void RemoveItem(HttpContext context, String id, object lockId, SessionStateStoreData item) { Debug.Assert(lockId != null, "lockId != null"); Debug.Trace("OutOfProcSessionStateStore", "Calling Remove, id=" + id); UnsafeNativeMethods.SessionNDMakeRequestResults results; int lockCookie = (int)lockId; MakeRequest(UnsafeNativeMethods.StateProtocolVerb.DELETE, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, 0, 0, lockCookie, null, 0, s_networkTimeout, out results); } public override void ResetItemTimeout(HttpContext context, String id) { UnsafeNativeMethods.SessionNDMakeRequestResults results; Debug.Trace("OutOfProcSessionStateStore", "Calling ResetTimeout, id=" + id); MakeRequest(UnsafeNativeMethods.StateProtocolVerb.HEAD, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, 0, 0, 0, null, 0, s_networkTimeout, out results); } public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout) { Debug.Assert(timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES"); return SessionStateUtility.CreateLegitStoreData(context, null, null, timeout); } public override void CreateUninitializedItem(HttpContext context, String id, int timeout) { UnsafeNativeMethods.SessionNDMakeRequestResults results; byte[] buf; int length; Debug.Trace("OutOfProcSessionStateStore", "Calling CreateUninitializedItem, id=" + id + " timeout=" + timeout); // Create an empty item SessionStateUtility.SerializeStoreData(CreateNewStoreData(context, timeout), 0, out buf, out length); // Save it to the store MakeRequest(UnsafeNativeMethods.StateProtocolVerb.PUT, id, UnsafeNativeMethods.StateProtocolExclusive.NONE, (int)SessionStateItemFlags.Uninitialized, timeout, 0, buf, length, s_networkTimeout, out results); } // Called during EndRequest event public override void EndRequest(HttpContext context) { } class StateServerPartitionInfo : PartitionInfo { string _server; int _port; int _stateServerVersion; internal StateServerPartitionInfo(ResourcePool rpool, string server, int port) : base(rpool) { _server = server; _port = port; _stateServerVersion = -1; Debug.Trace("PartitionInfo", "Created a new info, server=" + server + ", port=" + port); } internal string Server { get { return _server; } } internal int Port { get { return _port; } } internal int StateServerVersion { get { return _stateServerVersion; } set { _stateServerVersion = value; } } protected override string TracingPartitionString { get { return Server + ":" + Port; } } } class OutOfProcConnection : IDisposable { internal HandleRef _socketHandle; internal OutOfProcConnection(IntPtr socket) { Debug.Assert(socket != OutOfProcSessionStateStore.INVALID_SOCKET, "socket != OutOfProcSessionStateStore.INVALID_SOCKET"); _socketHandle = new HandleRef(this, socket); PerfCounters.IncrementCounter(AppPerfCounter.SESSION_STATE_SERVER_CONNECTIONS); } ~OutOfProcConnection() { Dispose(false); } public void Dispose() { Debug.Trace("ResourcePool", "Disposing OutOfProcConnection"); Dispose(true); System.GC.SuppressFinalize(this); } private void Dispose(bool dummy) { if (_socketHandle.Handle != OutOfProcSessionStateStore.INVALID_SOCKET) { UnsafeNativeMethods.SessionNDCloseConnection(_socketHandle); _socketHandle = new HandleRef(this, OutOfProcSessionStateStore.INVALID_SOCKET); PerfCounters.DecrementCounter(AppPerfCounter.SESSION_STATE_SERVER_CONNECTIONS); } } internal void Detach() { _socketHandle = new HandleRef(this, OutOfProcSessionStateStore.INVALID_SOCKET); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- OutputCacheProfileCollection.cs
- WebEvents.cs
- EncoderReplacementFallback.cs
- IisTraceWebEventProvider.cs
- ServicePointManager.cs
- PrintDocument.cs
- FormClosedEvent.cs
- Bits.cs
- FieldNameLookup.cs
- XmlConvert.cs
- OleDbCommand.cs
- OrderedEnumerableRowCollection.cs
- ThreadWorkerController.cs
- propertytag.cs
- Exceptions.cs
- NativeMethods.cs
- PathStreamGeometryContext.cs
- HttpConfigurationSystem.cs
- COM2TypeInfoProcessor.cs
- ObjectAssociationEndMapping.cs
- DataGridViewColumn.cs
- OdbcRowUpdatingEvent.cs
- ParserExtension.cs
- BamlRecords.cs
- COAUTHIDENTITY.cs
- AlignmentYValidation.cs
- DesignerTransactionCloseEvent.cs
- TableStyle.cs
- EncoderBestFitFallback.cs
- ToolStripLabel.cs
- MergeEnumerator.cs
- GiveFeedbackEvent.cs
- DocumentOrderComparer.cs
- ContentValidator.cs
- ReadOnlyDataSource.cs
- PrintPreviewControl.cs
- DataStreams.cs
- CatalogZoneBase.cs
- CustomExpression.cs
- ToolStripPanelCell.cs
- PopupRoot.cs
- MenuItemStyleCollectionEditor.cs
- Int64.cs
- BoundsDrawingContextWalker.cs
- DataPointer.cs
- _NegoStream.cs
- PkcsUtils.cs
- CookieParameter.cs
- ToolStripItemRenderEventArgs.cs
- CharacterMetrics.cs
- ContainerAction.cs
- IntPtr.cs
- Function.cs
- DataSourceView.cs
- SqlFunctionAttribute.cs
- GregorianCalendar.cs
- GeneratedCodeAttribute.cs
- RemotingServices.cs
- StdValidatorsAndConverters.cs
- ListViewGroupCollectionEditor.cs
- UnionCodeGroup.cs
- LocatorPart.cs
- KerberosReceiverSecurityToken.cs
- ForwardPositionQuery.cs
- IDictionary.cs
- Button.cs
- Rotation3DAnimationBase.cs
- NullableConverter.cs
- DataBoundControlDesigner.cs
- ToolboxItemWrapper.cs
- SimpleRecyclingCache.cs
- OdbcException.cs
- storepermission.cs
- ParenthesizePropertyNameAttribute.cs
- DataGridViewRowsAddedEventArgs.cs
- PtsHost.cs
- BaseTemplateParser.cs
- HtmlInputReset.cs
- AdRotator.cs
- MailAddress.cs
- SolidColorBrush.cs
- SafeMemoryMappedViewHandle.cs
- CuspData.cs
- LogExtent.cs
- XamlFilter.cs
- ClientScriptManagerWrapper.cs
- SystemBrushes.cs
- StorageSetMapping.cs
- CacheMode.cs
- odbcmetadatacollectionnames.cs
- ProviderUtil.cs
- TextParagraph.cs
- DataListItemCollection.cs
- VectorAnimationBase.cs
- WasNotInstalledException.cs
- CodeTypeOfExpression.cs
- Pair.cs
- UnsafeNativeMethods.cs
- SecurityPermission.cs
- AttributeProviderAttribute.cs