mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-07 06:36:55 +02:00
187 lines
7.0 KiB
Plaintext
187 lines
7.0 KiB
Plaintext
// Copyright (c) 2007, Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#import "OnDemandServer.h"
|
|
|
|
#import "Breakpad.h"
|
|
#include "common/mac/bootstrap_compat.h"
|
|
|
|
#if DEBUG
|
|
#define PRINT_MACH_RESULT(result_, message_) \
|
|
printf(message_"%s (%d)\n", mach_error_string(result_), result_ );
|
|
#if defined(MAC_OS_X_VERSION_10_5) && \
|
|
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
|
|
#define PRINT_BOOTSTRAP_RESULT(result_, message_) \
|
|
printf(message_"%s (%d)\n", bootstrap_strerror(result_), result_ );
|
|
#else
|
|
#define PRINT_BOOTSTRAP_RESULT(result_, message_) \
|
|
PRINT_MACH_RESULT(result_, message_)
|
|
#endif
|
|
#else
|
|
#define PRINT_MACH_RESULT(result_, message_)
|
|
#define PRINT_BOOTSTRAP_RESULT(result_, message_)
|
|
#endif
|
|
|
|
//==============================================================================
|
|
OnDemandServer *OnDemandServer::Create(const char *server_command,
|
|
const char *service_name,
|
|
bool unregister_on_cleanup,
|
|
kern_return_t *out_result) {
|
|
OnDemandServer *server = new OnDemandServer();
|
|
|
|
if (!server) return NULL;
|
|
|
|
kern_return_t result = server->Initialize(server_command,
|
|
service_name,
|
|
unregister_on_cleanup);
|
|
|
|
if (out_result) {
|
|
*out_result = result;
|
|
}
|
|
|
|
if (result == KERN_SUCCESS) {
|
|
return server;
|
|
}
|
|
|
|
delete server;
|
|
return NULL;
|
|
};
|
|
|
|
//==============================================================================
|
|
kern_return_t OnDemandServer::Initialize(const char *server_command,
|
|
const char *service_name,
|
|
bool unregister_on_cleanup) {
|
|
unregister_on_cleanup_ = unregister_on_cleanup;
|
|
|
|
mach_port_t self_task = mach_task_self();
|
|
|
|
mach_port_t bootstrap_port;
|
|
kern_return_t kr = task_get_bootstrap_port(self_task, &bootstrap_port);
|
|
if (kr != KERN_SUCCESS) {
|
|
PRINT_MACH_RESULT(kr, "task_get_bootstrap_port(): ");
|
|
return kr;
|
|
}
|
|
|
|
mach_port_t bootstrap_subset_port;
|
|
kr = bootstrap_subset(bootstrap_port, self_task, &bootstrap_subset_port);
|
|
if (kr != BOOTSTRAP_SUCCESS) {
|
|
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_subset(): ");
|
|
return kr;
|
|
}
|
|
|
|
// The inspector will be invoked with its bootstrap port set to the subset,
|
|
// but the sender will need access to the original bootstrap port. Although
|
|
// the original port is the subset's parent, bootstrap_parent can't be used
|
|
// because it requires extra privileges. Stash the original bootstrap port
|
|
// in the subset by registering it under a known name. The inspector will
|
|
// recover this port and set it as its own bootstrap port in Inspector.mm
|
|
// Inspector::ResetBootstrapPort.
|
|
kr = breakpad::BootstrapRegister(
|
|
bootstrap_subset_port,
|
|
const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT),
|
|
bootstrap_port);
|
|
if (kr != BOOTSTRAP_SUCCESS) {
|
|
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_register(): ");
|
|
return kr;
|
|
}
|
|
|
|
kr = bootstrap_create_server(bootstrap_subset_port,
|
|
const_cast<char*>(server_command),
|
|
geteuid(), // server uid
|
|
true,
|
|
&server_port_);
|
|
if (kr != BOOTSTRAP_SUCCESS) {
|
|
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_create_server(): ");
|
|
return kr;
|
|
}
|
|
|
|
strlcpy(service_name_, service_name, sizeof(service_name_));
|
|
|
|
// Create a service called service_name, and return send rights to
|
|
// that port in service_port_.
|
|
kr = bootstrap_create_service(server_port_,
|
|
const_cast<char*>(service_name),
|
|
&service_port_);
|
|
if (kr != BOOTSTRAP_SUCCESS) {
|
|
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_create_service(): ");
|
|
|
|
// perhaps the service has already been created - try to look it up
|
|
kr = bootstrap_look_up(bootstrap_port, (char*)service_name, &service_port_);
|
|
|
|
if (kr != BOOTSTRAP_SUCCESS) {
|
|
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_look_up(): ");
|
|
Unregister(); // clean up server port
|
|
return kr;
|
|
}
|
|
}
|
|
|
|
return KERN_SUCCESS;
|
|
}
|
|
|
|
//==============================================================================
|
|
OnDemandServer::~OnDemandServer() {
|
|
if (unregister_on_cleanup_) {
|
|
Unregister();
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
void OnDemandServer::LaunchOnDemand() {
|
|
// We need to do this, since the launched server is another process
|
|
// and holding on to this port delays launching until the current process
|
|
// exits!
|
|
mach_port_deallocate(mach_task_self(), server_port_);
|
|
server_port_ = MACH_PORT_DEAD;
|
|
|
|
// Now, the service is still registered and all we need to do is send
|
|
// a mach message to the service port in order to launch the server.
|
|
}
|
|
|
|
//==============================================================================
|
|
void OnDemandServer::Unregister() {
|
|
if (service_port_ != MACH_PORT_NULL) {
|
|
mach_port_deallocate(mach_task_self(), service_port_);
|
|
service_port_ = MACH_PORT_NULL;
|
|
}
|
|
|
|
if (server_port_ != MACH_PORT_NULL) {
|
|
// unregister the service
|
|
kern_return_t kr = breakpad::BootstrapRegister(server_port_,
|
|
service_name_,
|
|
MACH_PORT_NULL);
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
PRINT_MACH_RESULT(kr, "Breakpad UNREGISTER : bootstrap_register() : ");
|
|
}
|
|
|
|
mach_port_deallocate(mach_task_self(), server_port_);
|
|
server_port_ = MACH_PORT_NULL;
|
|
}
|
|
}
|