Compare commits

..

No commits in common. "master" and "v4.3.0.0" have entirely different histories.

49 changed files with 5463 additions and 5001 deletions

203
LICENSE
View File

@ -1,203 +0,0 @@
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are
distributed by that particular Contributor. A Contribution 'originates'
from a Contributor if it was added to the Program by such Contributor
itself or anyone acting on such Contributor's behalf. Contributions do not
include additions to the Program which: (i) are separate modules of
software distributed in conjunction with the Program under their own
license agreement, and (ii) are not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which are
necessarily infringed by the use or sale of its Contribution alone or when
combined with the Program.
"Program" means the Contributions distributed in accordance with this
Agreement.
"Recipient" means anyone who receives the Program under this Agreement,
including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free copyright license to
reproduce, prepare derivative works of, publicly display, publicly
perform, distribute and sublicense the Contribution of such Contributor,
if any, and such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free patent license under
Licensed Patents to make, use, sell, offer to sell, import and otherwise
transfer the Contribution of such Contributor, if any, in source code and
object code form. This patent license shall apply to the combination of
the Contribution and the Program if, at the time the Contribution is
added by the Contributor, such addition of the Contribution causes such
combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Contribution.
No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses
to its Contributions set forth herein, no assurances are provided by any
Contributor that the Program does not infringe the patent or other
intellectual property rights of any other entity. Each Contributor
disclaims any liability to Recipient for claims brought by any other
entity based on infringement of intellectual property rights or
otherwise. As a condition to exercising the rights and licenses granted
hereunder, each Recipient hereby assumes sole responsibility to secure
any other intellectual property rights needed, if any. For example, if a
third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license
before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient
copyright rights in its Contribution, if any, to grant the copyright
license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under
its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties
and conditions, express and implied, including warranties or
conditions of title and non-infringement, and implied warranties or
conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for
damages, including direct, indirect, special, incidental and
consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are
offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such
Contributor, and informs licensees how to obtain it in a reasonable
manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained
within the Program.
Each Contributor must identify itself as the originator of its Contribution,
if
any, in a manner that reasonably allows subsequent Recipients to identify the
originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with
respect to end users, business partners and the like. While this license is
intended to facilitate the commercial use of the Program, the Contributor who
includes the Program in a commercial product offering should do so in a manner
which does not create potential liability for other Contributors. Therefore,
if a Contributor includes the Program in a commercial product offering, such
Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
every other Contributor ("Indemnified Contributor") against any losses,
damages and costs (collectively "Losses") arising from claims, lawsuits and
other legal actions brought by a third party against the Indemnified
Contributor to the extent caused by the acts or omissions of such Commercial
Contributor in connection with its distribution of the Program in a commercial
product offering. The obligations in this section do not apply to any claims
or Losses relating to any actual or alleged intellectual property
infringement. In order to qualify, an Indemnified Contributor must:
a) promptly notify the Commercial Contributor in writing of such claim, and
b) allow the Commercial Contributor to control, and cooperate with the
Commercial Contributor in, the defense and any related settlement
negotiations. The Indemnified Contributor may participate in any such claim at
its own expense.
For example, a Contributor might include the Program in a commercial product
offering, Product X. That Contributor is then a Commercial Contributor. If
that Commercial Contributor then makes performance claims, or offers
warranties related to Product X, those performance claims and warranties are
such Commercial Contributor's responsibility alone. Under this section, the
Commercial Contributor would have to defend claims against the other
Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
Recipient is solely responsible for determining the appropriateness of using
and distributing the Program and assumes all risks associated with its
exercise of rights under this Agreement , including but not limited to the
risks and costs of program errors, compliance with applicable laws, damage to
or loss of data, programs or equipment, and unavailability or interruption of
operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of the
remainder of the terms of this Agreement, and without further action by the
parties hereto, such provision shall be reformed to the minimum extent
necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Program itself
(excluding combinations of the Program with other software or hardware)
infringes such Recipient's patent(s), then such Recipient's rights granted
under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to
comply with any of the material terms or conditions of this Agreement and does
not cure such failure in a reasonable period of time after becoming aware of
such noncompliance. If all Recipient's rights under this Agreement terminate,
Recipient agrees to cease use and distribution of the Program as soon as
reasonably practicable. However, Recipient's obligations under this Agreement
and any licenses granted by Recipient relating to the Program shall continue
and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in
order to avoid inconsistency the Agreement is copyrighted and may only be
modified in the following manner. The Agreement Steward reserves the right to
publish new versions (including revisions) of this Agreement from time to
time. No one other than the Agreement Steward has the right to modify this
Agreement. The Eclipse Foundation is the initial Agreement Steward. The
Eclipse Foundation may assign the responsibility to serve as the Agreement
Steward to a suitable separate entity. Each new version of the Agreement will
be given a distinguishing version number. The Program (including
Contributions) may always be distributed subject to the version of the
Agreement under which it was received. In addition, after a new version of the
Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly
stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
licenses to the intellectual property of any Contributor under this Agreement,
whether expressly, by implication, estoppel or otherwise. All rights in the
Program not expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the
intellectual property laws of the United States of America. No party to this
Agreement will bring a legal action under this Agreement more than one year
after the cause of action arose. Each party waives its rights to a jury trial in
any resulting litigation.

View File

@ -1,25 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29519.87
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt", "M2Mqtt\M2Mqtt.csproj", "{18F706D2-7610-428C-8324-8327F9D7BE90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{18F706D2-7610-428C-8324-8327F9D7BE90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18F706D2-7610-428C-8324-8327F9D7BE90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18F706D2-7610-428C-8324-8327F9D7BE90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18F706D2-7610-428C-8324-8327F9D7BE90}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EBFDF320-2C59-4F89-8211-5B6EF9C310ED}
EndGlobalSection
EndGlobal

View File

@ -16,104 +16,117 @@ Contributors:
using System; using System;
namespace uPLibrary.Networking.M2Mqtt.Exceptions { namespace uPLibrary.Networking.M2Mqtt.Exceptions
/// <summary> {
/// MQTT client exception
/// </summary>
public class MqttClientException : Exception {
/// <summary> /// <summary>
/// Constructor /// MQTT client exception
/// </summary> /// </summary>
/// <param name="code">Error code</param> public class MqttClientException : Exception
public MqttClientException(MqttClientErrorCode errorCode) => this.ErrorCode = errorCode; {
/// <summary>
/// Constructor
/// </summary>
/// <param name="code">Error code</param>
public MqttClientException(MqttClientErrorCode errorCode)
{
this.errorCode = errorCode;
}
// error code
private MqttClientErrorCode errorCode;
/// <summary>
/// Error code
/// </summary>
public MqttClientErrorCode ErrorCode
{
get { return this.errorCode; }
set { this.errorCode = value; }
}
}
/// <summary> /// <summary>
/// Error code /// MQTT client erroro code
/// </summary> /// </summary>
public MqttClientErrorCode ErrorCode { get; set; } public enum MqttClientErrorCode
} {
/// <summary>
/// <summary> /// Will error (topic, message or QoS level)
/// MQTT client erroro code /// </summary>
/// </summary> WillWrong = 1,
public enum MqttClientErrorCode {
/// <summary> /// <summary>
/// Will error (topic, message or QoS level) /// Keep alive period too large
/// </summary> /// </summary>
WillWrong = 1, KeepAliveWrong,
/// <summary> /// <summary>
/// Keep alive period too large /// Topic contains wildcards
/// </summary> /// </summary>
KeepAliveWrong, TopicWildcard,
/// <summary> /// <summary>
/// Topic contains wildcards /// Topic length wrong
/// </summary> /// </summary>
TopicWildcard, TopicLength,
/// <summary> /// <summary>
/// Topic length wrong /// QoS level not allowed
/// </summary> /// </summary>
TopicLength, QosNotAllowed,
/// <summary> /// <summary>
/// QoS level not allowed /// Topics list empty for subscribe
/// </summary> /// </summary>
QosNotAllowed, TopicsEmpty,
/// <summary> /// <summary>
/// Topics list empty for subscribe /// Qos levels list empty for subscribe
/// </summary> /// </summary>
TopicsEmpty, QosLevelsEmpty,
/// <summary> /// <summary>
/// Qos levels list empty for subscribe /// Topics / Qos Levels not match in subscribe
/// </summary> /// </summary>
QosLevelsEmpty, TopicsQosLevelsNotMatch,
/// <summary> /// <summary>
/// Topics / Qos Levels not match in subscribe /// Wrong message from broker
/// </summary> /// </summary>
TopicsQosLevelsNotMatch, WrongBrokerMessage,
/// <summary> /// <summary>
/// Wrong message from broker /// Wrong Message Id
/// </summary> /// </summary>
WrongBrokerMessage, WrongMessageId,
/// <summary> /// <summary>
/// Wrong Message Id /// Inflight queue is full
/// </summary> /// </summary>
WrongMessageId, InflightQueueFull,
/// <summary> // [v3.1.1]
/// Inflight queue is full /// <summary>
/// </summary> /// Invalid flag bits received
InflightQueueFull, /// </summary>
InvalidFlagBits,
// [v3.1.1]
/// <summary> // [v3.1.1]
/// Invalid flag bits received /// <summary>
/// </summary> /// Invalid connect flags received
InvalidFlagBits, /// </summary>
InvalidConnectFlags,
// [v3.1.1]
/// <summary> // [v3.1.1]
/// Invalid connect flags received /// <summary>
/// </summary> /// Invalid client id
InvalidConnectFlags, /// </summary>
InvalidClientId,
// [v3.1.1]
/// <summary> // [v3.1.1]
/// Invalid client id /// <summary>
/// </summary> /// Invalid protocol name
InvalidClientId, /// </summary>
InvalidProtocolName
// [v3.1.1] }
/// <summary>
/// Invalid protocol name
/// </summary>
InvalidProtocolName
}
} }

View File

@ -16,23 +16,27 @@ Contributors:
using System; using System;
namespace uPLibrary.Networking.M2Mqtt.Exceptions { namespace uPLibrary.Networking.M2Mqtt.Exceptions
/// <summary> {
/// Exception due to error communication with broker on socket
/// </summary>
public class MqttCommunicationException : Exception {
/// <summary> /// <summary>
/// Default constructor /// Exception due to error communication with broker on socket
/// </summary> /// </summary>
public MqttCommunicationException() { public class MqttCommunicationException : Exception
} {
/// <summary>
/// <summary> /// Default constructor
/// Constructor /// </summary>
/// </summary> public MqttCommunicationException()
/// <param name="e">Inner Exception</param> {
public MqttCommunicationException(Exception e) }
: base(String.Empty, e) {
} /// <summary>
} /// Constructor
/// </summary>
/// <param name="e">Inner Exception</param>
public MqttCommunicationException(Exception e)
: base(String.Empty, e)
{
}
}
} }

View File

@ -16,13 +16,16 @@ Contributors:
using System; using System;
namespace uPLibrary.Networking.M2Mqtt.Exceptions { namespace uPLibrary.Networking.M2Mqtt.Exceptions
/// <summary> {
/// Connection to the broker exception /// <summary>
/// </summary> /// Connection to the broker exception
public class MqttConnectionException : Exception { /// </summary>
public MqttConnectionException(String message, Exception innerException) public class MqttConnectionException : Exception
: base(message, innerException) { {
} public MqttConnectionException(string message, Exception innerException)
} : base(message, innerException)
{
}
}
} }

View File

@ -16,10 +16,12 @@ Contributors:
using System; using System;
namespace uPLibrary.Networking.M2Mqtt.Exceptions { namespace uPLibrary.Networking.M2Mqtt.Exceptions
/// <summary> {
/// Timeout on receiving from broker exception /// <summary>
/// </summary> /// Timeout on receiving from broker exception
public class MqttTimeoutException : Exception { /// </summary>
} public class MqttTimeoutException : Exception
{
}
} }

View File

@ -15,52 +15,55 @@ Contributors:
*/ */
using System; using System;
using System.Text;
namespace uPLibrary.Networking.M2Mqtt { namespace uPLibrary.Networking.M2Mqtt
/// <summary> {
/// Interface for channel under MQTT library
/// </summary>
public interface IMqttNetworkChannel {
/// <summary> /// <summary>
/// Data available on channel /// Interface for channel under MQTT library
/// </summary> /// </summary>
Boolean DataAvailable { get; } public interface IMqttNetworkChannel
{
/// <summary> /// <summary>
/// Receive data from the network channel /// Data available on channel
/// </summary> /// </summary>
/// <param name="buffer">Data buffer for receiving data</param> bool DataAvailable { get; }
/// <returns>Number of bytes received</returns>
Int32 Receive(Byte[] buffer); /// <summary>
/// Receive data from the network channel
/// <summary> /// </summary>
/// Receive data from the network channel with a specified timeout /// <param name="buffer">Data buffer for receiving data</param>
/// </summary> /// <returns>Number of bytes received</returns>
/// <param name="buffer">Data buffer for receiving data</param> int Receive(byte[] buffer);
/// <param name="timeout">Timeout on receiving (in milliseconds)</param>
/// <returns>Number of bytes received</returns> /// <summary>
Int32 Receive(Byte[] buffer, Int32 timeout); /// Receive data from the network channel with a specified timeout
/// </summary>
/// <summary> /// <param name="buffer">Data buffer for receiving data</param>
/// Send data on the network channel to the broker /// <param name="timeout">Timeout on receiving (in milliseconds)</param>
/// </summary> /// <returns>Number of bytes received</returns>
/// <param name="buffer">Data buffer to send</param> int Receive(byte[] buffer, int timeout);
/// <returns>Number of byte sent</returns>
Int32 Send(Byte[] buffer); /// <summary>
/// Send data on the network channel to the broker
/// <summary> /// </summary>
/// Close the network channel /// <param name="buffer">Data buffer to send</param>
/// </summary> /// <returns>Number of byte sent</returns>
void Close(); int Send(byte[] buffer);
/// <summary> /// <summary>
/// Connect to remote server /// Close the network channel
/// </summary> /// </summary>
void Connect(); void Close();
/// <summary> /// <summary>
/// Accept client connection /// Connect to remote server
/// </summary> /// </summary>
void Accept(); void Connect();
}
/// <summary>
/// Accept client connection
/// </summary>
void Accept();
}
} }

View File

@ -14,10 +14,12 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
namespace uPLibrary.Networking.M2Mqtt.Internal { namespace uPLibrary.Networking.M2Mqtt.Internal
/// <summary> {
/// Generic internal event for dispatching /// <summary>
/// </summary> /// Generic internal event for dispatching
public abstract class InternalEvent { /// </summary>
} public abstract class InternalEvent
{
}
} }

View File

@ -16,26 +16,36 @@ Contributors:
using uPLibrary.Networking.M2Mqtt.Messages; using uPLibrary.Networking.M2Mqtt.Messages;
namespace uPLibrary.Networking.M2Mqtt.Internal { namespace uPLibrary.Networking.M2Mqtt.Internal
/// <summary> {
/// Internal event with a message
/// </summary>
public class MsgInternalEvent : InternalEvent {
#region Properties ...
/// <summary> /// <summary>
/// Related message /// Internal event with a message
/// </summary> /// </summary>
public MqttMsgBase Message { get; set; } public class MsgInternalEvent : InternalEvent
{
#endregion #region Properties ...
// related message /// <summary>
/// Related message
/// <summary> /// </summary>
/// Constructor public MqttMsgBase Message
/// </summary> {
/// <param name="msg">Related message</param> get { return this.msg; }
public MsgInternalEvent(MqttMsgBase msg) => this.Message = msg; set { this.msg = value; }
} }
#endregion
// related message
protected MqttMsgBase msg;
/// <summary>
/// Constructor
/// </summary>
/// <param name="msg">Related message</param>
public MsgInternalEvent(MqttMsgBase msg)
{
this.msg = msg;
}
}
} }

View File

@ -14,31 +14,40 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using uPLibrary.Networking.M2Mqtt.Messages; using uPLibrary.Networking.M2Mqtt.Messages;
namespace uPLibrary.Networking.M2Mqtt.Internal { namespace uPLibrary.Networking.M2Mqtt.Internal
/// <summary> {
/// Internal event for a published message
/// </summary>
public class MsgPublishedInternalEvent : MsgInternalEvent {
#region Properties...
/// <summary> /// <summary>
/// Message published (or failed due to retries) /// Internal event for a published message
/// </summary> /// </summary>
public Boolean IsPublished { get; internal set; } public class MsgPublishedInternalEvent : MsgInternalEvent
{
#endregion #region Properties...
// published flag /// <summary>
/// Message published (or failed due to retries)
/// <summary> /// </summary>
/// Constructor public bool IsPublished
/// </summary> {
/// <param name="msg">Message published</param> get { return this.isPublished; }
/// <param name="isPublished">Publish flag</param> internal set { this.isPublished = value; }
public MsgPublishedInternalEvent(MqttMsgBase msg, Boolean isPublished) }
: base(msg) => this.IsPublished = isPublished;
} #endregion
// published flag
bool isPublished;
/// <summary>
/// Constructor
/// </summary>
/// <param name="msg">Message published</param>
/// <param name="isPublished">Publish flag</param>
public MsgPublishedInternalEvent(MqttMsgBase msg, bool isPublished)
: base(msg)
{
this.isPublished = isPublished;
}
}
} }

View File

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyName>M2Mqtt</AssemblyName>
<RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
<Description>MQTT Client Library for M2M communication</Description>
<Authors>Paolo Patierno</Authors>
<Company>Paolo Patierno</Company>
<Copyright>Copyright © Paolo Patierno 2014</Copyright>
<Version>4.3.0</Version>
<AssemblyVersion>4.3.0</AssemblyVersion>
<FileVersion>4.3.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;SSL</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;SSL</DefineConstants>
</PropertyGroup>
</Project>

View File

