[SCM] liblo/master: Pick patches from upstream disabling network tests
fsateler at users.alioth.debian.org
fsateler at users.alioth.debian.org
Mon Feb 10 14:51:56 UTC 2014
The following commit has been merged in the master branch:
commit b981c08d885d3ac433075f332b17bca436f2ad4f
Author: Felipe Sateler <fsateler at debian.org>
Date: Mon Feb 10 11:45:05 2014 -0300
Pick patches from upstream disabling network tests
those fail on buildd
diff --git a/debian/patches/Add-several-configure-options-for-the-sake-of-modula.patch b/debian/patches/Add-several-configure-options-for-the-sake-of-modula.patch
new file mode 100644
index 0000000..dfab3d5
--- /dev/null
+++ b/debian/patches/Add-several-configure-options-for-the-sake-of-modula.patch
@@ -0,0 +1,142 @@
+From 02f7754e245080626a590e43c190dfd4abe0d72f Mon Sep 17 00:00:00 2001
+From: Stephen Sinclair <radarsat1 at gmail.com>
+Date: Fri, 7 Feb 2014 13:55:54 +0100
+Subject: [PATCH 3/5] Add several configure options for the sake of modularity.
+
+This adds the following configure options:
+
+ --disable-tests Disable compiling test programs
+ --disable-network-tests Disable compiling network-based tests
+ --disable-tools Disable compiling tools
+ --disable-examples Disable compiling examples
+
+Additionally, it adds some code to configure.ac to print out some
+information about the current build. The --disable-network-tests flag
+is not yet implemented in testlo.
+---
+ Makefile.am | 6 +++++-
+ build/config-msvc.h | 3 +++
+ configure.ac | 37 +++++++++++++++++++++++++++++++++++++
+ src/Makefile.am | 11 ++++++++++-
+ 4 files changed, 55 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 7108987..e5e31cb 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,4 +1,8 @@
+-SUBDIRS = src examples lo build @DOXYGEN@
++SUBDIRS = src
++if COMPILE_EXAMPLES
++SUBDIRS += examples
++endif
++SUBDIRS += lo build @DOXYGEN@
+
+ EXTRA_DIST = libtool ltmain.sh autogen.sh
+
+diff --git a/build/config-msvc.h b/build/config-msvc.h
+index feb92cb..e55af42 100644
+--- a/build/config-msvc.h
++++ b/build/config-msvc.h
+@@ -4,6 +4,9 @@
+ /* Define this to enable ipv6. */
+ /* #undef ENABLE_IPV6 */
+
++/* Define this to enable network tests. */
++#define ENABLE_NETWORK_TESTS 1
++
+ /* Define this to enable threads. */
+ @DEFTHREADS@#define ENABLE_THREADS 1
+
+diff --git a/configure.ac b/configure.ac
+index c487d18..7be87bb 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -224,6 +224,43 @@ if test x"$enable_debug" = "xyes"; then
+ CXXFLAGS="$CF -O0 -g -Wall -Werror -DDEBUG"
+ fi
+
++AC_ARG_ENABLE(tests, [ --disable-tests Disable compiling test programs])
++AC_ARG_ENABLE(network-tests, [ --disable-network-tests Disable compiling network-based tests])
++AC_ARG_ENABLE(tools, [ --disable-tools Disable compiling tools])
++AC_ARG_ENABLE(examples, [ --disable-examples Disable compiling examples])
++
++AM_CONDITIONAL([COMPILE_TESTS],[test x$enable_tests != xno])
++AM_CONDITIONAL([COMPILE_TOOLS],[test x$enable_tools != xno])
++AM_CONDITIONAL([COMPILE_EXAMPLES],[test x$enable_examples != xno])
++
++if ! test x$enable_network_tests = xno; then
++ AC_DEFINE(ENABLE_NETWORK_TESTS, [1],
++ [Define this to enable network tests.])
++fi
++
++# Display some information about this build
++echo
++echo About this liblo build:
++echo
++echo CC=\"$CC\"
++echo CXX=\"$CXX\"
++echo DOXYGEN=\"$DOXYGEN\"
++echo CFLAGS=\"$CFLAGS\"
++echo CXXFLAGS=\"$CXXFLAGS\"
++echo LDFLAGS=\"$LDFLAGS\"
++echo LIBS=\"$LIBS\"
++echo
++test x$LO_BIGENDIAN = x0 && echo '== Building for little-endian architecture'
++test x$LO_BIGENDIAN = x1 && echo '== Building for big-endian architecture'
++test x$enable_debug = xyes && echo '== Compiling in debug mode'
++test x$enable_tests = xno && echo '== Disabled tests'
++test x$enable_networktests = xno && echo '== Disabled network-based tests'
++test x$enable_tools = xno && echo '== Disabled tools'
++test x$enable_examples = xno && echo '== Disabled examples'
++test x$HAVE_LAMBDA = xyes && echo '== Compiling C++ bindings' || echo '== Not compiling C++ bindings'
++test x$DOXYGEN = x && echo '== Disabled documentation (no doxygen found)'
++echo
++
+ AC_CONFIG_FILES([
+ Makefile
+ src/Makefile
+diff --git a/src/Makefile.am b/src/Makefile.am
+index d84818e..824f8bd 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -1,4 +1,7 @@
+-SUBDIRS = . tools
++SUBDIRS = .
++if COMPILE_TOOLS
++SUBDIRS += tools
++endif
+
+ MAINTAINERCLEANFILES = Makefile.in
+
+@@ -25,6 +28,7 @@ liblo_la_LDFLAGS = $(lt_windows) -export-dynamic -version-info @LO_SO_VERSION@
+
+ # Test programs depend on server threads, so skip them if threads are
+ # disabled.
++if COMPILE_TESTS
+ if ENABLE_THREADS
+ noinst_PROGRAMS = testlo subtest test_bidirectional_tcp
+ TESTS = testlo test_bidirectional_tcp
+@@ -33,6 +37,7 @@ noinst_PROGRAMS += cpp_test
+ TESTS += cpp_test
+ endif
+ endif
++endif
+
+ testlo_CFLAGS = -Wall -I$(top_srcdir)
+ testlo_SOURCES = testlo.c
+@@ -51,7 +56,11 @@ cpp_test_SOURCES = cpp_test.cpp
+ cpp_test_LDADD = liblo.la
+
+ test: all
++if COMPILE_TESTS
+ for i in $(TESTS); do echo Running $$i; if ! ./$$i; then exit 1; fi; done
++endif
+
+ memtest: all
++if COMPILE_TESTS
+ LD_LIBRARY_PATH=.libs valgrind --tool=memcheck .libs/testlo
++endif
+--
+1.9.rc1
+
diff --git a/debian/patches/Ensure-error-is-correctly-ignore-if-SO_REUSEPORT-is-.patch b/debian/patches/Ensure-error-is-correctly-ignore-if-SO_REUSEPORT-is-.patch
new file mode 100644
index 0000000..1bee6e8
--- /dev/null
+++ b/debian/patches/Ensure-error-is-correctly-ignore-if-SO_REUSEPORT-is-.patch
@@ -0,0 +1,86 @@
+From e5ba4c1708a51f4e19743f4a89c27598f991ce2d Mon Sep 17 00:00:00 2001
+From: Stephen Sinclair <radarsat1 at gmail.com>
+Date: Sun, 9 Feb 2014 00:55:19 +0100
+Subject: [PATCH 5/5] Ensure error is correctly ignore if SO_REUSEPORT is not
+ supported.
+
+Don't try to use it again if it was reported as unsupported.
+Apparently this can only be detected at run-time since kernel headers
+may not correspond with the running system.
+
+It could potentially be disabled entirely for Linux, but seems to
+cause failures with multicast on OS X if it is not set.
+---
+ src/server.c | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/src/server.c b/src/server.c
+index 3d01e88..407260e 100644
+--- a/src/server.c
++++ b/src/server.c
+@@ -78,6 +78,7 @@ typedef struct {
+ } queued_msg_list;
+
+ struct lo_cs lo_client_sockets = { -1, -1 };
++static int reuseport_supported = 1;
+
+ static int lo_can_coerce_spec(const char *a, const char *b);
+ static int lo_can_coerce(char a, char b);
+@@ -189,26 +190,28 @@ static unsigned int get_family_PF(const char *ip, const char *port)
+ }
+ #endif
+
+-static int lo_server_setsock_reuseaddr(lo_server s)
++static int lo_server_setsock_reuseaddr(lo_server s, int do_throw)
+ {
+ unsigned int yes = 1;
+ if (setsockopt(s->sockets[0].fd, SOL_SOCKET, SO_REUSEADDR,
+ (char*)&yes, sizeof(yes)) < 0) {
+ int err = geterror();
+- lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEADDR)");
++ if (do_throw)
++ lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEADDR)");
+ return err;
+ }
+ return 0;
+ }
+
+-static int lo_server_setsock_reuseport(lo_server s)
++static int lo_server_setsock_reuseport(lo_server s, int do_throw)
+ {
+ #ifdef SO_REUSEPORT
+ unsigned int yes = 1;
+ if (setsockopt(s->sockets[0].fd, SOL_SOCKET, SO_REUSEPORT,
+ &yes, sizeof(yes)) < 0) {
+ int err = geterror();
+- lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEPORT)");
++ if (do_throw)
++ lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEPORT)");
+ return err;
+ }
+ #endif
+@@ -485,17 +488,18 @@ lo_server lo_server_new_with_proto_internal(const char *group,
+ if (group != NULL
+ || proto == LO_TCP)
+ {
+- err = lo_server_setsock_reuseaddr(s);
++ err = lo_server_setsock_reuseaddr(s, 1);
+ if (err) {
+ lo_server_free(s);
+ return NULL;
+ }
+ }
+
+- if (group != NULL)
++ if (group != NULL && reuseport_supported)
+ {
+ /* Ignore the error if SO_REUSEPORT wasn't successful. */
+- lo_server_setsock_reuseport(s);
++ if (lo_server_setsock_reuseport(s, 0))
++ reuseport_supported = 0;
+ }
+
+ #if defined(WIN32) || defined(_MSC_VER)
+--
+1.9.rc1
+
diff --git a/debian/patches/Patch-for-missing-include-for-FreeBSD-from-SF-user-n.patch b/debian/patches/Patch-for-missing-include-for-FreeBSD-from-SF-user-n.patch
new file mode 100644
index 0000000..5b8c949
--- /dev/null
+++ b/debian/patches/Patch-for-missing-include-for-FreeBSD-from-SF-user-n.patch
@@ -0,0 +1,25 @@
+From 0b8977f3cd97ee06dae73be4a792f1bfd66c2cfe Mon Sep 17 00:00:00 2001
+From: Stephen Sinclair <radarsat1 at gmail.com>
+Date: Tue, 4 Feb 2014 08:46:11 +0100
+Subject: [PATCH 2/5] Patch for missing #include for FreeBSD from SF user
+ nemysisbsd.
+
+---
+ src/lo_types_internal.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/lo_types_internal.h b/src/lo_types_internal.h
+index dcaae54..5ef3b95 100644
+--- a/src/lo_types_internal.h
++++ b/src/lo_types_internal.h
+@@ -20,6 +20,7 @@
+ #else
+ #define closesocket close
+ #include <netdb.h>
++#include <netinet/in.h>
+ #include <arpa/inet.h>
+ #endif
+
+--
+1.9.rc1
+
diff --git a/debian/patches/Refactor-testlo-breaking-up-huge-list-of-tests-into-.patch b/debian/patches/Refactor-testlo-breaking-up-huge-list-of-tests-into-.patch
new file mode 100644
index 0000000..6a126f9
--- /dev/null
+++ b/debian/patches/Refactor-testlo-breaking-up-huge-list-of-tests-into-.patch
@@ -0,0 +1,2863 @@
+From 5c9e76a4fb505caf8e81e098971e265cc2cb26ba Mon Sep 17 00:00:00 2001
+From: Stephen Sinclair <radarsat1 at gmail.com>
+Date: Sat, 8 Feb 2014 13:58:29 +0100
+Subject: [PATCH 4/5] Refactor testlo, breaking up huge list of tests into
+ smaller functions.
+
+Also fixes any infinite wait loops and adds switch to disable
+network-based tests for when testlo must be tested on a firewalled or
+otherwise network-restricted environment such as the Debian build
+farm.
+---
+ configure.ac | 4 +-
+ src/Makefile.am | 7 +-
+ src/subtest.c | 25 +-
+ src/testlo.c | 2411 +++++++++++++++++++++++++++++--------------------------
+ 4 files changed, 1300 insertions(+), 1147 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 7be87bb..36ebc0d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -232,6 +232,7 @@ AC_ARG_ENABLE(examples, [ --disable-examples Disable compiling examples])
+ AM_CONDITIONAL([COMPILE_TESTS],[test x$enable_tests != xno])
+ AM_CONDITIONAL([COMPILE_TOOLS],[test x$enable_tools != xno])
+ AM_CONDITIONAL([COMPILE_EXAMPLES],[test x$enable_examples != xno])
++AM_CONDITIONAL([ENABLE_NETWORK_TESTS],[test x$enable_network_tests != xno])
+
+ if ! test x$enable_network_tests = xno; then
+ AC_DEFINE(ENABLE_NETWORK_TESTS, [1],
+@@ -244,7 +245,6 @@ echo About this liblo build:
+ echo
+ echo CC=\"$CC\"
+ echo CXX=\"$CXX\"
+-echo DOXYGEN=\"$DOXYGEN\"
+ echo CFLAGS=\"$CFLAGS\"
+ echo CXXFLAGS=\"$CXXFLAGS\"
+ echo LDFLAGS=\"$LDFLAGS\"
+@@ -254,7 +254,7 @@ test x$LO_BIGENDIAN = x0 && echo '== Building for little-endian architecture'
+ test x$LO_BIGENDIAN = x1 && echo '== Building for big-endian architecture'
+ test x$enable_debug = xyes && echo '== Compiling in debug mode'
+ test x$enable_tests = xno && echo '== Disabled tests'
+-test x$enable_networktests = xno && echo '== Disabled network-based tests'
++test x$enable_network_tests = xno && echo '== Disabled network-based tests'
+ test x$enable_tools = xno && echo '== Disabled tools'
+ test x$enable_examples = xno && echo '== Disabled examples'
+ test x$HAVE_LAMBDA = xyes && echo '== Compiling C++ bindings' || echo '== Not compiling C++ bindings'
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 824f8bd..b107a5e 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -31,13 +31,18 @@ liblo_la_LDFLAGS = $(lt_windows) -export-dynamic -version-info @LO_SO_VERSION@
+ if COMPILE_TESTS
+ if ENABLE_THREADS
+ noinst_PROGRAMS = testlo subtest test_bidirectional_tcp
+-TESTS = testlo test_bidirectional_tcp
++TESTS = testlo
+ if HAVE_LAMBDA
+ noinst_PROGRAMS += cpp_test
++endif
++if ENABLE_NETWORK_TESTS
++TESTS += test_bidirectional_tcp
++if HAVE_LAMBDA
+ TESTS += cpp_test
+ endif
+ endif
+ endif
++endif
+
+ testlo_CFLAGS = -Wall -I$(top_srcdir)
+ testlo_SOURCES = testlo.c
+diff --git a/src/subtest.c b/src/subtest.c
+index f8e03e4..0259372 100644
+--- a/src/subtest.c
++++ b/src/subtest.c
+@@ -23,6 +23,8 @@
+
+ #include "lo/lo.h"
+
++static int subtest_count = 0;
++
+ int subtest_handler(const char *path, const char *types, lo_arg ** argv,
+ int argc, lo_message data, void *user_data);
+
+@@ -30,6 +32,7 @@ int main(int argc, char *argv[])
+ {
+ lo_server_thread st;
+ lo_address t;
++ int tries;
+
+ printf("entered subtest\n");
+
+@@ -48,11 +51,19 @@ int main(int argc, char *argv[])
+ t = lo_address_new_from_url(argv[1]);
+ lo_send(t, "/subtest", "i", 0xf00);
+
++ tries = 400;
++ while (subtest_count == 0 && (--tries > 0)) {
+ #if defined(WIN32) || defined(_MSC_VER)
+- Sleep(4000);
++ Sleep(10);
+ #else
+- sleep(4);
++ usleep(10000);
+ #endif
++ }
++
++ if (tries == 0) {
++ printf("subtest: too many tries\n");
++ exit(1);
++ }
+
+ return 0;
+ }
+@@ -65,6 +76,7 @@ int subtest_handler(const char *path, const char *types, lo_arg ** argv,
+ static char *uri = NULL;
+
+ printf("subtest: got reply (%s)\n", path);
++
+ if (!uri) {
+ uri = lo_address_get_url(a);
+ } else {
+@@ -77,7 +89,9 @@ int subtest_handler(const char *path, const char *types, lo_arg ** argv,
+ }
+ free(new_uri);
+ }
++
+ lo_send(a, "/subtest-reply", "i", 0xbaa);
++
+ if (lo_address_errno(a)) {
+ fprintf(stderr, "subtest error %d: %s\n", lo_address_errno(a),
+ lo_address_errstr(a));
+@@ -86,15 +100,16 @@ int subtest_handler(const char *path, const char *types, lo_arg ** argv,
+ }
+
+ for (i = 0; i < 10; i++) {
++ lo_send(a, "/subtest-reply", "i", 0xbaa + i);
+ #if defined(WIN32) || defined(_MSC_VER)
+- /* TODO: Wait time of 2.233 not easily doable in Windows */
+ Sleep(2);
+ #else
+- usleep(2233);
++ usleep(2000);
+ #endif
+- lo_send(a, "/subtest-reply", "i", 0xbaa + i);
+ }
+
++ subtest_count ++;
++
+ return 0;
+ }
+
+diff --git a/src/testlo.c b/src/testlo.c
+index f7ecfa6..51898cf 100644
+--- a/src/testlo.c
++++ b/src/testlo.c
+@@ -47,9 +47,11 @@
+ #if defined(WIN32) || defined(_MSC_VER)
+ #define PATHDELIM "\\"
+ #define EXTEXE ".exe"
++#defnie SLEEP_MS(x) Sleep(x)
+ #else
+ #define PATHDELIM "/"
+ #define EXTEXE ""
++#define SLEEP_MS(x) usleep((x)*1000)
+ #endif
+
+ #ifndef MSG_NOSIGNAL
+@@ -57,9 +59,13 @@
+ #endif
+
+ #define TEST(cond) if (!(cond)) { fprintf(stderr, "FAILED " #cond \
+- " at %s:%d\n", __FILE__, __LINE__); \
+- exit(1); } \
+- else { printf("passed " #cond "\n"); }
++ " at %s:%d\n", __FILE__, __LINE__); \
++ exit(1); } \
++ else { printf("passed " #cond "\n"); }
++
++#define DOING(s) printf("\n == " s "() ==\n\n")
++
++#define HANDLER(h) printf(" <-- " h "_handler()\n")
+
+ union end_test32 {
+ uint32_t i;
+@@ -78,6 +84,7 @@ static int reply_count = 0;
+ static int subtest_count = 0;
+ static int subtest_reply_count = 0;
+ static int error_okay = 0;
++static int tcp_done = 0;
+
+ char testdata[5] = "ABCDE";
+
+@@ -86,6 +93,8 @@ static float jitter_total = 0.0f;
+ static float jitter_max = 0.0f;
+ static float jitter_min = 1000.0f;
+
++uint8_t midi_data[4] = { 0xff, 0xf7, 0xAA, 0x00 };
++
+ void exitcheck(void);
+ void test_deserialise(void);
+ void test_validation(lo_address a);
+@@ -131,1398 +140,1522 @@ int quit_handler(const char *path, const char *types, lo_arg ** argv,
+ int argc, lo_message data, void *user_data);
+
+ int test_varargs(lo_address a, const char *path, const char *types, ...);
+-
+-int test_tcp_nonblock();
+-
+ int test_version();
++void test_types();
++void test_url();
++void test_address();
++void test_blob();
++void test_server_thread(lo_server_thread *pst, lo_address *pa);
++void test_message(lo_address a);
++void test_pattern(lo_address a);
++void test_subtest(lo_server_thread st);
++void test_bundle(lo_server_thread st, lo_address a);
++void test_nonblock();
++void test_unix_sockets();
++void test_tcp();
++void test_tcp_nonblock();
++void cleanup(lo_server_thread st, lo_address a);
+
+ int main()
+ {
+- lo_blob btest = lo_blob_new(sizeof(testdata), testdata);
+- lo_server_thread st, sta, stb;
+- lo_server s = lo_server_new(NULL, error);
+- lo_bundle b;
+- lo_message m1, m2;
+- char *server_url, *path, *protocol, *host, *port;
+- const char *host2, *port2;
++#ifdef ENABLE_NETWORK_TESTS
++ lo_server_thread st;
+ lo_address a;
+- uint8_t midi_data[4] = { 0xff, 0xf7, 0xAA, 0x00 };
+- union end_test32 et32;
+- union end_test64 et64;
+- lo_timetag tt = { 0x1, 0x80000000 }, sched;
+- int count;
+- int proto;
+- char cmd[256];
+- const char *p;
+- int i, rc;
++#endif
+
+- test_version();
++ atexit(exitcheck);
+
++ test_version();
+ test_deserialise();
++ test_types();
++ test_url();
++ test_address();
++ test_blob();
+
+- sta = lo_server_thread_new("7591", error);
+- stb = lo_server_thread_new("7591", rep_error);
+- if (stb) {
+- fprintf(stderr, "FAILED: create bad server thread object!\n");
+- exit(1);
+- }
+- lo_server_thread_free(sta);
+-
+- /* leak check */
+- st = lo_server_thread_new(NULL, error);
+- lo_server_thread_start(st);
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(4);
++#ifdef ENABLE_NETWORK_TESTS
++ test_server_thread(&st, &a);
++ test_validation(a);
++ test_multicast(st);
++ test_message(a);
++ test_pattern(a);
++ test_subtest(st);
++ test_bundle(st, a);
++ test_nonblock(st);
++ test_unix_sockets();
++ test_tcp();
++ test_tcp_nonblock();
++ cleanup(st, a);
+ #else
+- usleep(4000);
++ done = 1;
+ #endif
+- lo_server_thread_stop(st);
+- lo_server_thread_free(st);
+- st = lo_server_thread_new(NULL, error);
+- lo_server_thread_start(st);
+- lo_server_thread_stop(st);
+- lo_server_thread_free(st);
+- st = lo_server_thread_new(NULL, error);
+- lo_server_thread_free(st);
+- st = lo_server_thread_new(NULL, error);
+- lo_server_thread_free(st);
+- st = lo_server_thread_new(NULL, error);
+-
+- a = lo_address_new_from_url("osc://localhost/");
+- TEST(a != NULL);
+- lo_address_free(a);
+-
+- a = lo_address_new_from_url("osc.://localhost/");
+- TEST(a == NULL);
+-
+-
+- atexit(exitcheck);
+
+- printf("type tests\n");
+- TEST(sizeof(float) == sizeof(int32_t));
+- TEST(sizeof(double) == sizeof(int64_t));
+-
+- et32.i = 0x23242526U;
+- et32.i = lo_htoo32(et32.i);
+- if (et32.c[0] != 0x23 || et32.c[1] != 0x24 || et32.c[2] != 0x25 ||
+- et32.c[3] != 0x26) {
+- fprintf(stderr, "failed 32bit endian conversion test\n");
+- fprintf(stderr, "0x23242526 -> %X\n", et32.i);
+- exit(1);
+- } else {
+- printf("passed 32bit endian conversion test\n");
+- }
++ return 0;
++}
+
+- et64.i = 0x232425262728292AULL;
+- et64.i = lo_htoo64(et64.i);
+- if (et64.c[0] != 0x23 || et64.c[1] != 0x24 || et64.c[2] != 0x25 ||
+- et64.c[3] != 0x26 || et64.c[4] != 0x27 || et64.c[5] != 0x28 ||
+- et64.c[6] != 0x29 || et64.c[7] != 0x2A) {
+- fprintf(stderr, "failed 64bit endian conversion\n");
+- fprintf(stderr, "0x232425262728292A -> %" PRINTF_LL "X\n",
+- (long long unsigned int) et64.i);
+- exit(1);
++void exitcheck(void)
++{
++ if (!done) {
++ fprintf(stderr, "\ntest run not completed\n" PACKAGE_NAME
++ " test FAILED\n");
+ } else {
+- printf("passed 64bit endian conversion\n");
++ printf(PACKAGE_NAME " test PASSED\n");
+ }
+- printf("\n");
++}
+
+- /* OSC URL tests */
+- path = lo_url_get_path("osc.udp://localhost:9999/a/path/is/here");
+- if (strcmp(path, "/a/path/is/here")) {
+- printf("failed lo_url_get_path() test1\n");
+- printf("'%s' != '/a/path/is/here'\n", path);
++void error(int num, const char *msg, const char *path)
++{
++ printf("liblo server error %d in %s: %s", num, path, msg);
++ if (!error_okay)
+ exit(1);
+- } else {
+- printf("passed lo_url_get_path() test1\n");
+- }
+- free(path);
++ else
++ printf(" (expected)\n");
++}
+
+- protocol =
+- lo_url_get_protocol("osc.udp://localhost:9999/a/path/is/here");
+- if (strcmp(protocol, "udp")) {
+- printf("failed lo_url_get_protocol() test1\n");
+- printf("'%s' != 'udp'\n", protocol);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_protocol() test1\n");
++void rep_error(int num, const char *msg, const char *path)
++{
++ if (num != 9904) {
++ error(num, msg, path);
+ }
+- free(protocol);
++}
+
+- protocol =
+- lo_url_get_protocol("osc.tcp://localhost:9999/a/path/is/here");
+- if (strcmp(protocol, "tcp")) {
+- printf("failed lo_url_get_protocol() test2\n");
+- printf("'%s' != 'tcp'\n", protocol);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_protocol() test2\n");
+- }
+- free(protocol);
++int generic_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ int i;
++ HANDLER("generic");
+
+- protocol =
+- lo_url_get_protocol
+- ("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
+- if (strcmp(protocol, "udp")) {
+- printf("failed lo_url_get_protocol() test1 (IPv6)\n");
+- printf("'%s' != 'udp'\n", protocol);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_protocol() test1 (IPv6)\n");
++ printf("path: <%s>\n", path);
++ for (i = 0; i < argc; i++) {
++ printf("arg %d '%c' ", i, types[i]);
++ lo_arg_pp(types[i], argv[i]);
++ printf("\n");
+ }
+- free(protocol);
++ printf("\n");
+
+- proto =
+- lo_url_get_protocol_id("osc.udp://localhost:9999/a/path/is/here");
+- if (proto != LO_UDP) {
+- printf("failed lo_url_get_protocol_id() test1\n");
+- printf("'%d' != LO_UDP\n", proto);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_protocol_id() test1\n");
+- }
++ return 1;
++}
+
+- proto =
+- lo_url_get_protocol_id("osc.tcp://localhost:9999/a/path/is/here");
+- if (proto != LO_TCP) {
+- printf("failed lo_url_get_protocol_id() test2\n");
+- printf("'%d' != LO_TCP\n", proto);
++int foo_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ HANDLER("foo");
++ lo_server serv = (lo_server) user_data;
++ lo_address src = lo_message_get_source(data);
++ char *url = lo_address_get_url(src);
++ char *server_url = lo_server_get_url(serv);
++ printf("Address of us: %s\n", server_url);
++ printf("%s <- f:%f, i:%d\n", path, argv[0]->f, argv[1]->i);
++ if (lo_send_from(src, serv, LO_TT_IMMEDIATE, "/reply", "s", "a reply")
++ == -1) {
++ printf("OSC reply error %d: %s\nSending to %s\n",
++ lo_address_errno(src), lo_address_errstr(src), url);
+ exit(1);
+ } else {
+- printf("passed lo_url_get_protocol_id() test2\n");
++ printf("Reply sent to %s\n\n", url);
+ }
++ free(server_url);
++ free(url);
+
+- proto =
+- lo_url_get_protocol_id
+- ("osc.invalid://localhost:9999/a/path/is/here");
+- if (proto != -1) {
+- printf("failed lo_url_get_protocol_id() test3\n");
+- printf("'%d' != -1\n", proto);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_protocol_id() test3\n");
+- }
++ return 0;
++}
+
+- proto =
+- lo_url_get_protocol_id
+- ("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
+- if (proto != LO_UDP) {
+- printf("failed lo_url_get_protocol_id() test1 (IPv6)\n");
+- printf("'%d' != LO_UDP\n", proto);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_protocol_id() test1 (IPv6)\n");
+- }
++int reply_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ HANDLER("reply");
++ lo_address src = lo_message_get_source(data);
++ char *url = lo_address_get_url(src);
++ printf("Reply received from %s\n", url);
++ free(url);
++ reply_count++;
+
+- host =
+- lo_url_get_hostname
+- ("osc.udp://foo.example.com:9999/a/path/is/here");
+- if (strcmp(host, "foo.example.com")) {
+- printf("failed lo_url_get_hostname() test1\n");
+- printf("'%s' != 'foo.example.com'\n", host);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_hostname() test1\n");
+- }
+- free(host);
++ return 0;
++}
+
+- host =
+- lo_url_get_hostname
+- ("osc.udp://[0000::::0001]:9999/a/path/is/here");
+- if (strcmp(host, "0000::::0001")) {
+- printf("failed lo_url_get_hostname() test2 (IPv6)\n");
+- printf("'%s' != '0000::::0001'\n", host);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_hostname() test2 (IPv6)\n");
+- }
+- free(host);
++int lots_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ lo_blob b;
++ unsigned char *d;
++ HANDLER("lots");
+
+- port = lo_url_get_port("osc.udp://localhost:9999/a/path/is/here");
+- if (strcmp(port, "9999")) {
+- printf("failed lo_url_get_port() test1\n");
+- printf("'%s' != '9999'\n", port);
++ if (strcmp(path, "/lotsofformats")) {
++ fprintf(stderr, "path != /lotsofformats\n");
+ exit(1);
+- } else {
+- printf("passed lo_url_get_port() test1\n");
+ }
+- free(port);
+-
+- port =
+- lo_url_get_port
+- ("osc.udp://[::ffff:127.0.0.1]:9999/a/path/is/here");
+- if (strcmp(port, "9999")) {
+- printf("failed lo_url_get_port() test1 (IPv6)\n");
+- printf("'%s' != '9999'\n", port);
+- exit(1);
+- } else {
+- printf("passed lo_url_get_port() test1 (IPv6)\n");
+- }
+- free(port);
++ printf("path = %s\n", path);
++ TEST(types[0] == 'f' && argv[0]->f == 0.12345678f);
++ TEST(types[1] == 'i' && argv[1]->i == 123);
++ TEST(types[2] == 's' && !strcmp(&argv[2]->s, "123"));
++ b = (lo_blob) argv[3];
++ d = lo_blob_dataptr(b);
++ TEST(types[3] == 'b' && lo_blob_datasize(b) == 5);
++ TEST(d[0] == 'A' && d[1] == 'B' && d[2] == 'C' && d[3] == 'D' &&
++ d[4] == 'E');
++ d = argv[4]->m;
++ TEST(d[0] == 0xff && d[1] == 0xf7 && d[2] == 0xaa && d[3] == 0x00);
++ TEST(types[5] == 'h' && argv[5]->h == 0x0123456789ABCDEFULL);
++ TEST(types[6] == 't' && argv[6]->t.sec == 1 &&
++ argv[6]->t.frac == 0x80000000);
++ TEST(types[7] == 'd' && argv[7]->d == 0.9999);
++ TEST(types[8] == 'S' && !strcmp(&argv[8]->S, "sym"));
++ printf("char: %d\n", argv[9]->c);
++ TEST(types[9] == 'c' && argv[9]->c == 'X');
++ TEST(types[10] == 'c' && argv[10]->c == 'Y');
++ TEST(types[11] == 'T');
++ TEST(types[12] == 'F');
++ TEST(types[13] == 'N');
++ TEST(types[14] == 'I');
++
+ printf("\n");
+
++ return 0;
++}
+
++int coerce_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ HANDLER("coerce");
++ printf("path = %s\n", path);
++ TEST(types[0] == 'd' && fabs(argv[0]->d - 0.1) < FLT_EPSILON);
++ TEST(types[1] == 'f' && fabs(argv[1]->f - 0.2) < FLT_EPSILON);
++ TEST(types[2] == 'h' && argv[2]->h == 123);
++ TEST(types[3] == 'i' && argv[3]->i == 124);
++ TEST(types[4] == 'S' && !strcmp(&argv[4]->S, "aaa"));
++ TEST(types[5] == 's' && !strcmp(&argv[5]->s, "bbb"));
++ printf("\n");
+
++ return 0;
++}
+
++int bundle_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ HANDLER("bundle");
++ bundle_count++;
++ printf("received bundle\n");
+
+- a = lo_address_new_from_url("osc.tcp://foo.example.com:9999/");
+- host2 = lo_address_get_hostname(a);
+- if (strcmp(host2, "foo.example.com")) {
+- printf("failed lo_address_get_hostname() test\n");
+- printf("'%s' != 'foo.example.com'\n", host2);
+- exit(1);
+- } else {
+- printf("passed lo_address_get_hostname() test\n");
+- }
++ return 0;
++}
+
+- port2 = lo_address_get_port(a);
+- if (strcmp(port2, "9999")) {
+- printf("failed lo_address_get_port() test\n");
+- printf("'%s' != '9999'\n", port2);
+- exit(1);
+- } else {
+- printf("passed lo_address_get_port() test\n");
+- }
++int timestamp_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ int bundled = argv[0]->i;
++ lo_timetag ts, arg_ts;
++ HANDLER("timestamp");
+
+- proto = lo_address_get_protocol(a);
+- if (proto != LO_TCP) {
+- printf("failed lo_address_get_protocol() test\n");
+- printf("'%d' != '%d'\n", proto, LO_TCP);
+- exit(1);
+- } else {
+- printf("passed lo_address_get_protocol() test\n");
+- }
++ ts = lo_message_get_timestamp(data);
++ arg_ts = argv[1]->t;
+
+- server_url = lo_address_get_url(a);
+- if (strcmp(server_url, "osc.tcp://foo.example.com:9999/")) {
+- printf("failed lo_address_get_url() test\n");
+- printf("'%s' != '%s'\n", server_url,
+- "osc.tcp://foo.example.com:9999/");
+- exit(1);
++ if (bundled) {
++ TEST((ts.sec == arg_ts.sec) && (ts.frac == arg_ts.frac));
+ } else {
+- printf("passed lo_address_get_url() test\n");
++ TEST(ts.sec == LO_TT_IMMEDIATE.sec
++ && ts.frac == LO_TT_IMMEDIATE.frac);
+ }
+- free(server_url);
+- lo_address_free(a);
+- printf("\n");
++ return 0;
++}
+
++int jitter_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ lo_timetag now;
++ float jitter;
+
+- /* Test blod sizes */
+- if (lo_blob_datasize(btest) != 5 || lo_blobsize(btest) != 12) {
+- printf("blob is %d (%d) bytes long, should be 5 (12)\n",
+- lo_blob_datasize(btest), lo_blobsize(btest));
+- lo_arg_pp(LO_BLOB, btest);
+- printf(" <- blob\n");
+- exit(1);
+- }
++ HANDLER("jitter");
+
++ lo_timetag_now(&now);
++ jitter = fabs(lo_timetag_diff(now, argv[0]->t));
++ jitter_count++;
++ //printf("jitter: %f\n", jitter);
++ printf("%d expected: %x:%x received %x:%x\n", argv[1]->i,
++ argv[0]->t.sec, argv[0]->t.frac, now.sec, now.frac);
++ jitter_total += jitter;
++ if (jitter > jitter_max)
++ jitter_max = jitter;
++ if (jitter < jitter_min)
++ jitter_min = jitter;
+
++ return 0;
++}
+
+- /* Server method handler tests */
+- server_url = lo_server_thread_get_url(st);
+- a = lo_address_new_from_url(server_url);
+- printf("Server URL: %s\n", server_url);
+- free(server_url);
++int pattern_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ HANDLER("pattern");
+
+- /* add method that will match the path /foo/bar, with two numbers, coerced
+- * to float and int */
++ pattern_count++;
++ printf("pattern matched %s\n", (char *) user_data);
+
+- lo_server_thread_add_method(st, "/foo/bar", "fi", foo_handler,
+- lo_server_thread_get_server(st));
++ return 0;
++}
+
+- lo_server_thread_add_method(st, "/reply", "s", reply_handler, NULL);
++int subtest_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ lo_address a;
++ HANDLER("subtest");
+
+- lo_server_thread_add_method(st, "/lotsofformats", "fisbmhtdSccTFNI",
+- lots_handler, NULL);
++ a = lo_message_get_source(data);
+
+- lo_server_thread_add_method(st, "/coerce", "dfhiSs",
+- coerce_handler, NULL);
++ subtest_count++;
++ lo_send_from(a, lo_server_thread_get_server(user_data),
++ LO_TT_IMMEDIATE, "/subtest", "i", subtest_count);
+
+- lo_server_thread_add_method(st, "/bundle", NULL, bundle_handler, NULL);
+- lo_server_thread_add_method(st, "/timestamp", NULL,
+- timestamp_handler, NULL);
+- lo_server_thread_add_method(st, "/jitter", "ti", jitter_handler, NULL);
++ return 0;
++}
+
+- lo_server_thread_add_method(st, "/pattern/foo", NULL,
+- pattern_handler, "foo");
+- lo_server_thread_add_method(st, "/pattern/bar", NULL,
+- pattern_handler, "bar");
+- lo_server_thread_add_method(st, "/pattern/baz", NULL,
+- pattern_handler, "baz");
++int subtest_reply_handler(const char *path, const char *types,
++ lo_arg ** argv, int argc, lo_message data,
++ void *user_data)
++{
++ HANDLER("subtest_reply");
++ subtest_reply_count++;
+
+- lo_server_thread_add_method(st, "/subtest", "i", subtest_handler, st);
++ return 0;
++}
+
+- lo_server_thread_add_method(st, "/subtest-reply", "i",
+- subtest_reply_handler, NULL);
++int quit_handler(const char *path, const char *types, lo_arg ** argv,
++ int argc, lo_message data, void *user_data)
++{
++ HANDLER("quit");
++ done = 1;
+
+- /* add method that will match any path and args */
+- lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL);
++ return 0;
++}
+
+- /* add method that will match the path /quit with no args */
+- lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL);
++int test_version()
++{
++ int major, minor, lt_maj, lt_min, lt_bug;
++ char extra[256];
++ char string[256];
++ DOING("test_version");
+
+- /* check that the thread restarts */
+- lo_server_thread_start(st);
+- lo_server_thread_stop(st);
+- lo_server_thread_start(st);
++ lo_version(string, 256,
++ &major, &minor, extra, 256,
++ <_maj, <_min, <_bug);
+
+- if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) < 0) {
+- printf("OSC error A %d: %s\n", lo_address_errno(a),
+- lo_address_errstr(a));
+- exit(1);
+- }
++ printf("liblo version string `%s'\n", string);
++ printf("liblo version: %d.%d%s\n", major, minor, extra);
++ printf("liblo libtool version: %d.%d.%d\n", lt_maj, lt_min, lt_bug);
++ printf("\n");
+
+- if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) < 0) {
+- printf("OSC error B %d: %s\n", lo_address_errno(a),
+- lo_address_errstr(a));
+- exit(1);
+- }
++ return 0;
++}
+
+- test_validation(a);
+- test_multicast(st);
++int test_varargs(lo_address a, const char *path, const char *types, ...)
++{
++ va_list ap;
++ lo_message m;
++ int error;
+
+- lo_send(a, "/", "i", 242);
+- lo_send(a, "/pattern/", "i", 243);
++ DOING("test_varargs");
+
+-#ifndef _MSC_VER /* MS compiler refuses to compile this case */
+- lo_send(a, "/bar", "ff", 0.12345678f, 1.0 / 0.0);
+-#endif
+- lo_send(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123,
+- "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999,
+- "sym", 'X', 'Y');
+- lo_send(a, "/coerce", "fdihsS", 0.1f, 0.2, 123, 124LL, "aaa", "bbb");
+- lo_send(a, "/coerce", "ffffss", 0.1f, 0.2f, 123.0, 124.0, "aaa",
+- "bbb");
+- lo_send(a, "/coerce", "ddddSS", 0.1, 0.2, 123.0, 124.0, "aaa", "bbb");
+- lo_send(a, "/a/b/c/d", "sfsff", "one", 0.12345678f, "three",
+- -0.00000023001f, 1.0);
+- lo_send(a, "/a/b/c/d", "b", btest);
++ m = lo_message_new();
+
+- TEST(test_varargs
+- (a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
+- btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym", 'X',
+- 'Y', LO_ARGS_END) == 0);
++ va_start(ap, types);
++ if ((error = lo_message_add_varargs(m, types, ap)) == 0)
++ lo_send_message(a, path, m);
++ else
++ printf("lo_message_add_varargs returned %d\n", error);
++ lo_message_free(m);
++ return error < 0;
++}
+
+-#ifdef __GNUC__
+-#ifndef USE_ANSI_C
+- // Note: Lack of support for variable-argument macros in non-GCC compilers
+- // does not allow us to test for these conditions.
++void replace_char(char *str, size_t size, const char find,
++ const char replace)
++{
++ char *p = str;
++ while (size--) {
++ if (find == *p) {
++ *p = replace;
++ }
++ ++p;
++ }
++}
+
+- // too many args
+- TEST(test_varargs(a, "/lotsofformats", "f", 0.12345678f, 123,
+- "123", btest, midi_data, 0x0123456789abcdefULL, tt,
+- 0.9999, "sym", 'X', 'Y', LO_ARGS_END) != 0);
+- // too many types
+- TEST(test_varargs
+- (a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
+- btest, midi_data, 0x0123456789abcdefULL, tt, 0.5,
+- LO_ARGS_END) != 0);
+-#endif
+-#endif
++void test_deserialise()
++{
++ char *buf, *buf2, *tmp;
++ const char *types = NULL, *path;
++ lo_arg **argv = NULL;
++ size_t len, size;
++ char data[256];
++ int result = 0;
+
+- // test lo_message_add
+- m1 = lo_message_new();
+- TEST(lo_message_add(m1, "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
+- btest, midi_data, 0x0123456789abcdefULL, tt,
+- 0.9999, "sym", 'X', 'Y') == 0);
+- lo_send_message(a, "/lotsofformats", m1);
+- lo_message_free(m1);
++ lo_blob btest;
++ lo_timetag tt = { 0x1, 0x80000000 };
++ lo_blob b = NULL;
+
+- lo_blob_free(btest);
++ DOING("test_deserialise");
+
+- lo_send(a, "/pattern/*", "s", "a");
+- lo_send(a, "/pattern/ba[rz]", "s", "b");
++ btest = lo_blob_new(sizeof(testdata), testdata);
+
+- server_url = lo_server_thread_get_url(st);
++ // build a message
++ lo_message msg = lo_message_new();
++ TEST(0 == lo_message_get_argc(msg));
++ lo_message_add_float(msg, 0.12345678f); // 0 f
++ lo_message_add_int32(msg, 123); // 1 i
++ lo_message_add_string(msg, "123"); // 2 s
++ lo_message_add_blob(msg, btest); // 3 b
++ lo_message_add_midi(msg, midi_data); // 4 m
++ lo_message_add_int64(msg, 0x0123456789abcdefULL); // 5 h
++ lo_message_add_timetag(msg, tt); // 6 t
++ lo_message_add_double(msg, 0.9999); // 7 d
++ lo_message_add_symbol(msg, "sym"); // 8 S
++ lo_message_add_char(msg, 'X'); // 9 c
++ lo_message_add_char(msg, 'Y'); // 10 c
++ lo_message_add_true(msg); // 11 T
++ lo_message_add_false(msg); // 12 F
++ lo_message_add_nil(msg); // 13 N
++ lo_message_add_infinitum(msg); // 14 I
+
+-#ifdef WIN32
+- {
+- char cwd[2048];
+- _getcwd(cwd, 2048);
+- sprintf(cmd, "%s" PATHDELIM "subtest" EXTEXE, cwd);
+- }
+- printf("spawning subtest with `%s'\n", cmd);
+- for (i=0; i<2; i++) {
+- int j=0;
+- rc = _spawnl( _P_NOWAIT, cmd, cmd, server_url, NULL );
+- if (rc == -1) {
+- fprintf(stderr, "Cannot execute subtest command (%d)\n", i);
+- exit(1);
+- }
+- else while (subtest_count < 1 && j < 20) {
+- Sleep(100);
+- j++;
+- }
+- if (j >= 20) {
+- fprintf(stderr, "Never got a message from subtest (%d) "
+- "after 2 seconds.\n", i);
+- exit(1);
+- }
+- }
+-#else
+- sprintf(cmd, "." PATHDELIM "subtest" EXTEXE " %s", server_url);
+- printf("executing subtest with `%s'\n", cmd);
+- for (i=0; i<2; i++) {
+- rc = system(cmd);
+- if (rc == -1) {
+- fprintf(stderr, "Cannot execute subtest command (%d)\n", i);
+- exit(1);
+- }
+- else if (rc > 0) {
+- fprintf(stderr, "subtest command returned %d\n", rc);
+- exit(1);
+- }
+- }
+-#endif
++ // test types, args
++ TEST(15 == lo_message_get_argc(msg));
++ types = lo_message_get_types(msg);
++ TEST(NULL != types);
++ argv = lo_message_get_argv(msg);
++ TEST(NULL != argv);
++ TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON);
++ TEST('i' == types[1] && 123 == argv[1]->i);
++ TEST('s' == types[2] && !strcmp(&argv[2]->s, "123"));
++ TEST('b' == types[3]);
++ b = (lo_blob) argv[3];
++ TEST(lo_blob_datasize(b) == sizeof(testdata));
++ TEST(12 == lo_blobsize(b));
++ TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata)));
++ TEST('m' == types[4] && !memcmp(&argv[4]->m, midi_data, 4));
++ TEST('h' == types[5] && 0x0123456789abcdefULL == argv[5]->h);
++ TEST('t' == types[6] && 1 == argv[6]->t.sec
++ && 0x80000000 == argv[6]->t.frac);
++ TEST('d' == types[7] && fabs(argv[7]->d - 0.9999) < FLT_EPSILON);
++ TEST('S' == types[8] && !strcmp(&argv[8]->s, "sym"));
++ TEST('c' == types[9] && 'X' == argv[9]->c);
++ TEST('c' == types[10] && 'Y' == argv[10]->c);
++ TEST('T' == types[11] && NULL == argv[11]);
++ TEST('F' == types[12] && NULL == argv[12]);
++ TEST('N' == types[13] && NULL == argv[13]);
++ TEST('I' == types[14] && NULL == argv[14]);
+
+- free(server_url);
++ // serialise it
++ len = lo_message_length(msg, "/foo");
++ printf("serialise message_length=%d\n", (int) len);
++ buf = calloc(len, sizeof(char));
++ size = 0;
++ tmp = lo_message_serialise(msg, "/foo", buf, &size);
++ TEST(tmp == buf && size == len && 92 == len);
++ lo_message_free(msg);
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(2000);
+-#else
+- sleep(2);
+-#endif
+- TEST(reply_count == 3);
+- TEST(pattern_count == 5);
+- TEST(subtest_count == 2);
+- TEST(subtest_reply_count == 22);
+- printf("\n");
++ // deserialise it
++ printf("deserialise\n");
++ path = lo_get_path(buf, len);
++ TEST(NULL != path && !strcmp(path, "/foo"));
++ msg = lo_message_deserialise(buf, size, NULL);
++ TEST(NULL != msg);
+
+- {
+- lo_timetag t = { 10, 0xFFFFFFFC };
+- b = lo_bundle_new(t);
+- }
+- m1 = lo_message_new();
+- lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
+- lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+- lo_bundle_add_message(b, "/bundle", m1);
+- lo_send_bundle(a, b);
++ // repeat same test as above
++ TEST(15 == lo_message_get_argc(msg));
++ types = lo_message_get_types(msg);
++ TEST(NULL != types);
++ argv = lo_message_get_argv(msg);
++ TEST(NULL != argv);
++ TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON);
++ TEST('i' == types[1] && 123 == argv[1]->i);
++ TEST('s' == types[2] && !strcmp(&argv[2]->s, "123"));
++ TEST('b' == types[3]);
++ b = (lo_blob) argv[3];
++ TEST(lo_blob_datasize(b) == sizeof(testdata));
++ TEST(12 == lo_blobsize(b));
++ TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata)));
++ TEST('m' == types[4] && !memcmp(&argv[4]->m, midi_data, 4));
++ TEST('h' == types[5] && 0x0123456789abcdefULL == argv[5]->h);
++ TEST('t' == types[6] && 1 == argv[6]->t.sec
++ && 0x80000000 == argv[6]->t.frac);
++ TEST('d' == types[7] && fabs(argv[7]->d - 0.9999) < FLT_EPSILON);
++ TEST('S' == types[8] && !strcmp(&argv[8]->s, "sym"));
++ TEST('c' == types[9] && 'X' == argv[9]->c);
++ TEST('c' == types[10] && 'Y' == argv[10]->c);
++ TEST('T' == types[11] && NULL == argv[11]);
++ TEST('F' == types[12] && NULL == argv[12]);
++ TEST('N' == types[13] && NULL == argv[13]);
++ TEST('I' == types[14] && NULL == argv[14]);
+
+- /* This should be safe for multiple copies of the same message. */
+- lo_bundle_free_messages(b);
++ // serialise it again, compare
++ len = lo_message_length(msg, "/foo");
++ printf("serialise message_length=%d\n", (int) len);
++ buf2 = calloc(len, sizeof(char));
++ size = 0;
++ tmp = lo_message_serialise(msg, "/foo", buf2, &size);
++ TEST(tmp == buf2 && size == len && 92 == len);
++ TEST(!memcmp(buf, buf2, len));
++ lo_message_free(msg);
+
+- {
+- lo_timetag t = { 1, 2 };
+- b = lo_bundle_new(t);
+- }
+- m1 = lo_message_new();
+- lo_message_add_int32(m1, 23);
+- lo_message_add_string(m1, "23");
+- lo_bundle_add_message(b, "/bundle", m1);
+- m2 = lo_message_new();
+- lo_message_add_string(m2, "24");
+- lo_message_add_int32(m2, 24);
+- lo_bundle_add_message(b, "/bundle", m2);
+- lo_bundle_add_message(b, "/bundle", m1);
+- TEST(lo_bundle_count(b)==3);
+- TEST(lo_bundle_get_message(b,1,&p)==m2);
+- TEST(strcmp(p, "/bundle")==0);
++ lo_blob_free(btest);
++ free(buf);
++ free(buf2);
+
+-/*
+- lo_send_bundle(a, b);
+- if (a->errnum) {
+- printf("error %d: %s\n", a->errnum, a->errstr);
+- exit(1);
+- }
+-*/
+- TEST(lo_send_bundle(a, b) == 88);
++ // deserialise failure tests with invalid message data
+
+- /* Should fail to add a bundle recursively */
+- TEST(lo_bundle_add_bundle(b, b) != 0)
++ msg = lo_message_deserialise(data, 0, &result); // 0 size
++ TEST(NULL == msg && LO_ESIZE == result);
+
+- /* But we can create a nested bundle and it should free
+- * successfully. */
+- {
+- lo_bundle b2 = 0;
+- {
+- lo_timetag t = { 10, 0xFFFFFFFE };
+- b2 = lo_bundle_new(t);
+- }
+- lo_bundle_add_message(b2, "/bundle", m1);
+- TEST(lo_bundle_add_bundle(b2, b) == 0);
++ snprintf(data, 256, "%s", "/foo"); // unterminated path string
++ msg = lo_message_deserialise(data, 4, &result);
++ TEST(NULL == msg && LO_EINVALIDPATH == result);
+
+- /* Test freeing out-of-order copies of messages in a bundle. */
+- lo_bundle_free_recursive(b2);
+- }
++ snprintf(data, 256, "%s", "/f_o"); // non-0 in pad area
++ msg = lo_message_deserialise(data, 4, &result);
++ TEST(NULL == msg && LO_EINVALIDPATH == result);
+
+- {
+- lo_timetag t = { 10, 0xFFFFFFFE };
+- b = lo_bundle_new(t);
+- }
+- m1 = lo_message_new();
+- lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
+- lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+- lo_bundle_add_message(b, "/bundle", m1);
+- lo_send_bundle(a, b);
+- lo_message_free(m1);
+- lo_bundle_free(b);
++ snprintf(data, 256, "%s", "/t__"); // types missing
++ replace_char(data, 4, '_', '\0');
++ msg = lo_message_deserialise(data, 4, &result);
++ TEST(NULL == msg && LO_ENOTYPE == result);
+
+- lo_timetag_now(&sched);
++ snprintf(data, 256, "%s%s", "/t__", "____"); // types empty
++ replace_char(data, 8, '_', '\0');
++ msg = lo_message_deserialise(data, 8, &result);
++ TEST(NULL == msg && LO_EBADTYPE == result);
+
+- sched.sec += 5;
+- b = lo_bundle_new(sched);
+- m1 = lo_message_new();
+- lo_message_add_string(m1, "future");
+- lo_message_add_string(m1, "time");
+- lo_message_add_string(m1, "test");
+- lo_bundle_add_message(b, "/bundle", m1);
++ snprintf(data, 256, "%s%s", "/t__", ",f_"); // short message
++ replace_char(data, 7, '_', '\0');
++ msg = lo_message_deserialise(data, 7, &result);
++ TEST(NULL == msg && LO_EINVALIDTYPE == result);
+
+- lo_send_bundle(a, b);
+- lo_message_free(m1);
+- lo_bundle_free(b);
++ snprintf(data, 256, "%s%s", "/t__", "ifi_"); // types missing comma
++ replace_char(data, 8, '_', '\0');
++ msg = lo_message_deserialise(data, 8, &result);
++ TEST(NULL == msg && LO_EBADTYPE == result);
++
++ snprintf(data, 256, "%s%s", "/t__", ",ifi"); // types unterminated
++ replace_char(data, 8, '_', '\0');
++ msg = lo_message_deserialise(data, 8, &result);
++ TEST(NULL == msg && LO_EINVALIDTYPE == result);
++
++ snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data
++ replace_char(data, 8, '_', '\0');
++ msg = lo_message_deserialise(data, 12, &result);
++ TEST(NULL == msg && LO_EINVALIDARG == result);
++
++ snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data again
++ replace_char(data, 8, '_', '\0');
++ msg = lo_message_deserialise(data, 15, &result);
++ TEST(NULL == msg && LO_EINVALIDARG == result);
++
++ snprintf(data, 256, "%s%s", "/t__", ",f__"); // too much arg data
++ replace_char(data, 8, '_', '\0');
++ msg = lo_message_deserialise(data, 16, &result);
++ TEST(NULL == msg && LO_ESIZE == result);
++
++ snprintf(data, 256, "%s%s", "/t__", ",bs_"); // blob longer than msg length
++ replace_char(data, 8, '_', '\0');
++ *(uint32_t *) (data + 8) = lo_htoo32((uint32_t) 99999);
++ msg = lo_message_deserialise(data, 256, &result);
++ TEST(NULL == msg && LO_EINVALIDARG == result);
++}
+
+- lo_send_timestamped(a, sched, "/bundle", "s",
+- "lo_send_timestamped() test");
++void test_validation(lo_address a)
++{
++ /* packet crafted to crash a lo_server when no input validation is performed */
++ char mem[] = { "/\0\0\0,bs\0,\x00\x0F\x42\x3F" }; // OSC: "/" ",bs" 999999
++ int eok = error_okay;
++ int sock = a->socket;
+
+- /* test bundle timestamp ends up in message struct (and doesn't end up in
+- unbundled messages) */
+- lo_timetag_now(&sched);
+- lo_send_timestamped(a, sched, "/timestamp", "it", 1, sched);
+- lo_send(a, "/timestamp", "it", 0, sched);
++ /* This code won't work with MSVC because the lo_client_sockets data structure
++ * is not explicitly made available to external programs. We could expose it
++ * in debug mode, perhaps, but let's just skip this test for now. (Can be tested
++ * on Windows using MingW.) */
++#ifdef _MSC_VER
++ return;
++#else
+
+-#define JITTER_ITS 25
+- /* jitter tests */
+- {
+- lo_timetag stamps[JITTER_ITS];
+- lo_timetag now;
++ DOING("test_validation");
+
+- for (i = 0; i < JITTER_ITS; i++) {
+- lo_timetag_now(&now);
+- stamps[i] = now;
+- stamps[i].sec += 1;
+- stamps[i].frac = rand();
+- lo_send_timestamped(a, stamps[i], "/jitter", "ti", stamps[i],
+- i);
+- }
++ /* Note: lo_client_sockets is not available when liblo is compiled
++ * as a DLL. */
++#if !defined(WIN32) && !defined(_MSC_VER)
++ if (sock == -1)
++ sock = lo_client_sockets.udp;
++#endif
++ if (sock == -1) {
++ fprintf(stderr,
++ "Warning: Couldn't get socket in test_validation(), "
++ "lo_client_sockets.udp not supported on Windows, %s:%d\n",
++ __FILE__, __LINE__);
++ return;
+ }
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(2000);
+-#else
+- sleep(2);
++ error_okay = 1;
++ if (sendto(sock, (void*)&mem, sizeof(mem), MSG_NOSIGNAL,
++ a->ai->ai_addr, a->ai->ai_addrlen) == -1) {
++ fprintf(stderr,
++ "Error sending packet in test_validation(), %s:%d\n",
++ __FILE__, __LINE__);
++ }
++ SLEEP_MS(10);
++ error_okay = eok;
+ #endif
++}
+
+- lo_address_free(a);
++void test_multicast(lo_server_thread st)
++{
++ lo_server ms;
++ lo_address ma;
+
+- TEST(lo_server_thread_events_pending(st));
++ DOING("test_multicast");
+
+- while (lo_server_thread_events_pending(st)) {
+- printf("pending events, wait...\n");
+-#if defined(WIN32) || defined(_MSC_VER)
+- fflush(stdout);
+- Sleep(1000);
+-#else
+- sleep(1);
+-#endif
++ /* test multicast server and sender */
++ /* message is sent from st otherwise reply doesn't work */
++ ms = lo_server_new_multicast("224.0.1.1", "15432", error);
++ ma = lo_address_new("224.0.1.1", "15432");
++ lo_address_set_ttl(ma, 1);
++ lo_server_add_method(ms, "/foo/bar", "fi", foo_handler, ms);
++ lo_server_add_method(ms, "/reply", "s", reply_handler, NULL);
++ if (lo_send_from(ma, lo_server_thread_get_server(st), LO_TT_IMMEDIATE,
++ "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) {
++ printf("multicast send error %d: %s\n", lo_address_errno(ma),
++ lo_address_errstr(ma));
++ exit(1);
+ }
++ TEST(lo_server_recv(ms) == 24);
++ lo_server_free(ms);
++ lo_address_free(ma);
++}
+
+- TEST(bundle_count == 7);
+- printf("\n");
++int test_received = 0;
++int ok_received = 0;
++int recv_times = 0;
+
+- printf("bundle timing jitter results:\n"
+- "max jitter = %fs\n"
+- "avg jitter = %fs\n"
+- "min jitter = %fs\n\n",
+- jitter_max, jitter_total / (float) jitter_count, jitter_min);
++int test_handler(const char *path, const char *types,
++ lo_arg **argv, int argc, lo_message m,
++ void *data)
++{
++ HANDLER("test");
++ printf("/test, %d, %s\n", argv[0]->i, &argv[1]->s);
++ test_received += 1;
++ return 0;
++}
+
+- server_url = lo_server_get_url(s);
++int ok_handler(const char *path, const char *types,
++ lo_arg **argv, int argc, lo_message m,
++ void *data)
++{
++ HANDLER("ok");
++ ok_received += 1;
++ return 0;
++}
+
+- lo_server_add_method(s, NULL, NULL, generic_handler, NULL);
+- a = lo_address_new_from_url(server_url);
+- TEST(lo_server_recv_noblock(s, 0) == 0);
+- printf("Testing noblock API on %s\n", server_url);
+- lo_send(a, "/non-block-test", "f", 23.0);
++void *test_tcp_thread(void *context)
++{
++ lo_server s;
++ printf("TCP thread started.\n");
+
+- count = 0;
+- while (!lo_server_recv_noblock(s, 10) && count++ < 1000) {
++ s = lo_server_new_with_proto("9000", LO_TCP, error);
++ if (!s) {
++ printf("Aborting thread, s=%p\n", s);
++ return (void*)1;
+ }
+- if (count >= 1000) {
+- printf("lo_server_recv_noblock() test failed\n");
+
+- exit(1);
+- }
++ lo_server_add_method(s, "/test", "is", test_handler, 0);
++ lo_server_add_method(s, "/ok", "", ok_handler, 0);
+
+- /* Delete methods */
+- lo_server_thread_del_method(st, "/coerce", "dfhiSs");
+- lo_server_del_method(s, NULL, NULL);
++ while (!(done || tcp_done)) {
++ printf("lo_server_recv_noblock()\n");
++ recv_times += 1;
++ if (!lo_server_recv_noblock(s, 0))
++ SLEEP_MS(300);
++ }
+
+- lo_address_free(a);
++ printf("Freeing.\n");
+ lo_server_free(s);
+- free(server_url);
++ printf("Done. Thread ending.\n");
++ return 0;
++}
+
+-#if !defined(WIN32) && !defined(_MSC_VER)
+- { /* UNIX domain tests */
+- lo_address ua;
+- lo_server us;
+- char *addr;
+-
+- unlink("/tmp/testlo.osc");
+- us = lo_server_new_with_proto("/tmp/testlo.osc", LO_UNIX, error);
+- ua = lo_address_new_from_url("osc.unix:///tmp/testlo.osc");
+- TEST(lo_server_get_protocol(us) == LO_UNIX);
+- TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
+- TEST(lo_server_recv(us) == 16);
+- addr = lo_server_get_url(us);
+- TEST(!strcmp("osc.unix:////tmp/testlo.osc", addr));
+- free(addr);
+- lo_address_free(ua);
+- ua = lo_address_new_with_proto(LO_UNIX, NULL, "/tmp/testlo.osc");
+- TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
+- TEST(lo_server_recv(us) == 16);
+- lo_server_free(us);
+- lo_address_free(ua);
+- }
+-#endif
++#define SLIP_END 0300 /* indicates end of packet */
+
+- { /* TCP tests */
+- lo_address ta;
+- lo_server ts;
+- char *addr;
++void test_tcp_halfsend(int stream_type)
++{
++ char prefixmsg[] = {0,0,0,0,
++ '/','t','e','s','t',0,0,0,
++ ',','i','s',0,
++ 0,0,0,4,
++ 'b','l','a','h',0,0,0,0,
++ 0,0,0,0,
++ '/','o','k',0,
++ ',',0,0,0};
+
+- ts = lo_server_new_with_proto(NULL, LO_TCP, error);
+- addr = lo_server_get_url(ts);
+- ta = lo_address_new_from_url(addr);
+- if (lo_address_errno(ta)) {
+- printf("err: %s\n", lo_address_errstr(ta));
+- exit(1);
+- }
+- TEST(lo_server_get_protocol(ts) == LO_TCP);
+- TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
+- TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
+- TEST(lo_server_recv(ts) == 16);
+- TEST(lo_server_recv(ts) == 16);
+- free(addr);
+- lo_server_free(ts);
+- lo_address_free(ta);
+- }
++ char slipmsg[] = {'/','t','e','s','t',0,0,0,
++ ',','i','s',0,
++ 0,0,0,4,
++ 'b','l','a','h',0,0,0,0,SLIP_END,
++ '/','o','k',0,
++ ',',0,0,0,SLIP_END};
+
+- server_url = lo_server_thread_get_url(st);
+- a = lo_address_new_from_url(server_url);
+- /* exit */
+- lo_send(a, "/quit", NULL);
+- lo_address_free(a);
++ char *msg;
++ int msglen;
+
+- while (!done) {
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(1);
+-#else
+- usleep(1000);
+-#endif
++ struct sockaddr_in sa;
++ int rc;
++ int sock = socket(AF_INET, SOCK_STREAM, 0);
++ if (sock < 0) {
++ perror("socket");
++ exit(1);
++ }
++ memset(&sa, 0, sizeof(struct sockaddr_in));
++ sa.sin_addr.s_addr = inet_addr("127.0.0.1");
++ sa.sin_port = htons(9000);
++ sa.sin_family = AF_INET;
++ rc = connect(sock, (struct sockaddr*)&sa, sizeof(struct sockaddr_in));
++ if (rc) {
++ perror("Error connecting");
++ closesocket(sock);
++ exit(1);
+ }
+
+- lo_server_thread_free(st);
+- free(server_url);
+-
+- TEST(test_tcp_nonblock()==0)
++ printf("Connected, sending...\n");
+
+- return 0;
+-}
++ switch (stream_type)
++ {
++ case 0:
++ printf("Testing a count-prefix stream.\n");
++ msg = prefixmsg;
++ msglen = sizeof(prefixmsg);
+
+-void exitcheck(void)
+-{
+- if (!done) {
+- fprintf(stderr, "\ntest run not completed\n" PACKAGE_NAME
+- " test FAILED\n");
+- } else {
+- printf(PACKAGE_NAME " test PASSED\n");
++ *(uint32_t*)msg = htonl(24);
++ *(uint32_t*)(msg+28) = htonl(8);
++ break;
++ case 1:
++ printf("Testing a SLIP stream.\n");
++ msg = slipmsg;
++ msglen = sizeof(slipmsg);
++ break;
++ default:
++ closesocket(sock);
++ return;
+ }
+-}
+
+-void error(int num, const char *msg, const char *path)
+-{
+- printf("liblo server error %d in %s: %s", num, path, msg);
+- if (!error_okay)
+- exit(1);
+- else
+- printf(" (expected)\n");
+-}
++ if (0)
++ {
++ printf("Sending everything in one big chunk.\n");
+
+-void rep_error(int num, const char *msg, const char *path)
+-{
+- if (num != 9904) {
+- error(num, msg, path);
++ rc = send(sock, msg, msglen, 0);
++ if (rc != msglen) printf("Error sending, rc = %d\n", rc);
++ else printf("Sent.\n");
+ }
+-}
++ else
++ {
++ rc = send(sock, msg, 13, 0);
++ if (rc != 13) printf("Error sending, rc = %d\n", rc);
++ else printf("Sent.\n");
+
+-int generic_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- int i;
++ SLEEP_MS(1000);
+
+- printf("path: <%s>\n", path);
+- for (i = 0; i < argc; i++) {
+- printf("arg %d '%c' ", i, types[i]);
+- lo_arg_pp(types[i], argv[i]);
+- printf("\n");
++ rc = send(sock, msg+13, 20, 0);
++ if (rc != 20) printf("Error sending2, rc = %d\n", rc);
++ else printf("Sent2.\n");
++
++ SLEEP_MS(1000);
++
++ rc = send(sock, msg+33, msglen-33, 0);
++ if (rc != (msglen-33)) printf("Error sending3, rc = %d\n", rc);
++ else printf("Sent3.\n");
+ }
+- printf("\n");
+
+- return 1;
++ closesocket(sock);
+ }
+
+-int foo_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
++void test_tcp_nonblock()
+ {
+- lo_server serv = (lo_server) user_data;
+- lo_address src = lo_message_get_source(data);
+- char *url = lo_address_get_url(src);
+- char *server_url = lo_server_get_url(serv);
+- printf("Address of us: %s\n", server_url);
+- printf("%s <- f:%f, i:%d\n", path, argv[0]->f, argv[1]->i);
+- if (lo_send_from(src, serv, LO_TT_IMMEDIATE, "/reply", "s", "a reply")
+- == -1) {
+- printf("OSC reply error %d: %s\nSending to %s\n",
+- lo_address_errno(src), lo_address_errstr(src), url);
++ void *retval;
++ pthread_t thread;
++
++ DOING("test_tcp_nonblock");
++
++ tcp_done = 0;
++ if (pthread_create(&thread, 0, test_tcp_thread, 0))
++ {
++ perror("pthread_create");
+ exit(1);
+- } else {
+- printf("Reply sent to %s\n\n", url);
+ }
+- free(server_url);
+- free(url);
+
+- return 0;
+-}
++ SLEEP_MS(1000);
++ test_tcp_halfsend(0);
++ SLEEP_MS(1000);
++ test_tcp_halfsend(1);
++ SLEEP_MS(1000);
+
+-int reply_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- lo_address src = lo_message_get_source(data);
+- char *url = lo_address_get_url(src);
+- printf("Reply received from %s\n", url);
+- free(url);
+- reply_count++;
++ tcp_done = 1;
++ pthread_join(thread, &retval);
++ printf("Thread joined, retval=%p\n", retval);
+
+- return 0;
++ TEST(retval == 0);
++ TEST(test_received == 2);
++ TEST(ok_received == 2);
++ TEST(recv_times > 10);
+ }
+
+-int lots_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
++void test_types()
+ {
+- lo_blob b;
+- unsigned char *d;
++ union end_test32 et32;
++ union end_test64 et64;
+
+- if (strcmp(path, "/lotsofformats")) {
+- fprintf(stderr, "path != /lotsofformats\n");
++ DOING("test_types");
++
++ TEST(sizeof(float) == sizeof(int32_t));
++ TEST(sizeof(double) == sizeof(int64_t));
++
++ et32.i = 0x23242526U;
++ et32.i = lo_htoo32(et32.i);
++ if (et32.c[0] != 0x23 || et32.c[1] != 0x24 || et32.c[2] != 0x25 ||
++ et32.c[3] != 0x26) {
++ fprintf(stderr, "failed 32bit endian conversion test\n");
++ fprintf(stderr, "0x23242526 -> %X\n", et32.i);
+ exit(1);
++ } else {
++ printf("passed 32bit endian conversion test\n");
+ }
+- printf("path = %s\n", path);
+- TEST(types[0] == 'f' && argv[0]->f == 0.12345678f);
+- TEST(types[1] == 'i' && argv[1]->i == 123);
+- TEST(types[2] == 's' && !strcmp(&argv[2]->s, "123"));
+- b = (lo_blob) argv[3];
+- d = lo_blob_dataptr(b);
+- TEST(types[3] == 'b' && lo_blob_datasize(b) == 5);
+- TEST(d[0] == 'A' && d[1] == 'B' && d[2] == 'C' && d[3] == 'D' &&
+- d[4] == 'E');
+- d = argv[4]->m;
+- TEST(d[0] == 0xff && d[1] == 0xf7 && d[2] == 0xaa && d[3] == 0x00);
+- TEST(types[5] == 'h' && argv[5]->h == 0x0123456789ABCDEFULL);
+- TEST(types[6] == 't' && argv[6]->t.sec == 1 &&
+- argv[6]->t.frac == 0x80000000);
+- TEST(types[7] == 'd' && argv[7]->d == 0.9999);
+- TEST(types[8] == 'S' && !strcmp(&argv[8]->S, "sym"));
+- printf("char: %d\n", argv[9]->c);
+- TEST(types[9] == 'c' && argv[9]->c == 'X');
+- TEST(types[10] == 'c' && argv[10]->c == 'Y');
+- TEST(types[11] == 'T');
+- TEST(types[12] == 'F');
+- TEST(types[13] == 'N');
+- TEST(types[14] == 'I');
+
++ et64.i = 0x232425262728292AULL;
++ et64.i = lo_htoo64(et64.i);
++ if (et64.c[0] != 0x23 || et64.c[1] != 0x24 || et64.c[2] != 0x25 ||
++ et64.c[3] != 0x26 || et64.c[4] != 0x27 || et64.c[5] != 0x28 ||
++ et64.c[6] != 0x29 || et64.c[7] != 0x2A) {
++ fprintf(stderr, "failed 64bit endian conversion\n");
++ fprintf(stderr, "0x232425262728292A -> %" PRINTF_LL "X\n",
++ (long long unsigned int) et64.i);
++ exit(1);
++ } else {
++ printf("passed 64bit endian conversion\n");
++ }
+ printf("\n");
+-
+- return 0;
+ }
+
+-int coerce_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
++void test_url()
+ {
+- printf("path = %s\n", path);
+- TEST(types[0] == 'd' && fabs(argv[0]->d - 0.1) < FLT_EPSILON);
+- TEST(types[1] == 'f' && fabs(argv[1]->f - 0.2) < FLT_EPSILON);
+- TEST(types[2] == 'h' && argv[2]->h == 123);
+- TEST(types[3] == 'i' && argv[3]->i == 124);
+- TEST(types[4] == 'S' && !strcmp(&argv[4]->S, "aaa"));
+- TEST(types[5] == 's' && !strcmp(&argv[5]->s, "bbb"));
+- printf("\n");
++ int proto;
++ char *path, *protocol, *host, *port;
+
+- return 0;
+-}
++ DOING("test_url");
+
+-int bundle_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- bundle_count++;
+- printf("received bundle\n");
++ /* OSC URL tests */
++ path = lo_url_get_path("osc.udp://localhost:9999/a/path/is/here");
++ if (strcmp(path, "/a/path/is/here")) {
++ printf("failed lo_url_get_path() test1\n");
++ printf("'%s' != '/a/path/is/here'\n", path);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_path() test1\n");
++ }
++ free(path);
+
+- return 0;
+-}
++ protocol =
++ lo_url_get_protocol("osc.udp://localhost:9999/a/path/is/here");
++ if (strcmp(protocol, "udp")) {
++ printf("failed lo_url_get_protocol() test1\n");
++ printf("'%s' != 'udp'\n", protocol);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_protocol() test1\n");
++ }
++ free(protocol);
+
+-int timestamp_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- int bundled = argv[0]->i;
++ protocol =
++ lo_url_get_protocol("osc.tcp://localhost:9999/a/path/is/here");
++ if (strcmp(protocol, "tcp")) {
++ printf("failed lo_url_get_protocol() test2\n");
++ printf("'%s' != 'tcp'\n", protocol);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_protocol() test2\n");
++ }
++ free(protocol);
+
+- lo_timetag ts, arg_ts;
+- ts = lo_message_get_timestamp(data);
+- arg_ts = argv[1]->t;
++ protocol =
++ lo_url_get_protocol
++ ("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
++ if (strcmp(protocol, "udp")) {
++ printf("failed lo_url_get_protocol() test1 (IPv6)\n");
++ printf("'%s' != 'udp'\n", protocol);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_protocol() test1 (IPv6)\n");
++ }
++ free(protocol);
+
+- if (bundled) {
+- TEST((ts.sec == arg_ts.sec) && (ts.frac == arg_ts.frac));
++ proto =
++ lo_url_get_protocol_id("osc.udp://localhost:9999/a/path/is/here");
++ if (proto != LO_UDP) {
++ printf("failed lo_url_get_protocol_id() test1\n");
++ printf("'%d' != LO_UDP\n", proto);
++ exit(1);
+ } else {
+- TEST(ts.sec == LO_TT_IMMEDIATE.sec
+- && ts.frac == LO_TT_IMMEDIATE.frac);
++ printf("passed lo_url_get_protocol_id() test1\n");
+ }
+- return 0;
+-}
+
+-int jitter_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- lo_timetag now;
+- float jitter;
++ proto =
++ lo_url_get_protocol_id("osc.tcp://localhost:9999/a/path/is/here");
++ if (proto != LO_TCP) {
++ printf("failed lo_url_get_protocol_id() test2\n");
++ printf("'%d' != LO_TCP\n", proto);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_protocol_id() test2\n");
++ }
+
+- lo_timetag_now(&now);
+- jitter = fabs(lo_timetag_diff(now, argv[0]->t));
+- jitter_count++;
+- //printf("jitter: %f\n", jitter);
+- printf("%d expected: %x:%x received %x:%x\n", argv[1]->i,
+- argv[0]->t.sec, argv[0]->t.frac, now.sec, now.frac);
+- jitter_total += jitter;
+- if (jitter > jitter_max)
+- jitter_max = jitter;
+- if (jitter < jitter_min)
+- jitter_min = jitter;
++ proto =
++ lo_url_get_protocol_id
++ ("osc.invalid://localhost:9999/a/path/is/here");
++ if (proto != -1) {
++ printf("failed lo_url_get_protocol_id() test3\n");
++ printf("'%d' != -1\n", proto);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_protocol_id() test3\n");
++ }
+
+- return 0;
+-}
++ proto =
++ lo_url_get_protocol_id
++ ("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
++ if (proto != LO_UDP) {
++ printf("failed lo_url_get_protocol_id() test1 (IPv6)\n");
++ printf("'%d' != LO_UDP\n", proto);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_protocol_id() test1 (IPv6)\n");
++ }
+
+-int pattern_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- pattern_count++;
+- printf("pattern matched %s\n", (char *) user_data);
++ host =
++ lo_url_get_hostname
++ ("osc.udp://foo.example.com:9999/a/path/is/here");
++ if (strcmp(host, "foo.example.com")) {
++ printf("failed lo_url_get_hostname() test1\n");
++ printf("'%s' != 'foo.example.com'\n", host);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_hostname() test1\n");
++ }
++ free(host);
++
++ host =
++ lo_url_get_hostname
++ ("osc.udp://[0000::::0001]:9999/a/path/is/here");
++ if (strcmp(host, "0000::::0001")) {
++ printf("failed lo_url_get_hostname() test2 (IPv6)\n");
++ printf("'%s' != '0000::::0001'\n", host);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_hostname() test2 (IPv6)\n");
++ }
++ free(host);
++
++ port = lo_url_get_port("osc.udp://localhost:9999/a/path/is/here");
++ if (strcmp(port, "9999")) {
++ printf("failed lo_url_get_port() test1\n");
++ printf("'%s' != '9999'\n", port);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_port() test1\n");
++ }
++ free(port);
+
+- return 0;
++ port =
++ lo_url_get_port
++ ("osc.udp://[::ffff:127.0.0.1]:9999/a/path/is/here");
++ if (strcmp(port, "9999")) {
++ printf("failed lo_url_get_port() test1 (IPv6)\n");
++ printf("'%s' != '9999'\n", port);
++ exit(1);
++ } else {
++ printf("passed lo_url_get_port() test1 (IPv6)\n");
++ }
++ free(port);
++ printf("\n");
+ }
+
+-int subtest_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
++void test_address()
+ {
+- lo_address a = lo_message_get_source(data);
++ const char *host, *port;
++ char *server_url;
++ lo_address a;
++ int proto;
+
+- subtest_count++;
+- printf("got subtest message %d\n", subtest_count);
+- lo_send_from(a, lo_server_thread_get_server(user_data),
+- LO_TT_IMMEDIATE, "/subtest", "i", subtest_count);
++ DOING("test_address");
+
+- return 0;
+-}
++ a = lo_address_new_from_url("osc://localhost/");
++ TEST(a != NULL);
++ lo_address_free(a);
+
+-int subtest_reply_handler(const char *path, const char *types,
+- lo_arg ** argv, int argc, lo_message data,
+- void *user_data)
+-{
+- subtest_reply_count++;
+- //printf("got subtest reply message %d\n", subtest_reply_count);
++ a = lo_address_new_from_url("osc.://localhost/");
++ TEST(a == NULL);
+
+- return 0;
+-}
++ a = lo_address_new_from_url("osc.tcp://foo.example.com:9999/");
+
+-int quit_handler(const char *path, const char *types, lo_arg ** argv,
+- int argc, lo_message data, void *user_data)
+-{
+- done = 1;
++ host = lo_address_get_hostname(a);
++ if (strcmp(host, "foo.example.com")) {
++ printf("failed lo_address_get_hostname() test\n");
++ printf("'%s' != 'foo.example.com'\n", host);
++ exit(1);
++ } else {
++ printf("passed lo_address_get_hostname() test\n");
++ }
+
+- return 0;
+-}
++ port = lo_address_get_port(a);
++ if (strcmp(port, "9999")) {
++ printf("failed lo_address_get_port() test\n");
++ printf("'%s' != '9999'\n", port);
++ exit(1);
++ } else {
++ printf("passed lo_address_get_port() test\n");
++ }
+
+-int test_version()
+-{
+- int major, minor, lt_maj, lt_min, lt_bug;
+- char extra[256];
+- char string[256];
++ proto = lo_address_get_protocol(a);
++ if (proto != LO_TCP) {
++ printf("failed lo_address_get_protocol() test\n");
++ printf("'%d' != '%d'\n", proto, LO_TCP);
++ exit(1);
++ } else {
++ printf("passed lo_address_get_protocol() test\n");
++ }
+
+- lo_version(string, 256,
+- &major, &minor, extra, 256,
+- <_maj, <_min, <_bug);
++ server_url = lo_address_get_url(a);
++ if (strcmp(server_url, "osc.tcp://foo.example.com:9999/")) {
++ printf("failed lo_address_get_url() test\n");
++ printf("'%s' != '%s'\n", server_url,
++ "osc.tcp://foo.example.com:9999/");
++ exit(1);
++ } else {
++ printf("passed lo_address_get_url() test\n");
++ }
+
+- printf("liblo version string `%s'\n", string);
+- printf("liblo version: %d.%d%s\n", major, minor, extra);
+- printf("liblo libtool version: %d.%d.%d\n", lt_maj, lt_min, lt_bug);
+- printf("\n");
++ free(server_url);
++ lo_address_free(a);
+
+- return 0;
++ printf("\n");
+ }
+
+-int test_varargs(lo_address a, const char *path, const char *types, ...)
++void test_blob()
+ {
+- va_list ap;
+- lo_message m = lo_message_new();
+- int error;
+- va_start(ap, types);
+- if ((error = lo_message_add_varargs(m, types, ap)) == 0)
+- lo_send_message(a, path, m);
+- else
+- printf("lo_message_add_varargs returned %d\n", error);
+- lo_message_free(m);
+- return error < 0;
+-}
++ lo_blob btest;
+
+-void replace_char(char *str, size_t size, const char find,
+- const char replace)
+-{
+- char *p = str;
+- while (size--) {
+- if (find == *p) {
+- *p = replace;
+- }
+- ++p;
++ DOING("test_blob");
++
++ btest = lo_blob_new(sizeof(testdata), testdata);
++
++ /* Test blob sizes */
++ if (lo_blob_datasize(btest) != 5 || lo_blobsize(btest) != 12) {
++ printf("blob is %d (%d) bytes long, should be 5 (12)\n",
++ lo_blob_datasize(btest), lo_blobsize(btest));
++ lo_arg_pp(LO_BLOB, btest);
++ printf(" <- blob\n");
++ exit(1);
+ }
++
++ lo_blob_free(btest);
+ }
+
+-void test_deserialise()
++void test_server_thread(lo_server_thread *pst, lo_address *pa)
+ {
+- char *buf, *buf2, *tmp;
+- const char *types = NULL, *path;
+- lo_arg **argv = NULL;
+- size_t len, size;
+- char data[256];
+- int result = 0;
+-
+- lo_blob btest = lo_blob_new(sizeof(testdata), testdata);
+- uint8_t midi_data[4] = { 0xff, 0xf7, 0xAA, 0x00 };
++ lo_address a;
++ char *server_url;
++ lo_server_thread st, sta, stb;
++ lo_blob btest;
+ lo_timetag tt = { 0x1, 0x80000000 };
+- lo_blob b = NULL;
+
+- // build a message
+- lo_message msg = lo_message_new();
+- TEST(0 == lo_message_get_argc(msg));
+- lo_message_add_float(msg, 0.12345678f); // 0 f
+- lo_message_add_int32(msg, 123); // 1 i
+- lo_message_add_string(msg, "123"); // 2 s
+- lo_message_add_blob(msg, btest); // 3 b
+- lo_message_add_midi(msg, midi_data); // 4 m
+- lo_message_add_int64(msg, 0x0123456789abcdefULL); // 5 h
+- lo_message_add_timetag(msg, tt); // 6 t
+- lo_message_add_double(msg, 0.9999); // 7 d
+- lo_message_add_symbol(msg, "sym"); // 8 S
+- lo_message_add_char(msg, 'X'); // 9 c
+- lo_message_add_char(msg, 'Y'); // 10 c
+- lo_message_add_true(msg); // 11 T
+- lo_message_add_false(msg); // 12 F
+- lo_message_add_nil(msg); // 13 N
+- lo_message_add_infinitum(msg); // 14 I
++ DOING("test_server_thread");
+
+- // test types, args
+- TEST(15 == lo_message_get_argc(msg));
+- types = lo_message_get_types(msg);
+- TEST(NULL != types);
+- argv = lo_message_get_argv(msg);
+- TEST(NULL != argv);
+- TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON);
+- TEST('i' == types[1] && 123 == argv[1]->i);
+- TEST('s' == types[2] && !strcmp(&argv[2]->s, "123"));
+- TEST('b' == types[3]);
+- b = (lo_blob) argv[3];
+- TEST(lo_blob_datasize(b) == sizeof(testdata));
+- TEST(12 == lo_blobsize(b));
+- TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata)));
+- TEST('m' == types[4] && !memcmp(&argv[4]->m, midi_data, 4));
+- TEST('h' == types[5] && 0x0123456789abcdefULL == argv[5]->h);
+- TEST('t' == types[6] && 1 == argv[6]->t.sec
+- && 0x80000000 == argv[6]->t.frac);
+- TEST('d' == types[7] && fabs(argv[7]->d - 0.9999) < FLT_EPSILON);
+- TEST('S' == types[8] && !strcmp(&argv[8]->s, "sym"));
+- TEST('c' == types[9] && 'X' == argv[9]->c);
+- TEST('c' == types[10] && 'Y' == argv[10]->c);
+- TEST('T' == types[11] && NULL == argv[11]);
+- TEST('F' == types[12] && NULL == argv[12]);
+- TEST('N' == types[13] && NULL == argv[13]);
+- TEST('I' == types[14] && NULL == argv[14]);
++ btest = lo_blob_new(sizeof(testdata), testdata);
+
+- // serialise it
+- len = lo_message_length(msg, "/foo");
+- printf("serialise message_length=%d\n", (int) len);
+- buf = calloc(len, sizeof(char));
+- size = 0;
+- tmp = lo_message_serialise(msg, "/foo", buf, &size);
+- TEST(tmp == buf && size == len && 92 == len);
+- lo_message_free(msg);
++ sta = lo_server_thread_new("7591", error);
++ stb = lo_server_thread_new("7591", rep_error);
++ if (stb) {
++ fprintf(stderr, "FAILED: create bad server thread object!\n");
++ exit(1);
++ }
++ lo_server_thread_free(sta);
+
+- // deserialise it
+- printf("deserialise\n");
+- path = lo_get_path(buf, len);
+- TEST(NULL != path && !strcmp(path, "/foo"));
+- msg = lo_message_deserialise(buf, size, NULL);
+- TEST(NULL != msg);
++ /* leak check */
++ st = lo_server_thread_new(NULL, error);
++ if (!st) {
++ printf("Error creating server thread\n");
++ exit(1);
++ }
+
+- // repeat same test as above
+- TEST(15 == lo_message_get_argc(msg));
+- types = lo_message_get_types(msg);
+- TEST(NULL != types);
+- argv = lo_message_get_argv(msg);
+- TEST(NULL != argv);
+- TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON);
+- TEST('i' == types[1] && 123 == argv[1]->i);
+- TEST('s' == types[2] && !strcmp(&argv[2]->s, "123"));
+- TEST('b' == types[3]);
+- b = (lo_blob) argv[3];
+- TEST(lo_blob_datasize(b) == sizeof(testdata));
+- TEST(12 == lo_blobsize(b));
+- TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata)));
+- TEST('m' == types[4] && !memcmp(&argv[4]->m, midi_data, 4));
+- TEST('h' == types[5] && 0x0123456789abcdefULL == argv[5]->h);
+- TEST('t' == types[6] && 1 == argv[6]->t.sec
+- && 0x80000000 == argv[6]->t.frac);
+- TEST('d' == types[7] && fabs(argv[7]->d - 0.9999) < FLT_EPSILON);
+- TEST('S' == types[8] && !strcmp(&argv[8]->s, "sym"));
+- TEST('c' == types[9] && 'X' == argv[9]->c);
+- TEST('c' == types[10] && 'Y' == argv[10]->c);
+- TEST('T' == types[11] && NULL == argv[11]);
+- TEST('F' == types[12] && NULL == argv[12]);
+- TEST('N' == types[13] && NULL == argv[13]);
+- TEST('I' == types[14] && NULL == argv[14]);
++ lo_server_thread_start(st);
++ SLEEP_MS(4);
++ lo_server_thread_stop(st);
++ lo_server_thread_free(st);
++ st = lo_server_thread_new(NULL, error);
++ lo_server_thread_start(st);
++ lo_server_thread_stop(st);
++ lo_server_thread_free(st);
++ st = lo_server_thread_new(NULL, error);
++ lo_server_thread_free(st);
++ st = lo_server_thread_new(NULL, error);
++ lo_server_thread_free(st);
++ st = lo_server_thread_new(NULL, error);
++
++ /* Server method handler tests */
++ server_url = lo_server_thread_get_url(st);
++ printf("Server URL: %s\n", server_url);
++ a = lo_address_new_from_url(server_url);
++ free(server_url);
++
++ /* add method that will match the path /foo/bar, with two numbers, coerced
++ * to float and int */
++
++ lo_server_thread_add_method(st, "/foo/bar", "fi", foo_handler,
++ lo_server_thread_get_server(st));
++
++ lo_server_thread_add_method(st, "/reply", "s", reply_handler, NULL);
+
+- // serialise it again, compare
+- len = lo_message_length(msg, "/foo");
+- printf("serialise message_length=%d\n", (int) len);
+- buf2 = calloc(len, sizeof(char));
+- size = 0;
+- tmp = lo_message_serialise(msg, "/foo", buf2, &size);
+- TEST(tmp == buf2 && size == len && 92 == len);
+- TEST(!memcmp(buf, buf2, len));
+- lo_message_free(msg);
++ lo_server_thread_add_method(st, "/lotsofformats", "fisbmhtdSccTFNI",
++ lots_handler, NULL);
+
+- lo_blob_free(btest);
+- free(buf);
+- free(buf2);
++ lo_server_thread_add_method(st, "/coerce", "dfhiSs",
++ coerce_handler, NULL);
+
+- // deserialise failure tests with invalid message data
++ lo_server_thread_add_method(st, "/bundle", NULL, bundle_handler, NULL);
++ lo_server_thread_add_method(st, "/timestamp", NULL,
++ timestamp_handler, NULL);
++ lo_server_thread_add_method(st, "/jitter", "ti", jitter_handler, NULL);
+
+- msg = lo_message_deserialise(data, 0, &result); // 0 size
+- TEST(NULL == msg && LO_ESIZE == result);
++ lo_server_thread_add_method(st, "/pattern/foo", NULL,
++ pattern_handler, "foo");
++ lo_server_thread_add_method(st, "/pattern/bar", NULL,
++ pattern_handler, "bar");
++ lo_server_thread_add_method(st, "/pattern/baz", NULL,
++ pattern_handler, "baz");
+
+- snprintf(data, 256, "%s", "/foo"); // unterminated path string
+- msg = lo_message_deserialise(data, 4, &result);
+- TEST(NULL == msg && LO_EINVALIDPATH == result);
++ lo_server_thread_add_method(st, "/subtest", "i", subtest_handler, st);
+
+- snprintf(data, 256, "%s", "/f_o"); // non-0 in pad area
+- msg = lo_message_deserialise(data, 4, &result);
+- TEST(NULL == msg && LO_EINVALIDPATH == result);
++ lo_server_thread_add_method(st, "/subtest-reply", "i",
++ subtest_reply_handler, NULL);
+
+- snprintf(data, 256, "%s", "/t__"); // types missing
+- replace_char(data, 4, '_', '\0');
+- msg = lo_message_deserialise(data, 4, &result);
+- TEST(NULL == msg && LO_ENOTYPE == result);
++ /* add method that will match any path and args */
++ lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL);
+
+- snprintf(data, 256, "%s%s", "/t__", "____"); // types empty
+- replace_char(data, 8, '_', '\0');
+- msg = lo_message_deserialise(data, 8, &result);
+- TEST(NULL == msg && LO_EBADTYPE == result);
++ /* add method that will match the path /quit with no args */
++ lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL);
+
+- snprintf(data, 256, "%s%s", "/t__", ",f_"); // short message
+- replace_char(data, 7, '_', '\0');
+- msg = lo_message_deserialise(data, 7, &result);
+- TEST(NULL == msg && LO_EINVALIDTYPE == result);
++ /* check that the thread restarts */
++ lo_server_thread_start(st);
++ lo_server_thread_stop(st);
++ lo_server_thread_start(st);
+
+- snprintf(data, 256, "%s%s", "/t__", "ifi_"); // types missing comma
+- replace_char(data, 8, '_', '\0');
+- msg = lo_message_deserialise(data, 8, &result);
+- TEST(NULL == msg && LO_EBADTYPE == result);
++ if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) < 0) {
++ printf("OSC error A %d: %s\n", lo_address_errno(a),
++ lo_address_errstr(a));
++ exit(1);
++ }
+
+- snprintf(data, 256, "%s%s", "/t__", ",ifi"); // types unterminated
+- replace_char(data, 8, '_', '\0');
+- msg = lo_message_deserialise(data, 8, &result);
+- TEST(NULL == msg && LO_EINVALIDTYPE == result);
++ if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) < 0) {
++ printf("OSC error B %d: %s\n", lo_address_errno(a),
++ lo_address_errstr(a));
++ exit(1);
++ }
+
+- snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data
+- replace_char(data, 8, '_', '\0');
+- msg = lo_message_deserialise(data, 12, &result);
+- TEST(NULL == msg && LO_EINVALIDARG == result);
++ lo_send(a, "/", "i", 242);
++ lo_send(a, "/pattern/", "i", 243);
+
+- snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data again
+- replace_char(data, 8, '_', '\0');
+- msg = lo_message_deserialise(data, 15, &result);
+- TEST(NULL == msg && LO_EINVALIDARG == result);
++#ifndef _MSC_VER /* MS compiler refuses to compile this case */
++ lo_send(a, "/bar", "ff", 0.12345678f, 1.0 / 0.0);
++#endif
++ lo_send(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123,
++ "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999,
++ "sym", 'X', 'Y');
++ lo_send(a, "/coerce", "fdihsS", 0.1f, 0.2, 123, 124LL, "aaa", "bbb");
++ lo_send(a, "/coerce", "ffffss", 0.1f, 0.2f, 123.0, 124.0, "aaa",
++ "bbb");
++ lo_send(a, "/coerce", "ddddSS", 0.1, 0.2, 123.0, 124.0, "aaa", "bbb");
++ lo_send(a, "/a/b/c/d", "sfsff", "one", 0.12345678f, "three",
++ -0.00000023001f, 1.0);
++ lo_send(a, "/a/b/c/d", "b", btest);
+
+- snprintf(data, 256, "%s%s", "/t__", ",f__"); // too much arg data
+- replace_char(data, 8, '_', '\0');
+- msg = lo_message_deserialise(data, 16, &result);
+- TEST(NULL == msg && LO_ESIZE == result);
++ /* Delete methods */
++ lo_server_thread_del_method(st, "/coerce", "dfhiSs");
+
+- snprintf(data, 256, "%s%s", "/t__", ",bs_"); // blob longer than msg length
+- replace_char(data, 8, '_', '\0');
+- *(uint32_t *) (data + 8) = lo_htoo32((uint32_t) 99999);
+- msg = lo_message_deserialise(data, 256, &result);
+- TEST(NULL == msg && LO_EINVALIDARG == result);
++ {
++ lo_server s = lo_server_new(NULL, error);
++ lo_server_del_method(s, NULL, NULL);
++ lo_server_free(s);
++ }
++
++ lo_blob_free(btest);
++
++ *pst = st;
++ *pa = a;
+ }
+
+-void test_validation(lo_address a)
++void test_message(lo_address a)
+ {
+- /* packet crafted to crash a lo_server when no input validation is performed */
+- char mem[] = { "/\0\0\0,bs\0,\x00\x0F\x42\x3F" }; // OSC: "/" ",bs" 999999
+- int eok = error_okay;
+- int sock = a->socket;
++ lo_blob btest;
++ lo_timetag tt = { 0x1, 0x80000000 };
++ lo_message m;
+
+- /* This code won't work with MSVC because the lo_client_sockets data structure
+- * is not explicitly made available to external programs. We could expose it
+- * in debug mode, perhaps, but let's just skip this test for now. (Can be tested
+- * on Windows using MingW.) */
+-#ifdef _MSC_VER
+- return;
+-#else
++ DOING("test_message");
+
+- printf("validation\n");
++ btest = lo_blob_new(sizeof(testdata), testdata);
+
+- /* Note: lo_client_sockets is not available when liblo is compiled
+- * as a DLL. */
+-#if !defined(WIN32) && !defined(_MSC_VER)
+- if (sock == -1)
+- sock = lo_client_sockets.udp;
+-#endif
+- if (sock == -1) {
+- fprintf(stderr,
+- "Warning: Couldn't get socket in test_validation(), "
+- "lo_client_sockets.udp not supported on Windows, %s:%d\n",
+- __FILE__, __LINE__);
+- return;
+- }
++ TEST(test_varargs
++ (a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
++ btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym", 'X',
++ 'Y', LO_ARGS_END) == 0);
+
+- error_okay = 1;
+- if (sendto(sock, (void*)&mem, sizeof(mem), MSG_NOSIGNAL,
+- a->ai->ai_addr, a->ai->ai_addrlen) == -1) {
+- fprintf(stderr,
+- "Error sending packet in test_validation(), %s:%d\n",
+- __FILE__, __LINE__);
+- }
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(10);
+-#else
+- usleep(10000);
++#ifdef __GNUC__
++#ifndef USE_ANSI_C
++ // Note: Lack of support for variable-argument macros in non-GCC compilers
++ // does not allow us to test for these conditions.
++
++ // too many args
++ TEST(test_varargs(a, "/lotsofformats", "f", 0.12345678f, 123,
++ "123", btest, midi_data, 0x0123456789abcdefULL, tt,
++ 0.9999, "sym", 'X', 'Y', LO_ARGS_END) != 0);
++ // too many types
++ TEST(test_varargs
++ (a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
++ btest, midi_data, 0x0123456789abcdefULL, tt, 0.5,
++ LO_ARGS_END) != 0);
+ #endif
+- error_okay = eok;
+ #endif
++
++ // test lo_message_add
++ m = lo_message_new();
++ TEST(lo_message_add(m, "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
++ btest, midi_data, 0x0123456789abcdefULL, tt,
++ 0.9999, "sym", 'X', 'Y') == 0);
++
++ lo_send_message(a, "/lotsofformats", m);
++
++ lo_message_free(m);
++ lo_blob_free(btest);
+ }
+
+-void test_multicast(lo_server_thread st)
++void test_pattern(lo_address a)
+ {
+- /* test multicast server and sender */
+- /* message is sent from st otherwise reply doesn't work */
+- lo_server ms = lo_server_new_multicast("224.0.1.1", "15432", error);
+- lo_address ma = lo_address_new("224.0.1.1", "15432");
+- lo_address_set_ttl(ma, 1);
+- lo_server_add_method(ms, "/foo/bar", "fi", foo_handler, ms);
+- lo_server_add_method(ms, "/reply", "s", reply_handler, NULL);
+- if (lo_send_from(ma, lo_server_thread_get_server(st), LO_TT_IMMEDIATE,
+- "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) {
+- printf("multicast send error %d: %s\n", lo_address_errno(ma),
+- lo_address_errstr(ma));
+- exit(1);
+- }
+- TEST(lo_server_recv(ms) == 24);
+- lo_server_free(ms);
+- lo_address_free(ma);
++ DOING("test_pattern");
++ lo_send(a, "/pattern/*", "s", "a");
++ lo_send(a, "/pattern/ba[rz]", "s", "b");
+ }
+
+-int test_received = 0;
+-int ok_received = 0;
+-int recv_times = 0;
+-
+-int test_handler(const char *path, const char *types,
+- lo_arg **argv, int argc, lo_message m,
+- void *data)
++void test_subtest(lo_server_thread st)
+ {
+- printf("/test, %d, %s\n", argv[0]->i, &argv[1]->s);
+- test_received += 1;
+- return 0;
++ char cmd[2048], *server_url;
++ int i, rc;
++
++ DOING("test_subtest");
++
++ server_url = lo_server_thread_get_url(st);
++
++#ifdef WIN32
++ {
++ char cwd[2048];
++ _getcwd(cwd, 2048);
++ snprintf(cmd, 2048, "%s" PATHDELIM "subtest" EXTEXE, cwd);
++ }
++ printf("spawning subtest with `%s'\n", cmd);
++ for (i=0; i<2; i++) {
++ int j=0;
++ rc = _spawnl( _P_NOWAIT, cmd, cmd, server_url, NULL );
++ if (rc == -1) {
++ fprintf(stderr, "Cannot execute subtest command (%d)\n", i);
++ exit(1);
++ }
++ else while (subtest_count < 1 && j < 20) {
++ SLEEP_MS(100);
++ j++;
++ }
++ if (j >= 20) {
++ fprintf(stderr, "Never got a message from subtest (%d) "
++ "after 2 seconds.\n", i);
++ exit(1);
++ }
++ }
++#else
++ sprintf(cmd, "." PATHDELIM "subtest" EXTEXE " %s", server_url);
++ printf("executing subtest with `%s'\n", cmd);
++ for (i=0; i<2; i++) {
++ int j=0;
++ rc = system(cmd);
++ if (rc == -1) {
++ fprintf(stderr, "Cannot execute subtest command (%d)\n", i);
++ exit(1);
++ }
++ else if (rc > 0) {
++ fprintf(stderr, "subtest command returned %d\n", rc);
++ exit(1);
++ }
++ while (subtest_count < 1 && j < 20) {
++ usleep(100000);
++ j++;
++ }
++ }
++#endif
++
++ free(server_url);
++
++ i = 20*1000;
++ while (subtest_reply_count != 22 && --i > 0)
++ {
++ SLEEP_MS(10);
++ }
++
++ TEST(reply_count == 3);
++ TEST(pattern_count == 5);
++ TEST(subtest_count == 2);
++ TEST(subtest_reply_count == 22);
++ printf("\n");
+ }
+
+-int ok_handler(const char *path, const char *types,
+- lo_arg **argv, int argc, lo_message m,
+- void *data)
++void test_bundle(lo_server_thread st, lo_address a)
+ {
+- printf("/ok\n");
+- ok_received += 1;
+- return 0;
+-}
++ lo_bundle b;
++ lo_timetag sched;
++ lo_message m1, m2;
++ const char *p;
++ int i, tries;
+
+-void *test_tcp_thread(void *context)
+-{
+- lo_server s;
+- printf("Thread started.\n");
++ lo_timetag t = { 10, 0xFFFFFFFC };
+
+- s = lo_server_new_with_proto("9000", LO_TCP, error);
+- if (!s) {
+- printf("Aborting thread, s=%p\n", s);
+- return (void*)1;
+- }
++ DOING("test_bundle");
+
+- lo_server_add_method(s, "/test", "is", test_handler, 0);
+- lo_server_add_method(s, "/ok", "", ok_handler, 0);
++ b = lo_bundle_new(t);
+
+- while (!done) {
+- printf("lo_server_recv_noblock()\n");
+- recv_times += 1;
+- if (!lo_server_recv_noblock(s, 0))
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(1000);
+-#else
+- sleep(1);
+-#endif
+- }
++ m1 = lo_message_new();
++ lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
++ lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
++ lo_bundle_add_message(b, "/bundle", m1);
++ lo_send_bundle(a, b);
+
+- printf("Freeing.\n");
+- lo_server_free(s);
+- printf("Done. Thread ending.\n");
+- return 0;
+-}
++ /* This should be safe for multiple copies of the same message. */
++ lo_bundle_free_messages(b);
+
+-#define SLIP_END 0300 /* indicates end of packet */
++ {
++ lo_timetag t = { 1, 2 };
++ b = lo_bundle_new(t);
++ }
++ m1 = lo_message_new();
++ lo_message_add_int32(m1, 23);
++ lo_message_add_string(m1, "23");
++ lo_bundle_add_message(b, "/bundle", m1);
++ m2 = lo_message_new();
++ lo_message_add_string(m2, "24");
++ lo_message_add_int32(m2, 24);
++ lo_bundle_add_message(b, "/bundle", m2);
++ lo_bundle_add_message(b, "/bundle", m1);
+
+-void test_tcp_halfsend(int stream_type)
+-{
+- char prefixmsg[] = {0,0,0,0,
+- '/','t','e','s','t',0,0,0,
+- ',','i','s',0,
+- 0,0,0,4,
+- 'b','l','a','h',0,0,0,0,
+- 0,0,0,0,
+- '/','o','k',0,
+- ',',0,0,0};
++ TEST(lo_bundle_count(b)==3);
++ TEST(lo_bundle_get_message(b,1,&p)==m2);
++ TEST(strcmp(p, "/bundle")==0);
+
+- char slipmsg[] = {'/','t','e','s','t',0,0,0,
+- ',','i','s',0,
+- 0,0,0,4,
+- 'b','l','a','h',0,0,0,0,SLIP_END,
+- '/','o','k',0,
+- ',',0,0,0,SLIP_END};
++ TEST(lo_send_bundle(a, b) == 88);
+
+- char *msg;
+- int msglen;
++ /* Should fail to add a bundle recursively */
++ TEST(lo_bundle_add_bundle(b, b) != 0)
+
+- struct sockaddr_in sa;
+- int rc;
+- int sock = socket(AF_INET, SOCK_STREAM, 0);
+- if (sock < 0) {
+- perror("socket");
+- exit(1);
++ /* But we can create a nested bundle and it should free
++ * successfully. */
++ {
++ lo_bundle b2 = 0;
++ {
++ lo_timetag t = { 10, 0xFFFFFFFE };
++ b2 = lo_bundle_new(t);
++ }
++ lo_bundle_add_message(b2, "/bundle", m1);
++ TEST(lo_bundle_add_bundle(b2, b) == 0);
++
++ /* Test freeing out-of-order copies of messages in a bundle. */
++ lo_bundle_free_recursive(b2);
+ }
+- memset(&sa, 0, sizeof(struct sockaddr_in));
+- sa.sin_addr.s_addr = inet_addr("127.0.0.1");
+- sa.sin_port = htons(9000);
+- sa.sin_family = AF_INET;
+- rc = connect(sock, (struct sockaddr*)&sa, sizeof(struct sockaddr_in));
+- if (rc) {
+- perror("Error connecting");
+- closesocket(sock);
+- exit(1);
++
++ {
++ lo_timetag t = { 10, 0xFFFFFFFE };
++ b = lo_bundle_new(t);
+ }
++ m1 = lo_message_new();
++ lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
++ lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
++ lo_bundle_add_message(b, "/bundle", m1);
++ lo_send_bundle(a, b);
++ lo_message_free(m1);
++ lo_bundle_free(b);
+
+- printf("Connected, sending...\n");
++ lo_timetag_now(&sched);
+
+- switch (stream_type)
+- {
+- case 0:
+- printf("Testing a count-prefix stream.\n");
+- msg = prefixmsg;
+- msglen = sizeof(prefixmsg);
++ sched.sec += 5;
++ b = lo_bundle_new(sched);
++ m1 = lo_message_new();
++ lo_message_add_string(m1, "future");
++ lo_message_add_string(m1, "time");
++ lo_message_add_string(m1, "test");
++ lo_bundle_add_message(b, "/bundle", m1);
+
+- *(uint32_t*)msg = htonl(24);
+- *(uint32_t*)(msg+28) = htonl(8);
+- break;
+- case 1:
+- printf("Testing a SLIP stream.\n");
+- msg = slipmsg;
+- msglen = sizeof(slipmsg);
+- break;
+- default:
+- closesocket(sock);
+- return;
+- }
++ lo_send_bundle(a, b);
++ lo_message_free(m1);
++ lo_bundle_free(b);
+
+- if (0)
++ lo_send_timestamped(a, sched, "/bundle", "s",
++ "lo_send_timestamped() test");
++
++ /* test bundle timestamp ends up in message struct (and doesn't end up in
++ unbundled messages) */
++ lo_timetag_now(&sched);
++ lo_send_timestamped(a, sched, "/timestamp", "it", 1, sched);
++ lo_send(a, "/timestamp", "it", 0, sched);
++
++#define JITTER_ITS 25
++ /* jitter tests */
+ {
+- printf("Sending everything in one big chunk.\n");
++ lo_timetag stamps[JITTER_ITS];
++ lo_timetag now;
+
+- rc = send(sock, msg, msglen, 0);
+- if (rc != msglen) printf("Error sending, rc = %d\n", rc);
+- else printf("Sent.\n");
++ for (i = 0; i < JITTER_ITS; i++) {
++ lo_timetag_now(&now);
++ stamps[i] = now;
++ stamps[i].sec += 1;
++ stamps[i].frac = rand();
++ lo_send_timestamped(a, stamps[i], "/jitter", "ti", stamps[i],
++ i);
++ }
+ }
+- else
+- {
+- rc = send(sock, msg, 13, 0);
+- if (rc != 13) printf("Error sending, rc = %d\n", rc);
+- else printf("Sent.\n");
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(3000);
+-#else
+- sleep(3);
+-#endif
++ SLEEP_MS(2000);
+
+- rc = send(sock, msg+13, 20, 0);
+- if (rc != 20) printf("Error sending2, rc = %d\n", rc);
+- else printf("Sent2.\n");
++ TEST(lo_server_thread_events_pending(st));
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(3000);
+-#else
+- sleep(3);
+-#endif
++ tries = 20;
++ while (lo_server_thread_events_pending(st)
++ && (--tries > 0))
++ {
++ printf("pending events, wait...\n");
++ fflush(stdout);
++ SLEEP_MS(1000);
++ }
+
+- rc = send(sock, msg+33, msglen-33, 0);
+- if (rc != (msglen-33)) printf("Error sending3, rc = %d\n", rc);
+- else printf("Sent3.\n");
++ if (tries == 0) {
++ printf("server thread still has pending"
++ " events after 20 seconds!\n");
++ exit(1);
+ }
+
+- closesocket(sock);
++ TEST(bundle_count == 7);
++ printf("\n");
++
++ printf("bundle timing jitter results:\n"
++ "max jitter = %fs\n"
++ "avg jitter = %fs\n"
++ "min jitter = %fs\n\n",
++ jitter_max, jitter_total / (float) jitter_count, jitter_min);
+ }
+
+-int test_tcp_nonblock()
++void test_nonblock()
+ {
+- void *retval;
+- pthread_t thread;
++ lo_server s;
++ char *server_url;
++ lo_address a;
+
+- printf("Testing TCP non-blocking behaviour.\n");
++ DOING("test_nonblock");
+
+- done = 0;
+- if (pthread_create(&thread, 0, test_tcp_thread, 0))
+- {
+- perror("pthread_create");
+- return 1;
+- }
++ s = lo_server_new(NULL, error);
++ server_url = lo_server_get_url(s);
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(1000);
+-#else
+- sleep(1);
+-#endif
++ lo_server_add_method(s, NULL, NULL, generic_handler, NULL);
++ a = lo_address_new_from_url(server_url);
++ TEST(lo_server_recv_noblock(s, 0) == 0);
++ printf("Testing noblock API on %s\n", server_url);
++ lo_send(a, "/non-block-test", "f", 23.0);
+
+- test_tcp_halfsend(0);
++ int tries = 1000;
++ while (!lo_server_recv_noblock(s, 10) && --tries > 0)
++ {
++ }
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(1000);
+-#else
+- sleep(1);
+-#endif
++ if (tries == 0) {
++ printf("lo_server_recv_noblock() test failed\n");
++ exit(1);
++ }
+
+- test_tcp_halfsend(1);
++ free(server_url);
++ lo_server_free(s);
++ lo_address_free(a);
++}
+
+-#if defined(WIN32) || defined(_MSC_VER)
+- Sleep(1000);
+-#else
+- sleep(1);
++void test_unix_sockets()
++{
++#if !defined(WIN32) && !defined(_MSC_VER)
++ lo_address ua;
++ lo_server us;
++ char *addr;
++
++ DOING("test_unix_sockets");
++
++ unlink("/tmp/testlo.osc");
++ us = lo_server_new_with_proto("/tmp/testlo.osc", LO_UNIX, error);
++ ua = lo_address_new_from_url("osc.unix:///tmp/testlo.osc");
++ TEST(lo_server_get_protocol(us) == LO_UNIX);
++ TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
++ TEST(lo_server_recv(us) == 16);
++ addr = lo_server_get_url(us);
++ TEST(!strcmp("osc.unix:////tmp/testlo.osc", addr));
++ free(addr);
++ lo_address_free(ua);
++ ua = lo_address_new_with_proto(LO_UNIX, NULL, "/tmp/testlo.osc");
++ TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
++ TEST(lo_server_recv(us) == 16);
++ lo_server_free(us);
++ lo_address_free(ua);
+ #endif
++}
+
+- done = 1;
+- pthread_join(thread, &retval);
+- printf("Thread joined, retval=%p\n", retval);
++void test_tcp()
++{
++ /* TCP tests */
++ lo_address ta;
++ lo_server ts;
++ char *addr;
++
++ DOING("test_tcp");
++
++ ts = lo_server_new_with_proto(NULL, LO_TCP, error);
++ addr = lo_server_get_url(ts);
++ ta = lo_address_new_from_url(addr);
++ if (lo_address_errno(ta)) {
++ printf("err: %s\n", lo_address_errstr(ta));
++ exit(1);
++ }
++ TEST(lo_server_get_protocol(ts) == LO_TCP);
++ TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
++ TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
++ TEST(lo_server_recv(ts) == 16);
++ TEST(lo_server_recv(ts) == 16);
++ free(addr);
++ lo_server_free(ts);
++ lo_address_free(ta);
++}
++
++void cleanup(lo_server_thread st, lo_address a)
++{
++ int tries;
++
++ DOING("cleanup");
++
++ /* exit */
++ lo_send(a, "/quit", NULL);
+
+- return (retval!=0
+- && test_received == 2
+- && ok_received == 2
+- && recv_times == 19);
++ tries = 20*1000;
++ while (!done && (--tries > 0)) {
++ SLEEP_MS(1);
++ }
++
++ if (tries == 0)
++ {
++ printf("Took too long to quit\n");
++ exit(1);
++ }
++
++ lo_address_free(a);
++ lo_server_thread_free(st);
+ }
+
+ /* vi:set ts=8 sts=4 sw=4: */
+--
+1.9.rc1
+
diff --git a/debian/patches/no-so-reuseport.patch b/debian/patches/no-so-reuseport.patch
deleted file mode 100644
index 79ea487..0000000
--- a/debian/patches/no-so-reuseport.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-Description: Disable SO_REUSEPORT usage unconditionally
-The correct solution would be a non-fatal runtime check, currently being
-discussed with upstream. This patch evidently cannot be forwarded as-is.
-Forwarded: no
-Author: Felipe Sateler <fsateler at debian.org>
---- a/src/server.c
-+++ b/src/server.c
-@@ -203,7 +203,7 @@ static int lo_server_setsock_reuseaddr(l
-
- static int lo_server_setsock_reuseport(lo_server s)
- {
--#ifdef SO_REUSEPORT
-+#if 0
- unsigned int yes = 1;
- if (setsockopt(s->sockets[0].fd, SOL_SOCKET, SO_REUSEPORT,
- &yes, sizeof(yes)) < 0) {
diff --git a/debian/patches/series b/debian/patches/series
index 747f730..7099707 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,4 @@
-no-so-reuseport.patch
+Patch-for-missing-include-for-FreeBSD-from-SF-user-n.patch
+Add-several-configure-options-for-the-sake-of-modula.patch
+Refactor-testlo-breaking-up-huge-list-of-tests-into-.patch
+Ensure-error-is-correctly-ignore-if-SO_REUSEPORT-is-.patch
diff --git a/debian/rules b/debian/rules
index 4a087ce..2999a9e 100755
--- a/debian/rules
+++ b/debian/rules
@@ -39,5 +39,8 @@ DEB_UPSTREAM_URL = http://downloads.sourceforge.net/liblo
DEB_UPSTREAM_TARBALL_MD5 = e2a4391a08b49bb316c03e2034e06fa2
#DEB_SHLIBDEPS_INCLUDE = lib/.libs
-DEB_CONFIGURE_USER_FLAGS = --enable-static
+DEB_CONFIGURE_USER_FLAGS = --enable-static \
+ --disable-network-tests \
+ --enable-tests \
+ --enable-examples
DEB_MAKE_CHECK_TARGET=test
--
liblo packaging
More information about the pkg-multimedia-commits
mailing list