Complete integration of original OSCPack lib

This commit is contained in:
brunoherbelin
2020-10-20 18:18:44 +02:00
parent 27239b7513
commit 65aefc9fb8
25 changed files with 4429 additions and 3142 deletions

View File

@@ -152,11 +152,19 @@ message(STATUS "Compiling 'TinyXML2' from https://github.com/leethomason/tinyxml
# #
# OSCPack # OSCPack
# #
if(UNIX)
set(OSCPACK_PLATFORM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/ip/posix/)
elseif(WIN32)
set(OSCPACK_PLATFORM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/ip/win32/)
endif()
set(OSCPACK_SRCS set(OSCPACK_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscTypes.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscTypes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscReceivedElements.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscReceivedElements.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscPrintReceivedElements.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscPrintReceivedElements.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/OscOutboundPacketStream.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/osc/OscOutboundPacketStream.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack/ip/IpEndpointName.cpp
${OSCPACK_PLATFORM_DIR}/NetworkingUtils.cpp
${OSCPACK_PLATFORM_DIR}/UdpSocket.cpp
) )
set(OSCPACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack) set(OSCPACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/OSCPack)
add_library(OSCPACK "${OSCPACK_SRCS}") add_library(OSCPACK "${OSCPACK_SRCS}")
@@ -218,7 +226,7 @@ include_directories(
${TINYFD_INCLUDE_DIR} ${TINYFD_INCLUDE_DIR}
${STB_INCLUDE_DIR} ${STB_INCLUDE_DIR}
${DIRENT_INCLUDE_DIR} ${DIRENT_INCLUDE_DIR}
${OBJLOADER_INCLUDE_DIR} ${OSCPACK_INCLUDE_DIR}
) )

View File