@ -17,220 +17,259 @@ Contributors:
using System; using System;
using System.Text; using System.Text;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Base class for all MQTT messages
/// </summary>
public abstract class MqttMsgBase {
#region Constants...
// mask, offset and size for fixed header fields
internal const Byte MSG_TYPE_MASK = 0xF0;
internal const Byte MSG_TYPE_OFFSET = 0x04;
internal const Byte MSG_TYPE_SIZE = 0x04;
internal const Byte MSG_FLAG_BITS_MASK = 0x0F; // [v3.1.1]
internal const Byte MSG_FLAG_BITS_OFFSET = 0x00; // [v3.1.1]
internal const Byte MSG_FLAG_BITS_SIZE = 0x04; // [v3.1.1]
internal const Byte DUP_FLAG_MASK = 0x08;
internal const Byte DUP_FLAG_OFFSET = 0x03;
internal const Byte DUP_FLAG_SIZE = 0x01;
internal const Byte QOS_LEVEL_MASK = 0x06;
internal const Byte QOS_LEVEL_OFFSET = 0x01;
internal const Byte QOS_LEVEL_SIZE = 0x02;
internal const Byte RETAIN_FLAG_MASK = 0x01;
internal const Byte RETAIN_FLAG_OFFSET = 0x00;
internal const Byte RETAIN_FLAG_SIZE = 0x01;
// MQTT message types
internal const Byte MQTT_MSG_CONNECT_TYPE = 0x01;
internal const Byte MQTT_MSG_CONNACK_TYPE = 0x02;
internal const Byte MQTT_MSG_PUBLISH_TYPE = 0x03;
internal const Byte MQTT_MSG_PUBACK_TYPE = 0x04;
internal const Byte MQTT_MSG_PUBREC_TYPE = 0x05;
internal const Byte MQTT_MSG_PUBREL_TYPE = 0x06;
internal const Byte MQTT_MSG_PUBCOMP_TYPE = 0x07;
internal const Byte MQTT_MSG_SUBSCRIBE_TYPE = 0x08;
internal const Byte MQTT_MSG_SUBACK_TYPE = 0x09;
internal const Byte MQTT_MSG_UNSUBSCRIBE_TYPE = 0x0A;
internal const Byte MQTT_MSG_UNSUBACK_TYPE = 0x0B;
internal const Byte MQTT_MSG_PINGREQ_TYPE = 0x0C;
internal const Byte MQTT_MSG_PINGRESP_TYPE = 0x0D;
internal const Byte MQTT_MSG_DISCONNECT_TYPE = 0x0E;
// [v3.1.1] MQTT flag bits
internal const Byte MQTT_MSG_CONNECT_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_CONNACK_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_PUBLISH_FLAG_BITS = 0x00; // just defined as 0x00 but depends on publish props (dup, qos, retain)
internal const Byte MQTT_MSG_PUBACK_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_PUBREC_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_PUBREL_FLAG_BITS = 0x02;
internal const Byte MQTT_MSG_PUBCOMP_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_SUBSCRIBE_FLAG_BITS = 0x02;
internal const Byte MQTT_MSG_SUBACK_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_UNSUBSCRIBE_FLAG_BITS = 0x02;
internal const Byte MQTT_MSG_UNSUBACK_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_PINGREQ_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_PINGRESP_FLAG_BITS = 0x00;
internal const Byte MQTT_MSG_DISCONNECT_FLAG_BITS = 0x00;
// QOS levels
public const Byte QOS_LEVEL_AT_MOST_ONCE = 0x00;
public const Byte QOS_LEVEL_AT_LEAST_ONCE = 0x01;
public const Byte QOS_LEVEL_EXACTLY_ONCE = 0x02;
// SUBSCRIBE QoS level granted failure [v3.1.1]
public const Byte QOS_LEVEL_GRANTED_FAILURE = 0x80;
internal const UInt16 MAX_TOPIC_LENGTH = 65535;
internal const UInt16 MIN_TOPIC_LENGTH = 1;
internal const Byte MESSAGE_ID_SIZE = 2;
#endregion
#region Properties...
/// <summary> /// <summary>
/// Message type /// Base class for all MQTT messages
/// </summary> /// </summary>
public Byte Type { get; set; } public abstract class MqttMsgBase
{
/// <summary> #region Constants...
/// Duplicate message flag
/// </summary> // mask, offset and size for fixed header fields
public Boolean DupFlag { get; set; } internal const byte MSG_TYPE_MASK = 0xF0;
internal const byte MSG_TYPE_OFFSET = 0x04;
/// <summary> internal const byte MSG_TYPE_SIZE = 0x04;
/// Quality of Service level internal const byte MSG_FLAG_BITS_MASK = 0x0F; // [v3.1.1]
/// </summary> internal const byte MSG_FLAG_BITS_OFFSET = 0x00; // [v3.1.1]
public Byte QosLevel { get; set; } internal const byte MSG_FLAG_BITS_SIZE = 0x04; // [v3.1.1]
internal const byte DUP_FLAG_MASK = 0x08;
/// <summary> internal const byte DUP_FLAG_OFFSET = 0x03;
/// Retain message flag internal const byte DUP_FLAG_SIZE = 0x01;
/// </summary> internal const byte QOS_LEVEL_MASK = 0x06;
public Boolean Retain { get; set; } internal const byte QOS_LEVEL_OFFSET = 0x01;
internal const byte QOS_LEVEL_SIZE = 0x02;
/// <summary> internal const byte RETAIN_FLAG_MASK = 0x01;
/// Message identifier for the message internal const byte RETAIN_FLAG_OFFSET = 0x00;
/// </summary> internal const byte RETAIN_FLAG_SIZE = 0x01;
public UInt16 MessageId { get; set; }
// MQTT message types
#endregion internal const byte MQTT_MSG_CONNECT_TYPE = 0x01;
internal const byte MQTT_MSG_CONNACK_TYPE = 0x02;
// message type internal const byte MQTT_MSG_PUBLISH_TYPE = 0x03;
// duplicate delivery internal const byte MQTT_MSG_PUBACK_TYPE = 0x04;
// quality of service level internal const byte MQTT_MSG_PUBREC_TYPE = 0x05;
// retain flag internal const byte MQTT_MSG_PUBREL_TYPE = 0x06;
// message identifier internal const byte MQTT_MSG_PUBCOMP_TYPE = 0x07;
internal const byte MQTT_MSG_SUBSCRIBE_TYPE = 0x08;
/// <summary> internal const byte MQTT_MSG_SUBACK_TYPE = 0x09;
/// Returns message bytes rapresentation internal const byte MQTT_MSG_UNSUBSCRIBE_TYPE = 0x0A;
/// </summary> internal const byte MQTT_MSG_UNSUBACK_TYPE = 0x0B;
/// <param name="protocolVersion">Protocol version</param> internal const byte MQTT_MSG_PINGREQ_TYPE = 0x0C;
/// <returns>Bytes rapresentation</returns> internal const byte MQTT_MSG_PINGRESP_TYPE = 0x0D;
public abstract Byte[] GetBytes(Byte protocolVersion); internal const byte MQTT_MSG_DISCONNECT_TYPE = 0x0E;
/// <summary> // [v3.1.1] MQTT flag bits
/// Encode remaining length and insert it into message buffer internal const byte MQTT_MSG_CONNECT_FLAG_BITS = 0x00;
/// </summary> internal const byte MQTT_MSG_CONNACK_FLAG_BITS = 0x00;
/// <param name="remainingLength">Remaining length value to encode</param> internal const byte MQTT_MSG_PUBLISH_FLAG_BITS = 0x00; // just defined as 0x00 but depends on publish props (dup, qos, retain)
/// <param name="buffer">Message buffer for inserting encoded value</param> internal const byte MQTT_MSG_PUBACK_FLAG_BITS = 0x00;
/// <param name="index">Index from which insert encoded value into buffer</param> internal const byte MQTT_MSG_PUBREC_FLAG_BITS = 0x00;
/// <returns>Index updated</returns> internal const byte MQTT_MSG_PUBREL_FLAG_BITS = 0x02;
protected Int32 EncodeRemainingLength(Int32 remainingLength, Byte[] buffer, Int32 index) { internal const byte MQTT_MSG_PUBCOMP_FLAG_BITS = 0x00;
do { internal const byte MQTT_MSG_SUBSCRIBE_FLAG_BITS = 0x02;
Int32 digit = remainingLength % 128; internal const byte MQTT_MSG_SUBACK_FLAG_BITS = 0x00;
remainingLength /= 128; internal const byte MQTT_MSG_UNSUBSCRIBE_FLAG_BITS = 0x02;
if (remainingLength > 0) { internal const byte MQTT_MSG_UNSUBACK_FLAG_BITS = 0x00;
digit |= 0x80; internal const byte MQTT_MSG_PINGREQ_FLAG_BITS = 0x00;
} internal const byte MQTT_MSG_PINGRESP_FLAG_BITS = 0x00;
internal const byte MQTT_MSG_DISCONNECT_FLAG_BITS = 0x00;
buffer[index++] = (Byte)digit;
} while (remainingLength > 0); // QOS levels
return index; public const byte QOS_LEVEL_AT_MOST_ONCE = 0x00;
} public const byte QOS_LEVEL_AT_LEAST_ONCE = 0x01;
public const byte QOS_LEVEL_EXACTLY_ONCE = 0x02;
/// <summary>
/// Decode remaining length reading bytes from socket // SUBSCRIBE QoS level granted failure [v3.1.1]
/// </summary> public const byte QOS_LEVEL_GRANTED_FAILURE = 0x80;
/// <param name="channel">Channel from reading bytes</param>
/// <returns>Decoded remaining length</returns> internal const ushort MAX_TOPIC_LENGTH = 65535;
protected static Int32 DecodeRemainingLength(IMqttNetworkChannel channel) { internal const ushort MIN_TOPIC_LENGTH = 1;
Int32 multiplier = 1; internal const byte MESSAGE_ID_SIZE = 2;
Int32 value = 0;
Byte[] nextByte = new Byte[1]; #endregion
Int32 digit;
do { #region Properties...
// next digit from stream
_ = channel.Receive(nextByte); /// <summary>
digit = nextByte[0]; /// Message type
value += (digit & 127) * multiplier; /// </summary>
multiplier *= 128; public byte Type
} while ((digit & 128) != 0); {
return value; get { return this.type; }
} set { this.type = value; }
}
/// <summary>
/// Duplicate message flag
/// </summary>
public bool DupFlag
{
get { return this.dupFlag; }
set { this.dupFlag = value; }
}
/// <summary>
/// Quality of Service level
/// </summary>
public byte QosLevel
{
get { return this.qosLevel; }
set { this.qosLevel = value; }
}
/// <summary>
/// Retain message flag
/// </summary>
public bool Retain
{
get { return this.retain; }
set { this.retain = value; }
}
/// <summary>
/// Message identifier for the message
/// </summary>
public ushort MessageId
{
get { return this.messageId; }
set { this.messageId = value; }
}
#endregion
// message type
protected byte type;
// duplicate delivery
protected bool dupFlag;
// quality of service level
protected byte qosLevel;
// retain flag
protected bool retain;
// message identifier
protected ushort messageId;
/// <summary>
/// Returns message bytes rapresentation
/// </summary>
/// <param name="protocolVersion">Protocol version</param>
/// <returns>Bytes rapresentation</returns>
public abstract byte[] GetBytes(byte protocolVersion);
/// <summary>
/// Encode remaining length and insert it into message buffer
/// </summary>
/// <param name="remainingLength">Remaining length value to encode</param>
/// <param name="buffer">Message buffer for inserting encoded value</param>
/// <param name="index">Index from which insert encoded value into buffer</param>
/// <returns>Index updated</returns>
protected int encodeRemainingLength(int remainingLength, byte[] buffer, int index)
{
int digit = 0;
do
{
digit = remainingLength % 128;
remainingLength /= 128;
if (remainingLength > 0)
digit = digit | 0x80;
buffer[index++] = (byte)digit;
} while (remainingLength > 0);
return index;
}
/// <summary>
/// Decode remaining length reading bytes from socket
/// </summary>
/// <param name="channel">Channel from reading bytes</param>
/// <returns>Decoded remaining length</returns>
protected static int decodeRemainingLength(IMqttNetworkChannel channel)
{
int multiplier = 1;
int value = 0;
int digit = 0;
byte[] nextByte = new byte[1];
do
{
// next digit from stream
channel.Receive(nextByte);
digit = nextByte[0];
value += ((digit & 127) * multiplier);
multiplier *= 128;
} while ((digit & 128) != 0);
return value;
}
#if TRACE #if TRACE
/// <summary> /// <summary>
/// Returns a string representation of the message for tracing /// Returns a string representation of the message for tracing
/// </summary> /// </summary>
/// <param name="name">Message name</param> /// <param name="name">Message name</param>
/// <param name="fieldNames">Message fields name</param> /// <param name="fieldNames">Message fields name</param>
/// <param name="fieldValues">Message fields value</param> /// <param name="fieldValues">Message fields value</param>
/// <returns>String representation of the message</returns> /// <returns>String representation of the message</returns>
protected String GetTraceString(String name, Object[] fieldNames, Object[] fieldValues) { protected string GetTraceString(string name, object[] fieldNames, object[] fieldValues)
StringBuilder sb = new StringBuilder(); {
_ = sb.Append(name); StringBuilder sb = new StringBuilder();
sb.Append(name);
if (fieldNames != null && fieldValues != null) {
_ = sb.Append("("); if ((fieldNames != null) && (fieldValues != null))
Boolean addComma = false; {
for (Int32 i = 0; i < fieldValues.Length; i++) { sb.Append("(");
if (fieldValues[i] != null) { bool addComma = false;
if (addComma) { for (int i = 0; i < fieldValues.Length; i++)
_ = sb.Append(","); {
} if (fieldValues[i] != null)
{
_ = sb.Append(fieldNames[i]); if (addComma)
_ = sb.Append(":"); {
_ = sb.Append(this.GetStringObject(fieldValues[i])); sb.Append(",");
addComma = true; }
}
} sb.Append(fieldNames[i]);
_ = sb.Append(")"); sb.Append(":");
} sb.Append(GetStringObject(fieldValues[i]));
addComma = true;
return sb.ToString(); }
} }
sb.Append(")");
Object GetStringObject(Object value) { }
if (value is Byte[] binary) {
String hexChars = "0123456789ABCDEF"; return sb.ToString();
StringBuilder sb = new StringBuilder(binary.Length * 2); }
for (Int32 i = 0; i < binary.Length; ++i) {
_ = sb.Append(hexChars[binary[i] >> 4]); object GetStringObject(object value)
_ = sb.Append(hexChars[binary[i] & 0x0F]); {
} byte[] binary = value as byte[];
if (binary != null)
return sb.ToString(); {
} string hexChars = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(binary.Length * 2);
if (value is Object[] list) { for (int i = 0; i < binary.Length; ++i)
StringBuilder sb = new StringBuilder(); {
_ = sb.Append('['); sb.Append(hexChars[binary[i] >> 4]);
for (Int32 i = 0; i < list.Length; ++i) { sb.Append(hexChars[binary[i] & 0x0F]);
if (i > 0) { }
_ = sb.Append(',');
} return sb.ToString();
}
_ = sb.Append(list[i]);
} object[] list = value as object[];
_ = sb.Append(']'); if (list != null)
{
return sb.ToString(); StringBuilder sb = new StringBuilder();
} sb.Append('[');
for (int i = 0; i < list.Length; ++i)
return value; {
} if (i > 0) sb.Append(',');
sb.Append(list[i]);
}
sb.Append(']');
return sb.ToString();
}
return value;
}
#endif #endif
} }
} }

View File

@ -17,153 +17,175 @@ Contributors:
using System; using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for CONNACK message from broker to client
/// </summary>
public class MqttMsgConnack : MqttMsgBase {
#region Constants...
// return codes for CONNACK message
public const Byte CONN_ACCEPTED = 0x00;
public const Byte CONN_REFUSED_PROT_VERS = 0x01;
public const Byte CONN_REFUSED_IDENT_REJECTED = 0x02;
public const Byte CONN_REFUSED_SERVER_UNAVAILABLE = 0x03;
public const Byte CONN_REFUSED_USERNAME_PASSWORD = 0x04;
public const Byte CONN_REFUSED_NOT_AUTHORIZED = 0x05;
//private const Byte TOPIC_NAME_COMP_RESP_BYTE_OFFSET = 0;
private const Byte TOPIC_NAME_COMP_RESP_BYTE_SIZE = 1;
// [v3.1.1] connect acknowledge flags replace "old" topic name compression respone (not used in 3.1)
private const Byte CONN_ACK_FLAGS_BYTE_OFFSET = 0;
private const Byte CONN_ACK_FLAGS_BYTE_SIZE = 1;
// [v3.1.1] session present flag
private const Byte SESSION_PRESENT_FLAG_MASK = 0x01;
private const Byte SESSION_PRESENT_FLAG_OFFSET = 0x00;
//private const Byte SESSION_PRESENT_FLAG_SIZE = 0x01;
private const Byte CONN_RETURN_CODE_BYTE_OFFSET = 1;
private const Byte CONN_RETURN_CODE_BYTE_SIZE = 1;
#endregion
#region Properties...
// [v3.1.1] session present flag
/// <summary> /// <summary>
/// Session present flag /// Class for CONNACK message from broker to client
/// </summary> /// </summary>
public Boolean SessionPresent { get; set; } public class MqttMsgConnack : MqttMsgBase
{
/// <summary> #region Constants...
/// Return Code
/// </summary> // return codes for CONNACK message
public Byte ReturnCode { get; set; } public const byte CONN_ACCEPTED = 0x00;
public const byte CONN_REFUSED_PROT_VERS = 0x01;
#endregion public const byte CONN_REFUSED_IDENT_REJECTED = 0x02;
public const byte CONN_REFUSED_SERVER_UNAVAILABLE = 0x03;
// [v3.1.1] session present flag public const byte CONN_REFUSED_USERNAME_PASSWORD = 0x04;
public const byte CONN_REFUSED_NOT_AUTHORIZED = 0x05;
/// <summary>
/// Constructor private const byte TOPIC_NAME_COMP_RESP_BYTE_OFFSET = 0;
/// </summary> private const byte TOPIC_NAME_COMP_RESP_BYTE_SIZE = 1;
public MqttMsgConnack() => this.Type = MQTT_MSG_CONNACK_TYPE; // [v3.1.1] connect acknowledge flags replace "old" topic name compression respone (not used in 3.1)
private const byte CONN_ACK_FLAGS_BYTE_OFFSET = 0;
/// <summary> private const byte CONN_ACK_FLAGS_BYTE_SIZE = 1;
/// Parse bytes for a CONNACK message // [v3.1.1] session present flag
/// </summary> private const byte SESSION_PRESENT_FLAG_MASK = 0x01;
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> private const byte SESSION_PRESENT_FLAG_OFFSET = 0x00;
/// <param name="protocolVersion">Protocol Version</param> private const byte SESSION_PRESENT_FLAG_SIZE = 0x01;
/// <param name="channel">Channel connected to the broker</param> private const byte CONN_RETURN_CODE_BYTE_OFFSET = 1;
/// <returns>CONNACK message instance</returns> private const byte CONN_RETURN_CODE_BYTE_SIZE = 1;
public static MqttMsgConnack Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) {
Byte[] buffer; #endregion
MqttMsgConnack msg = new MqttMsgConnack();
#region Properties...
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) {
// [v3.1.1] check flag bits // [v3.1.1] session present flag
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_CONNACK_FLAG_BITS) { /// <summary>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// Session present flag
} /// </summary>
} public bool SessionPresent
{
// get remaining length and allocate buffer get { return this.sessionPresent; }
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); set { this.sessionPresent = value; }
buffer = new Byte[remainingLength]; }
// read bytes from socket... /// <summary>
_ = channel.Receive(buffer); /// Return Code
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// </summary>
// [v3.1.1] ... set session present flag ... public byte ReturnCode
msg.SessionPresent = (buffer[CONN_ACK_FLAGS_BYTE_OFFSET] & SESSION_PRESENT_FLAG_MASK) != 0x00; {
} get { return this.returnCode; }
// ...and set return code from broker set { this.returnCode = value; }
msg.ReturnCode = buffer[CONN_RETURN_CODE_BYTE_OFFSET]; }
return msg; #endregion
}
// [v3.1.1] session present flag
public override Byte[] GetBytes(Byte ProtocolVersion) { private bool sessionPresent;
Int32 varHeaderSize = 0;
Int32 payloadSize = 0; // return code for CONNACK message
Int32 remainingLength = 0; private byte returnCode;
Byte[] buffer;
Int32 index = 0; /// <summary>
/// Constructor
if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// </summary>
// flags byte and connect return code public MqttMsgConnack()
varHeaderSize += CONN_ACK_FLAGS_BYTE_SIZE + CONN_RETURN_CODE_BYTE_SIZE; {
} else { this.type = MQTT_MSG_CONNACK_TYPE;
// topic name compression response and connect return code }
varHeaderSize += TOPIC_NAME_COMP_RESP_BYTE_SIZE + CONN_RETURN_CODE_BYTE_SIZE;
} /// <summary>
/// Parse bytes for a CONNACK message
remainingLength += varHeaderSize + payloadSize; /// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param>
// first byte of fixed header /// <param name="protocolVersion">Protocol Version</param>
Int32 fixedHeaderSize = 1; /// <param name="channel">Channel connected to the broker</param>
/// <returns>CONNACK message instance</returns>
Int32 temp = remainingLength; public static MqttMsgConnack Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
// increase fixed header size based on remaining length {
// (each remaining length byte can encode until 128) byte[] buffer;
do { MqttMsgConnack msg = new MqttMsgConnack();
fixedHeaderSize++;
temp /= 128; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
} while (temp > 0); {
// [v3.1.1] check flag bits
// allocate buffer for message if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_CONNACK_FLAG_BITS)
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize]; throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
}
// first fixed header byte
buffer[index++] = ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 // get remaining length and allocate buffer
? (Byte)((MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_CONNACK_FLAG_BITS) int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
: (Byte)(MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET); buffer = new byte[remainingLength];
// encode remaining length // read bytes from socket...
index = this.EncodeRemainingLength(remainingLength, buffer, index); channel.Receive(buffer);
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { {
// [v3.1.1] session present flag // [v3.1.1] ... set session present flag ...
buffer[index++] = this.SessionPresent ? (Byte)(1 << SESSION_PRESENT_FLAG_OFFSET) : (Byte)0x00; msg.sessionPresent = (buffer[CONN_ACK_FLAGS_BYTE_OFFSET] & SESSION_PRESENT_FLAG_MASK) != 0x00;
} else { }
// topic name compression response (reserved values. not used); // ...and set return code from broker
buffer[index++] = 0x00; msg.returnCode = buffer[CONN_RETURN_CODE_BYTE_OFFSET];
}
return msg;
// connect return code }
buffer[index++] = this.ReturnCode;
public override byte[] GetBytes(byte ProtocolVersion)
return buffer; {
} int fixedHeaderSize = 0;
int varHeaderSize = 0;
public override String ToString() => int payloadSize = 0;
int remainingLength = 0;
byte[] buffer;
int index = 0;
if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
// flags byte and connect return code
varHeaderSize += (CONN_ACK_FLAGS_BYTE_SIZE + CONN_RETURN_CODE_BYTE_SIZE);
else
// topic name compression response and connect return code
varHeaderSize += (TOPIC_NAME_COMP_RESP_BYTE_SIZE + CONN_RETURN_CODE_BYTE_SIZE);
remainingLength += (varHeaderSize + payloadSize);
// first byte of fixed header
fixedHeaderSize = 1;
int temp = remainingLength;
// increase fixed header size based on remaining length
// (each remaining length byte can encode until 128)
do
{
fixedHeaderSize++;
temp = temp / 128;
} while (temp > 0);
// allocate buffer for message
buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
// first fixed header byte
if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index++] = (MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_CONNACK_FLAG_BITS; // [v.3.1.1]
else
buffer[index++] = (byte)(MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET);
// encode remaining length
index = this.encodeRemainingLength(remainingLength, buffer, index);
if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
// [v3.1.1] session present flag
buffer[index++] = this.sessionPresent ? (byte)(1 << SESSION_PRESENT_FLAG_OFFSET) : (byte)0x00;
else
// topic name compression response (reserved values. not used);
buffer[index++] = 0x00;
// connect return code
buffer[index++] = this.returnCode;
return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"CONNACK", "CONNACK",
new Object[] { "returnCode" }, new object[] { "returnCode" },
new Object[] { this.ReturnCode }); new object[] { this.returnCode });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -14,26 +14,31 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for CONNECT message received from client
/// </summary>
public class MqttMsgConnectEventArgs : EventArgs {
/// <summary> /// <summary>
/// Message received from client /// Event Args class for CONNECT message received from client
/// </summary> /// </summary>
public MqttMsgConnect Message { get; private set; } public class MqttMsgConnectEventArgs : EventArgs
{
/// <summary> /// <summary>
/// Constructor /// Message received from client
/// </summary> /// </summary>
/// <param name="msg">CONNECT message received from client</param> public MqttMsgConnect Message { get; private set; }
public MqttMsgConnectEventArgs(MqttMsgConnect connect) => this.Message = connect;
} /// <summary>
} /// Constructor
/// </summary>
/// <param name="msg">CONNECT message received from client</param>
public MqttMsgConnectEventArgs(MqttMsgConnect connect)
{
this.Message = connect;
}
}
}

