Thrift Binary protocol improvements and application exceptions

Summary: Add application exceptions for unknown methods etc, and also let binary protocol support size limits on containers and strings

Reviewed By: aditya, xp-wayne


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665003 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index 9cac7d5..92ccdf1 100644
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -5,7 +5,8 @@
 
 # Define the source file for the module
 
-libthrift_sources = src/concurrency/Mutex.cpp \
+libthrift_sources = src/Thrift.cpp \
+                    src/concurrency/Mutex.cpp \
                     src/concurrency/Monitor.cpp \
                     src/concurrency/PosixThreadFactory.cpp \
                     src/concurrency/ThreadManager.cpp \
@@ -51,6 +52,7 @@
 include_protocoldir = $(include_thriftdir)/protocol
 include_protocol_HEADERS = \
                          src/protocol/TBinaryProtocol.h \
+                         src/protocol/TProtocolException.h \
                          src/protocol/TProtocol.h
 
 include_transportdir = $(include_thriftdir)/transport
diff --git a/lib/cpp/src/Thrift.cpp b/lib/cpp/src/Thrift.cpp
new file mode 100644
index 0000000..f6e33b2
--- /dev/null
+++ b/lib/cpp/src/Thrift.cpp
@@ -0,0 +1,61 @@
+#include <Thrift.h>
+#include <protocol/TProtocol.h>
+
+namespace facebook { namespace thrift {
+
+uint32_t TApplicationException::read(facebook::thrift::protocol::TProtocol* iprot) {
+  uint32_t xfer = 0;
+  std::string fname;
+  facebook::thrift::protocol::TType ftype;
+  int16_t fid;
+
+  xfer += iprot->readStructBegin(fname);
+
+  while (true) {
+    xfer += iprot->readFieldBegin(fname, ftype, fid);
+    if (ftype == facebook::thrift::protocol::T_STOP) { 
+      break;
+    }
+    switch (fid) {
+    case 1:
+      if (ftype == facebook::thrift::protocol::T_STRING) {
+        xfer += iprot->readString(message_);
+      } else {
+        xfer += iprot->skip(ftype);
+      }
+      break;
+    case 2:
+      if (ftype == facebook::thrift::protocol::T_I32) {
+        int32_t type;
+        xfer += iprot->readI32(type);
+        type_ = (TApplicationExceptionType)type;
+      } else {
+        xfer += iprot->skip(ftype);
+      }
+      break;
+    default:
+      xfer += iprot->skip(ftype);
+      break;
+    }
+    xfer += iprot->readFieldEnd();
+  }
+
+  xfer += iprot->readStructEnd();
+  return xfer;
+}
+
+uint32_t TApplicationException::write(facebook::thrift::protocol::TProtocol* oprot) const {
+  uint32_t xfer = 0;
+  xfer += oprot->writeStructBegin("TApplicationException");
+  xfer += oprot->writeFieldBegin("message", facebook::thrift::protocol::T_STRING, 1);
+  xfer += oprot->writeString(message_);
+  xfer += oprot->writeFieldEnd();
+  xfer += oprot->writeFieldBegin("type", facebook::thrift::protocol::T_I32, 2);
+  xfer += oprot->writeI32(type_);
+  xfer += oprot->writeFieldEnd();
+  xfer += oprot->writeFieldStop();
+  xfer += oprot->writeStructEnd();
+  return xfer;
+}
+
+}} // facebook::thrift
diff --git a/lib/cpp/src/Thrift.h b/lib/cpp/src/Thrift.h
index 2268c34..61edf5b 100644
--- a/lib/cpp/src/Thrift.h
+++ b/lib/cpp/src/Thrift.h
@@ -14,6 +14,10 @@
 
 namespace facebook { namespace thrift {
 
+namespace protocol {
+  class TProtocol;
+}
+
 class TException : public std::exception {
 public:
   TException() {}
@@ -36,6 +40,66 @@
 
 };
 
+class TApplicationException : public TException {
+public:
+
+  /**
+   * Error codes for the various types of exceptions.
+   */
+  enum TApplicationExceptionType {
+    UNKNOWN = 0,
+    INVALID_METHOD = 1,
+  };
+
+  TApplicationException() :
+    TException(),
+    type_(UNKNOWN) {}
+
+  TApplicationException(TApplicationExceptionType type) :
+    TException(), 
+    type_(type) {}
+
+  TApplicationException(const std::string message) :
+    TException(message),
+    type_(UNKNOWN) {}
+
+  TApplicationException(TApplicationExceptionType type,
+                        const std::string message) :
+    TException(message),
+    type_(type) {}
+
+  virtual ~TApplicationException() throw() {}
+
+  /**
+   * Returns an error code that provides information about the type of error
+   * that has occurred.
+   *
+   * @return Error code
+   */
+  TApplicationExceptionType getType() {
+    return type_;
+  }
+
+  virtual const char* what() const throw() {
+    if (message_.empty()) {
+      return "Default TApplicationException.";
+    } else {
+      return message_.c_str();
+    }
+  }
+
+  uint32_t TApplicationException::read(facebook::thrift::protocol::TProtocol* iprot);
+  uint32_t TApplicationException::write(facebook::thrift::protocol::TProtocol* oprot) const;
+
+protected:
+  /**
+   * Error code
+   */
+  TApplicationExceptionType type_;
+
+};
+
+
 }} // facebook::thrift
 
 #endif // #ifndef _THRIFT_THRIFT_H_
