Boost Message queue Not receiving across two processes

Viewed 600

I wrote a small test app to use the Boos Message_Queue to send data between two processes. That all worked correctly and I was able to print the data that I sent.

I moved my test code into my main project and now the main project is not waking from the Receives. The main project runs as systems so I tracked down one error and saw that the message_queue was not checking the same memory location for some reason. I defined BOOST_INTERPROCESS_SHARED_DIR_PATH and then the main project was able to open the queue created by the test app. But when the test app sends the main project never woke from its receive. The main project should be running as system and the test app as a user. But I figured since it is sharing the memory location it should work correctly?

If I open the queue in the test app again it wakes and receives all of the messages right away. Am I missing something or is this a limitation on BOOST message_queue?

The code from the test app:

MessageQueue::MessageQueue(int, boost::interprocess::permissions perm) :
    mq(boost::interprocess::create_only, "TestChannel", 100, sizeof(QueueData), perm)
{
}

MessageQueue::MessageQueue(bool) :
    mq(boost::interprocess::open_only, "TestChannel")
{
}


MessageQueue::~MessageQueue()
{
    int num = mq.get_num_msg();
    wprintf(_T("sent: %d\n"), num);
     boost::interprocess::message_queue::remove("TestChannel");
}

void MessageQueue::SetCommand(int i)
{
    QueueData qd;
    qd.fakeInfo = i; 
    qd.exit = false;
    CoCreateGuid(&qd.msgGuid);
    mq.send(&qd, sizeof(qd), 0);
    OLECHAR* uidOleStr;
    if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
        throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
    // Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
    CString guidString(uidOleStr);
    CoTaskMemFree(uidOleStr);
    wprintf(_T("sent: %d, %s\n"), qd.fakeInfo, guidString);
}

void MessageQueue::WaitForCommand()
{
    while(true)
    {
        QueueData qd;
        size_t size, pri;
        mq.receive(&qd, sizeof(qd), size, pri);        
        if (qd.fakeInfo == 2)
            sendExit();

        OLECHAR* uidOleStr;
        if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
            throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
        // Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
        CString guidString(uidOleStr);
        CoTaskMemFree(uidOleStr);
        wprintf(_T("Recieved: %d, %s\n"), qd.fakeInfo, guidString);
        if (qd.exit)
            break;
    }
}

void MessageQueue::sendExit()
{
    QueueData qd;
    qd.exit = true;
    mq.send(&qd, sizeof(qd), 0);
    wprintf(_T("Sent Exit"));
}

.h file:

#pragma once
#define BOOST_INTERPROCESS_SHARED_DIR_PATH "C:\\Program Files (x86)\\Users"
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/interprocess/permissions.hpp>


class QueueData
{
public:
    int fakeInfo;
    GUID msgGuid;
    bool exit;
};


class MessageQueue
{
public:
    MessageQueue(int, boost::interprocess::permissions perm);
    MessageQueue(bool);
    ~MessageQueue();

    boost::interprocess::message_queue mq;

    void SetCommand(int);
    void WaitForCommand();
    void sendExit();
};

test app running code: (I have been using breakpoints)

void waiter()
{
    MessageQueue mq(true);

    mq.WaitForCommand();
}

void sender()
{
    boost::interprocess::permissions perm;
    perm.set_unrestricted();
    try
    {
        boost::interprocess::message_queue::remove("TestChannel");
        MessageQueue mq(2, perm);

        mq.SetCommand(1);
        mq.SetCommand(1);
        mq.SetCommand(2);
    }
    catch (boost::interprocess::interprocess_exception e)
    {
    }
}

int main() {

    waiter();

    sender();

}

The code from the main project: (To test I did have it use the wait of the above code and still nothing)

void MemoryChannel::WaitForCmd( const std::function< void ( MemoryChannelCmd cmd, const char *pData, TCHAR *tempPath, GUID msgGuid ) > func )
{
    QueueData mcObject;
    size_t size, pri;
    while (true)
    {
        pMCD->dataQueue.timed_receive(&mcObject, sizeof(mcObject), size, pri, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(30000));
        size_t num = pMCD->dataQueue.get_num_msg();

        //func(MemoryChannelCmd::MEMORY_CHANNEL_RUN_SQL_SELECT, "", _T(""), mcObject.msgGuid);
    }
}

Doesn't seem to be a code issue since it works in the test app but not in the main project even sharing code.

I am at a loss.

1 Answers

For inter-process communication the higher privilege process must start first. Only then can lower privilege processes can connect.

In your example system process should start the queue, test app connects and then they can communicate. This is why it works when restarting the test app.

It's designed this way to prevent lower privilege users to access higher privilege user memory without permission.

Related