Beispiel #1
0
static already_AddRefed<SharedMemory>
ReadSegment(const IPC::Message& aDescriptor, Shmem::id_t* aId, size_t* aNBytes, size_t aExtraSize)
{
  if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
    NS_ERROR("expected 'shmem created' message");
    return nullptr;
  }
  SharedMemory::SharedMemoryType type;
  PickleIterator iter(aDescriptor);
  if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, aNBytes, &type)) {
    return nullptr;
  }
  RefPtr<SharedMemory> segment = NewSegment(type);
  if (!segment) {
    return nullptr;
  }
  if (!segment->ReadHandle(&aDescriptor, &iter)) {
    NS_ERROR("trying to open invalid handle");
    return nullptr;
  }
  aDescriptor.EndRead(iter);
  size_t size = SharedMemory::PageAlignedSize(*aNBytes + aExtraSize);
  if (!segment->Map(size)) {
    return nullptr;
  }
  // close the handle to the segment after it is mapped
  segment->CloseHandle();
  return segment.forget();
}
Beispiel #2
0
/* static */
already_AddRefed<nsIEventTarget>
nsIContentChild::GetConstructedEventTarget(const IPC::Message& aMsg)
{
  ActorHandle handle;
  TabId tabId, sameTabGroupAs;
  PickleIterator iter(aMsg);
  if (!IPC::ReadParam(&aMsg, &iter, &handle)) {
    return nullptr;
  }
  aMsg.IgnoreSentinel(&iter);
  if (!IPC::ReadParam(&aMsg, &iter, &tabId)) {
    return nullptr;
  }
  aMsg.IgnoreSentinel(&iter);
  if (!IPC::ReadParam(&aMsg, &iter, &sameTabGroupAs)) {
    return nullptr;
  }

  // If sameTabGroupAs is non-zero, then the new tab will be in the same
  // TabGroup as a previously created tab. Rather than try to find the
  // previously created tab (whose constructor message may not even have been
  // processed yet, in theory) and look up its event target, we just use the
  // default event target. This means that runnables for this tab will not be
  // labeled. However, this path is only taken for print preview and view
  // source, which are not performance-sensitive.
  if (sameTabGroupAs) {
    return nullptr;
  }

  // If the request for a new TabChild is coming from the parent process, then
  // there is no opener. Therefore, we create a fresh TabGroup.
  RefPtr<TabGroup> tabGroup = new TabGroup();
  nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
  return target.forget();
}
Beispiel #3
0
bool Process::Send(uint32_t id, uint32_t size, const uint8_t* data)
{
    // mutex from kill
    Helium::MutexScopeLock mutex ( m_KillMutex );

    if ( m_Connection && m_Connection->GetState() == IPC::ConnectionStates::Active )
    {
        IPC::Message* msg = m_Connection->CreateMessage(id, data ? size : 0);

        if (data && size)
        {
            memcpy(msg->GetData(), data, size);
        }

        if (m_Connection->Send(msg) == IPC::ConnectionStates::Active)
        {
            return true;
        }
        else
        {
            delete msg;
        }
    }

    return false;
}
Beispiel #4
0
// static
already_AddRefed<Shmem::SharedMemory>
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
                    const IPC::Message& aDescriptor,
                    id_t* aId,
                    bool /*unused*/)
{
  if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
    return nullptr;
  }

  SharedMemory::SharedMemoryType type;
  void* iter = nullptr;
  size_t size;
  if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
    return nullptr;

  nsRefPtr<SharedMemory> segment;
  size_t segmentSize = SharedMemory::PageAlignedSize(size + sizeof(uint32_t));

  if (SharedMemory::TYPE_BASIC == type) {
    SharedMemoryBasic::Handle handle;
    if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
      return nullptr;

    if (!SharedMemoryBasic::IsHandleValid(handle)) {
      return nullptr;
    }

    segment = CreateSegment(segmentSize, handle);
  }
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
  else if (SharedMemory::TYPE_SYSV == type) {
    SharedMemorySysV::Handle handle;
    if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
      return nullptr;

    if (!SharedMemorySysV::IsHandleValid(handle)) {
      return nullptr;
    }
    segment = CreateSegment(segmentSize, handle);
  }
