summaryrefslogtreecommitdiff
path: root/src/mongo/rpc
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2015-06-24 13:54:45 -0400
committerAdam Midvidy <amidvidy@gmail.com>2015-06-24 15:50:30 -0400
commit1fc9cba6988ab1b600be1a0549caf6146619e4df (patch)
treea5fcf53a04666b1bfc2ca43332cd824894154985 /src/mongo/rpc
parent313c3bdc2547f2746639e84f8668a756ad95d8f3 (diff)
downloadmongo-1fc9cba6988ab1b600be1a0549caf6146619e4df.tar.gz
SERVER-19035 autodetect support for OP_COMMAND in remote servers
Diffstat (limited to 'src/mongo/rpc')
-rw-r--r--src/mongo/rpc/factory.cpp28
-rw-r--r--src/mongo/rpc/factory.h13
-rw-r--r--src/mongo/rpc/protocol.cpp43
-rw-r--r--src/mongo/rpc/protocol.h6
-rw-r--r--src/mongo/rpc/protocol_test.cpp36
5 files changed, 126 insertions, 0 deletions
diff --git a/src/mongo/rpc/factory.cpp b/src/mongo/rpc/factory.cpp
index 085fa9e7a7b..ae16d16c62e 100644
--- a/src/mongo/rpc/factory.cpp
+++ b/src/mongo/rpc/factory.cpp
@@ -31,8 +31,12 @@
#include "mongo/rpc/factory.h"
#include "mongo/rpc/command_reply.h"
+#include "mongo/rpc/command_reply_builder.h"
+#include "mongo/rpc/command_request.h"
#include "mongo/rpc/command_request_builder.h"
#include "mongo/rpc/legacy_reply.h"
+#include "mongo/rpc/legacy_reply_builder.h"
+#include "mongo/rpc/legacy_request.h"
#include "mongo/rpc/legacy_request_builder.h"
#include "mongo/rpc/protocol.h"
#include "mongo/stdx/memory.h"
@@ -68,5 +72,29 @@ std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage) {
}
}
+std::unique_ptr<RequestInterface> makeRequest(const Message* unownedMessage) {
+ switch (unownedMessage->operation()) {
+ case mongo::dbQuery:
+ return stdx::make_unique<LegacyRequest>(unownedMessage);
+ case mongo::dbCommand:
+ return stdx::make_unique<CommandRequest>(unownedMessage);
+ default:
+ uasserted(ErrorCodes::UnsupportedFormat,
+ str::stream() << "Received a reply message with unexpected opcode: "
+ << unownedMessage->operation());
+ }
+}
+
+std::unique_ptr<ReplyBuilderInterface> makeReplyBuilder(Protocol protocol) {
+ switch (protocol) {
+ case Protocol::kOpQuery:
+ return stdx::make_unique<LegacyReplyBuilder>();
+ case Protocol::kOpCommandV1:
+ return stdx::make_unique<CommandReplyBuilder>();
+ default:
+ MONGO_UNREACHABLE;
+ }
+}
+
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/factory.h b/src/mongo/rpc/factory.h
index 7de92664b69..2776ffacc47 100644
--- a/src/mongo/rpc/factory.h
+++ b/src/mongo/rpc/factory.h
@@ -41,8 +41,10 @@ namespace mongo {
class Message;
namespace rpc {
+class ReplyBuilderInterface;
class ReplyInterface;
class RequestBuilderInterface;
+class RequestInterface;
/**
* Returns the appropriate concrete RequestBuilder. Throws if one cannot be chosen.
@@ -56,5 +58,16 @@ std::unique_ptr<RequestBuilderInterface> makeRequestBuilder(ProtocolSet clientPr
*/
std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage);
+/**
+ * Returns the appropriate concrete Request according to the contents of the message.
+ * Throws if one cannot be chosen.
+ */
+std::unique_ptr<RequestInterface> makeRequest(const Message* unownedMessage);
+
+/**
+ * Returns the appropriate concrete ReplyBuilder.
+ */
+std::unique_ptr<ReplyBuilderInterface> makeReplyBuilder(Protocol protocol);
+
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp
index f50860b85fd..3bb68f77672 100644
--- a/src/mongo/rpc/protocol.cpp
+++ b/src/mongo/rpc/protocol.cpp
@@ -34,6 +34,9 @@
#include <iterator>
#include "mongo/base/string_data.h"
+#include "mongo/bson/util/bson_extract.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/wire_version.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -105,5 +108,45 @@ StatusWith<ProtocolSet> parseProtocolSet(StringData repr) {
<< "and 'all' (0x3) are supported.");
}
+StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply) {
+ long long maxWireVersion;
+ auto maxWireExtractStatus =
+ bsonExtractIntegerField(isMasterReply, "maxWireVersion", &maxWireVersion);
+
+ long long minWireVersion;
+ auto minWireExtractStatus =
+ bsonExtractIntegerField(isMasterReply, "minWireVersion", &minWireVersion);
+
+ // MongoDB 2.4 and earlier do not have maxWireVersion/minWireVersion in their 'isMaster' replies
+ if ((maxWireExtractStatus == minWireExtractStatus) &&
+ (maxWireExtractStatus == ErrorCodes::NoSuchKey)) {
+ return supports::kOpQueryOnly;
+ } else if (!maxWireExtractStatus.isOK()) {
+ return maxWireExtractStatus;
+ } else if (!minWireExtractStatus.isOK()) {
+ return minWireExtractStatus;
+ }
+
+ bool hasWireVersionForOpCommandInMongod = (minWireVersion <= WireVersion::RELEASE_3_1_5) &&
+ (maxWireVersion >= WireVersion::RELEASE_3_1_5);
+
+ bool isMongos = false;
+
+ std::string msgField;
+ auto msgFieldExtractStatus = bsonExtractStringField(isMasterReply, "msg", &msgField);
+
+ if (msgFieldExtractStatus == ErrorCodes::NoSuchKey) {
+ isMongos = false;
+ } else if (!msgFieldExtractStatus.isOK()) {
+ return msgFieldExtractStatus;
+ } else {
+ isMongos = (msgField == "isdbgrid");
+ }
+
+ return (!isMongos && hasWireVersionForOpCommandInMongod) ? supports::kAll
+ : supports::kOpQueryOnly;
+}
+
+
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h
index 99e6cacc92c..8999f0b40d2 100644
--- a/src/mongo/rpc/protocol.h
+++ b/src/mongo/rpc/protocol.h
@@ -35,6 +35,7 @@
#include "mongo/platform/cstdint.h"
namespace mongo {
+class BSONObj;
namespace rpc {
/**
@@ -95,5 +96,10 @@ StatusWith<StringData> toString(ProtocolSet protocols);
*/
StatusWith<ProtocolSet> parseProtocolSet(StringData repr);
+/**
+ * Determines the ProtocolSet of a remote server from an isMaster reply.
+ */
+StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply);
+
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/protocol_test.cpp b/src/mongo/rpc/protocol_test.cpp
index 71ff1559fda..0f26cc586b2 100644
--- a/src/mongo/rpc/protocol_test.cpp
+++ b/src/mongo/rpc/protocol_test.cpp
@@ -29,12 +29,17 @@
#include "mongo/platform/basic.h"
#include "mongo/base/status.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/wire_version.h"
#include "mongo/rpc/protocol.h"
#include "mongo/unittest/unittest.h"
namespace {
+using mongo::WireVersion;
using namespace mongo::rpc;
+using mongo::unittest::assertGet;
+using mongo::BSONObj;
// Checks if negotiation of the first to protocol sets results in the 'proto'
const auto assert_negotiated = [](ProtocolSet fst, ProtocolSet snd, Protocol proto) {
@@ -63,4 +68,35 @@ TEST(Protocol, FailedNegotiation) {
assert_not_negotiated(supports::kOpCommandOnly, supports::kNone);
}
+TEST(Protocol, parseProtocolSetFromIsMasterReply) {
+ {
+ // MongoDB 3.2 (mongod)
+ auto mongod32 = BSON("maxWireVersion"
+ << static_cast<int>(WireVersion::RELEASE_3_1_5) << "minWireVersion"
+ << static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE));
+
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod32)), supports::kAll);
+ }
+ {
+ // MongoDB 3.2 (mongos)
+ auto mongos32 = BSON("maxWireVersion"
+ << static_cast<int>(WireVersion::RELEASE_3_1_5) << "minWireVersion"
+ << static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE) << "msg"
+ << "isdbgrid");
+
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongos32)), supports::kOpQueryOnly);
+ }
+ {
+ // MongoDB 3.0 (mongod)
+ auto mongod30 = BSON("maxWireVersion"
+ << static_cast<int>(WireVersion::RELEASE_2_7_7) << "minWireVersion"
+ << static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE));
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod30)), supports::kOpQueryOnly);
+ }
+ {
+ auto mongod24 = BSONObj();
+ ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod24)), supports::kOpQueryOnly);
+ }
+}
+
} // namespace