THRIFT-2032 C# client leaks sockets/handles

Patch: Jens Geyer
diff --git a/compiler/cpp/src/generate/t_csharp_generator.cc b/compiler/cpp/src/generate/t_csharp_generator.cc
index 37800a5..3f432da 100644
--- a/compiler/cpp/src/generate/t_csharp_generator.cc
+++ b/compiler/cpp/src/generate/t_csharp_generator.cc
@@ -1244,6 +1244,8 @@
   if (tservice->get_extends() != NULL) {
     extends = type_name(tservice->get_extends());
     extends_client = extends + ".Client, ";
+  } else {
+    extends_client = "IDisposable, ";
   }
 
   generate_csharp_doc(f_service_, tservice);
@@ -1290,6 +1292,35 @@
     indent(f_service_) << "get { return oprot_; }" << endl;
     scope_down(f_service_);
     f_service_ << endl << endl;
+    
+    indent(f_service_) << "#region \" IDisposable Support \"" << endl;
+    indent(f_service_) << "private bool _IsDisposed;" << endl << endl;
+    indent(f_service_) << "// IDisposable" << endl;
+    indent(f_service_) << "public void Dispose()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "Dispose(true);" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << endl << endl;
+    indent(f_service_) << "protected virtual void Dispose(bool disposing)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (!_IsDisposed)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (disposing)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (iprot_ != null)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "((IDisposable)iprot_).Dispose();" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << "if (oprot_ != null)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "((IDisposable)oprot_).Dispose();" << endl;
+    scope_down(f_service_);
+    scope_down(f_service_);
+    scope_down(f_service_);
+    indent(f_service_) << "_IsDisposed = true;" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << "#endregion" << endl;
+    f_service_ << endl << endl;
   }
 
   vector<t_function*> functions = tservice->get_functions();
diff --git a/lib/csharp/src/Protocol/TProtocol.cs b/lib/csharp/src/Protocol/TProtocol.cs
index ea3762c..70920d4 100644
--- a/lib/csharp/src/Protocol/TProtocol.cs
+++ b/lib/csharp/src/Protocol/TProtocol.cs
@@ -27,7 +27,7 @@
 
 namespace Thrift.Protocol
 {
-	public abstract class TProtocol
+	public abstract class TProtocol : IDisposable
 	{
 		protected TTransport trans;
 
@@ -41,6 +41,29 @@
 			get { return trans; }
 		}
 
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (trans is IDisposable)
+                        (trans as IDisposable).Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+
 		public abstract void WriteMessageBegin(TMessage message);
 		public abstract void WriteMessageEnd();
 		public abstract void WriteStructBegin(TStruct struc);
diff --git a/lib/csharp/src/Transport/TServerSocket.cs b/lib/csharp/src/Transport/TServerSocket.cs
index 1ad3bd8..eefa4f9 100644
--- a/lib/csharp/src/Transport/TServerSocket.cs
+++ b/lib/csharp/src/Transport/TServerSocket.cs
@@ -116,48 +116,48 @@
 			}
 		}
 
-		protected override TTransport AcceptImpl()
-		{
-			if (server == null)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
-			}
-			try
-			{
-				TcpClient result = server.AcceptTcpClient();
-				TSocket result2 = new TSocket(result);
-        try
+        protected override TTransport AcceptImpl()
         {
-          result2 = new TSocket(result);
-          result2.Timeout = clientTimeout;
-          if (useBufferedSockets)
-          {
-            TBufferedTransport result3 = new TBufferedTransport(result2);
-            return result3;
-          }
-          else
-          {
-            return result2;
-          }
+            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());
+            }
         }
-        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()
+        public override void Close()
 		{
 			if (server != null)
 			{
diff --git a/tutorial/csharp/CsharpClient/CsharpClient.cs b/tutorial/csharp/CsharpClient/CsharpClient.cs
index 8ce1085..113a472 100644
--- a/tutorial/csharp/CsharpClient/CsharpClient.cs
+++ b/tutorial/csharp/CsharpClient/CsharpClient.cs
@@ -37,45 +37,50 @@
                 Calculator.Client client = new Calculator.Client(protocol);
 
                 transport.Open();
-
-                client.ping();
-                Console.WriteLine("ping()");
-
-                int sum = client.add(1, 1);
-                Console.WriteLine("1+1={0}", sum);
-
-                Work work = new Work();
-
-                work.Op = Operation.DIVIDE;
-                work.Num1 = 1;
-                work.Num2 = 0;
                 try
                 {
-                    int quotient = client.calculate(1, work);
-                    Console.WriteLine("Whoa we can divide by 0");
-                }
-                catch (InvalidOperation io)
-                {
-                    Console.WriteLine("Invalid operation: " + io.Why);
-                }
+                    client.ping();
+                    Console.WriteLine("ping()");
 
-                work.Op = Operation.SUBTRACT;
-                work.Num1 = 15;
-                work.Num2 = 10;
-                try
-                {
-                    int diff = client.calculate(1, work);
-                    Console.WriteLine("15-10={0}", diff);
-                }
-                catch (InvalidOperation io)
-                {
-                    Console.WriteLine("Invalid operation: " + io.Why);
-                }
+                    int sum = client.add(1, 1);
+                    Console.WriteLine("1+1={0}", sum);
 
-                SharedStruct log = client.getStruct(1);
-                Console.WriteLine("Check log: {0}", log.Value);
+                    Work work = new Work();
 
-                transport.Close();
+                    work.Op = Operation.DIVIDE;
+                    work.Num1 = 1;
+                    work.Num2 = 0;
+                    try
+                    {
+                        int quotient = client.calculate(1, work);
+                        Console.WriteLine("Whoa we can divide by 0");
+                    }
+                    catch (InvalidOperation io)
+                    {
+                        Console.WriteLine("Invalid operation: " + io.Why);
+                    }
+
+                    work.Op = Operation.SUBTRACT;
+                    work.Num1 = 15;
+                    work.Num2 = 10;
+                    try
+                    {
+                        int diff = client.calculate(1, work);
+                        Console.WriteLine("15-10={0}", diff);
+                    }
+                    catch (InvalidOperation io)
+                    {
+                        Console.WriteLine("Invalid operation: " + io.Why);
+                    }
+
+                    SharedStruct log = client.getStruct(1);
+                    Console.WriteLine("Check log: {0}", log.Value);
+
+                }
+                finally
+                {
+                    transport.Close();
+                }
             }
             catch (TApplicationException x)
             {