mqttcfg.cpp 21 KB

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