diff --git a/FaceTrackerSteamOSC.sln b/FaceTrackerSteamOSC.sln
new file mode 100644
index 0000000..c5e9191
--- /dev/null
+++ b/FaceTrackerSteamOSC.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33502.453
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FaceTrackerSteamOSC", "FaceTrackerSteamOSC\FaceTrackerSteamOSC.vcxproj", "{B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Debug|x64.ActiveCfg = Debug|x64
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Debug|x64.Build.0 = Debug|x64
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Debug|x86.ActiveCfg = Debug|Win32
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Debug|x86.Build.0 = Debug|Win32
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Release|x64.ActiveCfg = Release|x64
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Release|x64.Build.0 = Release|x64
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Release|x86.ActiveCfg = Release|Win32
+ {B888FF32-C1F2-4050-B6D9-5C2BEE28AED5}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {98C268F9-8E12-487A-89E0-C9563F492C16}
+ EndGlobalSection
+EndGlobal
diff --git a/FaceTrackerSteamOSC/FaceTrackerSteamOSC.aps b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.aps
new file mode 100644
index 0000000..301c0a7
Binary files /dev/null and b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.aps differ
diff --git a/FaceTrackerSteamOSC/FaceTrackerSteamOSC.filters b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.filters
new file mode 100644
index 0000000..9f0d5cd
--- /dev/null
+++ b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.filters
@@ -0,0 +1,85 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {1b9d200c-4a0a-4b3d-a8fc-54b271dcc4de}
+
+
+ {bde4cd89-207f-48bf-a4a0-88e6ddcee8ca}
+
+
+
+
+ ソース ファイル
+
+
+ osc
+
+
+ osc
+
+
+ osc
+
+
+ osc
+
+
+ hello_xr
+
+
+ hello_xr
+
+
+ hello_xr
+
+
+ hello_xr
+
+
+ hello_xr
+
+
+ hello_xr
+
+
+ hello_xr
+
+
+ osc
+
+
+ osc
+
+
+ osc
+
+
+
+
+ ヘッダー ファイル
+
+
+
+
+ リソース ファイル
+
+
+
+
+ リソース ファイル
+
+
+
\ No newline at end of file
diff --git a/FaceTrackerSteamOSC/FaceTrackerSteamOSC.rc b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.rc
new file mode 100644
index 0000000..fd6d0ca
Binary files /dev/null and b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.rc differ
diff --git a/FaceTrackerSteamOSC/FaceTrackerSteamOSC.user b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.user
new file mode 100644
index 0000000..531c9a5
--- /dev/null
+++ b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.user
@@ -0,0 +1,23 @@
+
+
+
+
+
+ WindowsLocalDebugger
+
+
+
+
+ WindowsLocalDebugger
+
+
+
+
+ WindowsLocalDebugger
+
+
+
+
+ WindowsLocalDebugger
+
+
\ No newline at end of file
diff --git a/FaceTrackerSteamOSC/FaceTrackerSteamOSC.vcxproj b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.vcxproj
new file mode 100644
index 0000000..f319831
--- /dev/null
+++ b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.vcxproj
@@ -0,0 +1,188 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 16.0
+ Win32Proj
+ {b888ff32-c1f2-4050-b6d9-5c2bee28aed5}
+ FaceTrackerSteamOSC
+ 10.0
+ FaceTrackerSteamOSC
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)out\$(Platform)\$(Configuration)\
+ $(SolutionDir)tmp\$(ProjectName)\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)out\$(Platform)\$(Configuration)\
+ $(SolutionDir)tmp\$(ProjectName)\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)out\$(Platform)\$(Configuration)\
+ $(SolutionDir)tmp\$(ProjectName)\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)out\$(Platform)\$(Configuration)\
+ $(SolutionDir)tmp\$(ProjectName)\$(Platform)\$(Configuration)\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);__WIN32__
+ true
+ $(SolutionDir)external\oscpack_1_1_0;%(AdditionalIncludeDirectories)
+ 4996;%(DisableSpecificWarnings)
+
+
+ Console
+ true
+
+
+ ws2_32.lib;winmm.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);__WIN32__
+ true
+ $(SolutionDir)external\oscpack_1_1_0;%(AdditionalIncludeDirectories)
+ 4996;%(DisableSpecificWarnings)
+
+
+ Console
+ true
+ true
+ true
+
+
+ ws2_32.lib;winmm.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions);__WIN32__
+ true
+ $(SolutionDir)external\oscpack_1_1_0;%(AdditionalIncludeDirectories)
+ 4996;%(DisableSpecificWarnings)
+
+
+ Console
+ true
+
+
+ ws2_32.lib;winmm.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions);__WIN32__
+ true
+ $(SolutionDir)external\oscpack_1_1_0;%(AdditionalIncludeDirectories)
+ 4996;%(DisableSpecificWarnings)
+
+
+ Console
+ true
+ true
+ true
+
+
+ ws2_32.lib;winmm.lib;%(AdditionalDependencies)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FaceTrackerSteamOSC/FaceTrackerSteamOSC.vcxproj.user b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/FaceTrackerSteamOSC/FaceTrackerSteamOSC.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/FaceTrackerSteamOSC/icon.ico b/FaceTrackerSteamOSC/icon.ico
new file mode 100644
index 0000000..f695593
Binary files /dev/null and b/FaceTrackerSteamOSC/icon.ico differ
diff --git a/FaceTrackerSteamOSC/main.cpp b/FaceTrackerSteamOSC/main.cpp
new file mode 100644
index 0000000..4fc5a57
--- /dev/null
+++ b/FaceTrackerSteamOSC/main.cpp
@@ -0,0 +1,127 @@
+// Copyright (c) 2023-2023, A3
+//
+// License: MIT
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+class OscProcess : public osc::OscPacketListener
+{
+ const std::string steam = "/sl/xrfb/facew/";
+ const std::string a3 = "/avatar/parameters/";
+ UdpTransmitSocket* sendSocket;
+ UdpListeningReceiveSocket* recvSocket;
+
+ char buffer[6144];
+ osc::OutboundPacketStream sendPacket = osc::OutboundPacketStream(buffer,6144);
+
+public:
+ OscProcess(const char* ip= "127.0.0.1", int portSend = 9000, int portRecv = 9015) {
+ sendSocket = new UdpTransmitSocket(IpEndpointName(ip, portSend));
+ recvSocket = new UdpListeningReceiveSocket(IpEndpointName(IpEndpointName::ANY_ADDRESS, portRecv), this);
+ }
+ void RunUntilSigInt() {
+ recvSocket->RunUntilSigInt();
+ }
+protected:
+ virtual void ProcessMessage(const osc::ReceivedMessage& m, const IpEndpointName& endpoint)
+ {
+ std::string addressPattern = m.AddressPattern();
+ size_t pos = addressPattern.find(steam);
+ if (pos != std::string::npos) {
+ addressPattern.replace(pos, steam.length(), a3);
+ }
+ //std::cout << addressPattern;
+ sendPacket << osc::BeginMessage(addressPattern.c_str());
+ for (osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); arg != m.ArgumentsEnd();arg++) {
+ switch (arg->TypeTag()) {
+ case osc::FLOAT_TYPE_TAG:
+ {
+ float data = arg->AsFloat();
+ sendPacket << data;
+ //std::cout << data;
+ break;
+ }
+ case osc::DOUBLE_TYPE_TAG:
+ {
+ double data = arg->AsDouble();
+ sendPacket << data;
+ //std::cout << data;
+ break;
+ }
+ case osc::STRING_TYPE_TAG:
+ {
+ const char* data = arg->AsString();
+ sendPacket << data;
+ //std::cout << data;
+ break;
+ }
+ case osc::INT32_TYPE_TAG:
+ {
+ osc::int32 data = arg->AsInt32();
+ sendPacket << data;
+ //std::cout << data;
+ break;
+ }
+ case osc::INT64_TYPE_TAG:
+ {
+ osc::int64 data = arg->AsInt64();
+ sendPacket << data;
+ //std::cout << data;
+ break;
+ }
+ default:
+ std::cout << "Error:TYPE_TAG";
+ break;
+ }
+ }
+ sendPacket << osc::EndMessage;
+ //std::cout << std::endl;
+ }
+ virtual void ProcessPacket(const char* data, int size, const IpEndpointName& remoteEndpoint)
+ {
+ sendPacket.Clear();
+ sendPacket << osc::BeginBundleImmediate;
+
+ osc::ReceivedPacket p(data, size);
+ if (p.IsBundle())
+ ProcessBundle(osc::ReceivedBundle(p), remoteEndpoint);
+ else
+ ProcessMessage(osc::ReceivedMessage(p), remoteEndpoint);
+
+ sendPacket << osc::EndBundle;
+ sendSocket->Send(sendPacket.Data(), sendPacket.Size());
+ }
+};
+
+int main(int argc, char** argv)
+{
+ std::cout << "Face Tracker Steam OSC\n(c)A3\nhttps://twitter.com/A3_yuu" << std::endl;
+
+ //arg
+ const char *ip = "127.0.0.1";
+ int portSend = 9000;
+ int portRecv = 9015;
+
+ switch (argc > 4 ? 4 : argc) {
+ case 4:
+ portRecv = atoi(argv[3]);
+ case 3:
+ portSend = atoi(argv[2]);
+ case 2:
+ ip = argv[1];
+ default:
+ break;
+ }
+
+ OscProcess listener(ip, portSend, portRecv);
+ listener.RunUntilSigInt();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/FaceTrackerSteamOSC/resource.h b/FaceTrackerSteamOSC/resource.h
new file mode 100644
index 0000000..1bfeefc
--- /dev/null
+++ b/FaceTrackerSteamOSC/resource.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ �Ő������ꂽ�C���N���[�h �t�@�C���B
+// EyeTrackerOSC.rc �Ŏg�p
+//
+#define IDI_ICON1 101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..045f077
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 A3
+
+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.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f6f6a82
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# FaceTrackerSteamOSC
+
+SteamLinkでVRChatでフェイストラッキングを動かせるようになる。
+
+Quest Proが必要
+
+アバターの設定が必須
+
+## Build from source
+
+Open with VisualStudio
+
+Build
+
+## Option
+
+ip portSend portRecv
+
+## Avatar setting
+
+中身は「/sl/xrfb/facew/」を「/avatar/parameters/」に書き換えているだけ。
+
+OSCが来たらアバターの表情が動くように設定する。
+
+例:
+
+XR_FACE_EXPRESSION_BROW_LOWERER_R_FB
+
+→/avatar/parameters/BrowLowererR
+
+Boothにアニメーションファイルのサンプルをおいてるのでご参考。
+
+また、それぞれの設定すべき表情は下記から確認可能。
+
+https://developer.oculus.com/documentation/unity/move-face-tracking/
+
+## Donate
+
+https://a3s.booth.pm/items/4715968
+
+## Twitter
+
+https://twitter.com/A3_yuu
\ No newline at end of file
diff --git a/external/oscpack_1_1_0/LICENSE b/external/oscpack_1_1_0/LICENSE
new file mode 100644
index 0000000..ebaaac1
--- /dev/null
+++ b/external/oscpack_1_1_0/LICENSE
@@ -0,0 +1,34 @@
+oscpack -- Open Sound Control (OSC) packet manipulation library
+http://www.rossbencina.com/code/oscpack
+
+Copyright (c) 2004-2013 Ross Bencina
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files
+(the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+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.
\ No newline at end of file
diff --git a/external/oscpack_1_1_0/README b/external/oscpack_1_1_0/README
new file mode 100644
index 0000000..5d1d5c1
--- /dev/null
+++ b/external/oscpack_1_1_0/README
@@ -0,0 +1,150 @@
+oscpack -- Open Sound Control packet manipulation library
+A simple C++ library for packing and unpacking OSC packets.
+http://www.rossbencina.com/code/oscpack
+
+Copyright (c) 2004-2013 Ross Bencina
+
+
+Oscpack is simply a set of C++ classes for packing and unpacking OSC packets.
+Oscpack includes a minimal set of UDP networking classes for Windows and POSIX.
+The networking classes are sufficient for writing many OSC applications and servers,
+but you are encouraged to use another networking framework if it better suits your needs.
+Oscpack is not an OSC application framework. It doesn't include infrastructure for
+constructing or routing OSC namespaces, just classes for easily constructing,
+sending, receiving and parsing OSC packets. The library should also be easy to use
+for other transport methods (e.g. serial).
+
+The key goals of the oscpack library are:
+
+ - Be a simple and complete implementation of OSC
+ - Be portable to a wide variety of platforms
+ - Allow easy development of robust OSC applications
+ (for example it should be impossible to crash a server
+ by sending it malformed packets, and difficult to create
+ malformed packets.)
+
+Here's a quick run down of the key files:
+
+osc/OscReceivedElements -- classes for parsing a packet
+osc/OscPrintRecievedElements -- iostream << operators for printing packet elements
+osc/OscOutboundPacketStream -- a class for packing messages into a packet
+osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket
+ip/IpEndpointName -- class that represents an IP address and port number
+ip/UdpSocket -- classes for UDP transmission and listening sockets
+tests/OscUnitTests -- unit test program for the OSC modules
+tests/OscSendTests -- examples of how to send messages
+tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests
+examples/OscDump -- a program that prints received OSC packets
+examples/SimpleSend -- a minimal program to send an OSC message
+examples/SimpleReceive -- a minimal program to receive an OSC message
+
+osc/ contains all of the OSC related classes
+ip/ contains the networking classes
+
+ip/windows contains the Windows implementation of the networking classes
+ip/posix contains the POSIX implementation of the networking classes
+
+
+Building
+--------
+
+The idea is that you will embed this source code in your projects as you
+see fit. The Makefile has an install rule for building a shared library and
+installing headers in usr/local. It can also build a static library.
+There is a CMakeLists.txt for building with cmake.
+
+Makefile builds
+...............
+
+The Makefile works for Linux and Max OS X. It should also work on other platforms
+that have make. Just run:
+
+$ make
+
+You can run "make install" if you like.
+
+
+Cmake builds
+............
+
+There is a CMakeLists.txt file which has been tested with cmake on
+Windows and Linux. It should work on other platforms too.
+For example, to generate a Visual Studio 10 project, run cmake
+like this:
+
+> cmake -G "Visual Studio 10"
+
+Run cmake without any parameters to get a list of available generators.
+
+
+Mingw build batch file
+......................
+
+For Windows there is a batch file for doing a simple test build with
+MinGW gcc called make.MinGW32.bat. This will build the test executables
+and oscdump in ./bin and run the unit tests.
+
+
+Note:
+
+In some rare instances you may need to edit the Makefile or
+osc/OscHostEndianness.h to configure oscpack for the endianness of your
+processor (see the comments at the top of the Makefile for details).
+
+
+
+Verification test
+-----------------
+
+To run the unit tests:
+
+$ ./bin/OscUnitTests
+
+To run the send and receive tests. Open two terminals. In one run:
+
+$ ./bin/OscReceiveTest
+
+Then in the other terminal run:
+
+$./bin/OscSendTests
+
+
+You should see an indication that the messages were received
+in the first terminal.
+
+Note that OscSendTests intentionally sends some unexpected
+message parameters to test exception handling in the receiver.
+You will see some "error while parsing message" messages printed.
+
+You can use ./bin/OscDump to print out OSC messages received
+from any program, including the test programs.
+
+
+--
+
+
+If you fix anything or write a set of TCP send/receive classes
+please consider sending me a patch. My email address is
+rossb@audiomulch.com. Thanks :)
+
+For more information about Open Sound Control, see:
+http://opensoundcontrol.org/
+
+Thanks to Till Bovermann for helping with POSIX networking code and
+Mac compatibility, and to Martin Kaltenbrunner and the rest of the
+reacTable team for giving me a reason to finish this library. Thanks
+to Merlijn Blaauw for reviewing the interfaces. Thanks to Xavier Oliver
+for additional help with Linux builds and POSIX implementation details.
+
+Portions developed at the Music Technology Group, Audiovisual Institute,
+University Pompeu Fabra, Barcelona, during my stay as a visiting
+researcher, November 2004 - September 2005.
+
+Thanks to Syneme at the University of Calgary for providing financial
+support for the 1.1.0 update, December 2012 - March 2013.
+
+See the file CHANGES for information about recent updates.
+
+See the file LICENSE for information about distributing and using this code.
+
+###
diff --git a/external/oscpack_1_1_0/ip/IpEndpointName.cpp b/external/oscpack_1_1_0/ip/IpEndpointName.cpp
new file mode 100644
index 0000000..50b0262
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/IpEndpointName.cpp
@@ -0,0 +1,88 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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 "IpEndpointName.h"
+
+#include
+
+#include "NetworkingUtils.h"
+
+
+unsigned long IpEndpointName::GetHostByName( const char *s )
+{
+ return ::GetHostByName(s);
+}
+
+
+void IpEndpointName::AddressAsString( char *s ) const
+{
+ if( address == ANY_ADDRESS ){
+ std::sprintf( s, "" );
+ }else{
+ std::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 ){
+ std::sprintf( s, ":" );
+ }else{
+ std::sprintf( s, "%d.%d.%d.%d:",
+ (int)((address >> 24) & 0xFF),
+ (int)((address >> 16) & 0xFF),
+ (int)((address >> 8) & 0xFF),
+ (int)(address & 0xFF) );
+ }
+ }else{
+ if( address == ANY_ADDRESS ){
+ std::sprintf( s, ":%d", port );
+ }else{
+ std::sprintf( s, "%d.%d.%d.%d:%d",
+ (int)((address >> 24) & 0xFF),
+ (int)((address >> 16) & 0xFF),
+ (int)((address >> 8) & 0xFF),
+ (int)(address & 0xFF),
+ (int)port );
+ }
+ }
+}
diff --git a/external/oscpack_1_1_0/ip/IpEndpointName.h b/external/oscpack_1_1_0/ip/IpEndpointName.h
new file mode 100644
index 0000000..c83e1c3
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/IpEndpointName.h
@@ -0,0 +1,83 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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_IPENDPOINTNAME_H
+#define INCLUDED_OSCPACK_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;
+
+ bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; }
+
+ 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_OSCPACK_IPENDPOINTNAME_H */
diff --git a/external/oscpack_1_1_0/ip/NetworkingUtils.h b/external/oscpack_1_1_0/ip/NetworkingUtils.h
new file mode 100644
index 0000000..a83612a
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/NetworkingUtils.h
@@ -0,0 +1,56 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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_NETWORKINGUTILS_H
+#define INCLUDED_OSCPACK_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_OSCPACK_NETWORKINGUTILS_H */
diff --git a/external/oscpack_1_1_0/ip/PacketListener.h b/external/oscpack_1_1_0/ip/PacketListener.h
new file mode 100644
index 0000000..6c26b32
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/PacketListener.h
@@ -0,0 +1,50 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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_PACKETLISTENER_H
+#define INCLUDED_OSCPACK_PACKETLISTENER_H
+
+
+class IpEndpointName;
+
+class PacketListener{
+public:
+ virtual ~PacketListener() {}
+ virtual void ProcessPacket( const char *data, int size,
+ const IpEndpointName& remoteEndpoint ) = 0;
+};
+
+#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */
diff --git a/external/oscpack_1_1_0/ip/TimerListener.h b/external/oscpack_1_1_0/ip/TimerListener.h
new file mode 100644
index 0000000..59b4040
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/TimerListener.h
@@ -0,0 +1,47 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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_TIMERLISTENER_H
+#define INCLUDED_OSCPACK_TIMERLISTENER_H
+
+
+class TimerListener{
+public:
+ virtual ~TimerListener() {}
+ virtual void TimerExpired() = 0;
+};
+
+#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */
diff --git a/external/oscpack_1_1_0/ip/UdpSocket.h b/external/oscpack_1_1_0/ip/UdpSocket.h
new file mode 100644
index 0000000..2d7a189
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/UdpSocket.h
@@ -0,0 +1,176 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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_UDPSOCKET_H
+#define INCLUDED_OSCPACK_UDPSOCKET_H
+
+#include // size_t
+
+#include "NetworkingUtils.h"
+#include "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();
+
+ // Enable broadcast addresses (e.g. x.x.x.255)
+ // Sets SO_BROADCAST socket option.
+ void SetEnableBroadcast( bool enableBroadcast );
+
+ // Enable multiple listeners for a single port on same
+ // network interface*
+ // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X).
+ // [*] The exact behavior of SO_REUSEADDR and
+ // SO_REUSEPORT is undefined for some common cases
+ // and may have drastically different behavior on different
+ // operating systems.
+ void SetAllowReuse( bool allowReuse );
+
+
+ // 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, std::size_t size );
+ void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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;
+
+ std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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_OSCPACK_UDPSOCKET_H */
diff --git a/external/oscpack_1_1_0/ip/posix/NetworkingUtils.cpp b/external/oscpack_1_1_0/ip/posix/NetworkingUtils.cpp
new file mode 100644
index 0000000..7f36605
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/posix/NetworkingUtils.cpp
@@ -0,0 +1,64 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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 "ip/NetworkingUtils.h"
+
+#include
+#include
+#include
+
+#include
+
+
+
+NetworkInitializer::NetworkInitializer() {}
+
+NetworkInitializer::~NetworkInitializer() {}
+
+
+unsigned long GetHostByName( const char *name )
+{
+ unsigned long result = 0;
+
+ struct hostent *h = gethostbyname( name );
+ if( h ){
+ struct in_addr a;
+ std::memcpy( &a, h->h_addr_list[0], h->h_length );
+ result = ntohl(a.s_addr);
+ }
+
+ return result;
+}
diff --git a/external/oscpack_1_1_0/ip/posix/UdpSocket.cpp b/external/oscpack_1_1_0/ip/posix/UdpSocket.cpp
new file mode 100644
index 0000000..b8262fc
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/posix/UdpSocket.cpp
@@ -0,0 +1,602 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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 "ip/UdpSocket.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include // for sockaddr_in
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include // for memset
+#include
+#include
+
+#include "ip/PacketListener.h"
+#include "ip/TimerListener.h"
+
+
+#if defined(__APPLE__) && !defined(_SOCKLEN_T)
+// pre system 10.3 didn't have socklen_t
+typedef ssize_t socklen_t;
+#endif
+
+
+static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint )
+{
+ std::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");
+ }
+
+ std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
+ sendToAddr_.sin_family = AF_INET;
+ }
+
+ ~Implementation()
+ {
+ if (socket_ != -1) close(socket_);
+ }
+
+ void SetEnableBroadcast( bool enableBroadcast )
+ {
+ int broadcast = (enableBroadcast) ? 1 : 0; // int on posix
+ setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
+ }
+
+ void SetAllowReuse( bool allowReuse )
+ {
+ int reuseAddr = (allowReuse) ? 1 : 0; // int on posix
+ setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
+
+#ifdef __APPLE__
+ // needed also for OS X - enable multiple listeners for a single port on same network interface
+ int reusePort = (allowReuse) ? 1 : 0; // int on posix
+ setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort));
+#endif
+ }
+
+ 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;
+ std::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;
+ std::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, std::size_t size )
+ {
+ assert( isConnected_ );
+
+ send( socket_, data, size, 0 );
+ }
+
+ void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t 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_; }
+
+ std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size )
+ {
+ assert( isBound_ );
+
+ struct sockaddr_in fromAddr;
+ socklen_t fromAddrLen = sizeof(fromAddr);
+
+ ssize_t 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 (std::size_t)result;
+ }
+
+ int Socket() { return socket_; }
+};
+
+UdpSocket::UdpSocket()
+{
+ impl_ = new Implementation();
+}
+
+UdpSocket::~UdpSocket()
+{
+ delete impl_;
+}
+
+void UdpSocket::SetEnableBroadcast( bool enableBroadcast )
+{
+ impl_->SetEnableBroadcast( enableBroadcast );
+}
+
+void UdpSocket::SetAllowReuse( bool allowReuse )
+{
+ impl_->SetAllowReuse( allowReuse );
+}
+
+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, std::size_t size )
+{
+ impl_->Send( data, size );
+}
+
+void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
+{
+ impl_->SendTo( remoteEndpoint, data, size );
+}
+
+void UdpSocket::Bind( const IpEndpointName& localEndpoint )
+{
+ impl_->Bind( localEndpoint );
+}
+
+bool UdpSocket::IsBound() const
+{
+ return impl_->IsBound();
+}
+
+std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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;
+ char *data = 0;
+
+ try{
+
+ // 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;
+ 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;
+
+ long timoutSecondsPart = (long)(timeoutMs * .001);
+ timeout.tv_sec = (time_t)timoutSecondsPart;
+ // 1000000 microseconds in a second
+ timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000);
+ timeoutPtr = &timeout;
+ }
+
+ if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){
+ if( break_ ){
+ break;
+ }else if( errno == EINTR ){
+ // on returning an error, select() doesn't clear tempfds.
+ // so tempfds would remain all set, which would cause read( breakPipe_[0]...
+ // below to block indefinitely. therefore if select returns EINTR we restart
+ // the while() loop instead of continuing on to below.
+ continue;
+ }else{
+ 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 ) ){
+
+ std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
+ if( size > 0 ){
+ i->first->ProcessPacket( data, (int)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;
+ }catch(...){
+ if( data )
+ delete [] data;
+ throw;
+ }
+ }
+
+ 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();
+}
+
diff --git a/external/oscpack_1_1_0/ip/win32/NetworkingUtils.cpp b/external/oscpack_1_1_0/ip/win32/NetworkingUtils.cpp
new file mode 100644
index 0000000..882ebf9
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/win32/NetworkingUtils.cpp
@@ -0,0 +1,96 @@
+
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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 "ip/NetworkingUtils.h"
+
+#include // this must come first to prevent errors with MSVC7
+#include
+
+#include
+
+
+static LONG initCount_ = 0;
+static bool winsockInitialized_ = false;
+
+NetworkInitializer::NetworkInitializer()
+{
+ if( InterlockedIncrement( &initCount_ ) == 1 ){
+ // there is a race condition here if one thread tries to access
+ // the library while another is still initializing it.
+ // i can't think of an easy way to fix it so i'm telling you here
+ // incase you need to init the library from two threads at once.
+ // this is why the header file advises to instantiate one of these
+ // in main() so that the initialization happens globally
+
+ // initialize winsock
+ WSAData wsaData;
+ int nCode = WSAStartup(MAKEWORD(1, 1), &wsaData);
+ if( nCode != 0 ){
+ //std::cout << "WSAStartup() failed with error code " << nCode << "\n";
+ }else{
+ winsockInitialized_ = true;
+ }
+ }
+}
+
+
+NetworkInitializer::~NetworkInitializer()
+{
+ if( InterlockedDecrement( &initCount_ ) == 0 ){
+ if( winsockInitialized_ ){
+ WSACleanup();
+ winsockInitialized_ = false;
+ }
+ }
+}
+
+
+unsigned long GetHostByName( const char *name )
+{
+ NetworkInitializer networkInitializer;
+
+ unsigned long result = 0;
+
+ struct hostent *h = gethostbyname( name );
+ if( h ){
+ struct in_addr a;
+ std::memcpy( &a, h->h_addr_list[0], h->h_length );
+ result = ntohl(a.s_addr);
+ }
+
+ return result;
+}
diff --git a/external/oscpack_1_1_0/ip/win32/UdpSocket.cpp b/external/oscpack_1_1_0/ip/win32/UdpSocket.cpp
new file mode 100644
index 0000000..b34fb66
--- /dev/null
+++ b/external/oscpack_1_1_0/ip/win32/UdpSocket.cpp
@@ -0,0 +1,571 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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 // this must come first to prevent errors with MSVC7
+#include
+#include // for timeGetTime()
+
+#ifndef WINCE
+#include
+#endif
+
+#include
+#include
+#include // for memset
+#include
+#include
+
+#include "ip/UdpSocket.h" // usually I'd include the module header first
+ // but this is causing conflicts with BCB4 due to
+ // std::size_t usage.
+
+#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 )
+{
+ std::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");
+ }
+
+ std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) );
+ sendToAddr_.sin_family = AF_INET;
+ }
+
+ ~Implementation()
+ {
+ if (socket_ != INVALID_SOCKET) closesocket(socket_);
+ }
+
+ void SetEnableBroadcast( bool enableBroadcast )
+ {
+ char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32
+ setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
+ }
+
+ void SetAllowReuse( bool allowReuse )
+ {
+ // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article:
+ // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
+ // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx
+
+ char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32
+ setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
+ }
+
+ 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;
+ std::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, std::size_t size )
+ {
+ assert( isConnected_ );
+
+ send( socket_, data, (int)size, 0 );
+ }
+
+ void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
+ {
+ sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address );
+ sendToAddr_.sin_port = htons( (short)remoteEndpoint.port );
+
+ sendto( socket_, data, (int)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_; }
+
+ std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size )
+ {
+ assert( isBound_ );
+
+ struct sockaddr_in fromAddr;
+ socklen_t fromAddrLen = sizeof(fromAddr);
+
+ int result = recvfrom(socket_, data, (int)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_;
+}
+
+void UdpSocket::SetEnableBroadcast( bool enableBroadcast )
+{
+ impl_->SetEnableBroadcast( enableBroadcast );
+}
+
+void UdpSocket::SetAllowReuse( bool allowReuse )
+{
+ impl_->SetAllowReuse( allowReuse );
+}
+
+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, std::size_t size )
+{
+ impl_->Send( data, size );
+}
+
+void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size )
+{
+ impl_->SendTo( remoteEndpoint, data, size );
+}
+
+void UdpSocket::Bind( const IpEndpointName& localEndpoint )
+{
+ impl_->Bind( localEndpoint );
+}
+
+bool UdpSocket::IsBound() const
+{
+ return impl_->IsBound();
+}
+
+std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t 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();
+#ifndef WINCE
+ signal( SIGINT, SIG_DFL );
+#endif
+}
+
+
+class SocketReceiveMultiplexer::Implementation{
+ NetworkInitializer networkInitializer_;
+
+ std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_;
+ std::vector< AttachedTimerListener > timerListeners_;
+
+ volatile bool break_;
+ HANDLE breakEvent_;
+
+ double GetCurrentTimeMs() const
+ {
+#ifndef WINCE
+ return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days
+#else
+ return 0;
+#endif
+ }
+
+public:
+ Implementation()
+ {
+ breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL );
+ }
+
+ ~Implementation()
+ {
+ CloseHandle( breakEvent_ );
+ }
+
+ void AttachSocketListener( UdpSocket *socket, PacketListener *listener )
+ {
+ assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() );
+ // we don't check that the same socket has been added multiple times, even though this is an error
+ socketListeners_.push_back( std::make_pair( listener, socket ) );
+ }
+
+ void DetachSocketListener( UdpSocket *socket, PacketListener *listener )
+ {
+ std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i =
+ std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) );
+ assert( i != socketListeners_.end() );
+
+ socketListeners_.erase( i );
+ }
+
+ void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener )
+ {
+ timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) );
+ }
+
+ void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener )
+ {
+ timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) );
+ }
+
+ void DetachPeriodicTimerListener( TimerListener *listener )
+ {
+ std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
+ while( i != timerListeners_.end() ){
+ if( i->listener == listener )
+ break;
+ ++i;
+ }
+
+ assert( i != timerListeners_.end() );
+
+ timerListeners_.erase( i );
+ }
+
+ void Run()
+ {
+ break_ = false;
+
+ // prepare the window events which we use to wake up on incoming data
+ // we use this instead of select() primarily to support the AsyncBreak()
+ // mechanism.
+
+ std::vector events( socketListeners_.size() + 1, 0 );
+ int j=0;
+ for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin();
+ i != socketListeners_.end(); ++i, ++j ){
+
+ HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL );
+ WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below
+ events[j] = event;
+ }
+
+
+ events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event
+
+
+ // configure the timer queue
+ double currentTimeMs = GetCurrentTimeMs();
+
+ // expiry time ms, listener
+ std::vector< std::pair< double, AttachedTimerListener > > timerQueue_;
+ for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin();
+ i != timerListeners_.end(); ++i )
+ timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) );
+ std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls );
+
+ const int MAX_BUFFER_SIZE = 4098;
+ char *data = new char[ MAX_BUFFER_SIZE ];
+ IpEndpointName remoteEndpoint;
+
+ while( !break_ ){
+
+ double currentTimeMs = GetCurrentTimeMs();
+
+ DWORD waitTime = INFINITE;
+ if( !timerQueue_.empty() ){
+
+ waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs
+ ? timerQueue_.front().first - currentTimeMs
+ : 0 );
+ }
+
+ DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime );
+ if( break_ )
+ break;
+
+ if( waitResult != WAIT_TIMEOUT ){
+ for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){
+ std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE );
+ if( size > 0 ){
+ socketListeners_[i].first->ProcessPacket( data, (int)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;
+#ifndef WINCE
+ signal( SIGINT, InterruptSignalHandler );
+#endif
+ impl_->Run();
+#ifndef WINCE
+ signal( SIGINT, SIG_DFL );
+#endif
+ multiplexerInstanceToAbortWithSigInt_ = 0;
+}
+
+void SocketReceiveMultiplexer::Break()
+{
+ impl_->Break();
+}
+
+void SocketReceiveMultiplexer::AsynchronousBreak()
+{
+ impl_->AsynchronousBreak();
+}
+
diff --git a/external/oscpack_1_1_0/osc/MessageMappingOscPacketListener.h b/external/oscpack_1_1_0/osc/MessageMappingOscPacketListener.h
new file mode 100644
index 0000000..bf56b53
--- /dev/null
+++ b/external/oscpack_1_1_0/osc/MessageMappingOscPacketListener.h
@@ -0,0 +1,80 @@
+/*
+ oscpack -- Open Sound Control (OSC) packet manipulation library
+ http://www.rossbencina.com/code/oscpack
+
+ Copyright (c) 2004-2013 Ross Bencina
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ 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_MESSAGEMAPPINGOSCPACKETLISTENER_H
+#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H
+
+#include
+#include