THRIFT-1558 Named Pipe and Anonymous Pipe transport for Windows
Patch: Peace C

git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1325020 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/src/transport/TPipe.cpp b/lib/cpp/src/transport/TPipe.cpp
new file mode 100644
index 0000000..2c7cf56
--- /dev/null
+++ b/lib/cpp/src/transport/TPipe.cpp
@@ -0,0 +1,209 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+#ifdef _WIN32
+
+#include "TTransportException.h"
+#include "TPipe.h"
+
+namespace apache { namespace thrift { namespace transport {
+
+using namespace std;
+
+/**
+* TPipe implementation.
+*/
+
+//---- Constructors ----
+TPipe::TPipe(HANDLE hpipe) :
+  pipename_(""),
+  hPipe_(hpipe),
+  TimeoutSeconds_(3),
+  isAnonymous(false)
+{}
+
+TPipe::TPipe(string pipename) :
+  pipename_(pipename),
+  hPipe_(INVALID_HANDLE_VALUE),
+  TimeoutSeconds_(3),
+  isAnonymous(false)
+{}
+
+TPipe::TPipe(HANDLE hPipeRd, HANDLE hPipeWrt) :
+  pipename_(""),
+  hPipe_(hPipeRd),
+  hPipeWrt_(hPipeWrt),
+  TimeoutSeconds_(3),
+  isAnonymous(true)
+{}
+
+  TPipe::TPipe() :
+  pipename_(""),
+  hPipe_(INVALID_HANDLE_VALUE),
+  TimeoutSeconds_(3)
+{}
+
+//---- Destructor ----
+TPipe::~TPipe() {
+  close();
+}
+
+
+bool TPipe::isOpen() {
+  return (hPipe_ != INVALID_HANDLE_VALUE);
+}
+
+//---------------------------------------------------------
+// Transport callbacks
+//---------------------------------------------------------
+
+bool TPipe::peek() {
+  if (!isOpen()) {
+    return false;
+  }
+  DWORD bytesavail = 0;
+  int  PeekRet = 0;
+  PeekRet = PeekNamedPipe(hPipe_, NULL, 0, NULL, &bytesavail, NULL); 
+  return (PeekRet != 0 && bytesavail > 0);
+}
+
+void TPipe::open() {
+  if (isOpen()) {
+    return;
+  }
+
+  int SleepInterval = 500; //ms
+  int retries = TimeoutSeconds_ * 1000 / SleepInterval;
+  for(int i=0; i<retries; i++)
+  {
+    hPipe_ = CreateFile( 
+              pipename_.c_str(),
+              GENERIC_READ | GENERIC_WRITE, 
+              0,              // no sharing 
+              NULL,           // default security attributes
+              OPEN_EXISTING,  // opens existing pipe 
+              0,              // default attributes 
+              NULL);          // no template file 
+
+    if (hPipe_ == INVALID_HANDLE_VALUE) 
+      sleep(SleepInterval);
+    else
+      break;
+  }
+  if (hPipe_ == INVALID_HANDLE_VALUE) 
+    throw TTransportException(TTransportException::NOT_OPEN, "Unable to open pipe");
+
+  // The pipe connected; change to message-read mode. 
+  DWORD dwMode = PIPE_READMODE_MESSAGE; 
+  int fSuccess = SetNamedPipeHandleState( 
+              hPipe_,   // pipe handle 
+              &dwMode,  // new pipe mode 
+              NULL,     // don't set maximum bytes 
+              NULL);    // don't set maximum time 
+  if (fSuccess == 0)
+  {
+    throw TTransportException(TTransportException::NOT_OPEN, "SetNamedPipeHandleState failed");
+    close();
+  }
+}
+
+
+void TPipe::close() {
+  if (isOpen())
+  {
+    CloseHandle(hPipe_);
+    hPipe_ = INVALID_HANDLE_VALUE;
+  }
+}
+
+uint32_t TPipe::read(uint8_t* buf, uint32_t len) {
+  if (!isOpen())
+    throw TTransportException(TTransportException::NOT_OPEN, "Called read on non-open pipe");
+
+  DWORD  cbRead; 
+  int fSuccess = ReadFile( 
+              hPipe_,   // pipe handle 
+              buf,      // buffer to receive reply 
+              len,      // size of buffer 
+              &cbRead,  // number of bytes read 
+              NULL);    // not overlapped 
+
+  if ( !fSuccess && GetLastError() != ERROR_MORE_DATA )
+    return 0; // No more data, possibly because client disconnected.
+
+  return cbRead;
+}
+
+void TPipe::write(const uint8_t* buf, uint32_t len) {
+  if (!isOpen())
+    throw TTransportException(TTransportException::NOT_OPEN, "Called write on non-open pipe");
+
+  HANDLE WritePipe = isAnonymous? hPipeWrt_: hPipe_;
+  DWORD  cbWritten; 
+  int fSuccess = WriteFile( 
+              WritePipe,     // pipe handle 
+              buf,        // message 
+              len,        // message length 
+              &cbWritten, // bytes written 
+              NULL);      // not overlapped 
+
+  if ( !fSuccess) 
+    throw TTransportException(TTransportException::NOT_OPEN, "Write to pipe failed");
+}
+
+
+//---------------------------------------------------------
+// Accessors
+//---------------------------------------------------------
+
+string TPipe::getPipename() {
+  return pipename_;
+}
+
+void TPipe::setPipename(std::string pipename) {
+  pipename_ = pipename;
+}
+
+HANDLE TPipe::getPipeHandle() {
+  return hPipe_;
+}
+
+void TPipe::setPipeHandle(HANDLE pipehandle) {
+  hPipe_ = pipehandle;
+}
+
+HANDLE TPipe::getWrtPipeHandle() {
+  return hPipeWrt_;
+}
+
+void TPipe::setWrtPipeHandle(HANDLE pipehandle) {
+  hPipeWrt_ = pipehandle;
+}
+
+long TPipe::getConnectTimeout() {
+  return TimeoutSeconds_;
+}
+
+void TPipe::setConnectTimeout(long seconds) {
+  TimeoutSeconds_ = seconds;
+}
+
+}}} // apache::thrift::transport
+
+#endif //_WIN32