init
This commit is contained in:
435
Assets/Photon/PhotonLibs/WebSocket/SocketWebTcp.cs
Normal file
435
Assets/Photon/PhotonLibs/WebSocket/SocketWebTcp.cs
Normal file
@@ -0,0 +1,435 @@
|
||||
#if UNITY_WEBGL || WEBSOCKET || WEBSOCKET_PROXYCONFIG
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="SocketWebTcp.cs" company="Exit Games GmbH">
|
||||
// Copyright (c) Exit Games GmbH. All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>
|
||||
// Internal class to encapsulate the network i/o functionality for the realtime library.
|
||||
// </summary>
|
||||
// <author>developer@exitgames.com</author>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace ExitGames.Client.Photon
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Scripting;
|
||||
using SupportClassPun = SupportClass;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Yield Instruction to Wait for real seconds. Very important to keep connection working if Time.TimeScale is altered, we still want accurate network events
|
||||
/// </summary>
|
||||
public sealed class WaitForRealSeconds : CustomYieldInstruction
|
||||
{
|
||||
private readonly float _endTime;
|
||||
|
||||
public override bool keepWaiting
|
||||
{
|
||||
get { return this._endTime > Time.realtimeSinceStartup; }
|
||||
}
|
||||
|
||||
public WaitForRealSeconds(float seconds)
|
||||
{
|
||||
this._endTime = Time.realtimeSinceStartup + seconds;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal class to encapsulate the network i/o functionality for the realtime libary.
|
||||
/// </summary>
|
||||
public class SocketWebTcp : IPhotonSocket, IDisposable
|
||||
{
|
||||
private WebSocket sock;
|
||||
|
||||
private readonly object syncer = new object();
|
||||
|
||||
[Preserve]
|
||||
public SocketWebTcp(PeerBase npeer) : base(npeer)
|
||||
{
|
||||
this.ServerAddress = npeer.ServerAddress;
|
||||
this.ProxyServerAddress = npeer.ProxyServerAddress;
|
||||
if (this.ReportDebugOfLevel(DebugLevel.INFO))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "new SocketWebTcp() for Unity. Server: " + this.ServerAddress + (String.IsNullOrEmpty(this.ProxyServerAddress) ? "" : ", Proxy: " + this.ProxyServerAddress));
|
||||
}
|
||||
|
||||
//this.Protocol = ConnectionProtocol.WebSocket;
|
||||
this.PollReceive = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.State = PhotonSocketState.Disconnecting;
|
||||
|
||||
if (this.sock != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.sock.Connected)
|
||||
{
|
||||
this.sock.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.EnqueueDebugReturn(DebugLevel.INFO, "Exception in SocketWebTcp.Dispose(): " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.sock = null;
|
||||
this.State = PhotonSocketState.Disconnected;
|
||||
}
|
||||
|
||||
GameObject websocketConnectionObject;
|
||||
|
||||
public override bool Connect()
|
||||
{
|
||||
//bool baseOk = base.Connect();
|
||||
//if (!baseOk)
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
|
||||
|
||||
this.State = PhotonSocketState.Connecting;
|
||||
|
||||
|
||||
if (this.websocketConnectionObject != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(this.websocketConnectionObject);
|
||||
}
|
||||
|
||||
this.websocketConnectionObject = new GameObject("websocketConnectionObject");
|
||||
MonoBehaviour mb = this.websocketConnectionObject.AddComponent<MonoBehaviourExt>();
|
||||
this.websocketConnectionObject.hideFlags = HideFlags.HideInHierarchy;
|
||||
UnityEngine.Object.DontDestroyOnLoad(this.websocketConnectionObject);
|
||||
|
||||
|
||||
this.ConnectAddress += "&IPv6"; // this makes the Photon Server return a host name for the next server (NS points to MS and MS points to GS)
|
||||
|
||||
|
||||
// earlier, we read the proxy address/scheme and failed to connect entirely, if that wasn't successful...
|
||||
// it was either successful (using the resulting proxy address) or no connect at all...
|
||||
|
||||
// we want:
|
||||
// WITH support: fail if the scheme is wrong or use it if possible
|
||||
// WITHOUT support: use proxy address, if it's a direct value (not a scheme we provide) or fail if it's a scheme
|
||||
|
||||
string proxyServerAddress;
|
||||
if (!this.ReadProxyConfigScheme(this.ProxyServerAddress, this.ServerAddress, out proxyServerAddress))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "ReadProxyConfigScheme() failed. Using no proxy.");
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
this.sock = new WebSocket(new Uri(this.ConnectAddress), proxyServerAddress, this.SerializationProtocol);
|
||||
this.sock.DebugReturn = (DebugLevel l, string s) =>
|
||||
{
|
||||
if (this.State != PhotonSocketState.Disconnected)
|
||||
{
|
||||
this.Listener.DebugReturn(l, this.State + " " + s);
|
||||
}
|
||||
};
|
||||
|
||||
this.sock.Connect();
|
||||
mb.StartCoroutine(this.ReceiveLoop());
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "SocketWebTcp.Connect() caught exception: " + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to read a proxy configuration defined by a address prefix. Only available to Industries Circle members on demand.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Extended proxy support is available to Industries Circle members. Where available, proxy addresses may be defined as 'auto:', 'pac:' or 'system:'.
|
||||
/// In all other cases, the proxy address is used as is and fails to read configs (if one of the listed schemes is used).
|
||||
///
|
||||
/// Requires file ProxyAutoConfig.cs and compile define: WEBSOCKET_PROXYCONFIG_SUPPORT.
|
||||
/// </remarks>
|
||||
/// <param name="proxyAddress">Proxy address from the server configuration.</param>
|
||||
/// <param name="url">Url to connect to (one of the Photon servers).</param>
|
||||
/// <param name="proxyUrl">Resulting proxy URL to use.</param>
|
||||
/// <returns>False if there is some error and the resulting proxy address should not be used.</returns>
|
||||
private bool ReadProxyConfigScheme(string proxyAddress, string url, out string proxyUrl)
|
||||
{
|
||||
proxyUrl = null;
|
||||
|
||||
#if !WEBSOCKET_PROXYCONFIG
|
||||
|
||||
if (!string.IsNullOrEmpty(proxyAddress))
|
||||
{
|
||||
if (proxyAddress.StartsWith("auto:") || proxyAddress.StartsWith("pac:") || proxyAddress.StartsWith("system:"))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.WARNING, "Proxy configuration via auto, pac or system is only supported with the WEBSOCKET_PROXYCONFIG define. Using no proxy instead.");
|
||||
return true;
|
||||
}
|
||||
proxyUrl = proxyAddress;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#else
|
||||
|
||||
if (!string.IsNullOrEmpty(proxyAddress))
|
||||
{
|
||||
var httpUrl = url.ToString().Replace("ws://", "http://").Replace("wss://", "https://"); // http(s) schema required in GetProxyForUrlUsingPac call
|
||||
bool auto = proxyAddress.StartsWith("auto:", StringComparison.InvariantCultureIgnoreCase);
|
||||
bool pac = proxyAddress.StartsWith("pac:", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
if (auto || pac)
|
||||
{
|
||||
string pacUrl = "";
|
||||
if (pac)
|
||||
{
|
||||
pacUrl = proxyAddress.Substring(4);
|
||||
if (pacUrl.IndexOf("://") == -1)
|
||||
{
|
||||
pacUrl = "http://" + pacUrl; //default to http
|
||||
}
|
||||
}
|
||||
|
||||
string processTypeStr = auto ? "auto detect" : "pac url " + pacUrl;
|
||||
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "WebSocket Proxy: " + url + " " + processTypeStr);
|
||||
|
||||
string errDescr = "";
|
||||
var err = ProxyAutoConfig.GetProxyForUrlUsingPac(httpUrl, pacUrl, out proxyUrl, out errDescr);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "WebSocket Proxy: " + url + " " + processTypeStr + " ProxyAutoConfig.GetProxyForUrlUsingPac() error: " + err + " (" + errDescr + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (proxyAddress.StartsWith("system:", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "WebSocket Proxy: " + url + " system settings");
|
||||
string proxyAutoConfigPacUrl;
|
||||
var err = ProxySystemSettings.GetProxy(out proxyUrl, out proxyAutoConfigPacUrl);
|
||||
if (err != 0)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "WebSocket Proxy: " + url + " system settings ProxySystemSettings.GetProxy() error: " + err);
|
||||
return false;
|
||||
}
|
||||
if (proxyAutoConfigPacUrl != null)
|
||||
{
|
||||
if (proxyAutoConfigPacUrl.IndexOf("://") == -1)
|
||||
{
|
||||
proxyAutoConfigPacUrl = "http://" + proxyAutoConfigPacUrl; //default to http
|
||||
}
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "WebSocket Proxy: " + url + " system settings AutoConfigURL: " + proxyAutoConfigPacUrl);
|
||||
string errDescr = "";
|
||||
err = ProxyAutoConfig.GetProxyForUrlUsingPac(httpUrl, proxyAutoConfigPacUrl, out proxyUrl, out errDescr);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "WebSocket Proxy: " + url + " system settings AutoConfigURLerror: " + err + " (" + errDescr + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
proxyUrl = proxyAddress;
|
||||
}
|
||||
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "WebSocket Proxy: " + url + " -> " + (string.IsNullOrEmpty(proxyUrl) ? "DIRECT" : "PROXY " + proxyUrl));
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override bool Disconnect()
|
||||
{
|
||||
if (this.ReportDebugOfLevel(DebugLevel.INFO))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.INFO, "SocketWebTcp.Disconnect()");
|
||||
}
|
||||
|
||||
this.State = PhotonSocketState.Disconnecting;
|
||||
|
||||
lock (this.syncer)
|
||||
{
|
||||
if (this.sock != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.sock.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "Exception in SocketWebTcp.Disconnect(): " + ex);
|
||||
}
|
||||
|
||||
this.sock = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.websocketConnectionObject != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(this.websocketConnectionObject);
|
||||
}
|
||||
|
||||
this.State = PhotonSocketState.Disconnected;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// used by TPeer*
|
||||
/// </summary>
|
||||
public override PhotonSocketError Send(byte[] data, int length)
|
||||
{
|
||||
if (this.State != PhotonSocketState.Connected)
|
||||
{
|
||||
return PhotonSocketError.Skipped;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (data.Length > length)
|
||||
{
|
||||
byte[] trimmedData = new byte[length];
|
||||
Buffer.BlockCopy(data, 0, trimmedData, 0, length);
|
||||
data = trimmedData;
|
||||
}
|
||||
|
||||
//if (this.ReportDebugOfLevel(DebugLevel.ALL))
|
||||
//{
|
||||
// this.Listener.DebugReturn(DebugLevel.ALL, "Sending: " + SupportClassPun.ByteArrayToString(data));
|
||||
//}
|
||||
|
||||
if (this.sock != null)
|
||||
{
|
||||
this.sock.Send(data);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "Cannot send to: " + this.ServerAddress + ". " + e.Message);
|
||||
|
||||
this.HandleException(StatusCode.Exception);
|
||||
return PhotonSocketError.Exception;
|
||||
}
|
||||
|
||||
return PhotonSocketError.Success;
|
||||
}
|
||||
|
||||
public override PhotonSocketError Receive(out byte[] data)
|
||||
{
|
||||
data = null;
|
||||
return PhotonSocketError.NoData;
|
||||
}
|
||||
|
||||
|
||||
internal const int ALL_HEADER_BYTES = 9;
|
||||
internal const int TCP_HEADER_BYTES = 7;
|
||||
internal const int MSG_HEADER_BYTES = 2;
|
||||
|
||||
public IEnumerator ReceiveLoop()
|
||||
{
|
||||
//this.Listener.DebugReturn(DebugLevel.INFO, "ReceiveLoop()");
|
||||
if (this.sock != null)
|
||||
{
|
||||
while (this.sock != null && !this.sock.Connected && this.sock.Error == null)
|
||||
{
|
||||
yield return new WaitForRealSeconds(0.1f);
|
||||
}
|
||||
|
||||
if (this.sock != null)
|
||||
{
|
||||
if (this.sock.Error != null)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "Exiting receive thread. Server: " + this.ServerAddress + " Error: " + this.sock.Error);
|
||||
this.HandleException(StatusCode.ExceptionOnConnect);
|
||||
}
|
||||
else
|
||||
{
|
||||
// connected
|
||||
if (this.ReportDebugOfLevel(DebugLevel.ALL))
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ALL, "Receiving by websocket. this.State: " + this.State);
|
||||
}
|
||||
|
||||
this.State = PhotonSocketState.Connected;
|
||||
this.peerBase.OnConnect();
|
||||
|
||||
while (this.State == PhotonSocketState.Connected)
|
||||
{
|
||||
if (this.sock != null)
|
||||
{
|
||||
if (this.sock.Error != null)
|
||||
{
|
||||
this.Listener.DebugReturn(DebugLevel.ERROR, "Exiting receive thread (inside loop). Server: " + this.ServerAddress + " Error: " + this.sock.Error);
|
||||
this.HandleException(StatusCode.ExceptionOnReceive);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] inBuff = this.sock.Recv();
|
||||
if (inBuff == null || inBuff.Length == 0)
|
||||
{
|
||||
// nothing received. wait a bit, try again
|
||||
yield return new WaitForRealSeconds(0.02f);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (this.ReportDebugOfLevel(DebugLevel.ALL))
|
||||
//{
|
||||
// this.Listener.DebugReturn(DebugLevel.ALL, "TCP << " + inBuff.Length + " = " + SupportClassPun.ByteArrayToString(inBuff));
|
||||
//}
|
||||
|
||||
if (inBuff.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.HandleReceivedDatagram(inBuff, inBuff.Length, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (this.State != PhotonSocketState.Disconnecting && this.State != PhotonSocketState.Disconnected)
|
||||
{
|
||||
if (this.ReportDebugOfLevel(DebugLevel.ERROR))
|
||||
{
|
||||
this.EnqueueDebugReturn(DebugLevel.ERROR, "Receive issue. State: " + this.State + ". Server: '" + this.ServerAddress + "' Exception: " + e);
|
||||
}
|
||||
|
||||
this.HandleException(StatusCode.ExceptionOnReceive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Disconnect();
|
||||
}
|
||||
|
||||
|
||||
private class MonoBehaviourExt : MonoBehaviour
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user