Merge pull request #667 from Noisyfox/dev
Minor bug fix and improvements.
This commit is contained in:
@@ -116,8 +116,9 @@ namespace Shadowsocks.Controller
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Debug(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -122,6 +122,7 @@ namespace Shadowsocks.Controller
|
||||
* different instance will create their unique "privoxy_UID.conf" where
|
||||
* UID is hash of ss's location.
|
||||
*/
|
||||
|
||||
private static bool IsChildProcess(Process process)
|
||||
{
|
||||
if (Utils.IsPortableMode())
|
||||
@@ -129,8 +130,21 @@ namespace Shadowsocks.Controller
|
||||
/*
|
||||
* Under PortableMode, we could identify it by the path of ss_privoxy.exe.
|
||||
*/
|
||||
string path = process.MainModule.FileName;
|
||||
return Utils.GetTempPath("ss_privoxy.exe").Equals(path);
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Sometimes Process.GetProcessesByName will return some processes that
|
||||
* are already dead, and that will cause exceptions here.
|
||||
* We could simply ignore those exceptions.
|
||||
*/
|
||||
string path = process.MainModule.FileName;
|
||||
return Utils.GetTempPath("ss_privoxy.exe").Equals(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.LogUsefulException(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -48,12 +48,8 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
EndPoint remoteEP = SocketUtil.GetEndPoint("localhost", targetPort);
|
||||
|
||||
_remote = SocketUtil.CreateSocket(remoteEP);
|
||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
|
||||
// Connect to the remote endpoint.
|
||||
_remote.BeginConnect(remoteEP,
|
||||
new AsyncCallback(ConnectCallback), null);
|
||||
SocketUtil.BeginConnectTcp(remoteEP, ConnectCallback, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -70,7 +66,7 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
try
|
||||
{
|
||||
_remote.EndConnect(ar);
|
||||
_remote = SocketUtil.EndConnectTcp(ar);
|
||||
HandshakeReceive();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -80,6 +80,33 @@ namespace Shadowsocks.Controller
|
||||
|
||||
class TCPHandler
|
||||
{
|
||||
|
||||
class AsyncSession
|
||||
{
|
||||
public IProxy Remote { get; }
|
||||
|
||||
public AsyncSession(IProxy remote)
|
||||
{
|
||||
Remote = remote;
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncSession<T> : AsyncSession
|
||||
{
|
||||
public T State { get; set; }
|
||||
|
||||
public AsyncSession(IProxy remote, T state) : base(remote)
|
||||
{
|
||||
State = state;
|
||||
}
|
||||
|
||||
public AsyncSession(AsyncSession session, T state): base(session.Remote)
|
||||
{
|
||||
State = state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Size of receive buffer.
|
||||
public static readonly int RecvSize = 8192;
|
||||
public static readonly int RecvReserveSize = IVEncryptor.ONETIMEAUTH_BYTES + IVEncryptor.AUTH_BYTES; // reserve for one-time auth
|
||||
@@ -89,7 +116,8 @@ namespace Shadowsocks.Controller
|
||||
public IEncryptor encryptor;
|
||||
public Server server;
|
||||
// Client socket.
|
||||
public IProxy remote;
|
||||
private AsyncSession _currentRemoteSession;
|
||||
|
||||
public Socket connection;
|
||||
public ShadowsocksController controller;
|
||||
public TCPRelay tcprelay;
|
||||
@@ -177,6 +205,7 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
try
|
||||
{
|
||||
var remote = _currentRemoteSession?.Remote;
|
||||
remote?.Shutdown(SocketShutdown.Both);
|
||||
remote?.Close();
|
||||
}
|
||||
@@ -340,7 +369,8 @@ namespace Shadowsocks.Controller
|
||||
// inner class
|
||||
private class ProxyTimer : Timer
|
||||
{
|
||||
public IProxy Proxy;
|
||||
public AsyncSession Session;
|
||||
|
||||
public EndPoint DestEndPoint;
|
||||
public Server Server;
|
||||
|
||||
@@ -351,6 +381,8 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private class ServerTimer : Timer
|
||||
{
|
||||
public AsyncSession Session;
|
||||
|
||||
public Server Server;
|
||||
public ServerTimer(int p) : base(p) { }
|
||||
}
|
||||
@@ -362,6 +394,7 @@ namespace Shadowsocks.Controller
|
||||
CreateRemote();
|
||||
|
||||
// Setting up proxy
|
||||
IProxy remote;
|
||||
EndPoint proxyEP;
|
||||
if (_config.useProxy)
|
||||
{
|
||||
@@ -374,20 +407,22 @@ namespace Shadowsocks.Controller
|
||||
proxyEP = null;
|
||||
}
|
||||
|
||||
var session = new AsyncSession(remote);
|
||||
_currentRemoteSession = session;
|
||||
|
||||
ProxyTimer proxyTimer = new ProxyTimer(3000);
|
||||
proxyTimer.AutoReset = false;
|
||||
proxyTimer.Elapsed += proxyConnectTimer_Elapsed;
|
||||
proxyTimer.Enabled = true;
|
||||
|
||||
proxyTimer.Proxy = remote;
|
||||
proxyTimer.Session = session;
|
||||
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port);
|
||||
proxyTimer.Server = server;
|
||||
|
||||
_proxyConnected = false;
|
||||
|
||||
// Connect to the proxy server.
|
||||
remote.BeginConnectProxy(proxyEP, new AsyncCallback(ProxyConnectCallback), proxyTimer);
|
||||
remote.BeginConnectProxy(proxyEP, new AsyncCallback(ProxyConnectCallback), new AsyncSession<ProxyTimer>(remote, proxyTimer));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -402,10 +437,10 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
return;
|
||||
}
|
||||
var proxy = ((ProxyTimer)sender).Proxy;
|
||||
var proxy = ((ProxyTimer)sender).Session.Remote;
|
||||
|
||||
Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out");
|
||||
remote?.Close();
|
||||
proxy.Close();
|
||||
RetryConnect();
|
||||
}
|
||||
|
||||
@@ -418,13 +453,16 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
try
|
||||
{
|
||||
ProxyTimer timer = (ProxyTimer)ar.AsyncState;
|
||||
var session = (AsyncSession<ProxyTimer>) ar.AsyncState;
|
||||
ProxyTimer timer = session.State;
|
||||
var destEndPoint = timer.DestEndPoint;
|
||||
server = timer.Server;
|
||||
timer.Elapsed -= proxyConnectTimer_Elapsed;
|
||||
timer.Enabled = false;
|
||||
timer.Dispose();
|
||||
|
||||
var remote = session.Remote;
|
||||
|
||||
// Complete the connection.
|
||||
remote.EndConnectProxy(ar);
|
||||
|
||||
@@ -443,11 +481,12 @@ namespace Shadowsocks.Controller
|
||||
connectTimer.AutoReset = false;
|
||||
connectTimer.Elapsed += destConnectTimer_Elapsed;
|
||||
connectTimer.Enabled = true;
|
||||
connectTimer.Session = session;
|
||||
connectTimer.Server = server;
|
||||
|
||||
_destConnected = false;
|
||||
// Connect to the remote endpoint.
|
||||
remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), connectTimer);
|
||||
remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), new AsyncSession<ServerTimer>(session, connectTimer));
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
@@ -466,11 +505,12 @@ namespace Shadowsocks.Controller
|
||||
return;
|
||||
}
|
||||
|
||||
var session = ((ServerTimer) sender).Session;
|
||||
Server server = ((ServerTimer)sender).Server;
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.SetFailure(server);
|
||||
Logging.Info($"{server.FriendlyName()} timed out");
|
||||
remote?.Close();
|
||||
session.Remote.Close();
|
||||
RetryConnect();
|
||||
}
|
||||
|
||||
@@ -491,12 +531,14 @@ namespace Shadowsocks.Controller
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
ServerTimer timer = (ServerTimer)ar.AsyncState;
|
||||
var session = (AsyncSession<ServerTimer>) ar.AsyncState;
|
||||
ServerTimer timer = session.State;
|
||||
server = timer.Server;
|
||||
timer.Elapsed -= destConnectTimer_Elapsed;
|
||||
timer.Enabled = false;
|
||||
timer.Dispose();
|
||||
|
||||
var remote = session.Remote;
|
||||
// Complete the connection.
|
||||
remote?.EndConnectDest(ar);
|
||||
|
||||
@@ -512,7 +554,7 @@ namespace Shadowsocks.Controller
|
||||
strategy?.UpdateLatency(server, latency);
|
||||
_tcprelay.UpdateLatency(server, latency);
|
||||
|
||||
StartPipe();
|
||||
StartPipe(session);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
@@ -529,14 +571,15 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
}
|
||||
|
||||
private void StartPipe()
|
||||
private void StartPipe(AsyncSession session)
|
||||
{
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
_startReceivingTime = DateTime.Now;
|
||||
remote?.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
connection?.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
|
||||
connection?.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback),
|
||||
new AsyncSession<bool>(session, true) /* to tell the callback this is the first time reading packet, and we haven't found the header yet. */);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -550,8 +593,8 @@ namespace Shadowsocks.Controller
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
if ( remote == null ) return;
|
||||
int bytesRead = remote.EndReceive(ar);
|
||||
var session = (AsyncSession) ar.AsyncState;
|
||||
int bytesRead = session.Remote.EndReceive(ar);
|
||||
_totalRead += bytesRead;
|
||||
_tcprelay.UpdateInboundCounter(server, bytesRead);
|
||||
if (bytesRead > 0)
|
||||
@@ -563,7 +606,7 @@ namespace Shadowsocks.Controller
|
||||
if (_closed) return;
|
||||
encryptor.Decrypt(_remoteRecvBuffer, bytesRead, _remoteSendBuffer, out bytesToSend);
|
||||
}
|
||||
connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeConnectionSendCallback), null);
|
||||
connection.BeginSend(_remoteSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeConnectionSendCallback), session);
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.UpdateLastRead(server);
|
||||
}
|
||||
@@ -589,36 +632,48 @@ namespace Shadowsocks.Controller
|
||||
if(connection == null) return;
|
||||
int bytesRead = connection.EndReceive(ar);
|
||||
_totalWrite += bytesRead;
|
||||
|
||||
var session = (AsyncSession<bool>) ar.AsyncState;
|
||||
var remote = session.Remote;
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
int atyp = _connetionRecvBuffer[0];
|
||||
string dst_addr;
|
||||
int dst_port;
|
||||
switch (atyp)
|
||||
/*
|
||||
* Only the first packet contains the socks5 header, it doesn't make sense to parse every packets.
|
||||
* Also it's unnecessary to parse these data if we turn off the VerboseLogging.
|
||||
*/
|
||||
if (session.State && _config.isVerboseLogging)
|
||||
{
|
||||
case 1: // IPv4 address, 4 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(4).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[5] << 8) + _connetionRecvBuffer[6];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to {dst_addr}:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
case 3: // domain name, length + str
|
||||
int len = _connetionRecvBuffer[1];
|
||||
dst_addr = System.Text.Encoding.UTF8.GetString(_connetionRecvBuffer, 2, len);
|
||||
dst_port = (_connetionRecvBuffer[len + 2] << 8) + _connetionRecvBuffer[len + 3];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to {dst_addr}:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
case 4: // IPv6 address, 16 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(16).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[17] << 8) + _connetionRecvBuffer[18];
|
||||
if ( _config.isVerboseLogging ) {
|
||||
Logging.Info( $"connect to [{dst_addr}]:{dst_port}" );
|
||||
}
|
||||
break;
|
||||
int atyp = _connetionRecvBuffer[0];
|
||||
string dst_addr;
|
||||
int dst_port;
|
||||
switch (atyp)
|
||||
{
|
||||
case 1: // IPv4 address, 4 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(4).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[5] << 8) + _connetionRecvBuffer[6];
|
||||
|
||||
Logging.Info($"connect to {dst_addr}:{dst_port}");
|
||||
session.State = false;
|
||||
break;
|
||||
case 3: // domain name, length + str
|
||||
int len = _connetionRecvBuffer[1];
|
||||
dst_addr = System.Text.Encoding.UTF8.GetString(_connetionRecvBuffer, 2, len);
|
||||
dst_port = (_connetionRecvBuffer[len + 2] << 8) + _connetionRecvBuffer[len + 3];
|
||||
|
||||
Logging.Info($"connect to {dst_addr}:{dst_port}");
|
||||
session.State = false;
|
||||
break;
|
||||
case 4: // IPv6 address, 16 bytes
|
||||
dst_addr = new IPAddress(_connetionRecvBuffer.Skip(1).Take(16).ToArray()).ToString();
|
||||
dst_port = (_connetionRecvBuffer[17] << 8) + _connetionRecvBuffer[18];
|
||||
|
||||
Logging.Info($"connect to [{dst_addr}]:{dst_port}");
|
||||
session.State = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int bytesToSend;
|
||||
lock (_encryptionLock)
|
||||
{
|
||||
@@ -628,7 +683,7 @@ namespace Shadowsocks.Controller
|
||||
_tcprelay.UpdateOutboundCounter(server, bytesToSend);
|
||||
_startSendingTime = DateTime.Now;
|
||||
_bytesToSend = bytesToSend;
|
||||
remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeRemoteSendCallback), null);
|
||||
remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None, new AsyncCallback(PipeRemoteSendCallback), session);
|
||||
IStrategy strategy = controller.GetCurrentStrategy();
|
||||
strategy?.UpdateLastWrite(server);
|
||||
}
|
||||
@@ -651,8 +706,9 @@ namespace Shadowsocks.Controller
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
remote?.EndSend(ar);
|
||||
connection?.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), null);
|
||||
var session = (AsyncSession)ar.AsyncState;
|
||||
session.Remote.EndSend(ar);
|
||||
connection?.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeConnectionReceiveCallback), session);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -666,8 +722,9 @@ namespace Shadowsocks.Controller
|
||||
if (_closed) return;
|
||||
try
|
||||
{
|
||||
var session = (AsyncSession)ar.AsyncState;
|
||||
connection?.EndSend(ar);
|
||||
remote?.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), null);
|
||||
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Runtime.CompilerServices;
|
||||
using Shadowsocks.Controller.Strategy;
|
||||
using Shadowsocks.Encryption;
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
@@ -57,7 +56,7 @@ namespace Shadowsocks.Controller
|
||||
private byte[] _buffer = new byte[1500];
|
||||
|
||||
private IPEndPoint _localEndPoint;
|
||||
private EndPoint _remoteEndPoint;
|
||||
private IPEndPoint _remoteEndPoint;
|
||||
|
||||
public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
|
||||
{
|
||||
@@ -65,8 +64,16 @@ namespace Shadowsocks.Controller
|
||||
_server = server;
|
||||
_localEndPoint = localEndPoint;
|
||||
|
||||
_remoteEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port);
|
||||
_remote = SocketUtil.CreateSocket(_remoteEndPoint, ProtocolType.Udp);
|
||||
// TODO async resolving
|
||||
IPAddress ipAddress;
|
||||
bool parsed = IPAddress.TryParse(server.server, out ipAddress);
|
||||
if (!parsed)
|
||||
{
|
||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server);
|
||||
ipAddress = ipHostInfo.AddressList[0];
|
||||
}
|
||||
_remoteEndPoint = new IPEndPoint(ipAddress, server.server_port);
|
||||
_remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
}
|
||||
|
||||
public void Send(byte[] data, int length)
|
||||
|
||||
@@ -55,17 +55,12 @@ namespace Shadowsocks.Proxy
|
||||
{
|
||||
DestEndPoint = destEndPoint;
|
||||
|
||||
if (_remote == null)
|
||||
{
|
||||
_remote = SocketUtil.CreateSocket(destEndPoint);
|
||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
}
|
||||
_remote.BeginConnect(destEndPoint, callback, state);
|
||||
SocketUtil.BeginConnectTcp(destEndPoint, callback, state);
|
||||
}
|
||||
|
||||
public void EndConnectDest(IAsyncResult asyncResult)
|
||||
{
|
||||
_remote?.EndConnect(asyncResult);
|
||||
_remote = SocketUtil.EndConnectTcp(asyncResult);
|
||||
}
|
||||
|
||||
public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback,
|
||||
|
||||
@@ -52,16 +52,13 @@ namespace Shadowsocks.Proxy
|
||||
|
||||
public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state)
|
||||
{
|
||||
_remote = SocketUtil.CreateSocket(remoteEP);
|
||||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
|
||||
var st = new Socks5State();
|
||||
st.Callback = callback;
|
||||
st.AsyncState = state;
|
||||
|
||||
ProxyEndPoint = remoteEP;
|
||||
|
||||
_remote.BeginConnect(remoteEP, ConnectCallback, st);
|
||||
SocketUtil.BeginConnectTcp(remoteEP, ConnectCallback, st);
|
||||
}
|
||||
|
||||
public void EndConnectProxy(IAsyncResult asyncResult)
|
||||
@@ -180,7 +177,7 @@ namespace Shadowsocks.Proxy
|
||||
var state = (Socks5State) ar.AsyncState;
|
||||
try
|
||||
{
|
||||
_remote.EndConnect(ar);
|
||||
_remote = SocketUtil.EndConnectTcp(ar);
|
||||
|
||||
byte[] handshake = {5, 1, 0};
|
||||
_remote.BeginSend(handshake, 0, handshake.Length, 0, Socks5HandshakeSendCallback, state);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace Shadowsocks.Util
|
||||
{
|
||||
@@ -35,33 +36,68 @@ namespace Shadowsocks.Util
|
||||
return new DnsEndPoint2(host, port);
|
||||
}
|
||||
|
||||
public static Socket CreateSocket(EndPoint endPoint, ProtocolType protocolType = ProtocolType.Tcp)
|
||||
private class TcpUserToken : IAsyncResult
|
||||
{
|
||||
SocketType socketType;
|
||||
switch (protocolType)
|
||||
public AsyncCallback Callback { get; }
|
||||
public SocketAsyncEventArgs Args { get; }
|
||||
|
||||
public TcpUserToken(AsyncCallback callback, object state, SocketAsyncEventArgs args)
|
||||
{
|
||||
case ProtocolType.Tcp:
|
||||
socketType = SocketType.Stream;
|
||||
break;
|
||||
case ProtocolType.Udp:
|
||||
socketType = SocketType.Dgram;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Protocol " + protocolType + " doesn't supported!");
|
||||
Callback = callback;
|
||||
AsyncState = state;
|
||||
Args = args;
|
||||
}
|
||||
|
||||
if (endPoint is DnsEndPoint)
|
||||
{
|
||||
// use dual-mode socket
|
||||
var socket = new Socket(AddressFamily.InterNetworkV6, socketType, protocolType);
|
||||
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
|
||||
public bool IsCompleted { get; } = true;
|
||||
public WaitHandle AsyncWaitHandle { get; } = null;
|
||||
public object AsyncState { get; }
|
||||
public bool CompletedSynchronously { get; } = true;
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
else
|
||||
private static void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args)
|
||||
{
|
||||
TcpUserToken token = (TcpUserToken) args.UserToken;
|
||||
|
||||
token.Callback(token);
|
||||
}
|
||||
|
||||
public static void BeginConnectTcp(EndPoint endPoint, AsyncCallback callback, object state)
|
||||
{
|
||||
var arg = new SocketAsyncEventArgs();
|
||||
arg.RemoteEndPoint = endPoint;
|
||||
arg.Completed += OnTcpConnectCompleted;
|
||||
arg.UserToken = new TcpUserToken(callback, state, arg);
|
||||
|
||||
|
||||
Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg);
|
||||
}
|
||||
|
||||
public static Socket EndConnectTcp(IAsyncResult asyncResult)
|
||||
{
|
||||
var tut = asyncResult as TcpUserToken;
|
||||
if (tut == null)
|
||||
{
|
||||
return new Socket(endPoint.AddressFamily, socketType, protocolType);
|
||||
throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult));
|
||||
}
|
||||
|
||||
var arg = tut.Args;
|
||||
|
||||
if (arg.SocketError != SocketError.Success)
|
||||
{
|
||||
if (arg.ConnectByNameError != null)
|
||||
{
|
||||
throw arg.ConnectByNameError;
|
||||
}
|
||||
|
||||
var ex = new SocketException((int)arg.SocketError);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
var so = tut.Args.ConnectSocket;
|
||||
|
||||
so.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
|
||||
return so;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,17 @@
|
||||
<dpiAware>True/PM</dpiAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<!-- We specify these, in addition to the UAC above, so we avoid Program Compatibility Assistant in Vista and Win7 -->
|
||||
<!-- We try to avoid PCA so we can use Windows Job Objects -->
|
||||
<!-- See http://stackoverflow.com/questions/3342941/kill-child-process-when-parent-process-is-killed -->
|
||||
|
||||
<application>
|
||||
<!--The ID below indicates application support for Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
<!--The ID below indicates application support for Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
Reference in New Issue
Block a user