Эх сурвалжийг харах

Änderungen MQTT-Konfiguration. Fixes.

Rind 3 жил өмнө
parent
commit
85b809b712

+ 175 - 58
mqttcl/mqttcfg.cpp

@@ -20,18 +20,22 @@
 #define _CFG_KEY_NAME_TLS_CL_CRT_FILE			"tlsClCrtFile"
 #define _CFG_KEY_NAME_TLS_CL_KEY_FILE			"tlsClKeyFile"
 #define _CFG_KEY_NAME_TLS_PSK					"tlsPsk"
-#define _CFG_KEY_NAME_LAST_WILL_MESSAGE			"lastWillMessage"
+#define _CFG_KEY_NAME_LAST_WILL_MSG_STR			"lastWillMsgStr"
+#define _CFG_KEY_NAME_LAST_WILL_MSG_INT			"lastWillMsgInt"
 #define _CFG_KEY_NAME_LAST_WILL_TOPIC			"lastWillTopic"
 #define _CFG_KEY_NAME_LAST_WILL_QOS				"lastWillQos"
 #define _CFG_KEY_NAME_LAST_WILL_RETAIN			"lastWillRetain"
 #define _CFG_KEY_NAME_LAST_WILL_ON_EXIT			"lastWillOnExit"
-#define _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG		"lastWillOnExitMsg"
-#define _CFG_KEY_NAME_CONNECT_MESSAGE			"connectMessage"
+#define _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_STR	"lastWillOnExitMsgStr"
+#define _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_INT	"lastWillOnExitMsgInt"
+#define _CFG_KEY_NAME_CONNECT_MSG_STR			"connectMsgStr"
+#define _CFG_KEY_NAME_CONNECT_MSG_INT			"connectMsgInt"
 #define _CFG_KEY_NAME_CONNECT_TOPIC				"connectTopic"
 #define _CFG_KEY_NAME_CONNECT_QOS				"connectQos"
 #define _CFG_KEY_NAME_CONNECT_RETAIN			"connectRetain"
 #define _CFG_KEY_NAME_MAX_KEEP_ALIVE			"maxKeepAlive"
-#define _CFG_KEY_NAME_PREFIX_STRING				"topicPrefix"
+#define _CFG_KEY_NAME_TOPIC_PREFIX_STRING		"topicPrefix"
+#define _CFG_KEY_NAME_DISABLE_TOPIC_PREFIX		"disableTopicPrefix"
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -39,13 +43,17 @@ CMqttClConfig::CMqttClConfig(const char *pszShmUuid) :	m_strShmID(formatString("
 														m_nBrokerPort(0),
 														m_nDefaultQOS(0),
 														m_bDefaultRetain(MQTTCL_DEFAULT_RETAIN),
+														m_nLastWillMessage(0),
 														m_nLastWillQos(m_nDefaultQOS),
 														m_bLastWillRetain(MQTTCL_DEFAULT_RETAIN),
 														m_bHasLastWill(false),
 														m_bLastWillOnExit(false),
+														m_nLastWillOnExitMsg(0),
+														m_nConnectMessage(0),
 														m_nConnectQos(m_nDefaultQOS),
 														m_bConnectRetain(MQTTCL_DEFAULT_RETAIN),
 														m_bHasConnect(false),
+														m_bDisableTopicPrefix(false),
 														m_bHasPrefix(false),
 														m_nTlsMode(0),
 														m_nMaxKeepAlive(MQTTCL_DEFAULT_MAX_KEEP_ALIVE_TIME)
@@ -77,7 +85,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 	if(!(pjtCfg = ::json_load_file(pszCfgFilePath, JSON_REJECT_DUPLICATES, &err)))
 	{
-		rlf.Error("CMqttClConfig::LoadCfg: %s!\n", err.text);
+		rlf.Error("LoadCfg: Error loading file %s: %s!\n", pszCfgFilePath, err.text);
 		return false;
 	}
 
@@ -89,17 +97,12 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 	if(!GetIntValue(jtCfg, _CFG_KEY_NAME_TLS_MODE, m_nTlsMode, strErr))
 	{
 		m_nTlsMode = MQTTCL_TLS_MODE_OFF;
-		rlf.Warning("CMqttClConfig::LoadCfg: %s! TLS will not be used!\n", strErr.c_str());
+		rlf.Warning("LoadCfg: TLS will not be used!\n");
 	}
-	else if(m_nTlsMode < MQTTCL_TLS_MODE_OFF)
+	else if((m_nTlsMode < MQTTCL_TLS_MODE_OFF) || (m_nTlsMode > MQTTCL_TLS_MODE_PSK))
 	{
-		rlf.Warning("CMqttClConfig::LoadCfg: Invalid TLS mode: %d! TLS will be disabled!\n", m_nTlsMode);
-		m_nTlsMode = MQTTCL_TLS_MODE_OFF;
-	}
-	else if(m_nTlsMode > MQTTCL_TLS_MODE_PSK)
-	{
-		rlf.Warning("CMqttClConfig::LoadCfg: Invalid TLS mode: %d! TLS mode will be set to PSK!\n", m_nTlsMode);
-		m_nTlsMode = MQTTCL_TLS_MODE_PSK;
+		rlf.Error("LoadCfg: Invalid TLS mode: %d! No way to continue!\n", m_nTlsMode);
+		return false;
 	}
 
 	/////////////////////////////////////////////////////////////////////////
@@ -107,7 +110,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 	if(!GetStringValue(jtCfg, _CFG_KEY_NAME_BROKER_ADDR, m_strBrokerAddr, strErr))
 	{
-		rlf.Error("CMqttClConfig::LoadCfg: %s!\n", strErr.c_str());
+		rlf.Error("LoadCfg: %s!\n", strErr.c_str());
 		return false;
 	}
 
@@ -117,11 +120,11 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 	if(!GetIntValue(jtCfg, _CFG_KEY_NAME_BROKER_PORT, m_nBrokerPort, strErr))
 	{
 		m_nBrokerPort = (m_nTlsMode > MQTTCL_TLS_MODE_OFF) ? 8883 : 1883;
-		rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default broker port %d!\n", strErr.c_str(), m_nBrokerPort);
+		rlf.Info("LoadCfg: Using default broker port %d!\n", m_nBrokerPort);
 	}
 	else if(m_nBrokerPort < 0 || m_nBrokerPort > 0xffff)
 	{
-		rlf.Error("CMqttClConfig::LoadCfg: Invalid broker port number: %d!\n", m_nBrokerPort);
+		rlf.Error("LoadCfg: Invalid broker port number: %d! No way to continue!\n", m_nBrokerPort);
 		return false;
 	}
 
@@ -131,18 +134,22 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 	if(!GetIntValue(jtCfg, _CFG_KEY_NAME_DEFAULT_QOS, m_nDefaultQOS, strErr))
 	{
 		m_nDefaultQOS = MQTTCL_DEFAULT_QOS;
-		rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default QOS: %d!\n", strErr.c_str(), m_nDefaultQOS);
+		rlf.Info("LoadCfg: Using default QOS: %d!\n", m_nDefaultQOS);
 	}
 	else if(m_nDefaultQOS < MQTTCL_MIN_QOS)
 	{
-		rlf.Warning("CMqttClConfig::LoadCfg: Invalid QOS: %d - using %d!\n", m_nDefaultQOS, MQTTCL_MIN_QOS);
+		rlf.Warning("LoadCfg: Invalid QOS: %d - adjusted to %d!\n", m_nDefaultQOS, MQTTCL_MIN_QOS);
 		m_nDefaultQOS = MQTTCL_MIN_QOS;
 	}
 	else if(m_nDefaultQOS > MQTTCL_MAX_QOS)
 	{
-		rlf.Warning("CMqttClConfig::LoadCfg: Invalid QOS: %d - using %d!\n", m_nDefaultQOS, MQTTCL_MAX_QOS);
+		rlf.Warning("LoadCfg: Invalid QOS: %d - adjusted to %d!\n", m_nDefaultQOS, MQTTCL_MAX_QOS);
 		m_nDefaultQOS = MQTTCL_MAX_QOS;
 	}
+	else
+	{
+		rlf.Info("LoadCfg: Default QOS: %d!\n", m_nDefaultQOS);
+	}
 
 	/////////////////////////////////////////////////////////////////////////
 	// defaultRetain
@@ -150,18 +157,35 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 	if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_DEFAULT_RETAIN, m_bDefaultRetain, strErr))
 	{
 		m_bDefaultRetain = MQTTCL_DEFAULT_RETAIN;
-		rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default retain \"%s\"!\n", strErr.c_str(), m_bDefaultRetain ? "true" : "false");
+		rlf.Info("LoadCfg: Using default retain \"%s\"!\n", m_bDefaultRetain ? "true" : "false");
 	}
 
 	/////////////////////////////////////////////////////////////////////////
