X-Git-Url: http://xvm.mit.edu/gitweb/invirt/third/libt4.git/blobdiff_plain/eeab3e6cade87c1fe0a5f3d93522e12ccb9ec2ab..46fb2b4bbe3a0a8516ab04cfafa895a882c70f86:/rpc/marshall.h diff --git a/rpc/marshall.h b/rpc/marshall.h index 7a85d6b..98856e4 100644 --- a/rpc/marshall.h +++ b/rpc/marshall.h @@ -1,48 +1,58 @@ #ifndef marshall_h #define marshall_h -#include -#include -#include -#include -#include -#include -#include +#include "types.h" +#include #include -#include -#include "lang/verify.h" +#include + +using proc_t = uint32_t; +using status_t = int32_t; struct request_header { - request_header(int x=0, int p=0, int c=0, int s=0, int xi=0) : + request_header(int x=0, proc_t p=0, unsigned c=0, unsigned s=0, int xi=0) : xid(x), proc(p), clt_nonce(c), srv_nonce(s), xid_rep(xi) {} int xid; - int proc; + proc_t proc; unsigned int clt_nonce; unsigned int srv_nonce; int xid_rep; - request_header hton() const { - return { - htonl(xid), htonl(proc), htonl(clt_nonce), htonl(srv_nonce), htonl(xid_rep) - }; - } }; struct reply_header { reply_header(int x=0, int r=0): xid(x), ret(r) {} int xid; int ret; - reply_header hton() const { - return { - htonl(xid), htonl(ret) - }; - } }; +template inline T hton(T t); + +constexpr union { uint32_t i; uint8_t is_little_endian; } endianness{1}; + +template<> inline uint8_t hton(uint8_t t) { return t; } +template<> inline int8_t hton(int8_t t) { return t; } +template<> inline uint16_t hton(uint16_t t) { return htons(t); } +template<> inline int16_t hton(int16_t t) { return (int16_t)htons((uint16_t)t); } +template<> inline uint32_t hton(uint32_t t) { return htonl(t); } +template<> inline int32_t hton(int32_t t) { return (int32_t)htonl((uint32_t)t); } +template<> inline uint64_t hton(uint64_t t) { + if (!endianness.is_little_endian) + return t; + return (uint64_t)htonl((uint32_t)(t >> 32)) | ((uint64_t)htonl((uint32_t)t) << 32); +} +template<> inline int64_t hton(int64_t t) { return (int64_t)hton((uint64_t)t); } +template<> inline request_header hton(request_header h) { return {hton(h.xid), hton(h.proc), hton(h.clt_nonce), hton(h.srv_nonce), hton(h.xid_rep)}; } +template<> inline reply_header hton(reply_header h) { return {hton(h.xid), hton(h.ret)}; } + +template inline T ntoh(T t) { return hton(t); } + typedef int rpc_sz_t; //size of initial buffer allocation #define DEFAULT_RPC_SZ 1024 -#define RPC_HEADER_SZ (std::max(sizeof(request_header), sizeof(reply_header)) + sizeof(rpc_sz_t)) +#define RPC_HEADER_SZ (max(sizeof(request_header), sizeof(reply_header)) + sizeof(rpc_sz_t)) + +struct pass { template inline pass(Args&&...) {} }; class marshall { private: @@ -52,17 +62,14 @@ class marshall { inline void reserve(size_t n) { if((index_+n) > capacity_){ - capacity_ += std::max(capacity_, n); + capacity_ += max(capacity_, n); VERIFY (buf_ != NULL); buf_ = (char *)realloc(buf_, capacity_); VERIFY(buf_); } } public: - struct pass { template inline pass(Args&&...) {} }; - template - marshall(const Args&... args) { buf_ = (char *) malloc(sizeof(char)*DEFAULT_RPC_SZ); VERIFY(buf_); @@ -76,35 +83,35 @@ class marshall { free(buf_); } - int size() { return index_;} + size_t size() { return index_;} char *cstr() { return buf_;} const char *cstr() const { return buf_;} - void rawbyte(unsigned char x) { + void rawbyte(uint8_t x) { reserve(1); - buf_[index_++] = x; + buf_[index_++] = (int8_t)x; } - void rawbytes(const char *p, int n) { + void rawbytes(const char *p, size_t n) { reserve(n); memcpy(buf_+index_, p, n); index_ += n; } // Return the current content (excluding header) as a string - std::string get_content() { - return std::string(buf_+RPC_HEADER_SZ,index_-RPC_HEADER_SZ); + string get_content() { + return string(buf_+RPC_HEADER_SZ,index_-RPC_HEADER_SZ); } // Return the current content (excluding header) as a string - std::string str() { + string str() { return get_content(); } void pack_req_header(const request_header &h); void pack_reply_header(const reply_header &h); - void take_buf(char **b, int *s) { + void take_buf(char **b, size_t *s) { *b = buf_; *s = index_; buf_ = NULL; @@ -114,16 +121,16 @@ class marshall { }; marshall& operator<<(marshall &, bool); -marshall& operator<<(marshall &, unsigned int); -marshall& operator<<(marshall &, int); -marshall& operator<<(marshall &, unsigned char); -marshall& operator<<(marshall &, char); -marshall& operator<<(marshall &, unsigned short); -marshall& operator<<(marshall &, short); -marshall& operator<<(marshall &, unsigned long long); -marshall& operator<<(marshall &, const std::string &); - -template marshall & +marshall& operator<<(marshall &, uint32_t); +marshall& operator<<(marshall &, int32_t); +marshall& operator<<(marshall &, uint8_t); +marshall& operator<<(marshall &, int8_t); +marshall& operator<<(marshall &, uint16_t); +marshall& operator<<(marshall &, int16_t); +marshall& operator<<(marshall &, uint64_t); +marshall& operator<<(marshall &, const string &); + +template typename enable_if::value, marshall>::type & operator<<(marshall &m, const A &x) { m << (unsigned int) x.size(); for (const auto &a : x) @@ -132,24 +139,48 @@ operator<<(marshall &m, const A &x) { } template marshall & -operator<<(marshall &m, const std::pair &d) { - m << d.first; - m << d.second; - return m; +operator<<(marshall &m, const pair &d) { + return m << d.first << d.second; +} + +template +using enum_type_t = typename enable_if::value, typename underlying_type::type>::type; +template constexpr inline enum_type_t from_enum(E e) noexcept { return (enum_type_t)e; } +template constexpr inline E to_enum(enum_type_t value) noexcept { return (E)value; } + +template typename enable_if::value, marshall>::type & +operator<<(marshall &m, E e) { + return m << from_enum(e); } +class unmarshall; + +unmarshall& operator>>(unmarshall &, bool &); +unmarshall& operator>>(unmarshall &, uint8_t &); +unmarshall& operator>>(unmarshall &, int8_t &); +unmarshall& operator>>(unmarshall &, uint16_t &); +unmarshall& operator>>(unmarshall &, int16_t &); +unmarshall& operator>>(unmarshall &, uint32_t &); +unmarshall& operator>>(unmarshall &, int32_t &); +unmarshall& operator>>(unmarshall &, size_t &); +unmarshall& operator>>(unmarshall &, uint64_t &); +unmarshall& operator>>(unmarshall &, int64_t &); +unmarshall& operator>>(unmarshall &, string &); +template typename enable_if::value, unmarshall>::type & +operator>>(unmarshall &u, E &e); + class unmarshall { private: char *buf_; - int sz_; - int index_; + size_t sz_; + size_t index_; bool ok_; inline bool ensure(size_t n); public: unmarshall(): buf_(NULL),sz_(0),index_(0),ok_(false) {} - unmarshall(char *b, int sz): buf_(b),sz_(sz),index_(),ok_(true) {} - unmarshall(const std::string &s) : buf_(NULL),sz_(0),index_(0),ok_(false) + unmarshall(char *b, size_t sz): buf_(b),sz_(sz),index_(),ok_(true) {} + unmarshall(const string &s) : buf_(NULL),sz_(0),index_(0),ok_(false) { //take the content which does not exclude a RPC header from a string take_content(s); @@ -162,7 +193,7 @@ class unmarshall { void take_in(unmarshall &another); //take the content which does not exclude a RPC header from a string - void take_content(const std::string &s) { + void take_content(const string &s) { sz_ = s.size()+RPC_HEADER_SZ; buf_ = (char *)realloc(buf_,sz_); VERIFY(buf_); @@ -175,13 +206,13 @@ class unmarshall { char *cstr() { return buf_;} bool okdone() const { return ok_ && index_ == sz_; } - unsigned int rawbyte(); - void rawbytes(std::string &s, size_t n); + uint8_t rawbyte(); + void rawbytes(string &s, size_t n); + template void rawbytes(T &t); - int ind() { return index_;} - int size() { return sz_;} - void unpack(int *); //non-const ref - void take_buf(char **b, int *sz) { + size_t ind() { return index_;} + size_t size() { return sz_;} + void take_buf(char **b, size_t *sz) { *b = buf_; *sz = sz_; sz_ = index_ = 0; @@ -191,19 +222,14 @@ class unmarshall { void unpack_req_header(request_header *h) { //the first 4-byte is for channel to fill size of pdu index_ = sizeof(rpc_sz_t); - unpack(&h->xid); - unpack(&h->proc); - unpack((int *)&h->clt_nonce); - unpack((int *)&h->srv_nonce); - unpack(&h->xid_rep); + *this >> h->xid >> h->proc >> h->clt_nonce >> h->srv_nonce >> h->xid_rep; index_ = RPC_HEADER_SZ; } void unpack_reply_header(reply_header *h) { //the first 4-byte is for channel to fill size of pdu index_ = sizeof(rpc_sz_t); - unpack(&h->xid); - unpack(&h->ret); + *this >> h->xid >> h->ret; index_ = RPC_HEADER_SZ; } @@ -215,7 +241,8 @@ class unmarshall { } }; -template unmarshall & operator>>(unmarshall &u, A &x) { +template typename enable_if::value, unmarshall>::type & +operator>>(unmarshall &u, A &x) { unsigned n = u.grab(); x.clear(); while (n--) @@ -224,20 +251,26 @@ template unmarshall & operator>>(unmarshall &u, A &x) { } template unmarshall & -operator>>(unmarshall &u, std::map &x) { +operator>>(unmarshall &u, map &x) { unsigned n = u.grab(); x.clear(); while (n--) - x.emplace(u.grab>()); + x.emplace(u.grab>()); return u; } template unmarshall & -operator>>(unmarshall &u, std::pair &d) { +operator>>(unmarshall &u, pair &d) { return u >> d.first >> d.second; } -typedef std::function handler; +template typename enable_if::value, unmarshall>::type & +operator>>(unmarshall &u, E &e) { + e = to_enum(u.grab>()); + return u; +} + +typedef function handler; // // Automatic marshalling wrappers for RPC handlers @@ -247,7 +280,7 @@ typedef std::function handler; // C++11 does neither of these two things for us: // 1) Declare variables using a parameter pack expansion, like so // Args ...args; -// 2) Call a function with a std::tuple of the arguments it expects +// 2) Call a function with a tuple of the arguments it expects // // We implement an 'invoke' function for functions of the RPC handler // signature, i.e. int(R & r, const Args...) @@ -291,18 +324,18 @@ struct VerifyOnFailure { // One for function pointers... -template -typename std::enable_if::value, int>::type -invoke(F f, void *, R & r, args_type & t, tuple_indices) { - return f(r, std::move(std::get(t))...); +template +typename enable_if::value, RV>::type +invoke(RV, F f, void *, R & r, args_type & t, tuple_indices) { + return f(r, move(get(t))...); } // And one for pointers to member functions... -template -typename std::enable_if::value, int>::type -invoke(F f, C *c, R & r, args_type & t, tuple_indices) { - return (c->*f)(r, std::move(std::get(t))...); +template +typename enable_if::value, RV>::type +invoke(RV, F f, C *c, R & r, args_type & t, tuple_indices) { + return (c->*f)(r, move(get(t))...); } // The class marshalled_func_imp uses partial template specialization to @@ -319,32 +352,32 @@ template -struct marshalled_func_imp { +template +struct marshalled_func_imp { static inline handler *wrap(F f, C *c=nullptr) { // This type definition corresponds to an empty struct with // template parameters running from 0 up to (# args) - 1. using Indices = typename make_tuple_indices::type; // This type definition represents storage for f's unmarshalled - // arguments. std::decay is (most notably) stripping off const + // arguments. decay is (most notably) stripping off const // qualifiers. - using ArgsStorage = std::tuple::type...>; - // Allocate a handler (i.e. std::function) to hold the lambda + using ArgsStorage = tuple::type...>; + // Allocate a handler (i.e. function) to hold the lambda // which will unmarshall RPCs and call f. - return new handler([=](unmarshall &u, marshall &m) -> int { + return new handler([=](unmarshall &u, marshall &m) -> RV { // Unmarshall each argument with the correct type and store the // result in a tuple. - ArgsStorage t = {u.grab::type>()...}; + ArgsStorage t = {u.grab::type>()...}; // Verify successful unmarshalling of the entire input stream. if (!u.okdone()) - return ErrorHandler::unmarshall_args_failure(); + return (RV)ErrorHandler::unmarshall_args_failure(); // Allocate space for the RPC response -- will be passed into the // function as an lvalue reference. R r; // Perform the invocation. Note that Indices() calls the default // constructor of the empty struct with the special template // parameters. - int b = invoke(f, c, r, t, Indices()); + RV b = invoke(RV(), f, c, r, t, Indices()); // Marshall the response. m << r; // Make like a tree. @@ -361,16 +394,45 @@ struct marshalled_func_imp { template struct marshalled_func; -template -struct marshalled_func : - public marshalled_func_imp {}; +template +struct marshalled_func : + public marshalled_func_imp {}; -template -struct marshalled_func : - public marshalled_func_imp {}; +template +struct marshalled_func : + public marshalled_func_imp {}; template -struct marshalled_func> : +struct marshalled_func> : public marshalled_func_imp {}; +template unmarshall & +tuple_unmarshall_imp(unmarshall & u, tuple t, tuple_indices) { + (void)pass{(u >> get(t))...}; + return u; +} + +template unmarshall & +operator>>(unmarshall & u, tuple && t) { + using Indices = typename make_tuple_indices::type; + return tuple_unmarshall_imp(u, t, Indices()); +} + +template marshall & +tuple_marshall_imp(marshall & m, tuple & t, tuple_indices) { + (void)pass{(m << get(t))...}; + return m; +} + +template marshall & +operator<<(marshall & m, tuple && t) { + using Indices = typename make_tuple_indices::type; + return tuple_marshall_imp(m, t, Indices()); +} + +// for structs or classes containing a MEMBERS declaration +#define MARSHALLABLE(_c_) \ +inline unmarshall & operator>>(unmarshall &u, _c_ &a) { return u >> a._tuple_(); } \ +inline marshall & operator<<(marshall &m, _c_ a) { return m << a._tuple_(); } + #endif