internal void Startup() { TheDiagnostics.SetThreadName("WSStartup"); if (TheBaseAssets.MyServiceHostInfo.MyStationWSPort == 0) return; Uri tUri = new Uri(TheBaseAssets.MyServiceHostInfo.GetPrimaryStationURL(false)); MyHttpUrl = tUri.Scheme + "://*"; // +tUri.Host; MyHttpUrl += ":" + TheBaseAssets.MyServiceHostInfo.MyStationWSPort; MyHttpUrl += "/"; appServer = new WebSocketServer(); //Setup the appServer if (!appServer.Setup(new ServerConfig() { Port = TheBaseAssets.MyServiceHostInfo.MyStationWSPort, MaxRequestLength = 400000 })) //Setup with listening port { TheBaseAssets.MySYSLOG.WriteToLog(4343, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheWSServer", "Error During Startup", eMsgLevel.l1_Error)); return; } appServer.NewMessageReceived += new SessionHandler<WebSocketSession, string>(appServer_NewMessageReceived); appServer.NewDataReceived += appServer_NewDataReceived; appServer.NewSessionConnected += appServer_NewSessionConnected; appServer.SessionClosed += appServer_SessionClosed; //Try to start the appServer if (!appServer.Start()) { TheBaseAssets.MySYSLOG.WriteToLog(4343, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheWSServer", "Failed to start Super-Web-Socket Server", eMsgLevel.l1_Error)); IsActive = false; return; } IsActive = true; TheBaseAssets.MySYSLOG.WriteToLog(4343, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheWSServer", "New Super-Web-Socket Server started ", eMsgLevel.l4_Message)); }
public static async Task WaitForWSAccept(HttpListenerContext pContext) { TheDiagnostics.SetThreadName("WSWait4Accept"); var wsc = await pContext.AcceptWebSocketAsync(null); if (wsc != null) { TheRequestData tRequestData = new TheRequestData { RequestUri = pContext.Request.Url, UserAgent = pContext.Request.UserAgent, HttpMethod = pContext.Request.HttpMethod, Header = TheCommonUtils.cdeNameValueToDirectory(pContext.Request.Headers), ResponseMimeType = pContext.Request.ContentType, ServerTags = null, ClientCert = pContext.Request.GetClientCertificate() }; if (TheCommCore.MyHttpService != null && TheBaseAssets.MyServiceHostInfo.ClientCertificateUsage > 1) //If CDE requires a certificate, terminate all incoming requests before any processing { var err = TheCommCore.MyHttpService.ValidateCertificateRoot(tRequestData); if (!string.IsNullOrEmpty(err)) { pContext.Response.StatusCode = (int)eHttpStatusCode.AccessDenied; pContext.Response.OutputStream.Close(); return; } } TheWSProcessor8 tProcessor = new TheWSProcessor8(wsc.WebSocket); tProcessor.SetRequest(tRequestData); await tProcessor.ProcessWS(); } }
private void PollTelnetServer() { TheDiagnostics.SetThreadName("Telnet-Server", true); while (telnetClient.Connected && TheBaseAssets.MasterSwitch) { PollServer(); Thread.Sleep(50); } if (telnetClient.Connected) { telnetClient.Disconnect(); } eventClosed?.Invoke("Ended"); }
internal void CheckOnHealthTimer(long tTimerVal) { if (mDisableCollection) { return; } if ((tTimerVal % HealthUpdateCycle) != 0) { return; } if (TheCommonUtils.cdeIsLocked(lockCheckTimer)) { return; } lock (lockCheckTimer) { if (!AreCounterInit) { return; } TheBaseAssets.MySYSLOG.WriteToLog(8005, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("jcHealth", "Enter CheckOnHealthTimer", eMsgLevel.l7_HostDebugMessage)); TheDiagnostics.SetThreadName("C-MyComputer-HealthTimer", true); if (!IsEnergyRegistered) { TheThing tThing = TheThingRegistry.GetBaseEngineAsThing("CDMyEnergy.TheCDMyEnergyEngine"); if (tThing != null) { IsEnergyRegistered = true; tThing.RegisterEvent(eEngineEvents.MessageProcessed, sinkEnergyFound); } } SendHealthInfo(Guid.Empty); if (MyServiceHealthDataStore != null) { TheBaseAssets.MySYSLOG.WriteToLog(8006, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("jcHealth", "Storing HealthInfo", eMsgLevel.l7_HostDebugMessage, MyHealthData.cdeUptime.ToString())); if (!MyServiceHealthDataStore.IsReady) { MyServiceHealthDataStore.InitializeStore(false); TheBaseAssets.MySYSLOG.WriteToLog(8006, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("jcHealth", "Storing HealthInfo- Initializing store", eMsgLevel.l4_Message)); } MyServiceHealthDataStore.AddAnItem(TheThingStore.CloneFromTheThing(MyHealthData, true)); } TheBaseAssets.MySYSLOG.WriteToLog(8006, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("jcHealth", "Leave CheckOnHealthTimer", eMsgLevel.l7_HostDebugMessage)); } }
private static void sinkRequestFailed(object state) { TheDiagnostics.SetThreadName("TimedRequestFailed", true); TheTimedRequest <T> req = state as TheTimedRequest <T>; if (state != null) { TheTimedRequest <T> tReq = req; lock (MyStoreRequestsLock) { if (MyStoreRequests.ContainsKey(tReq.MagicID.ToString())) { TheBaseAssets.MySYSLOG.WriteToLog(472, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheTimedCallbacks", "Timed-Request Timed Out", eMsgLevel.l2_Warning)); MyStoreRequests.RemoveNoCare(tReq.MagicID.ToString()); tReq.MyRequest("Timed-Request Timed Out", (T)tReq.Cookie); } } } }
internal void Startup() { TheDiagnostics.SetThreadName("WSStartup"); if (TheBaseAssets.MyServiceHostInfo.MyStationWSPort == 0) return; try { if (TheBaseAssets.MyServiceHostInfo.MyStationPort == TheBaseAssets.MyServiceHostInfo.MyStationWSPort) TheBaseAssets.MyServiceHostInfo.MyStationWSPort =(ushort)(TheBaseAssets.MyServiceHostInfo.MyStationPort + 1); appServer = new WebSocketServer(TheBaseAssets.MyServiceHostInfo.MyStationWSPort) { ReuseAddress = true }; // tUri.ToString()); appServer.AddWebSocketService<CDEWSBehavior>(TheBaseAssets.MyServiceHostInfo.RootDir + "/ISB"); appServer.Log.Level = LogLevel.Fatal; appServer.Log.Output = sinkLog; appServer.Start(); IsActive = true; TheBaseAssets.MySYSLOG.WriteToLog(4378, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheWSServer", "New WebSocket-sharp Server started ", eMsgLevel.l4_Message, $"Port: {appServer.Port}")); } catch (Exception ee) { TheBaseAssets.MySYSLOG.WriteToLog(4378, new TSM("TheWSServer", "WebSocket-sharp could not start!", eMsgLevel.l1_Error, $"Port: {TheBaseAssets.MyServiceHostInfo.MyStationWSPort} {ee.ToString()}")); } }
public bool RegisterDevice(TheUPnPDeviceInfo pNewDevice, bool ForceUpdate) { TheDiagnostics.SetThreadName("UPnP-Notify", true); if (!TheBaseAssets.MasterSwitch || (TheCommonUtils.cdeIsLocked(LockNotify) && !ForceUpdate) || string.IsNullOrEmpty(pNewDevice?.LocationURL)) { return(false); } lock (LockNotify) { TheUPnPDeviceInfo tHistory = null; //tHistory = MyUPnPDiscoveryPast.MyMirrorCache.GetEntryByFunc((s) => s.LocationURL.Equals(pNewDevice.LocationURL, StringComparison.OrdinalIgnoreCase)); // string[] tUsn = pNewDevice.USN.Split(':'); string tNewUsn = pNewDevice.USN; if (tUsn.Length > 2) { tNewUsn = tUsn[0] + ':' + tUsn[1]; } tHistory = MyUPnPDiscoveryPast.MyMirrorCache.GetEntryByFunc((s) => s.USN.StartsWith(tNewUsn, StringComparison.OrdinalIgnoreCase)); // if (tHistory != null) //gUSN { try { tHistory.SourceIP = IPAddress.TryParse(pNewDevice.LocationURL.Split(':')[0], out IPAddress tIp) ? pNewDevice.LocationURL : new Uri(pNewDevice.LocationURL).Host; tHistory.LocationURL = pNewDevice.LocationURL; if (DateTimeOffset.Now.Subtract(tHistory.LastSeenAt).TotalSeconds < tHistory.MaxAge) { MyUPnPDiscoveryPast.MyMirrorCache.AddOrUpdateItem(tHistory); //gUSN if (tHistory.IsCDEngine) { ProcessCDEngine(tHistory, TheCommonUtils.CUri(tHistory.LocationURL, false)); } else { CheckForDeviceMatch(tHistory, null); } return(true); } tHistory.LastSeenAt = DateTimeOffset.Now; } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(111, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("UPnP", string.Format("UPnP {0} Invalid Device URL", pNewDevice), eMsgLevel.l1_Error, e.ToString())); return(false); } } if (tHistory == null) { tHistory = pNewDevice; } MyUPnPDiscoveryPast.MyMirrorCache.AddOrUpdateItem(tHistory); //gUSN Uri tLocationUrl; try { tLocationUrl = TheCommonUtils.CUri(tHistory.LocationURL, false); TheBaseAssets.MySYSLOG.WriteToLog(111, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("UPnP", string.Format("UPnP {0} Device Found", tHistory), eMsgLevel.l3_ImportantMessage)); CheckForDeviceMatch(tHistory, tLocationUrl); } catch (Exception eee) { TheBaseAssets.MySYSLOG.WriteToLog(111, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("UPnP", string.Format("Non UPnP conform device found: {0}", tHistory), eMsgLevel.l7_HostDebugMessage, eee.ToString())); return(false); } if (tHistory.IsCDEngine) { ProcessCDEngine(tHistory, tLocationUrl); } } return(true); }
private void sinkHeartBeatTimer(long NOTUSED) { try { TheDiagnostics.SetThreadName("HeartbeatTimer", true); mHeartBeatTicker++; TheBaseAssets.MySYSLOG.WriteToLog(2803, TSM.L(eDEBUG_LEVELS.EVERYTHING) ? null : new TSM("QSender", $"Enter HearbeatTimer for ORG:{MyTargetNodeChannel}", eMsgLevel.l7_HostDebugMessage)); TheTimeouts tTO = TheBaseAssets.MyServiceHostInfo.TO; if (!IsHeartBeatAlive(tTO.DeviceCleanSweepTimeout * 2) && TheCommonUtils.IsDeviceSenderType(MyTargetNodeChannel?.SenderType ?? cdeSenderType.NOTSET) && MyTargetNodeChannel?.IsWebSocket == false) //IDST-OK: Remove dead devices that might have hard disconnected (no correct disconnect) i.e. http browsers were just closed { TheBaseAssets.MySYSLOG.WriteToLog(2820, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("QSender", $"Forced Removal of QSender {MyTargetNodeChannel.ToMLString()} due to DeviceCleanSweep", eMsgLevel.l4_Message)); Guid?tTarget = MyTargetNodeChannel?.cdeMID; DisposeSender(true); if (tTarget.HasValue) { TheQueuedSenderRegistry.RemoveOrphan(tTarget.Value); TheCommCore.PublishCentral(new TSM(eEngineName.ContentService, "CDE_DELETEORPHAN", tTarget.ToString())); } return; } if (!IsAlive && !MyTargetNodeChannel?.IsWebSocket == true) { return; //NEW:V3 2013/12/13 allow for cloud reconnect if WebSockets } if ((mHeartBeatTicker % (tTO.HeartBeatRate * 2)) == 0) { if (MyTargetNodeChannel?.SenderType != cdeSenderType.CDE_LOCALHOST) { timerMyHeartbeatTimer(); } if (MyTargetNodeChannel?.SenderType == cdeSenderType.CDE_CLOUDROUTE && ((!IsConnected && !IsConnecting) || !IsAlive) && (mHeartBeatTicker % (tTO.HeartBeatRate * 10)) == 0) //tQ.MyTargetNodeChannel.IsWebSocket && NOW ALWAYS RECONNECT { TheCommonUtils.cdeRunAsync("ReconnectCloud", true, (o) => ReconnectCloud()); } if (MyTargetNodeChannel?.SenderType != cdeSenderType.CDE_LOCALHOST && IsAlive && IsConnected) //!TheBaseAssets.MyServiceHostInfo.IsCloudService && !tQ.MyTargetNodeChannel.IsWebSocket && { if (MyTargetNodeChannel?.IsWebSocket != true) { if (GetQueLength() == 0) { TheBaseAssets.MyServiceHostInfo.TO.MakeHeartPump(); // CODE REVIEW Markus: Isn't this backwards: we should pump faster while we have more work to do? SendPickupMessage(); //Pickup } else { TheBaseAssets.MyServiceHostInfo.TO.MakeHeartNormal(); } } else { SendPickupMessage(); //Pickup } } } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(2821, new TSM("QSRegistry", $"Fatal Error in HealthTimer for QS:{this.cdeMID} and MTNC:{MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l1_Error, e.ToString())); } }
private void TheWSSenderThread() { if (IsSenderThreadRunning /*|| MyTargetNodeChannel==null*/) { return; } if (MyTargetNodeChannel == null) { TheBaseAssets.MySYSLOG.WriteToLog(2371, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSQueuedSender", $"WSSender Thread could not be started because MTNC is null", eMsgLevel.l4_Message)); return; } TheDiagnostics.SetThreadName($"QSender:{MyTargetNodeChannel} WSSenderThread", true); IsSenderThreadRunning = true; mre = new ManualResetEvent(false); CloudCounter++; StringBuilder tSendBufferStr = new StringBuilder(TheBaseAssets.MyServiceHostInfo?.IsMemoryOptimized == true ? 1024 : TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType] * 2); int QDelay = TheCommonUtils.CInt(TheBaseAssets.MySettings.GetSetting("ThrottleWS")); if (QDelay < 2) { QDelay = 2; } if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON && TheBaseAssets.MyServiceHostInfo.WsJsThrottle > QDelay) { QDelay = TheBaseAssets.MyServiceHostInfo.WsJsThrottle; } if (eventSenderThreadRunning != null) { TheCommonUtils.cdeRunAsync("EventSenderThreadRunning", true, (p) => { eventSenderThreadRunning(this); }); } MyISBlock?.FireEvent("SenderThreadCreated"); try { while (TheBaseAssets.MasterSwitch && IsAlive && MyWebSocketProcessor.IsActive && IsSenderThreadRunning) { while (TheBaseAssets.MasterSwitch && IsAlive && MyWebSocketProcessor.IsActive && IsSenderThreadRunning && (MyTargetNodeChannel.MySessionState == null || IsConnecting || IsInWSPost || !MyWebSocketProcessor.ProcessingAllowed || MyCoreQueue.Count == 0)) { if (IsInWSPost && MyCoreQueue.Count > 200) { TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("WSQueuedSender", $"IsInWSPost was still on and has been reset for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l2_Warning)); IsInWSPost = false; } if (MyTargetNodeChannel.MySessionState == null && !IsConnecting && MyCoreQueue.Count > 0) { break; } mre.WaitOne(QDelay); // System.Diagnostics.Debug.WriteLine($"Waiting :{IsAlive} {MyCoreQueue.Count} {IsConnected} {IsConnecting} {IsInWSPost} {MyWebSocketProcessor.ProcessingAllowed}"); } if (!TheBaseAssets.MasterSwitch || !IsAlive || !MyWebSocketProcessor.IsActive || MyTargetNodeChannel.MySessionState == null) { TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("WSQueuedSender", $"WSSender Thread Condition failed - Ending SenderThread IsAlive:{IsAlive} MyWSProccAlive:{(MyWebSocketProcessor == null ? false : MyWebSocketProcessor.IsActive)},SessionState:{(MyTargetNodeChannel?.MySessionState != null)} IsConnecting:{IsConnecting} IsConnected:{IsConnected}", eMsgLevel.l2_Warning)); break; } IsInWSPost = true; int MCQCount = 0; int IsBatchOn = 0; int FinalCnt = 0; #if CDE_NET35 tSendBufferStr = new StringBuilder(TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType] * 2); #else tSendBufferStr.Clear(); #endif tSendBufferStr.Append("["); do { TheCoreQueueContent tQueued = GetNextMessage(out MCQCount); if (tQueued != null) { TheDeviceMessage tDev = new TheDeviceMessage(); if (tQueued.OrgMessage != null) { if (tQueued.OrgMessage.ToCloudOnly() && MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE) { tQueued.OrgMessage.SetToCloudOnly(false); } tQueued.OrgMessage.GetNextSerial(tQueued.SubMsgCnt); tDev.MSG = tQueued.OrgMessage; } var tCurSessState = MyTargetNodeChannel.MySessionState; if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON) { if (tDev.MSG == null) { // we have a pickup: never send to browser if (IsBatchOn > 0) { continue; //ignore HB as other messages are already in the queue } else { IsInWSPost = false; continue; //dont sent empty Message to Browser - HB not necessary } } else { tDev.MSG.SEID = null; //SECURITY: Don't send SEID to Browser tDev.MSG.UID = null; //SECURITY: Don't send SEID to Browser tDev.MSG.SID = null; //SECURITY: Don't send SID to Browser } tDev.DID = MyTargetNodeChannel.cdeMID.ToString(); } else { if (tDev.MSG == null) // CODE REVIEW: DO we also need to detect other simple topics with response message and ensure they get into their own batch? { // we have a pickup (only to be sent if nothing else is being sent) if (IsBatchOn > 0) { // Ignore pickups if another message is already being sent (can happen with race condition between check before pickup enqueue and dequeue here - another TSM could be enqueue in that time) continue; } else { // Close the batch here so that no other TSM gets into the same batch // Possible optimization: check if other TSMs are available and skip the pickup here as well IsBatchOn = -1; // IsInWSPost = false; } } tDev.DID = TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString(); if (!string.IsNullOrEmpty(tQueued?.OrgMessage?.SID)) { tDev.SID = tQueued.OrgMessage.SID; } else { if (TheBaseAssets.MyServiceHostInfo.EnableFastSecurity) { tDev.SID = tCurSessState.SScopeID; //SECURITY: All tDevs will have same Session Scrambled ScopeID - 4.209: SID from TSM if set. } else { tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(tCurSessState.SScopeID, false); //GRSI: high frequency } } } TheCDEKPIs.IncrementKPI(eKPINames.QSSent); tDev.TOP = tQueued.Topic; tDev.FID = tCurSessState.GetNextSerial().ToString(); if (TheCommonUtils.IsDeviceSenderType(MyTargetNodeChannel.SenderType)) //IDST-OK: Must create RSA for Devices { TheCommonUtils.CreateRSAKeys(tCurSessState); if (TheBaseAssets.MyServiceHostInfo.SecurityLevel > 3) { tDev.RSA = tCurSessState.RSAPublic; //TODO: Make depending on switch (HighSecurity=RSAGeneration every three seconds } } if (MyTargetNodeChannel.SenderType != cdeSenderType.CDE_CLOUDROUTE) //CODE-REVIEW: 4.0113 is this still valid: Must not reset HB if talking to cloud due to Cloud-Disconnect issue { ResetHeartbeatTimer(false, tCurSessState); } if (!cdeSenderType.CDE_JAVAJASON.Equals(MyTargetNodeChannel.SenderType)) { tDev.NPA = TheBaseAssets.MyScopeManager.GetISBPath(TheBaseAssets.MyServiceHostInfo.RootDir, MyTargetNodeChannel.SenderType, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType, tCurSessState.FID, tCurSessState.cdeMID, true); } if (MyTargetNodeChannel.MySessionState == null || MyTargetNodeChannel.MySessionState.HasExpired) { throw new Exception($"Session was deleted or has expired ({MyTargetNodeChannel?.MySessionState?.HasExpired})"); } #region Batch Serialization IsBatchOn++; FinalCnt++; var tToAdd = TheCommonUtils.SerializeObjectToJSONString(tDev); if (MCQCount == 0 || tQueued.IsChunked || IsBatchOn > TheBaseAssets.MyServiceHostInfo.MaxBatchedTelegrams) { if (MCQCount != 0) { tDev.CNT = MCQCount; } IsBatchOn = 0; } else { if (tSendBufferStr.Length + tToAdd.Length > TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType]) { tDev.CNT = MCQCount; IsBatchOn = 0; } } if (tSendBufferStr.Length > 1) { tSendBufferStr.Append(","); } tSendBufferStr.Append(tToAdd); #endregion } else { IsBatchOn = 0; } } while (IsBatchOn > 0 && IsInWSPost && TheBaseAssets.MasterSwitch); if (!IsInWSPost || tSendBufferStr.Length < 2) { IsInWSPost = false; continue; } tSendBufferStr.Append("]"); if (FinalCnt > 1) { TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("WSQueuedSender", $"Batched:{FinalCnt}", eMsgLevel.l3_ImportantMessage)); } if (!cdeSenderType.CDE_JAVAJASON.Equals(MyTargetNodeChannel.SenderType)) { MyWebSocketProcessor.PostToSocket(null, TheCommonUtils.cdeCompressString(tSendBufferStr.ToString()), true, false); } else { MyWebSocketProcessor.PostToSocket(null, TheCommonUtils.CUTF8String2Array(tSendBufferStr.ToString()), false, false); } IsInWSPost = false; } TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("WSQueuedSender", $"WSQSenderThread was closed for {MyTargetNodeChannel?.ToMLString()} IsAlive:{IsAlive} MyWSProccAlive:{(MyWebSocketProcessor == null ? "Is Null" : MyWebSocketProcessor?.IsActive.ToString())},SessionState:{(MyTargetNodeChannel?.MySessionState != null)} IsConnecting:{IsConnecting} IsConnected:{IsConnected}", eMsgLevel.l1_Error)); } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSQueuedSender", "Exception in WSSenderThread.", eMsgLevel.l1_Error, "Error:" + e)); } finally { IsInWSPost = false; IsSenderThreadRunning = false; StopHeartBeat(); } if (IsAlive || (MyWebSocketProcessor != null && MyWebSocketProcessor.IsActive)) { IsAlive = false; if (MyWebSocketProcessor != null) { MyWebSocketProcessor.Shutdown(true, "1310:SenderThread Closed"); } } CloudCounter--; }
public void TheRESTSenderThread() { if (IsSenderThreadRunning) { return; } try { TheDiagnostics.SetThreadName($"QSender:{MyTargetNodeChannel} SenderThread", true); MyREST = new TheREST(); IsSenderThreadRunning = true; StringBuilder tSendBufferStr = new StringBuilder(TheBaseAssets.MyServiceHostInfo?.IsMemoryOptimized == true ? 1024 : TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType] * 2); TargetUri = TheCommonUtils.CUri(MyTargetNodeChannel.TargetUrl, true); TargetUriPath = TargetUri.AbsolutePath; int QDelay = TheCommonUtils.CInt(TheBaseAssets.MySettings.GetSetting("ThrottleWS")); if (QDelay < 2) { QDelay = 2; } if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON && TheBaseAssets.MyServiceHostInfo.WsJsThrottle > QDelay) { QDelay = TheBaseAssets.MyServiceHostInfo.WsJsThrottle; } mre = new ManualResetEvent(false); if (eventSenderThreadRunning != null) { TheCommonUtils.cdeRunAsync("EventSenderThreadRunning", true, (p) => { eventSenderThreadRunning(this); }); } MyISBlock?.FireEvent("SenderThreadCreated"); while (TheBaseAssets.MasterSwitch && IsAlive && IsSenderThreadRunning) { if (QDelay > 2) { mre.WaitOne(QDelay); //Throtteling should be here not in the wait loop } int WaitCounter = 0; while (TheBaseAssets.MasterSwitch && IsAlive && IsSenderThreadRunning && ((MyCoreQueue.Count == 0 && IsConnected) || IsConnecting || IsInPost || MyREST.IsPosting > (IsConnected?TheBaseAssets.MyServiceHostInfo.ParallelPosts:0))) { // CODE REVIEW: This was seen looping after service route to local node was closed (due to node shutdown): IsCOnnecting/IsConnected/IsInPost were false; ISAlive true. MyREST.IsPosting was 8. Queue count ~345 // This should be fixed now with IsSenderThreadRunning in the loop (I was wrong :) this happens only with cloud connections where POST fails and the IsPosting was not reset properly). // Update: If found the same problem. Sometime IsPosting is not reduced properly when a Timeout or other error occured during Posting if (IsInPost && MyCoreQueue.Count > 100) { TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"IsInPost was still on and has been reset for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l2_Warning)); IsInPost = false; } if (!IsConnected) { if (IsConnecting && MyREST.IsPosting == 0) { TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"IsConnecting is set but no Pending Post {MyTargetNodeChannel?.ToMLString()} - resetting IsConnecting", eMsgLevel.l2_Warning)); IsConnecting = false; } if (!IsConnecting && MyREST.IsPosting > (IsConnected ? 10 : 0)) { WaitCounter++; if (WaitCounter > (10000 / QDelay)) { TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"MyREST.IsPosting ({MyREST.IsPosting}) was higher then expected...possible POST problem. Resetting POST Counter for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l2_Warning)); MyREST.IsPosting = 0; } } } mre.WaitOne(QDelay); } if (!TheBaseAssets.MasterSwitch || !IsAlive || !IsSenderThreadRunning) { IsInPost = false; break; } IsInPost = true; if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_BACKCHANNEL || MyTargetNodeChannel.SenderType == cdeSenderType.CDE_PHONE || MyTargetNodeChannel.SenderType == cdeSenderType.CDE_DEVICE || MyTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON) { TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"QSender Should NEVER GO HERE because SenderType is {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l1_Error)); IsInPost = false; IsSenderThreadRunning = false; return; } //NEW3.124: Sender Loop has to terminate if Cloud was Disabled. if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE && (TheBaseAssets.MyServiceHostInfo.IsCloudDisabled || string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ServiceRoute) || !TheBaseAssets.MyServiceHostInfo.HasServiceRoute(TargetUri))) //ServiceRoute can contain multiple routes... { break; } TheCoreQueueContent tQueued = null; int MCQCount = 0; int IsBatchOn = 0; #if CDE_NET35 tSendBufferStr = new StringBuilder(TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType] * 2); #else tSendBufferStr.Clear(); #endif tSendBufferStr.Append("["); byte[] BinSendBuffer = null; do { if (!IsConnected) { tQueued = new TheCoreQueueContent(); IsConnecting = true; ConnectRetries = 0; if (CloudInRetry) { var count = Interlocked.Increment(ref CloudRetryCount); if (count > 10) { int delaySeconds = TheBaseAssets.MyServiceHostInfo.HeartbeatDelay * TheBaseAssets.MyServiceHostInfo.TO.HeartBeatRate; TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("QueuedSender", $"Too many retries for {MyTargetNodeChannel?.ToMLString()}: {count}. Waiting {delaySeconds} seconds.", eMsgLevel.l2_Warning)); TheCommonUtils.SleepOneEye((uint)delaySeconds * 1000, 100); Interlocked.Exchange(ref CloudRetryCount, 0); } if (!TheBaseAssets.MasterSwitch || !IsAlive || !IsSenderThreadRunning || (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE && (TheBaseAssets.MyServiceHostInfo.IsCloudDisabled || string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ServiceRoute) || !TheBaseAssets.MyServiceHostInfo.HasServiceRoute(TargetUri)))) { //Very rare but required after Sleep throw new Exception("QSender had to be terminated in Cloud Retry due to disabling of ServiceRoute or C-DEngine Shutdown"); } }//NEW3.124: Sender Loop has to terminate if Cloud was Disabled. if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE && (TheBaseAssets.MyServiceHostInfo.IsCloudDisabled || string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ServiceRoute) || !TheBaseAssets.MyServiceHostInfo.HasServiceRoute(TargetUri))) { break; } } else { if (CloudInRetry) { CloudInRetry = false; IsInPost = false; continue; } tQueued = GetNextMessage(out MCQCount); } if (tQueued != null) { TheCDEKPIs.IncrementKPI(eKPINames.QSSent); if (tQueued.OrgMessage == null && !IsConnecting) { if (MySubscriptions.Count == 0) { if (IsBatchOn == 0) //Only jump out if no telegrams are in batch.. { IsInPost = false; continue; } } if (IsBatchOn == 0) //If telegrams are in the batch dont send short message { BinSendBuffer = new byte[1]; BinSendBuffer[0] = (byte)((int)(TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType)).ToString()[0]; break; } } if (tQueued.OrgMessage != null && tQueued.OrgMessage.ToCloudOnly() && MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE) { tQueued.OrgMessage.SetToCloudOnly(false); } TheDeviceMessage tDev = new TheDeviceMessage { DID = TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString() // MyTargetNodeChannel.cdeMID.ToString(); }; if (MyTargetNodeChannel.MySessionState != null) { //BUGFIX: After fast Cloud Disconnect/reconnect-Relay lost Scopeing because it Scope was not properly stored in SessionState if (string.IsNullOrEmpty(MyTargetNodeChannel.MySessionState.SScopeID) && TheBaseAssets.MyScopeManager.IsScopingEnabled) { MyTargetNodeChannel.MySessionState.SScopeID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(); //GRSI: rare } if (TheBaseAssets.MyServiceHostInfo.EnableFastSecurity) { tDev.SID = MyTargetNodeChannel.MySessionState.SScopeID; } else { tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(MyTargetNodeChannel.MySessionState.SScopeID, false); //GRSI: high frequency! } } else { tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(); //GRSI: rare } tDev.MSG = tQueued.OrgMessage; tDev.FID = "1"; if (IsConnecting) { tDev.TOP = TheCommCore.SetConnectingBufferStr(MyTargetNodeChannel, null); } else { tDev.TOP = tQueued.Topic; tQueued.OrgMessage?.GetNextSerial(tQueued.SubMsgCnt); if (MyTargetNodeChannel.MySessionState != null) { tDev.FID = MyTargetNodeChannel.MySessionState.GetNextSerial().ToString(); //(SendCounter + 1).ToString(); //V3B3: New was empty //V4.1010: Same as WS now } } #region Batch Serialization IsBatchOn++; if (MCQCount == 0 || IsBatchOn > TheBaseAssets.MyServiceHostInfo.MaxBatchedTelegrams || tQueued.IsChunked) { if (MCQCount != 0) { tDev.CNT = MCQCount; } IsBatchOn = 0; } else { if (tSendBufferStr.Length > TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType]) { tDev.CNT = MCQCount; IsBatchOn = 0; } } if (tSendBufferStr.Length > 1) { tSendBufferStr.Append(","); } tSendBufferStr.Append(TheCommonUtils.SerializeObjectToJSONString(tDev)); #endregion } else { IsBatchOn = 0; } } while (IsBatchOn > 0 && IsInPost && TheBaseAssets.MasterSwitch); if ((!IsInPost || tSendBufferStr.Length < 2) && BinSendBuffer == null) { IsInPost = false; continue; } string tMimeType = "application/octet-stream"; if (BinSendBuffer == null) { tSendBufferStr.Append("]"); if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_MINI || TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType == cdeSenderType.CDE_MINI) { tMimeType = "application/json"; BinSendBuffer = TheCommonUtils.CUTF8String2Array(tSendBufferStr.ToString()); } else { tMimeType = "application/x-gzip"; BinSendBuffer = TheCommonUtils.cdeCompressString(tSendBufferStr.ToString()); } } if (MyTargetNodeChannel == null) { TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("QueuedSender", $"Channel was deleted - exiting SenderThread", eMsgLevel.l2_Warning)); IsInPost = false; break; } string ISBPath = new Uri(TargetUri, TheBaseAssets.MyScopeManager.GetISBPath(TargetUriPath, TheCommonUtils.GetOriginST(MyTargetNodeChannel), MyTargetNodeChannel.SenderType, MyTargetNodeChannel.MySessionState == null? 1: MyTargetNodeChannel.MySessionState.FID /*Interlocked.Increment(ref SendCounter)*/, (MyTargetNodeChannel.MySessionState == null || !IsConnected) ?Guid.Empty: MyTargetNodeChannel.MySessionState.cdeMID, MyTargetNodeChannel.IsWebSocket)).ToString(); //V3B4: changed from TheBaseAssets.MyServiceHostInfo.MyDeviceInfo TheRequestData pData = new TheRequestData { RemoteAddress = TheBaseAssets.MyServiceHostInfo.GetPrimaryStationURL(false), RequestUri = new Uri(ISBPath), PostData = BinSendBuffer, ResponseMimeType = tMimeType, DeviceID = TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID, HttpMethod = "POST" }; if (!TheCertificates.SetClientCert(pData, MyTargetNodeChannel?.ClientCertificateThumb)) { throw new Exception("Client Certificate could not be added"); } MyREST.PostRESTAsync(pData, sinkUploadDataCompleted, FireSenderProblem); if (BinSendBuffer != null) { TheCDEKPIs.IncrementKPI(eKPINames.QKBSent, BinSendBuffer.Length); } IsInPost = false; } FlushQueue(); TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("QueuedSender", $"QSenderThread was closed for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l6_Debug)); } catch (Exception e) { IsInPost = false; TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("QueuedSender", "Exception in jcSenderThread.", eMsgLevel.l1_Error, "Error:" + e)); if (MyTargetNodeChannel?.SenderType != cdeSenderType.CDE_BACKCHANNEL) { FireSenderProblem(new TheRequestData() { ErrorDescription = $"1308:{e}" }); } } finally { IsSenderThreadRunning = false; IsAlive = false; IsInPost = false; CloudInRetry = false; StopHeartBeat(); } }
internal override void PostToSocket(TheDeviceMessage pMsg, byte[] pPostBuffer, bool PostAsBinary, bool IsInitialConnect) { TheDiagnostics.SetThreadName("WSPostToSocketCSWS:" + (MyQSender.MyTargetNodeChannel?.ToString() ?? "DEAD")); if (MyQSender != null && !MyQSender.IsConnected && !IsInitialConnect) { Shutdown(true, "1653:QSenderCSWS not connected but Posting in illegal state"); return; } if (!ProcessingAllowed) //NEW:V3BETA2: New Waiting Algorythm WaitUntilProcessingAllowed(); if (!IsActive || !TheBaseAssets.MasterSwitch) return; if (websocket == null && webSocketSession==null) { eventClosed?.Invoke("1654:WebSockets are down"); return; } ProcessingAllowed = false; try { if (pPostBuffer != null) { TheCDEKPIs.IncrementKPI(eKPINames.QKBSent, pPostBuffer.Length); if (PostAsBinary) { if (webSocketSession != null) webSocketSession.SendB(pPostBuffer); else { websocket?.Send(pPostBuffer); } } else { if (webSocketSession != null) webSocketSession.SendB(TheCommonUtils.CArray2UTF8String(pPostBuffer)); else { websocket?.Send(TheCommonUtils.CArray2UTF8String(pPostBuffer)); } } } else { string toSend = TheCommonUtils.SerializeObjectToJSONString(pMsg); if (PostAsBinary) { byte[] toSendb = TheCommonUtils.CUTF8String2Array(toSend); TheCDEKPIs.IncrementKPI(eKPINames.QKBSent, toSendb.Length); if (webSocketSession != null) webSocketSession.SendB(toSendb); else { websocket?.Send(toSendb); } } else { if (webSocketSession != null) webSocketSession.SendB(toSend); else { websocket?.Send(toSend); } } } } catch (Exception e) { Shutdown(true, "1655:DoPostToSocketCSWS had a fault: "+e); } if (mre != null) ProcessingAllowed = true; }
internal override void PostToSocket(TheDeviceMessage pMsg, byte[] pPostBuffer, bool SendAsBinary, bool IsInitialConnect) { TheDiagnostics.SetThreadName("WSPostToSocket:" + ((MyQSender?.MyTargetNodeChannel != null) ? MyQSender.MyTargetNodeChannel.ToString():"DEAD")); if (MyQSender?.MyTargetNodeChannel == null) { TheBaseAssets.MySYSLOG.WriteToLog(4369, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("ProcessWS", $"QSender8 not Has not QSender or TargetChannel {MyQSender}", eMsgLevel.l1_Error)); Shutdown(true, "1608:WS8 has not QSender but is Posting - illegal state"); return; } if (MyQSender != null && !MyQSender.IsConnected && !IsInitialConnect) { TheBaseAssets.MySYSLOG.WriteToLog(4369, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("ProcessWS", "QSender8 not connected but Posting - illegal state", eMsgLevel.l1_Error)); Shutdown(true, "1609:QSender8 not connected but Posting - illegal state"); return; } bool HasFaulted = false; lock (_postToSocketLock) // The lock needs to be at the websocket level: assumption is that there is at most one WSProcessor per socket! { if (!IsActive || !TheBaseAssets.MasterSwitch) { return; } ProcessingAllowed = false; string errorMsg = ""; try { if (!IsSocketReady(websocket)) { HasFaulted = true; errorMsg = "Socket Not Ready"; } else { // TODO MH - Move this outside of the lock so we can minimize the lock time? Or are there ordering constraints on the serialization for some reason? ArraySegment <byte> outputBuffer; if (pPostBuffer != null) { TheCDEKPIs.IncrementKPI(eKPINames.QKBSent, pPostBuffer.Length); outputBuffer = new ArraySegment <byte>(pPostBuffer); } else { string tStr = TheCommonUtils.SerializeObjectToJSONString(pMsg); TheCDEKPIs.IncrementKPI(eKPINames.QKBSent, tStr.Length); outputBuffer = new ArraySegment <byte>(Encoding.UTF8.GetBytes(tStr)); } //LogBufferToFile("wsoutputputlog", outputBuffer.Array, outputBuffer.Offset, outputBuffer.Count); Task tTask = websocket.SendAsync(outputBuffer, SendAsBinary ? WebSocketMessageType.Binary : WebSocketMessageType.Text, true, TheBaseAssets.MasterSwitchCancelationToken); tTask.Wait(TheBaseAssets.MyServiceHostInfo.TO.WsTimeOut * 10); if (!tTask.IsCompleted) { var timeoutValue = TheBaseAssets.MyServiceHostInfo.TO.WsTimeOut * 10; TheBaseAssets.MySYSLOG.WriteToLog(43610, new TSM("TheWSProcessor", $"WebSocketServer-PostToSocket error: PostAsync Timeout {tTask.Status} after {timeoutValue} ms for {MyQSender?.MyTargetNodeChannel}", eMsgLevel.l1_Error)); errorMsg = $"SendAsync timed out after {timeoutValue} ms"; HasFaulted = true; } } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(43610, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheWSProcessor", "WebSocketServer-PostToSocket Error:", eMsgLevel.l1_Error, ((int)TheBaseAssets.MyServiceHostInfo.DebugLevel > 1? e.ToString():e.Message))); errorMsg = $"PostToSocket failed: {e.Message}"; HasFaulted = true; } if (HasFaulted) { Shutdown(true, $"1610:{errorMsg}"); } //IsPosting = false; if (mre != null) { ProcessingAllowed = true; } } }
public async Task ProcessWS() { TheDiagnostics.SetThreadName("WSProcessWS"); if (MyQSender == null) { TheBaseAssets.MySYSLOG.WriteToLog(4366, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheWSProcessor", "ProcessWS - no QSender Specified! ", eMsgLevel.l1_Error)); return; } int tMaxMsgSize = 0; ArraySegment <byte> buffer; byte[] receiveBuffer; try { if (IsClient) { tMaxMsgSize = TheCommonUtils.GetMaxMessageSize(MyQSender.MyTargetNodeChannel.SenderType); } else { tMaxMsgSize = TheCommonUtils.GetMaxMessageSize(TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType); } receiveBuffer = new byte[tMaxMsgSize]; buffer = new ArraySegment <byte>(receiveBuffer); TheBaseAssets.MySYSLOG.WriteToLog(4367, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheWSProcessor", "New ProcessWS thread started ", eMsgLevel.l4_Message)); } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(4367, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheWSProcessor", "Failure while starting new ProcessWS thread", eMsgLevel.l4_Message, e.ToString())); return; } CloseFired = false; bool HasFaulted = false; string tCause = "1604:Thread ended"; try { if (IsSocketReady(websocket)) { if (IsClient) { //MyQSender.IsConnected = true; byte[] tSendBuffer = TheCommCore.SetConnectingBuffer(MyQSender); PostToSocket(null, tSendBuffer, false, true); } } while (TheBaseAssets.MasterSwitch && IsActive && IsSocketReady(websocket)) { WebSocketReceiveResult receiveResult = await websocket.ReceiveAsync(buffer, CancellationToken.None); if (receiveResult.MessageType == WebSocketMessageType.Close) { tCause = "1605:WebSocket Closed"; break; } //LogBufferToFile("wsinputlog.dat", buffer.Array, buffer.Offset, receiveResult.Count); if (MyQSender == null || !MyQSender.IsAlive) { tCause = "1606:QSender No longer alive"; break; } int offset = receiveResult.Count; bool IsUsingTArray = false; byte[] tPostData = null; int tPostDataLength = 0; if (receiveResult.EndOfMessage == false) { List <byte[]> tTelList = new List <byte[]>(); byte[] tArray = null; while (receiveResult.EndOfMessage == false) { if (IsUsingTArray) { var arraySeg = new ArraySegment <byte>(tArray, offset, tMaxMsgSize - offset); receiveResult = await websocket.ReceiveAsync(arraySeg, CancellationToken.None); //LogBufferToFile("wsinputlog.dat", arraySeg.Array, arraySeg.Offset, receiveResult.Count); } else { var arraySeg = new ArraySegment <byte>(receiveBuffer, offset, tMaxMsgSize - offset); receiveResult = await websocket.ReceiveAsync(arraySeg, CancellationToken.None); //LogBufferToFile("wsinputlog.dat", arraySeg.Array, arraySeg.Offset, receiveResult.Count); } if (receiveResult.Count == 0) { if (receiveResult.Count + offset != tMaxMsgSize) { TheBaseAssets.MySYSLOG.WriteToLog(4369, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("ProcessWS", string.Format("WS Buffer count wrong: Max={0} Offset={1} Count={2}", tMaxMsgSize, offset, receiveResult.Count), eMsgLevel.l1_Error)); } tArray = new byte[tMaxMsgSize]; if (!IsUsingTArray) { tTelList.Add(receiveBuffer); } tTelList.Add(tArray); IsUsingTArray = true; offset = 0; } else { offset += receiveResult.Count; } } if (tTelList.Count > 0) { tPostData = new byte[((tTelList.Count - 1) * tMaxMsgSize) + offset]; } tPostDataLength = 0; for (int i = 0; i < tTelList.Count - 1; i++) { byte[] tb = tTelList[i]; TheCommonUtils.cdeBlockCopy(tb, 0, tPostData, i * tMaxMsgSize, tMaxMsgSize); tb = null; } if (IsUsingTArray && offset > 0 && tTelList.Count > 0 && tPostData != null) { TheCommonUtils.cdeBlockCopy(tTelList[tTelList.Count - 1], 0, tPostData, (tTelList.Count - 1) * tMaxMsgSize, offset); tPostDataLength = tPostData.Length; } //tTelList.Clear(); } if (!IsUsingTArray) { tPostData = new byte[offset]; TheCommonUtils.cdeBlockCopy(receiveBuffer, 0, tPostData, 0, offset); tPostDataLength = offset; } //LogBufferToFile("wsinputbactchedlog.dat", tPostData, 0, tPostData.Length); TheCommonUtils.cdeRunAsync("ProcessFromWS", true, (o) => ProcessIncomingData(null, (byte [])o, ((byte[])o).Length), tPostData); } } catch (Exception eee) { HasFaulted = true; if (eee.Source == "System") { TheBaseAssets.MySYSLOG.WriteToLog(4369, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("ProcessWS", "ProcessWS Loop has failed because WebSocket was closed during ReceiveAsync.", eMsgLevel.l1_Error)); } else { TheBaseAssets.MySYSLOG.WriteToLog(4369, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("ProcessWS", "ProcessWS Loop has failed.", eMsgLevel.l1_Error, eee.ToString())); } } TheBaseAssets.MySYSLOG.WriteToLog(4369, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("ProcessWS", $"ProcessWS Loop for {OwnerNodeID} has ended. Faulted:{HasFaulted} HasWS:{websocket != null}", eMsgLevel.l3_ImportantMessage)); ConnectSuccess = false; if (HasFaulted || (websocket != null && websocket.State != WebSocketState.Closed)) { tCause = string.Format("1607:WebSocket Faulted:{0} WS State:{1}", HasFaulted, websocket != null?websocket.State.ToString():"is null"); } Shutdown(true, tCause); }
internal static void InitAssets(TheBaseApplication pApp) { if (IsInitialized) { return; } IsInitialized = true; if (MyServiceHostInfo == null || !(MySecrets?.IsApplicationIDValid() == true)) { MasterSwitch = false; return; } MyApplication = pApp; #region step 1: Moved from StartApplication to here as all the following code is updating TheBaseAssets //The following section are "app.config" only settings required before cdeTPI is loaded. These settings cannot be set via the Provisioning Service int delay = TheCommonUtils.CInt(MySettings.GetSetting("StartupDelay")); if (delay > 0) { TheCommonUtils.SleepOneEye((uint)(delay * 1000), 100); } string temp = MySettings.GetSetting("AllowEnvironmentVarsToOverrideConfig"); if (!string.IsNullOrEmpty(temp)) { MyServiceHostInfo.AllowEnvironmentVarsToOverrideConfig = TheCommonUtils.CBool(temp); } temp = MySettings.GetSetting("AllowEnvironmentVars"); if (!string.IsNullOrEmpty(temp)) { MyServiceHostInfo.AllowEnvironmentVars = TheCommonUtils.CBool(temp); } temp = MySettings.GetSetting("DEBUGLEVEL"); if (!string.IsNullOrEmpty(temp)) { MyServiceHostInfo.DebugLevel = (eDEBUG_LEVELS)TheCommonUtils.CInt(temp); } //Clouds have special behavior and the CDE needs to know this upfront temp = MySettings.GetSetting("IsCloudService"); if (!string.IsNullOrEmpty(temp)) { MyServiceHostInfo.IsCloudService = TheCommonUtils.CBool(temp); } temp = MySettings.GetSetting("ISOEN"); if (!string.IsNullOrEmpty(temp)) { MyServiceHostInfo.IsIsolated = true; MyServiceHostInfo.IsoEngine = temp; MyServiceHostInfo.cdeNodeType = cdeNodeType.Active; } else { temp = MySettings.GetSetting("UseRandomDeviceID"); if (!string.IsNullOrEmpty(temp)) { MyServiceHostInfo.UseRandomDeviceID = TheCommonUtils.CBool(temp); } } //Step 2: Restore from backup if exists #if CDE_NET45 // Backup/Restore only support on NET45 // To ensure that restored backups are not overwritten during shutdown, we write them to a temp directory and move them into place on start up if (!MyServiceHostInfo.UseRandomDeviceID && !MyServiceHostInfo.IsIsolated) { string cacheParentPath = TheCommonUtils.GetCurrentAppDomainBaseDirWithTrailingSlash() + "ClientBin\\"; if (Directory.Exists(cacheParentPath + "__CacheToRestore")) { // Keep the old Cache around just in case try { // First make space for the old copy, in case there was one already if (Directory.Exists(cacheParentPath + "__CacheOld")) { Directory.Delete(cacheParentPath + "__CacheOld", true); } } catch { //ignored } try { Directory.Move(cacheParentPath + "Cache", cacheParentPath + "__CacheOld"); } catch { //ignored } // Now move the restored cache into place try { Directory.Move(cacheParentPath + "__CacheToRestore", cacheParentPath + "Cache"); } catch { TheSystemMessageLog.ToCo("Failure while restoring backup"); } } } #endif MyServiceHostInfo.EnableTaskKPIs = TheCommonUtils.CBool(MySettings.GetSetting("EnableTaskKPIs")); if (MyServiceHostInfo.EnableTaskKPIs) { var taskKpiThread = new Thread(() => { do { var kpis = TheCommonUtils.GetTaskKpis(null); TheSystemMessageLog.ToCo($"Tasks {DateTime.Now}: {TheCommonUtils.SerializeObjectToJSONString(kpis)}"); Thread.Sleep(1000); // Keeping it simple here, to minimize interference on task scheduler/thread scheduler etc. (Assumption: not used on production systems) // TheCommonUtils.SleepOneEye(1000, 1000); } while (MasterSwitch && !Engines.TheCDEngines.IsHostReady && MyServiceHostInfo.EnableTaskKPIs); TheSystemMessageLog.ToCo($"Tasks {DateTime.Now}: KPIs Handoff to NodeHost"); }); taskKpiThread.Start(); } #endregion if (MyActivationManager == null) { MyActivationManager = new TheDefaultActivationManager(MySecrets, MySYSLOG); } #region step 3: analyse os environment information OperatingSystem os = Environment.OSVersion; var osInfoForLog = $"C-DEngine version: {BuildVersion} OS:{Environment.OSVersion} OS Version:{os.VersionString} OS Version Numbers: {os.Version.Major}.{os.Version.Minor}.{os.Version.Build}.{os.Version.Revision} Platform:{os.Platform} SP:{os.ServicePack} Processor Count: {Environment.ProcessorCount} IsMono:{(Type.GetType("Mono.Runtime") != null)} IsNetCore:{TheCommonUtils.IsNetCore()} Product: {TheCommonUtils.GetAssemblyProduct(typeof(TheBaseAssets))} "; TheSystemMessageLog.ToCo(osInfoForLog); MyServiceHostInfo.OSInfo = osInfoForLog; string dotNetInfoForLog = string.Empty; #if !CDE_NET35 && !CDE_NET4 try { string frameworkDescription = null; string osDescription = null; string processArchitecture = null; string osArchitecture = null; #if CDE_STANDARD frameworkDescription = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription; osDescription = System.Runtime.InteropServices.RuntimeInformation.OSDescription; processArchitecture = System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString(); osArchitecture = System.Runtime.InteropServices.RuntimeInformation.OSArchitecture.ToString(); #else var rtInfoType = Type.GetType("System.Runtime.InteropServices.RuntimeInformation, System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); if (rtInfoType != null) { frameworkDescription = rtInfoType.GetProperty("FrameworkDescription").GetValue(null).ToString(); osDescription = rtInfoType.GetProperty("OSDescription").GetValue(null).ToString(); processArchitecture = rtInfoType.GetProperty("ProcessArchitecture").GetValue(null).ToString(); osArchitecture = rtInfoType.GetProperty("OSArchitecture").GetValue(null).ToString(); } #endif if (!string.IsNullOrEmpty(frameworkDescription)) { dotNetInfoForLog = $"NetFrameWork:{frameworkDescription} Processor:{processArchitecture} OS:{osDescription } OS Arch:{osArchitecture}"; TheSystemMessageLog.ToCo(dotNetInfoForLog); MyServiceHostInfo.OSInfo += $" {dotNetInfoForLog}"; } } catch { } #endif if (TheCommonUtils.IsMono()) // CODE REVIEW: Need to clean this up - do we mean Mono or Linux or case-insensitive file systems? CM: No- here we need this to find out if we are running in the MONO Runtime { MyServiceHostInfo.cdePlatform = cdePlatform.MONO_V3; } else { #if CDE_NET35 MyServiceHostInfo.cdePlatform = cdePlatform.X32_V3; #elif CDE_NET4 MyServiceHostInfo.cdePlatform = Environment.Is64BitProcess ? cdePlatform.NETV4_64 : cdePlatform.NETV4_32; #elif CDE_STANDARD MyServiceHostInfo.cdePlatform = cdePlatform.NETSTD_V20; #else MyServiceHostInfo.cdePlatform = TheCommonUtils.GetAssemblyPlatform(Assembly.GetEntryAssembly(), false, out var empty);// old: Environment.Is64BitProcess ? cdePlatform.X64_V3 : cdePlatform.X32_V4; #endif } TheSystemMessageLog.ToCo("BaseDir: " + MyServiceHostInfo.BaseDirectory); #endregion #region step 4: Prepare essential Subsystems (Syslog, ScopeManager, Diagnostics, Caches, AppInfo) MySYSLOG = new TheSystemMessageLog(500); // No more ToCo after this point (will be ignored) TheCDEKPIs.Reset(); MyServiceHostInfo.MiniHostInfo.MySYSLOG = MySYSLOG; MyServiceHostInfo.MiniHostInfo.MyKPIs = new TheKPIs(); if (MyScopeManager == null) { MyScopeManager = new TheDefaultScopeManager(); } MyScopeManager.SetMiniHSI(MyServiceHostInfo.MiniHostInfo); MyScopeManager.RegisterScopeChanged(localEventScopeChanged); TheDiagnostics.InitDiagnostics(); TheDiagnostics.SetThreadName("MAIN THREAD"); TheQueuedSenderRegistry.Startup(); MyBlobCache = new TheMirrorCache <TheBlobData>(MyServiceHostInfo.TO.StorageCleanCycle); MyReceivedParts = new TheMirrorCache <TheReceivedParts>(MyServiceHostInfo.TO.StorageCleanCycle); //TODO: I hope there is a better way to do this for Metro! MyServiceTypes.Add(typeof(TheBaseAssets)); MyServiceHostInfo.TO.MakeHeartNormal(); MyAppInfo = new ThePluginInfo { cdeMID = MyServiceHostInfo.cdeMID, CurrentVersion = MyServiceHostInfo.CurrentVersion, Developer = MyServiceHostInfo.VendorName, DeveloperUrl = MyServiceHostInfo.VendorUrl, HomeUrl = MyServiceHostInfo.SiteName, IconUrl = MyServiceHostInfo.UPnPIcon, LongDescription = MyServiceHostInfo.Description, Platform = MyServiceHostInfo.cdePlatform, Copyrights = MyServiceHostInfo.Copyrights, Price = 0, ServiceDescription = MyServiceHostInfo.Title, ServiceName = MyServiceHostInfo.ApplicationName, Capabilities = new List <eThingCaps> { eThingCaps.Host }, Categories = new List <string>(), FilesManifest = new List <string>() }; if (MyServiceHostInfo.ManifestFiles != null) { MyAppInfo.FilesManifest.AddRange(MyServiceHostInfo.ManifestFiles); } #endregion //Now load provisioning and local settings then parse them #pragma warning disable CS0618 // Type or member is obsolete - its allowed here if (!TheCDESettings.ParseSettings(MyCmdArgs, true, false)) #pragma warning restore CS0618 // Type or member is obsolete { MasterSwitch = false; return; } if (MyCodeSigner == null) { MyCodeSigner = new TheDefaultCodeSigning(MySecrets, MySYSLOG); } string tBaseDir = MyServiceHostInfo.BaseDirectory; if (MyServiceHostInfo.cdeHostingType == cdeHostType.IIS) { tBaseDir += "bin\\"; } string uDir = tBaseDir; if (!string.IsNullOrEmpty(MyServiceHostInfo.ISMMainExecutable)) { uDir += MyServiceHostInfo.ISMMainExecutable; if (MyServiceHostInfo.cdeHostingType != cdeHostType.IIS) { var hostPath = uDir + ".exe"; if (!File.Exists(hostPath)) { // We may be running under .Net Core with a .dll-based host hostPath = uDir + ".dll"; } uDir = hostPath; } } else { uDir += "C-DEngine.dll"; } MyServiceHostInfo.CodeSignThumb = MyCodeSigner.GetAppCert(MyServiceHostInfo.DontVerifyTrust, uDir, MyServiceHostInfo.VerifyTrustPath, MyServiceHostInfo.DontVerifyIntegrity); //Must be loaded here to set trust level in HSI if (MyLoc as TheDefaultLocalizationUtils != null) { (MyLoc as TheDefaultLocalizationUtils).DoPseudoLoc = TheCommonUtils.CBool(MySettings.GetSetting("DoPseudoLoc")); } #region step 5: output some system information if (MyServiceHostInfo.IsMemoryOptimized) { MySYSLOG.SetMaxLogEntries(10); } MySYSLOG.WriteToLog(4151, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheBaseAssets", osInfoForLog, eMsgLevel.l4_Message)); if (!string.IsNullOrEmpty(dotNetInfoForLog)) { MySYSLOG.WriteToLog(4152, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheBaseAssets", dotNetInfoForLog, eMsgLevel.l4_Message)); } MySYSLOG.WriteToLog(4153, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("TheBaseAssets", "BaseDir: " + MyServiceHostInfo.BaseDirectory, eMsgLevel.l4_Message)); #endregion #region step 6: determine WebSocket8 vs. WebSocketsSharp var ws8FlagTemp = MySettings.GetSetting("DisallowWebSocket8"); if (!string.IsNullOrEmpty(ws8FlagTemp)) { MyServiceHostInfo.IsWebSocket8Active = !TheCommonUtils.CBool(ws8FlagTemp); MySYSLOG.WriteToLog(4154, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheBaseAssets", $"Setting IsWebSocket8Active to {MyServiceHostInfo.IsWebSocket8Active} due to config", eMsgLevel.l4_Message)); } else { MyServiceHostInfo.IsWebSocket8Active = true; } if ((os.Platform != PlatformID.Win32NT && !TheCommonUtils.IsNetCore()) || (os.Platform == PlatformID.Win32NT && (os.Version.Major < 6 || (os.Version.Major == 6 && os.Version.Minor < 2)))) { MyServiceHostInfo.IsWebSocket8Active = false; string tWSMsg = "Older Windows or non-Windows OS Detected - No OS Support for WebSockets Found: "; #if !CDE_USECSWS //OK TheBaseAssets.MyServiceHostInfo.DisableWebSockets = true; tWSMsg += "WebSockets are turned Off"; #else tWSMsg += "Switching to WebSockets-Sharp"; #endif MySYSLOG.WriteToLog(4155, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheBaseAssets", tWSMsg, eMsgLevel.l4_Message)); } #endregion #region step 7: Initialize Localization subsystem (ILocalizationHooks) bool bLocInitialized = false; try { var entryAssembly = Assembly.GetEntryAssembly(); //This does not work in IIS! if (entryAssembly != null) { var CDEPlugins = from t in entryAssembly.GetTypes() let ifs = t.GetInterfaces() where ifs != null && ifs.Length > 0 && (ifs.Contains(typeof(ILocalizationHooks))) select new { Type = t, t.Namespace, t.Name, t.FullName }; if (CDEPlugins != null && CDEPlugins.Any()) { MyLoc = Activator.CreateInstance(CDEPlugins.First().Type) as ILocalizationHooks; } bLocInitialized = true; } } catch { } if (!bLocInitialized) { MySYSLOG.WriteToLog(4156, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheBaseAssets", "3rd Party ILocalization Hooks not found - using built-in", eMsgLevel.l4_Message)); } #endregion #region step 8: Set MyStationUrl switch (MyServiceHostInfo.cdeHostingType) { case cdeHostType.Phone: case cdeHostType.Metro: MyServiceHostInfo.MyDeviceMoniker = "CDEV://"; break; case cdeHostType.Silverlight: MyServiceHostInfo.MyDeviceMoniker = "CDES://"; break; case cdeHostType.Device: MyServiceHostInfo.MyDeviceMoniker = "CDEC://"; break; case cdeHostType.Mini: MyServiceHostInfo.MyDeviceMoniker = "CDEM://"; break; default: //Services MyServiceHostInfo.MyDeviceMoniker = "CDEB://"; break; } if (TheCommonUtils.IsHostADevice()) { MyServiceHostInfo.MyStationURL = MyServiceHostInfo.MyDeviceMoniker + "{" + MyServiceHostInfo.MyDeviceInfo.DeviceID + "}".ToUpper(); //MSU-OK } else { if (MyServiceHostInfo.MyAltStationURLs.Count(s => s.StartsWith("CDEB")) == 0) { MyServiceHostInfo.MyAltStationURLs.Add("CDEB://{" + MyServiceHostInfo.MyDeviceInfo.DeviceID + "}"); //TODO: Backchannel Possibly save to Config File } } #endregion #region step 9: Start Localhost QSender and SessionStateManager MySession = new TheSessionStateManager(MyServiceHostInfo); LocalHostQSender = new TheQueuedSender(); //NO connected or Error Event necessary LocalHostQSender.StartSender(new TheChannelInfo(MyServiceHostInfo.MyDeviceInfo.DeviceID, MyScopeManager.ScopeID, MyServiceHostInfo.MyDeviceInfo.SenderType, MyServiceHostInfo.GetPrimaryStationURL(false)), null, false); //NEW:2.06 Setting Realscope here ///null correct - no subs on LocalhostQS in beginning //RScope-OK if ((MyServiceHostInfo.DisableWebSockets || MyServiceHostInfo.MyStationWSPort == 0) && !TheCommonUtils.IsHostADevice()) { MySYSLOG.WriteToLog(4157, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("TheBaseAssets", $"WebSockets Disabled - no WSPort specified {MyServiceHostInfo.MyStationWSPort} or DisableWebSocket={MyServiceHostInfo.DisableWebSockets}", eMsgLevel.l4_Message)); } #endregion // Post Device ID settings //Step 10: Save all settings to local cdeTPI MySettings.UpdateLocalSettings(); }