MqttNetworkChannel.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. Giovanni Paolo Vigano' - preprocessor directives for platform dependent compilation in Unity
  14. */
  15. #if ((!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Threading.Tasks;
  21. using Windows.Networking;
  22. using Windows.Networking.Sockets;
  23. using System.Runtime.InteropServices.WindowsRuntime;
  24. using Windows.Storage.Streams;
  25. using System.Threading;
  26. namespace uPLibrary.Networking.M2Mqtt
  27. {
  28. public class MqttNetworkChannel : IMqttNetworkChannel
  29. {
  30. // stream socket for communication
  31. private StreamSocket socket;
  32. // remote host information
  33. private HostName remoteHostName;
  34. private int remotePort;
  35. // using SSL
  36. private bool secure;
  37. // SSL/TLS protocol version
  38. private MqttSslProtocols sslProtocol;
  39. /// <summary>
  40. /// Constructor
  41. /// </summary>
  42. /// <param name="socket">Socket opened with the client</param>
  43. public MqttNetworkChannel(StreamSocket socket)
  44. {
  45. this.socket = socket;
  46. this.sslProtocol = MqttSslProtocols.None;
  47. }
  48. /// <summary>
  49. /// Constructor
  50. /// </summary>
  51. /// <param name="remoteHostName">Remote Host name</param>
  52. /// <param name="remotePort">Remote port</param>
  53. /// <param name="secure">Using SSL</param>
  54. /// <param name="sslProtocol">SSL/TLS protocol version</param>
  55. public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, MqttSslProtocols sslProtocol)
  56. {
  57. this.remoteHostName = new HostName(remoteHostName);
  58. this.remotePort = remotePort;
  59. this.secure = secure;
  60. this.sslProtocol = sslProtocol;
  61. if (secure && (sslProtocol == MqttSslProtocols.None))
  62. throw new ArgumentException("For secure connection, an SSL/TLS protocol version is needed");
  63. }
  64. public bool DataAvailable
  65. {
  66. get { return true; }
  67. }
  68. public int Receive(byte[] buffer)
  69. {
  70. IBuffer result;
  71. // read all data needed (until fill buffer)
  72. int idx = 0;
  73. while (idx < buffer.Length)
  74. {
  75. // fixed scenario with socket closed gracefully by peer/broker and
  76. // Read return 0. Avoid infinite loop.
  77. // read is executed synchronously
  78. result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask().Result;
  79. if (result.Length == 0)
  80. return 0;
  81. idx += (int)result.Length;
  82. }
  83. return buffer.Length;
  84. }
  85. public int Receive(byte[] buffer, int timeout)
  86. {
  87. CancellationTokenSource cts = new CancellationTokenSource(timeout);
  88. try
  89. {
  90. IBuffer result;
  91. // read all data needed (until fill buffer)
  92. int idx = 0;
  93. while (idx < buffer.Length)
  94. {
  95. // fixed scenario with socket closed gracefully by peer/broker and
  96. // Read return 0. Avoid infinite loop.
  97. // read is executed synchronously
  98. result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask(cts.Token).Result;
  99. if (result.Length == 0)
  100. return 0;
  101. idx += (int)result.Length;
  102. }
  103. return buffer.Length;
  104. }
  105. catch (TaskCanceledException)
  106. {
  107. return 0;
  108. }
  109. }
  110. public int Send(byte[] buffer)
  111. {
  112. // send is executed synchronously
  113. return (int)this.socket.OutputStream.WriteAsync(buffer.AsBuffer()).AsTask().Result;
  114. }
  115. public void Close()
  116. {
  117. this.socket.Dispose();
  118. }
  119. public void Connect()
  120. {
  121. this.socket = new StreamSocket();
  122. // connection is executed synchronously
  123. this.socket.ConnectAsync(this.remoteHostName,
  124. this.remotePort.ToString(),
  125. MqttSslUtility.ToSslPlatformEnum(this.sslProtocol)).AsTask().Wait();
  126. }
  127. public void Accept()
  128. {
  129. // TODO : SSL support with StreamSocket / StreamSocketListener seems to be NOT supported
  130. return;
  131. }
  132. }
  133. /// <summary>
  134. /// MQTT SSL utility class
  135. /// </summary>
  136. public static class MqttSslUtility
  137. {
  138. public static SocketProtectionLevel ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
  139. {
  140. switch (mqttSslProtocol)
  141. {
  142. case MqttSslProtocols.None:
  143. return SocketProtectionLevel.PlainSocket;
  144. case MqttSslProtocols.SSLv3:
  145. return SocketProtectionLevel.SslAllowNullEncryption;
  146. case MqttSslProtocols.TLSv1_0:
  147. return SocketProtectionLevel.Tls10;
  148. case MqttSslProtocols.TLSv1_1:
  149. return SocketProtectionLevel.Tls11;
  150. case MqttSslProtocols.TLSv1_2:
  151. return SocketProtectionLevel.Tls12;
  152. default:
  153. throw new ArgumentException("SSL/TLS protocol version not supported");
  154. }
  155. }
  156. }
  157. }
  158. #endif