diff --git a/lib/cpp/src/protocol/TBinaryProtocol.cpp b/lib/cpp/src/protocol/TBinaryProtocol.cpp
index 05de125..cea248b 100644
--- a/lib/cpp/src/protocol/TBinaryProtocol.cpp
+++ b/lib/cpp/src/protocol/TBinaryProtocol.cpp
@@ -123,9 +123,12 @@
 
   
 uint32_t TBinaryProtocol::writeString(const string& str) {
-  uint32_t result = writeI32(str.size());
-  trans_->write((uint8_t*)str.data(), str.size());
-  return result + str.size();
+  uint32_t size = str.size();
+  uint32_t result = writeI32((int32_t)size);
+  if (size > 0) {
+    trans_->write((uint8_t*)str.data(), size);
+  }
+  return result + size;
 }
 
 /**
@@ -188,7 +191,11 @@
   result += readByte(v);
   valType = (TType)v;
   result += readI32(sizei);
-  // TODO(mcslee): check for negative size
+  if (sizei < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  } else if (container_limit_ && sizei > container_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
   size = (uint32_t)sizei;
   return result;
 }
@@ -205,7 +212,11 @@
   result += readByte(e);
   elemType = (TType)e;
   result += readI32(sizei);
-  // TODO(mcslee): check for negative size
+  if (sizei < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  } else if (container_limit_ && sizei > container_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
   size = (uint32_t)sizei;
   return result;
 }
@@ -222,7 +233,11 @@
   result += readByte(e);
   elemType = (TType)e;
   result += readI32(sizei);
-  // TODO(mcslee): check for negative size
+  if (sizei < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  } else if (container_limit_ && sizei > container_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
   size = (uint32_t)sizei;
   return result;
 }
@@ -290,13 +305,31 @@
   int32_t size;
   result = readI32(size);
 
-  // TODO(mcslee): check for negative size
+  // Catch error cases
+  if (size < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  }
+  if (string_limit_ > 0 && size > string_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
+
+  // Catch empty string case
+  if (size == 0) {
+    str = "";
+    return result;
+  }
 
   // Use the heap here to prevent stack overflow for v. large strings
-  uint8_t *b = new uint8_t[size];
-  trans_->readAll(b, size);
-  str = string((char*)b, size);
-  delete [] b;
+  if (size > string_buf_size_ || string_buf_ == NULL) {
+    string_buf_ = (uint8_t*)realloc(string_buf_, (uint32_t)size);
+    if (string_buf_ == NULL) {
+      string_buf_size_ = 0;
+      throw TProtocolException(TProtocolException::UNKNOWN, "Out of memory in TBinaryProtocol::readString");
+    }
+    string_buf_size_ = size;
+  }
+  trans_->readAll(string_buf_, size);
+  str = string((char*)string_buf_, size);
 
   return result + (uint32_t)size;
 }
diff --git a/lib/cpp/src/protocol/TBinaryProtocol.h b/lib/cpp/src/protocol/TBinaryProtocol.h
index c0a1837..3414cec 100644
--- a/lib/cpp/src/protocol/TBinaryProtocol.h
+++ b/lib/cpp/src/protocol/TBinaryProtocol.h
@@ -15,12 +15,38 @@
  *
  * @author Mark Slee <mcslee@facebook.com>
  */
