class TheNetReturnAddress:
public WOscNetReturn
{
public:
struct sockaddr_in m_addr;
};
class WOscClient;
class WOscClientMethod:
public WOscReceiverMethod
{
public:
WOscClientMethod(
WOscContainer* parent,
WOscClient* receiverContext,
const char* methodName,
const char* methodDescription);
virtual void Method(
const WOscMessage *message,
const WOscTimeTag& when,
const TheNetReturnAddress* networkReturnAddress) = 0;
virtual WOscClient* GetContext();
protected:
virtual void Method(
const WOscMessage *message,
const WOscTimeTag& when,
const WOscNetReturn* networkReturnAddress);
};
class TheOscEchoMethod:
public WOscClientMethod
{
public:
TheOscEchoMethod(
WOscContainer* parent,
WOscClient* receiverContext);
virtual void Method(
const WOscMessage *message,
const WOscTimeTag& when,
const TheNetReturnAddress* networkReturnAddress);
};
class WOscClient:
public WOscReceiver
{
public:
WOscClient();
virtual ~WOscClient();
enum WOscClientErrors
{
WOS_ERR_NO_ERROR = 0,
WOS_ERR_SOCKET_CREATE = -1,
WOS_ERR_SOCKET_BIND = -2,
WOS_ERR_SOCKET_REUSE = -3,
WOS_ERR_SOCKET_BROADCAST = -4,
WOS_ERR_SOCKET_BLOCK = -5,
WOS_ERR_SOCKET_WSASTART = -6,
};
WOscClientErrors NetworkInit(int port);
WOscClientErrors NetworkHalt();
WOscClientErrors 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:
TheNetReturnAddress m_serverAddr;
char* m_rxbuffer;
int m_hSocket;
bool m_exit;
};
#include "config.h"
#if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1
# include <unistd.h>
# 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
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include "WOscReceiver.h"
#include "WOscNetReturn.h"
#include "WOscReceiverMethod.h"
#include "WOscClient.h"
#define OSC_SERVER_PORT 10000
#define PROTOCOL_UDP 17
#define WOS_MAX_RX_UDP_PACKET 2048
const char* WOSC_CLIENT_HELP_STR =
"\n"
" WOscClient 1.00 help\n"
"\n"
" Invoking \"woscclient\":\n"
" woscclient [local port] [remote port] [remote IP]\n"
"\n"
" Commands controlling \"woscclient\":\n"
"\n"
" exit Terminate \"woscclient\".\n"
" slp [port] Set local UDP port to [port]\n"
" srp [port] Set remote server UDP destination port to [port].\n"
" srip [ip] Set remote server UDP destination IP to [ip].\n"
" whereas [ip] is an IP string in dotted decimal notation\n"
" (127.0.0.1).\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";
#if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1
socklen_t WOS_SIZE_NRA = sizeof(sockaddr_in);
#else
int WOS_SIZE_NRA = sizeof(sockaddr_in);
#endif
WOscClientMethod::WOscClientMethod(WOscContainer* parent,
WOscClient* receiverContext, const char* methodName,
const char* methodDescription) :
WOscReceiverMethod(parent, (WOscReceiver*) receiverContext, methodName,
methodDescription)
{
}
WOscClient* WOscClientMethod::GetContext()
{
return (WOscClient*)WOscReceiverMethod::GetContext();
}
void WOscClientMethod::Method(const WOscMessage *message,
const WOscTimeTag& when, const WOscNetReturn* networkReturnAddress)
{
Method(message, when, (TheNetReturnAddress*) networkReturnAddress);
}
TheOscEchoMethod::TheOscEchoMethod(WOscContainer* parent,
WOscClient* receiverContext) :
WOscClientMethod(parent, receiverContext, "echo", "")
{
}
void TheOscEchoMethod::Method(const WOscMessage *message,
const WOscTimeTag& when,
const TheNetReturnAddress* networkReturnAddress)
{
std::cout << "Echo received from:\n"
<< "Port: " << ntohs(networkReturnAddress->m_addr.sin_port) << "\n"
<< "IP: " << inet_ntoa( networkReturnAddress->m_addr.sin_addr ) <<std::endl;
}
WOscClient::WOscClient()
{
WOscContainerInfo infoRoot("root");
WOscContainer* cntRoot = new WOscContainer(&infoRoot);
WOscContainerInfo rootInfo("root");
WOscContainerInfo infoTest("test");
WOscContainer* cntTest = new WOscContainer(&infoTest, cntRoot, "test");
WOscMethod* msgEcho = new TheOscEchoMethod(cntRoot, this);
msgEcho->AddMethodAlias(cntTest, "echo");
msgEcho->AddMethodAlias(cntTest, "echo2");
cntTest->AddContainerAlias(cntRoot, "test2");
SetAddressSpace(cntRoot);
WOscString addressSpaceStr = cntRoot->GetAddressSpace();
std::cout<<"Client address space:\n"<<addressSpaceStr.GetBuffer()<<std::flush;
m_rxbuffer = new char[WOS_MAX_RX_UDP_PACKET];
m_exit = false;
}
WOscClient::~WOscClient()
{
WOscContainer* as = GetAddressSpace();
if ( as ) as->RemoveAll();
}
bool WOscClient::Exit() const
{
return m_exit;
}
void WOscClient::SetExit()
{
m_exit = true;
}
void WOscClient::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 ) ;
if ( dataLen != actSend )
std::cout << "Error sending packet."<<std::endl ;
}
void
WOscClient::HandleOffendingPackets(const char* const data, int dataLen,
const WOscException& exception)
{
std::cout<<"HandleOffendingPackets."<<std::endl;
}
void WOscClient::HandleNonmatchedMessages(
const WOscMessage* msg,
const WOscNetReturn* networkReturnAddress)
{
int nStr = msg->GetNumStrings();
int nInt = msg->GetNumInts();
int nFlt = msg->GetNumFloats();
if ( !nStr && !nInt && !nFlt )
std::cout << "OSC message \"" << msg->GetOscAddress().GetBuffer()
<< "\" received."<< std::endl;
else
std::cout << "OSC message \"" << msg->GetOscAddress().GetBuffer()
<< "\" contains:"<<std::endl;
for (int i = 0; i < nStr; i++ )
std::cout << " str["<<i<<"]\t" <<
msg->GetString(i).GetBuffer()<< std::endl ;
for (int i = 0; i < nInt; i++ )
std::cout << " int["<<i<<"]\t" <<
msg->GetInt(i) << std::endl ;
for (int i = 0; i < nFlt; i++ )
std::cout << " flt["<<i<<"]\t" <<
msg->GetFloat(i) << std::endl ;
}
WOscClient::WOscClientErrors WOscClient::NetworkInit(int port)
{
int err;
const int REUSE_TRUE = 1, BROADCAST_TRUE = 1;
#if OS_IS_WIN32 == 1
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
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;
}
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);
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;
}
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;
}
#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
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;
}
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;
}
WOscClient::WOscClientErrors WOscClient::NetworkHalt()
{
#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;
}
WOscClient::WOscClientErrors WOscClient::CheckForPackets()
{
bool morePackets = 1;
while(morePackets)
{
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);
int nReceived = recvfrom(
m_hSocket,
m_rxbuffer,
WOS_MAX_RX_UDP_PACKET,
0,
(struct sockaddr*)&nra->m_addr,
(socklen_t*)&WOS_SIZE_NRA);
if (nReceived > 0) {
NetworkReceive (m_rxbuffer, nReceived, nra);
#if 1
WOscBundleParser bundleParser;
try {
bundleParser.Parse(m_rxbuffer, nReceived);
std::cout<<"Bundle time: "<<bundleParser.GetTimeTag().GetRawTimeTag()<<", bundle items: "<<bundleParser.GetItemCount()<<std::endl;
} catch (const WOscException& exp) {
std::cout<<"Error parsing raw bundle ("<<exp.GetErrStr()<<")."<<std::endl;
}
#endif
} else {
delete nra;
morePackets = false;
}
}
return WOS_ERR_NO_ERROR;
}
int main(int argc, char *argv[])
{
WOscClient client;
int localport = OSC_SERVER_PORT + 1;
int remoteport = OSC_SERVER_PORT;
char remoteIP[32];
strcpy(remoteIP, "127.0.0.1");
if ( argc > 1 )
localport = atoi( argv[1] );
if ( argc > 2 )
remoteport = atoi( argv[2] );
if ( argc > 3 )
strcpy(remoteIP, argv[3]);
#if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1
std::cout << "WOscClient 1.00 (UNIX/POSIX build)."<<std::endl ;
#elif OS_IS_WIN32 == 1
std::cout << "WOscClient 1.00 (Windows build)."<<std::endl ;
#endif
std::cout << "Setting up network layer:\n" <<
" local port: " << localport << "\n" <<
" remote port: " << remoteport << "\n" <<
" remote IP: " << remoteIP <<std::endl;
if ( client.NetworkInit( localport ) != WOscClient::WOS_ERR_NO_ERROR ) {
std::cout << "Exit."<<std::endl ;
return -1;
}
std::cout << "Please enter some commands..."<<std::endl ;
WOscBundle theBundle;
bool bundleOpen = false;
while ( ! client.Exit() ) {
char input[1024];
std::cin.getline(input,1024,'\n');
if ( input[0] == '/' ) {
try {
char* params[100];
int nParams = 0;
char* next = strchr ( input, ' ' );
while ( next != 0 || nParams >= 100 ) {
params[nParams] = next + 1;
*next = 0;
next = strchr ( params[nParams++], ' ' );
}
WOscMessage msg(input);
for ( int i = 0; i < nParams; i++ ) {
int parInt = atoi(params[i]);
float parFlt = atof(params[i]);
if ( strchr ( params[i], '.' ) ) {
msg.Add( parFlt );
} else if ( parInt != 0 ) {
msg.Add( parInt );
} else {
msg.Add( params[i] );
}
}
if ( bundleOpen ) {
theBundle.Add(new WOscMessage(msg));
} else {
TheNetReturnAddress ra;
ra.m_addr.sin_family = AF_INET;
ra.m_addr.sin_addr.s_addr = inet_addr(remoteIP);
ra.m_addr.sin_port = htons(remoteport);
client.NetworkSend(msg.GetBuffer(), msg.GetBufferLen(), &ra);
}
} catch(const WOscException& e ) {
std::cout<<"Exception: " << e.GetErrStr() <<std::endl;
}
}
else if (input[0] == '[') {
if ( bundleOpen ) {
std::cout<<"Bundle already open."<<std::endl;
} else {
theBundle = WOscBundle();
bundleOpen = true;
}
}
else if (input[0] == ']') {
if ( bundleOpen ) {
TheNetReturnAddress ra;
ra.m_addr.sin_family = AF_INET;
ra.m_addr.sin_addr.s_addr = inet_addr(remoteIP);
ra.m_addr.sin_port = htons(remoteport);
client.NetworkSend(theBundle.GetBuffer(), theBundle.GetBufferLen(), &ra);
bundleOpen = false;
} else {
std::cout<<"No bundle to close."<<std::endl;
}
}
else {
if ( strcmp("exit",input) == 0 ) {
break;
}
else if ( strcmp("help",input) == 0 ) {
std::cout << WOSC_CLIENT_HELP_STR ;
}
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 ;
}
else if ( strncmp("srp",input,3) == 0 ) {
remoteport = atoi( &input[4] );
std::cout << " Remote port set to " << remoteport << "."<<std::endl ;
}
else if ( strncmp("srip",input,4) == 0 )
{
strcpy(remoteIP, &input[5]);
std::cout << " Remote IP set to " << remoteIP << "."<<std::endl ;
}
}
#if OS_IS_LINUX == 1 || OS_IS_MACOSX == 1 || OS_IS_CYGWIN == 1
usleep(100000);
#elif OS_IS_WIN32 == 1
Sleep(100);
#endif
client.CheckForPackets();
}
client.NetworkHalt();
std::cout << "Exiting. Bye." <<std::endl;
return 0;
}