-	// lastWillMessage
+	// lastWillMsgStr
 
-	if(!GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_MESSAGE, m_strLastWillMessage, strErr))
+	if(GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_MSG_STR, m_strLastWillMessage, strErr))
 	{
-		rlf.Info("CMqttClConfig::LoadCfg: %s! No Last Will Message provided.\n", strErr.c_str());
+		m_bHasLastWill = true;
+		rlf.Info("LoadCfg: Last Will - String message: \"%s\".\n", m_strLastWillMessage.c_str());
 	}
 
-	if((m_bHasLastWill = !m_strLastWillMessage.empty()))
+	/////////////////////////////////////////////////////////////////////////
+	// lastWillMsgInt
+
+	if(!m_bHasLastWill)
+	{
+		if(GetInt64Value(jtCfg, _CFG_KEY_NAME_LAST_WILL_MSG_INT, m_nLastWillMessage, strErr))
+		{
+			m_bHasLastWill = true;
+			rlf.Info("LoadCfg: Last Will - Numeric message: %lld.\n", m_nLastWillMessage);
+		}
+		else
+		{
+			rlf.Warning("LoadCfg: %s! No Last Will Message provided.\n", strErr.c_str());
+		}
+	}
+
+	if(m_bHasLastWill)
 	{
 		/////////////////////////////////////////////////////////////////////
 		// lastWillTopic
@@ -169,7 +193,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 		if(!GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_TOPIC, m_strLastWillTopic, strErr))
 		{
 			m_strLastWillTopic = MQTTCL_DEFAULT_LAST_WILL_CONNECT_TOPIC;
-			rlf.Info("CMqttClConfig::LoadCfg: %s! Setting Last Will Topic to default: \"%s\".\n", strErr.c_str()), m_strLastWillTopic.c_str();
+			rlf.Info("LoadCfg: %s! Setting Last Will Topic to default: \"%s\".\n", strErr.c_str(), m_strLastWillTopic.c_str());
 		}
 
 		/////////////////////////////////////////////////////////////////////
@@ -178,7 +202,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 		if(!GetIntValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_QOS, m_nLastWillQos, strErr))
 		{
 			m_nLastWillQos = m_nDefaultQOS;
-			rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default Last Will Qos: %d!\n", strErr.c_str(), m_nLastWillQos);
+			rlf.Info("LoadCfg: %s! Using default Last Will QOS: %d!\n", strErr.c_str(), m_nLastWillQos);
 		}
 
 		/////////////////////////////////////////////////////////////////////
@@ -186,8 +210,8 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_RETAIN, m_bLastWillRetain, strErr))
 		{
-			m_bLastWillRetain = MQTTCL_DEFAULT_RETAIN;
-			rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default Last Will retain: %s!\n", strErr.c_str(), m_bLastWillRetain ? "true" : "false");
+			m_bLastWillRetain = m_bDefaultRetain;
+			rlf.Info("LoadCfg: %s! Using default Last Will retain: \"%s\"!\n", strErr.c_str(), m_bLastWillRetain ? "true" : "false");
 		}
 
 		/////////////////////////////////////////////////////////////////////
@@ -196,39 +220,83 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 		if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT, m_bLastWillOnExit, strErr))
 		{
 			m_bLastWillOnExit = false;
-			rlf.Warning("CMqttClConfig::LoadCfg: %s! No Last Will on Exit.\n", strErr.c_str());
+			rlf.Warning("LoadCfg: %s! No Last Will on Exit.\n", strErr.c_str());
 		}
-		
+
 		if(m_bLastWillOnExit)
 		{
 			/////////////////////////////////////////////////////////////////
-			// lastWillOnExitMsg
+			// lastWillOnExitMsgStr, lastWillOnExitMsgInt
 
-			if(!GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG, m_strLastWillOnExitMsg, strErr))
+			if(GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_STR, m_strLastWillOnExitMsg, strErr))
 			{
-				m_strLastWillOnExitMsg = m_strLastWillMessage;
-				rlf.Info("CMqttClConfig::LoadCfg: %s! Setting Last Will Exit Message to default: \"%s\".\n", strErr.c_str()), m_strLastWillOnExitMsg.c_str();
+				rlf.Info("LoadCfg: Last Will on Exit - String message: \"%s\".\n", m_strLastWillOnExitMsg.c_str());
+			}
+			else
+			{
+				if(GetInt64Value(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_INT, m_nLastWillOnExitMsg, strErr))
+				{
+					rlf.Info("LoadCfg: Last Will on Exit - Numeric message: %lld.\n", m_nLastWillOnExitMsg);
+				}
+				else
+				{
+					if(!m_strLastWillMessage.empty())
+					{
+						m_strLastWillOnExitMsg = m_strLastWillMessage;
+						rlf.Info("LoadCfg: Setting Last Will Exit Message to Last Will string: \"%s\".\n", m_strLastWillOnExitMsg.c_str());
+					}
+					else
+					{
+						m_nLastWillOnExitMsg = m_nLastWillMessage;
+						rlf.Info("LoadCfg: Setting Last Will Exit Message to Last Will numeric: %lld.\n", m_nLastWillOnExitMsg);
+					}
+				}
 			}
 		}
 	}
 
 	/////////////////////////////////////////////////////////////////////////
-	// connectMessage
+	// connectMsgStr
 
-	if(!GetStringValue(jtCfg, _CFG_KEY_NAME_CONNECT_MESSAGE, m_strConnectMessage, strErr))
+	if(GetStringValue(jtCfg, _CFG_KEY_NAME_CONNECT_MSG_STR, m_strConnectMessage, strErr))
 	{
-		rlf.Info("CMqttClConfig::LoadCfg: %s! No Connect Message provided.\n", strErr.c_str());
+		m_bHasConnect = true;
+		rlf.Info("LoadCfg: Connect - String message: \"%s\".\n", m_strConnectMessage.c_str());
 	}
 