#endif
  else {
    return nullptr;
  }

  if (!segment)
    return nullptr;

  // this is the only validity check done in non-DEBUG builds
  if (size != static_cast<size_t>(*PtrToSize(segment))) {
    return nullptr;
  }

  return segment.forget();
}
Beispiel #5
0
 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;
 }
Beispiel #6
0
// static
already_AddRefed<Shmem::SharedMemory>
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
                    const IPC::Message& aDescriptor,
                    id_t* aId,
                    bool aProtect)
{
  if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
    NS_ERROR("expected 'shmem created' message");
    return nullptr;
  }

  void* iter = nullptr;
  SharedMemory::SharedMemoryType type;
  size_t size;
  if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
    return nullptr;

  nsRefPtr<SharedMemory> segment;
  size_t pageSize = SharedMemory::SystemPageSize();
  // |2*pageSize| is for the front and back sentinels
  size_t segmentSize = SharedMemory::PageAlignedSize(size + 2*pageSize);

  if (SharedMemory::TYPE_BASIC == type) {
    SharedMemoryBasic::Handle handle;
    if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
      return nullptr;

    if (!SharedMemoryBasic::IsHandleValid(handle)) {
      NS_ERROR("trying to open invalid handle");
      return nullptr;
    }
    segment = CreateSegment(segmentSize, handle);
  }
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
  else if (SharedMemory::TYPE_SYSV == type) {
    SharedMemorySysV::Handle handle;
    if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
      return nullptr;

    if (!SharedMemorySysV::IsHandleValid(handle)) {
      NS_ERROR("trying to open invalid handle");
      return nullptr;
    }
    segment = CreateSegment(segmentSize, handle);
  }
