MqttMsgConnect.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*
  2. Copyright (c) 2013, 2014 Paolo Patierno
  3. All rights reserved. This program and the accompanying materials
  4. are made available under the terms of the Eclipse Public License v1.0
  5. and Eclipse Distribution License v1.0 which accompany this distribution.
  6. The Eclipse Public License is available at
  7. http://www.eclipse.org/legal/epl-v10.html
  8. and the Eclipse Distribution License is available at
  9. http://www.eclipse.org/org/documents/edl-v10.php.
  10. Contributors:
  11. Paolo Patierno - initial API and implementation and/or initial documentation
  12. */
  13. using System;
  14. using System.Text;
  15. using uPLibrary.Networking.M2Mqtt.Exceptions;
  16. namespace uPLibrary.Networking.M2Mqtt.Messages
  17. {
  18. /// <summary>
  19. /// Class for CONNECT message from client to broker
  20. /// </summary>
  21. public class MqttMsgConnect : MqttMsgBase
  22. {
  23. #region Constants...
  24. // protocol name supported
  25. internal const string PROTOCOL_NAME_V3_1 = "MQIsdp";
  26. internal const string PROTOCOL_NAME_V3_1_1 = "MQTT"; // [v.3.1.1]
  27. // max length for client id (removed in 3.1.1)
  28. internal const int CLIENT_ID_MAX_LENGTH = 23;
  29. // variable header fields
  30. internal const byte PROTOCOL_NAME_LEN_SIZE = 2;
  31. internal const byte PROTOCOL_NAME_V3_1_SIZE = 6;
  32. internal const byte PROTOCOL_NAME_V3_1_1_SIZE = 4; // [v.3.1.1]
  33. internal const byte PROTOCOL_VERSION_SIZE = 1;
  34. internal const byte CONNECT_FLAGS_SIZE = 1;
  35. internal const byte KEEP_ALIVE_TIME_SIZE = 2;
  36. internal const byte PROTOCOL_VERSION_V3_1 = 0x03;
  37. internal const byte PROTOCOL_VERSION_V3_1_1 = 0x04; // [v.3.1.1]
  38. internal const ushort KEEP_ALIVE_PERIOD_DEFAULT = 60; // seconds
  39. internal const ushort MAX_KEEP_ALIVE = 65535; // 16 bit
  40. // connect flags
  41. internal const byte USERNAME_FLAG_MASK = 0x80;
  42. internal const byte USERNAME_FLAG_OFFSET = 0x07;
  43. internal const byte USERNAME_FLAG_SIZE = 0x01;
  44. internal const byte PASSWORD_FLAG_MASK = 0x40;
  45. internal const byte PASSWORD_FLAG_OFFSET = 0x06;
  46. internal const byte PASSWORD_FLAG_SIZE = 0x01;
  47. internal const byte WILL_RETAIN_FLAG_MASK = 0x20;
  48. internal const byte WILL_RETAIN_FLAG_OFFSET = 0x05;
  49. internal const byte WILL_RETAIN_FLAG_SIZE = 0x01;
  50. internal const byte WILL_QOS_FLAG_MASK = 0x18;
  51. internal const byte WILL_QOS_FLAG_OFFSET = 0x03;
  52. internal const byte WILL_QOS_FLAG_SIZE = 0x02;
  53. internal const byte WILL_FLAG_MASK = 0x04;
  54. internal const byte WILL_FLAG_OFFSET = 0x02;
  55. internal const byte WILL_FLAG_SIZE = 0x01;
  56. internal const byte CLEAN_SESSION_FLAG_MASK = 0x02;
  57. internal const byte CLEAN_SESSION_FLAG_OFFSET = 0x01;
  58. internal const byte CLEAN_SESSION_FLAG_SIZE = 0x01;
  59. // [v.3.1.1] lsb (reserved) must be now 0
  60. internal const byte RESERVED_FLAG_MASK = 0x01;
  61. internal const byte RESERVED_FLAG_OFFSET = 0x00;
  62. internal const byte RESERVED_FLAG_SIZE = 0x01;
  63. #endregion
  64. #region Properties...
  65. /// <summary>
  66. /// Protocol name
  67. /// </summary>
  68. public string ProtocolName
  69. {
  70. get { return this.protocolName; }
  71. set { this.protocolName = value; }
  72. }
  73. /// <summary>
  74. /// Protocol version
  75. /// </summary>
  76. public byte ProtocolVersion
  77. {
  78. get { return this.protocolVersion; }
  79. set { this.protocolVersion = value; }
  80. }
  81. /// <summary>
  82. /// Client identifier
  83. /// </summary>
  84. public string ClientId
  85. {
  86. get { return this.clientId; }
  87. set { this.clientId = value; }
  88. }
  89. /// <summary>
  90. /// Will retain flag
  91. /// </summary>
  92. public bool WillRetain
  93. {
  94. get { return this.willRetain; }
  95. set { this.willRetain = value; }
  96. }
  97. /// <summary>
  98. /// Will QOS level
  99. /// </summary>
  100. public byte WillQosLevel
  101. {
  102. get { return this.willQosLevel; }
  103. set { this.willQosLevel = value; }
  104. }
  105. /// <summary>
  106. /// Will flag
  107. /// </summary>
  108. public bool WillFlag
  109. {
  110. get { return this.willFlag; }
  111. set { this.willFlag = value; }
  112. }
  113. /// <summary>
  114. /// Will topic
  115. /// </summary>
  116. public string WillTopic
  117. {
  118. get { return this.willTopic; }
  119. set { this.willTopic = value; }
  120. }
  121. /// <summary>
  122. /// Will message
  123. /// </summary>
  124. public string WillMessage
  125. {
  126. get { return this.willMessage; }
  127. set { this.willMessage = value; }
  128. }
  129. /// <summary>
  130. /// Username
  131. /// </summary>
  132. public string Username
  133. {
  134. get { return this.username; }
  135. set { this.username = value; }
  136. }
  137. /// <summary>
  138. /// Password
  139. /// </summary>
  140. public string Password
  141. {
  142. get { return this.password; }
  143. set { this.password = value; }
  144. }
  145. /// <summary>
  146. /// Clean session flag
  147. /// </summary>
  148. public bool CleanSession
  149. {
  150. get { return this.cleanSession; }
  151. set { this.cleanSession = value; }
  152. }
  153. /// <summary>
  154. /// Keep alive period
  155. /// </summary>
  156. public ushort KeepAlivePeriod
  157. {
  158. get { return this.keepAlivePeriod; }
  159. set { this.keepAlivePeriod = value; }
  160. }
  161. #endregion
  162. // protocol name
  163. private string protocolName;
  164. // protocol version
  165. private byte protocolVersion;
  166. // client identifier
  167. private string clientId;
  168. // will retain flag
  169. protected bool willRetain;
  170. // will quality of service level
  171. protected byte willQosLevel;
  172. // will flag
  173. private bool willFlag;
  174. // will topic
  175. private string willTopic;
  176. // will message
  177. private string willMessage;
  178. // username
  179. private string username;
  180. // password
  181. private string password;
  182. // clean session flag
  183. private bool cleanSession;
  184. // keep alive period (in sec)
  185. private ushort keepAlivePeriod;
  186. /// <summary>
  187. /// Constructor
  188. /// </summary>
  189. public MqttMsgConnect()
  190. {
  191. this.type = MQTT_MSG_CONNECT_TYPE;
  192. }
  193. /// <summary>
  194. /// Constructor
  195. /// </summary>
  196. /// <param name="clientId">Client identifier</param>
  197. public MqttMsgConnect(string clientId) :
  198. this(clientId, null, null, false, QOS_LEVEL_AT_LEAST_ONCE, false, null, null, true, KEEP_ALIVE_PERIOD_DEFAULT, PROTOCOL_VERSION_V3_1_1)
  199. {
  200. }
  201. /// <summary>
  202. /// Constructor
  203. /// </summary>
  204. /// <param name="clientId">Client identifier</param>
  205. /// <param name="username">Username</param>
  206. /// <param name="password">Password</param>
  207. /// <param name="willRetain">Will retain flag</param>
  208. /// <param name="willQosLevel">Will QOS level</param>
  209. /// <param name="willFlag">Will flag</param>
  210. /// <param name="willTopic">Will topic</param>
  211. /// <param name="willMessage">Will message</param>
  212. /// <param name="cleanSession">Clean sessione flag</param>
  213. /// <param name="keepAlivePeriod">Keep alive period</param>
  214. /// <param name="protocolVersion">Protocol version</param>
  215. public MqttMsgConnect(string clientId,
  216. string username,
  217. string password,
  218. bool willRetain,
  219. byte willQosLevel,
  220. bool willFlag,
  221. string willTopic,
  222. string willMessage,
  223. bool cleanSession,
  224. ushort keepAlivePeriod,
  225. byte protocolVersion
  226. )
  227. {
  228. this.type = MQTT_MSG_CONNECT_TYPE;
  229. this.clientId = clientId;
  230. this.username = username;
  231. this.password = password;
  232. this.willRetain = willRetain;
  233. this.willQosLevel = willQosLevel;
  234. this.willFlag = willFlag;
  235. this.willTopic = willTopic;
  236. this.willMessage = willMessage;
  237. this.cleanSession = cleanSession;
  238. this.keepAlivePeriod = keepAlivePeriod;
  239. // [v.3.1.1] added new protocol name and version
  240. this.protocolVersion = protocolVersion;
  241. this.protocolName = (this.protocolVersion == PROTOCOL_VERSION_V3_1_1) ? PROTOCOL_NAME_V3_1_1 : PROTOCOL_NAME_V3_1;
  242. }
  243. /// <summary>
  244. /// Parse bytes for a CONNECT message
  245. /// </summary>
  246. /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
  247. /// <param name="protocolVersion">Protocol Version</param>
  248. /// <param name="channel">Channel connected to the broker</param>
  249. /// <returns>CONNECT message instance</returns>
  250. public static MqttMsgConnect Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
  251. {
  252. byte[] buffer;
  253. int index = 0;
  254. int protNameUtf8Length;
  255. byte[] protNameUtf8;
  256. bool isUsernameFlag;
  257. bool isPasswordFlag;
  258. int clientIdUtf8Length;
  259. byte[] clientIdUtf8;
  260. int willTopicUtf8Length;
  261. byte[] willTopicUtf8;
  262. int willMessageUtf8Length;
  263. byte[] willMessageUtf8;
  264. int usernameUtf8Length;
  265. byte[] usernameUtf8;
  266. int passwordUtf8Length;
  267. byte[] passwordUtf8;
  268. MqttMsgConnect msg = new MqttMsgConnect();
  269. // get remaining length and allocate buffer
  270. int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
  271. buffer = new byte[remainingLength];
  272. // read bytes from socket...
  273. channel.Receive(buffer);
  274. // protocol name
  275. protNameUtf8Length = ((buffer[index++] << 8) & 0xFF00);
  276. protNameUtf8Length |= buffer[index++];
  277. protNameUtf8 = new byte[protNameUtf8Length];
  278. Array.Copy(buffer, index, protNameUtf8, 0, protNameUtf8Length);
  279. index += protNameUtf8Length;
  280. msg.protocolName = new String(Encoding.UTF8.GetChars(protNameUtf8));
  281. // [v3.1.1] wrong protocol name
  282. if (!msg.protocolName.Equals(PROTOCOL_NAME_V3_1) && !msg.protocolName.Equals(PROTOCOL_NAME_V3_1_1))
  283. throw new MqttClientException(MqttClientErrorCode.InvalidProtocolName);
  284. // protocol version
  285. msg.protocolVersion = buffer[index];
  286. index += PROTOCOL_VERSION_SIZE;
  287. // connect flags
  288. // [v3.1.1] check lsb (reserved) must be 0
  289. if ((msg.protocolVersion == PROTOCOL_VERSION_V3_1_1) &&
  290. ((buffer[index] & RESERVED_FLAG_MASK) != 0x00))
  291. throw new MqttClientException(MqttClientErrorCode.InvalidConnectFlags);
  292. isUsernameFlag = (buffer[index] & USERNAME_FLAG_MASK) != 0x00;
  293. isPasswordFlag = (buffer[index] & PASSWORD_FLAG_MASK) != 0x00;
  294. msg.willRetain = (buffer[index] & WILL_RETAIN_FLAG_MASK) != 0x00;
  295. msg.willQosLevel = (byte)((buffer[index] & WILL_QOS_FLAG_MASK) >> WILL_QOS_FLAG_OFFSET);
  296. msg.willFlag = (buffer[index] & WILL_FLAG_MASK) != 0x00;
  297. msg.cleanSession = (buffer[index] & CLEAN_SESSION_FLAG_MASK) != 0x00;
  298. index += CONNECT_FLAGS_SIZE;
  299. // keep alive timer
  300. msg.keepAlivePeriod = (ushort)((buffer[index++] << 8) & 0xFF00);
  301. msg.keepAlivePeriod |= buffer[index++];
  302. // client identifier [v3.1.1] it may be zero bytes long (empty string)
  303. clientIdUtf8Length = ((buffer[index++] << 8) & 0xFF00);
  304. clientIdUtf8Length |= buffer[index++];
  305. clientIdUtf8 = new byte[clientIdUtf8Length];
  306. Array.Copy(buffer, index, clientIdUtf8, 0, clientIdUtf8Length);
  307. index += clientIdUtf8Length;
  308. msg.clientId = new String(Encoding.UTF8.GetChars(clientIdUtf8));
  309. // [v3.1.1] if client identifier is zero bytes long, clean session must be true
  310. if ((msg.protocolVersion == PROTOCOL_VERSION_V3_1_1) && (clientIdUtf8Length == 0) && (!msg.cleanSession))
  311. throw new MqttClientException(MqttClientErrorCode.InvalidClientId);
  312. // will topic and will message
  313. if (msg.willFlag)
  314. {
  315. willTopicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
  316. willTopicUtf8Length |= buffer[index++];
  317. willTopicUtf8 = new byte[willTopicUtf8Length];
  318. Array.Copy(buffer, index, willTopicUtf8, 0, willTopicUtf8Length);
  319. index += willTopicUtf8Length;
  320. msg.willTopic = new String(Encoding.UTF8.GetChars(willTopicUtf8));
  321. willMessageUtf8Length = ((buffer[index++] << 8) & 0xFF00);
  322. willMessageUtf8Length |= buffer[index++];
  323. willMessageUtf8 = new byte[willMessageUtf8Length];
  324. Array.Copy(buffer, index, willMessageUtf8, 0, willMessageUtf8Length);
  325. index += willMessageUtf8Length;
  326. msg.willMessage = new String(Encoding.UTF8.GetChars(willMessageUtf8));
  327. }
  328. // username
  329. if (isUsernameFlag)
  330. {
  331. usernameUtf8Length = ((buffer[index++] << 8) & 0xFF00);
  332. usernameUtf8Length |= buffer[index++];
  333. usernameUtf8 = new byte[usernameUtf8Length];
  334. Array.Copy(buffer, index, usernameUtf8, 0, usernameUtf8Length);
  335. index += usernameUtf8Length;
  336. msg.username = new String(Encoding.UTF8.GetChars(usernameUtf8));
  337. }
  338. // password
  339. if (isPasswordFlag)
  340. {
  341. passwordUtf8Length = ((buffer[index++] << 8) & 0xFF00);
  342. passwordUtf8Length |= buffer[index++];
  343. passwordUtf8 = new byte[passwordUtf8Length];
  344. Array.Copy(buffer, index, passwordUtf8, 0, passwordUtf8Length);
  345. index += passwordUtf8Length;
  346. msg.password = new String(Encoding.UTF8.GetChars(passwordUtf8));
  347. }
  348. return msg;
  349. }
  350. public override byte[] GetBytes(byte protocolVersion)
  351. {
  352. int fixedHeaderSize = 0;
  353. int varHeaderSize = 0;
  354. int payloadSize = 0;
  355. int remainingLength = 0;
  356. byte[] buffer;
  357. int index = 0;
  358. byte[] clientIdUtf8 = Encoding.UTF8.GetBytes(this.clientId);
  359. byte[] willTopicUtf8 = (this.willFlag && (this.willTopic != null)) ? Encoding.UTF8.GetBytes(this.willTopic) : null;
  360. byte[] willMessageUtf8 = (this.willFlag && (this.willMessage != null)) ? Encoding.UTF8.GetBytes(this.willMessage) : null;
  361. byte[] usernameUtf8 = ((this.username != null) && (this.username.Length > 0)) ? Encoding.UTF8.GetBytes(this.username) : null;
  362. byte[] passwordUtf8 = ((this.password != null) && (this.password.Length > 0)) ? Encoding.UTF8.GetBytes(this.password) : null;
  363. // [v3.1.1]
  364. if (this.protocolVersion == PROTOCOL_VERSION_V3_1_1)
  365. {
  366. // will flag set, will topic and will message MUST be present
  367. if (this.willFlag && ((this.willQosLevel >= 0x03) ||
  368. (willTopicUtf8 == null) || (willMessageUtf8 == null) ||
  369. ((willTopicUtf8 != null) && (willTopicUtf8.Length == 0)) ||
  370. ((willMessageUtf8 != null) && (willMessageUtf8.Length == 0))))
  371. throw new MqttClientException(MqttClientErrorCode.WillWrong);
  372. // willflag not set, retain must be 0 and will topic and message MUST NOT be present
  373. else if (!this.willFlag && ((this.willRetain) ||
  374. (willTopicUtf8 != null) || (willMessageUtf8 != null) ||
  375. ((willTopicUtf8 != null) && (willTopicUtf8.Length != 0)) ||
  376. ((willMessageUtf8 != null) && (willMessageUtf8.Length != 0))))
  377. throw new MqttClientException(MqttClientErrorCode.WillWrong);
  378. }
  379. if (this.keepAlivePeriod > MAX_KEEP_ALIVE)
  380. throw new MqttClientException(MqttClientErrorCode.KeepAliveWrong);
  381. // check on will QoS Level
  382. if ((this.willQosLevel < MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE) ||
  383. (this.willQosLevel > MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))
  384. throw new MqttClientException(MqttClientErrorCode.WillWrong);
  385. // protocol name field size
  386. // MQTT version 3.1
  387. if (this.protocolVersion == PROTOCOL_VERSION_V3_1)
  388. {
  389. varHeaderSize += (PROTOCOL_NAME_LEN_SIZE + PROTOCOL_NAME_V3_1_SIZE);
  390. }
  391. // MQTT version 3.1.1
  392. else
  393. {
  394. varHeaderSize += (PROTOCOL_NAME_LEN_SIZE + PROTOCOL_NAME_V3_1_1_SIZE);
  395. }
  396. // protocol level field size
  397. varHeaderSize += PROTOCOL_VERSION_SIZE;
  398. // connect flags field size
  399. varHeaderSize += CONNECT_FLAGS_SIZE;
  400. // keep alive timer field size
  401. varHeaderSize += KEEP_ALIVE_TIME_SIZE;
  402. // client identifier field size
  403. payloadSize += clientIdUtf8.Length + 2;
  404. // will topic field size
  405. payloadSize += (willTopicUtf8 != null) ? (willTopicUtf8.Length + 2) : 0;
  406. // will message field size
  407. payloadSize += (willMessageUtf8 != null) ? (willMessageUtf8.Length + 2) : 0;
  408. // username field size
  409. payloadSize += (usernameUtf8 != null) ? (usernameUtf8.Length + 2) : 0;
  410. // password field size
  411. payloadSize += (passwordUtf8 != null) ? (passwordUtf8.Length + 2) : 0;
  412. remainingLength += (varHeaderSize + payloadSize);
  413. // first byte of fixed header
  414. fixedHeaderSize = 1;
  415. int temp = remainingLength;
  416. // increase fixed header size based on remaining length
  417. // (each remaining length byte can encode until 128)
  418. do
  419. {
  420. fixedHeaderSize++;
  421. temp = temp / 128;
  422. } while (temp > 0);
  423. // allocate buffer for message
  424. buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
  425. // first fixed header byte
  426. buffer[index++] = (MQTT_MSG_CONNECT_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_CONNECT_FLAG_BITS; // [v.3.1.1]
  427. // encode remaining length
  428. index = this.encodeRemainingLength(remainingLength, buffer, index);
  429. // protocol name
  430. buffer[index++] = 0; // MSB protocol name size
  431. // MQTT version 3.1
  432. if (this.protocolVersion == PROTOCOL_VERSION_V3_1)
  433. {
  434. buffer[index++] = PROTOCOL_NAME_V3_1_SIZE; // LSB protocol name size
  435. Array.Copy(Encoding.UTF8.GetBytes(PROTOCOL_NAME_V3_1), 0, buffer, index, PROTOCOL_NAME_V3_1_SIZE);
  436. index += PROTOCOL_NAME_V3_1_SIZE;
  437. // protocol version
  438. buffer[index++] = PROTOCOL_VERSION_V3_1;
  439. }
  440. // MQTT version 3.1.1
  441. else
  442. {
  443. buffer[index++] = PROTOCOL_NAME_V3_1_1_SIZE; // LSB protocol name size
  444. Array.Copy(Encoding.UTF8.GetBytes(PROTOCOL_NAME_V3_1_1), 0, buffer, index, PROTOCOL_NAME_V3_1_1_SIZE);
  445. index += PROTOCOL_NAME_V3_1_1_SIZE;
  446. // protocol version
  447. buffer[index++] = PROTOCOL_VERSION_V3_1_1;
  448. }
  449. // connect flags
  450. byte connectFlags = 0x00;
  451. connectFlags |= (usernameUtf8 != null) ? (byte)(1 << USERNAME_FLAG_OFFSET) : (byte)0x00;
  452. connectFlags |= (passwordUtf8 != null) ? (byte)(1 << PASSWORD_FLAG_OFFSET) : (byte)0x00;
  453. connectFlags |= (this.willRetain) ? (byte)(1 << WILL_RETAIN_FLAG_OFFSET) : (byte)0x00;
  454. // only if will flag is set, we have to use will QoS level (otherwise is MUST be 0)
  455. if (this.willFlag)
  456. connectFlags |= (byte)(this.willQosLevel << WILL_QOS_FLAG_OFFSET);
  457. connectFlags |= (this.willFlag) ? (byte)(1 << WILL_FLAG_OFFSET) : (byte)0x00;
  458. connectFlags |= (this.cleanSession) ? (byte)(1 << CLEAN_SESSION_FLAG_OFFSET) : (byte)0x00;
  459. buffer[index++] = connectFlags;
  460. // keep alive period
  461. buffer[index++] = (byte)((this.keepAlivePeriod >> 8) & 0x00FF); // MSB
  462. buffer[index++] = (byte)(this.keepAlivePeriod & 0x00FF); // LSB
  463. // client identifier
  464. buffer[index++] = (byte)((clientIdUtf8.Length >> 8) & 0x00FF); // MSB
  465. buffer[index++] = (byte)(clientIdUtf8.Length & 0x00FF); // LSB
  466. Array.Copy(clientIdUtf8, 0, buffer, index, clientIdUtf8.Length);
  467. index += clientIdUtf8.Length;
  468. // will topic
  469. if (this.willFlag && (willTopicUtf8 != null))
  470. {
  471. buffer[index++] = (byte)((willTopicUtf8.Length >> 8) & 0x00FF); // MSB
  472. buffer[index++] = (byte)(willTopicUtf8.Length & 0x00FF); // LSB
  473. Array.Copy(willTopicUtf8, 0, buffer, index, willTopicUtf8.Length);
  474. index += willTopicUtf8.Length;
  475. }
  476. // will message
  477. if (this.willFlag && (willMessageUtf8 != null))
  478. {
  479. buffer[index++] = (byte)((willMessageUtf8.Length >> 8) & 0x00FF); // MSB
  480. buffer[index++] = (byte)(willMessageUtf8.Length & 0x00FF); // LSB
  481. Array.Copy(willMessageUtf8, 0, buffer, index, willMessageUtf8.Length);
  482. index += willMessageUtf8.Length;
  483. }
  484. // username
  485. if (usernameUtf8 != null)
  486. {
  487. buffer[index++] = (byte)((usernameUtf8.Length >> 8) & 0x00FF); // MSB
  488. buffer[index++] = (byte)(usernameUtf8.Length & 0x00FF); // LSB
  489. Array.Copy(usernameUtf8, 0, buffer, index, usernameUtf8.Length);
  490. index += usernameUtf8.Length;
  491. }
  492. // password
  493. if (passwordUtf8 != null)
  494. {
  495. buffer[index++] = (byte)((passwordUtf8.Length >> 8) & 0x00FF); // MSB
  496. buffer[index++] = (byte)(passwordUtf8.Length & 0x00FF); // LSB
  497. Array.Copy(passwordUtf8, 0, buffer, index, passwordUtf8.Length);
  498. index += passwordUtf8.Length;
  499. }
  500. return buffer;
  501. }
  502. public override string ToString()
  503. {
  504. #if TRACE
  505. return this.GetTraceString(
  506. "CONNECT",
  507. new object[] { "protocolName", "protocolVersion", "clientId", "willFlag", "willRetain", "willQosLevel", "willTopic", "willMessage", "username", "password", "cleanSession", "keepAlivePeriod" },
  508. new object[] { this.protocolName, this.protocolVersion, this.clientId, this.willFlag, this.willRetain, this.willQosLevel, this.willTopic, this.willMessage, this.username, this.password, this.cleanSession, this.keepAlivePeriod });
  509. #else
  510. return base.ToString();
  511. #endif
  512. }
  513. }
  514. }