]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
encoding: new {ENCODE,DECODE}_{START,FINISH} macros
authorSage Weil <sage.weil@dreamhost.com>
Tue, 10 Jan 2012 22:00:31 +0000 (14:00 -0800)
committerSage Weil <sage.weil@dreamhost.com>
Mon, 23 Jan 2012 04:36:16 +0000 (20:36 -0800)
New macros to bracket encode/decode methods.  The encoding scheme:

 1 byte - version
 1 byte - incompat version
 4 bytes - length
 ... data ...

On decode, we verify that our known version is not < incompat version.
Otherwise, we throw an assertion, because the new code has decide that we
are too old to understand.  We also throw an assert if we overrun/decode
past the end (as determined by the length).  If we don't reach the end, we
skip whatever extra data is there.

An additional DECODE_START_LEGACY() macro is defined that takes an
additional lencompat argument.  If the decoded version is < than this
value, we do not decode the length.  This lets us transition away from
old encodings that do not include a length.

The value struct_v is defined for the "body" of the decode (between
_START and _FINISH).

The _START and _FINISH macros open a do { } while (false) block, so break
can be used to jump to _FINISH.

Signed-off-by: Sage Weil <sage.weil@dreamhost.com>
src/include/encoding.h

index cb968cba29db7c78587dc12a85aa197fa88a52a1..6d0741b0d675f9c052a641d9d9226fd1832b0e4f 100644 (file)
@@ -637,4 +637,62 @@ inline void decode(std::deque<T>& ls, bufferlist::iterator& p)
 }
 
 
+/*
+ * guards
+ */
+
+#define ENCODE_START(compat, incompat, bl)                  \
+  __u8 struct_v = compat, struct_incompat = incompat;   \
+  ::encode(struct_v, bl);                                   \
+  ::encode(struct_incompat, bl);                            \
+  __le32 struct_len = 0;                                    \
+  unsigned struct_len_pos = bl.length();                    \
+  ::encode(struct_len, bl);                                 \
+  do {
+
+#define ENCODE_FINISH()                                \
+  } while (false);                             \
+  struct_len = bl.length() - struct_len_pos;   \
+  bl.copy_in(struct_len_pos, 4, (char *)&struct_len);
+
+#define DECODE_ERR_VERSION(func, compat)                       \
+  "" #func " unknown encoding version > " #compat
+
+#define DECODE_ERR_PAST(func) \
+  "" #func " decode past end of struct encoding"
+
+#define DECODE_START(compat, bl)                                       \
+  __u8 struct_v = compat, struct_incompat = incompat;          \
+  ::decode(struct_v, bl);                                              \
+  ::decode(struct_incompat, bl);                                       \
+  if (compat < struct_incompat)                                                \
+    throw buffer::malformed_input(DECODE_ERR_VERSION(__PRETTY_FUNCTION__, compat)); \
+  __u32 struct_len;                                                    \
+  ::decode(struct_len, bl);                                            \
+  unsigned struct_end = bl.get_off() + struct_len;                     \
+  do {
+
+#define DECODE_START_LEGACY(compat, bl, lencompat)     \
+  __u8 struct_v, struct_incompat;                                      \
+  ::decode(struct_v, bl);                                              \
+  unsigned struct_end = 0;                                             \
+  if (struct_v >= lencompat) {                                         \
+    ::decode(struct_incompat, bl);                                     \
+    if (compat < struct_incompat)                                      \
+      throw buffer::malformed_input(DECODE_ERR_VERSION(__PRETTY_FUNCTION__, compat)); \
+    __u32 struct_len;                                                  \
+    ::decode(struct_len, bl);                                          \
+    struct_end = bl.get_off() + struct_len;                            \
+  }                                                                    \
+  do {
+
+#define DECODE_FINISH()                                                        \
+  } while (false);                                                     \
+  if (struct_end) {                                                    \
+    if (bl.get_off() > struct_end)                                     \
+      throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
+    if (bl.get_off() < struct_end)                                     \
+      bl.advance(struct_end - bl.get_off());                           \
+  }
+
 #endif