-	if((m_bHasConnect = !m_strConnectMessage.empty()))
+	/////////////////////////////////////////////////////////////////////////
+	// connectMsgInt
+
+	if(!m_bHasConnect)
+	{
+		if(GetInt64Value(jtCfg, _CFG_KEY_NAME_CONNECT_MSG_INT, m_nConnectMessage, strErr))
+		{
+			m_bHasConnect = true;
+			rlf.Info("LoadCfg: Connect - Numeric message: %lld.\n", m_nConnectMessage);
+		}
+		else
+		{
+			rlf.Warning("LoadCfg: %s! No Connect message provided.\n", strErr.c_str());
+		}
+	}
+
+	if(m_bHasConnect)
 	{
 		/////////////////////////////////////////////////////////////////////
 		// connectTopic
 
 		if(!GetStringValue(jtCfg, _CFG_KEY_NAME_CONNECT_TOPIC, m_strConnectTopic, strErr))
 		{
-			m_strConnectTopic = m_strLastWillTopic;
-			rlf.Info("CMqttClConfig::LoadCfg: %s! Setting Connect Topic to default: \"%s\".\n", strErr.c_str()), m_strLastWillTopic.c_str();
+			if(m_bHasLastWill)
+			{
+				m_strConnectTopic = m_strLastWillTopic;
+				rlf.Info("LoadCfg: %s! Setting Connect Topic to Last Will Topic: \"%s\".\n", strErr.c_str(), m_strConnectTopic.c_str());
+			}
+			else
+			{
+				m_strConnectTopic = MQTTCL_DEFAULT_LAST_WILL_CONNECT_TOPIC;
+				rlf.Info("LoadCfg: %s! Setting Connect Topic to default: \"%s\".\n", strErr.c_str(), m_strConnectTopic.c_str());
+			}
 		}
 
 		/////////////////////////////////////////////////////////////////////
@@ -236,8 +304,8 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetIntValue(jtCfg, _CFG_KEY_NAME_CONNECT_QOS, m_nConnectQos, strErr))
 		{
-			m_nConnectQos = m_nLastWillQos;
-			rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default Connect Qos: %d!\n", strErr.c_str(), m_nConnectQos);
+			m_nConnectQos = m_nDefaultQOS;
+			rlf.Info("LoadCfg: %s! Using default Connect Qos: %d!\n", strErr.c_str(), m_nConnectQos);
 		}
 
 		/////////////////////////////////////////////////////////////////////
@@ -245,8 +313,8 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_CONNECT_RETAIN, m_bConnectRetain, strErr))
 		{
-			m_bConnectRetain = m_bLastWillRetain;
-			rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default Last Will retain: %s!\n", strErr.c_str(), m_bConnectRetain ? "true" : "false");
+			m_bConnectRetain = m_bDefaultRetain;
+			rlf.Info("LoadCfg: %s! Using default Last Will retain: %s!\n", strErr.c_str(), m_bConnectRetain ? "true" : "false");
 		}
 	}
 
@@ -256,7 +324,12 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 	if(!GetIntValue(jtCfg, _CFG_KEY_NAME_MAX_KEEP_ALIVE, m_nMaxKeepAlive, strErr))
 	{
 		m_nMaxKeepAlive = MQTTCL_DEFAULT_MAX_KEEP_ALIVE_TIME;
-		rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default Keep-alive time: %d!\n", strErr.c_str(), m_nMaxKeepAlive);
+		rlf.Info("LoadCfg: %s! Using default Keep-alive time: %d!\n", strErr.c_str(), m_nMaxKeepAlive);
+	}
+	else if(m_nMaxKeepAlive < MQTTCL_MIN_MAX_KEEP_ALIVE_TIME)
+	{
+		rlf.Warning("LoadCfg: Adjusting max keep-alive time from %d to %d!\n", m_nMaxKeepAlive, MQTTCL_MIN_MAX_KEEP_ALIVE_TIME);
+		m_nMaxKeepAlive = MQTTCL_MIN_MAX_KEEP_ALIVE_TIME;
 	}
 
 	/////////////////////////////////////////////////////////////////////////
@@ -264,8 +337,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 	if(!GetStringValue(jtCfg, _CFG_KEY_NAME_DEVICE_PREFIX, m_strDevicePrefix, strErr))
 	{
-		m_strDevicePrefix = MQTTCL_DEVICE_PREFIX;
-		rlf.Warning("CMqttClConfig::LoadCfg: %s! Using default device prefix \"%s\"!\n", strErr.c_str(), m_strDevicePrefix.c_str());
+		rlf.Warning("LoadCfg: %s! Using empty device prefix!\n", strErr.c_str());
 	}
 
 	/////////////////////////////////////////////////////////////////////////
@@ -273,23 +345,45 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 	if(GetStringValue(jtCfg, _CFG_KEY_NAME_DEVICE_ID, m_strDeviceID, strErr))
 	{
-		rlf.Info("CMqttClConfig::LoadCfg: Using configured device ID: \"%s\"!\n", m_strDeviceID.c_str());
+		rlf.Info("LoadCfg: Using configured device ID: \"%s\"!\n", m_strDeviceID.c_str());
 	}
 	else
 	{
 		m_strDeviceID = CreateDeviceID(m_strDevicePrefix.c_str());
+		rlf.Info("LoadCfg: Using automatic device ID: \"%s\"!\n", m_strDeviceID.c_str());
+	}
+
+	/////////////////////////////////////////////////////////////////////
+	// disableTopicPrefix
+
+	if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_DISABLE_TOPIC_PREFIX, m_bDisableTopicPrefix, strErr))
+	{
+		m_bDisableTopicPrefix = false;
 	}
 
 	/////////////////////////////////////////////////////////////////////////
-	// topicPrefix string
+	// topicPrefix
 
-	if(!GetStringValue(jtCfg, _CFG_KEY_NAME_PREFIX_STRING, m_strPrefix, strErr))
+	if(!m_bDisableTopicPrefix)
 	{
-		m_strPrefix = formatString("%s/%s", GetDeviceID(), GetShmID());
+		if(GetStringValue(jtCfg, _CFG_KEY_NAME_TOPIC_PREFIX_STRING, m_strTopicPrefix, strErr))
+		{
+			rlf.Info("LoadCfg: Using configured topic prefix: \"%s\"!\n", m_strTopicPrefix.c_str());
+		}
+		else
+		{
+			m_strTopicPrefix = formatString("%s/%s", GetDeviceID(), GetShmID());
+			rlf.Info("LoadCfg: Using automatic topic prefix: \"%s\"!\n", m_strTopicPrefix.c_str());
+		}
+	}
+	else
+	{
+		m_strTopicPrefix.clear();
+		rlf.Warning("LoadCfg: Topic prefix disabled!\n");
 	}
 
 	/////////////////////////////////////////////////////////////////////////