-    class TBinaryProtocol : public TProtocol {
+class TBinaryProtocol : public TProtocol {
  public:
   TBinaryProtocol(shared_ptr<TTransport> trans) :
-    TProtocol(trans) {}
+    TProtocol(trans),
+    string_limit_(0),
+    container_limit_(0),
+    string_buf_(NULL),
+    string_buf_size_(0) {}
 
-  ~TBinaryProtocol() {}
+  TBinaryProtocol(shared_ptr<TTransport> trans,
+                  int32_t string_limit,
+                  int32_t container_limit) :
+    TProtocol(trans),
+    string_limit_(string_limit),
+    container_limit_(container_limit),
+    string_buf_(NULL),
+    string_buf_size_(0) {}
+
+  ~TBinaryProtocol() {
+    if (string_buf_ != NULL) {
+      free(string_buf_);
+      string_buf_size_ = 0;
+    }
+  }
+
+  void setStringSizeLimit(int32_t string_limit) {
+    string_limit_ = string_limit;
+  }
+
+  void setContainerSizeLimit(int32_t container_limit) {
+    container_limit_ = container_limit;
+  }
 
   /**
    * Writing functions.
@@ -126,6 +152,16 @@
   uint32_t readDouble(double& dub);
 
   uint32_t readString(std::string& str);
+
+ private:
+  int32_t string_limit_;
+  int32_t container_limit_;
+
+  // Buffer for reading strings, save for the lifetime of the protocol to
+  // avoid memory churn allocating memory on every string read
+  uint8_t* string_buf_;
+  int32_t string_buf_size_;
+
 };
 
 /**
@@ -133,13 +169,32 @@
  */
 class TBinaryProtocolFactory : public TProtocolFactory {
  public:
-  TBinaryProtocolFactory() {}
+  TBinaryProtocolFactory() :
+    string_limit_(0),
+    container_limit_(0) {}
+
+  TBinaryProtocolFactory(int32_t string_limit, int32_t container_limit) :
+    string_limit_(string_limit),
+    container_limit_(container_limit) {}
 
   virtual ~TBinaryProtocolFactory() {}
 
-  boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TProtocol>(new TBinaryProtocol(trans));
+  void setStringSizeLimit(int32_t string_limit) {
+    string_limit_ = string_limit;
   }
+
+  void setContainerSizeLimit(int32_t container_limit) {
+    container_limit_ = container_limit;
+  }
+
+  boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
+    return boost::shared_ptr<TProtocol>(new TBinaryProtocol(trans, string_limit_, container_limit_));
+  }
+
+ private:
+  int32_t string_limit_;
+  int32_t container_limit_;
+
 };
 
 }}} // facebook::thrift::protocol
diff --git a/lib/cpp/src/protocol/TProtocol.h b/lib/cpp/src/protocol/TProtocol.h
index 2ad5a57..42bea2b 100644
--- a/lib/cpp/src/protocol/TProtocol.h
+++ b/lib/cpp/src/protocol/TProtocol.h
@@ -2,6 +2,7 @@
 #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
 
 #include <transport/TTransport.h>
