--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2010 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ * Client requests often need to get forwarded from some monitor
+ * to the leader. This class encapsulates the original message
+ * along with the client's caps so the leader can do proper permissions
+ * checking.
+ */
+
+#ifndef CEPH_MFORWARD_H
+#define CEPH_MFORWARD_H
+
+#include "msg/Message.h"
+#include "mon/MonCap.h"
+#include "include/encoding.h"
+#include "include/stringify.h"
+
+struct MForward : public Message {
+ uint64_t tid;
+ entity_inst_t client;
+ MonCap client_caps;
+ uint64_t con_features;
+ EntityName entity_name;
+ PaxosServiceMessage *msg; // incoming or outgoing message
+
+ string msg_desc; // for operator<< only
+
+ static const int HEAD_VERSION = 3;
+ static const int COMPAT_VERSION = 3;
+
+ MForward() : Message(MSG_FORWARD, HEAD_VERSION, COMPAT_VERSION),
+ tid(0), con_features(0), msg(NULL) {}
+ //the message needs to have caps filled in!
+ MForward(uint64_t t, PaxosServiceMessage *m, uint64_t feat) :
+ Message(MSG_FORWARD, HEAD_VERSION, COMPAT_VERSION),
+ tid(t), msg(NULL) {
+ client = m->get_source_inst();
+ client_caps = m->get_session()->caps;
+ con_features = feat;
+ // we may need to reencode for the target mon
+ msg->clear_payload();
+ msg = (PaxosServiceMessage*)m->get();
+ }
+ MForward(uint64_t t, PaxosServiceMessage *m, uint64_t feat,
+ const MonCap& caps) :
+ Message(MSG_FORWARD, HEAD_VERSION, COMPAT_VERSION),
+ tid(t), client_caps(caps), msg(NULL) {
+ client = m->get_source_inst();
+ con_features = feat;
+ msg = (PaxosServiceMessage*)m->get();
+ }
+private:
+ ~MForward() override {
+ if (msg) {
+ // message was unclaimed
+ msg->put();
+ msg = NULL;
+ }
+ }
+
+public:
+ void encode_payload(uint64_t features) override {
+ ::encode(tid, payload);
+ ::encode(client, payload, features);
+ ::encode(client_caps, payload, features);
+ // Encode client message with intersection of target and source
+ // features. This could matter if the semantics of the encoded
+ // message are changed when reencoding with more features than the
+ // client had originally. That should never happen, but we may as
+ // well be defensive here.
+ if (con_features != features) {
+ msg->clear_payload();
+ }
+ encode_message(msg, features & con_features, payload);
+ ::encode(con_features, payload);
+ ::encode(entity_name, payload);
+ }
+
+ void decode_payload() override {
+ bufferlist::iterator p = payload.begin();
+ ::decode(tid, p);
+ ::decode(client, p);
+ ::decode(client_caps, p);
+ msg = (PaxosServiceMessage *)decode_message(NULL, 0, p);
+ ::decode(con_features, p);
+ ::decode(entity_name, p);
+ }
+
+ PaxosServiceMessage *claim_message() {
+ // let whoever is claiming the message deal with putting it.
+ assert(msg);
+ msg_desc = stringify(*msg);
+ PaxosServiceMessage *m = msg;
+ msg = NULL;
+ return m;
+ }
+
+ const char *get_type_name() const override { return "forward"; }
+ void print(ostream& o) const override {
+ o << "forward(";
+ if (msg) {
+ o << *msg;
+ } else {
+ o << msg_desc;
+ }
+ o << " caps " << client_caps
+ << " tid " << tid
+ << " con_features " << con_features << ")";
+ }
+};
+
+#endif