2a9c8c43c70aa5165d3e713175f83b8696091bf5
[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     public:
23         rsm_client(string dst);
24         rsm_protocol::status invoke(unsigned int proc, string &rep, const string &req);
25
26         template<class R, class ...Args>
27             int call(unsigned int proc, R & r, const Args & ...a1);
28     private:
29         template<class R> int call_m(unsigned int proc, R & r, const marshall & req);
30 };
31
32 inline string hexify(const string & s) {
33     string bytes;
34     for (char ch : s) {
35         bytes.push_back("0123456789abcdef"[(uint8_t)ch >> 4]);
36         bytes.push_back("0123456789abcdef"[(uint8_t)ch & 15]);
37     }
38     return bytes;
39 }
40
41 template<class R>
42 int rsm_client::call_m(unsigned int proc, R & r, const marshall & req) {
43     string rep;
44     string res;
45     int intret = invoke(proc, rep, req.content());
46     VERIFY( intret == rsm_client_protocol::OK );
47     unmarshall u(rep, false);
48     u >> intret;
49     if (intret < 0) return intret;
50     u >> res;
51     if (!u.okdone()) {
52         LOG("failed to unmarshall the reply.");
53         LOG("You probably forgot to set the reply string in " <<
54             "rsm::client_invoke, or you may have called RPC " <<
55             "0x" << hex << proc << " with the wrong return type");
56         LOG("here's what I got: \"" << hexify(rep) << "\"");
57         VERIFY(0);
58         return rpc_const::unmarshal_reply_failure;
59     }
60     unmarshall u1(res, false);
61     u1 >> r;
62     if(!u1.okdone()) {
63         LOG("failed to unmarshall the reply.");
64         LOG("You are probably calling RPC 0x" << hex << proc <<
65             " with the wrong return type.");
66         LOG("here's what I got: \"" << hexify(res) << "\"");
67         VERIFY(0);
68         return rpc_const::unmarshal_reply_failure;
69     }
70     return intret;
71 }
72
73 template<class R, class ...Args>
74 int rsm_client::call(unsigned int proc, R & r, const Args & ...a1) {
75     return call_m(proc, r, marshall{a1...});
76 }
77
78 #endif