Another example with its header (WOscServer.h):
/** The network return address. Through multiple inheritance this object * inherits the functionality required by WOscLib to keep it alive until * all messages ob a bundle are processed (reference counting) and the * networking data structure which contains the actual ip/port information. * */ class TheNetReturnAddress: public WOscNetReturn { public: TheNetReturnAddress() { memset(&m_addr, 0, sizeof(m_addr)); m_addr.sin_family = AF_INET; } TheNetReturnAddress(const TheNetReturnAddress& rhs) { this->m_addr = rhs.m_addr; } struct sockaddr_in m_addr; TheNetReturnAddress& operator=(const TheNetReturnAddress& rhs) { this->m_addr = rhs.m_addr; return *this; } }; /////////////////////////////////////////////////////////////////////////////// class WOscServer; /** All methods used in WOscServer are derived from this class. In a real * project the methods should be implemented in a header file to inline them * and eliminate the c++ overhead. * * This class avoids some pointer-casting but wouldn't be necessary but makes * all methods used type-save. */ class WOscServerMethod: public WOscReceiverMethod { public: WOscServerMethod( WOscContainer* parent, WOscServer* receiverContext, const char* methodName, const char* methodDescription); virtual void Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress) = 0; virtual WOscServer* GetContext(); protected: virtual void Method( const WOscMessage *message, const WOscTimeTag& when, const WOscNetReturn* networkReturnAddress); }; /////////////////////////////////////////////////////////////////////////////// /** A simple method which prints "hello world" on the console. Furthermore * All parameters send with a "/hello" message are printed on the console. * */ class TheOscHelloMethod: public WOscServerMethod { public: TheOscHelloMethod( WOscContainer* parent, WOscServer* receiverContext); virtual void Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress); }; /////////////////////////////////////////////////////////////////////////////// /** This message sets an exit-request, what results that the main while * loop condition evaluates to false and the application exits. */ class TheOscExitMethod: public WOscServerMethod { public: TheOscExitMethod( WOscContainer* parent, WOscServer* receiverContext); virtual void Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress); }; /////////////////////////////////////////////////////////////////////////////// /** A simple method which prints "hello world" on the console. Furthermore * All parameters send with a "/hello" message are printed on the console. * */ class TheOscEchoMethod: public WOscServerMethod { public: TheOscEchoMethod( WOscContainer* parent, WOscServer* receiverContext); virtual void Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress); }; /////////////////////////////////////////////////////////////////////////////// /** This is the central class which implements a full featured OSC server * including the network-layer implementation. * */ class WOscServer: public WOscReceiver { public: WOscServer(); virtual ~WOscServer(); /** Errors which can occur in the network layer. */ enum WOscServerErrors { WOS_ERR_NO_ERROR = 0, /**< No error. */ WOS_ERR_SOCKET_CREATE = -1, /**< Error when creating the socket. */ WOS_ERR_SOCKET_BIND = -2, /**< Error when binding the local * address and port to the socket. */ WOS_ERR_SOCKET_REUSE = -3, /**< Error when setting the socket- * reuse option. */ WOS_ERR_SOCKET_BROADCAST = -4, /**< Error when setting the socket- * broadcast option. */ WOS_ERR_SOCKET_BLOCK = -5, /**< Error when setting the socket to * the non-blocking mode. */ WOS_ERR_SOCKET_WSASTART = -6, /**< Error when starting the Windoze * winsock subsystem (Windows builds * only). */ }; WOscServerErrors NetworkInit(int port); WOscServerErrors NetworkHalt(); WOscServerErrors CheckForPackets(); bool Exit() const ; void SetExit() ; virtual void NetworkSend( const char* data, int dataLen, const WOscNetReturn* networkReturnAddress); protected: virtual void HandleOffendingPackets( const char* const data, int dataLen, const WOscException& exception); virtual void HandleNonmatchedMessages( const WOscMessage* msg, const WOscNetReturn* networkReturnAddress); private: /** The network address of the server when initialized. */ TheNetReturnAddress m_serverAddr; /** Databuffer for received data. */ char* m_rxbuffer; /** The socket handler of this OSC server. */ int m_hSocket; /** Flag set when termination of the application or server is desired. */ bool m_exit; };
#include "WOscConfig.h" /////////////////////////////////////////////////////////////////////////////// // OS dependent includes /////////////////////////////////////////////////////////////////////////////// #if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1 # include <unistd.h> // usleep # include <fcntl.h> # include <netinet/in.h> # include <arpa/inet.h> # include <sys/socket.h> #elif OS_IS_WIN32 == 1 # include "windows.h" # include "winsock2.h" # define socklen_t int #else # error "Invalid Platform" #endif /////////////////////////////////////////////////////////////////////////////// // general includes /////////////////////////////////////////////////////////////////////////////// #include <iostream> #include <stdlib.h> #include <string.h> #include "WOscReceiver.h" #include "WOscNetReturn.h" #include "WOscReceiverMethod.h" #include "WOscServer.h" /////////////////////////////////////////////////////////////////////////////// // defines /////////////////////////////////////////////////////////////////////////////// #define OSC_SERVER_PORT 10000 #define PROTOCOL_UDP 17 #define WOS_MAX_RX_UDP_PACKET 2048 #if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1 socklen_t WOS_SIZE_NRA = sizeof(sockaddr_in); #elif OS_IS_WIN32 == 1 int WOS_SIZE_NRA = sizeof(sockaddr_in); #endif /////////////////////////////////////////////////////////////////////////////// // WOscServerMethod /////////////////////////////////////////////////////////////////////////////// /** Constructor. Initializes WOscReceiverMethod base class. */ WOscServerMethod::WOscServerMethod( WOscContainer* parent, WOscServer* receiverContext, const char* methodName, const char* methodDescription) :WOscReceiverMethod( parent, (WOscReceiver*)receiverContext, methodName, methodDescription) {} /** Type-save access to receiver object, which is owning this object. */ WOscServer* WOscServerMethod::GetContext() { return (WOscServer*)WOscReceiverMethod::GetContext(); } /** Type-save method interface. All methods inherited from this class get * the correct TheNetReturnAddress pointers without caring about the * system below. */ void WOscServerMethod::Method( const WOscMessage *message, const WOscTimeTag& when, const WOscNetReturn* networkReturnAddress) { Method(message, when, (TheNetReturnAddress*)networkReturnAddress); } /////////////////////////////////////////////////////////////////////////////// // TheOscHelloMethod /////////////////////////////////////////////////////////////////////////////// /** Constructor. Sets the method name and info in the base class. */ TheOscHelloMethod::TheOscHelloMethod( WOscContainer* parent, WOscServer* receiverContext) :WOscServerMethod( parent, receiverContext, "hello", "A hello word method.") {} /** The hello method. Prints "Hello World!" and the contents of the message * on the console. */ void TheOscHelloMethod::Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress) { std::cout << "Hello World! This message contains:"<<std::endl ; int nStr = message->GetNumStrings(); int nInt = message->GetNumInts(); int nFlt = message->GetNumFloats(); for (int i = 0; i < nStr; i++ ) std::cout << " str["<<i<<"]\t" << message->GetString(i).GetBuffer() <<std::endl ; for (int i = 0; i < nInt; i++ ) std::cout << " int["<<i<<"]\t" << message->GetInt(i) <<std::endl ; for (int i = 0; i < nFlt; i++ ) std::cout << " flt["<<i<<"]\t" << message->GetFloat(i) <<std::endl ; } /////////////////////////////////////////////////////////////////////////////// // TheOscExitMethod /////////////////////////////////////////////////////////////////////////////// /** Constructor. Sets the method name and info in the base class. */ TheOscExitMethod::TheOscExitMethod( WOscContainer* parent, WOscServer* receiverContext) :WOscServerMethod( parent, receiverContext, "exit", "This method quits WOscServer") {} /** The exit method. Terminates the WOscServer by setting the exit flag. */ void TheOscExitMethod::Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress) { GetContext()->SetExit(); } /////////////////////////////////////////////////////////////////////////////// // TheOscEchoMethod /////////////////////////////////////////////////////////////////////////////// /** Constructor. Sets the method name and info in the base class. */ TheOscEchoMethod::TheOscEchoMethod( WOscContainer* parent, WOscServer* receiverContext) :WOscServerMethod( parent, receiverContext, "echo", "This method echoes the original message back.") {} /** The echo method. Echoes the message back to its origin. The "origin" can be * modified by passing an integer and string parameter with the message. The * integer modifies the return port and the string the return IP. */ void TheOscEchoMethod::Method( const WOscMessage *message, const WOscTimeTag& when, const TheNetReturnAddress* networkReturnAddress) { WOscMessage echoMsg = *message; TheNetReturnAddress ra = *networkReturnAddress; if ( message->GetNumInts() > 0 ) ra.m_addr.sin_port = htons (message->GetInt(0)); if ( message->GetNumStrings() > 0 ) ra.m_addr.sin_addr.s_addr = inet_addr(message->GetString(0).GetBuffer()); std::cout << "Echo to:\n" << "Port: " << ntohs(ra.m_addr.sin_port) << "\n" << "IP: " << inet_ntoa( ra.m_addr.sin_addr ) <<std::endl; GetContext()->NetworkSend( echoMsg.GetBuffer(), echoMsg.GetBufferLen(), &ra); } /////////////////////////////////////////////////////////////////////////////// // WOscServer /////////////////////////////////////////////////////////////////////////////// /** Constructor. Sets up the OSC address space, allocates an UDP receive buffer * and initializes the exit flag to "false". */ WOscServer::WOscServer() { // setup OSC address space // // containers WOscContainer* rootContainer = new WOscContainer(); WOscContainer* etcContainer = new WOscContainer(rootContainer, "etc"); // "root" methods new TheOscHelloMethod( rootContainer, this ); new TheOscExitMethod( rootContainer, this ); new TheOscEchoMethod( rootContainer, this ); // "etc" methods new TheOscHelloMethod( etcContainer, this ); SetAddressSpace(rootContainer); WOscString addressSpaceStr = rootContainer->GetAddressSpace(); std::cout<<"Client address space:\n"<<addressSpaceStr.GetBuffer()<<std::flush; // allocate RX buffer m_rxbuffer = new char[WOS_MAX_RX_UDP_PACKET]; m_exit = false; } /** Destructor. Removes the address space and deallocates the UDP receive * buffer. */ WOscServer::~WOscServer() { // remove address space // WOscContainer* as = GetAddressSpace(); if ( as ) as->RemoveAll(); } /** Checks the exit flag. * \returns * True if application/serve exit is requested. */ bool WOscServer::Exit() const { return m_exit; } /** Sets the exit flag, which is used to check for server termination. */ void WOscServer::SetExit() { m_exit = true; } /** Sends data over the network. * \param data * Pointer to buffer containing the data to be sent. * * \param dataLen * Number of bytes in the data buffer. * * \param networkReturnAddress * The destination network address. */ void WOscServer::NetworkSend( const char* data, int dataLen, const WOscNetReturn* networkReturnAddress) { const TheNetReturnAddress* nra = (const TheNetReturnAddress*)networkReturnAddress; int actSend = sendto( m_hSocket, data, dataLen, 0, (struct sockaddr*)&nra->m_addr, WOS_SIZE_NRA ) ; // check if transmission was successful if ( dataLen != actSend ) std::cout << "Error sending packet."<<std::endl ; } /** Callback for OSC packets which have caused an exception in the OSC * receiver. * \param data * Pointer to buffer containing the packet data. * \param dataLen * Length of the packet data in the buffer. * \exception * Exception that caused this handler to be called. */ void WOscServer::HandleOffendingPackets( const char* const data, int dataLen, const WOscException& exception) { std::cout<<"HandleOffendingPackets."<<std::endl; } /** Callback for messages not matching any address in the local OSC address * space. * \param msg * Message which hasn't been processed. * \param networkReturnAddress * Network origin of the message. */ void WOscServer::HandleNonmatchedMessages( const WOscMessage* msg, const WOscNetReturn* networkReturnAddress) { std::cout<<"HandleNonmatchedMessages."<<std::endl; } /** Initializes the underlying UDP network layer. * \param port * Port at which WOscServer should listen for OSC data. * \returns * Error code on error, WOS_ERR_NO_ERROR on success. */ WOscServer::WOscServerErrors WOscServer::NetworkInit(int port) { int err; const int REUSE_TRUE = 1, BROADCAST_TRUE = 1; #if OS_IS_WIN32 == 1 // fucking windows winsock startup WSADATA wsa; err = WSAStartup(MAKEWORD(2,0),&wsa); if ( err != 0 ) { std::cout << "Error starting Windows socket subsystem."<<std::endl ; return WOS_ERR_SOCKET_WSASTART; } #endif // #if OS_IS_WIN32 == 1 // create socket m_hSocket = socket (AF_INET, SOCK_DGRAM, PROTOCOL_UDP); if (m_hSocket < 0) { std::cout << "Create socket error."<<std::endl; return WOS_ERR_SOCKET_CREATE; } // initialize server address to localhost:port m_serverAddr.m_addr.sin_family = AF_INET; m_serverAddr.m_addr.sin_addr.s_addr = htonl (INADDR_ANY); m_serverAddr.m_addr.sin_port = htons (port); // set socket to reuse the address err = setsockopt( m_hSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&REUSE_TRUE, sizeof(REUSE_TRUE)); if ( err != 0 ) { std::cout << "Error setting socket reuse."<<std::endl ; return WOS_ERR_SOCKET_REUSE; } // enable broadcasting for this socket setsockopt( m_hSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&BROADCAST_TRUE, sizeof(BROADCAST_TRUE)); if ( err != 0 ) { std::cout << "Error setting socket broadcast."<<std::endl ; return WOS_ERR_SOCKET_BROADCAST; } // disable blocking, polling is used in this example. #if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1 err = fcntl(m_hSocket, F_SETFL, O_NONBLOCK); #elif OS_IS_WIN32 == 1 // disable blocking (for this example) unsigned long val = 1; err = ioctlsocket(m_hSocket, FIONBIO , &val); #endif if ( err != 0 ) { std::cout << "Error setting socket unblock."<<std::endl ; return WOS_ERR_SOCKET_BLOCK; } // bind for listening err = bind ( m_hSocket, (struct sockaddr *)&m_serverAddr.m_addr, WOS_SIZE_NRA ); if ( err != 0 ) { std::cout << "Error socket bind."<<std::endl ; return WOS_ERR_SOCKET_BIND; } return WOS_ERR_NO_ERROR; } /** Stops the network interface. * \returns * WOS_ERR_NO_ERROR on success. */ WOscServer::WOscServerErrors WOscServer::NetworkHalt() { // close socket... #if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1 close(m_hSocket); #elif OS_IS_WIN32 == 1 closesocket(m_hSocket); WSACleanup(); #endif return WOS_ERR_NO_ERROR; } /** Check if there is an UDP packet. On packet arrival it will be passed * to the OSC receiver. It returns if there are no more packets available. * \returns * WOS_ERR_NO_ERROR if no error occurred. */ WOscServer::WOscServerErrors WOscServer::CheckForPackets() { // as long there are packets waiting bool morePackets = 1; while(morePackets) { // has to be allocated on heap, because is reference // counted TheNetReturnAddress* nra = new TheNetReturnAddress; nra->m_addr.sin_family = AF_INET; nra->m_addr.sin_addr.s_addr = htonl (INADDR_ANY); nra->m_addr.sin_port = htons (0); // receive from network int nReceived = recvfrom( m_hSocket, m_rxbuffer, WOS_MAX_RX_UDP_PACKET, 0, (struct sockaddr*)&nra->m_addr, (socklen_t*)&WOS_SIZE_NRA); // nReceived is the number of bytes actually read from // network interface if (nReceived > 0) { NetworkReceive ( m_rxbuffer, nReceived, nra); } else { delete nra; morePackets = false; // stop receiving process } } return WOS_ERR_NO_ERROR; } /////////////////////////////////////////////////////////////////////////////// // main /////////////////////////////////////////////////////////////////////////////// /** The program's main function. The user can pass a port number at which * the OSC server starts listening. */ int main(int argc, char *argv[]) { int port = OSC_SERVER_PORT; if ( argc > 1 ) { port = atoi( argv[1] ); } #if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1 std::cout << "WOscServer 1.00 (UNIX/POSIX build).\n" ; #elif OS_IS_WIN32 == 1 std::cout << "WOscServer 1.00 (Windows build)."<<std::endl ; #endif // the one and only server object WOscServer server; std::cout << "Initializing Network Layer (port: " << port << ")"<<std::endl ; if ( server.NetworkInit( port ) != WOscServer::WOS_ERR_NO_ERROR ) { std::cout << "Exit."<<std::endl ; return -1; } std::cout << "Entering main loop and waiting for OSC packets..."<<std::endl ; // run osc server as long the "exit" flag isn't set. while ( ! server.Exit() ) { server.CheckForPackets(); // poll for new packets every millisecond // (this demo is non-blocking) #if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1 usleep(1000); #elif OS_IS_WIN32 == 1 Sleep(1); #endif } // stop network layer server.NetworkHalt(); std::cout << "Exiting. Bye." << std::endl ; return 0; }