-	// m_nTlsMode == (MQTTCL_TLS_MODE_CRT || MQTTCL_TLS_MODE_PSK)
+	// if m_nTlsMode != MQTTCL_TLS_MODE_OFF
 
 	if(m_nTlsMode == MQTTCL_TLS_MODE_CRT)
 	{
@@ -298,7 +392,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_CA_CRT_FILE, m_strTlsCaCrtFile, strErr))
 		{
-			rlf.Error("CMqttClConfig::LoadCfg: %s!\n", strErr.c_str());
+			rlf.Error("LoadCfg: %s! TLS-Mode = %d and no Certificate Authority file provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
 			return false;
 		}
 
@@ -307,7 +401,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_CL_CRT_FILE, m_strTlsClCrtFile, strErr))
 		{
-			rlf.Error("CMqttClConfig::LoadCfg: %s!\n", strErr.c_str());
+			rlf.Error("LoadCfg: %s! TLS-Mode = %d and no public Key Certificate file provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
 			return false;
 		}
 
@@ -316,7 +410,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_CL_KEY_FILE, m_strTlsClKeyFile, strErr))
 		{
-			rlf.Error("CMqttClConfig::LoadCfg: %s!\n", strErr.c_str());
+			rlf.Error("LoadCfg: %s! TLS-Mode = %d and no private Key file provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
 			return false;
 		}
 	}
@@ -327,7 +421,7 @@ bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
 
 		if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_PSK, m_strTlsPSK, strErr))
 		{
-			rlf.Error("CMqttClConfig::LoadCfg: %s!\n", strErr.c_str());
+			rlf.Error("LoadCfg: %s! TLS-Mode = %d and no Preshared Key provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
 			return false;
 		}
 	}
