crashpad/util/mach/bootstrap_test.cc
Mark Mentovai 280c4345c5 Add BootstrapCheckIn and its test.
TEST=util_test Bootstrap.BootstrapCheckIn
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/478713003
2014-08-18 20:41:00 -07:00

135 lines
5.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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/bootstrap.h"
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include <string.h>
#include <algorithm>
#include <string>
#include "base/basictypes.h"
#include "base/mac/scoped_mach_port.h"
#include "base/rand_util.h"
#include "gtest/gtest.h"
#include "util/test/mac/mach_errors.h"
namespace {
using namespace crashpad;
using namespace crashpad::test;
using namespace testing;
TEST(Bootstrap, BootstrapCheckIn) {
std::string service_name = "com.googlecode.crashpad.test.bootstrap.";
for (int index = 0; index < 16; ++index) {
service_name.append(1, base::RandInt('A', 'Z'));
}
// The service shouldnt be registered in the bootstrap namespace yet.
mach_port_t client_port = MACH_PORT_NULL;
kern_return_t kr =
bootstrap_look_up(bootstrap_port, service_name.c_str(), &client_port);
ASSERT_EQ(BOOTSTRAP_UNKNOWN_SERVICE, kr)
<< BootstrapErrorMessage(kr, "bootstrap_look_up");
// Check in, getting a receive right.
mach_port_t server_port;
kr = BootstrapCheckIn(bootstrap_port, service_name.c_str(), &server_port);
ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
<< BootstrapErrorMessage(kr, "bootstrap_check_in");
ASSERT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), server_port);
base::mac::ScopedMachReceiveRight server_port_owner(server_port);
// A subsequent checkin attempt should fail.
mach_port_t fail_port = MACH_PORT_NULL;
kr = BootstrapCheckIn(bootstrap_port, service_name.c_str(), &fail_port);
EXPECT_EQ(BOOTSTRAP_SERVICE_ACTIVE, kr);
EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), fail_port);
// Look up the service, getting a send right.
kr = bootstrap_look_up(bootstrap_port, service_name.c_str(), &client_port);
ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
<< BootstrapErrorMessage(kr, "bootstrap_look_up");
base::mac::ScopedMachSendRight client_port_owner(client_port);
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), client_port);
// Have the “client” send a message to the “server”.
struct SendMessage {
mach_msg_header_t header;
char data[64];
};
SendMessage send_message = {};
send_message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
send_message.header.msgh_size = sizeof(send_message);
send_message.header.msgh_remote_port = client_port;
const char kMessageData[] = "Mach messaging is not a big truck";
const size_t message_data_size =
std::min(sizeof(kMessageData), sizeof(send_message.data));
memcpy(send_message.data, kMessageData, message_data_size);
// The receive operation happens in this same thread after the send, so use a
// non-blocking send (MACH_SEND_TIMEOUT with MACH_MSG_TIMEOUT_NONE). This is a
// small and simple message and the destination ports queue should be empty
// so a non-blocking send should be successful.
kr = mach_msg(&send_message.header,
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
send_message.header.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg");
struct ReceiveMessage : public SendMessage {
mach_msg_trailer_t trailer;
};
ReceiveMessage receive_message;
memset(&receive_message, 0xa5, sizeof(receive_message));
kr = mach_msg(&receive_message.header,
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0,
sizeof(receive_message),
server_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg");
EXPECT_EQ(sizeof(send_message), receive_message.header.msgh_size);
EXPECT_EQ(0, memcmp(receive_message.data, kMessageData, message_data_size));
// Make sure that the bootstrap servers mapping disappears if the service
// does.
server_port_owner.reset();
server_port = MACH_PORT_NULL;
// With the server port gone, the client port should have become a dead name.
mach_port_type_t client_port_type;
kr = mach_port_type(mach_task_self(), client_port, &client_port_type);
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_type");
EXPECT_EQ(MACH_PORT_TYPE_DEAD_NAME, client_port_type);
client_port_owner.reset();
client_port = MACH_PORT_NULL;
kr = bootstrap_look_up(bootstrap_port, service_name.c_str(), &client_port);
ASSERT_EQ(BOOTSTRAP_UNKNOWN_SERVICE, kr)
<< BootstrapErrorMessage(kr, "bootstrap_look_up");
}
} // namespace