View File

@ -15,137 +15,145 @@ Contributors:
*/ */
using System; using System;
using System.Text;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Context for MQTT message
/// </summary>
public class MqttMsgContext {
/// <summary> /// <summary>
/// MQTT message /// Context for MQTT message
/// </summary> /// </summary>
public MqttMsgBase Message { get; set; } public class MqttMsgContext
{
/// <summary> /// <summary>
/// MQTT message state /// MQTT message
/// </summary> /// </summary>
public MqttMsgState State { get; set; } public MqttMsgBase Message { get; set; }
/// <summary>
/// MQTT message state
/// </summary>
public MqttMsgState State { get; set; }
/// <summary>
/// Flow of the message
/// </summary>
public MqttMsgFlow Flow { get; set; }
/// <summary>
/// Timestamp in ticks (for retry)
/// </summary>
public int Timestamp { get; set; }
/// <summary>
/// Attempt (for retry)
/// </summary>
public int Attempt { get; set; }
/// <summary>
/// Unique key
/// </summary>
public string Key
{
get { return this.Flow + "_" + this.Message.MessageId; }
}
}
/// <summary> /// <summary>
/// Flow of the message /// Flow of the message
/// </summary> /// </summary>
public MqttMsgFlow Flow { get; set; } public enum MqttMsgFlow
{
/// <summary>
/// To publish to subscribers
/// </summary>
ToPublish,
/// <summary>
/// To acknowledge to publisher
/// </summary>
ToAcknowledge
}
/// <summary> /// <summary>
/// Timestamp in ticks (for retry) /// MQTT message state
/// </summary> /// </summary>
public Int32 Timestamp { get; set; } public enum MqttMsgState
{
/// <summary> /// <summary>
/// Attempt (for retry) /// QOS = 0, Message queued
/// </summary> /// </summary>
public Int32 Attempt { get; set; } QueuedQos0,
/// <summary> /// <summary>
/// Unique key /// QOS = 1, Message queued
/// </summary> /// </summary>
public String Key => this.Flow + "_" + this.Message.MessageId; QueuedQos1,
}
/// <summary>
/// <summary> /// QOS = 2, Message queued
/// Flow of the message /// </summary>
/// </summary> QueuedQos2,
public enum MqttMsgFlow {
/// <summary> /// <summary>
/// To publish to subscribers /// QOS = 1, PUBLISH sent, wait for PUBACK
/// </summary> /// </summary>
ToPublish, WaitForPuback,
/// <summary> /// <summary>
/// To acknowledge to publisher /// QOS = 2, PUBLISH sent, wait for PUBREC
/// </summary> /// </summary>
ToAcknowledge WaitForPubrec,
}
/// <summary>
/// <summary> /// QOS = 2, PUBREC sent, wait for PUBREL
/// MQTT message state /// </summary>
/// </summary> WaitForPubrel,
public enum MqttMsgState {
/// <summary> /// <summary>
/// QOS = 0, Message queued /// QOS = 2, PUBREL sent, wait for PUBCOMP
/// </summary> /// </summary>
QueuedQos0, WaitForPubcomp,
/// <summary> /// <summary>
/// QOS = 1, Message queued /// QOS = 2, start first phase handshake send PUBREC
/// </summary> /// </summary>
QueuedQos1, SendPubrec,
/// <summary> /// <summary>
/// QOS = 2, Message queued /// QOS = 2, start second phase handshake send PUBREL
/// </summary> /// </summary>
QueuedQos2, SendPubrel,
/// <summary> /// <summary>
/// QOS = 1, PUBLISH sent, wait for PUBACK /// QOS = 2, end second phase handshake send PUBCOMP
/// </summary> /// </summary>
WaitForPuback, SendPubcomp,
/// <summary> /// <summary>
/// QOS = 2, PUBLISH sent, wait for PUBREC /// QOS = 1, PUBLISH received, send PUBACK
/// </summary> /// </summary>
WaitForPubrec, SendPuback,
/// <summary> // [v3.1.1] SUBSCRIBE isn't "officially" QOS = 1
/// QOS = 2, PUBREC sent, wait for PUBREL /// <summary>
/// </summary> /// Send SUBSCRIBE message
WaitForPubrel, /// </summary>
SendSubscribe,
/// <summary>
/// QOS = 2, PUBREL sent, wait for PUBCOMP // [v3.1.1] UNSUBSCRIBE isn't "officially" QOS = 1
/// </summary> /// <summary>
WaitForPubcomp, /// Send UNSUBSCRIBE message
/// </summary>
/// <summary> SendUnsubscribe,
/// QOS = 2, start first phase handshake send PUBREC
/// </summary> /// <summary>
SendPubrec, /// (QOS = 1), SUBSCRIBE sent, wait for SUBACK
/// </summary>
/// <summary> WaitForSuback,
/// QOS = 2, start second phase handshake send PUBREL
/// </summary> /// <summary>
SendPubrel, /// (QOS = 1), UNSUBSCRIBE sent, wait for UNSUBACK
/// </summary>
/// <summary> WaitForUnsuback
/// QOS = 2, end second phase handshake send PUBCOMP }
/// </summary>
SendPubcomp,
/// <summary>
/// QOS = 1, PUBLISH received, send PUBACK
/// </summary>
SendPuback,
// [v3.1.1] SUBSCRIBE isn't "officially" QOS = 1
/// <summary>
/// Send SUBSCRIBE message
/// </summary>
SendSubscribe,
// [v3.1.1] UNSUBSCRIBE isn't "officially" QOS = 1
/// <summary>
/// Send UNSUBSCRIBE message
/// </summary>
SendUnsubscribe,
/// <summary>
/// (QOS = 1), SUBSCRIBE sent, wait for SUBACK
/// </summary>
WaitForSuback,
/// <summary>
/// (QOS = 1), UNSUBSCRIBE sent, wait for UNSUBACK
/// </summary>
WaitForUnsuback
}
} }

View File

