MQTTConnectServer.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*******************************************************************************
  2. * Copyright (c) 2014 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  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
  15. *documentation
  16. *******************************************************************************/
  17. #include <string.h>
  18. #include "MQTTPacket.h"
  19. #include "StackTrace.h"
  20. #define min(a, b) ((a < b) ? a : b)
  21. /**
  22. * Validates MQTT protocol name and version combinations
  23. * @param protocol the MQTT protocol name as an MQTTString
  24. * @param version the MQTT protocol version number, as in the connect packet
  25. * @return correct MQTT combination? 1 is true, 0 is false
  26. */
  27. int MQTTPacket_checkVersion(MQTTString* protocol, int version) {
  28. int rc = 0;
  29. if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
  30. min(6, protocol->lenstring.len)) == 0)
  31. rc = 1;
  32. else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
  33. min(4, protocol->lenstring.len)) == 0)
  34. rc = 1;
  35. return rc;
  36. }
  37. /**
  38. * Deserializes the supplied (wire) buffer into connect data structure
  39. * @param data the connect data structure to be filled out
  40. * @param buf the raw buffer data, of the correct length determined by the
  41. * remaining length field
  42. * @param len the length in bytes of the data in the supplied buffer
  43. * @return error code. 1 is success, 0 is failure
  44. */
  45. int MQTTDeserialize_connect(MQTTPacket_connectData* data,
  46. unsigned char* buf,
  47. int len) {
  48. MQTTHeader header = {0};
  49. MQTTConnectFlags flags = {0};
  50. unsigned char* curdata = buf;
  51. unsigned char* enddata = &buf[len];
  52. int rc = 0;
  53. MQTTString Protocol;
  54. int version;
  55. int mylen = 0;
  56. FUNC_ENTRY;
  57. header.byte = readChar(&curdata);
  58. if (header.bits.type != CONNECT)
  59. goto exit;
  60. curdata +=
  61. MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
  62. if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
  63. enddata - curdata <
  64. 0) /* do we have enough data to read the protocol version byte? */
  65. goto exit;
  66. version = (int)readChar(&curdata); /* Protocol version */
  67. /* If we don't recognize the protocol version, we don't parse the connect
  68. * packet on the basis that we don't know what the format will be.
  69. */
  70. if (MQTTPacket_checkVersion(&Protocol, version)) {
  71. flags.all = readChar(&curdata);
  72. data->cleansession = flags.bits.cleansession;
  73. data->keepAliveInterval = readInt(&curdata);
  74. if (!readMQTTLenString(&data->clientID, &curdata, enddata))
  75. goto exit;
  76. data->willFlag = flags.bits.will;
  77. if (flags.bits.will) {
  78. data->will.qos = flags.bits.willQoS;
  79. data->will.retained = flags.bits.willRetain;
  80. if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
  81. !readMQTTLenString(&data->will.message, &curdata, enddata))
  82. goto exit;
  83. }
  84. if (flags.bits.username) {
  85. if (enddata - curdata < 3 ||
  86. !readMQTTLenString(&data->username, &curdata, enddata))
  87. goto exit; /* username flag set, but no username supplied -
  88. invalid */
  89. if (flags.bits.password &&
  90. (enddata - curdata < 3 ||
  91. !readMQTTLenString(&data->password, &curdata, enddata)))
  92. goto exit; /* password flag set, but no password supplied -
  93. invalid */
  94. } else if (flags.bits.password)
  95. goto exit; /* password flag set without username - invalid */
  96. rc = 1;
  97. }
  98. exit:
  99. FUNC_EXIT_RC(rc);
  100. return rc;
  101. }
  102. /**
  103. * Serializes the connack packet into the supplied buffer.
  104. * @param buf the buffer into which the packet will be serialized
  105. * @param buflen the length in bytes of the supplied buffer
  106. * @param connack_rc the integer connack return code to be used
  107. * @param sessionPresent the MQTT 3.1.1 sessionPresent flag
  108. * @return serialized length, or error if 0
  109. */
  110. int MQTTSerialize_connack(unsigned char* buf,
  111. int buflen,
  112. unsigned char connack_rc,
  113. unsigned char sessionPresent) {
  114. MQTTHeader header = {0};
  115. int rc = 0;
  116. unsigned char* ptr = buf;
  117. MQTTConnackFlags flags = {0};
  118. FUNC_ENTRY;
  119. if (buflen < 2) {
  120. rc = MQTTPACKET_BUFFER_TOO_SHORT;
  121. goto exit;
  122. }
  123. header.byte = 0;
  124. header.bits.type = CONNACK;
  125. writeChar(&ptr, header.byte); /* write header */
  126. ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
  127. flags.all = 0;
  128. flags.bits.sessionpresent = sessionPresent;
  129. writeChar(&ptr, flags.all);
  130. writeChar(&ptr, connack_rc);
  131. rc = ptr - buf;
  132. exit:
  133. FUNC_EXIT_RC(rc);
  134. return rc;
  135. }