// Core V3.4 server implementation #region ISessCtrlV131 Members /// <summary> /// /// </summary> /// <param name="header"></param> /// <param name="clientInfo"></param> /// <returns></returns> public V131SessionReply BeginSessionV131(V131SessionHeader header, V131ClientInfo clientInfo) { // validate new client Guid clientId = clientInfo.NodeGuid; // - ensure configured client/server envs are the same if (CoreHelper.ToEnvId(clientInfo.ConfigEnv) != _serverCfg.ModuleInfo.ConfigEnv) { // not valid string msg = $"Client environment ({clientInfo.ConfigEnv}) <> server environment ({_serverCfg.ModuleInfo.ConfigEnv})!"; Logger.LogWarning(msg); return(new V131SessionReply(msg)); } // - ensure build environment is backward compatible if (CoreHelper.ToEnvId(clientInfo.BuildEnv) < _serverCfg.ModuleInfo.BuildEnv) { // not valid string msg = $"Client build environment ({clientInfo.BuildEnv}) < server build environment ({_serverCfg.ModuleInfo.BuildEnv})!"; Logger.LogWarning(msg); return(new V131SessionReply(msg)); } // - check client version const string minimumVersion = "3.4.1723.1"; // 1.1.1501.1 March 01, 2019 const string optimalVersion = "3.4.1723.1"; if (!V131Helpers.CheckRequiredFileVersion(Logger, minimumVersion, clientInfo.CompInfo.AssmFVer)) { // older than minimum - reject connection string msg = $"Client version ({clientInfo.CompInfo.AssmFVer}) < minimum version ({minimumVersion})!"; Logger.LogError(msg); Logger.LogDebug("Connection: '{0}' rejected ({1})", clientId, header.ReplyAddress); return(new V131SessionReply(msg)); } if (!V131Helpers.CheckRequiredFileVersion(Logger, optimalVersion, clientInfo.CompInfo.AssmFVer)) { // older than optimal - log warning string msg = $"Client version ({clientInfo.CompInfo.AssmFVer}) < optimal version ({optimalVersion})!"; Logger.LogWarning(msg); } // - ensure STG/PRD envs servers only accessed by valid clients if (_serverCfg.ModuleInfo.ConfigEnv >= EnvId.Stg_StagingLive && (clientInfo.CompInfo.AssmPTok != _serverCfg.ModuleInfo.CorePTok)) { string msg = $"Client signature ({clientInfo.CompInfo.AssmPTok}) <> server signature ({_serverCfg.ModuleInfo.CorePTok})!"; Logger.LogWarning(msg); return(new V131SessionReply(msg)); } // - ensure automated unit tests are not running integration tests if (_serverCfg.ModuleInfo.ConfigEnv >= EnvId.Sit_SystemTest && clientInfo.ApplInfo.AssmName.Equals("QTAgent32", StringComparison.OrdinalIgnoreCase)) { string msg = $"Unauthorised client: {clientInfo.UserInfo.UserIdentityName} {clientInfo.HostName} {clientInfo.ApplInfo.AssmName}"; Logger.LogWarning(msg); return(new V131SessionReply(msg)); } IConnection newConnection; // build correct connection version if (header.ReplyContract == typeof(ITransferV341).FullName) { newConnection = new ConnectionV34( Logger, _cacheEngine, _serverCfg, clientId, header.ReplyAddress, NodeType.Client); } else { // reply contract not supported string msg = $"ReplyContract not supported: {header.ReplyContract}"; Logger.LogWarning(msg); return(new V131SessionReply(msg)); } // success - grant access IConnection connection = _connectionIndex.GetOrSet(clientId, () => newConnection); connection.ReplyAddress = header.ReplyAddress; _cacheEngine.UpdateConnectionState(connection.ClientId, connection.ContractName, connection.ReplyAddress); // update who stats: domain/name/host/app StatsCountersDelta.AddToHierarchy( $"ConnUser.{clientInfo.UserInfo.UserIdentityName}.{clientInfo.HostName}.{clientInfo.ApplInfo.AssmName}"); // update where stats: ip/host/app StatsCountersDelta.AddToHierarchy( $"ConnHost.{clientInfo.HostIpV4}.{clientInfo.HostName}.{clientInfo.ApplInfo.AssmName}"); // update version stats: StatsCountersDelta.AddToHierarchy( $"CVersion.{clientInfo.BuildEnv}.{string.Join(".", clientInfo.CompInfo.AssmFVer.Split('.'), 0, 2).Replace('.', '_')}.{String.Join(".", clientInfo.CompInfo.AssmFVer.Split('.'), 2, 2).Replace('.', '_')}.{clientInfo.HostName}.{clientInfo.ApplInfo.AssmName}"); Logger.LogDebug("Connection: '{0}' created ({1})", clientId, header.ReplyAddress); if (header.DebugRequest) { Logger.LogDebug(" Identity : {0} ({1})", clientInfo.UserInfo.UserIdentityName, clientInfo.UserInfo.UserFullName); Logger.LogDebug(" Application: {0} V{1}/{2} ({3}/{4})", clientInfo.ApplInfo.AssmName, clientInfo.ApplInfo.AssmNVer, clientInfo.ApplInfo.AssmFVer, clientInfo.ApplInfo.AssmPTok, clientInfo.ApplInfo.AssmHash); Logger.LogDebug(" Component : {0} V{1}/{2} ({3}/{4})", clientInfo.CompInfo.AssmName, clientInfo.CompInfo.AssmNVer, clientInfo.CompInfo.AssmFVer, clientInfo.CompInfo.AssmPTok, clientInfo.CompInfo.AssmHash); Logger.LogDebug(" Client Env.: {0} ({1} build)", clientInfo.ConfigEnv, clientInfo.BuildEnv); Logger.LogDebug(" Client Intf: {0}", header.ReplyContract); Logger.LogDebug(" Other Addrs: {0} ({1},{2})", clientInfo.HostName, clientInfo.HostIpV4, String.Join(",", clientInfo.NetAddrs.ToArray())); } return(new V131SessionReply(clientId, null)); }
protected override void OnStart() { // restore un-expired connections Logger.LogDebug("Restoring connections..."); DateTimeOffset dtNow = DateTimeOffset.Now; List <CommonItem> connItems = _cacheEngine.GetCacheItems( null, ItemKind.Local, typeof(ClientConnectionState).FullName, null, 0, dtNow, true, false); foreach (CommonItem item in connItems) { try { var oldConn = XmlSerializerHelper.DeserializeFromString <ClientConnectionState>( CompressionHelper.DecompressToString(item.YData)); IConnection connection = null; if (oldConn.Contract == typeof(ITransferV341).FullName) { var clientId = new Guid(oldConn.SourceId); connection = new ConnectionV34( Logger, _cacheEngine, _serverCfg, clientId, oldConn.ReplyAddress, NodeType.Client); connection.ExtendExpiry(); _connectionIndex.Set(clientId, connection); } if (connection != null) { Logger.LogDebug("Restored connection:"); Logger.LogDebug(" Client Id. : {0}", connection.ClientId); Logger.LogDebug(" Client Addr: {0}", connection.ReplyAddress); } else { Logger.LogDebug("Ignoring unsupported connection: '{0}'", oldConn.ReplyAddress); } } catch (Exception e) { // failed, however the show must go on Logger.Log(e); } } // restore subscriptions Logger.LogDebug("Restoring subscriptions..."); List <CommonItem> subsItems = _cacheEngine.GetCacheItems( null, ItemKind.Local, typeof(ClientSubscriptionState).FullName, null, 0, dtNow, true, false); foreach (CommonItem item in subsItems) { try { var oldSubscription = XmlSerializerHelper.DeserializeFromString <ClientSubscriptionState>( CompressionHelper.DecompressToString(item.YData)); var subscription = new ClientSubscription(oldSubscription); var clientId = new Guid(oldSubscription.ConnectionId); IConnection connection = GetValidConnection(clientId); if (connection != null) { _cacheEngine.RestoreSubscription(subscription); Logger.LogDebug("Restored subscription:"); Logger.LogDebug(" Client Id: {0}", connection.ClientId); Logger.LogDebug(" Address : {0}", connection.ReplyAddress); Logger.LogDebug(" Subs. Id : {0}", subscription.SubscriptionId); Logger.LogDebug(" AppScopes: {0}", (subscription.AppScopes == null) ? "*" : String.Join(",", subscription.AppScopes)); Logger.LogDebug(" ItemKind : {0}", (subscription.ItemKind == ItemKind.Undefined) ? "(any)" : subscription.ItemKind.ToString()); Logger.LogDebug(" DataType : {0}", subscription.DataTypeName ?? "(any)"); Logger.LogDebug(" Query : {0}", subscription.Expression.DisplayString()); Logger.LogDebug(" MinimumUSN > : {0}", subscription.MinimumUSN); Logger.LogDebug(" Excl.Deleted?: {0}", (subscription.ExcludeDeleted)); Logger.LogDebug(" Excl.DataBody: {0}", subscription.ExcludeDataBody); } else { _cacheEngine.DeleteSubscriptionState(subscription.SubscriptionId); Logger.LogDebug("Ignoring expired subscription id: {0}", oldSubscription.SubscriptionId); } } catch (Exception e) { // failed, however the show must go on Logger.Log(e); } } string svcName = EnvHelper.SvcPrefix(SvcId.CoreServer); // discovery service _discoverV111ServerHost = new CustomServiceHost <IDiscoverV111, DiscoverRecverV111>( Logger, new DiscoverRecverV111(this), _serverCfg.V31DiscoEndpoints, svcName, typeof(IDiscoverV111).Name, true); // V3.4 services _sessCtrlV131ServerHost = new CustomServiceHost <ISessCtrlV131, SessCtrlRecverV131>( Logger, new SessCtrlRecverV131(this), _serverCfg.V31DiscoEndpoints, svcName, typeof(ISessCtrlV131).Name, true); _transferV341ServerHost = new CustomServiceHost <ITransferV341, TransferRecverV341>( Logger, new TransferRecverV341(this), _serverCfg.V31AsyncEndpoints, svcName, typeof(ITransferV341).Name, true); // start housekeeping timer _housekeepTimer = new Timer(DispatchHousekeepTimeout, null, ServerCfg.CommsHousekeepInterval, ServerCfg.CommsHousekeepInterval); }