clean project
This commit is contained in:
431
Assets/Oculus/VR/Scripts/Util/OVRNetwork.cs
Normal file
431
Assets/Oculus/VR/Scripts/Util/OVRNetwork.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user