THRIFT-2408 Named Pipe Transport Option for C#

Patch: Carl Yeksigian & Jens Geyer
diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj
index 58d3793..d475ed6 100644
--- a/lib/csharp/src/Thrift.csproj
+++ b/lib/csharp/src/Thrift.csproj
@@ -112,6 +112,8 @@
     <Compile Include="Transport\TFramedTransport.cs" />
     <Compile Include="Transport\THttpClient.cs" />
     <Compile Include="Transport\THttpHandler.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" />
diff --git a/lib/csharp/src/Transport/TNamedPipeClientTransport.cs b/lib/csharp/src/Transport/TNamedPipeClientTransport.cs
new file mode 100644
index 0000000..4c320e6
--- /dev/null
+++ b/lib/csharp/src/Transport/TNamedPipeClientTransport.cs
@@ -0,0 +1,72 @@
+using System.IO.Pipes;
+
+namespace Thrift.Transport
+{
+	public class TNamedPipeClientTransport : TTransport
+	{
+		private NamedPipeClientStream client;
+		private string ServerName;
+		private string PipeName;
+
+		public TNamedPipeClientTransport(string pipe)
+		{
+			ServerName = ".";
+			PipeName = pipe;
+		}
+
+		public TNamedPipeClientTransport(string server, string pipe)
+		{
+			ServerName = (server != "") ? server : ".";
+			PipeName = pipe;
+		}
+
+		public override bool IsOpen
+		{
+			get { return client != null && client.IsConnected; }
+		}
+
+		public override void Open()
+		{
+			if (IsOpen)
+			{
+				throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen);
+			}
+			client = new NamedPipeClientStream(ServerName, PipeName, PipeDirection.InOut, PipeOptions.None);
+			client.Connect();
+		}
+
+		public override void Close()
+		{
+			if (client != null)
+			{
+				client.Close();
+				client = null;
+			}
+		}
+
+		public override int Read(byte[] buf, int off, int len)
+		{
+			if (client == null)
+			{
+				throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+			}
+
+			return client.Read(buf, off, len);
+		}
+
+		public override void Write(byte[] buf, int off, int len)
+		{
+			if (client == null)
+			{
+				throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+			}
+
+			client.Write(buf, off, len);
+		}
+
+		protected override void Dispose(bool disposing)
+		{
+			client.Dispose();
+		}
+	}
+}
\ No newline at end of file
diff --git a/lib/csharp/src/Transport/TNamedPipeServerTransport.cs b/lib/csharp/src/Transport/TNamedPipeServerTransport.cs
new file mode 100644
index 0000000..b87898e
--- /dev/null
+++ b/lib/csharp/src/Transport/TNamedPipeServerTransport.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.IO.Pipes;
+
+namespace Thrift.Transport
+{
+	public class TNamedPipeServerTransport : TServerTransport
+	{
+		/// <summary>
+		/// This is the address of the Pipe on the localhost.
+		/// </summary>
+		private readonly string pipeAddress;
+		NamedPipeServerStream stream = null;
+
+		public TNamedPipeServerTransport(string pipeAddress)
+		{
+			this.pipeAddress = pipeAddress;
+		}
+
+		public override void Listen()
+		{
+			// nothing to do here
+		}
+
+		public override void Close()
+		{
+			if (stream != null)
+			{
+				try
+				{
+					stream.Close();
+					stream.Dispose();
+				}
+				finally
+				{
+					stream = null;
+				}
+			}
+		}
+
+		private void EnsurePipeInstance()
+		{
+			if( stream == null)
+				stream = new NamedPipeServerStream(
+					pipeAddress, PipeDirection.InOut, 254,
+					PipeTransmissionMode.Byte,
+					PipeOptions.None, 4096, 4096 /*TODO: security*/);
+		}
+
+		protected override TTransport AcceptImpl()
+		{
+			try
+			{
+				EnsurePipeInstance();
+				stream.WaitForConnection();
+				var trans = new ServerTransport(stream);
+				stream = null;  // pass ownership to ServerTransport
+				return trans;
+			}
+			catch (Exception e)
+			{
+				Close();
+				throw new TTransportException(TTransportException.ExceptionType.NotOpen, e.Message);
+			}
+		}
+
+		private class ServerTransport : TTransport
+		{
+			private NamedPipeServerStream server;
+			public ServerTransport(NamedPipeServerStream server)
+			{
+				this.server = server;
+			}
+
+			public override bool IsOpen
+			{
+				get { return server != null && server.IsConnected; }
+			}
+
+			public override void Open()
+			{
+			}
+
+			public override void Close()
+			{
+				if (server != null) server.Close();
+			}
+
+			public override int Read(byte[] buf, int off, int len)
+			{
+				if (server == null)
+				{
+					throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+				}
+				return server.Read(buf, off, len);
+			}
+
+			public override void Write(byte[] buf, int off, int len)
+			{
+				if (server == null)
+				{
+					throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+				}
+				server.Write(buf, off, len);
+			}
+
+			protected override void Dispose(bool disposing)
+			{
+				server.Dispose();
+			}
+		}
+	}
+}
\ No newline at end of file