internal static void ParseUnsubscribe(string pTopics, TheQueuedSender pQSender) { TheBaseAssets.MySYSLOG.WriteToLog(301, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"ParseUnsubscribe for Topics={pTopics} of {pQSender.MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l7_HostDebugMessage)); if (string.IsNullOrEmpty(pTopics) || pQSender == null) { return; } bool WasSubscribed = pQSender.Unsubscribe(pTopics); TheBaseAssets.MySYSLOG.WriteToLog(302, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"ParseUnsubscribe: Removing Topic Topics={pTopics} of {pQSender.MyTargetNodeChannel?.ToMLString()} Was Sub'ed: {WasSubscribed}", eMsgLevel.l7_HostDebugMessage)); #region DebugInfo if (TheBaseAssets.MyServiceHostInfo.DebugLevel > eDEBUG_LEVELS.FULLVERBOSE) { string tContent = "ParseUnsubscribe - Unsubscribed from: " + pTopics; eMsgLevel tLev = eMsgLevel.l4_Message; if (WasSubscribed) { tLev = eMsgLevel.l2_Warning; tContent = "A Subscription was not Found for: " + pTopics; } TheBaseAssets.MySYSLOG.WriteToLog(304, new TSM("CoreComm", tContent, tLev)); } #endregion }
internal static void ParseSubscribe(string pScopedTopics, TheQueuedSender pQSender) { if (string.IsNullOrEmpty(pScopedTopics) || pQSender == null) { return; } TheBaseAssets.MySYSLOG.WriteToLog(295, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"DoParseSubscribe for Topics={pScopedTopics} of {pQSender.MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l7_HostDebugMessage)); bool HasSubscribedBefore = !pQSender.Subscribe(pScopedTopics, true); //Incoming Subs are native to connected node TheBaseAssets.MySYSLOG.WriteToLog(300, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"DoParseSubscribe: {pQSender.MyTargetNodeChannel?.ToMLString()} updates Subscription Topis: {pScopedTopics} Was Sub'ed before: {HasSubscribedBefore}", eMsgLevel.l7_HostDebugMessage)); }
/// <summary> /// Connect to a Custom URL via ISB Connect and a custom Scope /// </summary> /// <param name="pUrl">URL to connect to</param> /// <param name="pEasyScope">Easy ScopeID generator for the connection. If next parameter is true, this parameter will be interpreted as a scrambled ScopeID</param> /// <param name="pInitialSubscriptions">List of initial Subscriptions separated by ;</param> /// <param name="pIsScrambledID">If true, the EasyScopeID is a scrambled ScopeID</param> /// <returns></returns> public string Connect(string pUrl, string pEasyScope, string pInitialSubscriptions, bool pIsScrambledID) { if (string.IsNullOrEmpty(pUrl)) { ERR = "no url set!"; return(ERR); } if (string.IsNullOrEmpty(pEasyScope)) { ERR = "No scope set - unscoped connection not allowed"; return(ERR); } mURL = pUrl; mInitSubs = pInitialSubscriptions; TheSessionState tSessionState = TheBaseAssets.MySession.CreateSession(null, Guid.Empty); if (!string.IsNullOrEmpty(pEasyScope)) { if (pIsScrambledID) { mSScope = tSessionState.SScopeID = pEasyScope; RS = TheBaseAssets.MyScopeManager.GetRealScopeID(tSessionState.SScopeID); //GRSI: rare } else { RS = TheBaseAssets.MyScopeManager.GetRealScopeIDFromEasyID(pEasyScope); mSScope = tSessionState.SScopeID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(RS, true); //GRSI: rare } } MyQSender = new TheQueuedSender { MyISBlock = this }; IS = TheBaseAssets.MyScopeManager.AddScopeID(pInitialSubscriptions, false, RS); if (MyQSender.StartSender(new TheChannelInfo(Guid.Empty, RS, cdeSenderType.CDE_CUSTOMISB, pUrl) { MySessionState = tSessionState }, null, false)) { FNI = MyQSender.MyTargetNodeChannel.cdeMID.ToString(); SID = tSessionState.SScopeID; OnThisNode = true; } else { ERR = "Qsender could not be created"; TheBaseAssets.MySYSLOG.WriteToLog(299, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"CreateCustomSender: QueuedSender could not be created for Target:{pUrl}", eMsgLevel.l7_HostDebugMessage)); MyQSender = null; } return(ERR); }
internal void sinkExpired(TheSessionState pState) { if (pState != null) { if (pState.CID != Guid.Empty) { TheUserManager.RemoveTempUser(pState.CID); } TheQueuedSender tQSend = TheQueuedSenderRegistry.GetSenderBySEID(pState.cdeMID); if (tQSend != null) { tQSend.FireSenderProblem(new TheRequestData() { ErrorDescription = "1500:Session for this QSender expired" }); } } }
internal virtual bool Connect(TheQueuedSender pSender) { //ISM.TheDiagnostics.SetThreadName("WSConnect:4:" + pSender.MyTargetNodeChannel.ToString()); return(true); }
internal static bool ParseSimplex(string pScopedTopic, TSM pMessage, TheQueuedSender pQSender) //, TheSessionState pSessionState, Action<TSM> pLocalCallback) { if (pMessage == null) { return(false); } #if !JC_COMMDEBUG try { #endif if (pMessage?.TXT?.Equals("CDE_DELETEORPHAN") == true) { TheQueuedSenderRegistry.RemoveOrphan(TheCommonUtils.CGuid(pMessage.PLS)); return(false); } if (pQSender == null) { TheBaseAssets.MySYSLOG.WriteToLog(291, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", $"QSender not found! Received from ORG:{TheCommonUtils.GetDeviceIDML(pMessage?.ORG)}", eMsgLevel.l1_Error, pMessage?.PLS)); return(false); } //SECURITY-REVIEW: This cannot be permitted without extra tokens and Encryption! otherwise it can be used to change a nodes scope on the fly! //if ("CDE_UPDATESCOPE".Equals(pMessage.TXT)) //{ // pQSender.UpdateSubscriptionScope(TheBaseAssets.MyScopeManager.GetRealScopeID(pMessage.SID)); //GRSI: rare // return true; //} if (pQSender != null && pMessage.ENG?.StartsWith(eEngineName.ContentService) == true && pMessage?.TXT == "CDE_SERVICE_INFO" && pQSender.MyTargetNodeChannel?.RealScopeID == TheBaseAssets.MyScopeManager.GetRealScopeID(pMessage.SID)) { try { pQSender.SetNodeInfo(TheCommonUtils.DeserializeJSONStringToObject <TheNodeInfoClone>(pMessage?.PLS)); } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(23056, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"Error decoding SystemInfo {pQSender?.MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l1_Error, e.ToString())); } } if (pMessage.TXT?.Equals("CDE_SUBSCRIBE") == true || pMessage.TXT?.Equals("CDE_INITIALIZE") == true) //9-9-2012 CDEC Did not work right on CDE_INIT { TheBaseAssets.MySYSLOG.WriteToLog(292, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"Parse-Simplex Subscribe from {pQSender?.MyTargetNodeChannel?.ToMLString()} Parsed: {pMessage?.PLS}", eMsgLevel.l7_HostDebugMessage)); if (pQSender?.MyISBlock != null && !TheBaseAssets.MyServiceHostInfo.IsCloudService) { TheBaseAssets.MySYSLOG.WriteToLog(292, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", "Parse-Simplex Subscribe rejected for Custom ISBConnect", eMsgLevel.l7_HostDebugMessage)); return(true); } ParseSubscribe(pMessage.PLS, pQSender); if (pMessage.ENG.Equals("CLOUDSYNC")) { string[] tTopics = pMessage.PLS.Split(';'); foreach (string t in tTopics) { TSM.GetScrambledIDFromTopic(t, out string tEng); if (TheThingRegistry.IsEngineRegistered(tEng)) { IBaseEngine tsBase = TheThingRegistry.GetBaseEngine(tEng); tsBase?.GetBaseThing()?.FireEvent(eEngineEvents.NewSubscription, tsBase.GetBaseThing(), pQSender.MyTargetNodeChannel, true); } } return(true); } else { TheThing tBase2 = TheThingRegistry.GetBaseEngineAsThing(pMessage.ENG); if (tBase2 != null) { tBase2.FireEvent(eEngineEvents.NewSubscription, tBase2, pQSender.MyTargetNodeChannel, true); } } if (pMessage.TXT.Equals("CDE_SUBSCRIBE")) //NEW:2.06 Make sure Subscribe and Unsubscribe only go to first node { return(true); } else { return(false); } } if (pMessage.TXT?.Equals("CDE_UNSUBSCRIBE") == true) { TheBaseAssets.MySYSLOG.WriteToLog(292, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"Parse-Simplex Unsubscribe from {pQSender.MyTargetNodeChannel?.ToMLString()} Parsed: {pMessage.PLS}", eMsgLevel.l7_HostDebugMessage)); ParseUnsubscribe(pMessage.PLS, pQSender); return(true); //NEW:2.06 Make sure Subscribe and Unsubscribe only go to first node } #if !JC_COMMDEBUG } catch (Exception ee) { TheBaseAssets.MySYSLOG.WriteToLog(316, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", "Parse-Simplex", eMsgLevel.l1_Error, ee.ToString())); } #endif return(false); }
internal static void SetResponseBuffer(TheRequestData pRequestData, TheChannelInfo pChannelInfo, bool pSendPulse, string NopTopic, Guid owner, string pRefreshToken) { if (string.IsNullOrEmpty(NopTopic)) { TheQueuedSender tQ = null; if (pChannelInfo != null && pChannelInfo.cdeMID != Guid.Empty) //Send to Device First { tQ = TheQueuedSenderRegistry.GetSenderByGuid(pChannelInfo.cdeMID); } if (tQ != null) { if (pRequestData.WebSocket != null) { if (tQ.GetQueLength() == 0) { tQ.SendPickupMessage(); } return; } tQ.GetNextBackChannelBuffer(pRequestData); } } if (string.IsNullOrEmpty(NopTopic) && pRequestData.WebSocket != null) { return; //NEW:3.084 && !pSendPulse removed NEW:V3B3:2014-7-22 removed && pRequestData.ResponseBuffer != null } if (pRequestData.ResponseBuffer == null && pChannelInfo != null && (pSendPulse || (pChannelInfo.cdeMID != Guid.Empty || TheQueuedSenderRegistry.IsNodeIdInSenderList(pChannelInfo.cdeMID)))) { TheDeviceMessage tDev = new TheDeviceMessage { CNT = 0 }; //tDev.MET = 0; if (!string.IsNullOrEmpty(NopTopic)) { tDev.MSG = new TSM(); //Can be set without ORG and SID if (owner != Guid.Empty) { tDev.MSG.OWN = owner.ToString(); } if (NopTopic == "CDE_WSINIT") { NopTopic = TheCommCore.SetConnectingBufferStr(pChannelInfo, null); } } if (pChannelInfo.SenderType != cdeSenderType.CDE_JAVAJASON) //4.209: No longer sending SID to Browser; { if (TheBaseAssets.MyServiceHostInfo.EnableFastSecurity) { tDev.SID = pRequestData.SessionState.SScopeID; //SECURITY: All responses will have same Scrambled ScopeID - but ok because this is init telegram or HB } else { tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(pRequestData.SessionState.SScopeID, false); //GRSI: high frequency } } else { if (!string.IsNullOrEmpty(pRefreshToken)) { tDev.SID = pRefreshToken; } } tDev.FID = pRequestData.SessionState.GetNextSerial().ToString(); if (TheCommonUtils.IsDeviceSenderType(pChannelInfo.SenderType)) //IDST-OK: Must create RSA for Devices { TheCommonUtils.CreateRSAKeys(pRequestData.SessionState); tDev.RSA = pRequestData.SessionState.RSAPublic; } tDev.NPA = TheBaseAssets.MyScopeManager.GetISBPath(TheBaseAssets.MyServiceHostInfo.RootDir, pChannelInfo.SenderType, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType, pRequestData.SessionState.FID, pRequestData.SessionState.cdeMID, pRequestData.WebSocket != null); tDev.CNT = pSendPulse ? 1 : 0; tDev.TOP = NopTopic; tDev.DID = pChannelInfo.SenderType == cdeSenderType.CDE_JAVAJASON ? pChannelInfo.cdeMID.ToString() : TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString(); //There will be only one Message here - single poke or Mini Command or NOP Pickup List <TheDeviceMessage> tDevList = new List <TheDeviceMessage> { tDev }; if (pChannelInfo.SenderType == cdeSenderType.CDE_JAVAJASON || TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType == cdeSenderType.CDE_MINI || pChannelInfo.SenderType == cdeSenderType.CDE_MINI || pRequestData.WebSocket != null) { pRequestData.ResponseBuffer = TheCommonUtils.CUTF8String2Array(TheCommonUtils.SerializeObjectToJSONString(tDevList)); pRequestData.ResponseMimeType = "application/json"; } else { pRequestData.ResponseBuffer = TheCommonUtils.cdeCompressString(TheCommonUtils.SerializeObjectToJSONString(tDevList)); pRequestData.ResponseMimeType = "application/x-gzip"; } } if (pRequestData.ResponseBuffer == null && pChannelInfo != null && pChannelInfo.cdeMID != Guid.Empty) { TheBaseAssets.MySYSLOG.WriteToLog(290, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"Nothing to Send Back to {pChannelInfo?.ToMLString()}", eMsgLevel.l7_HostDebugMessage)); } }
internal static void DoExecuteCommand(string pInTopicBatch, TheQueuedSender pQSender, bool DoSendBackBuffer, TheRequestData pRequestData, List <TheDeviceMessage> pDevMessageList) { bool SendPulse = false; if (pDevMessageList != null && pDevMessageList.Count > 0) { foreach (TheDeviceMessage pDevMessage in pDevMessageList) { TSM recvMessage = null; string tTopic = ""; try { var tTargetNodeChannel = pQSender?.MyTargetNodeChannel; string pInTopic = pInTopicBatch; if (string.IsNullOrEmpty(pInTopic)) { pInTopic = pDevMessage.TOP; } recvMessage = pDevMessage.MSG; if (pQSender != null && tTargetNodeChannel != null && tTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON && recvMessage != null && string.IsNullOrEmpty(recvMessage.ORG)) { recvMessage.ORG = tTargetNodeChannel.cdeMID.ToString(); } #region ChunkResassembly string[] CommandParts = null; if (!string.IsNullOrEmpty(pInTopic)) { CommandParts = TheCommonUtils.cdeSplit(pInTopic, ":,:", false, false); tTopic = CommandParts[0]; } TheCDEKPIs.IncrementKPI(eKPINames.CCTSMsReceived); if (CommandParts != null && CommandParts.Length == 4 && !CommandParts[2].Equals("1")) { if (!TheCommonUtils.ProcessChunkedMessage(CommandParts, recvMessage)) { SendPulse = true; continue; } } #endregion if (recvMessage != null) { if (((TheBaseAssets.MyServiceHostInfo.RejectIncomingSETP && recvMessage.TXT?.StartsWith("SETP:") == true) || TheBaseAssets.MyServiceHostInfo.DisableNMIMessages) && recvMessage.ENG?.StartsWith(eEngineName.NMIService) == true) { TheCDEKPIs.IncrementKPI(eKPINames.QSSETPRejected); continue; } var tTopicSens = tTopic.Split('@')[0]; //only topic - no ScopeID var tTopicParts = tTopic.Split(';'); if (tTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON) { //4.209: JavaJason does no longer get the scope ID - hence telegrams coming from the browser have to be ammmended with SID here if (string.IsNullOrEmpty(recvMessage.SID) && !string.IsNullOrEmpty(pRequestData?.SessionState?.SScopeID)) { recvMessage.SID = pRequestData?.SessionState?.SScopeID; //Set the ScopeID in the SID of the message if (tTopic.StartsWith("CDE_SYSTEMWIDE")) { tTopic = $"{tTopicParts[0]}@{recvMessage.SID}"; if (tTopicParts.Length > 1) { tTopic += $";{tTopicParts[1]}"; //if a direct address is added use this too } } else if (!tTopic.Contains('@')) { tTopic += $"@{recvMessage.SID}"; } if (recvMessage.TXT == "CDE_SUBSCRIBE" || recvMessage.TXT == "CDE_INITIALIZE") { string MsgNoSID = null; recvMessage.PLS = TheBaseAssets.MyScopeManager.AddScopeID(recvMessage.PLS, recvMessage.SID, ref MsgNoSID, false, false); } } } if (tTopicParts.Length > 1) { tTopicSens += $";{tTopicParts[1]}"; //if a direct address is added use this too } if (TheQueuedSenderRegistry.WasTSMSeenBefore(recvMessage, pRequestData.SessionState.cdeMID, tTopicSens, tTargetNodeChannel?.RealScopeID)) //ATTENTION: RScope should come from pDevMessage { TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"EnterExecuteCommand: Message was seen before ORG:{TheCommonUtils.GetDeviceIDML(recvMessage?.ORG)} Topic:{tTopicSens}", eMsgLevel.l2_Warning)); //ORG-OK TheCDEKPIs.IncrementKPI(eKPINames.QSRejected); continue; } if (tTargetNodeChannel.cdeMID == Guid.Empty) { tTargetNodeChannel.cdeMID = recvMessage.GetLastRelay(); } if (tTargetNodeChannel.SenderType == cdeSenderType.NOTSET) { TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", "Sender Type for the QSender is not set! WE SHOULD NEVER GET HERE", eMsgLevel.l1_Error));//ORG-OK //3.218: Processing no longer allowed!!! return; } // Enable upper layers to do RSA decryption. Force overwrite for Browser even if SEID already set (may have been initialized to some other value) if (tTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON || String.IsNullOrEmpty(recvMessage.SEID)) { recvMessage.SEID = pRequestData.SessionState.cdeMID.ToString(); } if (pRequestData.SessionState != null && string.IsNullOrEmpty(pRequestData.SessionState.RemoteAddress)) { pRequestData.SessionState.RemoteAddress = tTargetNodeChannel.cdeMID.ToString(); } //NEW: User ID Management in Message after first node if (string.IsNullOrEmpty(recvMessage.UID) && pRequestData.SessionState != null && pRequestData.SessionState.CID != Guid.Empty) { recvMessage.UID = TheCommonUtils.cdeEncrypt(pRequestData.SessionState.CID.ToByteArray(), TheBaseAssets.MySecrets.GetAI()); //3.083: Must be cdeAI } } } catch (Exception ee) { TheBaseAssets.MySYSLOG.WriteToLog(319, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", "Execute Command Pre-Parsing Error", eMsgLevel.l1_Error, ee.ToString())); } if (recvMessage == null) { TheBaseAssets.MySYSLOG.WriteToLog(286, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"No Message for Parsing: Topic:{tTopic} - {pRequestData.ResponseBufferStr}", eMsgLevel.l7_HostDebugMessage)); } else { if (recvMessage.PLB != null && recvMessage.PLB.Length > 0 && string.IsNullOrEmpty(recvMessage.PLS)) { try { recvMessage.PLS = TheCommonUtils.cdeDecompressToString(recvMessage.PLB); recvMessage.PLB = null; } catch (Exception) { TheBaseAssets.MySYSLOG.WriteToLog(286, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"PLB to PLS decompress failed - Topic:{tTopic} Node:{pQSender?.MyTargetNodeChannel?.ToMLString()} ORG:{TheCommonUtils.GetDeviceIDML(recvMessage?.ORG)}", eMsgLevel.l7_HostDebugMessage, $"TXT:{recvMessage.TXT}"));//ORG-OK } } TheBaseAssets.MySYSLOG.WriteToLog(286, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"PLB to PLS parsing done - Topic:{tTopic} Node:{pQSender?.MyTargetNodeChannel?.ToMLString()} ORG:{TheCommonUtils.GetDeviceIDML(recvMessage?.ORG)}", eMsgLevel.l7_HostDebugMessage, $"TXT:{recvMessage.TXT}"));//ORG-OK if (!SendPulse) { SendPulse = recvMessage.SendPulse(); } TheCDEKPIs.IncrementKPI(eKPINames.CCTSMsEvaluated); } try { if (recvMessage != null && !string.IsNullOrEmpty(tTopic)) // tTopic != null) { if (!ParseSimplex(tTopic, recvMessage, pQSender)) //NEW:2.06 - No More Local Host processing here { if (TheBaseAssets.MyServiceHostInfo.MaximumHops == 0 || recvMessage.HobCount() < TheBaseAssets.MyServiceHostInfo.MaximumHops) { if (!tTopic.StartsWith("CDE_CONNECT") || !TheBaseAssets.MyServiceHostInfo.AllowMessagesInConnect) // Should never get here if AllowMessagesInConnect is false, but avoid global publish just in case... { TheCDEKPIs.IncrementKPI(eKPINames.CCTSMsRelayed); TheCommCore.PublishCentral(tTopic, recvMessage, false, null, false, pQSender?.MyTargetNodeChannel?.IsTrustedSender ?? false); } else { // Message is part of a CDE_CONNECT: Republish it to enable single-post message sending (i.e. MSB/Service Gateway scenario) TheCDEKPIs.IncrementKPI(eKPINames.CCTSMsRelayed); // TODO SHould we have a separate KPI for this TheCommCore.PublishCentral(recvMessage, true, pQSender.MyTargetNodeChannel.IsTrustedSender); } } } else { if (pQSender?.MyTargetNodeChannel != null && pQSender?.MyTargetNodeChannel?.SenderType != cdeSenderType.CDE_JAVAJASON) { SendPulse = true; } } } } catch (Exception ee) { TheBaseAssets.MySYSLOG.WriteToLog(319, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", "Execute Command Parsing Error", eMsgLevel.l1_Error, ee.ToString())); } TheBaseAssets.MySYSLOG.WriteToLog(286, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"Done with Do Execute Command for Topic:{tTopic}", eMsgLevel.l7_HostDebugMessage)); } } if (pRequestData.WebSocket == null) { if (DoSendBackBuffer) { SetResponseBuffer(pRequestData, pQSender.MyTargetNodeChannel, SendPulse, ""); } else if (SendPulse) { pQSender.SendPickupMessage(); //Pickup next message right away if pulse mode is on } } TheBaseAssets.MySYSLOG.WriteToLog(286, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", "Leave Do Execute Command", eMsgLevel.l7_HostDebugMessage)); }
/// <summary> /// Processes incoming Messages /// If a Batch comes in, only the first message must have a valid NPA Path /// </summary> internal static void ProcessClientDeviceMessage(TheQueuedSender MyQSender, TheRequestData pRequestData, List <TheDeviceMessage> tDevList) { var toRemove = new List <TheDeviceMessage>(); foreach (TheDeviceMessage tDev in tDevList) { if (string.IsNullOrEmpty(tDev.NPA)) { return; // CODE REVIEW: Really stop processing all subsequent TDMs here (malformed TDM -> security)? } string NPA = tDev.NPA.Substring(4); if (NPA.EndsWith(".ashx", StringComparison.OrdinalIgnoreCase)) { NPA = NPA.Substring(0, NPA.Length - 5); } if (TheBaseAssets.MyScopeManager.ParseISBPath(NPA, out Guid? ttSessionID, out cdeSenderType tSenderType, out long tFID, out string tVersion)) { Guid tSessionID = TheCommonUtils.CGuid(ttSessionID); Guid tDeviceID = TheCommonUtils.CGuid(tDev.DID); lock (TheBaseAssets.MySession.GetLock()) //CODE-REVIEW: VERY expensive lock! Really necessary? { var myTargetNodeChannel = MyQSender.MyTargetNodeChannel; if (MyQSender.IsConnected && myTargetNodeChannel.MySessionState != null) //!=null new in 3.2 { if (!tSessionID.Equals(myTargetNodeChannel.MySessionState.cdeMID)) { Guid tOldID = myTargetNodeChannel.MySessionState.cdeMID; myTargetNodeChannel.MySessionState = TheBaseAssets.MySession.ValidateSEID(tSessionID); //Measure Frequency if (myTargetNodeChannel.MySessionState == null) { TheBaseAssets.MySYSLOG.WriteToLog(243, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", $"No exiting session for remote node found. Using new session (possible reason: fast cloud reconnect) ...new: {tSessionID} old: {tOldID}", eMsgLevel.l2_Warning), true); myTargetNodeChannel.MySessionState = pRequestData.SessionState; } else { TheBaseAssets.MySession.RemoveSessionByID(tOldID); } } } if (tDeviceID != Guid.Empty && tDeviceID != myTargetNodeChannel.cdeMID) { if (myTargetNodeChannel.SenderType == cdeSenderType.CDE_CUSTOMISB) { if (myTargetNodeChannel.TruDID != tDeviceID) { myTargetNodeChannel.TruDID = tDeviceID; TheBaseAssets.MySYSLOG.WriteToLog(243, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", $"Custom ISB sets TruDID to: {TheCommonUtils.GetDeviceIDML(tDeviceID)} for MTNC: {myTargetNodeChannel.ToMLString()}", eMsgLevel.l4_Message), true); } } else { TheBaseAssets.MySYSLOG.WriteToLog(243, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", $"Different DeviceIDs received ...new: {TheCommonUtils.GetDeviceIDML(tDeviceID)} old: {TheCommonUtils.GetDeviceIDML(myTargetNodeChannel.cdeMID)} {(myTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE ? "For CloudRoute and Service normal" : "")}", eMsgLevel.l2_Warning), true); TheBaseAssets.MySession.RemoveSessionsByDeviceID(myTargetNodeChannel.cdeMID, Guid.Empty); TheQueuedSenderRegistry.UpdateQSenderID(myTargetNodeChannel.cdeMID, tDeviceID); myTargetNodeChannel.cdeMID = tDeviceID; if (pRequestData.DeviceID != tDeviceID) { TheBaseAssets.MySYSLOG.WriteToLog(243, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("CoreComm", $"Different DeviceIDs in DID and Request ...DID: {TheCommonUtils.GetDeviceIDML(tDeviceID)} Request: {TheCommonUtils.GetDeviceIDML(myTargetNodeChannel.cdeMID)}", eMsgLevel.l2_Warning), true); pRequestData.DeviceID = tDeviceID; } switch (pRequestData.ResponseMimeType) { case "cde/mini": myTargetNodeChannel.SenderType = cdeSenderType.CDE_MINI; break; } } } if (myTargetNodeChannel.MySessionState == null) { myTargetNodeChannel.MySessionState = TheBaseAssets.MySession.GetOrCreateSessionState(tSessionID, pRequestData); } myTargetNodeChannel.MySessionState.SiteVersion = tVersion; myTargetNodeChannel.MySessionState.cdeMID = tSessionID; myTargetNodeChannel.MySessionState.CurrentURL = myTargetNodeChannel.TargetUrl; // Keep the RSA public key of the other party, so we can use it to encrypt data when sending to that party in the future if (!String.IsNullOrEmpty(tDev.RSA)) { myTargetNodeChannel.MySessionState.RSAPublicSend = tDev.RSA; } if (MyQSender.IsConnecting && !MyQSender.IsConnected) { MyQSender.IsConnected = true; if (myTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE) { if (TheBaseAssets.MyServiceHostInfo.IsIsolated && TheBaseAssets.MyServiceHostInfo.MasterNode == Guid.Empty) { TheBaseAssets.MyServiceHostInfo.MasterNode = myTargetNodeChannel.cdeMID; TheQueuedSenderRegistry.SendMasterNodeQueue(); } MyQSender.StartHeartBeat(); TheBaseAssets.MySYSLOG.WriteToLog(23055, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", $"Cloud Route is back up to {myTargetNodeChannel.ToMLString()}", eMsgLevel.l4_Message)); if (TheQueuedSenderRegistry.eventCloudIsBackUp != null) { TheCommonUtils.cdeRunAsync("QS-StartEngineNU", true, o => { TheQueuedSenderRegistry.eventCloudIsBackUp(TheCDEngines.MyContentEngine, myTargetNodeChannel); }); } } if (MyQSender.eventConnected != null) { TheCommonUtils.cdeRunAsync("QueueConnected", true, (p) => { MyQSender.eventConnected(MyQSender, myTargetNodeChannel); }); } MyQSender.MyISBlock?.FireEvent("Connected"); } pRequestData.SessionState = myTargetNodeChannel.MySessionState; MyQSender?.SetLastHeartbeat(myTargetNodeChannel.MySessionState); } if (!string.IsNullOrEmpty(tDev.TOP) && tDev.TOP.StartsWith("CDE_CONNECT")) { string[] tP = TheCommonUtils.cdeSplit(tDev.TOP, ";:;", true, true); if (tP.Length > 1) { string tEngs = tP[1]; TheCommonUtils.cdeRunAsync("QS-StartEngineNU", false, o => { TheCDEngines.StartEngineWithNewUrl(MyQSender?.MyTargetNodeChannel, tEngs); }); } if (tDevList.Count > 1) { if (toRemove == null) { toRemove = new List <TheDeviceMessage>(); } toRemove.Add(tDev); continue; } else { return; } } if (string.IsNullOrEmpty(tDev.TOP) || tDev.TOP.StartsWith("CDE_PICKUP") || tDev.TOP.StartsWith("CDE_WSINIT")) { TheBaseAssets.MySYSLOG.WriteToLog(23056, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"Heartbeat received {MyQSender?.MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l4_Message)); if (tDevList.Count > 1) { if (toRemove == null) { toRemove = new List <TheDeviceMessage>(); } toRemove.Add(tDev); continue; } else { return; } } break; //Found valid path and can go out } } if (toRemove != null) { foreach (var tDev in toRemove) { tDevList.Remove(tDev); } } TheCommonUtils.cdeRunAsync("QS-UpCo2Exec", false, o => { pRequestData.ResponseBuffer = null; DoExecuteCommand(null, MyQSender, false, pRequestData, tDevList); }, tDevList); }
internal static void ExecuteCommand(string pInTopic, TheQueuedSender pQSender, bool DoSendBackBuffer, TheRequestData pRequestData, List <TheDeviceMessage> pDevMessageList) { if (pRequestData == null) { return; } #region Precheck on Execute Conditions if (pQSender?.MyTargetNodeChannel == null) { TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", "Enter Execute Command: OrgChannel is Null - not allowed ", eMsgLevel.l2_Warning)); pRequestData.ResponseBufferStr = "ERR: Illegal Request"; pRequestData.StatusCode = 400;// (int)nsCDEngine.Communication.HttpService.eHttpStatusCode.NotAcceptable; return; } if (!TheBaseAssets.MasterSwitch) { pRequestData.ResponseBufferStr = "ERR: Service is shutting Down..."; return; } if (pRequestData.SessionState == null && TheBaseAssets.MySession != null) { TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("CoreComm", "Enter Execute Command: Session no longer alive - Topic:" + pInTopic, eMsgLevel.l2_Warning)); pRequestData.ResponseBufferStr = "ERR: Session no longer alive"; pRequestData.StatusCode = 401; //(int)nsCDEngine.Communication.HttpService.eHttpStatusCode.NotAcceptable; return; } #endregion try { if (pDevMessageList == null) { #region Received BINARY Data in Post Data - Parsing //REVIEW: This should no longer be used in the future...all telegrams should come in as HTTP Bodies if (pRequestData.PostData != null && pRequestData.PostData.Length > 0 && pRequestData.PostDataIdx >= 0) { int tPostDataLength = pRequestData.PostData.Length; if (pRequestData.PostDataLength > 0) { tPostDataLength = pRequestData.PostDataLength; } if ((tPostDataLength - pRequestData.PostDataIdx) == 1) { if (pQSender.MyTargetNodeChannel.SenderType == cdeSenderType.NOTSET) { pQSender.MyTargetNodeChannel.SenderType = (cdeSenderType)(pRequestData.PostData[0] - 0x30); TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", $"ChannelChange: Was NOTSET and now is now: {pQSender.MyTargetNodeChannel.SenderType}", eMsgLevel.l3_ImportantMessage)); } } else { try { string tStr = null; bool isBin = false; if (pRequestData.ResponseMimeType.ToLower().Contains("zip")) { tStr = TheCommonUtils.cdeDecompressToString(pRequestData.PostData, pRequestData.PostDataIdx, tPostDataLength - pRequestData.PostDataIdx); isBin = true; } else { tStr = TheCommonUtils.CArray2UTF8String(pRequestData.PostData, pRequestData.PostDataIdx, tPostDataLength - pRequestData.PostDataIdx); } pDevMessageList = TheDeviceMessage.DeserializeJSONToObject(tStr); if (pQSender.MyTargetNodeChannel.SenderType == cdeSenderType.NOTSET) { pQSender.MyTargetNodeChannel.SenderType = isBin ? cdeSenderType.CDE_SERVICE : cdeSenderType.CDE_JAVAJASON; TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", $"ChannelChange: Was NOTSET and now is now: {pQSender.MyTargetNodeChannel.SenderType}", eMsgLevel.l3_ImportantMessage)); } } catch (Exception eee) { string remot = "unkown"; if (pRequestData.SessionState != null && pRequestData.SessionState.MyDevice != Guid.Empty) { remot = pRequestData.SessionState.MyDevice.ToString(); } TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", "Execute Command received JSON package failed", eMsgLevel.l2_Warning, $"{pRequestData.RequestUri} {remot} {eee}")); } } } #endregion } DoExecuteCommand(pInTopic, pQSender, DoSendBackBuffer, pRequestData, pDevMessageList); } catch (Exception eeee) { TheBaseAssets.MySYSLOG.WriteToLog(285, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("CoreComm", "Execute Command failed", eMsgLevel.l2_Warning, $"{pRequestData.RequestUri} {eeee}")); } }
internal override bool Connect(TheQueuedSender pSender) { if (pSender == null) // || pSender.IsConnecting) return false; if (pSender.IsConnected) return true; IsClient = true; if (MyQSender == null) MyQSender = pSender; Uri TargetUri = TheCommonUtils.CUri(pSender.MyTargetNodeChannel.TargetUrl, true); string TargetUriPath = TargetUri.AbsolutePath; OwnerNodeID = MyQSender.MyTargetNodeChannel.cdeMID; Uri tTarget = new Uri(TargetUri, TheBaseAssets.MyScopeManager.GetISBPath(TargetUriPath, TheCommonUtils.GetOriginST(pSender.MyTargetNodeChannel), pSender.MyTargetNodeChannel.SenderType, 1, Guid.Empty, true)); tTarget = tTarget.SetWSInfo(tTarget.Port, ""); try { IsActive = true; CloseFired = false; ConnectSuccess = true; if (websocket != null && !websocket.IsAlive) { try { websocket.OnError -= websocket_OnError; websocket.OnOpen -= websocket_Opened; websocket.OnMessage -= websocket_OnMessage; websocket.OnClose -= websocket_OnClose; websocket.Close(); TheBaseAssets.MySYSLOG.WriteToLog(8812, new TSM("WSProcessorConnect", string.Format("Websockets were still valid but not alive: closed and will recreate! IsConnecting:{0}", pSender.IsConnecting), eMsgLevel.l4_Message)); } catch { TheBaseAssets.MySYSLOG.WriteToLog(8812, new TSM("WSProcessorConnect", string.Format("Websockets were still valid but not alive: Error while closing, will recreate. Possible socket leak! IsConnecting:{0}", pSender.IsConnecting), eMsgLevel.l4_Message)); } finally { websocket = null; } } if (websocket == null) { websocket = new WebSocket(tTarget.ToString()); if (!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyUrl)) { try { websocket.SetProxy(TheBaseAssets.MyServiceHostInfo.ProxyUrl, TheBaseAssets.MyServiceHostInfo.ProxyUID, TheBaseAssets.MyServiceHostInfo.ProxyPWD); TheBaseAssets.MySYSLOG.WriteToLog(8812, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("WSProcessorCSWS", $"Websockets proxy set: {TheBaseAssets.MyServiceHostInfo.ProxyUrl} UID: {!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyUID)} PWD: {!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyPWD)}", eMsgLevel.l4_Message)); } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("WSProcessor", "Error setting Proxy credentials:", eMsgLevel.l1_Error, e.ToString())); } } websocket.Log.Level = LogLevel.Fatal; websocket.Log.Output = sinkLog; websocket.SslConfiguration.ServerCertificateValidationCallback += TheCommCore.ValidateServerCertificate; var myTargetNodeChannel = MyQSender?.MyTargetNodeChannel; if (!string.IsNullOrEmpty(myTargetNodeChannel?.ClientCertificateThumb)) { try { X509Certificate2Collection certs = TheCertificates.GetClientCertificatesByThumbprint(myTargetNodeChannel?.ClientCertificateThumb); if (certs?.Count < 1) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSProcessor", $"Error setting Client Certificate - Requested Cert with Thumbprint {myTargetNodeChannel?.ClientCertificateThumb} not found", eMsgLevel.l1_Error)); return false; } websocket.SslConfiguration.ClientCertificates = certs; websocket.SslConfiguration.ClientCertificateSelectionCallback = wsSharpClientCertSelector; } catch (Exception certex) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSProcessor", "Error setting Client Certificate", eMsgLevel.l1_Error, certex.ToString())); return false; } } websocket.OnError += websocket_OnError; websocket.OnOpen += websocket_Opened; websocket.OnMessage += websocket_OnMessage; websocket.OnClose += websocket_OnClose; websocket.Connect(); } else TheBaseAssets.MySYSLOG.WriteToLog(8812, new TSM("WSProcessorConnect", string.Format("Websockets are still valid and will be recycled! IsConnecting:{0}",pSender.IsConnecting),eMsgLevel.l4_Message)); } catch (Exception ex) { Shutdown(true, "1650:Connect Failed: " + ex); } return ConnectSuccess; }
internal override bool Connect(TheQueuedSender pSender) { if (pSender == null /*|| pSender.MyTargetNodeChannel==null*/) { return(false); } if (pSender.IsConnected) { return(true); } IsClient = true; if (MyQSender == null) { MyQSender = pSender; } var _MyTargetNodeChannel = pSender?.MyTargetNodeChannel; Uri TargetUri = TheCommonUtils.CUri(_MyTargetNodeChannel?.TargetUrl, true); if (TargetUri == null) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSProcessor", "Invalid Target URL", eMsgLevel.l1_Error, $"{_MyTargetNodeChannel?.ToString()}")); return(false); } OwnerNodeID = _MyTargetNodeChannel.cdeMID; string TargetUriPath = TargetUri.AbsolutePath; Uri tTarget = new Uri(TargetUri, TheBaseAssets.MyScopeManager.GetISBPath(TargetUriPath, TheCommonUtils.GetOriginST(_MyTargetNodeChannel), _MyTargetNodeChannel.SenderType, 1, Guid.Empty, true)); tTarget = tTarget.SetWSInfo(tTarget.Port, ""); string connectFailureReason = ""; try { IsActive = true; CloseFired = false; ConnectSuccess = false; ClientWebSocket wsClientSocket = new ClientWebSocket(); websocket = wsClientSocket; if (!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyUrl)) { try { System.Net.NetworkCredential tNet = null; if (!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyUID)) { tNet = new System.Net.NetworkCredential(TheBaseAssets.MyServiceHostInfo.ProxyUID, TheBaseAssets.MyServiceHostInfo.ProxyPWD); } if (wsClientSocket.Options != null) { wsClientSocket.Options.Proxy = new System.Net.WebProxy(TheBaseAssets.MyServiceHostInfo.ProxyUrl, true, null, tNet); TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("WSProcessor", $"Web Proxy set: {TheBaseAssets.MyServiceHostInfo.ProxyUrl} UID: {!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyUID)} PWD: {!string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ProxyPWD)}", eMsgLevel.l4_Message)); } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSProcessor", "Error setting Proxy credentials:", eMsgLevel.l1_Error, e.ToString())); } } if (!string.IsNullOrEmpty(_MyTargetNodeChannel?.ClientCertificateThumb)) { try { X509Certificate2Collection cert = TheCertificates.GetClientCertificatesByThumbprint(_MyTargetNodeChannel?.ClientCertificateThumb); if (cert?.Count < 1) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSProcessor", $"Error setting Client Certificate - Requested Cert with Thumbprint {_MyTargetNodeChannel?.ClientCertificateThumb} not found", eMsgLevel.l1_Error)); return(false); } wsClientSocket.Options.ClientCertificates = cert; } catch (Exception certex) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("WSProcessor", "Error setting Client Certificate", eMsgLevel.l1_Error, certex.ToString())); return(false); } } Task myTask = wsClientSocket.ConnectAsync(tTarget, CancellationToken.None); myTask.Wait(TheBaseAssets.MyServiceHostInfo.TO.WsTimeOut * 12); if (myTask.IsCompleted) { // CODE REVIEW MH: ProcessWS synchronously can run for quite a bit until the first await. Should we start this as a new task? ConnectSuccess = true; var taskNoWait = ProcessWS(); //Sets Connecting and Connected when ready } else { TheBaseAssets.MySYSLOG.WriteToLog(4365, new TSM("WSProcessor", $"WSClient Connect Request timed out Task:{myTask.Status}", eMsgLevel.l2_Warning)); connectFailureReason += "Connect Request Timeout"; } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(4365, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("WSProcessor", "ClientConnect Request Failed:", eMsgLevel.l1_Error, e.ToString())); connectFailureReason += TheCommonUtils.GetAggregateExceptionMessage(e, false); } if (ConnectSuccess) //This prevents double shutdown as the eventconnecte with ConnectSuccess=false will cause a shutdown again { eventConnected?.Invoke(this, ConnectSuccess, $"1602:{connectFailureReason}"); } else { Shutdown(true, $"1603:WSConnect was not successful ({connectFailureReason})"); } return(ConnectSuccess); }