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; }
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; }
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(); } } } }