Use Socket.ConnectAsync instead of socket.BeginConnect.

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>
This commit is contained in:
noisyfox
2016-08-20 11:36:27 +10:00
parent b335e6c8f5
commit f676d2185e
4 changed files with 62 additions and 38 deletions
@@ -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)
+2 -7
View File
@@ -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,
+2 -5
View File
@@ -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);
+56 -20
View File
@@ -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;
}
}
}