@ -14,66 +14,73 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for DISCONNECT message from client to broker
/// </summary>
public class MqttMsgDisconnect : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for DISCONNECT message from client to broker
/// </summary> /// </summary>
public MqttMsgDisconnect() => this.Type = MQTT_MSG_DISCONNECT_TYPE; public class MqttMsgDisconnect : MqttMsgBase
{
/// <summary> /// <summary>
/// Parse bytes for a DISCONNECT message /// Constructor
/// </summary> /// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> public MqttMsgDisconnect()
/// <param name="protocolVersion">Protocol Version</param> {
/// <param name="channel">Channel connected to the broker</param> this.type = MQTT_MSG_DISCONNECT_TYPE;
/// <returns>DISCONNECT message instance</returns> }
public static MqttMsgDisconnect Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) {
MqttMsgDisconnect msg = new MqttMsgDisconnect(); /// <summary>
/// Parse bytes for a DISCONNECT message
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// </summary>
// [v3.1.1] check flag bits /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_DISCONNECT_FLAG_BITS) { /// <param name="protocolVersion">Protocol Version</param>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="channel">Channel connected to the broker</param>
} /// <returns>DISCONNECT message instance</returns>
} public static MqttMsgDisconnect Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
{
// get remaining length and allocate buffer MqttMsgDisconnect msg = new MqttMsgDisconnect();
_ = DecodeRemainingLength(channel);
// NOTE : remainingLength must be 0 if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
{
return msg; // [v3.1.1] check flag bits
} if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_DISCONNECT_FLAG_BITS)
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
public override Byte[] GetBytes(Byte protocolVersion) { }
Byte[] buffer = new Byte[2];
Int32 index = 0; // get remaining length and allocate buffer
int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
// first fixed header byte // NOTE : remainingLength must be 0
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1
? (Byte)((MQTT_MSG_DISCONNECT_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_DISCONNECT_FLAG_BITS) return msg;
: (Byte)(MQTT_MSG_DISCONNECT_TYPE << MSG_TYPE_OFFSET); }
buffer[index++] = 0x00; public override byte[] GetBytes(byte protocolVersion)
{
return buffer; byte[] buffer = new byte[2];
} int index = 0;
public override String ToString() => // first fixed header byte
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index++] = (MQTT_MSG_DISCONNECT_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_DISCONNECT_FLAG_BITS; // [v.3.1.1]
else
buffer[index++] = (MQTT_MSG_DISCONNECT_TYPE << MSG_TYPE_OFFSET);
buffer[index++] = 0x00;
return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"DISCONNECT", "DISCONNECT",
null, null,
null); null);
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -14,66 +14,73 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for PINGREQ message from client to broker
/// </summary>
public class MqttMsgPingReq : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for PINGREQ message from client to broker
/// </summary> /// </summary>
public MqttMsgPingReq() => this.Type = MQTT_MSG_PINGREQ_TYPE; public class MqttMsgPingReq : MqttMsgBase
{
public override Byte[] GetBytes(Byte protocolVersion) { /// <summary>
Byte[] buffer = new Byte[2]; /// Constructor
Int32 index = 0; /// </summary>
public MqttMsgPingReq()
// first fixed header byte {
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 this.type = MQTT_MSG_PINGREQ_TYPE;
? (Byte)((MQTT_MSG_PINGREQ_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PINGREQ_FLAG_BITS) }
: (Byte)(MQTT_MSG_PINGREQ_TYPE << MSG_TYPE_OFFSET);
public override byte[] GetBytes(byte protocolVersion)
buffer[index++] = 0x00; {
byte[] buffer = new byte[2];
return buffer; int index = 0;
}
// first fixed header byte
/// <summary> if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
/// Parse bytes for a PINGREQ message buffer[index++] = (MQTT_MSG_PINGREQ_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PINGREQ_FLAG_BITS; // [v.3.1.1]
/// </summary> else
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> buffer[index++] = (MQTT_MSG_PINGREQ_TYPE << MSG_TYPE_OFFSET);
/// <param name="protocolVersion">Protocol Version</param> buffer[index++] = 0x00;
/// <param name="channel">Channel connected to the broker</param>
/// <returns>PINGREQ message instance</returns> return buffer;
public static MqttMsgPingReq Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { }
MqttMsgPingReq msg = new MqttMsgPingReq();
/// <summary>
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// Parse bytes for a PINGREQ message
// [v3.1.1] check flag bits /// </summary>
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGREQ_FLAG_BITS) { /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="protocolVersion">Protocol Version</param>
} /// <param name="channel">Channel connected to the broker</param>
} /// <returns>PINGREQ message instance</returns>
public static MqttMsgPingReq Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
// already know remaininglength is zero (MQTT specification), {
// so it isn't necessary to read other data from socket MqttMsgPingReq msg = new MqttMsgPingReq();
_ = DecodeRemainingLength(channel);
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
return msg; {
} // [v3.1.1] check flag bits
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGREQ_FLAG_BITS)
public override String ToString() => throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
}
// already know remaininglength is zero (MQTT specification),
// so it isn't necessary to read other data from socket
int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
return msg;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PINGREQ", "PINGREQ",
null, null,
null); null);
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -17,63 +17,71 @@ Contributors:
using System; using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for PINGRESP message from client to broker
/// </summary>
public class MqttMsgPingResp : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for PINGRESP message from client to broker
/// </summary> /// </summary>
public MqttMsgPingResp() => this.Type = MQTT_MSG_PINGRESP_TYPE; public class MqttMsgPingResp : MqttMsgBase
{
/// <summary> /// <summary>
/// Parse bytes for a PINGRESP message /// Constructor
/// </summary> /// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> public MqttMsgPingResp()
/// <param name="protocolVersion">Protocol Version</param> {
/// <param name="channel">Channel connected to the broker</param> this.type = MQTT_MSG_PINGRESP_TYPE;
/// <returns>PINGRESP message instance</returns> }
public static MqttMsgPingResp Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) {
MqttMsgPingResp msg = new MqttMsgPingResp(); /// <summary>
/// Parse bytes for a PINGRESP message
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// </summary>
// [v3.1.1] check flag bits /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGRESP_FLAG_BITS) { /// <param name="protocolVersion">Protocol Version</param>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="channel">Channel connected to the broker</param>
} /// <returns>PINGRESP message instance</returns>
} public static MqttMsgPingResp Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
{
// already know remaininglength is zero (MQTT specification), MqttMsgPingResp msg = new MqttMsgPingResp();
// so it isn't necessary to read other data from socket
_ = DecodeRemainingLength(channel); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
{
return msg; // [v3.1.1] check flag bits
} if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGRESP_FLAG_BITS)
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
public override Byte[] GetBytes(Byte protocolVersion) { }
Byte[] buffer = new Byte[2];
Int32 index = 0; // already know remaininglength is zero (MQTT specification),
// so it isn't necessary to read other data from socket
// first fixed header byte int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1
? (Byte)((MQTT_MSG_PINGRESP_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PINGRESP_FLAG_BITS) return msg;
: (Byte)(MQTT_MSG_PINGRESP_TYPE << MSG_TYPE_OFFSET); }
buffer[index++] = 0x00; public override byte[] GetBytes(byte protocolVersion)
{
return buffer; byte[] buffer = new byte[2];
} int index = 0;
public override String ToString() => // first fixed header byte
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index++] = (MQTT_MSG_PINGRESP_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PINGRESP_FLAG_BITS; // [v.3.1.1]
else
buffer[index++] = (MQTT_MSG_PINGRESP_TYPE << MSG_TYPE_OFFSET);
buffer[index++] = 0x00;
return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PINGRESP", "PINGRESP",
null, null,
null); null);
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -14,102 +14,112 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for PUBACK message from broker to client
/// </summary>
public class MqttMsgPuback : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for PUBACK message from broker to client
/// </summary> /// </summary>
public MqttMsgPuback() => this.Type = MQTT_MSG_PUBACK_TYPE; public class MqttMsgPuback : MqttMsgBase
{
public override Byte[] GetBytes(Byte protocolVersion) { /// <summary>
Int32 varHeaderSize = 0; /// Constructor
Int32 payloadSize = 0; /// </summary>
Int32 remainingLength = 0; public MqttMsgPuback()
Byte[] buffer; {
Int32 index = 0; this.type = MQTT_MSG_PUBACK_TYPE;
}
// message identifier
varHeaderSize += MESSAGE_ID_SIZE; public override byte[] GetBytes(byte protocolVersion)
{
remainingLength += varHeaderSize + payloadSize; int fixedHeaderSize = 0;
int varHeaderSize = 0;
// first byte of fixed header int payloadSize = 0;
Int32 fixedHeaderSize = 1; int remainingLength = 0;
byte[] buffer;
Int32 temp = remainingLength; int index = 0;
// increase fixed header size based on remaining length
// (each remaining length byte can encode until 128) // message identifier
do { varHeaderSize += MESSAGE_ID_SIZE;
fixedHeaderSize++;
temp /= 128; remainingLength += (varHeaderSize + payloadSize);
} while (temp > 0);
// first byte of fixed header
// allocate buffer for message fixedHeaderSize = 1;
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize];
int temp = remainingLength;
// first fixed header byte // increase fixed header size based on remaining length
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 // (each remaining length byte can encode until 128)
? (Byte)((MQTT_MSG_PUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBACK_FLAG_BITS) do
: (Byte)(MQTT_MSG_PUBACK_TYPE << MSG_TYPE_OFFSET); {
fixedHeaderSize++;
// encode remaining length temp = temp / 128;
index = this.EncodeRemainingLength(remainingLength, buffer, index); } while (temp > 0);
// get message identifier // allocate buffer for message
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB
// first fixed header byte
return buffer; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
} buffer[index++] = (MQTT_MSG_PUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBACK_FLAG_BITS; // [v.3.1.1]
else
/// <summary> buffer[index++] = (MQTT_MSG_PUBACK_TYPE << MSG_TYPE_OFFSET);
/// Parse bytes for a PUBACK message
/// </summary> // encode remaining length
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> index = this.encodeRemainingLength(remainingLength, buffer, index);
/// <param name="protocolVersion">Protocol Version</param>
/// <param name="channel">Channel connected to the broker</param> // get message identifier
/// <returns>PUBACK message instance</returns> buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
public static MqttMsgPuback Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
Byte[] buffer;
Int32 index = 0; return buffer;
MqttMsgPuback msg = new MqttMsgPuback(); }
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// <summary>
// [v3.1.1] check flag bits /// Parse bytes for a PUBACK message
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBACK_FLAG_BITS) { /// </summary>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
} /// <param name="protocolVersion">Protocol Version</param>
} /// <param name="channel">Channel connected to the broker</param>
/// <returns>PUBACK message instance</returns>
// get remaining length and allocate buffer public static MqttMsgPuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); {
buffer = new Byte[remainingLength]; byte[] buffer;
int index = 0;
// read bytes from socket... MqttMsgPuback msg = new MqttMsgPuback();
_ = channel.Receive(buffer);
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
// message id {
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00); // [v3.1.1] check flag bits
msg.MessageId |= buffer[index++]; if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBACK_FLAG_BITS)
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
return msg; }
}
// get remaining length and allocate buffer
public override String ToString() => int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
buffer = new byte[remainingLength];
// read bytes from socket...
channel.Receive(buffer);
// message id
msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
msg.messageId |= (buffer[index++]);
return msg;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PUBACK", "PUBACK",
new Object[] { "messageId" }, new object[] { "messageId" },
new Object[] { this.MessageId }); new object[] { this.messageId });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -14,102 +14,112 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for PUBCOMP message from broker to client
/// </summary>
public class MqttMsgPubcomp : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for PUBCOMP message from broker to client
/// </summary> /// </summary>
public MqttMsgPubcomp() => this.Type = MQTT_MSG_PUBCOMP_TYPE; public class MqttMsgPubcomp : MqttMsgBase
{
public override Byte[] GetBytes(Byte protocolVersion) { /// <summary>
Int32 varHeaderSize = 0; /// Constructor
Int32 payloadSize = 0; /// </summary>
Int32 remainingLength = 0; public MqttMsgPubcomp()
Byte[] buffer; {
Int32 index = 0; this.type = MQTT_MSG_PUBCOMP_TYPE;
}
// message identifier
varHeaderSize += MESSAGE_ID_SIZE; public override byte[] GetBytes(byte protocolVersion)
{
remainingLength += varHeaderSize + payloadSize; int fixedHeaderSize = 0;
int varHeaderSize = 0;
// first byte of fixed header int payloadSize = 0;
Int32 fixedHeaderSize = 1; int remainingLength = 0;
byte[] buffer;
Int32 temp = remainingLength; int index = 0;
// increase fixed header size based on remaining length
// (each remaining length byte can encode until 128) // message identifier
do { varHeaderSize += MESSAGE_ID_SIZE;
fixedHeaderSize++;
temp /= 128; remainingLength += (varHeaderSize + payloadSize);
} while (temp > 0);
// first byte of fixed header
// allocate buffer for message fixedHeaderSize = 1;
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize];
int temp = remainingLength;
// first fixed header byte // increase fixed header size based on remaining length
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 // (each remaining length byte can encode until 128)
? (Byte)((MQTT_MSG_PUBCOMP_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBCOMP_FLAG_BITS) do
: (Byte)(MQTT_MSG_PUBCOMP_TYPE << MSG_TYPE_OFFSET); {
fixedHeaderSize++;
// encode remaining length temp = temp / 128;
index = this.EncodeRemainingLength(remainingLength, buffer, index); } while (temp > 0);
// get message identifier // allocate buffer for message
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB
// first fixed header byte
return buffer; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
} buffer[index++] = (MQTT_MSG_PUBCOMP_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBCOMP_FLAG_BITS; // [v.3.1.1]
else
/// <summary> buffer[index++] = (MQTT_MSG_PUBCOMP_TYPE << MSG_TYPE_OFFSET);
/// Parse bytes for a PUBCOMP message
/// </summary> // encode remaining length
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> index = this.encodeRemainingLength(remainingLength, buffer, index);
/// <param name="protocolVersion">Protocol Version</param>
/// <param name="channel">Channel connected to the broker</param> // get message identifier
/// <returns>PUBCOMP message instance</returns> buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
public static MqttMsgPubcomp Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
Byte[] buffer;
Int32 index = 0; return buffer;
MqttMsgPubcomp msg = new MqttMsgPubcomp(); }
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// <summary>
// [v3.1.1] check flag bits /// Parse bytes for a PUBCOMP message
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBCOMP_FLAG_BITS) { /// </summary>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
} /// <param name="protocolVersion">Protocol Version</param>
} /// <param name="channel">Channel connected to the broker</param>
/// <returns>PUBCOMP message instance</returns>
// get remaining length and allocate buffer public static MqttMsgPubcomp Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); {
buffer = new Byte[remainingLength]; byte[] buffer;
int index = 0;
// read bytes from socket... MqttMsgPubcomp msg = new MqttMsgPubcomp();
_ = channel.Receive(buffer);
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
// message id {
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00); // [v3.1.1] check flag bits
msg.MessageId |= buffer[index++]; if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBCOMP_FLAG_BITS)
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
return msg; }
}
// get remaining length and allocate buffer
public override String ToString() => int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
buffer = new byte[remainingLength];
// read bytes from socket...
channel.Receive(buffer);
// message id
msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
msg.messageId |= (buffer[index++]);
return msg;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PUBCOMP", "PUBCOMP",
new Object[] { "messageId" }, new object[] { "messageId" },
new Object[] { this.MessageId }); new object[] { this.messageId });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -40,7 +40,9 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public MqttMsgPublish() => this.Type = MQTT_MSG_PUBLISH_TYPE; public MqttMsgPublish() {
this.type = MQTT_MSG_PUBLISH_TYPE;
}
/// <summary> /// <summary>
/// Constructor /// Constructor
@ -59,16 +61,17 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
/// <param name="qosLevel">Quality of Service level</param> /// <param name="qosLevel">Quality of Service level</param>
/// <param name="retain">Retain flag</param> /// <param name="retain">Retain flag</param>
public MqttMsgPublish(String topic, Byte[] message, Boolean dupFlag, Byte qosLevel, Boolean retain) : base() { public MqttMsgPublish(String topic, Byte[] message, Boolean dupFlag, Byte qosLevel, Boolean retain) : base() {
this.Type = MQTT_MSG_PUBLISH_TYPE; this.type = MQTT_MSG_PUBLISH_TYPE;
this.Topic = topic; this.Topic = topic;
this.Message = message; this.Message = message;
this.DupFlag = dupFlag; this.dupFlag = dupFlag;
this.QosLevel = qosLevel; this.qosLevel = qosLevel;
this.Retain = retain; this.retain = retain;
this.MessageId = 0; this.messageId = 0;
} }
public override Byte[] GetBytes(Byte protocolVersion) { public override Byte[] GetBytes(Byte protocolVersion) {
Int32 fixedHeaderSize = 0;
Int32 varHeaderSize = 0; Int32 varHeaderSize = 0;
Int32 payloadSize = 0; Int32 payloadSize = 0;
Int32 remainingLength = 0; Int32 remainingLength = 0;
@ -76,17 +79,17 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
Int32 index = 0; Int32 index = 0;
// topic can't contain wildcards // topic can't contain wildcards
if (this.Topic.IndexOf('#') != -1 || this.Topic.IndexOf('+') != -1) { if ((this.Topic.IndexOf('#') != -1) || (this.Topic.IndexOf('+') != -1)) {
throw new MqttClientException(MqttClientErrorCode.TopicWildcard); throw new MqttClientException(MqttClientErrorCode.TopicWildcard);
} }
// check topic length // check topic length
if (this.Topic.Length < MIN_TOPIC_LENGTH || this.Topic.Length > MAX_TOPIC_LENGTH) { if ((this.Topic.Length < MIN_TOPIC_LENGTH) || (this.Topic.Length > MAX_TOPIC_LENGTH)) {
throw new MqttClientException(MqttClientErrorCode.TopicLength); throw new MqttClientException(MqttClientErrorCode.TopicLength);
} }
// check wrong QoS level (both bits can't be set 1) // check wrong QoS level (both bits can't be set 1)
if (this.QosLevel > QOS_LEVEL_EXACTLY_ONCE) { if (this.qosLevel > QOS_LEVEL_EXACTLY_ONCE) {
throw new MqttClientException(MqttClientErrorCode.QosNotAllowed); throw new MqttClientException(MqttClientErrorCode.QosNotAllowed);
} }
@ -96,7 +99,7 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
varHeaderSize += topicUtf8.Length + 2; varHeaderSize += topicUtf8.Length + 2;
// message id is valid only with QOS level 1 or QOS level 2 // message id is valid only with QOS level 1 or QOS level 2
if (this.QosLevel == QOS_LEVEL_AT_LEAST_ONCE || this.QosLevel == QOS_LEVEL_EXACTLY_ONCE) { if ((this.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) || (this.qosLevel == QOS_LEVEL_EXACTLY_ONCE)) {
varHeaderSize += MESSAGE_ID_SIZE; varHeaderSize += MESSAGE_ID_SIZE;
} }
@ -106,30 +109,30 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
payloadSize += this.Message.Length; payloadSize += this.Message.Length;
} }
remainingLength += varHeaderSize + payloadSize; remainingLength += (varHeaderSize + payloadSize);
// first byte of fixed header // first byte of fixed header
Int32 fixedHeaderSize = 1; fixedHeaderSize = 1;
Int32 temp = remainingLength; Int32 temp = remainingLength;
// increase fixed header size based on remaining length // increase fixed header size based on remaining length
// (each remaining length byte can encode until 128) // (each remaining length byte can encode until 128)
do { do {
fixedHeaderSize++; fixedHeaderSize++;
temp /= 128; temp = temp / 128;
} while (temp > 0); } while (temp > 0);
// allocate buffer for message // allocate buffer for message
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize]; buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize];
// first fixed header byte // first fixed header byte
buffer[index] = (Byte)((MQTT_MSG_PUBLISH_TYPE << MSG_TYPE_OFFSET) | (this.QosLevel << QOS_LEVEL_OFFSET)); buffer[index] = (Byte)((MQTT_MSG_PUBLISH_TYPE << MSG_TYPE_OFFSET) | (this.qosLevel << QOS_LEVEL_OFFSET));
buffer[index] |= this.DupFlag ? (Byte)(1 << DUP_FLAG_OFFSET) : (Byte)0x00; buffer[index] |= this.dupFlag ? (Byte)(1 << DUP_FLAG_OFFSET) : (Byte)0x00;
buffer[index] |= this.Retain ? (Byte)(1 << RETAIN_FLAG_OFFSET) : (Byte)0x00; buffer[index] |= this.retain ? (Byte)(1 << RETAIN_FLAG_OFFSET) : (Byte)0x00;
index++; index++;
// encode remaining length // encode remaining length
index = this.EncodeRemainingLength(remainingLength, buffer, index); index = this.encodeRemainingLength(remainingLength, buffer, index);
// topic name // topic name
buffer[index++] = (Byte)((topicUtf8.Length >> 8) & 0x00FF); // MSB buffer[index++] = (Byte)((topicUtf8.Length >> 8) & 0x00FF); // MSB
@ -138,22 +141,22 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
index += topicUtf8.Length; index += topicUtf8.Length;
// message id is valid only with QOS level 1 or QOS level 2 // message id is valid only with QOS level 1 or QOS level 2
if (this.QosLevel == QOS_LEVEL_AT_LEAST_ONCE || if ((this.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) ||
this.QosLevel == QOS_LEVEL_EXACTLY_ONCE) { (this.qosLevel == QOS_LEVEL_EXACTLY_ONCE)) {
// check message identifier assigned // check message identifier assigned
if (this.MessageId == 0) { if (this.messageId == 0) {
throw new MqttClientException(MqttClientErrorCode.WrongMessageId); throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
} }
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB buffer[index++] = (Byte)((this.messageId >> 8) & 0x00FF); // MSB
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB buffer[index++] = (Byte)(this.messageId & 0x00FF); // LSB
} }
// check on message with zero length // check on message with zero length
if (this.Message != null) { if (this.Message != null) {
// message data // message data
Array.Copy(this.Message, 0, buffer, index, this.Message.Length); Array.Copy(this.Message, 0, buffer, index, this.Message.Length);
_ = this.Message.Length; index += this.Message.Length;
} }
return buffer; return buffer;
@ -174,14 +177,14 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
MqttMsgPublish msg = new MqttMsgPublish(); MqttMsgPublish msg = new MqttMsgPublish();
// get remaining length and allocate buffer // get remaining length and allocate buffer
Int32 remainingLength = DecodeRemainingLength(channel); Int32 remainingLength = decodeRemainingLength(channel);
buffer = new Byte[remainingLength]; buffer = new Byte[remainingLength];
// read bytes from socket... // read bytes from socket...
Int32 received = channel.Receive(buffer); Int32 received = channel.Receive(buffer);
// topic name // topic name
topicUtf8Length = (buffer[index++] << 8) & 0xFF00; topicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
topicUtf8Length |= buffer[index++]; topicUtf8Length |= buffer[index++];
topicUtf8 = new Byte[topicUtf8Length]; topicUtf8 = new Byte[topicUtf8Length];
Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length); Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length);
@ -189,22 +192,22 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
msg.Topic = new String(Encoding.UTF8.GetChars(topicUtf8)); msg.Topic = new String(Encoding.UTF8.GetChars(topicUtf8));
// read QoS level from fixed header // read QoS level from fixed header
msg.QosLevel = (Byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); msg.qosLevel = (Byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
// check wrong QoS level (both bits can't be set 1) // check wrong QoS level (both bits can't be set 1)
if (msg.QosLevel > QOS_LEVEL_EXACTLY_ONCE) { if (msg.qosLevel > QOS_LEVEL_EXACTLY_ONCE) {
throw new MqttClientException(MqttClientErrorCode.QosNotAllowed); throw new MqttClientException(MqttClientErrorCode.QosNotAllowed);
} }
// read DUP flag from fixed header // read DUP flag from fixed header
msg.DupFlag = (fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET == 0x01; msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
// read retain flag from fixed header // read retain flag from fixed header
msg.Retain = (fixedHeaderFirstByte & RETAIN_FLAG_MASK) >> RETAIN_FLAG_OFFSET == 0x01; msg.retain = (((fixedHeaderFirstByte & RETAIN_FLAG_MASK) >> RETAIN_FLAG_OFFSET) == 0x01);
// message id is valid only with QOS level 1 or QOS level 2 // message id is valid only with QOS level 1 or QOS level 2
if (msg.QosLevel == QOS_LEVEL_AT_LEAST_ONCE || if ((msg.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) ||
msg.QosLevel == QOS_LEVEL_EXACTLY_ONCE) { (msg.qosLevel == QOS_LEVEL_EXACTLY_ONCE)) {
// message id // message id
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00); msg.messageId = (UInt16)((buffer[index++] << 8) & 0xFF00);
msg.MessageId |= buffer[index++]; msg.messageId |= (buffer[index++]);
} }
// get payload with message data // get payload with message data
@ -217,8 +220,8 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
// copy first part of payload data received // copy first part of payload data received
Array.Copy(buffer, index, msg.Message, messageOffset, received - index); Array.Copy(buffer, index, msg.Message, messageOffset, received - index);
remaining -= received - index; remaining -= (received - index);
messageOffset += received - index; messageOffset += (received - index);
// if payload isn't finished // if payload isn't finished
while (remaining > 0) { while (remaining > 0) {
@ -232,15 +235,15 @@ namespace uPLibrary.Networking.M2Mqtt.Messages {
return msg; return msg;
} }
public override String ToString() => public override String ToString() {
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PUBLISH", "PUBLISH",
new Object[] { "messageId", "topic", "message" }, new Object[] { "messageId", "topic", "message" },
new Object[] { this.MessageId, this.Topic, this.Message }); new Object[] { this.messageId, this.Topic, this.Message });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -14,66 +14,98 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for PUBLISH message received from broker
/// </summary>
public class MqttMsgPublishEventArgs : EventArgs {
#region Properties...
/// <summary> /// <summary>
/// Message topic /// Event Args class for PUBLISH message received from broker
/// </summary> /// </summary>
public String Topic { get; internal set; } public class MqttMsgPublishEventArgs : EventArgs
{
/// <summary> #region Properties...
/// Message data
/// </summary> /// <summary>
public Byte[] Message { get; internal set; } /// Message topic
/// </summary>
/// <summary> public string Topic
/// Duplicate message flag {
/// </summary> get { return this.topic; }
public Boolean DupFlag { get; set; } internal set { this.topic = value; }
}
/// <summary>
/// Quality of Service level /// <summary>
/// </summary> /// Message data
public Byte QosLevel { get; internal set; } /// </summary>
public byte[] Message
/// <summary> {
/// Retain message flag get { return this.message; }
/// </summary> internal set { this.message = value; }
public Boolean Retain { get; internal set; } }
#endregion /// <summary>
/// Duplicate message flag
// message topic /// </summary>
public bool DupFlag
/// <summary> {
/// Constructor get { return this.dupFlag; }
/// </summary> set { this.dupFlag = value; }
/// <param name="topic">Message topic</param> }
/// <param name="message">Message data</param>
/// <param name="dupFlag">Duplicate delivery flag</param> /// <summary>
/// <param name="qosLevel">Quality of Service level</param> /// Quality of Service level
/// <param name="retain">Retain flag</param> /// </summary>
public MqttMsgPublishEventArgs(String topic, public byte QosLevel
Byte[] message, {
Boolean dupFlag, get { return this.qosLevel; }
Byte qosLevel, internal set { this.qosLevel = value; }
Boolean retain) { }
this.Topic = topic;
this.Message = message; /// <summary>
this.DupFlag = dupFlag; /// Retain message flag
this.QosLevel = qosLevel; /// </summary>
this.Retain = retain; public bool Retain
} {
} get { return this.retain; }
internal set { this.retain = value; }
}
#endregion
// message topic
private string topic;
// message data
private byte[] message;
// duplicate delivery
private bool dupFlag;
// quality of service level
private byte qosLevel;
// retain flag
private bool retain;
/// <summary>
/// Constructor
/// </summary>
/// <param name="topic">Message topic</param>
/// <param name="message">Message data</param>
/// <param name="dupFlag">Duplicate delivery flag</param>
/// <param name="qosLevel">Quality of Service level</param>
/// <param name="retain">Retain flag</param>
public MqttMsgPublishEventArgs(string topic,
byte[] message,
bool dupFlag,
byte qosLevel,
bool retain)
{
this.topic = topic;
this.message = message;
this.dupFlag = dupFlag;
this.qosLevel = qosLevel;
this.retain = retain;
}
}
} }

View File

@ -14,49 +14,65 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for published message
/// </summary>
public class MqttMsgPublishedEventArgs : EventArgs {
#region Properties...
/// <summary> /// <summary>
/// Message identifier /// Event Args class for published message
/// </summary> /// </summary>
public UInt16 MessageId { get; internal set; } public class MqttMsgPublishedEventArgs : EventArgs
{
/// <summary> #region Properties...
/// Message published (or failed due to retries)
/// </summary> /// <summary>
public Boolean IsPublished { get; internal set; } /// Message identifier
/// </summary>
#endregion public ushort MessageId
{
// message identifier get { return this.messageId; }
internal set { this.messageId = value; }
/// <summary> }
/// Constructor (published message)
/// </summary> /// <summary>
/// <param name="messageId">Message identifier published</param> /// Message published (or failed due to retries)
public MqttMsgPublishedEventArgs(UInt16 messageId) /// </summary>
: this(messageId, true) { public bool IsPublished
} {
get { return this.isPublished; }
/// <summary> internal set { this.isPublished = value; }
/// Constructor }
/// </summary>
/// <param name="messageId">Message identifier</param> #endregion
/// <param name="isPublished">Publish flag</param>
public MqttMsgPublishedEventArgs(UInt16 messageId, Boolean isPublished) { // message identifier
this.MessageId = messageId; ushort messageId;
this.IsPublished = isPublished;
} // published flag
} bool isPublished;
/// <summary>
/// Constructor (published message)
/// </summary>
/// <param name="messageId">Message identifier published</param>
public MqttMsgPublishedEventArgs(ushort messageId)
: this(messageId, true)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="messageId">Message identifier</param>
/// <param name="isPublished">Publish flag</param>
public MqttMsgPublishedEventArgs(ushort messageId, bool isPublished)
{
this.messageId = messageId;
this.isPublished = isPublished;
}
}
} }

View File

