Socket.ConnectAsync will create socket and handle the address family itself. This solves some compatibility issues on win7. Signed-off-by: noisyfox <timemanager.rick@gmail.com>tags/3.3
@@ -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) | |||
@@ -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; | |||
} | |||
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); | |||
return socket; | |||
Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg); | |||
} | |||
public static Socket EndConnectTcp(IAsyncResult asyncResult) | |||
{ | |||
var tut = asyncResult as TcpUserToken; | |||
if (tut == null) | |||
{ | |||
throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult)); | |||
} | |||
else | |||
var arg = tut.Args; | |||
if (arg.SocketError != SocketError.Success) | |||
{ | |||
return new Socket(endPoint.AddressFamily, socketType, protocolType); | |||
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; | |||
} | |||
} | |||
} |