gecko/ipc/glue/ProtocolUtils.cpp
Ryan VanderMeulen 7189c91e41 Backed out 10 changesets (bug 1033358, bug 774388, bug 1028383) for causing frequent shutdown crashes on a CLOSED TREE.
Backed out changeset a54b05c9e4a1 (bug 1028383)
Backed out changeset 37985f79e0c2 (bug 774388)
Backed out changeset d07521729077 (bug 774388)
Backed out changeset 9f14b17f358c (bug 774388)
Backed out changeset 2d347d6aa9bc (bug 774388)
Backed out changeset 99581dfb5ec4 (bug 774388)
Backed out changeset 2532e22d6135 (bug 774388)
Backed out changeset 719844108f1a (bug 774388)
Backed out changeset 7829c78348a4 (bug 1033358)
Backed out changeset c571df9a85de (bug 1033358)
2014-07-03 20:37:05 -04:00

204 lines
6.3 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/process_util.h"
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/Transport.h"
using namespace base;
using namespace IPC;
namespace mozilla {
namespace ipc {
IToplevelProtocol::~IToplevelProtocol()
{
mOpenActors.clear();
}
void IToplevelProtocol::AddOpenedActor(IToplevelProtocol* aActor)
{
#ifdef DEBUG
for (const IToplevelProtocol* actor = mOpenActors.getFirst();
actor;
actor = actor->getNext()) {
NS_ASSERTION(actor != aActor,
"Open the same protocol for more than one time");
}
#endif
mOpenActors.insertBack(aActor);
}
IToplevelProtocol*
IToplevelProtocol::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
base::ProcessHandle aPeerProcess,
ProtocolCloneContext* aCtx)
{
NS_NOTREACHED("Clone() for this protocol actor is not implemented");
return nullptr;
}
void
IToplevelProtocol::CloneOpenedToplevels(IToplevelProtocol* aTemplate,
const InfallibleTArray<ProtocolFdMapping>& aFds,
base::ProcessHandle aPeerProcess,
ProtocolCloneContext* aCtx)
{
for (IToplevelProtocol* actor = aTemplate->GetFirstOpenedActors();
actor;
actor = actor->getNext()) {
IToplevelProtocol* newactor = actor->CloneToplevel(aFds, aPeerProcess, aCtx);
AddOpenedActor(newactor);
}
}
class ChannelOpened : public IPC::Message
{
public:
ChannelOpened(TransportDescriptor aDescriptor,
ProcessId aOtherProcess,
ProtocolId aProtocol)
: IPC::Message(MSG_ROUTING_CONTROL, // these only go to top-level actors
CHANNEL_OPENED_MESSAGE_TYPE,
PRIORITY_NORMAL)
{
IPC::WriteParam(this, aDescriptor);
IPC::WriteParam(this, aOtherProcess);
IPC::WriteParam(this, static_cast<uint32_t>(aProtocol));
}
static bool Read(const IPC::Message& aMsg,
TransportDescriptor* aDescriptor,
ProcessId* aOtherProcess,
ProtocolId* aProtocol)
{
void* iter = nullptr;
if (!IPC::ReadParam(&aMsg, &iter, aDescriptor) ||
!IPC::ReadParam(&aMsg, &iter, aOtherProcess) ||
!IPC::ReadParam(&aMsg, &iter, reinterpret_cast<uint32_t*>(aProtocol))) {
return false;
}
aMsg.EndRead(iter);
return true;
}
};
bool
Bridge(const PrivateIPDLInterface&,
MessageChannel* aParentChannel, ProcessHandle aParentProcess,
MessageChannel* aChildChannel, ProcessHandle aChildProcess,
ProtocolId aProtocol, ProtocolId aChildProtocol)
{
ProcessId parentId = GetProcId(aParentProcess);
ProcessId childId = GetProcId(aChildProcess);
if (!parentId || !childId) {
return false;
}
TransportDescriptor parentSide, childSide;
if (!CreateTransport(aParentProcess, aChildProcess,
&parentSide, &childSide)) {
return false;
}
if (!aParentChannel->Send(new ChannelOpened(parentSide,
childId,
aProtocol)) ||
!aChildChannel->Send(new ChannelOpened(childSide,
parentId,
aChildProtocol))) {
CloseDescriptor(parentSide);
CloseDescriptor(childSide);
return false;
}
return true;
}
bool
Open(const PrivateIPDLInterface&,
MessageChannel* aOpenerChannel, ProcessHandle aOtherProcess,
Transport::Mode aOpenerMode,
ProtocolId aProtocol, ProtocolId aChildProtocol)
{
bool isParent = (Transport::MODE_SERVER == aOpenerMode);
ProcessHandle thisHandle = GetCurrentProcessHandle();
ProcessHandle parentHandle = isParent ? thisHandle : aOtherProcess;
ProcessHandle childHandle = !isParent ? thisHandle : aOtherProcess;
ProcessId parentId = GetProcId(parentHandle);
ProcessId childId = GetProcId(childHandle);
if (!parentId || !childId) {
return false;
}
TransportDescriptor parentSide, childSide;
if (!CreateTransport(parentHandle, childHandle,
&parentSide, &childSide)) {
return false;
}
Message* parentMsg = new ChannelOpened(parentSide, childId, aProtocol);
Message* childMsg = new ChannelOpened(childSide, parentId, aChildProtocol);
nsAutoPtr<Message> messageForUs(isParent ? parentMsg : childMsg);
nsAutoPtr<Message> messageForOtherSide(!isParent ? parentMsg : childMsg);
if (!aOpenerChannel->Echo(messageForUs.forget()) ||
!aOpenerChannel->Send(messageForOtherSide.forget())) {
CloseDescriptor(parentSide);
CloseDescriptor(childSide);
return false;
}
return true;
}
bool
UnpackChannelOpened(const PrivateIPDLInterface&,
const Message& aMsg,
TransportDescriptor* aTransport,
ProcessId* aOtherProcess,
ProtocolId* aProtocol)
{
return ChannelOpened::Read(aMsg, aTransport, aOtherProcess, aProtocol);
}
void
ProtocolErrorBreakpoint(const char* aMsg)
{
// Bugs that generate these error messages can be tough to
// reproduce. Log always in the hope that someone finds the error
// message.
printf_stderr("IPDL protocol error: %s\n", aMsg);
}
void
FatalError(const char* aProtocolName, const char* aMsg,
ProcessHandle aHandle, bool aIsParent)
{
ProtocolErrorBreakpoint(aMsg);
nsAutoCString formattedMessage("IPDL error [");
formattedMessage.AppendASCII(aProtocolName);
formattedMessage.AppendLiteral("]: \"");
formattedMessage.AppendASCII(aMsg);
if (aIsParent) {
formattedMessage.AppendLiteral("\". Killing child side as a result.");
NS_ERROR(formattedMessage.get());
if (aHandle != kInvalidProcessHandle &&
!base::KillProcess(aHandle, base::PROCESS_END_KILLED_BY_USER, false)) {
NS_ERROR("May have failed to kill child!");
}
} else {
formattedMessage.AppendLiteral("\". abort()ing as a result.");
NS_RUNTIMEABORT(formattedMessage.get());
}
}
} // namespace ipc
} // namespace mozilla