+#include <protocol/TProtocolException.h>
 
 #include <boost/shared_ptr.hpp>
 
@@ -59,7 +60,8 @@
  */
 enum TMessageType {
   T_CALL       = 1,
-  T_REPLY      = 2
+  T_REPLY      = 2,
+  T_EXCEPTION  = 3
 };
 
 /**
diff --git a/lib/cpp/src/protocol/TProtocolException.h b/lib/cpp/src/protocol/TProtocolException.h
new file mode 100644
index 0000000..74c55cd
--- /dev/null
+++ b/lib/cpp/src/protocol/TProtocolException.h
@@ -0,0 +1,78 @@
+#ifndef _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_
+#define _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_ 1
+
+#include <boost/lexical_cast.hpp>
+#include <string>
+
+namespace facebook { namespace thrift { namespace protocol { 
+
+/**
+ * Class to encapsulate all the possible types of protocol errors that may
+ * occur in various protocol systems. This provides a sort of generic
+ * wrapper around the shitty UNIX E_ error codes that lets a common code
+ * base of error handling to be used for various types of protocols, i.e.
+ * pipes etc.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class TProtocolException : public facebook::thrift::TException {
+ public:
+
+  /**
+   * Error codes for the various types of exceptions.
+   */
+  enum TProtocolExceptionType {
+    UNKNOWN = 0,
+    INVALID_DATA = 1,
+    NEGATIVE_SIZE = 2,
+    SIZE_LIMIT = 3
+  };
+
+  TProtocolException() :
+    facebook::thrift::TException(),
+    type_(UNKNOWN) {}
+
+  TProtocolException(TProtocolExceptionType type) :
+    facebook::thrift::TException(), 
+    type_(type) {}
+
+  TProtocolException(const std::string message) :
+    facebook::thrift::TException(message),
+    type_(UNKNOWN) {}
+
+  TProtocolException(TProtocolExceptionType type, const std::string message) :
+    facebook::thrift::TException(message),
+    type_(type) {}
+
+  virtual ~TProtocolException() throw() {}
+
+  /**
+   * Returns an error code that provides information about the type of error
+   * that has occurred.
+   *
+   * @return Error code
+   */
+  TProtocolExceptionType getType() {
+    return type_;
+  }
+
+  virtual const char* what() const throw() {
+    if (message_.empty()) {
+      return (std::string("Default Protocol Exception: ") +
+        boost::lexical_cast<std::string>(type_)).c_str();
+    } else {
+      return message_.c_str();
+    }
+  }
+
+ protected:
+  /** 
+   * Error code
+   */
+  TProtocolExceptionType type_;
+ 
+};
+
+}}} // facebook::thrift::protocol
+
+#endif // #ifndef _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_
diff --git a/lib/cpp/src/transport/TFileTransport.h b/lib/cpp/src/transport/TFileTransport.h
index 237234e..09cc531 100644
--- a/lib/cpp/src/transport/TFileTransport.h
+++ b/lib/cpp/src/transport/TFileTransport.h
@@ -336,7 +336,7 @@
 class TEOFException : public facebook::thrift::TTransportException {
  public:
   TEOFException():
-    facebook::thrift::TTransportException(TTX_EOF) {};
+    facebook::thrift::TTransportException(TTransportException::END_OF_FILE) {};
 };
 
 
diff --git a/lib/cpp/src/transport/TServerSocket.cpp b/lib/cpp/src/transport/TServerSocket.cpp
index 8d5e5e4..00860cc 100644
--- a/lib/cpp/src/transport/TServerSocket.cpp
+++ b/lib/cpp/src/transport/TServerSocket.cpp
@@ -42,7 +42,7 @@
   if (serverSocket_ == -1) {
     perror("TServerSocket::listen() socket");
     close();
-    throw TTransportException(TTX_NOT_OPEN, "Could not create server socket.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not create server socket.");
   }
 
   // Set reusaddress to prevent 2MSL delay on accept
