Simplifications and clean-ups
[invirt/third/libt4.git] / rsm_client.h
1 #ifndef rsm_client_h
2 #define rsm_client_h
3
4 #include "types.h"
5 #include "rsm_protocol.h"
6
7 //
8 // rsm client interface.
9 //
10 // The client stubs package up an rpc, and then call the invoke procedure
11 // on the replicated state machine passing the RPC as an argument.  This way
12 // the replicated state machine isn't service specific; any server can use it.
13 //
14
15 class rsm_client {
16     protected:
17         string primary;
18         vector<string> known_mems;
19         mutex rsm_client_mutex;
20         void primary_failure(lock & rsm_client_mutex_lock);
21         bool init_members(lock & rsm_client_mutex_lock);
22         rsm_protocol::status invoke(unsigned int proc, string & rep, const string & req);
23         template<class R> int call_m(unsigned int proc, R & r, const marshall & req);
24     public:
25         rsm_client(string dst);
26
27         template<class P, class R, class ...Args>
28         inline int call(rpc_protocol::proc_t<P> proc, R & r, const Args & ...a1) {
29             static_assert(is_valid_call<P, R, Args...>::value, "RSM method invoked with incorrect argument types");
30             return call_m(proc.id, r, marshall(a1...));
31         }
32 };
33
34 inline string hexify(const string & s) {
35     string bytes;
36     for (char ch : s) {
37         bytes.push_back("0123456789abcdef"[(uint8_t)ch >> 4]);
38         bytes.push_back("0123456789abcdef"[(uint8_t)ch & 15]);
39     }
40     return bytes;
41 }
42
43 template<class R>
44 int rsm_client::call_m(unsigned int proc, R & r, const marshall & req) {
45     string rep;
46     int intret = invoke(proc, rep, req.content());
47     VERIFY( intret == rsm_client_protocol::OK );
48     unmarshall u(rep, false, intret);
49     if (intret < 0) return intret;
50     string res;
51     u >> res;
52     if (!u.okdone()) {
53         LOG << "failed to unmarshall the reply.";
54         LOG << "You probably forgot to set the reply string in "
55             << "rsm::client_invoke, or you may have called RPC "
56             << "0x" << std::hex << proc << " with the wrong return type";
57         LOG << "here's what I got: \"" << hexify(rep) << "\"";
58         VERIFY(0);
59         return rpc_protocol::unmarshall_reply_failure;
60     }
61     if(!unmarshall(res, false, r).okdone()) {
62         LOG << "failed to unmarshall the reply.";
63         LOG << "You are probably calling RPC 0x" << std::hex << proc
64             << " with the wrong return type.";
65         LOG << "here's what I got: \"" << hexify(res) << "\"";
66         VERIFY(0);
67         return rpc_protocol::unmarshall_reply_failure;
68     }
69     return intret;
70 }
71
72 #endif