You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2017/02/23 22:51:08 UTC

[01/38] qpid-proton git commit: PROTON-1397: bump the so version to 11 on master for 0.18.0

Repository: qpid-proton
Updated Branches:
  refs/heads/go1 ed8e879f6 -> 569b4fca1


PROTON-1397: bump the so version to 11 on master for 0.18.0


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/5bce0dc1
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/5bce0dc1
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/5bce0dc1

Branch: refs/heads/go1
Commit: 5bce0dc198f78497d067b4a0c30801777c527417
Parents: 6ff92f0
Author: Robert Gemmell <ro...@apache.org>
Authored: Wed Feb 8 12:09:06 2017 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Wed Feb 8 12:09:06 2017 +0000

----------------------------------------------------------------------
 proton-c/soversion.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5bce0dc1/proton-c/soversion.cmake
----------------------------------------------------------------------
diff --git a/proton-c/soversion.cmake b/proton-c/soversion.cmake
index 58cc6f5..665edca 100644
--- a/proton-c/soversion.cmake
+++ b/proton-c/soversion.cmake
@@ -1,2 +1,2 @@
-set (PN_LIB_SOMAJOR 10)
+set (PN_LIB_SOMAJOR 11)
 set (PN_LIB_SOMINOR "0.0")


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[25/38] qpid-proton git commit: PROTON-1407: pn_collector_next and pn_collector_peek are inconsistent

Posted by ac...@apache.org.
PROTON-1407: pn_collector_next and pn_collector_peek are inconsistent

Make the behavior consistent as follows:
- peek returns the head of the collector
- pop() and next() remove the head of the collector, pop() discards it, next() returns it
- next() keeps the returned event alive until the following call to next()

next() no longer uses the head of the collector to keep returned events alive, the
returned event is remembered via a separate pointer.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/7368c34c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/7368c34c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/7368c34c

Branch: refs/heads/go1
Commit: 7368c34c1d141ba7754289161453d598860ea3da
Parents: 42d5e89
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 17 13:05:48 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Feb 17 13:05:48 2017 -0500

----------------------------------------------------------------------
 proton-c/include/proton/event.h       | 19 ++++-----------
 proton-c/src/core/connection_driver.c |  3 +--
 proton-c/src/core/event.c             | 38 ++++++++++++++++--------------
 proton-c/src/proactor/libuv.c         |  8 +------
 4 files changed, 27 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7368c34c/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 3cfcc82..b4dbfeb 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -431,7 +431,7 @@ PN_EXTERN pn_event_t *pn_collector_put(pn_collector_t *collector,
 PN_EXTERN pn_event_t *pn_collector_peek(pn_collector_t *collector);
 
 /**
- * Clear the head event on a collector.
+ * Remove the head event on a collector.
  *
  * @param[in] collector a collector object
  * @return true if the event was popped, false if the collector is empty
@@ -439,14 +439,8 @@ PN_EXTERN pn_event_t *pn_collector_peek(pn_collector_t *collector);
 PN_EXTERN bool pn_collector_pop(pn_collector_t *collector);
 
 /**
- * Return the next event to be handled.
- *
- * Returns the head event if it has not previously been returned by
- * pn_collector_next(), otherwise does pn_collector_pop() and returns
- * the new head event.
- *
- * The returned pointer is valid till the next call of pn_collector_pop(),
- * pn_collector_next(), pn_collector_release() or pn_collector_free()
+ * Pop and return the head event, returns NULL if the collector is empty.
+ * The returned pointer is valid till the next call of pn_collector_next().
  *
  * @param[in] collector a collector object
  * @return the next event.
@@ -454,10 +448,7 @@ PN_EXTERN bool pn_collector_pop(pn_collector_t *collector);
 PN_EXTERN pn_event_t *pn_collector_next(pn_collector_t *collector);
 
 /**
- * Return the same event as the previous call to pn_collector_next()
- *
- * The returned pointer is valid till the next call of pn_collector_pop(),
- * pn_collector_next(), pn_collector_release() or pn_collector_free()
+ * Return the same pointer as the most recent call to pn_collector_next().
  *
  * @param[in] collector a collector object
  * @return a pointer to the event returned by previous call to pn_collector_next()
@@ -465,7 +456,7 @@ PN_EXTERN pn_event_t *pn_collector_next(pn_collector_t *collector);
 PN_EXTERN pn_event_t *pn_collector_prev(pn_collector_t *collector);
 
 /**
- * Check if there are more events after the current event. If this
+ * Check if there are more events after the current head event. If this
  * returns true, then pn_collector_peek() will return an event even
  * after pn_collector_pop() is called.
  *

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7368c34c/proton-c/src/core/connection_driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_driver.c b/proton-c/src/core/connection_driver.c
index 63eed09..3393e64 100644
--- a/proton-c/src/core/connection_driver.c
+++ b/proton-c/src/core/connection_driver.c
@@ -127,8 +127,7 @@ pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *d) {
 }
 
 bool pn_connection_driver_has_event(pn_connection_driver_t *d) {
-  pn_collector_t *c = pn_connection_collector(d->connection);
-  return pn_collector_more(c) || (pn_collector_peek(c) && pn_collector_peek(c) != pn_collector_prev(c));
+  return pn_collector_peek(pn_connection_collector(d->connection));
 }
 
 bool pn_connection_driver_finished(pn_connection_driver_t *d) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7368c34c/proton-c/src/core/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/event.c b/proton-c/src/core/event.c
index e213c8f..7a80a72 100644
--- a/proton-c/src/core/event.c
+++ b/proton-c/src/core/event.c
@@ -28,8 +28,8 @@ struct pn_collector_t {
   pn_list_t *pool;
   pn_event_t *head;
   pn_event_t *tail;
+  pn_event_t *prev;         /* event returned by previous call to pn_collector_next() */
   bool freed;
-  bool head_returned;         /* Head has been returned by pn_collector_next() */
 };
 
 struct pn_event_t {
@@ -46,6 +46,7 @@ static void pn_collector_initialize(pn_collector_t *collector)
   collector->pool = pn_list(PN_OBJECT, 0);
   collector->head = NULL;
   collector->tail = NULL;
+  collector->prev = NULL;
   collector->freed = false;
 }
 
@@ -171,35 +172,36 @@ pn_event_t *pn_collector_peek(pn_collector_t *collector)
   return collector->head;
 }
 
-bool pn_collector_pop(pn_collector_t *collector)
-{
-  collector->head_returned = false;
+// Advance head pointer for pop or next, return the old head.
+static pn_event_t *pop_internal(pn_collector_t *collector) {
   pn_event_t *event = collector->head;
   if (event) {
     collector->head = event->next;
-  } else {
-    return false;
+    if (!collector->head) {
+      collector->tail = NULL;
+    }
   }
+  return event;
+}
 
-  if (!collector->head) {
-    collector->tail = NULL;
+bool pn_collector_pop(pn_collector_t *collector) {
+  pn_event_t *event = pop_internal(collector);
+  if (event) {
+    pn_decref(event);
   }
-
-  pn_decref(event);
-  return true;
+  return event;
 }
 
-pn_event_t *pn_collector_next(pn_collector_t *collector)
-{
-  if (collector->head_returned) {
-    pn_collector_pop(collector);
+pn_event_t *pn_collector_next(pn_collector_t *collector) {
+  if (collector->prev) {
+    pn_decref(collector->prev);
   }
-  collector->head_returned = collector->head;
-  return collector->head;
+  collector->prev = pop_internal(collector);
+  return collector->prev;
 }
 
 pn_event_t *pn_collector_prev(pn_collector_t *collector) {
-  return collector->head_returned ? collector->head : NULL;
+  return collector->prev;
 }
 
 bool pn_collector_more(pn_collector_t *collector)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7368c34c/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 0a10ac9..0e87d0a 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -621,17 +621,11 @@ static void pconnection_to_worker(pconnection_t *pc) {
   to_worker(&pc->psocket);
 }
 
-/* TODO aconway 2017-02-16: simplify collector API*/
-static bool collector_has_next(pn_collector_t *c) {
-  return pn_collector_more(c) ||
-    (pn_collector_peek(c) && pn_collector_peek(c) != pn_collector_prev(c));
-}
-
 /* Can't really detach a listener, as on_connection can always be called.
    Generate events here safely.
 */
 static void listener_to_worker(pn_listener_t *l) {
-  if (collector_has_next(l->collector)) { /* Already have events */
+  if (pn_collector_peek(l->collector)) { /* Already have events */
     to_worker(&l->psocket);
   } else if (l->err) {
     if (l->err != UV_EOF) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[17/38] qpid-proton git commit: PROTON-1360: Make sure pn_strndup doesn't overrun allocated memory

Posted by ac...@apache.org.
PROTON-1360: Make sure pn_strndup doesn't overrun allocated memory


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/7560f58e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/7560f58e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/7560f58e

Branch: refs/heads/go1
Commit: 7560f58ea708f971799442ac657d8e73a5b97e34
Parents: 39c70d1
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Feb 14 18:16:10 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed Feb 15 13:37:03 2017 -0500

----------------------------------------------------------------------
 proton-c/src/core/util.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7560f58e/proton-c/src/core/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.c b/proton-c/src/core/util.c
index 62eec9a..4309de3 100644
--- a/proton-c/src/core/util.c
+++ b/proton-c/src/core/util.c
@@ -147,7 +147,7 @@ char *pn_strndup(const char *src, size_t n)
 
     char *dest = (char *) malloc(size + 1);
     if (!dest) return NULL;
-    strncpy(dest, src, n);
+    strncpy(dest, src, pn_min(n, size));
     dest[size] = '\0';
     return dest;
   } else {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[21/38] qpid-proton git commit: NO-JIRA: Set the correct COMPILE_WARNING_FLAGS for clang C++

Posted by ac...@apache.org.
NO-JIRA: Set the correct COMPILE_WARNING_FLAGS for clang C++


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/ce6626be
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/ce6626be
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/ce6626be

Branch: refs/heads/go1
Commit: ce6626be74c0cb824bab91e80e4e81428a84c360
Parents: a1d84b0
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 16 00:07:00 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 16 16:52:44 2017 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ce6626be/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index c73f9df..30a77e2 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -274,8 +274,9 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
 endif (CMAKE_COMPILER_IS_GNUCC)
 
 if (CMAKE_C_COMPILER_ID MATCHES "Clang")
+  set (COMPILE_WARNING_FLAGS  "-Wall -pedantic")
   if (ENABLE_WARNING_ERROR)
-    set (COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic")
+    set (COMPILE_WARNING_FLAGS "-Werror ${COMPILE_WARNING_FLAGS}")
   endif (ENABLE_WARNING_ERROR)
 endif()
 
@@ -285,7 +286,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
   endif (ENABLE_WARNING_ERROR)
   # TODO aconway 2016-01-06: we should be able to clean up the code and turn on
   # some of these warnings.
-  set (CXX_WARNING_FLAGS "${WERROR} -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32 -Wno-documentation -Wno-documentation-unknown-command -Wno-old-style-cast -Wno-missing-noreturn")
+  set (CXX_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32 -Wno-documentation -Wno-documentation-unknown-command -Wno-old-style-cast -Wno-missing-noreturn")
 endif()
 
 # Make flags visible to examples.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[19/38] qpid-proton git commit: PROTON-1351: link go binding with qpid-proton-core library

Posted by ac...@apache.org.
PROTON-1351: link go binding with qpid-proton-core library

The go binding was still being linked with the qpid-proton library, even though it
only depends on symbols in qpid-proton-core. Link it with qpid-proton-core.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a1d84b0e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a1d84b0e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a1d84b0e

Branch: refs/heads/go1
Commit: a1d84b0e212ebd1b7a8b2f9a52dc83337995dca3
Parents: cd612ff
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Feb 15 21:27:00 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 16 16:52:27 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go     | 2 +-
 proton-c/bindings/go/src/qpid.apache.org/electron/doc.go | 2 +-
 proton-c/bindings/go/src/qpid.apache.org/proton/doc.go   | 2 +-
 proton-c/bindings/go/src/qpid.apache.org/proton/error.go | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a1d84b0e/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
index 701af55..c04c2b0 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
@@ -32,7 +32,7 @@ AMQP 1.0 is an open standard for inter-operable message exchange, see <http://ww
 */
 package amqp
 
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
 import "C"
 
 // This file is just for the package comment.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a1d84b0e/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go b/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
index f4baa31..39137c0 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
@@ -50,7 +50,7 @@ More realistic examples: https://github.com/apache/qpid-proton/blob/master/examp
 */
 package electron
 
-//#cgo LDFLAGS: -lqpid-proton
+//#cgo LDFLAGS: -lqpid-proton-core
 import "C"
 
 // Just for package comment

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a1d84b0e/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
index 1049e71..39716e2 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
@@ -60,7 +60,7 @@ applications.
 */
 package proton
 
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
 import "C"
 
 // This file is just for the package comment.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a1d84b0e/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/error.go b/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
index 80d9680..5232fec 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
@@ -20,7 +20,7 @@ under the License.
 // Internal implementation details - ignore.
 package proton
 
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
 // #include <proton/error.h>
 // #include <proton/codec.h>
 import "C"


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[24/38] qpid-proton git commit: PROTON-1403: Fixes for windows and platforms without libuv

Posted by ac...@apache.org.
PROTON-1403: Fixes for windows and platforms without libuv


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/42d5e89e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/42d5e89e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/42d5e89e

Branch: refs/heads/go1
Commit: 42d5e89ef248e5dd85ca892e79696f845c34796f
Parents: 9abc67d
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 16 13:16:30 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 16 18:25:21 2017 -0500

----------------------------------------------------------------------
 examples/c/proactor/CMakeLists.txt | 5 +----
 proton-c/CMakeLists.txt            | 1 +
 proton-c/src/proactor/libuv.c      | 4 ++--
 proton-c/src/tests/CMakeLists.txt  | 4 +++-
 4 files changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/42d5e89e/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index 153f35f..bb6cb0f 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -23,11 +23,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${Proton_INCLUDE_DIRS})
 
 # Check if the proton library has a proactor implementation.
 include(CheckFunctionExists)
-include(CMakePushCheckState)
-cmake_push_check_state()
-set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Proton_LIBRARIES})
+set(CMAKE_REQUIRED_LIBRARIES ${Proton_LIBRARIES})
 check_function_exists(pn_proactor HAS_PROACTOR)
-cmake_pop_check_state()
 
 if(HAS_PROACTOR)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/42d5e89e/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 0731b67..68ccc2c 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -618,6 +618,7 @@ configure_lib(PROTONLIB qpid-proton)
 configure_lib(PROTONCORELIB qpid-proton-core)
 
 if (qpid-proton-proactor)
+  set(HAS_PROACTOR 1)
   add_library (
     qpid-proton-proactor SHARED
     ${qpid-proton-proactor}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/42d5e89e/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 4ec7b03..0a10ac9 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -19,8 +19,6 @@
  *
  */
 
-#include <uv.h>
-
 #include <proton/condition.h>
 #include <proton/connection_driver.h>
 #include <proton/engine.h>
@@ -31,6 +29,8 @@
 #include <proton/transport.h>
 #include <proton/url.h>
 
+#include <uv.h>
+
 /* All asserts are cheap and should remain in a release build for debugability */
 #undef NDEBUG
 #include <assert.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/42d5e89e/proton-c/src/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/CMakeLists.txt b/proton-c/src/tests/CMakeLists.txt
index 70b30a0..3ad114a 100644
--- a/proton-c/src/tests/CMakeLists.txt
+++ b/proton-c/src/tests/CMakeLists.txt
@@ -49,4 +49,6 @@ pn_add_c_test (c-reactor-tests reactor.c)
 pn_add_c_test (c-event-tests event.c)
 pn_add_c_test (c-data-tests data.c)
 pn_add_c_test (c-condition-tests condition.c)
-pn_add_c_test (c-proactor-tests proactor.c)
+if(HAS_PROACTOR)
+  pn_add_c_test (c-proactor-tests proactor.c)
+endif(HAS_PROACTOR)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[34/38] qpid-proton git commit: PROTON-1415: go binding does not create durable subscriber

Posted by ac...@apache.org.
PROTON-1415: go binding does not create durable subscriber

Added `DurableSubscription(name string) LinkOption`, pass to Connection.Receiver()
to create a named durable subscription.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/38592d16
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/38592d16
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/38592d16

Branch: refs/heads/go1
Commit: 38592d1668eef9d192ed0c814b34e807039777d3
Parents: 540e74e
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 14:02:14 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 15:30:05 2017 -0500

----------------------------------------------------------------------
 .../src/qpid.apache.org/electron/connection.go  |   2 +-
 .../go/src/qpid.apache.org/electron/link.go     | 128 ++++++++++++++-----
 .../src/qpid.apache.org/electron/link_test.go   |  63 +++++++++
 3 files changed, 160 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/38592d16/proton-c/bindings/go/src/qpid.apache.org/electron/connection.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/connection.go b/proton-c/bindings/go/src/qpid.apache.org/electron/connection.go
index 7f3050f..8f62491 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/electron/connection.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/connection.go
@@ -276,7 +276,7 @@ func (c *connection) WaitTimeout(timeout time.Duration) error {
 }
 
 func (c *connection) Incoming() <-chan Incoming {
-	assert(c.incoming != nil, "electron.Connection.Incoming() disabled for %s", c)
+	assert(c.incoming != nil, "Incoming() is only allowed for a Connection created with the Server() option: %s", c)
 	return c.incoming
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/38592d16/proton-c/bindings/go/src/qpid.apache.org/electron/link.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/link.go b/proton-c/bindings/go/src/qpid.apache.org/electron/link.go
index 1d17894..4f927c1 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/electron/link.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/link.go
@@ -22,6 +22,7 @@ package electron
 import (
 	"fmt"
 	"qpid.apache.org/proton"
+	"time"
 )
 
 // Settings associated with a link
@@ -50,6 +51,12 @@ type LinkSettings interface {
 
 	// Session containing the Link
 	Session() Session
+
+	// Advanced settings for the source
+	SourceSettings() TerminusSettings
+
+	// Advanced settings for the target
+	TargetSettings() TerminusSettings
 }
 
 // LinkOption can be passed when creating a sender or receiver link to set optional configuration.
@@ -62,7 +69,7 @@ func Source(s string) LinkOption { return func(l *linkSettings) { l.source = s }
 func Target(s string) LinkOption { return func(l *linkSettings) { l.target = s } }
 
 // LinkName returns a LinkOption that sets the link name.
-func LinkName(s string) LinkOption { return func(l *linkSettings) { l.target = s } }
+func LinkName(s string) LinkOption { return func(l *linkSettings) { l.linkName = s } }
 
 // SndSettle returns a LinkOption that sets the send settle mode
 func SndSettle(m SndSettleMode) LinkOption { return func(l *linkSettings) { l.sndSettle = m } }
@@ -70,16 +77,23 @@ func SndSettle(m SndSettleMode) LinkOption { return func(l *linkSettings) { l.sn
 // RcvSettle returns a LinkOption that sets the send settle mode
 func RcvSettle(m RcvSettleMode) LinkOption { return func(l *linkSettings) { l.rcvSettle = m } }
 
-// SndSettleMode returns a LinkOption that defines when the sending end of the
-// link settles message delivery.
-type SndSettleMode proton.SndSettleMode
-
 // Capacity returns a LinkOption that sets the link capacity
 func Capacity(n int) LinkOption { return func(l *linkSettings) { l.capacity = n } }
 
 // Prefetch returns a LinkOption that sets a receivers pre-fetch flag. Not relevant for a sender.
 func Prefetch(p bool) LinkOption { return func(l *linkSettings) { l.prefetch = p } }
 
+// DurableSubscription returns a LinkOption that configures a Receiver as a named durable
+// subscription.  The name overrides (and is overridden by) LinkName() so you should normally
+// only use one of these options.
+func DurableSubscription(name string) LinkOption {
+	return func(l *linkSettings) {
+		l.linkName = name
+		l.sourceSettings.Durability = proton.Deliveries
+		l.sourceSettings.Expiry = proton.ExpireNever
+	}
+}
+
 // AtMostOnce returns a LinkOption that sets "fire and forget" mode, messages
 // are sent but no acknowledgment is received, messages can be lost if there is
 // a network failure. Sets SndSettleMode=SendSettled and RcvSettleMode=RcvFirst
@@ -102,6 +116,21 @@ func AtLeastOnce() LinkOption {
 	}
 }
 
+// SourceSettings returns a LinkOption that sets all the SourceSettings.
+// Note: it will override the source address set by a Source() option
+func SourceSettings(ts TerminusSettings) LinkOption {
+	return func(l *linkSettings) { l.sourceSettings = ts }
+}
+
+// TargetSettings returns a LinkOption that sets all the TargetSettings.
+// Note: it will override the target address set by a Target() option
+func TargetSettings(ts TerminusSettings) LinkOption {
+	return func(l *linkSettings) { l.targetSettings = ts }
+}
+
+// SndSettleMode defines when the sending end of the link settles message delivery.
+type SndSettleMode proton.SndSettleMode
+
 const (
 	// Messages are sent unsettled
 	SndUnsettled = SndSettleMode(proton.SndUnsettled)
@@ -122,16 +151,37 @@ const (
 )
 
 type linkSettings struct {
-	source    string
-	target    string
-	linkName  string
-	isSender  bool
-	sndSettle SndSettleMode
-	rcvSettle RcvSettleMode
-	capacity  int
-	prefetch  bool
-	session   *session
-	pLink     proton.Link
+	source         string
+	sourceSettings TerminusSettings
+	target         string
+	targetSettings TerminusSettings
+	linkName       string
+	isSender       bool
+	sndSettle      SndSettleMode
+	rcvSettle      RcvSettleMode
+	capacity       int
+	prefetch       bool
+	session        *session
+	pLink          proton.Link
+}
+
+// Advanced AMQP settings for the source or target of a link.
+// Usually these can be set via a more descriptive LinkOption, e.g. DurableSubscription()
+// and do not need to be set/examined directly.
+type TerminusSettings struct {
+	Durability proton.Durability
+	Expiry     proton.ExpiryPolicy
+	Timeout    time.Duration
+	Dynamic    bool
+}
+
+func makeTerminusSettings(t proton.Terminus) TerminusSettings {
+	return TerminusSettings{
+		Durability: t.Durability(),
+		Expiry:     t.ExpiryPolicy(),
+		Timeout:    t.Timeout(),
+		Dynamic:    t.IsDynamic(),
+	}
 }
 
 type link struct {
@@ -139,13 +189,15 @@ type link struct {
 	linkSettings
 }
 
-func (l *linkSettings) Source() string           { return l.source }
-func (l *linkSettings) Target() string           { return l.target }
-func (l *linkSettings) LinkName() string         { return l.linkName }
-func (l *linkSettings) IsSender() bool           { return l.isSender }
-func (l *linkSettings) IsReceiver() bool         { return !l.isSender }
-func (l *linkSettings) SndSettle() SndSettleMode { return l.sndSettle }
-func (l *linkSettings) RcvSettle() RcvSettleMode { return l.rcvSettle }
+func (l *linkSettings) Source() string                   { return l.source }
+func (l *linkSettings) Target() string                   { return l.target }
+func (l *linkSettings) LinkName() string                 { return l.linkName }
+func (l *linkSettings) IsSender() bool                   { return l.isSender }
+func (l *linkSettings) IsReceiver() bool                 { return !l.isSender }
+func (l *linkSettings) SndSettle() SndSettleMode         { return l.sndSettle }
+func (l *linkSettings) RcvSettle() RcvSettleMode         { return l.rcvSettle }
+func (l *linkSettings) SourceSettings() TerminusSettings { return l.sourceSettings }
+func (l *linkSettings) TargetSettings() TerminusSettings { return l.targetSettings }
 
 func (l *link) Session() Session       { return l.session }
 func (l *link) Connection() Connection { return l.session.Connection() }
@@ -175,7 +227,17 @@ func makeLocalLink(sn *session, isSender bool, setting ...LinkOption) (linkSetti
 		return l, fmt.Errorf("cannot create link %s", l.pLink)
 	}
 	l.pLink.Source().SetAddress(l.source)
+	l.pLink.Source().SetDurability(l.sourceSettings.Durability)
+	l.pLink.Source().SetExpiryPolicy(l.sourceSettings.Expiry)
+	l.pLink.Source().SetTimeout(l.sourceSettings.Timeout)
+	l.pLink.Source().SetDynamic(l.sourceSettings.Dynamic)
+
 	l.pLink.Target().SetAddress(l.target)
+	l.pLink.Target().SetDurability(l.targetSettings.Durability)
+	l.pLink.Target().SetExpiryPolicy(l.targetSettings.Expiry)
+	l.pLink.Target().SetTimeout(l.targetSettings.Timeout)
+	l.pLink.Target().SetDynamic(l.targetSettings.Dynamic)
+
 	l.pLink.SetSndSettleMode(proton.SndSettleMode(l.sndSettle))
 	l.pLink.SetRcvSettleMode(proton.RcvSettleMode(l.rcvSettle))
 	l.pLink.Open()
@@ -184,16 +246,18 @@ func makeLocalLink(sn *session, isSender bool, setting ...LinkOption) (linkSetti
 
 func makeIncomingLinkSettings(pLink proton.Link, sn *session) linkSettings {
 	return linkSettings{
-		isSender:  pLink.IsSender(),
-		source:    pLink.RemoteSource().Address(),
-		target:    pLink.RemoteTarget().Address(),
-		linkName:  pLink.Name(),
-		sndSettle: SndSettleMode(pLink.RemoteSndSettleMode()),
-		rcvSettle: RcvSettleMode(pLink.RemoteRcvSettleMode()),
-		capacity:  1,
-		prefetch:  false,
-		pLink:     pLink,
-		session:   sn,
+		isSender:       pLink.IsSender(),
+		source:         pLink.RemoteSource().Address(),
+		sourceSettings: makeTerminusSettings(pLink.RemoteSource()),
+		target:         pLink.RemoteTarget().Address(),
+		targetSettings: makeTerminusSettings(pLink.RemoteTarget()),
+		linkName:       pLink.Name(),
+		sndSettle:      SndSettleMode(pLink.RemoteSndSettleMode()),
+		rcvSettle:      RcvSettleMode(pLink.RemoteRcvSettleMode()),
+		capacity:       1,
+		prefetch:       false,
+		pLink:          pLink,
+		session:        sn,
 	}
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/38592d16/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go b/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
new file mode 100644
index 0000000..eb49c47
--- /dev/null
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
@@ -0,0 +1,63 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+// Test that link settings are propagated correctly
+package electron
+
+import (
+	"net"
+	"qpid.apache.org/proton"
+	"testing"
+)
+
+func TestLinkSettings(t *testing.T) {
+	cConn, sConn := net.Pipe()
+	done := make(chan error)
+	// FIXME aconway 2017-02-23: bug in timeout conversion (pn_second_t)
+	settings := TerminusSettings{Durability: 1, Expiry: 2 /*, Timeout: 42 * time.Second*/, Dynamic: true}
+	go func() { // Server
+		close(done)
+		defer sConn.Close()
+		c, err := NewConnection(sConn, Server())
+		fatalIf(t, err)
+		for in := range c.Incoming() {
+			ep := in.Accept()
+			switch ep := ep.(type) {
+			case Receiver:
+				errorIf(t, checkEqual("one.source", ep.Source()))
+				errorIf(t, checkEqual(TerminusSettings{}, ep.SourceSettings()))
+				errorIf(t, checkEqual("one.target", ep.Target()))
+				errorIf(t, checkEqual(settings, ep.TargetSettings()))
+			case Sender:
+				errorIf(t, checkEqual("two", ep.LinkName()))
+				errorIf(t, checkEqual("two.source", ep.Source()))
+				errorIf(t, checkEqual(TerminusSettings{Durability: proton.Deliveries, Expiry: proton.ExpireNever}, ep.SourceSettings()))
+			}
+		}
+	}()
+
+	// Client
+	c, err := NewConnection(cConn)
+	fatalIf(t, err)
+	c.Sender(Source("one.source"), Target("one.target"), TargetSettings(settings))
+
+	c.Receiver(Source("two.source"), DurableSubscription("two"))
+	c.Close(nil)
+	<-done
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[11/38] qpid-proton git commit: PROTON-1403: c proactor fix example test

Posted by ac...@apache.org.
PROTON-1403: c proactor fix example test

Fix incorrect  use of check_function_exists() in example CMakeLists.txt


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/03071a1d
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/03071a1d
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/03071a1d

Branch: refs/heads/go1
Commit: 03071a1db2cc950a8f8624116151edb7ba846321
Parents: 1d4fe54
Author: Alan Conway <ac...@redhat.com>
Authored: Sat Feb 11 12:31:09 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Sat Feb 11 12:31:09 2017 -0500

----------------------------------------------------------------------
 examples/c/CMakeLists.txt          |  7 +------
 examples/c/proactor/CMakeLists.txt | 13 ++++++++++++-
 2 files changed, 13 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/03071a1d/examples/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index b2f36d3..0fed71b 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -19,13 +19,8 @@
 
 find_package(Proton REQUIRED)
 include(CheckCCompilerFlag)
-include(CheckFunctionExists)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 
-check_function_exists(pn_proactor, HAS_PROACTOR)
-if (HAS_PROACTOR)
-  add_subdirectory(proactor)
-endif()
-
+add_subdirectory(proactor)
 add_subdirectory(messenger)
 add_subdirectory(reactor)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/03071a1d/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index 2ed4f94..7fec1c6 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -18,9 +18,19 @@
 #
 
 find_package(Proton REQUIRED)
-
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${Proton_INCLUDE_DIRS})
 
+# Check if the proton library has a proactor implementation.
+include(CheckFunctionExists)
+include(CMakePushCheckState)
+cmake_push_check_state()
+set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Proton_LIBRARIES})
+check_function_exists(pn_proactor HAS_PROACTOR)
+cmake_pop_check_state()
+
+if (HAS_PROACTOR)
+
 add_definitions(${COMPILE_WARNING_FLAGS} ${WERROR} ${COMPILE_PLATFORM_FLAGS} ${LINK_TIME_OPTIMIZATION})
 
 # Add a test with the correct environment to find test executables and valgrind.
@@ -40,3 +50,4 @@ endforeach()
 set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV})
 add_test(c-proactor ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py -v)
 
+endif()


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[35/38] qpid-proton git commit: PROTON-1415: go fix conversion of pn_seconds_t

Posted by ac...@apache.org.
PROTON-1415: go fix conversion of pn_seconds_t

genwrap.go: fix conversion of pn_seconds_t to time.Duration.
Exposed by adding TerminusSettings which includes a pn_seconds_t Timeout value.
This is the only place pn_seconds_t is used for a duration in proton instead of pn_millis_t.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/c87b23ef
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/c87b23ef
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/c87b23ef

Branch: refs/heads/go1
Commit: c87b23ef7b473cd48e8775ed9c353d042d99f3ca
Parents: 38592d1
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 15:37:24 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 15:37:24 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/go/genwrap.go                 |  6 ++--
 .../src/qpid.apache.org/electron/link_test.go   |  3 +-
 .../src/qpid.apache.org/proton/wrappers_gen.go  | 35 +++++++++++++++++++-
 3 files changed, 38 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c87b23ef/proton-c/bindings/go/genwrap.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/genwrap.go b/proton-c/bindings/go/genwrap.go
index 7782b0b..6885b74 100644
--- a/proton-c/bindings/go/genwrap.go
+++ b/proton-c/bindings/go/genwrap.go
@@ -161,10 +161,7 @@ func panicIf(err error) {
 }
 
 func readHeader(name string) string {
-	file, err := os.Open(path.Join(includeProton, name+".h"))
-	panicIf(err)
-	defer file.Close()
-	s, err := ioutil.ReadAll(file)
+	s, err := ioutil.ReadFile(path.Join(includeProton, name+".h"))
 	panicIf(err)
 	return string(s)
 }
@@ -314,6 +311,7 @@ func mapType(ctype string) (g genType) {
 	case "C.pn_seconds_t":
 		g.Gotype = "time.Duration"
 		g.ToGo = func(v string) string { return fmt.Sprintf("(time.Duration(%s) * time.Second)", v) }
+		g.ToC = func(v string) string { return fmt.Sprintf("C.pn_seconds_t(%s/time.Second)", v) }
 	case "C.pn_millis_t":
 		g.Gotype = "time.Duration"
 		g.ToGo = func(v string) string { return fmt.Sprintf("(time.Duration(%s) * time.Millisecond)", v) }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c87b23ef/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go b/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
index eb49c47..133faad 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/link_test.go
@@ -24,13 +24,14 @@ import (
 	"net"
 	"qpid.apache.org/proton"
 	"testing"
+	"time"
 )
 
 func TestLinkSettings(t *testing.T) {
 	cConn, sConn := net.Pipe()
 	done := make(chan error)
 	// FIXME aconway 2017-02-23: bug in timeout conversion (pn_second_t)
-	settings := TerminusSettings{Durability: 1, Expiry: 2 /*, Timeout: 42 * time.Second*/, Dynamic: true}
+	settings := TerminusSettings{Durability: 1, Expiry: 2, Timeout: 42 * time.Second, Dynamic: true}
 	go func() { // Server
 		close(done)
 		defer sConn.Close()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c87b23ef/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go b/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
index 19bfde2..a6c6635 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
@@ -78,6 +78,13 @@ const (
 	ETransportHeadClosed    EventType = C.PN_TRANSPORT_HEAD_CLOSED
 	ETransportTailClosed    EventType = C.PN_TRANSPORT_TAIL_CLOSED
 	ETransportClosed        EventType = C.PN_TRANSPORT_CLOSED
+	EConnectionWake         EventType = C.PN_CONNECTION_WAKE
+	EListenerAccept         EventType = C.PN_LISTENER_ACCEPT
+	EListenerClose          EventType = C.PN_LISTENER_CLOSE
+	EProactorInterrupt      EventType = C.PN_PROACTOR_INTERRUPT
+	EProactorTimeout        EventType = C.PN_PROACTOR_TIMEOUT
+	EProactorInactive       EventType = C.PN_PROACTOR_INACTIVE
+	EListenerOpen           EventType = C.PN_LISTENER_OPEN
 )
 
 func (e EventType) String() string {
@@ -143,6 +150,20 @@ func (e EventType) String() string {
 		return "TransportTailClosed"
 	case C.PN_TRANSPORT_CLOSED:
 		return "TransportClosed"
+	case C.PN_CONNECTION_WAKE:
+		return "ConnectionWake"
+	case C.PN_LISTENER_ACCEPT:
+		return "ListenerAccept"
+	case C.PN_LISTENER_CLOSE:
+		return "ListenerClose"
+	case C.PN_PROACTOR_INTERRUPT:
+		return "ProactorInterrupt"
+	case C.PN_PROACTOR_TIMEOUT:
+		return "ProactorTimeout"
+	case C.PN_PROACTOR_INACTIVE:
+		return "ProactorInactive"
+	case C.PN_LISTENER_OPEN:
+		return "ListenerOpen"
 	}
 	return "Unknown"
 }
@@ -352,6 +373,15 @@ func (l Link) SetDrain(drain bool) {
 func (l Link) Draining() bool {
 	return bool(C.pn_link_draining(l.pn))
 }
+func (l Link) MaxMessageSize() uint64 {
+	return uint64(C.pn_link_max_message_size(l.pn))
+}
+func (l Link) SetMaxMessageSize(size uint64) {
+	C.pn_link_set_max_message_size(l.pn, C.uint64_t(size))
+}
+func (l Link) RemoteMaxMessageSize() uint64 {
+	return uint64(C.pn_link_remote_max_message_size(l.pn))
+}
 
 // Wrappers for declarations in delivery.h
 
@@ -499,6 +529,9 @@ func (c Condition) RedirectHost() string {
 func (c Condition) RedirectPort() int {
 	return int(C.pn_condition_redirect_port(c.pn))
 }
+func (c Condition) Copy(src Condition) int {
+	return int(C.pn_condition_copy(c.pn, src.pn))
+}
 
 // Wrappers for declarations in terminus.h
 
@@ -630,7 +663,7 @@ func (t Terminus) Timeout() time.Duration {
 	return (time.Duration(C.pn_terminus_get_timeout(t.pn)) * time.Second)
 }
 func (t Terminus) SetTimeout(timeout time.Duration) int {
-	return int(C.pn_terminus_set_timeout(t.pn, C.pn_seconds_t(timeout)))
+	return int(C.pn_terminus_set_timeout(t.pn, C.pn_seconds_t(timeout/time.Second)))
 }
 func (t Terminus) IsDynamic() bool {
 	return bool(C.pn_terminus_is_dynamic(t.pn))


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[04/38] qpid-proton git commit: NO-JIRA: [C++ binding] make container test work with more containers

Posted by ac...@apache.org.
NO-JIRA: [C++ binding] make container test work with more containers


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/3ca4bdcd
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/3ca4bdcd
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/3ca4bdcd

Branch: refs/heads/go1
Commit: 3ca4bdcd64d32fb5e81adb5c5467391d3bb11693
Parents: 8cc266e
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed Feb 8 15:38:00 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Feb 9 21:23:20 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/src/container_test.cpp | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3ca4bdcd/proton-c/bindings/cpp/src/container_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_test.cpp b/proton-c/bindings/cpp/src/container_test.cpp
index 564a4ba..e02aff5 100644
--- a/proton-c/bindings/cpp/src/container_test.cpp
+++ b/proton-c/bindings/cpp/src/container_test.cpp
@@ -139,10 +139,12 @@ int test_container_bad_address() {
     proton::default_container c;
     // Default fixed-option listener. Valgrind for leaks.
     try { c.listen("999.666.999.666:0"); } catch (const proton::error&) {}
+    c.run();
     // Dummy listener.
     test_listener l;
     test_handler h2(std::string("999.999.999.666"), proton::connection_options());
     try { c.listen("999.666.999.666:0", l); } catch (const proton::error&) {}
+    c.run();
     ASSERT(!l.on_accept_);
     ASSERT(l.on_close_);
     ASSERT(!l.on_error_.empty());


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[07/38] qpid-proton git commit: PROTON-1402: Simplify access to connection_context

Posted by ac...@apache.org.
PROTON-1402: Simplify access to connection_context


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b9a57e8a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b9a57e8a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b9a57e8a

Branch: refs/heads/go1
Commit: b9a57e8a78c547bc1d01506ecb636b50dc4ee8d6
Parents: 431696d
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed Feb 8 13:26:15 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Feb 9 21:56:41 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/src/connection_options.cpp   | 4 ++--
 proton-c/bindings/cpp/src/container_impl.cpp       | 4 ++--
 proton-c/bindings/cpp/src/contexts.cpp             | 4 ----
 proton-c/bindings/cpp/src/include/contexts.hpp     | 2 --
 proton-c/bindings/cpp/src/io/connection_driver.cpp | 4 ++--
 proton-c/bindings/cpp/src/io/link_namer.cpp        | 3 ++-
 proton-c/bindings/cpp/src/session.cpp              | 2 +-
 7 files changed, 9 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/connection_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_options.cpp b/proton-c/bindings/cpp/src/connection_options.cpp
index c30b98d..506e84e 100644
--- a/proton-c/bindings/cpp/src/connection_options.cpp
+++ b/proton-c/bindings/cpp/src/connection_options.cpp
@@ -75,7 +75,7 @@ class connection_options::impl {
     void apply_unbound(connection& c) {
         pn_connection_t *pnc = unwrap(c);
         container::impl::connector *outbound = dynamic_cast<container::impl::connector*>(
-            connection_context::get(c).handler.get());
+            connection_context::get(unwrap(c)).handler.get());
 
         // Only apply connection options if uninit.
         bool uninit = c.uninitialized();
@@ -98,7 +98,7 @@ class connection_options::impl {
         // and if there is a pipelined open frame.
         pn_connection_t *pnc = unwrap(c);
         container::impl::connector *outbound = dynamic_cast<container::impl::connector*>(
-            connection_context::get(c).handler.get());
+            connection_context::get(unwrap(c)).handler.get());
 
         pn_transport_t *pnt = pn_connection_transport(pnc);
         if (!pnt) return;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_impl.cpp b/proton-c/bindings/cpp/src/container_impl.cpp
index 9cec831..d58fc09 100644
--- a/proton-c/bindings/cpp/src/container_impl.cpp
+++ b/proton-c/bindings/cpp/src/container_impl.cpp
@@ -190,7 +190,7 @@ returned<connection> container::impl::connect(const std::string &urlstr, const c
     proton::url  url(urlstr);
     connection conn(reactor_.connection_to_host(url.host(), url.port(), chandler.get()));
     internal::pn_unique_ptr<connector> ctor(new connector(conn, opts, url));
-    connection_context& cc(connection_context::get(conn));
+    connection_context& cc(connection_context::get(unwrap(conn)));
     cc.handler.reset(ctor.release());
     cc.event_loop_ = new event_loop::impl;
 
@@ -344,7 +344,7 @@ void container::impl::configure_server_connection(connection &c) {
         pn_record_t *record = pn_connection_attachments(unwrap(c));
         pn_record_set_handler(record, chandler.get());
     }
-    connection_context::get(c).event_loop_ = new event_loop::impl;
+    connection_context::get(unwrap(c)).event_loop_ = new event_loop::impl;
 }
 
 void container::impl::run() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/contexts.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/contexts.cpp b/proton-c/bindings/cpp/src/contexts.cpp
index 231506f..8da8f7c 100644
--- a/proton-c/bindings/cpp/src/contexts.cpp
+++ b/proton-c/bindings/cpp/src/contexts.cpp
@@ -77,10 +77,6 @@ context::id connection_context::id(pn_connection_t* c) {
     return context::id(pn_connection_attachments(c), CONNECTION_CONTEXT);
 }
 
-context::id connection_context::id(const connection& c) {
-    return id(unwrap(c));
-}
-
 void container_context::set(const reactor& r, container& c) {
     set_context(pn_reactor_attachments(unwrap(r)), CONTAINER_CONTEXT, PN_VOID, &c);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/include/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp
index e80c434..742b346 100644
--- a/proton-c/bindings/cpp/src/include/contexts.hpp
+++ b/proton-c/bindings/cpp/src/include/contexts.hpp
@@ -96,11 +96,9 @@ class connection_context : public context {
     event_loop event_loop_;
 
     static connection_context& get(pn_connection_t *c) { return ref<connection_context>(id(c)); }
-    static connection_context& get(const connection& c) { return ref<connection_context>(id(c)); }
 
   protected:
     static context::id id(pn_connection_t*);
-    static context::id id(const connection& c);
 };
 
 void container_context(const reactor&, container&);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/io/connection_driver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp
index 148a00b..38e5bf2 100644
--- a/proton-c/bindings/cpp/src/io/connection_driver.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -51,14 +51,14 @@ connection_driver::connection_driver() : handler_(0), container_(0) { init(); }
 
 connection_driver::connection_driver(class container& cont) : handler_(0), container_(&cont) {
     init();
-    connection_context& ctx = connection_context::get(connection());
+    connection_context& ctx = connection_context::get(unwrap(connection()));
     ctx.container = container_;
 }
 
 #if PN_CPP_HAS_RVALUE_REFERENCES
 connection_driver::connection_driver(class container& cont, event_loop&& loop) : handler_(0), container_(&cont) {
     init();
-    connection_context& ctx = connection_context::get(connection());
+    connection_context& ctx = connection_context::get(unwrap(connection()));
     ctx.container = container_;
     ctx.event_loop_ = loop.impl_.get();
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/io/link_namer.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/link_namer.cpp b/proton-c/bindings/cpp/src/io/link_namer.cpp
index 307c423..28c35c7 100644
--- a/proton-c/bindings/cpp/src/io/link_namer.cpp
+++ b/proton-c/bindings/cpp/src/io/link_namer.cpp
@@ -18,13 +18,14 @@
  */
 
 #include "proton/io/link_namer.hpp"
+#include "proton_bits.hpp"
 #include "contexts.hpp"
 
 namespace proton {
 namespace io {
 
 void set_link_namer(connection& c, link_namer& l) {
-    connection_context::get(c).link_gen = &l;
+    connection_context::get(unwrap(c)).link_gen = &l;
 }
 
 }}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b9a57e8a/proton-c/bindings/cpp/src/session.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/session.cpp b/proton-c/bindings/cpp/src/session.cpp
index de152d6..8036d2c 100644
--- a/proton-c/bindings/cpp/src/session.cpp
+++ b/proton-c/bindings/cpp/src/session.cpp
@@ -59,7 +59,7 @@ connection session::connection() const {
 
 namespace {
 std::string next_link_name(const connection& c) {
-    io::link_namer* ln = connection_context::get(c).link_gen;
+    io::link_namer* ln = connection_context::get(unwrap(c)).link_gen;
 
     return ln ? ln->link_name() : uuid::random().str();
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[15/38] qpid-proton git commit: PROTON-1403: c proactor direct example

Posted by ac...@apache.org.
PROTON-1403: c proactor direct example

direct server that can accept a connection from the send or receive examples and act
as a directly-connected receive or send as appropriate.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6291a75c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6291a75c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6291a75c

Branch: refs/heads/go1
Commit: 6291a75cbed5840578c0d2577424ed574b8ee56f
Parents: 8568737
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Feb 14 12:06:43 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Feb 14 12:51:31 2017 -0500

----------------------------------------------------------------------
 examples/c/proactor/CMakeLists.txt |   2 +-
 examples/c/proactor/README.dox     |  14 +-
 examples/c/proactor/broker.c       |   3 +-
 examples/c/proactor/direct.c       | 357 ++++++++++++++++++++++++++++++++
 examples/c/proactor/receive.c      |   2 +-
 examples/c/proactor/test.py        |  29 ++-
 examples/exampletest.py            |   1 +
 7 files changed, 398 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index 7fec1c6..4189cf5 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -41,7 +41,7 @@ else(WIN32)
   set(PLATFORM_LIBS pthread)
 endif(WIN32)
 
-foreach(name broker send receive)
+foreach(name broker send receive direct)
   add_executable(proactor-${name} ${name}.c)
   target_link_libraries(proactor-${name} ${Proton_LIBRARIES} ${PLATFORM_LIBS})
   set_target_properties(proactor-${name} PROPERTIES OUTPUT_NAME ${name})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/c/proactor/README.dox
----------------------------------------------------------------------
diff --git a/examples/c/proactor/README.dox b/examples/c/proactor/README.dox
index 4b09cb7..19083e5 100644
--- a/examples/c/proactor/README.dox
+++ b/examples/c/proactor/README.dox
@@ -2,16 +2,22 @@
  * @example send.c
  *
  * Send a fixed number of messages to the "example" node.
+ * Can be used with @ref broker.c, @ref direct.c or an external AMQP broker.
  *
  * @example receive.c
  *
- * Subscribes to the 'example' node and prints the message bodies
- * received.
+ * Subscribes to the 'example' node and prints the message bodies received.
+ * Can be used with @ref broker.c, @ref direct.c or an external AMQP broker.
+ *
+ * @example direct.c
+ *
+ * A server that can be used to demonstrate direct (no broker) peer-to-peer communication
+ * It can accept an incoming connection from either the @ref send.c or @ref receive.c examples
+ * and will act as the directly-connected counterpart (receive or send)
  *
  * @example broker.c
  *
- * A simple multithreaded broker that works with the send and receive
- * examples.
+ * A simple multithreaded broker that works with the @ref send.c and @ref receive.c examples.
  *
  * __Requires C++11__
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index 5679290..ebf4068 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -307,7 +307,7 @@ static void handle(broker_t* b, pn_event_t* e) {
     pn_listener_accept(pn_event_listener(e), pn_connection());
     break;
 
-   case PN_CONNECTION_INIT: 
+   case PN_CONNECTION_INIT:
      pn_connection_set_container(c, b->container_id);
      break;
 
@@ -398,6 +398,7 @@ static void handle(broker_t* b, pn_event_t* e) {
 
    case PN_LISTENER_CLOSE:
     check_condition(e, pn_listener_condition(pn_event_listener(e)));
+    broker_stop(b);
     break;
 
    case PN_PROACTOR_INACTIVE: /* listener and all connections closed */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/c/proactor/direct.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/direct.c b/examples/c/proactor/direct.c
new file mode 100644
index 0000000..26f1b33
--- /dev/null
+++ b/examples/c/proactor/direct.c
@@ -0,0 +1,357 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/connection.h>
+#include <proton/connection_driver.h>
+#include <proton/delivery.h>
+#include <proton/proactor.h>
+#include <proton/link.h>
+#include <proton/message.h>
+#include <proton/sasl.h>
+#include <proton/session.h>
+#include <proton/transport.h>
+#include <proton/url.h>
+#include "pncompat/misc_funcs.inc"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef char str[1024];
+
+typedef struct app_data_t {
+  /* Common values */
+  pn_proactor_t *proactor;
+  bool finished;
+  str address;
+  str container_id;
+  pn_rwbytes_t message_buffer;
+  int message_count;
+
+  /* Sender values */
+  int sent;
+  int acknowledged;
+  pn_link_t *sender;
+  pn_millis_t delay;
+  bool delaying;
+
+  /* Receiver values */
+  int received;
+} app_data_t;
+
+static const int BATCH = 1000; /* Batch size for unlimited receive */
+
+int exit_code = 0;
+
+static void check_condition(pn_event_t *e, pn_condition_t *cond) {
+  if (pn_condition_is_set(cond)) {
+    exit_code = 1;
+    fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)),
+            pn_condition_get_name(cond), pn_condition_get_description(cond));
+  }
+}
+
+/* Create a message with a map { "sequence" : number } encode it and return the encoded buffer. */
+static pn_bytes_t encode_message(app_data_t* app) {
+  /* Construct a message with the map { "sequence": app.sent } */
+  pn_message_t* message = pn_message();
+  pn_data_put_int(pn_message_id(message), app->sent); /* Set the message_id also */
+  pn_data_t* body = pn_message_body(message);
+  pn_data_put_map(body);
+  pn_data_enter(body);
+  pn_data_put_string(body, pn_bytes(sizeof("sequence")-1, "sequence"));
+  pn_data_put_int(body, app->sent); /* The sequence number */
+  pn_data_exit(body);
+
+  /* encode the message, expanding the encode buffer as needed */
+  if (app->message_buffer.start == NULL) {
+    static const size_t initial_size = 128;
+    app->message_buffer = pn_rwbytes(initial_size, (char*)malloc(initial_size));
+  }
+  /* app->message_buffer is the total buffer space available. */
+  /* mbuf wil point at just the portion used by the encoded message */
+  pn_rwbytes_t mbuf = pn_rwbytes(app->message_buffer.size, app->message_buffer.start);
+  int status = 0;
+  while ((status = pn_message_encode(message, mbuf.start, &mbuf.size)) == PN_OVERFLOW) {
+    app->message_buffer.size *= 2;
+    app->message_buffer.start = (char*)realloc(app->message_buffer.start, app->message_buffer.size);
+    mbuf.size = app->message_buffer.size;
+  }
+  if (status != 0) {
+    fprintf(stderr, "error encoding message: %s\n", pn_error_text(pn_message_error(message)));
+    exit(1);
+  }
+  pn_message_free(message);
+  return pn_bytes(mbuf.size, mbuf.start);
+}
+
+static void send(app_data_t* app) {
+  while (pn_link_credit(app->sender) > 0 && app->sent < app->message_count) {
+    ++app->sent;
+    // Use sent counter bytes as unique delivery tag.
+    pn_delivery(app->sender, pn_dtag((const char *)&app->sent, sizeof(app->sent)));
+    pn_bytes_t msgbuf = encode_message(app);
+    pn_link_send(app->sender, msgbuf.start, msgbuf.size);
+    pn_link_advance(app->sender);
+    if (app->delay && app->sent < app->message_count) {
+      /* If delay is set, wait for TIMEOUT event to send more */
+      app->delaying = true;
+      pn_proactor_set_timeout(app->proactor, app->delay);
+      break;
+    }
+  }
+}
+
+#define MAX_SIZE 1024
+
+static void decode_message(pn_delivery_t *dlv) {
+  static char buffer[MAX_SIZE];
+  ssize_t len;
+  // try to decode the message body
+  if (pn_delivery_pending(dlv) < MAX_SIZE) {
+    // read in the raw data
+    len = pn_link_recv(pn_delivery_link(dlv), buffer, MAX_SIZE);
+    if (len > 0) {
+      // decode it into a proton message
+      pn_message_t *m = pn_message();
+      if (PN_OK == pn_message_decode(m, buffer, len)) {
+        pn_string_t *s = pn_string(NULL);
+        pn_inspect(pn_message_body(m), s);
+        printf("%s\n", pn_string_get(s));
+        pn_free(s);
+      }
+      pn_message_free(m);
+    }
+  }
+}
+
+/* This function handles events when we are acting as the receiver */
+static void handle_receive(app_data_t* app, pn_event_t* event) {
+  switch (pn_event_type(event)) {
+
+   case PN_LINK_REMOTE_OPEN: {
+     pn_link_t *l = pn_event_link(event);
+     pn_link_open(l);
+     pn_link_flow(l, app->message_count ? app->message_count : BATCH);
+   } break;
+
+   case PN_DELIVERY: {
+     /* A message has been received */
+     pn_link_t *link = NULL;
+     pn_delivery_t *dlv = pn_event_delivery(event);
+     if (pn_delivery_readable(dlv) && !pn_delivery_partial(dlv)) {
+       link = pn_delivery_link(dlv);
+       decode_message(dlv);
+       /* Accept the delivery */
+       pn_delivery_update(dlv, PN_ACCEPTED);
+       /* done with the delivery, move to the next and free it */
+       pn_link_advance(link);
+       pn_delivery_settle(dlv);  /* dlv is now freed */
+
+       if (app->message_count == 0) {
+         /* receive forever - see if more credit is needed */
+         if (pn_link_credit(link) < BATCH/2) {
+           /* Grant enough credit to bring it up to BATCH: */
+           pn_link_flow(link, BATCH - pn_link_credit(link));
+         }
+       } else if (++app->received >= app->message_count) {
+         /* done receiving, close the endpoints */
+         printf("%d messages received\n", app->received);
+         pn_session_t *ssn = pn_link_session(link);
+         pn_link_close(link);
+         pn_session_close(ssn);
+         pn_connection_close(pn_session_connection(ssn));
+       }
+     }
+   } break;
+
+   default:
+    break;
+  }
+}
+
+/* This function handles events when we are acting as the sender */
+static void handle_send(app_data_t* app, pn_event_t* event) {
+  switch (pn_event_type(event)) {
+
+   case PN_LINK_REMOTE_OPEN: {
+     pn_link_t* l = pn_event_link(event);
+     pn_terminus_set_address(pn_link_target(l), app->address);
+     pn_link_open(l);
+   } break;
+
+   case PN_LINK_FLOW:
+    /* The peer has given us some credit, now we can send messages */
+    if (!app->delaying) {
+      app->sender = pn_event_link(event);
+      send(app);
+    } break;
+
+   case PN_DELIVERY: {
+     /* We received acknowledgedment from the peer that a message was delivered. */
+     pn_delivery_t* d = pn_event_delivery(event);
+     if (pn_delivery_remote_state(d) == PN_ACCEPTED) {
+       if (++app->acknowledged == app->message_count) {
+         printf("%d messages sent and acknowledged\n", app->acknowledged);
+         pn_connection_close(pn_event_connection(event));
+       }
+     }
+   } break;
+
+   default:
+    break;
+  }
+}
+
+/* Handle all events, delegate to handle_send or handle_receive depending on link mode */
+static void handle(app_data_t* app, pn_event_t* event) {
+  switch (pn_event_type(event)) {
+
+   case PN_LISTENER_ACCEPT:
+    pn_listener_accept(pn_event_listener(event), pn_connection());
+    break;
+
+   case PN_CONNECTION_INIT:
+    pn_connection_set_container(pn_event_connection(event), app->container_id);
+    break;
+
+   case PN_CONNECTION_BOUND: {
+     /* Turn off security */
+     pn_transport_t *t = pn_event_transport(event);
+     pn_transport_require_auth(t, false);
+     pn_sasl_allowed_mechs(pn_sasl(t), "ANONYMOUS");
+   }
+   case PN_CONNECTION_REMOTE_OPEN: {
+     pn_connection_open(pn_event_connection(event)); /* Complete the open */
+     break;
+   }
+
+   case PN_SESSION_REMOTE_OPEN: {
+     pn_session_open(pn_event_session(event));
+     break;
+   }
+
+   case PN_TRANSPORT_CLOSED:
+    check_condition(event, pn_transport_condition(pn_event_transport(event)));
+    app->finished = true;
+    break;
+
+   case PN_CONNECTION_REMOTE_CLOSE:
+    check_condition(event, pn_connection_remote_condition(pn_event_connection(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_SESSION_REMOTE_CLOSE:
+    check_condition(event, pn_session_remote_condition(pn_event_session(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_LINK_REMOTE_CLOSE:
+   case PN_LINK_REMOTE_DETACH:
+    check_condition(event, pn_link_remote_condition(pn_event_link(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_PROACTOR_TIMEOUT:
+    /* Wake the sender's connection */
+    pn_connection_wake(pn_session_connection(pn_link_session(app->sender)));
+    break;
+
+   case PN_CONNECTION_WAKE:
+    /* Timeout, we can send more. */
+    app->delaying = false;
+    send(app);
+    break;
+
+   case PN_PROACTOR_INACTIVE:
+    app->finished = true;
+    break;
+
+   case PN_LISTENER_CLOSE:
+    check_condition(event, pn_listener_condition(pn_event_listener(event)));
+    app->finished = true;
+    break;
+
+   default: {
+     pn_link_t *l = pn_event_link(event);
+     if (l) {                      /* Only delegate link-related events */
+       if (pn_link_is_sender(l)) {
+         handle_send(app, event);
+       } else {
+         handle_receive(app, event);
+       }
+     }
+   }
+  }
+}
+
+static void usage(const char *arg0) {
+  fprintf(stderr, "Usage: %s [-a URL] [-m message-count] [-d delay-ms]\n", arg0);
+  fprintf(stderr, "Demonstrates direct peer-to-peer AMQP communication without a broker. Accepts a connection from either the send.c or receive.c client and provides the complementary behavior (receive or send.");
+  exit(1);
+}
+
+int main(int argc, char **argv) {
+  /* Default values for application and connection. */
+  app_data_t app = {0};
+  app.message_count = 100;
+  const char* urlstr = NULL;
+
+  int opt;
+  while((opt = getopt(argc, argv, "a:m:d:")) != -1) {
+    switch(opt) {
+     case 'a': urlstr = optarg; break;
+     case 'm': app.message_count = atoi(optarg); break;
+     case 'd': app.delay = atoi(optarg); break;
+     default: usage(argv[0]); break;
+    }
+  }
+  if (optind < argc)
+    usage(argv[0]);
+  /* Note container-id should be unique */
+  snprintf(app.container_id, sizeof(app.container_id), "%s", argv[0]);
+
+  /* Parse the URL or use default values */
+  pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
+  /* Listen on IPv6 wildcard. On systems that do not set IPV6ONLY by default,
+     this will also listen for mapped IPv4 on the same port.
+  */
+  const char *host = url ? pn_url_get_host(url) : "::";
+  const char *port = url ? pn_url_get_port(url) : "amqp";
+
+  app.proactor = pn_proactor();
+  pn_proactor_listen(app.proactor, pn_listener(), host, port, 16);
+  printf("listening on '%s:%s'\n", host, port);
+  if (url) pn_url_free(url);
+
+  do {
+    pn_event_batch_t *events = pn_proactor_wait(app.proactor);
+    pn_event_t *e;
+    while ((e = pn_event_batch_next(events))) {
+      handle(&app, e);
+    }
+    pn_proactor_done(app.proactor, events);
+  } while(!app.finished);
+
+  pn_proactor_free(app.proactor);
+  free(app.message_buffer.start);
+  return exit_code;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index 1eb54b6..1bc5509 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -46,7 +46,7 @@ typedef struct app_data_t {
   bool finished;
 } app_data_t;
 
-static const int BATCH = 100; /* Batch size for unlimited receive */
+static const int BATCH = 1000; /* Batch size for unlimited receive */
 
 static int exit_code = 0;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/c/proactor/test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/test.py b/examples/c/proactor/test.py
index 29aa327..45bb817 100644
--- a/examples/c/proactor/test.py
+++ b/examples/c/proactor/test.py
@@ -19,11 +19,9 @@
 
 # This is a test script to run the examples and verify that they behave as expected.
 
+import unittest, sys, time
 from exampletest import *
 
-import unittest
-import sys
-
 def python_cmd(name):
     dir = os.path.dirname(__file__)
     return [sys.executable, os.path.join(dir, "..", "..", "python", name)]
@@ -55,6 +53,31 @@ class CExampleTest(BrokerTestCase):
         r = self.proc(["receive", "-a", self.addr, "-m3"])
         self.assertEqual(receive_expect(3), r.wait_out())
 
+    def retry(self, args, max=10):
+        """Run until output does not contain "connection refused", up to max retries"""
+        while True:
+            try:
+                return self.proc(args).wait_out()
+            except ProcError, e:
+                if "connection refused" in e.args[0] and max > 0:
+                    max -= 1
+                    time.sleep(.01)
+                    continue
+                raise
+
+    def test_send_direct(self):
+        """Send first then receive"""
+        addr = "127.0.0.1:%s/examples" % (pick_port())
+        d = self.proc(["direct", "-a", addr])
+        self.assertEqual("100 messages sent and acknowledged\n", self.retry(["send", "-a", addr]))
+        self.assertIn(receive_expect(100), d.wait_out())
+
+    def test_receive_direct(self):
+        """Send first then receive"""
+        addr = "127.0.0.1:%s/examples" % (pick_port())
+        d = self.proc(["direct", "-a", addr])
+        self.assertEqual(receive_expect(100), self.retry(["receive", "-a", addr]))
+        self.assertIn("100 messages sent and acknowledged\n", d.wait_out())
 
 if __name__ == "__main__":
     unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6291a75c/examples/exampletest.py
----------------------------------------------------------------------
diff --git a/examples/exampletest.py b/examples/exampletest.py
index d40b9cb..bf7ea9b 100644
--- a/examples/exampletest.py
+++ b/examples/exampletest.py
@@ -65,6 +65,7 @@ class Proc(Popen):
         """Start an example process"""
         args = list(args)
         self.args = args
+        self.kwargs = kwargs
         self._out = os.tmpfile()
         try:
             Popen.__init__(self, self.env_args + self.args, stdout=self._out, stderr=STDOUT, **kwargs)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[18/38] qpid-proton git commit: PROTON-1359: Make sure we don't try and read past the end of buffer - For ARRAY32, LIST32 & MAP32 types

Posted by ac...@apache.org.
PROTON-1359: Make sure we don't try and read past the end of buffer
- For ARRAY32, LIST32 & MAP32 types


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/cd612ffe
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/cd612ffe
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/cd612ffe

Branch: refs/heads/go1
Commit: cd612ffecc0b41a0765ffbb48dd6bd4467ff4879
Parents: 7560f58
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Feb 16 04:44:27 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Feb 16 04:44:27 2017 -0500

----------------------------------------------------------------------
 proton-c/src/core/decoder.c | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/cd612ffe/proton-c/src/core/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.c b/proton-c/src/core/decoder.c
index b0c8d79..fc01767 100644
--- a/proton-c/src/core/decoder.c
+++ b/proton-c/src/core/decoder.c
@@ -373,6 +373,7 @@ static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint
     case PNE_ARRAY32:
     case PNE_LIST32:
     case PNE_MAP32:
+      if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
       size = pn_decoder_readf32(decoder);
       count = pn_decoder_readf32(decoder);
       break;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[27/38] qpid-proton git commit: PROTON-1403: Add missing qpid-proton-proactor library configuration

Posted by ac...@apache.org.
PROTON-1403: Add missing qpid-proton-proactor library configuration


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d5c0152a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d5c0152a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d5c0152a

Branch: refs/heads/go1
Commit: d5c0152a71ea889c4f3688b78dd323e705796c83
Parents: 6a2316a
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 17 14:24:59 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Feb 17 15:14:06 2017 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt            | 24 +++++++++++++-----------
 proton-c/src/ProtonConfig.cmake.in |  3 +++
 2 files changed, 16 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d5c0152a/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 68ccc2c..60e739d 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -576,8 +576,18 @@ if (MSVC)
   include(WindowsC99CheckDef)
 endif(MSVC)
 
+if (qpid-proton-proactor)
+  set(HAS_PROACTOR 1)
+  add_library (
+    qpid-proton-proactor SHARED
+    ${qpid-proton-proactor}
+    )
+  target_link_libraries (qpid-proton-proactor qpid-proton-core ${PROACTOR_LIBS})
+  list(APPEND LIB_TARGETS qpid-proton-proactor)
+endif()
+
 # Install executables and libraries
-install (TARGETS qpid-proton qpid-proton-core
+install(TARGETS qpid-proton qpid-proton-core ${LIB_TARGETS}
   EXPORT  proton
   RUNTIME DESTINATION bin
   ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
@@ -616,17 +626,9 @@ endmacro()
 
 configure_lib(PROTONLIB qpid-proton)
 configure_lib(PROTONCORELIB qpid-proton-core)
-
-if (qpid-proton-proactor)
-  set(HAS_PROACTOR 1)
-  add_library (
-    qpid-proton-proactor SHARED
-    ${qpid-proton-proactor}
-    )
-  target_link_libraries (qpid-proton-proactor qpid-proton-core ${PROACTOR_LIBS})
+if(HAS_PROACTOR)
   configure_lib(PROTONPROACTORLIB qpid-proton-proactor)
-endif()
-
+endif(HAS_PROACTOR)
 
 include(WriteBasicConfigVersionFile)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d5c0152a/proton-c/src/ProtonConfig.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/ProtonConfig.cmake.in b/proton-c/src/ProtonConfig.cmake.in
index 5e50d7c..6d884f4 100644
--- a/proton-c/src/ProtonConfig.cmake.in
+++ b/proton-c/src/ProtonConfig.cmake.in
@@ -30,4 +30,7 @@ set (Proton_LIBRARIES     optimized @LIBDIR@/@PROTONLIB@ debug @LIBDIR@/@PROTONL
 set (ProtonCore_INCLUDE_DIRS  @INCLUDEDIR@)
 set (ProtonCore_LIBRARIES     optimized @LIBDIR@/@PROTONCORELIB@ debug @LIBDIR@/@PROTONCORELIBDEBUG@)
 
+set (ProtonProactor_INCLUDE_DIRS  @INCLUDEDIR@)
+set (ProtonProactor_LIBRARIES     optimized @LIBDIR@/@PROTONPROACTORLIB@ debug @LIBDIR@/@PROTONPROACTORLIBDEBUG@)
+
 set (Proton_FOUND True)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[20/38] qpid-proton git commit: NO-JIRA: go binding build results in binary dir, not source dir

Posted by ac...@apache.org.
NO-JIRA: go binding build results in binary dir, not source dir

Avoid polluting source directory and avoid races when multiple builds are done
in parallel from the same source.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9bd99ebf
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9bd99ebf
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9bd99ebf

Branch: refs/heads/go1
Commit: 9bd99ebf096ed83bd23ae05fe9cc0e6f65d9ac2e
Parents: ce6626b
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 16 00:44:52 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 16 16:52:44 2017 -0500

----------------------------------------------------------------------
 .gitignore                          |  7 -------
 examples/go/CMakeLists.txt          |  8 +++-----
 proton-c/bindings/go/CMakeLists.txt | 17 ++++++++---------
 3 files changed, 11 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9bd99ebf/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index aa9bc36..b769990 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,16 +31,9 @@ eclipse-classes
 # The usual location for proton-c build files
 proton-c/build
 
-# Executables built by go binding tests
-proton-c/bindings/go/bin
-
 # Testresults from the jenkins build script
 testresults
 
-# Go binding build output
-/proton-c/bindings/go/pkg
-/proton-c/bindings/go/bin
-
 # Python TOX test build output
 /proton-c/bindings/python/MANIFEST
 /proton-c/bindings/python/build

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9bd99ebf/examples/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/go/CMakeLists.txt b/examples/go/CMakeLists.txt
index c9aba01..861cdd8 100644
--- a/examples/go/CMakeLists.txt
+++ b/examples/go/CMakeLists.txt
@@ -20,12 +20,11 @@
 if(BUILD_GO)
 
   set(examples electron/broker electron/receive electron/send proton/broker)
-  file(GLOB_RECURSE example_source FOLLOW_SYMLINKS ${CMAKE_CURRENT_SOURCE_DIR}/*.go)
 
   # Build example exes
   foreach(example ${examples})
-    string(REPLACE / _ target ${example})
-    set(target "go_example_${target}")
+    string(REPLACE / - target ${example})
+    set(target "go-example-${target}")
     set(output ${CMAKE_CURRENT_BINARY_DIR}/${example})
     # Always run go_build, it will do nothing if there is nothing to do.
     # Otherwise it's too hard to get the dependencies right.
@@ -33,12 +32,11 @@ if(BUILD_GO)
       COMMAND ${GO_BUILD} ${GO_EXAMPLE_FLAGS} -o ${output} ${CMAKE_CURRENT_SOURCE_DIR}/${example}.go
       WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
       DEPENDS go-build)
-    list(APPEND example_targets ${target})
   endforeach()
 
   # Build test driver exe
   set(test_exe ${CMAKE_CURRENT_BINARY_DIR}/example_test)
-  add_custom_target(go_example_test ALL
+  add_custom_target(go-example-test ALL
     COMMAND ${GO_TEST} -c -o ${test_exe} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.go
     WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9bd99ebf/proton-c/bindings/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/CMakeLists.txt b/proton-c/bindings/go/CMakeLists.txt
index d0ffe9b..1cb9d6c 100644
--- a/proton-c/bindings/go/CMakeLists.txt
+++ b/proton-c/bindings/go/CMakeLists.txt
@@ -26,7 +26,6 @@ set(GO_TEST_FLAGS "-v" CACHE STRING "Flags for 'go test'")
 
 # Flags that differ for golang go and gcc go.
 if (go_ver MATCHES "gccgo")
-  # TODO aconway 2015-10-08: import cycles with -race under gccgo, investigate.
   set(GO_RPATH_FLAGS -gccgoflags "-Wl,-rpath=${CMAKE_BINARY_DIR}/proton-c")
 else()
   set(GO_RPATH_FLAGS -ldflags "-r ${CMAKE_BINARY_DIR}/proton-c")
@@ -37,7 +36,7 @@ separate_arguments(GO_TEST_FLAGS)
 
 # Following are CACHE INTERNAL so examples/CMakeLists.txt can see them.
 set(GO_ENV ${env_py} --
-  "GOPATH=${CMAKE_CURRENT_SOURCE_DIR}"
+  "GOPATH=${CMAKE_CURRENT_BINARY_DIR}"
   "CGO_CFLAGS=-I${CMAKE_SOURCE_DIR}/proton-c/include -I${CMAKE_BINARY_DIR}/proton-c/include"
   "CGO_LDFLAGS=-L${CMAKE_BINARY_DIR}/proton-c"
   "PN_INTEROP_DIR=${CMAKE_SOURCE_DIR}/tests/interop"
@@ -47,15 +46,15 @@ set(GO ${GO_ENV} ${GO_EXE} CACHE INTERNAL "Run go with environment set")
 
 set(GO_BUILD ${GO} build ${GO_BUILD_FLAGS} ${GO_RPATH_FLAGS} CACHE INTERNAL "Run go build")
 set(GO_INSTALL ${GO} install ${GO_BUILD_FLAGS} CACHE INTERNAL "Run go install" )
-set(GO_TEST ${GO} test ${GO_BUILD_FLAGS} ${GO_RPATH_FLAGS} ${GO_TEST_FLAGS} CACHE INTERNAL "Run go test")
+set(GO_TEST ${GO} test ${GO_TEST_FLAGS} ${GO_RPATH_FLAGS} CACHE INTERNAL "Run go test")
 
-# Go tools insist on standard Go layout which puts compiled code in the source tree :(
-# Build output is all under git-ignored pkg or bin subdirectories, they are removed by make clean.
-
-# The go build tools handle dependency checks and incremental builds better than
-# CMake so just run them every time, they do nothing if nothing needs to be
-# done.
+# The go build tools handle dependency checks and incremental builds better than CMake so
+# just run them every time, they do nothing if nothing needs to be done.
+#
+# The Go sources are copied to the binary directory so we can respect the standard Go tree
+# layout without polluting the source tree.
 add_custom_target(go-build ALL
+  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src
   COMMAND ${GO_INSTALL} qpid.apache.org/...
   DEPENDS qpid-proton-core
   WORKING_DIRECTORY $ENV{PWD})


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[09/38] qpid-proton git commit: c proactor: improved robustness and testing

Posted by ac...@apache.org.
c proactor: improved robustness and testing

Added assert self-tests to the libuv.c proactor. The assertions are kept in a
release build to fail fast and aid debugging.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/ec70d73d
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/ec70d73d
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/ec70d73d

Branch: refs/heads/go1
Commit: ec70d73dd5e5b58eaf64f5e137104fd9d4042e70
Parents: afacb16
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 10 21:44:25 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Feb 10 21:49:59 2017 -0500

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c | 557 ++++++++++++++++++++-----------------
 1 file changed, 306 insertions(+), 251 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec70d73d/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 42bbfab..6064bd6 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -30,7 +30,10 @@
 #include <proton/transport.h>
 #include <proton/url.h>
 
+/* All asserts are cheap and should remain in a release build for debugability */
+#undef NDEBUG
 #include <assert.h>
+
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -58,12 +61,10 @@
   wake-up to be processed in a single thread with no context switches.
 
   Function naming:
-  - on_ - called in leader thread via uv_run().
-  - leader_ - called in leader thread, while processing the leader_q.
-  - owner_ - called in owning thread, leader or worker but not concurrently.
-
-  Note on_ and leader_ functions can call each other, the prefix indicates the
-  path they are most often called on.
+  - on_* - called in leader thread by uv_run().
+  - leader_* - called in leader thread (either leader_q processing or from an on_ function)
+  - worker_* - called in worker thread
+  - *_lh - called with the relevant lock held
 */
 
 const char *COND_NAME = "proactor";
@@ -80,6 +81,13 @@ PN_HANDLE(PN_PROACTOR)
 PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
 PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
 
+/* A psocket (connection or listener) has the following *mutually exclusive* states. */
+typedef enum {
+  ON_WORKER,               /* On worker_q or in use by user code in worker thread  */
+  ON_LEADER,               /* On leader_q or in use the leader loop  */
+  ON_UV                    /* Scheduled for a UV event, or in use by leader thread in on_ handler*/
+} psocket_state_t;
+
 /* common to connection and listener */
 typedef struct psocket_t {
   /* Immutable */
@@ -87,14 +95,16 @@ typedef struct psocket_t {
 
   /* Protected by proactor.lock */
   struct psocket_t* next;
-  void (*wakeup)(struct psocket_t*); /* interrupting action for leader */
+  psocket_state_t state;
+  void (*action)(struct psocket_t*); /* deferred action for leader */
+  void (*wakeup)(struct psocket_t*); /* wakeup action for leader */
 
-  /* Only used by leader */
+  /* Only used by leader when it owns the psocket */
   uv_tcp_t tcp;
-  void (*action)(struct psocket_t*); /* deferred action for leader */
-  bool is_conn:1;
   char host[NI_MAXHOST];
   char port[NI_MAXSERV];
+  bool is_conn;
+
 } psocket_t;
 
 /* Special value for psocket.next pointer when socket is not on any any list. */
@@ -105,11 +115,12 @@ static void psocket_init(psocket_t* ps, pn_proactor_t* p, bool is_conn, const ch
   ps->next = &UNLISTED;
   ps->is_conn = is_conn;
   ps->tcp.data = ps;
+  ps->state = ON_WORKER;
 
   /* For platforms that don't know about "amqp" and "amqps" service names. */
-  if (strcmp(port, AMQP_PORT_NAME) == 0)
+  if (port && strcmp(port, AMQP_PORT_NAME) == 0)
     port = AMQP_PORT;
-  else if (strcmp(port, AMQPS_PORT_NAME) == 0)
+  else if (port && strcmp(port, AMQPS_PORT_NAME) == 0)
     port = AMQPS_PORT;
   /* Set to "\001" to indicate a NULL as opposed to an empty string "" */
   strncpy(ps->host, host ? host : "\001", sizeof(ps->host));
@@ -132,24 +143,27 @@ typedef struct pconnection_t {
   uv_timer_t timer;
   uv_write_t write;
   uv_shutdown_t shutdown;
-  size_t writing;
-  bool reading:1;
-  bool server:1;                /* accept, not connect */
+  size_t writing;               /* size of pending write request, 0 if none pending */
+  bool reading;                 /* true if a read request is pending */
+  bool server;                  /* accept, not connect */
 } pconnection_t;
 
 struct pn_listener_t {
   psocket_t psocket;
 
   /* Only used by owner thread */
-  pconnection_t *accepting;     /* accept in progress */
+  pconnection_t *accepting;     /* set in worker, used in UV loop for accept */
   pn_condition_t *condition;
   pn_collector_t *collector;
   pn_event_batch_t batch;
   pn_record_t *attachments;
   void *context;
   size_t backlog;
-};
+  bool closing;                 /* close requested or closed by error */
 
+  /* Only used in leader thread */
+  size_t connections;           /* number of connections waiting to be accepted  */
+};
 
 typedef struct queue { psocket_t *front, *back; } queue;
 
@@ -166,17 +180,16 @@ struct pn_proactor_t {
 
   /* Protected by lock */
   uv_mutex_t lock;
-  queue start_q;
-  queue worker_q;
-  queue leader_q;
+  queue worker_q;               /* psockets ready for work, to be returned via pn_proactor_wait()  */
+  queue leader_q;               /* psockets waiting for attention by the leader thread */
   size_t interrupt;             /* pending interrupts */
   pn_millis_t timeout;
   size_t count;                 /* psocket count */
-  bool inactive:1;
-  bool timeout_request:1;
-  bool timeout_elapsed:1;
-  bool has_leader:1;
-  bool batch_working:1;          /* batch belongs to a worker.  */
+  bool inactive;
+  bool timeout_request;
+  bool timeout_elapsed;
+  bool has_leader;
+  bool batch_working;          /* batch is being processed in a worker thread */
 };
 
 static bool push_lh(queue *q, psocket_t *ps) {
@@ -201,90 +214,46 @@ static psocket_t* pop_lh(queue *q) {
   return ps;
 }
 
-static inline pconnection_t *as_pconnection_t(psocket_t* ps) {
-  return ps->is_conn ? (pconnection_t*)ps : NULL;
-}
-
-static inline pn_listener_t *as_listener(psocket_t* ps) {
-  return ps->is_conn ? NULL: (pn_listener_t*)ps;
-}
-
-/* Put ps on the leader queue for processing. Thread safe. */
-static void to_leader_lh(psocket_t *ps) {
-  push_lh(&ps->proactor->leader_q, ps);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
-}
-
-static void to_leader(psocket_t *ps) {
-  uv_mutex_lock(&ps->proactor->lock);
-  to_leader_lh(ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-/* Detach from IO and put ps on the worker queue */
-static void leader_to_worker(psocket_t *ps) {
-  if (ps->is_conn) {
-    pconnection_t *pc = as_pconnection_t(ps);
-    /* Don't detach if there are no events yet. */
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      if (pc->writing) {
-        pc->writing  = 0;
-        uv_cancel((uv_req_t*)&pc->write);
-      }
-      if (pc->reading) {
-        pc->reading = false;
-        uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
-      }
-      if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
-        uv_timer_stop(&pc->timer);
-      }
-    }
-  } else {
-    pn_listener_t *l = as_listener(ps);
-    uv_read_stop((uv_stream_t*)&l->psocket.tcp);
-  }
-  uv_mutex_lock(&ps->proactor->lock);
-  push_lh(&ps->proactor->worker_q, ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-/* Set a deferred action for leader, if not already set. */
-static void owner_to_leader(psocket_t *ps, void (*action)(psocket_t*)) {
-  uv_mutex_lock(&ps->proactor->lock);
-  if (!ps->action) {
+/* Set state and action and push to relevant queue */
+static inline void set_state_lh(psocket_t *ps, psocket_state_t state, void (*action)(psocket_t*)) {
+  /* Illegal if ps is already listed under a different state */
+  assert(ps->next == &UNLISTED || ps->state == state);
+  ps->state = state;
+  if (action && !ps->action) {
     ps->action = action;
   }
-  to_leader_lh(ps);
-  uv_mutex_unlock(&ps->proactor->lock);
+  switch(state) {
+   case ON_LEADER: push_lh(&ps->proactor->leader_q, ps); break;
+   case ON_WORKER: push_lh(&ps->proactor->worker_q, ps); break;
+   case ON_UV:
+    assert(ps->next == &UNLISTED);
+    break;           /* No queue for UV loop */
+  }
 }
 
-/* Owner thread send to worker thread. Set deferred action if not already set. */
-static void owner_to_worker(psocket_t *ps, void (*action)(psocket_t*)) {
+/* Set state and action, push to queue and notify leader. Thread safe. */
+static void set_state(psocket_t *ps, psocket_state_t state, void (*action)(psocket_t*)) {
   uv_mutex_lock(&ps->proactor->lock);
-  if (!ps->action) {
-    ps->action = action;
-  }
-  push_lh(&ps->proactor->worker_q, ps);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
+  set_state_lh(ps, state, action);
+  uv_async_send(&ps->proactor->async);
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
+static inline pconnection_t *as_pconnection(psocket_t* ps) {
+  return ps->is_conn ? (pconnection_t*)ps : NULL;
+}
 
-/* Re-queue for further work */
-static void worker_requeue(psocket_t* ps) {
-  uv_mutex_lock(&ps->proactor->lock);
-  push_lh(&ps->proactor->worker_q, ps);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
-  uv_mutex_unlock(&ps->proactor->lock);
+static inline pn_listener_t *as_listener(psocket_t* ps) {
+  return ps->is_conn ? NULL: (pn_listener_t*)ps;
 }
 
-static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
+static pconnection_t *new_pconnection(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
   pconnection_t *pc = (pconnection_t*)calloc(1, sizeof(*pc));
-  if (!pc) return NULL;
-  if (pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
+  if (!pc || pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
     return NULL;
   }
   psocket_init(&pc->psocket, p,  true, host, port);
+  pc->write.data = &pc->psocket;
   if (server) {
     pn_transport_set_server(pc->driver.transport);
   }
@@ -319,74 +288,49 @@ static void leader_count(pn_proactor_t *p, int change) {
   uv_mutex_unlock(&p->lock);
 }
 
-/* Free if there are no uv callbacks pending and no events */
-static void leader_pconnection_t_maybe_free(pconnection_t *pc) {
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      leader_to_worker(&pc->psocket);         /* Return to worker */
-    } else if (!(pc->psocket.tcp.data || pc->write.data || pc->shutdown.data || pc->timer.data)) {
-      /* All UV requests are finished */
-      pn_connection_driver_destroy(&pc->driver);
-      leader_count(pc->psocket.proactor, -1);
-      free(pc);
-    }
+/* Final close event for a a pconnection_t */
+static void on_close_pconnection_final(uv_handle_t *h) {
+  pconnection_t *pc = (pconnection_t*)h->data;
+  free(pc);
 }
 
-/* Free if there are no uv callbacks pending and no events */
-static void leader_listener_maybe_free(pn_listener_t *l) {
-    if (pn_collector_peek(l->collector)) {
-      leader_to_worker(&l->psocket);         /* Return to worker */
-    } else if (!l->psocket.tcp.data) {
-      pn_condition_free(l->condition);
-      leader_count(l->psocket.proactor, -1);
-      free(l);
-    }
-}
-
-/* Free if there are no uv callbacks pending and no events */
-static void leader_maybe_free(psocket_t *ps) {
-  if (ps->is_conn) {
-    leader_pconnection_t_maybe_free(as_pconnection_t(ps));
-  } else {
-    leader_listener_maybe_free(as_listener(ps));
-  }
+/* Close event for uv_tcp_t of a pconnection_t */
+static void on_close_pconnection(uv_handle_t *h) {
+  pconnection_t *pc = (pconnection_t*)h->data;
+  assert(pc->psocket.state == ON_UV);
+  leader_count(pc->psocket.proactor, -1);
+  pn_connection_driver_destroy(&pc->driver);
+  uv_timer_stop(&pc->timer);
+  /* Close the timer with the final event to free the pconnection_t */
+  uv_close((uv_handle_t*)&pc->timer, on_close_pconnection_final);
 }
 
-static void on_close(uv_handle_t *h) {
-  psocket_t *ps = (psocket_t*)h->data;
-  h->data = NULL;               /* Mark closed */
-  leader_maybe_free(ps);
+/* Close event for uv_tcp_t of a pn_listener_t */
+static void on_close_listener(uv_handle_t *h) {
+  pn_listener_t *l = (pn_listener_t*)h->data;
+  pn_condition_free(l->condition);
+  free(l);
 }
 
-static void on_shutdown(uv_shutdown_t *shutdown, int err) {
-  psocket_t *ps = (psocket_t*)shutdown->data;
-  shutdown->data = NULL;        /* Mark closed */
-  leader_maybe_free(ps);
+static inline void leader_finished(psocket_t *ps) {
+  set_state(ps, ON_UV, NULL);
+  uv_close((uv_handle_t*)&ps->tcp, ps->is_conn ? on_close_pconnection : on_close_listener);
 }
 
-static inline void leader_close(psocket_t *ps) {
-  if (ps->tcp.data && !uv_is_closing((uv_handle_t*)&ps->tcp)) {
-    uv_close((uv_handle_t*)&ps->tcp, on_close);
-  }
-  pconnection_t *pc = as_pconnection_t(ps);
-  if (pc) {
-    pn_connection_driver_close(&pc->driver);
-    if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
-      uv_timer_stop(&pc->timer);
-      uv_close((uv_handle_t*)&pc->timer, on_close);
-    }
+static pconnection_t *get_pconnection(pn_connection_t* c) {
+  if (!c) {
+    return NULL;
   }
-  leader_maybe_free(ps);
-}
-
-static pconnection_t *get_pconnection_t(pn_connection_t* c) {
-  if (!c) return NULL;
   pn_record_t *r = pn_connection_attachments(c);
   return (pconnection_t*) pn_record_get(r, PN_PROACTOR);
 }
 
+static void leader_unwatch(psocket_t *ps);
+
 static void leader_error(psocket_t *ps, int err, const char* what) {
+  assert(ps->state != ON_WORKER);
   if (ps->is_conn) {
-    pn_connection_driver_t *driver = &as_pconnection_t(ps)->driver;
+    pn_connection_driver_t *driver = &as_pconnection(ps)->driver;
     pn_connection_driver_bind(driver); /* Bind so errors will be reported */
     pn_connection_driver_errorf(driver, COND_NAME, "%s %s:%s: %s",
                                 what, fixstr(ps->host), fixstr(ps->port),
@@ -398,16 +342,18 @@ static void leader_error(psocket_t *ps, int err, const char* what) {
                         what, fixstr(ps->host), fixstr(ps->port),
                         uv_strerror(err));
     pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
+    l->closing = true;
   }
-  leader_to_worker(ps);               /* Worker to handle the error */
+  leader_unwatch(ps);               /* Worker to handle the error */
 }
 
 /* uv-initialization */
 static int leader_init(psocket_t *ps) {
+  ps->state = ON_LEADER;
   leader_count(ps->proactor, +1);
   int err = uv_tcp_init(&ps->proactor->loop, &ps->tcp);
   if (!err) {
-    pconnection_t *pc = as_pconnection_t(ps);
+    pconnection_t *pc = as_pconnection(ps);
     if (pc) {
       pc->connect.data = ps;
       int err = uv_timer_init(&ps->proactor->loop, &pc->timer);
@@ -422,40 +368,53 @@ static int leader_init(psocket_t *ps) {
   return err;
 }
 
-/* Common logic for on_connect and on_accept */
-static void leader_connect_accept(pconnection_t *pc, int err, const char *what) {
+/* Outgoing connection */
+static void on_connect(uv_connect_t *connect, int err) {
+  pconnection_t *pc = (pconnection_t*)connect->data;
+  assert(pc->psocket.state == ON_UV);
   if (!err) {
-    leader_to_worker(&pc->psocket);
+    leader_unwatch(&pc->psocket);
   } else {
-    leader_error(&pc->psocket, err, what);
+    leader_error(&pc->psocket, err, "on connect to");
   }
 }
 
-static void on_connect(uv_connect_t *connect, int err) {
-  leader_connect_accept((pconnection_t*)connect->data, err, "on connect");
-}
-
-static void on_accept(uv_stream_t* server, int err) {
+/* Incoming connection ready to be accepted */
+static void on_connection(uv_stream_t* server, int err) {
+  /* Unlike most on_* functions, this one can be called by the leader thrad when the
+   * listener is ON_WORKER, because there's no way to stop libuv from calling
+   * on_connection() in leader_unwatch().  Just increase a counter and deal with it in the
+   * worker thread.
+   */
   pn_listener_t *l = (pn_listener_t*) server->data;
-  if (err) {
-    leader_error(&l->psocket, err, "on accept");
+  assert(l->psocket.state == ON_UV);
+  if (!err) {
+    ++l->connections;
+    leader_unwatch(&l->psocket);
+  } else {
+    leader_error(&l->psocket, err, "on incoming connection from");
   }
-  pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
-  leader_to_worker(&l->psocket); /* Let user call pn_listener_accept */
 }
 
-static void leader_accept(psocket_t *ps) {
-  pn_listener_t * l = as_listener(ps);
+static void leader_accept(pn_listener_t * l) {
+  assert(l->psocket.state == ON_UV);
+  assert(l->accepting);
   pconnection_t *pc = l->accepting;
   l->accepting = NULL;
-  if (pc) {
-    int err = leader_init(&pc->psocket);
-    if (!err) err = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
-    leader_connect_accept(pc, err, "on accept");
+  int err = leader_init(&pc->psocket);
+  if (!err) {
+    err = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
+  }
+  if (!err) {
+    leader_unwatch(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, err, "accepting from");
+    leader_error(&l->psocket, err, "accepting from");
   }
 }
 
 static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
+  assert(ps->state == ON_LEADER);
   int err = leader_init(ps);
   struct addrinfo hints = { 0 };
   if (server) hints.ai_flags = AI_PASSIVE;
@@ -466,55 +425,75 @@ static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
 }
 
 static void leader_connect(psocket_t *ps) {
-  pconnection_t *pc = as_pconnection_t(ps);
+  assert(ps->state == ON_LEADER);
+  pconnection_t *pc = as_pconnection(ps);
   uv_getaddrinfo_t info;
   int err = leader_resolve(ps, &info, false);
   if (!err) {
     err = uv_tcp_connect(&pc->connect, &pc->psocket.tcp, info.addrinfo->ai_addr, on_connect);
     uv_freeaddrinfo(info.addrinfo);
   }
-  if (err) {
-    leader_error(ps, err, "connect to");
+  if (!err) {
+    ps->state = ON_UV;
+  } else {
+    leader_error(ps, err, "connecting to");
   }
 }
 
 static void leader_listen(psocket_t *ps) {
+  assert(ps->state == ON_LEADER);
   pn_listener_t *l = as_listener(ps);
-   uv_getaddrinfo_t info;
+  uv_getaddrinfo_t info;
   int err = leader_resolve(ps, &info, true);
   if (!err) {
     err = uv_tcp_bind(&l->psocket.tcp, info.addrinfo->ai_addr, 0);
     uv_freeaddrinfo(info.addrinfo);
   }
-  if (!err) err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
-  if (err) {
-    leader_error(ps, err, "listen on ");
+  if (!err) {
+    err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_connection);
+  }
+  if (!err) {
+    set_state(ps, ON_UV, NULL);
+  } else {
+    leader_error(ps, err, "listening on");
   }
 }
 
-static void on_tick(uv_timer_t *timer) {
-  pconnection_t *pc = (pconnection_t*)timer->data;
+/* Generate tick events and return millis till next tick or 0 if no tick is required */
+static pn_millis_t leader_tick(pconnection_t *pc) {
+  assert(pc->psocket.state != ON_WORKER);
   pn_transport_t *t = pc->driver.transport;
   if (pn_transport_get_idle_timeout(t) || pn_transport_get_remote_idle_timeout(t)) {
-    uv_timer_stop(&pc->timer);
     uint64_t now = uv_now(pc->timer.loop);
     uint64_t next = pn_transport_tick(t, now);
-    if (next) {
-      uv_timer_start(&pc->timer, on_tick, next - now, 0);
-    }
+    return next ? next - now : 0;
+  }
+  return 0;
+}
+
+static void on_tick(uv_timer_t *timer) {
+  if (!timer->data) return;     /* timer closed */
+  pconnection_t *pc = (pconnection_t*)timer->data;
+  assert(pc->psocket.state == ON_UV);
+  uv_timer_stop(&pc->timer);
+  pn_millis_t next = leader_tick(pc);
+  if (pn_connection_driver_has_event(&pc->driver)) {
+    leader_unwatch(&pc->psocket);
+  } else if (next) {
+    uv_timer_start(&pc->timer, on_tick, next, 0);
   }
 }
 
 static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
   pconnection_t *pc = (pconnection_t*)stream->data;
+  assert(pc->psocket.state == ON_UV);
   if (nread >= 0) {
     pn_connection_driver_read_done(&pc->driver, nread);
     on_tick(&pc->timer);         /* check for tick changes. */
-    leader_to_worker(&pc->psocket);
     /* Reading continues automatically until stopped. */
   } else if (nread == UV_EOF) { /* hangup */
     pn_connection_driver_read_close(&pc->driver);
-    leader_maybe_free(&pc->psocket);
+    leader_unwatch(&pc->psocket);
   } else {
     leader_error(&pc->psocket, nread, "on read from");
   }
@@ -522,16 +501,17 @@ static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
 
 static void on_write(uv_write_t* write, int err) {
   pconnection_t *pc = (pconnection_t*)write->data;
-  write->data = NULL;
+  assert(pc->psocket.state == ON_UV);
+  size_t writing = pc->writing;
+  pc->writing = 0;              /* This write is done regardless of outcome */
   if (err == 0) {
-    pn_connection_driver_write_done(&pc->driver, pc->writing);
-    leader_to_worker(&pc->psocket);
+    pn_connection_driver_write_done(&pc->driver, writing);
+    leader_unwatch(&pc->psocket);
   } else if (err == UV_ECANCELED) {
-    leader_maybe_free(&pc->psocket);
+    leader_unwatch(&pc->psocket);    /* cancelled by leader_unwatch, complete the job */
   } else {
     leader_error(&pc->psocket, err, "on write to");
   }
-  pc->writing = 0;              /* Need to send a new write request */
 }
 
 static void on_timeout(uv_timer_t *timer) {
@@ -544,47 +524,93 @@ static void on_timeout(uv_timer_t *timer) {
 // Read buffer allocation function for uv, just returns the transports read buffer.
 static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
   pconnection_t *pc = (pconnection_t*)stream->data;
+  assert(pc->psocket.state == ON_UV);
   pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
   *buf = uv_buf_init(rbuf.start, rbuf.size);
 }
 
-static void leader_rewatch(psocket_t *ps) {
+/* Monitor a socket in the UV loop */
+static void leader_watch(psocket_t *ps) {
+  assert(ps->state == ON_LEADER);
   int err = 0;
+  set_state(ps, ON_UV, NULL); /* Assume we are going to UV loop unless sent to worker or leader. */
+
   if (ps->is_conn) {
-    pconnection_t *pc = as_pconnection_t(ps);
-    if (pc->timer.data) {         /* uv-initialized */
-      on_tick(&pc->timer);        /* Re-enable ticks if required */
+    pconnection_t *pc = as_pconnection(ps);
+    if (pn_connection_driver_finished(&pc->driver)) {
+      leader_finished(ps);
+      return;
     }
+    pn_millis_t next_tick = leader_tick(pc);
     pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
     pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
-
-    /* Ticks and checking buffers can generate events, process before proceeding */
     if (pn_connection_driver_has_event(&pc->driver)) {
-      leader_to_worker(ps);
-    } else {                      /* Re-watch for IO */
-      if (wbuf.size > 0 && !pc->writing) {
-        pc->writing = wbuf.size;
-        uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
-        pc->write.data = ps;
-        uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
-      } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
-        pc->shutdown.data = ps;
-        uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
-      }
-      if (rbuf.size > 0 && !pc->reading) {
-        pc->reading = true;
-        err = uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
-      }
+      /* Ticks and checking buffers have generated events, send back to worker to process */
+      set_state(ps, ON_WORKER, NULL);
+      return;
+    }
+    if (next_tick) {
+      uv_timer_start(&pc->timer, on_tick, next_tick, 0);
+    }
+    if (wbuf.size > 0 && !pc->writing) {
+      pc->writing = wbuf.size;
+      uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
+      err = uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
+    } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
+      pc->shutdown.data = ps;
+      err = uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, NULL);
+    }
+    if (rbuf.size > 0 && !pc->reading) {
+      pc->reading = true;
+      err = uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
     }
   } else {
     pn_listener_t *l = as_listener(ps);
-    err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
+    if (l->closing && pn_collector_peek(l->collector)) {
+        leader_finished(&l->psocket);
+    } else {
+      if (l->accepting) {
+        leader_accept(l);
+      }
+      if (l->connections) {
+        leader_unwatch(ps);
+      }
+    }
   }
   if (err) {
-    leader_error(ps, err, "rewatch");
+    leader_error(ps, err, "re-watching");
   }
 }
 
+/* Detach a socket from IO and put it on the worker queue */
+static void leader_unwatch(psocket_t *ps) {
+  assert(ps->state != ON_WORKER); /* From ON_UV or ON_LEADER */
+  if (ps->is_conn) {
+    pconnection_t *pc = as_pconnection(ps);
+    if (!pn_connection_driver_has_event(&pc->driver)) {
+      /* Don't return an empty event batch */
+      if (ps->state == ON_UV) {
+        return;                 /* Just leave it in the UV loop */
+      } else {
+        leader_watch(ps);     /* Re-attach to UV loop */
+      }
+      return;
+    } else {
+      if (pc->writing) {
+        uv_cancel((uv_req_t*)&pc->write);
+      }
+      if (pc->reading) {
+        pc->reading = false;
+        uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
+      }
+      if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
+        uv_timer_stop(&pc->timer);
+      }
+    }
+  }
+  set_state(ps, ON_WORKER, NULL);
+}
+
 /* Set the event in the proactor's batch  */
 static pn_event_batch_t *proactor_batch_lh(pn_proactor_t *p, pn_event_type_t t) {
   pn_collector_put(p->collector, pn_proactor__class(), p, t);
@@ -609,23 +635,32 @@ static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
     }
   }
   for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
+    assert(ps->state == ON_WORKER);
     if (ps->is_conn) {
-      pconnection_t *pc = as_pconnection_t(ps);
+      pconnection_t *pc = as_pconnection(ps);
       return &pc->driver.batch;
     } else {                    /* Listener */
       pn_listener_t *l = as_listener(ps);
+      /* Generate accept events one at a time */
+      if (l->connections && !pn_collector_peek(l->collector)) {
+        --l->connections;
+        pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
+      }
       return &l->batch;
     }
-    to_leader(ps);      /* No event, back to leader */
+    set_state_lh(ps, ON_LEADER, NULL); /* No event, back to leader */
   }
   return 0;
 }
 
-/* Called in any thread to set a wakeup action. Replaces any previous wakeup action. */
+/* Called in any thread to set a wakeup action */
 static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
   uv_mutex_lock(&ps->proactor->lock);
-  ps->wakeup = action;
-  to_leader_lh(ps);
+  if (action && !ps->wakeup) {
+    ps->wakeup = action;
+  }
+  set_state_lh(ps, ON_LEADER, NULL);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
@@ -634,30 +669,36 @@ pn_listener_t *pn_event_listener(pn_event_t *e) {
 }
 
 pn_proactor_t *pn_event_proactor(pn_event_t *e) {
-  if (pn_event_class(e) == pn_proactor__class()) return (pn_proactor_t*)pn_event_context(e);
+  if (pn_event_class(e) == pn_proactor__class()) {
+    return (pn_proactor_t*)pn_event_context(e);
+  }
   pn_listener_t *l = pn_event_listener(e);
-  if (l) return l->psocket.proactor;
+  if (l) {
+    return l->psocket.proactor;
+  }
   pn_connection_t *c = pn_event_connection(e);
-  if (c) return pn_connection_proactor(pn_event_connection(e));
+  if (c) {
+    return pn_connection_proactor(pn_event_connection(e));
+  }
   return NULL;
 }
 
 void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
   pconnection_t *pc = batch_pconnection(batch);
   if (pc) {
+    assert(pc->psocket.state == ON_WORKER);
     if (pn_connection_driver_has_event(&pc->driver)) {
-      /* Process all events before going back to IO. */
-      worker_requeue(&pc->psocket);
-    } else if (pn_connection_driver_finished(&pc->driver)) {
-      owner_to_leader(&pc->psocket, leader_close);
+      /* Process all events before going back to leader */
+      set_state(&pc->psocket, ON_WORKER, NULL);
     } else {
-      owner_to_leader(&pc->psocket, leader_rewatch);
+      set_state(&pc->psocket, ON_LEADER, leader_watch);
     }
     return;
   }
   pn_listener_t *l = batch_listener(batch);
   if (l) {
-    owner_to_leader(&l->psocket, leader_rewatch);
+    assert(l->psocket.state == ON_WORKER);
+    set_state(&l->psocket, ON_LEADER, leader_watch);
     return;
   }
   pn_proactor_t *bp = batch_proactor(batch);
@@ -692,14 +733,16 @@ pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
         }
       }
       for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
-        void (*action)(psocket_t*) = ps->action;
-        void (*wakeup)(psocket_t*) = ps->wakeup;
-        ps->action = NULL;
-        ps->wakeup = NULL;
-        if (action || wakeup) {
+        assert(ps->state == ON_LEADER);
+        if (ps->wakeup) {
+          uv_mutex_unlock(&p->lock);
+          ps->wakeup(ps);
+          ps->wakeup = NULL;
+          uv_mutex_lock(&p->lock);
+        } else if (ps->action) {
           uv_mutex_unlock(&p->lock);
-          if (action) action(ps);
-          if (wakeup) wakeup(ps);
+          ps->action(ps);
+          ps->action = NULL;
           uv_mutex_lock(&p->lock);
         }
       }
@@ -734,12 +777,11 @@ void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
 }
 
 int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {
-  pconnection_t *pc = new_pconnection_t(p, c, false, host, port);
+  pconnection_t *pc = new_pconnection(p, c, false, host, port);
   if (!pc) {
     return PN_OUT_OF_MEMORY;
   }
-  /* Process PN_CONNECTION_INIT before binding */
-  owner_to_worker(&pc->psocket, leader_connect);
+  set_state(&pc->psocket, ON_LEADER, leader_connect);
   return 0;
 }
 
@@ -747,24 +789,26 @@ int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *host, con
 {
   psocket_init(&l->psocket, p, false, host, port);
   l->backlog = backlog;
-  owner_to_leader(&l->psocket, leader_listen);
+  set_state(&l->psocket, ON_LEADER, leader_listen);
   return 0;
 }
 
 pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
-  pconnection_t *pc = get_pconnection_t(c);
+  pconnection_t *pc = get_pconnection(c);
   return pc ? pc->psocket.proactor : NULL;
 }
 
 void leader_wake_connection(psocket_t *ps) {
-  pconnection_t *pc = as_pconnection_t(ps);
+  assert(ps->state == ON_LEADER);
+  pconnection_t *pc = as_pconnection(ps);
   pn_connection_t *c = pc->driver.connection;
   pn_collector_put(pn_connection_collector(c), PN_OBJECT, c, PN_CONNECTION_WAKE);
-  leader_to_worker(ps);
+  leader_unwatch(ps);
 }
 
 void pn_connection_wake(pn_connection_t* c) {
-  wakeup(&get_pconnection_t(c)->psocket, leader_wake_connection);
+  /* May be called from any thread */
+  wakeup(&get_pconnection(c)->psocket, leader_wake_connection);
 }
 
 pn_proactor_t *pn_proactor() {
@@ -782,9 +826,11 @@ pn_proactor_t *pn_proactor() {
 }
 
 static void on_stopping(uv_handle_t* h, void* v) {
-  uv_close(h, NULL);           /* Close this handle */
+  if (!uv_is_closing(h)) {
+    uv_close(h, NULL);           /* Close this handle */
+  }
   if (!uv_loop_alive(h->loop)) /* Everything closed */
-    uv_stop(h->loop);        /* Stop the loop, pn_proactor_destroy() can return */
+    uv_stop(h->loop);          /* Stop the loop, pn_proactor_destroy() can return */
 }
 
 void pn_proactor_free(pn_proactor_t *p) {
@@ -799,10 +845,7 @@ void pn_proactor_free(pn_proactor_t *p) {
 
 static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
   pn_listener_t *l = batch_listener(batch);
-  pn_event_t *handled = pn_collector_prev(l->collector);
-  if (handled && pn_event_type(handled) == PN_LISTENER_CLOSE) {
-    owner_to_leader(&l->psocket, leader_close); /* Close event handled, do close */
-  }
+  assert(l->psocket.state == ON_WORKER);
   return pn_collector_next(l->collector);
 }
 
@@ -811,6 +854,7 @@ static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
 }
 
 static void pn_listener_free(pn_listener_t *l) {
+  assert(l->psocket.state == ON_WORKER);
   if (l) {
     if (!l->collector) pn_collector_free(l->collector);
     if (!l->condition) pn_condition_free(l->condition);
@@ -834,40 +878,51 @@ pn_listener_t *pn_listener() {
   return l;
 }
 
+void leader_listener_close(psocket_t *ps) {
+  assert(ps->state = ON_LEADER);
+  pn_listener_t *l = (pn_listener_t*)ps;
+  l->closing = true;
+  leader_watch(ps);
+}
+
 void pn_listener_close(pn_listener_t* l) {
-  wakeup(&l->psocket, leader_close);
+  /* This can be called from any thread, not just the owner of l */
+  wakeup(&l->psocket, leader_listener_close);
 }
 
 pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
+  assert(l->psocket.state == ON_WORKER);
   return l ? l->psocket.proactor : NULL;
 }
 
 pn_condition_t* pn_listener_condition(pn_listener_t* l) {
+  assert(l->psocket.state == ON_WORKER);
   return l->condition;
 }
 
 void *pn_listener_get_context(pn_listener_t *l) {
+  assert(l->psocket.state == ON_WORKER);
   return l->context;
 }
 
 void pn_listener_set_context(pn_listener_t *l, void *context) {
+  assert(l->psocket.state == ON_WORKER);
   l->context = context;
 }
 
 pn_record_t *pn_listener_attachments(pn_listener_t *l) {
+  assert(l->psocket.state == ON_WORKER);
   return l->attachments;
 }
 
 int pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
+  assert(l->psocket.state == ON_WORKER);
   if (l->accepting) {
     return PN_STATE_ERR;        /* Only one at a time */
   }
-  l->accepting = new_pconnection_t(
-      l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
+  l->accepting = new_pconnection(l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
   if (!l->accepting) {
     return UV_ENOMEM;
   }
-  owner_to_leader(&l->psocket, leader_accept);
   return 0;
 }
-


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[38/38] qpid-proton git commit: PROTON-1415: Merge branch 'master' into go1

Posted by ac...@apache.org.
PROTON-1415: Merge branch 'master' into go1

Merge DurableSubscription changes.
Also merge restored compatibility back to proton-c 0.10


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/569b4fca
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/569b4fca
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/569b4fca

Branch: refs/heads/go1
Commit: 569b4fca1ecf733bee925cd1abf33541456cf630
Parents: ed8e879 9ec97b5
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 17:50:40 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 17:50:40 2017 -0500

----------------------------------------------------------------------
 amqp/version.go        |   8 ++-
 electron/connection.go |   2 +-
 electron/link.go       | 128 +++++++++++++++++++++++++++++++++-----------
 electron/link_test.go  |  64 ++++++++++++++++++++++
 proton/wrappers_gen.go |   8 +--
 readme-go-get.md       |   1 +
 6 files changed, 174 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/569b4fca/amqp/version.go
----------------------------------------------------------------------
diff --cc amqp/version.go
index cefa904,0000000..bf33d2b
mode 100644,000000..100644
--- a/amqp/version.go
+++ b/amqp/version.go
@@@ -1,29 -1,0 +1,35 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +or more contributor license agreements.  See the NOTICE file
 +distributed with this work for additional information
 +regarding copyright ownership.  The ASF licenses this file
 +to you under the Apache License, Version 2.0 (the
 +"License"); you may not use this file except in compliance
 +with the License.  You may obtain a copy of the License at
 +
 +  http://www.apache.org/licenses/LICENSE-2.0
 +
 +Unless required by applicable law or agreed to in writing,
 +software distributed under the License is distributed on an
 +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +KIND, either express or implied.  See the License for the
 +specific language governing permissions and limitations
 +under the License.
 +*/
 +
++//
++// NOTE: DO NOT EDIT. This file was generated by genwrap.go from the proton header files.
++// Update the generator and re-run if you need to modify this code.
++//
++
++
 +package amqp
 +
 +// Version check for proton library.
 +// Done here because this is the lowest-level dependency for all the proton Go packages.
 +
 +// #include <proton/version.h>
- // #if PN_VERSION_MINOR < 10
++// #if PN_VERSION_MAJOR == 0 && PN_VERSION_MINOR < 10
 +// #error packages qpid.apache.org/... require Proton-C library version 0.10 or greater
 +// #endif
 +import "C"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/569b4fca/electron/connection.go
----------------------------------------------------------------------
diff --cc electron/connection.go
index 7f3050f,0000000..8f62491
mode 100644,000000..100644
--- a/electron/connection.go
+++ b/electron/connection.go
@@@ -1,405 -1,0 +1,405 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +or more contributor license agreements.  See the NOTICE file
 +distributed with this work for additional information
 +regarding copyright ownership.  The ASF licenses this file
 +to you under the Apache License, Version 2.0 (the
 +"License"); you may not use this file except in compliance
 +with the License.  You may obtain a copy of the License at
 +
 +  http://www.apache.org/licenses/LICENSE-2.0
 +
 +Unless required by applicable law or agreed to in writing,
 +software distributed under the License is distributed on an
 +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +KIND, either express or implied.  See the License for the
 +specific language governing permissions and limitations
 +under the License.
 +*/
 +
 +package electron
 +
 +// #include <proton/disposition.h>
 +import "C"
 +
 +import (
 +	"net"
 +	"qpid.apache.org/proton"
 +	"sync"
 +	"time"
 +)
 +
 +// Settings associated with a Connection.
 +type ConnectionSettings interface {
 +	// Authenticated user name associated with the connection.
 +	User() string
 +
 +	// The AMQP virtual host name for the connection.
 +	//
 +	// Optional, useful when the server has multiple names and provides different
 +	// service based on the name the client uses to connect.
 +	//
 +	// By default it is set to the DNS host name that the client uses to connect,
 +	// but it can be set to something different at the client side with the
 +	// VirtualHost() option.
 +	//
 +	// Returns error if the connection fails to authenticate.
 +	VirtualHost() string
 +
 +	// Heartbeat is the maximum delay between sending frames that the remote peer
 +	// has requested of us. If the interval expires an empty "heartbeat" frame
 +	// will be sent automatically to keep the connection open.
 +	Heartbeat() time.Duration
 +}
 +
 +// Connection is an AMQP connection, created by a Container.
 +type Connection interface {
 +	Endpoint
 +	ConnectionSettings
 +
 +	// Sender opens a new sender on the DefaultSession.
 +	Sender(...LinkOption) (Sender, error)
 +
 +	// Receiver opens a new Receiver on the DefaultSession().
 +	Receiver(...LinkOption) (Receiver, error)
 +
 +	// DefaultSession() returns a default session for the connection. It is opened
 +	// on the first call to DefaultSession and returned on subsequent calls.
 +	DefaultSession() (Session, error)
 +
 +	// Session opens a new session.
 +	Session(...SessionOption) (Session, error)
 +
 +	// Container for the connection.
 +	Container() Container
 +
 +	// Disconnect the connection abruptly with an error.
 +	Disconnect(error)
 +
 +	// Wait waits for the connection to be disconnected.
 +	Wait() error
 +
 +	// WaitTimeout is like Wait but returns Timeout if the timeout expires.
 +	WaitTimeout(time.Duration) error
 +
 +	// Incoming returns a channel for incoming endpoints opened by the remote peer.
 +	// See the Incoming interface for more.
 +	//
 +	// Not receiving from Incoming() and calling Accept/Reject will block the
 +	// electron event loop. You should run a loop to handle the types that
 +	// interest you in a switch{} and and Accept() all others.
 +	Incoming() <-chan Incoming
 +}
 +
 +type connectionSettings struct {
 +	user, virtualHost string
 +	heartbeat         time.Duration
 +}
 +
 +func (c connectionSettings) User() string             { return c.user }
 +func (c connectionSettings) VirtualHost() string      { return c.virtualHost }
 +func (c connectionSettings) Heartbeat() time.Duration { return c.heartbeat }
 +
 +// ConnectionOption can be passed when creating a connection to configure various options
 +type ConnectionOption func(*connection)
 +
 +// User returns a ConnectionOption sets the user name for a connection
 +func User(user string) ConnectionOption {
 +	return func(c *connection) {
 +		c.user = user
 +		c.pConnection.SetUser(user)
 +	}
 +}
 +
 +// VirtualHost returns a ConnectionOption to set the AMQP virtual host for the connection.
 +// Only applies to outbound client connection.
 +func VirtualHost(virtualHost string) ConnectionOption {
 +	return func(c *connection) {
 +		c.virtualHost = virtualHost
 +		c.pConnection.SetHostname(virtualHost)
 +	}
 +}
 +
 +// Password returns a ConnectionOption to set the password used to establish a
 +// connection.  Only applies to outbound client connection.
 +//
 +// The connection will erase its copy of the password from memory as soon as it
 +// has been used to authenticate. If you are concerned about paswords staying in
 +// memory you should never store them as strings, and should overwrite your
 +// copy as soon as you are done with it.
 +//
 +func Password(password []byte) ConnectionOption {
 +	return func(c *connection) { c.pConnection.SetPassword(password) }
 +}
 +
 +// Server returns a ConnectionOption to put the connection in server mode for incoming connections.
 +//
 +// A server connection will do protocol negotiation to accept a incoming AMQP
 +// connection. Normally you would call this for a connection created by
 +// net.Listener.Accept()
 +//
 +func Server() ConnectionOption {
 +	return func(c *connection) { c.engine.Server(); c.server = true; AllowIncoming()(c) }
 +}
 +
 +// AllowIncoming returns a ConnectionOption to enable incoming endpoints, see
 +// Connection.Incoming() This is automatically set for Server() connections.
 +func AllowIncoming() ConnectionOption {
 +	return func(c *connection) { c.incoming = make(chan Incoming) }
 +}
 +
 +// Parent returns a ConnectionOption that associates the Connection with it's Container
 +// If not set a connection will create its own default container.
 +func Parent(cont Container) ConnectionOption {
 +	return func(c *connection) { c.container = cont.(*container) }
 +}
 +
 +type connection struct {
 +	endpoint
 +	connectionSettings
 +
 +	defaultSessionOnce, closeOnce sync.Once
 +
 +	container   *container
 +	conn        net.Conn
 +	server      bool
 +	incoming    chan Incoming
 +	handler     *handler
 +	engine      *proton.Engine
 +	pConnection proton.Connection
 +
 +	defaultSession Session
 +}
 +
 +// NewConnection creates a connection with the given options.
 +func NewConnection(conn net.Conn, opts ...ConnectionOption) (*connection, error) {
 +	c := &connection{
 +		conn: conn,
 +	}
 +	c.handler = newHandler(c)
 +	var err error
 +	c.engine, err = proton.NewEngine(c.conn, c.handler.delegator)
 +	if err != nil {
 +		return nil, err
 +	}
 +	c.pConnection = c.engine.Connection()
 +	for _, set := range opts {
 +		set(c)
 +	}
 +	if c.container == nil {
 +		c.container = NewContainer("").(*container)
 +	}
 +	c.pConnection.SetContainer(c.container.Id())
 +	globalSASLInit(c.engine)
 +
 +	c.endpoint.init(c.engine.String())
 +	go c.run()
 +	return c, nil
 +}
 +
 +func (c *connection) run() {
 +	if !c.server {
 +		c.pConnection.Open()
 +	}
 +	_ = c.engine.Run()
 +	if c.incoming != nil {
 +		close(c.incoming)
 +	}
 +	_ = c.closed(Closed)
 +}
 +
 +func (c *connection) Close(err error) {
 +	c.err.Set(err)
 +	c.engine.Close(err)
 +}
 +
 +func (c *connection) Disconnect(err error) {
 +	c.err.Set(err)
 +	c.engine.Disconnect(err)
 +}
 +
 +func (c *connection) Session(opts ...SessionOption) (Session, error) {
 +	var s Session
 +	err := c.engine.InjectWait(func() error {
 +		if c.Error() != nil {
 +			return c.Error()
 +		}
 +		pSession, err := c.engine.Connection().Session()
 +		if err == nil {
 +			pSession.Open()
 +			if err == nil {
 +				s = newSession(c, pSession, opts...)
 +			}
 +		}
 +		return err
 +	})
 +	return s, err
 +}
 +
 +func (c *connection) Container() Container { return c.container }
 +
 +func (c *connection) DefaultSession() (s Session, err error) {
 +	c.defaultSessionOnce.Do(func() {
 +		c.defaultSession, err = c.Session()
 +	})
 +	if err == nil {
 +		err = c.Error()
 +	}
 +	return c.defaultSession, err
 +}
 +
 +func (c *connection) Sender(opts ...LinkOption) (Sender, error) {
 +	if s, err := c.DefaultSession(); err == nil {
 +		return s.Sender(opts...)
 +	} else {
 +		return nil, err
 +	}
 +}
 +
 +func (c *connection) Receiver(opts ...LinkOption) (Receiver, error) {
 +	if s, err := c.DefaultSession(); err == nil {
 +		return s.Receiver(opts...)
 +	} else {
 +		return nil, err
 +	}
 +}
 +
 +func (c *connection) Connection() Connection { return c }
 +
 +func (c *connection) Wait() error { return c.WaitTimeout(Forever) }
 +func (c *connection) WaitTimeout(timeout time.Duration) error {
 +	_, err := timedReceive(c.done, timeout)
 +	if err == Timeout {
 +		return Timeout
 +	}
 +	return c.Error()
 +}
 +
 +func (c *connection) Incoming() <-chan Incoming {
- 	assert(c.incoming != nil, "electron.Connection.Incoming() disabled for %s", c)
++	assert(c.incoming != nil, "Incoming() is only allowed for a Connection created with the Server() option: %s", c)
 +	return c.incoming
 +}
 +
 +type IncomingConnection struct {
 +	incoming
 +	connectionSettings
 +	c *connection
 +}
 +
 +func newIncomingConnection(c *connection) *IncomingConnection {
 +	c.user = c.pConnection.Transport().User()
 +	c.virtualHost = c.pConnection.RemoteHostname()
 +	return &IncomingConnection{
 +		incoming:           makeIncoming(c.pConnection),
 +		connectionSettings: c.connectionSettings,
 +		c:                  c}
 +}
 +
 +// AcceptConnection is like Accept() but takes ConnectionOption s
 +// For example you can set the Heartbeat() for the accepted connection.
 +func (in *IncomingConnection) AcceptConnection(opts ...ConnectionOption) Connection {
 +	return in.accept(func() Endpoint {
 +		for _, opt := range opts {
 +			opt(in.c)
 +		}
 +		in.c.pConnection.Open()
 +		return in.c
 +	}).(Connection)
 +}
 +
 +func (in *IncomingConnection) Accept() Endpoint {
 +	return in.AcceptConnection()
 +}
 +
 +func sasl(c *connection) proton.SASL { return c.engine.Transport().SASL() }
 +
 +// SASLEnable returns a ConnectionOption that enables SASL authentication.
 +// Only required if you don't set any other SASL options.
 +func SASLEnable() ConnectionOption { return func(c *connection) { sasl(c) } }
 +
 +// SASLAllowedMechs returns a ConnectionOption to set the list of allowed SASL
 +// mechanisms.
 +//
 +// Can be used on the client or the server to restrict the SASL for a connection.
 +// mechs is a space-separated list of mechanism names.
 +//
 +func SASLAllowedMechs(mechs string) ConnectionOption {
 +	return func(c *connection) { sasl(c).AllowedMechs(mechs) }
 +}
 +
 +// SASLAllowInsecure returns a ConnectionOption that allows or disallows clear
 +// text SASL authentication mechanisms
 +//
 +// By default the SASL layer is configured not to allow mechanisms that disclose
 +// the clear text of the password over an unencrypted AMQP connection. This specifically
 +// will disallow the use of the PLAIN mechanism without using SSL encryption.
 +//
 +// This default is to avoid disclosing password information accidentally over an
 +// insecure network.
 +//
 +func SASLAllowInsecure(b bool) ConnectionOption {
 +	return func(c *connection) { sasl(c).SetAllowInsecureMechs(b) }
 +}
 +
 +// Heartbeat returns a ConnectionOption that requests the maximum delay
 +// between sending frames for the remote peer. If we don't receive any frames
 +// within 2*delay we will close the connection.
 +//
 +func Heartbeat(delay time.Duration) ConnectionOption {
 +	// Proton-C divides the idle-timeout by 2 before sending, so compensate.
 +	return func(c *connection) { c.engine.Transport().SetIdleTimeout(2 * delay) }
 +}
 +
 +// GlobalSASLConfigDir sets the SASL configuration directory for every
 +// Connection created in this process. If not called, the default is determined
 +// by your SASL installation.
 +//
 +// You can set SASLAllowInsecure and SASLAllowedMechs on individual connections.
 +//
 +func GlobalSASLConfigDir(dir string) { globalSASLConfigDir = dir }
 +
 +// GlobalSASLConfigName sets the SASL configuration name for every Connection
 +// created in this process. If not called the default is "proton-server".
 +//
 +// The complete configuration file name is
 +//     <sasl-config-dir>/<sasl-config-name>.conf
 +//
 +// You can set SASLAllowInsecure and SASLAllowedMechs on individual connections.
 +//
 +func GlobalSASLConfigName(dir string) { globalSASLConfigName = dir }
 +
 +var (
 +	globalSASLConfigName string
 +	globalSASLConfigDir  string
 +)
 +
 +// TODO aconway 2016-09-15: Current pn_sasl C impl config is broken, so all we
 +// can realistically offer is global configuration. Later if/when the pn_sasl C
 +// impl is fixed we can offer per connection over-rides.
 +func globalSASLInit(eng *proton.Engine) {
 +	sasl := eng.Transport().SASL()
 +	if globalSASLConfigName != "" {
 +		sasl.ConfigName(globalSASLConfigName)
 +	}
 +	if globalSASLConfigDir != "" {
 +		sasl.ConfigPath(globalSASLConfigDir)
 +	}
 +}
 +
 +// Dial is shorthand for using net.Dial() then NewConnection()
 +func Dial(network, addr string, opts ...ConnectionOption) (c Connection, err error) {
 +	conn, err := net.Dial(network, addr)
 +	if err == nil {
 +		c, err = NewConnection(conn, opts...)
 +	}
 +	return
 +}
 +
 +// DialWithDialer is shorthand for using dialer.Dial() then NewConnection()
 +func DialWithDialer(dialer *net.Dialer, network, addr string, opts ...ConnectionOption) (c Connection, err error) {
 +	conn, err := dialer.Dial(network, addr)
 +	if err == nil {
 +		c, err = NewConnection(conn, opts...)
 +	}
 +	return
 +}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/569b4fca/electron/link.go
----------------------------------------------------------------------
diff --cc electron/link.go
index 1d17894,0000000..4f927c1
mode 100644,000000..100644
--- a/electron/link.go
+++ b/electron/link.go
@@@ -1,221 -1,0 +1,285 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +or more contributor license agreements.  See the NOTICE file
 +distributed with this work for additional information
 +regarding copyright ownership.  The ASF licenses this file
 +to you under the Apache License, Version 2.0 (the
 +"License"); you may not use this file except in compliance
 +with the License.  You may obtain a copy of the License at
 +
 +  http://www.apache.org/licenses/LICENSE-2.0
 +
 +Unless required by applicable law or agreed to in writing,
 +software distributed under the License is distributed on an
 +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +KIND, either express or implied.  See the License for the
 +specific language governing permissions and limitations
 +under the License.
 +*/
 +
 +package electron
 +
 +import (
 +	"fmt"
 +	"qpid.apache.org/proton"
++	"time"
 +)
 +
 +// Settings associated with a link
 +type LinkSettings interface {
 +	// Source address that messages are coming from.
 +	Source() string
 +
 +	// Target address that messages are going to.
 +	Target() string
 +
 +	// Name is a unique name for the link among links between the same
 +	// containers in the same direction. By default generated automatically.
 +	LinkName() string
 +
 +	// IsSender is true if this is the sending end of the link.
 +	IsSender() bool
 +
 +	// IsReceiver is true if this is the receiving end of the link.
 +	IsReceiver() bool
 +
 +	// SndSettle defines when the sending end of the link settles message delivery.
 +	SndSettle() SndSettleMode
 +
 +	// RcvSettle defines when the sending end of the link settles message delivery.
 +	RcvSettle() RcvSettleMode
 +
 +	// Session containing the Link
 +	Session() Session
++
++	// Advanced settings for the source
++	SourceSettings() TerminusSettings
++
++	// Advanced settings for the target
++	TargetSettings() TerminusSettings
 +}
 +
 +// LinkOption can be passed when creating a sender or receiver link to set optional configuration.
 +type LinkOption func(*linkSettings)
 +
 +// Source returns a LinkOption that sets address that messages are coming from.
 +func Source(s string) LinkOption { return func(l *linkSettings) { l.source = s } }
 +
 +// Target returns a LinkOption that sets address that messages are going to.
 +func Target(s string) LinkOption { return func(l *linkSettings) { l.target = s } }
 +
 +// LinkName returns a LinkOption that sets the link name.
- func LinkName(s string) LinkOption { return func(l *linkSettings) { l.target = s } }
++func LinkName(s string) LinkOption { return func(l *linkSettings) { l.linkName = s } }
 +
 +// SndSettle returns a LinkOption that sets the send settle mode
 +func SndSettle(m SndSettleMode) LinkOption { return func(l *linkSettings) { l.sndSettle = m } }
 +
 +// RcvSettle returns a LinkOption that sets the send settle mode
 +func RcvSettle(m RcvSettleMode) LinkOption { return func(l *linkSettings) { l.rcvSettle = m } }
 +
- // SndSettleMode returns a LinkOption that defines when the sending end of the
- // link settles message delivery.
- type SndSettleMode proton.SndSettleMode
- 
 +// Capacity returns a LinkOption that sets the link capacity
 +func Capacity(n int) LinkOption { return func(l *linkSettings) { l.capacity = n } }
 +
 +// Prefetch returns a LinkOption that sets a receivers pre-fetch flag. Not relevant for a sender.
 +func Prefetch(p bool) LinkOption { return func(l *linkSettings) { l.prefetch = p } }
 +
++// DurableSubscription returns a LinkOption that configures a Receiver as a named durable
++// subscription.  The name overrides (and is overridden by) LinkName() so you should normally
++// only use one of these options.
++func DurableSubscription(name string) LinkOption {
++	return func(l *linkSettings) {
++		l.linkName = name
++		l.sourceSettings.Durability = proton.Deliveries
++		l.sourceSettings.Expiry = proton.ExpireNever
++	}
++}
++
 +// AtMostOnce returns a LinkOption that sets "fire and forget" mode, messages
 +// are sent but no acknowledgment is received, messages can be lost if there is
 +// a network failure. Sets SndSettleMode=SendSettled and RcvSettleMode=RcvFirst
 +func AtMostOnce() LinkOption {
 +	return func(l *linkSettings) {
 +		SndSettle(SndSettled)(l)
 +		RcvSettle(RcvFirst)(l)
 +	}
 +}
 +
 +// AtLeastOnce returns a LinkOption that requests acknowledgment for every
 +// message, acknowledgment indicates the message was definitely received. In the
 +// event of a failure, unacknowledged messages can be re-sent but there is a
 +// chance that the message will be received twice in this case.  Sets
 +// SndSettleMode=SndUnsettled and RcvSettleMode=RcvFirst
 +func AtLeastOnce() LinkOption {
 +	return func(l *linkSettings) {
 +		SndSettle(SndUnsettled)(l)
 +		RcvSettle(RcvFirst)(l)
 +	}
 +}
 +
++// SourceSettings returns a LinkOption that sets all the SourceSettings.
++// Note: it will override the source address set by a Source() option
++func SourceSettings(ts TerminusSettings) LinkOption {
++	return func(l *linkSettings) { l.sourceSettings = ts }
++}
++
++// TargetSettings returns a LinkOption that sets all the TargetSettings.
++// Note: it will override the target address set by a Target() option
++func TargetSettings(ts TerminusSettings) LinkOption {
++	return func(l *linkSettings) { l.targetSettings = ts }
++}
++
++// SndSettleMode defines when the sending end of the link settles message delivery.
++type SndSettleMode proton.SndSettleMode
++
 +const (
 +	// Messages are sent unsettled
 +	SndUnsettled = SndSettleMode(proton.SndUnsettled)
 +	// Messages are sent already settled
 +	SndSettled = SndSettleMode(proton.SndSettled)
 +	// Sender can send either unsettled or settled messages.
 +	SendMixed = SndSettleMode(proton.SndMixed)
 +)
 +
 +// RcvSettleMode defines when the receiving end of the link settles message delivery.
 +type RcvSettleMode proton.RcvSettleMode
 +
 +const (
 +	// Receiver settles first.
 +	RcvFirst = RcvSettleMode(proton.RcvFirst)
 +	// Receiver waits for sender to settle before settling.
 +	RcvSecond = RcvSettleMode(proton.RcvSecond)
 +)
 +
 +type linkSettings struct {
- 	source    string
- 	target    string
- 	linkName  string
- 	isSender  bool
- 	sndSettle SndSettleMode
- 	rcvSettle RcvSettleMode
- 	capacity  int
- 	prefetch  bool
- 	session   *session
- 	pLink     proton.Link
++	source         string
++	sourceSettings TerminusSettings
++	target         string
++	targetSettings TerminusSettings
++	linkName       string
++	isSender       bool
++	sndSettle      SndSettleMode
++	rcvSettle      RcvSettleMode
++	capacity       int
++	prefetch       bool
++	session        *session
++	pLink          proton.Link
++}
++
++// Advanced AMQP settings for the source or target of a link.
++// Usually these can be set via a more descriptive LinkOption, e.g. DurableSubscription()
++// and do not need to be set/examined directly.
++type TerminusSettings struct {
++	Durability proton.Durability
++	Expiry     proton.ExpiryPolicy
++	Timeout    time.Duration
++	Dynamic    bool
++}
++
++func makeTerminusSettings(t proton.Terminus) TerminusSettings {
++	return TerminusSettings{
++		Durability: t.Durability(),
++		Expiry:     t.ExpiryPolicy(),
++		Timeout:    t.Timeout(),
++		Dynamic:    t.IsDynamic(),
++	}
 +}
 +
 +type link struct {
 +	endpoint
 +	linkSettings
 +}
 +
- func (l *linkSettings) Source() string           { return l.source }
- func (l *linkSettings) Target() string           { return l.target }
- func (l *linkSettings) LinkName() string         { return l.linkName }
- func (l *linkSettings) IsSender() bool           { return l.isSender }
- func (l *linkSettings) IsReceiver() bool         { return !l.isSender }
- func (l *linkSettings) SndSettle() SndSettleMode { return l.sndSettle }
- func (l *linkSettings) RcvSettle() RcvSettleMode { return l.rcvSettle }
++func (l *linkSettings) Source() string                   { return l.source }
++func (l *linkSettings) Target() string                   { return l.target }
++func (l *linkSettings) LinkName() string                 { return l.linkName }
++func (l *linkSettings) IsSender() bool                   { return l.isSender }
++func (l *linkSettings) IsReceiver() bool                 { return !l.isSender }
++func (l *linkSettings) SndSettle() SndSettleMode         { return l.sndSettle }
++func (l *linkSettings) RcvSettle() RcvSettleMode         { return l.rcvSettle }
++func (l *linkSettings) SourceSettings() TerminusSettings { return l.sourceSettings }
++func (l *linkSettings) TargetSettings() TerminusSettings { return l.targetSettings }
 +
 +func (l *link) Session() Session       { return l.session }
 +func (l *link) Connection() Connection { return l.session.Connection() }
 +func (l *link) engine() *proton.Engine { return l.session.connection.engine }
 +func (l *link) handler() *handler      { return l.session.connection.handler }
 +
 +// Open a link and return the linkSettings.
 +func makeLocalLink(sn *session, isSender bool, setting ...LinkOption) (linkSettings, error) {
 +	l := linkSettings{
 +		isSender: isSender,
 +		capacity: 1,
 +		prefetch: false,
 +		session:  sn,
 +	}
 +	for _, set := range setting {
 +		set(&l)
 +	}
 +	if l.linkName == "" {
 +		l.linkName = l.session.connection.container.nextLinkName()
 +	}
 +	if l.IsSender() {
 +		l.pLink = l.session.pSession.Sender(l.linkName)
 +	} else {
 +		l.pLink = l.session.pSession.Receiver(l.linkName)
 +	}
 +	if l.pLink.IsNil() {
 +		return l, fmt.Errorf("cannot create link %s", l.pLink)
 +	}
 +	l.pLink.Source().SetAddress(l.source)
++	l.pLink.Source().SetDurability(l.sourceSettings.Durability)
++	l.pLink.Source().SetExpiryPolicy(l.sourceSettings.Expiry)
++	l.pLink.Source().SetTimeout(l.sourceSettings.Timeout)
++	l.pLink.Source().SetDynamic(l.sourceSettings.Dynamic)
++
 +	l.pLink.Target().SetAddress(l.target)
++	l.pLink.Target().SetDurability(l.targetSettings.Durability)
++	l.pLink.Target().SetExpiryPolicy(l.targetSettings.Expiry)
++	l.pLink.Target().SetTimeout(l.targetSettings.Timeout)
++	l.pLink.Target().SetDynamic(l.targetSettings.Dynamic)
++
 +	l.pLink.SetSndSettleMode(proton.SndSettleMode(l.sndSettle))
 +	l.pLink.SetRcvSettleMode(proton.RcvSettleMode(l.rcvSettle))
 +	l.pLink.Open()
 +	return l, nil
 +}
 +
 +func makeIncomingLinkSettings(pLink proton.Link, sn *session) linkSettings {
 +	return linkSettings{
- 		isSender:  pLink.IsSender(),
- 		source:    pLink.RemoteSource().Address(),
- 		target:    pLink.RemoteTarget().Address(),
- 		linkName:  pLink.Name(),
- 		sndSettle: SndSettleMode(pLink.RemoteSndSettleMode()),
- 		rcvSettle: RcvSettleMode(pLink.RemoteRcvSettleMode()),
- 		capacity:  1,
- 		prefetch:  false,
- 		pLink:     pLink,
- 		session:   sn,
++		isSender:       pLink.IsSender(),
++		source:         pLink.RemoteSource().Address(),
++		sourceSettings: makeTerminusSettings(pLink.RemoteSource()),
++		target:         pLink.RemoteTarget().Address(),
++		targetSettings: makeTerminusSettings(pLink.RemoteTarget()),
++		linkName:       pLink.Name(),
++		sndSettle:      SndSettleMode(pLink.RemoteSndSettleMode()),
++		rcvSettle:      RcvSettleMode(pLink.RemoteRcvSettleMode()),
++		capacity:       1,
++		prefetch:       false,
++		pLink:          pLink,
++		session:        sn,
 +	}
 +}
 +
 +// Not part of Link interface but use by Sender and Receiver.
 +func (l *link) Credit() (credit int, err error) {
 +	err = l.engine().InjectWait(func() error {
 +		if l.Error() != nil {
 +			return l.Error()
 +		}
 +		credit = l.pLink.Credit()
 +		return nil
 +	})
 +	return
 +}
 +
 +// Not part of Link interface but use by Sender and Receiver.
 +func (l *link) Capacity() int { return l.capacity }
 +
 +func (l *link) Close(err error) {
 +	_ = l.engine().Inject(func() {
 +		if l.Error() == nil {
 +			localClose(l.pLink, err)
 +		}
 +	})
 +}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/569b4fca/electron/link_test.go
----------------------------------------------------------------------
diff --cc electron/link_test.go
index 0000000,0000000..133faad
new file mode 100644
--- /dev/null
+++ b/electron/link_test.go
@@@ -1,0 -1,0 +1,64 @@@
++/*
++Licensed to the Apache Software Foundation (ASF) under one
++or more contributor license agreements.  See the NOTICE file
++distributed with this work for additional information
++regarding copyright ownership.  The ASF licenses this file
++to you under the Apache License, Version 2.0 (the
++"License"); you may not use this file except in compliance
++with the License.  You may obtain a copy of the License at
++
++  http://www.apache.org/licenses/LICENSE-2.0
++
++Unless required by applicable law or agreed to in writing,
++software distributed under the License is distributed on an
++"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++KIND, either express or implied.  See the License for the
++specific language governing permissions and limitations
++under the License.
++*/
++
++// Test that link settings are propagated correctly
++package electron
++
++import (
++	"net"
++	"qpid.apache.org/proton"
++	"testing"
++	"time"
++)
++
++func TestLinkSettings(t *testing.T) {
++	cConn, sConn := net.Pipe()
++	done := make(chan error)
++	// FIXME aconway 2017-02-23: bug in timeout conversion (pn_second_t)
++	settings := TerminusSettings{Durability: 1, Expiry: 2, Timeout: 42 * time.Second, Dynamic: true}
++	go func() { // Server
++		close(done)
++		defer sConn.Close()
++		c, err := NewConnection(sConn, Server())
++		fatalIf(t, err)
++		for in := range c.Incoming() {
++			ep := in.Accept()
++			switch ep := ep.(type) {
++			case Receiver:
++				errorIf(t, checkEqual("one.source", ep.Source()))
++				errorIf(t, checkEqual(TerminusSettings{}, ep.SourceSettings()))
++				errorIf(t, checkEqual("one.target", ep.Target()))
++				errorIf(t, checkEqual(settings, ep.TargetSettings()))
++			case Sender:
++				errorIf(t, checkEqual("two", ep.LinkName()))
++				errorIf(t, checkEqual("two.source", ep.Source()))
++				errorIf(t, checkEqual(TerminusSettings{Durability: proton.Deliveries, Expiry: proton.ExpireNever}, ep.SourceSettings()))
++			}
++		}
++	}()
++
++	// Client
++	c, err := NewConnection(cConn)
++	fatalIf(t, err)
++	c.Sender(Source("one.source"), Target("one.target"), TargetSettings(settings))
++
++	c.Receiver(Source("two.source"), DurableSubscription("two"))
++	c.Close(nil)
++	<-done
++}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/569b4fca/proton/wrappers_gen.go
----------------------------------------------------------------------
diff --cc proton/wrappers_gen.go
index 19bfde2,0000000..0db04c8
mode 100644,000000..100644
--- a/proton/wrappers_gen.go
+++ b/proton/wrappers_gen.go
@@@ -1,937 -1,0 +1,939 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +or more contributor license agreements.  See the NOTICE file
 +distributed with this work for additional information
 +regarding copyright ownership.  The ASF licenses this file
 +to you under the Apache License, Version 2.0 (the
 +"License"); you may not use this file except in compliance
 +with the License.  You may obtain a copy of the License at
 +
 +  http://www.apache.org/licenses/LICENSE-2.0
 +
 +Unless required by applicable law or agreed to in writing,
 +software distributed under the License is distributed on an
 +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +KIND, either express or implied.  See the License for the
 +specific language governing permissions and limitations
 +under the License.
 +*/
 +
 +//
 +// NOTE: DO NOT EDIT. This file was generated by genwrap.go from the proton header files.
 +// Update the generator and re-run if you need to modify this code.
 +//
 +
 +package proton
 +
 +import (
 +	"time"
 +	"unsafe"
 +)
 +
- // #include <proton/types.h>
- // #include <proton/error.h>
 +// #include <proton/condition.h>
++// #include <proton/error.h>
 +// #include <proton/event.h>
++// #include <proton/types.h>
 +// #include <stdlib.h>
++import "C"
++
 +// #include <proton/session.h>
 +// #include <proton/link.h>
 +// #include <proton/delivery.h>
 +// #include <proton/disposition.h>
 +// #include <proton/condition.h>
 +// #include <proton/terminus.h>
 +// #include <proton/connection.h>
 +// #include <proton/transport.h>
 +// #include <proton/sasl.h>
 +import "C"
 +
 +type EventType int
 +
 +const (
 +	EConnectionInit         EventType = C.PN_CONNECTION_INIT
 +	EConnectionBound        EventType = C.PN_CONNECTION_BOUND
 +	EConnectionUnbound      EventType = C.PN_CONNECTION_UNBOUND
 +	EConnectionLocalOpen    EventType = C.PN_CONNECTION_LOCAL_OPEN
 +	EConnectionRemoteOpen   EventType = C.PN_CONNECTION_REMOTE_OPEN
 +	EConnectionLocalClose   EventType = C.PN_CONNECTION_LOCAL_CLOSE
 +	EConnectionRemoteClose  EventType = C.PN_CONNECTION_REMOTE_CLOSE
 +	EConnectionFinal        EventType = C.PN_CONNECTION_FINAL
 +	ESessionInit            EventType = C.PN_SESSION_INIT
 +	ESessionLocalOpen       EventType = C.PN_SESSION_LOCAL_OPEN
 +	ESessionRemoteOpen      EventType = C.PN_SESSION_REMOTE_OPEN
 +	ESessionLocalClose      EventType = C.PN_SESSION_LOCAL_CLOSE
 +	ESessionRemoteClose     EventType = C.PN_SESSION_REMOTE_CLOSE
 +	ESessionFinal           EventType = C.PN_SESSION_FINAL
 +	ELinkInit               EventType = C.PN_LINK_INIT
 +	ELinkLocalOpen          EventType = C.PN_LINK_LOCAL_OPEN
 +	ELinkRemoteOpen         EventType = C.PN_LINK_REMOTE_OPEN
 +	ELinkLocalClose         EventType = C.PN_LINK_LOCAL_CLOSE
 +	ELinkRemoteClose        EventType = C.PN_LINK_REMOTE_CLOSE
 +	ELinkLocalDetach        EventType = C.PN_LINK_LOCAL_DETACH
 +	ELinkRemoteDetach       EventType = C.PN_LINK_REMOTE_DETACH
 +	ELinkFlow               EventType = C.PN_LINK_FLOW
 +	ELinkFinal              EventType = C.PN_LINK_FINAL
 +	EDelivery               EventType = C.PN_DELIVERY
 +	ETransport              EventType = C.PN_TRANSPORT
 +	ETransportAuthenticated EventType = C.PN_TRANSPORT_AUTHENTICATED
 +	ETransportError         EventType = C.PN_TRANSPORT_ERROR
 +	ETransportHeadClosed    EventType = C.PN_TRANSPORT_HEAD_CLOSED
 +	ETransportTailClosed    EventType = C.PN_TRANSPORT_TAIL_CLOSED
 +	ETransportClosed        EventType = C.PN_TRANSPORT_CLOSED
 +)
 +
 +func (e EventType) String() string {
 +	switch e {
 +
 +	case C.PN_CONNECTION_INIT:
 +		return "ConnectionInit"
 +	case C.PN_CONNECTION_BOUND:
 +		return "ConnectionBound"
 +	case C.PN_CONNECTION_UNBOUND:
 +		return "ConnectionUnbound"
 +	case C.PN_CONNECTION_LOCAL_OPEN:
 +		return "ConnectionLocalOpen"
 +	case C.PN_CONNECTION_REMOTE_OPEN:
 +		return "ConnectionRemoteOpen"
 +	case C.PN_CONNECTION_LOCAL_CLOSE:
 +		return "ConnectionLocalClose"
 +	case C.PN_CONNECTION_REMOTE_CLOSE:
 +		return "ConnectionRemoteClose"
 +	case C.PN_CONNECTION_FINAL:
 +		return "ConnectionFinal"
 +	case C.PN_SESSION_INIT:
 +		return "SessionInit"
 +	case C.PN_SESSION_LOCAL_OPEN:
 +		return "SessionLocalOpen"
 +	case C.PN_SESSION_REMOTE_OPEN:
 +		return "SessionRemoteOpen"
 +	case C.PN_SESSION_LOCAL_CLOSE:
 +		return "SessionLocalClose"
 +	case C.PN_SESSION_REMOTE_CLOSE:
 +		return "SessionRemoteClose"
 +	case C.PN_SESSION_FINAL:
 +		return "SessionFinal"
 +	case C.PN_LINK_INIT:
 +		return "LinkInit"
 +	case C.PN_LINK_LOCAL_OPEN:
 +		return "LinkLocalOpen"
 +	case C.PN_LINK_REMOTE_OPEN:
 +		return "LinkRemoteOpen"
 +	case C.PN_LINK_LOCAL_CLOSE:
 +		return "LinkLocalClose"
 +	case C.PN_LINK_REMOTE_CLOSE:
 +		return "LinkRemoteClose"
 +	case C.PN_LINK_LOCAL_DETACH:
 +		return "LinkLocalDetach"
 +	case C.PN_LINK_REMOTE_DETACH:
 +		return "LinkRemoteDetach"
 +	case C.PN_LINK_FLOW:
 +		return "LinkFlow"
 +	case C.PN_LINK_FINAL:
 +		return "LinkFinal"
 +	case C.PN_DELIVERY:
 +		return "Delivery"
 +	case C.PN_TRANSPORT:
 +		return "Transport"
 +	case C.PN_TRANSPORT_AUTHENTICATED:
 +		return "TransportAuthenticated"
 +	case C.PN_TRANSPORT_ERROR:
 +		return "TransportError"
 +	case C.PN_TRANSPORT_HEAD_CLOSED:
 +		return "TransportHeadClosed"
 +	case C.PN_TRANSPORT_TAIL_CLOSED:
 +		return "TransportTailClosed"
 +	case C.PN_TRANSPORT_CLOSED:
 +		return "TransportClosed"
 +	}
 +	return "Unknown"
 +}
 +
 +// Wrappers for declarations in session.h
 +
 +type Session struct{ pn *C.pn_session_t }
 +
 +func (s Session) IsNil() bool          { return s.pn == nil }
 +func (s Session) CPtr() unsafe.Pointer { return unsafe.Pointer(s.pn) }
 +func (s Session) Free() {
 +	C.pn_session_free(s.pn)
 +}
 +func (s Session) State() State {
 +	return State(C.pn_session_state(s.pn))
 +}
 +func (s Session) Error() error {
 +	return PnError(C.pn_session_error(s.pn))
 +}
 +func (s Session) Condition() Condition {
 +	return Condition{C.pn_session_condition(s.pn)}
 +}
 +func (s Session) RemoteCondition() Condition {
 +	return Condition{C.pn_session_remote_condition(s.pn)}
 +}
 +func (s Session) Connection() Connection {
 +	return Connection{C.pn_session_connection(s.pn)}
 +}
 +func (s Session) Open() {
 +	C.pn_session_open(s.pn)
 +}
 +func (s Session) Close() {
 +	C.pn_session_close(s.pn)
 +}
 +func (s Session) IncomingCapacity() uint {
 +	return uint(C.pn_session_get_incoming_capacity(s.pn))
 +}
 +func (s Session) SetIncomingCapacity(capacity uint) {
 +	C.pn_session_set_incoming_capacity(s.pn, C.size_t(capacity))
 +}
 +func (s Session) OutgoingWindow() uint {
 +	return uint(C.pn_session_get_outgoing_window(s.pn))
 +}
 +func (s Session) SetOutgoingWindow(window uint) {
 +	C.pn_session_set_outgoing_window(s.pn, C.size_t(window))
 +}
 +func (s Session) OutgoingBytes() uint {
 +	return uint(C.pn_session_outgoing_bytes(s.pn))
 +}
 +func (s Session) IncomingBytes() uint {
 +	return uint(C.pn_session_incoming_bytes(s.pn))
 +}
 +func (s Session) Next(state State) Session {
 +	return Session{C.pn_session_next(s.pn, C.pn_state_t(state))}
 +}
 +
 +// Wrappers for declarations in link.h
 +
 +type SndSettleMode C.pn_snd_settle_mode_t
 +
 +const (
 +	SndUnsettled SndSettleMode = C.PN_SND_UNSETTLED
 +	SndSettled   SndSettleMode = C.PN_SND_SETTLED
 +	SndMixed     SndSettleMode = C.PN_SND_MIXED
 +)
 +
 +func (e SndSettleMode) String() string {
 +	switch e {
 +
 +	case C.PN_SND_UNSETTLED:
 +		return "SndUnsettled"
 +	case C.PN_SND_SETTLED:
 +		return "SndSettled"
 +	case C.PN_SND_MIXED:
 +		return "SndMixed"
 +	}
 +	return "unknown"
 +}
 +
 +type RcvSettleMode C.pn_rcv_settle_mode_t
 +
 +const (
 +	RcvFirst  RcvSettleMode = C.PN_RCV_FIRST
 +	RcvSecond RcvSettleMode = C.PN_RCV_SECOND
 +)
 +
 +func (e RcvSettleMode) String() string {
 +	switch e {
 +
 +	case C.PN_RCV_FIRST:
 +		return "RcvFirst"
 +	case C.PN_RCV_SECOND:
 +		return "RcvSecond"
 +	}
 +	return "unknown"
 +}
 +
 +type Link struct{ pn *C.pn_link_t }
 +
 +func (l Link) IsNil() bool          { return l.pn == nil }
 +func (l Link) CPtr() unsafe.Pointer { return unsafe.Pointer(l.pn) }
 +func (l Link) Free() {
 +	C.pn_link_free(l.pn)
 +}
 +func (l Link) Name() string {
 +	return C.GoString(C.pn_link_name(l.pn))
 +}
 +func (l Link) IsSender() bool {
 +	return bool(C.pn_link_is_sender(l.pn))
 +}
 +func (l Link) IsReceiver() bool {
 +	return bool(C.pn_link_is_receiver(l.pn))
 +}
 +func (l Link) State() State {
 +	return State(C.pn_link_state(l.pn))
 +}
 +func (l Link) Error() error {
 +	return PnError(C.pn_link_error(l.pn))
 +}
 +func (l Link) Condition() Condition {
 +	return Condition{C.pn_link_condition(l.pn)}
 +}
 +func (l Link) RemoteCondition() Condition {
 +	return Condition{C.pn_link_remote_condition(l.pn)}
 +}
 +func (l Link) Session() Session {
 +	return Session{C.pn_link_session(l.pn)}
 +}
 +func (l Link) Next(state State) Link {
 +	return Link{C.pn_link_next(l.pn, C.pn_state_t(state))}
 +}
 +func (l Link) Open() {
 +	C.pn_link_open(l.pn)
 +}
 +func (l Link) Close() {
 +	C.pn_link_close(l.pn)
 +}
 +func (l Link) Detach() {
 +	C.pn_link_detach(l.pn)
 +}
 +func (l Link) Source() Terminus {
 +	return Terminus{C.pn_link_source(l.pn)}
 +}
 +func (l Link) Target() Terminus {
 +	return Terminus{C.pn_link_target(l.pn)}
 +}
 +func (l Link) RemoteSource() Terminus {
 +	return Terminus{C.pn_link_remote_source(l.pn)}
 +}
 +func (l Link) RemoteTarget() Terminus {
 +	return Terminus{C.pn_link_remote_target(l.pn)}
 +}
 +func (l Link) Current() Delivery {
 +	return Delivery{C.pn_link_current(l.pn)}
 +}
 +func (l Link) Advance() bool {
 +	return bool(C.pn_link_advance(l.pn))
 +}
 +func (l Link) Credit() int {
 +	return int(C.pn_link_credit(l.pn))
 +}
 +func (l Link) Queued() int {
 +	return int(C.pn_link_queued(l.pn))
 +}
 +func (l Link) RemoteCredit() int {
 +	return int(C.pn_link_remote_credit(l.pn))
 +}
 +func (l Link) Drained() int {
 +	return int(C.pn_link_drained(l.pn))
 +}
 +func (l Link) Available() int {
 +	return int(C.pn_link_available(l.pn))
 +}
 +func (l Link) SndSettleMode() SndSettleMode {
 +	return SndSettleMode(C.pn_link_snd_settle_mode(l.pn))
 +}
 +func (l Link) RcvSettleMode() RcvSettleMode {
 +	return RcvSettleMode(C.pn_link_rcv_settle_mode(l.pn))
 +}
 +func (l Link) SetSndSettleMode(mode SndSettleMode) {
 +	C.pn_link_set_snd_settle_mode(l.pn, C.pn_snd_settle_mode_t(mode))
 +}
 +func (l Link) SetRcvSettleMode(mode RcvSettleMode) {
 +	C.pn_link_set_rcv_settle_mode(l.pn, C.pn_rcv_settle_mode_t(mode))
 +}
 +func (l Link) RemoteSndSettleMode() SndSettleMode {
 +	return SndSettleMode(C.pn_link_remote_snd_settle_mode(l.pn))
 +}
 +func (l Link) RemoteRcvSettleMode() RcvSettleMode {
 +	return RcvSettleMode(C.pn_link_remote_rcv_settle_mode(l.pn))
 +}
 +func (l Link) Unsettled() int {
 +	return int(C.pn_link_unsettled(l.pn))
 +}
 +func (l Link) Offered(credit int) {
 +	C.pn_link_offered(l.pn, C.int(credit))
 +}
 +func (l Link) Flow(credit int) {
 +	C.pn_link_flow(l.pn, C.int(credit))
 +}
 +func (l Link) Drain(credit int) {
 +	C.pn_link_drain(l.pn, C.int(credit))
 +}
 +func (l Link) SetDrain(drain bool) {
 +	C.pn_link_set_drain(l.pn, C.bool(drain))
 +}
 +func (l Link) Draining() bool {
 +	return bool(C.pn_link_draining(l.pn))
 +}
 +
 +// Wrappers for declarations in delivery.h
 +
 +type Delivery struct{ pn *C.pn_delivery_t }
 +
 +func (d Delivery) IsNil() bool          { return d.pn == nil }
 +func (d Delivery) CPtr() unsafe.Pointer { return unsafe.Pointer(d.pn) }
 +func (d Delivery) Tag() DeliveryTag {
 +	return DeliveryTag{C.pn_delivery_tag(d.pn)}
 +}
 +func (d Delivery) Link() Link {
 +	return Link{C.pn_delivery_link(d.pn)}
 +}
 +func (d Delivery) Local() Disposition {
 +	return Disposition{C.pn_delivery_local(d.pn)}
 +}
 +func (d Delivery) LocalState() uint64 {
 +	return uint64(C.pn_delivery_local_state(d.pn))
 +}
 +func (d Delivery) Remote() Disposition {
 +	return Disposition{C.pn_delivery_remote(d.pn)}
 +}
 +func (d Delivery) RemoteState() uint64 {
 +	return uint64(C.pn_delivery_remote_state(d.pn))
 +}
 +func (d Delivery) Settled() bool {
 +	return bool(C.pn_delivery_settled(d.pn))
 +}
 +func (d Delivery) Pending() uint {
 +	return uint(C.pn_delivery_pending(d.pn))
 +}
 +func (d Delivery) Partial() bool {
 +	return bool(C.pn_delivery_partial(d.pn))
 +}
 +func (d Delivery) Writable() bool {
 +	return bool(C.pn_delivery_writable(d.pn))
 +}
 +func (d Delivery) Readable() bool {
 +	return bool(C.pn_delivery_readable(d.pn))
 +}
 +func (d Delivery) Updated() bool {
 +	return bool(C.pn_delivery_updated(d.pn))
 +}
 +func (d Delivery) Update(state uint64) {
 +	C.pn_delivery_update(d.pn, C.uint64_t(state))
 +}
 +func (d Delivery) Clear() {
 +	C.pn_delivery_clear(d.pn)
 +}
 +func (d Delivery) Current() bool {
 +	return bool(C.pn_delivery_current(d.pn))
 +}
 +func (d Delivery) Settle() {
 +	C.pn_delivery_settle(d.pn)
 +}
 +func (d Delivery) Dump() {
 +	C.pn_delivery_dump(d.pn)
 +}
 +func (d Delivery) Buffered() bool {
 +	return bool(C.pn_delivery_buffered(d.pn))
 +}
 +
 +// Wrappers for declarations in disposition.h
 +
 +type Disposition struct{ pn *C.pn_disposition_t }
 +
 +func (d Disposition) IsNil() bool          { return d.pn == nil }
 +func (d Disposition) CPtr() unsafe.Pointer { return unsafe.Pointer(d.pn) }
 +func (d Disposition) Type() uint64 {
 +	return uint64(C.pn_disposition_type(d.pn))
 +}
 +func (d Disposition) Condition() Condition {
 +	return Condition{C.pn_disposition_condition(d.pn)}
 +}
 +func (d Disposition) Data() Data {
 +	return Data{C.pn_disposition_data(d.pn)}
 +}
 +func (d Disposition) SectionNumber() uint16 {
 +	return uint16(C.pn_disposition_get_section_number(d.pn))
 +}
 +func (d Disposition) SetSectionNumber(section_number uint16) {
 +	C.pn_disposition_set_section_number(d.pn, C.uint32_t(section_number))
 +}
 +func (d Disposition) SectionOffset() uint64 {
 +	return uint64(C.pn_disposition_get_section_offset(d.pn))
 +}
 +func (d Disposition) SetSectionOffset(section_offset uint64) {
 +	C.pn_disposition_set_section_offset(d.pn, C.uint64_t(section_offset))
 +}
 +func (d Disposition) IsFailed() bool {
 +	return bool(C.pn_disposition_is_failed(d.pn))
 +}
 +func (d Disposition) SetFailed(failed bool) {
 +	C.pn_disposition_set_failed(d.pn, C.bool(failed))
 +}
 +func (d Disposition) IsUndeliverable() bool {
 +	return bool(C.pn_disposition_is_undeliverable(d.pn))
 +}
 +func (d Disposition) SetUndeliverable(undeliverable bool) {
 +	C.pn_disposition_set_undeliverable(d.pn, C.bool(undeliverable))
 +}
 +func (d Disposition) Annotations() Data {
 +	return Data{C.pn_disposition_annotations(d.pn)}
 +}
 +
 +// Wrappers for declarations in condition.h
 +
 +type Condition struct{ pn *C.pn_condition_t }
 +
 +func (c Condition) IsNil() bool          { return c.pn == nil }
 +func (c Condition) CPtr() unsafe.Pointer { return unsafe.Pointer(c.pn) }
 +func (c Condition) IsSet() bool {
 +	return bool(C.pn_condition_is_set(c.pn))
 +}
 +func (c Condition) Clear() {
 +	C.pn_condition_clear(c.pn)
 +}
 +func (c Condition) Name() string {
 +	return C.GoString(C.pn_condition_get_name(c.pn))
 +}
 +func (c Condition) SetName(name string) int {
 +	nameC := C.CString(name)
 +	defer C.free(unsafe.Pointer(nameC))
 +
 +	return int(C.pn_condition_set_name(c.pn, nameC))
 +}
 +func (c Condition) Description() string {
 +	return C.GoString(C.pn_condition_get_description(c.pn))
 +}
 +func (c Condition) SetDescription(description string) int {
 +	descriptionC := C.CString(description)
 +	defer C.free(unsafe.Pointer(descriptionC))
 +
 +	return int(C.pn_condition_set_description(c.pn, descriptionC))
 +}
 +func (c Condition) Info() Data {
 +	return Data{C.pn_condition_info(c.pn)}
 +}
 +func (c Condition) IsRedirect() bool {
 +	return bool(C.pn_condition_is_redirect(c.pn))
 +}
 +func (c Condition) RedirectHost() string {
 +	return C.GoString(C.pn_condition_redirect_host(c.pn))
 +}
 +func (c Condition) RedirectPort() int {
 +	return int(C.pn_condition_redirect_port(c.pn))
 +}
 +
 +// Wrappers for declarations in terminus.h
 +
 +type TerminusType C.pn_terminus_type_t
 +
 +const (
 +	Unspecified TerminusType = C.PN_UNSPECIFIED
 +	Source      TerminusType = C.PN_SOURCE
 +	Target      TerminusType = C.PN_TARGET
 +	Coordinator TerminusType = C.PN_COORDINATOR
 +)
 +
 +func (e TerminusType) String() string {
 +	switch e {
 +
 +	case C.PN_UNSPECIFIED:
 +		return "Unspecified"
 +	case C.PN_SOURCE:
 +		return "Source"
 +	case C.PN_TARGET:
 +		return "Target"
 +	case C.PN_COORDINATOR:
 +		return "Coordinator"
 +	}
 +	return "unknown"
 +}
 +
 +type Durability C.pn_durability_t
 +
 +const (
 +	Nondurable    Durability = C.PN_NONDURABLE
 +	Configuration Durability = C.PN_CONFIGURATION
 +	Deliveries    Durability = C.PN_DELIVERIES
 +)
 +
 +func (e Durability) String() string {
 +	switch e {
 +
 +	case C.PN_NONDURABLE:
 +		return "Nondurable"
 +	case C.PN_CONFIGURATION:
 +		return "Configuration"
 +	case C.PN_DELIVERIES:
 +		return "Deliveries"
 +	}
 +	return "unknown"
 +}
 +
 +type ExpiryPolicy C.pn_expiry_policy_t
 +
 +const (
 +	ExpireWithLink       ExpiryPolicy = C.PN_EXPIRE_WITH_LINK
 +	ExpireWithSession    ExpiryPolicy = C.PN_EXPIRE_WITH_SESSION
 +	ExpireWithConnection ExpiryPolicy = C.PN_EXPIRE_WITH_CONNECTION
 +	ExpireNever          ExpiryPolicy = C.PN_EXPIRE_NEVER
 +)
 +
 +func (e ExpiryPolicy) String() string {
 +	switch e {
 +
 +	case C.PN_EXPIRE_WITH_LINK:
 +		return "ExpireWithLink"
 +	case C.PN_EXPIRE_WITH_SESSION:
 +		return "ExpireWithSession"
 +	case C.PN_EXPIRE_WITH_CONNECTION:
 +		return "ExpireWithConnection"
 +	case C.PN_EXPIRE_NEVER:
 +		return "ExpireNever"
 +	}
 +	return "unknown"
 +}
 +
 +type DistributionMode C.pn_distribution_mode_t
 +
 +const (
 +	DistModeUnspecified DistributionMode = C.PN_DIST_MODE_UNSPECIFIED
 +	DistModeCopy        DistributionMode = C.PN_DIST_MODE_COPY
 +	DistModeMove        DistributionMode = C.PN_DIST_MODE_MOVE
 +)
 +
 +func (e DistributionMode) String() string {
 +	switch e {
 +
 +	case C.PN_DIST_MODE_UNSPECIFIED:
 +		return "DistModeUnspecified"
 +	case C.PN_DIST_MODE_COPY:
 +		return "DistModeCopy"
 +	case C.PN_DIST_MODE_MOVE:
 +		return "DistModeMove"
 +	}
 +	return "unknown"
 +}
 +
 +type Terminus struct{ pn *C.pn_terminus_t }
 +
 +func (t Terminus) IsNil() bool          { return t.pn == nil }
 +func (t Terminus) CPtr() unsafe.Pointer { return unsafe.Pointer(t.pn) }
 +func (t Terminus) Type() TerminusType {
 +	return TerminusType(C.pn_terminus_get_type(t.pn))
 +}
 +func (t Terminus) SetType(type_ TerminusType) int {
 +	return int(C.pn_terminus_set_type(t.pn, C.pn_terminus_type_t(type_)))
 +}
 +func (t Terminus) Address() string {
 +	return C.GoString(C.pn_terminus_get_address(t.pn))
 +}
 +func (t Terminus) SetAddress(address string) int {
 +	addressC := C.CString(address)
 +	defer C.free(unsafe.Pointer(addressC))
 +
 +	return int(C.pn_terminus_set_address(t.pn, addressC))
 +}
 +func (t Terminus) SetDistributionMode(mode DistributionMode) int {
 +	return int(C.pn_terminus_set_distribution_mode(t.pn, C.pn_distribution_mode_t(mode)))
 +}
 +func (t Terminus) Durability() Durability {
 +	return Durability(C.pn_terminus_get_durability(t.pn))
 +}
 +func (t Terminus) SetDurability(durability Durability) int {
 +	return int(C.pn_terminus_set_durability(t.pn, C.pn_durability_t(durability)))
 +}
 +func (t Terminus) ExpiryPolicy() ExpiryPolicy {
 +	return ExpiryPolicy(C.pn_terminus_get_expiry_policy(t.pn))
 +}
 +func (t Terminus) SetExpiryPolicy(policy ExpiryPolicy) int {
 +	return int(C.pn_terminus_set_expiry_policy(t.pn, C.pn_expiry_policy_t(policy)))
 +}
 +func (t Terminus) Timeout() time.Duration {
 +	return (time.Duration(C.pn_terminus_get_timeout(t.pn)) * time.Second)
 +}
 +func (t Terminus) SetTimeout(timeout time.Duration) int {
- 	return int(C.pn_terminus_set_timeout(t.pn, C.pn_seconds_t(timeout)))
++	return int(C.pn_terminus_set_timeout(t.pn, C.pn_seconds_t(timeout/time.Second)))
 +}
 +func (t Terminus) IsDynamic() bool {
 +	return bool(C.pn_terminus_is_dynamic(t.pn))
 +}
 +func (t Terminus) SetDynamic(dynamic bool) int {
 +	return int(C.pn_terminus_set_dynamic(t.pn, C.bool(dynamic)))
 +}
 +func (t Terminus) Properties() Data {
 +	return Data{C.pn_terminus_properties(t.pn)}
 +}
 +func (t Terminus) Capabilities() Data {
 +	return Data{C.pn_terminus_capabilities(t.pn)}
 +}
 +func (t Terminus) Outcomes() Data {
 +	return Data{C.pn_terminus_outcomes(t.pn)}
 +}
 +func (t Terminus) Filter() Data {
 +	return Data{C.pn_terminus_filter(t.pn)}
 +}
 +func (t Terminus) Copy(src Terminus) int {
 +	return int(C.pn_terminus_copy(t.pn, src.pn))
 +}
 +
 +// Wrappers for declarations in connection.h
 +
 +type Connection struct{ pn *C.pn_connection_t }
 +
 +func (c Connection) IsNil() bool          { return c.pn == nil }
 +func (c Connection) CPtr() unsafe.Pointer { return unsafe.Pointer(c.pn) }
 +func (c Connection) Free() {
 +	C.pn_connection_free(c.pn)
 +}
 +func (c Connection) Release() {
 +	C.pn_connection_release(c.pn)
 +}
 +func (c Connection) Error() error {
 +	return PnError(C.pn_connection_error(c.pn))
 +}
 +func (c Connection) State() State {
 +	return State(C.pn_connection_state(c.pn))
 +}
 +func (c Connection) Open() {
 +	C.pn_connection_open(c.pn)
 +}
 +func (c Connection) Close() {
 +	C.pn_connection_close(c.pn)
 +}
 +func (c Connection) Reset() {
 +	C.pn_connection_reset(c.pn)
 +}
 +func (c Connection) Condition() Condition {
 +	return Condition{C.pn_connection_condition(c.pn)}
 +}
 +func (c Connection) RemoteCondition() Condition {
 +	return Condition{C.pn_connection_remote_condition(c.pn)}
 +}
 +func (c Connection) Container() string {
 +	return C.GoString(C.pn_connection_get_container(c.pn))
 +}
 +func (c Connection) SetContainer(container string) {
 +	containerC := C.CString(container)
 +	defer C.free(unsafe.Pointer(containerC))
 +
 +	C.pn_connection_set_container(c.pn, containerC)
 +}
 +func (c Connection) SetUser(user string) {
 +	userC := C.CString(user)
 +	defer C.free(unsafe.Pointer(userC))
 +
 +	C.pn_connection_set_user(c.pn, userC)
 +}
 +func (c Connection) User() string {
 +	return C.GoString(C.pn_connection_get_user(c.pn))
 +}
 +func (c Connection) Hostname() string {
 +	return C.GoString(C.pn_connection_get_hostname(c.pn))
 +}
 +func (c Connection) SetHostname(hostname string) {
 +	hostnameC := C.CString(hostname)
 +	defer C.free(unsafe.Pointer(hostnameC))
 +
 +	C.pn_connection_set_hostname(c.pn, hostnameC)
 +}
 +func (c Connection) RemoteContainer() string {
 +	return C.GoString(C.pn_connection_remote_container(c.pn))
 +}
 +func (c Connection) RemoteHostname() string {
 +	return C.GoString(C.pn_connection_remote_hostname(c.pn))
 +}
 +func (c Connection) OfferedCapabilities() Data {
 +	return Data{C.pn_connection_offered_capabilities(c.pn)}
 +}
 +func (c Connection) DesiredCapabilities() Data {
 +	return Data{C.pn_connection_desired_capabilities(c.pn)}
 +}
 +func (c Connection) Properties() Data {
 +	return Data{C.pn_connection_properties(c.pn)}
 +}
 +func (c Connection) RemoteOfferedCapabilities() Data {
 +	return Data{C.pn_connection_remote_offered_capabilities(c.pn)}
 +}
 +func (c Connection) RemoteDesiredCapabilities() Data {
 +	return Data{C.pn_connection_remote_desired_capabilities(c.pn)}
 +}
 +func (c Connection) RemoteProperties() Data {
 +	return Data{C.pn_connection_remote_properties(c.pn)}
 +}
 +func (c Connection) Transport() Transport {
 +	return Transport{C.pn_connection_transport(c.pn)}
 +}
 +
 +// Wrappers for declarations in transport.h
 +
 +type Transport struct{ pn *C.pn_transport_t }
 +
 +func (t Transport) IsNil() bool          { return t.pn == nil }
 +func (t Transport) CPtr() unsafe.Pointer { return unsafe.Pointer(t.pn) }
 +func (t Transport) SetServer() {
 +	C.pn_transport_set_server(t.pn)
 +}
 +func (t Transport) Free() {
 +	C.pn_transport_free(t.pn)
 +}
 +func (t Transport) User() string {
 +	return C.GoString(C.pn_transport_get_user(t.pn))
 +}
 +func (t Transport) RequireAuth(required bool) {
 +	C.pn_transport_require_auth(t.pn, C.bool(required))
 +}
 +func (t Transport) IsAuthenticated() bool {
 +	return bool(C.pn_transport_is_authenticated(t.pn))
 +}
 +func (t Transport) RequireEncryption(required bool) {
 +	C.pn_transport_require_encryption(t.pn, C.bool(required))
 +}
 +func (t Transport) IsEncrypted() bool {
 +	return bool(C.pn_transport_is_encrypted(t.pn))
 +}
 +func (t Transport) Condition() Condition {
 +	return Condition{C.pn_transport_condition(t.pn)}
 +}
 +func (t Transport) Error() error {
 +	return PnError(C.pn_transport_error(t.pn))
 +}
 +func (t Transport) Bind(connection Connection) int {
 +	return int(C.pn_transport_bind(t.pn, connection.pn))
 +}
 +func (t Transport) Unbind() int {
 +	return int(C.pn_transport_unbind(t.pn))
 +}
 +func (t Transport) Log(message string) {
 +	messageC := C.CString(message)
 +	defer C.free(unsafe.Pointer(messageC))
 +
 +	C.pn_transport_log(t.pn, messageC)
 +}
 +func (t Transport) ChannelMax() uint32 {
 +	return uint32(C.pn_transport_get_channel_max(t.pn))
 +}
 +func (t Transport) SetChannelMax(channel_max uint32) int {
 +	return int(C.pn_transport_set_channel_max(t.pn, C.uint16_t(channel_max)))
 +}
 +func (t Transport) RemoteChannelMax() uint32 {
 +	return uint32(C.pn_transport_remote_channel_max(t.pn))
 +}
 +func (t Transport) MaxFrame() uint16 {
 +	return uint16(C.pn_transport_get_max_frame(t.pn))
 +}
 +func (t Transport) SetMaxFrame(size uint16) {
 +	C.pn_transport_set_max_frame(t.pn, C.uint32_t(size))
 +}
 +func (t Transport) RemoteMaxFrame() uint16 {
 +	return uint16(C.pn_transport_get_remote_max_frame(t.pn))
 +}
 +func (t Transport) IdleTimeout() time.Duration {
 +	return (time.Duration(C.pn_transport_get_idle_timeout(t.pn)) * time.Millisecond)
 +}
 +func (t Transport) SetIdleTimeout(timeout time.Duration) {
 +	C.pn_transport_set_idle_timeout(t.pn, C.pn_millis_t(timeout/time.Millisecond))
 +}
 +func (t Transport) RemoteIdleTimeout() time.Duration {
 +	return (time.Duration(C.pn_transport_get_remote_idle_timeout(t.pn)) * time.Millisecond)
 +}
 +func (t Transport) Input(bytes string, available uint) int {
 +	bytesC := C.CString(bytes)
 +	defer C.free(unsafe.Pointer(bytesC))
 +
 +	return int(C.pn_transport_input(t.pn, bytesC, C.size_t(available)))
 +}
 +func (t Transport) Output(bytes string, size uint) int {
 +	bytesC := C.CString(bytes)
 +	defer C.free(unsafe.Pointer(bytesC))
 +
 +	return int(C.pn_transport_output(t.pn, bytesC, C.size_t(size)))
 +}
 +func (t Transport) Capacity() int {
 +	return int(C.pn_transport_capacity(t.pn))
 +}
 +func (t Transport) Process(size uint) int {
 +	return int(C.pn_transport_process(t.pn, C.size_t(size)))
 +}
 +func (t Transport) CloseTail() int {
 +	return int(C.pn_transport_close_tail(t.pn))
 +}
 +func (t Transport) Pending() int {
 +	return int(C.pn_transport_pending(t.pn))
 +}
 +func (t Transport) Peek(dst string, size uint) int {
 +	dstC := C.CString(dst)
 +	defer C.free(unsafe.Pointer(dstC))
 +
 +	return int(C.pn_transport_peek(t.pn, dstC, C.size_t(size)))
 +}
 +func (t Transport) Pop(size uint) {
 +	C.pn_transport_pop(t.pn, C.size_t(size))
 +}
 +func (t Transport) CloseHead() int {
 +	return int(C.pn_transport_close_head(t.pn))
 +}
 +func (t Transport) Quiesced() bool {
 +	return bool(C.pn_transport_quiesced(t.pn))
 +}
 +func (t Transport) Closed() bool {
 +	return bool(C.pn_transport_closed(t.pn))
 +}
 +func (t Transport) Tick(now time.Time) time.Time {
 +	return goTime(C.pn_transport_tick(t.pn, pnTime(now)))
 +}
 +func (t Transport) Connection() Connection {
 +	return Connection{C.pn_transport_connection(t.pn)}
 +}
 +
 +// Wrappers for declarations in sasl.h
 +
 +type SASLOutcome C.pn_sasl_outcome_t
 +
 +const (
 +	SASLNone SASLOutcome = C.PN_SASL_NONE
 +	SASLOk   SASLOutcome = C.PN_SASL_OK
 +	SASLAuth SASLOutcome = C.PN_SASL_AUTH
 +	SASLSys  SASLOutcome = C.PN_SASL_SYS
 +	SASLPerm SASLOutcome = C.PN_SASL_PERM
 +	SASLTemp SASLOutcome = C.PN_SASL_TEMP
 +)
 +
 +func (e SASLOutcome) String() string {
 +	switch e {
 +
 +	case C.PN_SASL_NONE:
 +		return "SASLNone"
 +	case C.PN_SASL_OK:
 +		return "SASLOk"
 +	case C.PN_SASL_AUTH:
 +		return "SASLAuth"
 +	case C.PN_SASL_SYS:
 +		return "SASLSys"
 +	case C.PN_SASL_PERM:
 +		return "SASLPerm"
 +	case C.PN_SASL_TEMP:
 +		return "SASLTemp"
 +	}
 +	return "unknown"
 +}
 +
 +type SASL struct{ pn *C.pn_sasl_t }
 +
 +func (s SASL) IsNil() bool          { return s.pn == nil }
 +func (s SASL) CPtr() unsafe.Pointer { return unsafe.Pointer(s.pn) }
 +func (s SASL) Done(outcome SASLOutcome) {
 +	C.pn_sasl_done(s.pn, C.pn_sasl_outcome_t(outcome))
 +}
 +func (s SASL) Outcome() SASLOutcome {
 +	return SASLOutcome(C.pn_sasl_outcome(s.pn))
 +}
 +func (s SASL) User() string {
 +	return C.GoString(C.pn_sasl_get_user(s.pn))
 +}
 +func (s SASL) Mech() string {
 +	return C.GoString(C.pn_sasl_get_mech(s.pn))
 +}
 +func (s SASL) AllowedMechs(mechs string) {
 +	mechsC := C.CString(mechs)
 +	defer C.free(unsafe.Pointer(mechsC))
 +
 +	C.pn_sasl_allowed_mechs(s.pn, mechsC)
 +}
 +func (s SASL) SetAllowInsecureMechs(insecure bool) {
 +	C.pn_sasl_set_allow_insecure_mechs(s.pn, C.bool(insecure))
 +}
 +func (s SASL) AllowInsecureMechs() bool {
 +	return bool(C.pn_sasl_get_allow_insecure_mechs(s.pn))
 +}
 +func (s SASL) ConfigName(name string) {
 +	nameC := C.CString(name)
 +	defer C.free(unsafe.Pointer(nameC))
 +
 +	C.pn_sasl_config_name(s.pn, nameC)
 +}
 +func (s SASL) ConfigPath(path string) {
 +	pathC := C.CString(path)
 +	defer C.free(unsafe.Pointer(pathC))
 +
 +	C.pn_sasl_config_path(s.pn, pathC)
 +}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/569b4fca/readme-go-get.md
----------------------------------------------------------------------
diff --cc readme-go-get.md
index 6eb1e2b,0000000..c59561f
mode 100644,000000..100644
--- a/readme-go-get.md
+++ b/readme-go-get.md
@@@ -1,18 -1,0 +1,19 @@@
 +The go-only subtree of proton is maintained on the branch `go1` for the `go get`
 +command.  `go1` is special to the `go get` command, it will use that branch
 +rather than `master` when it is present.
 +
 +Created with:
 +
 +    git subtree split --prefix=proton-c/bindings/go/src/qpid.apache.org -b go1
 +
 +Update with:
 +
 +    git checkout go1
++    git pull
 +    git merge -s recursive -Xsubtree=proton-c/bindings/go/src/qpid.apache.org master
 +
 +To see the branch description: `git config branch.go1.description`
 +
 +NOTE: when updating the branch, you should also visit the doc pages at
 +https://godoc.org/?q=qpid.apache.org and click "Refresh now" at the bottom of
 +the page


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[06/38] qpid-proton git commit: PROTON-1401: Change pn_handle_t type for more correct constness [ABI change]

Posted by ac...@apache.org.
PROTON-1401: Change pn_handle_t type for more correct constness [ABI change]


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/431696d2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/431696d2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/431696d2

Branch: refs/heads/go1
Commit: 431696d22df9923543406af6f082afcef9cdd923
Parents: a96bccb
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Feb 7 12:29:25 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Feb 9 21:31:41 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/include/proton/internal/data.hpp | 6 +++---
 proton-c/bindings/cpp/src/data.cpp                     | 4 ++--
 proton-c/include/proton/object.h                       | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/431696d2/proton-c/bindings/cpp/include/proton/internal/data.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/data.hpp b/proton-c/bindings/cpp/include/proton/internal/data.hpp
index bfc0e33..0e35486 100644
--- a/proton-c/bindings/cpp/include/proton/internal/data.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/data.hpp
@@ -65,8 +65,8 @@ class data : public object<pn_data_t> {
     PN_CPP_EXTERN int appendn(data src, int limit);
 
     PN_CPP_EXTERN bool next();
-    PN_CPP_EXTERN void* point() const;
-    PN_CPP_EXTERN void restore(void* h);
+    PN_CPP_EXTERN const void* point() const;
+    PN_CPP_EXTERN void restore(const void* h);
 
   protected:
     void narrow();
@@ -85,7 +85,7 @@ class data : public object<pn_data_t> {
 struct state_guard {
     /// @cond INTERNAL
     data& data_;
-    void* point_;
+    const void* point_;
     bool cancel_;
     /// @endcond
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/431696d2/proton-c/bindings/cpp/src/data.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/data.cpp b/proton-c/bindings/cpp/src/data.cpp
index 0f6e7f5..a8ebbec 100644
--- a/proton-c/bindings/cpp/src/data.cpp
+++ b/proton-c/bindings/cpp/src/data.cpp
@@ -46,9 +46,9 @@ void data::rewind() { ::pn_data_rewind(pn_object()); }
 
 bool data::empty() const { return ::pn_data_size(pn_object()) == 0; }
 
-void* data::point() const { return pn_data_point(pn_object()); }
+const void* data::point() const { return pn_data_point(pn_object()); }
 
-void data::restore(void* h) { pn_data_restore(pn_object(), pn_handle_t(h)); }
+void data::restore(const void* h) { pn_data_restore(pn_object(), pn_handle_t(h)); }
 
 void data::narrow() { pn_data_narrow(pn_object()); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/431696d2/proton-c/include/proton/object.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/object.h b/proton-c/include/proton/object.h
index e7efd94..bbd7de0 100644
--- a/proton-c/include/proton/object.h
+++ b/proton-c/include/proton/object.h
@@ -37,7 +37,7 @@ extern "C" {
  * @cond INTERNAL
  */
 
-typedef void* pn_handle_t;
+typedef const void* pn_handle_t;
 typedef intptr_t pn_shandle_t;
 
 typedef struct pn_class_t pn_class_t;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[26/38] qpid-proton git commit: PROTON-1403: Rename pn_proactor_grab -> pn_proactor_get

Posted by ac...@apache.org.
PROTON-1403: Rename pn_proactor_grab -> pn_proactor_get


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6a2316a5
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6a2316a5
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6a2316a5

Branch: refs/heads/go1
Commit: 6a2316a5d0a4e274802de81744ceae534323ba17
Parents: 7368c34
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 17 13:40:52 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Feb 17 13:40:52 2017 -0500

----------------------------------------------------------------------
 proton-c/include/proton/proactor.h | 2 +-
 proton-c/src/proactor/libuv.c      | 2 +-
 proton-c/src/tests/proactor.c      | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6a2316a5/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index af3acbc..94c4891 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -119,7 +119,7 @@ PNP_EXTERN pn_event_batch_t *pn_proactor_wait(pn_proactor_t *proactor);
  * Return a batch of events if one is available immediately, otherwise return NULL.  If it
  * does return an event batch, the rules are the same as for pn_proactor_wait()
  */
-PNP_EXTERN pn_event_batch_t *pn_proactor_grab(pn_proactor_t *proactor);
+PNP_EXTERN pn_event_batch_t *pn_proactor_get(pn_proactor_t *proactor);
 
 /**
  * Call when done handling a batch of events.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6a2316a5/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 0e87d0a..d2badbe 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -781,7 +781,7 @@ pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
   return batch;
 }
 
-pn_event_batch_t *pn_proactor_grab(struct pn_proactor_t* p) {
+pn_event_batch_t *pn_proactor_get(struct pn_proactor_t* p) {
   uv_mutex_lock(&p->lock);
   pn_event_batch_t *batch = get_batch_lh(p);
   if (batch == NULL && !p->has_leader) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6a2316a5/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index e90c45a..9f8b1fe 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -90,7 +90,7 @@ static void proactor_test_init(proactor_test_t *pts, size_t n) {
 }
 
 /* Iterate over an array of proactors, draining or handling events with the non-blocking
-   pn_proactor_grab.  Continue till all handlers return H_FINISHED (and return 0) or one
+   pn_proactor_get.  Continue till all handlers return H_FINISHED (and return 0) or one
    returns H_FAILED  (and return non-0)
 */
 int proactor_test_run(proactor_test_t *pts, size_t n) {
@@ -100,7 +100,7 @@ int proactor_test_run(proactor_test_t *pts, size_t n) {
   do {
     finished = 0;
     for (proactor_test_t *pt = pts; pt < pts + n; ++pt) {
-      pn_event_batch_t *events = pn_proactor_grab(pt->proactor);
+      pn_event_batch_t *events = pn_proactor_get(pt->proactor);
       if (events) {
           pn_event_t *e;
           while ((e = pn_event_batch_next(events))) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[13/38] qpid-proton git commit: PROTON-1403: c proactor remove incorrect asserts

Posted by ac...@apache.org.
PROTON-1403: c proactor remove incorrect asserts


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a21a03ee
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a21a03ee
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a21a03ee

Branch: refs/heads/go1
Commit: a21a03ee6ddea533c1de74e564f364952c12f515
Parents: 31b8cc6
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Feb 13 14:47:35 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Feb 13 14:48:42 2017 -0500

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c | 3 ---
 1 file changed, 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a21a03ee/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 6064bd6..29463d5 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -901,17 +901,14 @@ pn_condition_t* pn_listener_condition(pn_listener_t* l) {
 }
 
 void *pn_listener_get_context(pn_listener_t *l) {
-  assert(l->psocket.state == ON_WORKER);
   return l->context;
 }
 
 void pn_listener_set_context(pn_listener_t *l, void *context) {
-  assert(l->psocket.state == ON_WORKER);
   l->context = context;
 }
 
 pn_record_t *pn_listener_attachments(pn_listener_t *l) {
-  assert(l->psocket.state == ON_WORKER);
   return l->attachments;
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[29/38] qpid-proton git commit: PROTON-1403: C libuv proactor was not delivering interrupts correctly

Posted by ac...@apache.org.
PROTON-1403: C libuv proactor was not delivering interrupts correctly


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6b6dd869
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6b6dd869
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6b6dd869

Branch: refs/heads/go1
Commit: 6b6dd86990be06ec10d0abc94a55b63b565287c6
Parents: 31a3c99
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Feb 20 13:29:40 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Feb 20 15:12:34 2017 -0500

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6b6dd869/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index d2badbe..c7322cd 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -71,7 +71,6 @@
   of the uv_tcp_t handle, and executed in an on_close() handler when it is safe.
 */
 
-const char *COND_NAME = "proactor";
 const char *AMQP_PORT = "5672";
 const char *AMQP_PORT_NAME = "amqp";
 const char *AMQPS_PORT = "5671";
@@ -356,7 +355,7 @@ int pconnection_error(pconnection_t *pc, int err, const char* what) {
   if (err) {
     pn_connection_driver_t *driver = &pc->driver;
     pn_connection_driver_bind(driver); /* Bind so errors will be reported */
-    pn_connection_driver_errorf(driver, COND_NAME, "%s %s:%s: %s",
+    pn_connection_driver_errorf(driver, uv_err_name(err), "%s %s:%s: %s",
                                 what, fixstr(pc->psocket.host), fixstr(pc->psocket.port),
                                 uv_strerror(err));
     pn_connection_driver_close(driver);
@@ -629,7 +628,7 @@ static void listener_to_worker(pn_listener_t *l) {
     to_worker(&l->psocket);
   } else if (l->err) {
     if (l->err != UV_EOF) {
-      pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
+      pn_condition_format(l->condition, uv_err_name(l->err), "%s %s:%s: %s",
                           l->what, fixstr(l->psocket.host), fixstr(l->psocket.port),
                           uv_strerror(l->err));
     }
@@ -721,9 +720,9 @@ void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
     uv_mutex_lock(&p->lock);
     p->batch_working = false;
     uv_mutex_unlock(&p->lock);
+    uv_async_send(&p->async); /* Wake leader */
     return;
   }
-  uv_async_send(&p->async); /* Wake leader */
 }
 
 /* Process the leader_q, in the leader thread */
@@ -802,7 +801,7 @@ void pn_proactor_interrupt(pn_proactor_t *p) {
   uv_mutex_lock(&p->lock);
   ++p->interrupt;
   uv_mutex_unlock(&p->lock);
-  uv_async_send(&p->async);   /* Interrupt the UV loop */
+  uv_async_send(&p->async);   /* Wake the UV loop */
 }
 
 void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
@@ -810,7 +809,7 @@ void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
   p->timeout = t;
   p->timeout_request = true;
   uv_mutex_unlock(&p->lock);
-  uv_async_send(&p->async);   /* Interrupt the UV loop */
+  uv_async_send(&p->async);   /* Wake the UV loop */
 }
 
 int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[36/38] qpid-proton git commit: NO-JIRA: go wrappers re-generated to be compatible with proton-c 0.10

Posted by ac...@apache.org.
NO-JIRA: go wrappers re-generated to be compatible with proton-c 0.10

Some new definitions had creeped into the wrappers_gen.go that would fail to
build with older versions of proton-c.

Updated genwrap.go:
- -include option generates from installed headers instead of git source
- explicitly include the intended minimum C version
- fail attempts to generate from newer headers

Added test-versions.sh, takes a list of install prefixes where proton is
installed and runs go test on the git go sources against each one.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/c94301d5
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/c94301d5
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/c94301d5

Branch: refs/heads/go1
Commit: c94301d59ce0a9a8863d3bd71919c1acfebce533
Parents: c87b23e
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 16:39:14 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 17:10:22 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/go/genwrap.go                 | 77 ++++++++++++++++----
 .../go/src/qpid.apache.org/amqp/version.go      |  8 +-
 .../src/qpid.apache.org/proton/wrappers_gen.go  | 39 +---------
 proton-c/bindings/go/test-versions.sh           | 50 +++++++++++++
 4 files changed, 125 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c94301d5/proton-c/bindings/go/genwrap.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/genwrap.go b/proton-c/bindings/go/genwrap.go
index 6885b74..0bf13fa 100644
--- a/proton-c/bindings/go/genwrap.go
+++ b/proton-c/bindings/go/genwrap.go
@@ -22,6 +22,12 @@ under the License.
 // Not run automatically, generated sources are checked in. To update the
 // generated sources run `go run genwrap.go` in this directory.
 //
+// WARNING: generating code from the wrong proton header file versions
+// will break compatibility guarantees. This program will attempt to detect
+// such errors. If you are deliberately changing the compatibility requirements
+// update the variable minVersion below.
+//
+
 package main
 
 import (
@@ -37,12 +43,61 @@ import (
 	"text/template"
 )
 
-var includeProton = "../../include/proton"
-var outpath = "src/qpid.apache.org/proton/wrappers_gen.go"
+var minVersion = "0.10" // The minimum version of proton-c that the Go binding can use
+var include = flag.String("include", "../../include", "Directory containing proton/*.h include files")
+
+var versionH = regexp.MustCompile("(?s:PN_VERSION_MAJOR ([0-9]+).*PN_VERSION_MINOR ([0-9]+))")
+var versionTxt = regexp.MustCompile("^[0-9]+\\.[0-9]+")
 
 func main() {
 	flag.Parse()
-	out, err := os.Create(outpath)
+	genVersion()
+	genWrappers()
+}
+
+func getVersion() string {
+	_, err := ioutil.ReadFile(path.Join(*include, "proton/version.h.in"))
+	if err == nil {
+		// We are using the headers in git sources, get the version.txt
+		vt, err := ioutil.ReadFile(path.Join(*include, "../../version.txt"))
+		panicIf(err)
+		return versionTxt.FindString(string(vt))
+	}
+	vh, err := ioutil.ReadFile(path.Join(*include, "proton/version.h"))
+	if err == nil {
+		// We are using installed headers
+		return strings.Join(versionH.FindStringSubmatch(string(vh))[1:], ".")
+	}
+	panic(err)
+}
+
+func genVersion() {
+	version := getVersion()
+	if minVersion != version {
+		panic(fmt.Errorf("Generating from wrong version %v, expected %v", version, minVersion))
+	}
+	out, err := os.Create("src/qpid.apache.org/amqp/version.go")
+	panicIf(err)
+	defer out.Close()
+	splitVersion := strings.Split(minVersion, ".")
+	fmt.Fprintf(out, copyright+`
+
+package amqp
+
+// Version check for proton library.
+// Done here because this is the lowest-level dependency for all the proton Go packages.
+
+// #include <proton/version.h>
+// #if PN_VERSION_MAJOR == %s && PN_VERSION_MINOR < %s
+// #error packages qpid.apache.org/... require Proton-C library version 0.10 or greater
+// #endif
+import "C"
+`, splitVersion[0], splitVersion[1])
+}
+
+func genWrappers() {
+	outPath := "src/qpid.apache.org/proton/wrappers_gen.go"
+	out, err := os.Create(outPath)
 	panicIf(err)
 	defer out.Close()
 
@@ -56,11 +111,13 @@ import (
   "unsafe"
 )
 
-// #include <proton/types.h>
-// #include <proton/error.h>
 // #include <proton/condition.h>
+// #include <proton/error.h>
 // #include <proton/event.h>
+// #include <proton/types.h>
 // #include <stdlib.h>
+import "C"
+
 `)
 	for _, api := range apis {
 		fmt.Fprintf(out, "// #include <proton/%s.h>\n", api)
@@ -79,13 +136,7 @@ import (
 		apiWrapFns(api, header, out)
 	}
 	out.Close()
-
-	// Run gofmt.
-	cmd := exec.Command("gofmt", "-w", outpath)
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	err = cmd.Run()
-	if err != nil {
+	if err := exec.Command("gofmt", "-w", outPath).Run(); err != nil {
 		fmt.Fprintf(os.Stderr, "gofmt: %s", err)
 		os.Exit(1)
 	}
@@ -161,7 +212,7 @@ func panicIf(err error) {
 }
 
 func readHeader(name string) string {
-	s, err := ioutil.ReadFile(path.Join(includeProton, name+".h"))
+	s, err := ioutil.ReadFile(path.Join(*include, "proton", name+".h"))
 	panicIf(err)
 	return string(s)
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c94301d5/proton-c/bindings/go/src/qpid.apache.org/amqp/version.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/version.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/version.go
index cefa904..bf33d2b 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/version.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/version.go
@@ -17,13 +17,19 @@ specific language governing permissions and limitations
 under the License.
 */
 
+//
+// NOTE: DO NOT EDIT. This file was generated by genwrap.go from the proton header files.
+// Update the generator and re-run if you need to modify this code.
+//
+
+
 package amqp
 
 // Version check for proton library.
 // Done here because this is the lowest-level dependency for all the proton Go packages.
 
 // #include <proton/version.h>
-// #if PN_VERSION_MINOR < 10
+// #if PN_VERSION_MAJOR == 0 && PN_VERSION_MINOR < 10
 // #error packages qpid.apache.org/... require Proton-C library version 0.10 or greater
 // #endif
 import "C"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c94301d5/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go b/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
index a6c6635..0db04c8 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers_gen.go
@@ -29,11 +29,13 @@ import (
 	"unsafe"
 )
 
-// #include <proton/types.h>
-// #include <proton/error.h>
 // #include <proton/condition.h>
+// #include <proton/error.h>
 // #include <proton/event.h>
+// #include <proton/types.h>
 // #include <stdlib.h>
+import "C"
+
 // #include <proton/session.h>
 // #include <proton/link.h>
 // #include <proton/delivery.h>
@@ -78,13 +80,6 @@ const (
 	ETransportHeadClosed    EventType = C.PN_TRANSPORT_HEAD_CLOSED
 	ETransportTailClosed    EventType = C.PN_TRANSPORT_TAIL_CLOSED
 	ETransportClosed        EventType = C.PN_TRANSPORT_CLOSED
-	EConnectionWake         EventType = C.PN_CONNECTION_WAKE
-	EListenerAccept         EventType = C.PN_LISTENER_ACCEPT
-	EListenerClose          EventType = C.PN_LISTENER_CLOSE
-	EProactorInterrupt      EventType = C.PN_PROACTOR_INTERRUPT
-	EProactorTimeout        EventType = C.PN_PROACTOR_TIMEOUT
-	EProactorInactive       EventType = C.PN_PROACTOR_INACTIVE
-	EListenerOpen           EventType = C.PN_LISTENER_OPEN
 )
 
 func (e EventType) String() string {
@@ -150,20 +145,6 @@ func (e EventType) String() string {
 		return "TransportTailClosed"
 	case C.PN_TRANSPORT_CLOSED:
 		return "TransportClosed"
-	case C.PN_CONNECTION_WAKE:
-		return "ConnectionWake"
-	case C.PN_LISTENER_ACCEPT:
-		return "ListenerAccept"
-	case C.PN_LISTENER_CLOSE:
-		return "ListenerClose"
-	case C.PN_PROACTOR_INTERRUPT:
-		return "ProactorInterrupt"
-	case C.PN_PROACTOR_TIMEOUT:
-		return "ProactorTimeout"
-	case C.PN_PROACTOR_INACTIVE:
-		return "ProactorInactive"
-	case C.PN_LISTENER_OPEN:
-		return "ListenerOpen"
 	}
 	return "Unknown"
 }
@@ -373,15 +354,6 @@ func (l Link) SetDrain(drain bool) {
 func (l Link) Draining() bool {
 	return bool(C.pn_link_draining(l.pn))
 }
-func (l Link) MaxMessageSize() uint64 {
-	return uint64(C.pn_link_max_message_size(l.pn))
-}
-func (l Link) SetMaxMessageSize(size uint64) {
-	C.pn_link_set_max_message_size(l.pn, C.uint64_t(size))
-}
-func (l Link) RemoteMaxMessageSize() uint64 {
-	return uint64(C.pn_link_remote_max_message_size(l.pn))
-}
 
 // Wrappers for declarations in delivery.h
 
@@ -529,9 +501,6 @@ func (c Condition) RedirectHost() string {
 func (c Condition) RedirectPort() int {
 	return int(C.pn_condition_redirect_port(c.pn))
 }
-func (c Condition) Copy(src Condition) int {
-	return int(C.pn_condition_copy(c.pn, src.pn))
-}
 
 // Wrappers for declarations in terminus.h
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c94301d5/proton-c/bindings/go/test-versions.sh
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/test-versions.sh b/proton-c/bindings/go/test-versions.sh
new file mode 100755
index 0000000..0022ce3
--- /dev/null
+++ b/proton-c/bindings/go/test-versions.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Takes a list of install prefixes and tests the go source under the current directory
+# against the proton install in each prefix.
+#
+# NOTE: This script will fail if it finds proton headers or libraries installed in standard
+# places or on the existing paths, to avoid possible confusion.
+#
+
+for VAR in LD_LIBRARY_PATH LIBRARY_PATH C_INCLUDE_PATH; do
+    declare OLD_${VAR}=${!VAR};
+done
+
+prefix() {
+    prefix=$1
+    export LD_LIBRARY_PATH="$prefix/lib64:$prefix/lib:$OLD_LD_LIBRARY_PATH"
+    export LIBRARY_PATH="$prefix/lib64:$prefix/lib:$OLD_LIBRARY_PATH"
+    export C_INCLUDE_PATH="$prefix/include:$OLD_C_INCLUDE_PATH"
+}
+
+TEMP=$(mktemp -d)
+trap "rm -rf $TEMP"  EXIT
+set -o pipefail
+
+cat > $TEMP/test.c  <<EOF
+#include <proton/connection.h>
+int main(int c, char **a) { return 0; }
+EOF
+cc $TEMP/test.c 2> /dev/null && {
+    echo "cc found proton in include path"; cc -E | grep proton/connection.h | head -n1; exit 1; } 1>&2
+
+cat > $TEMP/test.c  <<EOF
+int main(int c, char **a) { return 0; }
+EOF
+cc -lqpid-proton $TEMPC 2>/dev/null && { echo "cc found proton in library path" 1>&2 ; exit 1; }
+
+for P in "$@"; do
+    (
+        case $P in
+            /*) ;;
+            *) P=$PWD/$P;;
+        esac
+        test -d $P || { echo "no such directory: $P"; continue; }
+        echo ==== $P
+        prefix $P
+        export GOPATH=$PWD
+        git clean -dfx
+        go test qpid.apache.org/...
+    )
+done


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[28/38] qpid-proton git commit: PROTON-1403: C proactor examples default to explicit IPv4

Posted by ac...@apache.org.
PROTON-1403: C proactor examples default to explicit IPv4

Use explicit IPv4 addresses to make the C examples interop more smoothly by
default with other examples, qpid-dispatch and other brokers. Command line
options still allow IPv6 addresses


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/31a3c99e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/31a3c99e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/31a3c99e

Branch: refs/heads/go1
Commit: 31a3c99e811d33e9baef362e322605152e4e91aa
Parents: d5c0152
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 17 17:35:22 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Feb 20 15:11:00 2017 -0500

----------------------------------------------------------------------
 examples/c/proactor/broker.c  | 12 +++++++-----
 examples/c/proactor/direct.c  | 13 ++++++++-----
 examples/c/proactor/receive.c | 11 ++++++++---
 examples/c/proactor/send.c    | 11 ++++++++---
 4 files changed, 31 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31a3c99e/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index 2a338e1..a7d8863 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -462,12 +462,14 @@ int main(int argc, char **argv) {
   broker_init(&b, container_id, nthreads, heartbeat);
 
   /* Parse the URL or use default values */
+  const char *host = "0.0.0.0";
+  const char *port = "amqp";
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-  /* Listen on IPv6 wildcard. On systems that do not set IPV6ONLY by default,
-     this will also listen for mapped IPv4 on the same port.
-  */
-  const char *host = url ? pn_url_get_host(url) : "::";
-  const char *port = url ? pn_url_get_port(url) : "amqp";
+  if (url) {
+    if (pn_url_get_host(url)) host = pn_url_get_host(url);
+    if (pn_url_get_port(url)) port = (pn_url_get_port(url));
+  }
+
   pn_proactor_listen(b.proactor, pn_listener(), host, port, 16);
   printf("listening on '%s:%s' %zd threads\n", host, port, b.threads);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31a3c99e/examples/c/proactor/direct.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/direct.c b/examples/c/proactor/direct.c
index 3d0a7d1..de2d6aa 100644
--- a/examples/c/proactor/direct.c
+++ b/examples/c/proactor/direct.c
@@ -331,12 +331,15 @@ int main(int argc, char **argv) {
   snprintf(app.container_id, sizeof(app.container_id), "%s", argv[0]);
 
   /* Parse the URL or use default values */
+  const char *host = "0.0.0.0";
+  const char *port = "amqp";
+  strncpy(app.address, "example", sizeof(app.address));
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-  /* Listen on IPv6 wildcard. On systems that do not set IPV6ONLY by default,
-     this will also listen for mapped IPv4 on the same port.
-  */
-  const char *host = url ? pn_url_get_host(url) : "::";
-  const char *port = url ? pn_url_get_port(url) : "amqp";
+  if (url) {
+    if (pn_url_get_host(url)) host = pn_url_get_host(url);
+    if (pn_url_get_port(url)) port = (pn_url_get_port(url));
+    if (pn_url_get_path(url)) strncpy(app.address, pn_url_get_path(url), sizeof(app.address));
+  }
 
   app.proactor = pn_proactor();
   pn_proactor_listen(app.proactor, pn_listener(), host, port, 16);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31a3c99e/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index 1bc5509..65ec069 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -180,10 +180,15 @@ int main(int argc, char **argv) {
   snprintf(app.container_id, sizeof(app.container_id), "%s", argv[0]);
 
   /* Parse the URL or use default values */
+  const char *host = "127.0.0.1";
+  const char *port = "amqp";
+  strncpy(app.address, "example", sizeof(app.address));
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-  const char *host = url ? pn_url_get_host(url) : NULL;
-  const char *port = url ? pn_url_get_port(url) : "amqp";
-  strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
+  if (url) {
+    if (pn_url_get_host(url)) host = pn_url_get_host(url);
+    if (pn_url_get_port(url)) port = (pn_url_get_port(url));
+    if (pn_url_get_path(url)) strncpy(app.address, pn_url_get_path(url), sizeof(app.address));
+  }
 
   /* Create the proactor and connect */
   app.proactor = pn_proactor();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31a3c99e/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index bba5d3e..0786f19 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -209,10 +209,15 @@ int main(int argc, char **argv) {
   snprintf(app.container_id, sizeof(app.container_id), "%s", argv[0]);
 
   /* Parse the URL or use default values */
+  const char *host = "127.0.0.1";
+  const char *port = "amqp";
+  strncpy(app.address, "example", sizeof(app.address));
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-  const char *host = url ? pn_url_get_host(url) : NULL;
-  const char *port = url ? pn_url_get_port(url) : "amqp";
-  strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
+  if (url) {
+    if (pn_url_get_host(url)) host = pn_url_get_host(url);
+    if (pn_url_get_port(url)) port = (pn_url_get_port(url));
+    if (pn_url_get_path(url)) strncpy(app.address, pn_url_get_path(url), sizeof(app.address));
+  }
 
   /* Create the proactor and connect */
   app.proactor = pn_proactor();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[33/38] qpid-proton git commit: PROTON-1415: event.h remove duplicate enums

Posted by ac...@apache.org.
PROTON-1415: event.h remove duplicate enums

event.h defines some "alias" enums, move these out of the enum declearation and
make them static const aliases instead. No effect on existing code but simplifies
code generation for Go binding.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/540e74e2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/540e74e2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/540e74e2

Branch: refs/heads/go1
Commit: 540e74e28266b1f914d1b3498168060264552d62
Parents: 45f7b05
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 08:41:06 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 15:26:09 2017 -0500

----------------------------------------------------------------------
 proton-c/include/proton/event.h | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/540e74e2/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index b4dbfeb..c1c4fed 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -282,12 +282,6 @@ typedef enum {
   PN_TRANSPORT_HEAD_CLOSED,
 
   /**
-   * The write side of the transport is closed, it will no longer produce bytes
-   * to write to external IO. Synonynm for PN_TRANSPORT_HEAD_CLOSED
-   */
-  PN_TRANSPORT_WRITE_CLOSED = PN_TRANSPORT_HEAD_CLOSED,
-
-  /**
    * Indicates that the tail of the transport has been closed. This
    * means the transport will never be able to process more bytes from
    * the network. Events of this type point to the relevant transport.
@@ -295,12 +289,6 @@ typedef enum {
   PN_TRANSPORT_TAIL_CLOSED,
 
   /**
-   * The read side of the transport is closed, it will no longer read bytes
-   * from external IO. Synonynm for PN_TRANSPORT_TAIL_CLOSED
-   */
-  PN_TRANSPORT_READ_CLOSED = PN_TRANSPORT_TAIL_CLOSED,
-
-  /**
    * Indicates that the both the head and tail of the transport are
    * closed. Events of this type point to the relevant transport.
    */
@@ -361,6 +349,19 @@ typedef enum {
 
 } pn_event_type_t;
 
+
+/**
+ * The write side of the transport is closed, it will no longer produce bytes
+ * to write to external IO. Synonynm for PN_TRANSPORT_HEAD_CLOSED
+ */
+static const pn_event_type_t PN_TRANSPORT_WRITE_CLOSED = PN_TRANSPORT_HEAD_CLOSED;
+
+/**
+ * The read side of the transport is closed, it will no longer read bytes
+ * from external IO. Synonynm for PN_TRANSPORT_TAIL_CLOSED
+ */
+static const pn_event_type_t PN_TRANSPORT_READ_CLOSED = PN_TRANSPORT_TAIL_CLOSED;
+
 /**
  * Get a human readable name for an event type.
  *


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[05/38] qpid-proton git commit: PROTON-1344: Add pn_proactor_t and pn_listener_t to

Posted by ac...@apache.org.
PROTON-1344: Add pn_proactor_t and pn_listener_t to <proton/types.h>


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/a96bccb2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a96bccb2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a96bccb2

Branch: refs/heads/go1
Commit: a96bccb23209f2bcf82ea6d3508ce4ac77316b99
Parents: 3ca4bdc
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Feb 7 15:01:47 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Feb 9 21:31:15 2017 -0500

----------------------------------------------------------------------
 proton-c/include/proton/listener.h | 15 +--------------
 proton-c/include/proton/proactor.h | 14 +-------------
 proton-c/include/proton/types.h    |  6 ++++++
 3 files changed, 8 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a96bccb2/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index 8b70c9a..729c095 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -20,6 +20,7 @@
  * under the License.
  */
 
+#include <proton/condition.h>
 #include <proton/types.h>
 
 #ifdef __cplusplus
@@ -37,20 +38,6 @@ extern "C" {
  */
 
 /**
- * @cond INTERNAL
- */
-typedef struct pn_proactor_t pn_proactor_t;
-typedef struct pn_condition_t pn_condition_t;
-/**
- * @endcond
- */
-
-/**
- * A listener accepts connections.
- */
-typedef struct pn_listener_t pn_listener_t;
-
-/**
  * Create a listener.
  *
  * You can use pn_listener_set_context() or pn_listener_attachments() to set

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a96bccb2/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index b8fb16a..695bbb1 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -23,20 +23,13 @@
 #include <proton/types.h>
 #include <proton/import_export.h>
 #include <proton/listener.h>
+#include <proton/event.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * @cond INTERNAL
- */
-typedef struct pn_condition_t pn_condition_t;
-/**
- * @endcond
- */
-
-/**
  * @file
  *
  * **Experimental** - Multithreaded IO
@@ -58,11 +51,6 @@ typedef struct pn_condition_t pn_condition_t;
  */
 
 /**
- * The proactor, see pn_proactor()
- */
-typedef struct pn_proactor_t pn_proactor_t;
-
-/**
  * Create a proactor. Must be freed with pn_proactor_free()
  */
 pn_proactor_t *pn_proactor(void);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a96bccb2/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index c28beac..4400393 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -426,6 +426,12 @@ typedef struct pn_transport_t pn_transport_t;
  * A pn_handler_t is target of ::pn_event_t dispatched by the pn_reactor_t
  */
 typedef struct pn_handler_t pn_handler_t;
+
+/**
+ *
+ */
+typedef struct pn_proactor_t pn_proactor_t;
+typedef struct pn_listener_t pn_listener_t;
 /**
  * @endcond
  */


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[32/38] qpid-proton git commit: Revert "PROTON-1351: link go binding with qpid-proton-core library"

Posted by ac...@apache.org.
Revert "PROTON-1351: link go binding with qpid-proton-core library"

This reverts commit a1d84b0e212ebd1b7a8b2f9a52dc83337995dca3.

Linking with the -core library makes the Go binding needlessly incompatible
with older versions of proton.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/45f7b05e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/45f7b05e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/45f7b05e

Branch: refs/heads/go1
Commit: 45f7b05eac7923d1f27a671c0574611c34361537
Parents: 5d1c247
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 15:20:37 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 15:26:09 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go     | 2 +-
 proton-c/bindings/go/src/qpid.apache.org/electron/doc.go | 2 +-
 proton-c/bindings/go/src/qpid.apache.org/proton/doc.go   | 2 +-
 proton-c/bindings/go/src/qpid.apache.org/proton/error.go | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45f7b05e/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
index c04c2b0..701af55 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go
@@ -32,7 +32,7 @@ AMQP 1.0 is an open standard for inter-operable message exchange, see <http://ww
 */
 package amqp
 
-// #cgo LDFLAGS: -lqpid-proton-core
+// #cgo LDFLAGS: -lqpid-proton
 import "C"
 
 // This file is just for the package comment.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45f7b05e/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go b/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
index 39137c0..f4baa31 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/electron/doc.go
@@ -50,7 +50,7 @@ More realistic examples: https://github.com/apache/qpid-proton/blob/master/examp
 */
 package electron
 
-//#cgo LDFLAGS: -lqpid-proton-core
+//#cgo LDFLAGS: -lqpid-proton
 import "C"
 
 // Just for package comment

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45f7b05e/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
index 39716e2..1049e71 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
@@ -60,7 +60,7 @@ applications.
 */
 package proton
 
-// #cgo LDFLAGS: -lqpid-proton-core
+// #cgo LDFLAGS: -lqpid-proton
 import "C"
 
 // This file is just for the package comment.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45f7b05e/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/error.go b/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
index 5232fec..80d9680 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/error.go
@@ -20,7 +20,7 @@ under the License.
 // Internal implementation details - ignore.
 package proton
 
-// #cgo LDFLAGS: -lqpid-proton-core
+// #cgo LDFLAGS: -lqpid-proton
 // #include <proton/error.h>
 // #include <proton/codec.h>
 import "C"


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[03/38] qpid-proton git commit: NO-JIRA: [C++ binding] Add error_loop to fwd.hpp

Posted by ac...@apache.org.
NO-JIRA: [C++ binding] Add error_loop to fwd.hpp


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9de1cc1a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9de1cc1a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9de1cc1a

Branch: refs/heads/go1
Commit: 9de1cc1ae6867ceb9d0bec5f84f06ec7b77ee05f
Parents: 5bce0dc
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Feb 6 17:00:09 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed Feb 8 14:39:21 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/include/proton/fwd.hpp | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9de1cc1a/proton-c/bindings/cpp/include/proton/fwd.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/fwd.hpp b/proton-c/bindings/cpp/include/proton/fwd.hpp
index 3ed9283..54d7646 100644
--- a/proton-c/bindings/cpp/include/proton/fwd.hpp
+++ b/proton-c/bindings/cpp/include/proton/fwd.hpp
@@ -31,6 +31,7 @@ class container;
 class delivery;
 class error_condition;
 class event;
+class event_loop;
 class message;
 class message_id;
 class messaging_handler;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[08/38] qpid-proton git commit: PROTON-1403: c proactor library

Posted by ac...@apache.org.
PROTON-1403: c proactor library

Move the libuv example proactor into an installed library.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/afacb165
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/afacb165
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/afacb165

Branch: refs/heads/go1
Commit: afacb16527e9f231ae76d5e16ca0d9ac7edcff86
Parents: b9a57e8
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 10 21:43:05 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Feb 10 21:49:32 2017 -0500

----------------------------------------------------------------------
 examples/c/proactor/CMakeLists.txt         |  33 +-
 examples/c/proactor/broker.c               |  44 +-
 examples/c/proactor/libuv_proactor.c       | 873 ------------------------
 examples/c/proactor/test.py                |  14 +-
 examples/c/proactor/thread.h               |  49 ++
 proton-c/CMakeLists.txt                    |  74 +-
 proton-c/include/proton/import_export.h    |   7 +
 proton-c/include/proton/listener.h         |   4 +-
 proton-c/include/proton/proactor.h         |  26 +-
 proton-c/include/proton/types.h            |  17 +-
 proton-c/src/libqpid-proton-proactor.pc.in |  30 +
 proton-c/src/proactor/libuv.c              | 873 ++++++++++++++++++++++++
 12 files changed, 1074 insertions(+), 970 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index f701651..2ed4f94 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -23,21 +23,20 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${Proton_INCLUDE_DIRS})
 
 add_definitions(${COMPILE_WARNING_FLAGS} ${WERROR} ${COMPILE_PLATFORM_FLAGS} ${LINK_TIME_OPTIMIZATION})
 
-find_package(Libuv)
-if (Libuv_FOUND)
-  foreach(name broker send receive)
-    add_executable(libuv_${name} ${name}.c libuv_proactor.c)
-    target_link_libraries(libuv_${name} ${Proton_LIBRARIES} ${Libuv_LIBRARIES})
-    set_target_properties(libuv_${name} PROPERTIES
-      COMPILE_DEFINITIONS  "PN_PROACTOR_INCLUDE=\"libuv_proactor.h\"")
-  endforeach()
+# Add a test with the correct environment to find test executables and valgrind.
+if(WIN32)
+  set(test_path "$<TARGET_FILE_DIR:broker>;$<TARGET_FILE_DIR:qpid-proton>")
+else(WIN32)
+  set(test_path "${CMAKE_CURRENT_BINARY_DIR}:$ENV{PATH}")
+  set(PLATFORM_LIBS pthread)
+endif(WIN32)
+
+foreach(name broker send receive)
+  add_executable(proactor-${name} ${name}.c)
+  target_link_libraries(proactor-${name} ${Proton_LIBRARIES} ${PLATFORM_LIBS})
+  set_target_properties(proactor-${name} PROPERTIES OUTPUT_NAME ${name})
+endforeach()
+
+set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV})
+add_test(c-proactor ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py -v)
 
-  # Add a test with the correct environment to find test executables and valgrind.
-  if(WIN32)
-    set(test_path "$<TARGET_FILE_DIR:libuv_broker>;$<TARGET_FILE_DIR:qpid-proton>")
-  else(WIN32)
-    set(test_path "${CMAKE_CURRENT_BINARY_DIR}:$ENV{PATH}")
-  endif(WIN32)
-  set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV})
-  add_test(c-proactor-libuv ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py)
-endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index ca52336..d6261f4 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+#include "thread.h"
+
 #include <proton/connection_driver.h>
 #include <proton/proactor.h>
 #include <proton/engine.h>
@@ -29,11 +31,6 @@
 #include <string.h>
 #include <unistd.h>
 
-/* TODO aconway 2016-10-14: this example does not require libuv IO,
-   it uses uv.h only for portable mutex and thread functions.
-*/
-#include <uv.h>
-
 bool enable_debug = false;
 
 void debug(const char* fmt, ...) {
@@ -91,7 +88,7 @@ void pcheck(int err, const char* s) {
 
 /* Simple thread-safe queue implementation */
 typedef struct queue_t {
-  uv_mutex_t lock;
+  pthread_mutex_t lock;
   char* name;
   VEC(pn_rwbytes_t) messages;   /* Messages on the queue_t */
   VEC(pn_connection_t*) waiting; /* Connections waiting to send messages from this queue */
@@ -101,7 +98,7 @@ typedef struct queue_t {
 
 static void queue_init(queue_t *q, const char* name, queue_t *next) {
   debug("created queue %s", name);
-  uv_mutex_init(&q->lock);
+  pthread_mutex_init(&q->lock, NULL);
   q->name = strdup(name);
   VEC_INIT(q->messages);
   VEC_INIT(q->waiting);
@@ -110,7 +107,7 @@ static void queue_init(queue_t *q, const char* name, queue_t *next) {
 }
 
 static void queue_destroy(queue_t *q) {
-  uv_mutex_destroy(&q->lock);
+  pthread_mutex_destroy(&q->lock);
   free(q->name);
   for (size_t i = 0; i < q->messages.len; ++i)
     free(q->messages.data[i].start);
@@ -126,7 +123,7 @@ static void queue_destroy(queue_t *q) {
 static void queue_send(queue_t *q, pn_link_t *s) {
   pn_rwbytes_t m = { 0 };
   size_t tag = 0;
-  uv_mutex_lock(&q->lock);
+  pthread_mutex_lock(&q->lock);
   if (q->messages.len == 0) { /* Empty, record connection as waiting */
     debug("queue is empty %s", q->name);
     /* Record connection for wake-up if not already on the list. */
@@ -143,7 +140,7 @@ static void queue_send(queue_t *q, pn_link_t *s) {
     VEC_POP(q->messages);
     tag = ++q->sent;
   }
-  uv_mutex_unlock(&q->lock);
+  pthread_mutex_unlock(&q->lock);
   if (m.start) {
     pn_delivery_t *d = pn_delivery(s, pn_dtag((char*)&tag, sizeof(tag)));
     pn_link_send(s, m.start, m.size);
@@ -172,7 +169,7 @@ bool pn_connection_get_check_queues(pn_connection_t *c) {
 */
 static void queue_receive(pn_proactor_t *d, queue_t *q, pn_rwbytes_t m) {
   debug("received to queue %s", q->name);
-  uv_mutex_lock(&q->lock);
+  pthread_mutex_lock(&q->lock);
   VEC_PUSH(q->messages, m);
   if (q->messages.len == 1) { /* Was empty, notify waiting connections */
     for (size_t i = 0; i < q->waiting.len; ++i) {
@@ -182,18 +179,18 @@ static void queue_receive(pn_proactor_t *d, queue_t *q, pn_rwbytes_t m) {
     }
     q->waiting.len = 0;
   }
-  uv_mutex_unlock(&q->lock);
+  pthread_mutex_unlock(&q->lock);
 }
 
 /* Thread safe set of queues */
 typedef struct queues_t {
-  uv_mutex_t lock;
+  pthread_mutex_t lock;
   queue_t *queues;
   size_t sent;
 } queues_t;
 
 void queues_init(queues_t *qs) {
-  uv_mutex_init(&qs->lock);
+  pthread_mutex_init(&qs->lock, NULL);
   qs->queues = NULL;
 }
 
@@ -202,12 +199,12 @@ void queues_destroy(queues_t *qs) {
     queue_destroy(q);
     free(q);
   }
-  uv_mutex_destroy(&qs->lock);
+  pthread_mutex_destroy(&qs->lock);
 }
 
 /** Get or create the named queue. */
 queue_t* queues_get(queues_t *qs, const char* name) {
-  uv_mutex_lock(&qs->lock);
+  pthread_mutex_lock(&qs->lock);
   queue_t *q;
   for (q = qs->queues; q && strcmp(q->name, name) != 0; q = q->next)
     ;
@@ -216,7 +213,7 @@ queue_t* queues_get(queues_t *qs, const char* name) {
     queue_init(q, name, qs->queues);
     qs->queues = q;
   }
-  uv_mutex_unlock(&qs->lock);
+  pthread_mutex_unlock(&qs->lock);
   return q;
 }
 
@@ -255,7 +252,7 @@ static void link_send(broker_t *b, pn_link_t *s) {
 }
 
 static void queue_unsub(queue_t *q, pn_connection_t *c) {
-  uv_mutex_lock(&q->lock);
+  pthread_mutex_lock(&q->lock);
   for (size_t i = 0; i < q->waiting.len; ++i) {
     if (q->waiting.data[i] == c){
       q->waiting.data[i] = q->waiting.data[0]; /* save old [0] */
@@ -263,7 +260,7 @@ static void queue_unsub(queue_t *q, pn_connection_t *c) {
       break;
     }
   }
-  uv_mutex_unlock(&q->lock);
+  pthread_mutex_unlock(&q->lock);
 }
 
 /* Unsubscribe from the queue of interest to this link. */
@@ -416,7 +413,7 @@ static void handle(broker_t* b, pn_event_t* e) {
   }
 }
 
-static void broker_thread(void *void_broker) {
+static void* broker_thread(void *void_broker) {
   broker_t *b = (broker_t*)void_broker;
   do {
     pn_event_batch_t *events = pn_proactor_wait(b->proactor);
@@ -426,6 +423,7 @@ static void broker_thread(void *void_broker) {
     }
     pn_proactor_done(b->proactor, events);
   } while(!b->finished);
+  return NULL;
 }
 
 static void usage(const char *arg0) {
@@ -474,13 +472,13 @@ int main(int argc, char **argv) {
     exit(1);
   }
   /* Start n-1 threads and use main thread */
-  uv_thread_t* threads = (uv_thread_t*)calloc(sizeof(uv_thread_t), b.threads);
+  pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), b.threads);
   for (size_t i = 0; i < b.threads-1; ++i) {
-    check(uv_thread_create(&threads[i], broker_thread, &b), "pthread_create");
+    check(pthread_create(&threads[i], NULL, broker_thread, &b), "pthread_create");
   }
   broker_thread(&b);            /* Use the main thread too. */
   for (size_t i = 0; i < b.threads-1; ++i) {
-    check(uv_thread_join(&threads[i]), "pthread_join");
+    check(pthread_join(threads[i], NULL), "pthread_join");
   }
   pn_proactor_free(b.proactor);
   free(threads);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
deleted file mode 100644
index 42bbfab..0000000
--- a/examples/c/proactor/libuv_proactor.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <uv.h>
-
-#include <proton/condition.h>
-#include <proton/connection_driver.h>
-#include <proton/engine.h>
-#include <proton/message.h>
-#include <proton/object.h>
-#include <proton/proactor.h>
-#include <proton/transport.h>
-#include <proton/url.h>
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
-  libuv loop functions are thread unsafe. The only exception is uv_async_send()
-  which is a thread safe "wakeup" that can wake the uv_loop from another thread.
-
-  To provide concurrency the proactor uses a "leader-worker-follower" model,
-  threads take turns at the roles:
-
-  - a single "leader" calls libuv functions and runs the uv_loop in short bursts
-    to generate work. When there is work available it gives up leadership and
-    becomes a "worker"
-
-  - "workers" handle events concurrently for distinct connections/listeners
-    They do as much work as they can get, when none is left they become "followers"
-
-  - "followers" wait for the leader to generate work and become workers.
-    When the leader itself becomes a worker, one of the followers takes over.
-
-  This model is symmetric: any thread can take on any role based on run-time
-  requirements. It also allows the IO and non-IO work associated with an IO
-  wake-up to be processed in a single thread with no context switches.
-
-  Function naming:
-  - on_ - called in leader thread via uv_run().
-  - leader_ - called in leader thread, while processing the leader_q.
-  - owner_ - called in owning thread, leader or worker but not concurrently.
-
-  Note on_ and leader_ functions can call each other, the prefix indicates the
-  path they are most often called on.
-*/
-
-const char *COND_NAME = "proactor";
-const char *AMQP_PORT = "5672";
-const char *AMQP_PORT_NAME = "amqp";
-const char *AMQPS_PORT = "5671";
-const char *AMQPS_PORT_NAME = "amqps";
-
-PN_HANDLE(PN_PROACTOR)
-
-/* pn_proactor_t and pn_listener_t are plain C structs with normal memory management.
-   Class definitions are for identification as pn_event_t context only.
-*/
-PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
-PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
-
-/* common to connection and listener */
-typedef struct psocket_t {
-  /* Immutable */
-  pn_proactor_t *proactor;
-
-  /* Protected by proactor.lock */
-  struct psocket_t* next;
-  void (*wakeup)(struct psocket_t*); /* interrupting action for leader */
-
-  /* Only used by leader */
-  uv_tcp_t tcp;
-  void (*action)(struct psocket_t*); /* deferred action for leader */
-  bool is_conn:1;
-  char host[NI_MAXHOST];
-  char port[NI_MAXSERV];
-} psocket_t;
-
-/* Special value for psocket.next pointer when socket is not on any any list. */
-psocket_t UNLISTED;
-
-static void psocket_init(psocket_t* ps, pn_proactor_t* p, bool is_conn, const char *host, const char *port) {
-  ps->proactor = p;
-  ps->next = &UNLISTED;
-  ps->is_conn = is_conn;
-  ps->tcp.data = ps;
-
-  /* For platforms that don't know about "amqp" and "amqps" service names. */
-  if (strcmp(port, AMQP_PORT_NAME) == 0)
-    port = AMQP_PORT;
-  else if (strcmp(port, AMQPS_PORT_NAME) == 0)
-    port = AMQPS_PORT;
-  /* Set to "\001" to indicate a NULL as opposed to an empty string "" */
-  strncpy(ps->host, host ? host : "\001", sizeof(ps->host));
-  strncpy(ps->port, port ? port : "\001", sizeof(ps->port));
-}
-
-/* Turn "\001" back to NULL */
-static inline const char* fixstr(const char* str) {
-  return str[0] == '\001' ? NULL : str;
-}
-
-typedef struct pconnection_t {
-  psocket_t psocket;
-
-  /* Only used by owner thread */
-  pn_connection_driver_t driver;
-
-  /* Only used by leader */
-  uv_connect_t connect;
-  uv_timer_t timer;
-  uv_write_t write;
-  uv_shutdown_t shutdown;
-  size_t writing;
-  bool reading:1;
-  bool server:1;                /* accept, not connect */
-} pconnection_t;
-
-struct pn_listener_t {
-  psocket_t psocket;
-
-  /* Only used by owner thread */
-  pconnection_t *accepting;     /* accept in progress */
-  pn_condition_t *condition;
-  pn_collector_t *collector;
-  pn_event_batch_t batch;
-  pn_record_t *attachments;
-  void *context;
-  size_t backlog;
-};
-
-
-typedef struct queue { psocket_t *front, *back; } queue;
-
-struct pn_proactor_t {
-  /* Leader thread  */
-  uv_cond_t cond;
-  uv_loop_t loop;
-  uv_async_t async;
-  uv_timer_t timer;
-
-  /* Owner thread: proactor collector and batch can belong to leader or a worker */
-  pn_collector_t *collector;
-  pn_event_batch_t batch;
-
-  /* Protected by lock */
-  uv_mutex_t lock;
-  queue start_q;
-  queue worker_q;
-  queue leader_q;
-  size_t interrupt;             /* pending interrupts */
-  pn_millis_t timeout;
-  size_t count;                 /* psocket count */
-  bool inactive:1;
-  bool timeout_request:1;
-  bool timeout_elapsed:1;
-  bool has_leader:1;
-  bool batch_working:1;          /* batch belongs to a worker.  */
-};
-
-static bool push_lh(queue *q, psocket_t *ps) {
-  if (ps->next != &UNLISTED)  /* Don't move if already listed. */
-    return false;
-  ps->next = NULL;
-  if (!q->front) {
-    q->front = q->back = ps;
-  } else {
-    q->back->next = ps;
-    q->back =  ps;
-  }
-  return true;
-}
-
-static psocket_t* pop_lh(queue *q) {
-  psocket_t *ps = q->front;
-  if (ps) {
-    q->front = ps->next;
-    ps->next = &UNLISTED;
-  }
-  return ps;
-}
-
-static inline pconnection_t *as_pconnection_t(psocket_t* ps) {
-  return ps->is_conn ? (pconnection_t*)ps : NULL;
-}
-
-static inline pn_listener_t *as_listener(psocket_t* ps) {
-  return ps->is_conn ? NULL: (pn_listener_t*)ps;
-}
-
-/* Put ps on the leader queue for processing. Thread safe. */
-static void to_leader_lh(psocket_t *ps) {
-  push_lh(&ps->proactor->leader_q, ps);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
-}
-
-static void to_leader(psocket_t *ps) {
-  uv_mutex_lock(&ps->proactor->lock);
-  to_leader_lh(ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-/* Detach from IO and put ps on the worker queue */
-static void leader_to_worker(psocket_t *ps) {
-  if (ps->is_conn) {
-    pconnection_t *pc = as_pconnection_t(ps);
-    /* Don't detach if there are no events yet. */
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      if (pc->writing) {
-        pc->writing  = 0;
-        uv_cancel((uv_req_t*)&pc->write);
-      }
-      if (pc->reading) {
-        pc->reading = false;
-        uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
-      }
-      if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
-        uv_timer_stop(&pc->timer);
-      }
-    }
-  } else {
-    pn_listener_t *l = as_listener(ps);
-    uv_read_stop((uv_stream_t*)&l->psocket.tcp);
-  }
-  uv_mutex_lock(&ps->proactor->lock);
-  push_lh(&ps->proactor->worker_q, ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-/* Set a deferred action for leader, if not already set. */
-static void owner_to_leader(psocket_t *ps, void (*action)(psocket_t*)) {
-  uv_mutex_lock(&ps->proactor->lock);
-  if (!ps->action) {
-    ps->action = action;
-  }
-  to_leader_lh(ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-/* Owner thread send to worker thread. Set deferred action if not already set. */
-static void owner_to_worker(psocket_t *ps, void (*action)(psocket_t*)) {
-  uv_mutex_lock(&ps->proactor->lock);
-  if (!ps->action) {
-    ps->action = action;
-  }
-  push_lh(&ps->proactor->worker_q, ps);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-
-/* Re-queue for further work */
-static void worker_requeue(psocket_t* ps) {
-  uv_mutex_lock(&ps->proactor->lock);
-  push_lh(&ps->proactor->worker_q, ps);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
-  pconnection_t *pc = (pconnection_t*)calloc(1, sizeof(*pc));
-  if (!pc) return NULL;
-  if (pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
-    return NULL;
-  }
-  psocket_init(&pc->psocket, p,  true, host, port);
-  if (server) {
-    pn_transport_set_server(pc->driver.transport);
-  }
-  pn_record_t *r = pn_connection_attachments(pc->driver.connection);
-  pn_record_def(r, PN_PROACTOR, PN_VOID);
-  pn_record_set(r, PN_PROACTOR, pc);
-  return pc;
-}
-
-static pn_event_t *listener_batch_next(pn_event_batch_t *batch);
-static pn_event_t *proactor_batch_next(pn_event_batch_t *batch);
-
-static inline pn_proactor_t *batch_proactor(pn_event_batch_t *batch) {
-  return (batch->next_event == proactor_batch_next) ?
-    (pn_proactor_t*)((char*)batch - offsetof(pn_proactor_t, batch)) : NULL;
-}
-
-static inline pn_listener_t *batch_listener(pn_event_batch_t *batch) {
-  return (batch->next_event == listener_batch_next) ?
-    (pn_listener_t*)((char*)batch - offsetof(pn_listener_t, batch)) : NULL;
-}
-
-static inline pconnection_t *batch_pconnection(pn_event_batch_t *batch) {
-  pn_connection_driver_t *d = pn_event_batch_connection_driver(batch);
-  return d ? (pconnection_t*)((char*)d - offsetof(pconnection_t, driver)) : NULL;
-}
-
-static void leader_count(pn_proactor_t *p, int change) {
-  uv_mutex_lock(&p->lock);
-  p->count += change;
-  p->inactive = (p->count == 0);
-  uv_mutex_unlock(&p->lock);
-}
-
-/* Free if there are no uv callbacks pending and no events */
-static void leader_pconnection_t_maybe_free(pconnection_t *pc) {
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      leader_to_worker(&pc->psocket);         /* Return to worker */
-    } else if (!(pc->psocket.tcp.data || pc->write.data || pc->shutdown.data || pc->timer.data)) {
-      /* All UV requests are finished */
-      pn_connection_driver_destroy(&pc->driver);
-      leader_count(pc->psocket.proactor, -1);
-      free(pc);
-    }
-}
-
-/* Free if there are no uv callbacks pending and no events */
-static void leader_listener_maybe_free(pn_listener_t *l) {
-    if (pn_collector_peek(l->collector)) {
-      leader_to_worker(&l->psocket);         /* Return to worker */
-    } else if (!l->psocket.tcp.data) {
-      pn_condition_free(l->condition);
-      leader_count(l->psocket.proactor, -1);
-      free(l);
-    }
-}
-
-/* Free if there are no uv callbacks pending and no events */
-static void leader_maybe_free(psocket_t *ps) {
-  if (ps->is_conn) {
-    leader_pconnection_t_maybe_free(as_pconnection_t(ps));
-  } else {
-    leader_listener_maybe_free(as_listener(ps));
-  }
-}
-
-static void on_close(uv_handle_t *h) {
-  psocket_t *ps = (psocket_t*)h->data;
-  h->data = NULL;               /* Mark closed */
-  leader_maybe_free(ps);
-}
-
-static void on_shutdown(uv_shutdown_t *shutdown, int err) {
-  psocket_t *ps = (psocket_t*)shutdown->data;
-  shutdown->data = NULL;        /* Mark closed */
-  leader_maybe_free(ps);
-}
-
-static inline void leader_close(psocket_t *ps) {
-  if (ps->tcp.data && !uv_is_closing((uv_handle_t*)&ps->tcp)) {
-    uv_close((uv_handle_t*)&ps->tcp, on_close);
-  }
-  pconnection_t *pc = as_pconnection_t(ps);
-  if (pc) {
-    pn_connection_driver_close(&pc->driver);
-    if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
-      uv_timer_stop(&pc->timer);
-      uv_close((uv_handle_t*)&pc->timer, on_close);
-    }
-  }
-  leader_maybe_free(ps);
-}
-
-static pconnection_t *get_pconnection_t(pn_connection_t* c) {
-  if (!c) return NULL;
-  pn_record_t *r = pn_connection_attachments(c);
-  return (pconnection_t*) pn_record_get(r, PN_PROACTOR);
-}
-
-static void leader_error(psocket_t *ps, int err, const char* what) {
-  if (ps->is_conn) {
-    pn_connection_driver_t *driver = &as_pconnection_t(ps)->driver;
-    pn_connection_driver_bind(driver); /* Bind so errors will be reported */
-    pn_connection_driver_errorf(driver, COND_NAME, "%s %s:%s: %s",
-                                what, fixstr(ps->host), fixstr(ps->port),
-                                uv_strerror(err));
-    pn_connection_driver_close(driver);
-  } else {
-    pn_listener_t *l = as_listener(ps);
-    pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
-                        what, fixstr(ps->host), fixstr(ps->port),
-                        uv_strerror(err));
-    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
-  }
-  leader_to_worker(ps);               /* Worker to handle the error */
-}
-
-/* uv-initialization */
-static int leader_init(psocket_t *ps) {
-  leader_count(ps->proactor, +1);
-  int err = uv_tcp_init(&ps->proactor->loop, &ps->tcp);
-  if (!err) {
-    pconnection_t *pc = as_pconnection_t(ps);
-    if (pc) {
-      pc->connect.data = ps;
-      int err = uv_timer_init(&ps->proactor->loop, &pc->timer);
-      if (!err) {
-        pc->timer.data = pc;
-      }
-    }
-  }
-  if (err) {
-    leader_error(ps, err, "initialization");
-  }
-  return err;
-}
-
-/* Common logic for on_connect and on_accept */
-static void leader_connect_accept(pconnection_t *pc, int err, const char *what) {
-  if (!err) {
-    leader_to_worker(&pc->psocket);
-  } else {
-    leader_error(&pc->psocket, err, what);
-  }
-}
-
-static void on_connect(uv_connect_t *connect, int err) {
-  leader_connect_accept((pconnection_t*)connect->data, err, "on connect");
-}
-
-static void on_accept(uv_stream_t* server, int err) {
-  pn_listener_t *l = (pn_listener_t*) server->data;
-  if (err) {
-    leader_error(&l->psocket, err, "on accept");
-  }
-  pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
-  leader_to_worker(&l->psocket); /* Let user call pn_listener_accept */
-}
-
-static void leader_accept(psocket_t *ps) {
-  pn_listener_t * l = as_listener(ps);
-  pconnection_t *pc = l->accepting;
-  l->accepting = NULL;
-  if (pc) {
-    int err = leader_init(&pc->psocket);
-    if (!err) err = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
-    leader_connect_accept(pc, err, "on accept");
-  }
-}
-
-static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
-  int err = leader_init(ps);
-  struct addrinfo hints = { 0 };
-  if (server) hints.ai_flags = AI_PASSIVE;
-  if (!err) {
-    err = uv_getaddrinfo(&ps->proactor->loop, info, NULL, fixstr(ps->host), fixstr(ps->port), &hints);
-  }
-  return err;
-}
-
-static void leader_connect(psocket_t *ps) {
-  pconnection_t *pc = as_pconnection_t(ps);
-  uv_getaddrinfo_t info;
-  int err = leader_resolve(ps, &info, false);
-  if (!err) {
-    err = uv_tcp_connect(&pc->connect, &pc->psocket.tcp, info.addrinfo->ai_addr, on_connect);
-    uv_freeaddrinfo(info.addrinfo);
-  }
-  if (err) {
-    leader_error(ps, err, "connect to");
-  }
-}
-
-static void leader_listen(psocket_t *ps) {
-  pn_listener_t *l = as_listener(ps);
-   uv_getaddrinfo_t info;
-  int err = leader_resolve(ps, &info, true);
-  if (!err) {
-    err = uv_tcp_bind(&l->psocket.tcp, info.addrinfo->ai_addr, 0);
-    uv_freeaddrinfo(info.addrinfo);
-  }
-  if (!err) err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
-  if (err) {
-    leader_error(ps, err, "listen on ");
-  }
-}
-
-static void on_tick(uv_timer_t *timer) {
-  pconnection_t *pc = (pconnection_t*)timer->data;
-  pn_transport_t *t = pc->driver.transport;
-  if (pn_transport_get_idle_timeout(t) || pn_transport_get_remote_idle_timeout(t)) {
-    uv_timer_stop(&pc->timer);
-    uint64_t now = uv_now(pc->timer.loop);
-    uint64_t next = pn_transport_tick(t, now);
-    if (next) {
-      uv_timer_start(&pc->timer, on_tick, next - now, 0);
-    }
-  }
-}
-
-static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
-  pconnection_t *pc = (pconnection_t*)stream->data;
-  if (nread >= 0) {
-    pn_connection_driver_read_done(&pc->driver, nread);
-    on_tick(&pc->timer);         /* check for tick changes. */
-    leader_to_worker(&pc->psocket);
-    /* Reading continues automatically until stopped. */
-  } else if (nread == UV_EOF) { /* hangup */
-    pn_connection_driver_read_close(&pc->driver);
-    leader_maybe_free(&pc->psocket);
-  } else {
-    leader_error(&pc->psocket, nread, "on read from");
-  }
-}
-
-static void on_write(uv_write_t* write, int err) {
-  pconnection_t *pc = (pconnection_t*)write->data;
-  write->data = NULL;
-  if (err == 0) {
-    pn_connection_driver_write_done(&pc->driver, pc->writing);
-    leader_to_worker(&pc->psocket);
-  } else if (err == UV_ECANCELED) {
-    leader_maybe_free(&pc->psocket);
-  } else {
-    leader_error(&pc->psocket, err, "on write to");
-  }
-  pc->writing = 0;              /* Need to send a new write request */
-}
-
-static void on_timeout(uv_timer_t *timer) {
-  pn_proactor_t *p = (pn_proactor_t*)timer->data;
-  uv_mutex_lock(&p->lock);
-  p->timeout_elapsed = true;
-  uv_mutex_unlock(&p->lock);
-}
-
-// Read buffer allocation function for uv, just returns the transports read buffer.
-static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
-  pconnection_t *pc = (pconnection_t*)stream->data;
-  pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
-  *buf = uv_buf_init(rbuf.start, rbuf.size);
-}
-
-static void leader_rewatch(psocket_t *ps) {
-  int err = 0;
-  if (ps->is_conn) {
-    pconnection_t *pc = as_pconnection_t(ps);
-    if (pc->timer.data) {         /* uv-initialized */
-      on_tick(&pc->timer);        /* Re-enable ticks if required */
-    }
-    pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
-    pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
-
-    /* Ticks and checking buffers can generate events, process before proceeding */
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      leader_to_worker(ps);
-    } else {                      /* Re-watch for IO */
-      if (wbuf.size > 0 && !pc->writing) {
-        pc->writing = wbuf.size;
-        uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
-        pc->write.data = ps;
-        uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
-      } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
-        pc->shutdown.data = ps;
-        uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
-      }
-      if (rbuf.size > 0 && !pc->reading) {
-        pc->reading = true;
-        err = uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
-      }
-    }
-  } else {
-    pn_listener_t *l = as_listener(ps);
-    err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
-  }
-  if (err) {
-    leader_error(ps, err, "rewatch");
-  }
-}
-
-/* Set the event in the proactor's batch  */
-static pn_event_batch_t *proactor_batch_lh(pn_proactor_t *p, pn_event_type_t t) {
-  pn_collector_put(p->collector, pn_proactor__class(), p, t);
-  p->batch_working = true;
-  return &p->batch;
-}
-
-/* Return the next event batch or 0 if no events are ready */
-static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
-  if (!p->batch_working) {       /* Can generate proactor events */
-    if (p->inactive) {
-      p->inactive = false;
-      return proactor_batch_lh(p, PN_PROACTOR_INACTIVE);
-    }
-    if (p->interrupt > 0) {
-      --p->interrupt;
-      return proactor_batch_lh(p, PN_PROACTOR_INTERRUPT);
-    }
-    if (p->timeout_elapsed) {
-      p->timeout_elapsed = false;
-      return proactor_batch_lh(p, PN_PROACTOR_TIMEOUT);
-    }
-  }
-  for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
-    if (ps->is_conn) {
-      pconnection_t *pc = as_pconnection_t(ps);
-      return &pc->driver.batch;
-    } else {                    /* Listener */
-      pn_listener_t *l = as_listener(ps);
-      return &l->batch;
-    }
-    to_leader(ps);      /* No event, back to leader */
-  }
-  return 0;
-}
-
-/* Called in any thread to set a wakeup action. Replaces any previous wakeup action. */
-static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
-  uv_mutex_lock(&ps->proactor->lock);
-  ps->wakeup = action;
-  to_leader_lh(ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
-pn_listener_t *pn_event_listener(pn_event_t *e) {
-  return (pn_event_class(e) == pn_listener__class()) ? (pn_listener_t*)pn_event_context(e) : NULL;
-}
-
-pn_proactor_t *pn_event_proactor(pn_event_t *e) {
-  if (pn_event_class(e) == pn_proactor__class()) return (pn_proactor_t*)pn_event_context(e);
-  pn_listener_t *l = pn_event_listener(e);
-  if (l) return l->psocket.proactor;
-  pn_connection_t *c = pn_event_connection(e);
-  if (c) return pn_connection_proactor(pn_event_connection(e));
-  return NULL;
-}
-
-void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
-  pconnection_t *pc = batch_pconnection(batch);
-  if (pc) {
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      /* Process all events before going back to IO. */
-      worker_requeue(&pc->psocket);
-    } else if (pn_connection_driver_finished(&pc->driver)) {
-      owner_to_leader(&pc->psocket, leader_close);
-    } else {
-      owner_to_leader(&pc->psocket, leader_rewatch);
-    }
-    return;
-  }
-  pn_listener_t *l = batch_listener(batch);
-  if (l) {
-    owner_to_leader(&l->psocket, leader_rewatch);
-    return;
-  }
-  pn_proactor_t *bp = batch_proactor(batch);
-  if (bp == p) {
-    uv_mutex_lock(&p->lock);
-    p->batch_working = false;
-    uv_async_send(&p->async); /* Wake leader */
-    uv_mutex_unlock(&p->lock);
-    return;
-  }
-}
-
-/* Run follower/leader loop till we can return an event and be a worker */
-pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
-  uv_mutex_lock(&p->lock);
-  /* Try to grab work immediately. */
-  pn_event_batch_t *batch = get_batch_lh(p);
-  if (batch == NULL) {
-    /* No work available, follow the leader */
-    while (p->has_leader) {
-      uv_cond_wait(&p->cond, &p->lock);
-    }
-    /* Lead till there is work to do. */
-    p->has_leader = true;
-    while (batch == NULL) {
-      if (p->timeout_request) {
-        p->timeout_request = false;
-        if (p->timeout) {
-          uv_timer_start(&p->timer, on_timeout, p->timeout, 0);
-        } else {
-          uv_timer_stop(&p->timer);
-        }
-      }
-      for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
-        void (*action)(psocket_t*) = ps->action;
-        void (*wakeup)(psocket_t*) = ps->wakeup;
-        ps->action = NULL;
-        ps->wakeup = NULL;
-        if (action || wakeup) {
-          uv_mutex_unlock(&p->lock);
-          if (action) action(ps);
-          if (wakeup) wakeup(ps);
-          uv_mutex_lock(&p->lock);
-        }
-      }
-      batch = get_batch_lh(p);
-      if (batch == NULL) {
-        uv_mutex_unlock(&p->lock);
-        uv_run(&p->loop, UV_RUN_ONCE);
-        uv_mutex_lock(&p->lock);
-      }
-    }
-    /* Signal the next leader and return to work */
-    p->has_leader = false;
-    uv_cond_signal(&p->cond);
-  }
-  uv_mutex_unlock(&p->lock);
-  return batch;
-}
-
-void pn_proactor_interrupt(pn_proactor_t *p) {
-  uv_mutex_lock(&p->lock);
-  ++p->interrupt;
-  uv_async_send(&p->async);   /* Interrupt the UV loop */
-  uv_mutex_unlock(&p->lock);
-}
-
-void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
-  uv_mutex_lock(&p->lock);
-  p->timeout = t;
-  p->timeout_request = true;
-  uv_async_send(&p->async);   /* Interrupt the UV loop */
-  uv_mutex_unlock(&p->lock);
-}
-
-int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {
-  pconnection_t *pc = new_pconnection_t(p, c, false, host, port);
-  if (!pc) {
-    return PN_OUT_OF_MEMORY;
-  }
-  /* Process PN_CONNECTION_INIT before binding */
-  owner_to_worker(&pc->psocket, leader_connect);
-  return 0;
-}
-
-int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *host, const char *port, int backlog)
-{
-  psocket_init(&l->psocket, p, false, host, port);
-  l->backlog = backlog;
-  owner_to_leader(&l->psocket, leader_listen);
-  return 0;
-}
-
-pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
-  pconnection_t *pc = get_pconnection_t(c);
-  return pc ? pc->psocket.proactor : NULL;
-}
-
-void leader_wake_connection(psocket_t *ps) {
-  pconnection_t *pc = as_pconnection_t(ps);
-  pn_connection_t *c = pc->driver.connection;
-  pn_collector_put(pn_connection_collector(c), PN_OBJECT, c, PN_CONNECTION_WAKE);
-  leader_to_worker(ps);
-}
-
-void pn_connection_wake(pn_connection_t* c) {
-  wakeup(&get_pconnection_t(c)->psocket, leader_wake_connection);
-}
-
-pn_proactor_t *pn_proactor() {
-  pn_proactor_t *p = (pn_proactor_t*)calloc(1, sizeof(*p));
-  p->collector = pn_collector();
-  p->batch.next_event = &proactor_batch_next;
-  if (!p->collector) return NULL;
-  uv_loop_init(&p->loop);
-  uv_mutex_init(&p->lock);
-  uv_cond_init(&p->cond);
-  uv_async_init(&p->loop, &p->async, NULL);
-  uv_timer_init(&p->loop, &p->timer); /* Just wake the loop */
-  p->timer.data = p;
-  return p;
-}
-
-static void on_stopping(uv_handle_t* h, void* v) {
-  uv_close(h, NULL);           /* Close this handle */
-  if (!uv_loop_alive(h->loop)) /* Everything closed */
-    uv_stop(h->loop);        /* Stop the loop, pn_proactor_destroy() can return */
-}
-
-void pn_proactor_free(pn_proactor_t *p) {
-  uv_walk(&p->loop, on_stopping, NULL); /* Close all handles */
-  uv_run(&p->loop, UV_RUN_DEFAULT);     /* Run till stop, all handles closed */
-  uv_loop_close(&p->loop);
-  uv_mutex_destroy(&p->lock);
-  uv_cond_destroy(&p->cond);
-  pn_collector_free(p->collector);
-  free(p);
-}
-
-static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
-  pn_listener_t *l = batch_listener(batch);
-  pn_event_t *handled = pn_collector_prev(l->collector);
-  if (handled && pn_event_type(handled) == PN_LISTENER_CLOSE) {
-    owner_to_leader(&l->psocket, leader_close); /* Close event handled, do close */
-  }
-  return pn_collector_next(l->collector);
-}
-
-static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
-  return pn_collector_next(batch_proactor(batch)->collector);
-}
-
-static void pn_listener_free(pn_listener_t *l) {
-  if (l) {
-    if (!l->collector) pn_collector_free(l->collector);
-    if (!l->condition) pn_condition_free(l->condition);
-    if (!l->attachments) pn_free(l->attachments);
-    free(l);
-  }
-}
-
-pn_listener_t *pn_listener() {
-  pn_listener_t *l = (pn_listener_t*)calloc(1, sizeof(pn_listener_t));
-  if (l) {
-    l->batch.next_event = listener_batch_next;
-    l->collector = pn_collector();
-    l->condition = pn_condition();
-    l->attachments = pn_record();
-    if (!l->condition || !l->collector || !l->attachments) {
-      pn_listener_free(l);
-      return NULL;
-    }
-  }
-  return l;
-}
-
-void pn_listener_close(pn_listener_t* l) {
-  wakeup(&l->psocket, leader_close);
-}
-
-pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
-  return l ? l->psocket.proactor : NULL;
-}
-
-pn_condition_t* pn_listener_condition(pn_listener_t* l) {
-  return l->condition;
-}
-
-void *pn_listener_get_context(pn_listener_t *l) {
-  return l->context;
-}
-
-void pn_listener_set_context(pn_listener_t *l, void *context) {
-  l->context = context;
-}
-
-pn_record_t *pn_listener_attachments(pn_listener_t *l) {
-  return l->attachments;
-}
-
-int pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
-  if (l->accepting) {
-    return PN_STATE_ERR;        /* Only one at a time */
-  }
-  l->accepting = new_pconnection_t(
-      l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
-  if (!l->accepting) {
-    return UV_ENOMEM;
-  }
-  owner_to_leader(&l->psocket, leader_accept);
-  return 0;
-}
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/examples/c/proactor/test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/test.py b/examples/c/proactor/test.py
index a86425d..29aa327 100644
--- a/examples/c/proactor/test.py
+++ b/examples/c/proactor/test.py
@@ -32,27 +32,27 @@ def receive_expect(n):
     return ''.join('{"sequence"=%s}\n'%i for i in xrange(1, n+1)) + "%s messages received\n"%n
 
 class CExampleTest(BrokerTestCase):
-    broker_exe = ["libuv_broker"]
+    broker_exe = ["broker"]
 
     def test_send_receive(self):
         """Send first then receive"""
-        s = self.proc(["libuv_send", "-a", self.addr])
+        s = self.proc(["send", "-a", self.addr])
         self.assertEqual("100 messages sent and acknowledged\n", s.wait_out())
-        r = self.proc(["libuv_receive", "-a", self.addr])
+        r = self.proc(["receive", "-a", self.addr])
         self.assertEqual(receive_expect(100), r.wait_out())
 
     def test_receive_send(self):
         """Start receiving  first, then send."""
-        r = self.proc(["libuv_receive", "-a", self.addr]);
-        s = self.proc(["libuv_send", "-a", self.addr]);
+        r = self.proc(["receive", "-a", self.addr]);
+        s = self.proc(["send", "-a", self.addr]);
         self.assertEqual("100 messages sent and acknowledged\n", s.wait_out())
         self.assertEqual(receive_expect(100), r.wait_out())
 
     def test_timed_send(self):
         """Send with timed delay"""
-        s = self.proc(["libuv_send", "-a", self.addr, "-d100", "-m3"])
+        s = self.proc(["send", "-a", self.addr, "-d100", "-m3"])
         self.assertEqual("3 messages sent and acknowledged\n", s.wait_out())
-        r = self.proc(["libuv_receive", "-a", self.addr, "-m3"])
+        r = self.proc(["receive", "-a", self.addr, "-m3"])
         self.assertEqual(receive_expect(3), r.wait_out())
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/examples/c/proactor/thread.h
----------------------------------------------------------------------
diff --git a/examples/c/proactor/thread.h b/examples/c/proactor/thread.h
new file mode 100644
index 0000000..3b9f19e
--- /dev/null
+++ b/examples/c/proactor/thread.h
@@ -0,0 +1,49 @@
+#ifndef _PROTON_EXAMPLES_C_PROACTOR_THREADS_H
+#define _PROTON_EXAMPLES_C_PROACTOR_THREADS_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* EXAMPLE USE ONLY. Simulate the subset of POSIX threads used by examples for windows */
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <time.h>
+#define _WIN32_WINNT 0x500 /* WINBASE.H - Enable SignalObjectAndWait */
+#include <process.h>
+#include <windows.h>
+
+#define pthread_function DWORD WINAPI
+#define pthread_function_return DWORD
+#define pthread_t HANDLE
+#define pthread_create(thhandle,attr,thfunc,tharg) (int)((*thhandle=(HANDLE)_beginthreadex(NULL,0,(DWORD WINAPI(*)())thfunc,tharg,0,NULL))==NULL)
+#define pthread_join(thread, result) ((WaitForSingleObject((thread),INFINITE)!=WAIT_OBJECT_0) || !CloseHandle(thread))
+#define pthread_mutex_T HANDLE
+#define pthread_mutex_init(pobject,pattr) (*pobject=CreateMutex(NULL,FALSE,NULL))
+#define pthread_mutex_destroy(pobject) CloseHandle(*pobject)
+#define pthread_mutex_lock(pobject) WaitForSingleObject(*pobject,INFINITE)
+#define pthread_mutex_unlock(pobject) ReleaseMutex(*pobject)
+
+#else
+
+#include <pthread.h>
+
+#endif
+
+#endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 8edb661..e5552c5 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -105,6 +105,13 @@ else(PN_WINAPI)
   set (pn_selector_impl src/reactor/io/posix/selector.c)
 endif(PN_WINAPI)
 
+# Select proactor impl
+find_package(Libuv)
+if (Libuv_FOUND)
+  set (qpid-proton-proactor src/proactor/libuv.c)
+  set (PROACTOR_LIBS ${Libuv_LIBRARIES})
+endif()
+
 # Link in SASL if present
 if (SASL_IMPL STREQUAL cyrus)
   set(pn_sasl_impl src/sasl/sasl.c src/sasl/cyrus_sasl.c)
@@ -116,7 +123,7 @@ endif ()
 
 # Set Compiler extra flags for Solaris when using SunStudio
 if(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro" )
-    set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mt" )
+  set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mt" )
 endif()
 
 if(CMAKE_C_COMPILER_ID STREQUAL "SunPro" )
@@ -327,6 +334,7 @@ set (qpid-proton-platform-all
   src/reactor/io/windows/selector.c
   src/reactor/io/posix/io.c
   src/reactor/io/posix/selector.c
+  src/proactor/libuv.c
   )
 
 # platform specific library build:
@@ -379,7 +387,7 @@ set (qpid-proton-core
   src/core/autodetect.c
   src/core/transport.c
   src/core/message.c
-  )
+)
 
 set (qpid-proton-include-generated
   ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
@@ -455,6 +463,7 @@ set (qpid-proton-include
   include/proton/log.h
   include/proton/message.h
   include/proton/object.h
+  include/proton/proactor.h
   include/proton/sasl.h
   include/proton/session.h
   include/proton/ssl.h
@@ -495,9 +504,15 @@ set_source_files_properties (
   COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
   )
 
+set_source_files_properties (${qpid-proton-proactor} PROPERTIES
+  # Skip COMPILE_LANGUAGE_FLAGS, libuv.h won't compile with --std=c99
+  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${LTO} "
+  )
+
 if (BUILD_WITH_CXX)
   set_source_files_properties (
     ${qpid-proton-core}
+    ${qpid-proton-proactor}
     ${qpid-proton-layers}
     ${qpid-proton-extra}
     ${qpid-proton-platform}
@@ -526,6 +541,12 @@ set_target_properties (
   LINK_FLAGS "${CATCH_UNDEFINED} ${LTO}"
   )
 
+add_library (
+  qpid-proton-proactor SHARED
+  ${qpid-proton-proactor}
+  )
+target_link_libraries (qpid-proton-proactor qpid-proton-core ${PROACTOR_LIBS})
+
 add_library(
   qpid-proton SHARED
   # Proton Core
@@ -534,7 +555,8 @@ add_library(
   ${qpid-proton-platform}
   ${qpid-proton-include}
   ${qpid-proton-include-generated}
-
+  # Proactor
+  ${qpid-proton-proactor}
   # Proton Reactor/Messenger
   ${qpid-proton-extra}
   ${qpid-proton-platform-io}
@@ -550,7 +572,7 @@ if (MSVC)
   add_dependencies(qpid-proton qpid-proton-core)
 endif (MSVC)
 
-target_link_libraries (qpid-proton ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
+target_link_libraries (qpid-proton ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS} ${PROACTOR_LIBS})
 
 set_target_properties (
   qpid-proton
@@ -586,32 +608,26 @@ install (FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/proton)
 install (FILES  ${CMAKE_CURRENT_BINARY_DIR}/include/proton/version.h
          DESTINATION ${INCLUDE_INSTALL_DIR}/proton)
 
-# Pkg config file
-configure_file(
-  ${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton.pc.in
-  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc @ONLY)
-install (FILES
-  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc
-  DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
-configure_file(
-  ${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton-core.pc.in
-  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton-core.pc @ONLY)
-install (FILES
-  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton-core.pc
-  DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
-
+# Set ${VAR}/${VAR}DEBUG variables, configure and install the packageconf files for LIB
+macro(configure_lib VAR LIB)
+  if(DEFINED CMAKE_IMPORT_LIBRARY_PREFIX)
+    set(LIB_PREFIX ${CMAKE_IMPORT_LIBRARY_PREFIX})
+    set(LIB_SUFFIX ${CMAKE_IMPORT_LIBRARY_SUFFIX})
+  else()
+    set(LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})
+    set(LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
+  endif()
+  set(${VAR} ${LIB_PREFIX}${LIB}${LIB_SUFFIX})
+  set("${VAR}DEBUG" ${LIB_PREFIX}${LIB}${CMAKE_DEBUG_POSTFIX}${LIB_SUFFIX})
+  configure_file(
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/lib${LIB}.pc.in
+    ${CMAKE_CURRENT_BINARY_DIR}/lib${LIB}.pc @ONLY)
+  install (FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${LIB}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+endmacro()
 
-if (DEFINED CMAKE_IMPORT_LIBRARY_PREFIX)
-set(PROTONLIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_IMPORT_LIBRARY_SUFFIX})
-set(PROTONLIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
-set(PROTONCORELIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton-core${CMAKE_IMPORT_LIBRARY_SUFFIX})
-set(PROTONCORELIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton-core${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
-else ()
-set(PROTONLIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_SHARED_LIBRARY_SUFFIX})
-set(PROTONLIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
-set(PROTONCORELIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton-core${CMAKE_SHARED_LIBRARY_SUFFIX})
-set(PROTONCORELIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton-core${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
-endif ()
+configure_lib(PROTONLIB qpid-proton)
+configure_lib(PROTONCORELIB qpid-proton-core)
+configure_lib(PROTONPROACTORLIB qpid-proton-proactor)
 
 include(WriteBasicConfigVersionFile)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/include/proton/import_export.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/import_export.h b/proton-c/include/proton/import_export.h
index 6547a07..86776cd 100644
--- a/proton-c/include/proton/import_export.h
+++ b/proton-c/include/proton/import_export.h
@@ -56,6 +56,13 @@
 #  define PN_EXTERN PN_IMPORT
 #endif
 
+// For proactor proton symbols
+#if defined(qpid_proton_proactor_EXPORTS) || defined(qpid_proton_EXPORTS)
+#  define PNP_EXTERN PN_EXPORT
+#else
+#  define PNP_EXTERN PN_IMPORT
+#endif
+
 // For extra proton symbols
 #if defined(qpid_proton_EXPORTS)
 #  define PNX_EXTERN PN_EXPORT

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index 729c095..4656ee4 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -63,7 +63,7 @@ PN_EXTERN pn_condition_t *pn_listener_condition(pn_listener_t *l);
 /**
  * @cond INTERNAL
  */
-    
+
 /**
  * @deprecated
  *
@@ -81,7 +81,7 @@ PN_EXTERN void pn_listener_set_context(pn_listener_t *listener, void *context);
 /**
  * @endcond
  */
-    
+
 /**
  * Get the attachments that are associated with a listener object.
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index 695bbb1..71a7dda 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -53,13 +53,13 @@ extern "C" {
 /**
  * Create a proactor. Must be freed with pn_proactor_free()
  */
-pn_proactor_t *pn_proactor(void);
+PNP_EXTERN pn_proactor_t *pn_proactor(void);
 
 /**
  * Free the proactor. Abort any open network connections and clean up all
  * associated resources.
  */
-void pn_proactor_free(pn_proactor_t *proactor);
+PNP_EXTERN void pn_proactor_free(pn_proactor_t *proactor);
 
 /**
  * Connect connection to host/port. Connection and transport events will be
@@ -72,9 +72,9 @@ void pn_proactor_free(pn_proactor_t *proactor);
  *
  * @return error on immediate error, e.g. an allocation failure.
  * Other errors are indicated by connection or transport events via
- * pn_proactor_wait()
+PNP_EXTERN  * pn_proactor_wait()
  */
-int pn_proactor_connect(pn_proactor_t *proactor, pn_connection_t *connection,
+PNP_EXTERN int pn_proactor_connect(pn_proactor_t *proactor, pn_connection_t *connection,
                         const char *host, const char *port);
 
 /**
@@ -91,7 +91,7 @@ int pn_proactor_connect(pn_proactor_t *proactor, pn_connection_t *connection,
  * Other errors are indicated by pn_listener_condition() on the
  * PN_LISTENER_CLOSE event.
  */
-int pn_proactor_listen(pn_proactor_t *proactor, pn_listener_t *listener,
+PNP_EXTERN int pn_proactor_listen(pn_proactor_t *proactor, pn_listener_t *listener,
                        const char *host, const char *port, int backlog);
 
 /**
@@ -111,7 +111,7 @@ int pn_proactor_listen(pn_proactor_t *proactor, pn_listener_t *listener,
  * batch must be handled in sequence, but batches returned by separate
  * calls to pn_proactor_wait() can be handled concurrently.
  */
-pn_event_batch_t *pn_proactor_wait(pn_proactor_t *proactor);
+PNP_EXTERN pn_event_batch_t *pn_proactor_wait(pn_proactor_t *proactor);
 
 /**
  * Call when done handling a batch of events.
@@ -122,7 +122,7 @@ pn_event_batch_t *pn_proactor_wait(pn_proactor_t *proactor);
  * @note Thread-safe: may be called from any thread provided the
  * exactly once rule is respected.
  */
-void pn_proactor_done(pn_proactor_t *proactor, pn_event_batch_t *events);
+PNP_EXTERN void pn_proactor_done(pn_proactor_t *proactor, pn_event_batch_t *events);
 
 /**
  * Cause PN_PROACTOR_INTERRUPT to be returned to exactly one call of
@@ -136,7 +136,7 @@ void pn_proactor_done(pn_proactor_t *proactor, pn_event_batch_t *events);
  *
  * @note Thread-safe.
  */
-void pn_proactor_interrupt(pn_proactor_t *proactor);
+PNP_EXTERN void pn_proactor_interrupt(pn_proactor_t *proactor);
 
 /**
  * Cause PN_PROACTOR_TIMEOUT to be returned to a thread calling wait()
@@ -148,7 +148,7 @@ void pn_proactor_interrupt(pn_proactor_t *proactor);
  * timeout. `pn_proactor_set_timeout(0)` will cancel the timeout
  * without setting a new one.
  */
-void pn_proactor_set_timeout(pn_proactor_t *proactor, pn_millis_t timeout);
+PNP_EXTERN void pn_proactor_set_timeout(pn_proactor_t *proactor, pn_millis_t timeout);
 
 /**
  * Cause a PN_CONNECTION_WAKE event to be returned by the proactor, even if
@@ -160,22 +160,22 @@ void pn_proactor_set_timeout(pn_proactor_t *proactor, pn_millis_t timeout);
  * Wakes can be "coalesced" - if several pn_connection_wake() calls happen
  * concurrently, there may be only one PN_CONNECTION_WAKE event.
  */
-void pn_connection_wake(pn_connection_t *connection);
+PNP_EXTERN void pn_connection_wake(pn_connection_t *connection);
 
 /**
  * Return the proactor associated with a connection or NULL.
  */
-pn_proactor_t *pn_connection_proactor(pn_connection_t *connection);
+PNP_EXTERN pn_proactor_t *pn_connection_proactor(pn_connection_t *connection);
 
 /**
  * Return the proactor associated with an event or NULL.
  */
-pn_proactor_t *pn_event_proactor(pn_event_t *event);
+PNP_EXTERN pn_proactor_t *pn_event_proactor(pn_event_t *event);
 
 /**
  * Return the listener associated with an event or NULL.
  */
-pn_listener_t *pn_event_listener(pn_event_t *event);
+PNP_EXTERN pn_listener_t *pn_event_listener(pn_event_t *event);
 
 /**
  * @}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index 4400393..1abe9e6 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -407,6 +407,12 @@ typedef struct pn_delivery_t pn_delivery_t;
 typedef struct pn_collector_t pn_collector_t;
 
 /**
+ * A listener accepts connections.
+ * @ingroup listener
+ */
+typedef struct pn_listener_t pn_listener_t;
+
+/**
  * An AMQP Transport object.
  *
  * A pn_transport_t encapsulates the transport related state of all
@@ -419,6 +425,11 @@ typedef struct pn_collector_t pn_collector_t;
 typedef struct pn_transport_t pn_transport_t;
 
 /**
+ * The proactor, see pn_proactor()
+ */
+typedef struct pn_proactor_t pn_proactor_t;
+
+/**
  * @cond INTERNAL
  *
  * An event handler
@@ -426,12 +437,6 @@ typedef struct pn_transport_t pn_transport_t;
  * A pn_handler_t is target of ::pn_event_t dispatched by the pn_reactor_t
  */
 typedef struct pn_handler_t pn_handler_t;
-
-/**
- *
- */
-typedef struct pn_proactor_t pn_proactor_t;
-typedef struct pn_listener_t pn_listener_t;
 /**
  * @endcond
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/src/libqpid-proton-proactor.pc.in
----------------------------------------------------------------------
diff --git a/proton-c/src/libqpid-proton-proactor.pc.in b/proton-c/src/libqpid-proton-proactor.pc.in
new file mode 100644
index 0000000..19007a8
--- /dev/null
+++ b/proton-c/src/libqpid-proton-proactor.pc.in
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: Proton Proactor
+Description: Qpid Proton C proative IO library
+Version: @PN_VERSION@
+URL: http://qpid.apache.org/proton/
+Libs: -L${libdir} -lqpid-proton-proactor
+Cflags: -I${includedir}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/afacb165/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
new file mode 100644
index 0000000..42bbfab
--- /dev/null
+++ b/proton-c/src/proactor/libuv.c
@@ -0,0 +1,873 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <uv.h>
+
+#include <proton/condition.h>
+#include <proton/connection_driver.h>
+#include <proton/engine.h>
+#include <proton/message.h>
+#include <proton/object.h>
+#include <proton/proactor.h>
+#include <proton/transport.h>
+#include <proton/url.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+  libuv loop functions are thread unsafe. The only exception is uv_async_send()
+  which is a thread safe "wakeup" that can wake the uv_loop from another thread.
+
+  To provide concurrency the proactor uses a "leader-worker-follower" model,
+  threads take turns at the roles:
+
+  - a single "leader" calls libuv functions and runs the uv_loop in short bursts
+    to generate work. When there is work available it gives up leadership and
+    becomes a "worker"
+
+  - "workers" handle events concurrently for distinct connections/listeners
+    They do as much work as they can get, when none is left they become "followers"
+
+  - "followers" wait for the leader to generate work and become workers.
+    When the leader itself becomes a worker, one of the followers takes over.
+
+  This model is symmetric: any thread can take on any role based on run-time
+  requirements. It also allows the IO and non-IO work associated with an IO
+  wake-up to be processed in a single thread with no context switches.
+
+  Function naming:
+  - on_ - called in leader thread via uv_run().
+  - leader_ - called in leader thread, while processing the leader_q.
+  - owner_ - called in owning thread, leader or worker but not concurrently.
+
+  Note on_ and leader_ functions can call each other, the prefix indicates the
+  path they are most often called on.
+*/
+
+const char *COND_NAME = "proactor";
+const char *AMQP_PORT = "5672";
+const char *AMQP_PORT_NAME = "amqp";
+const char *AMQPS_PORT = "5671";
+const char *AMQPS_PORT_NAME = "amqps";
+
+PN_HANDLE(PN_PROACTOR)
+
+/* pn_proactor_t and pn_listener_t are plain C structs with normal memory management.
+   Class definitions are for identification as pn_event_t context only.
+*/
+PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
+PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
+
+/* common to connection and listener */
+typedef struct psocket_t {
+  /* Immutable */
+  pn_proactor_t *proactor;
+
+  /* Protected by proactor.lock */
+  struct psocket_t* next;
+  void (*wakeup)(struct psocket_t*); /* interrupting action for leader */
+
+  /* Only used by leader */
+  uv_tcp_t tcp;
+  void (*action)(struct psocket_t*); /* deferred action for leader */
+  bool is_conn:1;
+  char host[NI_MAXHOST];
+  char port[NI_MAXSERV];
+} psocket_t;
+
+/* Special value for psocket.next pointer when socket is not on any any list. */
+psocket_t UNLISTED;
+
+static void psocket_init(psocket_t* ps, pn_proactor_t* p, bool is_conn, const char *host, const char *port) {
+  ps->proactor = p;
+  ps->next = &UNLISTED;
+  ps->is_conn = is_conn;
+  ps->tcp.data = ps;
+
+  /* For platforms that don't know about "amqp" and "amqps" service names. */
+  if (strcmp(port, AMQP_PORT_NAME) == 0)
+    port = AMQP_PORT;
+  else if (strcmp(port, AMQPS_PORT_NAME) == 0)
+    port = AMQPS_PORT;
+  /* Set to "\001" to indicate a NULL as opposed to an empty string "" */
+  strncpy(ps->host, host ? host : "\001", sizeof(ps->host));
+  strncpy(ps->port, port ? port : "\001", sizeof(ps->port));
+}
+
+/* Turn "\001" back to NULL */
+static inline const char* fixstr(const char* str) {
+  return str[0] == '\001' ? NULL : str;
+}
+
+typedef struct pconnection_t {
+  psocket_t psocket;
+
+  /* Only used by owner thread */
+  pn_connection_driver_t driver;
+
+  /* Only used by leader */
+  uv_connect_t connect;
+  uv_timer_t timer;
+  uv_write_t write;
+  uv_shutdown_t shutdown;
+  size_t writing;
+  bool reading:1;
+  bool server:1;                /* accept, not connect */
+} pconnection_t;
+
+struct pn_listener_t {
+  psocket_t psocket;
+
+  /* Only used by owner thread */
+  pconnection_t *accepting;     /* accept in progress */
+  pn_condition_t *condition;
+  pn_collector_t *collector;
+  pn_event_batch_t batch;
+  pn_record_t *attachments;
+  void *context;
+  size_t backlog;
+};
+
+
+typedef struct queue { psocket_t *front, *back; } queue;
+
+struct pn_proactor_t {
+  /* Leader thread  */
+  uv_cond_t cond;
+  uv_loop_t loop;
+  uv_async_t async;
+  uv_timer_t timer;
+
+  /* Owner thread: proactor collector and batch can belong to leader or a worker */
+  pn_collector_t *collector;
+  pn_event_batch_t batch;
+
+  /* Protected by lock */
+  uv_mutex_t lock;
+  queue start_q;
+  queue worker_q;
+  queue leader_q;
+  size_t interrupt;             /* pending interrupts */
+  pn_millis_t timeout;
+  size_t count;                 /* psocket count */
+  bool inactive:1;
+  bool timeout_request:1;
+  bool timeout_elapsed:1;
+  bool has_leader:1;
+  bool batch_working:1;          /* batch belongs to a worker.  */
+};
+
+static bool push_lh(queue *q, psocket_t *ps) {
+  if (ps->next != &UNLISTED)  /* Don't move if already listed. */
+    return false;
+  ps->next = NULL;
+  if (!q->front) {
+    q->front = q->back = ps;
+  } else {
+    q->back->next = ps;
+    q->back =  ps;
+  }
+  return true;
+}
+
+static psocket_t* pop_lh(queue *q) {
+  psocket_t *ps = q->front;
+  if (ps) {
+    q->front = ps->next;
+    ps->next = &UNLISTED;
+  }
+  return ps;
+}
+
+static inline pconnection_t *as_pconnection_t(psocket_t* ps) {
+  return ps->is_conn ? (pconnection_t*)ps : NULL;
+}
+
+static inline pn_listener_t *as_listener(psocket_t* ps) {
+  return ps->is_conn ? NULL: (pn_listener_t*)ps;
+}
+
+/* Put ps on the leader queue for processing. Thread safe. */
+static void to_leader_lh(psocket_t *ps) {
+  push_lh(&ps->proactor->leader_q, ps);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+}
+
+static void to_leader(psocket_t *ps) {
+  uv_mutex_lock(&ps->proactor->lock);
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Detach from IO and put ps on the worker queue */
+static void leader_to_worker(psocket_t *ps) {
+  if (ps->is_conn) {
+    pconnection_t *pc = as_pconnection_t(ps);
+    /* Don't detach if there are no events yet. */
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      if (pc->writing) {
+        pc->writing  = 0;
+        uv_cancel((uv_req_t*)&pc->write);
+      }
+      if (pc->reading) {
+        pc->reading = false;
+        uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
+      }
+      if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
+        uv_timer_stop(&pc->timer);
+      }
+    }
+  } else {
+    pn_listener_t *l = as_listener(ps);
+    uv_read_stop((uv_stream_t*)&l->psocket.tcp);
+  }
+  uv_mutex_lock(&ps->proactor->lock);
+  push_lh(&ps->proactor->worker_q, ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Set a deferred action for leader, if not already set. */
+static void owner_to_leader(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  if (!ps->action) {
+    ps->action = action;
+  }
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Owner thread send to worker thread. Set deferred action if not already set. */
+static void owner_to_worker(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  if (!ps->action) {
+    ps->action = action;
+  }
+  push_lh(&ps->proactor->worker_q, ps);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+
+/* Re-queue for further work */
+static void worker_requeue(psocket_t* ps) {
+  uv_mutex_lock(&ps->proactor->lock);
+  push_lh(&ps->proactor->worker_q, ps);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
+  pconnection_t *pc = (pconnection_t*)calloc(1, sizeof(*pc));
+  if (!pc) return NULL;
+  if (pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
+    return NULL;
+  }
+  psocket_init(&pc->psocket, p,  true, host, port);
+  if (server) {
+    pn_transport_set_server(pc->driver.transport);
+  }
+  pn_record_t *r = pn_connection_attachments(pc->driver.connection);
+  pn_record_def(r, PN_PROACTOR, PN_VOID);
+  pn_record_set(r, PN_PROACTOR, pc);
+  return pc;
+}
+
+static pn_event_t *listener_batch_next(pn_event_batch_t *batch);
+static pn_event_t *proactor_batch_next(pn_event_batch_t *batch);
+
+static inline pn_proactor_t *batch_proactor(pn_event_batch_t *batch) {
+  return (batch->next_event == proactor_batch_next) ?
+    (pn_proactor_t*)((char*)batch - offsetof(pn_proactor_t, batch)) : NULL;
+}
+
+static inline pn_listener_t *batch_listener(pn_event_batch_t *batch) {
+  return (batch->next_event == listener_batch_next) ?
+    (pn_listener_t*)((char*)batch - offsetof(pn_listener_t, batch)) : NULL;
+}
+
+static inline pconnection_t *batch_pconnection(pn_event_batch_t *batch) {
+  pn_connection_driver_t *d = pn_event_batch_connection_driver(batch);
+  return d ? (pconnection_t*)((char*)d - offsetof(pconnection_t, driver)) : NULL;
+}
+
+static void leader_count(pn_proactor_t *p, int change) {
+  uv_mutex_lock(&p->lock);
+  p->count += change;
+  p->inactive = (p->count == 0);
+  uv_mutex_unlock(&p->lock);
+}
+
+/* Free if there are no uv callbacks pending and no events */
+static void leader_pconnection_t_maybe_free(pconnection_t *pc) {
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      leader_to_worker(&pc->psocket);         /* Return to worker */
+    } else if (!(pc->psocket.tcp.data || pc->write.data || pc->shutdown.data || pc->timer.data)) {
+      /* All UV requests are finished */
+      pn_connection_driver_destroy(&pc->driver);
+      leader_count(pc->psocket.proactor, -1);
+      free(pc);
+    }
+}
+
+/* Free if there are no uv callbacks pending and no events */
+static void leader_listener_maybe_free(pn_listener_t *l) {
+    if (pn_collector_peek(l->collector)) {
+      leader_to_worker(&l->psocket);         /* Return to worker */
+    } else if (!l->psocket.tcp.data) {
+      pn_condition_free(l->condition);
+      leader_count(l->psocket.proactor, -1);
+      free(l);
+    }
+}
+
+/* Free if there are no uv callbacks pending and no events */
+static void leader_maybe_free(psocket_t *ps) {
+  if (ps->is_conn) {
+    leader_pconnection_t_maybe_free(as_pconnection_t(ps));
+  } else {
+    leader_listener_maybe_free(as_listener(ps));
+  }
+}
+
+static void on_close(uv_handle_t *h) {
+  psocket_t *ps = (psocket_t*)h->data;
+  h->data = NULL;               /* Mark closed */
+  leader_maybe_free(ps);
+}
+
+static void on_shutdown(uv_shutdown_t *shutdown, int err) {
+  psocket_t *ps = (psocket_t*)shutdown->data;
+  shutdown->data = NULL;        /* Mark closed */
+  leader_maybe_free(ps);
+}
+
+static inline void leader_close(psocket_t *ps) {
+  if (ps->tcp.data && !uv_is_closing((uv_handle_t*)&ps->tcp)) {
+    uv_close((uv_handle_t*)&ps->tcp, on_close);
+  }
+  pconnection_t *pc = as_pconnection_t(ps);
+  if (pc) {
+    pn_connection_driver_close(&pc->driver);
+    if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
+      uv_timer_stop(&pc->timer);
+      uv_close((uv_handle_t*)&pc->timer, on_close);
+    }
+  }
+  leader_maybe_free(ps);
+}
+
+static pconnection_t *get_pconnection_t(pn_connection_t* c) {
+  if (!c) return NULL;
+  pn_record_t *r = pn_connection_attachments(c);
+  return (pconnection_t*) pn_record_get(r, PN_PROACTOR);
+}
+
+static void leader_error(psocket_t *ps, int err, const char* what) {
+  if (ps->is_conn) {
+    pn_connection_driver_t *driver = &as_pconnection_t(ps)->driver;
+    pn_connection_driver_bind(driver); /* Bind so errors will be reported */
+    pn_connection_driver_errorf(driver, COND_NAME, "%s %s:%s: %s",
+                                what, fixstr(ps->host), fixstr(ps->port),
+                                uv_strerror(err));
+    pn_connection_driver_close(driver);
+  } else {
+    pn_listener_t *l = as_listener(ps);
+    pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
+                        what, fixstr(ps->host), fixstr(ps->port),
+                        uv_strerror(err));
+    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
+  }
+  leader_to_worker(ps);               /* Worker to handle the error */
+}
+
+/* uv-initialization */
+static int leader_init(psocket_t *ps) {
+  leader_count(ps->proactor, +1);
+  int err = uv_tcp_init(&ps->proactor->loop, &ps->tcp);
+  if (!err) {
+    pconnection_t *pc = as_pconnection_t(ps);
+    if (pc) {
+      pc->connect.data = ps;
+      int err = uv_timer_init(&ps->proactor->loop, &pc->timer);
+      if (!err) {
+        pc->timer.data = pc;
+      }
+    }
+  }
+  if (err) {
+    leader_error(ps, err, "initialization");
+  }
+  return err;
+}
+
+/* Common logic for on_connect and on_accept */
+static void leader_connect_accept(pconnection_t *pc, int err, const char *what) {
+  if (!err) {
+    leader_to_worker(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, err, what);
+  }
+}
+
+static void on_connect(uv_connect_t *connect, int err) {
+  leader_connect_accept((pconnection_t*)connect->data, err, "on connect");
+}
+
+static void on_accept(uv_stream_t* server, int err) {
+  pn_listener_t *l = (pn_listener_t*) server->data;
+  if (err) {
+    leader_error(&l->psocket, err, "on accept");
+  }
+  pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
+  leader_to_worker(&l->psocket); /* Let user call pn_listener_accept */
+}
+
+static void leader_accept(psocket_t *ps) {
+  pn_listener_t * l = as_listener(ps);
+  pconnection_t *pc = l->accepting;
+  l->accepting = NULL;
+  if (pc) {
+    int err = leader_init(&pc->psocket);
+    if (!err) err = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
+    leader_connect_accept(pc, err, "on accept");
+  }
+}
+
+static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
+  int err = leader_init(ps);
+  struct addrinfo hints = { 0 };
+  if (server) hints.ai_flags = AI_PASSIVE;
+  if (!err) {
+    err = uv_getaddrinfo(&ps->proactor->loop, info, NULL, fixstr(ps->host), fixstr(ps->port), &hints);
+  }
+  return err;
+}
+
+static void leader_connect(psocket_t *ps) {
+  pconnection_t *pc = as_pconnection_t(ps);
+  uv_getaddrinfo_t info;
+  int err = leader_resolve(ps, &info, false);
+  if (!err) {
+    err = uv_tcp_connect(&pc->connect, &pc->psocket.tcp, info.addrinfo->ai_addr, on_connect);
+    uv_freeaddrinfo(info.addrinfo);
+  }
+  if (err) {
+    leader_error(ps, err, "connect to");
+  }
+}
+
+static void leader_listen(psocket_t *ps) {
+  pn_listener_t *l = as_listener(ps);
+   uv_getaddrinfo_t info;
+  int err = leader_resolve(ps, &info, true);
+  if (!err) {
+    err = uv_tcp_bind(&l->psocket.tcp, info.addrinfo->ai_addr, 0);
+    uv_freeaddrinfo(info.addrinfo);
+  }
+  if (!err) err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
+  if (err) {
+    leader_error(ps, err, "listen on ");
+  }
+}
+
+static void on_tick(uv_timer_t *timer) {
+  pconnection_t *pc = (pconnection_t*)timer->data;
+  pn_transport_t *t = pc->driver.transport;
+  if (pn_transport_get_idle_timeout(t) || pn_transport_get_remote_idle_timeout(t)) {
+    uv_timer_stop(&pc->timer);
+    uint64_t now = uv_now(pc->timer.loop);
+    uint64_t next = pn_transport_tick(t, now);
+    if (next) {
+      uv_timer_start(&pc->timer, on_tick, next - now, 0);
+    }
+  }
+}
+
+static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+  pconnection_t *pc = (pconnection_t*)stream->data;
+  if (nread >= 0) {
+    pn_connection_driver_read_done(&pc->driver, nread);
+    on_tick(&pc->timer);         /* check for tick changes. */
+    leader_to_worker(&pc->psocket);
+    /* Reading continues automatically until stopped. */
+  } else if (nread == UV_EOF) { /* hangup */
+    pn_connection_driver_read_close(&pc->driver);
+    leader_maybe_free(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, nread, "on read from");
+  }
+}
+
+static void on_write(uv_write_t* write, int err) {
+  pconnection_t *pc = (pconnection_t*)write->data;
+  write->data = NULL;
+  if (err == 0) {
+    pn_connection_driver_write_done(&pc->driver, pc->writing);
+    leader_to_worker(&pc->psocket);
+  } else if (err == UV_ECANCELED) {
+    leader_maybe_free(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, err, "on write to");
+  }
+  pc->writing = 0;              /* Need to send a new write request */
+}
+
+static void on_timeout(uv_timer_t *timer) {
+  pn_proactor_t *p = (pn_proactor_t*)timer->data;
+  uv_mutex_lock(&p->lock);
+  p->timeout_elapsed = true;
+  uv_mutex_unlock(&p->lock);
+}
+
+// Read buffer allocation function for uv, just returns the transports read buffer.
+static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
+  pconnection_t *pc = (pconnection_t*)stream->data;
+  pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
+  *buf = uv_buf_init(rbuf.start, rbuf.size);
+}
+
+static void leader_rewatch(psocket_t *ps) {
+  int err = 0;
+  if (ps->is_conn) {
+    pconnection_t *pc = as_pconnection_t(ps);
+    if (pc->timer.data) {         /* uv-initialized */
+      on_tick(&pc->timer);        /* Re-enable ticks if required */
+    }
+    pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
+    pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
+
+    /* Ticks and checking buffers can generate events, process before proceeding */
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      leader_to_worker(ps);
+    } else {                      /* Re-watch for IO */
+      if (wbuf.size > 0 && !pc->writing) {
+        pc->writing = wbuf.size;
+        uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
+        pc->write.data = ps;
+        uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
+      } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
+        pc->shutdown.data = ps;
+        uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
+      }
+      if (rbuf.size > 0 && !pc->reading) {
+        pc->reading = true;
+        err = uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
+      }
+    }
+  } else {
+    pn_listener_t *l = as_listener(ps);
+    err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
+  }
+  if (err) {
+    leader_error(ps, err, "rewatch");
+  }
+}
+
+/* Set the event in the proactor's batch  */
+static pn_event_batch_t *proactor_batch_lh(pn_proactor_t *p, pn_event_type_t t) {
+  pn_collector_put(p->collector, pn_proactor__class(), p, t);
+  p->batch_working = true;
+  return &p->batch;
+}
+
+/* Return the next event batch or 0 if no events are ready */
+static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
+  if (!p->batch_working) {       /* Can generate proactor events */
+    if (p->inactive) {
+      p->inactive = false;
+      return proactor_batch_lh(p, PN_PROACTOR_INACTIVE);
+    }
+    if (p->interrupt > 0) {
+      --p->interrupt;
+      return proactor_batch_lh(p, PN_PROACTOR_INTERRUPT);
+    }
+    if (p->timeout_elapsed) {
+      p->timeout_elapsed = false;
+      return proactor_batch_lh(p, PN_PROACTOR_TIMEOUT);
+    }
+  }
+  for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
+    if (ps->is_conn) {
+      pconnection_t *pc = as_pconnection_t(ps);
+      return &pc->driver.batch;
+    } else {                    /* Listener */
+      pn_listener_t *l = as_listener(ps);
+      return &l->batch;
+    }
+    to_leader(ps);      /* No event, back to leader */
+  }
+  return 0;
+}
+
+/* Called in any thread to set a wakeup action. Replaces any previous wakeup action. */
+static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  ps->wakeup = action;
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+pn_listener_t *pn_event_listener(pn_event_t *e) {
+  return (pn_event_class(e) == pn_listener__class()) ? (pn_listener_t*)pn_event_context(e) : NULL;
+}
+
+pn_proactor_t *pn_event_proactor(pn_event_t *e) {
+  if (pn_event_class(e) == pn_proactor__class()) return (pn_proactor_t*)pn_event_context(e);
+  pn_listener_t *l = pn_event_listener(e);
+  if (l) return l->psocket.proactor;
+  pn_connection_t *c = pn_event_connection(e);
+  if (c) return pn_connection_proactor(pn_event_connection(e));
+  return NULL;
+}
+
+void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
+  pconnection_t *pc = batch_pconnection(batch);
+  if (pc) {
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      /* Process all events before going back to IO. */
+      worker_requeue(&pc->psocket);
+    } else if (pn_connection_driver_finished(&pc->driver)) {
+      owner_to_leader(&pc->psocket, leader_close);
+    } else {
+      owner_to_leader(&pc->psocket, leader_rewatch);
+    }
+    return;
+  }
+  pn_listener_t *l = batch_listener(batch);
+  if (l) {
+    owner_to_leader(&l->psocket, leader_rewatch);
+    return;
+  }
+  pn_proactor_t *bp = batch_proactor(batch);
+  if (bp == p) {
+    uv_mutex_lock(&p->lock);
+    p->batch_working = false;
+    uv_async_send(&p->async); /* Wake leader */
+    uv_mutex_unlock(&p->lock);
+    return;
+  }
+}
+
+/* Run follower/leader loop till we can return an event and be a worker */
+pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
+  uv_mutex_lock(&p->lock);
+  /* Try to grab work immediately. */
+  pn_event_batch_t *batch = get_batch_lh(p);
+  if (batch == NULL) {
+    /* No work available, follow the leader */
+    while (p->has_leader) {
+      uv_cond_wait(&p->cond, &p->lock);
+    }
+    /* Lead till there is work to do. */
+    p->has_leader = true;
+    while (batch == NULL) {
+      if (p->timeout_request) {
+        p->timeout_request = false;
+        if (p->timeout) {
+          uv_timer_start(&p->timer, on_timeout, p->timeout, 0);
+        } else {
+          uv_timer_stop(&p->timer);
+        }
+      }
+      for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
+        void (*action)(psocket_t*) = ps->action;
+        void (*wakeup)(psocket_t*) = ps->wakeup;
+        ps->action = NULL;
+        ps->wakeup = NULL;
+        if (action || wakeup) {
+          uv_mutex_unlock(&p->lock);
+          if (action) action(ps);
+          if (wakeup) wakeup(ps);
+          uv_mutex_lock(&p->lock);
+        }
+      }
+      batch = get_batch_lh(p);
+      if (batch == NULL) {
+        uv_mutex_unlock(&p->lock);
+        uv_run(&p->loop, UV_RUN_ONCE);
+        uv_mutex_lock(&p->lock);
+      }
+    }
+    /* Signal the next leader and return to work */
+    p->has_leader = false;
+    uv_cond_signal(&p->cond);
+  }
+  uv_mutex_unlock(&p->lock);
+  return batch;
+}
+
+void pn_proactor_interrupt(pn_proactor_t *p) {
+  uv_mutex_lock(&p->lock);
+  ++p->interrupt;
+  uv_async_send(&p->async);   /* Interrupt the UV loop */
+  uv_mutex_unlock(&p->lock);
+}
+
+void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
+  uv_mutex_lock(&p->lock);
+  p->timeout = t;
+  p->timeout_request = true;
+  uv_async_send(&p->async);   /* Interrupt the UV loop */
+  uv_mutex_unlock(&p->lock);
+}
+
+int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {
+  pconnection_t *pc = new_pconnection_t(p, c, false, host, port);
+  if (!pc) {
+    return PN_OUT_OF_MEMORY;
+  }
+  /* Process PN_CONNECTION_INIT before binding */
+  owner_to_worker(&pc->psocket, leader_connect);
+  return 0;
+}
+
+int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *host, const char *port, int backlog)
+{
+  psocket_init(&l->psocket, p, false, host, port);
+  l->backlog = backlog;
+  owner_to_leader(&l->psocket, leader_listen);
+  return 0;
+}
+
+pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
+  pconnection_t *pc = get_pconnection_t(c);
+  return pc ? pc->psocket.proactor : NULL;
+}
+
+void leader_wake_connection(psocket_t *ps) {
+  pconnection_t *pc = as_pconnection_t(ps);
+  pn_connection_t *c = pc->driver.connection;
+  pn_collector_put(pn_connection_collector(c), PN_OBJECT, c, PN_CONNECTION_WAKE);
+  leader_to_worker(ps);
+}
+
+void pn_connection_wake(pn_connection_t* c) {
+  wakeup(&get_pconnection_t(c)->psocket, leader_wake_connection);
+}
+
+pn_proactor_t *pn_proactor() {
+  pn_proactor_t *p = (pn_proactor_t*)calloc(1, sizeof(*p));
+  p->collector = pn_collector();
+  p->batch.next_event = &proactor_batch_next;
+  if (!p->collector) return NULL;
+  uv_loop_init(&p->loop);
+  uv_mutex_init(&p->lock);
+  uv_cond_init(&p->cond);
+  uv_async_init(&p->loop, &p->async, NULL);
+  uv_timer_init(&p->loop, &p->timer); /* Just wake the loop */
+  p->timer.data = p;
+  return p;
+}
+
+static void on_stopping(uv_handle_t* h, void* v) {
+  uv_close(h, NULL);           /* Close this handle */
+  if (!uv_loop_alive(h->loop)) /* Everything closed */
+    uv_stop(h->loop);        /* Stop the loop, pn_proactor_destroy() can return */
+}
+
+void pn_proactor_free(pn_proactor_t *p) {
+  uv_walk(&p->loop, on_stopping, NULL); /* Close all handles */
+  uv_run(&p->loop, UV_RUN_DEFAULT);     /* Run till stop, all handles closed */
+  uv_loop_close(&p->loop);
+  uv_mutex_destroy(&p->lock);
+  uv_cond_destroy(&p->cond);
+  pn_collector_free(p->collector);
+  free(p);
+}
+
+static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
+  pn_listener_t *l = batch_listener(batch);
+  pn_event_t *handled = pn_collector_prev(l->collector);
+  if (handled && pn_event_type(handled) == PN_LISTENER_CLOSE) {
+    owner_to_leader(&l->psocket, leader_close); /* Close event handled, do close */
+  }
+  return pn_collector_next(l->collector);
+}
+
+static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
+  return pn_collector_next(batch_proactor(batch)->collector);
+}
+
+static void pn_listener_free(pn_listener_t *l) {
+  if (l) {
+    if (!l->collector) pn_collector_free(l->collector);
+    if (!l->condition) pn_condition_free(l->condition);
+    if (!l->attachments) pn_free(l->attachments);
+    free(l);
+  }
+}
+
+pn_listener_t *pn_listener() {
+  pn_listener_t *l = (pn_listener_t*)calloc(1, sizeof(pn_listener_t));
+  if (l) {
+    l->batch.next_event = listener_batch_next;
+    l->collector = pn_collector();
+    l->condition = pn_condition();
+    l->attachments = pn_record();
+    if (!l->condition || !l->collector || !l->attachments) {
+      pn_listener_free(l);
+      return NULL;
+    }
+  }
+  return l;
+}
+
+void pn_listener_close(pn_listener_t* l) {
+  wakeup(&l->psocket, leader_close);
+}
+
+pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
+  return l ? l->psocket.proactor : NULL;
+}
+
+pn_condition_t* pn_listener_condition(pn_listener_t* l) {
+  return l->condition;
+}
+
+void *pn_listener_get_context(pn_listener_t *l) {
+  return l->context;
+}
+
+void pn_listener_set_context(pn_listener_t *l, void *context) {
+  l->context = context;
+}
+
+pn_record_t *pn_listener_attachments(pn_listener_t *l) {
+  return l->attachments;
+}
+
+int pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
+  if (l->accepting) {
+    return PN_STATE_ERR;        /* Only one at a time */
+  }
+  l->accepting = new_pconnection_t(
+      l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
+  if (!l->accepting) {
+    return UV_ENOMEM;
+  }
+  owner_to_leader(&l->psocket, leader_accept);
+  return 0;
+}
+


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[12/38] qpid-proton git commit: PROTON-1403: Export pn_listener APIs from libqpid_proton_proactor library

Posted by ac...@apache.org.
PROTON-1403: Export pn_listener APIs from libqpid_proton_proactor library


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/31b8cc65
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/31b8cc65
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/31b8cc65

Branch: refs/heads/go1
Commit: 31b8cc654f8e76ffd29f36bf808815ea22a13d9a
Parents: 03071a1
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Feb 13 10:59:02 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Feb 13 11:02:04 2017 -0500

----------------------------------------------------------------------
 proton-c/include/proton/listener.h | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/31b8cc65/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index 4656ee4..18feca7 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -46,19 +46,19 @@ extern "C" {
  * You must pass the returned listener to pn_proactor_listen(), the proactor
  * will free the listener when it is no longer active.
  */
-PN_EXTERN pn_listener_t *pn_listener(void);
+PNP_EXTERN pn_listener_t *pn_listener(void);
 
 /**
  * Asynchronously accept a connection using the listener.
  *
  * @param[in] connection the listener takes ownership, do not free.
  */
-PN_EXTERN int pn_listener_accept(pn_listener_t*, pn_connection_t *connection);
+PNP_EXTERN int pn_listener_accept(pn_listener_t*, pn_connection_t *connection);
 
 /**
  * Get the error condition for a listener.
  */
-PN_EXTERN pn_condition_t *pn_listener_condition(pn_listener_t *l);
+PNP_EXTERN pn_condition_t *pn_listener_condition(pn_listener_t *l);
 
 /**
  * @cond INTERNAL
@@ -69,14 +69,14 @@ PN_EXTERN pn_condition_t *pn_listener_condition(pn_listener_t *l);
  *
  * Get the application context that is associated with a listener.
  */
-PN_EXTERN void *pn_listener_get_context(pn_listener_t *listener);
+PNP_EXTERN void *pn_listener_get_context(pn_listener_t *listener);
 
 /**
  * @deprecated
  *
  * Set a new application context for a listener.
  */
-PN_EXTERN void pn_listener_set_context(pn_listener_t *listener, void *context);
+PNP_EXTERN void pn_listener_set_context(pn_listener_t *listener, void *context);
 
 /**
  * @endcond
@@ -85,17 +85,17 @@ PN_EXTERN void pn_listener_set_context(pn_listener_t *listener, void *context);
 /**
  * Get the attachments that are associated with a listener object.
  */
-PN_EXTERN pn_record_t *pn_listener_attachments(pn_listener_t *listener);
+PNP_EXTERN pn_record_t *pn_listener_attachments(pn_listener_t *listener);
 
 /**
  * Close the listener (thread safe).
  */
-PN_EXTERN void pn_listener_close(pn_listener_t *l);
+PNP_EXTERN void pn_listener_close(pn_listener_t *l);
 
 /**
  * The proactor associated with a listener.
  */
-PN_EXTERN pn_proactor_t *pn_listener_proactor(pn_listener_t *c);
+PNP_EXTERN pn_proactor_t *pn_listener_proactor(pn_listener_t *c);
 
 
 /**


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[31/38] qpid-proton git commit: Revert "NO-JIRA: go binding build results in binary dir, not source dir"

Posted by ac...@apache.org.
Revert "NO-JIRA: go binding build results in binary dir, not source dir"

This reverts commit 9bd99ebf096ed83bd23ae05fe9cc0e6f65d9ac2e.

Copying sources into the bin dir for compliation is a bad idea:
- compile errors are located in the binary copy, not the source
- deleted source files are not reflected in the binary copy

Need a better solution.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/5d1c2479
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/5d1c2479
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/5d1c2479

Branch: refs/heads/go1
Commit: 5d1c24796a0411e659e082e81171cde511b04f02
Parents: 204c847
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 09:05:39 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 13:46:57 2017 -0500

----------------------------------------------------------------------
 .gitignore                          |  7 +++++++
 examples/go/CMakeLists.txt          |  8 +++++---
 proton-c/bindings/go/CMakeLists.txt | 17 +++++++++--------
 3 files changed, 21 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5d1c2479/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index b769990..aa9bc36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,9 +31,16 @@ eclipse-classes
 # The usual location for proton-c build files
 proton-c/build
 
+# Executables built by go binding tests
+proton-c/bindings/go/bin
+
 # Testresults from the jenkins build script
 testresults
 
+# Go binding build output
+/proton-c/bindings/go/pkg
+/proton-c/bindings/go/bin
+
 # Python TOX test build output
 /proton-c/bindings/python/MANIFEST
 /proton-c/bindings/python/build

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5d1c2479/examples/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/go/CMakeLists.txt b/examples/go/CMakeLists.txt
index 861cdd8..c9aba01 100644
--- a/examples/go/CMakeLists.txt
+++ b/examples/go/CMakeLists.txt
@@ -20,11 +20,12 @@
 if(BUILD_GO)
 
   set(examples electron/broker electron/receive electron/send proton/broker)
+  file(GLOB_RECURSE example_source FOLLOW_SYMLINKS ${CMAKE_CURRENT_SOURCE_DIR}/*.go)
 
   # Build example exes
   foreach(example ${examples})
-    string(REPLACE / - target ${example})
-    set(target "go-example-${target}")
+    string(REPLACE / _ target ${example})
+    set(target "go_example_${target}")
     set(output ${CMAKE_CURRENT_BINARY_DIR}/${example})
     # Always run go_build, it will do nothing if there is nothing to do.
     # Otherwise it's too hard to get the dependencies right.
@@ -32,11 +33,12 @@ if(BUILD_GO)
       COMMAND ${GO_BUILD} ${GO_EXAMPLE_FLAGS} -o ${output} ${CMAKE_CURRENT_SOURCE_DIR}/${example}.go
       WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
       DEPENDS go-build)
+    list(APPEND example_targets ${target})
   endforeach()
 
   # Build test driver exe
   set(test_exe ${CMAKE_CURRENT_BINARY_DIR}/example_test)
-  add_custom_target(go-example-test ALL
+  add_custom_target(go_example_test ALL
     COMMAND ${GO_TEST} -c -o ${test_exe} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.go
     WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5d1c2479/proton-c/bindings/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/CMakeLists.txt b/proton-c/bindings/go/CMakeLists.txt
index 1cb9d6c..d0ffe9b 100644
--- a/proton-c/bindings/go/CMakeLists.txt
+++ b/proton-c/bindings/go/CMakeLists.txt
@@ -26,6 +26,7 @@ set(GO_TEST_FLAGS "-v" CACHE STRING "Flags for 'go test'")
 
 # Flags that differ for golang go and gcc go.
 if (go_ver MATCHES "gccgo")
+  # TODO aconway 2015-10-08: import cycles with -race under gccgo, investigate.
   set(GO_RPATH_FLAGS -gccgoflags "-Wl,-rpath=${CMAKE_BINARY_DIR}/proton-c")
 else()
   set(GO_RPATH_FLAGS -ldflags "-r ${CMAKE_BINARY_DIR}/proton-c")
@@ -36,7 +37,7 @@ separate_arguments(GO_TEST_FLAGS)
 
 # Following are CACHE INTERNAL so examples/CMakeLists.txt can see them.
 set(GO_ENV ${env_py} --
-  "GOPATH=${CMAKE_CURRENT_BINARY_DIR}"
+  "GOPATH=${CMAKE_CURRENT_SOURCE_DIR}"
   "CGO_CFLAGS=-I${CMAKE_SOURCE_DIR}/proton-c/include -I${CMAKE_BINARY_DIR}/proton-c/include"
   "CGO_LDFLAGS=-L${CMAKE_BINARY_DIR}/proton-c"
   "PN_INTEROP_DIR=${CMAKE_SOURCE_DIR}/tests/interop"
@@ -46,15 +47,15 @@ set(GO ${GO_ENV} ${GO_EXE} CACHE INTERNAL "Run go with environment set")
 
 set(GO_BUILD ${GO} build ${GO_BUILD_FLAGS} ${GO_RPATH_FLAGS} CACHE INTERNAL "Run go build")
 set(GO_INSTALL ${GO} install ${GO_BUILD_FLAGS} CACHE INTERNAL "Run go install" )
-set(GO_TEST ${GO} test ${GO_TEST_FLAGS} ${GO_RPATH_FLAGS} CACHE INTERNAL "Run go test")
+set(GO_TEST ${GO} test ${GO_BUILD_FLAGS} ${GO_RPATH_FLAGS} ${GO_TEST_FLAGS} CACHE INTERNAL "Run go test")
 
-# The go build tools handle dependency checks and incremental builds better than CMake so
-# just run them every time, they do nothing if nothing needs to be done.
-#
-# The Go sources are copied to the binary directory so we can respect the standard Go tree
-# layout without polluting the source tree.
+# Go tools insist on standard Go layout which puts compiled code in the source tree :(
+# Build output is all under git-ignored pkg or bin subdirectories, they are removed by make clean.
+
+# The go build tools handle dependency checks and incremental builds better than
+# CMake so just run them every time, they do nothing if nothing needs to be
+# done.
 add_custom_target(go-build ALL
-  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/src
   COMMAND ${GO_INSTALL} qpid.apache.org/...
   DEPENDS qpid-proton-core
   WORKING_DIRECTORY $ENV{PWD})


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[37/38] qpid-proton git commit: NO-JIRA: go minor update to readme-go-get.md

Posted by ac...@apache.org.
NO-JIRA: go minor update to readme-go-get.md


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9ec97b51
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9ec97b51
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9ec97b51

Branch: refs/heads/go1
Commit: 9ec97b51c1fed9a77e5c3dc537e301fb7ae3c5fe
Parents: c94301d
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 23 17:50:10 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 23 17:50:10 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/go/src/qpid.apache.org/readme-go-get.md | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9ec97b51/proton-c/bindings/go/src/qpid.apache.org/readme-go-get.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/readme-go-get.md b/proton-c/bindings/go/src/qpid.apache.org/readme-go-get.md
index 6eb1e2b..c59561f 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/readme-go-get.md
+++ b/proton-c/bindings/go/src/qpid.apache.org/readme-go-get.md
@@ -9,6 +9,7 @@ Created with:
 Update with:
 
     git checkout go1
+    git pull
     git merge -s recursive -Xsubtree=proton-c/bindings/go/src/qpid.apache.org master
 
 To see the branch description: `git config branch.go1.description`


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[16/38] qpid-proton git commit: PROTON-1403: c libuv proactor missing writable transition on SASL

Posted by ac...@apache.org.
PROTON-1403: c libuv proactor missing writable transition on SASL

Regression from previous fixes, the libuv proactor was missing the event-less
writable transition when the engine receives an incoming SASL header.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/39c70d11
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/39c70d11
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/39c70d11

Branch: refs/heads/go1
Commit: 39c70d11e16275df0f356601a1e355388290b97e
Parents: 6291a75
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Feb 14 13:30:21 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Feb 14 13:30:21 2017 -0500

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/39c70d11/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 173f767..d17136a 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -493,8 +493,7 @@ static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
   assert(pc->psocket.state == ON_UV);
   if (nread >= 0) {
     pn_connection_driver_read_done(&pc->driver, nread);
-    on_tick(&pc->timer);         /* check for tick changes. */
-    /* Reading continues automatically until stopped. */
+    leader_unwatch(&pc->psocket); /* Handle events */
   } else if (nread == UV_EOF) { /* hangup */
     pn_connection_driver_read_close(&pc->driver);
     leader_unwatch(&pc->psocket);
@@ -535,7 +534,7 @@ static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
 
 /* Monitor a socket in the UV loop */
 static void leader_watch(psocket_t *ps) {
-  assert(ps->state == ON_LEADER);
+  assert(ps->state != ON_WORKER);
   int err = 0;
   set_state(ps, ON_UV, NULL); /* Assume we are going to UV loop unless sent to worker or leader. */
 
@@ -593,12 +592,8 @@ static void leader_unwatch(psocket_t *ps) {
   if (ps->is_conn) {
     pconnection_t *pc = as_pconnection(ps);
     if (!pn_connection_driver_has_event(&pc->driver)) {
-      /* Don't return an empty event batch */
-      if (ps->state == ON_UV) {
-        return;                 /* Just leave it in the UV loop */
-      } else {
-        leader_watch(ps);     /* Re-attach to UV loop */
-      }
+      /* Don't return an empty event batch, re-attach to UV loop */
+      leader_watch(ps);
       return;
     } else {
       if (pc->writing) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[30/38] qpid-proton git commit: PROTON-1403: C libuv proactor fixes and tests

Posted by ac...@apache.org.
PROTON-1403: C libuv proactor fixes and tests

- wake before connection prevented connection
- early errors (e.g. bad host/port) not handled correctly
- INACTIVE event not generated on listener closed


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/204c8474
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/204c8474
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/204c8474

Branch: refs/heads/go1
Commit: 204c8474d2b34f640189eb5c3063622b45fb5cc9
Parents: 6b6dd86
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Feb 20 19:56:19 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Feb 20 20:01:54 2017 -0500

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c   |  28 ++++----
 proton-c/src/tests/proactor.c   | 133 +++++++++++++++++++----------------
 proton-c/src/tests/test_tools.h |  14 ++++
 3 files changed, 102 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/204c8474/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index c7322cd..61239ac 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -235,11 +235,8 @@ static void to_leader(psocket_t *ps, void (*action)(psocket_t*)) {
 /* Push to the worker thread */
 static void to_worker(psocket_t *ps) {
   uv_mutex_lock(&ps->proactor->lock);
-  /* If already ON_WORKER do nothing */
-  if (ps->next == &UNLISTED && ps->state != ON_WORKER) {
-    ps->state = ON_WORKER;
-    push_lh(&ps->proactor->worker_q, ps);
-  }
+  ps->state = ON_WORKER;
+  push_lh(&ps->proactor->worker_q, ps);
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
@@ -310,7 +307,10 @@ static inline pconnection_t *batch_pconnection(pn_event_batch_t *batch) {
 static void leader_count(pn_proactor_t *p, int change) {
   uv_mutex_lock(&p->lock);
   p->count += change;
-  p->inactive = (p->count == 0);
+  if (p->count == 0) {
+    p->inactive = true;
+    uv_async_send(&p->async); /* Wake leader */
+  }
   uv_mutex_unlock(&p->lock);
 }
 
@@ -329,8 +329,8 @@ static void on_close_pconnection_final(uv_handle_t *h) {
 /* Close event for uv_tcp_t of a psocket_t */
 static void on_close_psocket(uv_handle_t *h) {
   psocket_t *ps = (psocket_t*)h->data;
+  leader_count(ps->proactor, -1);
   if (ps->is_conn) {
-    leader_count(ps->proactor, -1);
     pconnection_t *pc = as_pconnection(ps);
     uv_timer_stop(&pc->timer);
     /* Delay the free till the timer handle is also closed */
@@ -465,7 +465,7 @@ static void leader_connect(psocket_t *ps) {
   if (!err) {
     ps->state = ON_UV;
   } else {
-    psocket_error(ps, err, "connecting to");
+    pconnection_error(pc, err, "connecting to");
   }
 }
 
@@ -737,16 +737,16 @@ static void leader_process_lh(pn_proactor_t *p) {
   }
   for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
     assert(ps->state == ON_LEADER);
-    if (ps->wakeup) {
-      uv_mutex_unlock(&p->lock);
-      ps->wakeup(ps);
-      ps->wakeup = NULL;
-      uv_mutex_lock(&p->lock);
-    } else if (ps->action) {
+    if (ps->action) {
       uv_mutex_unlock(&p->lock);
       ps->action(ps);
       ps->action = NULL;
       uv_mutex_lock(&p->lock);
+    } else if (ps->wakeup) {
+      uv_mutex_unlock(&p->lock);
+      ps->wakeup(ps);
+      ps->wakeup = NULL;
+      uv_mutex_lock(&p->lock);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/204c8474/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index 9f8b1fe..6b95c11 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -32,6 +32,11 @@ static pn_millis_t timeout = 5*1000; /* timeout for hanging tests */
 
 static const char *localhost = "127.0.0.1"; /* host for connect/listen */
 
+struct test_events {
+  pn_proactor_t *proactor;
+  pn_event_batch_t *events;
+};
+
 /* Wait for the next single event, return its type */
 static pn_event_type_t wait_next(pn_proactor_t *proactor) {
   pn_event_batch_t *events = pn_proactor_wait(proactor);
@@ -121,49 +126,40 @@ int proactor_test_run(proactor_test_t *pts, size_t n) {
 }
 
 
-/* Simple test of client connect to a listening server */
-handler_state_t listen_connect_server(test_t *t, pn_event_t *e) {
-  switch (pn_event_type(e)) {
-    /* Ignore these events */
-   case PN_LISTENER_OPEN:
-   case PN_CONNECTION_LOCAL_OPEN:
-   case PN_CONNECTION_REMOTE_OPEN:
-   case PN_CONNECTION_BOUND:
-    return H_CONTINUE;
-
-    /* Act on these events */
-   case PN_LISTENER_ACCEPT:
-     pn_listener_accept(pn_event_listener(e), pn_connection());
-     return H_CONTINUE;
-   case PN_CONNECTION_INIT:
-    pn_connection_open(pn_event_connection(e));
-    return H_CONTINUE;
-   case PN_CONNECTION_REMOTE_CLOSE:
-    return H_FINISHED;
+/* Handler for test_listen_connect, does both sides of the connection */
+handler_state_t listen_connect_handler(test_t *t, pn_event_t *e) {
+  pn_connection_t *c = pn_event_connection(e);
+  pn_listener_t *l = pn_event_listener(e);
 
-   default:
-    TEST_CHECK(t, false, "unexpected event %s", pn_event_type_name(pn_event_type(e)));
-    return H_FAILED;
-    break;
-  }
-}
-
-handler_state_t listen_connect_client(test_t *t, pn_event_t *e) {
   switch (pn_event_type(e)) {
     /* Ignore these events */
    case PN_CONNECTION_LOCAL_OPEN:
    case PN_CONNECTION_BOUND:
+   case PN_CONNECTION_INIT:
     return H_CONTINUE;
 
     /* Act on these events */
-   case PN_CONNECTION_INIT:
-    pn_connection_open(pn_event_connection(e));
+   case PN_LISTENER_ACCEPT: {
+    pn_connection_t *accepted = pn_connection();
+    pn_connection_open(accepted);
+    pn_listener_accept(l, accepted); /* Listener takes ownership of accepted */
     return H_CONTINUE;
+   }
+
    case PN_CONNECTION_REMOTE_OPEN:
-    pn_connection_close(pn_event_connection(e));
+    if (pn_connection_state(c) | PN_LOCAL_ACTIVE) { /* Client is fully open - the test is done */
+      pn_connection_close(c);
+      return H_FINISHED;
+    }  else {                   /* Server returns the open */
+      pn_connection_open(c);
+    }
+
+   case PN_CONNECTION_REMOTE_CLOSE:
+    if (pn_connection_state(c) | PN_LOCAL_ACTIVE) {
+      pn_connection_close(c);    /* Return the close */
+    }
     return H_FINISHED;
 
-    /* Unexpected events */
    default:
     TEST_CHECK(t, false, "unexpected event %s", pn_event_type_name(pn_event_type(e)));
     return H_FAILED;
@@ -171,38 +167,18 @@ handler_state_t listen_connect_client(test_t *t, pn_event_t *e) {
   }
 }
 
-/* Simplest client/server interaction */
-static void test_listen_connect(test_t *t) {
-  proactor_test_t pts[] =  { { t, listen_connect_client }, { t, listen_connect_server } };
-  proactor_test_t *client = &pts[0], *server = &pts[1];
-  proactor_test_init(pts, 2);
-
-  sock_t sock = sock_bind0();          /* Hold a port */
-  char port_str[16];
-  snprintf(port_str, sizeof(port_str), "%d", sock_port(sock));
-  pn_proactor_listen(server->proactor, pn_listener(), localhost, port_str, 4);
-  pn_event_type_t etype = wait_for(server->proactor, PN_LISTENER_OPEN);
-  if (TEST_CHECK(t, PN_LISTENER_OPEN == etype, pn_event_type_name(etype))) {
-    pn_proactor_connect(client->proactor, pn_connection(), localhost, port_str);
-    proactor_test_run(pts, 2);
-  }
-  sock_close(sock);
-  pn_proactor_free(client->proactor);
-  pn_proactor_free(server->proactor);
-}
-
-/* Test error handling */
-static void test_listen_connect_error(test_t *t) {
+/* Test bad-address error handling for listen and connect */
+static void test_early_error(test_t *t) {
   pn_proactor_t *p = pn_proactor();
   pn_proactor_set_timeout(p, timeout); /* In case of hang */
   pn_connection_t *c = pn_connection();
-  pn_proactor_connect(p, c, "nosuchost", "nosuchport");
+  pn_proactor_connect(p, c, "badhost", "amqp");
   pn_event_type_t etype = wait_for(p, PN_TRANSPORT_CLOSED);
   TEST_CHECK(t, PN_TRANSPORT_CLOSED == etype, pn_event_type_name(etype));
   TEST_CHECK(t, pn_condition_is_set(pn_transport_condition(pn_connection_transport(c))), "");
 
   pn_listener_t *l = pn_listener();
-  pn_proactor_listen(p, l, "nosuchost", "nosuchport", 1);
+  pn_proactor_listen(p, l, "badhost", "amqp", 1);
   etype = wait_for(p, PN_LISTENER_CLOSE);
   TEST_CHECK(t, PN_LISTENER_CLOSE == etype, pn_event_type_name(etype));
   TEST_CHECK(t, pn_condition_is_set(pn_listener_condition(l)), "");
@@ -210,12 +186,51 @@ static void test_listen_connect_error(test_t *t) {
   pn_proactor_free(p);
 }
 
+/* Simplest client/server interaction with 2 proactors */
+static void test_listen_connect(test_t *t) {
+  proactor_test_t pts[] =  { { t, listen_connect_handler }, { t, listen_connect_handler } };
+  proactor_test_init(pts, 2);
+  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
+  test_port_t port = test_port();          /* Hold a port */
+
+  pn_proactor_listen(server, pn_listener(), localhost, port.str, 4);
+  pn_event_type_t etype = wait_for(server, PN_LISTENER_OPEN);
+  if (TEST_CHECK(t, PN_LISTENER_OPEN == etype, pn_event_type_name(etype))) {
+    sock_close(port.sock);
+    pn_proactor_connect(client, pn_connection(), localhost, port.str);
+    proactor_test_run(pts, 2);
+  }
+  pn_proactor_free(client);
+  pn_proactor_free(server);
+}
+
+/* Test that INACTIVE event is generated when last connections/listeners closes. */
+static void test_inactive(test_t *t) {
+  proactor_test_t pts[] =  { { t, listen_connect_handler }, { t, listen_connect_handler }};
+  proactor_test_init(pts, 2);
+  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
+  test_port_t port = test_port();          /* Hold a port */
+
+  pn_listener_t *l = pn_listener();
+  pn_proactor_listen(server, l, localhost, port.str,  4);
+  pn_event_type_t etype = wait_for(server, PN_LISTENER_OPEN);
+  if (TEST_CHECK(t, PN_LISTENER_OPEN == etype, pn_event_type_name(etype))) {
+    sock_close(port.sock);
+    pn_proactor_connect(client, pn_connection(), localhost, port.str);
+    proactor_test_run(pts, 2);
+    etype = wait_for(client, PN_PROACTOR_INACTIVE);
+    pn_listener_close(l);
+    etype = wait_for(server, PN_PROACTOR_INACTIVE);
+  }
+  pn_proactor_free(client);
+  pn_proactor_free(server);
+}
+
 int main(int argv, char** argc) {
   int failed = 0;
-  if (0) {
-    RUN_TEST(failed, t, test_interrupt_timeout(&t));
-    RUN_TEST(failed, t, test_listen_connect_error(&t));
-  }
+  RUN_TEST(failed, t, test_inactive(&t));
+  RUN_TEST(failed, t, test_interrupt_timeout(&t));
+  RUN_TEST(failed, t, test_early_error(&t));
   RUN_TEST(failed, t, test_listen_connect(&t));
   return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/204c8474/proton-c/src/tests/test_tools.h
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/test_tools.h b/proton-c/src/tests/test_tools.h
index 2619337..2663dcf 100644
--- a/proton-c/src/tests/test_tools.h
+++ b/proton-c/src/tests/test_tools.h
@@ -153,4 +153,18 @@ static int sock_port(sock_t sock) {
   return ntohs(port);
 }
 
+typedef struct test_port_t {
+  sock_t sock;
+  int port;
+  char str[256];
+} test_port_t;
+
+static inline test_port_t test_port(void) {
+  test_port_t tp = {0};
+  tp.sock = sock_bind0();
+  tp.port = sock_port(tp.sock);
+  snprintf(tp.str, sizeof(tp.str), "%d", tp.port);
+  return tp;
+}
+
 #endif // TESTS_TEST_TOOLS_H


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[02/38] qpid-proton git commit: NO-JIRA: [C++ binding] Removed unnecessary include

Posted by ac...@apache.org.
NO-JIRA: [C++ binding] Removed unnecessary include


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/8cc266e2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/8cc266e2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/8cc266e2

Branch: refs/heads/go1
Commit: 8cc266e27f74f71ba0c1de67ee3a6475ae9a538d
Parents: 9de1cc1
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Feb 7 14:26:11 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed Feb 8 14:39:21 2017 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/src/connection.cpp | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8cc266e2/proton-c/bindings/cpp/src/connection.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection.cpp b/proton-c/bindings/cpp/src/connection.cpp
index 113932c..f706df4 100644
--- a/proton-c/bindings/cpp/src/connection.cpp
+++ b/proton-c/bindings/cpp/src/connection.cpp
@@ -31,7 +31,6 @@
 #include "proton/session_options.hpp"
 #include "proton/transport.hpp"
 
-#include "connector.hpp"
 #include "contexts.hpp"
 #include "msg.hpp"
 #include "proton_bits.hpp"


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[14/38] qpid-proton git commit: PROTON-1403: c proactor memory leaks

Posted by ac...@apache.org.
PROTON-1403: c proactor memory leaks


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/85687373
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/85687373
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/85687373

Branch: refs/heads/go1
Commit: 85687373d8d5ec84cc9ac81ba4af2e1a81d9e294
Parents: a21a03e
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Feb 14 12:06:26 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Feb 14 12:06:26 2017 -0500

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c | 85 +++++++++++++++++++++-----------------
 1 file changed, 47 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/85687373/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 29463d5..173f767 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -65,6 +65,12 @@
   - leader_* - called in leader thread (either leader_q processing or from an on_ function)
   - worker_* - called in worker thread
   - *_lh - called with the relevant lock held
+
+  LIFECYCLE: pconnection_t and pn_listener_t objects must not be deleted until all their
+  UV handles have received an on_close(). Freeing resources is always initiated by
+  uv_close() of the uv_tcp_t handle, and completed in on_close() handler functions when it
+  is safe. The only exception is when an error occurs that prevents a pn_connection_t or
+  pn_listener_t from being associated with a uv handle at all.
 */
 
 const char *COND_NAME = "proactor";
@@ -247,7 +253,7 @@ static inline pn_listener_t *as_listener(psocket_t* ps) {
   return ps->is_conn ? NULL: (pn_listener_t*)ps;
 }
 
-static pconnection_t *new_pconnection(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
+static pconnection_t *pconnection(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
   pconnection_t *pc = (pconnection_t*)calloc(1, sizeof(*pc));
   if (!pc || pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
     return NULL;
@@ -288,33 +294,31 @@ static void leader_count(pn_proactor_t *p, int change) {
   uv_mutex_unlock(&p->lock);
 }
 
-/* Final close event for a a pconnection_t */
-static void on_close_pconnection_final(uv_handle_t *h) {
-  pconnection_t *pc = (pconnection_t*)h->data;
+static void pconnection_free(pconnection_t *pc) {
+  pn_connection_driver_destroy(&pc->driver);
   free(pc);
 }
 
-/* Close event for uv_tcp_t of a pconnection_t */
-static void on_close_pconnection(uv_handle_t *h) {
-  pconnection_t *pc = (pconnection_t*)h->data;
-  assert(pc->psocket.state == ON_UV);
-  leader_count(pc->psocket.proactor, -1);
-  pn_connection_driver_destroy(&pc->driver);
-  uv_timer_stop(&pc->timer);
-  /* Close the timer with the final event to free the pconnection_t */
-  uv_close((uv_handle_t*)&pc->timer, on_close_pconnection_final);
-}
+static void pn_listener_free(pn_listener_t *l);
 
-/* Close event for uv_tcp_t of a pn_listener_t */
-static void on_close_listener(uv_handle_t *h) {
-  pn_listener_t *l = (pn_listener_t*)h->data;
-  pn_condition_free(l->condition);
-  free(l);
+/* Final close event for for a pconnection_t, closes the timer */
+static void on_close_pconnection_final(uv_handle_t *h) {
+  pconnection_free((pconnection_t*)h->data);
 }
 
-static inline void leader_finished(psocket_t *ps) {
-  set_state(ps, ON_UV, NULL);
-  uv_close((uv_handle_t*)&ps->tcp, ps->is_conn ? on_close_pconnection : on_close_listener);
+/* Close event for uv_tcp_t of a psocket_t */
+static void on_close_psocket(uv_handle_t *h) {
+  /* No assert(ps->state == ON_UV); may be called in other states during shutdown. */
+  psocket_t *ps = (psocket_t*)h->data;
+  if (ps->is_conn) {
+    leader_count(ps->proactor, -1);
+    pconnection_t *pc = as_pconnection(ps);
+    uv_timer_stop(&pc->timer);
+    /* Delay the free till the timer handle is also closed */
+    uv_close((uv_handle_t*)&pc->timer, on_close_pconnection_final);
+  } else {
+    pn_listener_free(as_listener(ps));
+  }
 }
 
 static pconnection_t *get_pconnection(pn_connection_t* c) {
@@ -358,7 +362,7 @@ static int leader_init(psocket_t *ps) {
       pc->connect.data = ps;
       int err = uv_timer_init(&ps->proactor->loop, &pc->timer);
       if (!err) {
-        pc->timer.data = pc;
+        pc->timer.data = ps;
       }
     }
   }
@@ -392,7 +396,7 @@ static void on_connection(uv_stream_t* server, int err) {
     ++l->connections;
     leader_unwatch(&l->psocket);
   } else {
-    leader_error(&l->psocket, err, "on incoming connection from");
+    leader_error(&l->psocket, err, "on connection from");
   }
 }
 
@@ -538,7 +542,7 @@ static void leader_watch(psocket_t *ps) {
   if (ps->is_conn) {
     pconnection_t *pc = as_pconnection(ps);
     if (pn_connection_driver_finished(&pc->driver)) {
-      leader_finished(ps);
+      uv_close((uv_handle_t*)&ps->tcp, on_close_psocket);
       return;
     }
     pn_millis_t next_tick = leader_tick(pc);
@@ -567,7 +571,8 @@ static void leader_watch(psocket_t *ps) {
   } else {
     pn_listener_t *l = as_listener(ps);
     if (l->closing && pn_collector_peek(l->collector)) {
-        leader_finished(&l->psocket);
+      uv_close((uv_handle_t*)&ps->tcp, on_close_psocket);
+      return;
     } else {
       if (l->accepting) {
         leader_accept(l);
@@ -777,7 +782,7 @@ void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
 }
 
 int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {
-  pconnection_t *pc = new_pconnection(p, c, false, host, port);
+  pconnection_t *pc = pconnection(p, c, false, host, port);
   if (!pc) {
     return PN_OUT_OF_MEMORY;
   }
@@ -826,16 +831,20 @@ pn_proactor_t *pn_proactor() {
 }
 
 static void on_stopping(uv_handle_t* h, void* v) {
-  if (!uv_is_closing(h)) {
-    uv_close(h, NULL);           /* Close this handle */
+  /* Close all the TCP handles. on_close_psocket will close any other handles if needed */
+  if (h->type == UV_TCP && !uv_is_closing(h)) {
+    uv_close(h, on_close_psocket);
   }
-  if (!uv_loop_alive(h->loop)) /* Everything closed */
-    uv_stop(h->loop);          /* Stop the loop, pn_proactor_destroy() can return */
 }
 
 void pn_proactor_free(pn_proactor_t *p) {
-  uv_walk(&p->loop, on_stopping, NULL); /* Close all handles */
-  uv_run(&p->loop, UV_RUN_DEFAULT);     /* Run till stop, all handles closed */
+  uv_timer_stop(&p->timer);
+  uv_close((uv_handle_t*)&p->timer, NULL);
+  uv_close((uv_handle_t*)&p->async, NULL);
+  uv_walk(&p->loop, on_stopping, NULL); /* Close all TCP handles */
+  while (uv_loop_alive(&p->loop)) {
+    uv_run(&p->loop, UV_RUN_ONCE);       /* Run till all handles closed */
+  }
   uv_loop_close(&p->loop);
   uv_mutex_destroy(&p->lock);
   uv_cond_destroy(&p->cond);
@@ -854,11 +863,11 @@ static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
 }
 
 static void pn_listener_free(pn_listener_t *l) {
-  assert(l->psocket.state == ON_WORKER);
+  /* No  assert(l->psocket.state == ON_WORKER);  can be called during shutdown */
   if (l) {
-    if (!l->collector) pn_collector_free(l->collector);
-    if (!l->condition) pn_condition_free(l->condition);
-    if (!l->attachments) pn_free(l->attachments);
+    if (l->collector) pn_collector_free(l->collector);
+    if (l->condition) pn_condition_free(l->condition);
+    if (l->attachments) pn_free(l->attachments);
     free(l);
   }
 }
@@ -917,7 +926,7 @@ int pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
   if (l->accepting) {
     return PN_STATE_ERR;        /* Only one at a time */
   }
-  l->accepting = new_pconnection(l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
+  l->accepting = pconnection(l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
   if (!l->accepting) {
     return UV_ENOMEM;
   }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[22/38] qpid-proton git commit: PROTON-1403: C proactor tests, fixes & additions

Posted by ac...@apache.org.
PROTON-1403: C proactor tests, fixes & additions

proactor API additions:
- PN_LISTENER_OPEN: event when listener is listening and connects will succeed.
- pn_proactor_grab(): non-blocking version of pn_proactor_wait(), used in tests

src/tests/test_tools.h - simple C test framework
src/tests/proactor.c - initial tests for basic proactor functionality
src/proactor/libuv.c
 - fixed some assertion bugs and memory leaks
 - renaming and simplifying the code
examples/broker.c: exit with non-0 if broker stops because of an error


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b987a6a7
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b987a6a7
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b987a6a7

Branch: refs/heads/go1
Commit: b987a6a70f30dc593bbea6c98ebae36ec77e4b7d
Parents: 9bd99eb
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jan 13 16:41:43 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 16 17:58:20 2017 -0500

----------------------------------------------------------------------
 CMakeLists.txt                                  |   2 +-
 examples/c/proactor/CMakeLists.txt              |   6 +-
 examples/c/proactor/broker.c                    |   6 +-
 examples/c/proactor/direct.c                    |   5 +-
 examples/c/proactor/send.c                      |   2 +-
 proton-c/CMakeLists.txt                         |   6 -
 .../cpp/include/proton/io/connection_driver.hpp |   1 +
 proton-c/include/proton/event.h                 |  17 +-
 proton-c/include/proton/listener.h              |   2 +-
 proton-c/include/proton/proactor.h              |  34 +-
 proton-c/src/core/connection_driver.c           |   4 +-
 proton-c/src/core/event.c                       |   2 +
 proton-c/src/proactor/libuv.c                   | 518 ++++++++++---------
 proton-c/src/tests/CMakeLists.txt               |   9 +-
 proton-c/src/tests/proactor.c                   | 217 ++++++++
 proton-c/src/tests/test_tools.h                 | 140 +++++
 16 files changed, 698 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b538ffd..294fd03 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,7 +71,7 @@ if (CMAKE_BUILD_TYPE MATCHES "Coverage")
   make_directory(coverage_results)
   add_custom_target(coverage
     WORKING_DIRECTORY ./coverage_results
-    COMMAND ${CMAKE_SOURCE_DIR}/bin/record-coverage.sh ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
+    CgOMMAND ${CMAKE_SOURCE_DIR}/bin/record-coverage.sh ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
 endif()
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index 4189cf5..153f35f 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -29,7 +29,7 @@ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${Proton_LIBRARIES})
 check_function_exists(pn_proactor HAS_PROACTOR)
 cmake_pop_check_state()
 
-if (HAS_PROACTOR)
+if(HAS_PROACTOR)
 
 add_definitions(${COMPILE_WARNING_FLAGS} ${WERROR} ${COMPILE_PLATFORM_FLAGS} ${LINK_TIME_OPTIMIZATION})
 
@@ -48,6 +48,6 @@ foreach(name broker send receive direct)
 endforeach()
 
 set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV})
-add_test(c-proactor ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py -v)
+add_test(c-example-proactor ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py -v)
 
-endif()
+endif(HAS_PROACTOR)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index ebf4068..2a338e1 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -22,6 +22,7 @@
 #include <proton/connection_driver.h>
 #include <proton/proactor.h>
 #include <proton/engine.h>
+#include <proton/listener.h>
 #include <proton/sasl.h>
 #include <proton/transport.h>
 #include <proton/url.h>
@@ -288,8 +289,11 @@ static void session_unsub(broker_t *b, pn_session_t *ssn) {
   }
 }
 
+static int exit_code = 0;
+
 static void check_condition(pn_event_t *e, pn_condition_t *cond) {
   if (pn_condition_is_set(cond)) {
+    exit_code = 1;
     const char *ename = e ? pn_event_type_name(pn_event_type(e)) : "UNKNOWN";
     fprintf(stderr, "%s: %s: %s\n", ename,
             pn_condition_get_name(cond), pn_condition_get_description(cond));
@@ -483,5 +487,5 @@ int main(int argc, char **argv) {
   }
   pn_proactor_free(b.proactor);
   free(threads);
-  return 0;
+  return exit_code;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/examples/c/proactor/direct.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/direct.c b/examples/c/proactor/direct.c
index 26f1b33..3d0a7d1 100644
--- a/examples/c/proactor/direct.c
+++ b/examples/c/proactor/direct.c
@@ -22,9 +22,10 @@
 #include <proton/connection.h>
 #include <proton/connection_driver.h>
 #include <proton/delivery.h>
-#include <proton/proactor.h>
 #include <proton/link.h>
+#include <proton/listener.h>
 #include <proton/message.h>
+#include <proton/proactor.h>
 #include <proton/sasl.h>
 #include <proton/session.h>
 #include <proton/transport.h>
@@ -59,7 +60,7 @@ typedef struct app_data_t {
 
 static const int BATCH = 1000; /* Batch size for unlimited receive */
 
-int exit_code = 0;
+static int exit_code = 0;
 
 static void check_condition(pn_event_t *e, pn_condition_t *cond) {
   if (pn_condition_is_set(cond)) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index 48fcecd..bba5d3e 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -50,7 +50,7 @@ typedef struct app_data_t {
   bool finished;
 } app_data_t;
 
-int exit_code = 0;
+static int exit_code = 0;
 
 static void check_condition(pn_event_t *e, pn_condition_t *cond) {
   if (pn_condition_is_set(cond)) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 30a77e2..0731b67 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -278,12 +278,6 @@ if (CMAKE_C_COMPILER_ID MATCHES "Clang")
   if (ENABLE_WARNING_ERROR)
     set (COMPILE_WARNING_FLAGS "-Werror ${COMPILE_WARNING_FLAGS}")
   endif (ENABLE_WARNING_ERROR)
-endif()
-
-if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-  if (ENABLE_WARNING_ERROR)
-    set (WERROR "-Werror")
-  endif (ENABLE_WARNING_ERROR)
   # TODO aconway 2016-01-06: we should be able to clean up the code and turn on
   # some of these warnings.
   set (CXX_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32 -Wno-documentation -Wno-documentation-unknown-command -Wno-old-style-cast -Wno-missing-noreturn")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
index 4a0efe9..759b1fc 100644
--- a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
+++ b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
@@ -113,6 +113,7 @@ PN_CPP_CLASS_EXTERN connection_driver {
     ///
     PN_CPP_EXTERN connection_driver(proton::container&);
 #if PN_CPP_HAS_RVALUE_REFERENCES
+    /// @copydoc connection_driver()
     PN_CPP_EXTERN connection_driver(proton::container&, event_loop&& loop);
 #endif
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 4a88368..3cfcc82 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -321,7 +321,8 @@ typedef enum {
   PN_CONNECTION_WAKE,
 
   /**
-   * Indicates the listener is ready to call pn_listener_accept() 
+   * Indicates the listener has an incoming connection, call pn_listener_accept()
+   * to accept it.
    * Events of this type point to the @ref pn_listener_t.
    */
   PN_LISTENER_ACCEPT,
@@ -350,7 +351,13 @@ typedef enum {
    *
    * Events of this type point to the @ref pn_proactor_t.
    */
-  PN_PROACTOR_INACTIVE
+  PN_PROACTOR_INACTIVE,
+
+  /**
+   * Indicates the listener is listeneing.
+   * Events of this type point to the @ref pn_listener_t.
+   */
+  PN_LISTENER_OPEN
 
 } pn_event_type_t;
 
@@ -537,9 +544,9 @@ PN_EXTERN pn_transport_t *pn_event_transport(pn_event_t *event);
 PN_EXTERN pn_record_t *pn_event_attachments(pn_event_t *event);
 
 /**
- * **Experimental** - A batch of events to handle. Call
- * pn_event_batch_next() in a loop until it returns NULL to handle
- * them.
+ * **Experimental** - A batch of events that must be handled in sequence.
+ * Call pn_event_batch_next() in a loop until it returns NULL to extract
+ * the events.
  */
 typedef struct pn_event_batch_t pn_event_batch_t;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index 18feca7..2038c06 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -20,7 +20,7 @@
  * under the License.
  */
 
-#include <proton/condition.h>
+#include <proton/import_export.h>
 #include <proton/types.h>
 
 #ifdef __cplusplus

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index 71a7dda..af3acbc 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -20,10 +20,9 @@
  * under the License.
  */
 
-#include <proton/types.h>
-#include <proton/import_export.h>
-#include <proton/listener.h>
 #include <proton/event.h>
+#include <proton/import_export.h>
+#include <proton/types.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -95,25 +94,34 @@ PNP_EXTERN int pn_proactor_listen(pn_proactor_t *proactor, pn_listener_t *listen
                        const char *host, const char *port, int backlog);
 
 /**
- * Wait for events to handle.
+ * Wait until there is at least one event to handle.
+ * Always returns a non-empty batch of events.
  *
- * Handle events in the returned batch by calling
- * pn_event_batch_next() until it returns NULL. You must call
- * pn_proactor_done() when you are finished with the batch.
+ * You must call pn_proactor_done() when you are finished with the batch, you
+ * must not use the batch pointer after calling pn_proactor_done().
  *
- * If you call pn_proactor_done() before finishing the batch, the
- * remaining events will be returned again by another call
- * pn_proactor_wait().  This is less efficient, but allows you to
- * handle part of a batch and then hand off the rest to another
- * thread.
+ * Normally it is most efficient to handle the entire batch in one thread, but
+ * you can call pn_proactor_done() on an unfinished the batch. The remaining
+ * events will be returned by another call to pn_proactor_done(), possibly in a
+ * different thread.
+ *
+ * @note You can generate events to force threads to wake up from
+ * pn_proactor_wait() using pn_proactor_interrupt(), pn_proactor_set_timeout()
+ * and pn_connection_wake()
  *
  * @note Thread-safe: can be called concurrently. Events in a single
  * batch must be handled in sequence, but batches returned by separate
- * calls to pn_proactor_wait() can be handled concurrently.
+ * calls can be handled concurrently.
  */
 PNP_EXTERN pn_event_batch_t *pn_proactor_wait(pn_proactor_t *proactor);
 
 /**
+ * Return a batch of events if one is available immediately, otherwise return NULL.  If it
+ * does return an event batch, the rules are the same as for pn_proactor_wait()
+ */
+PNP_EXTERN pn_event_batch_t *pn_proactor_grab(pn_proactor_t *proactor);
+
+/**
  * Call when done handling a batch of events.
  *
  * Must be called exactly once to match each call to

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/src/core/connection_driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_driver.c b/proton-c/src/core/connection_driver.c
index 3393e64..0d1db21 100644
--- a/proton-c/src/core/connection_driver.c
+++ b/proton-c/src/core/connection_driver.c
@@ -127,7 +127,9 @@ pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *d) {
 }
 
 bool pn_connection_driver_has_event(pn_connection_driver_t *d) {
-  return pn_collector_peek(pn_connection_collector(d->connection));
+  /* FIXME aconway 2017-02-15: this is ugly */
+  pn_collector_t *c = pn_connection_collector(d->connection);
+  return pn_collector_more(c) || (pn_collector_peek(c) && pn_collector_peek(c) != pn_collector_prev(c));
 }
 
 bool pn_connection_driver_finished(pn_connection_driver_t *d) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/src/core/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/event.c b/proton-c/src/core/event.c
index 41ff6d1..e213c8f 100644
--- a/proton-c/src/core/event.c
+++ b/proton-c/src/core/event.c
@@ -395,6 +395,8 @@ const char *pn_event_type_name(pn_event_type_t type)
     return "PN_PROACTOR_TIMEOUT";
    case PN_PROACTOR_INACTIVE:
     return "PN_PROACTOR_INACTIVE";
+   case PN_LISTENER_OPEN:
+    return "PN_LISTENER_OPEN";
    default:
     return "PN_UNKNOWN";
   }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index d17136a..0ccfcda 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -24,6 +24,7 @@
 #include <proton/condition.h>
 #include <proton/connection_driver.h>
 #include <proton/engine.h>
+#include <proton/listener.h>
 #include <proton/message.h>
 #include <proton/object.h>
 #include <proton/proactor.h>
@@ -40,37 +41,34 @@
 #include <string.h>
 
 /*
-  libuv loop functions are thread unsafe. The only exception is uv_async_send()
-  which is a thread safe "wakeup" that can wake the uv_loop from another thread.
+  libuv functions are thread unsafe. The exception is uv_async_send(), a thread safe
+  "wakeup" that can wake the uv_loop from another thread.
 
-  To provide concurrency the proactor uses a "leader-worker-follower" model,
-  threads take turns at the roles:
+  To provide concurrency proactor uses a "leader-worker-follower" model, threads take
+  turns at the roles:
 
-  - a single "leader" calls libuv functions and runs the uv_loop in short bursts
-    to generate work. When there is work available it gives up leadership and
-    becomes a "worker"
+  - a single "leader" thread uses libuv, it runs the uv_loop the in short bursts to
+  generate work. Once there is work it becomes becomes a "worker" thread, another thread
+  takes over as leader.
 
-  - "workers" handle events concurrently for distinct connections/listeners
-    They do as much work as they can get, when none is left they become "followers"
+  - "workers" handle events for separate connections or listeners concurrently. They do as
+  much work as they can, when none is left they become "followers"
 
-  - "followers" wait for the leader to generate work and become workers.
-    When the leader itself becomes a worker, one of the followers takes over.
+  - "followers" wait for the leader to generate work. One follower becomes the new leader,
+  the others become workers or continue to follow till they can get work.
 
-  This model is symmetric: any thread can take on any role based on run-time
-  requirements. It also allows the IO and non-IO work associated with an IO
-  wake-up to be processed in a single thread with no context switches.
+  Any thread in a pool can take on any role necessary at run-time. All the work generated
+  by an IO wake-up for a single connection can be processed in a single single worker
+  thread to minimize context switching.
 
   Function naming:
-  - on_* - called in leader thread by uv_run().
+  - on_* - called in leader thread via  uv_run().
   - leader_* - called in leader thread (either leader_q processing or from an on_ function)
-  - worker_* - called in worker thread
   - *_lh - called with the relevant lock held
 
   LIFECYCLE: pconnection_t and pn_listener_t objects must not be deleted until all their
-  UV handles have received an on_close(). Freeing resources is always initiated by
-  uv_close() of the uv_tcp_t handle, and completed in on_close() handler functions when it
-  is safe. The only exception is when an error occurs that prevents a pn_connection_t or
-  pn_listener_t from being associated with a uv handle at all.
+  UV handles have received a close callback. Freeing resources is initiated by uv_close()
+  of the uv_tcp_t handle, and executed in an on_close() handler when it is safe.
 */
 
 const char *COND_NAME = "proactor";
@@ -82,12 +80,12 @@ const char *AMQPS_PORT_NAME = "amqps";
 PN_HANDLE(PN_PROACTOR)
 
 /* pn_proactor_t and pn_listener_t are plain C structs with normal memory management.
-   Class definitions are for identification as pn_event_t context only.
+   CLASSDEF is for identification when used as a pn_event_t context.
 */
 PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
 PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
 
-/* A psocket (connection or listener) has the following *mutually exclusive* states. */
+/* A psocket (connection or listener) has the following mutually exclusive states. */
 typedef enum {
   ON_WORKER,               /* On worker_q or in use by user code in worker thread  */
   ON_LEADER,               /* On leader_q or in use the leader loop  */
@@ -105,12 +103,11 @@ typedef struct psocket_t {
   void (*action)(struct psocket_t*); /* deferred action for leader */
   void (*wakeup)(struct psocket_t*); /* wakeup action for leader */
 
-  /* Only used by leader when it owns the psocket */
+  /* Only used by leader thread when it owns the psocket */
   uv_tcp_t tcp;
   char host[NI_MAXHOST];
   char port[NI_MAXSERV];
   bool is_conn;
-
 } psocket_t;
 
 /* Special value for psocket.next pointer when socket is not on any any list. */
@@ -138,6 +135,7 @@ static inline const char* fixstr(const char* str) {
   return str[0] == '\001' ? NULL : str;
 }
 
+/* Holds a psocket and a pn_connection_driver  */
 typedef struct pconnection_t {
   psocket_t psocket;
 
@@ -150,10 +148,11 @@ typedef struct pconnection_t {
   uv_write_t write;
   uv_shutdown_t shutdown;
   size_t writing;               /* size of pending write request, 0 if none pending */
-  bool reading;                 /* true if a read request is pending */
-  bool server;                  /* accept, not connect */
+  bool server;                  /* accepting not connecting */
 } pconnection_t;
 
+
+/* pn_listener_t with a psocket_t  */
 struct pn_listener_t {
   psocket_t psocket;
 
@@ -169,6 +168,8 @@ struct pn_listener_t {
 
   /* Only used in leader thread */
   size_t connections;           /* number of connections waiting to be accepted  */
+  int err;                      /* uv error code, 0 = OK, UV_EOF = closed */
+  const char *what;             /* static description string */
 };
 
 typedef struct queue { psocket_t *front, *back; } queue;
@@ -198,9 +199,9 @@ struct pn_proactor_t {
   bool batch_working;          /* batch is being processed in a worker thread */
 };
 
-static bool push_lh(queue *q, psocket_t *ps) {
-  if (ps->next != &UNLISTED)  /* Don't move if already listed. */
-    return false;
+/* Push ps to back of q. Must not be on a different queue */
+static void push_lh(queue *q, psocket_t *ps) {
+  assert(ps->next == &UNLISTED);
   ps->next = NULL;
   if (!q->front) {
     q->front = q->back = ps;
@@ -208,9 +209,9 @@ static bool push_lh(queue *q, psocket_t *ps) {
     q->back->next = ps;
     q->back =  ps;
   }
-  return true;
 }
 
+/* Pop returns front of q or NULL if empty */
 static psocket_t* pop_lh(queue *q) {
   psocket_t *ps = q->front;
   if (ps) {
@@ -220,29 +221,49 @@ static psocket_t* pop_lh(queue *q) {
   return ps;
 }
 
-/* Set state and action and push to relevant queue */
-static inline void set_state_lh(psocket_t *ps, psocket_state_t state, void (*action)(psocket_t*)) {
-  /* Illegal if ps is already listed under a different state */
-  assert(ps->next == &UNLISTED || ps->state == state);
-  ps->state = state;
-  if (action && !ps->action) {
-    ps->action = action;
+/* Queue an action for the leader thread */
+static void to_leader(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  ps->action = action;
+  if (ps->next == &UNLISTED) {
+    ps->state = ON_LEADER;
+    push_lh(&ps->proactor->leader_q, ps);
+  }
+  uv_mutex_unlock(&ps->proactor->lock);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+}
+
+/* Push to the worker thread */
+static void to_worker(psocket_t *ps) {
+  uv_mutex_lock(&ps->proactor->lock);
+  /* If already ON_WORKER do nothing */
+  if (ps->next == &UNLISTED && ps->state != ON_WORKER) {
+    ps->state = ON_WORKER;
+    push_lh(&ps->proactor->worker_q, ps);
   }
-  switch(state) {
-   case ON_LEADER: push_lh(&ps->proactor->leader_q, ps); break;
-   case ON_WORKER: push_lh(&ps->proactor->worker_q, ps); break;
-   case ON_UV:
-    assert(ps->next == &UNLISTED);
-    break;           /* No queue for UV loop */
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Set state to ON_UV */
+static void to_uv(psocket_t *ps) {
+  uv_mutex_lock(&ps->proactor->lock);
+  if (ps->next == &UNLISTED) {
+    ps->state = ON_UV;
   }
+  uv_mutex_unlock(&ps->proactor->lock);
 }
 
-/* Set state and action, push to queue and notify leader. Thread safe. */
-static void set_state(psocket_t *ps, psocket_state_t state, void (*action)(psocket_t*)) {
+/* Called in any thread to set a wakeup action */
+static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
   uv_mutex_lock(&ps->proactor->lock);
-  set_state_lh(ps, state, action);
-  uv_async_send(&ps->proactor->async);
+  ps->wakeup = action;
+  /* If ON_WORKER we'll do the wakeup in pn_proactor_done() */
+  if (ps->next == &UNLISTED && ps->state != ON_WORKER) {
+    push_lh(&ps->proactor->leader_q, ps);
+    ps->state = ON_LEADER;      /* Otherwise notify the leader */
+  }
   uv_mutex_unlock(&ps->proactor->lock);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
 }
 
 static inline pconnection_t *as_pconnection(psocket_t* ps) {
@@ -308,7 +329,6 @@ static void on_close_pconnection_final(uv_handle_t *h) {
 
 /* Close event for uv_tcp_t of a psocket_t */
 static void on_close_psocket(uv_handle_t *h) {
-  /* No assert(ps->state == ON_UV); may be called in other states during shutdown. */
   psocket_t *ps = (psocket_t*)h->data;
   if (ps->is_conn) {
     leader_count(ps->proactor, -1);
@@ -329,29 +349,43 @@ static pconnection_t *get_pconnection(pn_connection_t* c) {
   return (pconnection_t*) pn_record_get(r, PN_PROACTOR);
 }
 
-static void leader_unwatch(psocket_t *ps);
+static void pconnection_to_worker(pconnection_t *pc);
+static void listener_to_worker(pn_listener_t *l);
 
-static void leader_error(psocket_t *ps, int err, const char* what) {
-  assert(ps->state != ON_WORKER);
-  if (ps->is_conn) {
-    pn_connection_driver_t *driver = &as_pconnection(ps)->driver;
+int pconnection_error(pconnection_t *pc, int err, const char* what) {
+  if (err) {
+    pn_connection_driver_t *driver = &pc->driver;
     pn_connection_driver_bind(driver); /* Bind so errors will be reported */
     pn_connection_driver_errorf(driver, COND_NAME, "%s %s:%s: %s",
-                                what, fixstr(ps->host), fixstr(ps->port),
+                                what, fixstr(pc->psocket.host), fixstr(pc->psocket.port),
                                 uv_strerror(err));
     pn_connection_driver_close(driver);
-  } else {
-    pn_listener_t *l = as_listener(ps);
-    pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
-                        what, fixstr(ps->host), fixstr(ps->port),
-                        uv_strerror(err));
-    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
-    l->closing = true;
+    pconnection_to_worker(pc);
+  }
+  return err;
+}
+
+static int listener_error(pn_listener_t *l, int err, const char* what) {
+  if (err) {
+    l->err = err;
+    l->what = what;
+    listener_to_worker(l);
   }
-  leader_unwatch(ps);               /* Worker to handle the error */
+  return err;
 }
 
-/* uv-initialization */
+static int psocket_error(psocket_t *ps, int err, const char* what) {
+  if (err) {
+    if (ps->is_conn) {
+      pconnection_error(as_pconnection(ps), err, "initialization");
+    } else {
+      listener_error(as_listener(ps), err, "initialization");
+    }
+  }
+  return err;
+}
+
+/* psocket uv-initialization */
 static int leader_init(psocket_t *ps) {
   ps->state = ON_LEADER;
   leader_count(ps->proactor, +1);
@@ -365,9 +399,8 @@ static int leader_init(psocket_t *ps) {
         pc->timer.data = ps;
       }
     }
-  }
-  if (err) {
-    leader_error(ps, err, "initialization");
+  } else {
+    psocket_error(ps, err, "initialization");
   }
   return err;
 }
@@ -375,33 +408,27 @@ static int leader_init(psocket_t *ps) {
 /* Outgoing connection */
 static void on_connect(uv_connect_t *connect, int err) {
   pconnection_t *pc = (pconnection_t*)connect->data;
-  assert(pc->psocket.state == ON_UV);
   if (!err) {
-    leader_unwatch(&pc->psocket);
+    pconnection_to_worker(pc);
   } else {
-    leader_error(&pc->psocket, err, "on connect to");
+    pconnection_error(pc, err, "on connect to");
   }
 }
 
 /* Incoming connection ready to be accepted */
 static void on_connection(uv_stream_t* server, int err) {
-  /* Unlike most on_* functions, this one can be called by the leader thrad when the
+  /* Unlike most on_* functions, this one can be called by the leader thread when the
    * listener is ON_WORKER, because there's no way to stop libuv from calling
-   * on_connection() in leader_unwatch().  Just increase a counter and deal with it in the
-   * worker thread.
+   * on_connection().  Just increase a counter and generate events in to_worker.
    */
   pn_listener_t *l = (pn_listener_t*) server->data;
-  assert(l->psocket.state == ON_UV);
-  if (!err) {
-    ++l->connections;
-    leader_unwatch(&l->psocket);
-  } else {
-    leader_error(&l->psocket, err, "on connection from");
-  }
+  l->err = err;
+  if (!err) ++l->connections;
+  listener_to_worker(l);        /* If already ON_WORKER it will stay there */
 }
 
+/* FIXME aconway 2017-02-16:  listener events in unwatch*/
 static void leader_accept(pn_listener_t * l) {
-  assert(l->psocket.state == ON_UV);
   assert(l->accepting);
   pconnection_t *pc = l->accepting;
   l->accepting = NULL;
@@ -410,10 +437,10 @@ static void leader_accept(pn_listener_t * l) {
     err = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
   }
   if (!err) {
-    leader_unwatch(&pc->psocket);
+    pconnection_to_worker(pc);
   } else {
-    leader_error(&pc->psocket, err, "accepting from");
-    leader_error(&l->psocket, err, "accepting from");
+    pconnection_error(pc, err, "accepting from");
+    listener_error(l, err, "accepting from");
   }
 }
 
@@ -440,7 +467,7 @@ static void leader_connect(psocket_t *ps) {
   if (!err) {
     ps->state = ON_UV;
   } else {
-    leader_error(ps, err, "connecting to");
+    psocket_error(ps, err, "connecting to");
   }
 }
 
@@ -457,32 +484,26 @@ static void leader_listen(psocket_t *ps) {
     err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_connection);
   }
   if (!err) {
-    set_state(ps, ON_UV, NULL);
+    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_OPEN);
+    listener_to_worker(l);      /* Let worker see the OPEN event */
   } else {
-    leader_error(ps, err, "listening on");
+    listener_error(l, err, "listening on");
   }
 }
 
 /* Generate tick events and return millis till next tick or 0 if no tick is required */
 static pn_millis_t leader_tick(pconnection_t *pc) {
   assert(pc->psocket.state != ON_WORKER);
-  pn_transport_t *t = pc->driver.transport;
-  if (pn_transport_get_idle_timeout(t) || pn_transport_get_remote_idle_timeout(t)) {
-    uint64_t now = uv_now(pc->timer.loop);
-    uint64_t next = pn_transport_tick(t, now);
-    return next ? next - now : 0;
-  }
-  return 0;
+  uint64_t now = uv_now(pc->timer.loop);
+  uint64_t next = pn_transport_tick(pc->driver.transport, now);
+  return next ? next - now : 0;
 }
 
 static void on_tick(uv_timer_t *timer) {
-  if (!timer->data) return;     /* timer closed */
   pconnection_t *pc = (pconnection_t*)timer->data;
-  assert(pc->psocket.state == ON_UV);
-  uv_timer_stop(&pc->timer);
-  pn_millis_t next = leader_tick(pc);
+  pn_millis_t next = leader_tick(pc); /* May generate events */
   if (pn_connection_driver_has_event(&pc->driver)) {
-    leader_unwatch(&pc->psocket);
+    pconnection_to_worker(pc);
   } else if (next) {
     uv_timer_start(&pc->timer, on_tick, next, 0);
   }
@@ -490,31 +511,28 @@ static void on_tick(uv_timer_t *timer) {
 
 static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
   pconnection_t *pc = (pconnection_t*)stream->data;
-  assert(pc->psocket.state == ON_UV);
   if (nread >= 0) {
     pn_connection_driver_read_done(&pc->driver, nread);
-    leader_unwatch(&pc->psocket); /* Handle events */
+    pconnection_to_worker(pc);
   } else if (nread == UV_EOF) { /* hangup */
     pn_connection_driver_read_close(&pc->driver);
-    leader_unwatch(&pc->psocket);
+    pconnection_to_worker(pc);
   } else {
-    leader_error(&pc->psocket, nread, "on read from");
+    pconnection_error(pc, nread, "on read from");
   }
 }
 
 static void on_write(uv_write_t* write, int err) {
   pconnection_t *pc = (pconnection_t*)write->data;
-  assert(pc->psocket.state == ON_UV);
-  size_t writing = pc->writing;
-  pc->writing = 0;              /* This write is done regardless of outcome */
   if (err == 0) {
-    pn_connection_driver_write_done(&pc->driver, writing);
-    leader_unwatch(&pc->psocket);
+    pn_connection_driver_write_done(&pc->driver, pc->writing);
+    pconnection_to_worker(pc);
   } else if (err == UV_ECANCELED) {
-    leader_unwatch(&pc->psocket);    /* cancelled by leader_unwatch, complete the job */
+    pconnection_to_worker(pc);
   } else {
-    leader_error(&pc->psocket, err, "on write to");
+    pconnection_error(pc, err, "on write to");
   }
+  pc->writing = 0;
 }
 
 static void on_timeout(uv_timer_t *timer) {
@@ -527,88 +545,111 @@ static void on_timeout(uv_timer_t *timer) {
 // Read buffer allocation function for uv, just returns the transports read buffer.
 static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
   pconnection_t *pc = (pconnection_t*)stream->data;
-  assert(pc->psocket.state == ON_UV);
   pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
   *buf = uv_buf_init(rbuf.start, rbuf.size);
 }
 
-/* Monitor a socket in the UV loop */
-static void leader_watch(psocket_t *ps) {
-  assert(ps->state != ON_WORKER);
-  int err = 0;
-  set_state(ps, ON_UV, NULL); /* Assume we are going to UV loop unless sent to worker or leader. */
-
-  if (ps->is_conn) {
-    pconnection_t *pc = as_pconnection(ps);
-    if (pn_connection_driver_finished(&pc->driver)) {
-      uv_close((uv_handle_t*)&ps->tcp, on_close_psocket);
-      return;
+static void pconnection_to_uv(pconnection_t *pc) {
+  to_uv(&pc->psocket);          /* Assume we're going to UV unless sent elsewhere */
+  if (pn_connection_driver_finished(&pc->driver)) {
+    if (!uv_is_closing((uv_handle_t*)&pc->psocket)) {
+      uv_close((uv_handle_t*)&pc->psocket.tcp, on_close_psocket);
     }
-    pn_millis_t next_tick = leader_tick(pc);
-    pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
-    pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
-    if (pn_connection_driver_has_event(&pc->driver)) {
-      /* Ticks and checking buffers have generated events, send back to worker to process */
-      set_state(ps, ON_WORKER, NULL);
+    return;
+  }
+  pn_millis_t next_tick = leader_tick(pc);
+  pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
+  pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
+  if (pn_connection_driver_has_event(&pc->driver)) {
+    to_worker(&pc->psocket);  /* Ticks/buffer checks generated events */
+    return;
+  }
+  if (next_tick &&
+      pconnection_error(pc, uv_timer_start(&pc->timer, on_tick, next_tick, 0), "timer start")) {
+    return;
+  }
+  if (wbuf.size > 0) {
+    uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
+    if (pconnection_error(
+          pc, uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write), "write"))
       return;
+    pc->writing = wbuf.size;
+  } else if (pn_connection_driver_write_closed(&pc->driver)) {
+    pc->shutdown.data = &pc->psocket;
+    if (pconnection_error(
+          pc, uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, NULL), "shutdown write"))
+      return;
+  }
+  if (rbuf.size > 0) {
+    if (pconnection_error(
+          pc, uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read), "read"))
+        return;
+  }
+}
+
+static void listener_to_uv(pn_listener_t *l) {
+  to_uv(&l->psocket);           /* Assume we're going to UV unless sent elsewhere */
+  if (l->err) {
+    if (!uv_is_closing((uv_handle_t*)&l->psocket.tcp)) {
+      uv_close((uv_handle_t*)&l->psocket.tcp, on_close_psocket);
     }
-    if (next_tick) {
-      uv_timer_start(&pc->timer, on_tick, next_tick, 0);
-    }
-    if (wbuf.size > 0 && !pc->writing) {
-      pc->writing = wbuf.size;
-      uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
-      err = uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
-    } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
-      pc->shutdown.data = ps;
-      err = uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, NULL);
+  } else {
+    if (l->accepting) {
+      leader_accept(l);
     }
-    if (rbuf.size > 0 && !pc->reading) {
-      pc->reading = true;
-      err = uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
+    if (l->connections) {
+      listener_to_worker(l);
     }
+  }
+}
+
+/* Monitor a psocket_t in the UV loop */
+static void psocket_to_uv(psocket_t *ps) {
+  if (ps->is_conn) {
+    pconnection_to_uv(as_pconnection(ps));
   } else {
-    pn_listener_t *l = as_listener(ps);
-    if (l->closing && pn_collector_peek(l->collector)) {
-      uv_close((uv_handle_t*)&ps->tcp, on_close_psocket);
-      return;
-    } else {
-      if (l->accepting) {
-        leader_accept(l);
-      }
-      if (l->connections) {
-        leader_unwatch(ps);
-      }
-    }
+    listener_to_uv(as_listener(ps));
   }
-  if (err) {
-    leader_error(ps, err, "re-watching");
+}
+
+/* Detach a connection from IO and put it on the worker queue */
+static void pconnection_to_worker(pconnection_t *pc) {
+  /* Can't go to worker if a write is outstanding or the batch is empty */
+  if (!pc->writing && pn_connection_driver_has_event(&pc->driver)) {
+    uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
+    uv_timer_stop(&pc->timer);
   }
+  to_worker(&pc->psocket);
 }
 
-/* Detach a socket from IO and put it on the worker queue */
-static void leader_unwatch(psocket_t *ps) {
-  assert(ps->state != ON_WORKER); /* From ON_UV or ON_LEADER */
-  if (ps->is_conn) {
-    pconnection_t *pc = as_pconnection(ps);
-    if (!pn_connection_driver_has_event(&pc->driver)) {
-      /* Don't return an empty event batch, re-attach to UV loop */
-      leader_watch(ps);
-      return;
-    } else {
-      if (pc->writing) {
-        uv_cancel((uv_req_t*)&pc->write);
-      }
-      if (pc->reading) {
-        pc->reading = false;
-        uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
-      }
-      if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
-        uv_timer_stop(&pc->timer);
-      }
+/* TODO aconway 2017-02-16: simplify collector API*/
+static bool collector_has_next(pn_collector_t *c) {
+  return pn_collector_more(c) ||
+    (pn_collector_peek(c) && pn_collector_peek(c) != pn_collector_prev(c));
+}
+
+/* Can't really detach a listener, as on_connection can always be called.
+   Generate events here safely.
+*/
+static void listener_to_worker(pn_listener_t *l) {
+  if (collector_has_next(l->collector)) { /* Already have events */
+    to_worker(&l->psocket);
+  } else if (l->err) {
+    if (l->err != UV_EOF) {
+      pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
+                          l->what, fixstr(l->psocket.host), fixstr(l->psocket.port),
+                          uv_strerror(l->err));
     }
+    l->err = 0;
+    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
+    to_worker(&l->psocket);
+  } else if (l->connections) {    /* Generate accept events one at a time */
+    --l->connections;
+    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
+    to_worker(&l->psocket);
+  } else {
+    listener_to_uv(l);
   }
-  set_state(ps, ON_WORKER, NULL);
 }
 
 /* Set the event in the proactor's batch  */
@@ -618,7 +659,7 @@ static pn_event_batch_t *proactor_batch_lh(pn_proactor_t *p, pn_event_type_t t)
   return &p->batch;
 }
 
-/* Return the next event batch or 0 if no events are ready */
+/* Return the next event batch or 0 if no events are available in the worker_q */
 static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
   if (!p->batch_working) {       /* Can generate proactor events */
     if (p->inactive) {
@@ -637,33 +678,14 @@ static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
   for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
     assert(ps->state == ON_WORKER);
     if (ps->is_conn) {
-      pconnection_t *pc = as_pconnection(ps);
-      return &pc->driver.batch;
+      return &as_pconnection(ps)->driver.batch;
     } else {                    /* Listener */
-      pn_listener_t *l = as_listener(ps);
-      /* Generate accept events one at a time */
-      if (l->connections && !pn_collector_peek(l->collector)) {
-        --l->connections;
-        pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
-      }
-      return &l->batch;
+      return &as_listener(ps)->batch;
     }
-    set_state_lh(ps, ON_LEADER, NULL); /* No event, back to leader */
   }
   return 0;
 }
 
-/* Called in any thread to set a wakeup action */
-static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
-  uv_mutex_lock(&ps->proactor->lock);
-  if (action && !ps->wakeup) {
-    ps->wakeup = action;
-  }
-  set_state_lh(ps, ON_LEADER, NULL);
-  uv_async_send(&ps->proactor->async); /* Wake leader */
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
 pn_listener_t *pn_event_listener(pn_event_t *e) {
   return (pn_event_class(e) == pn_listener__class()) ? (pn_listener_t*)pn_event_context(e) : NULL;
 }
@@ -689,26 +711,52 @@ void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
     assert(pc->psocket.state == ON_WORKER);
     if (pn_connection_driver_has_event(&pc->driver)) {
       /* Process all events before going back to leader */
-      set_state(&pc->psocket, ON_WORKER, NULL);
+      pconnection_to_worker(pc);
     } else {
-      set_state(&pc->psocket, ON_LEADER, leader_watch);
+      to_leader(&pc->psocket, psocket_to_uv);
     }
     return;
   }
   pn_listener_t *l = batch_listener(batch);
   if (l) {
     assert(l->psocket.state == ON_WORKER);
-    set_state(&l->psocket, ON_LEADER, leader_watch);
+    to_leader(&l->psocket, psocket_to_uv);
     return;
   }
   pn_proactor_t *bp = batch_proactor(batch);
   if (bp == p) {
     uv_mutex_lock(&p->lock);
     p->batch_working = false;
-    uv_async_send(&p->async); /* Wake leader */
     uv_mutex_unlock(&p->lock);
     return;
   }
+  uv_async_send(&p->async); /* Wake leader */
+}
+
+/* Process the leader_q, in the leader thread */
+static void leader_process_lh(pn_proactor_t *p) {
+  if (p->timeout_request) {
+    p->timeout_request = false;
+    if (p->timeout) {
+      uv_timer_start(&p->timer, on_timeout, p->timeout, 0);
+    } else {
+      uv_timer_stop(&p->timer);
+    }
+  }
+  for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
+    assert(ps->state == ON_LEADER);
+    if (ps->wakeup) {
+      uv_mutex_unlock(&p->lock);
+      ps->wakeup(ps);
+      ps->wakeup = NULL;
+      uv_mutex_lock(&p->lock);
+    } else if (ps->action) {
+      uv_mutex_unlock(&p->lock);
+      ps->action(ps);
+      ps->action = NULL;
+      uv_mutex_lock(&p->lock);
+    }
+  }
 }
 
 /* Run follower/leader loop till we can return an event and be a worker */
@@ -724,28 +772,7 @@ pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
     /* Lead till there is work to do. */
     p->has_leader = true;
     while (batch == NULL) {
-      if (p->timeout_request) {
-        p->timeout_request = false;
-        if (p->timeout) {
-          uv_timer_start(&p->timer, on_timeout, p->timeout, 0);
-        } else {
-          uv_timer_stop(&p->timer);
-        }
-      }
-      for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
-        assert(ps->state == ON_LEADER);
-        if (ps->wakeup) {
-          uv_mutex_unlock(&p->lock);
-          ps->wakeup(ps);
-          ps->wakeup = NULL;
-          uv_mutex_lock(&p->lock);
-        } else if (ps->action) {
-          uv_mutex_unlock(&p->lock);
-          ps->action(ps);
-          ps->action = NULL;
-          uv_mutex_lock(&p->lock);
-        }
-      }
+      leader_process_lh(p);
       batch = get_batch_lh(p);
       if (batch == NULL) {
         uv_mutex_unlock(&p->lock);
@@ -753,7 +780,7 @@ pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
         uv_mutex_lock(&p->lock);
       }
     }
-    /* Signal the next leader and return to work */
+    /* Signal the next leader and go to work */
     p->has_leader = false;
     uv_cond_signal(&p->cond);
   }
@@ -761,19 +788,36 @@ pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
   return batch;
 }
 
+pn_event_batch_t *pn_proactor_grab(struct pn_proactor_t* p) {
+  uv_mutex_lock(&p->lock);
+  pn_event_batch_t *batch = get_batch_lh(p);
+  if (batch == NULL && !p->has_leader) {
+    /* If there is no leader, try a non-waiting lead to generate some work */
+    p->has_leader = true;
+    leader_process_lh(p);
+    uv_mutex_unlock(&p->lock);
+    uv_run(&p->loop, UV_RUN_NOWAIT);
+    uv_mutex_lock(&p->lock);
+    batch = get_batch_lh(p);
+    p->has_leader = false;
+  }
+  uv_mutex_unlock(&p->lock);
+  return batch;
+}
+
 void pn_proactor_interrupt(pn_proactor_t *p) {
   uv_mutex_lock(&p->lock);
   ++p->interrupt;
-  uv_async_send(&p->async);   /* Interrupt the UV loop */
   uv_mutex_unlock(&p->lock);
+  uv_async_send(&p->async);   /* Interrupt the UV loop */
 }
 
 void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
   uv_mutex_lock(&p->lock);
   p->timeout = t;
   p->timeout_request = true;
-  uv_async_send(&p->async);   /* Interrupt the UV loop */
   uv_mutex_unlock(&p->lock);
+  uv_async_send(&p->async);   /* Interrupt the UV loop */
 }
 
 int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {
@@ -781,7 +825,7 @@ int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host,
   if (!pc) {
     return PN_OUT_OF_MEMORY;
   }
-  set_state(&pc->psocket, ON_LEADER, leader_connect);
+  to_leader(&pc->psocket, leader_connect);
   return 0;
 }
 
@@ -789,7 +833,7 @@ int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *host, con
 {
   psocket_init(&l->psocket, p, false, host, port);
   l->backlog = backlog;
-  set_state(&l->psocket, ON_LEADER, leader_listen);
+  to_leader(&l->psocket, leader_listen);
   return 0;
 }
 
@@ -803,7 +847,7 @@ void leader_wake_connection(psocket_t *ps) {
   pconnection_t *pc = as_pconnection(ps);
   pn_connection_t *c = pc->driver.connection;
   pn_collector_put(pn_connection_collector(c), PN_OBJECT, c, PN_CONNECTION_WAKE);
-  leader_unwatch(ps);
+  pconnection_to_worker(pc);
 }
 
 void pn_connection_wake(pn_connection_t* c) {
@@ -850,11 +894,17 @@ void pn_proactor_free(pn_proactor_t *p) {
 static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
   pn_listener_t *l = batch_listener(batch);
   assert(l->psocket.state == ON_WORKER);
+  pn_event_t *prev = pn_collector_prev(l->collector);
+  if (prev && pn_event_type(prev) == PN_LISTENER_CLOSE) {
+    l->err = UV_EOF;
+  }
   return pn_collector_next(l->collector);
 }
 
 static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
-  return pn_collector_next(batch_proactor(batch)->collector);
+  pn_proactor_t *p = batch_proactor(batch);
+  assert(p->batch_working);
+  return pn_collector_next(p->collector);
 }
 
 static void pn_listener_free(pn_listener_t *l) {
@@ -867,7 +917,7 @@ static void pn_listener_free(pn_listener_t *l) {
   }
 }
 
-pn_listener_t *pn_listener() {
+pn_listener_t *pn_listener(void) {
   pn_listener_t *l = (pn_listener_t*)calloc(1, sizeof(pn_listener_t));
   if (l) {
     l->batch.next_event = listener_batch_next;
@@ -885,8 +935,8 @@ pn_listener_t *pn_listener() {
 void leader_listener_close(psocket_t *ps) {
   assert(ps->state = ON_LEADER);
   pn_listener_t *l = (pn_listener_t*)ps;
-  l->closing = true;
-  leader_watch(ps);
+  l->err = UV_EOF;
+  listener_to_uv(l);
 }
 
 void pn_listener_close(pn_listener_t* l) {
@@ -895,12 +945,10 @@ void pn_listener_close(pn_listener_t* l) {
 }
 
 pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
-  assert(l->psocket.state == ON_WORKER);
   return l ? l->psocket.proactor : NULL;
 }
 
 pn_condition_t* pn_listener_condition(pn_listener_t* l) {
-  assert(l->psocket.state == ON_WORKER);
   return l->condition;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/src/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/CMakeLists.txt b/proton-c/src/tests/CMakeLists.txt
index 59c7665..70b30a0 100644
--- a/proton-c/src/tests/CMakeLists.txt
+++ b/proton-c/src/tests/CMakeLists.txt
@@ -20,15 +20,15 @@
 add_definitions(${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS})
 
 if (ENABLE_VALGRIND AND VALGRIND_EXE)
-  set(memcheck-cmd ${VALGRIND_EXE} --error-exitcode=1 --quiet
+  set(memcheck-cmd ${VALGRIND_EXE} --error-exitcode=42 --quiet
                    --leak-check=full --trace-children=yes)
 endif ()
 
-macro (pn_add_c_test test file)
-  add_executable (${test} ${file})
+macro (pn_add_c_test test)
+  add_executable (${test} ${ARGN})
   target_link_libraries (${test} qpid-proton)
   if (BUILD_WITH_CXX)
-    set_source_files_properties (${file} PROPERTIES LANGUAGE CXX)
+    set_source_files_properties (${ARGN} PROPERTIES LANGUAGE CXX)
   endif (BUILD_WITH_CXX)
   if (CMAKE_SYSTEM_NAME STREQUAL Windows)
     add_test (NAME ${test}
@@ -49,3 +49,4 @@ pn_add_c_test (c-reactor-tests reactor.c)
 pn_add_c_test (c-event-tests event.c)
 pn_add_c_test (c-data-tests data.c)
 pn_add_c_test (c-condition-tests condition.c)
+pn_add_c_test (c-proactor-tests proactor.c)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
new file mode 100644
index 0000000..ae5b1f6
--- /dev/null
+++ b/proton-c/src/tests/proactor.c
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_tools.h"
+#include <proton/condition.h>
+#include <proton/connection.h>
+#include <proton/event.h>
+#include <proton/listener.h>
+#include <proton/proactor.h>
+#include <proton/transport.h>
+#include <stdlib.h>
+#include <string.h>
+
+static pn_millis_t timeout = 5*1000; /* timeout for hanging tests */
+
+static const char *localhost = "127.0.0.1"; /* host for connect/listen */
+
+/* Wait for the next single event, return its type */
+static pn_event_type_t wait_next(pn_proactor_t *proactor) {
+  pn_event_batch_t *events = pn_proactor_wait(proactor);
+  pn_event_type_t etype = pn_event_type(pn_event_batch_next(events));
+  pn_proactor_done(proactor, events);
+  return etype;
+}
+
+/* Get events until an event of `type` or a PN_TRANSPORT_CLOSED/PN_PROACTOR_TIMEOUT */
+static pn_event_type_t wait_for(pn_proactor_t *proactor, pn_event_type_t etype) {
+  while (true) {
+    pn_event_type_t t = wait_next(proactor);
+    if (t == etype || t == PN_PROACTOR_TIMEOUT) {
+      return t;
+    }
+  }
+}
+
+/* Test that interrupt and timeout events cause pn_proactor_wait() to return. */
+static void test_interrupt_timeout(test_t *t) {
+  pn_proactor_t *p = pn_proactor();
+  pn_proactor_interrupt(p);
+  pn_event_type_t etype = wait_next(p);
+  TEST_CHECK(t, PN_PROACTOR_INTERRUPT == etype, pn_event_type_name(etype));
+  pn_proactor_set_timeout(p, 1); /* very short timeout */
+  etype = wait_next(p);
+  TEST_CHECK(t, PN_PROACTOR_TIMEOUT == etype, pn_event_type_name(etype));
+  pn_proactor_free(p);
+}
+
+/* Test handler return value  */
+typedef enum {
+  H_CONTINUE,                   /**@<< handler wants more events */
+  H_FINISHED,                   /**@<< handler completed without error */
+  H_FAILED                      /**@<< handler hit an error and cannot continue */
+} handler_state_t;
+
+typedef handler_state_t (*test_handler_fn)(test_t *, pn_event_t*);
+
+/* Proactor and handler that take part in a test */
+typedef struct proactor_test_t {
+  test_t *t;
+  test_handler_fn handler;
+  pn_proactor_t *proactor;
+  handler_state_t state;                    /* Result of last handler call */
+} proactor_test_t;
+
+
+/* Initialize an array of proactor_test_t */
+static void proactor_test_init(proactor_test_t *pts, size_t n) {
+  for (proactor_test_t *pt = pts; pt < pts + n; ++pt) {
+    if (!pt->proactor) pt->proactor = pn_proactor();
+    pn_proactor_set_timeout(pt->proactor, timeout);
+    pt->state = H_CONTINUE;
+  }
+}
+
+/* Iterate over an array of proactors, draining or handling events with the non-blocking
+   pn_proactor_grab.  Continue till all handlers return H_FINISHED (and return 0) or one
+   returns H_FAILED  (and return non-0)
+*/
+int proactor_test_run(proactor_test_t *pts, size_t n) {
+  /* Make sure pts are initialized */
+  proactor_test_init(pts, n);
+  size_t finished = 0;
+  do {
+    finished = 0;
+    for (proactor_test_t *pt = pts; pt < pts + n; ++pt) {
+      pn_event_batch_t *events = pn_proactor_grab(pt->proactor);
+      if (events) {
+          pn_event_t *e;
+          while ((e = pn_event_batch_next(events))) {
+            if (pt->state == H_CONTINUE) {
+              pt->state = pt->handler(pt->t, e);
+            }
+          }
+          pn_proactor_done(pt->proactor, events);
+      }
+      switch (pt->state) {
+       case H_CONTINUE: break;
+       case H_FINISHED: ++finished; break;
+       case H_FAILED: return 1;
+      }
+    }
+  } while (finished < n);
+  return 0;
+}
+
+
+/* Simple test of client connect to a listening server */
+handler_state_t listen_connect_server(test_t *t, pn_event_t *e) {
+  switch (pn_event_type(e)) {
+    /* Ignore these events */
+   case PN_LISTENER_OPEN:
+   case PN_CONNECTION_LOCAL_OPEN:
+   case PN_CONNECTION_REMOTE_OPEN:
+   case PN_CONNECTION_BOUND:
+    return H_CONTINUE;
+
+    /* Act on these events */
+   case PN_LISTENER_ACCEPT:
+     pn_listener_accept(pn_event_listener(e), pn_connection());
+     return H_CONTINUE;
+   case PN_CONNECTION_INIT:
+    pn_connection_open(pn_event_connection(e));
+    return H_CONTINUE;
+   case PN_CONNECTION_REMOTE_CLOSE:
+    return H_FINISHED;
+
+   default:
+    TEST_CHECK(t, false, "unexpected event %s", pn_event_type_name(pn_event_type(e)));
+    return H_FAILED;
+    break;
+  }
+}
+
+handler_state_t listen_connect_client(test_t *t, pn_event_t *e) {
+  switch (pn_event_type(e)) {
+    /* Ignore these events */
+   case PN_CONNECTION_LOCAL_OPEN:
+   case PN_CONNECTION_BOUND:
+    return H_CONTINUE;
+
+    /* Act on these events */
+   case PN_CONNECTION_INIT:
+    pn_connection_open(pn_event_connection(e));
+    return H_CONTINUE;
+   case PN_CONNECTION_REMOTE_OPEN:
+    pn_connection_close(pn_event_connection(e));
+    return H_FINISHED;
+
+    /* Unexpected events */
+   default:
+    TEST_CHECK(t, false, "unexpected event %s", pn_event_type_name(pn_event_type(e)));
+    return H_FAILED;
+    break;
+  }
+}
+
+/* Simplest client/server interaction */
+static void test_listen_connect(test_t *t) {
+  proactor_test_t pts[] =  { { t, listen_connect_client }, { t, listen_connect_server } };
+  proactor_test_t *client = &pts[0], *server = &pts[1];
+  proactor_test_init(pts, 2);
+
+  int port = pick_port();
+  char port_str[16];
+  snprintf(port_str, sizeof(port_str), "%d", port);
+  pn_proactor_listen(server->proactor, pn_listener(), localhost, port_str, 4);
+  pn_event_type_t etype = wait_for(server->proactor, PN_LISTENER_OPEN);
+  if (TEST_CHECK(t, PN_LISTENER_OPEN == etype, pn_event_type_name(etype))) {
+    pn_proactor_connect(client->proactor, pn_connection(), localhost, port_str);
+    proactor_test_run(pts, 2);
+  }
+  pn_proactor_free(client->proactor);
+  pn_proactor_free(server->proactor);
+}
+
+/* Test error handling */
+static void test_listen_connect_error(test_t *t) {
+  pn_proactor_t *p = pn_proactor();
+  pn_proactor_set_timeout(p, timeout); /* In case of hang */
+  pn_connection_t *c = pn_connection();
+  pn_proactor_connect(p, c, "nosuchost", "nosuchport");
+  pn_event_type_t etype = wait_for(p, PN_TRANSPORT_CLOSED);
+  TEST_CHECK(t, PN_TRANSPORT_CLOSED == etype, pn_event_type_name(etype));
+  TEST_CHECK(t, pn_condition_is_set(pn_transport_condition(pn_connection_transport(c))), "");
+
+  pn_listener_t *l = pn_listener();
+  pn_proactor_listen(p, l, "nosuchost", "nosuchport", 1);
+  etype = wait_for(p, PN_LISTENER_CLOSE);
+  TEST_CHECK(t, PN_LISTENER_CLOSE == etype, pn_event_type_name(etype));
+  TEST_CHECK(t, pn_condition_is_set(pn_listener_condition(l)), "");
+
+  pn_proactor_free(p);
+}
+
+int main(int argv, char** argc) {
+  int failed = 0;
+  RUN_TEST(failed, t, test_interrupt_timeout(&t));
+  RUN_TEST(failed, t, test_listen_connect(&t));
+  RUN_TEST(failed, t, test_listen_connect_error(&t));
+  return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b987a6a7/proton-c/src/tests/test_tools.h
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/test_tools.h b/proton-c/src/tests/test_tools.h
new file mode 100644
index 0000000..047ab42
--- /dev/null
+++ b/proton-c/src/tests/test_tools.h
@@ -0,0 +1,140 @@
+#ifndef TESTS_TEST_TOOLS_H
+#define TESTS_TEST_TOOLS_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/type_compat.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Call via ASSERT macro. */
+static void assert_fail_(const char* cond, const char* file, int line) {
+  printf("%s:%d: Assertion failed: %s\n", file, line, cond);
+  abort();
+}
+
+/* Unconditional assert (does not depend on NDEBUG) for tests. */
+#define ASSERT(expr)                                            \
+  ((expr) ?  (void)0 : assert_fail_(#expr, __FILE__, __LINE__))
+
+/* Call via macro ASSERT_PERROR */
+static void assert_perror_fail_(const char* cond, const char* file, int line) {
+  perror(cond);
+  printf("%s:%d: Assertion failed (error above): %s\n", file, line, cond);
+  abort();
+}
+
+/* Like ASSERT but also calls perror() to print the current errno error. */
+#define ASSERT_PERROR(expr)                                             \
+  ((expr) ?  (void)0 : assert_perror_fail_(#expr, __FILE__, __LINE__))
+
+
+/* A struct to collect the results of a test.
+ * Declare and initialize with TEST_START(t) where t will be declared as a test_t
+ */
+typedef struct test_t {
+  const char* name;
+  int errors;
+} test_t;
+
+/* if !expr print the printf-style error and increment t->errors. Use via macros. Returns expr. */
+static inline bool test_check_(test_t *t, bool expr, const char *sexpr, const char *file, int line, const char* fmt, ...) {
+  if (!expr) {
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "%s:%d:[%s] check failed: (%s)", file, line, t->name, sexpr);
+    if (fmt && *fmt) {
+      fprintf(stderr, " - ");
+      vfprintf(stderr, fmt, ap);
+    }
+    fprintf(stderr, "\n");
+    fflush(stderr);
+    ++t->errors;
+  }
+  return expr;
+}
+
+#define TEST_CHECK(TEST, EXPR, ...) test_check_((TEST), (EXPR), #EXPR, __FILE__, __LINE__, __VA_ARGS__)
+
+/* T is name of a test_t variable, EXPR is the test expression (which should update T)
+   FAILED is incremented if the test has errors
+*/
+#define RUN_TEST(FAILED, T, EXPR) do {                          \
+    printf("TEST: %s\n", #EXPR);                                \
+    fflush(stdout);                                             \
+    test_t T = { #EXPR, 0 };                                    \
+    (EXPR);                                                     \
+    if (T.errors) {                                             \
+      printf("FAIL: %s (%d errors)\n", #EXPR, T.errors);        \
+      ++(FAILED);                                               \
+    }                                                           \
+  } while(0)
+
+#if defined(WIN32)
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+typedef SOCKET sock_t;
+static inline void sock_close(sock_t sock) { closesocket(sock); }
+
+#else
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <unistd.h>
+
+static int port_in_use(int port) {
+  /* Attempt to bind a dummy socket to test if the port is in use. */
+  int dummy_socket = socket(AF_INET, SOCK_STREAM, 0);
+  ASSERT_PERROR(dummy_socket >= 0);
+  struct sockaddr_in addr = {0};
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(port);
+  int ret = bind(dummy_socket, (struct sockaddr *) &addr, sizeof(addr));
+  close(dummy_socket);
+  return ret < 0;
+}
+
+/* Try to pick an unused port by picking random ports till we find one
+   that is not in use. This is not foolproof as some other process may
+   grab it before the caller binds or connects.
+*/
+static int pick_port(void) {
+  srand(time(NULL));
+  static int MAX_TRIES = 10;
+  int port = -1;
+  int i = 0;
+  do {
+    /* Pick a random port. Avoid the standard OS ephemeral port range used by
+       bind(0) - ports can be allocated and re-allocated very rapidly there.
+    */
+    port =  (rand()%10000) + 10000;
+  } while (i++ < MAX_TRIES && port_in_use(port));
+  ASSERT(i < MAX_TRIES && "cannot pick a port");
+  return port;
+}
+
+#endif
+
+#endif // TESTS_TEST_TOOLS_H


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[23/38] qpid-proton git commit: PROTON-1403: Better port allocation for test servers using bind(0)

Posted by ac...@apache.org.
PROTON-1403: Better port allocation for test servers using bind(0)

Use bind(0) with SO_REUSEADDR to hold onto the bound port until the test server
is listening on it. Works in python and C.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9abc67de
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9abc67de
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9abc67de

Branch: refs/heads/go1
Commit: 9abc67de8c40ffea0c988ad9408d513fbb400196
Parents: b987a6a
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Feb 16 11:25:07 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Feb 16 18:25:17 2017 -0500

----------------------------------------------------------------------
 examples/c/proactor/test.py           |  24 +++---
 examples/exampletest.py               |  24 ++++--
 proton-c/src/core/connection_driver.c |   1 -
 proton-c/src/proactor/libuv.c         |   1 -
 proton-c/src/tests/proactor.c         |  12 ++-
 proton-c/src/tests/test_tools.h       | 118 ++++++++++++++++-------------
 6 files changed, 105 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9abc67de/examples/c/proactor/test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/test.py b/examples/c/proactor/test.py
index 45bb817..7d6f3fc 100644
--- a/examples/c/proactor/test.py
+++ b/examples/c/proactor/test.py
@@ -61,23 +61,25 @@ class CExampleTest(BrokerTestCase):
             except ProcError, e:
                 if "connection refused" in e.args[0] and max > 0:
                     max -= 1
-                    time.sleep(.01)
                     continue
                 raise
 
     def test_send_direct(self):
-        """Send first then receive"""
-        addr = "127.0.0.1:%s/examples" % (pick_port())
-        d = self.proc(["direct", "-a", addr])
-        self.assertEqual("100 messages sent and acknowledged\n", self.retry(["send", "-a", addr]))
-        self.assertIn(receive_expect(100), d.wait_out())
+        """Send to direct server"""
+        with bind0() as sock:
+            addr = "127.0.0.1:%s/examples" % sock.port()
+            d = self.proc(["direct", "-a", addr])
+            self.assertEqual("100 messages sent and acknowledged\n", self.retry(["send", "-a", addr]))
+            self.assertIn(receive_expect(100), d.wait_out())
 
     def test_receive_direct(self):
-        """Send first then receive"""
-        addr = "127.0.0.1:%s/examples" % (pick_port())
-        d = self.proc(["direct", "-a", addr])
-        self.assertEqual(receive_expect(100), self.retry(["receive", "-a", addr]))
-        self.assertIn("100 messages sent and acknowledged\n", d.wait_out())
+        """Receive from direct server"""
+        with bind0() as sock:
+            addr = "127.0.0.1:%s/examples" % sock.port()
+            d = self.proc(["direct", "-a", addr])
+            self.assertEqual(receive_expect(100), self.retry(["receive", "-a", addr]))
+            self.assertIn("100 messages sent and acknowledged\n", d.wait_out())
+
 
 if __name__ == "__main__":
     unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9abc67de/examples/exampletest.py
----------------------------------------------------------------------
diff --git a/examples/exampletest.py b/examples/exampletest.py
index bf7ea9b..8dbd1ed 100644
--- a/examples/exampletest.py
+++ b/examples/exampletest.py
@@ -29,10 +29,18 @@ from copy import copy
 import platform
 from os.path import dirname as dirname
 
-def pick_port():
-    """Pick a random port."""
-    p =  randrange(10000, 20000)
-    return p
+def bind0():
+    """Bind a socket with bind(0) and SO_REUSEADDR to get a free port to listen on"""
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    
+    sock.bind(('', 0))
+    return sock
+
+# Monkeypatch add port() and with support to socket.socket
+socket.socket.port = lambda(self): socket.getnameinfo(self.getsockname(), 0)[1]
+socket.socket.__enter__ = lambda(self): self
+def socket__exit__(self, *args): self.close()
+socket.socket.__exit__ = socket__exit__
 
 class ProcError(Exception):
     """An exception that captures failed process output"""
@@ -91,7 +99,7 @@ class Proc(Popen):
         t.join(timeout)
         if self.poll() is None:      # Still running
             self.kill()
-            raise ProcError(self, "timeout")
+            raise ProcError(self, "still running after %ss" % timeout)
         if expect is not None and self.poll() != expect:
             raise ProcError(self)
         return self.out
@@ -148,7 +156,7 @@ def wait_port(port, timeout=10):
         except socket.error, e:
             if e.errno != errno.ECONNREFUSED: # Only retry on connection refused error.
                 raise
-    raise socket.timeout()
+    raise socket.timeout("waiting for port %s" % port)
 
 
 class BrokerTestCase(ExampleTestCase):
@@ -159,7 +167,8 @@ class BrokerTestCase(ExampleTestCase):
 
     @classmethod
     def setUpClass(cls):
-        cls.port = pick_port()
+        sock = bind0()
+        cls.port = sock.port()
         cls.addr = "127.0.0.1:%s/examples" % (cls.port)
         cls.broker = None       # In case Proc throws, create the attribute.
         cls.broker = Proc(cls.broker_exe + ["-a", cls.addr])
@@ -168,6 +177,7 @@ class BrokerTestCase(ExampleTestCase):
         except Exception, e:
             cls.broker.kill()
             raise ProcError(cls.broker, "timed out waiting for port")
+        sock.close()
 
     @classmethod
     def tearDownClass(cls):

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9abc67de/proton-c/src/core/connection_driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_driver.c b/proton-c/src/core/connection_driver.c
index 0d1db21..63eed09 100644
--- a/proton-c/src/core/connection_driver.c
+++ b/proton-c/src/core/connection_driver.c
@@ -127,7 +127,6 @@ pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *d) {
 }
 
 bool pn_connection_driver_has_event(pn_connection_driver_t *d) {
-  /* FIXME aconway 2017-02-15: this is ugly */
   pn_collector_t *c = pn_connection_collector(d->connection);
   return pn_collector_more(c) || (pn_collector_peek(c) && pn_collector_peek(c) != pn_collector_prev(c));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9abc67de/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 0ccfcda..4ec7b03 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -427,7 +427,6 @@ static void on_connection(uv_stream_t* server, int err) {
   listener_to_worker(l);        /* If already ON_WORKER it will stay there */
 }
 
-/* FIXME aconway 2017-02-16:  listener events in unwatch*/
 static void leader_accept(pn_listener_t * l) {
   assert(l->accepting);
   pconnection_t *pc = l->accepting;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9abc67de/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index ae5b1f6..e90c45a 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -24,6 +24,7 @@
 #include <proton/listener.h>
 #include <proton/proactor.h>
 #include <proton/transport.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -176,15 +177,16 @@ static void test_listen_connect(test_t *t) {
   proactor_test_t *client = &pts[0], *server = &pts[1];
   proactor_test_init(pts, 2);
 
-  int port = pick_port();
+  sock_t sock = sock_bind0();          /* Hold a port */
   char port_str[16];
-  snprintf(port_str, sizeof(port_str), "%d", port);
+  snprintf(port_str, sizeof(port_str), "%d", sock_port(sock));
   pn_proactor_listen(server->proactor, pn_listener(), localhost, port_str, 4);
   pn_event_type_t etype = wait_for(server->proactor, PN_LISTENER_OPEN);
   if (TEST_CHECK(t, PN_LISTENER_OPEN == etype, pn_event_type_name(etype))) {
     pn_proactor_connect(client->proactor, pn_connection(), localhost, port_str);
     proactor_test_run(pts, 2);
   }
+  sock_close(sock);
   pn_proactor_free(client->proactor);
   pn_proactor_free(server->proactor);
 }
@@ -210,8 +212,10 @@ static void test_listen_connect_error(test_t *t) {
 
 int main(int argv, char** argc) {
   int failed = 0;
-  RUN_TEST(failed, t, test_interrupt_timeout(&t));
+  if (0) {
+    RUN_TEST(failed, t, test_interrupt_timeout(&t));
+    RUN_TEST(failed, t, test_listen_connect_error(&t));
+  }
   RUN_TEST(failed, t, test_listen_connect(&t));
-  RUN_TEST(failed, t, test_listen_connect_error(&t));
   return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9abc67de/proton-c/src/tests/test_tools.h
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/test_tools.h b/proton-c/src/tests/test_tools.h
index 047ab42..2619337 100644
--- a/proton-c/src/tests/test_tools.h
+++ b/proton-c/src/tests/test_tools.h
@@ -22,30 +22,45 @@
 
 #include <proton/type_compat.h>
 
+#include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
-/* Call via ASSERT macro. */
-static void assert_fail_(const char* cond, const char* file, int line) {
-  printf("%s:%d: Assertion failed: %s\n", file, line, cond);
+/*
+  All output from test marcros goes to stdout not stderr, error messages are normal for a test.
+  Some errno handling functions are thread-unsafe
+  */
+
+
+/* Call via TEST_ASSERT macros */
+static void assert_fail_(const char* cond, const char* file, int line, const char *fmt, ...) {
+  printf("%s:%d: Assertion failed: %s", file, line, cond);
+  if (fmt && *fmt) {
+    va_list ap;
+    va_start(ap, fmt);
+    printf(" - ");
+    vprintf(fmt, ap);
+    printf("\n");
+    fflush(stdout);
+    va_end(ap);
+  }
   abort();
 }
 
 /* Unconditional assert (does not depend on NDEBUG) for tests. */
-#define ASSERT(expr)                                            \
-  ((expr) ?  (void)0 : assert_fail_(#expr, __FILE__, __LINE__))
+#define TEST_ASSERT(expr) \
+  ((expr) ?  (void)0 : assert_fail_(#expr, __FILE__, __LINE__, NULL))
 
-/* Call via macro ASSERT_PERROR */
-static void assert_perror_fail_(const char* cond, const char* file, int line) {
-  perror(cond);
-  printf("%s:%d: Assertion failed (error above): %s\n", file, line, cond);
-  abort();
-}
+/* Unconditional assert with printf-style message (does not depend on NDEBUG) for tests. */
+#define TEST_ASSERTF(expr, ...) \
+  ((expr) ?  (void)0 : assert_fail_(#expr, __FILE__, __LINE__, __VA_ARGS__))
 
-/* Like ASSERT but also calls perror() to print the current errno error. */
-#define ASSERT_PERROR(expr)                                             \
-  ((expr) ?  (void)0 : assert_perror_fail_(#expr, __FILE__, __LINE__))
+/* Like TEST_ASSERT but includes  errno string for err */
+/* TODO aconway 2017-02-16: not thread safe, replace with safe strerror_r or similar */
+#define TEST_ASSERT_ERRNO(expr, err) \
+  TEST_ASSERTF((expr), "%s", strerror(err))
 
 
 /* A struct to collect the results of a test.
@@ -61,12 +76,12 @@ static inline bool test_check_(test_t *t, bool expr, const char *sexpr, const ch
   if (!expr) {
     va_list ap;
     va_start(ap, fmt);
-    fprintf(stderr, "%s:%d:[%s] check failed: (%s)", file, line, t->name, sexpr);
+    printf("%s:%d:[%s] check failed: (%s)", file, line, t->name, sexpr);
     if (fmt && *fmt) {
-      fprintf(stderr, " - ");
-      vfprintf(stderr, fmt, ap);
+      printf(" - ");
+      vprintf(fmt, ap);
     }
-    fprintf(stderr, "\n");
+    printf("\n");
     fflush(stderr);
     ++t->errors;
   }
@@ -89,6 +104,8 @@ static inline bool test_check_(test_t *t, bool expr, const char *sexpr, const ch
     }                                                           \
   } while(0)
 
+
+/* Some very simple platform-secifics to acquire an unused socket */
 #if defined(WIN32)
 
 #include <winsock2.h>
@@ -96,45 +113,44 @@ static inline bool test_check_(test_t *t, bool expr, const char *sexpr, const ch
 typedef SOCKET sock_t;
 static inline void sock_close(sock_t sock) { closesocket(sock); }
 
-#else
+#else  /* POSIX */
+
+typedef int sock_t;
+# include <netinet/in.h>
+# include <unistd.h>
+static inline void sock_close(sock_t sock) { close(sock); }
+#endif
 
-#include <netdb.h>
-#include <netinet/in.h>
-#include <time.h>
-#include <unistd.h>
 
-static int port_in_use(int port) {
-  /* Attempt to bind a dummy socket to test if the port is in use. */
-  int dummy_socket = socket(AF_INET, SOCK_STREAM, 0);
-  ASSERT_PERROR(dummy_socket >= 0);
+/* Create a socket and bind(LOOPBACK:0) to get a free port.
+   Use SO_REUSEADDR so other processes can bind and listen on this port.
+   Close the returned fd when the other process is listening.
+   Asserts on error.
+*/
+static sock_t sock_bind0(void) {
+  int sock =  socket(AF_INET, SOCK_STREAM, 0);
+  TEST_ASSERT_ERRNO(sock >= 0, errno);
+  int on = 1;
+  TEST_ASSERT_ERRNO(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == 0, errno);
   struct sockaddr_in addr = {0};
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons(port);
-  int ret = bind(dummy_socket, (struct sockaddr *) &addr, sizeof(addr));
-  close(dummy_socket);
-  return ret < 0;
+  addr.sin_family = AF_INET;    /* set the type of connection to TCP/IP */
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr.sin_port = 0;            /* bind to port 0 */
+  TEST_ASSERT_ERRNO(bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0, errno);
+  return sock;
 }
 
-/* Try to pick an unused port by picking random ports till we find one
-   that is not in use. This is not foolproof as some other process may
-   grab it before the caller binds or connects.
-*/
-static int pick_port(void) {
-  srand(time(NULL));
-  static int MAX_TRIES = 10;
+static int sock_port(sock_t sock) {
+  struct sockaddr addr = {0};
+  socklen_t len = sizeof(addr);
+  TEST_ASSERT_ERRNO(getsockname(sock, &addr, &len) == 0, errno);
   int port = -1;
-  int i = 0;
-  do {
-    /* Pick a random port. Avoid the standard OS ephemeral port range used by
-       bind(0) - ports can be allocated and re-allocated very rapidly there.
-    */
-    port =  (rand()%10000) + 10000;
-  } while (i++ < MAX_TRIES && port_in_use(port));
-  ASSERT(i < MAX_TRIES && "cannot pick a port");
-  return port;
+  switch (addr.sa_family) {
+   case AF_INET: port = ((struct sockaddr_in*)&addr)->sin_port; break;
+   case AF_INET6: port = ((struct sockaddr_in6*)&addr)->sin6_port; break;
+   default: TEST_ASSERTF(false, "unknown protocol type %d\n", addr.sa_family); break;
+  }
+  return ntohs(port);
 }
 
-#endif
-
 #endif // TESTS_TEST_TOOLS_H


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[10/38] qpid-proton git commit: PROTON-1403: c proactor library windows fixes.

Posted by ac...@apache.org.
PROTON-1403: c proactor library windows fixes.

Don't build the proactor lib and examples unless there is one for the platform.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1d4fe545
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1d4fe545
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1d4fe545

Branch: refs/heads/go1
Commit: 1d4fe545e394d1b0eed57dcf36624565f20d69b8
Parents: ec70d73
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Feb 10 22:08:23 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Feb 10 22:39:01 2017 -0500

----------------------------------------------------------------------
 examples/c/CMakeLists.txt     |  8 ++++++--
 examples/c/proactor/broker.c  |  6 +++---
 examples/c/proactor/receive.c |  6 +++---
 examples/c/proactor/send.c    |  6 +++---
 proton-c/CMakeLists.txt       | 17 ++++++++++-------
 5 files changed, 25 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d4fe545/examples/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index 0d0c7e9..b2f36d3 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -19,9 +19,13 @@
 
 find_package(Proton REQUIRED)
 include(CheckCCompilerFlag)
-
+include(CheckFunctionExists)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 
-add_subdirectory(proactor)
+check_function_exists(pn_proactor, HAS_PROACTOR)
+if (HAS_PROACTOR)
+  add_subdirectory(proactor)
+endif()
+
 add_subdirectory(messenger)
 add_subdirectory(reactor)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d4fe545/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index d6261f4..5679290 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -25,11 +25,11 @@
 #include <proton/sasl.h>
 #include <proton/transport.h>
 #include <proton/url.h>
+#include "pncompat/misc_funcs.inc"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 
 bool enable_debug = false;
 
@@ -435,8 +435,8 @@ int main(int argc, char **argv) {
   /* Command line options */
   char *urlstr = NULL;
   char container_id[256];
-  /* Default container-id is program:pid */
-  snprintf(container_id, sizeof(container_id), "%s:%d", argv[0], getpid());
+  /* Note container-id should be unique */
+  snprintf(container_id, sizeof(container_id), "%s", argv[0]);
   size_t nthreads = 4;
   pn_millis_t heartbeat = 0;
   int opt;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d4fe545/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index b8edcd6..1eb54b6 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -28,11 +28,11 @@
 #include <proton/session.h>
 #include <proton/transport.h>
 #include <proton/url.h>
+#include "pncompat/misc_funcs.inc"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 
 typedef char str[1024];
 
@@ -176,8 +176,8 @@ int main(int argc, char **argv) {
   }
   if (optind < argc)
     usage(argv[0]);
-
-  snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
+  /* Note container-id should be unique */
+  snprintf(app.container_id, sizeof(app.container_id), "%s", argv[0]);
 
   /* Parse the URL or use default values */
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d4fe545/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index d611b3d..48fcecd 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -28,11 +28,11 @@
 #include <proton/session.h>
 #include <proton/transport.h>
 #include <proton/url.h>
+#include "pncompat/misc_funcs.inc"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 
 typedef char str[1024];
 
@@ -205,8 +205,8 @@ int main(int argc, char **argv) {
   }
   if (optind < argc)
     usage(argv[0]);
-
-  snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
+  /* Note container-id should be unique */
+  snprintf(app.container_id, sizeof(app.container_id), "%s", argv[0]);
 
   /* Parse the URL or use default values */
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1d4fe545/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index e5552c5..c73f9df 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -541,12 +541,6 @@ set_target_properties (
   LINK_FLAGS "${CATCH_UNDEFINED} ${LTO}"
   )
 
-add_library (
-  qpid-proton-proactor SHARED
-  ${qpid-proton-proactor}
-  )
-target_link_libraries (qpid-proton-proactor qpid-proton-core ${PROACTOR_LIBS})
-
 add_library(
   qpid-proton SHARED
   # Proton Core
@@ -627,7 +621,16 @@ endmacro()
 
 configure_lib(PROTONLIB qpid-proton)
 configure_lib(PROTONCORELIB qpid-proton-core)
-configure_lib(PROTONPROACTORLIB qpid-proton-proactor)
+
+if (qpid-proton-proactor)
+  add_library (
+    qpid-proton-proactor SHARED
+    ${qpid-proton-proactor}
+    )
+  target_link_libraries (qpid-proton-proactor qpid-proton-core ${PROACTOR_LIBS})
+  configure_lib(PROTONPROACTORLIB qpid-proton-proactor)
+endif()
+
 
 include(WriteBasicConfigVersionFile)
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org