/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ #include "TestEndpointBridgeMain.h" #include "base/task.h" #include "IPDLUnitTests.h" // fail etc. #include "IPDLUnitTestSubprocess.h" using namespace std; namespace mozilla { namespace _ipdltest { //----------------------------------------------------------------------------- // main process void TestEndpointBridgeMainParent::Main() { if (!SendStart()) { fail("sending Start"); } } mozilla::ipc::IPCResult TestEndpointBridgeMainParent::RecvBridged( Endpoint&& endpoint) { TestEndpointBridgeMainSubParent* a = new TestEndpointBridgeMainSubParent(); if (!endpoint.Bind(a)) { fail("Bind failed"); } return IPC_OK(); } void TestEndpointBridgeMainParent::ActorDestroy(ActorDestroyReason why) { if (NormalShutdown != why) { fail("unexpected destruction!"); } passed("ok"); QuitParent(); } mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHello() { if (!SendHi()) { return IPC_FAIL_NO_REASON(this); } return IPC_OK(); } mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHelloSync() { return IPC_OK(); } mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::AnswerHelloRpc() { if (!CallHiRpc()) { return IPC_FAIL_NO_REASON(this); } return IPC_OK(); } void TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) { if (NormalShutdown != why) { fail("unexpected destruction!"); } // ActorDestroy() is just a callback from IPDL-generated code, // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( do_AddRef(new DeleteTask(this))); } //----------------------------------------------------------------------------- // sub process --- child of main TestEndpointBridgeMainChild* gEndpointBridgeMainChild; TestEndpointBridgeMainChild::TestEndpointBridgeMainChild() : mSubprocess(nullptr) { gEndpointBridgeMainChild = this; } mozilla::ipc::IPCResult TestEndpointBridgeMainChild::RecvStart() { vector subsubArgs; subsubArgs.push_back("TestEndpointBridgeSub"); mSubprocess = new IPDLUnitTestSubprocess(); if (!mSubprocess->SyncLaunch(subsubArgs)) { fail("problem launching subprocess"); } IPC::Channel* transport = mSubprocess->GetChannel(); if (!transport) { fail("no transport"); } TestEndpointBridgeSubParent* bsp = new TestEndpointBridgeSubParent(); bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle())); bsp->Main(); return IPC_OK(); } void TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why) { if (NormalShutdown != why) { fail("unexpected destruction!"); } // NB: this is kosher because QuitChild() joins with the IO thread mSubprocess->Destroy(); mSubprocess = nullptr; QuitChild(); } void TestEndpointBridgeSubParent::Main() { if (!SendPing()) { fail("sending Ping"); } } mozilla::ipc::IPCResult TestEndpointBridgeSubParent::RecvBridgeEm() { Endpoint parent; Endpoint child; nsresult rv; rv = PTestEndpointBridgeMainSub::CreateEndpoints( gEndpointBridgeMainChild->OtherPid(), OtherPid(), &parent, &child); if (NS_FAILED(rv)) { fail("opening PTestEndpointOpensOpened"); } if (!gEndpointBridgeMainChild->SendBridged(std::move(parent))) { fail("SendBridge failed for parent"); } if (!SendBridged(std::move(child))) { fail("SendBridge failed for child"); } return IPC_OK(); } void TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why) { if (NormalShutdown != why) { fail("unexpected destruction!"); } gEndpointBridgeMainChild->Close(); // ActorDestroy() is just a callback from IPDL-generated code, // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( do_AddRef(new DeleteTask(this))); } //----------------------------------------------------------------------------- // subsub process --- child of sub static TestEndpointBridgeSubChild* gBridgeSubChild; TestEndpointBridgeSubChild::TestEndpointBridgeSubChild() { gBridgeSubChild = this; } mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvPing() { if (!SendBridgeEm()) { fail("sending BridgeEm"); } return IPC_OK(); } mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvBridged( Endpoint&& endpoint) { TestEndpointBridgeMainSubChild* a = new TestEndpointBridgeMainSubChild(); if (!endpoint.Bind(a)) { fail("failed to Bind"); } if (!a->SendHello()) { fail("sending Hello"); } return IPC_OK(); } void TestEndpointBridgeSubChild::ActorDestroy(ActorDestroyReason why) { if (NormalShutdown != why) { fail("unexpected destruction!"); } QuitChild(); } mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::RecvHi() { if (!SendHelloSync()) { fail("sending HelloSync"); } if (!CallHelloRpc()) { fail("calling HelloRpc"); } if (!mGotHi) { fail("didn't answer HiRpc"); } // Need to close the channel without message-processing frames on // the C++ stack MessageLoop::current()->PostTask( NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this, &TestEndpointBridgeMainSubChild::Close)); return IPC_OK(); } mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::AnswerHiRpc() { mGotHi = true; // d00d return IPC_OK(); } void TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) { if (NormalShutdown != why) { fail("unexpected destruction!"); } gBridgeSubChild->Close(); // ActorDestroy() is just a callback from IPDL-generated code, // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( do_AddRef(new DeleteTask(this))); } } // namespace _ipdltest } // namespace mozilla