xdrpp
RFC4506 XDR compiler and message library
server.cc
1 
2 #include <iostream>
3 #include <xdrpp/server.h>
4 
5 namespace xdr {
6 
7 bool xdr_trace_server = std::getenv("XDR_TRACE_SERVER");
8 
9 msg_ptr
10 rpc_accepted_error_msg(uint32_t xid, accept_stat stat)
11 {
12  assert(stat != SUCCESS && stat != PROG_MISMATCH);
13  msg_ptr buf(message_t::alloc(24));
14  xdr_put p(buf);
15  p(xid);
16  p(REPLY);
17  p(MSG_ACCEPTED);
18  p(AUTH_NONE);
19  p(uint32_t(0));
20  p(stat);
21  assert(p.p_ == p.e_);
22  return buf;
23 }
24 
25 msg_ptr
26 rpc_prog_mismatch_msg(uint32_t xid, uint32_t low, uint32_t high)
27 {
28  msg_ptr buf(message_t::alloc(32));
29  xdr_put p(buf);
30  p(xid);
31  p(REPLY);
32  p(MSG_ACCEPTED);
33  p(AUTH_NONE);
34  p(uint32_t(0));
35  p(PROG_MISMATCH);
36  p(low);
37  p(high);
38  assert(p.p_ == p.e_);
39  return buf;
40 }
41 
42 msg_ptr
43 rpc_auth_error_msg(uint32_t xid, auth_stat stat)
44 {
45  msg_ptr buf(message_t::alloc(20));
46  xdr_put p(buf);
47  p(xid);
48  p(REPLY);
49  p(MSG_DENIED);
50  p(AUTH_ERROR);
51  p(stat);
52  assert(p.p_ == p.e_);
53  return buf;
54 }
55 
56 msg_ptr
57 rpc_rpc_mismatch_msg(uint32_t xid)
58 {
59  msg_ptr buf(message_t::alloc(24));
60  xdr_put p(buf);
61  p(xid);
62  p(REPLY);
63  p(MSG_DENIED);
64  p(RPC_MISMATCH);
65  p(uint32_t(2));
66  p(uint32_t(2));
67  assert(p.p_ == p.e_);
68  return buf;
69 }
70 
71 
72 void
73 rpc_server_base::register_service_base(service_base *s)
74 {
75  servers_[s->prog_][s->vers_].reset(s);
76 }
77 
78 void
79 rpc_server_base::dispatch(void *session, msg_ptr m, service_base::cb_t reply)
80 {
81  xdr_get g(m);
82  rpc_msg hdr;
83 
84  try { archive(g, hdr); }
85  catch (const xdr_runtime_error &e) {
86  std::cerr << "rpc_server_base::dispatch: ignoring malformed header: "
87  << e.what() << std::endl;
88  return;
89  }
90  if (hdr.body.mtype() != CALL) {
91  std::cerr << "rpc_server_base::dispatch: ignoring non-CALL" << std::endl;
92  return;
93  }
94 
95  if (hdr.body.cbody().rpcvers != 2)
96  return reply(rpc_rpc_mismatch_msg(hdr.xid));
97 
98  auto prog = servers_.find(hdr.body.cbody().prog);
99  if (prog == servers_.end())
100  return reply(rpc_accepted_error_msg(hdr.xid, PROG_UNAVAIL));
101 
102  auto vers = prog->second.find(hdr.body.cbody().vers);
103  if (vers == prog->second.end()) {
104  uint32_t low = prog->second.cbegin()->first;
105  uint32_t high = prog->second.crbegin()->first;
106  return reply(rpc_prog_mismatch_msg(hdr.xid, low, high));
107  }
108 
109  try {
110  vers->second->process(session, hdr, g, reply);
111  return;
112  }
113  catch (const xdr_runtime_error &e) {
114  std::cerr << "rpc_server_base::dispatch: " << e.what() << std::endl;
115  }
116  reply(rpc_accepted_error_msg(hdr.xid, GARBAGE_ARGS));
117 }
118 
119 
120 rpc_tcp_listener_common::rpc_tcp_listener_common(pollset &ps, unique_sock &&s,
121  bool reg)
122  : listen_sock_(s ? std::move(s) : tcp_listen()), use_rpcbind_(reg),
123  ps_(ps)
124 {
125  set_close_on_exec(listen_sock_.get());
126  ps_.fd_cb(listen_sock_.get(), pollset::Read,
127  std::bind(&rpc_tcp_listener_common::accept_cb, this));
128 }
129 
130 rpc_tcp_listener_common::~rpc_tcp_listener_common()
131 {
132  ps_.fd_cb(listen_sock_.get(), pollset::Read);
133  // XXX should clean up if use_rpcbind_.
134 }
135 
136 void
137 rpc_tcp_listener_common::accept_cb()
138 {
139  sock_t s = accept(listen_sock_.get(), nullptr, 0);
140  if (s == invalid_sock) {
141  std::cerr << "rpc_tcp_listener_common: accept: " << sock_errmsg()
142  << std::endl;
143  return;
144  }
146  rpc_sock *ms = new rpc_sock(ps_, s);
147  ms->set_servcb(std::bind(&rpc_tcp_listener_common::receive_cb, this, ms,
148  session_alloc(ms), std::placeholders::_1));
149 }
150 
151 void
152 rpc_tcp_listener_common::receive_cb(rpc_sock *ms, void *session, msg_ptr mp)
153 {
154  if (!mp) {
155  session_free(session);
156  delete ms;
157  return;
158  }
159  try {
160  dispatch(session, std::move(mp), rpc_sock_reply_t(ms));
161  }
162  catch (const xdr_runtime_error &e) {
163  std::cerr << e.what() << std::endl;
164  session_free(session);
165  delete ms;
166  }
167 }
168 
169 }
static msg_ptr alloc(std::size_t size)
Allocate a new buffer.
Definition: marshal.cc:7
Specify interest in read-ready condition.
Definition: pollset.h:34
Most of the xdrpp library is encapsulated in the xdr namespace.
Definition: arpc.cc:4
Definition: socket.h:47
Classes for implementing RPC servers.
xdr_generic_get< marshal_swap > xdr_get
Archive for unmarshaling in RFC4506 big-endian order.
Definition: marshal.h:198
void fd_cb(sock_t s, op_t op, CB &&cb)
Set a read or write callback on a particular file descriptor.
Definition: pollset.h:108
sock_t accept(sock_t s, sockaddr *addr, socklen_t *addrlen)
Wrapper around accept for sock_t.
Definition: socket.h:84
xdr_generic_put< marshal_swap > xdr_put
Archive for marshaling in RFC4506 big-endian order.
Definition: marshal.h:196
const char * sock_errmsg()
Last socket error message (strerror(errno) on POSIX).
Definition: socket_unix.cc:25
unique_sock tcp_listen(const char *service, int family, int backlog)
Create bind a listening TCP socket.
Definition: socket.cc:133
sock_t get() const
Return the file descriptor number, but maintain ownership.
Definition: socket.h:138
void set_close_on_exec(sock_t s)
Set the close-on-exec flag of a file descriptor.
Definition: socket_unix.cc:79