@ -14,102 +14,112 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for PUBREC message from broker to client
/// </summary>
public class MqttMsgPubrec : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for PUBREC message from broker to client
/// </summary> /// </summary>
public MqttMsgPubrec() => this.Type = MQTT_MSG_PUBREC_TYPE; public class MqttMsgPubrec : MqttMsgBase
{
public override Byte[] GetBytes(Byte protocolVersion) { /// <summary>
Int32 varHeaderSize = 0; /// Constructor
Int32 payloadSize = 0; /// </summary>
Int32 remainingLength = 0; public MqttMsgPubrec()
Byte[] buffer; {
Int32 index = 0; this.type = MQTT_MSG_PUBREC_TYPE;
}
// message identifier
varHeaderSize += MESSAGE_ID_SIZE; public override byte[] GetBytes(byte protocolVersion)
{
remainingLength += varHeaderSize + payloadSize; int fixedHeaderSize = 0;
int varHeaderSize = 0;
// first byte of fixed header int payloadSize = 0;
Int32 fixedHeaderSize = 1; int remainingLength = 0;
byte[] buffer;
Int32 temp = remainingLength; int index = 0;
// increase fixed header size based on remaining length
// (each remaining length byte can encode until 128) // message identifier
do { varHeaderSize += MESSAGE_ID_SIZE;
fixedHeaderSize++;
temp /= 128; remainingLength += (varHeaderSize + payloadSize);
} while (temp > 0);
// first byte of fixed header
// allocate buffer for message fixedHeaderSize = 1;
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize];
int temp = remainingLength;
// first fixed header byte // increase fixed header size based on remaining length
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 // (each remaining length byte can encode until 128)
? (Byte)((MQTT_MSG_PUBREC_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBREC_FLAG_BITS) do
: (Byte)(MQTT_MSG_PUBREC_TYPE << MSG_TYPE_OFFSET); {
fixedHeaderSize++;
// encode remaining length temp = temp / 128;
index = this.EncodeRemainingLength(remainingLength, buffer, index); } while (temp > 0);
// get message identifier // allocate buffer for message
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB
// first fixed header byte
return buffer; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
} buffer[index++] = (MQTT_MSG_PUBREC_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBREC_FLAG_BITS; // [v.3.1.1]
else
/// <summary> buffer[index++] = (MQTT_MSG_PUBREC_TYPE << MSG_TYPE_OFFSET);
/// Parse bytes for a PUBREC message
/// </summary> // encode remaining length
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> index = this.encodeRemainingLength(remainingLength, buffer, index);
/// <param name="protocolVersion">Protocol Version</param>
/// <param name="channel">Channel connected to the broker</param> // get message identifier
/// <returns>PUBREC message instance</returns> buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
public static MqttMsgPubrec Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
Byte[] buffer;
Int32 index = 0; return buffer;
MqttMsgPubrec msg = new MqttMsgPubrec(); }
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// <summary>
// [v3.1.1] check flag bits /// Parse bytes for a PUBREC message
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREC_FLAG_BITS) { /// </summary>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
} /// <param name="protocolVersion">Protocol Version</param>
} /// <param name="channel">Channel connected to the broker</param>
/// <returns>PUBREC message instance</returns>
// get remaining length and allocate buffer public static MqttMsgPubrec Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); {
buffer = new Byte[remainingLength]; byte[] buffer;
int index = 0;
// read bytes from socket... MqttMsgPubrec msg = new MqttMsgPubrec();
_ = channel.Receive(buffer);
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
// message id {
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00); // [v3.1.1] check flag bits
msg.MessageId |= buffer[index++]; if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREC_FLAG_BITS)
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
return msg; }
}
// get remaining length and allocate buffer
public override String ToString() => int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
buffer = new byte[remainingLength];
// read bytes from socket...
channel.Receive(buffer);
// message id
msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
msg.messageId |= (buffer[index++]);
return msg;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PUBREC", "PUBREC",
new Object[] { "messageId" }, new object[] { "messageId" },
new Object[] { this.MessageId }); new object[] { this.messageId });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -16,117 +16,127 @@ Contributors:
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for PUBREL message from client top broker
/// </summary>
public class MqttMsgPubrel : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for PUBREL message from client top broker
/// </summary> /// </summary>
public MqttMsgPubrel() { public class MqttMsgPubrel : MqttMsgBase
this.Type = MQTT_MSG_PUBREL_TYPE; {
// PUBREL message use QoS Level 1 (not "officially" in 3.1.1) /// <summary>
this.QosLevel = QOS_LEVEL_AT_LEAST_ONCE; /// Constructor
} /// </summary>
public MqttMsgPubrel()
public override System.Byte[] GetBytes(System.Byte protocolVersion) { {
System.Int32 varHeaderSize = 0; this.type = MQTT_MSG_PUBREL_TYPE;
System.Int32 payloadSize = 0; // PUBREL message use QoS Level 1 (not "officially" in 3.1.1)
System.Int32 remainingLength = 0; this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
System.Byte[] buffer; }
System.Int32 index = 0;
public override byte[] GetBytes(byte protocolVersion)
// message identifier {
varHeaderSize += MESSAGE_ID_SIZE; int fixedHeaderSize = 0;
int varHeaderSize = 0;
remainingLength += varHeaderSize + payloadSize; int payloadSize = 0;
int remainingLength = 0;
// first byte of fixed header byte[] buffer;
System.Int32 fixedHeaderSize = 1; int index = 0;
System.Int32 temp = remainingLength; // message identifier
// increase fixed header size based on remaining length varHeaderSize += MESSAGE_ID_SIZE;
// (each remaining length byte can encode until 128)
do { remainingLength += (varHeaderSize + payloadSize);
fixedHeaderSize++;
temp /= 128; // first byte of fixed header
} while (temp > 0); fixedHeaderSize = 1;
// allocate buffer for message int temp = remainingLength;
buffer = new System.Byte[fixedHeaderSize + varHeaderSize + payloadSize]; // increase fixed header size based on remaining length
// (each remaining length byte can encode until 128)
// first fixed header byte do
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { {
buffer[index++] = (MQTT_MSG_PUBREL_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBREL_FLAG_BITS; // [v.3.1.1] fixedHeaderSize++;
} else { temp = temp / 128;
buffer[index] = (System.Byte)((MQTT_MSG_PUBREL_TYPE << MSG_TYPE_OFFSET) | } while (temp > 0);
(this.QosLevel << QOS_LEVEL_OFFSET));
buffer[index] |= this.DupFlag ? (System.Byte)(1 << DUP_FLAG_OFFSET) : (System.Byte)0x00; // allocate buffer for message
index++; buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
}
// first fixed header byte
// encode remaining length if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
index = this.EncodeRemainingLength(remainingLength, buffer, index); buffer[index++] = (MQTT_MSG_PUBREL_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBREL_FLAG_BITS; // [v.3.1.1]
else
// get next message identifier {
buffer[index++] = (System.Byte)((this.MessageId >> 8) & 0x00FF); // MSB buffer[index] = (byte)((MQTT_MSG_PUBREL_TYPE << MSG_TYPE_OFFSET) |
buffer[index++] = (System.Byte)(this.MessageId & 0x00FF); // LSB (this.qosLevel << QOS_LEVEL_OFFSET));
buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
return buffer; index++;
} }
/// <summary> // encode remaining length
/// Parse bytes for a PUBREL message index = this.encodeRemainingLength(remainingLength, buffer, index);
/// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> // get next message identifier
/// <param name="protocolVersion">Protocol Version</param> buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
/// <param name="channel">Channel connected to the broker</param> buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
/// <returns>PUBREL message instance</returns>
public static MqttMsgPubrel Parse(System.Byte fixedHeaderFirstByte, System.Byte protocolVersion, IMqttNetworkChannel channel) { return buffer;
System.Byte[] buffer; }
System.Int32 index = 0;
MqttMsgPubrel msg = new MqttMsgPubrel(); /// <summary>
/// Parse bytes for a PUBREL message
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// </summary>
// [v3.1.1] check flag bits /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREL_FLAG_BITS) { /// <param name="protocolVersion">Protocol Version</param>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <param name="channel">Channel connected to the broker</param>
} /// <returns>PUBREL message instance</returns>
} public static MqttMsgPubrel Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
{
// get remaining length and allocate buffer byte[] buffer;
System.Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); int index = 0;
buffer = new System.Byte[remainingLength]; MqttMsgPubrel msg = new MqttMsgPubrel();
// read bytes from socket... if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
_ = channel.Receive(buffer); {
// [v3.1.1] check flag bits
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1) { if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREL_FLAG_BITS)
// only 3.1.0 throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
}
// read QoS level from fixed header (would be QoS Level 1)
msg.QosLevel = (System.Byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); // get remaining length and allocate buffer
// read DUP flag from fixed header int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
msg.DupFlag = (fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET == 0x01; buffer = new byte[remainingLength];
}
// read bytes from socket...
// message id channel.Receive(buffer);
msg.MessageId = (System.UInt16)((buffer[index++] << 8) & 0xFF00);
msg.MessageId |= buffer[index++]; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1)
{
return msg; // only 3.1.0
}
// read QoS level from fixed header (would be QoS Level 1)
public override System.String ToString() => msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
// read DUP flag from fixed header
msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
}
// message id
msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
msg.messageId |= (buffer[index++]);
return msg;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"PUBREL", "PUBREL",
new System.Object[] { "messageId" }, new object[] { "messageId" },
new System.Object[] { this.MessageId }); new object[] { this.messageId });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -17,127 +17,146 @@ Contributors:
using System; using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for SUBACK message from broker to client
/// </summary>
public class MqttMsgSuback : MqttMsgBase {
#region Properties...
/// <summary> /// <summary>
/// List of granted QOS Levels /// Class for SUBACK message from broker to client
/// </summary> /// </summary>
public Byte[] GrantedQoSLevels { get; set; } public class MqttMsgSuback : MqttMsgBase
{
#endregion #region Properties...
// granted QOS levels /// <summary>
/// List of granted QOS Levels
/// <summary> /// </summary>
/// Constructor public byte[] GrantedQoSLevels
/// </summary> {
public MqttMsgSuback() => this.Type = MQTT_MSG_SUBACK_TYPE; get { return this.grantedQosLevels; }
set { this.grantedQosLevels = value; }
/// <summary> }
/// Parse bytes for a SUBACK message
/// </summary> #endregion
/// <param name="fixedHeaderFirstByte">First fixed header byte</param>
/// <param name="protocolVersion">Protocol Version</param> // granted QOS levels
/// <param name="channel">Channel connected to the broker</param> byte[] grantedQosLevels;
/// <returns>SUBACK message instance</returns>
public static MqttMsgSuback Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { /// <summary>
Byte[] buffer; /// Constructor
Int32 index = 0; /// </summary>
MqttMsgSuback msg = new MqttMsgSuback(); public MqttMsgSuback()
{
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { this.type = MQTT_MSG_SUBACK_TYPE;
// [v3.1.1] check flag bits }
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBACK_FLAG_BITS) {
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// <summary>
} /// Parse bytes for a SUBACK message
} /// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param>
// get remaining length and allocate buffer /// <param name="protocolVersion">Protocol Version</param>
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); /// <param name="channel">Channel connected to the broker</param>
buffer = new Byte[remainingLength]; /// <returns>SUBACK message instance</returns>
public static MqttMsgSuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
// read bytes from socket... {
_ = channel.Receive(buffer); byte[] buffer;
int index = 0;
// message id MqttMsgSuback msg = new MqttMsgSuback();
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00);
msg.MessageId |= buffer[index++]; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
{
// payload contains QoS levels granted // [v3.1.1] check flag bits
msg.GrantedQoSLevels = new Byte[remainingLength - MESSAGE_ID_SIZE]; if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBACK_FLAG_BITS)
Int32 qosIdx = 0; throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
do { }
msg.GrantedQoSLevels[qosIdx++] = buffer[index++];
} while (index < remainingLength); // get remaining length and allocate buffer
int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
return msg; buffer = new byte[remainingLength];
}
// read bytes from socket...
public override Byte[] GetBytes(Byte protocolVersion) { channel.Receive(buffer);
Int32 varHeaderSize = 0;
Int32 payloadSize = 0; // message id
Int32 remainingLength = 0; msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
Byte[] buffer; msg.messageId |= (buffer[index++]);
Int32 index = 0;
// payload contains QoS levels granted
// message identifier msg.grantedQosLevels = new byte[remainingLength - MESSAGE_ID_SIZE];
varHeaderSize += MESSAGE_ID_SIZE; int qosIdx = 0;
do
Int32 grantedQosIdx; {
for (grantedQosIdx = 0; grantedQosIdx < this.GrantedQoSLevels.Length; grantedQosIdx++) { msg.grantedQosLevels[qosIdx++] = buffer[index++];
payloadSize++; } while (index < remainingLength);
}
return msg;
remainingLength += varHeaderSize + payloadSize; }
// first byte of fixed header public override byte[] GetBytes(byte protocolVersion)
Int32 fixedHeaderSize = 1; {
int fixedHeaderSize = 0;
Int32 temp = remainingLength; int varHeaderSize = 0;
// increase fixed header size based on remaining length int payloadSize = 0;
// (each remaining length byte can encode until 128) int remainingLength = 0;
do { byte[] buffer;
fixedHeaderSize++; int index = 0;
temp /= 128;
} while (temp > 0); // message identifier
varHeaderSize += MESSAGE_ID_SIZE;
// allocate buffer for message
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize]; int grantedQosIdx = 0;
for (grantedQosIdx = 0; grantedQosIdx < this.grantedQosLevels.Length; grantedQosIdx++)
// first fixed header byte {
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 payloadSize++;
? (Byte)((MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_SUBACK_FLAG_BITS) }
: (Byte)(MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET);
remainingLength += (varHeaderSize + payloadSize);
// encode remaining length
index = this.EncodeRemainingLength(remainingLength, buffer, index); // first byte of fixed header
fixedHeaderSize = 1;
// message id
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB int temp = remainingLength;
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB // increase fixed header size based on remaining length
// (each remaining length byte can encode until 128)
// payload contains QoS levels granted do
for (grantedQosIdx = 0; grantedQosIdx < this.GrantedQoSLevels.Length; grantedQosIdx++) { {
buffer[index++] = this.GrantedQoSLevels[grantedQosIdx]; fixedHeaderSize++;
} temp = temp / 128;
} while (temp > 0);
return buffer;
} // allocate buffer for message
buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
public override String ToString() =>
// first fixed header byte
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index++] = (MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_SUBACK_FLAG_BITS; // [v.3.1.1]
else
buffer[index++] = (byte)(MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET);
// encode remaining length
index = this.encodeRemainingLength(remainingLength, buffer, index);
// message id
buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
// payload contains QoS levels granted
for (grantedQosIdx = 0; grantedQosIdx < this.grantedQosLevels.Length; grantedQosIdx++)
{
buffer[index++] = this.grantedQosLevels[grantedQosIdx];
}
return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"SUBACK", "SUBACK",
new Object[] { "messageId", "grantedQosLevels" }, new object[] { "messageId", "grantedQosLevels" },
new Object[] { this.MessageId, this.GrantedQoSLevels }); new object[] { this.messageId, this.grantedQosLevels });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -16,234 +16,257 @@ Contributors:
using System; using System;
// if NOT .Net Micro Framework // if NOT .Net Micro Framework
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System.Collections.Generic; using System.Collections.Generic;
#endif #endif
using System.Collections; using System.Collections;
using System.Text; using System.Text;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for SUBSCRIBE message from client to broker
/// </summary>
public class MqttMsgSubscribe : MqttMsgBase {
#region Properties...
/// <summary> /// <summary>
/// List of topics to subscribe /// Class for SUBSCRIBE message from client to broker
/// </summary> /// </summary>
public String[] Topics { get; set; } public class MqttMsgSubscribe : MqttMsgBase
{
/// <summary> #region Properties...
/// List of QOS Levels related to topics
/// </summary> /// <summary>
public Byte[] QoSLevels { get; set; } /// List of topics to subscribe
/// </summary>
#endregion public string[] Topics
{
// topics to subscribe get { return this.topics; }
set { this.topics = value; }
/// <summary> }
/// Constructor
/// </summary> /// <summary>
public MqttMsgSubscribe() => this.Type = MQTT_MSG_SUBSCRIBE_TYPE; /// List of QOS Levels related to topics
/// </summary>
/// <summary> public byte[] QoSLevels
/// Constructor {
/// </summary> get { return this.qosLevels; }
/// <param name="topics">List of topics to subscribe</param> set { this.qosLevels = value; }
/// <param name="qosLevels">List of QOS Levels related to topics</param> }
public MqttMsgSubscribe(String[] topics, Byte[] qosLevels) {
this.Type = MQTT_MSG_SUBSCRIBE_TYPE; #endregion
this.Topics = topics; // topics to subscribe
this.QoSLevels = qosLevels; string[] topics;
// QOS levels related to topics
// SUBSCRIBE message uses QoS Level 1 (not "officially" in 3.1.1) byte[] qosLevels;
this.QosLevel = QOS_LEVEL_AT_LEAST_ONCE;
} /// <summary>
/// Constructor
/// <summary> /// </summary>
/// Parse bytes for a SUBSCRIBE message public MqttMsgSubscribe()
/// </summary> {
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> this.type = MQTT_MSG_SUBSCRIBE_TYPE;
/// <param name="protocolVersion">Protocol Version</param> }
/// <param name="channel">Channel connected to the broker</param>
/// <returns>SUBSCRIBE message instance</returns> /// <summary>
public static MqttMsgSubscribe Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { /// Constructor
Byte[] buffer; /// </summary>
Int32 index = 0; /// <param name="topics">List of topics to subscribe</param>
Byte[] topicUtf8; /// <param name="qosLevels">List of QOS Levels related to topics</param>
Int32 topicUtf8Length; public MqttMsgSubscribe(string[] topics, byte[] qosLevels)
MqttMsgSubscribe msg = new MqttMsgSubscribe(); {
this.type = MQTT_MSG_SUBSCRIBE_TYPE;
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) {
// [v3.1.1] check flag bits this.topics = topics;
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBSCRIBE_FLAG_BITS) { this.qosLevels = qosLevels;
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
} // SUBSCRIBE message uses QoS Level 1 (not "officially" in 3.1.1)
} this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
}
// get remaining length and allocate buffer
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel); /// <summary>
buffer = new Byte[remainingLength]; /// Parse bytes for a SUBSCRIBE message
/// </summary>
// read bytes from socket... /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
Int32 received = channel.Receive(buffer); /// <param name="protocolVersion">Protocol Version</param>
/// <param name="channel">Channel connected to the broker</param>
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1) { /// <returns>SUBSCRIBE message instance</returns>
// only 3.1.0 public static MqttMsgSubscribe Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
{
// read QoS level from fixed header byte[] buffer;
msg.QosLevel = (Byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); int index = 0;
// read DUP flag from fixed header byte[] topicUtf8;
msg.DupFlag = (fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET == 0x01; int topicUtf8Length;
// retain flag not used MqttMsgSubscribe msg = new MqttMsgSubscribe();
msg.Retain = false;
} if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
{
// message id // [v3.1.1] check flag bits
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00); if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBSCRIBE_FLAG_BITS)
msg.MessageId |= buffer[index++]; throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
}
// payload contains topics and QoS levels
// NOTE : before, I don't know how many topics will be in the payload (so use List) // get remaining length and allocate buffer
int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
// if .Net Micro Framework buffer = new byte[remainingLength];
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3
// read bytes from socket...
int received = channel.Receive(buffer);
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1)
{
// only 3.1.0
// read QoS level from fixed header
msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
// read DUP flag from fixed header
msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
// retain flag not used
msg.retain = false;
}
// message id
msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
msg.messageId |= (buffer[index++]);
// payload contains topics and QoS levels
// NOTE : before, I don't know how many topics will be in the payload (so use List)
// if .Net Micro Framework
#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
IList tmpTopics = new ArrayList(); IList tmpTopics = new ArrayList();
IList tmpQosLevels = new ArrayList(); IList tmpQosLevels = new ArrayList();
// else other frameworks (.Net, .Net Compact, Mono, Windows Phone) // else other frameworks (.Net, .Net Compact, Mono, Windows Phone)
#else #else
IList<String> tmpTopics = new List<String>(); IList<String> tmpTopics = new List<String>();
IList<Byte> tmpQosLevels = new List<Byte>(); IList<byte> tmpQosLevels = new List<byte>();
#endif #endif
do { do
// topic name {
topicUtf8Length = (buffer[index++] << 8) & 0xFF00; // topic name
topicUtf8Length |= buffer[index++]; topicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
topicUtf8 = new Byte[topicUtf8Length]; topicUtf8Length |= buffer[index++];
Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length); topicUtf8 = new byte[topicUtf8Length];
index += topicUtf8Length; Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length);
tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8))); index += topicUtf8Length;
tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8)));
// QoS level
tmpQosLevels.Add(buffer[index++]); // QoS level
tmpQosLevels.Add(buffer[index++]);
} while (index < remainingLength);
} while (index < remainingLength);
// copy from list to array
msg.Topics = new String[tmpTopics.Count]; // copy from list to array
msg.QoSLevels = new Byte[tmpQosLevels.Count]; msg.topics = new string[tmpTopics.Count];
for (Int32 i = 0; i < tmpTopics.Count; i++) { msg.qosLevels = new byte[tmpQosLevels.Count];
msg.Topics[i] = (String)tmpTopics[i]; for (int i = 0; i < tmpTopics.Count; i++)
msg.QoSLevels[i] = (Byte)tmpQosLevels[i]; {
} msg.topics[i] = (string)tmpTopics[i];
msg.qosLevels[i] = (byte)tmpQosLevels[i];
return msg; }
}
return msg;
public override Byte[] GetBytes(Byte protocolVersion) { }
Int32 varHeaderSize = 0;
Int32 payloadSize = 0; public override byte[] GetBytes(byte protocolVersion)
Int32 remainingLength = 0; {
Byte[] buffer; int fixedHeaderSize = 0;
Int32 index = 0; int varHeaderSize = 0;
int payloadSize = 0;
// topics list empty int remainingLength = 0;
if (this.Topics == null || this.Topics.Length == 0) { byte[] buffer;
throw new MqttClientException(MqttClientErrorCode.TopicsEmpty); int index = 0;
}
// topics list empty
// qos levels list empty if ((this.topics == null) || (this.topics.Length == 0))
if (this.QoSLevels == null || this.QoSLevels.Length == 0) { throw new MqttClientException(MqttClientErrorCode.TopicsEmpty);
throw new MqttClientException(MqttClientErrorCode.QosLevelsEmpty);
} // qos levels list empty
if ((this.qosLevels == null) || (this.qosLevels.Length == 0))
// topics and qos levels lists length don't match throw new MqttClientException(MqttClientErrorCode.QosLevelsEmpty);
if (this.Topics.Length != this.QoSLevels.Length) {
throw new MqttClientException(MqttClientErrorCode.TopicsQosLevelsNotMatch); // topics and qos levels lists length don't match
} if (this.topics.Length != this.qosLevels.Length)
throw new MqttClientException(MqttClientErrorCode.TopicsQosLevelsNotMatch);
// message identifier
varHeaderSize += MESSAGE_ID_SIZE; // message identifier
Byte[][] topicsUtf8 = new Byte[this.Topics.Length][]; varHeaderSize += MESSAGE_ID_SIZE;
int topicIdx = 0;
Int32 topicIdx; byte[][] topicsUtf8 = new byte[this.topics.Length][];
for (topicIdx = 0; topicIdx < this.Topics.Length; topicIdx++) {
// check topic length for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
if (this.Topics[topicIdx].Length < MIN_TOPIC_LENGTH || this.Topics[topicIdx].Length > MAX_TOPIC_LENGTH) { {
throw new MqttClientException(MqttClientErrorCode.TopicLength); // check topic length
} if ((this.topics[topicIdx].Length < MIN_TOPIC_LENGTH) || (this.topics[topicIdx].Length > MAX_TOPIC_LENGTH))
throw new MqttClientException(MqttClientErrorCode.TopicLength);
topicsUtf8[topicIdx] = Encoding.UTF8.GetBytes(this.Topics[topicIdx]);
payloadSize += 2; // topic size (MSB, LSB) topicsUtf8[topicIdx] = Encoding.UTF8.GetBytes(this.topics[topicIdx]);
payloadSize += topicsUtf8[topicIdx].Length; payloadSize += 2; // topic size (MSB, LSB)
payloadSize++; // byte for QoS payloadSize += topicsUtf8[topicIdx].Length;
} payloadSize++; // byte for QoS
}
remainingLength += varHeaderSize + payloadSize;
remainingLength += (varHeaderSize + payloadSize);
// first byte of fixed header
Int32 fixedHeaderSize = 1; // first byte of fixed header
fixedHeaderSize = 1;
Int32 temp = remainingLength;
// increase fixed header size based on remaining length int temp = remainingLength;
// (each remaining length byte can encode until 128) // increase fixed header size based on remaining length
do { // (each remaining length byte can encode until 128)
fixedHeaderSize++; do
temp /= 128; {
} while (temp > 0); fixedHeaderSize++;
temp = temp / 128;
// allocate buffer for message } while (temp > 0);
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize];
// allocate buffer for message
// first fixed header byte buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) {
buffer[index++] = (MQTT_MSG_SUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_SUBSCRIBE_FLAG_BITS; // [v.3.1.1] // first fixed header byte
} else { if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index] = (Byte)((MQTT_MSG_SUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | buffer[index++] = (MQTT_MSG_SUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_SUBSCRIBE_FLAG_BITS; // [v.3.1.1]
(this.QosLevel << QOS_LEVEL_OFFSET)); else
buffer[index] |= this.DupFlag ? (Byte)(1 << DUP_FLAG_OFFSET) : (Byte)0x00; {
index++; buffer[index] = (byte)((MQTT_MSG_SUBSCRIBE_TYPE << MSG_TYPE_OFFSET) |
} (this.qosLevel << QOS_LEVEL_OFFSET));
buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
// encode remaining length index++;
index = this.EncodeRemainingLength(remainingLength, buffer, index); }
// check message identifier assigned (SUBSCRIBE uses QoS Level 1, so message id is mandatory) // encode remaining length
if (this.MessageId == 0) { index = this.encodeRemainingLength(remainingLength, buffer, index);
throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
} // check message identifier assigned (SUBSCRIBE uses QoS Level 1, so message id is mandatory)
if (this.messageId == 0)
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB buffer[index++] = (byte)((messageId >> 8) & 0x00FF); // MSB
buffer[index++] = (byte)(messageId & 0x00FF); // LSB
for (topicIdx = 0; topicIdx < this.Topics.Length; topicIdx++) {
// topic name topicIdx = 0;
buffer[index++] = (Byte)((topicsUtf8[topicIdx].Length >> 8) & 0x00FF); // MSB for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
buffer[index++] = (Byte)(topicsUtf8[topicIdx].Length & 0x00FF); // LSB {
Array.Copy(topicsUtf8[topicIdx], 0, buffer, index, topicsUtf8[topicIdx].Length); // topic name
index += topicsUtf8[topicIdx].Length; buffer[index++] = (byte)((topicsUtf8[topicIdx].Length >> 8) & 0x00FF); // MSB
buffer[index++] = (byte)(topicsUtf8[topicIdx].Length & 0x00FF); // LSB
// requested QoS Array.Copy(topicsUtf8[topicIdx], 0, buffer, index, topicsUtf8[topicIdx].Length);
buffer[index++] = this.QoSLevels[topicIdx]; index += topicsUtf8[topicIdx].Length;
}
// requested QoS
return buffer; buffer[index++] = this.qosLevels[topicIdx];
} }
public override String ToString() => return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"SUBSCRIBE", "SUBSCRIBE",
new Object[] { "messageId", "topics", "qosLevels" }, new object[] { "messageId", "topics", "qosLevels" },
new Object[] { this.MessageId, this.Topics, this.QoSLevels }); new object[] { this.messageId, this.topics, this.qosLevels });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -14,48 +14,68 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for subscribe request on topics
/// </summary>
public class MqttMsgSubscribeEventArgs : EventArgs {
#region Properties...
/// <summary> /// <summary>
/// Message identifier /// Event Args class for subscribe request on topics
/// </summary> /// </summary>
public UInt16 MessageId { get; internal set; } public class MqttMsgSubscribeEventArgs : EventArgs
{
/// <summary> #region Properties...
/// Topics requested to subscribe
/// </summary> /// <summary>
public String[] Topics { get; internal set; } /// Message identifier
/// </summary>
/// <summary> public ushort MessageId
/// List of QOS Levels requested {
/// </summary> get { return this.messageId; }
public Byte[] QoSLevels { get; internal set; } internal set { this.messageId = value; }
}
#endregion
/// <summary>
// message identifier /// Topics requested to subscribe
/// </summary>
/// <summary> public string[] Topics
/// Constructor {
/// </summary> get { return this.topics; }
/// <param name="messageId">Message identifier for subscribe topics request</param> internal set { this.topics = value; }
/// <param name="topics">Topics requested to subscribe</param> }
/// <param name="qosLevels">List of QOS Levels requested</param>
public MqttMsgSubscribeEventArgs(UInt16 messageId, String[] topics, Byte[] qosLevels) { /// <summary>
this.MessageId = messageId; /// List of QOS Levels requested
this.Topics = topics; /// </summary>
this.QoSLevels = qosLevels; public byte[] QoSLevels
} {
} get { return this.qosLevels; }
internal set { this.qosLevels = value; }
}
#endregion
// message identifier
ushort messageId;
// topics requested to subscribe
string[] topics;
// QoS levels requested
byte[] qosLevels;
/// <summary>
/// Constructor
/// </summary>
/// <param name="messageId">Message identifier for subscribe topics request</param>
/// <param name="topics">Topics requested to subscribe</param>
/// <param name="qosLevels">List of QOS Levels requested</param>
public MqttMsgSubscribeEventArgs(ushort messageId, string[] topics, byte[] qosLevels)
{
this.messageId = messageId;
this.topics = topics;
this.qosLevels = qosLevels;
}
}
} }

