mqttcfg.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. #include <stdio.h>
  2. #include <limits.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include "fileutil.h"
  6. #include "strutil.h"
  7. #include "mqttcfg.h"
  8. #include "debug.h"
  9. #define _DEFAULT_CFG_FILE_NAME "mqttcl.cfg.json"
  10. #define _CFG_KEY_NAME_BROKER_ADDR "brokerAddr"
  11. #define _CFG_KEY_NAME_BROKER_PORT "brokerPort"
  12. #define _CFG_KEY_NAME_DEFAULT_QOS "defaultQos"
  13. #define _CFG_KEY_NAME_DEFAULT_RETAIN "defaultRetain"
  14. #define _CFG_KEY_NAME_DEVICE_PREFIX "devicePrefix"
  15. #define _CFG_KEY_NAME_DEVICE_ID "deviceID"
  16. #define _CFG_KEY_NAME_TLS_MODE "tlsMode"
  17. #define _CFG_KEY_NAME_TLS_CA_CRT_FILE "tlsCaCrtFile"
  18. #define _CFG_KEY_NAME_TLS_CL_CRT_FILE "tlsClCrtFile"
  19. #define _CFG_KEY_NAME_TLS_CL_KEY_FILE "tlsClKeyFile"
  20. #define _CFG_KEY_NAME_TLS_PSK "tlsPsk"
  21. #define _CFG_KEY_NAME_LAST_WILL_MSG_STR "lastWillMsgStr"
  22. #define _CFG_KEY_NAME_LAST_WILL_MSG_INT "lastWillMsgInt"
  23. #define _CFG_KEY_NAME_LAST_WILL_TOPIC "lastWillTopic"
  24. #define _CFG_KEY_NAME_LAST_WILL_QOS "lastWillQos"
  25. #define _CFG_KEY_NAME_LAST_WILL_RETAIN "lastWillRetain"
  26. #define _CFG_KEY_NAME_LAST_WILL_ON_EXIT "lastWillOnExit"
  27. #define _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_STR "lastWillOnExitMsgStr"
  28. #define _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_INT "lastWillOnExitMsgInt"
  29. #define _CFG_KEY_NAME_CONNECT_MSG_STR "connectMsgStr"
  30. #define _CFG_KEY_NAME_CONNECT_MSG_INT "connectMsgInt"
  31. #define _CFG_KEY_NAME_CONNECT_TOPIC "connectTopic"
  32. #define _CFG_KEY_NAME_CONNECT_QOS "connectQos"
  33. #define _CFG_KEY_NAME_CONNECT_RETAIN "connectRetain"
  34. #define _CFG_KEY_NAME_MAX_KEEP_ALIVE "maxKeepAlive"
  35. #define _CFG_KEY_NAME_TOPIC_PREFIX_STRING "topicPrefix"
  36. #define _CFG_KEY_NAME_DISABLE_TOPIC_PREFIX "disableTopicPrefix"
  37. /////////////////////////////////////////////////////////////////////////////
  38. CMqttClConfig::CMqttClConfig(const char *pszShmUuid) : m_strShmID(formatString("SHM-%s", strucase(pszShmUuid).c_str())),
  39. m_nBrokerPort(0),
  40. m_nDefaultQOS(0),
  41. m_bDefaultRetain(MQTTCL_DEFAULT_RETAIN),
  42. m_nLastWillMessage(0),
  43. m_nLastWillQos(m_nDefaultQOS),
  44. m_bLastWillRetain(MQTTCL_DEFAULT_RETAIN),
  45. m_bHasLastWill(false),
  46. m_bLastWillOnExit(false),
  47. m_nLastWillOnExitMsg(0),
  48. m_nConnectMessage(0),
  49. m_nConnectQos(m_nDefaultQOS),
  50. m_bConnectRetain(MQTTCL_DEFAULT_RETAIN),
  51. m_bHasConnect(false),
  52. m_bDisableTopicPrefix(false),
  53. m_bHasPrefix(false),
  54. m_nTlsMode(0),
  55. m_nMaxKeepAlive(MQTTCL_DEFAULT_MAX_KEEP_ALIVE_TIME)
  56. {
  57. }
  58. CMqttClConfig::~CMqttClConfig(void)
  59. {
  60. }
  61. /////////////////////////////////////////////////////////////////////////////
  62. // LoadCfg
  63. bool CMqttClConfig::LoadCfg(const char *pszCfgFilePath, CLogfile &rlf)
  64. {
  65. char szCfgFilePath[PATH_MAX];
  66. std::string strErr;
  67. if(!pszCfgFilePath)
  68. { // use default config file path
  69. pszCfgFilePath = ::BuildCanonicalFilePath(NULL, _DEFAULT_CFG_FILE_NAME, szCfgFilePath, sizeof(szCfgFilePath));
  70. }
  71. /////////////////////////////////////////////////////////////////////////
  72. // load and parse config file
  73. json_t *pjtCfg;
  74. json_error_t err;
  75. if(!(pjtCfg = ::json_load_file(pszCfgFilePath, JSON_REJECT_DUPLICATES, &err)))
  76. {
  77. rlf.Error("LoadCfg: Error loading file %s: %s!\n", pszCfgFilePath, err.text);
  78. return false;
  79. }
  80. CJson_t jtCfg(pjtCfg, true);
  81. /////////////////////////////////////////////////////////////////////////
  82. // tlsMode
  83. if(!GetIntValue(jtCfg, _CFG_KEY_NAME_TLS_MODE, m_nTlsMode, strErr))
  84. {
  85. m_nTlsMode = MQTTCL_TLS_MODE_OFF;
  86. rlf.Warning("LoadCfg: TLS will not be used!\n");
  87. }
  88. else if((m_nTlsMode < MQTTCL_TLS_MODE_OFF) || (m_nTlsMode > MQTTCL_TLS_MODE_PSK))
  89. {
  90. rlf.Error("LoadCfg: Invalid TLS mode: %d! No way to continue!\n", m_nTlsMode);
  91. return false;
  92. }
  93. /////////////////////////////////////////////////////////////////////////
  94. // brokerAddr
  95. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_BROKER_ADDR, m_strBrokerAddr, strErr))
  96. {
  97. rlf.Error("LoadCfg: %s!\n", strErr.c_str());
  98. return false;
  99. }
  100. /////////////////////////////////////////////////////////////////////////
  101. // brokerPort
  102. if(!GetIntValue(jtCfg, _CFG_KEY_NAME_BROKER_PORT, m_nBrokerPort, strErr))
  103. {
  104. m_nBrokerPort = (m_nTlsMode > MQTTCL_TLS_MODE_OFF) ? 8883 : 1883;
  105. rlf.Info("LoadCfg: Using default broker port %d!\n", m_nBrokerPort);
  106. }
  107. else if(m_nBrokerPort < 0 || m_nBrokerPort > 0xffff)
  108. {
  109. rlf.Error("LoadCfg: Invalid broker port number: %d! No way to continue!\n", m_nBrokerPort);
  110. return false;
  111. }
  112. /////////////////////////////////////////////////////////////////////////
  113. // defaultQos
  114. if(!GetIntValue(jtCfg, _CFG_KEY_NAME_DEFAULT_QOS, m_nDefaultQOS, strErr))
  115. {
  116. m_nDefaultQOS = MQTTCL_DEFAULT_QOS;
  117. rlf.Info("LoadCfg: Using default QOS: %d!\n", m_nDefaultQOS);
  118. }
  119. else if(m_nDefaultQOS < MQTTCL_MIN_QOS)
  120. {
  121. rlf.Warning("LoadCfg: Invalid QOS: %d - adjusted to %d!\n", m_nDefaultQOS, MQTTCL_MIN_QOS);
  122. m_nDefaultQOS = MQTTCL_MIN_QOS;
  123. }
  124. else if(m_nDefaultQOS > MQTTCL_MAX_QOS)
  125. {
  126. rlf.Warning("LoadCfg: Invalid QOS: %d - adjusted to %d!\n", m_nDefaultQOS, MQTTCL_MAX_QOS);
  127. m_nDefaultQOS = MQTTCL_MAX_QOS;
  128. }
  129. else
  130. {
  131. rlf.Info("LoadCfg: Default QOS: %d!\n", m_nDefaultQOS);
  132. }
  133. /////////////////////////////////////////////////////////////////////////
  134. // defaultRetain
  135. if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_DEFAULT_RETAIN, m_bDefaultRetain, strErr))
  136. {
  137. m_bDefaultRetain = MQTTCL_DEFAULT_RETAIN;
  138. rlf.Info("LoadCfg: Using default retain \"%s\"!\n", m_bDefaultRetain ? "true" : "false");
  139. }
  140. /////////////////////////////////////////////////////////////////////////
  141. // lastWillMsgStr
  142. if(GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_MSG_STR, m_strLastWillMessage, strErr))
  143. {
  144. m_bHasLastWill = true;
  145. rlf.Info("LoadCfg: Last Will - String message: \"%s\".\n", m_strLastWillMessage.c_str());
  146. }
  147. /////////////////////////////////////////////////////////////////////////
  148. // lastWillMsgInt
  149. if(!m_bHasLastWill)
  150. {
  151. if(GetInt64Value(jtCfg, _CFG_KEY_NAME_LAST_WILL_MSG_INT, m_nLastWillMessage, strErr))
  152. {
  153. m_bHasLastWill = true;
  154. rlf.Info("LoadCfg: Last Will - Numeric message: %lld.\n", m_nLastWillMessage);
  155. }
  156. else
  157. {
  158. rlf.Warning("LoadCfg: %s! No Last Will Message provided.\n", strErr.c_str());
  159. }
  160. }
  161. if(m_bHasLastWill)
  162. {
  163. /////////////////////////////////////////////////////////////////////
  164. // lastWillTopic
  165. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_TOPIC, m_strLastWillTopic, strErr))
  166. {
  167. m_strLastWillTopic = MQTTCL_DEFAULT_LAST_WILL_CONNECT_TOPIC;
  168. rlf.Info("LoadCfg: %s! Setting Last Will Topic to default: \"%s\".\n", strErr.c_str(), m_strLastWillTopic.c_str());
  169. }
  170. /////////////////////////////////////////////////////////////////////
  171. // lastWillQos
  172. if(!GetIntValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_QOS, m_nLastWillQos, strErr))
  173. {
  174. m_nLastWillQos = m_nDefaultQOS;
  175. rlf.Info("LoadCfg: %s! Using default Last Will QOS: %d!\n", strErr.c_str(), m_nLastWillQos);
  176. }
  177. /////////////////////////////////////////////////////////////////////
  178. // lastWillRetain
  179. if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_RETAIN, m_bLastWillRetain, strErr))
  180. {
  181. m_bLastWillRetain = m_bDefaultRetain;
  182. rlf.Info("LoadCfg: %s! Using default Last Will retain: \"%s\"!\n", strErr.c_str(), m_bLastWillRetain ? "true" : "false");
  183. }
  184. /////////////////////////////////////////////////////////////////////
  185. // lastWillOnExit
  186. if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT, m_bLastWillOnExit, strErr))
  187. {
  188. m_bLastWillOnExit = false;
  189. rlf.Warning("LoadCfg: %s! No Last Will on Exit.\n", strErr.c_str());
  190. }
  191. if(m_bLastWillOnExit)
  192. {
  193. /////////////////////////////////////////////////////////////////
  194. // lastWillOnExitMsgStr, lastWillOnExitMsgInt
  195. if(GetStringValue(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_STR, m_strLastWillOnExitMsg, strErr))
  196. {
  197. rlf.Info("LoadCfg: Last Will on Exit - String message: \"%s\".\n", m_strLastWillOnExitMsg.c_str());
  198. }
  199. else
  200. {
  201. if(GetInt64Value(jtCfg, _CFG_KEY_NAME_LAST_WILL_ON_EXIT_MSG_INT, m_nLastWillOnExitMsg, strErr))
  202. {
  203. rlf.Info("LoadCfg: Last Will on Exit - Numeric message: %lld.\n", m_nLastWillOnExitMsg);
  204. }
  205. else
  206. {
  207. if(!m_strLastWillMessage.empty())
  208. {
  209. m_strLastWillOnExitMsg = m_strLastWillMessage;
  210. rlf.Info("LoadCfg: Setting Last Will Exit Message to Last Will string: \"%s\".\n", m_strLastWillOnExitMsg.c_str());
  211. }
  212. else
  213. {
  214. m_nLastWillOnExitMsg = m_nLastWillMessage;
  215. rlf.Info("LoadCfg: Setting Last Will Exit Message to Last Will numeric: %lld.\n", m_nLastWillOnExitMsg);
  216. }
  217. }
  218. }
  219. }
  220. }
  221. /////////////////////////////////////////////////////////////////////////
  222. // connectMsgStr
  223. if(GetStringValue(jtCfg, _CFG_KEY_NAME_CONNECT_MSG_STR, m_strConnectMessage, strErr))
  224. {
  225. m_bHasConnect = true;
  226. rlf.Info("LoadCfg: Connect - String message: \"%s\".\n", m_strConnectMessage.c_str());
  227. }
  228. /////////////////////////////////////////////////////////////////////////
  229. // connectMsgInt
  230. if(!m_bHasConnect)
  231. {
  232. if(GetInt64Value(jtCfg, _CFG_KEY_NAME_CONNECT_MSG_INT, m_nConnectMessage, strErr))
  233. {
  234. m_bHasConnect = true;
  235. rlf.Info("LoadCfg: Connect - Numeric message: %lld.\n", m_nConnectMessage);
  236. }
  237. else
  238. {
  239. rlf.Warning("LoadCfg: %s! No Connect message provided.\n", strErr.c_str());
  240. }
  241. }
  242. if(m_bHasConnect)
  243. {
  244. /////////////////////////////////////////////////////////////////////
  245. // connectTopic
  246. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_CONNECT_TOPIC, m_strConnectTopic, strErr))
  247. {
  248. if(m_bHasLastWill)
  249. {
  250. m_strConnectTopic = m_strLastWillTopic;
  251. rlf.Info("LoadCfg: %s! Setting Connect Topic to Last Will Topic: \"%s\".\n", strErr.c_str(), m_strConnectTopic.c_str());
  252. }
  253. else
  254. {
  255. m_strConnectTopic = MQTTCL_DEFAULT_LAST_WILL_CONNECT_TOPIC;
  256. rlf.Info("LoadCfg: %s! Setting Connect Topic to default: \"%s\".\n", strErr.c_str(), m_strConnectTopic.c_str());
  257. }
  258. }
  259. /////////////////////////////////////////////////////////////////////
  260. // connectQos
  261. if(!GetIntValue(jtCfg, _CFG_KEY_NAME_CONNECT_QOS, m_nConnectQos, strErr))
  262. {
  263. m_nConnectQos = m_nDefaultQOS;
  264. rlf.Info("LoadCfg: %s! Using default Connect Qos: %d!\n", strErr.c_str(), m_nConnectQos);
  265. }
  266. /////////////////////////////////////////////////////////////////////
  267. // connectRetain
  268. if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_CONNECT_RETAIN, m_bConnectRetain, strErr))
  269. {
  270. m_bConnectRetain = m_bDefaultRetain;
  271. rlf.Info("LoadCfg: %s! Using default Last Will retain: %s!\n", strErr.c_str(), m_bConnectRetain ? "true" : "false");
  272. }
  273. }
  274. /////////////////////////////////////////////////////////////////////////
  275. // maxKeepAlive
  276. if(!GetIntValue(jtCfg, _CFG_KEY_NAME_MAX_KEEP_ALIVE, m_nMaxKeepAlive, strErr))
  277. {
  278. m_nMaxKeepAlive = MQTTCL_DEFAULT_MAX_KEEP_ALIVE_TIME;
  279. rlf.Info("LoadCfg: %s! Using default Keep-alive time: %d!\n", strErr.c_str(), m_nMaxKeepAlive);
  280. }
  281. else if(m_nMaxKeepAlive < MQTTCL_MIN_MAX_KEEP_ALIVE_TIME)
  282. {
  283. rlf.Warning("LoadCfg: Adjusting max keep-alive time from %d to %d!\n", m_nMaxKeepAlive, MQTTCL_MIN_MAX_KEEP_ALIVE_TIME);
  284. m_nMaxKeepAlive = MQTTCL_MIN_MAX_KEEP_ALIVE_TIME;
  285. }
  286. /////////////////////////////////////////////////////////////////////////
  287. // devicePrefix
  288. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_DEVICE_PREFIX, m_strDevicePrefix, strErr))
  289. {
  290. rlf.Warning("LoadCfg: %s! Using empty device prefix!\n", strErr.c_str());
  291. }
  292. /////////////////////////////////////////////////////////////////////////
  293. // deviceID
  294. if(GetStringValue(jtCfg, _CFG_KEY_NAME_DEVICE_ID, m_strDeviceID, strErr))
  295. {
  296. rlf.Info("LoadCfg: Using configured device ID: \"%s\"!\n", m_strDeviceID.c_str());
  297. }
  298. else
  299. {
  300. m_strDeviceID = CreateDeviceID(m_strDevicePrefix.c_str());
  301. rlf.Info("LoadCfg: Using automatic device ID: \"%s\"!\n", m_strDeviceID.c_str());
  302. }
  303. /////////////////////////////////////////////////////////////////////
  304. // disableTopicPrefix
  305. if(!GetBoolValue(jtCfg, _CFG_KEY_NAME_DISABLE_TOPIC_PREFIX, m_bDisableTopicPrefix, strErr))
  306. {
  307. m_bDisableTopicPrefix = false;
  308. }
  309. /////////////////////////////////////////////////////////////////////////
  310. // topicPrefix
  311. if(!m_bDisableTopicPrefix)
  312. {
  313. if(GetStringValue(jtCfg, _CFG_KEY_NAME_TOPIC_PREFIX_STRING, m_strTopicPrefix, strErr))
  314. {
  315. rlf.Info("LoadCfg: Using configured topic prefix: \"%s\"!\n", m_strTopicPrefix.c_str());
  316. }
  317. else
  318. {
  319. m_strTopicPrefix = formatString("%s/%s", GetDeviceID(), GetShmID());
  320. rlf.Info("LoadCfg: Using automatic topic prefix: \"%s\"!\n", m_strTopicPrefix.c_str());
  321. }
  322. }
  323. else
  324. {
  325. m_strTopicPrefix.clear();
  326. rlf.Warning("LoadCfg: Topic prefix disabled!\n");
  327. }
  328. /////////////////////////////////////////////////////////////////////////
  329. // if m_nTlsMode != MQTTCL_TLS_MODE_OFF
  330. if(m_nTlsMode == MQTTCL_TLS_MODE_CRT)
  331. {
  332. /////////////////////////////////////////////////////////////////////
  333. // tlsCaCrtFile
  334. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_CA_CRT_FILE, m_strTlsCaCrtFile, strErr))
  335. {
  336. rlf.Error("LoadCfg: %s! TLS-Mode = %d and no Certificate Authority file provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
  337. return false;
  338. }
  339. /////////////////////////////////////////////////////////////////////
  340. // tlsClCrtFile
  341. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_CL_CRT_FILE, m_strTlsClCrtFile, strErr))
  342. {
  343. rlf.Error("LoadCfg: %s! TLS-Mode = %d and no public Key Certificate file provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
  344. return false;
  345. }
  346. /////////////////////////////////////////////////////////////////////
  347. // tlsClKeyFile
  348. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_CL_KEY_FILE, m_strTlsClKeyFile, strErr))
  349. {
  350. rlf.Error("LoadCfg: %s! TLS-Mode = %d and no private Key file provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
  351. return false;
  352. }
  353. }
  354. else if(m_nTlsMode == MQTTCL_TLS_MODE_PSK)
  355. {
  356. /////////////////////////////////////////////////////////////////////
  357. // tlsPsk
  358. if(!GetStringValue(jtCfg, _CFG_KEY_NAME_TLS_PSK, m_strTlsPSK, strErr))
  359. {
  360. rlf.Error("LoadCfg: %s! TLS-Mode = %d and no Preshared Key provided! No way to continue!\n", strErr.c_str(), m_nTlsMode);
  361. return false;
  362. }
  363. }
  364. return true;
  365. }
  366. /////////////////////////////////////////////////////////////////////////////
  367. bool CMqttClConfig::GetValue(CJson_t &rjtParent, const char *pszKey, CJson_t &rjtVal, std::string &strErr)
  368. {
  369. if(!rjtParent.GetValue(pszKey, rjtVal))
  370. {
  371. strErr = formatString("Key \"%s\" not found", pszKey);
  372. return false;
  373. }
  374. return true;
  375. }
  376. /////////////////////////////////////////////////////////////////////////////
  377. bool CMqttClConfig::GetBoolValue(CJson_t &rjtParent, const char *pszKey, bool &rbVal, std::string &strErr)
  378. {
  379. CJson_t jtVal;
  380. if(GetValue(rjtParent, pszKey, jtVal, strErr))
  381. {
  382. int nType;
  383. switch((nType = jtVal.Type()))
  384. {
  385. case JSON_TRUE:
  386. case JSON_FALSE:
  387. rbVal = (nType == JSON_TRUE);
  388. return true;
  389. default:
  390. strErr = formatString("\"%s\" (type=%d) is not a boolean value", pszKey, nType);
  391. return false;
  392. }
  393. }
  394. return false;
  395. }
  396. /////////////////////////////////////////////////////////////////////////////
  397. bool CMqttClConfig::GetIntValue(CJson_t &rjtParent, const char *pszKey, int &rnVal, std::string &strErr)
  398. {
  399. CJson_t jtVal;
  400. if(GetValue(rjtParent, pszKey, jtVal, strErr))
  401. {
  402. if(json_is_integer(jtVal.operator const json_t*()))
  403. {
  404. rnVal = (int)::json_integer_value(jtVal);
  405. return true;
  406. }
  407. strErr = formatString("\"%s\" (type=%d) is not an integer value", pszKey, jtVal.Type());
  408. }
  409. return false;
  410. }
  411. /////////////////////////////////////////////////////////////////////////////
  412. bool CMqttClConfig::GetInt64Value(CJson_t &rjtParent, const char *pszKey, long long &rnVal, std::string &strErr)
  413. {
  414. CJson_t jtVal;
  415. if(GetValue(rjtParent, pszKey, jtVal, strErr))
  416. {
  417. if(json_is_integer(jtVal.operator const json_t*()))
  418. {
  419. rnVal = (long long)::json_integer_value(jtVal);
  420. return true;
  421. }
  422. strErr = formatString("\"%s\" (type=%d) is not an integer value", pszKey, jtVal.Type());
  423. }
  424. return false;
  425. }
  426. /////////////////////////////////////////////////////////////////////////////
  427. bool CMqttClConfig::GetStringValue(CJson_t &rjtParent, const char *pszKey, std::string &rstrVal, std::string &strErr)
  428. {
  429. CJson_t jtVal;
  430. if(GetValue(rjtParent, pszKey, jtVal, strErr))
  431. {
  432. if(json_is_string(jtVal.operator const json_t*()))
  433. {
  434. rstrVal = ::json_string_value(jtVal);
  435. return !rstrVal.empty();
  436. }
  437. strErr = formatString("\"%s\" (type=%d) is not a string value", pszKey, jtVal.Type());
  438. }
  439. rstrVal.clear();
  440. return false;
  441. }
  442. /////////////////////////////////////////////////////////////////////////////
  443. sa_family_t CMqttClConfig::GetDevIdInterfaceName(char *pszItfName, size_t nCChItfName, const char *pszRequested)
  444. {
  445. sa_family_t nFamily = 0;
  446. struct ifaddrs *ifaddr, *ifa;
  447. memset(pszItfName, 0, nCChItfName);
  448. if(getifaddrs(&ifaddr) == 0)
  449. {
  450. for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
  451. {
  452. if(!ifa->ifa_addr || (ifa->ifa_flags & IFF_LOOPBACK))
  453. continue;
  454. if( ifa->ifa_addr->sa_family == AF_INET ||
  455. ifa->ifa_addr->sa_family == AF_INET6)
  456. {
  457. if(!strcmp(ifa->ifa_name, pszRequested))
  458. {
  459. strncpy(pszItfName, ifa->ifa_name, nCChItfName - 1);
  460. nFamily = ifa->ifa_addr->sa_family;
  461. break;
  462. }
  463. else if(!nFamily)
  464. {
  465. strncpy(pszItfName, ifa->ifa_name, nCChItfName - 1);
  466. nFamily = ifa->ifa_addr->sa_family;
  467. }
  468. }
  469. }
  470. freeifaddrs(ifaddr);
  471. }
  472. return nFamily;
  473. }
  474. const char* CMqttClConfig::GetMacAddress(std::string &s)
  475. {
  476. int fd;
  477. struct ifreq ifr;
  478. s.clear();
  479. if((ifr.ifr_addr.sa_family = CMqttClConfig::GetDevIdInterfaceName(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0")))
  480. {
  481. if((fd = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) >= 0)
  482. {
  483. if( (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) &&
  484. (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER))
  485. {
  486. const char *m = (const char*)ifr.ifr_hwaddr.sa_data;
  487. s = formatString("%0.2hhX:%0.2hhX:%0.2hhX:%0.2hhX:%0.2hhX:%0.2hhX" , m[0], m[1], m[2], m[3], m[4], m[5]);
  488. }
  489. close(fd);
  490. }
  491. }
  492. return s.c_str();
  493. }
  494. std::string CMqttClConfig::CreateDeviceID(const char *pszDevicePrefix)
  495. {
  496. std::string m, s;
  497. if(pszDevicePrefix && *pszDevicePrefix)
  498. s = formatString("%s-%s", pszDevicePrefix, CMqttClConfig::GetMacAddress(m));
  499. else
  500. CMqttClConfig::GetMacAddress(s);
  501. return s;
  502. }