@@ -394,6 +488,26 @@ bool CMqttClConfig::GetIntValue(CJson_t &rjtParent, const char *pszKey, int &rnV
 
 /////////////////////////////////////////////////////////////////////////////
 
+bool CMqttClConfig::GetInt64Value(CJson_t &rjtParent, const char *pszKey, long long &rnVal, std::string &strErr)
+{
+	CJson_t jtVal;
+
+	if(GetValue(rjtParent, pszKey, jtVal, strErr))
+	{
+		if(json_is_integer(jtVal.operator const json_t*()))
+		{
+			rnVal = (long long)::json_integer_value(jtVal);
+			return true;
+		}
+
+		strErr = formatString("\"%s\" (type=%d) is not an integer value", pszKey, jtVal.Type());
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 bool CMqttClConfig::GetStringValue(CJson_t &rjtParent, const char *pszKey, std::string &rstrVal, std::string &strErr)
 {
 	CJson_t jtVal;
@@ -477,6 +591,9 @@ const char* CMqttClConfig::GetMacAddress(std::string &s)
 std::string CMqttClConfig::CreateDeviceID(const char *pszDevicePrefix)
 {
 	std::string m, s;
-	s = formatString("%s-%s", pszDevicePrefix, CMqttClConfig::GetMacAddress(m));
+	if(pszDevicePrefix && *pszDevicePrefix)
+		s = formatString("%s-%s", pszDevicePrefix, CMqttClConfig::GetMacAddress(m));
+	else
+		CMqttClConfig::GetMacAddress(s);
 	return s;
 }

+ 40 - 25
mqttcl/mqttcfg.h

@@ -24,19 +24,17 @@
 /////////////////////////////////////////////////////////////////////////////
 // mqttcfg.h - Declarations:
 
-#define MQTTCL_TLS_MODE_OFF		0 // no TLS
-#define MQTTCL_TLS_MODE_CRT		1 // TLS using certificates
-#define MQTTCL_TLS_MODE_PSK		2 // TLS using preshared key
-
-#define MQTTCL_MIN_QOS			0
-#define MQTTCL_MAX_QOS			2
-#define MQTTCL_DEFAULT_QOS		MQTTCL_MAX_QOS
-
-#define MQTTCL_DEFAULT_RETAIN	false
-#define MQTTCL_DEVICE_PREFIX	"GfA"
-
-#define MQTTCL_DEFAULT_LAST_WILL_CONNECT_TOPIC				"LAST_WILL_CONNECT"
-#define MQTTCL_DEFAULT_MAX_KEEP_ALIVE_TIME					60
+#define MQTTCL_TLS_MODE_OFF						0 // no TLS
+#define MQTTCL_TLS_MODE_CRT						1 // TLS using certificates
+#define MQTTCL_TLS_MODE_PSK						2 // TLS using preshared key
+
+#define MQTTCL_MIN_QOS							0
+#define MQTTCL_MAX_QOS							2
+#define MQTTCL_DEFAULT_QOS						MQTTCL_MAX_QOS
+#define MQTTCL_DEFAULT_RETAIN					false
+#define MQTTCL_DEFAULT_LAST_WILL_CONNECT_TOPIC	"LWC"
+#define MQTTCL_MIN_MAX_KEEP_ALIVE_TIME			10
+#define MQTTCL_DEFAULT_MAX_KEEP_ALIVE_TIME		60
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -96,20 +94,24 @@ public:
 		return m_strShmID.empty() ? NULL : m_strShmID.c_str();
 	}
 
-	inline const char* GetPrefix(void) const {
-		return m_strPrefix.empty() ? NULL : m_strPrefix.c_str();
+	inline const char* GetTopicPrefix(void) const {
+		return m_strTopicPrefix.empty() ? NULL : m_strTopicPrefix.c_str();
 	}
 
 	inline const char* GetLastWillTopic(void) const {
 		return m_strLastWillTopic.empty() ? NULL : m_strLastWillTopic.c_str();
 	}
 
-	inline const char* GetLastWillMessage(void) const {
-		return m_strLastWillMessage.empty() ? NULL : m_strLastWillMessage.c_str();
+	inline const void* GetLastWillMessage(void) const {
+		if(!m_bHasLastWill)
+			return nullptr;
+		return m_strLastWillMessage.empty() ? (const void*)&m_nLastWillMessage : (const void*)m_strLastWillMessage.c_str();
 	}
 
 	inline int GetLastWillMessageLength(void) const {
-		return (int)m_strLastWillMessage.length();
+		if(!m_bHasLastWill)
+			return 0;
+		return (int)(m_strLastWillMessage.empty() ? sizeof(m_nLastWillMessage) : m_strLastWillMessage.length());
 	}
 
 	inline int GetLastWillQOS(void) const {
@@ -128,24 +130,28 @@ public:
 		return m_bLastWillOnExit;
 	}
 
-	inline const char* GetLastWillOnExitMessage(void) const {
-		return m_strLastWillOnExitMsg.empty() ? NULL : m_strLastWillOnExitMsg.c_str();
+	inline const void* GetLastWillOnExitMessage(void) const {
+		return m_strLastWillOnExitMsg.empty() ? (const void*)&m_nLastWillOnExitMsg : (const void*)m_strLastWillOnExitMsg.c_str();
 	}
 
 	inline int GetLastWillOnExitMessageLength(void) const {
-		return (int)m_strLastWillOnExitMsg.length();
+		return (int)(m_strLastWillOnExitMsg.empty() ? sizeof(m_nLastWillOnExitMsg) : m_strLastWillOnExitMsg.length());
 	}
 
 	inline const char* GetConnectTopic(void) const {
 		return m_strConnectTopic.empty() ? NULL : m_strConnectTopic.c_str();
 	}
 
-	inline const char* GetConnectMessage(void) const {
-		return m_strConnectMessage.empty() ? NULL : m_strConnectMessage.c_str();
+	inline const void* GetConnectMessage(void) const {
+		if(!m_bHasConnect)
+			return nullptr;
+		return m_strConnectMessage.empty() ? (const void*)&m_nConnectMessage : (const void*)m_strConnectMessage.c_str();
 	}
 
 	inline int GetConnectMessageLength(void) const {
-		return (int)m_strConnectMessage.length();
+		if(!m_bHasConnect)
+			return 0;
+		return (int)(m_strConnectMessage.empty() ? sizeof(m_nConnectMessage) : m_strConnectMessage.length());
 	}
 
 	inline int GetConnectQOS(void) const {
@@ -160,6 +166,10 @@ public:
 		return m_bHasConnect;
 	}
 
+	inline bool TopicPrefixDisabled(void) const {
+		return m_bDisableTopicPrefix;
+	}
+
 	inline bool HasPrefix(void) const {
 		return m_bHasPrefix;
 	}
@@ -176,6 +186,7 @@ private:
 	bool GetValue(CJson_t &rjtParent, const char *pszKey, CJson_t &rjtVal, std::string &strErr);
 	bool GetBoolValue(CJson_t &rjtParent, const char *pszKey, bool &rbVal, std::string &strErr);
 	bool GetIntValue(CJson_t &rjtParent, const char *pszKey, int &rnVal, std::string &strErr);
+	bool GetInt64Value(CJson_t &rjtParent, const char *pszKey, long long &rnVal, std::string &strErr);
 	bool GetStringValue(CJson_t &rjtParent, const char *pszKey, std::string &rstrVal, std::string &strErr);
 
 private:
@@ -187,25 +198,29 @@ private:
 	std::string	m_strTlsPSK;
 	std::string	m_strDeviceID;
 	std::string	m_strShmID;
-	std::string	m_strPrefix;
+	std::string	m_strTopicPrefix;
 	int			m_nBrokerPort;
 	int			m_nDefaultQOS;
 	bool		m_bDefaultRetain;
 
 	std::string	m_strLastWillTopic;
 	std::string	m_strLastWillMessage;
+	long long	m_nLastWillMessage;
 	int			m_nLastWillQos;
 	bool		m_bLastWillRetain;
 	bool		m_bHasLastWill;
 	bool		m_bLastWillOnExit;
 	std::string	m_strLastWillOnExitMsg;
+	long long	m_nLastWillOnExitMsg;
 
 	std::string	m_strConnectTopic;
 	std::string	m_strConnectMessage;
+	long long	m_nConnectMessage;
 	int			m_nConnectQos;
 	bool		m_bConnectRetain;
 	bool		m_bHasConnect;
 	
+	bool		m_bDisableTopicPrefix;
 	bool		m_bHasPrefix;
 
 	int			m_nTlsMode;

+ 1 - 0
mqttcl/mqttclient.cpp

@@ -141,6 +141,7 @@ bool CMqttClient::EvalError(int nErr, bool &rbReconnect, bool &rbConnPending, bo
 
 	case MOSQ_ERR_NO_CONN:		// (maybe) recoverable errors
 	case MOSQ_ERR_CONN_LOST:
+	case MOSQ_ERR_EAI:
 		rbReconnect = true;
 		rbConnPending = false;
 		bRet = false;

+ 2 - 2
mqttcl/mqttvar.h

@@ -358,8 +358,8 @@ protected:
 
 	std::string CreateTopic(const char *pszTopicDevID, const char *pszTopicShmID, const char *pszValueFormat, const char *pszTopicCmd)
 	{
-		if((!pszTopicDevID || !*pszTopicDevID) && (!pszTopicShmID && !*pszTopicShmID))
-			return "";
+		if((!pszTopicDevID || !*pszTopicDevID) && (!pszTopicShmID || !*pszTopicShmID))
+			return ::formatString("%s/%s%s", pszValueFormat, pszTopicCmd, m_pszPath);
 		else if(pszTopicDevID && *pszTopicDevID && pszTopicShmID && *pszTopicShmID)
 			return ::formatString("%s/%s/%s/%s%s", pszTopicDevID, pszTopicShmID, pszValueFormat, pszTopicCmd, m_pszPath);
 		else

+ 1 - 0
mqttcl/tls/certgen.sh

@@ -6,6 +6,7 @@ CWD=$(pwd)
 cd $CFG_DIR
 
 clear.sh
+rm -f client/* || true
 
 #Selbst signiertes Zertifikat erstellen (CA):
 openssl req -batch -x509 -config openssl.conf -newkey rsa:4096 -sha256 -nodes -out ca.crt -outform PEM

+ 2 - 2
mqttcl/tls/clear.sh

@@ -5,7 +5,7 @@ CWD=$(pwd)
 
 cd $CFG_DIR
 
-rm -f *.crt *.csr *.key index.* serial.* serial.* *.txt *.pem client/*
-rmdir client &> /dev/null || true
+rm -f *.crt *.csr *.key index.* serial.* serial.* *.txt *.pem # client/*
+# rmdir client &> /dev/null || true
 
 cd $CWD

+ 1 - 1
mqttcl/tls/client.conf

@@ -8,7 +8,7 @@ req_extensions     = client_extensions
 [ distinguished_name ]
 
 commonName           = Common Name
-commonName_default   = Client
+commonName_default   = 04:A3:16:E9:40:9C
 
 ####################################################################
 [ client_extensions ]

+ 1 - 1
mqttcl/topic.txt

@@ -15,7 +15,7 @@ Allgemeines Topic-Format:
 
 Topic zum Publishen von Variablen-Werten:
 
-<Format>:	"BINLE" (little endian), "BINBE" (big endian), "JSON" oder "PBUF" (Protocol Buffers, nicht implementiert).
+<Format>:	"BINLE" (binär little endian), "BINBE" (binär big endian), "JSON" oder "PBUF" (Protocol Buffers, nicht implementiert).
 <Command>:	"VALUE".
 
 Beispiel:

+ 6 - 2
rest/helpers.cpp

@@ -14,9 +14,12 @@ DEFINE_UUID(UUID_REST_PLUGIN,
 typedef struct _PLUGIN
 {
 	std::string sName;
+	std::string sLibPath;
 	void *hLib;
 }PLUGIN;
 
+typedef int (*PFN_REST_REQUEST_HANDLER)(const struct _u_request*, struct _u_response*, void*);
+
 /////////////////////////////////////////////////////////////////////////////
 
 static std::vector<FILEREQUEST> g_afr;
@@ -43,7 +46,7 @@ static bool _IsSharedLib(const char *pszFilename)
 
 /////////////////////////////////////////////////////////////////////////////
 
-int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr, void *pCtx)
+int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr, PCREST_PLUGIN_REQUEST_CONTEXT prc)
 {
 	DIR *d;
 	int nLoaded = 0;
@@ -76,6 +79,7 @@ int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t
 							{
 								PLUGIN plugin;
 								plugin.sName = ppi->pszPluginName;
+								plugin.sLibPath = szPluginLib;
 								plugin.hLib = hLib;
 								g_aPlugins.push_back(plugin);
 								
@@ -86,7 +90,7 @@ int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t
 									
 									if(RequestHandler)
 									{
-										if(ulfius_add_endpoint_by_val(pInst, rh.pszMethod, rh.pszVUrl, nullptr, 0, RequestHandler, pCtx) == U_OK)
+										if(ulfius_add_endpoint_by_val(pInst, rh.pszHttpMethod, rh.pszVirtPath, nullptr, 0, RequestHandler, (void*)prc) == U_OK)
 											++nLoaded;
 									}
 								}

+ 1 - 1
rest/helpers.h

@@ -10,7 +10,7 @@
 // helpers.h - Declarations:
 
 int InitializeStaticFiles(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr);
-int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr, void *pCtx);
+int LoadPlugins(const char *pszRootDir, struct _u_instance *pInst, json_error_t &rJerr, PCREST_PLUGIN_REQUEST_CONTEXT prc);
 void UnloadPlugins(void);
 
 /////////////////////////////////////////////////////////////////////////////

+ 0 - 489
rest/main.cpp

@@ -1,489 +0,0 @@
-#include "main.h"
-#include "projal.h"
-#include "helpers.h"
-#include "callback.h"
-#include "instance.h"
-
-#if _REST_USE_SSL
-#include "keys.c"
-#endif	//	_REST_USE_SSL
-
-#if _REST_LINEAR_GET
-#define GetShmPostResponseCallback	GetShmPostResponseCallback_M
-#else	//	_REST_LINEAR_GET
-#define GetShmPostResponseCallback	GetShmPostResponseCallback_O
-#endif	//	_REST_LINEAR_GET
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// app control
-
-#define _APPID						GFA_APPCTRL_APPID_REST
-#define _APPNAME					"REST"
-#define _DEPENDENCIES				((appid_t)(GFA_APPCTRL_APPID_REMANENT))
-#define _REST_CYCLE_INTV_MS			200
-
-/////////////////////////////////////////////////////////////////////////////
-
-static volatile bool				g_fRun			= false;
-static volatile bool				g_fPauseImp		= false;
-static volatile bool				g_fPauseCmd		= false;
-static volatile bool				g_fZombie		= false;
-static appid_t						g_nDepRunning	= 0;
-static sigset_t						g_set;
-int									g_nLastSig = -1;
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void _SigHandler(int sig)
-{
-	g_nLastSig = sig;
-	g_fRun = g_fPauseImp = g_fPauseCmd = g_fZombie = false;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void _ProcessCtrlMessages(HAPPCTRL hAC, HAPPINFO hAI)
-{
-    ctrlmsg_t nCtrlMsg;
-
-	while(g_fRun && (nCtrlMsg = ::GfaIpcAppCtrlGetNextCtrlMsg(hAI)))
-	{
-		switch(nCtrlMsg)
-		{
-		case GFA_APPCTRL_CTRLMSG_STOP:
-			g_fRun = false;
-			g_fPauseImp = false;
-			g_fPauseCmd = false;
-			g_fZombie = false;
-			TRACE("Received Control Message 'Stop'\n");
-			return;
-		case GFA_APPCTRL_CTRLMSG_PAUSE:
-			if(!g_fPauseCmd)
-			{
-				g_fPauseCmd = true;
-				if(!g_fPauseImp)
-				{
-					::GfaIpcAppCtrlSetState(hAC, GIAS_Paused);
-					TRACE("Received Control Message 'Pause'\n");
-					TRACE("%-8s: State: %s\n", "Me", ::GfaIpcAppCtrlGetStateText(GIAS_Paused));
-				}
-			}
-			break;
-		case GFA_APPCTRL_CTRLMSG_RESUME:
-			if(g_fPauseCmd)
-			{
-				g_fPauseCmd = false;
-				if(!g_fPauseImp)
-				{
-					TRACE("Received Control Message 'Resume'\n");
-					::GfaIpcAppCtrlSetState(hAC, GIAS_Running);
-					TRACE("%-8s: State: %s\n", "Me", ::GfaIpcAppCtrlGetStateText(GIAS_Running));
-				}
-			}
-			break;
-		default:
-			break;
-		}
-	}
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void _ProcessStateEvents(HAPPCTRL hAC, HAPPINFO hAI)
-{
-    appid_t nAppIdSrc;
-    bool fOldPaused = g_fPauseImp;
-	char szDispName[128];
-
-	while(g_fRun && (nAppIdSrc = ::GfaIpcAppCtrlGetNextStateEvtSrc(hAI)))
-	{
-		GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(hAC, nAppIdSrc);
-		GfaIpcAppCtrlGetDisplayName(hAC, nAppIdSrc, szDispName, sizeof(szDispName));
-		TRACE("%-8s: State: %s\n", szDispName, ::GfaIpcAppCtrlGetStateText(state));
-		
-		if(nAppIdSrc & _DEPENDENCIES)
-		{
-			if(state == GIAS_Running)
-			{
-				TRACE("%s -> %s.\n", szDispName, ::GfaIpcAppCtrlGetStateText(state));
-				g_nDepRunning |= nAppIdSrc;
-			}
-			else
-			{
-				TRACE("%s -> %s.\n", szDispName, ::GfaIpcAppCtrlGetStateText(state));
-				g_nDepRunning &= ~nAppIdSrc;
-			}
-		}
-	}
-
-	if(g_fRun)
-	{
-		g_fPauseImp = (g_nDepRunning != _DEPENDENCIES);
-
-		if(!g_fPauseCmd && (fOldPaused != g_fPauseImp))
-		{
-			fOldPaused = g_fPauseImp;
-			GfaIpcAppStates newState = g_fPauseImp ? GIAS_Paused : GIAS_Running;
-			::GfaIpcAppCtrlSetState(hAC, newState);
-			if(g_fPauseImp)
-			{
-				TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(newState));
-			}
-			else
-			{
-				TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(newState));
-			}
-		}
-	}
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// main
-
-int main(int argc, char *argv[])
-{
-	UNUSED(argc);
-	UNUSED(argv);
-
-	int nRet = 0;
-	HSHM hShm = NULL;
-	void *pShm = NULL;
-	HAPPCTRL hAC = NULL;
-	HAPPINFO hAI;
-	struct _u_instance instance;
-	CURLcode cuGlobInit = CURL_LAST;
-	int ulfInit = U_ERROR, ulfStart = U_ERROR;
-	bool bUlfFrmwrkStarted = false;
-
-    /////////////////////////////////////////////////////////////////////////
-    // check for multiple instances
-
-    CProcessInstance pi;
-
-    if(!pi.LockInstance(UUID_SHM))
-    {
-        ETRACE("Failed to start instance!\n");
-        return -1;
-    }
-
-	/////////////////////////////////////////////////////////////////////////
-
-	do
-	{
-		char szRootDir[PATH_MAX];
-		const char *pszRootDir;
-		json_error_t jerr;
-
-		g_fZombie = true;
-
-		/////////////////////////////////////////////////////////////
-		// configure signal handling
-
-		struct sigaction sa;
-		memset(&sa, 0, sizeof(sa));
-		sigfillset(&g_set);
-
-		// handle signals
-		sa.sa_handler = _SigHandler;
-	    sigaction(SIGHUP, &sa, NULL);	// handles user's terminal disconnect
-	    sigaction(SIGQUIT, &sa, NULL);	// handles Ctrl + '\'
-		sigaction(SIGTERM, &sa, NULL);	// handles normal termination
-		sigaction(SIGABRT, &sa, NULL);	// handles abnormal termination (i.e. abort())
-		sigaction(SIGINT, &sa, NULL);	// handles Ctrl + 'C'
-
-		// ignore signals
-		sa.sa_handler = SIG_IGN;
-	    sigaction(SIGTSTP, &sa, NULL);	// ignores Ctrl + 'Z'
-	    sigaction(SIGSTOP, &sa, NULL);	// ignores Stop
-	    sigaction(SIGCONT, &sa, NULL);	// ignores Continue
-	    sigaction(SIGCHLD, &sa, NULL);	// ignores child process termination
-	    sigaction(0, &sa, NULL);		// ignores shell termination
-
-		/////////////////////////////////////////////////////////////
-		// initialize app control
-
-		if(!(hAC = ::GfaIpcAppCtrlAcquire(_APPID, _APPNAME, _REST_CYCLE_INTV_MS * 1000, _REST_CYCLE_INTV_MS * 3000)))
-		{
-			ETRACE("Failed to acquire AppCtrl-Handle!\n");
-			nRet = -1;
-			break;
-		}
-
-		::GfaIpcAppCtrlSetState(hAC, GIAS_Initializing);
-		TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(GIAS_Initializing));
-
-		if(!::GfaIpcAppCtrlSubscribeStateEvents(hAC, _DEPENDENCIES))
-		{
-			ETRACE("Failed to subscribe state event notifications!\n");
-			nRet = -1;
-			break;
-		}
-
-		/////////////////////////////////////////////////////////////////////
-
-		pszRootDir = GetAppDirectory(szRootDir, _COUNTOF(szRootDir));
-
-		/////////////////////////////////////////////////////////////////////
-		// initialize CURL
-
-		if((cuGlobInit = curl_global_init(CURL_GLOBAL_ALL)) != CURLE_OK)
-		{
-			ETRACE("Failed to initialize CURL!\n");
-			nRet = -1;
-			break;
-		}
-
-	    if(!(hShm = acquire_shm(sizeof(shm_t))))
-	    {
-			ETRACE("GfaIpcAcquireSHM failed!\n");
-			nRet = -1;
-			break;
-	    }
-
-	    if(!(pShm = GfaIpcAcquirePointer(hShm)))
-	    {
-			ETRACE("GfaIpcAcquirePointer failed!\n");
-			nRet = -1;
-			break;
-	    }
-	    
-#ifdef _DEBUG
-		GfaIpcDumpSHMROT();
-		fflush(stdout);
-#endif	//	_DEBUG
-
-		/////////////////////////////////////////////////////////////////////
-
-		if((ulfInit = ulfius_init_instance(&instance, _REST_PORT, NULL, NULL)) != U_OK)
-		{
-			ETRACE("ulfius_init_instance failed!\n");
-			nRet = -1;
-			break;
-		}
-			
-		/////////////////////////////////////////////////////////////////////
-		// SHM and SHM variables table
-
-		CRestVarTable map;
-		CShm_t shm(pShm, hShm);
-		shm.InitPath(NULL, NULL);
-		shm.CreateMembersTable(map);
-
-		/////////////////////////////////////////////////////////////////////
-		// initialize request parameters
-
-		SHM_REQUEST_PARAMS srp;
-		srp.pMap	= &map;
-		srp.pszUuid	= UUID_SHM;
-
-		/////////////////////////////////////////////////////////////////////
-		/////////////////////////////////////////////////////////////////////
-		// add handler functions
-		// initialize static files if any
-		if(InitializeStaticFiles(pszRootDir, &instance, jerr) < 0)
-		{
-			ETRACE("InitializeStaticFiles failed!\n");
-			nRet = -1;
-			break;
-		}
-
-		/////////////////////////////////////////////////////////////////////
-		// POST
-		if(ulfius_add_endpoint_by_val(&instance, "POST", GET_SHM_PREFIX, NULL, 0, &GetShmPostResponseCallback, &srp) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-		if(ulfius_add_endpoint_by_val(&instance, "POST", SET_SHM_PREFIX, NULL, 0, &SetShmPostResponseCallback, &srp) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-
-#if _REST_IMPLEMENT_GET
-		/////////////////////////////////////////////////////////////////////
-		// GET
-		if(ulfius_add_endpoint_by_val(&instance, "GET", GET_SHM_PREFIX, "/*", 0, &GetShmGetResponseCallback, &srp) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-#endif	//	_REST_IMPLEMENT_GET
-
-		/////////////////////////////////////////////////////////////////////
-		// OPTIONS
-		if(ulfius_add_endpoint_by_val(&instance, "OPTIONS", NULL, "/*", 0, &OptionsResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-
-		/////////////////////////////////////////////////////////////////////
-		// handler for HTTP verbs that are not allowed
-		if(ulfius_add_endpoint_by_val(&instance, "HEAD", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-		if(ulfius_add_endpoint_by_val(&instance, "PUT", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-		if(ulfius_add_endpoint_by_val(&instance, "DELETE", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-		if(ulfius_add_endpoint_by_val(&instance, "CONNECT", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-		if(ulfius_add_endpoint_by_val(&instance, "TRACE", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-		if(ulfius_add_endpoint_by_val(&instance, "PATCH", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
-		{
-			ETRACE("ulfius_add_endpoint_by_val failed!\n");
-			nRet = -1;
-			break;
-		}
-
-		/////////////////////////////////////////////////////////////////////
-		// start service
-
-#if _REST_USE_SSL
-	    if((ulfStart = ulfius_start_secure_framework(&instance, g_pszKeyPem, g_pszCertPem)) != U_OK)
-#else	// _REST_USE_SSL
-		if((ulfStart = ulfius_start_framework(&instance)) != U_OK)
-#endif	// _REST_USE_SSL
-		{
-			ETRACE("ulfius_start_framework failed!\n");
-			nRet = -1;
-			break;
-		}
-
-		TRACE("Service started at port %hu.\n", instance.port);
-
-		bUlfFrmwrkStarted = true;
-		g_fZombie = false;
-		g_fRun = true;
-		::GfaIpcAppCtrlSetState(hAC, GIAS_Running);
-	}
-	while(false);
-
-	/////////////////////////////////////////////////////////////////////////
-	/////////////////////////////////////////////////////////////////////////
-	/////////////////////////////////////////////////////////////////////////
-
-	while(g_fRun)
-	{
-		////////////////////////////////////////////////////////////////////////////////////////
-		// update app control info
-
-		if((hAI = ::GfaIpcAppCtrlInfoUpdate(hAC, 0)))
-		{
-			_ProcessCtrlMessages(hAC, hAI);
-			if(!g_fRun)
-				break;
-			_ProcessStateEvents(hAC, hAI);
-		}
-		
-		if(bUlfFrmwrkStarted && (g_fPauseImp || g_fPauseCmd))
-		{
-			ulfius_stop_framework(&instance);
-			bUlfFrmwrkStarted = false;
-			TRACE("Service exit.\n");
-		}
-		else if(!bUlfFrmwrkStarted && !g_fPauseImp && !g_fPauseCmd)
-		{
-#if _REST_USE_SSL
-		    if((ulfStart = ulfius_start_secure_framework(&instance, g_pszKeyPem, g_pszCertPem)) != U_OK)
-#else	// _REST_USE_SSL
-			if((ulfStart = ulfius_start_framework(&instance)) != U_OK)
-#endif	// _REST_USE_SSL
-			{
-				ETRACE("ulfius_start_framework failed!\n");
-				g_fZombie = true;
-				g_fRun = false;
-				nRet = -1;
-				break;
-			}
-
-			bUlfFrmwrkStarted = true;
-			TRACE("Service started at port %hu.\n", instance.port);
-		}
-
-		usleep(_REST_CYCLE_INTV_MS * 1000);
-	}
-
-	/////////////////////////////////////////////////////////////////////////
-	/////////////////////////////////////////////////////////////////////////
-	/////////////////////////////////////////////////////////////////////////
-
-	if(g_nLastSig >= 0)
-	{
-		TRACE("Received signal '%s'.\n", strsignal(g_nLastSig));
-		g_nLastSig = -1;
-	}
-
-	if(bUlfFrmwrkStarted)
-	{
-		ulfius_stop_framework(&instance);
-		TRACE("Service exit.\n");
-	}
-
-	if(ulfInit == U_OK)
-		ulfius_clean_instance(&instance);
-
-	if(hShm)
-	{
-		if(pShm)
-		{
-			TRACE("Releasing SHM Pointer ...\n");
-			::GfaIpcReleasePointer(hShm, pShm);
-		}
-
-		TRACE("Releasing SHM Handle ...\n");
-    	::GfaIpcReleaseSHM(hShm);
-    }
-
-	if(cuGlobInit == CURLE_OK)
-	   	curl_global_cleanup();
-	
-	if(g_fZombie)
-	{
-		if(hAC)
-			::GfaIpcAppCtrlSetState(hAC, GIAS_Zombie);
-		TRACE("Enter Zombie state ...\n");
-		pause();
-
-		if(g_nLastSig >= 0)
-		{
-			TRACE("Received signal '%s'.\n", strsignal(g_nLastSig));
-		}
-	}
-
-	if(hAC)
-	{
-//		TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(GIAS_Terminating));
-		::GfaIpcAppCtrlSetState(hAC, GIAS_Terminating);
-		TRACE("Releasing App Control ...\n");
-		::GfaIpcAppCtrlRelease(hAC);
-	}
-
-	TRACE("Process exit.\n");
-	return nRet;
-}

+ 2 - 0
rest/main.h

@@ -19,10 +19,12 @@
 #include <gfa/svc/common/debug.h>
 #include <gfa/svc/common/fileutil.h>
 #include <gfa/svc/rest/defines.h>
+#include <gfa/svc/rest/plugin.h>
 #else	//	_LIBBUILD
 #include "common/debug.h"
 #include "common/fileutil.h"
 #include "defines.h"
+#include "plugin.h"
 #endif	//	_LIBBUILD
 
 //#include "apikey.h"

+ 26 - 18
rest/plugin.h

@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <gfa/gfaipc.h>
 #ifndef _LIBBUILD
 #include <gfa/svc/common/uuid.h>
 #else	//	_LIBBUILD
@@ -17,7 +18,6 @@ extern "C" {
 #endif	//	__cplusplus
 
 #include <ulfius.h>
-#include <gfa/gfaipc.h>
 
 /////////////////////////////////////////////////////////////////////////////
 // plugin.h - Declarations:
@@ -25,44 +25,52 @@ extern "C" {
 typedef struct _REST_REQUEST_HANDLER
 {
 	const char *pszHandlerName;
-	const char *pszMethod;
-	const char *pszVUrl;
-	const char *pszMime;
+	const char *pszHttpMethod;
+	const char *pszVirtPath;
+	const char *pszContentType;
 	const char *pszFunctionName;
-}REST_REQUEST_HANDLER, *LPREST_REQUEST_HANDLER;
-typedef const REST_REQUEST_HANDLER *LPCREST_REQUEST_HANDLER;
+}REST_REQUEST_HANDLER, *PREST_REQUEST_HANDLER;
+typedef const REST_REQUEST_HANDLER *PCREST_REQUEST_HANDLER;
 
 typedef struct _REST_PLUGIN_INFO
 {
-	uuid_t signature;
+	uuid_t signature;			// must be {0x75ed2211, 0x0a25, 0x4a55, 0x96, 0x2b, 0x31, 0xd3, 0xb0, 0xe6, 0x12, 0x3a}
 	const char *pszPluginName;
 	size_t nHandlerCnt;
 	REST_REQUEST_HANDLER handler[1];
-}REST_PLUGIN_INFO, *LPREST_PLUGIN_INFO;
-typedef const REST_PLUGIN_INFO *LPCREST_PLUGIN_INFO;
+}REST_PLUGIN_INFO, *PREST_PLUGIN_INFO;
+typedef const REST_PLUGIN_INFO *PCREST_PLUGIN_INFO;
+
+/////////////////////////////////////////////////////////////////////////////
 
-typedef struct _REST_PLUGIN_REQUEST_HANDLER_PARAMS
+typedef struct _REST_PLUGIN_REQUEST_CONTEXT
 {
 	uuid_t uuidShm;
 	HSHM hShm;
 	void *pShm;
-	void *pParam;
-}REST_PLUGIN_REQUEST_HANDLER_PARAMS, *LPREST_PLUGIN_REQUEST_HANDLER_PARAMS;
-typedef const REST_PLUGIN_REQUEST_HANDLER_PARAMS *LPCREST_PLUGIN_REQUEST_HANDLER_PARAMS;
+	void (*pfnLockSHM)(HSHM);
+	void (*pfnUnlockSHM)(HSHM);
+}REST_PLUGIN_REQUEST_CONTEXT, *PREST_PLUGIN_REQUEST_CONTEXT;
+typedef const REST_PLUGIN_REQUEST_CONTEXT *PCREST_PLUGIN_REQUEST_CONTEXT;
 
-DECLARE_UUID(UUID_REST_PLUGIN);
+/////////////////////////////////////////////////////////////////////////////
+
+#define _HTTP_METHOD_GET			"GET"
+#define _HTTP_METHOD_POST			"POST"
 
 /////////////////////////////////////////////////////////////////////////////
 
-typedef const REST_PLUGIN_INFO* (*PFN_GETPLUGININFO)(void);
-typedef int (*PFN_REST_REQUEST_HANDLER)(const struct _u_request*, struct _u_response*, void*);
+typedef PCREST_PLUGIN_INFO (*PFN_GETPLUGININFO)(void);
 
 /*
 Prototype example:
 
-extern "C" int PluginRequestHandler(const struct _u_request *request, struct _u_response *response, void *user_data)
+extern "C" int PluginRequestHandler(const struct _u_request *pRequ, struct _u_response *pResp, PCREST_PLUGIN_REQUEST_CONTEXT prc)
 {
-...
+	...
+	...
+
+	return U_CALLBACK_CONTINUE;
 }
 */