THRIFT-2704 - compiler: T_ONEWAY type used for oneway methods instead of T_CALL

Patch: Konrad Grochowski

This closes #216
diff --git a/lib/cpp/src/thrift/processor/PeekProcessor.cpp b/lib/cpp/src/thrift/processor/PeekProcessor.cpp
index bfc4ac7..9303a13 100644
--- a/lib/cpp/src/thrift/processor/PeekProcessor.cpp
+++ b/lib/cpp/src/thrift/processor/PeekProcessor.cpp
@@ -66,7 +66,7 @@
   int32_t seqid;
   in->readMessageBegin(fname, mtype, seqid);
 
-  if (mtype != T_CALL) {
+  if (mtype != T_CALL && mtype != T_ONEWAY) {
     throw TException("Unexpected message type");
   }
 
diff --git a/lib/cpp/src/thrift/processor/StatsProcessor.h b/lib/cpp/src/thrift/processor/StatsProcessor.h
index 58cd1dc..0fc123e 100644
--- a/lib/cpp/src/thrift/processor/StatsProcessor.h
+++ b/lib/cpp/src/thrift/processor/StatsProcessor.h
@@ -50,7 +50,7 @@
     int32_t seqid;
 
     piprot_->readMessageBegin(fname, mtype, seqid);
-    if (mtype != apache::thrift::protocol::T_CALL) {
+    if (mtype != apache::thrift::protocol::T_CALL && mtype != apache::thrift::protocol::T_ONEWAY) {
       if (print_) {
         printf("Unknown message type\n");
       }
diff --git a/lib/cpp/src/thrift/protocol/TCompactProtocol.h b/lib/cpp/src/thrift/protocol/TCompactProtocol.h
index d6da745..ce60b45 100644
--- a/lib/cpp/src/thrift/protocol/TCompactProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TCompactProtocol.h
@@ -39,6 +39,7 @@
   static const int8_t  VERSION_N = 1;
   static const int8_t  VERSION_MASK = 0x1f; // 0001 1111
   static const int8_t  TYPE_MASK = (int8_t)0xE0u; // 1110 0000
+  static const int8_t  TYPE_BITS = 0x07; // 0000 0111
   static const int32_t TYPE_SHIFT_AMOUNT = 5;
 
   Transport_* trans_;
diff --git a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
index a0955fc..85dde6c 100644
--- a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
@@ -433,7 +433,7 @@
     throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
   }
 
-  messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+  messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
   rsize += readVarint32(seqid);
   rsize += readString(name);
 
diff --git a/lib/cpp/test/AllProtocolTests.tcc b/lib/cpp/test/AllProtocolTests.tcc
index 7ccaef5..3c98943 100644
--- a/lib/cpp/test/AllProtocolTests.tcc
+++ b/lib/cpp/test/AllProtocolTests.tcc
@@ -97,14 +97,16 @@
     const char* name;
     TMessageType type;
     int32_t seqid;
-  } messages[4] = {
+  } messages[] = {
     {"short message name", T_CALL, 0},
     {"1", T_REPLY, 12345},
     {"loooooooooooooooooooooooooooooooooong", T_EXCEPTION, 1 << 16},
+    {"one way push", T_ONEWAY, 12},
     {"Janky", T_CALL, 0}
   };
+  const int messages_count = sizeof(messages) / sizeof(TMessage);
 
-  for (int i = 0; i < 4; i++) {
+  for (int i = 0; i < messages_count; i++) {
     shared_ptr<TTransport> transport(new TMemoryBuffer());
     shared_ptr<TProtocol> protocol(new TProto(transport));
 
diff --git a/lib/csharp/src/Protocol/TCompactProtocol.cs b/lib/csharp/src/Protocol/TCompactProtocol.cs
index 2c94c0c..c992e9b 100644
--- a/lib/csharp/src/Protocol/TCompactProtocol.cs
+++ b/lib/csharp/src/Protocol/TCompactProtocol.cs
@@ -41,6 +41,7 @@
         private const byte VERSION = 1;
         private const byte VERSION_MASK = 0x1f; // 0001 1111
         private const byte TYPE_MASK = 0xE0; // 1110 0000
+        private const byte TYPE_BITS = 0x07; // 0000 0111
         private const int TYPE_SHIFT_AMOUNT = 5;
 
         /**
@@ -490,7 +491,7 @@
             {
                 throw new TProtocolException("Expected version " + VERSION + " but got " + version);
             }
-            byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+            byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
             int seqid = (int)ReadVarint32();
             String messageName = ReadString();
             return new TMessage(messageName, (TMessageType)type, seqid);
diff --git a/lib/d/src/thrift/protocol/compact.d b/lib/d/src/thrift/protocol/compact.d
index e970fd1..e03b67d 100644
--- a/lib/d/src/thrift/protocol/compact.d
+++ b/lib/d/src/thrift/protocol/compact.d
@@ -259,7 +259,7 @@
         TProtocolException.Type.BAD_VERSION);
     }
 
-    msg.type = cast(TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+    msg.type = cast(TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
     msg.seqid = readVarint32();
     msg.name = readString();
 
@@ -589,6 +589,7 @@
   enum VERSION_N = 1;
   enum VERSION_MASK = 0b0001_1111;
   enum TYPE_MASK = 0b1110_0000;
+  enum TYPE_BITS = 0b0000_0111;
   enum TYPE_SHIFT_AMOUNT = 5;
 
   // Probably need to implement a better stack at some point.
diff --git a/lib/go/thrift/compact_protocol.go b/lib/go/thrift/compact_protocol.go
index c275cf4..0857a7a 100644
--- a/lib/go/thrift/compact_protocol.go
+++ b/lib/go/thrift/compact_protocol.go
@@ -31,6 +31,7 @@
 	COMPACT_VERSION           = 1
 	COMPACT_VERSION_MASK      = 0x1f
 	COMPACT_TYPE_MASK         = 0x0E0
+	COMPACT_TYPE_BITS         = 0x07
 	COMPACT_TYPE_SHIFT_AMOUNT = 5
 )
 
@@ -335,7 +336,7 @@
 	}
 	versionAndType, err := p.ReadByte()
 	version := versionAndType & COMPACT_VERSION_MASK
-	typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & 0x03)
+	typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS)
 	if err != nil {
 		return
 	}
diff --git a/lib/hs/src/Thrift/Protocol/Compact.hs b/lib/hs/src/Thrift/Protocol/Compact.hs
index c3bd22d..a329f4e 100644
--- a/lib/hs/src/Thrift/Protocol/Compact.hs
+++ b/lib/hs/src/Thrift/Protocol/Compact.hs
@@ -60,6 +60,7 @@
 version     = 0x01
 versionMask = 0x1f -- 0001 1111
 typeMask    = 0xe0 -- 1110 0000
+typeBits    = 0x07 -- 0000 0111
 typeShiftAmount :: Int
 typeShiftAmount = 5
 
@@ -81,7 +82,7 @@
       w <- fromIntegral <$> P.anyWord8
       let ver = w .&. versionMask 
       when (ver /= version) $ error "Bad Protocol version"
-      let typ = (w `shiftR` typeShiftAmount) .&. 0x03
+      let typ = (w `shiftR` typeShiftAmount) .&. typeBits
       seqId <- parseVarint zigZagToI32
       TString name <- parseCompactValue T_STRING
       return (decodeUtf8 name, toEnum $ fromIntegral $ typ, seqId)
diff --git a/lib/hs/src/Thrift/Types.hs b/lib/hs/src/Thrift/Types.hs
index b014ac6..b90c42c 100644
--- a/lib/hs/src/Thrift/Types.hs
+++ b/lib/hs/src/Thrift/Types.hs
@@ -113,17 +113,20 @@
     = M_CALL
     | M_REPLY
     | M_EXCEPTION
+    | M_ONEWAY
       deriving ( Eq, Show )
 
 instance Enum MessageType where
     fromEnum M_CALL      =  1
     fromEnum M_REPLY     =  2
     fromEnum M_EXCEPTION =  3
+    fromEnum M_ONEWAY    =  4
 
     toEnum 1 = M_CALL
     toEnum 2 = M_REPLY
     toEnum 3 = M_EXCEPTION
+    toEnum 4 = M_ONEWAY
     toEnum t = error $ "Invalid MessageType " ++ show t
 
 instance Arbitrary MessageType where
-  arbitrary = elements [M_CALL, M_REPLY, M_EXCEPTION]
+  arbitrary = elements [M_CALL, M_REPLY, M_EXCEPTION, M_ONEWAY]
diff --git a/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java b/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
index 0a653a1..5973fcd 100644
--- a/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
+++ b/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
@@ -89,6 +89,7 @@
   private static final byte VERSION = 1;
   private static final byte VERSION_MASK = 0x1f; // 0001 1111
   private static final byte TYPE_MASK = (byte)0xE0; // 1110 0000
+  private static final byte TYPE_BITS = 0x07; // 0000 0111
   private static final int  TYPE_SHIFT_AMOUNT = 5;
 
   /**
@@ -506,7 +507,7 @@
     if (version != VERSION) {
       throw new TProtocolException("Expected version " + VERSION + " but got " + version);
     }
-    byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+    byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
     int seqid = readVarint32();
     String messageName = readString();
     return new TMessage(messageName, type, seqid);
diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js
index 9bfe268..6c4d9e6 100644
--- a/lib/nodejs/lib/thrift/protocol.js
+++ b/lib/nodejs/lib/thrift/protocol.js
@@ -425,6 +425,13 @@
 TCompactProtocol.TYPE_MASK = -32;     //1110 0000
 
 /**
+  * Compact Protocol message type bits for ensuring message type bit size.
+  * @readonly
+  * @const {number} TYPE_BITS
+  */
+TCompactProtocol.TYPE_BITS = 7; //0000 0111
+
+/**
   * Compact Protocol message type shift amount for combining protocol version and message type in one byte.
   * @readonly
   * @const {number} TYPE_SHIFT_AMOUNT
@@ -837,7 +844,7 @@
   if (version != TCompactProtocol.VERSION_N) {
     throw new TProtocolException(BAD_VERSION, "Bad protocol version " + version);
   }
-  var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & 0x03);
+  var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_BITS);
 
   //Read SeqId
   var seqid = this.readVarint32();
diff --git a/lib/php/lib/Thrift/Protocol/TCompactProtocol.php b/lib/php/lib/Thrift/Protocol/TCompactProtocol.php
index 880da25..337511e 100644
--- a/lib/php/lib/Thrift/Protocol/TCompactProtocol.php
+++ b/lib/php/lib/Thrift/Protocol/TCompactProtocol.php
@@ -61,6 +61,7 @@
   const VERSION = 1;
   const PROTOCOL_ID = 0x82;
   const TYPE_MASK = 0xe0;
+  const TYPE_BITS = 0x07;
   const TYPE_SHIFT_AMOUNT = 5;
 
   protected static $ctypes = array(
@@ -381,8 +382,7 @@
     }
     $verType = 0;
     $result += $this->readUByte($verType);
-    $type = ($verType & TCompactProtocol::TYPE_MASK) >>
-      TCompactProtocol::TYPE_SHIFT_AMOUNT;
+    $type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS;
     $version = $verType & TCompactProtocol::VERSION_MASK;
     if ($version != TCompactProtocol::VERSION) {
       throw new TProtocolException('Bad version in TCompact message');
diff --git a/lib/py/src/protocol/TCompactProtocol.py b/lib/py/src/protocol/TCompactProtocol.py
index c34edb8..79deda8 100644
--- a/lib/py/src/protocol/TCompactProtocol.py
+++ b/lib/py/src/protocol/TCompactProtocol.py
@@ -120,6 +120,7 @@
   VERSION = 1
   VERSION_MASK = 0x1f
   TYPE_MASK = 0xe0
+  TYPE_BITS = 0x07
   TYPE_SHIFT_AMOUNT = 5
 
   def __init__(self, trans):
@@ -310,7 +311,7 @@
       raise TProtocolException(TProtocolException.BAD_VERSION,
           'Bad protocol id in the message: %d' % proto_id)
     ver_type = self.__readUByte()
-    type = (ver_type & self.TYPE_MASK) >> self.TYPE_SHIFT_AMOUNT
+    type = (ver_type >> self.TYPE_SHIFT_AMOUNT) & self.TYPE_BITS
     version = ver_type & self.VERSION_MASK
     if version != self.VERSION:
       raise TProtocolException(TProtocolException.BAD_VERSION,
diff --git a/lib/rb/ext/compact_protocol.c b/lib/rb/ext/compact_protocol.c
index 725d338..c0f46b9 100644
--- a/lib/rb/ext/compact_protocol.c
+++ b/lib/rb/ext/compact_protocol.c
@@ -40,6 +40,7 @@
 static int VERSION;
 static int VERSION_MASK;
 static int TYPE_MASK;
+static int TYPE_BITS;
 static int TYPE_SHIFT_AMOUNT;
 static int PROTOCOL_ID;
 
@@ -450,7 +451,7 @@
     rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf)));
   }
   
-  int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03;
+  int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS;
   int32_t seqid = read_varint64(self);
   VALUE messageName = rb_thrift_compact_proto_read_string(self);
   return rb_ary_new3(3, messageName, INT2FIX(type), INT2NUM(seqid));
@@ -570,6 +571,7 @@
   VERSION = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION")));
   VERSION_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION_MASK")));
   TYPE_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_MASK")));
+  TYPE_BITS = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_BITS")));
   TYPE_SHIFT_AMOUNT = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_SHIFT_AMOUNT")));
   PROTOCOL_ID = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("PROTOCOL_ID")));
 
diff --git a/lib/rb/lib/thrift/protocol/compact_protocol.rb b/lib/rb/lib/thrift/protocol/compact_protocol.rb
index 07a6792..605eea6 100644
--- a/lib/rb/lib/thrift/protocol/compact_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/compact_protocol.rb
@@ -24,6 +24,7 @@
     VERSION = 1
     VERSION_MASK = 0x1f
     TYPE_MASK = 0xE0
+    TYPE_BITS = 0x07
     TYPE_SHIFT_AMOUNT = 5
 
     TSTOP = ["", Types::STOP, 0]
@@ -231,7 +232,7 @@
         raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
       end
       
-      type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03
+      type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS
       seqid = read_varint32()
       messageName = read_string()
       [messageName, type, seqid]