@@ -1,127 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H
/*
Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
We try to use preprocessor symbols to deduce the host endianness.
Alternatively you can define one of the above symbols from the command line.
Usually you do this with the -D flag to the compiler. e.g.:
$ g++ -DOSC_HOST_LITTLE_ENDIAN ...
*/
#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
// endianness defined on the command line. nothing to do here.
#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
// 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
#elif defined(__BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
// should cover gcc and clang
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#else
// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__
// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/
#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \
|| (defined(__ARMEL__) && !defined(__ARMEB__)) \
|| (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \
|| (defined(_MIPSEL) && !defined(_MIPSEB)) \
|| (defined(__MIPSEL) && !defined(__MIPSEB)) \
|| (defined(__MIPSEL__) && !defined(__MIPSEB__))
#define OSC_HOST_LITTLE_ENDIAN 1
#undef OSC_HOST_BIG_ENDIAN
#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \
|| (defined(__ARMEB__) && !defined(__ARMEL__)) \
|| (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \
|| (defined(_MIPSEB) && !defined(_MIPSEL)) \
|| (defined(__MIPSEB) && !defined(__MIPSEL)) \
|| (defined(__MIPSEB__) && !defined(__MIPSEL__))
#define OSC_HOST_BIG_ENDIAN 1
#undef OSC_HOST_LITTLE_ENDIAN
#endif
#endif
#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness
#endif
#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */

View File

@@ -1,797 +0,0 @@
/*
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
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.
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.
*/
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscReceivedElements.h"
#include "OscHostEndianness.h"
#include <cstddef> // ptrdiff_t
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;
}
// round up to the next highest multiple of 4. unless x is already a multiple of 4
static inline uint32 RoundUp4( uint32 x )
{
return (x + 3) & ~((uint32)0x03);
}
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
}
static inline int64 ToInt64( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::int64 i;
char c[8];
} 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
}
static inline uint64 ToUInt64( const char *p )
{
#ifdef OSC_HOST_LITTLE_ENDIAN
union{
osc::uint64 i;
char c[8];
} 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] == '#');
}
osc_bundle_element_size_t ReceivedBundleElement::Size() const
{
return ToInt32( sizePtr_ );
}
//------------------------------------------------------------------------------
bool ReceivedMessageArgument::AsBool() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else if( *typeTagPtr_ == FALSE_TYPE_TAG )
return false;
else
throw WrongArgumentTypeException();
}
bool ReceivedMessageArgument::AsBoolUnchecked() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TRUE_TYPE_TAG )
return true;
else
return false;
}
int32 ReceivedMessageArgument::AsInt32() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == 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] = argumentPtr_[3];
u.c[1] = argumentPtr_[2];
u.c[2] = argumentPtr_[1];
u.c[3] = argumentPtr_[0];
return u.i;
#else
return *(int32*)argument_;
#endif
}
float ReceivedMessageArgument::AsFloat() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == 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] = argumentPtr_[3];
u.c[1] = argumentPtr_[2];
u.c[2] = argumentPtr_[1];
u.c[3] = argumentPtr_[0];
return u.f;
#else
return *(float*)argument_;
#endif
}
char ReceivedMessageArgument::AsChar() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == CHAR_TYPE_TAG )
return AsCharUnchecked();
else
throw WrongArgumentTypeException();
}
char ReceivedMessageArgument::AsCharUnchecked() const
{
return (char)ToInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsRgbaColor() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG )
return AsRgbaColorUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
uint32 ReceivedMessageArgument::AsMidiMessage() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG )
return AsMidiMessageUnchecked();
else
throw WrongArgumentTypeException();
}
uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
{
return ToUInt32( argumentPtr_ );
}
int64 ReceivedMessageArgument::AsInt64() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == INT64_TYPE_TAG )
return AsInt64Unchecked();
else
throw WrongArgumentTypeException();
}
int64 ReceivedMessageArgument::AsInt64Unchecked() const
{
return ToInt64( argumentPtr_ );
}
uint64 ReceivedMessageArgument::AsTimeTag() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG )
return AsTimeTagUnchecked();
else
throw WrongArgumentTypeException();
}
uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
{
return ToUInt64( argumentPtr_ );
}
double ReceivedMessageArgument::AsDouble() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == 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] = argumentPtr_[7];
u.c[1] = argumentPtr_[6];
u.c[2] = argumentPtr_[5];
u.c[3] = argumentPtr_[4];
u.c[4] = argumentPtr_[3];
u.c[5] = argumentPtr_[2];
u.c[6] = argumentPtr_[1];
u.c[7] = argumentPtr_[0];
return u.d;
#else
return *(double*)argument_;
#endif
}
const char* ReceivedMessageArgument::AsString() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == STRING_TYPE_TAG )
return argumentPtr_;
else
throw WrongArgumentTypeException();
}
const char* ReceivedMessageArgument::AsSymbol() const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == SYMBOL_TYPE_TAG )
return argumentPtr_;
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const
{
if( !typeTagPtr_ )
throw MissingArgumentException();
else if( *typeTagPtr_ == BLOB_TYPE_TAG )
AsBlobUnchecked( data, size );
else
throw WrongArgumentTypeException();
}
void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const
{
// read blob size as an unsigned int then validate
osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ );
if( !IsValidElementSizeValue(sizeResult) )
throw MalformedMessageException("invalid blob size");
size = sizeResult;
data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32);
}
std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const
{
// it is only valid to call ComputeArrayItemCount when the argument is the array start marker
if( !IsArrayBegin() )
throw WrongArgumentTypeException();
std::size_t result = 0;
unsigned int level = 0;
const char *typeTag = typeTagPtr_ + 1;
// iterate through all type tags. note that ReceivedMessage::Init
// has already checked that the message is well formed.
while( *typeTag ) {
switch( *typeTag++ ) {
case ARRAY_BEGIN_TYPE_TAG:
level += 1;
break;
case ARRAY_END_TYPE_TAG:
if(level == 0)
return result;
level -= 1;
break;
default:
if( level == 0 ) // only count items at level 0
++result;
}
}
return result;
}
//------------------------------------------------------------------------------
void ReceivedMessageArgumentIterator::Advance()
{
if( !value_.typeTagPtr_ )
return;
switch( *value_.typeTagPtr_++ ){
case '\0':
// don't advance past end
--value_.typeTagPtr_;
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_.argumentPtr_ += 4;
break;
case INT64_TYPE_TAG:
case TIME_TAG_TYPE_TAG:
case DOUBLE_TYPE_TAG:
value_.argumentPtr_ += 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_.argumentPtr_ = FindStr4End( value_.argumentPtr_ );
break;
case BLOB_TYPE_TAG:
{
// treat blob size as an unsigned int for the purposes of this calculation
uint32 blobSize = ToUInt32( value_.argumentPtr_ );
value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
}
break;
case ARRAY_BEGIN_TYPE_TAG:
case ARRAY_END_TYPE_TAG:
// [ 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.
// zero length, don't advance argument ptr
break;
default: // unknown type tag
// don't advance
--value_.typeTagPtr_;
break;
}
}
//------------------------------------------------------------------------------
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, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
throw MalformedMessageException( "invalid message size" );
if( size == 0 )
throw MalformedMessageException( "zero length messages not permitted" );
if( !IsMultipleOf4(size) )
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_;
unsigned int arrayLevel = 0;
do{
switch( *typeTag ){
case TRUE_TYPE_TAG:
case FALSE_TYPE_TAG:
case NIL_TYPE_TAG:
case INFINITUM_TYPE_TAG:
// zero length
break;
// [ 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.
case ARRAY_BEGIN_TYPE_TAG:
++arrayLevel;
// (zero length argument data)
break;
case ARRAY_END_TYPE_TAG:
--arrayLevel;
// (zero length argument data)
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 + osc::OSC_SIZEOF_INT32 > end )
MalformedMessageException( "arguments exceed message size" );
// treat blob size as an unsigned int for the purposes of this calculation
uint32 blobSize = ToUInt32( argument );
argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
if( argument > end )
MalformedMessageException( "arguments exceed message size" );
}
break;
default:
throw MalformedMessageException( "unknown type tag" );
}
}while( *++typeTag != '\0' );
typeTagsEnd_ = typeTag;
if( arrayLevel != 0 )
throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" );
}
// These invariants should be guaranteed by the above code.
// we depend on them in the implementation of ArgumentCount()
#ifndef NDEBUG
std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_;
assert( argumentCount >= 0 );
assert( argumentCount <= OSC_INT32_MAX );
#endif
}
}
//------------------------------------------------------------------------------
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, osc_bundle_element_size_t size )
{
if( !IsValidElementSizeValue(size) )
throw MalformedBundleException( "invalid bundle size" );
if( size < 16 )
throw MalformedBundleException( "packet too short for bundle" );
if( !IsMultipleOf4(size) )
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 + osc::OSC_SIZEOF_INT32 > end_ )
throw MalformedBundleException( "packet too short for elementSize" );
// treat element size as an unsigned int for the purposes of this calculation
uint32 elementSize = ToUInt32( p );
if( (elementSize & ((uint32)0x03)) != 0 )
throw MalformedBundleException( "bundle element size must be multiple of four" );
p += osc::OSC_SIZEOF_INT32 + 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

View File