View File

@ -14,41 +14,55 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for subscribed topics
/// </summary>
public class MqttMsgSubscribedEventArgs : EventArgs {
#region Properties...
/// <summary> /// <summary>
/// Message identifier /// Event Args class for subscribed topics
/// </summary> /// </summary>
public UInt16 MessageId { get; internal set; } public class MqttMsgSubscribedEventArgs : EventArgs
{
/// <summary> #region Properties...
/// List of granted QOS Levels
/// </summary> /// <summary>
public Byte[] GrantedQoSLevels { get; internal set; } /// Message identifier
/// </summary>
#endregion public ushort MessageId
{
// message identifier get { return this.messageId; }
internal set { this.messageId = value; }
/// <summary> }
/// Constructor
/// </summary> /// <summary>
/// <param name="messageId">Message identifier for subscribed topics</param> /// List of granted QOS Levels
/// <param name="grantedQosLevels">List of granted QOS Levels</param> /// </summary>
public MqttMsgSubscribedEventArgs(UInt16 messageId, Byte[] grantedQosLevels) { public byte[] GrantedQoSLevels
this.MessageId = messageId; {
this.GrantedQoSLevels = grantedQosLevels; get { return this.grantedQosLevels; }
} internal set { this.grantedQosLevels = value; }
} }
#endregion
// message identifier
ushort messageId;
// granted QOS levels
byte[] grantedQosLevels;
/// <summary>
/// Constructor
/// </summary>
/// <param name="messageId">Message identifier for subscribed topics</param>
/// <param name="grantedQosLevels">List of granted QOS Levels</param>
public MqttMsgSubscribedEventArgs(ushort messageId, byte[] grantedQosLevels)
{
this.messageId = messageId;
this.grantedQosLevels = grantedQosLevels;
}
}
} }

View File

@ -17,99 +17,110 @@ Contributors:
using System; using System;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for UNSUBACK message from broker to client
/// </summary>
public class MqttMsgUnsuback : MqttMsgBase {
/// <summary> /// <summary>
/// Constructor /// Class for UNSUBACK message from broker to client
/// </summary> /// </summary>
public MqttMsgUnsuback() => this.Type = MQTT_MSG_UNSUBACK_TYPE; public class MqttMsgUnsuback : MqttMsgBase
{
/// <summary> /// <summary>
/// Parse bytes for a UNSUBACK message /// Constructor
/// </summary> /// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> public MqttMsgUnsuback()
/// <param name="protocolVersion">Protocol Version</param> {
/// <param name="channel">Channel connected to the broker</param> this.type = MQTT_MSG_UNSUBACK_TYPE;
/// <returns>UNSUBACK message instance</returns> }
public static MqttMsgUnsuback Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) {
Byte[] buffer; /// <summary>
Int32 index = 0; /// Parse bytes for a UNSUBACK message
MqttMsgUnsuback msg = new MqttMsgUnsuback(); /// </summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param>
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { /// <param name="protocolVersion">Protocol Version</param>
// [v3.1.1] check flag bits /// <param name="channel">Channel connected to the broker</param>
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBACK_FLAG_BITS) { /// <returns>UNSUBACK message instance</returns>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); public static MqttMsgUnsuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
} {
} byte[] buffer;
int index = 0;
// get remaining length and allocate buffer MqttMsgUnsuback msg = new MqttMsgUnsuback();
Int32 remainingLength = MqttMsgBase.DecodeRemainingLength(channel);
buffer = new Byte[remainingLength]; if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
{
// read bytes from socket... // [v3.1.1] check flag bits
_ = channel.Receive(buffer); if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBACK_FLAG_BITS)
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
// message id }
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00);
msg.MessageId |= buffer[index++]; // get remaining length and allocate buffer
int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
return msg; buffer = new byte[remainingLength];
}
// read bytes from socket...
public override Byte[] GetBytes(Byte protocolVersion) { channel.Receive(buffer);
Int32 varHeaderSize = 0;
Int32 payloadSize = 0; // message id
Int32 remainingLength = 0; msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
Byte[] buffer; msg.messageId |= (buffer[index++]);
Int32 index = 0;
return msg;
// message identifier }
varHeaderSize += MESSAGE_ID_SIZE;
public override byte[] GetBytes(byte protocolVersion)
remainingLength += varHeaderSize + payloadSize; {
int fixedHeaderSize = 0;
// first byte of fixed header int varHeaderSize = 0;
Int32 fixedHeaderSize = 1; int payloadSize = 0;
int remainingLength = 0;
Int32 temp = remainingLength; byte[] buffer;
// increase fixed header size based on remaining length int index = 0;
// (each remaining length byte can encode until 128)
do { // message identifier
fixedHeaderSize++; varHeaderSize += MESSAGE_ID_SIZE;
temp /= 128;
} while (temp > 0); remainingLength += (varHeaderSize + payloadSize);
// allocate buffer for message // first byte of fixed header
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize]; fixedHeaderSize = 1;
// first fixed header byte int temp = remainingLength;
buffer[index++] = protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1 // increase fixed header size based on remaining length
? (Byte)((MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_UNSUBACK_FLAG_BITS) // (each remaining length byte can encode until 128)
: (Byte)(MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET); do
{
// encode remaining length fixedHeaderSize++;
index = this.EncodeRemainingLength(remainingLength, buffer, index); temp = temp / 128;
} while (temp > 0);
// message id
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB // allocate buffer for message
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
return buffer; // first fixed header byte
} if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index++] = (MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_UNSUBACK_FLAG_BITS; // [v.3.1.1]
public override String ToString() => else
buffer[index++] = (byte)(MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET);
// encode remaining length
index = this.encodeRemainingLength(remainingLength, buffer, index);
// message id
buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"UNSUBACK", "UNSUBACK",
new Object[] { "messageId" }, new object[] { "messageId" },
new Object[] { this.MessageId }); new object[] { this.messageId });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -16,205 +16,224 @@ Contributors:
using System; using System;
// if NOT .Net Micro Framework // if NOT .Net Micro Framework
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System.Collections.Generic; using System.Collections.Generic;
#endif #endif
using System.Collections; using System.Collections;
using System.Text; using System.Text;
using uPLibrary.Networking.M2Mqtt.Exceptions; using uPLibrary.Networking.M2Mqtt.Exceptions;
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Class for UNSUBSCRIBE message from client to broker
/// </summary>
public class MqttMsgUnsubscribe : MqttMsgBase {
#region Properties...
/// <summary> /// <summary>
/// List of topics to unsubscribe /// Class for UNSUBSCRIBE message from client to broker
/// </summary> /// </summary>
public String[] Topics { get; set; } public class MqttMsgUnsubscribe : MqttMsgBase
{
#endregion #region Properties...
// topics to unsubscribe /// <summary>
/// List of topics to unsubscribe
/// <summary> /// </summary>
/// Constructor public string[] Topics
/// </summary> {
public MqttMsgUnsubscribe() => this.Type = MQTT_MSG_UNSUBSCRIBE_TYPE; get { return this.topics; }
set { this.topics = value; }
/// <summary> }
/// Constructor
/// </summary> #endregion
/// <param name="topics">List of topics to unsubscribe</param>
public MqttMsgUnsubscribe(String[] topics) { // topics to unsubscribe
this.Type = MQTT_MSG_UNSUBSCRIBE_TYPE; string[] topics;
this.Topics = topics; /// <summary>
/// Constructor
// UNSUBSCRIBE message uses QoS Level 1 (not "officially" in 3.1.1) /// </summary>
this.QosLevel = QOS_LEVEL_AT_LEAST_ONCE; public MqttMsgUnsubscribe()
} {
this.type = MQTT_MSG_UNSUBSCRIBE_TYPE;
/// <summary> }
/// Parse bytes for a UNSUBSCRIBE message
/// </summary> /// <summary>
/// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// Constructor
/// <param name="protocolVersion">Protocol Version</param> /// </summary>
/// <param name="channel">Channel connected to the broker</param> /// <param name="topics">List of topics to unsubscribe</param>
/// <returns>UNSUBSCRIBE message instance</returns> public MqttMsgUnsubscribe(string[] topics)
public static MqttMsgUnsubscribe Parse(Byte fixedHeaderFirstByte, Byte protocolVersion, IMqttNetworkChannel channel) { {
Byte[] buffer; this.type = MQTT_MSG_UNSUBSCRIBE_TYPE;
Int32 index = 0;
Byte[] topicUtf8; this.topics = topics;
Int32 topicUtf8Length;
MqttMsgUnsubscribe msg = new MqttMsgUnsubscribe(); // UNSUBSCRIBE message uses QoS Level 1 (not "officially" in 3.1.1)
this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { }
// [v3.1.1] check flag bits
if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBSCRIBE_FLAG_BITS) { /// <summary>
throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); /// Parse bytes for a UNSUBSCRIBE message
} /// </summary>
} /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
/// <param name="protocolVersion">Protocol Version</param>
// get remaining length and allocate buffer /// <param name="channel">Channel connected to the broker</param>
Int32 remainingLength = DecodeRemainingLength(channel); /// <returns>UNSUBSCRIBE message instance</returns>
buffer = new Byte[remainingLength]; public static MqttMsgUnsubscribe Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
{
// read bytes from socket... byte[] buffer;
Int32 received = channel.Receive(buffer); int index = 0;
byte[] topicUtf8;
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1) { int topicUtf8Length;
// only 3.1.0 MqttMsgUnsubscribe msg = new MqttMsgUnsubscribe();
// read QoS level from fixed header if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
msg.QosLevel = (Byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); {
// read DUP flag from fixed header // [v3.1.1] check flag bits
msg.DupFlag = (fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET == 0x01; if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBSCRIBE_FLAG_BITS)
// retain flag not used throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
msg.Retain = false; }
}
// get remaining length and allocate buffer
// message id int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
msg.MessageId = (UInt16)((buffer[index++] << 8) & 0xFF00); buffer = new byte[remainingLength];
msg.MessageId |= buffer[index++];
// read bytes from socket...
// payload contains topics int received = channel.Receive(buffer);
// NOTE : before, I don't know how many topics will be in the payload (so use List)
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1)
// if .Net Micro Framework {
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 // only 3.1.0
// read QoS level from fixed header
msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
// read DUP flag from fixed header
msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
// retain flag not used
msg.retain = false;
}
// message id
msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
msg.messageId |= (buffer[index++]);
// payload contains topics
// NOTE : before, I don't know how many topics will be in the payload (so use List)
// if .Net Micro Framework
#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
IList tmpTopics = new ArrayList(); IList tmpTopics = new ArrayList();
// else other frameworks (.Net, .Net Compact, Mono, Windows Phone) // else other frameworks (.Net, .Net Compact, Mono, Windows Phone)
#else #else
IList<String> tmpTopics = new List<String>(); IList<String> tmpTopics = new List<String>();
#endif #endif
do { do
// topic name {
topicUtf8Length = (buffer[index++] << 8) & 0xFF00; // topic name
topicUtf8Length |= buffer[index++]; topicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
topicUtf8 = new Byte[topicUtf8Length]; topicUtf8Length |= buffer[index++];
Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length); topicUtf8 = new byte[topicUtf8Length];
index += topicUtf8Length; Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length);
tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8))); index += topicUtf8Length;
} while (index < remainingLength); tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8)));
} while (index < remainingLength);
// copy from list to array
msg.Topics = new String[tmpTopics.Count]; // copy from list to array
for (Int32 i = 0; i < tmpTopics.Count; i++) { msg.topics = new string[tmpTopics.Count];
msg.Topics[i] = (String)tmpTopics[i]; for (int i = 0; i < tmpTopics.Count; i++)
} {
msg.topics[i] = (string)tmpTopics[i];
return msg; }
}
return msg;
public override Byte[] GetBytes(Byte protocolVersion) { }
Int32 varHeaderSize = 0;
Int32 payloadSize = 0; public override byte[] GetBytes(byte protocolVersion)
Int32 remainingLength = 0; {
Byte[] buffer; int fixedHeaderSize = 0;
Int32 index = 0; int varHeaderSize = 0;
int payloadSize = 0;
// topics list empty int remainingLength = 0;
if (this.Topics == null || this.Topics.Length == 0) { byte[] buffer;
throw new MqttClientException(MqttClientErrorCode.TopicsEmpty); int index = 0;
}
// topics list empty
// message identifier if ((this.topics == null) || (this.topics.Length == 0))
varHeaderSize += MESSAGE_ID_SIZE; throw new MqttClientException(MqttClientErrorCode.TopicsEmpty);
Byte[][] topicsUtf8 = new Byte[this.Topics.Length][];
// message identifier
varHeaderSize += MESSAGE_ID_SIZE;
Int32 topicIdx;
for (topicIdx = 0; topicIdx < this.Topics.Length; topicIdx++) { int topicIdx = 0;
// check topic length byte[][] topicsUtf8 = new byte[this.topics.Length][];
if (this.Topics[topicIdx].Length < MIN_TOPIC_LENGTH || this.Topics[topicIdx].Length > MAX_TOPIC_LENGTH) {
throw new MqttClientException(MqttClientErrorCode.TopicLength); for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
} {
// check topic length
topicsUtf8[topicIdx] = Encoding.UTF8.GetBytes(this.Topics[topicIdx]); if ((this.topics[topicIdx].Length < MIN_TOPIC_LENGTH) || (this.topics[topicIdx].Length > MAX_TOPIC_LENGTH))
payloadSize += 2; // topic size (MSB, LSB) throw new MqttClientException(MqttClientErrorCode.TopicLength);
payloadSize += topicsUtf8[topicIdx].Length;
} topicsUtf8[topicIdx] = Encoding.UTF8.GetBytes(this.topics[topicIdx]);
payloadSize += 2; // topic size (MSB, LSB)
remainingLength += varHeaderSize + payloadSize; payloadSize += topicsUtf8[topicIdx].Length;
}
// first byte of fixed header
Int32 fixedHeaderSize = 1; remainingLength += (varHeaderSize + payloadSize);
Int32 temp = remainingLength; // first byte of fixed header
// increase fixed header size based on remaining length fixedHeaderSize = 1;
// (each remaining length byte can encode until 128)
do { int temp = remainingLength;
fixedHeaderSize++; // increase fixed header size based on remaining length
temp /= 128; // (each remaining length byte can encode until 128)
} while (temp > 0); do
{
// allocate buffer for message fixedHeaderSize++;
buffer = new Byte[fixedHeaderSize + varHeaderSize + payloadSize]; temp = temp / 128;
} while (temp > 0);
// first fixed header byte
if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // allocate buffer for message
buffer[index++] = (MQTT_MSG_UNSUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_UNSUBSCRIBE_FLAG_BITS; // [v.3.1.1] buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
} else {
buffer[index] = (Byte)((MQTT_MSG_UNSUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | // first fixed header byte
(this.QosLevel << QOS_LEVEL_OFFSET)); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
buffer[index] |= this.DupFlag ? (Byte)(1 << DUP_FLAG_OFFSET) : (Byte)0x00; buffer[index++] = (MQTT_MSG_UNSUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_UNSUBSCRIBE_FLAG_BITS; // [v.3.1.1]
index++; else
} {
buffer[index] = (byte)((MQTT_MSG_UNSUBSCRIBE_TYPE << MSG_TYPE_OFFSET) |
// encode remaining length (this.qosLevel << QOS_LEVEL_OFFSET));
index = this.EncodeRemainingLength(remainingLength, buffer, index); buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
index++;
// check message identifier assigned }
if (this.MessageId == 0) {
throw new MqttClientException(MqttClientErrorCode.WrongMessageId); // encode remaining length
} index = this.encodeRemainingLength(remainingLength, buffer, index);
buffer[index++] = (Byte)((this.MessageId >> 8) & 0x00FF); // MSB // check message identifier assigned
buffer[index++] = (Byte)(this.MessageId & 0x00FF); // LSB if (this.messageId == 0)
throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
for (topicIdx = 0; topicIdx < this.Topics.Length; topicIdx++) { buffer[index++] = (byte)((messageId >> 8) & 0x00FF); // MSB
// topic name buffer[index++] = (byte)(messageId & 0x00FF); // LSB
buffer[index++] = (Byte)((topicsUtf8[topicIdx].Length >> 8) & 0x00FF); // MSB
buffer[index++] = (Byte)(topicsUtf8[topicIdx].Length & 0x00FF); // LSB topicIdx = 0;
Array.Copy(topicsUtf8[topicIdx], 0, buffer, index, topicsUtf8[topicIdx].Length); for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
index += topicsUtf8[topicIdx].Length; {
} // topic name
buffer[index++] = (byte)((topicsUtf8[topicIdx].Length >> 8) & 0x00FF); // MSB
return buffer; buffer[index++] = (byte)(topicsUtf8[topicIdx].Length & 0x00FF); // LSB
} Array.Copy(topicsUtf8[topicIdx], 0, buffer, index, topicsUtf8[topicIdx].Length);
index += topicsUtf8[topicIdx].Length;
public override String ToString() => }
return buffer;
}
public override string ToString()
{
#if TRACE #if TRACE
this.GetTraceString( return this.GetTraceString(
"UNSUBSCRIBE", "UNSUBSCRIBE",
new Object[] { "messageId", "topics" }, new object[] { "messageId", "topics" },
new Object[] { this.MessageId, this.Topics }); new object[] { this.messageId, this.topics });
#else #else
base.ToString(); return base.ToString();
#endif #endif
}
} }
} }

