mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
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:
parent
821ed8fe0f
commit
c83e773c33
@ -103,6 +103,12 @@ bool ChildPortServer::MachMessageServerFunction(
|
||||
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() {
|
||||
return sizeof(__RequestUnion__handle_child_port_subsystem);
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ class ChildPortServer : public MachMessageServer::Interface {
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
|
@ -101,6 +101,10 @@ TEST(ChildPortServer, MockChildPortCheckIn) {
|
||||
MockChildPortServerInterface 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;
|
||||
EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize());
|
||||
|
||||
|
86
util/mach/composite_mach_message_server.cc
Normal file
86
util/mach/composite_mach_message_server.cc
Normal 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 aren’t 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 can’t 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
|
103
util/mach/composite_mach_message_server.h
Normal file
103
util/mach/composite_mach_message_server.h
Normal 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 message’s 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_
|
303
util/mach/composite_mach_message_server_test.cc
Normal file
303
util/mach/composite_mach_message_server_test.cc
Normal 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 can’t 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
|
@ -318,6 +318,16 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
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() {
|
||||
return sizeof(__RequestUnion__exc_subsystem);
|
||||
}
|
||||
@ -459,6 +469,16 @@ bool MachExcServer::MachMessageServerFunction(
|
||||
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() {
|
||||
return sizeof(__RequestUnion__mach_exc_subsystem);
|
||||
}
|
||||
@ -689,6 +709,17 @@ bool UniversalMachExcServer::MachMessageServerFunction(
|
||||
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() {
|
||||
return std::max(mach_exc_server_.MachMessageServerRequestSize(),
|
||||
exc_server_.MachMessageServerRequestSize());
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "util/mach/mach_message_server.h"
|
||||
|
||||
@ -118,6 +120,8 @@ class ExcServer : public MachMessageServer::Interface {
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
@ -217,6 +221,8 @@ class MachExcServer : public MachMessageServer::Interface {
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
@ -483,6 +489,8 @@ class UniversalMachExcServer
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
|
@ -584,6 +584,10 @@ TEST(ExcServerVariants, MockExceptionRaise) {
|
||||
MockUniversalMachExcServer 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;
|
||||
EXPECT_LE(request.Head.msgh_size,
|
||||
universal_mach_exc_server.MachMessageServerRequestSize());
|
||||
@ -625,6 +629,10 @@ TEST(ExcServerVariants, MockExceptionRaiseState) {
|
||||
MockUniversalMachExcServer 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;
|
||||
EXPECT_LE(request.Head.msgh_size,
|
||||
universal_mach_exc_server.MachMessageServerRequestSize());
|
||||
@ -670,6 +678,10 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) {
|
||||
MockUniversalMachExcServer 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;
|
||||
EXPECT_LE(request.Head.msgh_size,
|
||||
universal_mach_exc_server.MachMessageServerRequestSize());
|
||||
@ -712,6 +724,10 @@ TEST(ExcServerVariants, MockMachExceptionRaise) {
|
||||
MockUniversalMachExcServer 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;
|
||||
EXPECT_LE(request.Head.msgh_size,
|
||||
universal_mach_exc_server.MachMessageServerRequestSize());
|
||||
@ -755,6 +771,10 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) {
|
||||
MockUniversalMachExcServer 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;
|
||||
EXPECT_LE(request.Head.msgh_size,
|
||||
universal_mach_exc_server.MachMessageServerRequestSize());
|
||||
@ -801,6 +821,10 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) {
|
||||
MockUniversalMachExcServer 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;
|
||||
EXPECT_LE(request.Head.msgh_size,
|
||||
universal_mach_exc_server.MachMessageServerRequestSize());
|
||||
@ -882,6 +906,10 @@ TEST(ExcServerVariants, MockUnknownID) {
|
||||
|
||||
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);
|
||||
EXPECT_LE(sizeof(request),
|
||||
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,
|
||||
public UniversalMachExcServer::Interface {
|
||||
public:
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -68,6 +70,10 @@ class MachMessageServer {
|
||||
mach_msg_header_t* out,
|
||||
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
|
||||
//! be received as the \a in parameter of MachMessageServerFunction().
|
||||
virtual mach_msg_size_t MachMessageServerRequestSize() = 0;
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <mach/mach.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -222,7 +224,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
EXPECT_EQ(RemotePort(), request->header.msgh_remote_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) {
|
||||
EXPECT_EQ(1u, request->body.msgh_descriptor_count);
|
||||
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_remote_port = request->header.msgh_remote_port;
|
||||
reply->Head.msgh_local_port = MACH_PORT_NULL;
|
||||
reply->Head.msgh_id = kReplyMessageId;
|
||||
reply->Head.msgh_id = kReplyMessageID;
|
||||
reply->NDR = NDR_record;
|
||||
reply->RetCode = options_.server_mig_retcode;
|
||||
reply->number = replies_++;
|
||||
@ -274,6 +276,12 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
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 {
|
||||
return sizeof(RequestMessage);
|
||||
}
|
||||
@ -469,7 +477,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
break;
|
||||
}
|
||||
}
|
||||
request.header.msgh_id = kRequestMessageId;
|
||||
request.header.msgh_id = kRequestMessageID;
|
||||
if (options_.client_send_complex) {
|
||||
// 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
|
||||
@ -534,7 +542,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
ASSERT_EQ(sizeof(ReplyMessage), reply.Head.msgh_size);
|
||||
ASSERT_EQ(kMachPortNull, reply.Head.msgh_remote_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(options_.server_mig_retcode, reply.RetCode);
|
||||
ASSERT_EQ(replies_, reply.number);
|
||||
@ -584,16 +592,16 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
static uint32_t requests_;
|
||||
static uint32_t replies_;
|
||||
|
||||
static const mach_msg_id_t kRequestMessageId = 16237;
|
||||
static const mach_msg_id_t kReplyMessageId = kRequestMessageId + 100;
|
||||
static const mach_msg_id_t kRequestMessageID = 16237;
|
||||
static const mach_msg_id_t kReplyMessageID = kRequestMessageID + 100;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMachMessageServer);
|
||||
};
|
||||
|
||||
uint32_t TestMachMessageServer::requests_;
|
||||
uint32_t TestMachMessageServer::replies_;
|
||||
const mach_msg_id_t TestMachMessageServer::kRequestMessageId;
|
||||
const mach_msg_id_t TestMachMessageServer::kReplyMessageId;
|
||||
const mach_msg_id_t TestMachMessageServer::kRequestMessageID;
|
||||
const mach_msg_id_t TestMachMessageServer::kReplyMessageID;
|
||||
|
||||
TEST(MachMessageServer, Basic) {
|
||||
// The client sends one message to the server, which will wait indefinitely in
|
||||
|
@ -45,6 +45,8 @@
|
||||
'mach/child_port_server.cc',
|
||||
'mach/child_port_server.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.h',
|
||||
'mach/exc_server_variants.cc',
|
||||
@ -240,6 +242,7 @@
|
||||
'mac/service_management_test.mm',
|
||||
'mach/child_port_handshake_test.cc',
|
||||
'mach/child_port_server_test.cc',
|
||||
'mach/composite_mach_message_server_test.cc',
|
||||
'mach/exc_client_variants_test.cc',
|
||||
'mach/exc_server_variants_test.cc',
|
||||
'mach/exception_behaviors_test.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user