MqttNetworkChannel.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. Copyright (c) 2013, 2014 Paolo Patierno
  3. All rights reserved. This program and the accompanying materials
  4. are made available under the terms of the Eclipse Public License v1.0
  5. and Eclipse Distribution License v1.0 which accompany this distribution.
  6. The Eclipse Public License is available at
  7. http://www.eclipse.org/legal/epl-v10.html
  8. and the Eclipse Distribution License is available at
  9. http://www.eclipse.org/org/documents/edl-v10.php.
  10. Contributors:
  11. Paolo Patierno - initial API and implementation and/or initial documentation
  12. */
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Threading.Tasks;
  18. using Windows.Networking;
  19. using Windows.Networking.Sockets;
  20. using System.Runtime.InteropServices.WindowsRuntime;
  21. using Windows.Storage.Streams;
  22. using System.Threading;
  23. namespace uPLibrary.Networking.M2Mqtt
  24. {
  25. public class MqttNetworkChannel : IMqttNetworkChannel
  26. {
  27. // stream socket for communication
  28. private StreamSocket socket;
  29. // remote host information
  30. private HostName remoteHostName;
  31. private int remotePort;
  32. // using SSL
  33. private bool secure;
  34. // SSL/TLS protocol version
  35. private MqttSslProtocols sslProtocol;
  36. /// <summary>
  37. /// Constructor
  38. /// </summary>
  39. /// <param name="socket">Socket opened with the client</param>
  40. public MqttNetworkChannel(StreamSocket socket)
  41. {
  42. this.socket = socket;
  43. this.sslProtocol = MqttSslProtocols.None;
  44. }
  45. /// <summary>
  46. /// Constructor
  47. /// </summary>
  48. /// <param name="remoteHostName">Remote Host name</param>
  49. /// <param name="remotePort">Remote port</param>
  50. /// <param name="secure">Using SSL</param>
  51. /// <param name="sslProtocol">SSL/TLS protocol version</param>
  52. public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, MqttSslProtocols sslProtocol)
  53. {
  54. this.remoteHostName = new HostName(remoteHostName);
  55. this.remotePort = remotePort;
  56. this.secure = secure;
  57. this.sslProtocol = sslProtocol;
  58. if (secure && (sslProtocol == MqttSslProtocols.None))
  59. throw new ArgumentException("For secure connection, an SSL/TLS protocol version is needed");
  60. }
  61. public bool DataAvailable
  62. {
  63. get { return true; }
  64. }
  65. public int Receive(byte[] buffer)
  66. {
  67. IBuffer result;
  68. // read all data needed (until fill buffer)
  69. int idx = 0;
  70. while (idx < buffer.Length)
  71. {
  72. // fixed scenario with socket closed gracefully by peer/broker and
  73. // Read return 0. Avoid infinite loop.
  74. // read is executed synchronously
  75. result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask().Result;
  76. if (result.Length == 0)
  77. return 0;
  78. idx += (int)result.Length;
  79. }
  80. return buffer.Length;
  81. }
  82. public int Receive(byte[] buffer, int timeout)
  83. {
  84. CancellationTokenSource cts = new CancellationTokenSource(timeout);
  85. try
  86. {
  87. IBuffer result;
  88. // read all data needed (until fill buffer)
  89. int idx = 0;
  90. while (idx < buffer.Length)
  91. {
  92. // fixed scenario with socket closed gracefully by peer/broker and
  93. // Read return 0. Avoid infinite loop.
  94. // read is executed synchronously
  95. result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask(cts.Token).Result;
  96. if (result.Length == 0)
  97. return 0;
  98. idx += (int)result.Length;
  99. }
  100. return buffer.Length;
  101. }
  102. catch (TaskCanceledException)
  103. {
  104. return 0;
  105. }
  106. }
  107. public int Send(byte[] buffer)
  108. {
  109. // send is executed synchronously
  110. return (int)this.socket.OutputStream.WriteAsync(buffer.AsBuffer()).AsTask().Result;
  111. }
  112. public void Close()
  113. {
  114. this.socket.Dispose();
  115. }
  116. public void Connect()
  117. {
  118. this.socket = new StreamSocket();
  119. // connection is executed synchronously
  120. this.socket.ConnectAsync(this.remoteHostName,
  121. this.remotePort.ToString(),
  122. MqttSslUtility.ToSslPlatformEnum(this.sslProtocol)).AsTask().Wait();
  123. }
  124. public void Accept()
  125. {
  126. // TODO : SSL support with StreamSocket / StreamSocketListener seems to be NOT supported
  127. return;
  128. }
  129. }
  130. /// <summary>
  131. /// MQTT SSL utility class
  132. /// </summary>
  133. public static class MqttSslUtility
  134. {
  135. public static SocketProtectionLevel ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
  136. {
  137. switch (mqttSslProtocol)
  138. {
  139. case MqttSslProtocols.None:
  140. return SocketProtectionLevel.PlainSocket;
  141. case MqttSslProtocols.SSLv3:
  142. return SocketProtectionLevel.SslAllowNullEncryption;
  143. case MqttSslProtocols.TLSv1_0:
  144. return SocketProtectionLevel.Tls10;
  145. case MqttSslProtocols.TLSv1_1:
  146. return SocketProtectionLevel.Tls11;
  147. case MqttSslProtocols.TLSv1_2:
  148. return SocketProtectionLevel.Tls12;
  149. default:
  150. throw new ArgumentException("SSL/TLS protocol version not supported");
  151. }
  152. }
  153. }
  154. }