Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
12 KiB

  1. /************************************************************************************
  2. Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
  3. Licensed under the Oculus Utilities SDK License Version 1.31 (the "License"); you may not use
  4. the Utilities SDK except in compliance with the License, which is provided at the time of installation
  5. or download, or which otherwise accompanies this software in either electronic or hard copy form.
  6. You may obtain a copy of the License at
  7. https://developer.oculus.com/licenses/utilities-1.31
  8. Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
  9. under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
  10. ANY KIND, either express or implied. See the License for the specific language governing
  11. permissions and limitations under the License.
  12. ************************************************************************************/
  13. using System;
  14. using System.Collections;
  15. using System.Collections.Generic;
  16. using System.Net;
  17. using System.Net.Sockets;
  18. using System.Diagnostics;
  19. using System.Runtime.InteropServices;
  20. using System.Threading;
  21. using UnityEngine;
  22. using Debug = UnityEngine.Debug;
  23. public class OVRNetwork
  24. {
  25. public const int MaxBufferLength = 65536;
  26. public const int MaxPayloadLength = MaxBufferLength - FrameHeader.StructSize;
  27. public const uint FrameHeaderMagicIdentifier = 0x5283A76B;
  28. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  29. struct FrameHeader
  30. {
  31. public uint protocolIdentifier;
  32. public int payloadType;
  33. public int payloadLength;
  34. public const int StructSize = sizeof(uint) + sizeof(int) + sizeof(int);
  35. // endianness conversion is NOT handled since all our current mobile/PC devices are little-endian
  36. public byte[] ToBytes()
  37. {
  38. int size = Marshal.SizeOf(this);
  39. Trace.Assert(size == StructSize);
  40. byte[] arr = new byte[size];
  41. IntPtr ptr = Marshal.AllocHGlobal(size);
  42. Marshal.StructureToPtr(this, ptr, true);
  43. Marshal.Copy(ptr, arr, 0, size);
  44. Marshal.FreeHGlobal(ptr);
  45. return arr;
  46. }
  47. public static FrameHeader FromBytes(byte[] arr)
  48. {
  49. FrameHeader header = new FrameHeader();
  50. int size = Marshal.SizeOf(header);
  51. Trace.Assert(size == StructSize);
  52. IntPtr ptr = Marshal.AllocHGlobal(size);
  53. Marshal.Copy(arr, 0, ptr, size);
  54. header = (FrameHeader)Marshal.PtrToStructure(ptr, header.GetType());
  55. Marshal.FreeHGlobal(ptr);
  56. return header;
  57. }
  58. }
  59. public class OVRNetworkTcpServer
  60. {
  61. public TcpListener tcpListener = null;
  62. private readonly object clientsLock = new object();
  63. public readonly List<TcpClient> clients = new List<TcpClient>();
  64. public void StartListening(int listeningPort)
  65. {
  66. if (tcpListener != null)
  67. {
  68. Debug.LogWarning("[OVRNetworkTcpServer] tcpListener is not null");
  69. return;
  70. }
  71. IPAddress localAddr = IPAddress.Any;
  72. tcpListener = new TcpListener(localAddr, listeningPort);
  73. try
  74. {
  75. tcpListener.Start();
  76. Debug.LogFormat("TcpListener started. Local endpoint: {0}", tcpListener.LocalEndpoint.ToString());
  77. }
  78. catch (SocketException e)
  79. {
  80. Debug.LogWarningFormat("[OVRNetworkTcpServer] Unsable to start TcpListener. Socket exception: {0}", e.Message);
  81. Debug.LogWarning("It could be caused by multiple instances listening at the same port, or the port is forwarded to the Android device through ADB");
  82. Debug.LogWarning("If the port is forwarded through ADB, use the Android Tools in Tools/Oculus/System Metrics Profiler to kill the server");
  83. tcpListener = null;
  84. }
  85. if (tcpListener != null)
  86. {
  87. Debug.LogFormat("[OVRNetworkTcpServer] Start Listening on port {0}", listeningPort);
  88. try
  89. {
  90. tcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), tcpListener);
  91. }
  92. catch (Exception e)
  93. {
  94. Debug.LogWarningFormat("[OVRNetworkTcpServer] can't accept new client: {0}", e.Message);
  95. }
  96. }
  97. }
  98. public void StopListening()
  99. {
  100. if (tcpListener == null)
  101. {
  102. Debug.LogWarning("[OVRNetworkTcpServer] tcpListener is null");
  103. return;
  104. }
  105. lock (clientsLock)
  106. {
  107. clients.Clear();
  108. }
  109. tcpListener.Stop();
  110. tcpListener = null;
  111. Debug.Log("[OVRNetworkTcpServer] Stopped listening");
  112. }
  113. private void DoAcceptTcpClientCallback(IAsyncResult ar)
  114. {
  115. TcpListener listener = ar.AsyncState as TcpListener;
  116. try
  117. {
  118. TcpClient client = listener.EndAcceptTcpClient(ar);
  119. lock (clientsLock)
  120. {
  121. clients.Add(client);
  122. Debug.Log("[OVRNetworkTcpServer] client added");
  123. }
  124. try
  125. {
  126. tcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), tcpListener);
  127. }
  128. catch (Exception e)
  129. {
  130. Debug.LogWarningFormat("[OVRNetworkTcpServer] can't accept new client: {0}", e.Message);
  131. }
  132. }
  133. catch (ObjectDisposedException)
  134. {
  135. // Do nothing. It happens when stop preview in editor, which is normal behavior.
  136. }
  137. catch (Exception e)
  138. {
  139. Debug.LogWarningFormat("[OVRNetworkTcpServer] EndAcceptTcpClient failed: {0}", e.Message);
  140. }
  141. }
  142. public bool HasConnectedClient()
  143. {
  144. lock (clientsLock)
  145. {
  146. foreach (TcpClient client in clients)
  147. {
  148. if (client.Connected)
  149. {
  150. return true;
  151. }
  152. }
  153. }
  154. return false;
  155. }
  156. public void Broadcast(int payloadType, byte[] payload)
  157. {
  158. if (payload.Length > OVRNetwork.MaxPayloadLength)
  159. {
  160. Debug.LogWarningFormat("[OVRNetworkTcpServer] drop payload because it's too long: {0} bytes", payload.Length);
  161. }
  162. FrameHeader header = new FrameHeader();
  163. header.protocolIdentifier = FrameHeaderMagicIdentifier;
  164. header.payloadType = payloadType;
  165. header.payloadLength = payload.Length;
  166. byte[] headerBuffer = header.ToBytes();
  167. byte[] dataBuffer = new byte[headerBuffer.Length + payload.Length];
  168. headerBuffer.CopyTo(dataBuffer, 0);
  169. payload.CopyTo(dataBuffer, headerBuffer.Length);
  170. lock (clientsLock)
  171. {
  172. foreach (TcpClient client in clients)
  173. {
  174. if (client.Connected)
  175. {
  176. try
  177. {
  178. client.GetStream().BeginWrite(dataBuffer, 0, dataBuffer.Length, new AsyncCallback(DoWriteDataCallback), client.GetStream());
  179. }
  180. catch (SocketException e)
  181. {
  182. Debug.LogWarningFormat("[OVRNetworkTcpServer] close client because of socket error: {0}", e.Message);
  183. client.GetStream().Close();
  184. client.Close();
  185. }
  186. }
  187. }
  188. }
  189. }
  190. private void DoWriteDataCallback(IAsyncResult ar)
  191. {
  192. NetworkStream stream = ar.AsyncState as NetworkStream;
  193. stream.EndWrite(ar);
  194. }
  195. }
  196. public class OVRNetworkTcpClient
  197. {
  198. public Action connectionStateChangedCallback;
  199. public Action<int, byte[], int, int> payloadReceivedCallback;
  200. public enum ConnectionState
  201. {
  202. Disconnected,
  203. Connected,
  204. Connecting
  205. }
  206. public ConnectionState connectionState
  207. {
  208. get
  209. {
  210. if (tcpClient == null)
  211. {
  212. return ConnectionState.Disconnected;
  213. }
  214. else
  215. {
  216. if (tcpClient.Connected)
  217. {
  218. return ConnectionState.Connected;
  219. }
  220. else
  221. {
  222. return ConnectionState.Connecting;
  223. }
  224. }
  225. }
  226. }
  227. public bool Connected
  228. {
  229. get
  230. {
  231. return connectionState == ConnectionState.Connected;
  232. }
  233. }
  234. TcpClient tcpClient = null;
  235. byte[][] receivedBuffers = { new byte[OVRNetwork.MaxBufferLength], new byte[OVRNetwork.MaxBufferLength] };
  236. int receivedBufferIndex = 0;
  237. int receivedBufferDataSize = 0;
  238. ManualResetEvent readyReceiveDataEvent = new ManualResetEvent(true);
  239. public void Connect(int listeningPort)
  240. {
  241. if (tcpClient == null)
  242. {
  243. receivedBufferIndex = 0;
  244. receivedBufferDataSize = 0;
  245. readyReceiveDataEvent.Set();
  246. string remoteAddress = "127.0.0.1";
  247. tcpClient = new TcpClient(AddressFamily.InterNetwork);
  248. tcpClient.BeginConnect(remoteAddress, listeningPort, new AsyncCallback(ConnectCallback), tcpClient);
  249. if (connectionStateChangedCallback != null)
  250. {
  251. connectionStateChangedCallback();
  252. }
  253. }
  254. else
  255. {
  256. Debug.LogWarning("[OVRNetworkTcpClient] already connected");
  257. }
  258. }
  259. void ConnectCallback(IAsyncResult ar)
  260. {
  261. try
  262. {
  263. TcpClient client = ar.AsyncState as TcpClient;
  264. client.EndConnect(ar);
  265. Debug.LogFormat("[OVRNetworkTcpClient] connected to {0}", client.ToString());
  266. }
  267. catch (Exception e)
  268. {
  269. Debug.LogWarningFormat("[OVRNetworkTcpClient] connect error {0}", e.Message);
  270. }
  271. if (connectionStateChangedCallback != null)
  272. {
  273. connectionStateChangedCallback();
  274. }
  275. }
  276. public void Disconnect()
  277. {
  278. if (tcpClient != null)
  279. {
  280. if (!readyReceiveDataEvent.WaitOne(5))
  281. {
  282. Debug.LogWarning("[OVRNetworkTcpClient] readyReceiveDataEvent not signaled. data receiving timeout?");
  283. }
  284. Debug.Log("[OVRNetworkTcpClient] close tcpClient");
  285. try
  286. {
  287. tcpClient.GetStream().Close();
  288. tcpClient.Close();
  289. }
  290. catch (Exception e)
  291. {
  292. Debug.LogWarning("[OVRNetworkTcpClient] " + e.Message);
  293. }
  294. tcpClient = null;
  295. if (connectionStateChangedCallback != null)
  296. {
  297. connectionStateChangedCallback();
  298. }
  299. }
  300. else
  301. {
  302. Debug.LogWarning("[OVRNetworkTcpClient] not connected");
  303. }
  304. }
  305. public void Tick()
  306. {
  307. if (tcpClient == null || !tcpClient.Connected)
  308. {
  309. return;
  310. }
  311. if (readyReceiveDataEvent.WaitOne(TimeSpan.Zero))
  312. {
  313. if (tcpClient.GetStream().DataAvailable)
  314. {
  315. if (receivedBufferDataSize >= OVRNetwork.MaxBufferLength)
  316. {
  317. Debug.LogWarning("[OVRNetworkTcpClient] receive buffer overflow. It should not happen since we have the constraint on message size");
  318. Disconnect();
  319. return;
  320. }
  321. readyReceiveDataEvent.Reset();
  322. int maximumDataSize = OVRSystemPerfMetrics.MaxBufferLength - receivedBufferDataSize;
  323. tcpClient.GetStream().BeginRead(receivedBuffers[receivedBufferIndex], receivedBufferDataSize, maximumDataSize, new AsyncCallback(OnReadDataCallback), tcpClient.GetStream());
  324. }
  325. }
  326. }
  327. void OnReadDataCallback(IAsyncResult ar)
  328. {
  329. NetworkStream stream = ar.AsyncState as NetworkStream;
  330. try
  331. {
  332. int numBytes = stream.EndRead(ar);
  333. receivedBufferDataSize += numBytes;
  334. while (receivedBufferDataSize >= FrameHeader.StructSize)
  335. {
  336. FrameHeader header = FrameHeader.FromBytes(receivedBuffers[receivedBufferIndex]);
  337. if (header.protocolIdentifier != OVRNetwork.FrameHeaderMagicIdentifier)
  338. {
  339. Debug.LogWarning("[OVRNetworkTcpClient] header mismatch");
  340. Disconnect();
  341. return;
  342. }
  343. if (header.payloadLength < 0 || header.payloadLength > OVRNetwork.MaxPayloadLength)
  344. {
  345. Debug.LogWarningFormat("[OVRNetworkTcpClient] Sanity check failed. PayloadLength %d", header.payloadLength);
  346. Disconnect();
  347. return;
  348. }
  349. if (receivedBufferDataSize >= FrameHeader.StructSize + header.payloadLength)
  350. {
  351. if (payloadReceivedCallback != null)
  352. {
  353. payloadReceivedCallback(header.payloadType, receivedBuffers[receivedBufferIndex], FrameHeader.StructSize, header.payloadLength);
  354. }
  355. // swap receive buffer
  356. int newBufferIndex = 1 - receivedBufferIndex;
  357. int newBufferDataSize = receivedBufferDataSize - (FrameHeader.StructSize + header.payloadLength);
  358. if (newBufferDataSize > 0)
  359. {
  360. Array.Copy(receivedBuffers[receivedBufferIndex], (FrameHeader.StructSize + header.payloadLength), receivedBuffers[newBufferIndex], 0, newBufferDataSize);
  361. }
  362. receivedBufferIndex = newBufferIndex;
  363. receivedBufferDataSize = newBufferDataSize;
  364. }
  365. }
  366. readyReceiveDataEvent.Set();
  367. }
  368. catch (SocketException e)
  369. {
  370. Debug.LogErrorFormat("[OVRNetworkTcpClient] OnReadDataCallback: socket error: {0}", e.Message);
  371. Disconnect();
  372. }
  373. }
  374. }
  375. }