Repository: thrift Updated Branches: refs/heads/master 8d377fa6b -> feea47852
THRIFT-3000 .NET implementation has trouble with mixed IP modes Client: C# Patch: Jens Geyer, based on https://github.com/apache/thrift/pull/377 This closes #1167 Project: http://git-wip-us.apache.org/repos/asf/thrift/repo Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/feea4785 Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/feea4785 Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/feea4785 Branch: refs/heads/master Commit: feea47852c50f502139952b7fa96cc71c45690bf Parents: 8d377fa Author: Jens Geyer <[email protected]> Authored: Sat Jan 28 19:53:28 2017 +0100 Committer: Jens Geyer <[email protected]> Committed: Tue Jan 31 21:22:06 2017 +0100 ---------------------------------------------------------------------- lib/csharp/Makefile.am | 1 + lib/csharp/src/Thrift.45.csproj | 9 +- lib/csharp/src/Thrift.csproj | 15 +- lib/csharp/src/Transport/TServerSocket.cs | 260 ++++++------- lib/csharp/src/Transport/TSocket.cs | 406 ++++++++++---------- lib/csharp/src/Transport/TSocketVersionizer.cs | 55 +++ lib/csharp/src/Transport/TTLSServerSocket.cs | 4 +- lib/csharp/src/Transport/TTLSSocket.cs | 2 +- 8 files changed, 405 insertions(+), 347 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/Makefile.am ---------------------------------------------------------------------- diff --git a/lib/csharp/Makefile.am b/lib/csharp/Makefile.am index bf02c87..1fd5462 100644 --- a/lib/csharp/Makefile.am +++ b/lib/csharp/Makefile.am @@ -52,6 +52,7 @@ THRIFTCODE = \ src/Transport/TBufferedTransport.cs \ src/Transport/TTransport.cs \ src/Transport/TSocket.cs \ + src/Transport/TSocketVersionizer.cs \ src/Transport/TTransportException.cs \ src/Transport/TStreamTransport.cs \ src/Transport/TFramedTransport.cs \ http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Thrift.45.csproj ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Thrift.45.csproj b/lib/csharp/src/Thrift.45.csproj index 949f373..78089fc 100644 --- a/lib/csharp/src/Thrift.45.csproj +++ b/lib/csharp/src/Thrift.45.csproj @@ -35,7 +35,7 @@ <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> + <DefineConstants>TRACE;DEBUG;NET45</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> @@ -43,7 +43,7 @@ <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> + <DefineConstants>TRACE;NET45</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> @@ -88,17 +88,17 @@ <Compile Include="Server\TThreadedServer.cs" /> <Compile Include="Server\TThreadPoolServer.cs" /> <Compile Include="TApplicationException.cs" /> + <Compile Include="TAsyncProcessor.cs" /> <Compile Include="TControllingHandler.cs" /> <Compile Include="TException.cs" /> - <Compile Include="TAsyncProcessor.cs" /> <Compile Include="TProcessor.cs" /> <Compile Include="TProcessorFactory.cs" /> <Compile Include="TPrototypeProcessorFactory.cs" /> <Compile Include="Transport\TBufferedTransport.cs" /> <Compile Include="Transport\TFramedTransport.cs" /> - <Compile Include="Transport\THttpTaskAsyncHandler.cs" /> <Compile Include="Transport\THttpClient.cs" /> <Compile Include="Transport\THttpHandler.cs" /> + <Compile Include="Transport\THttpTaskAsyncHandler.cs" /> <Compile Include="Transport\TMemoryBuffer.cs" /> <Compile Include="Transport\TNamedPipeClientTransport.cs" /> <Compile Include="Transport\TNamedPipeServerTransport.cs" /> @@ -106,6 +106,7 @@ <Compile Include="Transport\TServerTransport.cs" /> <Compile Include="Transport\TSilverlightSocket.cs" /> <Compile Include="Transport\TSocket.cs" /> + <Compile Include="Transport\TSocketVersionizer.cs" /> <Compile Include="Transport\TStreamTransport.cs" /> <Compile Include="Transport\TTLSServerSocket.cs" /> <Compile Include="Transport\TTLSSocket.cs" /> http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Thrift.csproj ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj index 99c6b46..e3022a4 100644 --- a/lib/csharp/src/Thrift.csproj +++ b/lib/csharp/src/Thrift.csproj @@ -79,8 +79,6 @@ <ItemGroup> <Compile Include="Collections\TCollections.cs" /> <Compile Include="Collections\THashSet.cs" /> - <Compile Include="TControllingHandler.cs" /> - <Compile Include="TProcessorFactory.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Protocol\TAbstractBase.cs" /> <Compile Include="Protocol\TBase.cs" /> @@ -103,32 +101,35 @@ <Compile Include="Protocol\TSet.cs" /> <Compile Include="Protocol\TStruct.cs" /> <Compile Include="Protocol\TType.cs" /> - <Compile Include="TPrototypeProcessorFactory.cs" /> - <Compile Include="TSingletonProcessorFactory.cs" /> - <Compile Include="Server\TThreadedServer.cs" /> <Compile Include="Server\TServer.cs" /> <Compile Include="Server\TServerEventHandler.cs" /> <Compile Include="Server\TSimpleServer.cs" /> + <Compile Include="Server\TThreadedServer.cs" /> <Compile Include="Server\TThreadPoolServer.cs" /> - <Compile Include="TException.cs" /> <Compile Include="TApplicationException.cs" /> + <Compile Include="TControllingHandler.cs" /> + <Compile Include="TException.cs" /> <Compile Include="TProcessor.cs" /> + <Compile Include="TProcessorFactory.cs" /> + <Compile Include="TPrototypeProcessorFactory.cs" /> <Compile Include="Transport\TBufferedTransport.cs" /> <Compile Include="Transport\TFramedTransport.cs" /> <Compile Include="Transport\THttpClient.cs" /> <Compile Include="Transport\THttpHandler.cs" /> + <Compile Include="Transport\TMemoryBuffer.cs" /> <Compile Include="Transport\TNamedPipeClientTransport.cs" /> <Compile Include="Transport\TNamedPipeServerTransport.cs" /> <Compile Include="Transport\TServerSocket.cs" /> <Compile Include="Transport\TServerTransport.cs" /> <Compile Include="Transport\TSocket.cs" /> + <Compile Include="Transport\TSocketVersionizer.cs" /> <Compile Include="Transport\TStreamTransport.cs" /> <Compile Include="Transport\TTLSServerSocket.cs" /> <Compile Include="Transport\TTLSSocket.cs" /> <Compile Include="Transport\TTransport.cs" /> <Compile Include="Transport\TTransportException.cs" /> <Compile Include="Transport\TTransportFactory.cs" /> - <Compile Include="Transport\TMemoryBuffer.cs" /> + <Compile Include="TSingletonProcessorFactory.cs" /> </ItemGroup> <ItemGroup> <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Transport/TServerSocket.cs ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Transport/TServerSocket.cs b/lib/csharp/src/Transport/TServerSocket.cs index 82a367c..453df34 100644 --- a/lib/csharp/src/Transport/TServerSocket.cs +++ b/lib/csharp/src/Transport/TServerSocket.cs @@ -27,150 +27,150 @@ using System.Net.Sockets; namespace Thrift.Transport { - public class TServerSocket : TServerTransport - { + public class TServerSocket : TServerTransport + { /** * Underlying server with socket */ - private TcpListener server = null; + private TcpListener server = null; - /** - * Port to listen on - */ - private int port = 0; + /** + * Port to listen on + */ + private int port = 0; - /** - * Timeout for client sockets from accept - */ - private int clientTimeout = 0; + /** + * Timeout for client sockets from accept + */ + private int clientTimeout = 0; - /** - * Whether or not to wrap new TSocket connections in buffers - */ - private bool useBufferedSockets = false; + /** + * Whether or not to wrap new TSocket connections in buffers + */ + private bool useBufferedSockets = false; - /** - * Creates a server socket from underlying socket object - */ - public TServerSocket(TcpListener listener) + /** + * Creates a server socket from underlying socket object + */ + public TServerSocket(TcpListener listener) :this(listener, 0) - { - } + { + } - /** - * Creates a server socket from underlying socket object - */ - public TServerSocket(TcpListener listener, int clientTimeout) - { - this.server = listener; - this.clientTimeout = clientTimeout; - } + /** + * Creates a server socket from underlying socket object + */ + public TServerSocket(TcpListener listener, int clientTimeout) + { + this.server = listener; + this.clientTimeout = clientTimeout; + } - /** - * Creates just a port listening server socket - */ - public TServerSocket(int port) - : this(port, 0) - { - } + /** + * Creates just a port listening server socket + */ + public TServerSocket(int port) + : this(port, 0) + { + } - /** - * Creates just a port listening server socket - */ - public TServerSocket(int port, int clientTimeout) + /** + * Creates just a port listening server socket + */ + public TServerSocket(int port, int clientTimeout) :this(port, clientTimeout, false) - { - } + { + } - public TServerSocket(int port, int clientTimeout, bool useBufferedSockets) - { - this.port = port; - this.clientTimeout = clientTimeout; - this.useBufferedSockets = useBufferedSockets; - try - { - // Make server socket - server = new TcpListener(System.Net.IPAddress.Any, this.port); - server.Server.NoDelay = true; - } - catch (Exception) - { - server = null; - throw new TTransportException("Could not create ServerSocket on port " + port + "."); - } - } + public TServerSocket(int port, int clientTimeout, bool useBufferedSockets) + { + this.port = port; + this.clientTimeout = clientTimeout; + this.useBufferedSockets = useBufferedSockets; + try + { + // Make server socket + this.server = TSocketVersionizer.CreateTcpListener(port); + this.server.Server.NoDelay = true; + } + catch (Exception) + { + server = null; + throw new TTransportException("Could not create ServerSocket on port " + port + "."); + } + } - public override void Listen() - { - // Make sure not to block on accept - if (server != null) - { - try - { - server.Start(); - } - catch (SocketException sx) - { - throw new TTransportException("Could not accept on listening socket: " + sx.Message); - } - } - } + public override void Listen() + { + // Make sure not to block on accept + if (server != null) + { + try + { + server.Start(); + } + catch (SocketException sx) + { + throw new TTransportException("Could not accept on listening socket: " + sx.Message); + } + } + } - protected override TTransport AcceptImpl() - { - if (server == null) - { - throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); - } - try - { - TSocket result2 = null; - TcpClient result = server.AcceptTcpClient(); - try - { - result2 = new TSocket(result); - result2.Timeout = clientTimeout; - if (useBufferedSockets) - { - TBufferedTransport result3 = new TBufferedTransport(result2); - return result3; - } - else - { - return result2; - } - } - catch (System.Exception) - { - // If a TSocket was successfully created, then let - // it do proper cleanup of the TcpClient object. - if (result2 != null) - result2.Dispose(); - else // Otherwise, clean it up ourselves. - ((IDisposable)result).Dispose(); - throw; - } - } - catch (Exception ex) - { - throw new TTransportException(ex.ToString()); - } - } + protected override TTransport AcceptImpl() + { + if (server == null) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket."); + } + try + { + TSocket result2 = null; + TcpClient result = server.AcceptTcpClient(); + try + { + result2 = new TSocket(result); + result2.Timeout = clientTimeout; + if (useBufferedSockets) + { + TBufferedTransport result3 = new TBufferedTransport(result2); + return result3; + } + else + { + return result2; + } + } + catch (System.Exception) + { + // If a TSocket was successfully created, then let + // it do proper cleanup of the TcpClient object. + if (result2 != null) + result2.Dispose(); + else // Otherwise, clean it up ourselves. + ((IDisposable)result).Dispose(); + throw; + } + } + catch (Exception ex) + { + throw new TTransportException(ex.ToString()); + } + } - public override void Close() - { - if (server != null) - { - try - { - server.Stop(); - } - catch (Exception ex) - { - throw new TTransportException("WARNING: Could not close server socket: " + ex); - } - server = null; - } - } - } + public override void Close() + { + if (server != null) + { + try + { + server.Stop(); + } + catch (Exception ex) + { + throw new TTransportException("WARNING: Could not close server socket: " + ex); + } + server = null; + } + } + } } http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Transport/TSocket.cs ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Transport/TSocket.cs b/lib/csharp/src/Transport/TSocket.cs index cf1a440..7501e30 100644 --- a/lib/csharp/src/Transport/TSocket.cs +++ b/lib/csharp/src/Transport/TSocket.cs @@ -26,216 +26,216 @@ using System.Net.Sockets; namespace Thrift.Transport { - public class TSocket : TStreamTransport - { - private TcpClient client = null; - private string host = null; - private int port = 0; - private int timeout = 0; - - public TSocket(TcpClient client) - { - this.client = client; - - if (IsOpen) - { - inputStream = client.GetStream(); - outputStream = client.GetStream(); - } - } - - public TSocket(string host, int port) - : this(host, port, 0) - { - } - - public TSocket(string host, int port, int timeout) - { - this.host = host; - this.port = port; - this.timeout = timeout; - - InitSocket(); - } - - private void InitSocket() - { - client = new TcpClient(); - client.ReceiveTimeout = client.SendTimeout = timeout; - client.Client.NoDelay = true; - } - - public int Timeout - { - set - { - client.ReceiveTimeout = client.SendTimeout = timeout = value; - } - } - - public TcpClient TcpClient - { - get - { - return client; - } - } - - public string Host - { - get - { - return host; - } - } - - public int Port - { - get - { - return port; - } - } - - public override bool IsOpen - { - get - { - if (client == null) - { - return false; - } - - return client.Connected; - } - } - - public override void Open() - { - if (IsOpen) - { - throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected"); - } - - if (String.IsNullOrEmpty(host)) - { - throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host"); - } - - if (port <= 0) - { - throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port"); - } - - if (client == null) - { - InitSocket(); - } + public class TSocket : TStreamTransport + { + private TcpClient client = null; + private string host = null; + private int port = 0; + private int timeout = 0; + + public TSocket(TcpClient client) + { + this.client = client; + + if (IsOpen) + { + inputStream = client.GetStream(); + outputStream = client.GetStream(); + } + } + + public TSocket(string host, int port) + : this(host, port, 0) + { + } + + public TSocket(string host, int port, int timeout) + { + this.host = host; + this.port = port; + this.timeout = timeout; + + InitSocket(); + } + + private void InitSocket() + { + this.client = TSocketVersionizer.CreateTcpClient(); + this.client.ReceiveTimeout = client.SendTimeout = timeout; + this.client.Client.NoDelay = true; + } + + public int Timeout + { + set + { + client.ReceiveTimeout = client.SendTimeout = timeout = value; + } + } + + public TcpClient TcpClient + { + get + { + return client; + } + } + + public string Host + { + get + { + return host; + } + } + + public int Port + { + get + { + return port; + } + } + + public override bool IsOpen + { + get + { + if (client == null) + { + return false; + } + + return client.Connected; + } + } + + public override void Open() + { + if (IsOpen) + { + throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected"); + } + + if (String.IsNullOrEmpty(host)) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host"); + } + + if (port <= 0) + { + throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port"); + } + + if (client == null) + { + InitSocket(); + } if( timeout == 0) // no timeout -> infinite - { - client.Connect(host, port); - } - else // we have a timeout -> use it - { - ConnectHelper hlp = new ConnectHelper(client); - IAsyncResult asyncres = client.BeginConnect(host, port, new AsyncCallback(ConnectCallback), hlp); - bool bConnected = asyncres.AsyncWaitHandle.WaitOne(timeout) && client.Connected; - if (!bConnected) - { - lock (hlp.Mutex) - { + { + client.Connect(host, port); + } + else // we have a timeout -> use it + { + ConnectHelper hlp = new ConnectHelper(client); + IAsyncResult asyncres = client.BeginConnect(host, port, new AsyncCallback(ConnectCallback), hlp); + bool bConnected = asyncres.AsyncWaitHandle.WaitOne(timeout) && client.Connected; + if (!bConnected) + { + lock (hlp.Mutex) + { if( hlp.CallbackDone) - { - asyncres.AsyncWaitHandle.Close(); - client.Close(); - } - else - { - hlp.DoCleanup = true; - client = null; - } - } - throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Connect timed out"); - } - } - - inputStream = client.GetStream(); - outputStream = client.GetStream(); - } - - - static void ConnectCallback(IAsyncResult asyncres) - { - ConnectHelper hlp = asyncres.AsyncState as ConnectHelper; - lock (hlp.Mutex) - { - hlp.CallbackDone = true; - - try - { + { + asyncres.AsyncWaitHandle.Close(); + client.Close(); + } + else + { + hlp.DoCleanup = true; + client = null; + } + } + throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Connect timed out"); + } + } + + inputStream = client.GetStream(); + outputStream = client.GetStream(); + } + + + static void ConnectCallback(IAsyncResult asyncres) + { + ConnectHelper hlp = asyncres.AsyncState as ConnectHelper; + lock (hlp.Mutex) + { + hlp.CallbackDone = true; + + try + { if( hlp.Client.Client != null) - hlp.Client.EndConnect(asyncres); - } - catch (Exception) - { - // catch that away - } - - if (hlp.DoCleanup) - { + hlp.Client.EndConnect(asyncres); + } + catch (Exception) + { + // catch that away + } + + if (hlp.DoCleanup) + { try { - asyncres.AsyncWaitHandle.Close(); + asyncres.AsyncWaitHandle.Close(); } catch (Exception) {} try { - if (hlp.Client is IDisposable) - ((IDisposable)hlp.Client).Dispose(); + if (hlp.Client is IDisposable) + ((IDisposable)hlp.Client).Dispose(); } catch (Exception) {} - hlp.Client = null; - } - } - } - - private class ConnectHelper - { - public object Mutex = new object(); - public bool DoCleanup = false; - public bool CallbackDone = false; - public TcpClient Client; - public ConnectHelper(TcpClient client) - { - Client = client; - } - } - - public override void Close() - { - base.Close(); - if (client != null) - { - client.Close(); - client = null; - } - } - - #region " IDisposable Support " - private bool _IsDisposed; - - // IDisposable - protected override void Dispose(bool disposing) - { - if (!_IsDisposed) - { - if (disposing) - { - if (client != null) - ((IDisposable)client).Dispose(); - base.Dispose(disposing); - } - } - _IsDisposed = true; - } - #endregion - } + hlp.Client = null; + } + } + } + + private class ConnectHelper + { + public object Mutex = new object(); + public bool DoCleanup = false; + public bool CallbackDone = false; + public TcpClient Client; + public ConnectHelper(TcpClient client) + { + Client = client; + } + } + + public override void Close() + { + base.Close(); + if (client != null) + { + client.Close(); + client = null; + } + } + + #region " IDisposable Support " + private bool _IsDisposed; + + // IDisposable + protected override void Dispose(bool disposing) + { + if (!_IsDisposed) + { + if (disposing) + { + if (client != null) + ((IDisposable)client).Dispose(); + base.Dispose(disposing); + } + } + _IsDisposed = true; + } + #endregion + } } http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Transport/TSocketVersionizer.cs ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Transport/TSocketVersionizer.cs b/lib/csharp/src/Transport/TSocketVersionizer.cs new file mode 100644 index 0000000..904e519 --- /dev/null +++ b/lib/csharp/src/Transport/TSocketVersionizer.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +#if NET45 +using System.Threading.Tasks; +#endif + +namespace Thrift.Transport +{ + /** + * PropertyInfo for the DualMode property of the System.Net.Sockets.Socket class. Used to determine if the sockets are capable of + * automatic IPv4 and IPv6 handling. If DualMode is present the sockets automatically handle IPv4 and IPv6 connections. + * If the DualMode is not available the system configuration determines whether IPv4 or IPv6 is used. + */ + internal static class TSocketVersionizer + { + /* + * Creates a TcpClient according to the capabilitites of the used framework + */ + internal static TcpClient CreateTcpClient() + { + TcpClient client = null; + +#if NET45 + client = new TcpClient(AddressFamily.InterNetworkV6); + client.Client.DualMode = true; +#else + client = new TcpClient(AddressFamily.InterNetwork); +#endif + + return client; + } + + /* + * Creates a TcpListener according to the capabilitites of the used framework + */ + internal static TcpListener CreateTcpListener(Int32 port) + { + TcpListener listener = null; + +#if NET45 + listener = new TcpListener(System.Net.IPAddress.IPv6Any, port); + listener.Server.DualMode = true; +#else + + listener = new TcpListener(System.Net.IPAddress.Any, port); +#endif + + return listener; + } + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Transport/TTLSServerSocket.cs ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Transport/TTLSServerSocket.cs b/lib/csharp/src/Transport/TTLSServerSocket.cs index d6e69eb..86a4494 100644 --- a/lib/csharp/src/Transport/TTLSServerSocket.cs +++ b/lib/csharp/src/Transport/TTLSServerSocket.cs @@ -126,8 +126,8 @@ namespace Thrift.Transport try { // Create server socket - server = new TcpListener(System.Net.IPAddress.Any, this.port); - server.Server.NoDelay = true; + this.server = TSocketVersionizer.CreateTcpListener(port); + this.server.Server.NoDelay = true; } catch (Exception) { http://git-wip-us.apache.org/repos/asf/thrift/blob/feea4785/lib/csharp/src/Transport/TTLSSocket.cs ---------------------------------------------------------------------- diff --git a/lib/csharp/src/Transport/TTLSSocket.cs b/lib/csharp/src/Transport/TTLSSocket.cs index 08f0215..27be0f4 100644 --- a/lib/csharp/src/Transport/TTLSSocket.cs +++ b/lib/csharp/src/Transport/TTLSSocket.cs @@ -192,7 +192,7 @@ namespace Thrift.Transport /// </summary> private void InitSocket() { - this.client = new TcpClient(); + client = TSocketVersionizer.CreateTcpClient(); client.ReceiveTimeout = client.SendTimeout = timeout; client.Client.NoDelay = true; }
