oscpack-1.0.2/0000755000175000017500000000000011512123504013001 5ustar mordredmordredoscpack-1.0.2/TODO0000644000175000017500000000461710530430404013500 0ustar mordredmordredTODO: - consider adding the local endpoint name to PacketListener::PacketReceived() params - consider adding ListenerThread class to support old seperate thread listener functionality, something like: class UdpSocketListenerThread{ public: UdpSocketListenerThread( UdpSocket& socket, Listener *listener ); UdpSocketListenerThread( UdpSocketReceiveMultiplexer *mux ); ~UdpSocketListenerThread(); void Run(); void Stop(); }; - provide some kind of automatic endianness configuration (hopefully there are gcc symbols for this) - work out a way to make the parsing classes totally safe. at a minimum this means adding functions to test for invalid float/doublevalues, making sure the iterators never pass the end of the message, ... (passing end of message can happen if: - too many args in type tags a. typetags overflow message size b. args fulfilling typetags overflow message size - strings too long or not terminated correctly - blobs too long or not terminated correctly if the message was fully checked during construction, the end() iterator could be moved back until only arguments which fit withing size() may be interated (this could be none). A flag could be set to indicate that something was wrong. - other packet badness could include: - time tags too far into the future (the scheduler should deal with that i guess). - message address patterns which aren't correctly terminated - improve the ability to parse messages without tags (SC uses methods which get the data and advance the iterator in one step.) - Check* could be modified to do this - ie if typetags are not present it could check that reading the field won't escape the message size and return the data, or return false if some consistency constraint is violated. (or alternately drop support for messages without type tags) - add a method to discard an inprogress message if it gets half constructed and the buffer is full in OutboundPacket - write a stress testing app which can send garbage packets to try to flush out other bugs in the parsing code. oscpack-1.0.2/ip/0000755000175000017500000000000010530430404013410 5ustar mordredmordredoscpack-1.0.2/ip/win32/0000755000175000017500000000000010530430402014350 5ustar mordredmordredoscpack-1.0.2/ip/win32/UdpSocket.cpp0000644000175000017500000003610210530430402016757 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ip/UdpSocket.h" #include // this must come first to prevent errors with MSVC7 #include #include // for timeGetTime() #include #include #include #include #include #include "ip/NetworkingUtils.h" #include "ip/PacketListener.h" #include "ip/TimerListener.h" typedef int socklen_t; static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) { memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = (endpoint.address == IpEndpointName::ANY_ADDRESS) ? INADDR_ANY : htonl( endpoint.address ); sockAddr.sin_port = (endpoint.port == IpEndpointName::ANY_PORT) ? (short)0 : htons( (short)endpoint.port ); } static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr ) { return IpEndpointName( (sockAddr.sin_addr.s_addr == INADDR_ANY) ? IpEndpointName::ANY_ADDRESS : ntohl( sockAddr.sin_addr.s_addr ), (sockAddr.sin_port == 0) ? IpEndpointName::ANY_PORT : ntohs( sockAddr.sin_port ) ); } class UdpSocket::Implementation{ NetworkInitializer networkInitializer_; bool isBound_; bool isConnected_; SOCKET socket_; struct sockaddr_in connectedAddr_; struct sockaddr_in sendToAddr_; public: Implementation() : isBound_( false ) , isConnected_( false ) , socket_( INVALID_SOCKET ) { if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){ throw std::runtime_error("unable to create udp socket\n"); } memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); sendToAddr_.sin_family = AF_INET; } ~Implementation() { if (socket_ != INVALID_SOCKET) closesocket(socket_); } IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { assert( isBound_ ); // first connect the socket to the remote server struct sockaddr_in connectSockAddr; SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint ); if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) { throw std::runtime_error("unable to connect udp socket\n"); } // get the address struct sockaddr_in sockAddr; memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); socklen_t length = sizeof(sockAddr); if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { throw std::runtime_error("unable to getsockname\n"); } if( isConnected_ ){ // reconnect to the connected address if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { throw std::runtime_error("unable to connect udp socket\n"); } }else{ // unconnect from the remote address struct sockaddr_in unconnectSockAddr; SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() ); if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0 && WSAGetLastError() != WSAEADDRNOTAVAIL ){ throw std::runtime_error("unable to un-connect udp socket\n"); } } return IpEndpointNameFromSockaddr( sockAddr ); } void Connect( const IpEndpointName& remoteEndpoint ) { SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint ); if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { throw std::runtime_error("unable to connect udp socket\n"); } isConnected_ = true; } void Send( const char *data, int size ) { assert( isConnected_ ); send( socket_, data, size, 0 ); } void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) { sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); sendToAddr_.sin_port = htons( (short)remoteEndpoint.port ); sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); } void Bind( const IpEndpointName& localEndpoint ) { struct sockaddr_in bindSockAddr; SockaddrFromIpEndpointName( bindSockAddr, localEndpoint ); if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) { throw std::runtime_error("unable to bind udp socket\n"); } isBound_ = true; } bool IsBound() const { return isBound_; } int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) { assert( isBound_ ); struct sockaddr_in fromAddr; socklen_t fromAddrLen = sizeof(fromAddr); int result = recvfrom(socket_, data, size, 0, (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); if( result < 0 ) return 0; remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); remoteEndpoint.port = ntohs(fromAddr.sin_port); return result; } SOCKET& Socket() { return socket_; } }; UdpSocket::UdpSocket() { impl_ = new Implementation(); } UdpSocket::~UdpSocket() { delete impl_; } IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { return impl_->LocalEndpointFor( remoteEndpoint ); } void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) { impl_->Connect( remoteEndpoint ); } void UdpSocket::Send( const char *data, int size ) { impl_->Send( data, size ); } void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) { impl_->SendTo( remoteEndpoint, data, size ); } void UdpSocket::Bind( const IpEndpointName& localEndpoint ) { impl_->Bind( localEndpoint ); } bool UdpSocket::IsBound() const { return impl_->IsBound(); } int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) { return impl_->ReceiveFrom( remoteEndpoint, data, size ); } struct AttachedTimerListener{ AttachedTimerListener( int id, int p, TimerListener *tl ) : initialDelayMs( id ) , periodMs( p ) , listener( tl ) {} int initialDelayMs; int periodMs; TimerListener *listener; }; static bool CompareScheduledTimerCalls( const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs ) { return lhs.first < rhs.first; } SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0; extern "C" /*static*/ void InterruptSignalHandler( int ); /*static*/ void InterruptSignalHandler( int ) { multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); signal( SIGINT, SIG_DFL ); } class SocketReceiveMultiplexer::Implementation{ NetworkInitializer networkInitializer_; std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; std::vector< AttachedTimerListener > timerListeners_; volatile bool break_; HANDLE breakEvent_; double GetCurrentTimeMs() const { return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days } public: Implementation() { breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL ); } ~Implementation() { CloseHandle( breakEvent_ ); } void AttachSocketListener( UdpSocket *socket, PacketListener *listener ) { assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() ); // we don't check that the same socket has been added multiple times, even though this is an error socketListeners_.push_back( std::make_pair( listener, socket ) ); } void DetachSocketListener( UdpSocket *socket, PacketListener *listener ) { std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ); assert( i != socketListeners_.end() ); socketListeners_.erase( i ); } void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) { timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) ); } void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) { timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) ); } void DetachPeriodicTimerListener( TimerListener *listener ) { std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); while( i != timerListeners_.end() ){ if( i->listener == listener ) break; ++i; } assert( i != timerListeners_.end() ); timerListeners_.erase( i ); } void Run() { break_ = false; // prepare the window events which we use to wake up on incoming data // we use this instead of select() primarily to support the AsyncBreak() // mechanism. std::vector events( socketListeners_.size() + 1, 0 ); int j=0; for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); i != socketListeners_.end(); ++i, ++j ){ HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL ); WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below events[j] = event; } events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event // configure the timer queue double currentTimeMs = GetCurrentTimeMs(); // expiry time ms, listener std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); i != timerListeners_.end(); ++i ) timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); const int MAX_BUFFER_SIZE = 4098; char *data = new char[ MAX_BUFFER_SIZE ]; IpEndpointName remoteEndpoint; while( !break_ ){ double currentTimeMs = GetCurrentTimeMs(); DWORD waitTime = INFINITE; if( !timerQueue_.empty() ){ waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs ? timerQueue_.front().first - currentTimeMs : 0 ); } DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime ); if( break_ ) break; if( waitResult != WAIT_TIMEOUT ){ for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){ int size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); if( size > 0 ){ socketListeners_[i].first->ProcessPacket( data, size, remoteEndpoint ); if( break_ ) break; } } } // execute any expired timers currentTimeMs = GetCurrentTimeMs(); bool resort = false; for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ i->second.listener->TimerExpired(); if( break_ ) break; i->first += i->second.periodMs; resort = true; } if( resort ) std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); } delete [] data; // free events j = 0; for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); i != socketListeners_.end(); ++i, ++j ){ WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event CloseHandle( events[j] ); unsigned long enableNonblocking = 0; ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again } } void Break() { break_ = true; } void AsynchronousBreak() { break_ = true; SetEvent( breakEvent_ ); } }; SocketReceiveMultiplexer::SocketReceiveMultiplexer() { impl_ = new Implementation(); } SocketReceiveMultiplexer::~SocketReceiveMultiplexer() { delete impl_; } void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener ) { impl_->AttachSocketListener( socket, listener ); } void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener ) { impl_->DetachSocketListener( socket, listener ); } void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) { impl_->AttachPeriodicTimerListener( periodMilliseconds, listener ); } void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) { impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ); } void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener ) { impl_->DetachPeriodicTimerListener( listener ); } void SocketReceiveMultiplexer::Run() { impl_->Run(); } 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; } void SocketReceiveMultiplexer::Break() { impl_->Break(); } void SocketReceiveMultiplexer::AsynchronousBreak() { impl_->AsynchronousBreak(); } oscpack-1.0.2/ip/win32/NetworkingUtils.cpp0000644000175000017500000000601310530430402020224 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ip/NetworkingUtils.h" #include // this must come first to prevent errors with MSVC7 #include #include #include static LONG initCount_ = 0; static bool winsockInitialized_ = false; NetworkInitializer::NetworkInitializer() { if( InterlockedIncrement( &initCount_ ) == 1 ){ // there is a race condition here if one thread tries to access // the library while another is still initializing it. // i can't think of an easy way to fix it so i'm telling you here // incase you need to init the library from two threads at once. // this is why the header file advises to instantiate one of these // in main() so that the initialization happens globally // initialize winsock WSAData wsaData; int nCode = WSAStartup(MAKEWORD(1, 1), &wsaData); if( nCode != 0 ){ //std::cout << "WSAStartup() failed with error code " << nCode << "\n"; }else{ winsockInitialized_ = true; } } } NetworkInitializer::~NetworkInitializer() { if( InterlockedDecrement( &initCount_ ) == 0 ){ if( winsockInitialized_ ){ WSACleanup(); winsockInitialized_ = false; } } } unsigned long GetHostByName( const char *name ) { NetworkInitializer networkInitializer; unsigned long result = 0; struct hostent *h = gethostbyname( name ); if( h ){ struct in_addr a; memcpy( &a, h->h_addr_list[0], h->h_length ); result = ntohl(a.s_addr); } return result; } oscpack-1.0.2/ip/IpEndpointName.h0000644000175000017500000000547710530430404016450 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_IPENDPOINTNAME_H #define INCLUDED_IPENDPOINTNAME_H class IpEndpointName{ static unsigned long GetHostByName( const char *s ); public: static const unsigned long ANY_ADDRESS = 0xFFFFFFFF; static const int ANY_PORT = -1; IpEndpointName() : address( ANY_ADDRESS ), port( ANY_PORT ) {} IpEndpointName( int port_ ) : address( ANY_ADDRESS ), port( port_ ) {} IpEndpointName( unsigned long ipAddress_, int port_ ) : address( ipAddress_ ), port( port_ ) {} IpEndpointName( const char *addressName, int port_=ANY_PORT ) : address( GetHostByName( addressName ) ) , port( port_ ) {} IpEndpointName( int addressA, int addressB, int addressC, int addressD, int port_=ANY_PORT ) : address( ( (addressA << 24) | (addressB << 16) | (addressC << 8) | addressD ) ) , port( port_ ) {} // address and port are maintained in host byte order here unsigned long address; int port; enum { ADDRESS_STRING_LENGTH=17 }; void AddressAsString( char *s ) const; enum { ADDRESS_AND_PORT_STRING_LENGTH=23}; void AddressAndPortAsString( char *s ) const; }; inline bool operator==( const IpEndpointName& lhs, const IpEndpointName& rhs ) { return (lhs.address == rhs.address && lhs.port == rhs.port ); } inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs ) { return !(lhs == rhs); } #endif /* INCLUDED_IPENDPOINTNAME_H */ oscpack-1.0.2/ip/NetworkingUtils.h0000644000175000017500000000373310530430404016737 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_NETWORKINGUTILS_H #define INCLUDED_NETWORKINGUTILS_H // in general NetworkInitializer is only used internally, but if you're // application creates multiple sockets from different threads at runtime you // should instantiate one of these in main just to make sure the networking // layer is initialized. class NetworkInitializer{ public: NetworkInitializer(); ~NetworkInitializer(); }; // return ip address of host name in host byte order unsigned long GetHostByName( const char *name ); #endif /* INCLUDED_NETWORKINGUTILS_H */ oscpack-1.0.2/ip/PacketListener.h0000644000175000017500000000333010530430404016475 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_PACKETLISTENER_H #define INCLUDED_PACKETLISTENER_H class IpEndpointName; class PacketListener{ public: virtual ~PacketListener() {} virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) = 0; }; #endif /* INCLUDED_PACKETLISTENER_H */ oscpack-1.0.2/ip/IpEndpointName.cpp0000644000175000017500000000477410530430404017002 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "IpEndpointName.h" #include #include "NetworkingUtils.h" unsigned long IpEndpointName::GetHostByName( const char *s ) { return ::GetHostByName(s); } void IpEndpointName::AddressAsString( char *s ) const { if( address == ANY_ADDRESS ){ sprintf( s, "" ); }else{ sprintf( s, "%d.%d.%d.%d", (int)((address >> 24) & 0xFF), (int)((address >> 16) & 0xFF), (int)((address >> 8) & 0xFF), (int)(address & 0xFF) ); } } void IpEndpointName::AddressAndPortAsString( char *s ) const { if( port == ANY_PORT ){ if( address == ANY_ADDRESS ){ sprintf( s, ":" ); }else{ sprintf( s, "%d.%d.%d.%d:", (int)((address >> 24) & 0xFF), (int)((address >> 16) & 0xFF), (int)((address >> 8) & 0xFF), (int)(address & 0xFF) ); } }else{ if( address == ANY_ADDRESS ){ sprintf( s, ":%d", port ); }else{ sprintf( s, "%d.%d.%d.%d:%d", (int)((address >> 24) & 0xFF), (int)((address >> 16) & 0xFF), (int)((address >> 8) & 0xFF), (int)(address & 0xFF), (int)port ); } } } oscpack-1.0.2/ip/TimerListener.h0000644000175000017500000000316210530430404016351 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_TIMERLISTENER_H #define INCLUDED_TIMERLISTENER_H class TimerListener{ public: virtual ~TimerListener() {} virtual void TimerExpired() = 0; }; #endif /* INCLUDED_TIMERLISTENER_H */ oscpack-1.0.2/ip/UdpSocket.h0000644000175000017500000001267010530430404015470 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_UDPSOCKET_H #define INCLUDED_UDPSOCKET_H #ifndef INCLUDED_NETWORKINGUTILITIES_H #include "NetworkingUtils.h" #endif /* INCLUDED_NETWORKINGUTILITIES_H */ #ifndef INCLUDED_IPENDPOINTNAME_H #include "IpEndpointName.h" #endif /* INCLUDED_IPENDPOINTNAME_H */ class PacketListener; class TimerListener; class UdpSocket; class SocketReceiveMultiplexer{ class Implementation; Implementation *impl_; friend class UdpSocket; public: SocketReceiveMultiplexer(); ~SocketReceiveMultiplexer(); // only call the attach/detach methods _before_ calling Run // only one listener per socket, each socket at most once void AttachSocketListener( UdpSocket *socket, PacketListener *listener ); void DetachSocketListener( UdpSocket *socket, PacketListener *listener ); void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ); void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ); void DetachPeriodicTimerListener( TimerListener *listener ); void Run(); // loop and block processing messages indefinitely void RunUntilSigInt(); void Break(); // call this from a listener to exit once the listener returns void AsynchronousBreak(); // call this from another thread or signal handler to exit the Run() state }; class UdpSocket{ class Implementation; Implementation *impl_; friend class SocketReceiveMultiplexer::Implementation; public: // ctor throws std::runtime_error if there's a problem // initializing the socket. UdpSocket(); virtual ~UdpSocket(); // the socket is created in an unbound, unconnected state // such a socket can only be used to send to an arbitrary // address using SendTo(). To use Send() you need to first // connect to a remote endpoint using Connect(). To use // ReceiveFrom you need to first bind to a local endpoint // using Bind(). // retrieve the local endpoint name when sending to 'to' IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const; // Connect to a remote endpoint which is used as the target // for calls to Send() void Connect( const IpEndpointName& remoteEndpoint ); void Send( const char *data, int size ); void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ); // Bind a local endpoint to receive incoming data. Endpoint // can be 'any' for the system to choose an endpoint void Bind( const IpEndpointName& localEndpoint ); bool IsBound() const; int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ); }; // convenience classes for transmitting and receiving // they just call Connect and/or Bind in the ctor. // note that you can still use a receive socket // for transmitting etc class UdpTransmitSocket : public UdpSocket{ public: UdpTransmitSocket( const IpEndpointName& remoteEndpoint ) { Connect( remoteEndpoint ); } }; class UdpReceiveSocket : public UdpSocket{ public: UdpReceiveSocket( const IpEndpointName& localEndpoint ) { Bind( localEndpoint ); } }; // UdpListeningReceiveSocket provides a simple way to bind one listener // to a single socket without having to manually set up a SocketReceiveMultiplexer class UdpListeningReceiveSocket : public UdpSocket{ SocketReceiveMultiplexer mux_; PacketListener *listener_; public: UdpListeningReceiveSocket( const IpEndpointName& localEndpoint, PacketListener *listener ) : listener_( listener ) { Bind( localEndpoint ); mux_.AttachSocketListener( this, listener_ ); } ~UdpListeningReceiveSocket() { mux_.DetachSocketListener( this, listener_ ); } // see SocketReceiveMultiplexer above for the behaviour of these methods... void Run() { mux_.Run(); } void RunUntilSigInt() { mux_.RunUntilSigInt(); } void Break() { mux_.Break(); } void AsynchronousBreak() { mux_.AsynchronousBreak(); } }; #endif /* INCLUDED_UDPSOCKET_H */ oscpack-1.0.2/ip/posix/0000755000175000017500000000000010530430402014550 5ustar mordredmordredoscpack-1.0.2/ip/posix/UdpSocket.cpp0000644000175000017500000003640210530430402017162 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ip/UdpSocket.h" #include #include #include #include #include #include #include #include // for memset #include #include #include #include #include #include #include #include #include // for sockaddr_in #include "ip/PacketListener.h" #include "ip/TimerListener.h" #if defined(__APPLE__) && !defined(_SOCKLEN_T) // pre system 10.3 didn have socklen_t typedef ssize_t socklen_t; #endif static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) { memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = (endpoint.address == IpEndpointName::ANY_ADDRESS) ? INADDR_ANY : htonl( endpoint.address ); sockAddr.sin_port = (endpoint.port == IpEndpointName::ANY_PORT) ? 0 : htons( endpoint.port ); } static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr ) { return IpEndpointName( (sockAddr.sin_addr.s_addr == INADDR_ANY) ? IpEndpointName::ANY_ADDRESS : ntohl( sockAddr.sin_addr.s_addr ), (sockAddr.sin_port == 0) ? IpEndpointName::ANY_PORT : ntohs( sockAddr.sin_port ) ); } class UdpSocket::Implementation{ bool isBound_; bool isConnected_; int socket_; struct sockaddr_in connectedAddr_; struct sockaddr_in sendToAddr_; public: Implementation() : isBound_( false ) , isConnected_( false ) , socket_( -1 ) { if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 ){ throw std::runtime_error("unable to create udp socket\n"); } memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); sendToAddr_.sin_family = AF_INET; } ~Implementation() { if (socket_ != -1) close(socket_); } IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { assert( isBound_ ); // first connect the socket to the remote server struct sockaddr_in connectSockAddr; SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint ); if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) { throw std::runtime_error("unable to connect udp socket\n"); } // get the address struct sockaddr_in sockAddr; memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); socklen_t length = sizeof(sockAddr); if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { throw std::runtime_error("unable to getsockname\n"); } if( isConnected_ ){ // reconnect to the connected address if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { throw std::runtime_error("unable to connect udp socket\n"); } }else{ // unconnect from the remote address struct sockaddr_in unconnectSockAddr; memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) ); unconnectSockAddr.sin_family = AF_UNSPEC; // address fields are zero int connectResult = connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)); if ( connectResult < 0 && errno != EAFNOSUPPORT ) { throw std::runtime_error("unable to un-connect udp socket\n"); } } return IpEndpointNameFromSockaddr( sockAddr ); } void Connect( const IpEndpointName& remoteEndpoint ) { SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint ); if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { throw std::runtime_error("unable to connect udp socket\n"); } isConnected_ = true; } void Send( const char *data, int size ) { assert( isConnected_ ); send( socket_, data, size, 0 ); } void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) { sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); sendToAddr_.sin_port = htons( remoteEndpoint.port ); sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); } void Bind( const IpEndpointName& localEndpoint ) { struct sockaddr_in bindSockAddr; SockaddrFromIpEndpointName( bindSockAddr, localEndpoint ); if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) { throw std::runtime_error("unable to bind udp socket\n"); } isBound_ = true; } bool IsBound() const { return isBound_; } int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) { assert( isBound_ ); struct sockaddr_in fromAddr; socklen_t fromAddrLen = sizeof(fromAddr); int result = recvfrom(socket_, data, size, 0, (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); if( result < 0 ) return 0; remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); remoteEndpoint.port = ntohs(fromAddr.sin_port); return result; } int Socket() { return socket_; } }; UdpSocket::UdpSocket() { impl_ = new Implementation(); } UdpSocket::~UdpSocket() { delete impl_; } IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { return impl_->LocalEndpointFor( remoteEndpoint ); } void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) { impl_->Connect( remoteEndpoint ); } void UdpSocket::Send( const char *data, int size ) { impl_->Send( data, size ); } void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) { impl_->SendTo( remoteEndpoint, data, size ); } void UdpSocket::Bind( const IpEndpointName& localEndpoint ) { impl_->Bind( localEndpoint ); } bool UdpSocket::IsBound() const { return impl_->IsBound(); } int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) { return impl_->ReceiveFrom( remoteEndpoint, data, size ); } struct AttachedTimerListener{ AttachedTimerListener( int id, int p, TimerListener *tl ) : initialDelayMs( id ) , periodMs( p ) , listener( tl ) {} int initialDelayMs; int periodMs; TimerListener *listener; }; static bool CompareScheduledTimerCalls( const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs ) { return lhs.first < rhs.first; } SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0; extern "C" /*static*/ void InterruptSignalHandler( int ); /*static*/ void InterruptSignalHandler( int ) { multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); signal( SIGINT, SIG_DFL ); } class SocketReceiveMultiplexer::Implementation{ std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; std::vector< AttachedTimerListener > timerListeners_; volatile bool break_; int breakPipe_[2]; // [0] is the reader descriptor and [1] the writer double GetCurrentTimeMs() const { struct timeval t; gettimeofday( &t, 0 ); return ((double)t.tv_sec*1000.) + ((double)t.tv_usec / 1000.); } public: Implementation() { if( pipe(breakPipe_) != 0 ) throw std::runtime_error( "creation of asynchronous break pipes failed\n" ); } ~Implementation() { close( breakPipe_[0] ); close( breakPipe_[1] ); } void AttachSocketListener( UdpSocket *socket, PacketListener *listener ) { assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() ); // we don't check that the same socket has been added multiple times, even though this is an error socketListeners_.push_back( std::make_pair( listener, socket ) ); } void DetachSocketListener( UdpSocket *socket, PacketListener *listener ) { std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ); assert( i != socketListeners_.end() ); socketListeners_.erase( i ); } void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) { timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) ); } void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) { timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) ); } void DetachPeriodicTimerListener( TimerListener *listener ) { std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); while( i != timerListeners_.end() ){ if( i->listener == listener ) break; ++i; } assert( i != timerListeners_.end() ); timerListeners_.erase( i ); } void Run() { break_ = false; // configure the master fd_set for select() fd_set masterfds, tempfds; FD_ZERO( &masterfds ); FD_ZERO( &tempfds ); // in addition to listening to the inbound sockets we // also listen to the asynchronous break pipe, so that AsynchronousBreak() // can break us out of select() from another thread. FD_SET( breakPipe_[0], &masterfds ); int fdmax = breakPipe_[0]; for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); i != socketListeners_.end(); ++i ){ if( fdmax < i->second->impl_->Socket() ) fdmax = i->second->impl_->Socket(); FD_SET( i->second->impl_->Socket(), &masterfds ); } // configure the timer queue double currentTimeMs = GetCurrentTimeMs(); // expiry time ms, listener std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); i != timerListeners_.end(); ++i ) timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); const int MAX_BUFFER_SIZE = 4098; char *data = new char[ MAX_BUFFER_SIZE ]; IpEndpointName remoteEndpoint; struct timeval timeout; while( !break_ ){ tempfds = masterfds; struct timeval *timeoutPtr = 0; if( !timerQueue_.empty() ){ double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs(); if( timeoutMs < 0 ) timeoutMs = 0; // 1000000 microseconds in a second timeout.tv_sec = (long)(timeoutMs * .001); timeout.tv_usec = (long)((timeoutMs - (timeout.tv_sec * 1000)) * 1000); timeoutPtr = &timeout; } if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 && errno != EINTR ){ throw std::runtime_error("select failed\n"); } if ( FD_ISSET( breakPipe_[0], &tempfds ) ){ // clear pending data from the asynchronous break pipe char c; read( breakPipe_[0], &c, 1 ); } if( break_ ) break; for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); i != socketListeners_.end(); ++i ){ if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){ int size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); if( size > 0 ){ i->first->ProcessPacket( data, size, remoteEndpoint ); if( break_ ) break; } } } // execute any expired timers currentTimeMs = GetCurrentTimeMs(); bool resort = false; for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ i->second.listener->TimerExpired(); if( break_ ) break; i->first += i->second.periodMs; resort = true; } if( resort ) std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); } delete [] data; } 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 ); } }; SocketReceiveMultiplexer::SocketReceiveMultiplexer() { impl_ = new Implementation(); } SocketReceiveMultiplexer::~SocketReceiveMultiplexer() { delete impl_; } void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener ) { impl_->AttachSocketListener( socket, listener ); } void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener ) { impl_->DetachSocketListener( socket, listener ); } void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) { impl_->AttachPeriodicTimerListener( periodMilliseconds, listener ); } void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) { impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ); } void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener ) { impl_->DetachPeriodicTimerListener( listener ); } void SocketReceiveMultiplexer::Run() { impl_->Run(); } 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; } void SocketReceiveMultiplexer::Break() { impl_->Break(); } void SocketReceiveMultiplexer::AsynchronousBreak() { impl_->AsynchronousBreak(); } oscpack-1.0.2/ip/posix/NetworkingUtils.cpp0000644000175000017500000000367010530430402020432 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ip/NetworkingUtils.h" #include #include #include #include #include NetworkInitializer::NetworkInitializer() {} NetworkInitializer::~NetworkInitializer() {} unsigned long GetHostByName( const char *name ) { unsigned long result = 0; struct hostent *h = gethostbyname( name ); if( h ){ struct in_addr a; memcpy( &a, h->h_addr_list[0], h->h_length ); result = ntohl(a.s_addr); } return result; } oscpack-1.0.2/examples/0000755000175000017500000000000010530430404014616 5ustar mordredmordredoscpack-1.0.2/examples/SimpleReceive.cpp0000644000175000017500000000520010530430404020053 0ustar mordredmordred/* Example of two different ways to process received OSC messages using oscpack. Receives the messages from the SimpleSend.cpp example. */ #include #include "osc/OscReceivedElements.h" #include "osc/OscPacketListener.h" #include "ip/UdpSocket.h" #define PORT 7000 class ExamplePacketListener : public osc::OscPacketListener { protected: virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ) { try{ // example of parsing single messages. osc::OsckPacketListener // handles the bundle traversal. if( strcmp( m.AddressPattern(), "/test1" ) == 0 ){ // example #1 -- argument stream interface osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); bool a1; osc::int32 a2; float a3; const char *a4; args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage; std::cout << "received '/test1' message with arguments: " << a1 << " " << a2 << " " << a3 << " " << a4 << "\n"; }else if( strcmp( m.AddressPattern(), "/test2" ) == 0 ){ // example #2 -- argument iterator interface, supports // reflection for overloaded messages (eg you can call // (*arg)->IsBool() to check if a bool was passed etc). osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); bool a1 = (arg++)->AsBool(); int a2 = (arg++)->AsInt32(); float a3 = (arg++)->AsFloat(); const char *a4 = (arg++)->AsString(); if( arg != m.ArgumentsEnd() ) throw osc::ExcessArgumentException(); std::cout << "received '/test2' message with arguments: " << a1 << " " << a2 << " " << a3 << " " << a4 << "\n"; } }catch( osc::Exception& e ){ // any parsing errors such as unexpected argument types, or // missing arguments get thrown as exceptions. std::cout << "error while parsing message: " << m.AddressPattern() << ": " << e.what() << "\n"; } } }; int main(int argc, char* argv[]) { ExamplePacketListener listener; UdpListeningReceiveSocket s( IpEndpointName( IpEndpointName::ANY_ADDRESS, PORT ), &listener ); std::cout << "press ctrl-c to end\n"; s.RunUntilSigInt(); return 0; } oscpack-1.0.2/examples/OscDump.cpp0000644000175000017500000000505710530430404016703 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* OscDump prints incoming Osc packets. Unlike the Berkeley dumposc program OscDump uses a different printing format which indicates the type of each message argument. */ #include #include "osc/OscReceivedElements.h" #include "osc/OscPrintReceivedElements.h" #include "ip/UdpSocket.h" #include "ip/PacketListener.h" class OscDumpPacketListener : public PacketListener{ public: virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { std::cout << osc::ReceivedPacket( data, size ); } }; int main(int argc, char* argv[]) { if( argc >= 2 && strcmp( argv[1], "-h" ) == 0 ){ std::cout << "usage: OscDump [port]\n"; return 0; } int port = 7000; if( argc >= 2 ) port = atoi( argv[1] ); OscDumpPacketListener listener; UdpListeningReceiveSocket s( IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), &listener ); std::cout << "listening for input on port " << port << "...\n"; std::cout << "press ctrl-c to end\n"; s.RunUntilSigInt(); std::cout << "finishing.\n"; return 0; } oscpack-1.0.2/examples/SimpleSend.cpp0000644000175000017500000000145210530430404017367 0ustar mordredmordred/* Simple example of sending an OSC message using oscpack. */ #include "osc/OscOutboundPacketStream.h" #include "ip/UdpSocket.h" #define ADDRESS "127.0.0.1" #define PORT 7000 #define OUTPUT_BUFFER_SIZE 1024 int main(int argc, char* argv[]) { UdpTransmitSocket transmitSocket( IpEndpointName( ADDRESS, PORT ) ); char buffer[OUTPUT_BUFFER_SIZE]; osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE ); p << osc::BeginBundleImmediate << osc::BeginMessage( "/test1" ) << true << 23 << (float)3.1415 << "hello" << osc::EndMessage << osc::BeginMessage( "/test2" ) << true << 24 << (float)10.8 << "world" << osc::EndMessage << osc::EndBundle; transmitSocket.Send( p.Data(), p.Size() ); } oscpack-1.0.2/LICENSE0000644000175000017500000000257310530430404014014 0ustar mordredmordredoscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/code/oscpack Copyright (c) 2004 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. oscpack-1.0.2/osc/0000755000175000017500000000000010530430402013562 5ustar mordredmordredoscpack-1.0.2/osc/OscPrintReceivedElements.cpp0000644000175000017500000001601110530430402021172 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscPrintReceivedElements.h" #include #include #include namespace osc{ std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg ) { switch( arg.TypeTag() ){ case TRUE_TYPE_TAG: os << "bool:true"; break; case FALSE_TYPE_TAG: os << "bool:false"; break; case NIL_TYPE_TAG: os << "(Nil)"; break; case INFINITUM_TYPE_TAG: os << "(Infinitum)"; break; case INT32_TYPE_TAG: os << "int32:" << arg.AsInt32Unchecked(); break; case FLOAT_TYPE_TAG: os << "float32:" << arg.AsFloatUnchecked(); break; case CHAR_TYPE_TAG: { char s[2] = {0}; s[0] = arg.AsCharUnchecked(); os << "char:'" << s << "'"; } break; case RGBA_COLOR_TYPE_TAG: { uint32 color = arg.AsRgbaColorUnchecked(); os << "RGBA:0x" << std::hex << std::setfill('0') << std::setw(2) << (int)((color>>24) & 0xFF) << std::setw(2) << (int)((color>>16) & 0xFF) << std::setw(2) << (int)((color>>8) & 0xFF) << std::setw(2) << (int)(color & 0xFF) << std::setfill(' '); os.unsetf(std::ios::basefield); } break; case MIDI_MESSAGE_TYPE_TAG: { uint32 m = arg.AsMidiMessageUnchecked(); os << "midi (port, status, data1, data2):<<" << std::hex << std::setfill('0') << "0x" << std::setw(2) << (int)((m>>24) & 0xFF) << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF) << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF) << " 0x" << std::setw(2) << (int)(m & 0xFF) << std::setfill(' ') << ">>"; os.unsetf(std::ios::basefield); } break; case INT64_TYPE_TAG: os << "int64:" << arg.AsInt64Unchecked(); break; case TIME_TAG_TYPE_TAG: { os << "OSC-timetag:" << arg.AsTimeTagUnchecked(); std::time_t t = (unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); // strip trailing newline from string returned by ctime const char *timeString = std::ctime( &t ); size_t len = strlen( timeString ); char *s = new char[ len + 1 ]; strcpy( s, timeString ); if( len ) s[ len - 1 ] = '\0'; os << " " << s; } break; case DOUBLE_TYPE_TAG: os << "double:" << arg.AsDoubleUnchecked(); break; case STRING_TYPE_TAG: os << "OSC-string:`" << arg.AsStringUnchecked() << "'"; break; case SYMBOL_TYPE_TAG: os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'"; break; case BLOB_TYPE_TAG: { unsigned long size; const void *data; arg.AsBlobUnchecked( data, size ); os << "OSC-blob:<<" << std::hex << std::setfill('0'); unsigned char *p = (unsigned char*)data; for( unsigned long i = 0; i < size; ++i ){ os << "0x" << std::setw(2) << int(p[i]); if( i != size-1 ) os << ' '; } os.unsetf(std::ios::basefield); os << ">>" << std::setfill(' '); } break; default: os << "unknown"; } return os; } std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) { os << "[" << m.AddressPattern(); bool first = true; for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); i != m.ArgumentsEnd(); ++i ){ if( first ){ os << " "; first = false; }else{ os << ", "; } os << *i; } os << "]"; return os; } std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ) { static int indent = 0; for( int j=0; j < indent; ++j ) os << " "; os << "{ ( "; if( b.TimeTag() == 1 ) os << "immediate"; else os << b.TimeTag(); os << " )\n"; ++indent; for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ if( i->IsBundle() ){ ReceivedBundle b(*i); os << b << "\n"; }else{ ReceivedMessage m(*i); for( int j=0; j < indent; ++j ) os << " "; os << m << "\n"; } } --indent; for( int j=0; j < indent; ++j ) os << " "; os << "}"; return os; } std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ) { if( p.IsBundle() ){ ReceivedBundle b(p); os << b << "\n"; }else{ ReceivedMessage m(p); os << m << "\n"; } return os; } } // namespace osc oscpack-1.0.2/osc/OscHostEndianness.h0000644000175000017500000000455510530430402017336 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef OSC_HOSTENDIANNESS_H #define OSC_HOSTENDIANNESS_H /* Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined If you know a way to enhance the detection below for Linux and/or MacOSX please let me know! I've tried a few things which don't work. */ #if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN) // you can define one of the above symbols from the command line // then you don't have to edit this file. #elif defined(__WIN32__) || defined(WIN32) // assume that __WIN32__ is only defined on little endian systems #define OSC_HOST_LITTLE_ENDIAN 1 #undef OSC_HOST_BIG_ENDIAN #elif defined(__APPLE__) #if defined(__LITTLE_ENDIAN__) #define OSC_HOST_LITTLE_ENDIAN 1 #undef OSC_HOST_BIG_ENDIAN #else #define OSC_HOST_BIG_ENDIAN 1 #undef OSC_HOST_LITTLE_ENDIAN #endif #else #error please edit OSCHostEndianness.h to configure endianness #endif #endif /* OSC_HOSTENDIANNESS_H */ oscpack-1.0.2/osc/OscReceivedElements.h0000644000175000017500000003234710530667752017660 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCRECEIVEDELEMENTS_H #define INCLUDED_OSCRECEIVEDELEMENTS_H #include "OscTypes.h" #include "OscException.h" namespace osc{ class MalformedMessageException : public Exception{ public: MalformedMessageException( const char *w="malformed message" ) : Exception( w ) {} }; class MalformedBundleException : public Exception{ public: MalformedBundleException( const char *w="malformed bundle" ) : Exception( w ) {} }; class WrongArgumentTypeException : public Exception{ public: WrongArgumentTypeException( const char *w="wrong argument type" ) : Exception( w ) {} }; class MissingArgumentException : public Exception{ public: MissingArgumentException( const char *w="missing argument" ) : Exception( w ) {} }; class ExcessArgumentException : public Exception{ public: ExcessArgumentException( const char *w="too many arguments" ) : Exception( w ) {} }; class ReceivedPacket{ public: ReceivedPacket( const char *contents, int32 size ) : contents_( contents ) , size_( size ) {} bool IsMessage() const { return !IsBundle(); } bool IsBundle() const; int32 Size() const { return size_; } const char *Contents() const { return contents_; } private: const char *contents_; int32 size_; }; class ReceivedBundleElement{ public: ReceivedBundleElement( const char *size ) : size_( size ) {} friend class ReceivedBundleElementIterator; bool IsMessage() const { return !IsBundle(); } bool IsBundle() const; int32 Size() const; const char *Contents() const { return size_ + 4; } private: const char *size_; }; class ReceivedBundleElementIterator{ public: ReceivedBundleElementIterator( const char *sizePtr ) : value_( sizePtr ) {} ReceivedBundleElementIterator operator++() { Advance(); return *this; } ReceivedBundleElementIterator operator++(int) { ReceivedBundleElementIterator old( *this ); Advance(); return old; } const ReceivedBundleElement& operator*() const { return value_; } const ReceivedBundleElement* operator->() const { return &value_; } friend bool operator==(const ReceivedBundleElementIterator& lhs, const ReceivedBundleElementIterator& rhs ); private: ReceivedBundleElement value_; void Advance() { value_.size_ = value_.Contents() + value_.Size(); } bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const { return value_.size_ == rhs.value_.size_; } }; inline bool operator==(const ReceivedBundleElementIterator& lhs, const ReceivedBundleElementIterator& rhs ) { return lhs.IsEqualTo( rhs ); } inline bool operator!=(const ReceivedBundleElementIterator& lhs, const ReceivedBundleElementIterator& rhs ) { return !( lhs == rhs ); } class ReceivedMessageArgument{ public: ReceivedMessageArgument( const char *typeTag, const char *argument ) : typeTag_( typeTag ) , argument_( argument ) {} friend class ReceivedMessageArgumentIterator; const char TypeTag() const { return *typeTag_; } // the unchecked methods below don't check whether the argument actually // is of the specified type. they should only be used if you've already // checked the type tag or the associated IsType() method. bool IsBool() const { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; } bool AsBool() const; bool AsBoolUnchecked() const; bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; } bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; } bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; } int32 AsInt32() const; int32 AsInt32Unchecked() const; bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; } float AsFloat() const; float AsFloatUnchecked() const; bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; } char AsChar() const; char AsCharUnchecked() const; bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; } uint32 AsRgbaColor() const; uint32 AsRgbaColorUnchecked() const; bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; } uint32 AsMidiMessage() const; uint32 AsMidiMessageUnchecked() const; bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; } int64 AsInt64() const; int64 AsInt64Unchecked() const; bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; } uint64 AsTimeTag() const; uint64 AsTimeTagUnchecked() const; bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; } double AsDouble() const; double AsDoubleUnchecked() const; bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; } const char* AsString() const; const char* AsStringUnchecked() const { return argument_; } bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; } const char* AsSymbol() const; const char* AsSymbolUnchecked() const { return argument_; } bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; } void AsBlob( const void*& data, unsigned long& size ) const; void AsBlobUnchecked( const void*& data, unsigned long& size ) const; private: const char *typeTag_; const char *argument_; }; class ReceivedMessageArgumentIterator{ public: ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) : value_( typeTags, arguments ) {} ReceivedMessageArgumentIterator operator++() { Advance(); return *this; } ReceivedMessageArgumentIterator operator++(int) { ReceivedMessageArgumentIterator old( *this ); Advance(); return old; } const ReceivedMessageArgument& operator*() const { return value_; } const ReceivedMessageArgument* operator->() const { return &value_; } friend bool operator==(const ReceivedMessageArgumentIterator& lhs, const ReceivedMessageArgumentIterator& rhs ); private: ReceivedMessageArgument value_; void Advance(); bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const { return value_.typeTag_ == rhs.value_.typeTag_; } }; inline bool operator==(const ReceivedMessageArgumentIterator& lhs, const ReceivedMessageArgumentIterator& rhs ) { return lhs.IsEqualTo( rhs ); } inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, const ReceivedMessageArgumentIterator& rhs ) { return !( lhs == rhs ); } class ReceivedMessageArgumentStream{ friend class ReceivedMessage; ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, const ReceivedMessageArgumentIterator& end ) : p_( begin ) , end_( end ) {} ReceivedMessageArgumentIterator p_, end_; public: // end of stream bool Eos() const { return p_ == end_; } ReceivedMessageArgumentStream& operator>>( bool& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsBool(); return *this; } // not sure if it would be useful to stream Nil and Infinitum // for now it's not possible ReceivedMessageArgumentStream& operator>>( int32& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsInt32(); return *this; } ReceivedMessageArgumentStream& operator>>( float& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsFloat(); return *this; } ReceivedMessageArgumentStream& operator>>( char& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsChar(); return *this; } ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs.value = (*p_++).AsRgbaColor(); return *this; } ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs.value = (*p_++).AsMidiMessage(); return *this; } ReceivedMessageArgumentStream& operator>>( int64& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsInt64(); return *this; } ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs.value = (*p_++).AsTimeTag(); return *this; } ReceivedMessageArgumentStream& operator>>( double& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsDouble(); return *this; } ReceivedMessageArgumentStream& operator>>( Blob& rhs ) { if( Eos() ) throw MissingArgumentException(); (*p_++).AsBlob( rhs.data, rhs.size ); return *this; } ReceivedMessageArgumentStream& operator>>( const char*& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs = (*p_++).AsString(); return *this; } ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) { if( Eos() ) throw MissingArgumentException(); rhs.value = (*p_++).AsSymbol(); return *this; } ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) { if( !Eos() ) throw ExcessArgumentException(); return *this; } }; class ReceivedMessage{ void Init( const char *bundle, unsigned long size ); public: explicit ReceivedMessage( const ReceivedPacket& packet ); explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); const char *AddressPattern() const { return addressPattern_; } // Support for non-standad SuperCollider integer address patterns: bool AddressPatternIsUInt32() const; uint32 AddressPatternAsUInt32() const; unsigned long ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } const char *TypeTags() const { return typeTagsBegin_; } typedef ReceivedMessageArgumentIterator const_iterator; ReceivedMessageArgumentIterator ArgumentsBegin() const { return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); } ReceivedMessageArgumentIterator ArgumentsEnd() const { return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); } ReceivedMessageArgumentStream ArgumentStream() const { return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); } private: const char *addressPattern_; const char *typeTagsBegin_; const char *typeTagsEnd_; const char *arguments_; }; class ReceivedBundle{ void Init( const char *message, unsigned long size ); public: explicit ReceivedBundle( const ReceivedPacket& packet ); explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); uint64 TimeTag() const; unsigned long ElementCount() const { return elementCount_; } typedef ReceivedBundleElementIterator const_iterator; ReceivedBundleElementIterator ElementsBegin() const { return ReceivedBundleElementIterator( timeTag_ + 8 ); } ReceivedBundleElementIterator ElementsEnd() const { return ReceivedBundleElementIterator( end_ ); } private: const char *timeTag_; const char *end_; unsigned long elementCount_; }; } // namespace osc #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */ oscpack-1.0.2/osc/OscTypes.cpp0000644000175000017500000000314610530430402016043 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscTypes.h" namespace osc{ BundleInitiator BeginBundleImmediate(1); BundleTerminator EndBundle; MessageTerminator EndMessage; NilType Nil; InfinitumType Infinitum; } // namespace osc oscpack-1.0.2/osc/OscOutboundPacketStream.h0000644000175000017500000001166210530430402020511 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCOUTBOUNDPACKET_H #define INCLUDED_OSCOUTBOUNDPACKET_H #include "OscTypes.h" #include "OscException.h" namespace osc{ class OutOfBufferMemoryException : public Exception{ public: OutOfBufferMemoryException( const char *w="out of buffer memory" ) : Exception( w ) {} }; class BundleNotInProgressException : public Exception{ public: BundleNotInProgressException( const char *w="call to EndBundle when bundle is not in progress" ) : Exception( w ) {} }; class MessageInProgressException : public Exception{ public: MessageInProgressException( const char *w="opening or closing bundle or message while message is in progress" ) : Exception( w ) {} }; class MessageNotInProgressException : public Exception{ public: MessageNotInProgressException( const char *w="call to EndMessage when message is not in progress" ) : Exception( w ) {} }; class OutboundPacketStream{ public: OutboundPacketStream( char *buffer, unsigned long capacity ); ~OutboundPacketStream(); void Clear(); unsigned int Capacity() const; // invariant: size() is valid even while building a message. unsigned int Size() const; const char *Data() const; // indicates that all messages have been closed with a matching EndMessage // and all bundles have been closed with a matching EndBundle bool IsReady() const; bool IsMessageInProgress() const; bool IsBundleInProgress() const; OutboundPacketStream& operator<<( const BundleInitiator& rhs ); OutboundPacketStream& operator<<( const BundleTerminator& rhs ); OutboundPacketStream& operator<<( const BeginMessage& rhs ); OutboundPacketStream& operator<<( const MessageTerminator& rhs ); OutboundPacketStream& operator<<( bool rhs ); OutboundPacketStream& operator<<( const NilType& rhs ); OutboundPacketStream& operator<<( const InfinitumType& rhs ); OutboundPacketStream& operator<<( int32 rhs ); #ifndef x86_64 OutboundPacketStream& operator<<( int rhs ) { *this << (int32)rhs; return *this; } #endif OutboundPacketStream& operator<<( float rhs ); OutboundPacketStream& operator<<( char rhs ); OutboundPacketStream& operator<<( const RgbaColor& rhs ); OutboundPacketStream& operator<<( const MidiMessage& rhs ); OutboundPacketStream& operator<<( int64 rhs ); OutboundPacketStream& operator<<( const TimeTag& rhs ); OutboundPacketStream& operator<<( double rhs ); OutboundPacketStream& operator<<( const char* rhs ); OutboundPacketStream& operator<<( const Symbol& rhs ); OutboundPacketStream& operator<<( const Blob& rhs ); private: char *BeginElement( char *beginPtr ); void EndElement( char *endPtr ); bool ElementSizeSlotRequired() const; void CheckForAvailableBundleSpace(); void CheckForAvailableMessageSpace( const char *addressPattern ); void CheckForAvailableArgumentSpace( long argumentLength ); char *data_; char *end_; char *typeTagsCurrent_; // stored in reverse order char *messageCursor_; char *argumentCurrent_; // elementSizePtr_ has two special values: 0 indicates that a bundle // isn't open, and elementSizePtr_==data_ indicates that a bundle is // open but that it doesn't have a size slot (ie the outermost bundle) uint32 *elementSizePtr_; bool messageIsInProgress_; }; } // namespace osc #endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */ oscpack-1.0.2/osc/OscException.h0000644000175000017500000000402610530430402016340 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSC_EXCEPTION_H #define INCLUDED_OSC_EXCEPTION_H #include namespace osc{ class Exception : public std::exception { const char *what_; public: Exception() throw() {} Exception( const Exception& src ) throw() : what_( src.what_ ) {} Exception( const char *w ) throw() : what_( w ) {} Exception& operator=( const Exception& src ) throw() { what_ = src.what_; return *this; } virtual ~Exception() throw() {} virtual const char* what() const throw() { return what_; } }; } // namespace osc #endif /* INCLUDED_OSC_EXCEPTION_H */ oscpack-1.0.2/osc/MessageMappingOscPacketListener.h0000644000175000017500000000517710530430402022150 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H #define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H #include #include #include "OscPacketListener.h" namespace osc{ template< class T > class MessageMappingOscPacketListener : public OscPacketListener{ public: typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&); protected: void RegisterMessageFunction( const char *addressPattern, function_type f ) { functions_.insert( std::make_pair( addressPattern, f ) ); } virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ) { typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); if( i != functions_.end() ) (dynamic_cast(this)->*(i->second))( m, remoteEndpoint ); } private: struct cstr_compare{ bool operator()( const char *lhs, const char *rhs ) const { return strcmp( lhs, rhs ) < 0; } }; typedef std::map function_map_type; function_map_type functions_; }; } // namespace osc #endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */oscpack-1.0.2/osc/OscPrintReceivedElements.h0000644000175000017500000000401710530430402020642 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H #define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H #include #ifndef INCLUDED_OSCRECEIVEDELEMENTS_H #include "OscReceivedElements.h" #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */ namespace osc{ std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ); std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg ); std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ); std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); } // namespace osc #endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */ oscpack-1.0.2/osc/OscTypes.h0000644000175000017500000001013610530430402015505 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCTYPES_H #define INCLUDED_OSCTYPES_H namespace osc{ // basic types #if defined(__BORLANDC__) || defined(_MSC_VER) typedef __int64 int64; typedef unsigned __int64 uint64; #else typedef long long int64; typedef unsigned long long uint64; #endif #ifdef x86_64 typedef signed int int32; typedef unsigned int uint32; #else typedef signed long int32; typedef unsigned long uint32; #endif enum TypeTagValues { TRUE_TYPE_TAG = 'T', FALSE_TYPE_TAG = 'F', NIL_TYPE_TAG = 'N', INFINITUM_TYPE_TAG = 'I', INT32_TYPE_TAG = 'i', FLOAT_TYPE_TAG = 'f', CHAR_TYPE_TAG = 'c', RGBA_COLOR_TYPE_TAG = 'r', MIDI_MESSAGE_TYPE_TAG = 'm', INT64_TYPE_TAG = 'h', TIME_TAG_TYPE_TAG = 't', DOUBLE_TYPE_TAG = 'd', STRING_TYPE_TAG = 's', SYMBOL_TYPE_TAG = 'S', BLOB_TYPE_TAG = 'b' }; // i/o manipulators used for streaming interfaces struct BundleInitiator{ explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {} uint64 timeTag; }; extern BundleInitiator BeginBundleImmediate; inline BundleInitiator BeginBundle( uint64 timeTag=1 ) { return BundleInitiator(timeTag); } struct BundleTerminator{ }; extern BundleTerminator EndBundle; struct BeginMessage{ explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {} const char *addressPattern; }; struct MessageTerminator{ }; extern MessageTerminator EndMessage; // osc specific types. they are defined as structs so they can be used // as separately identifiable types with the streaming operators. struct NilType{ }; extern NilType Nil; struct InfinitumType{ }; extern InfinitumType Infinitum; struct RgbaColor{ RgbaColor() {} explicit RgbaColor( uint32 value_ ) : value( value_ ) {} uint32 value; operator uint32() const { return value; } }; struct MidiMessage{ MidiMessage() {} explicit MidiMessage( uint32 value_ ) : value( value_ ) {} uint32 value; operator uint32() const { return value; } }; struct TimeTag{ TimeTag() {} explicit TimeTag( uint64 value_ ) : value( value_ ) {} uint64 value; operator uint64() const { return value; } }; struct Symbol{ Symbol() {} explicit Symbol( const char* value_ ) : value( value_ ) {} const char* value; operator const char *() const { return value; } }; struct Blob{ Blob() {} explicit Blob( const void* data_, unsigned long size_ ) : data( data_ ), size( size_ ) {} const void* data; unsigned long size; }; } // namespace osc #endif /* INCLUDED_OSCTYPES_H */ oscpack-1.0.2/osc/OscOutboundPacketStream.cpp0000644000175000017500000003576210530430402021053 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscOutboundPacketStream.h" #include #include #include #if defined(__WIN32__) || defined(WIN32) #include // for alloca #endif #include "OscHostEndianness.h" namespace osc{ static void FromInt32( char *p, int32 x ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::int32 i; char c[4]; } u; u.i = x; p[3] = u.c[0]; p[2] = u.c[1]; p[1] = u.c[2]; p[0] = u.c[3]; #else *reinterpret_cast(p) = x; #endif } static void FromUInt32( char *p, uint32 x ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::uint32 i; char c[4]; } u; u.i = x; p[3] = u.c[0]; p[2] = u.c[1]; p[1] = u.c[2]; p[0] = u.c[3]; #else *reinterpret_cast(p) = x; #endif } static void FromInt64( char *p, int64 x ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::int64 i; char c[8]; } u; u.i = x; p[7] = u.c[0]; p[6] = u.c[1]; p[5] = u.c[2]; p[4] = u.c[3]; p[3] = u.c[4]; p[2] = u.c[5]; p[1] = u.c[6]; p[0] = u.c[7]; #else *reinterpret_cast(p) = x; #endif } static void FromUInt64( char *p, uint64 x ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::uint64 i; char c[8]; } u; u.i = x; p[7] = u.c[0]; p[6] = u.c[1]; p[5] = u.c[2]; p[4] = u.c[3]; p[3] = u.c[4]; p[2] = u.c[5]; p[1] = u.c[6]; p[0] = u.c[7]; #else *reinterpret_cast(p) = x; #endif } static inline long RoundUp4( long x ) { return ((x-1) & (~0x03L)) + 4; } OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity ) : data_( buffer ) , end_( data_ + capacity ) , typeTagsCurrent_( end_ ) , messageCursor_( data_ ) , argumentCurrent_( data_ ) , elementSizePtr_( 0 ) , messageIsInProgress_( false ) { } OutboundPacketStream::~OutboundPacketStream() { } char *OutboundPacketStream::BeginElement( char *beginPtr ) { if( elementSizePtr_ == 0 ){ elementSizePtr_ = reinterpret_cast(data_); return beginPtr; }else{ // store an offset to the old element size ptr in the element size slot // we store an offset rather than the actual pointer to be 64 bit clean. *reinterpret_cast(beginPtr) = (uint32)(reinterpret_cast(elementSizePtr_) - data_); elementSizePtr_ = reinterpret_cast(beginPtr); return beginPtr + 4; } } void OutboundPacketStream::EndElement( char *endPtr ) { assert( elementSizePtr_ != 0 ); if( elementSizePtr_ == reinterpret_cast(data_) ){ elementSizePtr_ = 0; }else{ // while building an element, an offset to the containing element's // size slot is stored in the elements size slot (or a ptr to data_ // if there is no containing element). We retrieve that here uint32 *previousElementSizePtr = (uint32*)(data_ + *reinterpret_cast(elementSizePtr_)); // then we store the element size in the slot, note that the element // size does not include the size slot, hence the - 4 below. uint32 elementSize = (endPtr - reinterpret_cast(elementSizePtr_)) - 4; FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); // finally, we reset the element size ptr to the containing element elementSizePtr_ = previousElementSizePtr; } } bool OutboundPacketStream::ElementSizeSlotRequired() const { return (elementSizePtr_ != 0); } void OutboundPacketStream::CheckForAvailableBundleSpace() { unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; if( required > Capacity() ) throw OutOfBufferMemoryException(); } void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) { // plus 4 for at least four bytes of type tag unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + RoundUp4(strlen(addressPattern) + 1) + 4; if( required > Capacity() ) throw OutOfBufferMemoryException(); } void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength ) { // plus three for extra type tag, comma and null terminator unsigned long required = (argumentCurrent_ - data_) + argumentLength + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); if( required > Capacity() ) throw OutOfBufferMemoryException(); } void OutboundPacketStream::Clear() { typeTagsCurrent_ = end_; messageCursor_ = data_; argumentCurrent_ = data_; elementSizePtr_ = 0; messageIsInProgress_ = false; } unsigned int OutboundPacketStream::Capacity() const { return end_ - data_; } unsigned int OutboundPacketStream::Size() const { unsigned int result = argumentCurrent_ - data_; if( IsMessageInProgress() ){ // account for the length of the type tag string. the total type tag // includes an initial comma, plus at least one terminating \0 result += RoundUp4( (end_ - typeTagsCurrent_) + 2 ); } return result; } const char *OutboundPacketStream::Data() const { return data_; } bool OutboundPacketStream::IsReady() const { return (!IsMessageInProgress() && !IsBundleInProgress()); } bool OutboundPacketStream::IsMessageInProgress() const { return messageIsInProgress_; } bool OutboundPacketStream::IsBundleInProgress() const { return (elementSizePtr_ != 0); } OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) { if( IsMessageInProgress() ) throw MessageInProgressException(); CheckForAvailableBundleSpace(); messageCursor_ = BeginElement( messageCursor_ ); memcpy( messageCursor_, "#bundle\0", 8 ); FromUInt64( messageCursor_ + 8, rhs.timeTag ); messageCursor_ += 16; argumentCurrent_ = messageCursor_; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs ) { (void) rhs; if( !IsBundleInProgress() ) throw BundleNotInProgressException(); if( IsMessageInProgress() ) throw MessageInProgressException(); EndElement( messageCursor_ ); return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) { if( IsMessageInProgress() ) throw MessageInProgressException(); CheckForAvailableMessageSpace( rhs.addressPattern ); messageCursor_ = BeginElement( messageCursor_ ); strcpy( messageCursor_, rhs.addressPattern ); unsigned long rhsLength = strlen(rhs.addressPattern); messageCursor_ += rhsLength + 1; // zero pad to 4-byte boundary unsigned long i = rhsLength + 1; while( i & 0x3 ){ *messageCursor_++ = '\0'; ++i; } argumentCurrent_ = messageCursor_; typeTagsCurrent_ = end_; messageIsInProgress_ = true; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs ) { (void) rhs; if( !IsMessageInProgress() ) throw MessageNotInProgressException(); int typeTagsCount = end_ - typeTagsCurrent_; if( typeTagsCount ){ char *tempTypeTags = (char*)alloca(typeTagsCount); memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); // slot size includes comma and null terminator int typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); uint32 argumentsSize = argumentCurrent_ - messageCursor_; memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); messageCursor_[0] = ','; // copy type tags in reverse (really forward) order for( int i=0; i < typeTagsCount; ++i ) messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; char *p = messageCursor_ + 1 + typeTagsCount; for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) *p++ = '\0'; typeTagsCurrent_ = end_; // advance messageCursor_ for next message messageCursor_ += typeTagSlotSize + argumentsSize; }else{ // send an empty type tags string memcpy( messageCursor_, ",\0\0\0", 4 ); // advance messageCursor_ for next message messageCursor_ += 4; } argumentCurrent_ = messageCursor_; EndElement( messageCursor_ ); messageIsInProgress_ = false; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) { CheckForAvailableArgumentSpace(0); *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG); return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) { (void) rhs; CheckForAvailableArgumentSpace(0); *(--typeTagsCurrent_) = NIL_TYPE_TAG; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) { (void) rhs; CheckForAvailableArgumentSpace(0); *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) { CheckForAvailableArgumentSpace(4); *(--typeTagsCurrent_) = INT32_TYPE_TAG; FromInt32( argumentCurrent_, rhs ); argumentCurrent_ += 4; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) { CheckForAvailableArgumentSpace(4); *(--typeTagsCurrent_) = FLOAT_TYPE_TAG; #ifdef OSC_HOST_LITTLE_ENDIAN union{ float f; char c[4]; } u; u.f = rhs; argumentCurrent_[3] = u.c[0]; argumentCurrent_[2] = u.c[1]; argumentCurrent_[1] = u.c[2]; argumentCurrent_[0] = u.c[3]; #else *reinterpret_cast(argumentCurrent_) = rhs; #endif argumentCurrent_ += 4; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) { CheckForAvailableArgumentSpace(4); *(--typeTagsCurrent_) = CHAR_TYPE_TAG; FromInt32( argumentCurrent_, rhs ); argumentCurrent_ += 4; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) { CheckForAvailableArgumentSpace(4); *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG; FromUInt32( argumentCurrent_, rhs ); argumentCurrent_ += 4; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) { CheckForAvailableArgumentSpace(4); *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG; FromUInt32( argumentCurrent_, rhs ); argumentCurrent_ += 4; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) { CheckForAvailableArgumentSpace(8); *(--typeTagsCurrent_) = INT64_TYPE_TAG; FromInt64( argumentCurrent_, rhs ); argumentCurrent_ += 8; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) { CheckForAvailableArgumentSpace(8); *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG; FromUInt64( argumentCurrent_, rhs ); argumentCurrent_ += 8; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) { CheckForAvailableArgumentSpace(8); *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG; #ifdef OSC_HOST_LITTLE_ENDIAN union{ double f; char c[8]; } u; u.f = rhs; argumentCurrent_[7] = u.c[0]; argumentCurrent_[6] = u.c[1]; argumentCurrent_[5] = u.c[2]; argumentCurrent_[4] = u.c[3]; argumentCurrent_[3] = u.c[4]; argumentCurrent_[2] = u.c[5]; argumentCurrent_[1] = u.c[6]; argumentCurrent_[0] = u.c[7]; #else *reinterpret_cast(argumentCurrent_) = rhs; #endif argumentCurrent_ += 8; return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) { CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) ); *(--typeTagsCurrent_) = STRING_TYPE_TAG; strcpy( argumentCurrent_, rhs ); unsigned long rhsLength = strlen(rhs); argumentCurrent_ += rhsLength + 1; // zero pad to 4-byte boundary unsigned long i = rhsLength + 1; while( i & 0x3 ){ *argumentCurrent_++ = '\0'; ++i; } return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) { CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) ); *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; strcpy( argumentCurrent_, rhs ); unsigned long rhsLength = strlen(rhs); argumentCurrent_ += rhsLength + 1; // zero pad to 4-byte boundary unsigned long i = rhsLength + 1; while( i & 0x3 ){ *argumentCurrent_++ = '\0'; ++i; } return *this; } OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) { CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); *(--typeTagsCurrent_) = BLOB_TYPE_TAG; FromUInt32( argumentCurrent_, rhs.size ); argumentCurrent_ += 4; memcpy( argumentCurrent_, rhs.data, rhs.size ); argumentCurrent_ += rhs.size; // zero pad to 4-byte boundary unsigned long i = rhs.size; while( i & 0x3 ){ *argumentCurrent_++ = '\0'; ++i; } return *this; } } // namespace osc oscpack-1.0.2/osc/OscPacketListener.h0000644000175000017500000000516410530430402017323 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCPACKETLISTENER_H #define INCLUDED_OSCPACKETLISTENER_H #include "OscReceivedElements.h" #include "../ip/PacketListener.h" namespace osc{ class OscPacketListener : public PacketListener{ protected: virtual void ProcessBundle( const osc::ReceivedBundle& b, const IpEndpointName& remoteEndpoint ) { // ignore bundle time tag for now for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ if( i->IsBundle() ) ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); else ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); } } virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ) = 0; public: virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { osc::ReceivedPacket p( data, size ); if( p.IsBundle() ) ProcessBundle( ReceivedBundle(p), remoteEndpoint ); else ProcessMessage( ReceivedMessage(p), remoteEndpoint ); } }; } // namespace osc #endif /* INCLUDED_OSCPACKETLISTENER_H */ oscpack-1.0.2/osc/OscReceivedElements.cpp0000644000175000017500000004402610530670320020171 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscReceivedElements.h" #include #include "OscHostEndianness.h" namespace osc{ // return the first 4 byte boundary after the end of a str4 // be careful about calling this version if you don't know whether // the string is terminated correctly. static inline const char* FindStr4End( const char *p ) { if( p[0] == '\0' ) // special case for SuperCollider integer address pattern return p + 4; p += 3; while( *p ) p += 4; return p + 1; } // return the first 4 byte boundary after the end of a str4 // returns 0 if p == end or if the string is unterminated static inline const char* FindStr4End( const char *p, const char *end ) { if( p >= end ) return 0; if( p[0] == '\0' ) // special case for SuperCollider integer address pattern return p + 4; p += 3; end -= 1; while( p < end && *p ) p += 4; if( *p ) return 0; else return p + 1; } static inline unsigned long RoundUp4( unsigned long x ) { unsigned long remainder = x & 0x3UL; if( remainder ) return x + (4 - remainder); else return x; } static inline int32 ToInt32( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::int32 i; char c[4]; } u; u.c[0] = p[3]; u.c[1] = p[2]; u.c[2] = p[1]; u.c[3] = p[0]; return u.i; #else return *(int32*)p; #endif } static inline uint32 ToUInt32( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::uint32 i; char c[4]; } u; u.c[0] = p[3]; u.c[1] = p[2]; u.c[2] = p[1]; u.c[3] = p[0]; return u.i; #else return *(uint32*)p; #endif } int64 ToInt64( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::int64 i; char c[4]; } u; u.c[0] = p[7]; u.c[1] = p[6]; u.c[2] = p[5]; u.c[3] = p[4]; u.c[4] = p[3]; u.c[5] = p[2]; u.c[6] = p[1]; u.c[7] = p[0]; return u.i; #else return *(int64*)p; #endif } uint64 ToUInt64( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::uint64 i; char c[4]; } u; u.c[0] = p[7]; u.c[1] = p[6]; u.c[2] = p[5]; u.c[3] = p[4]; u.c[4] = p[3]; u.c[5] = p[2]; u.c[6] = p[1]; u.c[7] = p[0]; return u.i; #else return *(uint64*)p; #endif } //------------------------------------------------------------------------------ bool ReceivedPacket::IsBundle() const { return (Size() > 0 && Contents()[0] == '#'); } //------------------------------------------------------------------------------ bool ReceivedBundleElement::IsBundle() const { return (Size() > 0 && Contents()[0] == '#'); } int32 ReceivedBundleElement::Size() const { return ToUInt32( size_ ); } //------------------------------------------------------------------------------ bool ReceivedMessageArgument::AsBool() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == TRUE_TYPE_TAG ) return true; else if( *typeTag_ == FALSE_TYPE_TAG ) return false; else throw WrongArgumentTypeException(); } bool ReceivedMessageArgument::AsBoolUnchecked() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == TRUE_TYPE_TAG ) return true; else return false; } int32 ReceivedMessageArgument::AsInt32() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == INT32_TYPE_TAG ) return AsInt32Unchecked(); else throw WrongArgumentTypeException(); } int32 ReceivedMessageArgument::AsInt32Unchecked() const { #ifdef OSC_HOST_LITTLE_ENDIAN union{ osc::int32 i; char c[4]; } u; u.c[0] = argument_[3]; u.c[1] = argument_[2]; u.c[2] = argument_[1]; u.c[3] = argument_[0]; return u.i; #else return *(int32*)argument_; #endif } float ReceivedMessageArgument::AsFloat() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == FLOAT_TYPE_TAG ) return AsFloatUnchecked(); else throw WrongArgumentTypeException(); } float ReceivedMessageArgument::AsFloatUnchecked() const { #ifdef OSC_HOST_LITTLE_ENDIAN union{ float f; char c[4]; } u; u.c[0] = argument_[3]; u.c[1] = argument_[2]; u.c[2] = argument_[1]; u.c[3] = argument_[0]; return u.f; #else return *(float*)argument_; #endif } char ReceivedMessageArgument::AsChar() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == CHAR_TYPE_TAG ) return AsCharUnchecked(); else throw WrongArgumentTypeException(); } char ReceivedMessageArgument::AsCharUnchecked() const { return (char)ToInt32( argument_ ); } uint32 ReceivedMessageArgument::AsRgbaColor() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == RGBA_COLOR_TYPE_TAG ) return AsRgbaColorUnchecked(); else throw WrongArgumentTypeException(); } uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const { return ToUInt32( argument_ ); } uint32 ReceivedMessageArgument::AsMidiMessage() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG ) return AsMidiMessageUnchecked(); else throw WrongArgumentTypeException(); } uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const { return ToUInt32( argument_ ); } int64 ReceivedMessageArgument::AsInt64() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == INT64_TYPE_TAG ) return AsInt64Unchecked(); else throw WrongArgumentTypeException(); } int64 ReceivedMessageArgument::AsInt64Unchecked() const { return ToInt64( argument_ ); } uint64 ReceivedMessageArgument::AsTimeTag() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == TIME_TAG_TYPE_TAG ) return AsTimeTagUnchecked(); else throw WrongArgumentTypeException(); } uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const { return ToUInt64( argument_ ); } double ReceivedMessageArgument::AsDouble() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == DOUBLE_TYPE_TAG ) return AsDoubleUnchecked(); else throw WrongArgumentTypeException(); } double ReceivedMessageArgument::AsDoubleUnchecked() const { #ifdef OSC_HOST_LITTLE_ENDIAN union{ double d; char c[8]; } u; u.c[0] = argument_[7]; u.c[1] = argument_[6]; u.c[2] = argument_[5]; u.c[3] = argument_[4]; u.c[4] = argument_[3]; u.c[5] = argument_[2]; u.c[6] = argument_[1]; u.c[7] = argument_[0]; return u.d; #else return *(double*)argument_; #endif } const char* ReceivedMessageArgument::AsString() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == STRING_TYPE_TAG ) return argument_; else throw WrongArgumentTypeException(); } const char* ReceivedMessageArgument::AsSymbol() const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == SYMBOL_TYPE_TAG ) return argument_; else throw WrongArgumentTypeException(); } void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const { if( !typeTag_ ) throw MissingArgumentException(); else if( *typeTag_ == BLOB_TYPE_TAG ) AsBlobUnchecked( data, size ); else throw WrongArgumentTypeException(); } void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const { size = ToUInt32( argument_ ); data = (void*)(argument_+4); } //------------------------------------------------------------------------------ void ReceivedMessageArgumentIterator::Advance() { if( !value_.typeTag_ ) return; switch( *value_.typeTag_++ ){ case '\0': // don't advance past end --value_.typeTag_; break; case TRUE_TYPE_TAG: case FALSE_TYPE_TAG: case NIL_TYPE_TAG: case INFINITUM_TYPE_TAG: // zero length break; case INT32_TYPE_TAG: case FLOAT_TYPE_TAG: case CHAR_TYPE_TAG: case RGBA_COLOR_TYPE_TAG: case MIDI_MESSAGE_TYPE_TAG: value_.argument_ += 4; break; case INT64_TYPE_TAG: case TIME_TAG_TYPE_TAG: case DOUBLE_TYPE_TAG: value_.argument_ += 8; break; case STRING_TYPE_TAG: case SYMBOL_TYPE_TAG: // we use the unsafe function FindStr4End(char*) here because all of // the arguments have already been validated in // ReceivedMessage::Init() below. value_.argument_ = FindStr4End( value_.argument_ ); break; case BLOB_TYPE_TAG: { uint32 blobSize = ToUInt32( value_.argument_ ); value_.argument_ = value_.argument_ + 4 + RoundUp4( blobSize ); } break; default: // unknown type tag // don't advance --value_.typeTag_; break; // not handled: // [ Indicates the beginning of an array. The tags following are for // data in the Array until a close brace tag is reached. // ] Indicates the end of an array. } } //------------------------------------------------------------------------------ ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet ) : addressPattern_( packet.Contents() ) { Init( packet.Contents(), packet.Size() ); } ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement ) : addressPattern_( bundleElement.Contents() ) { Init( bundleElement.Contents(), bundleElement.Size() ); } bool ReceivedMessage::AddressPatternIsUInt32() const { return (addressPattern_[0] == '\0'); } uint32 ReceivedMessage::AddressPatternAsUInt32() const { return ToUInt32( addressPattern_ ); } void ReceivedMessage::Init( const char *message, unsigned long size ) { if( size == 0 ) throw MalformedMessageException( "zero length messages not permitted" ); if( (size & 0x03L) != 0 ) throw MalformedMessageException( "message size must be multiple of four" ); const char *end = message + size; typeTagsBegin_ = FindStr4End( addressPattern_, end ); if( typeTagsBegin_ == 0 ){ // address pattern was not terminated before end throw MalformedMessageException( "unterminated address pattern" ); } if( typeTagsBegin_ == end ){ // message consists of only the address pattern - no arguments or type tags. typeTagsBegin_ = 0; typeTagsEnd_ = 0; arguments_ = 0; }else{ if( *typeTagsBegin_ != ',' ) throw MalformedMessageException( "type tags not present" ); if( *(typeTagsBegin_ + 1) == '\0' ){ // zero length type tags typeTagsBegin_ = 0; typeTagsEnd_ = 0; arguments_ = 0; }else{ // check that all arguments are present and well formed arguments_ = FindStr4End( typeTagsBegin_, end ); if( arguments_ == 0 ){ throw MalformedMessageException( "type tags were not terminated before end of message" ); } ++typeTagsBegin_; // advance past initial ',' const char *typeTag = typeTagsBegin_; const char *argument = arguments_; do{ switch( *typeTag ){ case TRUE_TYPE_TAG: case FALSE_TYPE_TAG: case NIL_TYPE_TAG: case INFINITUM_TYPE_TAG: // zero length break; case INT32_TYPE_TAG: case FLOAT_TYPE_TAG: case CHAR_TYPE_TAG: case RGBA_COLOR_TYPE_TAG: case MIDI_MESSAGE_TYPE_TAG: if( argument == end ) throw MalformedMessageException( "arguments exceed message size" ); argument += 4; if( argument > end ) throw MalformedMessageException( "arguments exceed message size" ); break; case INT64_TYPE_TAG: case TIME_TAG_TYPE_TAG: case DOUBLE_TYPE_TAG: if( argument == end ) throw MalformedMessageException( "arguments exceed message size" ); argument += 8; if( argument > end ) throw MalformedMessageException( "arguments exceed message size" ); break; case STRING_TYPE_TAG: case SYMBOL_TYPE_TAG: if( argument == end ) throw MalformedMessageException( "arguments exceed message size" ); argument = FindStr4End( argument, end ); if( argument == 0 ) throw MalformedMessageException( "unterminated string argument" ); break; case BLOB_TYPE_TAG: { if( argument + 4 > end ) MalformedMessageException( "arguments exceed message size" ); uint32 blobSize = ToUInt32( argument ); argument = argument + 4 + RoundUp4( blobSize ); if( argument > end ) MalformedMessageException( "arguments exceed message size" ); } break; default: throw MalformedMessageException( "unknown type tag" ); // not handled: // [ Indicates the beginning of an array. The tags following are for // data in the Array until a close brace tag is reached. // ] Indicates the end of an array. } }while( *++typeTag != '\0' ); typeTagsEnd_ = typeTag; } } } //------------------------------------------------------------------------------ ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet ) : elementCount_( 0 ) { Init( packet.Contents(), packet.Size() ); } ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement ) : elementCount_( 0 ) { Init( bundleElement.Contents(), bundleElement.Size() ); } void ReceivedBundle::Init( const char *bundle, unsigned long size ) { if( size < 16 ) throw MalformedBundleException( "packet too short for bundle" ); if( (size & 0x03L) != 0 ) throw MalformedBundleException( "bundle size must be multiple of four" ); if( bundle[0] != '#' || bundle[1] != 'b' || bundle[2] != 'u' || bundle[3] != 'n' || bundle[4] != 'd' || bundle[5] != 'l' || bundle[6] != 'e' || bundle[7] != '\0' ) throw MalformedBundleException( "bad bundle address pattern" ); end_ = bundle + size; timeTag_ = bundle + 8; const char *p = timeTag_ + 8; while( p < end_ ){ if( p + 4 > end_ ) throw MalformedBundleException( "packet too short for elementSize" ); uint32 elementSize = ToUInt32( p ); if( (elementSize & 0x03L) != 0 ) throw MalformedBundleException( "bundle element size must be multiple of four" ); p += 4 + elementSize; if( p > end_ ) throw MalformedBundleException( "packet too short for bundle element" ); ++elementCount_; } if( p != end_ ) throw MalformedBundleException( "bundle contents " ); } uint64 ReceivedBundle::TimeTag() const { return ToUInt64( timeTag_ ); } } // namespace osc oscpack-1.0.2/CHANGES0000644000175000017500000000643410530430404014002 0ustar mordredmordredSeptember 28, 2005 ------------------ Compared to the previous official snapshot (November 2004) the current version of oscpack includes a re-written set of network classes and some changes to the syntax of the networking code. It no longer uses threads, which means that you don't need to use sleep() if you are writing a simple single-threaded server, or you need to spawn your own threads in a more complex application. The list below summarises the changes if you are porting code from the previous release. - there are no longer any threads in oscpack. if you need to set up an asynchronous listener you can create your own thread and call Run on an instance of SocketReceiveMultiplexer or UdpListeningReceiveSocket (see ip/UdpSocket.h) yourself. - host byte order is now used for network (IP) addresses - functions which used to take two parameters now take an instance of IpEndpointName (see ip/IpEndpointName.h) this class has a number of convenient constructors for converting numbers and strings to internet addresses. For example there is one which takes a string and another that take the dotted address components as separate parameters. - The UdpTransmitPort class, formerly in UdpTransmitPort.h, is now called UdpTransmitSocket, which is simply a convenience class derived from UdpSocket (see ip/UdpSocket.h). Where you used to use the constructor UdpTransmitPort( address, port) now you can use UdpTransmitSocket( IpEndpointName( address, port ) ) or you can any of the other possible ctors to IpEndpointName () (see above). The Send() method is unchanged. - The packet listener base class is now located in ip/PacketListener.h instead of PacketListenerPort.h. The ProcessPacket method now has an additional parameter indicating the remote endpoint - The preferred way to set up listeners is with SocketReceiveMultiplexer (in ip/UdpSocket.h), this also allows attaching periodic timers. For simple applications which only listen to a single socket with no timers you can use UdpListeningReceiveSocket (also in UdpSocket.h) See osc/OscReceiveTest.cpp or osc/OscDump.cpp for examples of this. This is more or less equivalent to the UdpPacketListenerPort object in the old oscpack versions except that you need to explicitly call Run() before it will start receiving packets and it runs in the same thread, not a separate thread so Run() won't usually return. - Explicit calls to InitializeNetworking() and TerminateNetworking() are no longer required for simple applications (more complex windows applications should instantiate NetworkInitializer in main() or WinMain (see ip/NetworkingUtils.h/.cpp) - The OscPacketListener base class (OscPacketListener.h) was added to make traversing OSC packets easier, it handles bundle traversal automatically so you only need to process messages in your derived classes. - On Windows be sure to link with ws2_32.lib or you will see a linker error about WSAEventSelect not being found. Also you will need to link with winmm.lib for timeGetTime() oscpack-1.0.2/make.MinGW32.bat0000644000175000017500000000241710530432244015542 0ustar mordredmordreddel bin\OscUnitTests.exe del bin\OscDump.exe del bin\OscSendTests.exe del bin\OscReceiveTest.exe mkdir bin g++ tests\OscUnitTests.cpp osc\OscTypes.cpp osc\OscReceivedElements.cpp osc\OscPrintReceivedElements.cpp osc\OscOutboundPacketStream.cpp -Wall -I. -lws2_32 -o bin\OscUnitTests.exe g++ examples\OscDump.cpp osc\OscTypes.cpp osc\OscReceivedElements.cpp osc\OscPrintReceivedElements.cpp ip\win32\NetworkingUtils.cpp ip\win32\UdpSocket.cpp -Wall -I. -lws2_32 -lwinmm -o bin\OscDump.exe g++ examples\SimpleSend.cpp osc\OscTypes.cpp osc\OscOutboundPacketStream.cpp ip\win32\NetworkingUtils.cpp ip\win32\UdpSocket.cpp ip\IpEndpointName.cpp -Wall -I. -lws2_32 -lwinmm -o bin\SimpleSend.exe g++ examples\SimpleReceive.cpp osc\OscTypes.cpp osc\OscReceivedElements.cpp ip\win32\NetworkingUtils.cpp ip\win32\UdpSocket.cpp -Wall -I. -lws2_32 -lwinmm -o bin\SimpleReceive.exe g++ tests\OscSendTests.cpp osc\OscTypes.cpp osc\OscOutboundPacketStream.cpp ip\win32\NetworkingUtils.cpp ip\win32\UdpSocket.cpp ip\IpEndpointName.cpp -Wall -I. -lws2_32 -lwinmm -o bin\OscSendTests.exe g++ tests\OscReceiveTest.cpp osc\OscTypes.cpp osc\OscReceivedElements.cpp ip\win32\NetworkingUtils.cpp ip\win32\UdpSocket.cpp -Wall -I. -lws2_32 -lwinmm -o bin\OscReceiveTest.exe .\bin\OscUnitTests.exeoscpack-1.0.2/README0000644000175000017500000000675710530430404013677 0ustar mordredmordredoscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/code/oscpack Copyright (c) 2004-2005 Ross Bencina A simple C++ library for packing and unpacking OSC packets. Oscpack is simply a set of C++ classes for packing and unpacking OSC packets. Oscpack includes a minimal set of UDP networking classes for windows and posix which are sufficient for writing many OSC applications and servers, but you are encouraged to use another networking framework if it better suits your needs. Oscpack is not an OSC application framework, it doesn't include infrastructure for constructing or routing OSC namespaces, just classes for easily constructing, sending, receiving and parsing OSC packets. The library should also be easy to use for other transport methods (eg serial). The key goals of the oscpack library are: - to be a simple and complete implementation of OSC - to be portable to a wide variety of platforms - to allow easy development of robust OSC applications (for example it should be impossible to crash a server by sending it malformed packets, and difficult to create malformed packets.) Here's a summary of the key files: osc/OscReceivedElements -- classes for parsing a packet osc/OscPrintRecievedElements -- iostream << operators for printing packet elements osc/OscOutboundPacket -- a class for packing messages into a packet osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket tests/OscUnitTests -- unit test program for the OSC modules tests/OscSendTests -- examples of how to send messages tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests examples/OscDump -- a program that prints received OSC packets Building -------- In general the idea is that you will embed this source code in your projects as you see fit. The Makefile has an install rule for building a shared library and installing headers in usr/local. The Makefile works for Linux and MaxOS X except that if you are on a big endian machine such as PowerPC Macintosh you need to edit the line which sets the endianness to OSC_HOST_BIG_ENDIAN (see the makefile comment for details) or it won't work. If you want to build and install liboscpack as a library on OS X you also need to edit the $(LIBFILENAME) rule by commenting out the Linux case and uncommenting the OS X case since OS X uses different gcc flags for shared libraries. On Windows there is a batch file for doing a simple test build with MinGW gcc called make.MinGW32.bat. This will build the test executables and oscdump in ./bin and run the unit tests. -- If you fix anything or write a set of TCP send/recieve classes please consider sending me a patch. Thanks :) For more information about Open Sound Control, see: http://www.cnmat.berkeley.edu/OpenSoundControl/ Thanks to Till Bovermann for helping with POSIX networking code and Mac compatibility, and to Martin Kaltenbrunner and the rest of the reacTable team for giving me a reason to finish this library. Thanks to Merlijn Blaauw for reviewing the interfaces. Thanks to Xavier Oliver for additional help with Linux builds and POSIX implementation details. Portions developed at the Music Technology Group, Audiovisual Institute, University Pompeu Fabra, Barcelona, during my stay as a visiting researcher, November 2004 - September 2005. See the file LICENSE for information about distributing and using this code. oscpack-1.0.2/tests/0000755000175000017500000000000010530430402014140 5ustar mordredmordredoscpack-1.0.2/tests/OscSendTests.h0000644000175000017500000000314210530430402016672 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCSENDTESTS_H #define INCLUDED_OSCSENDTESTS_H namespace osc{ void RunSendTests( unsigned long address, int port ); } // namespace osc #endif /* INCLUDED_OSCSENDTESTS_H */ oscpack-1.0.2/tests/OscReceiveTest.cpp0000644000175000017500000002333610530430402017542 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscReceiveTest.h" #include #include #include "osc/OscReceivedElements.h" #include "ip/UdpSocket.h" #include "osc/OscPacketListener.h" namespace osc{ class OscReceiveTestPacketListener : public OscPacketListener{ protected: void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ) { // a more complex scheme involving std::map or some other method of // processing address patterns could be used here // (see MessageMappingOscPacketListener.h for example). however, the main // purpose of this example is to illustrate and test different argument // parsing methods try { // argument stream, and argument iterator, used in different // examples below. ReceivedMessageArgumentStream args = m.ArgumentStream(); ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); if( strcmp( m.AddressPattern(), "/test1" ) == 0 ){ // example #1: // parse an expected format using the argument stream interface: bool a1; osc::int32 a2; float a3; const char *a4; args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage; std::cout << "received '/test1' message with arguments: " << a1 << " " << a2 << " " << a3 << " " << a4 << "\n"; }else if( strcmp( m.AddressPattern(), "/test2" ) == 0 ){ // example #2: // parse an expected format using the argument iterator interface // this is a more complicated example of doing the same thing // as above. bool a1 = (arg++)->AsBool(); int a2 = (arg++)->AsInt32(); float a3 = (arg++)->AsFloat(); const char *a4 = (arg++)->AsString(); if( arg != m.ArgumentsEnd() ) throw ExcessArgumentException(); std::cout << "received '/test2' message with arguments: " << a1 << " " << a2 << " " << a3 << " " << a4 << "\n"; }else if( strcmp( m.AddressPattern(), "/test3" ) == 0 ){ // example #3: // parse a variable argument format using the argument iterator // interface. this is where it is necessary to use // argument iterators instead of streams. // When messages may contain arguments of varying type, you can // use the argument iterator interface to query the types at // runtime. this is more flexible that the argument stream // interface, which requires each argument to have a fixed type if( arg->IsBool() ){ bool a = (arg++)->AsBoolUnchecked(); std::cout << "received '/test3' message with bool argument: " << a << "\n"; }else if( arg->IsInt32() ){ int a = (arg++)->AsInt32Unchecked(); std::cout << "received '/test3' message with int32 argument: " << a << "\n"; }else if( arg->IsFloat() ){ float a = (arg++)->AsFloatUnchecked(); std::cout << "received '/test3' message with float argument: " << a << "\n"; }else if( arg->IsString() ){ const char *a = (arg++)->AsStringUnchecked(); std::cout << "received '/test3' message with string argument: '" << a << "'\n"; }else{ std::cout << "received '/test3' message with unexpected argument type\n"; } if( arg != m.ArgumentsEnd() ) throw ExcessArgumentException(); }else if( strcmp( m.AddressPattern(), "/no_arguments" ) == 0 ){ args >> osc::EndMessage; std::cout << "received '/no_arguments' message\n"; }else if( strcmp( m.AddressPattern(), "/a_bool" ) == 0 ){ bool a; args >> a >> osc::EndMessage; std::cout << "received '/a_bool' message: " << a << "\n"; }else if( strcmp( m.AddressPattern(), "/nil" ) == 0 ){ std::cout << "received '/nil' message\n"; }else if( strcmp( m.AddressPattern(), "/inf" ) == 0 ){ std::cout << "received '/inf' message\n"; }else if( strcmp( m.AddressPattern(), "/an_int" ) == 0 ){ osc::int32 a; args >> a >> osc::EndMessage; std::cout << "received '/an_int' message: " << a << "\n"; }else if( strcmp( m.AddressPattern(), "/a_float" ) == 0 ){ float a; args >> a >> osc::EndMessage; std::cout << "received '/a_float' message: " << a << "\n"; }else if( strcmp( m.AddressPattern(), "/a_char" ) == 0 ){ char a; args >> a >> osc::EndMessage; char s[2] = {0}; s[0] = a; std::cout << "received '/a_char' message: '" << s << "'\n"; }else if( strcmp( m.AddressPattern(), "/an_rgba_color" ) == 0 ){ osc::RgbaColor a; args >> a >> osc::EndMessage; std::cout << "received '/an_rgba_color' message: " << a.value << "\n"; }else if( strcmp( m.AddressPattern(), "/a_midi_message" ) == 0 ){ osc::MidiMessage a; args >> a >> osc::EndMessage; std::cout << "received '/a_midi_message' message: " << a.value << "\n"; }else if( strcmp( m.AddressPattern(), "/an_int64" ) == 0 ){ osc::int64 a; args >> a >> osc::EndMessage; std::cout << "received '/an_int64' message: " << a << "\n"; }else if( strcmp( m.AddressPattern(), "/a_time_tag" ) == 0 ){ osc::TimeTag a; args >> a >> osc::EndMessage; std::cout << "received '/a_time_tag' message: " << a.value << "\n"; }else if( strcmp( m.AddressPattern(), "/a_double" ) == 0 ){ double a; args >> a >> osc::EndMessage; std::cout << "received '/a_double' message: " << a << "\n"; }else if( strcmp( m.AddressPattern(), "/a_string" ) == 0 ){ const char *a; args >> a >> osc::EndMessage; std::cout << "received '/a_string' message: '" << a << "'\n"; }else if( strcmp( m.AddressPattern(), "/a_symbol" ) == 0 ){ osc::Symbol a; args >> a >> osc::EndMessage; std::cout << "received '/a_symbol' message: '" << a.value << "'\n"; }else if( strcmp( m.AddressPattern(), "/a_blob" ) == 0 ){ osc::Blob a; args >> a >> osc::EndMessage; std::cout << "received '/a_blob' message\n"; }else{ std::cout << "unrecognised address pattern: " << m.AddressPattern() << "\n"; } }catch( Exception& e ){ std::cout << "error while parsing message: " << m.AddressPattern() << ": " << e.what() << "\n"; } } }; void RunReceiveTest( int port ) { osc::OscReceiveTestPacketListener listener; UdpListeningReceiveSocket s( IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), &listener ); std::cout << "listening for input on port " << port << "...\n"; std::cout << "press ctrl-c to end\n"; s.RunUntilSigInt(); std::cout << "finishing.\n"; } } // namespace osc #ifndef NO_OSC_TEST_MAIN int main(int argc, char* argv[]) { if( argc >= 2 && strcmp( argv[1], "-h" ) == 0 ){ std::cout << "usage: OscReceiveTest [port]\n"; return 0; } int port = 7000; if( argc >= 2 ) port = atoi( argv[1] ); osc::RunReceiveTest( port ); return 0; } #endif /* NO_OSC_TEST_MAIN */ oscpack-1.0.2/tests/OscSendTests.cpp0000644000175000017500000001516110530430402017231 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscSendTests.h" #include #include #include "osc/OscOutboundPacketStream.h" #include "ip/UdpSocket.h" #include "ip/IpEndpointName.h" #define IP_MTU_SIZE 1536 namespace osc{ void RunSendTests( const IpEndpointName& host ) { char buffer[IP_MTU_SIZE]; osc::OutboundPacketStream p( buffer, IP_MTU_SIZE ); UdpTransmitSocket socket( host ); p.Clear(); p << osc::BeginMessage( "/test1" ) << true << 23 << (float)3.1415 << "hello" << osc::EndMessage; socket.Send( p.Data(), p.Size() ); // test1 message with too few arguments p.Clear(); p << osc::BeginMessage( "/test1" ) << true << osc::EndMessage; socket.Send( p.Data(), p.Size() ); // test1 message with too many arguments p.Clear(); p << osc::BeginMessage( "/test1" ) << true << 23 << (float)3.1415 << "hello" << 42 << osc::EndMessage; socket.Send( p.Data(), p.Size() ); // test1 message with wrong argument type p.Clear(); p << osc::BeginMessage( "/test1" ) << true << 1.0 << (float)3.1415 << "hello" << osc::EndMessage; socket.Send( p.Data(), p.Size() ); p.Clear(); p << osc::BeginMessage( "/test2" ) << true << 23 << (float)3.1415 << "hello" << osc::EndMessage; socket.Send( p.Data(), p.Size() ); // send four /test3 messages, each with a different type of argument p.Clear(); p << osc::BeginMessage( "/test3" ) << true << osc::EndMessage; socket.Send( p.Data(), p.Size() ); p.Clear(); p << osc::BeginMessage( "/test3" ) << 23 << osc::EndMessage; socket.Send( p.Data(), p.Size() ); p.Clear(); p << osc::BeginMessage( "/test3" ) << (float)3.1415 << osc::EndMessage; socket.Send( p.Data(), p.Size() ); p.Clear(); p << osc::BeginMessage( "/test3" ) << "hello" << osc::EndMessage; socket.Send( p.Data(), p.Size() ); // send a bundle p.Clear(); p << osc::BeginBundle(); p << osc::BeginMessage( "/no_arguments" ) << osc::EndMessage; p << osc::BeginMessage( "/a_bool" ) << true << osc::EndMessage; p << osc::BeginMessage( "/a_bool" ) << false << osc::EndMessage; p << osc::BeginMessage( "/a_bool" ) << (bool)1234 << osc::EndMessage; p << osc::BeginMessage( "/nil" ) << osc::Nil << osc::EndMessage; p << osc::BeginMessage( "/inf" ) << osc::Infinitum << osc::EndMessage; p << osc::BeginMessage( "/an_int" ) << 1234 << osc::EndMessage; p << osc::BeginMessage( "/a_float" ) << 3.1415926f << osc::EndMessage; p << osc::BeginMessage( "/a_char" ) << 'c' << osc::EndMessage; p << osc::BeginMessage( "/an_rgba_color" ) << osc::RgbaColor(0x22334455) << osc::EndMessage; p << osc::BeginMessage( "/a_midi_message" ) << MidiMessage(0x7F) << osc::EndMessage; p << osc::BeginMessage( "/an_int64" ) << (int64)(0xFFFFFFF) << osc::EndMessage; p << osc::BeginMessage( "/a_time_tag" ) << osc::TimeTag(0xFFFFFFFUL) << osc::EndMessage; p << osc::BeginMessage( "/a_double" ) << (double)3.1415926 << osc::EndMessage; p << osc::BeginMessage( "/a_string" ) << "hello world" << osc::EndMessage; p << osc::BeginMessage( "/a_symbol" ) << osc::Symbol("foobar") << osc::EndMessage; // blob { char blobData[] = "abcd"; p << osc::BeginMessage( "/a_blob" ) << osc::Blob( blobData, 4 ) << osc::EndMessage; } p << osc::EndBundle; socket.Send( p.Data(), p.Size() ); // nested bundles, and multiple messages in bundles... p.Clear(); p << osc::BeginBundle( 1234 ) << osc::BeginMessage( "/an_int" ) << 1 << osc::EndMessage << osc::BeginMessage( "/an_int" ) << 2 << osc::EndMessage << osc::BeginMessage( "/an_int" ) << 3 << osc::EndMessage << osc::BeginMessage( "/an_int" ) << 4 << osc::EndMessage << osc::BeginBundle( 12345 ) << osc::BeginMessage( "/an_int" ) << 5 << osc::EndMessage << osc::BeginMessage( "/an_int" ) << 6 << osc::EndMessage << osc::EndBundle << osc::EndBundle; socket.Send( p.Data(), p.Size() ); } } // namespace osc #ifndef NO_OSC_TEST_MAIN int main(int argc, char* argv[]) { if( argc >= 2 && strcmp( argv[1], "-h" ) == 0 ){ std::cout << "usage: OscSendTests [hostname [port]]\n"; return 0; } char *hostName = "localhost"; int port = 7000; if( argc >= 2 ) hostName = argv[1]; if( argc >= 3 ) port = atoi( argv[2] ); IpEndpointName host( hostName, port ); char hostIpAddress[ IpEndpointName::ADDRESS_STRING_LENGTH ]; host.AddressAsString( hostIpAddress ); std::cout << "sending test messages to " << hostName << " (" << hostIpAddress << ") on port " << port << "...\n"; osc::RunSendTests( host ); } #endif /* NO_OSC_TEST_MAIN */ oscpack-1.0.2/tests/OscReceiveTest.h0000644000175000017500000000312310530430402017177 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCRECEIVETEST_H #define INCLUDED_OSCRECEIVETEST_H namespace osc{ void RunReceiveTest( int port ); } // namespace osc #endif /* INCLUDED_OSCSENDTESTS_H */ oscpack-1.0.2/tests/OscUnitTests.h0000644000175000017500000000310110530430402016713 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef INCLUDED_OSCUNITTESTS_H #define INCLUDED_OSCUNITTESTS_H namespace osc{ void RunUnitTests(); } // namespace osc #endif /* INCLUDED_OSCUNITTESTS_H */ oscpack-1.0.2/tests/OscUnitTests.cpp0000644000175000017500000003342410530430402017261 0ustar mordredmordred/* oscpack -- Open Sound Control packet manipulation library http://www.audiomulch.com/~rossb/oscpack Copyright (c) 2004-2005 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "OscUnitTests.h" #include #include #include "osc/OscReceivedElements.h" #include "osc/OscPrintReceivedElements.h" #include "osc/OscOutboundPacketStream.h" namespace osc{ static int passCount_=0, failCount_=0; void PrintTestSummary() { std::cout << (passCount_+failCount_) << " tests run, " << passCount_ << " passed, " << failCount_ << " failed.\n"; } void pass_equality( const char *slhs, const char *srhs, const char *file, int line ) { ++passCount_; std::cout << file << "(" << line << "): PASSED : " << slhs << " == " << srhs << "\n"; } void fail_equality( const char *slhs, const char *srhs, const char *file, int line ) { ++failCount_; std::cout << file << "(" << line << "): FAILED : " << slhs << " != " << srhs << "\n"; } template void assertEqual_( const T& lhs, const T& rhs, const char *slhs, const char *srhs, const char *file, int line ) { if( lhs == rhs ) pass_equality( slhs, srhs, file, line ); else fail_equality( slhs, srhs, file, line ); } template void assertEqual_( const T* lhs, const T* rhs, const char *slhs, const char *srhs, const char *file, int line ) { if( lhs == rhs ) pass_equality( slhs, srhs, file, line ); else fail_equality( slhs, srhs, file, line ); } template <> void assertEqual_( const char* lhs, const char* rhs, const char *slhs, const char *srhs, const char *file, int line ) { if( strcmp( lhs, rhs ) == 0 ) pass_equality( slhs, srhs, file, line ); else fail_equality( slhs, srhs, file, line ); } #define assertEqual( a, b ) assertEqual_( (a), (b), #a, #b, __FILE__, __LINE__ ) //--------------------------------------------------------------------------- char * AllocateAligned4( unsigned long size ) { char *s = new char[ size + 4 ]; //allocate on stack to get 4 byte alignment return (char*)((long)(s-1) & (~0x03L)) + 4; } // allocate a 4 byte aligned copy of s char * NewMessageBuffer( const char *s, unsigned long length ) { char *p = AllocateAligned4( length ); memcpy( p, s, length ); return p; } void test1() { const char s[] = "/test\0\0\0,fiT\0\0\0\0\0\0\0\0\0\0\0A"; char *buffer = NewMessageBuffer( s, sizeof(s)-1 ); // test argument iterator interface bool unexpectedExceptionCaught = false; try{ ReceivedMessage m( ReceivedPacket(buffer, sizeof(s)-1) ); assertEqual( strcmp( m.AddressPattern(), "/test" ), 0 ); assertEqual( strcmp( m.TypeTags(), "fiT" ), 0 ); ReceivedMessage::const_iterator i = m.ArgumentsBegin(); ++i; ++i; ++i; assertEqual( i, m.ArgumentsEnd() ); i = m.ArgumentsBegin(); float f = (i++)->AsFloat(); (void)f; int n = (i++)->AsInt32(); (void)n; bool b = (i++)->AsBool(); (void)b; i = m.ArgumentsBegin(); bool exceptionThrown = false; try{ int n = (i++)->AsInt32(); (void)n; }catch( Exception& ){ exceptionThrown = true; } assertEqual( exceptionThrown, true ); }catch( Exception& e ){ std::cout << "unexpected exception: " << e.what() << "\n"; unexpectedExceptionCaught = true; } assertEqual( unexpectedExceptionCaught, false ); // test argument stream interface unexpectedExceptionCaught = false; try{ ReceivedMessage m( ReceivedPacket(buffer, sizeof(s)-1) ); ReceivedMessageArgumentStream args = m.ArgumentStream(); assertEqual( args.Eos(), false ); float f; long n; bool b; args >> f >> n >> b; (void) f; (void) n; (void) b; assertEqual( args.Eos(), true ); }catch( Exception& e ){ std::cout << "unexpected exception: " << e.what() << "\n"; unexpectedExceptionCaught = true; } assertEqual( unexpectedExceptionCaught, false ); } //--------------------------------------------------------------------------- #define TEST2_PRINT( ss )\ {\ const char s[] = ss;\ ReceivedPacket p( NewMessageBuffer( s, sizeof(s)-1 ), sizeof(s)-1 ); \ ReceivedMessage m( p );\ std::cout << m << "\n";\ } void test2() { bool unexpectedExceptionCaught = false; try{ // 012301230 1 2 3 TEST2_PRINT( "/no_args\0\0\0\0" ); // 012301230 1 2 3 01 2 3 TEST2_PRINT( "/no_args\0\0\0\0,\0\0\0" ); // 01230123 012 3 0 1 2 3 TEST2_PRINT( "/an_int\0,i\0\0\0\0\0A" ); // 012301230 1 2 3 012 3 0 1 2 3 TEST2_PRINT( "/a_float\0\0\0\0,f\0\0\0\0\0\0" ); // 0123012301 2 3 012 3 012301230123 TEST2_PRINT( "/a_string\0\0\0,s\0\0hello world\0" ); // 01230123 012 3 0 1 2 3 0 1 2 3 TEST2_PRINT( "/a_blob\0,b\0\0\0\0\0\x4\x0\x1\x2\x3" ); // 0123012301 2 3 012 3 0 1 2 3 0 1 2 3 TEST2_PRINT( "/an_int64\0\0\0,h\0\0\0\0\0\0\0\0\0\x1" ); // 01230123012 3 012 3 0 1 2 3 0 1 2 3 TEST2_PRINT( "/a_timetag\0\0,t\0\0\0\0\0\0\0\0\0\x1" ); // 0123012301 2 3 012 3 0 1 2 3 0 1 2 3 TEST2_PRINT( "/a_double\0\0\0,d\0\0\0\0\0\0\0\0\0\0" ); // 0123012301 2 3 012 3 012301230123 TEST2_PRINT( "/a_symbol\0\0\0,S\0\0hello world\0" ); // 01230123 012 3 0 1 2 3 TEST2_PRINT( "/a_char\0,c\0\0\0\0\0A" ); // 012301230 1 2 3 012 3 0 1 2 3 TEST2_PRINT( "/a_color\0\0\0\0,r\0\0\0\0\0\0" ); // 012301230123012 3 012 3 0 1 2 3 TEST2_PRINT( "/a_midimessage\0\0,m\0\0\0\0\0\0" ); // 01230123 012 3 TEST2_PRINT( "/a_bool\0,T\0\0" ); // 01230123 012 3 TEST2_PRINT( "/a_bool\0,F\0\0" ); // 01230 1 2 3 012 3 TEST2_PRINT( "/Nil\0\0\0\0,N\0\0" ); // 01230 1 2 3 012 3 TEST2_PRINT( "/Inf\0\0\0\0,I\0\0" ); TEST2_PRINT( "/test\0\0\0,fiT\0\0\0\0\0\0\0\0\0\0\0A" ); bool exceptionThrown = false; try{ TEST2_PRINT( "/a_char\0,x\0\0\0\0\0A" ); // unknown type tag 'x' }catch( Exception& ){ exceptionThrown = true; } assertEqual( exceptionThrown, true ); }catch( Exception& e ){ std::cout << "unexpected exception: " << e.what() << "\n"; unexpectedExceptionCaught = true; } assertEqual( unexpectedExceptionCaught, false ); } //----------------------------------------------------------------------- // pack a message and then unpack it and check that the result is the same // also print each message // repeat the process inside a bundle #define TEST_PACK_UNPACK0( addressPattern, argument, value, recieveGetter ) \ { \ memset( buffer, 0x74, bufferSize ); \ OutboundPacketStream ps( buffer, bufferSize ); \ ps << BeginMessage( addressPattern ) \ << argument \ << EndMessage;\ assertEqual( ps.IsReady(), true );\ ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) );\ std::cout << m << "\n";\ assertEqual( m.ArgumentsBegin()-> recieveGetter () , value );\ } \ { \ memset( buffer, 0x74, bufferSize ); \ OutboundPacketStream ps( buffer, bufferSize ); \ ps << BeginBundle( 1234 ) \ << BeginMessage( addressPattern ) \ << argument \ << EndMessage \ << EndBundle;\ assertEqual( ps.IsReady(), true );\ ReceivedBundle b( ReceivedPacket(ps.Data(), ps.Size()) );\ ReceivedMessage m( *b.ElementsBegin() );\ std::cout << m << "\n";\ assertEqual( m.ArgumentsBegin()-> recieveGetter () , value );\ } #define TEST_PACK_UNPACK( addressPattern, argument, type, recieveGetter ) \ { \ memset( buffer, 0x74, bufferSize ); \ OutboundPacketStream ps( buffer, bufferSize ); \ ps << BeginMessage( addressPattern ) \ << argument \ << EndMessage;\ assertEqual( ps.IsReady(), true );\ ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) );\ std::cout << m << "\n";\ assertEqual( m.ArgumentsBegin()-> recieveGetter () , ( type ) argument );\ } \ { \ memset( buffer, 0x74, bufferSize ); \ OutboundPacketStream ps( buffer, bufferSize ); \ ps << BeginBundle( 1234 ) \ << BeginMessage( addressPattern ) \ << argument \ << EndMessage \ << EndBundle;\ assertEqual( ps.IsReady(), true );\ ReceivedBundle b( ReceivedPacket(ps.Data(), ps.Size()) );\ ReceivedMessage m( *b.ElementsBegin() );\ std::cout << m << "\n";\ assertEqual( m.ArgumentsBegin()-> recieveGetter () , ( type ) argument );\ } void test3() { int bufferSize = 1000; char *buffer = AllocateAligned4( bufferSize ); // single message tests // empty message { memset( buffer, 0x74, bufferSize ); OutboundPacketStream ps( buffer, bufferSize ); ps << BeginMessage( "/no_arguments" ) << EndMessage; assertEqual( ps.IsReady(), true ); ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) ); std::cout << m << "\n";\ } TEST_PACK_UNPACK( "/a_bool", true, bool, AsBool ); TEST_PACK_UNPACK( "/a_bool", false, bool, AsBool ); TEST_PACK_UNPACK( "/a_bool", (bool)1, bool, AsBool ); TEST_PACK_UNPACK0( "/nil", Nil, true, IsNil ); TEST_PACK_UNPACK0( "/inf", Infinitum, true, IsInfinitum ); TEST_PACK_UNPACK( "/an_int", (int32)1234, int32, AsInt32 ); TEST_PACK_UNPACK( "/a_float", 3.1415926f, float, AsFloat ); TEST_PACK_UNPACK( "/a_char", 'c', char, AsChar ); TEST_PACK_UNPACK( "/an_rgba_color", RgbaColor(0x22334455), uint32, AsRgbaColor ); TEST_PACK_UNPACK( "/a_midi_message", MidiMessage(0x7F), uint32, AsMidiMessage ); TEST_PACK_UNPACK( "/an_int64", (int64)(0xFFFFFFFF), int64, AsInt64 ); TEST_PACK_UNPACK( "/a_time_tag", TimeTag(0xFFFFFFFF), uint64, AsTimeTag ); TEST_PACK_UNPACK( "/a_double", (double)3.1415926, double, AsDouble ); // blob { char blobData[] = "abcd"; memset( buffer, 0x74, bufferSize ); OutboundPacketStream ps( buffer, bufferSize ); ps << BeginMessage( "/a_blob" ) << Blob( blobData, 4 ) << EndMessage; assertEqual( ps.IsReady(), true ); ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) ); std::cout << m << "\n"; const void *value; unsigned long size; m.ArgumentsBegin()->AsBlob( value, size ); assertEqual( size, (unsigned long)4 ); assertEqual( (memcmp( value, blobData, 4 ) == 0), true ); } TEST_PACK_UNPACK( "/a_string", "hello world", const char*, AsString ); TEST_PACK_UNPACK( "/a_symbol", Symbol("foobar"), const char*, AsSymbol ); // nested bundles, and multiple messages in bundles... { memset( buffer, 0x74, bufferSize ); OutboundPacketStream ps( buffer, bufferSize ); ps << BeginBundle() << BeginMessage( "/message_one" ) << 1 << 2 << 3 << 4 << EndMessage << BeginMessage( "/message_two" ) << 1 << 2 << 3 << 4 << EndMessage << BeginMessage( "/message_three" ) << 1 << 2 << 3 << 4 << EndMessage << BeginMessage( "/message_four" ) << 1 << 2 << 3 << 4 << EndMessage << EndBundle; assertEqual( ps.IsReady(), true ); ReceivedBundle b( ReceivedPacket(ps.Data(), ps.Size()) ); std::cout << b << "\n"; } } void RunUnitTests() { test1(); test2(); test3(); PrintTestSummary(); } } // namespace osc #ifndef NO_OSC_TEST_MAIN int main(int argc, char* argv[]) { (void)argc; (void)argv; osc::RunUnitTests(); } #endif oscpack-1.0.2/Makefile0000644000175000017500000000714010537361254014457 0ustar mordredmordred# should be either OSC_HOST_BIG_ENDIAN or OSC_HOST_LITTLE_ENDIAN # Apple Mac OS X: OSC_HOST_BIG_ENDIAN # Win32: OSC_HOST_LITTLE_ENDIAN # i386 GNU/Linux: OSC_HOST_LITTLE_ENDIAN ENDIANESS=OSC_HOST_LITTLE_ENDIAN CXX = g++ INCLUDES = -I./ COPTS = -Wall -O3 CDEBUG = -Wall -g CXXFLAGS = $(COPTS) $(INCLUDES) -D$(ENDIANESS) PREFIX = /usr/local INSTALL = /usr/bin/install -c #Name definitions UNITTESTS=OscUnitTests SEND=OscSendTests RECEIVE=OscReceiveTest DUMP=OscDump INCLUDEDIR = oscpack LIBNAME = liboscpack LIBSONAME = $(LIBNAME).so LIBFILENAME = $(LIBSONAME).1.0.2 #Test and example source SENDSOURCES = ./tests/OscSendTests.cpp ./osc/OscOutboundPacketStream.cpp ./osc/OscTypes.cpp ./ip/posix/NetworkingUtils.cpp ./ip/posix/UdpSocket.cpp ./ip/IpEndpointName.cpp SENDOBJECTS = $(SENDSOURCES:.cpp=.o) RECEIVESOURCES = ./tests/OscReceiveTest.cpp ./osc/OscTypes.cpp ./osc/OscReceivedElements.cpp ./osc/OscPrintReceivedElements.cpp ./ip/posix/NetworkingUtils.cpp ./ip/posix/UdpSocket.cpp RECEIVEOBJECTS = $(RECEIVESOURCES:.cpp=.o) DUMPSOURCES = ./examples/OscDump.cpp ./osc/OscTypes.cpp ./osc/OscReceivedElements.cpp ./osc/OscPrintReceivedElements.cpp ./ip/posix/NetworkingUtils.cpp ./ip/posix/UdpSocket.cpp DUMPOBJECTS = $(DUMPSOURCES:.cpp=.o) UNITTESTSOURCES = ./tests/OscUnitTests.cpp ./osc/OscOutboundPacketStream.cpp ./osc/OscTypes.cpp ./osc/OscReceivedElements.cpp ./osc/OscPrintReceivedElements.cpp UNITTESTOBJECTS = $(UNITTESTSOURCES:.cpp=.o) #Library sources LIBSOURCES = ./ip/IpEndpointName.cpp \ ./ip/posix/NetworkingUtils.cpp ./ip/posix/UdpSocket.cpp\ ./osc/OscOutboundPacketStream.cpp ./osc/OscPrintReceivedElements.cpp ./osc/OscReceivedElements.cpp ./osc/OscTypes.cpp LIBOBJECTS = $(LIBSOURCES:.cpp=.o) all: unittests send receive dump unittests : $(UNITTESTOBJECTS) @if [ ! -d bin ] ; then mkdir bin ; fi $(CXX) -o bin/$(UNITTESTS) $+ $(LIBS) send : $(SENDOBJECTS) @if [ ! -d bin ] ; then mkdir bin ; fi $(CXX) -o bin/$(SEND) $+ $(LIBS) receive : $(RECEIVEOBJECTS) @if [ ! -d bin ] ; then mkdir bin ; fi $(CXX) -o bin/$(RECEIVE) $+ $(LIBS) dump : $(DUMPOBJECTS) @if [ ! -d bin ] ; then mkdir bin ; fi $(CXX) -o bin/$(DUMP) $+ $(LIBS) clean: rm -rf bin $(UNITTESTOBJECTS) $(SENDOBJECTS) $(RECEIVEOBJECTS) $(DUMPOBJECTS) $(LIBOBJECTS) $(LIBFILENAME) include lib oscpack &> /dev/null $(LIBFILENAME): $(LIBOBJECTS) @#GNU/Linux case $(CXX) -shared -Wl,-soname,$(LIBSONAME) -o $(LIBFILENAME) $(LIBOBJECTS) -lc @#Mac OS X case @#$(CXX) -dynamiclib -Wl,-install_name,$(LIBSONAME) -o $(LIBFILENAME) $(LIBOBJECTS) -lc lib: $(LIBFILENAME) #Installs the library on a system global location install: lib @$(INSTALL) -m 755 $(LIBFILENAME) $(PREFIX)/lib/$(LIBFILENAME) @ln -s -f $(PREFIX)/lib/$(LIBFILENAME) $(PREFIX)/lib/$(LIBSONAME) @mkdir -p $(PREFIX)/include/oscpack/ip $(PREFIX)/include/oscpack/osc @$(INSTALL) -m 644 ip/*.h $(PREFIX)/include/oscpack/ip @$(INSTALL) -m 644 osc/*.h $(PREFIX)/include/oscpack/osc @echo "SUCCESS! oscpack has been installed in $(PREFIX)/lib and $(PREFIX)/include/ospack/" @echo "now doing ldconfig..." @ldconfig #Installs the include/lib structure locally install-local: lib @echo "" @echo " Installing in local directory <$(INCLUDEDIR)>" @echo " > Creating symbolic link" @ln -s $(LIBFILENAME) $(LIBSONAME) @echo " > Creating directories" @mkdir -p oscpack/lib @mkdir -p oscpack/include/ip @mkdir -p oscpack/include/osc @echo " > Copying files" @mv $(LIBFILENAME) $(LIBSONAME) oscpack/lib @cp ip/*.h oscpack/include/ip @cp osc/*.h oscpack/include/osc @echo "" @echo " > Success!"