From d32139351433124aed5a3b98786f55828f4e1531 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 10 Jan 2012 14:00:31 -0800 Subject: [PATCH] encoding: new {ENCODE,DECODE}_{START,FINISH} macros 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 --- src/include/encoding.h | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/include/encoding.h b/src/include/encoding.h index cb968cba29db7..6d0741b0d675f 100644 --- a/src/include/encoding.h +++ b/src/include/encoding.h @@ -637,4 +637,62 @@ inline void decode(std::deque& 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 -- 2.39.5