@@ -51,7 +51,7 @@
                        &one, sizeof(one))) {
     perror("TServerSocket::listen() SO_REUSEADDR");
     close();
-    throw TTransportException(TTX_NOT_OPEN, "Could not set SO_REUSEADDR");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_REUSEADDR");
   }
 
   // Defer accept
@@ -60,7 +60,7 @@
                        &one, sizeof(one))) {
     perror("TServerSocket::listen() TCP_DEFER_ACCEPT");
     close();
-    throw TTransportException(TTX_NOT_OPEN, "Could not set TCP_DEFER_ACCEPT");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_DEFER_ACCEPT");
   }
   #endif // #ifdef TCP_DEFER_ACCEPT
 
@@ -70,7 +70,7 @@
                        &ling, sizeof(ling))) {
     close();
     perror("TServerSocket::listen() SO_LINGER");
-    throw TTransportException(TTX_NOT_OPEN, "Could not set SO_LINGER");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_LINGER");
   }
 
   // TCP Nodelay, speed over bandwidth
@@ -78,7 +78,7 @@
                        &one, sizeof(one))) {
     close();
     perror("setsockopt TCP_NODELAY");
-    throw TTransportException(TTX_NOT_OPEN, "Could not set TCP_NODELAY");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_NODELAY");
   }
 
   // Bind to a port
@@ -92,14 +92,14 @@
     sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
     perror(errbuf);
     close();
-    throw TTransportException(TTX_NOT_OPEN, "Could not bind");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not bind");
   }
 
   // Call listen
   if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
     perror("TServerSocket::listen() LISTEN");
     close();
-    throw TTransportException(TTX_NOT_OPEN, "Could not listen");
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not listen");
   }
 
   // The socket is now listening!
@@ -107,7 +107,7 @@
 
 shared_ptr<TTransport> TServerSocket::acceptImpl() {
   if (serverSocket_ < 0) {
-    throw TTransportException(TTX_NOT_OPEN, "TServerSocket not listening");
+    throw TTransportException(TTransportException::NOT_OPEN, "TServerSocket not listening");
   }
 
   struct sockaddr_in clientAddress;
@@ -118,7 +118,7 @@
     
   if (clientSocket < 0) {
     perror("TServerSocket::accept()");
-    throw TTransportException(TTX_UNKNOWN, "ERROR:" + errno);
+    throw TTransportException(TTransportException::UNKNOWN, "ERROR:" + errno);
   }
   
   shared_ptr<TSocket> client(new TSocket(clientSocket));
diff --git a/lib/cpp/src/transport/TSocket.cpp b/lib/cpp/src/transport/TSocket.cpp
index 9df78a1..58bb9f4 100644
--- a/lib/cpp/src/transport/TSocket.cpp
+++ b/lib/cpp/src/transport/TSocket.cpp
@@ -92,7 +92,7 @@
   if (r == -1) {
     perror("TSocket::peek()");
     close();
-    throw TTransportException(TTX_UNKNOWN, "recv() ERROR:" + errno);
+    throw TTransportException(TTransportException::UNKNOWN, "recv() ERROR:" + errno);
   }
   return (r > 0);
 }
@@ -103,7 +103,7 @@
   if (socket_ == -1) {
     perror("TSocket::open() socket");
     close();
-    throw TTransportException(TTX_NOT_OPEN, "socket() ERROR:" + errno);
+    throw TTransportException(TTransportException::NOT_OPEN, "socket() ERROR:" + errno);
   }
 
   // Send timeout
@@ -135,7 +135,7 @@
     if (host_entry == NULL) {
       perror("TSocket: dns error: failed call to gethostbyname.");
       close();
-      throw TTransportException(TTX_NOT_OPEN, "gethostbyname() failed");
+      throw TTransportException(TTransportException::NOT_OPEN, "gethostbyname() failed");
     }
     
     addr.sin_port = htons(port_);