View File

@ -14,41 +14,55 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for unsubscribe request on topics
/// </summary>
public class MqttMsgUnsubscribeEventArgs : EventArgs {
#region Properties...
/// <summary> /// <summary>
/// Message identifier /// Event Args class for unsubscribe request on topics
/// </summary> /// </summary>
public UInt16 MessageId { get; internal set; } public class MqttMsgUnsubscribeEventArgs : EventArgs
{
/// <summary> #region Properties...
/// Topics requested to subscribe
/// </summary> /// <summary>
public String[] Topics { get; internal set; } /// Message identifier
/// </summary>
#endregion public ushort MessageId
{
// message identifier get { return this.messageId; }
internal set { this.messageId = value; }
/// <summary> }
/// Constructor
/// </summary> /// <summary>
/// <param name="messageId">Message identifier for subscribed topics</param> /// Topics requested to subscribe
/// <param name="topics">Topics requested to subscribe</param> /// </summary>
public MqttMsgUnsubscribeEventArgs(UInt16 messageId, String[] topics) { public string[] Topics
this.MessageId = messageId; {
this.Topics = topics; get { return this.topics; }
} internal set { this.topics = value; }
} }
#endregion
// message identifier
ushort messageId;
// topics requested to unsubscribe
string[] topics;
/// <summary>
/// Constructor
/// </summary>
/// <param name="messageId">Message identifier for subscribed topics</param>
/// <param name="topics">Topics requested to subscribe</param>
public MqttMsgUnsubscribeEventArgs(ushort messageId, string[] topics)
{
this.messageId = messageId;
this.topics = topics;
}
}
} }

View File

@ -14,32 +14,42 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
using System; using System;
#else #else
using Microsoft.SPOT; using Microsoft.SPOT;
#endif #endif
namespace uPLibrary.Networking.M2Mqtt.Messages { namespace uPLibrary.Networking.M2Mqtt.Messages
/// <summary> {
/// Event Args class for unsubscribed topic
/// </summary>
public class MqttMsgUnsubscribedEventArgs : EventArgs {
#region Properties...
/// <summary> /// <summary>
/// Message identifier /// Event Args class for unsubscribed topic
/// </summary> /// </summary>
public UInt16 MessageId { get; internal set; } public class MqttMsgUnsubscribedEventArgs : EventArgs
{
#endregion #region Properties...
// message identifier /// <summary>
/// Message identifier
/// <summary> /// </summary>
/// Constructor public ushort MessageId
/// </summary> {
/// <param name="messageId">Message identifier for unsubscribed topic</param> get { return this.messageId; }
public MqttMsgUnsubscribedEventArgs(UInt16 messageId) => this.MessageId = messageId; internal set { this.messageId = value; }
} }
#endregion
// message identifier
ushort messageId;
/// <summary>
/// Constructor
/// </summary>
/// <param name="messageId">Message identifier for unsubscribed topic</param>
public MqttMsgUnsubscribedEventArgs(ushort messageId)
{
this.messageId = messageId;
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -14,15 +14,17 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
namespace uPLibrary.Networking.M2Mqtt { namespace uPLibrary.Networking.M2Mqtt
/// <summary> {
/// Supported SSL/TLS protocol versions /// <summary>
/// </summary> /// Supported SSL/TLS protocol versions
public enum MqttSslProtocols { /// </summary>
None, public enum MqttSslProtocols
SSLv3, {
TLSv1_0, None,
TLSv1_1, SSLv3,
TLSv1_2 TLSv1_0,
} TLSv1_1,
TLSv1_2
}
} }

View File

@ -14,90 +14,91 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System; namespace uPLibrary.Networking.M2Mqtt
{
/// <summary>
/// Settings class for the MQTT broker
/// </summary>
public class MqttSettings
{
// default port for MQTT protocol
public const int MQTT_BROKER_DEFAULT_PORT = 1883;
public const int MQTT_BROKER_DEFAULT_SSL_PORT = 8883;
// default timeout on receiving from client
public const int MQTT_DEFAULT_TIMEOUT = 30000;
// max publish, subscribe and unsubscribe retry for QoS Level 1 or 2
public const int MQTT_ATTEMPTS_RETRY = 3;
// delay for retry publish, subscribe and unsubscribe for QoS Level 1 or 2
public const int MQTT_DELAY_RETRY = 10000;
// broker need to receive the first message (CONNECT)
// within a reasonable amount of time after TCP/IP connection
public const int MQTT_CONNECT_TIMEOUT = 30000;
// default inflight queue size
public const int MQTT_MAX_INFLIGHT_QUEUE_SIZE = int.MaxValue;
namespace uPLibrary.Networking.M2Mqtt { /// <summary>
/// <summary> /// Listening connection port
/// Settings class for the MQTT broker /// </summary>
/// </summary> public int Port { get; internal set; }
public class MqttSettings {
// default port for MQTT protocol /// <summary>
public const Int32 MQTT_BROKER_DEFAULT_PORT = 1883; /// Listening connection SSL port
public const Int32 MQTT_BROKER_DEFAULT_SSL_PORT = 8883; /// </summary>
// default timeout on receiving from client public int SslPort { get; internal set; }
public const Int32 MQTT_DEFAULT_TIMEOUT = 30000;
// max publish, subscribe and unsubscribe retry for QoS Level 1 or 2 /// <summary>
public const Int32 MQTT_ATTEMPTS_RETRY = 3; /// Timeout on client connection (before receiving CONNECT message)
// delay for retry publish, subscribe and unsubscribe for QoS Level 1 or 2 /// </summary>
public const Int32 MQTT_DELAY_RETRY = 10000; public int TimeoutOnConnection { get; internal set; }
// broker need to receive the first message (CONNECT)
// within a reasonable amount of time after TCP/IP connection /// <summary>
public const Int32 MQTT_CONNECT_TIMEOUT = 30000; /// Timeout on receiving
// default inflight queue size /// </summary>
public const Int32 MQTT_MAX_INFLIGHT_QUEUE_SIZE = Int32.MaxValue; public int TimeoutOnReceiving { get; internal set; }
/// <summary> /// <summary>
/// Listening connection port /// Attempts on retry
/// </summary> /// </summary>
public Int32 Port { get; internal set; } public int AttemptsOnRetry { get; internal set; }
/// <summary> /// <summary>
/// Listening connection SSL port /// Delay on retry
/// </summary> /// </summary>
public Int32 SslPort { get; internal set; } public int DelayOnRetry { get; internal set; }
/// <summary> /// <summary>
/// Timeout on client connection (before receiving CONNECT message) /// Inflight queue size
/// </summary> /// </summary>
public Int32 TimeoutOnConnection { get; internal set; } public int InflightQueueSize { get; set; }
/// <summary> /// <summary>
/// Timeout on receiving /// Singleton instance of settings
/// </summary> /// </summary>
public Int32 TimeoutOnReceiving { get; internal set; } public static MqttSettings Instance
{
/// <summary> get
/// Attempts on retry {
/// </summary> if (instance == null)
public Int32 AttemptsOnRetry { get; internal set; } instance = new MqttSettings();
return instance;
/// <summary> }
/// Delay on retry }
/// </summary>
public Int32 DelayOnRetry { get; internal set; } // singleton instance
private static MqttSettings instance;
/// <summary>
/// Inflight queue size /// <summary>
/// </summary> /// Constructor
public Int32 InflightQueueSize { get; set; } /// </summary>
private MqttSettings()
/// <summary> {
/// Singleton instance of settings this.Port = MQTT_BROKER_DEFAULT_PORT;
/// </summary> this.SslPort = MQTT_BROKER_DEFAULT_SSL_PORT;
public static MqttSettings Instance { this.TimeoutOnReceiving = MQTT_DEFAULT_TIMEOUT;
get { this.AttemptsOnRetry = MQTT_ATTEMPTS_RETRY;
if (instance == null) { this.DelayOnRetry = MQTT_DELAY_RETRY;
instance = new MqttSettings(); this.TimeoutOnConnection = MQTT_CONNECT_TIMEOUT;
} this.InflightQueueSize = MQTT_MAX_INFLIGHT_QUEUE_SIZE;
}
return instance; }
}
}
// singleton instance
private static MqttSettings instance;
/// <summary>
/// Constructor
/// </summary>
private MqttSettings() {
this.Port = MQTT_BROKER_DEFAULT_PORT;
this.SslPort = MQTT_BROKER_DEFAULT_SSL_PORT;
this.TimeoutOnReceiving = MQTT_DEFAULT_TIMEOUT;
this.AttemptsOnRetry = MQTT_ATTEMPTS_RETRY;
this.DelayOnRetry = MQTT_DELAY_RETRY;
this.TimeoutOnConnection = MQTT_CONNECT_TIMEOUT;
this.InflightQueueSize = MQTT_MAX_INFLIGHT_QUEUE_SIZE;
}
}
} }

View File

@ -14,16 +14,23 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using System.Threading; using System.Threading;
namespace uPLibrary.Networking.M2Mqtt { namespace uPLibrary.Networking.M2Mqtt
/// <summary> {
/// Support methods fos specific framework /// <summary>
/// </summary> /// Support methods fos specific framework
public class Fx { /// </summary>
public static void StartThread(ThreadStart threadStart) => new Thread(threadStart).Start(); public class Fx
{
public static void SleepThread(Int32 millisecondsTimeout) => Thread.Sleep(millisecondsTimeout); public static void StartThread(ThreadStart threadStart)
} {
new Thread(threadStart).Start();
}
public static void SleepThread(int millisecondsTimeout)
{
Thread.Sleep(millisecondsTimeout);
}
}
} }

View File

