123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /************************************************************************************
- Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
- Licensed under the Oculus Utilities SDK License Version 1.31 (the "License"); you may not use
- the Utilities SDK except in compliance with the License, which is provided at the time of installation
- or download, or which otherwise accompanies this software in either electronic or hard copy form.
- You may obtain a copy of the License at
- https://developer.oculus.com/licenses/utilities-1.31
- Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
- under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
- ANY KIND, either express or implied. See the License for the specific language governing
- permissions and limitations under the License.
- ************************************************************************************/
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Net;
- using System.Net.Sockets;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- using System.Threading;
- using UnityEngine;
- using Debug = UnityEngine.Debug;
- public class OVRNetwork
- {
- public const int MaxBufferLength = 65536;
- public const int MaxPayloadLength = MaxBufferLength - FrameHeader.StructSize;
- public const uint FrameHeaderMagicIdentifier = 0x5283A76B;
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- struct FrameHeader
- {
- public uint protocolIdentifier;
- public int payloadType;
- public int payloadLength;
- public const int StructSize = sizeof(uint) + sizeof(int) + sizeof(int);
- // endianness conversion is NOT handled since all our current mobile/PC devices are little-endian
- public byte[] ToBytes()
- {
- int size = Marshal.SizeOf(this);
- Trace.Assert(size == StructSize);
- byte[] arr = new byte[size];
- IntPtr ptr = Marshal.AllocHGlobal(size);
- Marshal.StructureToPtr(this, ptr, true);
- Marshal.Copy(ptr, arr, 0, size);
- Marshal.FreeHGlobal(ptr);
- return arr;
- }
- public static FrameHeader FromBytes(byte[] arr)
- {
- FrameHeader header = new FrameHeader();
- int size = Marshal.SizeOf(header);
- Trace.Assert(size == StructSize);
- IntPtr ptr = Marshal.AllocHGlobal(size);
- Marshal.Copy(arr, 0, ptr, size);
- header = (FrameHeader)Marshal.PtrToStructure(ptr, header.GetType());
- Marshal.FreeHGlobal(ptr);
- return header;
- }
- }
- public class OVRNetworkTcpServer
- {
- public TcpListener tcpListener = null;
- private readonly object clientsLock = new object();
- public readonly List<TcpClient> clients = new List<TcpClient>();
- public void StartListening(int listeningPort)
- {
- if (tcpListener != null)
- {
- Debug.LogWarning("[OVRNetworkTcpServer] tcpListener is not null");
- return;
- }
- IPAddress localAddr = IPAddress.Any;
- tcpListener = new TcpListener(localAddr, listeningPort);
- try
- {
- tcpListener.Start();
- Debug.LogFormat("TcpListener started. Local endpoint: {0}", tcpListener.LocalEndpoint.ToString());
- }
- catch (SocketException e)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpServer] Unsable to start TcpListener. Socket exception: {0}", e.Message);
- 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");
- Debug.LogWarning("If the port is forwarded through ADB, use the Android Tools in Tools/Oculus/System Metrics Profiler to kill the server");
- tcpListener = null;
- }
- if (tcpListener != null)
- {
- Debug.LogFormat("[OVRNetworkTcpServer] Start Listening on port {0}", listeningPort);
- try
- {
- tcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), tcpListener);
- }
- catch (Exception e)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpServer] can't accept new client: {0}", e.Message);
- }
- }
- }
- public void StopListening()
- {
- if (tcpListener == null)
- {
- Debug.LogWarning("[OVRNetworkTcpServer] tcpListener is null");
- return;
- }
- lock (clientsLock)
- {
- clients.Clear();
- }
- tcpListener.Stop();
- tcpListener = null;
- Debug.Log("[OVRNetworkTcpServer] Stopped listening");
- }
- private void DoAcceptTcpClientCallback(IAsyncResult ar)
- {
- TcpListener listener = ar.AsyncState as TcpListener;
- try
- {
- TcpClient client = listener.EndAcceptTcpClient(ar);
- lock (clientsLock)
- {
- clients.Add(client);
- Debug.Log("[OVRNetworkTcpServer] client added");
- }
- try
- {
- tcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), tcpListener);
- }
- catch (Exception e)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpServer] can't accept new client: {0}", e.Message);
- }
- }
- catch (ObjectDisposedException)
- {
- // Do nothing. It happens when stop preview in editor, which is normal behavior.
- }
- catch (Exception e)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpServer] EndAcceptTcpClient failed: {0}", e.Message);
- }
- }
- public bool HasConnectedClient()
- {
- lock (clientsLock)
- {
- foreach (TcpClient client in clients)
- {
- if (client.Connected)
- {
- return true;
- }
- }
- }
- return false;
- }
- public void Broadcast(int payloadType, byte[] payload)
- {
- if (payload.Length > OVRNetwork.MaxPayloadLength)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpServer] drop payload because it's too long: {0} bytes", payload.Length);
- }
- FrameHeader header = new FrameHeader();
- header.protocolIdentifier = FrameHeaderMagicIdentifier;
- header.payloadType = payloadType;
- header.payloadLength = payload.Length;
- byte[] headerBuffer = header.ToBytes();
- byte[] dataBuffer = new byte[headerBuffer.Length + payload.Length];
- headerBuffer.CopyTo(dataBuffer, 0);
- payload.CopyTo(dataBuffer, headerBuffer.Length);
- lock (clientsLock)
- {
- foreach (TcpClient client in clients)
- {
- if (client.Connected)
- {
- try
- {
- client.GetStream().BeginWrite(dataBuffer, 0, dataBuffer.Length, new AsyncCallback(DoWriteDataCallback), client.GetStream());
- }
- catch (SocketException e)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpServer] close client because of socket error: {0}", e.Message);
- client.GetStream().Close();
- client.Close();
- }
- }
- }
- }
- }
- private void DoWriteDataCallback(IAsyncResult ar)
- {
- NetworkStream stream = ar.AsyncState as NetworkStream;
- stream.EndWrite(ar);
- }
- }
- public class OVRNetworkTcpClient
- {
- public Action connectionStateChangedCallback;
- public Action<int, byte[], int, int> payloadReceivedCallback;
- public enum ConnectionState
- {
- Disconnected,
- Connected,
- Connecting
- }
- public ConnectionState connectionState
- {
- get
- {
- if (tcpClient == null)
- {
- return ConnectionState.Disconnected;
- }
- else
- {
- if (tcpClient.Connected)
- {
- return ConnectionState.Connected;
- }
- else
- {
- return ConnectionState.Connecting;
- }
- }
- }
- }
- public bool Connected
- {
- get
- {
- return connectionState == ConnectionState.Connected;
- }
- }
- TcpClient tcpClient = null;
- byte[][] receivedBuffers = { new byte[OVRNetwork.MaxBufferLength], new byte[OVRNetwork.MaxBufferLength] };
- int receivedBufferIndex = 0;
- int receivedBufferDataSize = 0;
- ManualResetEvent readyReceiveDataEvent = new ManualResetEvent(true);
- public void Connect(int listeningPort)
- {
- if (tcpClient == null)
- {
- receivedBufferIndex = 0;
- receivedBufferDataSize = 0;
- readyReceiveDataEvent.Set();
- string remoteAddress = "127.0.0.1";
- tcpClient = new TcpClient(AddressFamily.InterNetwork);
- tcpClient.BeginConnect(remoteAddress, listeningPort, new AsyncCallback(ConnectCallback), tcpClient);
- if (connectionStateChangedCallback != null)
- {
- connectionStateChangedCallback();
- }
- }
- else
- {
- Debug.LogWarning("[OVRNetworkTcpClient] already connected");
- }
- }
- void ConnectCallback(IAsyncResult ar)
- {
- try
- {
- TcpClient client = ar.AsyncState as TcpClient;
- client.EndConnect(ar);
- Debug.LogFormat("[OVRNetworkTcpClient] connected to {0}", client.ToString());
- }
- catch (Exception e)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpClient] connect error {0}", e.Message);
- }
- if (connectionStateChangedCallback != null)
- {
- connectionStateChangedCallback();
- }
- }
- public void Disconnect()
- {
- if (tcpClient != null)
- {
- if (!readyReceiveDataEvent.WaitOne(5))
- {
- Debug.LogWarning("[OVRNetworkTcpClient] readyReceiveDataEvent not signaled. data receiving timeout?");
- }
- Debug.Log("[OVRNetworkTcpClient] close tcpClient");
- try
- {
- tcpClient.GetStream().Close();
- tcpClient.Close();
- }
- catch (Exception e)
- {
- Debug.LogWarning("[OVRNetworkTcpClient] " + e.Message);
- }
- tcpClient = null;
- if (connectionStateChangedCallback != null)
- {
- connectionStateChangedCallback();
- }
- }
- else
- {
- Debug.LogWarning("[OVRNetworkTcpClient] not connected");
- }
- }
- public void Tick()
- {
- if (tcpClient == null || !tcpClient.Connected)
- {
- return;
- }
- if (readyReceiveDataEvent.WaitOne(TimeSpan.Zero))
- {
- if (tcpClient.GetStream().DataAvailable)
- {
- if (receivedBufferDataSize >= OVRNetwork.MaxBufferLength)
- {
- Debug.LogWarning("[OVRNetworkTcpClient] receive buffer overflow. It should not happen since we have the constraint on message size");
- Disconnect();
- return;
- }
- readyReceiveDataEvent.Reset();
- int maximumDataSize = OVRSystemPerfMetrics.MaxBufferLength - receivedBufferDataSize;
- tcpClient.GetStream().BeginRead(receivedBuffers[receivedBufferIndex], receivedBufferDataSize, maximumDataSize, new AsyncCallback(OnReadDataCallback), tcpClient.GetStream());
- }
- }
- }
- void OnReadDataCallback(IAsyncResult ar)
- {
- NetworkStream stream = ar.AsyncState as NetworkStream;
- try
- {
- int numBytes = stream.EndRead(ar);
- receivedBufferDataSize += numBytes;
- while (receivedBufferDataSize >= FrameHeader.StructSize)
- {
- FrameHeader header = FrameHeader.FromBytes(receivedBuffers[receivedBufferIndex]);
- if (header.protocolIdentifier != OVRNetwork.FrameHeaderMagicIdentifier)
- {
- Debug.LogWarning("[OVRNetworkTcpClient] header mismatch");
- Disconnect();
- return;
- }
- if (header.payloadLength < 0 || header.payloadLength > OVRNetwork.MaxPayloadLength)
- {
- Debug.LogWarningFormat("[OVRNetworkTcpClient] Sanity check failed. PayloadLength %d", header.payloadLength);
- Disconnect();
- return;
- }
- if (receivedBufferDataSize >= FrameHeader.StructSize + header.payloadLength)
- {
- if (payloadReceivedCallback != null)
- {
- payloadReceivedCallback(header.payloadType, receivedBuffers[receivedBufferIndex], FrameHeader.StructSize, header.payloadLength);
- }
- // swap receive buffer
- int newBufferIndex = 1 - receivedBufferIndex;
- int newBufferDataSize = receivedBufferDataSize - (FrameHeader.StructSize + header.payloadLength);
- if (newBufferDataSize > 0)
- {
- Array.Copy(receivedBuffers[receivedBufferIndex], (FrameHeader.StructSize + header.payloadLength), receivedBuffers[newBufferIndex], 0, newBufferDataSize);
- }
- receivedBufferIndex = newBufferIndex;
- receivedBufferDataSize = newBufferDataSize;
- }
- }
- readyReceiveDataEvent.Set();
- }
- catch (SocketException e)
- {
- Debug.LogErrorFormat("[OVRNetworkTcpClient] OnReadDataCallback: socket error: {0}", e.Message);
- Disconnect();
- }
- }
- }
- }
|