676a68239b64b71a8a4d3f6e96bd723fc37ea563
[invirt/third/libt4.git] / rpc / marshall.h
1 #ifndef marshall_h
2 #define marshall_h
3
4 #include <iostream>
5 #include <sstream>
6 #include <string>
7 #include <vector>
8 #include <map>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <cstddef>
12 #include <inttypes.h>
13 #include "lang/verify.h"
14
15 struct request_header {
16     request_header(int x=0, int p=0, unsigned c=0, unsigned s=0, int xi=0) :
17         xid(x), proc(p), clt_nonce(c), srv_nonce(s), xid_rep(xi) {}
18     int xid;
19     int proc;
20     unsigned int clt_nonce;
21     unsigned int srv_nonce;
22     int xid_rep;
23 };
24
25 struct reply_header {
26     reply_header(int x=0, int r=0): xid(x), ret(r) {}
27     int xid;
28     int ret;
29 };
30
31 template<class T> inline T hton(T t);
32
33 constexpr union { uint32_t i; uint8_t is_little_endian; } endianness{1};
34
35 template<> inline uint8_t hton(uint8_t t) { return t; }
36 template<> inline int8_t hton(int8_t t) { return t; }
37 template<> inline uint16_t hton(uint16_t t) { return htons(t); }
38 template<> inline int16_t hton(int16_t t) { return (int16_t)htons((uint16_t)t); }
39 template<> inline uint32_t hton(uint32_t t) { return htonl(t); }
40 template<> inline int32_t hton(int32_t t) { return (int32_t)htonl((uint32_t)t); }
41 template<> inline uint64_t hton(uint64_t t) {
42     if (!endianness.is_little_endian)
43         return t;
44     return (uint64_t)htonl((uint32_t)(t >> 32)) | ((uint64_t)htonl((uint32_t)t) << 32);
45 }
46 template<> inline int64_t hton(int64_t t) { return (int64_t)hton((uint64_t)t); }
47 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)}; }
48 template<> inline reply_header hton(reply_header h) { return {hton(h.xid), hton(h.ret)}; }
49
50 template <class T> inline T ntoh(T t) { return hton(t); }
51
52 typedef int rpc_sz_t;
53
54 //size of initial buffer allocation
55 #define DEFAULT_RPC_SZ 1024
56 #define RPC_HEADER_SZ (std::max(sizeof(request_header), sizeof(reply_header)) + sizeof(rpc_sz_t))
57
58 class marshall {
59     private:
60         char *buf_;     // Base of the raw bytes buffer (dynamically readjusted)
61         size_t capacity_;  // Capacity of the buffer
62         size_t index_;     // Read/write head position
63
64         inline void reserve(size_t n) {
65             if((index_+n) > capacity_){
66                 capacity_ += std::max(capacity_, n);
67                 VERIFY (buf_ != NULL);
68                 buf_ = (char *)realloc(buf_, capacity_);
69                 VERIFY(buf_);
70             }
71         }
72     public:
73         struct pass { template <typename... Args> inline pass(Args&&...) {} };
74
75         template <typename... Args>
76
77         marshall(const Args&... args) {
78             buf_ = (char *) malloc(sizeof(char)*DEFAULT_RPC_SZ);
79             VERIFY(buf_);
80             capacity_ = DEFAULT_RPC_SZ;
81             index_ = RPC_HEADER_SZ;
82             (void)pass{(*this << args)...};
83         }
84
85         ~marshall() {
86             if (buf_)
87                 free(buf_);
88         }
89
90         size_t size() { return index_;}
91         char *cstr() { return buf_;}
92         const char *cstr() const { return buf_;}
93
94         void rawbyte(uint8_t x) {
95             reserve(1);
96             buf_[index_++] = (int8_t)x;
97         }
98
99         void rawbytes(const char *p, size_t n) {
100             reserve(n);
101             memcpy(buf_+index_, p, n);
102             index_ += n;
103         }
104
105         // Return the current content (excluding header) as a string
106         std::string get_content() {
107             return std::string(buf_+RPC_HEADER_SZ,index_-RPC_HEADER_SZ);
108         }
109
110         // Return the current content (excluding header) as a string
111         std::string str() {
112             return get_content();
113         }
114
115         void pack_req_header(const request_header &h);
116         void pack_reply_header(const reply_header &h);
117
118         void take_buf(char **b, size_t *s) {
119             *b = buf_;
120             *s = index_;
121             buf_ = NULL;
122             index_ = 0;
123             return;
124         }
125 };
126
127 marshall& operator<<(marshall &, bool);
128 marshall& operator<<(marshall &, uint32_t);
129 marshall& operator<<(marshall &, int32_t);
130 marshall& operator<<(marshall &, uint8_t);
131 marshall& operator<<(marshall &, int8_t);
132 marshall& operator<<(marshall &, uint16_t);
133 marshall& operator<<(marshall &, int16_t);
134 marshall& operator<<(marshall &, uint64_t);
135 marshall& operator<<(marshall &, const std::string &);
136
137 template <class A> marshall &
138 operator<<(marshall &m, const A &x) {
139     m << (unsigned int) x.size();
140     for (const auto &a : x)
141         m << a;
142     return m;
143 }
144
145 template <class A, class B> marshall &
146 operator<<(marshall &m, const std::pair<A,B> &d) {
147     m << d.first;
148     m << d.second;
149     return m;
150 }
151
152 class unmarshall;
153
154 unmarshall& operator>>(unmarshall &, bool &);
155 unmarshall& operator>>(unmarshall &, uint8_t &);
156 unmarshall& operator>>(unmarshall &, int8_t &);
157 unmarshall& operator>>(unmarshall &, uint16_t &);
158 unmarshall& operator>>(unmarshall &, int16_t &);
159 unmarshall& operator>>(unmarshall &, uint32_t &);
160 unmarshall& operator>>(unmarshall &, int32_t &);
161 unmarshall& operator>>(unmarshall &, size_t &);
162 unmarshall& operator>>(unmarshall &, uint64_t &);
163 unmarshall& operator>>(unmarshall &, int64_t &);
164 unmarshall& operator>>(unmarshall &, std::string &);
165
166 class unmarshall {
167     private:
168         char *buf_;
169         size_t sz_;
170         size_t index_;
171         bool ok_;
172
173         inline bool ensure(size_t n);
174     public:
175         unmarshall(): buf_(NULL),sz_(0),index_(0),ok_(false) {}
176         unmarshall(char *b, size_t sz): buf_(b),sz_(sz),index_(),ok_(true) {}
177         unmarshall(const std::string &s) : buf_(NULL),sz_(0),index_(0),ok_(false)
178         {
179             //take the content which does not exclude a RPC header from a string
180             take_content(s);
181         }
182         ~unmarshall() {
183             if (buf_) free(buf_);
184         }
185
186         //take contents from another unmarshall object
187         void take_in(unmarshall &another);
188
189         //take the content which does not exclude a RPC header from a string
190         void take_content(const std::string &s) {
191             sz_ = s.size()+RPC_HEADER_SZ;
192             buf_ = (char *)realloc(buf_,sz_);
193             VERIFY(buf_);
194             index_ = RPC_HEADER_SZ;
195             memcpy(buf_+index_, s.data(), s.size());
196             ok_ = true;
197         }
198
199         bool ok() const { return ok_; }
200         char *cstr() { return buf_;}
201         bool okdone() const { return ok_ && index_ == sz_; }
202
203         uint8_t rawbyte();
204         void rawbytes(std::string &s, size_t n);
205         template <class T> void rawbytes(T &t);
206
207         size_t ind() { return index_;}
208         size_t size() { return sz_;}
209         void take_buf(char **b, size_t *sz) {
210             *b = buf_;
211             *sz = sz_;
212             sz_ = index_ = 0;
213             buf_ = NULL;
214         }
215
216         void unpack_req_header(request_header *h) {
217             //the first 4-byte is for channel to fill size of pdu
218             index_ = sizeof(rpc_sz_t);
219             *this >> h->xid >> h->proc >> h->clt_nonce >> h->srv_nonce >> h->xid_rep;
220             index_ = RPC_HEADER_SZ;
221         }
222
223         void unpack_reply_header(reply_header *h) {
224             //the first 4-byte is for channel to fill size of pdu
225             index_ = sizeof(rpc_sz_t);
226             *this >> h->xid >> h->ret;
227             index_ = RPC_HEADER_SZ;
228         }
229
230         template <class A>
231         inline A grab() {
232             A a;
233             *this >> a;
234             return a;
235         }
236 };
237
238 template <class A> unmarshall & operator>>(unmarshall &u, A &x) {
239     unsigned n = u.grab<unsigned>();
240     x.clear();
241     while (n--)
242         x.emplace_back(u.grab<typename A::value_type>());
243     return u;
244 }
245
246 template <class A, class B> unmarshall &
247 operator>>(unmarshall &u, std::map<A,B> &x) {
248     unsigned n = u.grab<unsigned>();
249     x.clear();
250     while (n--)
251         x.emplace(u.grab<std::pair<A,B>>());
252     return u;
253 }
254
255 template <class A, class B> unmarshall &
256 operator>>(unmarshall &u, std::pair<A,B> &d) {
257     return u >> d.first >> d.second;
258 }
259
260 typedef std::function<int(unmarshall &, marshall &)> handler;
261
262 //
263 // Automatic marshalling wrappers for RPC handlers
264 //
265
266 // PAI 2013/09/19
267 // C++11 does neither of these two things for us:
268 // 1) Declare variables using a parameter pack expansion, like so
269 //      Args ...args;
270 // 2) Call a function with a std::tuple of the arguments it expects
271 //
272 // We implement an 'invoke' function for functions of the RPC handler
273 // signature, i.e. int(R & r, const Args...)
274 //
275 // One thing we need in order to accomplish this is a way to cause the compiler
276 // to specialize 'invoke' with a parameter pack containing a list of indices
277 // for the elements of the tuple.  This will allow us to call the underlying
278 // function with the exploded contents of the tuple.  The empty type
279 // tuple_indices<size_t...> accomplishes this.  It will be passed in to
280 // 'invoke' as a parameter which will be ignored, but its type will force the
281 // compiler to specialize 'invoke' appropriately.
282
283 // The following implementation of tuple_indices is redistributed under the MIT
284 // License as an insubstantial portion of the LLVM compiler infrastructure.
285
286 template <size_t...> struct tuple_indices {};
287 template <size_t S, class IntTuple, size_t E> struct make_indices_imp;
288 template <size_t S, size_t ...Indices, size_t E> struct make_indices_imp<S, tuple_indices<Indices...>, E> {
289     typedef typename make_indices_imp<S+1, tuple_indices<Indices..., S>, E>::type type;
290 };
291 template <size_t E, size_t ...Indices> struct make_indices_imp<E, tuple_indices<Indices...>, E> {
292     typedef tuple_indices<Indices...> type;
293 };
294 template <size_t E, size_t S=0> struct make_tuple_indices {
295     typedef typename make_indices_imp<S, tuple_indices<>, E>::type type;
296 };
297
298 // This class encapsulates the default response to runtime unmarshalling
299 // failures.  The templated wrappers below may optionally use a different
300 // class.
301
302 struct VerifyOnFailure {
303     static inline int unmarshall_args_failure() {
304         VERIFY(0);
305         return 0;
306     }
307 };
308
309 // Here's the implementation of 'invoke'.  It could be more general, but this
310 // meets our needs.
311
312 // One for function pointers...
313
314 template <class F, class R, class args_type, size_t ...Indices>
315 typename std::enable_if<!std::is_member_function_pointer<F>::value, int>::type
316 invoke(F f, void *, R & r, args_type & t, tuple_indices<Indices...>) {
317     return f(r, std::move(std::get<Indices>(t))...);
318 }
319
320 // And one for pointers to member functions...
321
322 template <class F, class C, class R, class args_type, size_t ...Indices>
323 typename std::enable_if<std::is_member_function_pointer<F>::value, int>::type
324 invoke(F f, C *c, R & r, args_type & t, tuple_indices<Indices...>) {
325     return (c->*f)(r, std::move(std::get<Indices>(t))...);
326 }
327
328 // The class marshalled_func_imp uses partial template specialization to
329 // implement the ::wrap static function.  ::wrap takes a function pointer or a
330 // pointer to a member function and returns a handler * object which
331 // unmarshalls arguments, verifies successful unmarshalling, calls the supplied
332 // function, and marshalls the response.
333
334 template <class Functor, class Instance, class Signature,
335           class ErrorHandler=VerifyOnFailure> struct marshalled_func_imp;
336
337 // Here we specialize on the Signature template parameter to obtain the list of
338 // argument types.  Note that we do not assume that the Functor parameter has
339 // the same pattern as Signature; this allows us to ignore the distinctions
340 // between various types of callable objects at this level of abstraction.
341
342 template <class F, class C, class ErrorHandler, class R, class... Args>
343 struct marshalled_func_imp<F, C, int(R&, Args...), ErrorHandler> {
344     static inline handler *wrap(F f, C *c=nullptr) {
345         // This type definition corresponds to an empty struct with
346         // template parameters running from 0 up to (# args) - 1.
347         using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
348         // This type definition represents storage for f's unmarshalled
349         // arguments.  std::decay is (most notably) stripping off const
350         // qualifiers.
351         using ArgsStorage = std::tuple<typename std::decay<Args>::type...>;
352         // Allocate a handler (i.e. std::function) to hold the lambda
353         // which will unmarshall RPCs and call f.
354         return new handler([=](unmarshall &u, marshall &m) -> int {
355             // Unmarshall each argument with the correct type and store the
356             // result in a tuple.
357             ArgsStorage t = {u.grab<typename std::decay<Args>::type>()...};
358             // Verify successful unmarshalling of the entire input stream.
359             if (!u.okdone())
360                 return ErrorHandler::unmarshall_args_failure();
361             // Allocate space for the RPC response -- will be passed into the
362             // function as an lvalue reference.
363             R r;
364             // Perform the invocation.  Note that Indices() calls the default
365             // constructor of the empty struct with the special template
366             // parameters.
367             int b = invoke(f, c, r, t, Indices());
368             // Marshall the response.
369             m << r;
370             // Make like a tree.
371             return b;
372         });
373     }
374 };
375
376 // More partial template specialization shenanigans to reduce the number of
377 // parameters which must be provided explicitly and to support a few common
378 // callable types.  C++11 doesn't allow partial function template
379 // specialization, so we use classes (structs).
380
381 template <class Functor, class ErrorHandler=VerifyOnFailure,
382     class Signature=Functor> struct marshalled_func;
383
384 template <class F, class ErrorHandler, class... Args>
385 struct marshalled_func<F, ErrorHandler, int(*)(Args...)> :
386     public marshalled_func_imp<F, void, int(Args...), ErrorHandler> {};
387
388 template <class F, class ErrorHandler, class C, class... Args>
389 struct marshalled_func<F, ErrorHandler, int(C::*)(Args...)> :
390     public marshalled_func_imp<F, C, int(Args...), ErrorHandler> {};
391
392 template <class F, class ErrorHandler, class Signature>
393 struct marshalled_func<F, ErrorHandler, std::function<Signature>> :
394     public marshalled_func_imp<F, void, Signature, ErrorHandler> {};
395
396 #endif