WOscStreamingServer.cpp

OSC server using TCP transport.

/*
 * WOscStreamingServer.cpp - A streaming OSC server using posix threads and sockets
 *
 *  Created on: Oct 22, 2010
 *      Author: uli
 *
 */

#include "WOscConfig.h"

#if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1

#include <iostream>
#include <arpa/inet.h>

#include "WOscTcpServer.h"

static void
msgPrint(const WOscMessage* msg)
{
    int nI = msg->GetNumInts(), nS = msg->GetNumStrings(), nF = msg->GetNumFloats();
    std::cout<<msg->GetOscAddress()<<(nI+nS+nF>0?":\n":"\n");
    for ( int i = nI-1; i >= 0; i-- )
        std::cout<<"int["<<i<<"]: "<<msg->GetInt(i)<<std::endl;
    for ( int i = nS-1; i >= 0; i-- )
        std::cout<<"str["<<i<<"]: "<<msg->GetString(i)<<std::endl;
    for ( int i = nF-1; i >= 0; i-- )
        std::cout<<"flt["<<i<<"]: "<<msg->GetFloat(i)<<std::endl;
}

class WOscStreamingHandler;

class WOscTcpHandlerPrintMethod: public WOscTcpHandlerMethod {
public:
    WOscTcpHandlerPrintMethod(WOscContainer* parent, WOscTcpHandler* receiverContext) :
                WOscTcpHandlerMethod(parent, receiverContext, "print", "I will just print to stdout.") {
    }
protected:
    virtual void Method(const WOscMessage *message) {
        msgPrint(message);
    }
};

class WOscTcpHandlerEchoMethod: public WOscTcpHandlerMethod {
public:
    WOscTcpHandlerEchoMethod(WOscContainer* parent, WOscTcpHandler* receiverContext) :
                WOscTcpHandlerMethod(parent, receiverContext, "echo", "I will return the message to its origin.") {
    }
protected:
    virtual void Method(const WOscMessage *message) {
        msgPrint(message);
        WOscMessage msg(message);
        GetContext()->NetworkSend(msg.GetBuffer(), msg.GetBufferLen());
    }
};

class WOscStreamingHandler: public WOscTcpServerHandler
{
public:
    WOscStreamingHandler(WOscTcpServer* server) : WOscTcpServerHandler(server)
    {
        //
        // Setup OSC address space
        //

        // containers
        WOscContainer* cntRoot = new WOscContainer();
        WOscContainer* cntTest = new WOscContainer(cntRoot, "test");

        // "root" methods
        /*WOscMethod* methodEcho =*/ new WOscTcpHandlerEchoMethod(cntRoot, this);
        WOscMethod* methodPrint = new WOscTcpHandlerPrintMethod(cntRoot, this);
        methodPrint->AddMethodAlias(cntTest, "prt");

        // add alias of method to same container where the original resides (to test the clean up)
        methodPrint->AddMethodAlias(cntTest, "prt2");

        // add alias of container to same container where the original resides (to test the clean up)
        cntTest->AddContainerAlias(cntRoot, "test2");

        SetAddressSpace(cntRoot);

        std::cout<<"Handler's address space:\n"<<cntRoot->GetAddressSpace().GetBuffer()<<std::flush;
    }

    virtual void HandleNonmatchedMessages(const WOscMessage* msg,
                const WOscNetReturn* networkReturnAddress)
    {
        std::cout<<"No handler installed for:"<<std::endl;
        msgPrint(msg);
    }
};

class WOscStreamingServer: public WOscTcpServer
{
public:
    virtual WOscTcpServerHandler::Error SetupHandlerForNewConnection(WOscTcpServerHandler** handler, int socket, const TheNetReturnAddress& peer)
    {
        WOscTcpServerHandler* h = new WOscStreamingHandler(this);
        WOscTcpServerHandler::Error err = h->Start(socket, peer);
        if (err != WOscTcpServerHandler::WOS_ERR_NO_ERROR ) {
            WOSC_ERR_PRT("Starting connection handler failed with "<<err);
            delete h;
        } else {
            *handler = h;
        }
        return err;
    }
};

const char* WOSC_TCP_SERVER_HELP_STR =
        "\n"
        " WOscStreamingServer, Copyright 2004-2010 Uli Franke\n"
        "\n"
        " Invoking \"woscstreamingserver\":\n"
        " woscstreamingserver [server url] [server port]\n"
        "\n"
        " Commands controlling \"woscclient\":\n"
        "\n"
        " exit           Terminate \"woscclient\".\n"
        "\n"
        " /[msg] [prms]  Broadcast an OSC message \"/msg\" to all connected OSC clients\n"
        "                  parameters [prms]. [prms] can be a space separated\n"
        "                  list containing integers ( 666 ), floats ( 3.14 ) and\n"
        "                  strings ( hello_world ).\n"
        "\n"
        " [              Start a bundle (currently no nesting). Messages can be\n"
        "                  added to the bundle afterwards as depicted above.\n"
        " ]              Close a bundle and transmit it.\n"
        "\n";

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>


