예제 #1
0
파일: RPC.cpp 프로젝트: euler0/Helium
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;
}
예제 #2
0
파일: RPC.cpp 프로젝트: euler0/Helium
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;
}
예제 #3
0
파일: RPC.cpp 프로젝트: euler0/Helium
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();
            }
        }
    }
}