#endif
  else {
    NS_ERROR("unknown shmem type");
    return nullptr;
  }

  if (!segment)
    return nullptr;

  Header* header = GetHeader(segment);

  if (size != header->mSize) {
    NS_ERROR("Wrong size for this Shmem!");
    return nullptr;
  }

  // The caller of this function may not know whether the segment is
  // unsafe or not
  if (!header->mUnsafe && aProtect)
    Protect(segment);

  return segment.forget();
}
Beispiel #7
0
bool Host::Process(bool wait)
{
    bool result = true;

    if (Connected())
    {
        if (m_ConnectionCount != m_Connection->GetConnectCount())
        {
#ifdef RPC_DEBUG
            printf("RPC::Connection cycled, resetting stack\n");
#endif
            m_ConnectionCount = m_Connection->GetConnectCount();
            m_Stack.Reset();
        }

        if (m_Connection->GetState() != IPC::ConnectionStates::Active)
        {
            result = false;
        }

        while (result)
        {
            IPC::Message* msg = NULL;
            IPC::ConnectionState state = m_Connection->Receive(&msg, wait);

            if (state != IPC::ConnectionStates::Active || msg == NULL)
            {
                result = false;
                break;
            }

#ifdef RPC_DEBUG_MSG
            printf("RPC::Got message id 0x%08x, size %d, transaction %d\n", msg->GetID(), msg->GetSize(), msg->GetTransaction());
#endif

            bool is_reply = m_Connection->CreatedMessage(msg->GetTransaction());
            if (is_reply && m_Stack.Size() > 0)
            {
                Frame* top = m_Stack.Top();

                bool is_current = msg->GetTransaction() == top->m_ReplyTransaction;
                if (is_current)
                {
#ifdef RPC_DEBUG
                    printf("RPC::Got reply to transaction %d\n", msg->GetTransaction());
#endif

                    // subsume the message into the frame
                    top->m_Replied = true;
                    top->m_ReplyID = msg->GetID();
                    top->m_ReplyData = msg->TakeData();  // taking this will disconnect it from the message, making delete below *safe*
                    top->m_ReplySize = msg->GetSize();

                    // free msg
                    delete msg;

                    // we have our reply, break out of processing messages
                    break;
                }
                else
                {
                    printf("RPC::Got reply to transaction %d, however its not a reply for the top of the stack (stack size: %d)\n", msg->GetTransaction(), m_Stack.Size());
                }
            }
            else // else this is not a reply, meaning this is a new invocation
            {
                int32_t size HELIUM_ASSERT_ONLY = m_Stack.Size();

                // allocate a frame for this local call
                Frame* frame = m_Stack.Push();

                frame->m_ReplyTransaction = msg->GetTransaction();

#ifdef RPC_DEBUG
                printf("RPC::Pushing invocation transaction %d, stack size %d\n", frame->m_ReplyTransaction, m_Stack.Size());
#endif

                // the one and only call to invoke, this expects our frame to be allocated
                if (Invoke(msg))
                {
#ifdef RPC_DEBUG
                    printf("RPC::Popping invocation transaction %d, stack size %d\n", frame->m_ReplyTransaction, m_Stack.Size());
#endif

                    // success, pop the call
                    m_Stack.Pop();

                    HELIUM_ASSERT(size == m_Stack.Size());
                }
                else
                {
                    printf("RPC::Invocation failed, resetting stack\n");
                    m_Stack.Reset();
                }
            }
        }
    }
    else
    {
        result = false;
    }

    return result;
}
Beispiel #8
0
bool Host::Invoke(IPC::Message* msg)
{
#pragma TODO("Unpack the invoker and interface name from the message data")
    const char* invokerName = NULL;
    const char* interfaceName = NULL;

    // find the interface
    Interface* interface = GetInterface(interfaceName);
    if (interface == NULL)
    {
        printf("RPC::Unable to find interface '%s'\n", interfaceName);
        delete msg;
        return true;
    }

    // find the invoker
    Invoker* invoker = interface->GetInvoker(invokerName);
    if (invoker == NULL)
    {
        printf("RPC::Unable to find invoker '%s' in interface '%s'\n", invokerName, interfaceName);
        delete msg;
        return true;
    }

    // get our frame from the top of the stack
    Frame* frame = m_Stack.Top();

    HELIUM_ASSERT(frame->m_Message == NULL);
    frame->m_Message = msg;

    // call the function
    frame->m_MessageTaken = false;
    invoker->Invoke(msg->GetData(), msg->GetSize());

    HELIUM_ASSERT(frame->m_Message != NULL);
    frame->m_Message = NULL;

    Args* args = (Args*)msg->GetData();

    if (args->m_Flags & RPC::Flags::NonBlocking)
    {
        if (!frame->m_MessageTaken)
        {
            delete msg;
        }

        return true; // async call, we are done
    }

    // our reply
    IPC::Message* reply = NULL;

    // if we have data, and a reference args or payload
    if (msg->GetSize() > 0 && args->m_Flags & (RPC::Flags::ReplyWithArgs | RPC::Flags::ReplyWithPayload))
    {
        // total size of reply
        uint32_t size = 0;

        // size of args section
        uint32_t argSize = invoker->GetArgsSize();

        // size of payload section
        uint32_t payload_size = msg->GetSize() - argSize;

        // if we have a ref args
        if (args->m_Flags & RPC::Flags::ReplyWithArgs)
        {
            // alloc for args block
            size += argSize;
        }

        // if we have a ref payload
        if (args->m_Flags & RPC::Flags::ReplyWithPayload)
        {
            // alloc for payload block
            size += payload_size;
        }

        // create message
        reply = Create(invoker, size, msg->GetTransaction());

        // where to write
        uint8_t* ptr = reply->GetData();

        // if we have a ref args
        if (args->m_Flags & RPC::Flags::ReplyWithArgs)
        {
            if (Swizzle())
            {
                invoker->Swizzle( msg->GetData() );
            }

            // write to ptr
            memcpy(ptr, msg->GetData(), argSize);  

            // incr ptr by amount written
            ptr += argSize;
        }

        // if we have a ref payload
        if (args->m_Flags & RPC::Flags::ReplyWithPayload)
        {
            // write to ptr
            memcpy(ptr, msg->GetData() + argSize, payload_size);

            // incr ptr by amount written
            ptr += payload_size;
        }

        // assert we did not overrun message size
        HELIUM_ASSERT((uint32_t)(ptr - reply->GetData()) == size);
    }
    else // no data, or no ref args or payload
    {
        // just create an empty reply, the other side is blocking
        reply = Create(invoker, 0, msg->GetTransaction());
    }

    if (m_Connection->Send(reply)!= IPC::ConnectionStates::Active)
    {
        delete reply;
    }

#ifdef RPC_DEBUG_MSG
    printf("RPC::Put message id 0x%08x, size %d, transaction %d\n", reply->GetID(), reply->GetSize(), reply->GetTransaction());
#endif

    if (!frame->m_MessageTaken)
    {
        delete msg;
    }

    return true;
}
Beispiel #9
0
void Host::Emit(Invoker* invoker, Args* args, uint32_t size, SwizzleFunc swizzler)
{
    if (Connected())
    {
        if (m_ConnectionCount != m_Connection->GetConnectCount())
        {
#ifdef RPC_DEBUG
            printf("RPC::Connection cycled, resetting stack\n");
#endif
            m_ConnectionCount = m_Connection->GetConnectCount();
            m_Stack.Reset();
        }

        uint32_t size = 0;

        if (args != NULL)
        {
            HELIUM_ASSERT(size > 0);
            size += size;
        }

        if (args->m_Payload != NULL)
        {
            HELIUM_ASSERT(args->m_PayloadSize > 0);
            size += args->m_PayloadSize;
        }

        IPC::Message* message = Create(invoker, size);

        uint8_t* ptr = message->GetData();

        if (args != NULL)
        {
            if (Swizzle())
            {
                swizzler(args);
            }

            memcpy(ptr, args, size);
            ptr += size;

            if (Swizzle())
            {
                swizzler(args);
            }
        }

        if (args->m_Payload != NULL)
        {
            memcpy(ptr, args->m_Payload, args->m_PayloadSize);
            ptr += args->m_PayloadSize;
        }

        HELIUM_ASSERT((uint32_t)(ptr - message->GetData()) == size);

#ifdef RPC_DEBUG_MSG
        uint32_t msg_id = message->GetID();
        uint32_t msg_size = message->GetSize();
#endif

        int32_t msg_transaction = message->GetTransaction();
        if (m_Connection->Send(message)!=IPC::ConnectionStates::Active)
        {
            delete message;
            return;
        }

#ifdef RPC_DEBUG_MSG
        printf("RPC::Put message id 0x%08x, size %d, transaction %d\n", msg_id, msg_size, msg_transaction);
#endif

        message = NULL; // assume its GONE

        if (args->m_Flags & RPC::Flags::NonBlocking)
        {
#ifdef RPC_DEBUG
            printf("RPC::Emitting async transaction %d\n", msg_transaction);
#endif
        }
        else
        {
            // create frame for call
            Frame* frame = m_Stack.Push();

            // set the transaction we are blocking on
            frame->m_ReplyTransaction = msg_transaction;

#ifdef RPC_DEBUG
            printf("RPC::Emitting transaction %d, stack size %d\n", msg_transaction, m_Stack.Size());
#endif

            // process until we retrieve it
            frame->m_Replied = false;

            // process messages until we receive our reply
            while (Process(true) && !frame->m_Replied);

            // if we did not get our reply
            if (!frame->m_Replied)
            {
#ifdef RPC_DEBUG
                printf("RPC::Emit failed for transaction %d, stack size %d\n", msg_transaction, m_Stack.Size());
#endif

                // if we didn't reset and the call timed out, pop
                if (m_Stack.Size())
                {
                    m_Stack.Pop();
                }
            }
            else
            {
#ifdef RPC_DEBUG
                printf("RPC::Emit success for transaction %d, stack size %d\n", msg_transaction, m_Stack.Size());
#endif

                size = 0;
                ptr = frame->m_ReplyData;

                if (args != NULL)
                {
                    HELIUM_ASSERT(size > 0);
                    size += size;
                }

                if (args->m_Payload != NULL)
                {
                    HELIUM_ASSERT(args->m_PayloadSize > 0);
                    size += args->m_PayloadSize;
                }

                // do ref args processing here
                if (args->m_Flags & RPC::Flags::ReplyWithArgs && args != NULL)
                {
                    if (Swizzle())
                    {
                        swizzler(ptr);
                    }

                    // copy our data BACK
                    memcpy(args, ptr, size);

                    ptr += size;
                }

                // do ref payload processing here
                if (args->m_Flags & RPC::Flags::ReplyWithPayload && args->m_Payload != NULL)
                {
                    // copy our data BACK
                    memcpy(args->m_Payload, ptr, args->m_PayloadSize);
                    ptr += args->m_PayloadSize;
                }

                // clean up our reply message's memory
                delete[] frame->m_ReplyData;

                // call complete, pop
                m_Stack.Pop();
            }
        }
    }
}