int main()
{
//  const char* default_serverurl = "localhost";
    short default_serverport = 7554;
    in_addr_t default_serveraddr = INADDR_ANY;
    WOscStreamingServer server;

    WOscStreamingServer::Error err = server.Bind(default_serverport, default_serveraddr);
    if ( err != WOscStreamingServer::WOS_TCPS_ERR_NO_ERR ) {
        std::cout<<"Server bind failed with: "<<WOscTcpServer::GetErrStr(err)<<std::endl;
        return -1;
    }
//  std::cout<<"Listening at ("<<*inet_ntoa(default_serveraddr) <<")."<<std::endl;
    std::cout<<"Listening at port "<<default_serverport<<"."<<std::endl;

    //
    // Main loop
    //
//  WOscBundle theBundle;
//  bool bundleOpen = false;

    while ( true ) {
        char input[1024];

        fd_set rfds;
        struct timeval tv;
        int retval;

        /* Watch stdin (fd 0) to see when it has input. */
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
//          FD_SET(client.GetSocketID(), &rfds);

        /* Wait up to five seconds. */
        tv.tv_sec = 0;
        tv.tv_usec = 0;

        retval = select(FD_SETSIZE, &rfds, NULL, NULL, NULL/*&tv*/);
        /* Don't rely on the value of tv now! */

        if (retval == -1) {
            perror("select()");
            break;
        } else if (retval) {
            if ( FD_ISSET(0, &rfds) ) {
                std::cin.getline(input,1024,'\n');
            /*
            } else if ( FD_ISSET(client.GetSocketID(), &rfds) ) {
                WOscTcpClient::Error err = client.NetworkReceive();
                if ( err == WOscTcpClient::WOS_ERR_NO_ERROR )
                    continue;
                else if ( err == WOscTcpClient::WOS_ERR_CONNECTION_CLOSED ) {
                    std::cout<<"Connection has been closed by peer."<<std::endl;
                    break;
                } else {
                    std::cout<<"Connection failure on receive."<<std::endl;
                    break;
                }
            */
            } else {
                std::cout<<"No file descriptor for this select."<<std::endl;
                break;
            }
        } else {
            printf("Select timeout.\n");
            continue;
        }

#if 0
        if ( input[0] == '/' ) {
            // message assembly
            try {
                // parse parameters
                char* params[100];
                int nParams = 0;
                char* next = strchr ( input, ' ' );
                while ( next != 0 || nParams >= 100 ) {
                    // add parameter to list
                    params[nParams] = next + 1;
                    // and zero-terminate previous
                    *next = 0;
                    // try to find new parameter
                    next = strchr ( params[nParams++], ' ' );
                }

                // assemble message
                WOscMessage msg(input);
                // add parameters
                for ( int i = 0; i < nParams; i++ ) {
                    int parInt = atoi(params[i]);
                    float parFlt = atof(params[i]);
                    // check if float
                    if ( strchr ( params[i], '.' ) ) {
                        msg.Add( parFlt );
                    } else if ( parInt != 0 ) {
                        msg.Add( parInt );
                    } else {
                        msg.Add( params[i] );
                    }
                }
                // we pack message into bundle when open
                if ( bundleOpen ) {
                    theBundle.Add(new WOscMessage(msg));
                } else {
                    clientError = client.NetworkSend(msg.GetBuffer(), msg.GetBufferLen());
                    if ( clientError != WOscTcpClient::WOS_ERR_NO_ERROR ) {
                        std::cout<<"Client transmit failed with: "<<WOscTcpClient::GetErrStr(clientError)<<std::endl;
                        break;
                    }
                }
            } catch(const WOscException& e ) {
                std::cout<<"Exception: " << e.GetErrStr() <<std::endl;
            }
        }
        // open bundle
        else if (input[0] == '[') {
            if ( bundleOpen ) {
                std::cout<<"Bundle already open."<<std::endl;
            } else {
                theBundle.Reset();
                bundleOpen = true;
            }
        }
        // close bundle
        else if (input[0] == ']') {
            if ( bundleOpen ) {
                clientError = client.NetworkSend(theBundle.GetBuffer(), theBundle.GetBufferLen());
                if ( clientError != WOscTcpClient::WOS_ERR_NO_ERROR ) {
                    std::cout<<"Client transmit of bundle failed with: "<<WOscTcpClient::GetErrStr(clientError)<<std::endl;
                    break;
                }
                bundleOpen = false;
            } else {
                std::cout<<"No bundle to close."<<std::endl;
            }
        }
        // other commands
        else
#endif
        {
            // exit command
            if ( strcmp("exit",input) == 0 ) {
                break;
            }
            // help command
            else if ( strcmp("help",input) == 0 ) {
                    std::cout << WOSC_TCP_SERVER_HELP_STR ;
            }
        }
    }
    std::cout<<"Stopping server."<<std::endl;
    err = server.Stop();
    if ( err != WOscTcpServer::WOS_TCPS_ERR_NO_ERR ) {
        std::cout<<"Server stop failed with: "<<WOscTcpServer::GetErrStr(err)<<std::endl;
        return -1;
    }
    std::cout<<"Done."<<std::endl;

    return 0;
}

#elif OS_IS_WIN32 == 1
/* currently this example does not support windows - volunteers?
#   include "windows.h"
#   include "winsock2.h"
#   define socklen_t    int
*/
#   warning "WOscStreamingServer not supported on this platform"
int main() { return 0; }
#endif
Generated on Sat Oct 23 03:05:59 2010 for WOscLib by  doxygen 1.6.3