@@ -0,0 +1,81 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 <stdio.h>
#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, "<any>" );
}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, "<any>:<any>" );
}else{
sprintf( s, "%d.%d.%d.%d:<any>",
(int)((address >> 24) & 0xFF),
(int)((address >> 16) & 0xFF),
(int)((address >> 8) & 0xFF),
(int)(address & 0xFF) );
}
}else{
if( address == ANY_ADDRESS ){
sprintf( s, "<any>:%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 );
}
}
}

View File

@@ -0,0 +1,74 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 */

View File

@@ -0,0 +1,49 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 */

View File

@@ -0,0 +1,43 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 */

View File

@@ -0,0 +1,40 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 */

158
ext/OSCPack/ip/UdpSocket.h Normal file
View File

@@ -0,0 +1,158 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 */

View File

@@ -0,0 +1,57 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
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;
}

View File

@@ -0,0 +1,546 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 <vector>
#include <algorithm>
#include <stdexcept>
#include <assert.h>
#include <signal.h>
#include <math.h>
#include <errno.h>
#include <string.h> // for memset
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h> // 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();
}

View File

@@ -0,0 +1,88 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 <winsock2.h> // this must come first to prevent errors with MSVC7
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
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;
}

View File

@@ -0,0 +1,521 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 <winsock2.h> // this must come first to prevent errors with MSVC7
#include <windows.h>
#include <mmsystem.h> // for timeGetTime()
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <assert.h>
#include <signal.h>
#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<HANDLE> 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();
}

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,21 +27,10 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
/* #include <string.h>
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
#include <cstring>
#include <map> #include <map>
#include "OscPacketListener.h" #include "OscPacketListener.h"
@@ -68,7 +61,7 @@ protected:
private: private:
struct cstr_compare{ struct cstr_compare{
bool operator()( const char *lhs, const char *rhs ) const bool operator()( const char *lhs, const char *rhs ) const
{ return std::strcmp( lhs, rhs ) < 0; } { return strcmp( lhs, rhs ) < 0; }
}; };
typedef std::map<const char*, function_type, cstr_compare> function_map_type; typedef std::map<const char*, function_type, cstr_compare> function_map_type;
@@ -77,4 +70,4 @@ private:
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */ #endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,19 +27,8 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_OSC_EXCEPTION_H
/* #define INCLUDED_OSC_EXCEPTION_H
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H
#define INCLUDED_OSCPACK_OSCEXCEPTION_H
#include <exception> #include <exception>
@@ -47,8 +40,7 @@ class Exception : public std::exception {
public: public:
Exception() throw() {} Exception() throw() {}
Exception( const Exception& src ) throw() Exception( const Exception& src ) throw()
: std::exception( src ) : what_( src.what_ ) {}
, what_( src.what_ ) {}
Exception( const char *w ) throw() Exception( const char *w ) throw()
: what_( w ) {} : what_( w ) {}
Exception& operator=( const Exception& src ) throw() Exception& operator=( const Exception& src ) throw()
@@ -59,4 +51,4 @@ public:
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */ #endif /* INCLUDED_OSC_EXCEPTION_H */

View File