@ -15,17 +15,13 @@ Contributors:
*/ */
#if SSL #if SSL
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
using Microsoft.SPOT.Net.Security; using Microsoft.SPOT.Net.Security;
#else #else
using System.Security.Authentication;
#if NETCOREAPP
using System.Net.Security; using System.Net.Security;
#endif using System.Security.Authentication;
#endif #endif
#endif #endif
using System.Net.Sockets; using System.Net.Sockets;
using System.Net; using System.Net;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
@ -33,74 +29,90 @@ using System;
//using System.Security.Authentication; //using System.Security.Authentication;
//using System.Net.Security; //using System.Net.Security;
namespace uPLibrary.Networking.M2Mqtt { namespace uPLibrary.Networking.M2Mqtt
/// <summary> {
/// Channel to communicate over the network /// <summary>
/// </summary> /// Channel to communicate over the network
public class MqttNetworkChannel : IMqttNetworkChannel { /// </summary>
public class MqttNetworkChannel : IMqttNetworkChannel
{
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
private readonly RemoteCertificateValidationCallback userCertificateValidationCallback; private readonly RemoteCertificateValidationCallback userCertificateValidationCallback;
private readonly LocalCertificateSelectionCallback userCertificateSelectionCallback; private readonly LocalCertificateSelectionCallback userCertificateSelectionCallback;
#endif #endif
// remote host information // remote host information
private string remoteHostName;
private IPAddress remoteIpAddress;
private int remotePort;
// socket for communication // socket for communication
private Socket socket; private Socket socket;
// using SSL // using SSL
private readonly Boolean secure; private bool secure;
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3
// CA certificate (on client)
private readonly X509Certificate caCert;
#endif
// Server certificate (on broker)
private readonly X509Certificate serverCert;
// client certificate (on client)
private readonly X509Certificate clientCert;
// SSL/TLS protocol version // CA certificate (on client)
private readonly MqttSslProtocols sslProtocol; private X509Certificate caCert;
// Server certificate (on broker)
private X509Certificate serverCert;
// client certificate (on client)
private X509Certificate clientCert;
/// <summary> // SSL/TLS protocol version
/// Remote host name private MqttSslProtocols sslProtocol;
/// </summary>
public String RemoteHostName { get; }
/// <summary> /// <summary>
/// Remote IP address /// Remote host name
/// </summary> /// </summary>
public IPAddress RemoteIpAddress { get; } public string RemoteHostName { get { return this.remoteHostName; } }
/// <summary> /// <summary>
/// Remote port /// Remote IP address
/// </summary> /// </summary>
public Int32 RemotePort { get; } public IPAddress RemoteIpAddress { get { return this.remoteIpAddress; } }
/// <summary>
/// Remote port
/// </summary>
public int RemotePort { get { return this.remotePort; } }
#if SSL #if SSL
// SSL stream // SSL stream
private SslStream sslStream; private SslStream sslStream;
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
private NetworkStream netStream; private NetworkStream netStream;
#endif #endif
#endif #endif
/// <summary> /// <summary>
/// Data available on the channel /// Data available on the channel
/// </summary> /// </summary>
public bool DataAvailable
{
get
{
#if SSL #if SSL
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
public Boolean DataAvailable => this.secure ? this.sslStream.DataAvailable : this.socket.Available > 0; if (secure)
return this.sslStream.DataAvailable;
else
return (this.socket.Available > 0);
#else #else
public Boolean DataAvailable => this.secure ? this.netStream.DataAvailable : this.socket.Available > 0; if (secure)
return this.netStream.DataAvailable;
else
return (this.socket.Available > 0);
#endif #endif
#else #else
public Boolean DataAvailable => this.socket.Available > 0; return (this.socket.Available > 0);
#endif #endif
}
}
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="socket">Socket opened with the client</param> /// <param name="socket">Socket opened with the client</param>
public MqttNetworkChannel(Socket socket) public MqttNetworkChannel(Socket socket)
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
: this(socket, false, null, MqttSslProtocols.None, null, null) : this(socket, false, null, MqttSslProtocols.None, null, null)
#else #else
@ -108,205 +120,212 @@ namespace uPLibrary.Networking.M2Mqtt {
#endif #endif
{ {
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="socket">Socket opened with the client</param> /// <param name="socket">Socket opened with the client</param>
/// <param name="secure">Secure connection (SSL/TLS)</param> /// <param name="secure">Secure connection (SSL/TLS)</param>
/// <param name="serverCert">Server X509 certificate for secure connection</param> /// <param name="serverCert">Server X509 certificate for secure connection</param>
/// <param name="sslProtocol">SSL/TLS protocol version</param> /// <param name="sslProtocol">SSL/TLS protocol version</param>
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
/// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param> /// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
/// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param> /// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
public MqttNetworkChannel(Socket socket, Boolean secure, X509Certificate serverCert, MqttSslProtocols sslProtocol, public MqttNetworkChannel(Socket socket, bool secure, X509Certificate serverCert, MqttSslProtocols sslProtocol,
RemoteCertificateValidationCallback userCertificateValidationCallback, RemoteCertificateValidationCallback userCertificateValidationCallback,
LocalCertificateSelectionCallback userCertificateSelectionCallback) LocalCertificateSelectionCallback userCertificateSelectionCallback)
#else #else
public MqttNetworkChannel(Socket socket, bool secure, X509Certificate serverCert, MqttSslProtocols sslProtocol) public MqttNetworkChannel(Socket socket, bool secure, X509Certificate serverCert, MqttSslProtocols sslProtocol)
#endif #endif
{ {
this.socket = socket; this.socket = socket;
this.secure = secure; this.secure = secure;
this.serverCert = serverCert; this.serverCert = serverCert;
this.sslProtocol = sslProtocol; this.sslProtocol = sslProtocol;
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
this.userCertificateValidationCallback = userCertificateValidationCallback; this.userCertificateValidationCallback = userCertificateValidationCallback;
this.userCertificateSelectionCallback = userCertificateSelectionCallback; this.userCertificateSelectionCallback = userCertificateSelectionCallback;
#endif #endif
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="remoteHostName">Remote Host name</param> /// <param name="remoteHostName">Remote Host name</param>
/// <param name="remotePort">Remote port</param> /// <param name="remotePort">Remote port</param>
public MqttNetworkChannel(String remoteHostName, Int32 remotePort) public MqttNetworkChannel(string remoteHostName, int remotePort)
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
: this(remoteHostName, remotePort, false, null, null, MqttSslProtocols.None, null, null) : this(remoteHostName, remotePort, false, null, null, MqttSslProtocols.None, null, null)
#else #else
: this(remoteHostName, remotePort, false, null, null, MqttSslProtocols.None) : this(remoteHostName, remotePort, false, null, null, MqttSslProtocols.None)
#endif #endif
{ {
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="remoteHostName">Remote Host name</param> /// <param name="remoteHostName">Remote Host name</param>
/// <param name="remotePort">Remote port</param> /// <param name="remotePort">Remote port</param>
/// <param name="secure">Using SSL</param> /// <param name="secure">Using SSL</param>
/// <param name="caCert">CA certificate</param> /// <param name="caCert">CA certificate</param>
/// <param name="clientCert">Client certificate</param> /// <param name="clientCert">Client certificate</param>
/// <param name="sslProtocol">SSL/TLS protocol version</param> /// <param name="sslProtocol">SSL/TLS protocol version</param>
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
/// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param> /// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
/// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param> /// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
public MqttNetworkChannel(String remoteHostName, Int32 remotePort, Boolean secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol, public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol,
RemoteCertificateValidationCallback userCertificateValidationCallback, RemoteCertificateValidationCallback userCertificateValidationCallback,
LocalCertificateSelectionCallback userCertificateSelectionCallback) LocalCertificateSelectionCallback userCertificateSelectionCallback)
#else #else
public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol) public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol)
#endif #endif
{ {
IPAddress remoteIpAddress = null; IPAddress remoteIpAddress = null;
try { try
// check if remoteHostName is a valid IP address and get it {
remoteIpAddress = IPAddress.Parse(remoteHostName); // check if remoteHostName is a valid IP address and get it
} catch { remoteIpAddress = IPAddress.Parse(remoteHostName);
} }
catch
{
}
// in this case the parameter remoteHostName isn't a valid IP address // in this case the parameter remoteHostName isn't a valid IP address
if (remoteIpAddress == null) { if (remoteIpAddress == null)
IPHostEntry hostEntry = Dns.GetHostEntry(remoteHostName); {
if (hostEntry != null && hostEntry.AddressList.Length > 0) { IPHostEntry hostEntry = Dns.GetHostEntry(remoteHostName);
// check for the first address not null if ((hostEntry != null) && (hostEntry.AddressList.Length > 0))
// it seems that with .Net Micro Framework, the IPV6 addresses aren't supported and return "null" {
Int32 i = 0; // check for the first address not null
while (hostEntry.AddressList[i] == null) { // it seems that with .Net Micro Framework, the IPV6 addresses aren't supported and return "null"
i++; int i = 0;
} while (hostEntry.AddressList[i] == null) i++;
remoteIpAddress = hostEntry.AddressList[i];
}
else
{
throw new Exception("No address found for the remote host name");
}
}
remoteIpAddress = hostEntry.AddressList[i]; this.remoteHostName = remoteHostName;
} else { this.remoteIpAddress = remoteIpAddress;
throw new Exception("No address found for the remote host name"); this.remotePort = remotePort;
} this.secure = secure;
} this.caCert = caCert;
this.clientCert = clientCert;
this.RemoteHostName = remoteHostName; this.sslProtocol = sslProtocol;
this.RemoteIpAddress = remoteIpAddress;
this.RemotePort = remotePort;
this.secure = secure;
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3
this.caCert = caCert;
#endif
this.clientCert = clientCert;
this.sslProtocol = sslProtocol;
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
this.userCertificateValidationCallback = userCertificateValidationCallback; this.userCertificateValidationCallback = userCertificateValidationCallback;
this.userCertificateSelectionCallback = userCertificateSelectionCallback; this.userCertificateSelectionCallback = userCertificateSelectionCallback;
#endif #endif
} }
/// <summary> /// <summary>
/// Connect to remote server /// Connect to remote server
/// </summary> /// </summary>
public void Connect() { public void Connect()
this.socket = new Socket(IPAddressUtility.GetAddressFamily(this.RemoteIpAddress), SocketType.Stream, ProtocolType.Tcp); {
// try connection to the broker this.socket = new Socket(IPAddressUtility.GetAddressFamily(this.remoteIpAddress), SocketType.Stream, ProtocolType.Tcp);
this.socket.Connect(new IPEndPoint(this.RemoteIpAddress, this.RemotePort)); // try connection to the broker
this.socket.Connect(new IPEndPoint(this.remoteIpAddress, this.remotePort));
#if SSL #if SSL
// secure channel requested // secure channel requested
if (this.secure) { if (secure)
// create SSL stream {
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 // create SSL stream
#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
this.sslStream = new SslStream(this.socket); this.sslStream = new SslStream(this.socket);
#else #else
this.netStream = new NetworkStream(this.socket); this.netStream = new NetworkStream(this.socket);
this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback); this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback);
#endif #endif
// server authentication (SSL/TLS handshake) // server authentication (SSL/TLS handshake)
#if MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
this.sslStream.AuthenticateAsClient(this.remoteHostName, this.sslStream.AuthenticateAsClient(this.remoteHostName,
this.clientCert, this.clientCert,
new X509Certificate[] { this.caCert }, new X509Certificate[] { this.caCert },
SslVerification.CertificateRequired, SslVerification.CertificateRequired,
MqttSslUtility.ToSslPlatformEnum(this.sslProtocol)); MqttSslUtility.ToSslPlatformEnum(this.sslProtocol));
#else #else
X509CertificateCollection clientCertificates = null; X509CertificateCollection clientCertificates = null;
// check if there is a client certificate to add to the collection, otherwise it's null (as empty) // check if there is a client certificate to add to the collection, otherwise it's null (as empty)
if (this.clientCert != null) { if (this.clientCert != null)
clientCertificates = new X509CertificateCollection(new X509Certificate[] { this.clientCert }); clientCertificates = new X509CertificateCollection(new X509Certificate[] { this.clientCert });
this.sslStream.AuthenticateAsClient(this.remoteHostName,
clientCertificates,
MqttSslUtility.ToSslPlatformEnum(this.sslProtocol),
false);
#endif
}
#endif
} }
this.sslStream.AuthenticateAsClient(this.RemoteHostName, /// <summary>
clientCertificates, /// Send data on the network channel
MqttSslUtility.ToSslPlatformEnum(this.sslProtocol), /// </summary>
false); /// <param name="buffer">Data buffer to send</param>
/// <returns>Number of byte sent</returns>
#endif public int Send(byte[] buffer)
} {
#endif
}
/// <summary>
/// Send data on the network channel
/// </summary>
/// <param name="buffer">Data buffer to send</param>
/// <returns>Number of byte sent</returns>
public Int32 Send(Byte[] buffer) {
#if SSL #if SSL
if (this.secure) { if (this.secure)
this.sslStream.Write(buffer, 0, buffer.Length); {
this.sslStream.Flush(); this.sslStream.Write(buffer, 0, buffer.Length);
return buffer.Length; this.sslStream.Flush();
} else { return buffer.Length;
return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None); }
} else
return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
#else #else
return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None); return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
#endif #endif
} }
/// <summary> /// <summary>
/// Receive data from the network /// Receive data from the network
/// </summary> /// </summary>
/// <param name="buffer">Data buffer for receiving data</param> /// <param name="buffer">Data buffer for receiving data</param>
/// <returns>Number of bytes received</returns> /// <returns>Number of bytes received</returns>
public Int32 Receive(Byte[] buffer) { public int Receive(byte[] buffer)
{
#if SSL #if SSL
if (this.secure) { if (this.secure)
// read all data needed (until fill buffer) {
Int32 idx = 0, read = 0; // read all data needed (until fill buffer)
while (idx < buffer.Length) { int idx = 0, read = 0;
// fixed scenario with socket closed gracefully by peer/broker and while (idx < buffer.Length)
// Read return 0. Avoid infinite loop. {
read = this.sslStream.Read(buffer, idx, buffer.Length - idx); // fixed scenario with socket closed gracefully by peer/broker and
if (read == 0) { // Read return 0. Avoid infinite loop.
return 0; read = this.sslStream.Read(buffer, idx, buffer.Length - idx);
} if (read == 0)
return 0;
idx += read; idx += read;
} }
return buffer.Length; return buffer.Length;
} else { }
// read all data needed (until fill buffer) else
Int32 idx = 0, read = 0; {
while (idx < buffer.Length) { // read all data needed (until fill buffer)
// fixed scenario with socket closed gracefully by peer/broker and int idx = 0, read = 0;
// Read return 0. Avoid infinite loop. while (idx < buffer.Length)
read = this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None); {
if (read == 0) { // fixed scenario with socket closed gracefully by peer/broker and
return 0; // Read return 0. Avoid infinite loop.
} read = this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None);
if (read == 0)
idx += read; return 0;
} idx += read;
return buffer.Length; }
} return buffer.Length;
}
#else #else
// read all data needed (until fill buffer) // read all data needed (until fill buffer)
int idx = 0, read = 0; int idx = 0, read = 0;
@ -321,94 +340,118 @@ namespace uPLibrary.Networking.M2Mqtt {
} }
return buffer.Length; return buffer.Length;
#endif #endif
} }
/// <summary> /// <summary>
/// Receive data from the network channel with a specified timeout /// Receive data from the network channel with a specified timeout
/// </summary> /// </summary>
/// <param name="buffer">Data buffer for receiving data</param> /// <param name="buffer">Data buffer for receiving data</param>
/// <param name="timeout">Timeout on receiving (in milliseconds)</param> /// <param name="timeout">Timeout on receiving (in milliseconds)</param>
/// <returns>Number of bytes received</returns> /// <returns>Number of bytes received</returns>
public Int32 Receive(Byte[] buffer, Int32 timeout) => public int Receive(byte[] buffer, int timeout)
// check data availability (timeout is in microseconds) {
this.socket.Poll(timeout * 1000, SelectMode.SelectRead) ? this.Receive(buffer) : 0; // check data availability (timeout is in microseconds)
if (this.socket.Poll(timeout * 1000, SelectMode.SelectRead))
{
return this.Receive(buffer);
}
else
{
return 0;
}
}
/// <summary> /// <summary>
/// Close the network channel /// Close the network channel
/// </summary> /// </summary>
public void Close() { public void Close()
{
#if SSL #if SSL
if (this.secure) { if (this.secure)
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 {
this.netStream.Close(); #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
this.netStream.Close();
#endif #endif
this.sslStream.Close(); this.sslStream.Close();
} }
this.socket.Close(); this.socket.Close();
#else #else
this.socket.Close(); this.socket.Close();
#endif #endif
} }
/// <summary> /// <summary>
/// Accept connection from a remote client /// Accept connection from a remote client
/// </summary> /// </summary>
public void Accept() { public void Accept()
{
#if SSL #if SSL
// secure channel requested // secure channel requested
if (this.secure) { if (secure)
{
#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3) #if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
this.netStream = new NetworkStream(this.socket); this.netStream = new NetworkStream(this.socket);
this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback); this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback);
this.sslStream.AuthenticateAsServer(this.serverCert, false, MqttSslUtility.ToSslPlatformEnum(this.sslProtocol), false); this.sslStream.AuthenticateAsServer(this.serverCert, false, MqttSslUtility.ToSslPlatformEnum(this.sslProtocol), false);
#endif #endif
} }
return; return;
#else #else
return; return;
#endif #endif
}
} }
}
/// <summary>
/// IPAddress Utility class
/// </summary>
public static class IPAddressUtility {
/// <summary> /// <summary>
/// Return AddressFamily for the IP address /// IPAddress Utility class
/// </summary> /// </summary>
/// <param name="ipAddress">IP address to check</param> public static class IPAddressUtility
/// <returns>Address family</returns> {
public static AddressFamily GetAddressFamily(IPAddress ipAddress) => /// <summary>
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 /// Return AddressFamily for the IP address
ipAddress.AddressFamily; /// </summary>
/// <param name="ipAddress">IP address to check</param>
/// <returns>Address family</returns>
public static AddressFamily GetAddressFamily(IPAddress ipAddress)
{
#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
return ipAddress.AddressFamily;
#else #else
return (ipAddress.ToString().IndexOf(':') != -1) ? return (ipAddress.ToString().IndexOf(':') != -1) ?
AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork; AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
#endif #endif
}
}
} /// <summary>
/// MQTT SSL utility class
/// <summary> /// </summary>
/// MQTT SSL utility class public static class MqttSslUtility
/// </summary>
public static class MqttSslUtility {
#if !MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 && !COMPACT_FRAMEWORK
public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol) => mqttSslProtocol switch
{ {
MqttSslProtocols.None => SslProtocols.None, #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 && !COMPACT_FRAMEWORK)
//MqttSslProtocols.SSLv3 => SslProtocols.Ssl3, public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
MqttSslProtocols.TLSv1_0 => SslProtocols.Tls, {
MqttSslProtocols.TLSv1_1 => SslProtocols.Tls11, switch (mqttSslProtocol)
MqttSslProtocols.TLSv1_2 => SslProtocols.Tls12, {
_ => throw new ArgumentException("SSL/TLS protocol version not supported"), case MqttSslProtocols.None:
}; return SslProtocols.None;
#elif MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 case MqttSslProtocols.SSLv3:
public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol) return SslProtocols.Ssl3;
case MqttSslProtocols.TLSv1_0:
return SslProtocols.Tls;
/*case MqttSslProtocols.TLSv1_1:
return SslProtocols.Tls11;
case MqttSslProtocols.TLSv1_2:
return SslProtocols.Tls12;*/
default:
throw new ArgumentException("SSL/TLS protocol version not supported");
}
}
#elif (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
{ {
switch (mqttSslProtocol) switch (mqttSslProtocol)
{ {
@ -425,5 +468,5 @@ namespace uPLibrary.Networking.M2Mqtt {
} }
} }
#endif #endif
} }
} }

View File

@ -13,7 +13,7 @@ and the Eclipse Distribution License is available at
Contributors: Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !NETCOREAPP
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -41,5 +41,4 @@ using System.Runtime.InteropServices;
// to avoid compilation error (AssemblyFileVersionAttribute doesn't exist) under .Net CF 3.5 // to avoid compilation error (AssemblyFileVersionAttribute doesn't exist) under .Net CF 3.5
#if !WindowsCE #if !WindowsCE
[assembly: AssemblyFileVersion("4.3.0.0")] [assembly: AssemblyFileVersion("4.3.0.0")]
#endif
#endif #endif

View File

@ -14,18 +14,20 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System; namespace uPLibrary.Networking.M2Mqtt.Session
{
namespace uPLibrary.Networking.M2Mqtt.Session {
/// <summary>
/// MQTT Client Session
/// </summary>
public class MqttClientSession : MqttSession {
/// <summary> /// <summary>
/// Constructor /// MQTT Client Session
/// </summary> /// </summary>
/// <param name="clientId">Client Id to create session</param> public class MqttClientSession : MqttSession
public MqttClientSession(String clientId) : base(clientId) { {
} /// <summary>
} /// Constructor
/// </summary>
/// <param name="clientId">Client Id to create session</param>
public MqttClientSession(string clientId)
: base(clientId)
{
}
}
} }

View File

@ -14,46 +14,50 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using System.Collections; using System.Collections;
namespace uPLibrary.Networking.M2Mqtt.Session { namespace uPLibrary.Networking.M2Mqtt.Session
/// <summary> {
/// MQTT Session base class
/// </summary>
public abstract class MqttSession {
/// <summary> /// <summary>
/// Client Id /// MQTT Session base class
/// </summary> /// </summary>
public String ClientId { get; set; } public abstract class MqttSession
{
/// <summary> /// <summary>
/// Messages inflight during session /// Client Id
/// </summary> /// </summary>
public Hashtable InflightMessages { get; set; } public string ClientId { get; set; }
/// <summary> /// <summary>
/// Constructor /// Messages inflight during session
/// </summary> /// </summary>
public MqttSession() public Hashtable InflightMessages { get; set; }
: this(null) {
} /// <summary>
/// Constructor
/// <summary> /// </summary>
/// Constructor public MqttSession()
/// </summary> : this(null)
/// <param name="clientId">Client Id to create session</param> {
public MqttSession(String clientId) { }
this.ClientId = clientId;
this.InflightMessages = new Hashtable(); /// <summary>
} /// Constructor
/// </summary>
/// <summary> /// <param name="clientId">Client Id to create session</param>
/// Clean session public MqttSession(string clientId)
/// </summary> {
public virtual void Clear() { this.ClientId = clientId;
this.ClientId = null; this.InflightMessages = new Hashtable();
this.InflightMessages.Clear(); }
}
} /// <summary>
} /// Clean session
/// </summary>
public virtual void Clear()
{
this.ClientId = null;
this.InflightMessages.Clear();
}
}
}

View File

@ -17,31 +17,34 @@ Contributors:
using System; using System;
using System.Collections; using System.Collections;
namespace uPLibrary.Networking.M2Mqtt.Utility { namespace uPLibrary.Networking.M2Mqtt.Utility
/// <summary> {
/// Extension class for a Queue
/// </summary>
internal static class QueueExtension {
/// <summary> /// <summary>
/// Predicate for searching inside a queue /// Extension class for a Queue
/// </summary> /// </summary>
/// <param name="item">Item of the queue</param> internal static class QueueExtension
/// <returns>Result of predicate</returns> {
internal delegate Boolean QueuePredicate(Object item); /// <summary>
/// Predicate for searching inside a queue
/// <summary> /// </summary>
/// Get (without removing) an item from queue based on predicate /// <param name="item">Item of the queue</param>
/// </summary> /// <returns>Result of predicate</returns>
/// <param name="queue">Queue in which to search</param> internal delegate bool QueuePredicate(object item);
/// <param name="predicate">Predicate to verify to get item</param>
/// <returns>Item matches the predicate</returns> /// <summary>
internal static Object Get(Queue queue, QueuePredicate predicate) { /// Get (without removing) an item from queue based on predicate
foreach (Object item in queue) { /// </summary>
if (predicate(item)) { /// <param name="queue">Queue in which to search</param>
return item; /// <param name="predicate">Predicate to verify to get item</param>
} /// <returns>Item matches the predicate</returns>
} internal static object Get(Queue queue, QueuePredicate predicate)
return null; {
} foreach (var item in queue)
} {
if (predicate(item))
return item;
}
return null;
}
}
} }

View File

@ -14,57 +14,73 @@ Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
using System;
using System.Diagnostics; using System.Diagnostics;
namespace uPLibrary.Networking.M2Mqtt.Utility { namespace uPLibrary.Networking.M2Mqtt.Utility
/// <summary> {
/// Tracing levels /// <summary>
/// </summary> /// Tracing levels
public enum TraceLevel { /// </summary>
Error = 0x01, public enum TraceLevel
Warning = 0x02, {
Information = 0x04, Error = 0x01,
Verbose = 0x0F, Warning = 0x02,
Frame = 0x10, Information = 0x04,
Queuing = 0x20 Verbose = 0x0F,
} Frame = 0x10,
Queuing = 0x20
// delegate for writing trace }
public delegate void WriteTrace(String format, params Object[] args);
// delegate for writing trace
/// <summary> public delegate void WriteTrace(string format, params object[] args);
/// Tracing class
/// </summary> /// <summary>
public static class Trace { /// Tracing class
public static TraceLevel TraceLevel; /// </summary>
public static WriteTrace TraceListener; public static class Trace
{
[Conditional("DEBUG")] public static TraceLevel TraceLevel;
public static void Debug(String format, params Object[] args) => TraceListener?.Invoke(format, args); public static WriteTrace TraceListener;
public static void WriteLine(TraceLevel level, String format) { [Conditional("DEBUG")]
if ((level & TraceLevel) > 0) { public static void Debug(string format, params object[] args)
TraceListener.Invoke(format); {
} if (TraceListener != null)
} {
TraceListener(format, args);
public static void WriteLine(TraceLevel level, String format, Object arg1) { }
if ( (level & TraceLevel) > 0) { }
TraceListener.Invoke(format, arg1);
} public static void WriteLine(TraceLevel level, string format)
} {
if (TraceListener != null && (level & TraceLevel) > 0)
public static void WriteLine(TraceLevel level, String format, Object arg1, Object arg2) { {
if ((level & TraceLevel) > 0) { TraceListener(format);
TraceListener.Invoke(format, arg1, arg2); }
} }
}
public static void WriteLine(TraceLevel level, string format, object arg1)
public static void WriteLine(TraceLevel level, String format, Object arg1, Object arg2, Object arg3) { {
if ((level & TraceLevel) > 0) { if (TraceListener != null && (level & TraceLevel) > 0)
TraceListener.Invoke(format, arg1, arg2, arg3); {
} TraceListener(format, arg1);
} }
} }
public static void WriteLine(TraceLevel level, string format, object arg1, object arg2)
{
if (TraceListener != null && (level & TraceLevel) > 0)
{
TraceListener(format, arg1, arg2);
}
}
public static void WriteLine(TraceLevel level, string format, object arg1, object arg2, object arg3)
{
if (TraceListener != null && (level & TraceLevel) > 0)
{
TraceListener(format, arg1, arg2, arg3);
}
}
}
} }

View File

@ -13,7 +13,7 @@ and the Eclipse Distribution License is available at
Contributors: Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !NETCOREAPP
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -33,5 +33,4 @@ namespace uPLibrary.Networking.M2Mqtt
public static void SleepThread(int millisecondsTimeout) { Task.Delay(millisecondsTimeout).RunSynchronously(); } public static void SleepThread(int millisecondsTimeout) { Task.Delay(millisecondsTimeout).RunSynchronously(); }
} }
} }
#endif

View File

@ -13,7 +13,7 @@ and the Eclipse Distribution License is available at
Contributors: Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !NETCOREAPP
using System.Collections.Generic; using System.Collections.Generic;
namespace uPLibrary.Networking.M2Mqtt namespace uPLibrary.Networking.M2Mqtt
@ -25,4 +25,3 @@ namespace uPLibrary.Networking.M2Mqtt
{ {
} }
} }
#endif

View File

@ -13,7 +13,7 @@ and the Eclipse Distribution License is available at
Contributors: Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !NETCOREAPP
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -177,4 +177,3 @@ namespace uPLibrary.Networking.M2Mqtt
} }
} }
} }
#endif

View File

@ -13,7 +13,7 @@ and the Eclipse Distribution License is available at
Contributors: Contributors:
Paolo Patierno - initial API and implementation and/or initial documentation Paolo Patierno - initial API and implementation and/or initial documentation
*/ */
#if !NETCOREAPP
using System.Collections.Generic; using System.Collections.Generic;
namespace uPLibrary.Networking.M2Mqtt namespace uPLibrary.Networking.M2Mqtt
@ -25,4 +25,3 @@ namespace uPLibrary.Networking.M2Mqtt
{ {
} }
} }
#endif

View File

@ -1,4 +0,0 @@
# M2Mqtt
Based on https://github.com/eclipse/paho.mqtt.m2mqtt
Maybe you find this Repo on Github. This is a mirror from [here](https://git.blubbfish.net/vs_librarys/mqtt).