MQTTConnectServer.c 4.6 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 documentation
  15. *******************************************************************************/
  16. #include "StackTrace.h"
  17. #include "MQTTPacket.h"
  18. #include <string.h>
  19. #define min(a, b) ((a < b) ? a : b)
  20. /**
  21. * Validates MQTT protocol name and version combinations
  22. * @param protocol the MQTT protocol name as an MQTTString
  23. * @param version the MQTT protocol version number, as in the connect packet
  24. * @return correct MQTT combination? 1 is true, 0 is false
  25. */
  26. int MQTTPacket_checkVersion(MQTTString* protocol, int version)
  27. {
  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 remaining length field
  41. * @param len the length in bytes of the data in the supplied buffer
  42. * @return error code. 1 is success, 0 is failure
  43. */
  44. int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
  45. {
  46. MQTTHeader header = {0};
  47. MQTTConnectFlags flags = {0};
  48. unsigned char* curdata = buf;
  49. unsigned char* enddata = &buf[len];
  50. int rc = 0;
  51. MQTTString Protocol;
  52. int version;
  53. int mylen = 0;
  54. FUNC_ENTRY;
  55. header.byte = readChar(&curdata);
  56. if (header.bits.type != CONNECT)
  57. goto exit;
  58. curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
  59. if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
  60. enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
  61. goto exit;
  62. version = (int)readChar(&curdata); /* Protocol version */
  63. /* If we don't recognize the protocol version, we don't parse the connect packet on the
  64. * basis that we don't know what the format will be.
  65. */
  66. if (MQTTPacket_checkVersion(&Protocol, version))
  67. {
  68. flags.all = readChar(&curdata);
  69. data->cleansession = flags.bits.cleansession;
  70. data->keepAliveInterval = readInt(&curdata);
  71. if (!readMQTTLenString(&data->clientID, &curdata, enddata))
  72. goto exit;
  73. data->willFlag = flags.bits.will;
  74. if (flags.bits.will)
  75. {
  76. data->will.qos = flags.bits.willQoS;
  77. data->will.retained = flags.bits.willRetain;
  78. if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
  79. !readMQTTLenString(&data->will.message, &curdata, enddata))
  80. goto exit;
  81. }
  82. if (flags.bits.username)
  83. {
  84. if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
  85. goto exit; /* username flag set, but no username supplied - invalid */
  86. if (flags.bits.password &&
  87. (enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
  88. goto exit; /* password flag set, but no password supplied - invalid */
  89. }
  90. else if (flags.bits.password)
  91. goto exit; /* password flag set without username - invalid */
  92. rc = 1;
  93. }
  94. exit:
  95. FUNC_EXIT_RC(rc);
  96. return rc;
  97. }
  98. /**
  99. * Serializes the connack packet into the supplied buffer.
  100. * @param buf the buffer into which the packet will be serialized
  101. * @param buflen the length in bytes of the supplied buffer
  102. * @param connack_rc the integer connack return code to be used
  103. * @param sessionPresent the MQTT 3.1.1 sessionPresent flag
  104. * @return serialized length, or error if 0
  105. */
  106. int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
  107. {
  108. MQTTHeader header = {0};
  109. int rc = 0;
  110. unsigned char *ptr = buf;
  111. MQTTConnackFlags flags = {0};
  112. FUNC_ENTRY;
  113. if (buflen < 2)
  114. {
  115. rc = MQTTPACKET_BUFFER_TOO_SHORT;
  116. goto exit;
  117. }
  118. header.byte = 0;
  119. header.bits.type = CONNACK;
  120. writeChar(&ptr, header.byte); /* write header */
  121. ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
  122. flags.all = 0;
  123. flags.bits.sessionpresent = sessionPresent;
  124. writeChar(&ptr, flags.all);
  125. writeChar(&ptr, connack_rc);
  126. rc = ptr - buf;
  127. exit:
  128. FUNC_EXIT_RC(rc);
  129. return rc;
  130. }