@@ -168,7 +168,7 @@
     char buff[1024];
     sprintf(buff, "TSocket::open() connect %s %d", host_.c_str(), port_);
     perror(buff);
-    throw TTransportException(TTX_NOT_OPEN, "open() ERROR: " + errno);
+    throw TTransportException(TTransportException::NOT_OPEN, "open() ERROR: " + errno);
   }
 
   fd_set fds;
@@ -185,22 +185,22 @@
     if (ret2 == -1) {
       close();
       perror("TSocket::open() getsockopt SO_ERROR");
-      throw TTransportException(TTX_NOT_OPEN, "open() ERROR: " + errno);
+      throw TTransportException(TTransportException::NOT_OPEN, "open() ERROR: " + errno);
     }
     if (val == 0) {
       goto done;
     }
     close();
     perror("TSocket::open() SO_ERROR was set");
-    throw TTransportException(TTX_NOT_OPEN, "open() ERROR: " + errno);
+    throw TTransportException(TTransportException::NOT_OPEN, "open() ERROR: " + errno);
   } else if (ret == 0) {
     close();
     perror("TSocket::open() timeed out");
-    throw TTransportException(TTX_NOT_OPEN, "open() ERROR: " + errno);   
+    throw TTransportException(TTransportException::NOT_OPEN, "open() ERROR: " + errno);   
   } else {
     close();
     perror("TSocket::open() select error");
-    throw TTransportException(TTX_NOT_OPEN, "open() ERROR: " + errno);
+    throw TTransportException(TTransportException::NOT_OPEN, "open() ERROR: " + errno);
   }
 
  done:
@@ -218,7 +218,7 @@
 
 uint32_t TSocket::read(uint8_t* buf, uint32_t len) {
   if (socket_ < 0) {
-    throw TTransportException(TTX_NOT_OPEN, "Called read on non-open socket");
+    throw TTransportException(TTransportException::NOT_OPEN, "Called read on non-open socket");
   }
 
   uint32_t retries = 0;
@@ -246,21 +246,21 @@
 
     // If we disconnect with no linger time
     if (errno == ECONNRESET) {
-      throw TTransportException(TTX_NOT_OPEN, "ECONNRESET");
+      throw TTransportException(TTransportException::NOT_OPEN, "ECONNRESET");
     }
     
     // This ish isn't open
     if (errno == ENOTCONN) {
-      throw TTransportException(TTX_NOT_OPEN, "ENOTCONN");
+      throw TTransportException(TTransportException::NOT_OPEN, "ENOTCONN");
     }
     
     // Timed out!
     if (errno == ETIMEDOUT) {
-      throw TTransportException(TTX_TIMED_OUT, "ETIMEDOUT");
+      throw TTransportException(TTransportException::TIMED_OUT, "ETIMEDOUT");
     }
     
     // Some other error, whatevz
-    throw TTransportException(TTX_UNKNOWN, "ERROR:" + errno);
+    throw TTransportException(TTransportException::UNKNOWN, "ERROR:" + errno);
   }
   
   // The remote host has closed the socket
@@ -275,7 +275,7 @@
 
 void TSocket::write(const uint8_t* buf, uint32_t len) {
   if (socket_ < 0) {
-    throw TTransportException(TTX_NOT_OPEN, "Called write on non-open socket");
+    throw TTransportException(TTransportException::NOT_OPEN, "Called write on non-open socket");
   }
 
   uint32_t sent = 0;
@@ -296,26 +296,26 @@
     if (b < 0) {
       if (errno == EPIPE) {
         close();
-        throw TTransportException(TTX_NOT_OPEN, "EPIPE");
+        throw TTransportException(TTransportException::NOT_OPEN, "EPIPE");
       }
 
       if (errno == ECONNRESET) {
         close();
-        throw TTransportException(TTX_NOT_OPEN, "ECONNRESET");
+        throw TTransportException(TTransportException::NOT_OPEN, "ECONNRESET");
       }
 
       if (errno == ENOTCONN) {
         close();
-        throw TTransportException(TTX_NOT_OPEN, "ENOTCONN");
+        throw TTransportException(TTransportException::NOT_OPEN, "ENOTCONN");
       }
 
       perror("TSocket::write() send < 0");
-      throw TTransportException(TTX_UNKNOWN, "ERROR:" + errno);
+      throw TTransportException(TTransportException::UNKNOWN, "ERROR:" + errno);
     }
     
     // Fail on blocked send
     if (b == 0) {
-      throw TTransportException(TTX_NOT_OPEN, "Socket send returned 0.");
+      throw TTransportException(TTransportException::NOT_OPEN, "Socket send returned 0.");
     }
     sent += b;
   }
