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
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 @@
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 \
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" />
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">
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 @@
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;
+ }
+ }
+ }
}
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 @@
namespace Thrift.Transport
{
- public class TSocket : TStreamTransport
- {
- private TcpClient client = null;
- private string host = null;
- private int port = 0;
- private int timeout = 0;
+ 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;
+ public TSocket(TcpClient client)
+ {
+ this.client = client;
- if (IsOpen)
- {
- inputStream = client.GetStream();
- outputStream = client.GetStream();
- }
- }
+ if (IsOpen)
+ {
+ inputStream = client.GetStream();
+ outputStream = client.GetStream();
+ }
+ }
- public TSocket(string host, int port)
- : this(host, port, 0)
- {
- }
+ 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;
+ public TSocket(string host, int port, int timeout)
+ {
+ this.host = host;
+ this.port = port;
+ this.timeout = timeout;
- InitSocket();
- }
+ InitSocket();
+ }
- private void InitSocket()
- {
- client = new TcpClient();
- client.ReceiveTimeout = client.SendTimeout = timeout;
- client.Client.NoDelay = true;
- }
+ 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 int Timeout
+ {
+ set
+ {
+ client.ReceiveTimeout = client.SendTimeout = timeout = value;
+ }
+ }
- public TcpClient TcpClient
- {
- get
- {
- return client;
- }
- }
+ public TcpClient TcpClient
+ {
+ get
+ {
+ return client;
+ }
+ }
- public string Host
- {
- get
- {
- return host;
- }
- }
+ public string Host
+ {
+ get
+ {
+ return host;
+ }
+ }
- public int Port
- {
- get
- {
- return port;
- }
- }
+ public int Port
+ {
+ get
+ {
+ return port;
+ }
+ }
- public override bool IsOpen
- {
- get
- {
- if (client == null)
- {
- return false;
- }
+ public override bool IsOpen
+ {
+ get
+ {
+ if (client == null)
+ {
+ return false;
+ }
- return client.Connected;
- }
- }
+ return client.Connected;
+ }
+ }
- public override void Open()
- {
- if (IsOpen)
- {
- throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already 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 (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 (port <= 0)
+ {
+ throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+ }
- if (client == null)
- {
- InitSocket();
- }
+ 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");
- }
- }
+ {
+ 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();
- }
+ inputStream = client.GetStream();
+ outputStream = client.GetStream();
+ }
- static void ConnectCallback(IAsyncResult asyncres)
- {
- ConnectHelper hlp = asyncres.AsyncState as ConnectHelper;
- lock (hlp.Mutex)
- {
- hlp.CallbackDone = true;
+ static void ConnectCallback(IAsyncResult asyncres)
+ {
+ ConnectHelper hlp = asyncres.AsyncState as ConnectHelper;
+ lock (hlp.Mutex)
+ {
+ hlp.CallbackDone = true;
- try
- {
+ try
+ {
if( hlp.Client.Client != null)
- hlp.Client.EndConnect(asyncres);
- }
- catch (Exception)
- {
- // catch that away
- }
+ hlp.Client.EndConnect(asyncres);
+ }
+ catch (Exception)
+ {
+ // catch that away
+ }
- if (hlp.DoCleanup)
- {
+ 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;
- }
- }
- }
+ 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;
- }
- }
+ 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;
- }
- }
+ public override void Close()
+ {
+ base.Close();
+ if (client != null)
+ {
+ client.Close();
+ client = null;
+ }
+ }
- #region " IDisposable Support "
- private bool _IsDisposed;
+ #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
- }
+ // IDisposable
+ protected override void Dispose(bool disposing)
+ {
+ if (!_IsDisposed)
+ {
+ if (disposing)
+ {
+ if (client != null)
+ ((IDisposable)client).Dispose();
+ base.Dispose(disposing);
+ }
+ }
+ _IsDisposed = true;
+ }
+ #endregion
+ }
}
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;
+ }
+ }
+}
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 @@
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)
{
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 @@
/// </summary>
private void InitSocket()
{
- this.client = new TcpClient();
+ client = TSocketVersionizer.CreateTcpClient();
client.ReceiveTimeout = client.SendTimeout = timeout;
client.Client.NoDelay = true;
}