Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Interrupting UDP Listener. Compiled using oscpack in Xcode

Tags:

c++

sockets

udp

osc

I have successfully incorporated an UDPreceive function into my application. HOWEVER! I can not figure out how to stop UDP listener from running infinitely. The OSCPack library has a Break() and AsynchronousBreak() built into it, but I have been unable to implement these.

in the udpSocket.cpp file within oscpack:

void Run() //the listener function (WORKING!)
{
    break_ = false; 
    //UDP Listener Code

    void Break()
    {
        break_ = true;
    }
    void AsynchronousBreak()
    {
        break_ = true;
        // Send a termination message to the asynchronous break pipe, so select() will return
        write( breakPipe_[1], "!", 1 );
    }
}

My attempt to call Break() from the packet Listener class doesn't appear to do anything, despite the compiler suggesting that everything is being called correctly:

SocketReceiveMultiplexer s;
s.Break();

Another method that I have tried was to raise an interrupt flag in accordance with the RunUntilSigInt() function. Within the packet listener class:

raise(SIGINT);

but this terminates the whole program, rather than just breaking from the UDPListener. For reference, here is the RunUntilSigInt() code within udpSocket.cpp:

void SocketReceiveMultiplexer::RunUntilSigInt()
{
    assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
    multiplexerInstanceToAbortWithSigInt_ = this;
    signal( SIGINT, InterruptSignalHandler );
    impl_->Run();
    signal( SIGINT, SIG_DFL );
    multiplexerInstanceToAbortWithSigInt_ = 0;
}

I'm completely stuck on this one, any help/advice will be greatly appreciated.

Thanks, Tom

like image 386
Tom Wilson Avatar asked Sep 19 '14 15:09

Tom Wilson


2 Answers

I know this is a somewhat old question, but I had to overcome this recently and didn't find a good answer online. The model used by oscpack seems to be that they control the infinite Run loop, and you implement everything you want to do inside a class derived from OscPacketListener. If you don't want to do things that way, you need to run the Run loop in a separate thread. It seems in the oscpack 1.1.0 release, there is no internal support for threading anymore. They explain in the CHANGES file for that release that you would need to implement your own threading solution. The Run routine in SocketReceiveMultiplexer never returns, so any code after that call is unreachable. The various Break routines are for controlling the execution of the Run loop from a different thread. In the below example I'm using c++11 <threads> but you can use any threading library you choose to accomplish something similar. In my example, you'll have to

#include <threads>
#include <mutex>

and compile your code with a c++11 compatible compiler. In g++ you would need the -std=c++11 command line argument.

If you start with the receiver example (parsing single messages example) in the SVN, you could change the main() function to be something like

void ListnerThread()
{
    PacketListener listener;
    UdpListeningReceiveSocket s(
            IpEndpointName( IpEndpointName::ANY_ADDRESS, PORT ),
            &listener );
    s.Run();
}

Somewhere else in your code, make a call like

std::thread lt(ListnerThread);

in order to start the listener running. You'll have to create some means of sharing information between your main thread and the listener thread. One simple method is to use a global variable surrounded by a mutex (also global). There are certainly other (better?) ways but this is very easy. Declare these globally (following their example) instead of within the ProcessMessage function:

std::mutex oscMutex;

bool a1;
osc::int32 a2;
float a3;
const char *a4;

Inside the ExamplePacketListener, where they set the variables from the args stream and then make a call to cout you would do something like

oscMutex.lock();
args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage;
oscMutex.unlock();

Just be sure to also lock() and unlock() the mutex in the same way wherever you access those variables elsewhere in your code.

like image 68
matth Avatar answered Nov 12 '22 20:11

matth


This is old, but this is the only page on the web about this issue. In case someone needs oit

Using raise(SIGINT) when i run the listener with RunUntilSigInt() function does the trick for me. It's a quick hack and it is ugly but it goes like this:

        if (std::strcmp(m.AddressPattern(), "/test1") == 0) {

            osc::ReceivedMessageArgumentStream args = m.ArgumentStream();

            osc::int32 a1, a2, a3;
            const char *a4;
            args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage;

            raise(SIGINT);
        }

In this case, i stop the listener when i receive one pack, but you can modify it as you wish.

like image 29
Cagan Arslan Avatar answered Nov 12 '22 21:11

Cagan Arslan