diff --git a/lib/cpp/src/transport/TTransport.h b/lib/cpp/src/transport/TTransport.h
index 02dd89c..4f49d99 100644
--- a/lib/cpp/src/transport/TTransport.h
+++ b/lib/cpp/src/transport/TTransport.h
@@ -47,14 +47,14 @@
    * @throws TTransportException if opening failed
    */
   virtual void open() {
-    throw TTransportException(TTX_NOT_OPEN, "Cannot open base TTransport.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Cannot open base TTransport.");
   }
 
   /**
    * Closes the transport.
    */
   virtual void close() {
-    throw TTransportException(TTX_NOT_OPEN, "Cannot close base TTransport.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Cannot close base TTransport.");
   }
 
   /**
@@ -66,7 +66,7 @@
    * @throws TTransportException If an error occurs
    */
   virtual uint32_t read(uint8_t* buf, uint32_t len) {
-    throw TTransportException(TTX_NOT_OPEN, "Base TTransport cannot read.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot read.");
   }
 
   /**
@@ -110,7 +110,7 @@
    * @throws TTransportException if an error occurs
    */
   virtual void write(const uint8_t* buf, uint32_t len) {
-    throw TTransportException(TTX_NOT_OPEN, "Base TTransport cannot write.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot write.");
   }
 
   /**
diff --git a/lib/cpp/src/transport/TTransportException.h b/lib/cpp/src/transport/TTransportException.h
index 6dbfb13..3ab1d66 100644
--- a/lib/cpp/src/transport/TTransportException.h
+++ b/lib/cpp/src/transport/TTransportException.h
@@ -7,16 +7,6 @@
 namespace facebook { namespace thrift { namespace transport { 
 
 /**
- * Error codes for the various types of exceptions.
- */
-enum TTransportExceptionType {
-  TTX_UNKNOWN = 0,
-  TTX_NOT_OPEN = 1,
-  TTX_TIMED_OUT = 2,
-  TTX_EOF = 3,
-};
-
-/**
  * Class to encapsulate all the possible types of transport errors that may
  * occur in various transport systems. This provides a sort of generic
  * wrapper around the shitty UNIX E_ error codes that lets a common code
@@ -27,9 +17,19 @@
  */
 class TTransportException : public facebook::thrift::TException {
  public:
+  /**
+   * Error codes for the various types of exceptions.
+   */
+  enum TTransportExceptionType {
+    UNKNOWN = 0,
+    NOT_OPEN = 1,
+    TIMED_OUT = 2,
+    END_OF_FILE = 3,
+  };
+  
   TTransportException() :
     facebook::thrift::TException(),
-    type_(TTX_UNKNOWN) {}
+    type_(UNKNOWN) {}
 
   TTransportException(TTransportExceptionType type) :
     facebook::thrift::TException(), 
@@ -37,7 +37,7 @@
 
   TTransportException(const std::string message) :
     facebook::thrift::TException(message),
-    type_(TTX_UNKNOWN) {}
+    type_(UNKNOWN) {}
 
   TTransportException(TTransportExceptionType type, const std::string message) :
     facebook::thrift::TException(message),