MQTTProtocolClient.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  1. /*******************************************************************************
  2. * Copyright (c) 2009, 2024 IBM Corp. and Ian Craggs
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v2.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * https://www.eclipse.org/legal/epl-2.0/
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Ian Craggs - initial API and implementation and/or initial documentation
  15. * Ian Craggs - fix for bug 413429 - connectionLost not called
  16. * Ian Craggs - fix for bug 421103 - trying to write to same socket, in retry
  17. * Rong Xiang, Ian Craggs - C++ compatibility
  18. * Ian Craggs - turn off DUP flag for PUBREL - MQTT 3.1.1
  19. * Ian Craggs - ensure that acks are not sent if write is outstanding on socket
  20. * Ian Craggs - MQTT 5.0 support
  21. *******************************************************************************/
  22. /**
  23. * @file
  24. * \brief Functions dealing with the MQTT protocol exchanges
  25. *
  26. * Some other related functions are in the MQTTProtocolOut module
  27. * */
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <stdint.h>
  31. #include "MQTTProtocolClient.h"
  32. #if !defined(NO_PERSISTENCE)
  33. #include "MQTTPersistence.h"
  34. #endif
  35. #include "Socket.h"
  36. #include "SocketBuffer.h"
  37. #include "StackTrace.h"
  38. #include "Heap.h"
  39. #if !defined(min)
  40. #define min(A,B) ( (A) < (B) ? (A):(B))
  41. #endif
  42. extern MQTTProtocol state;
  43. extern ClientStates* bstate;
  44. static void MQTTProtocol_storeQoS0(Clients* pubclient, Publish* publish);
  45. static int MQTTProtocol_startPublishCommon(
  46. Clients* pubclient,
  47. Publish* publish,
  48. int qos,
  49. int retained);
  50. static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regardless);
  51. static int MQTTProtocol_queueAck(Clients* client, int ackType, int msgId);
  52. typedef struct {
  53. int messageId;
  54. int ackType;
  55. } AckRequest;
  56. /**
  57. * List callback function for comparing Message structures by message id
  58. * @param a first integer value
  59. * @param b second integer value
  60. * @return boolean indicating whether a and b are equal
  61. */
  62. int messageIDCompare(void* a, void* b)
  63. {
  64. Messages* msg = (Messages*)a;
  65. return msg->msgid == *(int*)b;
  66. }
  67. /**
  68. * Assign a new message id for a client. Make sure it isn't already being used and does
  69. * not exceed the maximum.
  70. * @param client a client structure
  71. * @return the next message id to use, or 0 if none available
  72. */
  73. int MQTTProtocol_assignMsgId(Clients* client)
  74. {
  75. int start_msgid = client->msgID;
  76. int msgid = start_msgid;
  77. FUNC_ENTRY;
  78. msgid = (msgid == MAX_MSG_ID) ? 1 : msgid + 1;
  79. while (ListFindItem(client->outboundMsgs, &msgid, messageIDCompare) != NULL)
  80. {
  81. msgid = (msgid == MAX_MSG_ID) ? 1 : msgid + 1;
  82. if (msgid == start_msgid)
  83. { /* we've tried them all - none free */
  84. msgid = 0;
  85. break;
  86. }
  87. }
  88. if (msgid != 0)
  89. client->msgID = msgid;
  90. FUNC_EXIT_RC(msgid);
  91. return msgid;
  92. }
  93. static void MQTTProtocol_storeQoS0(Clients* pubclient, Publish* publish)
  94. {
  95. int len;
  96. pending_write* pw = NULL;
  97. FUNC_ENTRY;
  98. /* store the publication until the write is finished */
  99. if ((pw = malloc(sizeof(pending_write))) == NULL)
  100. goto exit;
  101. Log(TRACE_MIN, 12, NULL);
  102. if ((pw->p = MQTTProtocol_storePublication(publish, &len)) == NULL)
  103. {
  104. free(pw);
  105. goto exit;
  106. }
  107. pw->socket = pubclient->net.socket;
  108. if (!ListAppend(&(state.pending_writes), pw, sizeof(pending_write)+len))
  109. {
  110. free(pw->p);
  111. free(pw);
  112. goto exit;
  113. }
  114. /* we don't copy QoS 0 messages unless we have to, so now we have to tell the socket buffer where
  115. the saved copy is */
  116. if (SocketBuffer_updateWrite(pw->socket, pw->p->topic, pw->p->payload) == NULL)
  117. Log(LOG_SEVERE, 0, "Error updating write");
  118. publish->payload = publish->topic = NULL;
  119. exit:
  120. FUNC_EXIT;
  121. }
  122. /**
  123. * Utility function to start a new publish exchange.
  124. * @param pubclient the client to send the publication to
  125. * @param publish the publication data
  126. * @param qos the MQTT QoS to use
  127. * @param retained boolean - whether to set the MQTT retained flag
  128. * @return the completion code
  129. */
  130. static int MQTTProtocol_startPublishCommon(Clients* pubclient, Publish* publish, int qos, int retained)
  131. {
  132. int rc = TCPSOCKET_COMPLETE;
  133. FUNC_ENTRY;
  134. rc = MQTTPacket_send_publish(publish, 0, qos, retained, &pubclient->net, pubclient->clientID);
  135. if (qos == 0 && rc == TCPSOCKET_INTERRUPTED)
  136. MQTTProtocol_storeQoS0(pubclient, publish);
  137. FUNC_EXIT_RC(rc);
  138. return rc;
  139. }
  140. /**
  141. * Start a new publish exchange. Store any state necessary and try to send the packet
  142. * @param pubclient the client to send the publication to
  143. * @param publish the publication data
  144. * @param qos the MQTT QoS to use
  145. * @param retained boolean - whether to set the MQTT retained flag
  146. * @param mm - pointer to the message to send
  147. * @return the completion code
  148. */
  149. int MQTTProtocol_startPublish(Clients* pubclient, Publish* publish, int qos, int retained, Messages** mm)
  150. {
  151. Publish qos12pub = *publish;
  152. int rc = 0;
  153. FUNC_ENTRY;
  154. if (qos > 0)
  155. {
  156. *mm = MQTTProtocol_createMessage(publish, mm, qos, retained, 0);
  157. ListAppend(pubclient->outboundMsgs, *mm, (*mm)->len);
  158. /* we change these pointers to the saved message location just in case the packet could not be written
  159. entirely; the socket buffer will use these locations to finish writing the packet */
  160. qos12pub.payload = (*mm)->publish->payload;
  161. qos12pub.topic = (*mm)->publish->topic;
  162. qos12pub.properties = (*mm)->properties;
  163. qos12pub.MQTTVersion = (*mm)->MQTTVersion;
  164. publish = &qos12pub;
  165. }
  166. rc = MQTTProtocol_startPublishCommon(pubclient, publish, qos, retained);
  167. if (qos > 0)
  168. memcpy((*mm)->publish->mask, publish->mask, sizeof((*mm)->publish->mask));
  169. FUNC_EXIT_RC(rc);
  170. return rc;
  171. }
  172. /**
  173. * Copy and store message data for retries
  174. * @param publish the publication data
  175. * @param mm - pointer to the message data to store
  176. * @param qos the MQTT QoS to use
  177. * @param retained boolean - whether to set the MQTT retained flag
  178. * @param allocatePayload boolean - whether or not to malloc payload
  179. * @return pointer to the message data stored
  180. */
  181. Messages* MQTTProtocol_createMessage(Publish* publish, Messages **mm, int qos, int retained, int allocatePayload)
  182. {
  183. Messages* m = malloc(sizeof(Messages));
  184. FUNC_ENTRY;
  185. if (!m)
  186. goto exit;
  187. m->len = sizeof(Messages);
  188. if (*mm == NULL || (*mm)->publish == NULL)
  189. {
  190. int len1;
  191. *mm = m;
  192. if ((m->publish = MQTTProtocol_storePublication(publish, &len1)) == NULL)
  193. {
  194. free(m);
  195. goto exit;
  196. }
  197. m->len += len1;
  198. if (allocatePayload)
  199. {
  200. char *temp = m->publish->payload;
  201. if ((m->publish->payload = malloc(m->publish->payloadlen)) == NULL)
  202. {
  203. free(m);
  204. goto exit;
  205. }
  206. memcpy(m->publish->payload, temp, m->publish->payloadlen);
  207. }
  208. }
  209. else /* this is now never used, I think */
  210. {
  211. ++(((*mm)->publish)->refcount);
  212. m->publish = (*mm)->publish;
  213. }
  214. m->msgid = publish->msgId;
  215. m->qos = qos;
  216. m->retain = retained;
  217. m->MQTTVersion = publish->MQTTVersion;
  218. if (m->MQTTVersion >= 5)
  219. m->properties = MQTTProperties_copy(&publish->properties);
  220. m->lastTouch = MQTTTime_now();
  221. if (qos == 2)
  222. m->nextMessageType = PUBREC;
  223. exit:
  224. FUNC_EXIT;
  225. return m;
  226. }
  227. /**
  228. * Store message data for possible retry
  229. * @param publish the publication data
  230. * @param len returned length of the data stored
  231. * @return the publication stored
  232. */
  233. Publications* MQTTProtocol_storePublication(Publish* publish, int* len)
  234. {
  235. Publications* p = malloc(sizeof(Publications));
  236. FUNC_ENTRY;
  237. if (!p)
  238. goto exit;
  239. p->refcount = 1;
  240. *len = (int)strlen(publish->topic)+1;
  241. p->topic = publish->topic;
  242. publish->topic = NULL;
  243. *len += sizeof(Publications);
  244. p->topiclen = publish->topiclen;
  245. p->payloadlen = publish->payloadlen;
  246. p->payload = publish->payload;
  247. publish->payload = NULL;
  248. *len += publish->payloadlen;
  249. memcpy(p->mask, publish->mask, sizeof(p->mask));
  250. if ((ListAppend(&(state.publications), p, *len)) == NULL)
  251. {
  252. free(p);
  253. p = NULL;
  254. }
  255. exit:
  256. FUNC_EXIT;
  257. return p;
  258. }
  259. /**
  260. * Remove stored message data. Opposite of storePublication
  261. * @param p stored publication to remove
  262. */
  263. void MQTTProtocol_removePublication(Publications* p)
  264. {
  265. FUNC_ENTRY;
  266. if (p && --(p->refcount) == 0)
  267. {
  268. if (p->payload)
  269. {
  270. free(p->payload);
  271. p->payload = NULL;
  272. }
  273. if (p->topic)
  274. {
  275. free(p->topic);
  276. p->topic = NULL;
  277. }
  278. ListRemove(&(state.publications), p);
  279. }
  280. FUNC_EXIT;
  281. }
  282. /**
  283. * Process an incoming publish packet for a socket
  284. * The payload field of the packet has not been transferred to another buffer at this point.
  285. * If it's needed beyond the scope of this function, it has to be copied.
  286. * @param pack pointer to the publish packet
  287. * @param sock the socket on which the packet was received
  288. * @return completion code
  289. */
  290. int MQTTProtocol_handlePublishes(void* pack, SOCKET sock)
  291. {
  292. Publish* publish = (Publish*)pack;
  293. Clients* client = NULL;
  294. char* clientid = NULL;
  295. int rc = TCPSOCKET_COMPLETE;
  296. int socketHasPendingWrites = 0;
  297. FUNC_ENTRY;
  298. client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
  299. clientid = client->clientID;
  300. /* Format and print publish data to trace */
  301. {
  302. #if defined(_WIN32) || defined(_WIN64)
  303. #define buflen 30
  304. #else
  305. const int buflen = 30;
  306. #endif
  307. char buf[buflen];
  308. int len = 0;
  309. len = MQTTPacket_formatPayload(buflen, buf, publish->payloadlen, publish->payload);
  310. Log(LOG_PROTOCOL, 11, NULL, sock, clientid, publish->msgId, publish->header.bits.qos,
  311. publish->header.bits.retain, publish->payloadlen, len, buf);
  312. }
  313. if (publish->header.bits.qos == 0)
  314. {
  315. Protocol_processPublication(publish, client, 1);
  316. goto exit;
  317. }
  318. socketHasPendingWrites = !Socket_noPendingWrites(sock);
  319. if (publish->header.bits.qos == 1)
  320. {
  321. Protocol_processPublication(publish, client, 1);
  322. if (socketHasPendingWrites)
  323. rc = MQTTProtocol_queueAck(client, PUBACK, publish->msgId);
  324. else
  325. rc = MQTTPacket_send_puback(publish->MQTTVersion, publish->msgId, &client->net, client->clientID);
  326. }
  327. else if (publish->header.bits.qos == 2)
  328. {
  329. /* store publication in inbound list */
  330. int len;
  331. int already_received = 0;
  332. ListElement* listElem = NULL;
  333. Messages* m = malloc(sizeof(Messages));
  334. Publications* p = NULL;
  335. if (!m)
  336. {
  337. rc = PAHO_MEMORY_ERROR;
  338. goto exit;
  339. }
  340. p = MQTTProtocol_storePublication(publish, &len);
  341. m->publish = p;
  342. m->msgid = publish->msgId;
  343. m->qos = publish->header.bits.qos;
  344. m->retain = publish->header.bits.retain;
  345. m->MQTTVersion = publish->MQTTVersion;
  346. if (m->MQTTVersion >= MQTTVERSION_5)
  347. m->properties = MQTTProperties_copy(&publish->properties);
  348. m->nextMessageType = PUBREL;
  349. if ((listElem = ListFindItem(client->inboundMsgs, &(m->msgid), messageIDCompare)) != NULL)
  350. { /* discard queued publication with same msgID that the current incoming message */
  351. Messages* msg = (Messages*)(listElem->content);
  352. MQTTProtocol_removePublication(msg->publish);
  353. if (msg->MQTTVersion >= MQTTVERSION_5)
  354. MQTTProperties_free(&msg->properties);
  355. ListInsert(client->inboundMsgs, m, sizeof(Messages) + len, listElem);
  356. ListRemove(client->inboundMsgs, msg);
  357. already_received = 1;
  358. } else
  359. ListAppend(client->inboundMsgs, m, sizeof(Messages) + len);
  360. if (m->MQTTVersion >= MQTTVERSION_5 && already_received == 0)
  361. {
  362. Publish publish1;
  363. publish1.header.bits.qos = m->qos;
  364. publish1.header.bits.retain = m->retain;
  365. publish1.msgId = m->msgid;
  366. publish1.topic = m->publish->topic;
  367. publish1.topiclen = m->publish->topiclen;
  368. publish1.payload = m->publish->payload;
  369. publish1.payloadlen = m->publish->payloadlen;
  370. publish1.MQTTVersion = m->MQTTVersion;
  371. publish1.properties = m->properties;
  372. Protocol_processPublication(&publish1, client, 1);
  373. ListRemove(&(state.publications), m->publish);
  374. m->publish = NULL;
  375. } else
  376. { /* allocate and copy payload data as it's needed for pubrel.
  377. For other cases, it's done in Protocol_processPublication */
  378. char *temp = m->publish->payload;
  379. if ((m->publish->payload = malloc(m->publish->payloadlen)) == NULL)
  380. {
  381. rc = PAHO_MEMORY_ERROR;
  382. goto exit;
  383. }
  384. memcpy(m->publish->payload, temp, m->publish->payloadlen);
  385. }
  386. if (socketHasPendingWrites)
  387. rc = MQTTProtocol_queueAck(client, PUBREC, publish->msgId);
  388. else
  389. rc = MQTTPacket_send_pubrec(publish->MQTTVersion, publish->msgId, &client->net, client->clientID);
  390. publish->topic = NULL;
  391. }
  392. exit:
  393. MQTTPacket_freePublish(publish);
  394. FUNC_EXIT_RC(rc);
  395. return rc;
  396. }
  397. /**
  398. * Process an incoming puback packet for a socket
  399. * @param pack pointer to the publish packet
  400. * @param sock the socket on which the packet was received
  401. * @return completion code
  402. */
  403. int MQTTProtocol_handlePubacks(void* pack, SOCKET sock, Publications** pubToRemove)
  404. {
  405. Puback* puback = (Puback*)pack;
  406. Clients* client = NULL;
  407. int rc = TCPSOCKET_COMPLETE;
  408. FUNC_ENTRY;
  409. client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
  410. Log(LOG_PROTOCOL, 14, NULL, sock, client->clientID, puback->msgId);
  411. /* look for the message by message id in the records of outbound messages for this client */
  412. if (ListFindItem(client->outboundMsgs, &(puback->msgId), messageIDCompare) == NULL)
  413. Log(TRACE_MIN, 3, NULL, "PUBACK", client->clientID, puback->msgId);
  414. else
  415. {
  416. Messages* m = (Messages*)(client->outboundMsgs->current->content);
  417. if (m->qos != 1)
  418. Log(TRACE_MIN, 4, NULL, "PUBACK", client->clientID, puback->msgId, m->qos);
  419. else
  420. {
  421. Log(TRACE_MIN, 6, NULL, "PUBACK", client->clientID, puback->msgId);
  422. #if !defined(NO_PERSISTENCE)
  423. rc = MQTTPersistence_remove(client,
  424. (m->MQTTVersion >= MQTTVERSION_5) ? PERSISTENCE_V5_PUBLISH_SENT : PERSISTENCE_PUBLISH_SENT,
  425. m->qos, puback->msgId);
  426. #endif
  427. if (pubToRemove != NULL)
  428. *pubToRemove = m->publish;
  429. else
  430. MQTTProtocol_removePublication(m->publish);
  431. if (m->MQTTVersion >= MQTTVERSION_5)
  432. MQTTProperties_free(&m->properties);
  433. ListRemove(client->outboundMsgs, m);
  434. }
  435. }
  436. if (puback->MQTTVersion >= MQTTVERSION_5)
  437. MQTTProperties_free(&puback->properties);
  438. free(pack);
  439. FUNC_EXIT_RC(rc);
  440. return rc;
  441. }
  442. /**
  443. * Process an incoming pubrec packet for a socket
  444. * @param pack pointer to the publish packet
  445. * @param sock the socket on which the packet was received
  446. * @return completion code
  447. */
  448. int MQTTProtocol_handlePubrecs(void* pack, SOCKET sock, Publications** pubToRemove)
  449. {
  450. Pubrec* pubrec = (Pubrec*)pack;
  451. Clients* client = NULL;
  452. int rc = TCPSOCKET_COMPLETE;
  453. int send_pubrel = 1; /* boolean to send PUBREL or not */
  454. FUNC_ENTRY;
  455. client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
  456. Log(LOG_PROTOCOL, 15, NULL, sock, client->clientID, pubrec->msgId);
  457. /* look for the message by message id in the records of outbound messages for this client */
  458. client->outboundMsgs->current = NULL;
  459. if (ListFindItem(client->outboundMsgs, &(pubrec->msgId), messageIDCompare) == NULL)
  460. {
  461. if (pubrec->header.bits.dup == 0)
  462. Log(TRACE_MIN, 3, NULL, "PUBREC", client->clientID, pubrec->msgId);
  463. }
  464. else
  465. {
  466. Messages* m = (Messages*)(client->outboundMsgs->current->content);
  467. if (m->qos != 2)
  468. {
  469. if (pubrec->header.bits.dup == 0)
  470. Log(TRACE_MIN, 4, NULL, "PUBREC", client->clientID, pubrec->msgId, m->qos);
  471. }
  472. else if (m->nextMessageType != PUBREC)
  473. {
  474. if (pubrec->header.bits.dup == 0)
  475. Log(TRACE_MIN, 5, NULL, "PUBREC", client->clientID, pubrec->msgId);
  476. }
  477. else
  478. {
  479. if (pubrec->MQTTVersion >= MQTTVERSION_5 && pubrec->rc >= MQTTREASONCODE_UNSPECIFIED_ERROR)
  480. {
  481. Log(TRACE_MIN, -1, "Pubrec error %d received for client %s msgid %d, not sending PUBREL",
  482. pubrec->rc, client->clientID, pubrec->msgId);
  483. #if !defined(NO_PERSISTENCE)
  484. rc = MQTTPersistence_remove(client,
  485. (pubrec->MQTTVersion >= MQTTVERSION_5) ? PERSISTENCE_V5_PUBLISH_SENT : PERSISTENCE_PUBLISH_SENT,
  486. m->qos, pubrec->msgId);
  487. #endif
  488. if (pubToRemove != NULL)
  489. *pubToRemove = m->publish;
  490. else
  491. MQTTProtocol_removePublication(m->publish);
  492. if (m->MQTTVersion >= MQTTVERSION_5)
  493. MQTTProperties_free(&m->properties);
  494. ListRemove(client->outboundMsgs, m);
  495. (++state.msgs_sent);
  496. send_pubrel = 0; /* in MQTT v5, stop the exchange if there is an error reported */
  497. }
  498. else
  499. {
  500. m->nextMessageType = PUBCOMP;
  501. m->lastTouch = MQTTTime_now();
  502. }
  503. }
  504. }
  505. if (!send_pubrel)
  506. ; /* only don't send ack on MQTT v5 PUBREC error, otherwise send ack under all circumstances because MQTT state can get out of step */
  507. else if (!Socket_noPendingWrites(sock))
  508. rc = MQTTProtocol_queueAck(client, PUBREL, pubrec->msgId);
  509. else
  510. rc = MQTTPacket_send_pubrel(pubrec->MQTTVersion, pubrec->msgId, 0, &client->net, client->clientID);
  511. if (pubrec->MQTTVersion >= MQTTVERSION_5)
  512. MQTTProperties_free(&pubrec->properties);
  513. free(pack);
  514. FUNC_EXIT_RC(rc);
  515. return rc;
  516. }
  517. /**
  518. * Process an incoming pubrel packet for a socket
  519. * @param pack pointer to the publish packet
  520. * @param sock the socket on which the packet was received
  521. * @return completion code
  522. */
  523. int MQTTProtocol_handlePubrels(void* pack, SOCKET sock)
  524. {
  525. Pubrel* pubrel = (Pubrel*)pack;
  526. Clients* client = NULL;
  527. int rc = TCPSOCKET_COMPLETE;
  528. FUNC_ENTRY;
  529. client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
  530. Log(LOG_PROTOCOL, 17, NULL, sock, client->clientID, pubrel->msgId);
  531. /* look for the message by message id in the records of inbound messages for this client */
  532. if (ListFindItem(client->inboundMsgs, &(pubrel->msgId), messageIDCompare) == NULL)
  533. {
  534. if (pubrel->header.bits.dup == 0)
  535. Log(TRACE_MIN, 3, NULL, "PUBREL", client->clientID, pubrel->msgId);
  536. }
  537. else
  538. {
  539. Messages* m = (Messages*)(client->inboundMsgs->current->content);
  540. if (m->qos != 2)
  541. Log(TRACE_MIN, 4, NULL, "PUBREL", client->clientID, pubrel->msgId, m->qos);
  542. else if (m->nextMessageType != PUBREL)
  543. Log(TRACE_MIN, 5, NULL, "PUBREL", client->clientID, pubrel->msgId);
  544. else
  545. {
  546. Publish publish;
  547. memset(&publish, '\0', sizeof(publish));
  548. publish.header.bits.qos = m->qos;
  549. publish.header.bits.retain = m->retain;
  550. publish.msgId = m->msgid;
  551. if (m->publish)
  552. {
  553. publish.topic = m->publish->topic;
  554. publish.topiclen = m->publish->topiclen;
  555. publish.payload = m->publish->payload;
  556. publish.payloadlen = m->publish->payloadlen;
  557. }
  558. publish.MQTTVersion = m->MQTTVersion;
  559. if (publish.MQTTVersion >= MQTTVERSION_5)
  560. publish.properties = m->properties;
  561. else
  562. Protocol_processPublication(&publish, client, 0); /* only for 3.1.1 and lower */
  563. #if !defined(NO_PERSISTENCE)
  564. rc += MQTTPersistence_remove(client,
  565. (m->MQTTVersion >= MQTTVERSION_5) ? PERSISTENCE_V5_PUBLISH_RECEIVED : PERSISTENCE_PUBLISH_RECEIVED,
  566. m->qos, pubrel->msgId);
  567. #endif
  568. if (m->MQTTVersion >= MQTTVERSION_5)
  569. MQTTProperties_free(&m->properties);
  570. if (m->publish)
  571. ListRemove(&(state.publications), m->publish);
  572. ListRemove(client->inboundMsgs, m);
  573. ++(state.msgs_received);
  574. }
  575. }
  576. /* Send ack under all circumstances because MQTT state can get out of step - this standard also says to do this */
  577. if (!Socket_noPendingWrites(sock))
  578. rc = MQTTProtocol_queueAck(client, PUBCOMP, pubrel->msgId);
  579. else
  580. rc = MQTTPacket_send_pubcomp(pubrel->MQTTVersion, pubrel->msgId, &client->net, client->clientID);
  581. if (pubrel->MQTTVersion >= MQTTVERSION_5)
  582. MQTTProperties_free(&pubrel->properties);
  583. free(pack);
  584. FUNC_EXIT_RC(rc);
  585. return rc;
  586. }
  587. /**
  588. * Process an incoming pubcomp packet for a socket
  589. * @param pack pointer to the publish packet
  590. * @param sock the socket on which the packet was received
  591. * @return completion code
  592. */
  593. int MQTTProtocol_handlePubcomps(void* pack, SOCKET sock, Publications** pubToRemove)
  594. {
  595. Pubcomp* pubcomp = (Pubcomp*)pack;
  596. Clients* client = NULL;
  597. int rc = TCPSOCKET_COMPLETE;
  598. FUNC_ENTRY;
  599. client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
  600. Log(LOG_PROTOCOL, 19, NULL, sock, client->clientID, pubcomp->msgId);
  601. /* look for the message by message id in the records of outbound messages for this client */
  602. if (ListFindItem(client->outboundMsgs, &(pubcomp->msgId), messageIDCompare) == NULL)
  603. {
  604. if (pubcomp->header.bits.dup == 0)
  605. Log(TRACE_MIN, 3, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
  606. }
  607. else
  608. {
  609. Messages* m = (Messages*)(client->outboundMsgs->current->content);
  610. if (m->qos != 2)
  611. Log(TRACE_MIN, 4, NULL, "PUBCOMP", client->clientID, pubcomp->msgId, m->qos);
  612. else
  613. {
  614. if (m->nextMessageType != PUBCOMP)
  615. Log(TRACE_MIN, 5, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
  616. else
  617. {
  618. Log(TRACE_MIN, 6, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
  619. #if !defined(NO_PERSISTENCE)
  620. rc = MQTTPersistence_remove(client,
  621. (m->MQTTVersion >= MQTTVERSION_5) ? PERSISTENCE_V5_PUBLISH_SENT : PERSISTENCE_PUBLISH_SENT,
  622. m->qos, pubcomp->msgId);
  623. if (rc != 0)
  624. Log(LOG_ERROR, -1, "Error removing PUBCOMP for client id %s msgid %d from persistence", client->clientID, pubcomp->msgId);
  625. #endif
  626. if (pubToRemove != NULL)
  627. *pubToRemove = m->publish;
  628. else
  629. MQTTProtocol_removePublication(m->publish);
  630. if (m->MQTTVersion >= MQTTVERSION_5)
  631. MQTTProperties_free(&m->properties);
  632. ListRemove(client->outboundMsgs, m);
  633. (++state.msgs_sent);
  634. }
  635. }
  636. }
  637. if (pubcomp->MQTTVersion >= MQTTVERSION_5)
  638. MQTTProperties_free(&pubcomp->properties);
  639. free(pack);
  640. FUNC_EXIT_RC(rc);
  641. return rc;
  642. }
  643. /**
  644. * MQTT protocol keepAlive processing. Sends PINGREQ packets as required.
  645. * @param now current time
  646. */
  647. void MQTTProtocol_keepalive(START_TIME_TYPE now)
  648. {
  649. ListElement* current = NULL;
  650. FUNC_ENTRY;
  651. ListNextElement(bstate->clients, &current);
  652. while (current)
  653. {
  654. Clients* client = (Clients*)(current->content);
  655. ListNextElement(bstate->clients, &current);
  656. if (client->connected == 0 || client->keepAliveInterval == 0)
  657. continue;
  658. if (client->ping_outstanding == 1)
  659. {
  660. if (MQTTTime_difftime(now, client->net.lastPing) >= (DIFF_TIME_TYPE)(client->keepAliveInterval * 1500) &&
  661. /* if last received is more recent, we could be receiving a large packet */
  662. MQTTTime_difftime(now, client->net.lastReceived) >= (DIFF_TIME_TYPE)(client->keepAliveInterval * 1500))
  663. {
  664. Log(TRACE_PROTOCOL, -1, "PINGRESP not received in keepalive interval for client %s on socket %d, disconnecting", client->clientID, client->net.socket);
  665. MQTTProtocol_closeSession(client, 1);
  666. }
  667. }
  668. else if (client->ping_due == 1 &&
  669. (MQTTTime_difftime(now, client->ping_due_time) >= (DIFF_TIME_TYPE)(client->keepAliveInterval * 1500)))
  670. {
  671. /* if the last received time is more recent than the ping due time, we could be receiving a large packet,
  672. * preventing the PINGRESP being received */
  673. if (MQTTTime_difftime(now, client->ping_due_time) <= MQTTTime_difftime(now, client->net.lastReceived))
  674. {
  675. /* ping still outstanding after keep alive interval, so close session */
  676. Log(TRACE_PROTOCOL, -1, "PINGREQ still outstanding for client %s on socket %d, disconnecting", client->clientID, client->net.socket);
  677. MQTTProtocol_closeSession(client, 1);
  678. }
  679. }
  680. else if (MQTTTime_difftime(now, client->net.lastSent) >= (DIFF_TIME_TYPE)(client->keepAliveInterval * 1000))
  681. /* the time since we last sent a packet, or part of a packet has exceeded the keep alive, so we need to send a ping */
  682. {
  683. if (Socket_noPendingWrites(client->net.socket))
  684. {
  685. if (MQTTPacket_send_pingreq(&client->net, client->clientID) != TCPSOCKET_COMPLETE)
  686. {
  687. Log(TRACE_PROTOCOL, -1, "Error sending PINGREQ for client %s on socket %d, disconnecting", client->clientID, client->net.socket);
  688. MQTTProtocol_closeSession(client, 1);
  689. }
  690. else
  691. {
  692. client->ping_due = 0;
  693. client->net.lastPing = now;
  694. client->ping_outstanding = 1;
  695. }
  696. }
  697. else if (client->ping_due == 0)
  698. {
  699. Log(TRACE_PROTOCOL, -1, "Couldn't send PINGREQ for client %s on socket %d, noting",
  700. client->clientID, client->net.socket);
  701. client->ping_due = 1;
  702. client->ping_due_time = now;
  703. }
  704. }
  705. else if (MQTTTime_difftime(now, client->net.lastReceived) >= (DIFF_TIME_TYPE)(client->keepAliveInterval * 1000))
  706. /* the time since we last received any data has exceeded the keep alive, so we can send a ping to see if the server is alive */
  707. {
  708. /* Check that no writes are pending for the socket. If there are, forget about it, as this PING use is optional */
  709. if (Socket_noPendingWrites(client->net.socket))
  710. {
  711. if (MQTTPacket_send_pingreq(&client->net, client->clientID) != TCPSOCKET_COMPLETE)
  712. {
  713. Log(TRACE_PROTOCOL, -1, "Error sending PINGREQ for client %s on socket %d, disconnecting", client->clientID, client->net.socket);
  714. MQTTProtocol_closeSession(client, 1);
  715. }
  716. else
  717. {
  718. client->ping_due = 0;
  719. client->net.lastPing = now;
  720. client->ping_outstanding = 1;
  721. }
  722. }
  723. }
  724. }
  725. FUNC_EXIT;
  726. }
  727. /**
  728. * MQTT retry processing per client
  729. * @param now current time
  730. * @param client - the client to which to apply the retry processing
  731. * @param regardless boolean - retry packets regardless of retry interval (used on reconnect)
  732. */
  733. static void MQTTProtocol_retries(START_TIME_TYPE now, Clients* client, int regardless)
  734. {
  735. ListElement* outcurrent = NULL;
  736. FUNC_ENTRY;
  737. if (!regardless && client->retryInterval <= 0 && /* 0 or -ive retryInterval turns off retry except on reconnect */
  738. client->connect_sent == client->connect_count)
  739. goto exit;
  740. if (regardless)
  741. client->connect_count = client->outboundMsgs->count; /* remember the number of messages to retry on connect */
  742. else if (client->connect_sent < client->connect_count) /* continue a connect retry which didn't complete first time around */
  743. regardless = 1;
  744. while (client && ListNextElement(client->outboundMsgs, &outcurrent) &&
  745. client->connected && client->good && /* client is connected and has no errors */
  746. Socket_noPendingWrites(client->net.socket)) /* there aren't any previous packets still stacked up on the socket */
  747. {
  748. Messages* m = (Messages*)(outcurrent->content);
  749. if (regardless || MQTTTime_difftime(now, m->lastTouch) > (DIFF_TIME_TYPE)(max(client->retryInterval, 10) * 1000))
  750. {
  751. if (regardless)
  752. ++client->connect_sent;
  753. if (m->qos == 1 || (m->qos == 2 && m->nextMessageType == PUBREC))
  754. {
  755. Publish publish;
  756. int rc;
  757. Log(TRACE_MIN, 7, NULL, "PUBLISH", client->clientID, client->net.socket, m->msgid);
  758. publish.msgId = m->msgid;
  759. publish.topic = m->publish->topic;
  760. publish.payload = m->publish->payload;
  761. publish.payloadlen = m->publish->payloadlen;
  762. publish.properties = m->properties;
  763. publish.MQTTVersion = m->MQTTVersion;
  764. memcpy(publish.mask, m->publish->mask, sizeof(publish.mask));
  765. rc = MQTTPacket_send_publish(&publish, 1, m->qos, m->retain, &client->net, client->clientID);
  766. memcpy(m->publish->mask, publish.mask, sizeof(m->publish->mask)); /* store websocket mask used in send */
  767. if (rc == SOCKET_ERROR)
  768. {
  769. client->good = 0;
  770. Log(TRACE_PROTOCOL, 29, NULL, client->clientID, client->net.socket,
  771. Socket_getpeer(client->net.socket));
  772. MQTTProtocol_closeSession(client, 1);
  773. client = NULL;
  774. }
  775. else
  776. {
  777. if (m->qos == 0 && rc == TCPSOCKET_INTERRUPTED)
  778. MQTTProtocol_storeQoS0(client, &publish);
  779. m->lastTouch = MQTTTime_now();
  780. }
  781. }
  782. else if (m->qos && m->nextMessageType == PUBCOMP)
  783. {
  784. Log(TRACE_MIN, 7, NULL, "PUBREL", client->clientID, client->net.socket, m->msgid);
  785. if (MQTTPacket_send_pubrel(m->MQTTVersion, m->msgid, 0, &client->net, client->clientID) != TCPSOCKET_COMPLETE)
  786. {
  787. client->good = 0;
  788. Log(TRACE_PROTOCOL, 29, NULL, client->clientID, client->net.socket,
  789. Socket_getpeer(client->net.socket));
  790. MQTTProtocol_closeSession(client, 1);
  791. client = NULL;
  792. }
  793. else
  794. m->lastTouch = MQTTTime_now();
  795. }
  796. }
  797. }
  798. exit:
  799. FUNC_EXIT;
  800. }
  801. /**
  802. * Queue an ack message. This is used when the socket is full (e.g. SSL_ERROR_WANT_WRITE).
  803. * To be completed/cleared when the socket is no longer full
  804. * @param client the client that received the published message
  805. * @param ackType the type of ack to send
  806. * @param msgId the msg id of the message we are acknowledging
  807. * @return the completion code
  808. */
  809. int MQTTProtocol_queueAck(Clients* client, int ackType, int msgId)
  810. {
  811. int rc = 0;
  812. AckRequest* ackReq = NULL;
  813. FUNC_ENTRY;
  814. ackReq = malloc(sizeof(AckRequest));
  815. if (!ackReq)
  816. rc = PAHO_MEMORY_ERROR;
  817. else
  818. {
  819. ackReq->messageId = msgId;
  820. ackReq->ackType = ackType;
  821. ListAppend(client->outboundQueue, ackReq, sizeof(AckRequest));
  822. }
  823. FUNC_EXIT_RC(rc);
  824. return rc;
  825. }
  826. /**
  827. * MQTT retry protocol and socket pending writes processing.
  828. * @param now current time
  829. * @param doRetry boolean - retries as well as pending writes?
  830. * @param regardless boolean - retry packets regardless of retry interval (used on reconnect)
  831. */
  832. void MQTTProtocol_retry(START_TIME_TYPE now, int doRetry, int regardless)
  833. {
  834. ListElement* current = NULL;
  835. FUNC_ENTRY;
  836. ListNextElement(bstate->clients, &current);
  837. /* look through the outbound message list of each client, checking to see if a retry is necessary */
  838. while (current)
  839. {
  840. Clients* client = (Clients*)(current->content);
  841. ListNextElement(bstate->clients, &current);
  842. if (client->connected == 0)
  843. continue;
  844. if (client->good == 0)
  845. {
  846. MQTTProtocol_closeSession(client, 1);
  847. continue;
  848. }
  849. if (Socket_noPendingWrites(client->net.socket) == 0)
  850. continue;
  851. if (doRetry)
  852. MQTTProtocol_retries(now, client, regardless);
  853. }
  854. FUNC_EXIT;
  855. }
  856. /**
  857. * Free a client structure
  858. * @param client the client data to free
  859. */
  860. void MQTTProtocol_freeClient(Clients* client)
  861. {
  862. FUNC_ENTRY;
  863. /* free up pending message lists here, and any other allocated data */
  864. MQTTProtocol_freeMessageList(client->outboundMsgs);
  865. MQTTProtocol_freeMessageList(client->inboundMsgs);
  866. ListFree(client->messageQueue);
  867. ListFree(client->outboundQueue);
  868. free(client->clientID);
  869. client->clientID = NULL;
  870. if (client->will)
  871. {
  872. free(client->will->payload);
  873. free(client->will->topic);
  874. free(client->will);
  875. client->will = NULL;
  876. }
  877. if (client->username)
  878. free((void*)client->username);
  879. if (client->password)
  880. free((void*)client->password);
  881. if (client->httpProxy)
  882. free(client->httpProxy);
  883. if (client->httpsProxy)
  884. free(client->httpsProxy);
  885. if (client->net.http_proxy_auth)
  886. free(client->net.http_proxy_auth);
  887. #if defined(OPENSSL)
  888. if (client->net.https_proxy_auth)
  889. free(client->net.https_proxy_auth);
  890. if (client->sslopts)
  891. {
  892. if (client->sslopts->trustStore)
  893. free((void*)client->sslopts->trustStore);
  894. if (client->sslopts->keyStore)
  895. free((void*)client->sslopts->keyStore);
  896. if (client->sslopts->privateKey)
  897. free((void*)client->sslopts->privateKey);
  898. if (client->sslopts->privateKeyPassword)
  899. free((void*)client->sslopts->privateKeyPassword);
  900. if (client->sslopts->enabledCipherSuites)
  901. free((void*)client->sslopts->enabledCipherSuites);
  902. if (client->sslopts->struct_version >= 2)
  903. {
  904. if (client->sslopts->CApath)
  905. free((void*)client->sslopts->CApath);
  906. }
  907. if (client->sslopts->struct_version >= 5)
  908. {
  909. if (client->sslopts->protos)
  910. free((void*)client->sslopts->protos);
  911. }
  912. free(client->sslopts);
  913. client->sslopts = NULL;
  914. }
  915. #endif
  916. /* don't free the client structure itself... this is done elsewhere */
  917. FUNC_EXIT;
  918. }
  919. /**
  920. * Empty a message list, leaving it able to accept new messages
  921. * @param msgList the message list to empty
  922. */
  923. void MQTTProtocol_emptyMessageList(List* msgList)
  924. {
  925. ListElement* current = NULL;
  926. FUNC_ENTRY;
  927. while (ListNextElement(msgList, &current))
  928. {
  929. Messages* m = (Messages*)(current->content);
  930. MQTTProtocol_removePublication(m->publish);
  931. if (m->MQTTVersion >= MQTTVERSION_5)
  932. MQTTProperties_free(&m->properties);
  933. }
  934. ListEmpty(msgList);
  935. FUNC_EXIT;
  936. }
  937. /**
  938. * Empty and free up all storage used by a message list
  939. * @param msgList the message list to empty and free
  940. */
  941. void MQTTProtocol_freeMessageList(List* msgList)
  942. {
  943. FUNC_ENTRY;
  944. MQTTProtocol_emptyMessageList(msgList);
  945. ListFree(msgList);
  946. FUNC_EXIT;
  947. }
  948. /**
  949. * Callback that is invoked when the socket is available for writing.
  950. * This is the last attempt made to acknowledge a message. Failures that
  951. * occur here are ignored.
  952. * @param socket the socket that is available for writing
  953. */
  954. void MQTTProtocol_writeAvailable(SOCKET socket)
  955. {
  956. Clients* client = NULL;
  957. ListElement* current = NULL;
  958. int rc = 0;
  959. FUNC_ENTRY;
  960. client = (Clients*)(ListFindItem(bstate->clients, &socket, clientSocketCompare)->content);
  961. current = NULL;
  962. while (ListNextElement(client->outboundQueue, &current) && rc == 0)
  963. {
  964. AckRequest* ackReq = (AckRequest*)(current->content);
  965. switch (ackReq->ackType)
  966. {
  967. case PUBACK:
  968. rc = MQTTPacket_send_puback(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID);
  969. break;
  970. case PUBREC:
  971. rc = MQTTPacket_send_pubrec(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID);
  972. break;
  973. case PUBREL:
  974. rc = MQTTPacket_send_pubrel(client->MQTTVersion, ackReq->messageId, 0, &client->net, client->clientID);
  975. break;
  976. case PUBCOMP:
  977. rc = MQTTPacket_send_pubcomp(client->MQTTVersion, ackReq->messageId, &client->net, client->clientID);
  978. break;
  979. default:
  980. Log(LOG_ERROR, -1, "unknown ACK type %d, dropping msg", ackReq->ackType);
  981. break;
  982. }
  983. }
  984. ListEmpty(client->outboundQueue);
  985. FUNC_EXIT_RC(rc);
  986. }
  987. /**
  988. * Copy no more than dest_size -1 characters from the string pointed to by src to the array pointed to by dest.
  989. * The destination string will always be null-terminated.
  990. * @param dest the array which characters copy to
  991. * @param src the source string which characters copy from
  992. * @param dest_size the size of the memory pointed to by dest: copy no more than this -1 (allow for null). Must be >= 1
  993. * @return the destination string pointer
  994. */
  995. char* MQTTStrncpy(char *dest, const char *src, size_t dest_size)
  996. {
  997. size_t count = dest_size;
  998. char *temp = dest;
  999. FUNC_ENTRY;
  1000. if (dest_size < strlen(src))
  1001. Log(TRACE_MIN, -1, "the src string is truncated");
  1002. /* We must copy only the first (dest_size - 1) bytes */
  1003. while (count > 1 && (*temp++ = *src++))
  1004. count--;
  1005. *temp = '\0';
  1006. FUNC_EXIT;
  1007. return dest;
  1008. }
  1009. /**
  1010. * Duplicate a string, safely, allocating space on the heap
  1011. * @param src the source string which characters copy from
  1012. * @return the duplicated, allocated string
  1013. */
  1014. char* MQTTStrdup(const char* src)
  1015. {
  1016. size_t mlen = strlen(src) + 1;
  1017. char* temp = malloc(mlen);
  1018. if (temp)
  1019. MQTTStrncpy(temp, src, mlen);
  1020. else
  1021. Log(LOG_ERROR, -1, "memory allocation error in MQTTStrdup");
  1022. return temp;
  1023. }