/* M2Mqtt - MQTT Client Library for .Net Copyright (c) 2014, Paolo Patierno, All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. */ #if SSL #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3) using Microsoft.SPOT.Net.Security; #else using System.Net.Security; using System.Security.Authentication; #endif #endif using System.Net.Sockets; using System.Net; using System.Security.Cryptography.X509Certificates; namespace uPLibrary.Networking.M2Mqtt { /// /// Channel to communicate over the network /// public class MqttNetworkChannel : IMqttNetworkChannel { // remote host information private string remoteHostName; private IPAddress remoteIpAddress; private int remotePort; // socket for communication private Socket socket; // using SSL private bool secure; // CA certificate private X509Certificate caCert; /// /// Remote host name /// public string RemoteHostName { get { return this.remoteHostName; } } /// /// Remote IP address /// public IPAddress RemoteIpAddress { get { return this.remoteIpAddress; } } /// /// Remote port /// public int RemotePort { get { return this.remotePort; } } #if SSL // SSL stream private SslStream sslStream; #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3) private NetworkStream netStream; #endif #endif /// /// Data available on the channel /// public bool DataAvailable { get { #if SSL #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3) if (secure) return this.sslStream.DataAvailable; else return (this.socket.Available > 0); #else if (secure) return this.netStream.DataAvailable; else return (this.socket.Available > 0); #endif #else return (this.socket.Available > 0); #endif } } /// /// Constructor /// /// Socket opened with the client public MqttNetworkChannel(Socket socket) { this.socket = socket; } /// /// Constructor /// /// Remote Host name /// Remote IP address /// Remote port public MqttNetworkChannel(string remoteHostName, IPAddress remoteIpAddress, int remotePort) : this(remoteHostName, remoteIpAddress, remotePort, false, null) { } /// /// Constructor /// /// Remote Host name /// Remote IP address /// Remote port /// Using SSL /// CA certificate public MqttNetworkChannel(string remoteHostName, IPAddress remoteIpAddress, int remotePort, bool secure, X509Certificate caCert) { this.remoteHostName = remoteHostName; this.remoteIpAddress = remoteIpAddress; this.remotePort = remotePort; this.secure = secure; this.caCert = caCert; } /// /// Connect to remote server /// public void Connect() { this.socket = new Socket(IPAddressUtility.GetAddressFamily(this.remoteIpAddress), SocketType.Stream, ProtocolType.Tcp); // try connection to the broker this.socket.Connect(new IPEndPoint(this.remoteIpAddress, this.remotePort)); #if SSL // secure channel requested if (secure) { // create SSL stream #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3) this.sslStream = new SslStream(this.socket); #else this.netStream = new NetworkStream(this.socket); this.sslStream = new SslStream(this.netStream); #endif // server authentication (SSL/TLS handshake) #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3) this.sslStream.AuthenticateAsClient(this.remoteHostName, null, new X509Certificate[] { this.caCert }, SslVerification.CertificateRequired, SslProtocols.TLSv1); #else this.sslStream.AuthenticateAsClient(this.remoteHostName, new X509CertificateCollection(new X509Certificate[] { this.caCert }), SslProtocols.Tls, false); #endif } #endif } /// /// Send data on the network channel /// /// Data buffer to send /// Number of byte sent public int Send(byte[] buffer) { #if SSL if (this.secure) { this.sslStream.Write(buffer, 0, buffer.Length); return buffer.Length; } else return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None); #else return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None); #endif } /// /// Receive data from the network /// /// Data buffer for receiving data /// Number of bytes received public int Receive(byte[] buffer) { #if SSL if (this.secure) { // read all data needed (until fill buffer) int idx = 0; while (idx < buffer.Length) { idx += this.sslStream.Read(buffer, idx, buffer.Length - idx); } return buffer.Length; } else { // read all data needed (until fill buffer) int idx = 0; while (idx < buffer.Length) { idx += this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None); } return buffer.Length; } #else // read all data needed (until fill buffer) int idx = 0; while (idx < buffer.Length) { idx += this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None); } return buffer.Length; #endif } /// /// Close the network channel /// public void Close() { #if SSL if (this.secure) { #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3) this.netStream.Close(); #endif this.sslStream.Close(); } this.socket.Close(); #else this.socket.Close(); #endif } } /// /// IPAddress Utility class /// public static class IPAddressUtility { /// /// Return AddressFamily for the IP address /// /// IP address to check /// Address family public static AddressFamily GetAddressFamily(IPAddress ipAddress) { #if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3) return ipAddress.AddressFamily; #else return (ipAddress.ToString().IndexOf(':') != -1) ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork; #endif } } }