@@ -0,0 +1,63 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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.
*/
// you can define one of the above symbols from the command line
// then you don't have to edit this file.
#if 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
#else
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _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
#endif
#endif // OSC_HOSTENDIANNESS_H

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,37 +27,18 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscOutboundPacketStream.h" #include "OscOutboundPacketStream.h"
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) #include <string.h>
#include <malloc.h> // for alloca #include <stdlib.h>
#else #include <assert.h>
//#include <alloca.h> // alloca on Linux (also OSX)
#include <stdlib.h> // alloca on OSX and FreeBSD (and Linux?)
#endif
#include <cassert> #if defined(__WIN32__) || defined(WIN32)
#include <cstring> // memcpy, memmove, strcpy, strlen #include <malloc.h> // for alloca
#include <cstddef> // ptrdiff_t #endif
#include "OscHostEndianness.h" #include "OscHostEndianness.h"
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
namespace std {
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
}
#endif
namespace osc{ namespace osc{
@@ -145,14 +130,13 @@ static void FromUInt64( char *p, uint64 x )
} }
// round up to the next highest multiple of 4. unless x is already a multiple of 4 static inline long RoundUp4( long x )
static inline std::size_t RoundUp4( std::size_t x )
{ {
return (x + 3) & ~((std::size_t)0x03); return ((x-1) & (~0x03L)) + 4;
} }
OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )
: data_( buffer ) : data_( buffer )
, end_( data_ + capacity ) , end_( data_ + capacity )
, typeTagsCurrent_( end_ ) , typeTagsCurrent_( end_ )
@@ -161,12 +145,7 @@ OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
, elementSizePtr_( 0 ) , elementSizePtr_( 0 )
, messageIsInProgress_( false ) , messageIsInProgress_( false )
{ {
// sanity check integer types declared in OscTypes.h
// you'll need to fix OscTypes.h if any of these asserts fail
assert( sizeof(osc::int32) == 4 );
assert( sizeof(osc::uint32) == 4 );
assert( sizeof(osc::int64) == 8 );
assert( sizeof(osc::uint64) == 8 );
} }
@@ -210,15 +189,12 @@ void OutboundPacketStream::EndElement( char *endPtr )
// size slot is stored in the elements size slot (or a ptr to data_ // size slot is stored in the elements size slot (or a ptr to data_
// if there is no containing element). We retrieve that here // if there is no containing element). We retrieve that here
uint32 *previousElementSizePtr = uint32 *previousElementSizePtr =
reinterpret_cast<uint32*>(data_ + *elementSizePtr_); (uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));
// then we store the element size in the slot. note that the element // then we store the element size in the slot, note that the element
// size does not include the size slot, hence the - 4 below. // size does not include the size slot, hence the - 4 below.
uint32 elementSize =
std::ptrdiff_t d = endPtr - reinterpret_cast<char*>(elementSizePtr_); (endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;
// assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb
uint32 elementSize = static_cast<uint32>(d - 4);
FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize ); FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
// finally, we reset the element size ptr to the containing element // finally, we reset the element size ptr to the containing element
@@ -235,7 +211,7 @@ bool OutboundPacketStream::ElementSizeSlotRequired() const
void OutboundPacketStream::CheckForAvailableBundleSpace() void OutboundPacketStream::CheckForAvailableBundleSpace()
{ {
std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
if( required > Capacity() ) if( required > Capacity() )
throw OutOfBufferMemoryException(); throw OutOfBufferMemoryException();
@@ -245,18 +221,18 @@ void OutboundPacketStream::CheckForAvailableBundleSpace()
void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
{ {
// plus 4 for at least four bytes of type tag // plus 4 for at least four bytes of type tag
std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)
+ RoundUp4(std::strlen(addressPattern) + 1) + 4; + RoundUp4(strlen(addressPattern) + 1) + 4;
if( required > Capacity() ) if( required > Capacity() )
throw OutOfBufferMemoryException(); throw OutOfBufferMemoryException();
} }
void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength ) void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )
{ {
// plus three for extra type tag, comma and null terminator // plus three for extra type tag, comma and null terminator
std::size_t required = (argumentCurrent_ - data_) + argumentLength unsigned long required = (argumentCurrent_ - data_) + argumentLength
+ RoundUp4( (end_ - typeTagsCurrent_) + 3 ); + RoundUp4( (end_ - typeTagsCurrent_) + 3 );
if( required > Capacity() ) if( required > Capacity() )
@@ -274,15 +250,15 @@ void OutboundPacketStream::Clear()
} }
std::size_t OutboundPacketStream::Capacity() const unsigned int OutboundPacketStream::Capacity() const
{ {
return end_ - data_; return end_ - data_;
} }
std::size_t OutboundPacketStream::Size() const unsigned int OutboundPacketStream::Size() const
{ {
std::size_t result = argumentCurrent_ - data_; unsigned int result = argumentCurrent_ - data_;
if( IsMessageInProgress() ){ if( IsMessageInProgress() ){
// account for the length of the type tag string. the total type tag // account for the length of the type tag string. the total type tag
// includes an initial comma, plus at least one terminating \0 // includes an initial comma, plus at least one terminating \0
@@ -326,7 +302,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& r
messageCursor_ = BeginElement( messageCursor_ ); messageCursor_ = BeginElement( messageCursor_ );
std::memcpy( messageCursor_, "#bundle\0", 8 ); memcpy( messageCursor_, "#bundle\0", 8 );
FromUInt64( messageCursor_ + 8, rhs.timeTag ); FromUInt64( messageCursor_ + 8, rhs.timeTag );
messageCursor_ += 16; messageCursor_ += 16;
@@ -360,12 +336,12 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs
messageCursor_ = BeginElement( messageCursor_ ); messageCursor_ = BeginElement( messageCursor_ );
std::strcpy( messageCursor_, rhs.addressPattern ); strcpy( messageCursor_, rhs.addressPattern );
std::size_t rhsLength = std::strlen(rhs.addressPattern); unsigned long rhsLength = strlen(rhs.addressPattern);
messageCursor_ += rhsLength + 1; messageCursor_ += rhsLength + 1;
// zero pad to 4-byte boundary // zero pad to 4-byte boundary
std::size_t i = rhsLength + 1; unsigned long i = rhsLength + 1;
while( i & 0x3 ){ while( i & 0x3 ){
*messageCursor_++ = '\0'; *messageCursor_++ = '\0';
++i; ++i;
@@ -387,27 +363,27 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator&
if( !IsMessageInProgress() ) if( !IsMessageInProgress() )
throw MessageNotInProgressException(); throw MessageNotInProgressException();
std::size_t typeTagsCount = end_ - typeTagsCurrent_; int typeTagsCount = end_ - typeTagsCurrent_;
if( typeTagsCount ){ if( typeTagsCount ){
char *tempTypeTags = (char*)alloca(typeTagsCount); char *tempTypeTags = (char*)alloca(typeTagsCount);
std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
// slot size includes comma and null terminator // slot size includes comma and null terminator
std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
std::size_t argumentsSize = argumentCurrent_ - messageCursor_; uint32 argumentsSize = argumentCurrent_ - messageCursor_;
std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
messageCursor_[0] = ','; messageCursor_[0] = ',';
// copy type tags in reverse (really forward) order // copy type tags in reverse (really forward) order
for( std::size_t i=0; i < typeTagsCount; ++i ) for( int i=0; i < typeTagsCount; ++i )
messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
char *p = messageCursor_ + 1 + typeTagsCount; char *p = messageCursor_ + 1 + typeTagsCount;
for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
*p++ = '\0'; *p++ = '\0';
typeTagsCurrent_ = end_; typeTagsCurrent_ = end_;
@@ -417,7 +393,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator&
}else{ }else{
// send an empty type tags string // send an empty type tags string
std::memcpy( messageCursor_, ",\0\0\0", 4 ); memcpy( messageCursor_, ",\0\0\0", 4 );
// advance messageCursor_ for next message // advance messageCursor_ for next message
messageCursor_ += 4; messageCursor_ += 4;
@@ -599,15 +575,15 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
{ {
CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
*(--typeTagsCurrent_) = STRING_TYPE_TAG; *(--typeTagsCurrent_) = STRING_TYPE_TAG;
std::strcpy( argumentCurrent_, rhs ); strcpy( argumentCurrent_, rhs );
std::size_t rhsLength = std::strlen(rhs); unsigned long rhsLength = strlen(rhs);
argumentCurrent_ += rhsLength + 1; argumentCurrent_ += rhsLength + 1;
// zero pad to 4-byte boundary // zero pad to 4-byte boundary
std::size_t i = rhsLength + 1; unsigned long i = rhsLength + 1;
while( i & 0x3 ){ while( i & 0x3 ){
*argumentCurrent_++ = '\0'; *argumentCurrent_++ = '\0';
++i; ++i;
@@ -619,15 +595,15 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
{ {
CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
*(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
std::strcpy( argumentCurrent_, rhs ); strcpy( argumentCurrent_, rhs );
std::size_t rhsLength = std::strlen(rhs); unsigned long rhsLength = strlen(rhs);
argumentCurrent_ += rhsLength + 1; argumentCurrent_ += rhsLength + 1;
// zero pad to 4-byte boundary // zero pad to 4-byte boundary
std::size_t i = rhsLength + 1; unsigned long i = rhsLength + 1;
while( i & 0x3 ){ while( i & 0x3 ){
*argumentCurrent_++ = '\0'; *argumentCurrent_++ = '\0';
++i; ++i;
@@ -645,7 +621,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
FromUInt32( argumentCurrent_, rhs.size ); FromUInt32( argumentCurrent_, rhs.size );
argumentCurrent_ += 4; argumentCurrent_ += 4;
std::memcpy( argumentCurrent_, rhs.data, rhs.size ); memcpy( argumentCurrent_, rhs.data, rhs.size );
argumentCurrent_ += rhs.size; argumentCurrent_ += rhs.size;
// zero pad to 4-byte boundary // zero pad to 4-byte boundary
@@ -658,26 +634,6 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
return *this; return *this;
} }
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs )
{
(void) rhs;
CheckForAvailableArgumentSpace(0);
*(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
return *this;
}
OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
{
(void) rhs;
CheckForAvailableArgumentSpace(0);
*(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;
return *this;
}
} // namespace osc } // namespace osc

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,21 +27,8 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
/* #define INCLUDED_OSCOUTBOUNDPACKET_H
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H
#include <cstring> // size_t
#include "OscTypes.h" #include "OscTypes.h"
#include "OscException.h" #include "OscException.h"
@@ -75,15 +66,15 @@ public:
class OutboundPacketStream{ class OutboundPacketStream{
public: public:
OutboundPacketStream( char *buffer, std::size_t capacity ); OutboundPacketStream( char *buffer, unsigned long capacity );
~OutboundPacketStream(); ~OutboundPacketStream();
void Clear(); void Clear();
std::size_t Capacity() const; unsigned int Capacity() const;
// invariant: size() is valid even while building a message. // invariant: size() is valid even while building a message.
std::size_t Size() const; unsigned int Size() const;
const char *Data() const; const char *Data() const;
@@ -105,7 +96,7 @@ public:
OutboundPacketStream& operator<<( const InfinitumType& rhs ); OutboundPacketStream& operator<<( const InfinitumType& rhs );
OutboundPacketStream& operator<<( int32 rhs ); OutboundPacketStream& operator<<( int32 rhs );
#if !(defined(__x86_64__) || defined(_M_X64)) #ifndef x86_64
OutboundPacketStream& operator<<( int rhs ) OutboundPacketStream& operator<<( int rhs )
{ *this << (int32)rhs; return *this; } { *this << (int32)rhs; return *this; }
#endif #endif
@@ -121,9 +112,6 @@ public:
OutboundPacketStream& operator<<( const Symbol& rhs ); OutboundPacketStream& operator<<( const Symbol& rhs );
OutboundPacketStream& operator<<( const Blob& rhs ); OutboundPacketStream& operator<<( const Blob& rhs );
OutboundPacketStream& operator<<( const ArrayInitiator& rhs );
OutboundPacketStream& operator<<( const ArrayTerminator& rhs );
private: private:
char *BeginElement( char *beginPtr ); char *BeginElement( char *beginPtr );
@@ -132,7 +120,7 @@ private:
bool ElementSizeSlotRequired() const; bool ElementSizeSlotRequired() const;
void CheckForAvailableBundleSpace(); void CheckForAvailableBundleSpace();
void CheckForAvailableMessageSpace( const char *addressPattern ); void CheckForAvailableMessageSpace( const char *addressPattern );
void CheckForAvailableArgumentSpace( std::size_t argumentLength ); void CheckForAvailableArgumentSpace( long argumentLength );
char *data_; char *data_;
char *end_; char *end_;
@@ -151,4 +139,4 @@ private:
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */ #endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,19 +27,8 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_OSCPACKETLISTENER_H
/* #define INCLUDED_OSCPACKETLISTENER_H
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H
#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H
#include "OscReceivedElements.h" #include "OscReceivedElements.h"
#include "../ip/PacketListener.h" #include "../ip/PacketListener.h"
@@ -76,4 +69,4 @@ public:
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */ #endif /* INCLUDED_OSCPACKETLISTENER_H */

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,29 +27,13 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscPrintReceivedElements.h" #include "OscPrintReceivedElements.h"
#include <cstring>
#include <ctime>
#include <iostream> #include <iostream>
#include <cstring>
#include <iomanip> #include <iomanip>
#include <ctime>
#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
namespace std {
using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
}
#endif
namespace osc{ namespace osc{
@@ -121,17 +109,20 @@ std::ostream& operator<<( std::ostream & os,
case TIME_TAG_TYPE_TAG: case TIME_TAG_TYPE_TAG:
{ {
os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " "; os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
std::time_t t = std::time_t t =
(unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); (unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
// strip trailing newline from string returned by ctime
const char *timeString = std::ctime( &t ); const char *timeString = std::ctime( &t );
size_t len = std::strlen( timeString ); size_t len = strlen( timeString );
char *s = new char[ len + 1 ];
strcpy( s, timeString );
if( len )
s[ len - 1 ] = '\0';
// -1 to omit trailing newline from string returned by ctime() os << " " << s;
if( len > 1 )
os.write( timeString, len - 1 );
} }
break; break;
@@ -149,12 +140,12 @@ std::ostream& operator<<( std::ostream & os,
case BLOB_TYPE_TAG: case BLOB_TYPE_TAG:
{ {
unsigned long size;
const void *data; const void *data;
osc_bundle_element_size_t size;
arg.AsBlobUnchecked( data, size ); arg.AsBlobUnchecked( data, size );
os << "OSC-blob:<<" << std::hex << std::setfill('0'); os << "OSC-blob:<<" << std::hex << std::setfill('0');
unsigned char *p = (unsigned char*)data; unsigned char *p = (unsigned char*)data;
for( osc_bundle_element_size_t i = 0; i < size; ++i ){ for( unsigned long i = 0; i < size; ++i ){
os << "0x" << std::setw(2) << int(p[i]); os << "0x" << std::setw(2) << int(p[i]);
if( i != size-1 ) if( i != size-1 )
os << ' '; os << ' ';
@@ -164,14 +155,6 @@ std::ostream& operator<<( std::ostream & os,
} }
break; break;
case ARRAY_BEGIN_TYPE_TAG:
os << "[";
break;
case ARRAY_END_TYPE_TAG:
os << "]";
break;
default: default:
os << "unknown"; os << "unknown";
} }
@@ -182,13 +165,10 @@ std::ostream& operator<<( std::ostream & os,
std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
{ {
os << "[";
if( m.AddressPatternIsUInt32() )
os << m.AddressPatternAsUInt32();
else
os << m.AddressPattern();
os << "[" << m.AddressPattern();
bool first = true; bool first = true;
for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
i != m.ArgumentsEnd(); ++i ){ i != m.ArgumentsEnd(); ++i ){
if( first ){ if( first ){

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,23 +27,14 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
/* #define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H
#include <iosfwd> #include <iosfwd>
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
#include "OscReceivedElements.h" #include "OscReceivedElements.h"
#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
namespace osc{ namespace osc{
@@ -51,4 +46,4 @@ std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */ #endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */

View File

@@ -0,0 +1,722 @@
/*
oscpack -- Open Sound Control packet manipulation library
http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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 <cassert>
#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

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,23 +27,8 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
/* #define INCLUDED_OSCRECEIVEDELEMENTS_H
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
#include <cassert>
#include <cstddef>
#include <cstring> // size_t
#include "OscTypes.h" #include "OscTypes.h"
#include "OscException.h" #include "OscException.h"
@@ -48,12 +37,6 @@
namespace osc{ namespace osc{
class MalformedPacketException : public Exception{
public:
MalformedPacketException( const char *w="malformed packet" )
: Exception( w ) {}
};
class MalformedMessageException : public Exception{ class MalformedMessageException : public Exception{
public: public:
MalformedMessageException( const char *w="malformed message" ) MalformedMessageException( const char *w="malformed message" )
@@ -87,73 +70,37 @@ public:
class ReceivedPacket{ class ReceivedPacket{
public: public:
// Although the OSC spec is not entirely clear on this, we only support ReceivedPacket( const char *contents, int32 size )
// packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value
// representable by an int32). An exception will be raised if you pass a
// larger value to the ReceivedPacket() constructor.
ReceivedPacket( const char *contents, osc_bundle_element_size_t size )
: contents_( contents ) : contents_( contents )
, size_( ValidateSize(size) ) {} , size_( size ) {}
ReceivedPacket( const char *contents, std::size_t size )
: contents_( contents )
, size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
#if !(defined(__x86_64__) || defined(_M_X64))
ReceivedPacket( const char *contents, int size )
: contents_( contents )
, size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
#endif
bool IsMessage() const { return !IsBundle(); } bool IsMessage() const { return !IsBundle(); }
bool IsBundle() const; bool IsBundle() const;
osc_bundle_element_size_t Size() const { return size_; } int32 Size() const { return size_; }
const char *Contents() const { return contents_; } const char *Contents() const { return contents_; }
private: private:
const char *contents_; const char *contents_;
osc_bundle_element_size_t size_; int32 size_;
static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size )
{
// sanity check integer types declared in OscTypes.h
// you'll need to fix OscTypes.h if any of these asserts fail
assert( sizeof(osc::int32) == 4 );
assert( sizeof(osc::uint32) == 4 );
assert( sizeof(osc::int64) == 8 );
assert( sizeof(osc::uint64) == 8 );
if( !IsValidElementSizeValue(size) )
throw MalformedPacketException( "invalid packet size" );
if( size == 0 )
throw MalformedPacketException( "zero length elements not permitted" );
if( !IsMultipleOf4(size) )
throw MalformedPacketException( "element size must be multiple of four" );
return size;
}
}; };
class ReceivedBundleElement{ class ReceivedBundleElement{
public: public:
ReceivedBundleElement( const char *sizePtr ) ReceivedBundleElement( const char *size )
: sizePtr_( sizePtr ) {} : size_( size ) {}
friend class ReceivedBundleElementIterator; friend class ReceivedBundleElementIterator;
bool IsMessage() const { return !IsBundle(); } bool IsMessage() const { return !IsBundle(); }
bool IsBundle() const; bool IsBundle() const;
osc_bundle_element_size_t Size() const; int32 Size() const;
const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } const char *Contents() const { return size_ + 4; }
private: private:
const char *sizePtr_; const char *size_;
}; };
@@ -185,11 +132,11 @@ public:
private: private:
ReceivedBundleElement value_; ReceivedBundleElement value_;
void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } void Advance() { value_.size_ = value_.Contents() + value_.Size(); }
bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
{ {
return value_.sizePtr_ == rhs.value_.sizePtr_; return value_.size_ == rhs.value_.size_;
} }
}; };
@@ -208,79 +155,73 @@ inline bool operator!=(const ReceivedBundleElementIterator& lhs,
class ReceivedMessageArgument{ class ReceivedMessageArgument{
public: public:
ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) ReceivedMessageArgument( const char *typeTag, const char *argument )
: typeTagPtr_( typeTagPtr ) : typeTag_( typeTag )
, argumentPtr_( argumentPtr ) {} , argument_( argument ) {}
friend class ReceivedMessageArgumentIterator; friend class ReceivedMessageArgumentIterator;
char TypeTag() const { return *typeTagPtr_; } const char TypeTag() const { return *typeTag_; }
// the unchecked methods below don't check whether the argument actually // 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 // is of the specified type. they should only be used if you've already
// checked the type tag or the associated IsType() method. // checked the type tag or the associated IsType() method.
bool IsBool() const bool IsBool() const
{ return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }
bool AsBool() const; bool AsBool() const;
bool AsBoolUnchecked() const; bool AsBoolUnchecked() const;
bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }
bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }
bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }
int32 AsInt32() const; int32 AsInt32() const;
int32 AsInt32Unchecked() const; int32 AsInt32Unchecked() const;
bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }
float AsFloat() const; float AsFloat() const;
float AsFloatUnchecked() const; float AsFloatUnchecked() const;
bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }
char AsChar() const; char AsChar() const;
char AsCharUnchecked() const; char AsCharUnchecked() const;
bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }
uint32 AsRgbaColor() const; uint32 AsRgbaColor() const;
uint32 AsRgbaColorUnchecked() const; uint32 AsRgbaColorUnchecked() const;
bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }
uint32 AsMidiMessage() const; uint32 AsMidiMessage() const;
uint32 AsMidiMessageUnchecked() const; uint32 AsMidiMessageUnchecked() const;
bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }
int64 AsInt64() const; int64 AsInt64() const;
int64 AsInt64Unchecked() const; int64 AsInt64Unchecked() const;
bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }
uint64 AsTimeTag() const; uint64 AsTimeTag() const;
uint64 AsTimeTagUnchecked() const; uint64 AsTimeTagUnchecked() const;
bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }
double AsDouble() const; double AsDouble() const;
double AsDoubleUnchecked() const; double AsDoubleUnchecked() const;
bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }
const char* AsString() const; const char* AsString() const;
const char* AsStringUnchecked() const { return argumentPtr_; } const char* AsStringUnchecked() const { return argument_; }
bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }
const char* AsSymbol() const; const char* AsSymbol() const;
const char* AsSymbolUnchecked() const { return argumentPtr_; } const char* AsSymbolUnchecked() const { return argument_; }
bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }
void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; void AsBlob( const void*& data, unsigned long& size ) const;
void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; void AsBlobUnchecked( const void*& data, unsigned long& size ) const;
bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; }
bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; }
// Calculate the number of top-level items in the array. Nested arrays count as one item.
// Only valid at array start. Will throw an exception if IsArrayStart() == false.
std::size_t ComputeArrayItemCount() const;
private: private:
const char *typeTagPtr_; const char *typeTag_;
const char *argumentPtr_; const char *argument_;
}; };
@@ -316,7 +257,7 @@ private:
bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
{ {
return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; return value_.typeTag_ == rhs.value_.typeTag_;
} }
}; };
@@ -358,7 +299,6 @@ public:
// not sure if it would be useful to stream Nil and Infinitum // not sure if it would be useful to stream Nil and Infinitum
// for now it's not possible // for now it's not possible
// same goes for array boundaries
ReceivedMessageArgumentStream& operator>>( int32& rhs ) ReceivedMessageArgumentStream& operator>>( int32& rhs )
{ {
@@ -461,8 +401,6 @@ public:
ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
{ {
(void) rhs; // suppress unused parameter warning
if( !Eos() ) if( !Eos() )
throw ExcessArgumentException(); throw ExcessArgumentException();
@@ -472,18 +410,18 @@ public:
class ReceivedMessage{ class ReceivedMessage{
void Init( const char *bundle, osc_bundle_element_size_t size ); void Init( const char *bundle, unsigned long size );
public: public:
explicit ReceivedMessage( const ReceivedPacket& packet ); explicit ReceivedMessage( const ReceivedPacket& packet );
explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
const char *AddressPattern() const { return addressPattern_; } const char *AddressPattern() const { return addressPattern_; }
// Support for non-standard SuperCollider integer address patterns: // Support for non-standad SuperCollider integer address patterns:
bool AddressPatternIsUInt32() const; bool AddressPatternIsUInt32() const;
uint32 AddressPatternAsUInt32() const; uint32 AddressPatternAsUInt32() const;
uint32 ArgumentCount() const { return static_cast<uint32>(typeTagsEnd_ - typeTagsBegin_); } unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }
const char *TypeTags() const { return typeTagsBegin_; } const char *TypeTags() const { return typeTagsBegin_; }
@@ -514,14 +452,14 @@ private:
class ReceivedBundle{ class ReceivedBundle{
void Init( const char *message, osc_bundle_element_size_t size ); void Init( const char *message, unsigned long size );
public: public:
explicit ReceivedBundle( const ReceivedPacket& packet ); explicit ReceivedBundle( const ReceivedPacket& packet );
explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
uint64 TimeTag() const; uint64 TimeTag() const;
uint32 ElementCount() const { return elementCount_; } unsigned long ElementCount() const { return elementCount_; }
typedef ReceivedBundleElementIterator const_iterator; typedef ReceivedBundleElementIterator const_iterator;
@@ -538,11 +476,11 @@ public:
private: private:
const char *timeTag_; const char *timeTag_;
const char *end_; const char *end_;
uint32 elementCount_; unsigned long elementCount_;
}; };
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,17 +27,6 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
/*
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#include "OscTypes.h" #include "OscTypes.h"
namespace osc{ namespace osc{
@@ -41,12 +34,7 @@ namespace osc{
BundleInitiator BeginBundleImmediate(1); BundleInitiator BeginBundleImmediate(1);
BundleTerminator EndBundle; BundleTerminator EndBundle;
MessageTerminator EndMessage; MessageTerminator EndMessage;
NilType OscNil; NilType Nil;
#ifndef _OBJC_OBJC_H_
NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
#endif
InfinitumType Infinitum; InfinitumType Infinitum;
ArrayInitiator BeginArray;
ArrayTerminator EndArray;
} // namespace osc } // namespace osc

View File

@@ -1,8 +1,8 @@
/* /*
oscpack -- Open Sound Control (OSC) packet manipulation library oscpack -- Open Sound Control packet manipulation library
http://www.rossbencina.com/code/oscpack http://www.audiomulch.com/~rossb/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com> Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files a copy of this software and associated documentation files
@@ -15,6 +15,10 @@
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. 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, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -23,19 +27,8 @@
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef INCLUDED_OSCTYPES_H
/* #define INCLUDED_OSCTYPES_H
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
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. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.
*/
#ifndef INCLUDED_OSCPACK_OSCTYPES_H
#define INCLUDED_OSCPACK_OSCTYPES_H
namespace osc{ namespace osc{
@@ -47,11 +40,6 @@ namespace osc{
typedef __int64 int64; typedef __int64 int64;
typedef unsigned __int64 uint64; typedef unsigned __int64 uint64;
#elif defined(__x86_64__) || defined(_M_X64)
typedef long int64;
typedef unsigned long uint64;
#else #else
typedef long long int64; typedef long long int64;
@@ -61,7 +49,7 @@ typedef unsigned long long uint64;
#if defined(__x86_64__) || defined(_M_X64) #ifdef x86_64
typedef signed int int32; typedef signed int int32;
typedef unsigned int uint32; typedef unsigned int uint32;
@@ -74,41 +62,6 @@ typedef unsigned long uint32;
#endif #endif
enum ValueTypeSizes{
OSC_SIZEOF_INT32 = 4,
OSC_SIZEOF_UINT32 = 4,
OSC_SIZEOF_INT64 = 8,
OSC_SIZEOF_UINT64 = 8,
};
// osc_bundle_element_size_t is used for the size of bundle elements and blobs
// the OSC spec specifies these as int32 (signed) but we ensure that they
// are always positive since negative field sizes make no sense.
typedef int32 osc_bundle_element_size_t;
enum {
OSC_INT32_MAX = 0x7FFFFFFF,
// Element sizes are specified to be int32, and are always rounded up to nearest
// multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC.
OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC
};
inline bool IsValidElementSizeValue( osc_bundle_element_size_t x )
{
// sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX
return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX;
}
inline bool IsMultipleOf4( osc_bundle_element_size_t x )
{
return (x & ((osc_bundle_element_size_t)0x03)) == 0;
}
enum TypeTagValues { enum TypeTagValues {
TRUE_TYPE_TAG = 'T', TRUE_TYPE_TAG = 'T',
@@ -125,9 +78,7 @@ enum TypeTagValues {
DOUBLE_TYPE_TAG = 'd', DOUBLE_TYPE_TAG = 'd',
STRING_TYPE_TAG = 's', STRING_TYPE_TAG = 's',
SYMBOL_TYPE_TAG = 'S', SYMBOL_TYPE_TAG = 'S',
BLOB_TYPE_TAG = 'b', BLOB_TYPE_TAG = 'b'
ARRAY_BEGIN_TYPE_TAG = '[',
ARRAY_END_TYPE_TAG = ']'
}; };
@@ -169,11 +120,8 @@ extern MessageTerminator EndMessage;
struct NilType{ struct NilType{
}; };
extern NilType OscNil; extern NilType Nil;
#ifndef _OBJC_OBJC_H_
extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead
#endif
struct InfinitumType{ struct InfinitumType{
}; };
@@ -218,23 +166,13 @@ struct Symbol{
struct Blob{ struct Blob{
Blob() {} Blob() {}
explicit Blob( const void* data_, osc_bundle_element_size_t size_ ) explicit Blob( const void* data_, unsigned long size_ )
: data( data_ ), size( size_ ) {} : data( data_ ), size( size_ ) {}
const void* data; const void* data;
osc_bundle_element_size_t size; unsigned long size;
}; };
struct ArrayInitiator{
};
extern ArrayInitiator BeginArray;
struct ArrayTerminator{
};
extern ArrayTerminator EndArray;
} // namespace osc } // namespace osc
#endif /* INCLUDED_OSCPACK_OSCTYPES_H */ #endif /* INCLUDED_OSCTYPES_H */