Esempio n. 1
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;
}