📄 stunclient.cs
字号:
namespace Imps.Client.Core.P2P.ICE
{
using Imps.Client.Core.P2P.ICE.Message;
using Imps.Client.Utils;
using NCindy;
using NCindy.Session.AIO;
using NCindy.Util;
using NCindy.Util.Logging;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
public class StunClient
{
private EndQuery _endQuery;
private static StunResult _result;
private IPEndPoint changedEndPoint;
private static readonly AutoResetEvent endQueryEvent = new AutoResetEvent(false);
private static readonly ILogger log = LogFactory.CreateLogger(MethodBase.GetCurrentMethod().ReflectedType);
private AsyncUdpSession querySession;
private Step queryStep;
private IPEndPoint remoteEndPoint;
protected StunClient()
{
}
protected void BeginQuery(string host, int port, EndQuery endQuery)
{
this._endQuery = endQuery;
this.querySession = new AsyncUdpSession(new IPEndPoint(Dns.GetHostAddresses(host)[0], port));
this.querySession.PacketDecoder = new StunDecoder();
this.querySession.PacketEncoder = new StunEncoder();
this.querySession.ObjectReceived += new EventHandler<SessionEventArgs>(this, (IntPtr) this.OnQueryResultReceived);
this.querySession.StateChanged += new EventHandler<SessionEventArgs>(this, (IntPtr) this.OnQuerySessionOpened);
this.querySession.Open();
}
private void DoEndQuery(StunResult result)
{
try
{
if (this._endQuery != null)
{
this._endQuery(result);
}
}
catch (Exception exception)
{
log.Error("DoEndQuery failed.", exception);
}
finally
{
endQueryEvent.Set();
}
}
private static StunMessage DoTransaction(StunMessage request, Socket socket, IPEndPoint remoteEndPoint)
{
byte[] buffer = request.ToByteData();
Stopwatch stopwatch = Stopwatch.StartNew();
while (stopwatch.get_ElapsedMilliseconds() < 0x7d0)
{
try
{
socket.SendTo(buffer, remoteEndPoint);
if (!socket.Poll(0x186a0, SelectMode.SelectRead))
{
continue;
}
byte[] buffer2 = new byte[0x200];
socket.Receive(buffer2);
StunMessage message = new StunMessage();
message.Parse(buffer2);
if (!request.TransactionID.Equals(message.TransactionID))
{
continue;
}
return message;
}
catch (Exception exception)
{
Console.WriteLine(exception);
continue;
}
}
stopwatch.Stop();
return null;
}
public static IPEndPoint GetPublicEndpoint(Socket socket, string host, int port)
{
LangHelper.CheckNullArgument("host", host);
LangHelper.CheckNullArgument("socket", socket);
try
{
if (port < 1)
{
throw new ArgumentException("Port value must be >= 1 !");
}
IPEndPoint remoteEndPoint = new IPEndPoint(Dns.GetHostAddresses(host)[0], port);
socket.set_ReceiveTimeout(0xbb8);
socket.set_SendTimeout(0xbb8);
StunMessage request = new StunMessage();
request.Type = StunMessageType.BindingRequest;
StunMessage message2 = DoTransaction(request, socket, remoteEndPoint);
if (message2 == null)
{
return null;
}
return message2.MappedAddress;
}
catch (Exception exception)
{
ClientLogger.WriteException("检测公共端点失败", exception);
}
return null;
}
private void GetSharedSecret()
{
}
private void OnQueryResultReceived(object sender, SessionEventArgs e)
{
StunMessage testResponse = e.Obj as StunMessage;
IPEndPoint localEndPoint = ((AsyncUdpSession) e.Session).LocalEndPoint;
switch (this.queryStep)
{
case Step.PublicIPTest:
this.ProcessPublicIPTestResult(testResponse, localEndPoint);
return;
case Step.OpenInternetTest:
this.ProcessOpenInternetTestResult(testResponse, localEndPoint);
return;
case Step.FullConeTest:
this.ProcessFullConeTestResult(testResponse, localEndPoint);
return;
case Step.SymmetricTest:
this.ProcessSymmetricTestResult(testResponse, localEndPoint);
return;
case Step.RestrictedTest:
this.ProcessRestrictedTestResult(testResponse, localEndPoint);
break;
case Step.End:
break;
default:
return;
}
}
private void OnQuerySessionOpened(object sender, SessionEventArgs e)
{
if (e.Session.State == SessionState.Opened)
{
this.queryStep = Step.PublicIPTest;
StunMessage message = new StunMessage();
message.Type = StunMessageType.BindingRequest;
this.querySession.Send(message);
}
}
private void ProcessFullConeTestResult(StunMessage testResponse, IPEndPoint localEndPoint)
{
if (testResponse != null)
{
this.queryStep = Step.End;
this.DoEndQuery(new StunResult(StunNetType.FullCone, this.remoteEndPoint, localEndPoint));
}
else
{
this.queryStep = Step.SymmetricTest;
StunMessage message = new StunMessage();
message.Type = StunMessageType.BindingRequest;
this.querySession.RemoteEndPoint = this.changedEndPoint;
this.querySession.Send(message);
}
}
private void ProcessOpenInternetTestResult(StunMessage testResponse, IPEndPoint localEndPoint)
{
if (testResponse != null)
{
this.DoEndQuery(new StunResult(StunNetType.OpenInternet, testResponse.MappedAddress, localEndPoint));
this.queryStep = Step.End;
}
else
{
this.DoEndQuery(new StunResult(StunNetType.SymmetricUdpFirewall, this.remoteEndPoint, localEndPoint));
this.queryStep = Step.End;
}
}
private void ProcessPublicIPTestResult(StunMessage testResponse, IPEndPoint localEndPoint)
{
if (testResponse == null)
{
this.DoEndQuery(new StunResult(StunNetType.UdpBlocked, null, localEndPoint));
this.queryStep = Step.End;
}
else
{
StunMessage message = new StunMessage();
message.Type = StunMessageType.BindingRequest;
message.ChangeRequest = new StunChangeRequestParams(true, true);
this.remoteEndPoint = testResponse.MappedAddress;
this.changedEndPoint = testResponse.ChangedAddress;
if (!localEndPoint.Equals(this.remoteEndPoint))
{
this.queryStep = Step.FullConeTest;
}
else
{
this.queryStep = Step.OpenInternetTest;
}
this.querySession.Send(message);
}
}
private void ProcessRestrictedTestResult(StunMessage testResponse, IPEndPoint localEndPoint)
{
this.queryStep = Step.End;
if (testResponse != null)
{
this.DoEndQuery(new StunResult(StunNetType.RestrictedCone, this.remoteEndPoint, localEndPoint));
}
else
{
this.DoEndQuery(new StunResult(StunNetType.PortRestrictedCone, this.remoteEndPoint, localEndPoint));
}
}
private void ProcessSymmetricTestResult(StunMessage testResponse, IPEndPoint localEndPoint)
{
if (testResponse == null)
{
this.queryStep = Step.End;
throw new Exception("Symmetric NAT test did not get resonse !");
}
if (!testResponse.MappedAddress.Equals(this.remoteEndPoint))
{
this.queryStep = Step.End;
this.DoEndQuery(new StunResult(StunNetType.Symmetric, this.remoteEndPoint, localEndPoint));
}
else
{
this.queryStep = Step.RestrictedTest;
StunMessage message = new StunMessage();
message.Type = StunMessageType.BindingRequest;
message.ChangeRequest = new StunChangeRequestParams(false, true);
this.querySession.RemoteEndPoint = this.changedEndPoint;
this.querySession.Send(message);
}
}
public static StunResult Query(string host, int port)
{
try
{
new StunClient().BeginQuery(host, port, delegate (StunResult result) {
_result = result;
});
}
catch (Exception exception)
{
log.Error("Query failed.", exception);
}
endQueryEvent.WaitOne();
return _result;
}
protected delegate void EndQuery(StunResult result);
private enum Step
{
PublicIPTest,
OpenInternetTest,
FullConeTest,
SymmetricTest,
RestrictedTest,
End
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -