Add CompositeMachMessageServer and its test.

TEST=util_test CompositeMachMessageServer*
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/781823002
This commit is contained in:
Mark Mentovai 2014-12-04 16:45:02 -05:00
parent 821ed8fe0f
commit c83e773c33
12 changed files with 614 additions and 8 deletions

View File

@ -103,6 +103,12 @@ bool ChildPortServer::MachMessageServerFunction(
return false; return false;
} }
std::set<mach_msg_id_t> ChildPortServer::MachMessageServerRequestIDs() {
const mach_msg_id_t request_ids[] = {kMachMessageIDChildPortCheckIn};
return std::set<mach_msg_id_t>(
&request_ids[0], &request_ids[arraysize(request_ids)]);
}
mach_msg_size_t ChildPortServer::MachMessageServerRequestSize() { mach_msg_size_t ChildPortServer::MachMessageServerRequestSize() {
return sizeof(__RequestUnion__handle_child_port_subsystem); return sizeof(__RequestUnion__handle_child_port_subsystem);
} }

View File

@ -62,6 +62,8 @@ class ChildPortServer : public MachMessageServer::Interface {
mach_msg_header_t* out_header, mach_msg_header_t* out_header,
bool* destroy_complex_request) override; bool* destroy_complex_request) override;
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
mach_msg_size_t MachMessageServerRequestSize() override; mach_msg_size_t MachMessageServerRequestSize() override;
mach_msg_size_t MachMessageServerReplySize() override; mach_msg_size_t MachMessageServerReplySize() override;

View File

@ -101,6 +101,10 @@ TEST(ChildPortServer, MockChildPortCheckIn) {
MockChildPortServerInterface server_interface; MockChildPortServerInterface server_interface;
ChildPortServer server(&server_interface); ChildPortServer server(&server_interface);
std::set<mach_msg_id_t> expect_request_ids;
expect_request_ids.insert(10011); // There is no constant for this.
EXPECT_EQ(expect_request_ids, server.MachMessageServerRequestIDs());
ChildPortCheckInRequest request; ChildPortCheckInRequest request;
EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize());

View File

@ -0,0 +1,86 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/mach/composite_mach_message_server.h"
#include <algorithm>
#include <utility>
#include "base/logging.h"
#include "util/mach/mach_message.h"
namespace crashpad {
CompositeMachMessageServer::CompositeMachMessageServer()
: MachMessageServer::Interface(),
handler_map_(),
request_size_(sizeof(mach_msg_header_t)),
reply_size_(sizeof(mig_reply_error_t)) {
}
CompositeMachMessageServer::~CompositeMachMessageServer() {
}
void CompositeMachMessageServer::AddHandler(
MachMessageServer::Interface* handler) {
// Other cycles would be invalid as well, but they arent currently checked.
DCHECK_NE(handler, this);
std::set<mach_msg_id_t> request_ids = handler->MachMessageServerRequestIDs();
for (mach_msg_id_t request_id : request_ids) {
std::pair<HandlerMap::const_iterator, bool> result =
handler_map_.insert(std::make_pair(request_id, handler));
CHECK(result.second) << "duplicate request ID " << request_id;
}
request_size_ =
std::max(request_size_, handler->MachMessageServerRequestSize());
reply_size_ = std::max(reply_size_, handler->MachMessageServerReplySize());
}
bool CompositeMachMessageServer::MachMessageServerFunction(
const mach_msg_header_t* in,
mach_msg_header_t* out,
bool* destroy_complex_request) {
HandlerMap::const_iterator iterator = handler_map_.find(in->msgh_id);
if (iterator == handler_map_.end()) {
// Do what MIG-generated server routines do when they cant dispatch a
// message.
PrepareMIGReplyFromRequest(in, out);
SetMIGReplyError(out, MIG_BAD_ID);
return false;
}
MachMessageServer::Interface* handler = iterator->second;
return handler->MachMessageServerFunction(in, out, destroy_complex_request);
}
std::set<mach_msg_id_t>
CompositeMachMessageServer::MachMessageServerRequestIDs() {
std::set<mach_msg_id_t> request_ids;
for (const auto& entry : handler_map_) {
request_ids.insert(entry.first);
}
return request_ids;
}
mach_msg_size_t CompositeMachMessageServer::MachMessageServerRequestSize() {
return request_size_;
}
mach_msg_size_t CompositeMachMessageServer::MachMessageServerReplySize() {
return reply_size_;
}
} // namespace crashpad

View File

@ -0,0 +1,103 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_UTIL_MACH_COMPOSITE_MACH_MESSAGE_SERVER_H_
#define CRASHPAD_UTIL_MACH_COMPOSITE_MACH_MESSAGE_SERVER_H_
#include <mach/mach.h>
#include <map>
#include <set>
#include "base/basictypes.h"
#include "util/mach/mach_message_server.h"
namespace crashpad {
//! \brief Adapts multiple MachMessageServer::Interface implementations for
//! simultaneous use in a single MachMessageServer::Run() call.
//!
//! This class implements a MachMessageServer::Interface that contains other
//! other MachMessageServer::Interface objects.
//!
//! In some situations, it may be desirable for a Mach message server to handle
//! messages from distinct MIG subsystems with distinct
//! MachMessageServer::Interface implementations. This may happen if a single
//! receive right is shared for multiple subsystems, or if distinct receive
//! rights are combined in a Mach port set. In these cases, this class performs
//! a first-level demultiplexing to forward request messages to the proper
//! subsystem-level demultiplexers.
class CompositeMachMessageServer : public MachMessageServer::Interface {
public:
CompositeMachMessageServer();
~CompositeMachMessageServer();
//! \brief Adds a handler that messages can be dispatched to based on request
//! message ID.
//!
//! \param[in] handler A MachMessageServer handler. Ownership of this object
//! is not taken. Cycles must not be created between objects. It is
//! invalid to add an object as its own handler.
//!
//! If \a handler claims to support any request ID that this object is already
//! able to handle, execution will be terminated.
void AddHandler(MachMessageServer::Interface* handler);
// MachMessageServer::Interface:
//! \copydoc MachMessageServer::Interface::MachMessageServerFunction()
//!
//! This implementation forwards the message to an appropriate handler added
//! by AddHandler() on the basis of the \a in request messages message ID.
//! If no appropriate handler exists, the \a out reply message is treated as
//! a `mig_reply_error_t`, its return code is set to `MIG_BAD_ID`, and `false`
//! is returned.
bool MachMessageServerFunction(const mach_msg_header_t* in,
mach_msg_header_t* out,
bool* destroy_complex_request) override;
//! \copydoc MachMessageServer::Interface::MachMessageServerRequestIDs()
//!
//! This implementation returns the set of all request message Mach message
//! IDs of all handlers added by AddHandler().
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
//! \copydoc MachMessageServer::Interface::MachMessageServerRequestSize()
//!
//! This implementation returns the maximum request message size of all
//! handlers added by AddHandler(). If no handlers are present, returns the
//! size of `mach_msg_header_t`, the minimum size of a MIG request message
//! that can be received for demultiplexing purposes.
mach_msg_size_t MachMessageServerRequestSize() override;
//! \copydoc MachMessageServer::Interface::MachMessageServerReplySize()
//!
//! This implementation returns the maximum reply message size of all handlers
//! added by AddHandler(). If no handlers are present, returns the size of
//! `mig_reply_error_t`, the minimum size of a MIG reply message.
mach_msg_size_t MachMessageServerReplySize() override;
private:
using HandlerMap = std::map<mach_msg_id_t, MachMessageServer::Interface*>;
HandlerMap handler_map_; // weak
mach_msg_size_t request_size_;
mach_msg_size_t reply_size_;
DISALLOW_COPY_AND_ASSIGN(CompositeMachMessageServer);
};
} // namespace crashpad
#endif // CRASHPAD_UTIL_MACH_COMPOSITE_MACH_MESSAGE_SERVER_H_

View File

@ -0,0 +1,303 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/mach/composite_mach_message_server.h"
#include "base/strings/stringprintf.h"
#include "gtest/gtest.h"
#include "util/mach/mach_message.h"
namespace crashpad {
namespace test {
namespace {
TEST(CompositeMachMessageServer, Empty) {
CompositeMachMessageServer server;
EXPECT_TRUE(server.MachMessageServerRequestIDs().empty());
mach_msg_empty_rcv_t request = {};
EXPECT_EQ(sizeof(request.header), server.MachMessageServerRequestSize());
mig_reply_error_t reply = {};
EXPECT_EQ(sizeof(reply), server.MachMessageServerReplySize());
bool destroy_complex_request = false;
EXPECT_FALSE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
}
class TestMachMessageHandler : public MachMessageServer::Interface {
public:
TestMachMessageHandler()
: MachMessageServer::Interface(),
request_ids_(),
request_size_(0),
reply_size_(0),
return_code_(KERN_FAILURE),
return_value_(false),
destroy_complex_request_(false) {
}
~TestMachMessageHandler() {
}
void SetReturnCodes(bool return_value,
kern_return_t return_code,
bool destroy_complex_request) {
return_value_ = return_value;
return_code_ = return_code;
destroy_complex_request_ = destroy_complex_request;
}
void AddRequestID(mach_msg_id_t request_id) {
request_ids_.insert(request_id);
}
void SetRequestSize(mach_msg_size_t request_size) {
request_size_ = request_size;
}
void SetReplySize(mach_msg_size_t reply_size) {
reply_size_ = reply_size;
}
// MachMessageServer::Interface:
bool MachMessageServerFunction(const mach_msg_header_t* in,
mach_msg_header_t* out,
bool* destroy_complex_request) override {
EXPECT_NE(request_ids_.end(), request_ids_.find(in->msgh_id));
*destroy_complex_request = destroy_complex_request_;
PrepareMIGReplyFromRequest(in, out);
SetMIGReplyError(out, return_code_);
return return_value_;
}
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
return request_ids_;
}
mach_msg_size_t MachMessageServerRequestSize() override {
return request_size_;
}
mach_msg_size_t MachMessageServerReplySize() override {
return reply_size_;
}
private:
std::set<mach_msg_id_t> request_ids_;
mach_msg_size_t request_size_;
mach_msg_size_t reply_size_;
kern_return_t return_code_;
bool return_value_;
bool destroy_complex_request_;
DISALLOW_COPY_AND_ASSIGN(TestMachMessageHandler);
};
TEST(CompositeMachMessageServer, HandlerDoesNotHandle) {
TestMachMessageHandler handler;
CompositeMachMessageServer server;
server.AddHandler(&handler);
EXPECT_TRUE(server.MachMessageServerRequestIDs().empty());
mach_msg_empty_rcv_t request = {};
EXPECT_EQ(sizeof(request.header), server.MachMessageServerRequestSize());
mig_reply_error_t reply = {};
EXPECT_EQ(sizeof(reply), server.MachMessageServerReplySize());
bool destroy_complex_request = false;
EXPECT_FALSE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
EXPECT_FALSE(destroy_complex_request);
}
TEST(CompositeMachMessageServer, OneHandler) {
const mach_msg_id_t kRequestID = 100;
const mach_msg_size_t kRequestSize = 256;
const mach_msg_size_t kReplySize = 128;
const kern_return_t kReturnCode = KERN_SUCCESS;
TestMachMessageHandler handler;
handler.AddRequestID(kRequestID);
handler.SetRequestSize(kRequestSize);
handler.SetReplySize(kReplySize);
handler.SetReturnCodes(true, kReturnCode, true);
CompositeMachMessageServer server;
// The chosen request and reply sizes must be larger than the defaults for
// that portion fo the test to be valid.
EXPECT_GT(kRequestSize, server.MachMessageServerRequestSize());
EXPECT_GT(kReplySize, server.MachMessageServerReplySize());
server.AddHandler(&handler);
std::set<mach_msg_id_t> expect_request_ids;
expect_request_ids.insert(kRequestID);
EXPECT_EQ(expect_request_ids, server.MachMessageServerRequestIDs());
EXPECT_EQ(kRequestSize, server.MachMessageServerRequestSize());
EXPECT_EQ(kReplySize, server.MachMessageServerReplySize());
mach_msg_empty_rcv_t request = {};
mig_reply_error_t reply = {};
// Send a message with an unknown request ID.
request.header.msgh_id = 0;
bool destroy_complex_request = false;
EXPECT_FALSE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
EXPECT_FALSE(destroy_complex_request);
// Send a message with a known request ID.
request.header.msgh_id = kRequestID;
EXPECT_TRUE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(kReturnCode, reply.RetCode);
EXPECT_TRUE(destroy_complex_request);
}
TEST(CompositeMachMessageServer, ThreeHandlers) {
const mach_msg_id_t kRequestIDs0[] = {5};
const kern_return_t kReturnCode0 = KERN_SUCCESS;
const mach_msg_id_t kRequestIDs1[] = {4, 7};
const kern_return_t kReturnCode1 = KERN_PROTECTION_FAILURE;
const mach_msg_id_t kRequestIDs2[] = {10, 0, 20};
const mach_msg_size_t kRequestSize2 = 6144;
const mach_msg_size_t kReplySize2 = 16384;
const kern_return_t kReturnCode2 = KERN_NOT_RECEIVER;
TestMachMessageHandler handlers[3];
std::set<mach_msg_id_t> expect_request_ids;
for (size_t index = 0; index < arraysize(kRequestIDs0); ++index) {
const mach_msg_id_t request_id = kRequestIDs0[index];
handlers[0].AddRequestID(request_id);
expect_request_ids.insert(request_id);
}
handlers[0].SetRequestSize(sizeof(mach_msg_header_t));
handlers[0].SetReplySize(sizeof(mig_reply_error_t));
handlers[0].SetReturnCodes(true, kReturnCode0, false);
for (size_t index = 0; index < arraysize(kRequestIDs1); ++index) {
const mach_msg_id_t request_id = kRequestIDs1[index];
handlers[1].AddRequestID(request_id);
expect_request_ids.insert(request_id);
}
handlers[1].SetRequestSize(100);
handlers[1].SetReplySize(200);
handlers[1].SetReturnCodes(false, kReturnCode1, true);
for (size_t index = 0; index < arraysize(kRequestIDs2); ++index) {
const mach_msg_id_t request_id = kRequestIDs2[index];
handlers[2].AddRequestID(request_id);
expect_request_ids.insert(request_id);
}
handlers[2].SetRequestSize(kRequestSize2);
handlers[2].SetReplySize(kReplySize2);
handlers[2].SetReturnCodes(true, kReturnCode2, true);
CompositeMachMessageServer server;
// The chosen request and reply sizes must be larger than the defaults for
// that portion fo the test to be valid.
EXPECT_GT(kRequestSize2, server.MachMessageServerRequestSize());
EXPECT_GT(kReplySize2, server.MachMessageServerReplySize());
server.AddHandler(&handlers[0]);
server.AddHandler(&handlers[1]);
server.AddHandler(&handlers[2]);
EXPECT_EQ(expect_request_ids, server.MachMessageServerRequestIDs());
EXPECT_EQ(kRequestSize2, server.MachMessageServerRequestSize());
EXPECT_EQ(kReplySize2, server.MachMessageServerReplySize());
mach_msg_empty_rcv_t request = {};
mig_reply_error_t reply = {};
// Send a message with an unknown request ID.
request.header.msgh_id = 100;
bool destroy_complex_request = false;
EXPECT_FALSE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
EXPECT_FALSE(destroy_complex_request);
// Send messages with known request IDs.
for (size_t index = 0; index < arraysize(kRequestIDs0); ++index) {
request.header.msgh_id = kRequestIDs0[index];
SCOPED_TRACE(base::StringPrintf(
"handler 0, index %zu, id %d", index, request.header.msgh_id));
EXPECT_TRUE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(kReturnCode0, reply.RetCode);
EXPECT_FALSE(destroy_complex_request);
}
for (size_t index = 0; index < arraysize(kRequestIDs1); ++index) {
request.header.msgh_id = kRequestIDs1[index];
SCOPED_TRACE(base::StringPrintf(
"handler 1, index %zu, id %d", index, request.header.msgh_id));
EXPECT_FALSE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(kReturnCode1, reply.RetCode);
EXPECT_TRUE(destroy_complex_request);
}
for (size_t index = 0; index < arraysize(kRequestIDs2); ++index) {
request.header.msgh_id = kRequestIDs2[index];
SCOPED_TRACE(base::StringPrintf(
"handler 2, index %zu, id %d", index, request.header.msgh_id));
EXPECT_TRUE(server.MachMessageServerFunction(
&request.header, &reply.Head, &destroy_complex_request));
EXPECT_EQ(kReturnCode2, reply.RetCode);
EXPECT_TRUE(destroy_complex_request);
}
}
// CompositeMachMessageServer cant deal with two handlers that want to handle
// the same request ID.
TEST(CompositeMachMessageServerDeathTest, DuplicateRequestID) {
const mach_msg_id_t kRequestID = 400;
TestMachMessageHandler handlers[2];
handlers[0].AddRequestID(kRequestID);
handlers[1].AddRequestID(kRequestID);
CompositeMachMessageServer server;
server.AddHandler(&handlers[0]);
EXPECT_DEATH(server.AddHandler(&handlers[1]), "duplicate request ID");
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -318,6 +318,16 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
return false; return false;
} }
std::set<mach_msg_id_t> ExcServer::MachMessageServerRequestIDs() {
const mach_msg_id_t request_ids[] = {
kMachMessageIDExceptionRaise,
kMachMessageIDExceptionRaiseState,
kMachMessageIDExceptionRaiseStateIdentity
};
return std::set<mach_msg_id_t>(
&request_ids[0], &request_ids[arraysize(request_ids)]);
}
mach_msg_size_t ExcServer::MachMessageServerRequestSize() { mach_msg_size_t ExcServer::MachMessageServerRequestSize() {
return sizeof(__RequestUnion__exc_subsystem); return sizeof(__RequestUnion__exc_subsystem);
} }
@ -459,6 +469,16 @@ bool MachExcServer::MachMessageServerFunction(
return false; return false;
} }
std::set<mach_msg_id_t> MachExcServer::MachMessageServerRequestIDs() {
const mach_msg_id_t request_ids[] = {
kMachMessageIDMachExceptionRaise,
kMachMessageIDMachExceptionRaiseState,
kMachMessageIDMachExceptionRaiseStateIdentity
};
return std::set<mach_msg_id_t>(
&request_ids[0], &request_ids[arraysize(request_ids)]);
}
mach_msg_size_t MachExcServer::MachMessageServerRequestSize() { mach_msg_size_t MachExcServer::MachMessageServerRequestSize() {
return sizeof(__RequestUnion__mach_exc_subsystem); return sizeof(__RequestUnion__mach_exc_subsystem);
} }
@ -689,6 +709,17 @@ bool UniversalMachExcServer::MachMessageServerFunction(
return false; return false;
} }
std::set<mach_msg_id_t> UniversalMachExcServer::MachMessageServerRequestIDs() {
std::set<mach_msg_id_t> request_ids =
exc_server_.MachMessageServerRequestIDs();
std::set<mach_msg_id_t> mach_exc_request_ids =
mach_exc_server_.MachMessageServerRequestIDs();
request_ids.insert(mach_exc_request_ids.begin(), mach_exc_request_ids.end());
return request_ids;
}
mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() { mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() {
return std::max(mach_exc_server_.MachMessageServerRequestSize(), return std::max(mach_exc_server_.MachMessageServerRequestSize(),
exc_server_.MachMessageServerRequestSize()); exc_server_.MachMessageServerRequestSize());

View File

@ -17,6 +17,8 @@
#include <mach/mach.h> #include <mach/mach.h>
#include <set>
#include "build/build_config.h" #include "build/build_config.h"
#include "util/mach/mach_message_server.h" #include "util/mach/mach_message_server.h"
@ -118,6 +120,8 @@ class ExcServer : public MachMessageServer::Interface {
mach_msg_header_t* out_header, mach_msg_header_t* out_header,
bool* destroy_complex_request) override; bool* destroy_complex_request) override;
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
mach_msg_size_t MachMessageServerRequestSize() override; mach_msg_size_t MachMessageServerRequestSize() override;
mach_msg_size_t MachMessageServerReplySize() override; mach_msg_size_t MachMessageServerReplySize() override;
@ -217,6 +221,8 @@ class MachExcServer : public MachMessageServer::Interface {
mach_msg_header_t* out_header, mach_msg_header_t* out_header,
bool* destroy_complex_request) override; bool* destroy_complex_request) override;
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
mach_msg_size_t MachMessageServerRequestSize() override; mach_msg_size_t MachMessageServerRequestSize() override;
mach_msg_size_t MachMessageServerReplySize() override; mach_msg_size_t MachMessageServerReplySize() override;
@ -483,6 +489,8 @@ class UniversalMachExcServer
mach_msg_header_t* out_header, mach_msg_header_t* out_header,
bool* destroy_complex_request) override; bool* destroy_complex_request) override;
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
mach_msg_size_t MachMessageServerRequestSize() override; mach_msg_size_t MachMessageServerRequestSize() override;
mach_msg_size_t MachMessageServerReplySize() override; mach_msg_size_t MachMessageServerReplySize() override;

View File

@ -584,6 +584,10 @@ TEST(ExcServerVariants, MockExceptionRaise) {
MockUniversalMachExcServer server; MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server); UniversalMachExcServer universal_mach_exc_server(&server);
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_NE(ids.end(), ids.find(2401)); // There is no constant for this.
ExceptionRaiseRequest request; ExceptionRaiseRequest request;
EXPECT_LE(request.Head.msgh_size, EXPECT_LE(request.Head.msgh_size,
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -625,6 +629,10 @@ TEST(ExcServerVariants, MockExceptionRaiseState) {
MockUniversalMachExcServer server; MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server); UniversalMachExcServer universal_mach_exc_server(&server);
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_NE(ids.end(), ids.find(2402)); // There is no constant for this.
ExceptionRaiseStateRequest request; ExceptionRaiseStateRequest request;
EXPECT_LE(request.Head.msgh_size, EXPECT_LE(request.Head.msgh_size,
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -670,6 +678,10 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) {
MockUniversalMachExcServer server; MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server); UniversalMachExcServer universal_mach_exc_server(&server);
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_NE(ids.end(), ids.find(2403)); // There is no constant for this.
ExceptionRaiseStateIdentityRequest request; ExceptionRaiseStateIdentityRequest request;
EXPECT_LE(request.Head.msgh_size, EXPECT_LE(request.Head.msgh_size,
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -712,6 +724,10 @@ TEST(ExcServerVariants, MockMachExceptionRaise) {
MockUniversalMachExcServer server; MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server); UniversalMachExcServer universal_mach_exc_server(&server);
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_NE(ids.end(), ids.find(2405)); // There is no constant for this.
MachExceptionRaiseRequest request; MachExceptionRaiseRequest request;
EXPECT_LE(request.Head.msgh_size, EXPECT_LE(request.Head.msgh_size,
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -755,6 +771,10 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) {
MockUniversalMachExcServer server; MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server); UniversalMachExcServer universal_mach_exc_server(&server);
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_NE(ids.end(), ids.find(2406)); // There is no constant for this.
MachExceptionRaiseStateRequest request; MachExceptionRaiseStateRequest request;
EXPECT_LE(request.Head.msgh_size, EXPECT_LE(request.Head.msgh_size,
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -801,6 +821,10 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) {
MockUniversalMachExcServer server; MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server); UniversalMachExcServer universal_mach_exc_server(&server);
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_NE(ids.end(), ids.find(2407)); // There is no constant for this.
MachExceptionRaiseStateIdentityRequest request; MachExceptionRaiseStateIdentityRequest request;
EXPECT_LE(request.Head.msgh_size, EXPECT_LE(request.Head.msgh_size,
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -882,6 +906,10 @@ TEST(ExcServerVariants, MockUnknownID) {
SCOPED_TRACE(base::StringPrintf("unknown id %d", id)); SCOPED_TRACE(base::StringPrintf("unknown id %d", id));
std::set<mach_msg_id_t> ids =
universal_mach_exc_server.MachMessageServerRequestIDs();
EXPECT_EQ(ids.end(), ids.find(id));
InvalidRequest request(id); InvalidRequest request(id);
EXPECT_LE(sizeof(request), EXPECT_LE(sizeof(request),
universal_mach_exc_server.MachMessageServerRequestSize()); universal_mach_exc_server.MachMessageServerRequestSize());
@ -906,6 +934,24 @@ TEST(ExcServerVariants, MockUnknownID) {
} }
} }
TEST(ExcServerVariants, MachMessageServerRequestIDs) {
std::set<mach_msg_id_t> expect_request_ids;
// There are no constants for these.
expect_request_ids.insert(2401);
expect_request_ids.insert(2402);
expect_request_ids.insert(2403);
expect_request_ids.insert(2405);
expect_request_ids.insert(2406);
expect_request_ids.insert(2407);
MockUniversalMachExcServer server;
UniversalMachExcServer universal_mach_exc_server(&server);
EXPECT_EQ(expect_request_ids,
universal_mach_exc_server.MachMessageServerRequestIDs());
}
class TestExcServerVariants : public MachMultiprocess, class TestExcServerVariants : public MachMultiprocess,
public UniversalMachExcServer::Interface { public UniversalMachExcServer::Interface {
public: public:

View File

@ -17,6 +17,8 @@
#include <mach/mach.h> #include <mach/mach.h>
#include <set>
#include "base/basictypes.h" #include "base/basictypes.h"
namespace crashpad { namespace crashpad {
@ -68,6 +70,10 @@ class MachMessageServer {
mach_msg_header_t* out, mach_msg_header_t* out,
bool* destroy_complex_request) = 0; bool* destroy_complex_request) = 0;
//! \return The set of request message Mach message IDs that
//! MachMessageServerFunction() is able to handle.
virtual std::set<mach_msg_id_t> MachMessageServerRequestIDs() = 0;
//! \return The expected or maximum size, in bytes, of a request message to //! \return The expected or maximum size, in bytes, of a request message to
//! be received as the \a in parameter of MachMessageServerFunction(). //! be received as the \a in parameter of MachMessageServerFunction().
virtual mach_msg_size_t MachMessageServerRequestSize() = 0; virtual mach_msg_size_t MachMessageServerRequestSize() = 0;

View File

@ -17,6 +17,8 @@
#include <mach/mach.h> #include <mach/mach.h>
#include <string.h> #include <string.h>
#include <set>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/mac/scoped_mach_port.h" #include "base/mac/scoped_mach_port.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -222,7 +224,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
EXPECT_EQ(RemotePort(), request->header.msgh_remote_port); EXPECT_EQ(RemotePort(), request->header.msgh_remote_port);
} }
EXPECT_EQ(LocalPort(), request->header.msgh_local_port); EXPECT_EQ(LocalPort(), request->header.msgh_local_port);
EXPECT_EQ(kRequestMessageId, request->header.msgh_id); EXPECT_EQ(kRequestMessageID, request->header.msgh_id);
if (options_.client_send_complex) { if (options_.client_send_complex) {
EXPECT_EQ(1u, request->body.msgh_descriptor_count); EXPECT_EQ(1u, request->body.msgh_descriptor_count);
EXPECT_NE(kMachPortNull, request->port_descriptor.name); EXPECT_NE(kMachPortNull, request->port_descriptor.name);
@ -266,7 +268,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
reply->Head.msgh_size = sizeof(*reply); reply->Head.msgh_size = sizeof(*reply);
reply->Head.msgh_remote_port = request->header.msgh_remote_port; reply->Head.msgh_remote_port = request->header.msgh_remote_port;
reply->Head.msgh_local_port = MACH_PORT_NULL; reply->Head.msgh_local_port = MACH_PORT_NULL;
reply->Head.msgh_id = kReplyMessageId; reply->Head.msgh_id = kReplyMessageID;
reply->NDR = NDR_record; reply->NDR = NDR_record;
reply->RetCode = options_.server_mig_retcode; reply->RetCode = options_.server_mig_retcode;
reply->number = replies_++; reply->number = replies_++;
@ -274,6 +276,12 @@ class TestMachMessageServer : public MachMessageServer::Interface,
return true; return true;
} }
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
const mach_msg_id_t request_ids[] = {kRequestMessageID};
return std::set<mach_msg_id_t>(
&request_ids[0], &request_ids[arraysize(request_ids)]);
}
mach_msg_size_t MachMessageServerRequestSize() override { mach_msg_size_t MachMessageServerRequestSize() override {
return sizeof(RequestMessage); return sizeof(RequestMessage);
} }
@ -469,7 +477,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
break; break;
} }
} }
request.header.msgh_id = kRequestMessageId; request.header.msgh_id = kRequestMessageID;
if (options_.client_send_complex) { if (options_.client_send_complex) {
// Allocate a new receive right in this process and make a send right that // Allocate a new receive right in this process and make a send right that
// will appear in the parent process. This is used to test that the server // will appear in the parent process. This is used to test that the server
@ -534,7 +542,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
ASSERT_EQ(sizeof(ReplyMessage), reply.Head.msgh_size); ASSERT_EQ(sizeof(ReplyMessage), reply.Head.msgh_size);
ASSERT_EQ(kMachPortNull, reply.Head.msgh_remote_port); ASSERT_EQ(kMachPortNull, reply.Head.msgh_remote_port);
ASSERT_EQ(LocalPort(), reply.Head.msgh_local_port); ASSERT_EQ(LocalPort(), reply.Head.msgh_local_port);
ASSERT_EQ(kReplyMessageId, reply.Head.msgh_id); ASSERT_EQ(kReplyMessageID, reply.Head.msgh_id);
ASSERT_EQ(0, memcmp(&reply.NDR, &NDR_record, sizeof(NDR_record))); ASSERT_EQ(0, memcmp(&reply.NDR, &NDR_record, sizeof(NDR_record)));
ASSERT_EQ(options_.server_mig_retcode, reply.RetCode); ASSERT_EQ(options_.server_mig_retcode, reply.RetCode);
ASSERT_EQ(replies_, reply.number); ASSERT_EQ(replies_, reply.number);
@ -584,16 +592,16 @@ class TestMachMessageServer : public MachMessageServer::Interface,
static uint32_t requests_; static uint32_t requests_;
static uint32_t replies_; static uint32_t replies_;
static const mach_msg_id_t kRequestMessageId = 16237; static const mach_msg_id_t kRequestMessageID = 16237;
static const mach_msg_id_t kReplyMessageId = kRequestMessageId + 100; static const mach_msg_id_t kReplyMessageID = kRequestMessageID + 100;
DISALLOW_COPY_AND_ASSIGN(TestMachMessageServer); DISALLOW_COPY_AND_ASSIGN(TestMachMessageServer);
}; };
uint32_t TestMachMessageServer::requests_; uint32_t TestMachMessageServer::requests_;
uint32_t TestMachMessageServer::replies_; uint32_t TestMachMessageServer::replies_;
const mach_msg_id_t TestMachMessageServer::kRequestMessageId; const mach_msg_id_t TestMachMessageServer::kRequestMessageID;
const mach_msg_id_t TestMachMessageServer::kReplyMessageId; const mach_msg_id_t TestMachMessageServer::kReplyMessageID;
TEST(MachMessageServer, Basic) { TEST(MachMessageServer, Basic) {
// The client sends one message to the server, which will wait indefinitely in // The client sends one message to the server, which will wait indefinitely in

View File

@ -45,6 +45,8 @@
'mach/child_port_server.cc', 'mach/child_port_server.cc',
'mach/child_port_server.h', 'mach/child_port_server.h',
'mach/child_port_types.h', 'mach/child_port_types.h',
'mach/composite_mach_message_server.cc',
'mach/composite_mach_message_server.h',
'mach/exc_client_variants.cc', 'mach/exc_client_variants.cc',
'mach/exc_client_variants.h', 'mach/exc_client_variants.h',
'mach/exc_server_variants.cc', 'mach/exc_server_variants.cc',
@ -240,6 +242,7 @@
'mac/service_management_test.mm', 'mac/service_management_test.mm',
'mach/child_port_handshake_test.cc', 'mach/child_port_handshake_test.cc',
'mach/child_port_server_test.cc', 'mach/child_port_server_test.cc',
'mach/composite_mach_message_server_test.cc',
'mach/exc_client_variants_test.cc', 'mach/exc_client_variants_test.cc',
'mach/exc_server_variants_test.cc', 'mach/exc_server_variants_test.cc',
'mach/exception_behaviors_test.cc', 'mach/exception_behaviors_test.cc',