WOscStreamingClient.cpp

OSC client using TCP transport.

/* WOscStreamingClient.cpp - A streaming OSC client using posix threads and sockets
 *
 *  Created on: Apr 21, 2010
 *      Author: uli
 *
 */

#include "WOscConfig.h"

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

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

#include "WOscTcpClient.h"

static bool
resolve(struct in_addr& ia, const char* host)
{
    struct hostent* h = gethostbyname (host);
    if (h == NULL) {
        return false;
    }

    for (int i = 0; h->h_addr_list[i]; i++) {
        if (h->h_addrtype == AF_INET) {
            /* A records (IPv4) */
            if ((unsigned int) h->h_length > sizeof(ia)) {
                // Address size mismatch
                continue;
            }
            memcpy (&ia, h->h_addr_list[i], h->h_length);
            return true;
        }
    }
    return false;
}

class WOscStreamingClient: public WOscTcpClient
{
public:
    WOscStreamingClient(bool threading) : WOscTcpClient(threading)
    {

    }
    virtual void HandleNonmatchedMessages(const WOscMessage* msg,
                const WOscNetReturn* networkReturnAddress)
    {
        std::cout<<msg->GetOscAddress()<<":\n"<<std::endl;
        for ( int i = msg->GetNumInts()-1; i >= 0; i-- )
            std::cout<<"int["<<i<<"]: "<<msg->GetInt(i)<<std::endl;
        for ( int i = msg->GetNumStrings()-1; i >= 0; i-- )
            std::cout<<"str["<<i<<"]: "<<msg->GetString(i)<<std::endl;
        for ( int i = msg->GetNumFloats()-1; i >= 0; i-- )
            std::cout<<"flt["<<i<<"]: "<<msg->GetFloat(i)<<std::endl;
    }
};

const char* WOSC_TCP_CLIENT_HELP_STR =
        "\n"
        " WOscTcpClient, Copyright 2004-2010 Uli Franke\n"
        "\n"
        " Invoking \"wosctcpclient\":\n"
        " woscclient <server url> <server port>\n"
        "\n"
        " Commands controlling \"woscclient\":\n"
        "\n"
        " exit           Terminate \"woscclient\".\n"
        "\n"
        " /[msg] [prms]  Send an OSC message \"/msg\" to remote OSC server with\n"
        "                  parameters [params]. [params] 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;
    bool threading = false;
    WOscStreamingClient client(threading);

    //
    // Setup OSC address space
    //

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

    // "root" methods
    WOscMethod* msgEcho = new WOscTcpHandlerMethod(cntRoot, &client, "printed", "printed description.");
    msgEcho->AddMethodAlias(cntTest, "echo");

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

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

    client.SetAddressSpace(cntRoot);

    WOscString addressSpaceStr = cntRoot->GetAddressSpace();
    std::cout<<"Client address space:\n"<<addressSpaceStr.GetBuffer()<<std::flush;

    //
    // Connect to server
    //

    TheNetReturnAddress serverAddress;
    serverAddress.m_addr.sin_family = AF_INET;
    serverAddress.m_addr.sin_port = htons(default_serverport);
    if ( resolve(serverAddress.m_addr.sin_addr, default_serverurl) ) {
        std::cout<<"Resolved \""<<default_serverurl<<"\" successfully."<<std::endl;
    } else {
        std::cout<<"Failed to resolve \""<<default_serverurl<<"\". Defaulting to 127.0.0.1"<<std::endl;
        default_serverurl = "127.0.0.1";
        serverAddress.m_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    }
    std::cout<<"Connecting to \""<<default_serverurl<<"\" ("<<*inet_ntoa(serverAddress.m_addr.sin_addr) <<")."<<std::endl;

    WOscTcpClient::Error clientError = client.Connect(serverAddress);
    if ( clientError != WOscTcpClient::WOS_ERR_NO_ERROR ) {
        std::cout<<"Client connect failed with: "<<WOscTcpClient::GetErrStr(clientError)<<std::endl;
        return -1;
    }

    std::cout<<"Connected. Entering mainloop."<<std::endl;

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

    while ( true ) {
        char input[1024];
        if ( threading ) {
            std::cin.getline(input,1024,'\n');
        } else {

            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(client.GetSocketID()+1, &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 ( 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 {
            // exit command
            if ( strcmp("exit",input) == 0 ) {
                break;
            }
            // help command
            else if ( strcmp("help",input) == 0 ) {
//              std::cout << WOSC_CLIENT_HELP_STR ;
            }
            // set local port (slp)
            else if  ( strncmp("slp",input,3) == 0 ) {
                /*
                localport = atoi( &input[4] );
                std::cout << "  Trying to set local port to " << localport << "."<<std::endl ;
                client.NetworkHalt();
                if ( client.NetworkInit( localport ) != WOscClient::WOS_ERR_NO_ERROR ) {
                    std::cout << "Exit."<<std::endl ;
                    return -1;
                }
                std::cout << "  Port successfully changed and network restarted."<<std::endl ;
                */
            }
            // set remote port (srp)
            else if  ( strncmp("srp",input,3) == 0 ) {
                /*
                remoteport = atoi( &input[4] );
                std::cout << "  Remote port set to " << remoteport << "."<<std::endl ;
                */
            }
            // set remote IP (srip)
            else if  ( strncmp("srip",input,4) == 0 ) {
                /*
                strcpy(remoteIP, &input[5]);
                std::cout << "  Remote IP set to " << remoteIP << "."<<std::endl ;
                */
            }
        }
    }

    clientError = client.Close();
    if ( clientError != WOscTcpClient::WOS_ERR_NO_ERROR ) {
        std::cout<<"Client close failed with: "<<WOscTcpClient::GetErrStr(clientError)<<std::endl;
        return -1;
    }

    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 "WOscStreamingClient 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