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/06/09 01:25:24 UTC

[01/50] [abbrv] qpid-proton git commit: PROTON-1460: fix compile errors in epoll.c on travis, clang.

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


PROTON-1460: fix compile errors in epoll.c on travis, clang.


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

Branch: refs/heads/go1
Commit: 4b33c423c5d5f2c3cfc50b7c4ea29b67f9e57a0e
Parents: e28859b
Author: Alan Conway <ac...@redhat.com>
Authored: Mon May 8 15:19:18 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon May 8 15:23:23 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4b33c423/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 2545045..3b71eac 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -364,7 +364,8 @@ static bool wake(pcontext_t *ctx) {
 // part2: make OS call without lock held
 static inline void wake_notify(pcontext_t *ctx) {
   uint64_t increment = 1;
-  write(ctx->proactor->eventfd, &increment, sizeof(uint64_t));  // TODO: check for error
+  int err = write(ctx->proactor->eventfd, &increment, sizeof(uint64_t));
+  (void)err;  // TODO: check for error
 }
 
 // call with no locks
@@ -384,7 +385,8 @@ static pcontext_t *wake_pop_front(pn_proactor_t *p) {
        * Note that if the reads/writes happen out of order, the wake
        * mechanism will hang. */
       uint64_t ignored;
-      read(p->eventfd, &ignored, sizeof(uint64_t)); // TODO: check for error
+      int err = read(p->eventfd, &ignored, sizeof(uint64_t));
+      (void)err; // TODO: check for error
       p->wakes_in_progress = false;
     }
   }
@@ -885,7 +887,7 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
 
   if (!pconnection_rclosed(pc)) {
     pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
-    if (rbuf.size >= 0 && !pc->read_blocked) {
+    if (rbuf.size > 0 && !pc->read_blocked) {
       ssize_t n = read(pc->psocket.sockfd, rbuf.start, rbuf.size);
 
       if (n > 0) {


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


[45/50] [abbrv] qpid-proton git commit: PROTON-1495: c epoll proactor handling file descriptor shortage

Posted by ac...@apache.org.
PROTON-1495: c epoll proactor handling file descriptor shortage

Previously if the proactor ran out of file descriptors during pn_listener_accept the
listener closed, and could not accept further connections even when FDs became
free.

Now the affected listener(s) are put into "overflow" mode and dispabled until
the proactor closes an FD, at which point it re-enables overflowing listeners.

The error is reported as a PN_TRANSPORT_ERROR on the connection that the
application attempted to use for pn_listener_accept() Clients will experience a
delay and/or be disconnected while the listener is in overflow mode.

NOTE: we should also have a timeout to re-try overflow listeners even if the
proactor has not closed any file descriptors, in case other parts of the
application have. This is not yet done.


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

Branch: refs/heads/go1
Commit: 087b94faef6f0bc3fc2eac50ba0d2c2b03d82fbd
Parents: 11fa24d
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Jun 5 14:14:01 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 8 12:52:53 2017 -0400

----------------------------------------------------------------------
 CMakeLists.txt                    |  10 +++
 examples/CMakeLists.txt           |   9 --
 examples/c/proactor/broker.c      |  10 +--
 proton-c/include/proton/event.h   |   1 -
 proton-c/src/proactor/epoll.c     | 160 ++++++++++++++++++++++-----------
 proton-c/src/tests/CMakeLists.txt |  12 +++
 proton-c/src/tests/fdlimit.py     |  85 ++++++++++++++++++
 7 files changed, 219 insertions(+), 68 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 294fd03..7fe25e3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -170,6 +170,16 @@ if (ENABLE_VALGRIND)
   endif ()
 endif (ENABLE_VALGRIND)
 
+# Set result to a native search path - used by examples and binding tests.
+# args after result are directories or search paths.
+macro(set_search_path result)
+  set(${result} ${ARGN})
+  if (UNIX)
+    string(REPLACE ";" ":" ${result} "${${result}}") # native search path separators.
+  endif()
+  file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
+endmacro()
+
 add_subdirectory(proton-c)
 add_subdirectory(examples)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 8a8327a..160647d 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -20,15 +20,6 @@
 set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set (ProtonCpp_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
-# Set result to a native search path
-macro(set_search_path result)  # args after result are directories or search paths.
-  set(${result} ${ARGN})
-  if (UNIX)
-    string(REPLACE ";" ":" ${result} "${${result}}") # native search path separators.
-  endif()
-  file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
-endmacro()
-
 # Add the tools directory for the 'proctest' module
 set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_SOURCE_DIR}/tools/py" "$ENV{PYTHON_PATH}")
 set(EXAMPLE_ENV "PYTHONPATH=${EXAMPLE_PYTHONPATH}")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index d9285db..e0d9672 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -251,9 +251,7 @@ static void check_condition(pn_event_t *e, pn_condition_t *cond) {
   if (pn_condition_is_set(cond)) {
     fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)),
             pn_condition_get_name(cond), pn_condition_get_description(cond));
-    pn_connection_t *c = pn_event_connection(e);
-    if (c) pn_connection_close(c); /* It might be a listener event */
-    exit_code = 1;
+    exit_code = 1;              /* Remeber there was an unexpected error */
   }
 }
 
@@ -282,6 +280,7 @@ static void handle(broker_t* b, pn_event_t* e) {
      pn_transport_t *t = pn_connection_transport(c);
      pn_transport_require_auth(t, false);
      pn_sasl_allowed_mechs(pn_sasl(t), "ANONYMOUS");
+     break;
    }
    case PN_CONNECTION_REMOTE_OPEN: {
      pn_connection_open(pn_event_connection(e)); /* Complete the open */
@@ -337,13 +336,12 @@ static void handle(broker_t* b, pn_event_t* e) {
    }
 
    case PN_TRANSPORT_CLOSED:
-    connection_unsub(b, pn_event_connection(e));
     check_condition(e, pn_transport_condition(pn_event_transport(e)));
+    connection_unsub(b, pn_event_connection(e));
     break;
 
    case PN_CONNECTION_REMOTE_CLOSE:
     check_condition(e, pn_connection_remote_condition(pn_event_connection(e)));
-    connection_unsub(b, pn_event_connection(e));
     pn_connection_close(pn_event_connection(e));
     break;
 
@@ -405,7 +403,7 @@ int main(int argc, char **argv) {
   const char *host = (argc > i) ? argv[i++] : "";
   const char *port = (argc > i) ? argv[i++] : "amqp";
 
-  /* Listenf on addr */
+  /* Listen on addr */
   char addr[PN_MAX_ADDR];
   pn_proactor_addr(addr, sizeof(addr), host, port);
   pn_proactor_listen(b.proactor, pn_listener(), addr, 16);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 1e28a23..06e9c5f 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -346,7 +346,6 @@ typedef enum {
    * Events of this type point to the @ref pn_listener_t.
    */
   PN_LISTENER_OPEN
-
 } pn_event_type_t;
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index a0f6519..1f10ca0 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -391,6 +391,9 @@ struct pn_proactor_t {
   pcontext_t *wake_list_last;
   // Interrupts have a dedicated eventfd because they must be async-signal safe.
   int interruptfd;
+  // If the process runs out of file descriptors, disarm listeners temporarily and save them here.
+  pn_listener_t *overflow;
+  pmutex overflow_mutex;
 };
 
 static void rearm(pn_proactor_t *p, epoll_extended_t *ee);
@@ -528,6 +531,7 @@ struct pn_listener_t {
   psocket_t *acceptable, *accepted;
   bool close_dispatched;
   bool armed;
+  pn_listener_t *overflow;       /* Next overflowed listener */
 };
 
 
@@ -623,6 +627,48 @@ static void rearm(pn_proactor_t *p, epoll_extended_t *ee) {
     EPOLL_FATAL("arming polled file descriptor", errno);
 }
 
+// Add an overflowing listener to the overflow list. Called with listener context lock held.
+static void listener_set_overflow(pn_listener_t *l) {
+  pn_proactor_t *p = l->psockets[0].proactor;
+  lock(&p->overflow_mutex);
+  l->overflow = p->overflow;
+  p->overflow = l;
+  unlock(&p->overflow_mutex);
+}
+
+static const int dummy__ = 0;
+static pn_listener_t * const NO_OVERFLOW = (pn_listener_t*)&dummy__; /* Bogus pointer */
+
+/* TODO aconway 2017-06-08: we should also call proactor_rearm_overflow after a fixed delay,
+   even if the proactor has not freed any file descriptors, since other parts of the process
+   might have*/
+
+// Activate overflowing listeners, called when there may be available file descriptors.
+static void proactor_rearm_overflow(pn_proactor_t *p) {
+  lock(&p->overflow_mutex);
+  pn_listener_t *l = p->overflow;
+  p->overflow = NULL;
+  unlock(&p->overflow_mutex);
+  while (l) {
+    lock(&l->context.mutex);
+    rearm(l->accepted->proactor, &l->accepted->epoll_io);
+    l->armed = true;
+    l->accepted = NULL;
+    pn_listener_t *next = l->overflow;
+    l->overflow = NO_OVERFLOW;
+    unlock(&l->context.mutex);
+    l = next;
+  }
+}
+
+// Close an FD and rearm overflow listeners
+static int pclosefd(pn_proactor_t *p, int fd) {
+  int err = close(fd);
+  if (!err) proactor_rearm_overflow(p);
+  return err;
+}
+
+
 // ========================================================================
 // pconnection
 // ========================================================================
@@ -639,10 +685,8 @@ static void pconnection_finalize(void *vp_pconnection) {
   pcontext_finalize(&pc->context);
 }
 
-
 static const pn_class_t pconnection_class = PN_CLASS(pconnection);
 
-
 static void pconnection_tick(pconnection_t *pc);
 
 static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bool server, const char *addr)
@@ -652,10 +696,6 @@ static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bo
   if (pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
     return NULL;
   }
-  if (!ptimer_init(&pc->timer, &pc->psocket)) {
-    perror("timer setup failure");
-    abort();
-  }
   pcontext_init(&pc->context, PCONNECTION, p, pc);
   psocket_init(&pc->psocket, p, NULL, addr);
   pc->new_events = 0;
@@ -679,6 +719,12 @@ static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bo
   pn_record_t *r = pn_connection_attachments(pc->driver.connection);
   pn_record_def(r, PN_PROACTOR, &pconnection_class);
   pn_record_set(r, PN_PROACTOR, pc);
+
+  if (!ptimer_init(&pc->timer, &pc->psocket)) {
+    psocket_error(&pc->psocket, errno, "timer setup");
+    pc->disconnected = true;    /* Already failed */
+  }
+
   pn_decref(pc);                /* Will be deleted when the connection is */
   return pc;
 }
@@ -704,7 +750,7 @@ static void pconnection_final_free(pconnection_t *pc) {
 static void pconnection_cleanup(pconnection_t *pc) {
   stop_polling(&pc->psocket.epoll_io, pc->psocket.proactor->epollfd);
   if (pc->psocket.sockfd != -1)
-    close(pc->psocket.sockfd);
+    pclosefd(pc->psocket.proactor, pc->psocket.sockfd);
   stop_polling(&pc->timer.epoll_io, pc->psocket.proactor->epollfd);
   ptimer_finalize(&pc->timer);
   lock(&pc->context.mutex);
@@ -753,8 +799,9 @@ static pn_event_t *pconnection_batch_next(pn_event_batch_t *batch) {
   pconnection_t *pc = batch_pconnection(batch);
   pn_event_t *e = pn_connection_driver_next_event(&pc->driver);
   if (!e && pc->hog_count < HOG_MAX) {
-    pconnection_process(pc, 0, false, true);  // top up
-    e = pn_connection_driver_next_event(&pc->driver);
+    if (pconnection_process(pc, 0, false, true)) {
+      e = pn_connection_driver_next_event(&pc->driver);
+    }
   }
   return e;
 }
@@ -776,7 +823,7 @@ static inline bool pconnection_wclosed(pconnection_t  *pc) {
    rearm(EPOLLHUP | EPOLLERR | EPOLLONESHOT) and leaves doubt that the
    EPOLL_CTL_DEL can prevent a parallel HUP/ERR error notification during
    close/shutdown.  Let read()/write() return 0 or -1 to trigger cleanup logic.
- */
+*/
 static bool pconnection_rearm_check(pconnection_t *pc) {
   if (pconnection_rclosed(pc) && pconnection_wclosed(pc)) {
     return false;
@@ -945,9 +992,9 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
       else
         pconnection_connected_lh(pc); /* Non error event means we are connected */
       if (pc->new_events & EPOLLOUT)
-          pc->write_blocked = false;
+        pc->write_blocked = false;
       if (pc->new_events & EPOLLIN)
-          pc->read_blocked = false;
+        pc->read_blocked = false;
     }
     pc->current_arm = 0;
     pc->new_events = 0;
@@ -1153,14 +1200,20 @@ void pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *addr)
   pn_connection_open(pc->driver.connection); /* Auto-open */
 
   bool notify = false;
-  int gai_error = pgetaddrinfo(pc->psocket.host, pc->psocket.port, 0, &pc->addrinfo);
-  if (!gai_error) {
-    pc->ai = pc->addrinfo;
-    pconnection_maybe_connect_lh(pc); /* Start connection attempts */
-    notify = pc->disconnected;
+
+  if (pc->disconnected) {
+    notify = wake(&pc->context);    /* Error during initialization */
   } else {
-    psocket_gai_error(&pc->psocket, gai_error, "connect to ");
-    notify = wake(&pc->context);
+    int gai_error = pgetaddrinfo(pc->psocket.host, pc->psocket.port, 0, &pc->addrinfo);
+    if (!gai_error) {
+      pn_connection_open(pc->driver.connection); /* Auto-open */
+      pc->ai = pc->addrinfo;
+      pconnection_maybe_connect_lh(pc); /* Start connection attempts */
+      notify = pc->disconnected;
+    } else {
+      psocket_gai_error(&pc->psocket, gai_error, "connect to ");
+      notify = wake(&pc->context);
+    }
   }
   unlock(&pc->context.mutex);
   if (notify) wake_notify(&pc->context);
@@ -1236,6 +1289,7 @@ void pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *addr, in
   lock(&l->context.mutex);
   l->context.proactor = p;;
   l->backlog = backlog;
+  l->overflow = NO_OVERFLOW;
 
   char addr_buf[PN_MAX_ADDR];
   const char *host, *port;
@@ -1336,7 +1390,7 @@ static void listener_begin_close(pn_listener_t* l) {
       psocket_t *ps = &l->psockets[i];
       if (ps->sockfd >= 0) {
         stop_polling(&ps->epoll_io, ps->proactor->epollfd);
-        close(ps->sockfd);
+        pclosefd(l->psockets[0].proactor, ps->sockfd);
       }
     }
     pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
@@ -1415,17 +1469,15 @@ static void listener_done(pn_listener_t *l) {
       pn_listener_free(l);
       return;
     }
-  } else {
-    if (listener_has_event(l))
-      notify = wake(&l->context);
-    else {
-      /* Don't rearm until the current socket is accepted */
-      if (!l->context.closing && !l->armed && !l->acceptable && l->accepted) {
-        rearm(l->accepted->proactor, &l->accepted->epoll_io);
-        l->armed = true;
-        l->accepted = NULL;
-      }
-    }
+  } else if (listener_has_event(l)) {
+    notify = wake(&l->context);
+  } else if (l->overflow == NO_OVERFLOW &&
+             !l->context.closing && !l->armed && !l->acceptable && l->accepted)
+  {
+    /* Don't rearm until the current socket is accepted */
+    rearm(l->accepted->proactor, &l->accepted->epoll_io);
+    l->armed = true;
+    l->accepted = NULL;
   }
   unlock(&l->context.mutex);
   if (notify) wake_notify(&l->context);
@@ -1456,37 +1508,41 @@ void pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
   pconnection_t *pc = new_pconnection_t(l->psockets[0].proactor, c, true, "");
   assert(pc);  // TODO: memory safety
   int err = 0;
+  int newfd = -1;
+  bool need_done = false;
 
   lock(&l->context.mutex);
   proactor_add(&pc->context);
-  if (l->context.closing)
+  if (l->context.closing) {
     err = EBADF;
-  else if (l->acceptable == 0) {
-      err = EAGAIN;
+  } else if (l->acceptable == 0) {
+    err = EAGAIN;
+  } else {
+    l->accepted = l->acceptable;
+    l->acceptable = 0;
+    newfd = accept(l->accepted->sockfd, NULL, 0);
+    if (newfd < 0) err = errno;
   }
-
   if (err) {
-    psocket_error(&l->psockets[0], errno, "listener accepting from");
-    unlock(&l->context.mutex);
-    return;
-  }
-  psocket_t *ps = l->accepted = l->acceptable;
-  l->acceptable = 0;
-
-  int newfd = accept(ps->sockfd, NULL, 0);
-  if (newfd < 0) {
-    err = errno;
-    psocket_error(&pc->psocket, err, "accepting from");
-    psocket_error(ps, err, "accepting from");
-  } else {
+    lock(&pc->context.mutex);
+    psocket_error(&pc->psocket, err, "accepting from"); /* Always signal error on the connection */
+    pconnection_begin_close(pc);
+    need_done = true;
+    unlock(&pc->context.mutex);
+    if (err == EMFILE || err == ENFILE) { /* Out of FDs does not close the listener */
+      listener_set_overflow(l);
+    } else {
+      psocket_error(l->accepted, err, "accepting from");
+    }
+  } else {                      /* No errors */
     lock(&pc->context.mutex);
     configure_socket(newfd);
     pc->psocket.sockfd = newfd;
     pconnection_start(pc);
     unlock(&pc->context.mutex);
   }
-
   unlock(&l->context.mutex);
+  if (need_done) pconnection_done(pc);
 }
 
 
@@ -1964,7 +2020,7 @@ int pn_netaddr_str(const pn_netaddr_t* na, char *buf, size_t len) {
 }
 
 pn_millis_t pn_proactor_now(void) {
-    struct timespec t;
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    return t.tv_sec*1000 + t.tv_nsec/1000000;
+  struct timespec t;
+  clock_gettime(CLOCK_MONOTONIC, &t);
+  return t.tv_sec*1000 + t.tv_nsec/1000000;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/proton-c/src/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/CMakeLists.txt b/proton-c/src/tests/CMakeLists.txt
index 14f353f..f2edef9 100644
--- a/proton-c/src/tests/CMakeLists.txt
+++ b/proton-c/src/tests/CMakeLists.txt
@@ -53,6 +53,18 @@ 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)
+
 if(HAS_PROACTOR)
   pn_add_c_test (c-proactor-tests proactor.c)
+
+  if(WIN32)
+    set(path "$<TARGET_FILE_DIR:proactor-broker>;$<TARGET_FILE_DIR:qpid-proton>")
+  else(WIN32)
+    set(path "${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/examples/c/proactor:$ENV{PATH}")
+  endif(WIN32)
+  # Add the tools directory for the 'proctest' module
+  set_search_path(pypath "${CMAKE_SOURCE_DIR}/tools/py" "$ENV{PYTHON_PATH}")
+
+  add_test(NAME c-fdlimit-tests COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/fdlimit.py)
+  set_tests_properties(c-fdlimit-tests PROPERTIES ENVIRONMENT "PATH=${path};PYTHONPATH=${pypath}")
 endif(HAS_PROACTOR)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/087b94fa/proton-c/src/tests/fdlimit.py
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/fdlimit.py b/proton-c/src/tests/fdlimit.py
new file mode 100644
index 0000000..28fdecf
--- /dev/null
+++ b/proton-c/src/tests/fdlimit.py
@@ -0,0 +1,85 @@
+#
+# 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
+#
+
+from proctest import *
+
+class LimitedBroker(object):
+    def __init__(self, test, fdlimit):
+        self.test = test
+        self.fdlimit = fdlimit
+
+    def __enter__(self):
+        with TestPort() as tp:
+            self.port = str(tp.port)
+            self.proc = self.test.proc(['prlimit', '-n%d' % self.fdlimit, 'broker', '', self.port],
+                                       skip_valgrind=True)
+            self.proc.wait_re("listening")
+            return self
+
+    def __exit__(self, *args):
+        b = getattr(self, "proc")
+        if b:
+            if b.poll() !=  None: # Broker crashed
+                raise ProcError(b, "broker crash")
+            b.kill()
+
+# Check if we can run prlimit to control resources
+try:
+    Proc(["prlimit"]).wait_exit()
+    has_prlimit = True
+except:
+    has_prlimit = False
+
+class FdLimitTest(ProcTestCase):
+
+    def setUp(self):
+        global has_prlimit
+        if not has_prlimit:
+            self.skipTest("prlimit not available")
+        super(FdLimitTest, self).setUp()
+
+    def test_fd_limit_broker(self):
+        """Check behaviour when running out of file descriptors on accept"""
+        # Not too many FDs but not too few either, some are used for system purposes.
+        fdlimit = 256
+        with LimitedBroker(self, fdlimit) as b:
+            receivers = []
+            # Start enough receivers to use all FDs, make sure the broker logs an error
+            for i in xrange(fdlimit+1):
+                receivers.append(self.proc(["receive", "", b.port, str(i)]))
+
+            # Note: libuv silently swallows EMFILE/ENFILE errors so there is no error reporting.
+            # The epoll proactor will close the users connection with the EMFILE/ENFILE error
+            if "TRANSPORT_CLOSED" in b.proc.out:
+                self.assertIn("open files", b.proc.out)
+
+            # All FDs are now in use, send attempt should fail or hang
+            self.assertIn(self.proc(["send", "", b.port, "x"]).poll(), [1, None])
+
+            # Kill receivers to free up FDs
+            for r in receivers:
+                r.kill()
+            for r in receivers:
+                r.wait_exit(expect=None)
+            # send/receive should succeed now
+            self.assertIn("10 messages sent", self.proc(["send", "", b.port]).wait_exit())
+            self.assertIn("10 messages received", self.proc(["receive", "", b.port]).wait_exit())
+
+if __name__ == "__main__":
+    main()


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


[48/50] [abbrv] qpid-proton git commit: PROTON-1450: go electron filter support

Posted by ac...@apache.org.
PROTON-1450: go electron filter support

electron.Filter() creates LinkOption to set filter, LinkSettings.Filter() gets filter.
proton.Data.Marshal()/Unmarshal() allow setting/getting proton.Data content.


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

Branch: refs/heads/go1
Commit: c31e2ecf08fa3e5b46dc5c00a81049ec0d555196
Parents: 4cf899b
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jun 8 21:05:51 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 8 21:18:47 2017 -0400

----------------------------------------------------------------------
 .../go/src/qpid.apache.org/amqp/marshal.go      | 33 ++++++++-------
 .../go/src/qpid.apache.org/amqp/message.go      |  8 ----
 .../go/src/qpid.apache.org/amqp/unmarshal.go    |  7 ++++
 .../go/src/qpid.apache.org/electron/link.go     | 42 +++++++++++++++-----
 .../src/qpid.apache.org/electron/link_test.go   |  5 ++-
 .../go/src/qpid.apache.org/proton/wrappers.go   | 37 ++++++++++++-----
 6 files changed, 89 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c31e2ecf/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
index dad3d25..ca5e380 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
@@ -50,6 +50,16 @@ func dataMarshalError(v interface{}, data *C.pn_data_t) error {
 	return nil
 }
 
+func recoverMarshal(err *error) {
+	if r := recover(); r != nil {
+		if merr, ok := r.(*MarshalError); ok {
+			*err = merr
+		} else {
+			panic(r)
+		}
+	}
+}
+
 /*
 Marshal encodes a Go value as AMQP data in buffer.
 If buffer is nil, or is not large enough, a new buffer  is created.
@@ -99,16 +109,7 @@ Go types: struct, complex64/128.
 AMQP types: decimal32/64/128, char, timestamp, uuid, array.
 */
 func Marshal(v interface{}, buffer []byte) (outbuf []byte, err error) {
-	defer func() {
-		if r := recover(); r != nil {
-			if merr, ok := r.(*MarshalError); ok {
-				err = merr
-			} else {
-				panic(r)
-			}
-		}
-	}()
-
+	defer recoverMarshal(&err)
 	data := C.pn_data(0)
 	defer C.pn_data_free(data)
 	marshal(v, data)
@@ -126,6 +127,13 @@ func Marshal(v interface{}, buffer []byte) (outbuf []byte, err error) {
 	return encodeGrow(buffer, encode)
 }
 
+// Internal
+func MarshalUnsafe(v interface{}, pn_data unsafe.Pointer) (err error) {
+	defer recoverMarshal(&err)
+	marshal(v, (*C.pn_data_t)(pn_data))
+	return
+}
+
 const minEncode = 256
 
 // overflow is returned when an encoding function can't fit data in the buffer.
@@ -271,8 +279,3 @@ func (e *Encoder) Encode(v interface{}) (err error) {
 	}
 	return err
 }
-
-func replace(data *C.pn_data_t, v interface{}) {
-	C.pn_data_clear(data)
-	marshal(v, data)
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c31e2ecf/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
index f2270f0..d1ad2eb 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
@@ -38,7 +38,6 @@ import (
 	"fmt"
 	"runtime"
 	"time"
-	"unsafe"
 )
 
 // Message is the interface to an AMQP message.
@@ -275,13 +274,6 @@ func setData(v interface{}, data *C.pn_data_t) {
 	marshal(v, data)
 }
 
-func dataString(data *C.pn_data_t) string {
-	str := C.pn_string(C.CString(""))
-	defer C.pn_free(unsafe.Pointer(str))
-	C.pn_inspect(unsafe.Pointer(data), str)
-	return C.GoString(C.pn_string_get(str))
-}
-
 func (m *message) SetInferred(b bool)  { C.pn_message_set_inferred(m.pn, C.bool(b)) }
 func (m *message) SetDurable(b bool)   { C.pn_message_set_durable(m.pn, C.bool(b)) }
 func (m *message) SetPriority(b uint8) { C.pn_message_set_priority(m.pn, C.uint8_t(b)) }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c31e2ecf/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index f679abc..253d66d 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -223,6 +223,13 @@ func Unmarshal(bytes []byte, v interface{}) (n int, err error) {
 	return n, nil
 }
 
+// Internal
+func UnmarshalUnsafe(pn_data unsafe.Pointer, v interface{}) (err error) {
+	defer recoverUnmarshal(&err)
+	unmarshal(v, (*C.pn_data_t)(pn_data))
+	return
+}
+
 // more reads more data when we can't parse a complete AMQP type
 func (d *Decoder) more() error {
 	var readSize int64 = minDecode

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c31e2ecf/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 4f927c1..de8a995 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
@@ -21,6 +21,7 @@ package electron
 
 import (
 	"fmt"
+	"qpid.apache.org/amqp"
 	"qpid.apache.org/proton"
 	"time"
 )
@@ -52,6 +53,9 @@ type LinkSettings interface {
 	// Session containing the Link
 	Session() Session
 
+	// Filter for the link
+	Filter() map[amqp.Symbol]interface{}
+
 	// Advanced settings for the source
 	SourceSettings() TerminusSettings
 
@@ -116,6 +120,11 @@ func AtLeastOnce() LinkOption {
 	}
 }
 
+// Filter returns a LinkOption that sets a filter.
+func Filter(m map[amqp.Symbol]interface{}) LinkOption {
+	return func(l *linkSettings) { l.filter = m }
+}
+
 // 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 {
@@ -161,6 +170,7 @@ type linkSettings struct {
 	rcvSettle      RcvSettleMode
 	capacity       int
 	prefetch       bool
+	filter         map[amqp.Symbol]interface{}
 	session        *session
 	pLink          proton.Link
 }
@@ -189,15 +199,16 @@ 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) SourceSettings() TerminusSettings { return l.sourceSettings }
-func (l *linkSettings) TargetSettings() TerminusSettings { return l.targetSettings }
+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) Filter() map[amqp.Symbol]interface{} { return l.filter }
+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() }
@@ -227,6 +238,12 @@ 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)
+
+	if len(l.filter) > 0 {
+		if err := l.pLink.Source().Filter().Marshal(l.filter); err != nil {
+			panic(err) // Shouldn't happen
+		}
+	}
 	l.pLink.Source().SetDurability(l.sourceSettings.Durability)
 	l.pLink.Source().SetExpiryPolicy(l.sourceSettings.Expiry)
 	l.pLink.Source().SetTimeout(l.sourceSettings.Timeout)
@@ -245,7 +262,7 @@ func makeLocalLink(sn *session, isSender bool, setting ...LinkOption) (linkSetti
 }
 
 func makeIncomingLinkSettings(pLink proton.Link, sn *session) linkSettings {
-	return linkSettings{
+	l := linkSettings{
 		isSender:       pLink.IsSender(),
 		source:         pLink.RemoteSource().Address(),
 		sourceSettings: makeTerminusSettings(pLink.RemoteSource()),
@@ -259,6 +276,11 @@ func makeIncomingLinkSettings(pLink proton.Link, sn *session) linkSettings {
 		pLink:          pLink,
 		session:        sn,
 	}
+	filter := l.pLink.RemoteSource().Filter()
+	if !filter.Empty() {
+		filter.Unmarshal(&l.filter) // TODO aconway 2017-06-08: ignoring errors
+	}
+	return l
 }
 
 // Not part of Link interface but use by Sender and Receiver.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c31e2ecf/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 2576046..feb1f20 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
@@ -22,6 +22,7 @@ package electron
 
 import (
 	"net"
+	"qpid.apache.org/amqp"
 	"qpid.apache.org/proton"
 	"testing"
 	"time"
@@ -31,6 +32,7 @@ func TestLinkSettings(t *testing.T) {
 	cConn, sConn := net.Pipe()
 	done := make(chan error)
 	settings := TerminusSettings{Durability: 1, Expiry: 2, Timeout: 42 * time.Second, Dynamic: true}
+	filterMap := map[amqp.Symbol]interface{}{"int": int32(33), "str": "hello"}
 	go func() { // Server
 		close(done)
 		defer sConn.Close()
@@ -48,6 +50,7 @@ func TestLinkSettings(t *testing.T) {
 				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()))
+				errorIf(t, checkEqual(filterMap, ep.Filter()))
 			}
 		}
 	}()
@@ -57,7 +60,7 @@ func TestLinkSettings(t *testing.T) {
 	fatalIf(t, err)
 	c.Sender(Source("one.source"), Target("one.target"), TargetSettings(settings))
 
-	c.Receiver(Source("two.source"), DurableSubscription("two"))
+	c.Receiver(Source("two.source"), DurableSubscription("two"), Filter(filterMap))
 	c.Close(nil)
 	<-done
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c31e2ecf/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers.go b/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers.go
index b6386b8..879ad53 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/wrappers.go
@@ -114,18 +114,37 @@ func (e Event) String() string         { return e.Type().String() }
 // functions) to let them inject functions back into the handlers goroutine.
 func (e Event) Injecter() Injecter { return e.injecter }
 
-// Data holds a pointer to decoded AMQP data.
-// Use amqp.marshal/unmarshal to access it as Go data types.
-//
+// Data is an intermediate form of decoded AMQP data.
 type Data struct{ pn *C.pn_data_t }
 
-func NewData(p unsafe.Pointer) Data { return Data{(*C.pn_data_t)(p)} }
+func (d Data) Free()                { C.pn_data_free(d.pn) }
+func (d Data) CPtr() unsafe.Pointer { return unsafe.Pointer(d.pn) }
+func (d Data) Clear()               { C.pn_data_clear(d.pn) }
+func (d Data) Rewind()              { C.pn_data_rewind(d.pn) }
+func (d Data) Next()                { C.pn_data_next(d.pn) }
+func (d Data) Error() error         { return PnError(C.pn_data_error(d.pn)) }
+func (d Data) Empty() bool          { return C.pn_data_size(d.pn) == 0 }
+
+func (d Data) String() string {
+	str := C.pn_string(C.CString(""))
+	defer C.pn_free(unsafe.Pointer(str))
+	C.pn_inspect(unsafe.Pointer(d.pn), str)
+	return C.GoString(C.pn_string_get(str))
+}
+
+// Unmarshal the value of d into value pointed at by ptr, see amqp.Unmarshal() for details
+func (d Data) Unmarshal(ptr interface{}) error {
+	d.Rewind()
+	d.Next()
+	err := amqp.UnmarshalUnsafe(d.CPtr(), ptr)
+	return err
+}
 
-func (d Data) Free()                   { C.pn_data_free(d.pn) }
-func (d Data) Pointer() unsafe.Pointer { return unsafe.Pointer(d.pn) }
-func (d Data) Clear()                  { C.pn_data_clear(d.pn) }
-func (d Data) Rewind()                 { C.pn_data_rewind(d.pn) }
-func (d Data) Error() error            { return PnError(C.pn_data_error(d.pn)) }
+// Marshal the value v into d, see amqp.Marshal() for details
+func (d Data) Marshal(v interface{}) error {
+	d.Clear()
+	return amqp.MarshalUnsafe(v, d.CPtr())
+}
 
 // State holds the state flags for an AMQP endpoint.
 type State byte


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


[15/50] [abbrv] qpid-proton git commit: PROTON-1460: epoll lower HOGMAX for better performance

Posted by ac...@apache.org.
PROTON-1460: epoll lower HOGMAX for better performance


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

Branch: refs/heads/go1
Commit: adb17eb727ef914e03f7cb542a02b2a32a48afee
Parents: b0be770
Author: Clifford Jansen <cl...@apache.org>
Authored: Tue May 16 08:20:14 2017 -0700
Committer: Clifford Jansen <cl...@apache.org>
Committed: Tue May 16 08:20:14 2017 -0700

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/adb17eb7/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 9fd7d06..d79f0da 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -210,10 +210,10 @@ const char *AMQP_PORT_NAME = "amqp";
 PN_HANDLE(PN_PROACTOR)
 
 // The number of times a connection event batch may be replenished for
-// a thread between calls to wait().
-// TODO: consider some instrumentation to determine an optimal number
-// or perhaps switch to cpu time based limit.
-#define HOG_MAX 3
+// a thread between calls to wait().  Some testing shows that
+// increasing this value above 1 actually slows performance slightly
+// and increases latency.
+#define HOG_MAX 1
 
 /* 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.


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


[37/50] [abbrv] qpid-proton git commit: PROTON-1493: c epoll proactor fix bug in interrupt

Posted by ac...@apache.org.
PROTON-1493: c epoll proactor fix bug in interrupt

Missing rearm of interrupt file descriptor.


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

Branch: refs/heads/go1
Commit: 54645b79372d60b51462ce832c5213e8dcb9d86c
Parents: 4f724ac
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jun 2 14:09:04 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Jun 2 14:12:08 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/54645b79/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index b258da3..3e5327e 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -1674,6 +1674,7 @@ static bool proactor_remove(pcontext_t *ctx) {
 
 static pn_event_batch_t *process_inbound_wake(pn_proactor_t *p, epoll_extended_t *ee) {
   if  (ee->fd == p->interruptfd) {        /* Interrupts have their own dedicated eventfd */
+    rearm(p, &p->epoll_interrupt);
     return proactor_process(p, PN_PROACTOR_INTERRUPT);
   }
   pcontext_t *ctx = wake_pop_front(p);


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


[06/50] [abbrv] qpid-proton git commit: PROTON-1466: proton-c mixing up links with names that are prefixes

Posted by ac...@apache.org.
PROTON-1466: proton-c mixing up links with names that are prefixes

Creating links where one link name is a prefix of the other, e.g. "xx" and
"xxyy" sometimes caused the links to be confused.


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

Branch: refs/heads/go1
Commit: ea875055e446da8514b10e3b6af0942997544af0
Parents: 19f345a
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 10 16:30:14 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 10 16:51:54 2017 -0400

----------------------------------------------------------------------
 proton-c/src/core/codec.c     |  2 +-
 proton-c/src/core/transport.c | 14 +++++-----
 proton-c/src/core/util.h      | 11 ++++++++
 proton-c/src/extra/scanner.c  |  8 +++---
 proton-c/src/tests/engine.c   | 55 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 79 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ea875055/proton-c/src/core/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/codec.c b/proton-c/src/core/codec.c
index 67769ad..7809907 100644
--- a/proton-c/src/core/codec.c
+++ b/proton-c/src/core/codec.c
@@ -1328,7 +1328,7 @@ bool pn_data_lookup(pn_data_t *data, const char *name)
     case PN_SYMBOL:
       {
         pn_bytes_t bytes = pn_data_get_bytes(data);
-        if (strlen(name) == bytes.size && !strncmp(name, bytes.start, bytes.size)) {
+        if (pn_bytes_equal(bytes, pn_bytes(strlen(name), name))) {
           return pn_data_next(data);
         }
       }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ea875055/proton-c/src/core/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/transport.c b/proton-c/src/core/transport.c
index 8777318..f9eea7b 100644
--- a/proton-c/src/core/transport.c
+++ b/proton-c/src/core/transport.c
@@ -1277,7 +1277,7 @@ pn_link_t *pn_find_link(pn_session_t *ssn, pn_bytes_t name, bool is_sender)
         // which is closed both locally and remotely, assume that is
         // no longer in use.
         !((link->endpoint.state & PN_LOCAL_CLOSED) && (link->endpoint.state & PN_REMOTE_CLOSED)) &&
-        !strncmp(name.start, pn_string_get(link->name), name.size))
+        pn_bytes_equal(name, pn_string_bytes(link->name)))
     {
       return link;
     }
@@ -1290,13 +1290,13 @@ static pn_expiry_policy_t symbol2policy(pn_bytes_t symbol)
   if (!symbol.start)
     return PN_EXPIRE_WITH_SESSION;
 
-  if (!strncmp(symbol.start, "link-detach", symbol.size))
+  if (pn_bytes_equal(symbol, PN_BYTES_LITERAL(link-detach)))
     return PN_EXPIRE_WITH_LINK;
-  if (!strncmp(symbol.start, "session-end", symbol.size))
+  if (pn_bytes_equal(symbol, PN_BYTES_LITERAL(session-end)))
     return PN_EXPIRE_WITH_SESSION;
-  if (!strncmp(symbol.start, "connection-close", symbol.size))
+  if (pn_bytes_equal(symbol, PN_BYTES_LITERAL(connection-close)))
     return PN_EXPIRE_WITH_CONNECTION;
-  if (!strncmp(symbol.start, "never", symbol.size))
+  if (pn_bytes_equal(symbol, PN_BYTES_LITERAL(never)))
     return PN_EXPIRE_NEVER;
 
   return PN_EXPIRE_WITH_SESSION;
@@ -1307,9 +1307,9 @@ static pn_distribution_mode_t symbol2dist_mode(const pn_bytes_t symbol)
   if (!symbol.start)
     return PN_DIST_MODE_UNSPECIFIED;
 
-  if (!strncmp(symbol.start, "move", symbol.size))
+  if (pn_bytes_equal(symbol, PN_BYTES_LITERAL(move)))
     return PN_DIST_MODE_MOVE;
-  if (!strncmp(symbol.start, "copy", symbol.size))
+  if (pn_bytes_equal(symbol, PN_BYTES_LITERAL(copy)))
     return PN_DIST_MODE_COPY;
 
   return PN_DIST_MODE_UNSPECIFIED;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ea875055/proton-c/src/core/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.h b/proton-c/src/core/util.h
index b54f689..4d3ba3b 100644
--- a/proton-c/src/core/util.h
+++ b/proton-c/src/core/util.h
@@ -44,6 +44,17 @@ char *pn_strndup(const char *src, size_t n);
 int pn_strcasecmp(const char* a, const char* b);
 int pn_strncasecmp(const char* a, const char* b, size_t len);
 
+static inline bool pn_bytes_equal(const pn_bytes_t a, const pn_bytes_t b) {
+  return (a.size == b.size && !memcmp(a.start, b.start, a.size));
+}
+
+static inline pn_bytes_t pn_string_bytes(pn_string_t *s) {
+  return pn_bytes(pn_string_size(s), pn_string_get(s));
+}
+
+/* Create a literal bytes value, e.g. PN_BYTES_LITERAL(foo) == pn_bytes(3, "foo") */
+#define PN_BYTES_LITERAL(X) (pn_bytes(sizeof(#X)-1, #X))
+
 #define DIE_IFR(EXPR, STRERR)                                           \
   do {                                                                  \
     int __code__ = (EXPR);                                              \

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ea875055/proton-c/src/extra/scanner.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/scanner.c b/proton-c/src/extra/scanner.c
index beb7322..99c35d2 100644
--- a/proton-c/src/extra/scanner.c
+++ b/proton-c/src/extra/scanner.c
@@ -20,6 +20,7 @@
  */
 
 #include "scanner.h"
+#include "../core/util.h"
 
 #include "platform/platform.h"
 
@@ -217,12 +218,13 @@ static int pni_scanner_alpha_end(pn_scanner_t *scanner, const char *str, int sta
 static int pni_scanner_alpha(pn_scanner_t *scanner, const char *str)
 {
   int n = pni_scanner_alpha_end(scanner, str, 0);
+  pn_bytes_t b = pn_bytes(n, str);
   pn_token_type_t type;
-  if (!strncmp(str, "true", n)) {
+  if (pn_bytes_equal(b, PN_BYTES_LITERAL(true))) {
     type = PN_TOK_TRUE;
-  } else if (!strncmp(str, "false", n)) {
+  } else if (pn_bytes_equal(b, PN_BYTES_LITERAL(false))) {
     type = PN_TOK_FALSE;
-  } else if (!strncmp(str, "null", n)) {
+  } else if (pn_bytes_equal(b, PN_BYTES_LITERAL(null))) {
     type = PN_TOK_NULL;
   } else {
     type = PN_TOK_ID;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ea875055/proton-c/src/tests/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/engine.c b/proton-c/src/tests/engine.c
index 87d8d95..41d17a0 100644
--- a/proton-c/src/tests/engine.c
+++ b/proton-c/src/tests/engine.c
@@ -294,12 +294,67 @@ int test_free_link(int argc, char **argv)
     return 0;
 }
 
+// regression test fo PROTON-1466 - confusion between links with prefix names
+static int test_link_name_prefix(int argc, char **argv)
+{
+    fprintf(stdout, "test_link_name_prefix\n");
+    pn_connection_t *c1 = pn_connection();
+    pn_transport_t  *t1 = pn_transport();
+    pn_transport_bind(t1, c1);
+
+    pn_connection_t *c2 = pn_connection();
+    pn_transport_t  *t2 = pn_transport();
+    pn_transport_set_server(t2);
+    pn_transport_bind(t2, c2);
+
+    pn_connection_open(c1);
+    pn_connection_open(c2);
+
+    pn_session_t *s1 = pn_session(c1);
+    pn_session_open(s1);
+
+    pn_link_t *l = pn_receiver(s1, "l");
+    pn_link_open(l);
+    pn_link_t *lll = pn_receiver(s1, "lll");
+    pn_link_open(lll);
+    pn_link_t *ll = pn_receiver(s1, "ll");
+    pn_link_open(ll);
+
+    while (pump(t1, t2)) {
+        process_endpoints(c1);
+        process_endpoints(c2);
+    }
+
+    // session and link should be up, c2 should have a receiver link:
+    assert(pn_session_state( s1 ) == (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+    assert(pn_link_state( l ) == (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+    assert(pn_link_state( lll ) == (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+    assert(pn_link_state( ll ) == (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+
+    pn_link_t *r = pn_link_head(c2, (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+    assert(!strcmp(pn_link_name(r), "l"));
+    r = pn_link_next(r, (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+    assert(!strcmp(pn_link_name(r), "lll"));
+    r = pn_link_next(r, (PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE));
+    assert(!strcmp(pn_link_name(r), "ll"));
+
+    pn_transport_unbind(t1);
+    pn_transport_free(t1);
+    pn_connection_free(c1);
+
+    pn_transport_unbind(t2);
+    pn_transport_free(t2);
+    pn_connection_free(c2);
+
+    return 0;
+}
 
 typedef int (*test_ptr_t)(int argc, char **argv);
 
 test_ptr_t tests[] = {test_free_connection,
                       test_free_session,
                       test_free_link,
+                      test_link_name_prefix,
                       NULL};
 
 int main(int argc, char **argv)


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


[32/50] [abbrv] qpid-proton git commit: PROTON-1491: epoll proactor - remove spurrious IO rearm on close

Posted by ac...@apache.org.
PROTON-1491: epoll proactor - remove spurrious IO rearm on close


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

Branch: refs/heads/go1
Commit: 4edd7fe17430ea39bb388a0f085a19ea68619238
Parents: f669380
Author: Clifford Jansen <cl...@apache.org>
Authored: Fri May 26 13:15:12 2017 -0700
Committer: Clifford Jansen <cl...@apache.org>
Committed: Fri May 26 13:15:12 2017 -0700

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4edd7fe1/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index c65fa44..7490ecd 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -700,12 +700,7 @@ static void pconnection_begin_close(pconnection_t *pc) {
   if (!pc->context.closing) {
     pc->context.closing = true;
     if (pc->current_arm != 0 && !pc->new_events) {
-      // Force io callback via hangup
-      if (pc->current_arm != (EPOLLIN | EPOLLOUT)) {
-        pc->current_arm = (EPOLLIN | EPOLLOUT);
-        pc->psocket.epoll_io.wanted = pc->current_arm;;
-        rearm(pc->psocket.proactor, &pc->psocket.epoll_io);
-      }
+      // Force io callback via an EPOLLHUP
       shutdown(pc->psocket.sockfd, SHUT_RDWR);
     }
 


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


[50/50] [abbrv] qpid-proton git commit: Merge branch 'master' into go1

Posted by ac...@apache.org.
Merge branch 'master' into go1

Filter and described type support


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

Branch: refs/heads/go1
Commit: 847a83cc632bf4b69c6d1a57716aac1912d7b1c5
Parents: 569b4fc c31e2ec
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jun 8 21:24:27 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 8 21:24:27 2017 -0400

----------------------------------------------------------------------
 amqp/interop_test.go  |   8 --
 amqp/marshal.go       |  54 ++++++++-----
 amqp/marshal_test.go  |  90 +++++++++++++++++++++
 amqp/message.go       | 120 +++++++++++++++++++--------
 amqp/message_test.go  |  47 +++++++++--
 amqp/types.go         |  29 ++++++-
 amqp/types_test.go    | 197 +++++++++++++++++++++++++++++++++++++++++++++
 amqp/unmarshal.go     | 197 ++++++++++++++++++++++++++++++---------------
 electron/link.go      |  42 +++++++---
 electron/link_test.go |   6 +-
 proton/wrappers.go    |  37 ++++++---
 11 files changed, 673 insertions(+), 154 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/interop_test.go
----------------------------------------------------------------------
diff --cc amqp/interop_test.go
index b3e27bc,0000000..a5fb92e
mode 100644,000000..100644
--- a/amqp/interop_test.go
+++ b/amqp/interop_test.go
@@@ -1,385 -1,0 +1,377 @@@
 +/*
 +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 conversion of Go type to/from AMQP is compatible with other
 +// bindings.
 +//
 +package amqp
 +
 +import (
 +	"bytes"
- 	"fmt"
 +	"io"
 +	"io/ioutil"
 +	"os"
 +	"reflect"
 +	"strings"
 +	"testing"
 +)
 +
- func checkEqual(want interface{}, got interface{}) error {
- 	if !reflect.DeepEqual(want, got) {
- 		return fmt.Errorf("%#v != %#v", want, got)
- 	}
- 	return nil
- }
- 
 +func getReader(t *testing.T, name string) (r io.Reader) {
 +	dir := os.Getenv("PN_INTEROP_DIR")
 +	if dir == "" {
 +		t.Skip("no PN_INTEROP_DIR in environment")
 +	}
 +	r, err := os.Open(dir + "/" + name + ".amqp")
 +	if err != nil {
 +		t.Fatalf("can't open %#v: %v", name, err)
 +	}
 +	return
 +}
 +
 +func remaining(d *Decoder) string {
 +	remainder, _ := ioutil.ReadAll(io.MultiReader(d.Buffered(), d.reader))
 +	return string(remainder)
 +}
 +
 +// checkDecode: want is the expected value, gotPtr is a pointer to a
 +// instance of the same type for Decode.
 +func checkDecode(d *Decoder, want interface{}, gotPtr interface{}, t *testing.T) {
 +
 +	if err := d.Decode(gotPtr); err != nil {
 +		t.Error("Decode failed", err)
 +		return
 +	}
 +	got := reflect.ValueOf(gotPtr).Elem().Interface()
 +	if err := checkEqual(want, got); err != nil {
 +		t.Error("Decode bad value:", err)
 +		return
 +	}
 +
 +	// Try round trip encoding
 +	bytes, err := Marshal(want, nil)
 +	if err != nil {
 +		t.Error("Marshal failed", err)
 +		return
 +	}
 +	n, err := Unmarshal(bytes, gotPtr)
 +	if err != nil {
 +		t.Error("Unmarshal failed", err)
 +		return
 +	}
 +	if err := checkEqual(n, len(bytes)); err != nil {
 +		t.Error("Bad unmarshal length", err)
 +		return
 +	}
 +	got = reflect.ValueOf(gotPtr).Elem().Interface()
 +	if err = checkEqual(want, got); err != nil {
 +		t.Error("Bad unmarshal value", err)
 +		return
 +	}
 +}
 +
 +func TestUnmarshal(t *testing.T) {
 +	bytes, err := ioutil.ReadAll(getReader(t, "strings"))
 +	if err != nil {
 +		t.Error(err)
 +	}
 +	for _, want := range []string{"abc\000defg", "abcdefg", "abcdefg", "", "", ""} {
 +		var got string
 +		n, err := Unmarshal(bytes, &got)
 +		if err != nil {
 +			t.Error(err)
 +		}
 +		if want != got {
 +			t.Errorf("%#v != %#v", want, got)
 +		}
 +		bytes = bytes[n:]
 +	}
 +}
 +
 +func TestPrimitivesExact(t *testing.T) {
 +	d := NewDecoder(getReader(t, "primitives"))
 +	// Decoding into exact types
 +	var b bool
 +	checkDecode(d, true, &b, t)
 +	checkDecode(d, false, &b, t)
 +	var u8 uint8
 +	checkDecode(d, uint8(42), &u8, t)
 +	var u16 uint16
 +	checkDecode(d, uint16(42), &u16, t)
 +	var i16 int16
 +	checkDecode(d, int16(-42), &i16, t)
 +	var u32 uint32
 +	checkDecode(d, uint32(12345), &u32, t)
 +	var i32 int32
 +	checkDecode(d, int32(-12345), &i32, t)
 +	var u64 uint64
 +	checkDecode(d, uint64(12345), &u64, t)
 +	var i64 int64
 +	checkDecode(d, int64(-12345), &i64, t)
 +	var f32 float32
 +	checkDecode(d, float32(0.125), &f32, t)
 +	var f64 float64
 +	checkDecode(d, float64(0.125), &f64, t)
 +}
 +
 +func TestPrimitivesCompatible(t *testing.T) {
 +	d := NewDecoder(getReader(t, "primitives"))
 +	// Decoding into compatible types
 +	var b bool
 +	var i int
 +	var u uint
 +	var f float64
 +	checkDecode(d, true, &b, t)
 +	checkDecode(d, false, &b, t)
 +	checkDecode(d, uint(42), &u, t)
 +	checkDecode(d, uint(42), &u, t)
 +	checkDecode(d, -42, &i, t)
 +	checkDecode(d, uint(12345), &u, t)
 +	checkDecode(d, -12345, &i, t)
 +	checkDecode(d, uint(12345), &u, t)
 +	checkDecode(d, -12345, &i, t)
 +	checkDecode(d, 0.125, &f, t)
 +	checkDecode(d, 0.125, &f, t)
 +}
 +
 +// checkDecodeValue: want is the expected value, decode into a reflect.Value
 +func checkDecodeInterface(d *Decoder, want interface{}, t *testing.T) {
 +
 +	var got, got2 interface{}
 +	if err := d.Decode(&got); err != nil {
 +		t.Error("Decode failed", err)
 +		return
 +	}
 +	if err := checkEqual(want, got); err != nil {
 +		t.Error(err)
 +		return
 +	}
 +	// Try round trip encoding
 +	bytes, err := Marshal(got, nil)
 +	if err != nil {
 +		t.Error(err)
 +		return
 +	}
 +	n, err := Unmarshal(bytes, &got2)
 +	if err != nil {
 +		t.Error(err)
 +		return
 +	}
 +	if err := checkEqual(n, len(bytes)); err != nil {
 +		t.Error(err)
 +		return
 +	}
 +	if err := checkEqual(want, got2); err != nil {
 +		t.Error(err)
 +		return
 +	}
 +}
 +
 +func TestPrimitivesInterface(t *testing.T) {
 +	d := NewDecoder(getReader(t, "primitives"))
 +	checkDecodeInterface(d, true, t)
 +	checkDecodeInterface(d, false, t)
 +	checkDecodeInterface(d, uint8(42), t)
 +	checkDecodeInterface(d, uint16(42), t)
 +	checkDecodeInterface(d, int16(-42), t)
 +	checkDecodeInterface(d, uint32(12345), t)
 +	checkDecodeInterface(d, int32(-12345), t)
 +	checkDecodeInterface(d, uint64(12345), t)
 +	checkDecodeInterface(d, int64(-12345), t)
 +	checkDecodeInterface(d, float32(0.125), t)
 +	checkDecodeInterface(d, float64(0.125), t)
 +}
 +
 +func TestStrings(t *testing.T) {
 +	d := NewDecoder(getReader(t, "strings"))
 +	// Test decoding as plain Go strings
 +	for _, want := range []string{"abc\000defg", "abcdefg", "abcdefg", "", "", ""} {
 +		var got string
 +		checkDecode(d, want, &got, t)
 +	}
 +	remains := remaining(d)
 +	if remains != "" {
 +		t.Errorf("leftover: %s", remains)
 +	}
 +
 +	// Test decoding as specific string types
 +	d = NewDecoder(getReader(t, "strings"))
 +	var bytes []byte
 +	var str, sym string
 +	checkDecode(d, []byte("abc\000defg"), &bytes, t)
 +	checkDecode(d, "abcdefg", &str, t)
 +	checkDecode(d, "abcdefg", &sym, t)
 +	checkDecode(d, make([]byte, 0), &bytes, t)
 +	checkDecode(d, "", &str, t)
 +	checkDecode(d, "", &sym, t)
 +	remains = remaining(d)
 +	if remains != "" {
 +		t.Fatalf("leftover: %s", remains)
 +	}
 +
 +	// Test some error handling
 +	d = NewDecoder(getReader(t, "strings"))
 +	var s string
 +	err := d.Decode(s)
 +	if err == nil {
 +		t.Fatal("Expected error")
 +	}
 +	if !strings.Contains(err.Error(), "not a pointer") {
 +		t.Error(err)
 +	}
 +	var i int
 +	err = d.Decode(&i)
 +	if !strings.Contains(err.Error(), "cannot unmarshal") {
 +		t.Error(err)
 +	}
 +	_, err = Unmarshal([]byte{}, nil)
 +	if !strings.Contains(err.Error(), "not enough data") {
 +		t.Error(err)
 +	}
 +	_, err = Unmarshal([]byte("foobar"), nil)
 +	if !strings.Contains(err.Error(), "invalid-argument") {
 +		t.Error(err)
 +	}
 +}
 +
 +func TestEncodeDecode(t *testing.T) {
 +	type data struct {
 +		s  string
 +		i  int
 +		u8 uint8
 +		b  bool
 +		f  float32
 +		v  interface{}
 +	}
 +
 +	in := data{"foo", 42, 9, true, 1.234, "thing"}
 +
 +	buf := bytes.Buffer{}
 +	e := NewEncoder(&buf)
 +	if err := e.Encode(in.s); err != nil {
 +		t.Error(err)
 +	}
 +	if err := e.Encode(in.i); err != nil {
 +		t.Error(err)
 +	}
 +	if err := e.Encode(in.u8); err != nil {
 +		t.Error(err)
 +	}
 +	if err := e.Encode(in.b); err != nil {
 +		t.Error(err)
 +	}
 +	if err := e.Encode(in.f); err != nil {
 +		t.Error(err)
 +	}
 +	if err := e.Encode(in.v); err != nil {
 +		t.Error(err)
 +	}
 +
 +	var out data
 +	d := NewDecoder(&buf)
 +	if err := d.Decode(&out.s); err != nil {
 +		t.Error(err)
 +	}
 +	if err := d.Decode(&out.i); err != nil {
 +		t.Error(err)
 +	}
 +	if err := d.Decode(&out.u8); err != nil {
 +		t.Error(err)
 +	}
 +	if err := d.Decode(&out.b); err != nil {
 +		t.Error(err)
 +	}
 +	if err := d.Decode(&out.f); err != nil {
 +		t.Error(err)
 +	}
 +	if err := d.Decode(&out.v); err != nil {
 +		t.Error(err)
 +	}
 +
 +	if err := checkEqual(in, out); err != nil {
 +		t.Error(err)
 +	}
 +}
 +
 +func TestMap(t *testing.T) {
 +	d := NewDecoder(getReader(t, "maps"))
 +
 +	// Generic map
 +	var m Map
 +	checkDecode(d, Map{"one": int32(1), "two": int32(2), "three": int32(3)}, &m, t)
 +
 +	// Interface as map
 +	var i interface{}
 +	checkDecode(d, Map{int32(1): "one", int32(2): "two", int32(3): "three"}, &i, t)
 +
 +	d = NewDecoder(getReader(t, "maps"))
 +	// Specific typed map
 +	var m2 map[string]int
 +	checkDecode(d, map[string]int{"one": 1, "two": 2, "three": 3}, &m2, t)
 +
 +	// Nested map
 +	m = Map{int64(1): "one", "two": int32(2), true: Map{uint8(1): true, uint8(2): false}}
 +	bytes, err := Marshal(m, nil)
 +	if err != nil {
 +		t.Fatal(err)
 +	}
 +	_, err = Unmarshal(bytes, &i)
 +	if err != nil {
 +		t.Fatal(err)
 +	}
 +	if err = checkEqual(m, i); err != nil {
 +		t.Fatal(err)
 +	}
 +}
 +
 +func TestList(t *testing.T) {
 +	d := NewDecoder(getReader(t, "lists"))
 +	var l List
 +	checkDecode(d, List{int32(32), "foo", true}, &l, t)
 +	checkDecode(d, List{}, &l, t)
 +}
 +
 +// TODO aconway 2015-09-08: the message.amqp file seems to be incorrectly coded as
 +// as an AMQP string *inside* an AMQP binary?? Skip the test for now.
 +func TODO_TestMessage(t *testing.T) {
 +	bytes, err := ioutil.ReadAll(getReader(t, "message"))
 +	if err != nil {
 +		t.Fatal(err)
 +	}
 +
 +	m, err := DecodeMessage(bytes)
 +	if err != nil {
 +		t.Fatal(err)
 +	} else {
 +		if err := checkEqual(m.Body(), "hello"); err != nil {
 +			t.Error(err)
 +		}
 +	}
 +
 +	m2 := NewMessageWith("hello")
 +	bytes2, err := m2.Encode(nil)
 +	if err != nil {
 +		t.Error(err)
 +	} else {
 +		if err = checkEqual(bytes, bytes2); err != nil {
 +			t.Error(err)
 +		}
 +	}
 +}
 +
 +// TODO aconway 2015-03-13: finish the full interop test

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/marshal.go
----------------------------------------------------------------------
diff --cc amqp/marshal.go
index b6adf90,0000000..ca5e380
mode 100644,000000..100644
--- a/amqp/marshal.go
+++ b/amqp/marshal.go
@@@ -1,271 -1,0 +1,281 @@@
 +/*
 +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 amqp
 +
 +// #include <proton/codec.h>
 +import "C"
 +
 +import (
 +	"fmt"
 +	"io"
 +	"reflect"
 +	"unsafe"
 +)
 +
 +// Error returned if Go data cannot be marshaled as an AMQP type.
 +type MarshalError struct {
 +	// The Go type.
 +	GoType reflect.Type
 +	s      string
 +}
 +
 +func (e MarshalError) Error() string { return e.s }
 +
 +func newMarshalError(v interface{}, s string) *MarshalError {
 +	t := reflect.TypeOf(v)
 +	return &MarshalError{GoType: t, s: fmt.Sprintf("cannot marshal %s: %s", t, s)}
 +}
 +
 +func dataMarshalError(v interface{}, data *C.pn_data_t) error {
 +	if pe := PnError(C.pn_data_error(data)); pe != nil {
 +		return newMarshalError(v, pe.Error())
 +	}
 +	return nil
 +}
 +
++func recoverMarshal(err *error) {
++	if r := recover(); r != nil {
++		if merr, ok := r.(*MarshalError); ok {
++			*err = merr
++		} else {
++			panic(r)
++		}
++	}
++}
++
 +/*
 +Marshal encodes a Go value as AMQP data in buffer.
 +If buffer is nil, or is not large enough, a new buffer  is created.
 +
 +Returns the buffer used for encoding with len() adjusted to the actual size of data.
 +
 +Go types are encoded as follows
 +
 + +-------------------------------------+--------------------------------------------+
 + |Go type                              |AMQP type                                   |
 + +-------------------------------------+--------------------------------------------+
 + |bool                                 |bool                                        |
 + +-------------------------------------+--------------------------------------------+
 + |int8, int16, int32, int64 (int)      |byte, short, int, long (int or long)        |
 + +-------------------------------------+--------------------------------------------+
 + |uint8, uint16, uint32, uint64 (uint) |ubyte, ushort, uint, ulong (uint or ulong)  |
 + +-------------------------------------+--------------------------------------------+
 + |float32, float64                     |float, double.                              |
 + +-------------------------------------+--------------------------------------------+
 + |string                               |string                                      |
 + +-------------------------------------+--------------------------------------------+
 + |[]byte, Binary                       |binary                                      |
 + +-------------------------------------+--------------------------------------------+
 + |Symbol                               |symbol                                      |
 + +-------------------------------------+--------------------------------------------+
 + |interface{}                          |the contained type                          |
 + +-------------------------------------+--------------------------------------------+
 + |nil                                  |null                                        |
 + +-------------------------------------+--------------------------------------------+
 + |map[K]T                              |map with K and T converted as above         |
 + +-------------------------------------+--------------------------------------------+
 + |Map                                  |map, may have mixed types for keys, values  |
 + +-------------------------------------+--------------------------------------------+
 + |[]T                                  |list with T converted as above              |
 + +-------------------------------------+--------------------------------------------+
 + |List                                 |list, may have mixed types  values          |
 + +-------------------------------------+--------------------------------------------+
++ |Described                            |described type                              |
++ +-------------------------------------+--------------------------------------------+
 +
- The following Go types cannot be marshaled: uintptr, function, interface, channel
- 
- TODO
- 
- Go types: array, slice, struct, complex64/128.
++The following Go types cannot be marshaled: uintptr, function, channel, array (use slice), struct
 +
- AMQP types: decimal32/64/128, char, timestamp, uuid, array, multi-section message bodies.
++TODO: Not yet implemented:
 +
- Described types.
++Go types: struct, complex64/128.
 +
++AMQP types: decimal32/64/128, char, timestamp, uuid, array.
 +*/
 +func Marshal(v interface{}, buffer []byte) (outbuf []byte, err error) {
- 	defer func() {
- 		if r := recover(); r != nil {
- 			if merr, ok := r.(*MarshalError); ok {
- 				err = merr
- 			} else {
- 				panic(r)
- 			}
- 		}
- 	}()
- 
++	defer recoverMarshal(&err)
 +	data := C.pn_data(0)
 +	defer C.pn_data_free(data)
 +	marshal(v, data)
 +	encode := func(buf []byte) ([]byte, error) {
 +		n := int(C.pn_data_encode(data, cPtr(buf), cLen(buf)))
 +		switch {
 +		case n == int(C.PN_OVERFLOW):
 +			return buf, overflow
 +		case n < 0:
 +			return buf, dataMarshalError(v, data)
 +		default:
 +			return buf[:n], nil
 +		}
 +	}
 +	return encodeGrow(buffer, encode)
 +}
 +
++// Internal
++func MarshalUnsafe(v interface{}, pn_data unsafe.Pointer) (err error) {
++	defer recoverMarshal(&err)
++	marshal(v, (*C.pn_data_t)(pn_data))
++	return
++}
++
 +const minEncode = 256
 +
 +// overflow is returned when an encoding function can't fit data in the buffer.
 +var overflow = fmt.Errorf("buffer too small")
 +
 +// encodeFn encodes into buffer[0:len(buffer)].
 +// Returns buffer with length adjusted for data encoded.
 +// If buffer too small, returns overflow as error.
 +type encodeFn func(buffer []byte) ([]byte, error)
 +
 +// encodeGrow calls encode() into buffer, if it returns overflow grows the buffer.
 +// Returns the final buffer.
 +func encodeGrow(buffer []byte, encode encodeFn) ([]byte, error) {
 +	if buffer == nil || len(buffer) == 0 {
 +		buffer = make([]byte, minEncode)
 +	}
 +	var err error
 +	for buffer, err = encode(buffer); err == overflow; buffer, err = encode(buffer) {
 +		buffer = make([]byte, 2*len(buffer))
 +	}
 +	return buffer, err
 +}
 +
 +func marshal(v interface{}, data *C.pn_data_t) {
 +	switch v := v.(type) {
 +	case nil:
 +		C.pn_data_put_null(data)
 +	case bool:
 +		C.pn_data_put_bool(data, C.bool(v))
 +	case int8:
 +		C.pn_data_put_byte(data, C.int8_t(v))
 +	case int16:
 +		C.pn_data_put_short(data, C.int16_t(v))
 +	case int32:
 +		C.pn_data_put_int(data, C.int32_t(v))
 +	case int64:
 +		C.pn_data_put_long(data, C.int64_t(v))
 +	case int:
 +		if unsafe.Sizeof(int(0)) == 8 {
 +			C.pn_data_put_long(data, C.int64_t(v))
 +		} else {
 +			C.pn_data_put_int(data, C.int32_t(v))
 +		}
 +	case uint8:
 +		C.pn_data_put_ubyte(data, C.uint8_t(v))
 +	case uint16:
 +		C.pn_data_put_ushort(data, C.uint16_t(v))
 +	case uint32:
 +		C.pn_data_put_uint(data, C.uint32_t(v))
 +	case uint64:
 +		C.pn_data_put_ulong(data, C.uint64_t(v))
 +	case uint:
 +		if unsafe.Sizeof(int(0)) == 8 {
 +			C.pn_data_put_ulong(data, C.uint64_t(v))
 +		} else {
 +			C.pn_data_put_uint(data, C.uint32_t(v))
 +		}
 +	case float32:
 +		C.pn_data_put_float(data, C.float(v))
 +	case float64:
 +		C.pn_data_put_double(data, C.double(v))
 +	case string:
 +		C.pn_data_put_string(data, pnBytes([]byte(v)))
 +	case []byte:
 +		C.pn_data_put_binary(data, pnBytes(v))
 +	case Binary:
 +		C.pn_data_put_binary(data, pnBytes([]byte(v)))
 +	case Symbol:
 +		C.pn_data_put_symbol(data, pnBytes([]byte(v)))
 +	case Map: // Special map type
 +		C.pn_data_put_map(data)
 +		C.pn_data_enter(data)
 +		for key, val := range v {
 +			marshal(key, data)
 +			marshal(val, data)
 +		}
 +		C.pn_data_exit(data)
++	case Described:
++		C.pn_data_put_described(data)
++		C.pn_data_enter(data)
++		marshal(v.Descriptor, data)
++		marshal(v.Value, data)
++		C.pn_data_exit(data)
++	case AnnotationKey:
++		marshal(v.Get(), data)
 +	default:
 +		switch reflect.TypeOf(v).Kind() {
 +		case reflect.Map:
 +			putMap(data, v)
 +		case reflect.Slice:
 +			putList(data, v)
 +		default:
 +			panic(newMarshalError(v, "no conversion"))
 +		}
 +	}
 +	if err := dataMarshalError(v, data); err != nil {
 +		panic(err)
 +	}
 +	return
 +}
 +
 +func clearMarshal(v interface{}, data *C.pn_data_t) {
 +	C.pn_data_clear(data)
 +	marshal(v, data)
 +}
 +
 +func putMap(data *C.pn_data_t, v interface{}) {
 +	mapValue := reflect.ValueOf(v)
 +	C.pn_data_put_map(data)
 +	C.pn_data_enter(data)
 +	for _, key := range mapValue.MapKeys() {
 +		marshal(key.Interface(), data)
 +		marshal(mapValue.MapIndex(key).Interface(), data)
 +	}
 +	C.pn_data_exit(data)
 +}
 +
 +func putList(data *C.pn_data_t, v interface{}) {
 +	listValue := reflect.ValueOf(v)
 +	C.pn_data_put_list(data)
 +	C.pn_data_enter(data)
 +	for i := 0; i < listValue.Len(); i++ {
 +		marshal(listValue.Index(i).Interface(), data)
 +	}
 +	C.pn_data_exit(data)
 +}
 +
 +// Encoder encodes AMQP values to an io.Writer
 +type Encoder struct {
 +	writer io.Writer
 +	buffer []byte
 +}
 +
 +// New encoder returns a new encoder that writes to w.
 +func NewEncoder(w io.Writer) *Encoder {
 +	return &Encoder{w, make([]byte, minEncode)}
 +}
 +
 +func (e *Encoder) Encode(v interface{}) (err error) {
 +	e.buffer, err = Marshal(v, e.buffer)
 +	if err == nil {
 +		_, err = e.writer.Write(e.buffer)
 +	}
 +	return err
 +}
- 
- func replace(data *C.pn_data_t, v interface{}) {
- 	C.pn_data_clear(data)
- 	marshal(v, data)
- }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/marshal_test.go
----------------------------------------------------------------------
diff --cc amqp/marshal_test.go
index 0000000,0000000..d8e0711
new file mode 100644
--- /dev/null
+++ b/amqp/marshal_test.go
@@@ -1,0 -1,0 +1,90 @@@
++/*
++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 amqp
++
++import (
++	"testing"
++)
++
++func TestSymbolKey(t *testing.T) {
++	bytes, err := Marshal(AnnotationKeySymbol("foo"), nil)
++	if err != nil {
++		t.Fatal(err)
++	}
++	var k AnnotationKey
++	if _, err := Unmarshal(bytes, &k); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual("foo", string(k.Get().(Symbol))); err != nil {
++		t.Error(err)
++	}
++	var sym Symbol
++	if _, err := Unmarshal(bytes, &sym); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual("foo", sym.String()); err != nil {
++		t.Error(err)
++	}
++
++}
++
++func TestStringKey(t *testing.T) {
++	bytes, err := Marshal(AnnotationKeyString("foo"), nil)
++	if err != nil {
++		t.Fatal(err)
++	}
++	var k AnnotationKey
++	if _, err := Unmarshal(bytes, &k); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual("foo", string(k.Get().(Symbol))); err != nil {
++		t.Error(err)
++	}
++	var s string
++	if _, err := Unmarshal(bytes, &s); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual("foo", s); err != nil {
++		t.Error(err)
++	}
++
++}
++
++func TestIntKey(t *testing.T) {
++	bytes, err := Marshal(AnnotationKeyUint64(12345), nil)
++	if err != nil {
++		t.Fatal(err)
++	}
++	var k AnnotationKey
++	if _, err := Unmarshal(bytes, &k); err != nil {
++		t.Error(err)
++	}
++	if 12345 != k.Get().(uint64) {
++		t.Errorf("(%T)%v != (%T)%v", 12345, k.Get().(uint64))
++	}
++	var n uint64
++	if _, err := Unmarshal(bytes, &n); err != nil {
++		t.Error(err)
++	}
++	if 12345 != n {
++		t.Errorf("%v != %v", 12345, k.Get().(uint64))
++	}
++
++}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/message.go
----------------------------------------------------------------------
diff --cc amqp/message.go
index 753682e,0000000..d1ad2eb
mode 100644,000000..100644
--- a/amqp/message.go
+++ b/amqp/message.go
@@@ -1,348 -1,0 +1,402 @@@
 +/*
 +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 amqp
 +
 +// #include <proton/codec.h>
 +// #include <proton/types.h>
 +// #include <proton/message.h>
 +// #include <stdlib.h>
 +//
 +// /* Helper for setting message string fields */
 +// typedef int (*set_fn)(pn_message_t*, const char*);
 +// int msg_set_str(pn_message_t* m, char* s, set_fn set) {
 +//     int result = set(m, s);
 +//     free(s);
 +//     return result;
 +// }
 +//
 +import "C"
 +
 +import (
 +	"fmt"
 +	"runtime"
 +	"time"
- 	"unsafe"
 +)
 +
 +// Message is the interface to an AMQP message.
 +type Message interface {
 +	// Durable indicates that any parties taking responsibility
 +	// for the message must durably store the content.
 +	Durable() bool
 +	SetDurable(bool)
 +
 +	// Priority impacts ordering guarantees. Within a
 +	// given ordered context, higher priority messages may jump ahead of
 +	// lower priority messages.
 +	Priority() uint8
 +	SetPriority(uint8)
 +
 +	// TTL or Time To Live, a message it may be dropped after this duration
 +	TTL() time.Duration
 +	SetTTL(time.Duration)
 +
 +	// FirstAcquirer indicates
 +	// that the recipient of the message is the first recipient to acquire
 +	// the message, i.e. there have been no failed delivery attempts to
 +	// other acquirers. Note that this does not mean the message has not
 +	// been delivered to, but not acquired, by other recipients.
 +	FirstAcquirer() bool
 +	SetFirstAcquirer(bool)
 +
 +	// DeliveryCount tracks how many attempts have been made to
 +	// delivery a message.
 +	DeliveryCount() uint32
 +	SetDeliveryCount(uint32)
 +
 +	// MessageId provides a unique identifier for a message.
 +	// it can be an a string, an unsigned long, a uuid or a
 +	// binary value.
 +	MessageId() interface{}
 +	SetMessageId(interface{})
 +
 +	UserId() string
 +	SetUserId(string)
 +
 +	Address() string
 +	SetAddress(string)
 +
 +	Subject() string
 +	SetSubject(string)
 +
 +	ReplyTo() string
 +	SetReplyTo(string)
 +
 +	// CorrelationId is set on correlated request and response messages. It can be
 +	// an a string, an unsigned long, a uuid or a binary value.
 +	CorrelationId() interface{}
 +	SetCorrelationId(interface{})
 +
 +	ContentType() string
 +	SetContentType(string)
 +
 +	ContentEncoding() string
 +	SetContentEncoding(string)
 +
 +	// ExpiryTime indicates an absoulte time when the message may be dropped.
 +	// A Zero time (i.e. t.isZero() == true) indicates a message never expires.
 +	ExpiryTime() time.Time
 +	SetExpiryTime(time.Time)
 +
 +	CreationTime() time.Time
 +	SetCreationTime(time.Time)
 +
 +	GroupId() string
 +	SetGroupId(string)
 +
 +	GroupSequence() int32
 +	SetGroupSequence(int32)
 +
 +	ReplyToGroupId() string
 +	SetReplyToGroupId(string)
 +
- 	// Instructions - AMQP delivery instructions.
- 	Instructions() map[string]interface{}
- 	SetInstructions(v map[string]interface{})
++	// Property map set by the application to be carried with the message.
++	// Values must be simple types (not maps, lists or sequences)
++	ApplicationProperties() map[string]interface{}
++	SetApplicationProperties(map[string]interface{})
 +
- 	// Annotations - AMQP annotations.
- 	Annotations() map[string]interface{}
- 	SetAnnotations(v map[string]interface{})
++	// Per-delivery annotations to provide delivery instructions.
++	// May be added or removed by intermediaries during delivery.
++	DeliveryAnnotations() map[AnnotationKey]interface{}
++	SetDeliveryAnnotations(map[AnnotationKey]interface{})
 +
- 	// Properties - Application properties.
- 	Properties() map[string]interface{}
- 	SetProperties(v map[string]interface{})
++	// Message annotations added as part of the bare message at creation, usually
++	// by an AMQP library. See ApplicationProperties() for adding application data.
++	MessageAnnotations() map[AnnotationKey]interface{}
++	SetMessageAnnotations(map[AnnotationKey]interface{})
 +
 +	// Inferred indicates how the message content
 +	// is encoded into AMQP sections. If inferred is true then binary and
 +	// list values in the body of the message will be encoded as AMQP DATA
 +	// and AMQP SEQUENCE sections, respectively. If inferred is false,
 +	// then all values in the body of the message will be encoded as AMQP
 +	// VALUE sections regardless of their type.
 +	Inferred() bool
 +	SetInferred(bool)
 +
 +	// Marshal a Go value into the message body. See amqp.Marshal() for details.
 +	Marshal(interface{})
 +
 +	// Unmarshal the message body into the value pointed to by v. See amqp.Unmarshal() for details.
 +	Unmarshal(interface{})
 +
 +	// Body value resulting from the default unmarshalling of message body as interface{}
 +	Body() interface{}
 +
 +	// Encode encodes the message as AMQP data. If buffer is non-nil and is large enough
 +	// the message is encoded into it, otherwise a new buffer is created.
 +	// Returns the buffer containing the message.
 +	Encode(buffer []byte) ([]byte, error)
 +
 +	// Decode data into this message. Overwrites an existing message content.
 +	Decode(buffer []byte) error
 +
 +	// Clear the message contents.
 +	Clear()
 +
 +	// Copy the contents of another message to this one.
 +	Copy(m Message) error
++
++	// Deprecated: use DeliveryAnnotations() for a more type-safe interface
++	Instructions() map[string]interface{}
++	SetInstructions(v map[string]interface{})
++
++	// Deprecated: use MessageAnnotations() for a more type-safe interface
++	Annotations() map[string]interface{}
++	SetAnnotations(v map[string]interface{})
++
++	// Deprecated: use ApplicationProperties() for a more type-safe interface
++	Properties() map[string]interface{}
++	SetProperties(v map[string]interface{})
 +}
 +
 +type message struct{ pn *C.pn_message_t }
 +
 +func freeMessage(m *message) {
 +	C.pn_message_free(m.pn)
 +	m.pn = nil
 +}
 +
 +// NewMessage creates a new message instance.
 +func NewMessage() Message {
 +	m := &message{C.pn_message()}
 +	runtime.SetFinalizer(m, freeMessage)
 +	return m
 +}
 +
 +// NewMessageWith creates a message with value as the body. Equivalent to
 +//     m := NewMessage(); m.Marshal(body)
 +func NewMessageWith(value interface{}) Message {
 +	m := NewMessage()
 +	m.Marshal(value)
 +	return m
 +}
 +
 +func (m *message) Clear() { C.pn_message_clear(m.pn) }
 +
 +func (m *message) Copy(x Message) error {
 +	if data, err := x.Encode(nil); err == nil {
 +		return m.Decode(data)
 +	} else {
 +		return err
 +	}
 +}
 +
 +// ==== message get functions
 +
 +func rewindGet(data *C.pn_data_t) (v interface{}) {
 +	C.pn_data_rewind(data)
 +	C.pn_data_next(data)
 +	unmarshal(&v, data)
 +	return v
 +}
 +
- func rewindMap(data *C.pn_data_t) (v map[string]interface{}) {
- 	C.pn_data_rewind(data)
- 	C.pn_data_next(data)
- 	unmarshal(&v, data)
- 	return v
- }
- 
 +func (m *message) Inferred() bool  { return bool(C.pn_message_is_inferred(m.pn)) }
 +func (m *message) Durable() bool   { return bool(C.pn_message_is_durable(m.pn)) }
 +func (m *message) Priority() uint8 { return uint8(C.pn_message_get_priority(m.pn)) }
 +func (m *message) TTL() time.Duration {
 +	return time.Duration(C.pn_message_get_ttl(m.pn)) * time.Millisecond
 +}
 +func (m *message) FirstAcquirer() bool        { return bool(C.pn_message_is_first_acquirer(m.pn)) }
 +func (m *message) DeliveryCount() uint32      { return uint32(C.pn_message_get_delivery_count(m.pn)) }
 +func (m *message) MessageId() interface{}     { return rewindGet(C.pn_message_id(m.pn)) }
 +func (m *message) UserId() string             { return goString(C.pn_message_get_user_id(m.pn)) }
 +func (m *message) Address() string            { return C.GoString(C.pn_message_get_address(m.pn)) }
 +func (m *message) Subject() string            { return C.GoString(C.pn_message_get_subject(m.pn)) }
 +func (m *message) ReplyTo() string            { return C.GoString(C.pn_message_get_reply_to(m.pn)) }
 +func (m *message) CorrelationId() interface{} { return rewindGet(C.pn_message_correlation_id(m.pn)) }
 +func (m *message) ContentType() string        { return C.GoString(C.pn_message_get_content_type(m.pn)) }
 +func (m *message) ContentEncoding() string    { return C.GoString(C.pn_message_get_content_encoding(m.pn)) }
 +
 +func (m *message) ExpiryTime() time.Time {
 +	return time.Unix(0, int64(time.Millisecond*time.Duration(C.pn_message_get_expiry_time(m.pn))))
 +}
 +func (m *message) CreationTime() time.Time {
 +	return time.Unix(0, int64(time.Millisecond)*int64(C.pn_message_get_creation_time(m.pn)))
 +}
 +func (m *message) GroupId() string        { return C.GoString(C.pn_message_get_group_id(m.pn)) }
 +func (m *message) GroupSequence() int32   { return int32(C.pn_message_get_group_sequence(m.pn)) }
 +func (m *message) ReplyToGroupId() string { return C.GoString(C.pn_message_get_reply_to_group_id(m.pn)) }
 +
- func (m *message) Instructions() map[string]interface{} {
- 	return rewindMap(C.pn_message_instructions(m.pn))
++func getAnnotations(data *C.pn_data_t) (v map[AnnotationKey]interface{}) {
++	C.pn_data_rewind(data)
++	C.pn_data_next(data)
++	unmarshal(&v, data)
++	return v
 +}
- func (m *message) Annotations() map[string]interface{} {
- 	return rewindMap(C.pn_message_annotations(m.pn))
++
++func (m *message) DeliveryAnnotations() map[AnnotationKey]interface{} {
++	return getAnnotations(C.pn_message_instructions(m.pn))
 +}
- func (m *message) Properties() map[string]interface{} {
- 	return rewindMap(C.pn_message_properties(m.pn))
++func (m *message) MessageAnnotations() map[AnnotationKey]interface{} {
++	return getAnnotations(C.pn_message_annotations(m.pn))
++}
++
++func (m *message) ApplicationProperties() map[string]interface{} {
++	var v map[string]interface{}
++	data := C.pn_message_properties(m.pn)
++	C.pn_data_rewind(data)
++	C.pn_data_next(data)
++	unmarshal(&v, data)
++	return v
 +}
 +
 +// ==== message set methods
 +
 +func setData(v interface{}, data *C.pn_data_t) {
 +	C.pn_data_clear(data)
 +	marshal(v, data)
 +}
 +
- func dataString(data *C.pn_data_t) string {
- 	str := C.pn_string(C.CString(""))
- 	defer C.pn_free(unsafe.Pointer(str))
- 	C.pn_inspect(unsafe.Pointer(data), str)
- 	return C.GoString(C.pn_string_get(str))
- }
- 
 +func (m *message) SetInferred(b bool)  { C.pn_message_set_inferred(m.pn, C.bool(b)) }
 +func (m *message) SetDurable(b bool)   { C.pn_message_set_durable(m.pn, C.bool(b)) }
 +func (m *message) SetPriority(b uint8) { C.pn_message_set_priority(m.pn, C.uint8_t(b)) }
 +func (m *message) SetTTL(d time.Duration) {
 +	C.pn_message_set_ttl(m.pn, C.pn_millis_t(d/time.Millisecond))
 +}
 +func (m *message) SetFirstAcquirer(b bool)     { C.pn_message_set_first_acquirer(m.pn, C.bool(b)) }
 +func (m *message) SetDeliveryCount(c uint32)   { C.pn_message_set_delivery_count(m.pn, C.uint32_t(c)) }
 +func (m *message) SetMessageId(id interface{}) { setData(id, C.pn_message_id(m.pn)) }
 +func (m *message) SetUserId(s string)          { C.pn_message_set_user_id(m.pn, pnBytes(([]byte)(s))) }
 +func (m *message) SetAddress(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_address))
 +}
 +func (m *message) SetSubject(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_subject))
 +}
 +func (m *message) SetReplyTo(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_reply_to))
 +}
 +func (m *message) SetCorrelationId(c interface{}) { setData(c, C.pn_message_correlation_id(m.pn)) }
 +func (m *message) SetContentType(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_content_type))
 +}
 +func (m *message) SetContentEncoding(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_content_encoding))
 +}
 +func (m *message) SetExpiryTime(t time.Time)   { C.pn_message_set_expiry_time(m.pn, pnTime(t)) }
 +func (m *message) SetCreationTime(t time.Time) { C.pn_message_set_creation_time(m.pn, pnTime(t)) }
 +func (m *message) SetGroupId(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_group_id))
 +}
 +func (m *message) SetGroupSequence(s int32) {
 +	C.pn_message_set_group_sequence(m.pn, C.pn_sequence_t(s))
 +}
 +func (m *message) SetReplyToGroupId(s string) {
 +	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_reply_to_group_id))
 +}
 +
- func (m *message) SetInstructions(v map[string]interface{}) {
++func (m *message) SetDeliveryAnnotations(v map[AnnotationKey]interface{}) {
 +	setData(v, C.pn_message_instructions(m.pn))
 +}
- func (m *message) SetAnnotations(v map[string]interface{}) { setData(v, C.pn_message_annotations(m.pn)) }
- func (m *message) SetProperties(v map[string]interface{})  { setData(v, C.pn_message_properties(m.pn)) }
++func (m *message) SetMessageAnnotations(v map[AnnotationKey]interface{}) {
++	setData(v, C.pn_message_annotations(m.pn))
++}
++func (m *message) SetApplicationProperties(v map[string]interface{}) {
++	setData(v, C.pn_message_properties(m.pn))
++}
 +
 +// Marshal/Unmarshal body
 +func (m *message) Marshal(v interface{})   { clearMarshal(v, C.pn_message_body(m.pn)) }
 +func (m *message) Unmarshal(v interface{}) { rewindUnmarshal(v, C.pn_message_body(m.pn)) }
 +func (m *message) Body() (v interface{})   { m.Unmarshal(&v); return }
 +
 +func (m *message) Decode(data []byte) error {
 +	m.Clear()
 +	if len(data) == 0 {
 +		return fmt.Errorf("empty buffer for decode")
 +	}
 +	if C.pn_message_decode(m.pn, cPtr(data), cLen(data)) < 0 {
 +		return fmt.Errorf("decoding message: %s", PnError(C.pn_message_error(m.pn)))
 +	}
 +	return nil
 +}
 +
 +func DecodeMessage(data []byte) (m Message, err error) {
 +	m = NewMessage()
 +	err = m.Decode(data)
 +	return
 +}
 +
 +func (m *message) Encode(buffer []byte) ([]byte, error) {
 +	encode := func(buf []byte) ([]byte, error) {
 +		len := cLen(buf)
 +		result := C.pn_message_encode(m.pn, cPtr(buf), &len)
 +		switch {
 +		case result == C.PN_OVERFLOW:
 +			return buf, overflow
 +		case result < 0:
 +			return buf, fmt.Errorf("cannot encode message: %s", PnErrorCode(result))
 +		default:
 +			return buf[:len], nil
 +		}
 +	}
 +	return encodeGrow(buffer, encode)
 +}
 +
 +// TODO aconway 2015-09-14: Multi-section messages.
 +
 +// TODO aconway 2016-09-09: Message.String() use inspect.
++
++// ==== Deprecated functions
++func oldGetAnnotations(data *C.pn_data_t) (v map[string]interface{}) {
++	C.pn_data_rewind(data)
++	C.pn_data_next(data)
++	unmarshal(&v, data)
++	return v
++}
++
++func (m *message) Instructions() map[string]interface{} {
++	return oldGetAnnotations(C.pn_message_instructions(m.pn))
++}
++func (m *message) Annotations() map[string]interface{} {
++	return oldGetAnnotations(C.pn_message_annotations(m.pn))
++}
++func (m *message) Properties() map[string]interface{} {
++	return oldGetAnnotations(C.pn_message_properties(m.pn))
++}
++
++// Convert old string-keyed annotations to an AnnotationKey map
++func fixAnnotations(old map[string]interface{}) (annotations map[AnnotationKey]interface{}) {
++	annotations = make(map[AnnotationKey]interface{})
++	for k, v := range old {
++		annotations[AnnotationKeyString(k)] = v
++	}
++	return
++}
++
++func (m *message) SetInstructions(v map[string]interface{}) {
++	setData(fixAnnotations(v), C.pn_message_instructions(m.pn))
++}
++func (m *message) SetAnnotations(v map[string]interface{}) {
++	setData(fixAnnotations(v), C.pn_message_annotations(m.pn))
++}
++func (m *message) SetProperties(v map[string]interface{}) {
++	setData(fixAnnotations(v), C.pn_message_properties(m.pn))
++}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/message_test.go
----------------------------------------------------------------------
diff --cc amqp/message_test.go
index 7a6e5a8,0000000..bfebfa1
mode 100644,000000..100644
--- a/amqp/message_test.go
+++ b/amqp/message_test.go
@@@ -1,166 -1,0 +1,201 @@@
 +/*
 +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 amqp
 +
 +import (
 +	"testing"
 +	"time"
 +)
 +
 +func roundTrip(m Message) error {
 +	buffer, err := m.Encode(nil)
 +	if err != nil {
 +		return err
 +	}
 +	m2, err := DecodeMessage(buffer)
 +	if err != nil {
 +		return err
 +	}
 +	return checkEqual(m, m2)
 +}
 +
 +func TestDefaultMessage(t *testing.T) {
 +	m := NewMessage()
 +	// Check defaults
 +	for _, data := range [][]interface{}{
 +		{m.Inferred(), false},
 +		{m.Durable(), false},
 +		{m.Priority(), uint8(4)},
 +		{m.TTL(), time.Duration(0)},
 +		{m.UserId(), ""},
 +		{m.Address(), ""},
 +		{m.Subject(), ""},
 +		{m.ReplyTo(), ""},
 +		{m.ContentType(), ""},
 +		{m.ContentEncoding(), ""},
 +		{m.GroupId(), ""},
 +		{m.GroupSequence(), int32(0)},
 +		{m.ReplyToGroupId(), ""},
 +		{m.MessageId(), nil},
 +		{m.CorrelationId(), nil},
++		{m.DeliveryAnnotations(), map[AnnotationKey]interface{}{}},
++		{m.MessageAnnotations(), map[AnnotationKey]interface{}{}},
++		{m.ApplicationProperties(), map[string]interface{}{}},
++
++		// Deprecated
 +		{m.Instructions(), map[string]interface{}{}},
 +		{m.Annotations(), map[string]interface{}{}},
 +		{m.Properties(), map[string]interface{}{}},
 +		{m.Body(), nil},
 +	} {
 +		if err := checkEqual(data[0], data[1]); err != nil {
 +			t.Error(err)
 +		}
 +	}
 +	if err := roundTrip(m); err != nil {
 +		t.Error(err)
 +	}
 +}
 +
 +func TestMessageRoundTrip(t *testing.T) {
 +	m := NewMessage()
 +	m.SetInferred(false)
 +	m.SetDurable(true)
 +	m.SetPriority(42)
 +	m.SetTTL(0)
 +	m.SetUserId("user")
 +	m.SetAddress("address")
 +	m.SetSubject("subject")
 +	m.SetReplyTo("replyto")
 +	m.SetContentType("content")
 +	m.SetContentEncoding("encoding")
 +	m.SetGroupId("group")
 +	m.SetGroupSequence(42)
 +	m.SetReplyToGroupId("replytogroup")
 +	m.SetMessageId("id")
 +	m.SetCorrelationId("correlation")
- 	m.SetInstructions(map[string]interface{}{"instructions": "foo"})
- 	m.SetAnnotations(map[string]interface{}{"annotations": "foo"})
- 	m.SetProperties(map[string]interface{}{"int": int32(32), "bool": true, "string": "foo"})
++	m.SetDeliveryAnnotations(map[AnnotationKey]interface{}{AnnotationKeySymbol("instructions"): "foo"})
++	m.SetMessageAnnotations(map[AnnotationKey]interface{}{AnnotationKeySymbol("annotations"): "bar"})
++	m.SetApplicationProperties(map[string]interface{}{"int": int32(32), "bool": true})
 +	m.Marshal("hello")
 +
 +	for _, data := range [][]interface{}{
 +		{m.Inferred(), false},
 +		{m.Durable(), true},
 +		{m.Priority(), uint8(42)},
 +		{m.TTL(), time.Duration(0)},
 +		{m.UserId(), "user"},
 +		{m.Address(), "address"},
 +		{m.Subject(), "subject"},
 +		{m.ReplyTo(), "replyto"},
 +		{m.ContentType(), "content"},
 +		{m.ContentEncoding(), "encoding"},
 +		{m.GroupId(), "group"},
 +		{m.GroupSequence(), int32(42)},
 +		{m.ReplyToGroupId(), "replytogroup"},
 +		{m.MessageId(), "id"},
 +		{m.CorrelationId(), "correlation"},
- 		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
- 		{m.Annotations(), map[string]interface{}{"annotations": "foo"}},
- 		{m.Properties(), map[string]interface{}{"int": int32(32), "bool": true, "string": "foo"}},
++
++		{m.DeliveryAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("instructions"): "foo"}},
++		{m.MessageAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("annotations"): "bar"}},
++		{m.ApplicationProperties(), map[string]interface{}{"int": int32(32), "bool": true}},
 +		{m.Body(), "hello"},
++
++		// Deprecated
++		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
++		{m.Annotations(), map[string]interface{}{"annotations": "bar"}},
++	} {
++		if err := checkEqual(data[0], data[1]); err != nil {
++			t.Error(err)
++		}
++	}
++	if err := roundTrip(m); err != nil {
++		t.Error(err)
++	}
++}
++
++func TestDeprecated(t *testing.T) {
++	m := NewMessage()
++
++	m.SetInstructions(map[string]interface{}{"instructions": "foo"})
++	m.SetAnnotations(map[string]interface{}{"annotations": "bar"})
++	m.SetProperties(map[string]interface{}{"int": int32(32), "bool": true})
++
++	for _, data := range [][]interface{}{
++		{m.DeliveryAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("instructions"): "foo"}},
++		{m.MessageAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("annotations"): "bar"}},
++		{m.ApplicationProperties(), map[string]interface{}{"int": int32(32), "bool": true}},
++
++		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
++		{m.Annotations(), map[string]interface{}{"annotations": "bar"}},
++		{m.Properties(), map[string]interface{}{"int": int32(32), "bool": true}},
 +	} {
 +		if err := checkEqual(data[0], data[1]); err != nil {
 +			t.Error(err)
 +		}
 +	}
 +	if err := roundTrip(m); err != nil {
 +		t.Error(err)
 +	}
 +}
 +
 +func TestMessageBodyTypes(t *testing.T) {
 +	var s string
 +	var body interface{}
 +	var i int64
 +
 +	m := NewMessageWith(int64(42))
 +	m.Unmarshal(&body)
 +	m.Unmarshal(&i)
 +	if err := checkEqual(body.(int64), int64(42)); err != nil {
 +		t.Error(err)
 +	}
 +	if err := checkEqual(i, int64(42)); err != nil {
 +		t.Error(err)
 +	}
 +
 +	m = NewMessageWith("hello")
 +	m.Unmarshal(&s)
 +	m.Unmarshal(&body)
 +	if err := checkEqual(s, "hello"); err != nil {
 +		t.Error(err)
 +	}
 +	if err := checkEqual(body.(string), "hello"); err != nil {
 +		t.Error(err)
 +	}
 +	if err := roundTrip(m); err != nil {
 +		t.Error(err)
 +	}
 +
 +	m = NewMessageWith(Binary("bin"))
 +	m.Unmarshal(&s)
 +	m.Unmarshal(&body)
 +	if err := checkEqual(body.(Binary), Binary("bin")); err != nil {
 +		t.Error(err)
 +	}
 +	if err := checkEqual(s, "bin"); err != nil {
 +		t.Error(err)
 +	}
 +	if err := roundTrip(m); err != nil {
 +		t.Error(err)
 +	}
 +
 +	// TODO aconway 2015-09-08: array etc.
 +}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/types.go
----------------------------------------------------------------------
diff --cc amqp/types.go
index 2852c23,0000000..9d41de6
mode 100644,000000..100644
--- a/amqp/types.go
+++ b/amqp/types.go
@@@ -1,194 -1,0 +1,221 @@@
 +/*
 +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 amqp
 +
 +// #include <proton/codec.h>
 +import "C"
 +
 +import (
 +	"bytes"
 +	"fmt"
 +	"reflect"
 +	"time"
 +	"unsafe"
 +)
 +
 +func (t C.pn_type_t) String() string {
 +	switch C.pn_type_t(t) {
 +	case C.PN_NULL:
 +		return "null"
 +	case C.PN_BOOL:
 +		return "bool"
 +	case C.PN_UBYTE:
 +		return "ubyte"
 +	case C.PN_BYTE:
 +		return "byte"
 +	case C.PN_USHORT:
 +		return "ushort"
 +	case C.PN_SHORT:
 +		return "short"
 +	case C.PN_CHAR:
 +		return "char"
 +	case C.PN_UINT:
 +		return "uint"
 +	case C.PN_INT:
 +		return "int"
 +	case C.PN_ULONG:
 +		return "ulong"
 +	case C.PN_LONG:
 +		return "long"
 +	case C.PN_TIMESTAMP:
 +		return "timestamp"
 +	case C.PN_FLOAT:
 +		return "float"
 +	case C.PN_DOUBLE:
 +		return "double"
 +	case C.PN_DECIMAL32:
 +		return "decimal32"
 +	case C.PN_DECIMAL64:
 +		return "decimal64"
 +	case C.PN_DECIMAL128:
 +		return "decimal128"
 +	case C.PN_UUID:
 +		return "uuid"
 +	case C.PN_BINARY:
 +		return "binary"
 +	case C.PN_STRING:
 +		return "string"
 +	case C.PN_SYMBOL:
 +		return "symbol"
 +	case C.PN_DESCRIBED:
 +		return "described"
 +	case C.PN_ARRAY:
 +		return "array"
 +	case C.PN_LIST:
 +		return "list"
 +	case C.PN_MAP:
 +		return "map"
 +	default:
- 		return "no-data"
++		return fmt.Sprintf("<bad-type %v>", int(t))
 +	}
 +}
 +
 +// Go types
 +var (
 +	bytesType = reflect.TypeOf([]byte{})
 +	valueType = reflect.TypeOf(reflect.Value{})
 +)
 +
 +// TODO aconway 2015-04-08: can't handle AMQP maps with key types that are not valid Go map keys.
 +
 +// Map is a generic map that can have mixed key and value types and so can represent any AMQP map
 +type Map map[interface{}]interface{}
 +
 +// List is a generic list that can hold mixed values and can represent any AMQP list.
 +//
 +type List []interface{}
 +
 +// Symbol is a string that is encoded as an AMQP symbol
 +type Symbol string
 +
++func (s Symbol) String() string   { return string(s) }
 +func (s Symbol) GoString() string { return fmt.Sprintf("s\"%s\"", s) }
 +
 +// Binary is a string that is encoded as an AMQP binary.
 +// It is a string rather than a byte[] because byte[] is not hashable and can't be used as
 +// a map key, AMQP frequently uses binary types as map keys. It can convert to and from []byte
 +type Binary string
 +
++func (b Binary) String() string   { return string(b) }
 +func (b Binary) GoString() string { return fmt.Sprintf("b\"%s\"", b) }
 +
 +// GoString for Map prints values with their types, useful for debugging.
 +func (m Map) GoString() string {
 +	out := &bytes.Buffer{}
 +	fmt.Fprintf(out, "%T{", m)
 +	i := len(m)
 +	for k, v := range m {
 +		fmt.Fprintf(out, "%T(%#v): %T(%#v)", k, k, v, v)
 +		i--
 +		if i > 0 {
 +			fmt.Fprint(out, ", ")
 +		}
 +	}
 +	fmt.Fprint(out, "}")
 +	return out.String()
 +}
 +
 +// GoString for List prints values with their types, useful for debugging.
 +func (l List) GoString() string {
 +	out := &bytes.Buffer{}
 +	fmt.Fprintf(out, "%T{", l)
 +	for i := 0; i < len(l); i++ {
 +		fmt.Fprintf(out, "%T(%#v)", l[i], l[i])
 +		if i == len(l)-1 {
 +			fmt.Fprint(out, ", ")
 +		}
 +	}
 +	fmt.Fprint(out, "}")
 +	return out.String()
 +}
 +
 +// pnTime converts Go time.Time to Proton millisecond Unix time.
 +func pnTime(t time.Time) C.pn_timestamp_t {
 +	secs := t.Unix()
 +	// Note: sub-second accuracy is not guaraunteed if the Unix time in
 +	// nanoseconds cannot be represented by an int64 (sometime around year 2260)
 +	msecs := (t.UnixNano() % int64(time.Second)) / int64(time.Millisecond)
 +	return C.pn_timestamp_t(secs*1000 + msecs)
 +}
 +
 +// goTime converts a pn_timestamp_t to a Go time.Time.
 +func goTime(t C.pn_timestamp_t) time.Time {
 +	secs := int64(t) / 1000
 +	nsecs := (int64(t) % 1000) * int64(time.Millisecond)
 +	return time.Unix(secs, nsecs)
 +}
 +
 +func goBytes(cBytes C.pn_bytes_t) (bytes []byte) {
 +	if cBytes.start != nil {
 +		bytes = C.GoBytes(unsafe.Pointer(cBytes.start), C.int(cBytes.size))
 +	}
 +	return
 +}
 +
 +func goString(cBytes C.pn_bytes_t) (str string) {
 +	if cBytes.start != nil {
 +		str = C.GoStringN(cBytes.start, C.int(cBytes.size))
 +	}
 +	return
 +}
 +
 +func pnBytes(b []byte) C.pn_bytes_t {
 +	if len(b) == 0 {
 +		return C.pn_bytes_t{0, nil}
 +	} else {
 +		return C.pn_bytes_t{C.size_t(len(b)), (*C.char)(unsafe.Pointer(&b[0]))}
 +	}
 +}
 +
 +func cPtr(b []byte) *C.char {
 +	if len(b) == 0 {
 +		return nil
 +	}
 +	return (*C.char)(unsafe.Pointer(&b[0]))
 +}
 +
 +func cLen(b []byte) C.size_t {
 +	return C.size_t(len(b))
 +}
++
++// AnnotationKey is used as a map key for AMQP annotation maps which are
++// allowed to have keys that are either symbol or ulong but no other type.
++//
++type AnnotationKey struct {
++	value interface{}
++}
++
++func AnnotationKeySymbol(v Symbol) AnnotationKey { return AnnotationKey{v} }
++func AnnotationKeyUint64(v uint64) AnnotationKey { return AnnotationKey{v} }
++func AnnotationKeyString(v string) AnnotationKey { return AnnotationKey{Symbol(v)} }
++
++// Returns the value which must be Symbol, uint64 or nil
++func (k AnnotationKey) Get() interface{} { return k.value }
++
++func (k AnnotationKey) String() string { return fmt.Sprintf("%v", k.Get()) }
++
++// Described represents an AMQP described type, which is really
++// just a pair of AMQP values - the first is treated as a "descriptor",
++// and is normally a string or ulong providing information about the type.
++// The second is the "value" and can be any AMQP value.
++type Described struct {
++	Descriptor interface{}
++	Value      interface{}
++}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/types_test.go
----------------------------------------------------------------------
diff --cc amqp/types_test.go
index 0000000,0000000..959a558
new file mode 100644
--- /dev/null
+++ b/amqp/types_test.go
@@@ -1,0 -1,0 +1,197 @@@
++/*
++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 amqp
++
++import (
++	"fmt"
++	"reflect"
++	"testing"
++)
++
++func checkEqual(want interface{}, got interface{}) error {
++	if !reflect.DeepEqual(want, got) {
++		return fmt.Errorf("%#v != %#v", want, got)
++	}
++	return nil
++}
++
++func checkUnmarshal(marshalled []byte, v interface{}) error {
++	got, err := Unmarshal(marshalled, v)
++	if err != nil {
++		return err
++	}
++	if got != len(marshalled) {
++		return fmt.Errorf("Wanted to Unmarshal %v bytes, got %v", len(marshalled), got)
++	}
++	return nil
++}
++
++func ExampleKey() {
++	var k AnnotationKey = AnnotationKeySymbol(Symbol("foo"))
++	fmt.Println(k.Get().(Symbol))
++	k = AnnotationKeyUint64(42)
++	fmt.Println(k.Get().(uint64))
++	// Output:
++	// foo
++	// 42
++}
++
++// Values that are unchanged by a marshal/unmarshal round-trip from interface{}
++// to interface{}
++var rtValues = []interface{}{
++	true,
++	int8(-8), int16(-16), int32(-32), int64(-64),
++	uint8(8), uint16(16), uint32(32), uint64(64),
++	float32(0.32), float64(0.64),
++	"string", Binary("Binary"), Symbol("symbol"),
++	nil,
++	Map{"V": "X"},
++	List{"V", int32(1)},
++	Described{"D", "V"},
++}
++
++// Go values that unmarshal as an equivalent value but a different type
++// if unmarshalled to interface{}.
++var oddValues = []interface{}{
++	int(-99), uint(99), // [u]int32|64
++	[]byte("byte"),            // amqp.Binary
++	map[string]int{"str": 99}, // amqp.Map
++	[]string{"a", "b"},        // amqp.List
++}
++
++var allValues = append(rtValues, oddValues...)
++
++// %v formatted representation of allValues
++var vstrings = []string{
++	// for rtValues
++	"true",
++	"-8", "-16", "-32", "-64",
++	"8", "16", "32", "64",
++	"0.32", "0.64",
++	"string", "Binary", "symbol",
++	"<nil>",
++	"map[V:X]",
++	"[V 1]",
++	"{D V}",
++	// for oddValues
++	"-99", "99",
++	"[98 121 116 101]", /*"byte"*/
++	"map[str:99]",
++	"[a b]",
++}
++
++// Round-trip encoding test
++func TestTypesRoundTrip(t *testing.T) {
++	for _, x := range rtValues {
++		marshalled, err := Marshal(x, nil)
++		if err != nil {
++			t.Error(err)
++		}
++		var v interface{}
++		if err := checkUnmarshal(marshalled, &v); err != nil {
++			t.Error(err)
++		}
++		if err := checkEqual(v, x); err != nil {
++			t.Error(t, err)
++		}
++	}
++}
++
++// Round trip from T to T where T is the type of the value.
++func TestTypesRoundTripAll(t *testing.T) {
++	for _, x := range allValues {
++		marshalled, err := Marshal(x, nil)
++		if err != nil {
++			t.Error(err)
++		}
++		if x == nil { // We can't create an instance of nil to unmarshal to.
++			continue
++		}
++		vp := reflect.New(reflect.TypeOf(x)) // v points to a Zero of the same type as x
++		if err := checkUnmarshal(marshalled, vp.Interface()); err != nil {
++			t.Error(err)
++		}
++		v := vp.Elem().Interface()
++		if err := checkEqual(v, x); err != nil {
++			t.Error(err)
++		}
++	}
++}
++
++func TestTypesPrint(t *testing.T) {
++	// Default %v representations of rtValues and oddValues
++	for i, x := range allValues {
++		if s := fmt.Sprintf("%v", x); vstrings[i] != s {
++			t.Errorf("printing %T: want %v, got %v", x, vstrings[i], s)
++		}
++	}
++}
++
++func TestDescribed(t *testing.T) {
++	want := Described{"D", "V"}
++	marshalled, _ := Marshal(want, nil)
++
++	// Unmarshal to Described type
++	var d Described
++	if err := checkUnmarshal(marshalled, &d); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual(want, d); err != nil {
++		t.Error(err)
++	}
++
++	// Unmarshal to interface{}
++	var i interface{}
++	if err := checkUnmarshal(marshalled, &i); err != nil {
++		t.Error(err)
++	}
++	if _, ok := i.(Described); !ok {
++		t.Errorf("Expected Described, got %T(%v)", i, i)
++	}
++	if err := checkEqual(want, i); err != nil {
++		t.Error(err)
++	}
++
++	// Unmarshal value only (drop descriptor) to the value type
++	var s string
++	if err := checkUnmarshal(marshalled, &s); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual(want.Value, s); err != nil {
++		t.Error(err)
++	}
++
++	// Nested described types
++	want = Described{Described{int64(123), true}, "foo"}
++	marshalled, _ = Marshal(want, nil)
++	if err := checkUnmarshal(marshalled, &d); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual(want, d); err != nil {
++		t.Error(err)
++	}
++	// Nested to interface
++	if err := checkUnmarshal(marshalled, &i); err != nil {
++		t.Error(err)
++	}
++	if err := checkEqual(want, i); err != nil {
++		t.Error(err)
++	}
++}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/amqp/unmarshal.go
----------------------------------------------------------------------
diff --cc amqp/unmarshal.go
index d56cbd2,0000000..253d66d
mode 100644,000000..100644
--- a/amqp/unmarshal.go
+++ b/amqp/unmarshal.go
@@@ -1,567 -1,0 +1,638 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +oor 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 amqp
 +
 +// #include <proton/codec.h>
 +import "C"
 +
 +import (
 +	"bytes"
 +	"fmt"
 +	"io"
 +	"reflect"
++	"strings"
 +	"unsafe"
 +)
 +
 +const minDecode = 1024
 +
 +// Error returned if AMQP data cannot be unmarshaled as the desired Go type.
 +type UnmarshalError struct {
 +	// The name of the AMQP type.
 +	AMQPType string
 +	// The Go type.
 +	GoType reflect.Type
 +
 +	s string
 +}
 +
 +func (e UnmarshalError) Error() string { return e.s }
 +
- func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
++func newUnmarshalErrorMsg(pnType C.pn_type_t, v interface{}, msg string) *UnmarshalError {
++	if len(msg) > 0 && !strings.HasPrefix(msg, ":") {
++		msg = ": " + msg
++	}
 +	e := &UnmarshalError{AMQPType: C.pn_type_t(pnType).String(), GoType: reflect.TypeOf(v)}
 +	if e.GoType.Kind() != reflect.Ptr {
- 		e.s = fmt.Sprintf("cannot unmarshal to type %s, not a pointer", e.GoType)
++		e.s = fmt.Sprintf("cannot unmarshal to type %s, not a pointer%s", e.GoType, msg)
 +	} else {
- 		e.s = fmt.Sprintf("cannot unmarshal AMQP %s to %s", e.AMQPType, e.GoType)
++		e.s = fmt.Sprintf("cannot unmarshal AMQP %s to %s%s", e.AMQPType, e.GoType, msg)
 +	}
 +	return e
 +}
 +
++func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
++	return newUnmarshalErrorMsg(pnType, v, "")
++}
++
 +func newUnmarshalErrorData(data *C.pn_data_t, v interface{}) *UnmarshalError {
 +	err := PnError(C.pn_data_error(data))
 +	if err == nil {
 +		return nil
 +	}
 +	e := newUnmarshalError(C.pn_data_type(data), v)
 +	e.s = e.s + ": " + err.Error()
 +	return e
 +}
 +
 +func recoverUnmarshal(err *error) {
 +	if r := recover(); r != nil {
 +		if uerr, ok := r.(*UnmarshalError); ok {
 +			*err = uerr
 +		} else {
 +			panic(r)
 +		}
 +	}
 +}
 +
 +//
 +// Decoding from a pn_data_t
 +//
 +// NOTE: we use panic() to signal a decoding error, simplifies decoding logic.
 +// We recover() at the highest possible level - i.e. in the exported Unmarshal or Decode.
 +//
 +
 +// Decoder decodes AMQP values from an io.Reader.
 +//
 +type Decoder struct {
 +	reader io.Reader
 +	buffer bytes.Buffer
 +}
 +
 +// NewDecoder returns a new decoder that reads from r.
 +//
 +// The decoder has it's own buffer and may read more data than required for the
 +// AMQP values requested.  Use Buffered to see if there is data left in the
 +// buffer.
 +//
 +func NewDecoder(r io.Reader) *Decoder {
 +	return &Decoder{r, bytes.Buffer{}}
 +}
 +
 +// Buffered returns a reader of the data remaining in the Decoder's buffer. The
 +// reader is valid until the next call to Decode.
 +//
 +func (d *Decoder) Buffered() io.Reader {
 +	return bytes.NewReader(d.buffer.Bytes())
 +}
 +
 +// Decode reads the next AMQP value from the Reader and stores it in the value pointed to by v.
 +//
 +// See the documentation for Unmarshal for details about the conversion of AMQP into a Go value.
 +//
 +func (d *Decoder) Decode(v interface{}) (err error) {
 +	defer recoverUnmarshal(&err)
 +	data := C.pn_data(0)
 +	defer C.pn_data_free(data)
 +	var n int
 +	for n == 0 {
 +		n, err = decode(data, d.buffer.Bytes())
 +		if err != nil {
 +			return err
 +		}
 +		if n == 0 { // n == 0 means not enough data, read more
 +			err = d.more()
 +		} else {
 +			unmarshal(v, data)
 +		}
 +	}
 +	d.buffer.Next(n)
 +	return
 +}
 +
 +/*
- Unmarshal decodes AMQP-encoded bytes and stores the result in the value pointed to by v.
++Unmarshal decodes AMQP-encoded bytes and stores the result in the Go value pointed to by v.
 +Types are converted as follows:
 +
-  +---------------------------+----------------------------------------------------------------------+
-  |To Go types                |From AMQP types                                                       |
-  +===========================+======================================================================+
-  |bool                       |bool                                                                  |
-  +---------------------------+----------------------------------------------------------------------+
-  |int, int8, int16,          |Equivalent or smaller signed integer type: byte, short, int, long.    |
-  |int32, int64               |                                                                      |
-  +---------------------------+----------------------------------------------------------------------+
-  |uint, uint8, uint16,       |Equivalent or smaller unsigned integer type: ubyte, ushort, uint,     |
-  |uint32, uint64 types       |ulong                                                                 |
-  +---------------------------+----------------------------------------------------------------------+
-  |float32, float64           |Equivalent or smaller float or double.                                |
-  +---------------------------+----------------------------------------------------------------------+
-  |string, []byte             |string, symbol or binary.                                             |
-  +---------------------------+----------------------------------------------------------------------+
-  |Symbol                     |symbol                                                                |
-  +---------------------------+----------------------------------------------------------------------+
-  |map[K]T                    |map, provided all keys and values can unmarshal to types K, T         |
-  +---------------------------+----------------------------------------------------------------------+
-  |Map                        |map, any AMQP map                                                     |
-  +---------------------------+----------------------------------------------------------------------+
-  |interface{}                |Any AMQP value can be unmarshaled to an interface{} as follows:       |
-  |                           +------------------------+---------------------------------------------+
-  |                           |AMQP Type               |Go Type in interface{}                       |
-  |                           +========================+=============================================+
-  |                           |bool                    |bool                                         |
-  |                           +------------------------+---------------------------------------------+
-  |                           |byte,short,int,long     |int8,int16,int32,int64                       |
-  |                           +------------------------+---------------------------------------------+
-  |                           |ubyte,ushort,uint,ulong |uint8,uint16,uint32,uint64                   |
-  |                           +------------------------+---------------------------------------------+
-  |                           |float, double           |float32, float64                             |
-  |                           +------------------------+---------------------------------------------+
-  |                           |string                  |string                                       |
-  |                           +------------------------+---------------------------------------------+
-  |                           |symbol                  |Symbol                                       |
-  |                           +------------------------+---------------------------------------------+
-  |                           |binary                  |Binary                                       |
-  |                           +------------------------+---------------------------------------------+
-  |                           |nulll                   |nil                                          |
-  |                           +------------------------+---------------------------------------------+
-  |                           |map                     |Map                                          |
-  |                           +------------------------+---------------------------------------------+
-  |                           |list                    |List                                         |
-  +---------------------------+------------------------+---------------------------------------------+
- 
- The following Go types cannot be unmarshaled: uintptr, function, interface, channel.
- 
- TODO
- 
- Go types: array, struct.
- 
- AMQP types: decimal32/64/128, char (round trip), timestamp, uuid, array, multi-section message bodies.
- 
- AMQP maps with mixed/unhashable key types need an alternate representation.
- 
- Described types.
++ +------------------------+-------------------------------------------------+
++ |To Go types             |From AMQP types                                  |
++ +========================+=================================================+
++ |bool                    |bool                                             |
++ +------------------------+-------------------------------------------------+
++ |int, int8, int16, int32,|Equivalent or smaller signed integer type: byte, |
++ |int64                   |short, int, long.                                |
++ +------------------------+-------------------------------------------------+
++ |uint, uint8, uint16,    |Equivalent or smaller unsigned integer type:     |
++ |uint32, uint64          |ubyte, ushort, uint, ulong                       |
++ +------------------------+-------------------------------------------------+
++ |float32, float64        |Equivalent or smaller float or double.           |
++ +------------------------+-------------------------------------------------+
++ |string, []byte          |string, symbol or binary.                        |
++ +------------------------+-------------------------------------------------+
++ |Symbol                  |symbol                                           |
++ +------------------------+-------------------------------------------------+
++ |map[K]T                 |map, provided all keys and values can unmarshal  |
++ |                        |to types K,T                                     |
++ +------------------------+-------------------------------------------------+
++ |Map                     |map, any AMQP map                                |
++ +------------------------+-------------------------------------------------+
++ |Described               |described type                                   |
++ +------------------------+-------------------------------------------------+
++
++An AMQP described type can unmarshal into the corresponding plain type, discarding the descriptor.
++For example an AMQP described string can unmarshal into a plain go string.
++Unmarshal into the Described type preserves the descriptor.
++
++Any AMQP type can unmarshal to an interface{}, the Go type used to unmarshal is chosen from the AMQP type as follows
++
++ +------------------------+-------------------------------------------------+
++ |AMQP Type               |Go Type in interface{}                           |
++ +========================+=================================================+
++ |bool                    |bool                                             |
++ +------------------------+-------------------------------------------------+
++ |byte,short,int,long     |int8,int16,int32,int64                           |
++ +------------------------+-------------------------------------------------+
++ |ubyte,ushort,uint,ulong |uint8,uint16,uint32,uint64                       |
++ +------------------------+-------------------------------------------------+
++ |float, double           |float32, float64                                 |
++ +------------------------+-------------------------------------------------+
++ |string                  |string                                           |
++ +------------------------+-------------------------------------------------+
++ |symbol                  |Symbol                                           |
++ +------------------------+-------------------------------------------------+
++ |binary                  |Binary                                           |
++ +------------------------+-------------------------------------------------+
++ |null                    |nil                                              |
++ +------------------------+-------------------------------------------------+
++ |map                     |Map                                              |
++ +------------------------+-------------------------------------------------+
++ |list                    |List                                             |
++ +------------------------+-------------------------------------------------+
++ |described type          |Described                                        |
++ +--------------------------------------------------------------------------+
++
++The following Go types cannot be unmarshaled: uintptr, function, interface, channel, array (use slice), struct
++
++TODO: Not yet implemented:
++
++AMQP types: decimal32/64/128, char (round trip), timestamp, uuid.
++
++AMQP maps with mixed key types, or key types that are not legal Go map keys.
 +*/
 +func Unmarshal(bytes []byte, v interface{}) (n int, err error) {
 +	defer recoverUnmarshal(&err)
 +
 +	data := C.pn_data(0)
 +	defer C.pn_data_free(data)
 +	n, err = decode(data, bytes)
 +	if err != nil {
 +		return 0, err
 +	}
 +	if n == 0 {
 +		return 0, fmt.Errorf("not enough data")
 +	} else {
 +		unmarshal(v, data)
 +	}
 +	return n, nil
 +}
 +
++// Internal
++func UnmarshalUnsafe(pn_data unsafe.Pointer, v interface{}) (err error) {
++	defer recoverUnmarshal(&err)
++	unmarshal(v, (*C.pn_data_t)(pn_data))
++	return
++}
++
 +// more reads more data when we can't parse a complete AMQP type
 +func (d *Decoder) more() error {
 +	var readSize int64 = minDecode
 +	if int64(d.buffer.Len()) > readSize { // Grow by doubling
 +		readSize = int64(d.buffer.Len())
 +	}
 +	var n int64
 +	n, err := d.buffer.ReadFrom(io.LimitReader(d.reader, readSize))
 +	if n == 0 && err == nil { // ReadFrom won't report io.EOF, just returns 0
 +		err = io.EOF
 +	}
 +	return err
 +}
 +
 +// Unmarshal from data into value pointed at by v.
 +func unmarshal(v interface{}, data *C.pn_data_t) {
 +	pnType := C.pn_data_type(data)
++
++	// Check for PN_DESCRIBED first, as described types can unmarshal into any of the Go types.
++	// Interfaces are handled in the switch below, even for described types.
++	if _, isInterface := v.(*interface{}); !isInterface && bool(C.pn_data_is_described(data)) {
++		getDescribed(data, v)
++		return
++	}
++
++	// Unmarshal based on the target type
 +	switch v := v.(type) {
 +	case *bool:
 +		switch pnType {
 +		case C.PN_BOOL:
 +			*v = bool(C.pn_data_get_bool(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *int8:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int8(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int8(C.pn_data_get_byte(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *uint8:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint8(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint8(C.pn_data_get_ubyte(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *int16:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int16(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int16(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int16(C.pn_data_get_short(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *uint16:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint16(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint16(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint16(C.pn_data_get_ushort(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *int32:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int32(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int32(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int32(C.pn_data_get_short(data))
 +		case C.PN_INT:
 +			*v = int32(C.pn_data_get_int(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *uint32:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint32(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint32(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint32(C.pn_data_get_ushort(data))
 +		case C.PN_UINT:
 +			*v = uint32(C.pn_data_get_uint(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *int64:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int64(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int64(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int64(C.pn_data_get_short(data))
 +		case C.PN_INT:
 +			*v = int64(C.pn_data_get_int(data))
 +		case C.PN_LONG:
 +			*v = int64(C.pn_data_get_long(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *uint64:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint64(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint64(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint64(C.pn_data_get_ushort(data))
 +		case C.PN_ULONG:
 +			*v = uint64(C.pn_data_get_ulong(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *int:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int(C.pn_data_get_short(data))
 +		case C.PN_INT:
 +			*v = int(C.pn_data_get_int(data))
 +		case C.PN_LONG:
 +			if unsafe.Sizeof(int(0)) == 8 {
 +				*v = int(C.pn_data_get_long(data))
 +			} else {
 +				panic(newUnmarshalError(pnType, v))
 +			}
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *uint:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint(C.pn_data_get_ushort(data))
 +		case C.PN_UINT:
 +			*v = uint(C.pn_data_get_uint(data))
 +		case C.PN_ULONG:
 +			if unsafe.Sizeof(int(0)) == 8 {
 +				*v = uint(C.pn_data_get_ulong(data))
 +			} else {
 +				panic(newUnmarshalError(pnType, v))
 +			}
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *float32:
 +		switch pnType {
 +		case C.PN_FLOAT:
 +			*v = float32(C.pn_data_get_float(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *float64:
 +		switch pnType {
 +		case C.PN_FLOAT:
 +			*v = float64(C.pn_data_get_float(data))
 +		case C.PN_DOUBLE:
 +			*v = float64(C.pn_data_get_double(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *string:
 +		switch pnType {
 +		case C.PN_STRING:
 +			*v = goString(C.pn_data_get_string(data))
 +		case C.PN_SYMBOL:
 +			*v = goString(C.pn_data_get_symbol(data))
 +		case C.PN_BINARY:
 +			*v = goString(C.pn_data_get_binary(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *[]byte:
 +		switch pnType {
 +		case C.PN_STRING:
 +			*v = goBytes(C.pn_data_get_string(data))
 +		case C.PN_SYMBOL:
 +			*v = goBytes(C.pn_data_get_symbol(data))
 +		case C.PN_BINARY:
 +			*v = goBytes(C.pn_data_get_binary(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *Binary:
 +		switch pnType {
 +		case C.PN_BINARY:
 +			*v = Binary(goBytes(C.pn_data_get_binary(data)))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *Symbol:
 +		switch pnType {
 +		case C.PN_SYMBOL:
 +			*v = Symbol(goBytes(C.pn_data_get_symbol(data)))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *interface{}:
 +		getInterface(data, v)
 +
- 	default:
++	case *AnnotationKey:
++		if pnType == C.PN_ULONG || pnType == C.PN_SYMBOL || pnType == C.PN_STRING {
++			unmarshal(&v.value, data)
++		} else {
++			panic(newUnmarshalError(pnType, v))
++		}
++
++	default: // This is not one of the fixed well-known types, reflect for map and slice types
 +		if reflect.TypeOf(v).Kind() != reflect.Ptr {
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +		switch reflect.TypeOf(v).Elem().Kind() {
 +		case reflect.Map:
 +			getMap(data, v)
 +		case reflect.Slice:
 +			getList(data, v)
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	}
 +	if err := newUnmarshalErrorData(data, v); err != nil {
 +		panic(err)
 +	}
 +	return
 +}
 +
 +func rewindUnmarshal(v interface{}, data *C.pn_data_t) {
 +	C.pn_data_rewind(data)
 +	C.pn_data_next(data)
 +	unmarshal(v, data)
 +}
 +
 +// Getting into an interface is driven completely by the AMQP type, since the interface{}
 +// target is type-neutral.
 +func getInterface(data *C.pn_data_t, v *interface{}) {
 +	pnType := C.pn_data_type(data)
 +	switch pnType {
 +	case C.PN_BOOL:
 +		*v = bool(C.pn_data_get_bool(data))
 +	case C.PN_UBYTE:
 +		*v = uint8(C.pn_data_get_ubyte(data))
 +	case C.PN_BYTE:
 +		*v = int8(C.pn_data_get_byte(data))
 +	case C.PN_USHORT:
 +		*v = uint16(C.pn_data_get_ushort(data))
 +	case C.PN_SHORT:
 +		*v = int16(C.pn_data_get_short(data))
 +	case C.PN_UINT:
 +		*v = uint32(C.pn_data_get_uint(data))
 +	case C.PN_INT:
 +		*v = int32(C.pn_data_get_int(data))
 +	case C.PN_CHAR:
 +		*v = uint8(C.pn_data_get_char(data))
 +	case C.PN_ULONG:
 +		*v = uint64(C.pn_data_get_ulong(data))
 +	case C.PN_LONG:
 +		*v = int64(C.pn_data_get_long(data))
 +	case C.PN_FLOAT:
 +		*v = float32(C.pn_data_get_float(data))
 +	case C.PN_DOUBLE:
 +		*v = float64(C.pn_data_get_double(data))
 +	case C.PN_BINARY:
 +		*v = Binary(goBytes(C.pn_data_get_binary(data)))
 +	case C.PN_STRING:
 +		*v = goString(C.pn_data_get_string(data))
 +	case C.PN_SYMBOL:
 +		*v = Symbol(goString(C.pn_data_get_symbol(data)))
 +	case C.PN_MAP:
 +		m := make(Map)
 +		unmarshal(&m, data)
 +		*v = m
 +	case C.PN_LIST:
 +		l := make(List, 0)
 +		unmarshal(&l, data)
 +		*v = l
- 	default: // No data (-1 or NULL)
++	case C.PN_DESCRIBED:
++		d := Described{}
++		unmarshal(&d, data)
++		*v = d
++	case C.PN_NULL:
 +		*v = nil
++	case C.PN_INVALID:
++		// Allow decoding from an empty data object to an interface, treat it like NULL.
++		// This happens when optional values or properties are omitted from a message.
++		*v = nil
++	default: // Don't know how to handle this
++		panic(newUnmarshalError(pnType, v))
 +	}
 +}
 +
 +// get into map pointed at by v
 +func getMap(data *C.pn_data_t, v interface{}) {
 +	mapValue := reflect.ValueOf(v).Elem()
 +	mapValue.Set(reflect.MakeMap(mapValue.Type())) // Clear the map
 +	switch pnType := C.pn_data_type(data); pnType {
 +	case C.PN_MAP:
 +		count := int(C.pn_data_get_map(data))
 +		if bool(C.pn_data_enter(data)) {
 +			defer C.pn_data_exit(data)
 +			for i := 0; i < count/2; i++ {
 +				if bool(C.pn_data_next(data)) {
 +					key := reflect.New(mapValue.Type().Key())
 +					unmarshal(key.Interface(), data)
 +					if bool(C.pn_data_next(data)) {
 +						val := reflect.New(mapValue.Type().Elem())
 +						unmarshal(val.Interface(), data)
 +						mapValue.SetMapIndex(key.Elem(), val.Elem())
 +					}
 +				}
 +			}
 +		}
 +	default: // Empty/error/unknown, leave map empty
 +	}
 +}
 +
 +func getList(data *C.pn_data_t, v interface{}) {
 +	pnType := C.pn_data_type(data)
 +	if pnType != C.PN_LIST {
 +		panic(newUnmarshalError(pnType, v))
 +	}
 +	count := int(C.pn_data_get_list(data))
 +	listValue := reflect.MakeSlice(reflect.TypeOf(v).Elem(), count, count)
 +	if bool(C.pn_data_enter(data)) {
 +		for i := 0; i < count; i++ {
 +			if bool(C.pn_data_next(data)) {
 +				val := reflect.New(listValue.Type().Elem())
 +				unmarshal(val.Interface(), data)
 +				listValue.Index(i).Set(val.Elem())
 +			}
 +		}
 +		C.pn_data_exit(data)
 +	}
 +	reflect.ValueOf(v).Elem().Set(listValue)
 +}
 +
++func getDescribed(data *C.pn_data_t, v interface{}) {
++	d, _ := v.(*Described)
++	pnType := C.pn_data_type(data)
++	if bool(C.pn_data_enter(data)) {
++		defer C.pn_data_exit(data)
++		if bool(C.pn_data_next(data)) {
++			if d != nil {
++				unmarshal(&d.Descriptor, data)
++			}
++			if bool(C.pn_data_next(data)) {
++				if d != nil {
++					unmarshal(&d.Value, data)
++				} else {
++					unmarshal(v, data)
++				}
++				return
++			}
++		}
++	}
++	// The pn_data cursor didn't move as expected
++	panic(newUnmarshalErrorMsg(pnType, v, "bad described value encoding"))
++}
++
 +// decode from bytes.
 +// Return bytes decoded or 0 if we could not decode a complete object.
 +//
 +func decode(data *C.pn_data_t, bytes []byte) (int, error) {
 +	if len(bytes) == 0 {
 +		return 0, nil
 +	}
 +	n := int(C.pn_data_decode(data, cPtr(bytes), cLen(bytes)))
 +	if n == int(C.PN_UNDERFLOW) {
 +		C.pn_error_clear(C.pn_data_error(data))
 +		return 0, nil
 +	} else if n <= 0 {
 +		return 0, fmt.Errorf("unmarshal %s", PnErrorCode(n))
 +	}
 +	return n, nil
 +}


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


[30/50] [abbrv] qpid-proton git commit: PROTON-1490: c-proactor-test sporadic failures

Posted by ac...@apache.org.
PROTON-1490: c-proactor-test sporadic failures

Fixed bugs in test code - port binding and cleanup.


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

Branch: refs/heads/go1
Commit: b86234c65ca470d2d555e218c0c53082011676b4
Parents: 876daa7
Author: Alan Conway <ac...@redhat.com>
Authored: Thu May 25 15:32:36 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu May 25 15:32:36 2017 -0400

----------------------------------------------------------------------
 proton-c/src/tests/proactor.c   | 131 +++++++++++++----------------------
 proton-c/src/tests/test_tools.h |   2 +-
 2 files changed, 50 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b86234c6/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index 0a6df71..19cc7f3 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -296,15 +296,12 @@ static pn_event_type_t open_wake_handler(test_t *t, pn_event_t *e) {
 static void test_connection_wake(test_t *t) {
   proactor_test_t pts[] =  { { open_wake_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
-  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
-  test_port_t port = test_port(localhost);          /* Hold a port */
-  pn_proactor_listen(server, pn_listener(), port.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port.sock);
+  pn_proactor_t *client = pts[0].proactor;
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], localhost);
 
   pn_connection_t *c = pn_connection();
   pn_incref(c);                 /* Keep a reference for wake() after free */
-  pn_proactor_connect(client, c, port.host_port);
+  pn_proactor_connect(client, c, l.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   TEST_CHECK(t, pn_proactor_get(client) == NULL); /* Should be idle */
   pn_connection_wake(c);
@@ -317,7 +314,7 @@ static void test_connection_wake(test_t *t) {
 
   /* Verify we don't get a wake after close even if they happen together */
   pn_connection_t *c2 = pn_connection();
-  pn_proactor_connect(client, c2, port.host_port);
+  pn_proactor_connect(client, c2, l.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   pn_connection_wake(c2);
   pn_proactor_disconnect(client, NULL);
@@ -352,13 +349,9 @@ static pn_event_type_t listen_abort_handler(test_t *t, pn_event_t *e) {
 static void test_abort(test_t *t) {
   proactor_test_t pts[] ={ { open_close_handler }, { listen_abort_handler } };
   PROACTOR_TEST_INIT(pts, t);
-  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
-  test_port_t port = test_port(localhost);
-  pn_listener_t *l = pn_listener();
-  pn_proactor_listen(server, l, port.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port.sock);
-  pn_proactor_connect(client, pn_connection(), port.host_port);
+  pn_proactor_t *client = pts[0].proactor;
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], localhost);
+  pn_proactor_connect(client, pn_connection(), l.port.host_port);
 
   /* server transport closes */
   if (TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts))) {
@@ -371,7 +364,7 @@ static void test_abort(test_t *t) {
     TEST_COND_DESC(t, "abort", last_condition);
   }
 
-  pn_listener_close(l);
+  pn_listener_close(l.listener);
 
   while (PROACTOR_TEST_RUN(pts) != PN_PROACTOR_INACTIVE) {}
   while (PROACTOR_TEST_RUN(pts) != PN_PROACTOR_INACTIVE) {}
@@ -474,13 +467,9 @@ static void test_inactive(test_t *t) {
   proactor_test_t pts[] =  { { open_wake_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
   pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
-  test_port_t port = test_port(localhost);          /* Hold a port */
-
-  pn_listener_t *l = pn_listener();
-  pn_proactor_listen(server, l, port.host_port,  4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], localhost);
   pn_connection_t *c = pn_connection();
-  pn_proactor_connect(client, c, port.host_port);
+  pn_proactor_connect(client, c, l.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   pn_connection_wake(c);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_WAKE, PROACTOR_TEST_RUN(pts));
@@ -490,11 +479,10 @@ static void test_inactive(test_t *t) {
   TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
   /* server won't be INACTIVE until listener is closed */
   TEST_CHECK(t, pn_proactor_get(server) == NULL);
-  pn_listener_close(l);
+  pn_listener_close(l.listener);
   TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, PROACTOR_TEST_RUN(pts));
   TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
 
-  sock_close(port.sock);
   PROACTOR_TEST_FREE(pts);
 }
 
@@ -534,14 +522,10 @@ static void test_errors(test_t *t) {
 static void test_ipv4_ipv6(test_t *t) {
   proactor_test_t pts[] ={ { open_close_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
-  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
+  pn_proactor_t *client = pts[0].proactor;
 
   /* Listen on all interfaces for IPv6 only. If this fails, skip IPv6 tests */
-  test_port_t port6 = test_port("::");
-  pn_listener_t *l6 = pn_listener();
-  pn_proactor_listen(server, l6, port6.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port6.sock);
+  proactor_test_listener_t l6 = proactor_test_listen(&pts[1], "::");
   pn_event_type_t e = PROACTOR_TEST_GET(pts);
   bool has_ipv6 = (e != PN_LISTENER_CLOSE);
   if (!has_ipv6) {
@@ -550,20 +534,12 @@ static void test_ipv4_ipv6(test_t *t) {
   PROACTOR_TEST_DRAIN(pts);
 
   /* Listen on all interfaces for IPv4 only. */
-  test_port_t port4 = test_port("0.0.0.0");
-  pn_listener_t *l4 = pn_listener();
-  pn_proactor_listen(server, l4, port4.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port4.sock);
-  TEST_CHECKF(t, PROACTOR_TEST_GET(pts) != PN_LISTENER_CLOSE, "listener error: %s",  pn_condition_get_description(last_condition));
+  proactor_test_listener_t l4 = proactor_test_listen(&pts[1], "0.0.0.0");
+  TEST_CHECKF(t, PROACTOR_TEST_GET(pts) != PN_LISTENER_CLOSE, "listener error: %s", pn_condition_get_description(last_condition));
   PROACTOR_TEST_DRAIN(pts);
 
   /* Empty address listens on both IPv4 and IPv6 on all interfaces */
-  test_port_t port = test_port("");
-  pn_listener_t *l = pn_listener();
-  pn_proactor_listen(server, l, port.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port.sock);
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], "");
   e = PROACTOR_TEST_GET(pts);
   TEST_CHECKF(t, PROACTOR_TEST_GET(pts) != PN_LISTENER_CLOSE, "listener error: %s",  pn_condition_get_description(last_condition));
   PROACTOR_TEST_DRAIN(pts);
@@ -582,28 +558,28 @@ static void test_ipv4_ipv6(test_t *t) {
     PROACTOR_TEST_DRAIN(pts);                                           \
   } while(0)
 
-  EXPECT_CONNECT(port4, "127.0.0.1"); /* v4->v4 */
-  EXPECT_CONNECT(port4, "");          /* local->v4*/
+  EXPECT_CONNECT(l4.port, "127.0.0.1"); /* v4->v4 */
+  EXPECT_CONNECT(l4.port, "");          /* local->v4*/
 
-  EXPECT_CONNECT(port, "127.0.0.1"); /* v4->all */
-  EXPECT_CONNECT(port, "");          /* local->all */
+  EXPECT_CONNECT(l.port, "127.0.0.1"); /* v4->all */
+  EXPECT_CONNECT(l.port, "");          /* local->all */
 
   if (has_ipv6) {
-    EXPECT_CONNECT(port6, "::"); /* v6->v6 */
-    EXPECT_CONNECT(port6, "");     /* local->v6 */
-    EXPECT_CONNECT(port, "::1"); /* v6->all */
+    EXPECT_CONNECT(l6.port, "::"); /* v6->v6 */
+    EXPECT_CONNECT(l6.port, "");     /* local->v6 */
+    EXPECT_CONNECT(l.port, "::1"); /* v6->all */
 
-    EXPECT_FAIL(port6, "127.0.0.1"); /* fail v4->v6 */
-    EXPECT_FAIL(port4, "::1");     /* fail v6->v4 */
+    EXPECT_FAIL(l6.port, "127.0.0.1"); /* fail v4->v6 */
+    EXPECT_FAIL(l4.port, "::1");     /* fail v6->v4 */
   }
   PROACTOR_TEST_DRAIN(pts);
 
-  pn_listener_close(l);
+  pn_listener_close(l.listener);
   TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, PROACTOR_TEST_RUN(pts));
-  pn_listener_close(l4);
+  pn_listener_close(l4.listener);
   TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, PROACTOR_TEST_RUN(pts));
   if (has_ipv6) {
-    pn_listener_close(l6);
+    pn_listener_close(l6.listener);
     TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, PROACTOR_TEST_RUN(pts));
   }
 
@@ -614,19 +590,16 @@ static void test_ipv4_ipv6(test_t *t) {
 static void test_release_free(test_t *t) {
   proactor_test_t pts[] = { { open_wake_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
-  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
-  test_port_t port = test_port(localhost);
-  pn_listener_t *l = pn_listener();
-  pn_proactor_listen(server, l, port.host_port, 2);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
+  pn_proactor_t *client = pts[0].proactor;
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], localhost);
 
   /* leave one connection to the proactor  */
-  pn_proactor_connect(client, pn_connection(), port.host_port);
+  pn_proactor_connect(client, pn_connection(), l.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
 
   /* release c1 and free immediately */
   pn_connection_t *c1 = pn_connection();
-  pn_proactor_connect(client, c1, port.host_port);
+  pn_proactor_connect(client, c1, l.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   pn_proactor_release_connection(c1); /* We free but socket should still be cleaned up */
   pn_connection_free(c1);
@@ -635,7 +608,7 @@ static void test_release_free(test_t *t) {
 
   /* release c2 and but don't free till after proactor free */
   pn_connection_t *c2 = pn_connection();
-  pn_proactor_connect(client, c2, port.host_port);
+  pn_proactor_connect(client, c2, l.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   pn_proactor_release_connection(c2);
   TEST_CHECK(t, pn_proactor_get(client) == NULL); /* Should be idle */
@@ -694,13 +667,10 @@ static void test_ssl(test_t *t) {
 
   proactor_test_t pts[] ={ { ssl_handler }, { ssl_handler } };
   PROACTOR_TEST_INIT(pts, t);
-  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
-  test_port_t port = test_port(localhost);
-  pn_proactor_listen(server, pn_listener(), port.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port.sock);
+  pn_proactor_t *client = pts[0].proactor;
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], localhost);
   pn_connection_t *c = pn_connection();
-  pn_proactor_connect(client, c, port.host_port);
+  pn_proactor_connect(client, c, l.port.host_port);
   /* Open ok at both ends */
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   TEST_COND_EMPTY(t, last_condition);
@@ -785,23 +755,25 @@ static void test_parse_addr(test_t *t) {
 static void test_netaddr(test_t *t) {
   proactor_test_t pts[] ={ { open_wake_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
-  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
-  test_port_t port = test_port("127.0.0.1"); /* Use IPv4 to get consistent results all platforms */
-  pn_listener_t *l = pn_listener();
-  pn_proactor_listen(server, l, port.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
+  pn_proactor_t *client = pts[0].proactor;
+  /* Use IPv4 to get consistent results all platforms */
+  proactor_test_listener_t l = proactor_test_listen(&pts[1], "127.0.0.1");  
   pn_connection_t *c = pn_connection();
-  pn_proactor_connect(client, c, port.host_port);
-  TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
+  pn_proactor_connect(client, c, l.port.host_port);
+  if (!TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts))) {
+    TEST_COND_EMPTY(t, last_condition); /* Show the last condition */
+    return;                     /* don't continue if connection is closed */
+  }
 
   /* client remote, client local, server remote and server local address strings */
   char cr[1024], cl[1024], sr[1024], sl[1024];
 
   pn_transport_t *ct = pn_connection_transport(c);
   pn_netaddr_str(pn_netaddr_remote(ct), cr, sizeof(cr));
-  TEST_STR_IN(t, test_port_use_host(&port, ""), cr); /* remote address has listening port */
+  TEST_STR_IN(t, test_port_use_host(&l.port, ""), cr); /* remote address has listening port */
 
   pn_connection_t *s = last_accepted; /* server side of the connection */
+
   pn_transport_t *st = pn_connection_transport(s);
   if (!TEST_CHECK(t, st)) return;
   pn_netaddr_str(pn_netaddr_local(st), sl, sizeof(sl));
@@ -822,13 +794,12 @@ static void test_netaddr(test_t *t) {
                         NI_NUMERICHOST | NI_NUMERICSERV);
   TEST_CHECK(t, 0 == err);
   TEST_STR_EQUAL(t, "127.0.0.1", host);
-  TEST_STR_EQUAL(t, port.str, serv);
+  TEST_STR_EQUAL(t, l.port.str, serv);
 
   /* Make sure you can use NULL, 0 to get length of address string without a crash */
   size_t len = pn_netaddr_str(pn_netaddr_local(ct), NULL, 0);
   TEST_CHECKF(t, strlen(cl) == len, "%d != %d", strlen(cl), len);
 
-  sock_close(port.sock);
   PROACTOR_TEST_DRAIN(pts);
   PROACTOR_TEST_FREE(pts);
 }
@@ -879,12 +850,8 @@ static void test_disconnect(test_t *t) {
   TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
 
   /* Make sure the proactors are still functional */
-  test_port_t port3 = test_port(localhost);
-  pn_listener_t* l3 = pn_listener();
-  pn_proactor_listen(server, l3, port3.host_port, 4);
-  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
-  sock_close(port3.sock);
-  pn_proactor_connect(client, pn_connection(), port3.host_port);
+  proactor_test_listener_t l3 = proactor_test_listen(&pts[1], localhost);
+  pn_proactor_connect(client, pn_connection(), l3.port.host_port);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   pn_proactor_disconnect(client, NULL);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b86234c6/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 04ae0f1..af4f217 100644
--- a/proton-c/src/tests/test_tools.h
+++ b/proton-c/src/tests/test_tools.h
@@ -289,7 +289,7 @@ test_port_t test_port(const char* host) {
   socklen_t len = sizeof(addr);
   err = getsockname(tp.sock, (struct sockaddr*)&addr, &len); /* Get the bound port */
   TEST_ASSERT_ERRNO(!err, errno);
-  tp.port = addr.sin_port;
+  tp.port = ntohs(addr.sin_port);
   snprintf(tp.str, sizeof(tp.str), "%d", tp.port);
   test_port_use_host(&tp, host);
   return tp;


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


[23/50] [abbrv] qpid-proton git commit: PROTON-1288: c++ reinstate engine_test as connection_driver_test

Posted by ac...@apache.org.
PROTON-1288: c++ reinstate engine_test as connection_driver_test


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

Branch: refs/heads/go1
Commit: f2df847b552685f80429715832e55207d68bbbcb
Parents: 48a5e47
Author: Alan Conway <ac...@redhat.com>
Authored: Fri May 19 11:04:44 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 15:05:14 2017 -0400

----------------------------------------------------------------------
 examples/cpp/message_properties.cpp             | 101 +++++++
 proton-c/bindings/cpp/CMakeLists.txt            |   2 +-
 .../bindings/cpp/include/proton/terminus.hpp    |   2 +-
 .../bindings/cpp/src/connection_driver_test.cpp | 260 ++++++++++++++++++
 proton-c/bindings/cpp/src/engine_test.cpp       | 268 -------------------
 .../bindings/cpp/src/include/proton_bits.hpp    |   4 +-
 .../bindings/cpp/src/include/proton_event.hpp   |   5 +
 .../cpp/src/include/test_dummy_container.hpp    |   1 -
 8 files changed, 370 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/examples/cpp/message_properties.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/message_properties.cpp b/examples/cpp/message_properties.cpp
new file mode 100644
index 0000000..64d597b
--- /dev/null
+++ b/examples/cpp/message_properties.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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/message.hpp>
+#include <proton/types.hpp>
+#include <iostream>
+#include <map>
+
+int main(int argc, char **argv) {
+    try {
+        proton::message m;
+
+        // Setting properties: legal types are converted automatically to their
+        // AMQP counterpart.
+        m.properties().put("short", int16_t(123));
+        m.properties().put("string", "foo");
+        m.properties().put("symbol", proton::symbol("sym"));
+        m.properties().put("bool", true);
+
+        // Examining properties using proton::get()
+
+        // 1 argument get<>() template specifies expected type of property.
+        std::string s = proton::get<std::string>(m.properties().get("string"));
+
+        // 2 argument get, property must have matching type to output argument.
+        int16_t i;
+        proton::get(m.properties().get("short"), i);
+
+        // Checking property types
+        proton::type_id type = m.properties().get("symbol").type();
+        if (type != proton::SYMBOL) {
+            throw std::logic_error("wrong type!");
+        }
+
+        // proton::scalar has its own ostream <<
+        std::cout << "using put/get:"
+                  << " short=" << i
+                  << " string=" << s
+                  << " symbol=" << m.properties().get("symbol")
+                  << " bool=" << m.properties().get("bool")
+                  << std::endl;
+
+        // Converting properties to a compatible type
+        std::cout << "using coerce:"
+                  << " short(as int)=" <<  proton::coerce<int>(m.properties().get("short"))
+                  << " bool(as int)=" << proton::coerce<int>(m.properties().get("bool"))
+                  << std::endl;
+
+        // Extract the properties map for more complex map operations.
+        proton::property_std_map props;
+        proton::get(m.properties().value(), props);
+        for (proton::property_std_map::iterator i = props.begin(); i != props.end(); ++i) {
+            std::cout << "props[" << i->first << "]=" << i->second << std::endl;
+        }
+        props["string"] = "bar";
+        props["short"] = 42;
+        // Update the properties in the message from props
+        m.properties().value() = props;
+
+        std::cout << "short=" << m.properties().get("short")
+                  << " string=" << m.properties().get("string")
+                  << std::endl;
+
+        // proton::get throws an exception if types do not match exactly.
+        try {
+            proton::get<uint32_t>(m.properties().get("short")); // bad: uint32_t != int16_t
+            throw std::logic_error("expected exception");
+        } catch (const proton::conversion_error& e) {
+            std::cout << "expected conversion_error: \"" << e.what() << '"' << std::endl;
+        }
+
+        // proton::coerce throws an exception if types are not convertible.
+        try {
+            proton::get<uint32_t>(m.properties().get("string"));  // bad: string to uint32_t
+            throw std::logic_error("expected exception");
+        } catch (const proton::conversion_error& e) {
+            std::cout << "expected conversion_error: \"" << e.what() << '"' << std::endl;
+        }
+
+        return 0;
+    } catch (const std::exception& e) {
+        std::cerr << "unexpected exception: " << e.what() << std::endl;
+        return 1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index 0cc4024..04cb568 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -172,7 +172,7 @@ macro(add_cpp_test test)
 endmacro(add_cpp_test)
 
 add_cpp_test(codec_test)
-#add_cpp_test(engine_test)
+add_cpp_test(connection_driver_test)
 add_cpp_test(thread_safe_test)
 add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
 add_cpp_test(message_test)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/include/proton/terminus.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/terminus.hpp b/proton-c/bindings/cpp/include/proton/terminus.hpp
index b63a8ad..e339b84 100644
--- a/proton-c/bindings/cpp/include/proton/terminus.hpp
+++ b/proton-c/bindings/cpp/include/proton/terminus.hpp
@@ -94,7 +94,7 @@ class terminus {
     PN_CPP_EXTERN value node_properties() const;
 
   protected:
-    pn_terminus_t *pn_object() { return object_; }
+    pn_terminus_t *pn_object() const { return object_; }
   private:
     pn_terminus_t* object_;
     pn_link_t* parent_;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
new file mode 100644
index 0000000..372240b
--- /dev/null
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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_bits.hpp"
+#include "proton_bits.hpp"
+
+#include "proton/io/connection_driver.hpp"
+#include "proton/io/link_namer.hpp"
+#include "proton/link.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/receiver_options.hpp"
+#include "proton/sender_options.hpp"
+#include "proton/source_options.hpp"
+#include "proton/types_fwd.hpp"
+#include "proton/uuid.hpp"
+
+#include <deque>
+#include <algorithm>
+
+namespace {
+
+using namespace std;
+using namespace proton;
+
+using proton::io::connection_driver;
+using proton::io::const_buffer;
+using proton::io::mutable_buffer;
+
+typedef std::deque<char> byte_stream;
+
+/// In memory connection_driver that reads and writes from byte_streams
+struct in_memory_driver : public connection_driver {
+
+    byte_stream& reads;
+    byte_stream& writes;
+
+    in_memory_driver(byte_stream& rd, byte_stream& wr) : reads(rd), writes(wr) {}
+
+    void do_read() {
+        mutable_buffer rbuf = read_buffer();
+        size_t size = std::min(reads.size(), rbuf.size);
+        if (size) {
+            copy(reads.begin(), reads.begin()+size, static_cast<char*>(rbuf.data));
+            read_done(size);
+            reads.erase(reads.begin(), reads.begin()+size);
+        }
+    }
+
+    void do_write() {
+        const_buffer wbuf = write_buffer();
+        if (wbuf.size) {
+            writes.insert(writes.begin(),
+                          static_cast<const char*>(wbuf.data),
+                          static_cast<const char*>(wbuf.data) + wbuf.size);
+            write_done(wbuf.size);
+        }
+    }
+
+    void process() {
+        if (!dispatch())
+            throw std::runtime_error("unexpected close: "+connection().error().what());
+        do_read();
+        do_write();
+        dispatch();
+    }
+};
+
+/// A pair of drivers that talk to each other in-memory, simulating a connection.
+struct driver_pair {
+    byte_stream ab, ba;
+    in_memory_driver a, b;
+
+    driver_pair(const connection_options& oa, const connection_options& ob)
+        : a(ba, ab), b(ab, ba)
+    {
+        a.connect(oa);
+        b.accept(ob);
+    }
+
+    void process() { a.process(); b.process(); }
+};
+
+template <class S> typename S::value_type quick_pop(S& s) {
+    ASSERT(!s.empty());
+    typename S::value_type x = s.front();
+    s.pop_front();
+    return x;
+}
+
+/// A handler that records incoming endpoints, errors etc.
+struct record_handler : public messaging_handler {
+    std::deque<proton::receiver> receivers;
+    std::deque<proton::sender> senders;
+    std::deque<proton::session> sessions;
+    std::deque<std::string> unhandled_errors, transport_errors, connection_errors;
+
+    void on_receiver_open(receiver &l) PN_CPP_OVERRIDE {
+        receivers.push_back(l);
+    }
+
+    void on_sender_open(sender &l) PN_CPP_OVERRIDE {
+        senders.push_back(l);
+    }
+
+    void on_session_open(session &s) PN_CPP_OVERRIDE {
+        sessions.push_back(s);
+    }
+
+    void on_transport_error(transport& t) PN_CPP_OVERRIDE {
+        transport_errors.push_back(t.error().what());
+    }
+
+    void on_connection_error(connection& c) PN_CPP_OVERRIDE {
+        connection_errors.push_back(c.error().what());
+    }
+
+    void on_error(const proton::error_condition& c) PN_CPP_OVERRIDE {
+        unhandled_errors.push_back(c.what());
+    }
+};
+
+struct namer : public io::link_namer {
+    char name;
+    namer(char c) : name(c) {}
+    std::string link_name() { return std::string(1, name++); }
+};
+
+void test_driver_link_id() {
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+    e.a.connect(ha);
+    e.b.accept(hb);
+
+    namer na('x');
+    namer nb('b');
+    connection ca = e.a.connection();
+    connection cb = e.b.connection();
+    set_link_namer(ca, na);
+    set_link_namer(cb, nb);
+
+    e.b.connection().open();
+
+    e.a.connection().open_sender("foo");
+    while (ha.senders.empty() || hb.receivers.empty()) e.process();
+    sender s = quick_pop(ha.senders);
+    ASSERT_EQUAL("x", s.name());
+
+    ASSERT_EQUAL("x", quick_pop(hb.receivers).name());
+
+    e.a.connection().open_receiver("bar");
+    while (ha.receivers.empty() || hb.senders.empty()) e.process();
+    ASSERT_EQUAL("y", quick_pop(ha.receivers).name());
+    ASSERT_EQUAL("y", quick_pop(hb.senders).name());
+
+    e.b.connection().open_receiver("");
+    while (ha.senders.empty() || hb.receivers.empty()) e.process();
+    ASSERT_EQUAL("b", quick_pop(ha.senders).name());
+    ASSERT_EQUAL("b", quick_pop(hb.receivers).name());
+}
+
+void test_endpoint_close() {
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+    e.a.connection().open_sender("x");
+    e.a.connection().open_receiver("y");
+    while (ha.senders.size()+ha.receivers.size() < 2 ||
+           hb.senders.size()+hb.receivers.size() < 2) e.process();
+    proton::link ax = quick_pop(ha.senders), ay = quick_pop(ha.receivers);
+    proton::link bx = quick_pop(hb.receivers), by = quick_pop(hb.senders);
+
+    // Close a link
+    ax.close(proton::error_condition("err", "foo bar"));
+    while (!bx.closed()) e.process();
+    proton::error_condition c = bx.error();
+    ASSERT_EQUAL("err", c.name());
+    ASSERT_EQUAL("foo bar", c.description());
+    ASSERT_EQUAL("err: foo bar", c.what());
+
+    // Close a link with an empty condition
+    ay.close(proton::error_condition());
+    while (!by.closed()) e.process();
+    ASSERT(by.error().empty());
+
+    // Close a connection
+    connection ca = e.a.connection(), cb = e.b.connection();
+    ca.close(proton::error_condition("conn", "bad connection"));
+    while (!cb.closed()) e.process();
+    ASSERT_EQUAL("conn: bad connection", cb.error().what());
+    ASSERT_EQUAL(1u, hb.connection_errors.size());
+    ASSERT_EQUAL("conn: bad connection", hb.connection_errors.front());
+}
+
+void test_driver_disconnected() {
+    // driver.disconnected() aborts the connection and calls the local on_transport_error()
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+    e.a.connect(ha);
+    e.b.accept(hb);
+    while (!e.a.connection().active() || !e.b.connection().active())
+        e.process();
+
+    // Close a with an error condition. The AMQP connection is still open.
+    e.a.disconnected(proton::error_condition("oops", "driver failure"));
+    ASSERT(!e.a.dispatch());
+    ASSERT(!e.a.connection().closed());
+    ASSERT(e.a.connection().error().empty());
+    ASSERT_EQUAL(0u, ha.connection_errors.size());
+    ASSERT_EQUAL("oops: driver failure", e.a.transport().error().what());
+    ASSERT_EQUAL(1u, ha.transport_errors.size());
+    ASSERT_EQUAL("oops: driver failure", ha.transport_errors.front());
+
+    // In a real app the IO code would detect the abort and do this:
+    e.b.disconnected(proton::error_condition("broken", "it broke"));
+    ASSERT(!e.b.dispatch());
+    ASSERT(!e.b.connection().closed());
+    ASSERT(e.b.connection().error().empty());
+    ASSERT_EQUAL(0u, hb.connection_errors.size());
+    // Proton-C adds (connection aborted) if transport closes too early,
+    // and provides a default message if there is no user message.
+    ASSERT_EQUAL("broken: it broke (connection aborted)", e.b.transport().error().what());
+    ASSERT_EQUAL(1u, hb.transport_errors.size());
+    ASSERT_EQUAL("broken: it broke (connection aborted)", hb.transport_errors.front());
+}
+
+void test_no_container() {
+    // An driver with no container should throw, not crash.
+    connection_driver e;
+    try {
+        e.connection().container();
+        FAIL("expected error");
+    } catch (proton::error) {}
+}
+
+}
+
+int main(int, char**) {
+    int failed = 0;
+    RUN_TEST(failed, test_driver_link_id());
+    RUN_TEST(failed, test_endpoint_close());
+    RUN_TEST(failed, test_driver_disconnected());
+    RUN_TEST(failed, test_no_container());
+    return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/engine_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/engine_test.cpp b/proton-c/bindings/cpp/src/engine_test.cpp
deleted file mode 100644
index 991836d..0000000
--- a/proton-c/bindings/cpp/src/engine_test.cpp
+++ /dev/null
@@ -1,268 +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 "test_bits.hpp"
-#include "test_dummy_container.hpp"
-#include "proton_bits.hpp"
-
-#include "proton/container.hpp"
-#include "proton/uuid.hpp"
-#include "proton/io/connection_driver.hpp"
-#include "proton/io/link_namer.hpp"
-#include "proton/messaging_handler.hpp"
-#include "proton/types_fwd.hpp"
-#include "proton/link.hpp"
-#include <deque>
-#include <algorithm>
-
-namespace {
-
-using namespace std;
-using namespace proton;
-
-using proton::io::connection_driver;
-using proton::io::const_buffer;
-using proton::io::mutable_buffer;
-
-using test::dummy_container;
-
-typedef std::deque<char> byte_stream;
-
-/// In memory connection_driver that reads and writes from byte_streams
-struct in_memory_engine : public connection_driver {
-
-    byte_stream& reads;
-    byte_stream& writes;
-
-    in_memory_engine(byte_stream& rd, byte_stream& wr, class container& cont) :
-        connection_driver(cont), reads(rd), writes(wr) {}
-
-    void do_read() {
-        mutable_buffer rbuf = read_buffer();
-        size_t size = std::min(reads.size(), rbuf.size);
-        if (size) {
-            copy(reads.begin(), reads.begin()+size, static_cast<char*>(rbuf.data));
-            read_done(size);
-            reads.erase(reads.begin(), reads.begin()+size);
-        }
-    }
-
-    void do_write() {
-        const_buffer wbuf = write_buffer();
-        if (wbuf.size) {
-            writes.insert(writes.begin(),
-                          static_cast<const char*>(wbuf.data),
-                          static_cast<const char*>(wbuf.data) + wbuf.size);
-            write_done(wbuf.size);
-        }
-    }
-
-    void process() {
-        if (!dispatch())
-            throw std::runtime_error("unexpected close: "+connection().error().what());
-        do_read();
-        do_write();
-        dispatch();
-    }
-};
-
-/// A pair of engines that talk to each other in-memory, simulating a connection.
-struct engine_pair {
-    dummy_container conta, contb;
-    byte_stream ab, ba;
-    in_memory_engine a, b;
-
-    engine_pair(const connection_options& oa, const connection_options& ob,
-                const std::string& name=""
-    ) :
-        conta(name+"a"), contb(name+"b"), a(ba, ab, conta), b(ab, ba, contb)
-    {
-        a.connect(oa);
-        b.accept(ob);
-    }
-
-    void process() { a.process(); b.process(); }
-};
-
-template <class S> typename S::value_type quick_pop(S& s) {
-    ASSERT(!s.empty());
-    typename S::value_type x = s.front();
-    s.pop_front();
-    return x;
-}
-
-/// A handler that records incoming endpoints, errors etc.
-struct record_handler : public messaging_handler {
-    std::deque<proton::receiver> receivers;
-    std::deque<proton::sender> senders;
-    std::deque<proton::session> sessions;
-    std::deque<std::string> unhandled_errors, transport_errors, connection_errors;
-
-    void on_receiver_open(receiver &l) PN_CPP_OVERRIDE {
-        receivers.push_back(l);
-    }
-
-    void on_sender_open(sender &l) PN_CPP_OVERRIDE {
-        senders.push_back(l);
-    }
-
-    void on_session_open(session &s) PN_CPP_OVERRIDE {
-        sessions.push_back(s);
-    }
-
-    void on_transport_error(transport& t) PN_CPP_OVERRIDE {
-        transport_errors.push_back(t.error().what());
-    }
-
-    void on_connection_error(connection& c) PN_CPP_OVERRIDE {
-        connection_errors.push_back(c.error().what());
-    }
-
-    void on_error(const proton::error_condition& c) PN_CPP_OVERRIDE {
-        unhandled_errors.push_back(c.what());
-    }
-};
-
-struct namer : public io::link_namer {
-    char name;
-    namer(char c) : name(c) {}
-    std::string link_name() { return std::string(1, name++); }
-};
-
-void test_engine_container_link_id() {
-    record_handler ha, hb;
-    engine_pair e(ha, hb, "ids-");
-    e.a.connect(ha);
-    e.b.accept(hb);
-
-    namer na('x');
-    namer nb('b');
-    connection ca = e.a.connection();
-    connection cb = e.b.connection();
-    set_link_namer(ca, na);
-    set_link_namer(cb, nb);
-
-    ASSERT_EQUAL("ids-a", e.a.connection().container_id());
-    e.b.connection().open();
-    ASSERT_EQUAL("ids-b", e.b.connection().container_id());
-
-    e.a.connection().open_sender("foo");
-    while (ha.senders.empty() || hb.receivers.empty()) e.process();
-    sender s = quick_pop(ha.senders);
-    ASSERT_EQUAL("x", s.name());
-
-    ASSERT_EQUAL("x", quick_pop(hb.receivers).name());
-
-    e.a.connection().open_receiver("bar");
-    while (ha.receivers.empty() || hb.senders.empty()) e.process();
-    ASSERT_EQUAL("y", quick_pop(ha.receivers).name());
-    ASSERT_EQUAL("y", quick_pop(hb.senders).name());
-
-    e.b.connection().open_receiver("");
-    while (ha.senders.empty() || hb.receivers.empty()) e.process();
-    ASSERT_EQUAL("b", quick_pop(ha.senders).name());
-    ASSERT_EQUAL("b", quick_pop(hb.receivers).name());
-}
-
-void test_endpoint_close() {
-    record_handler ha, hb;
-    engine_pair e(ha, hb);
-    e.a.connection().open_sender("x");
-    e.a.connection().open_receiver("y");
-    while (ha.senders.size()+ha.receivers.size() < 2 ||
-           hb.senders.size()+hb.receivers.size() < 2) e.process();
-    proton::link ax = quick_pop(ha.senders), ay = quick_pop(ha.receivers);
-    proton::link bx = quick_pop(hb.receivers), by = quick_pop(hb.senders);
-
-    // Close a link
-    ax.close(proton::error_condition("err", "foo bar"));
-    while (!bx.closed()) e.process();
-    proton::error_condition c = bx.error();
-    ASSERT_EQUAL("err", c.name());
-    ASSERT_EQUAL("foo bar", c.description());
-    ASSERT_EQUAL("err: foo bar", c.what());
-
-    // Close a link with an empty condition
-    ay.close(proton::error_condition());
-    while (!by.closed()) e.process();
-    ASSERT(by.error().empty());
-
-    // Close a connection
-    connection ca = e.a.connection(), cb = e.b.connection();
-    ca.close(proton::error_condition("conn", "bad connection"));
-    while (!cb.closed()) e.process();
-    ASSERT_EQUAL("conn: bad connection", cb.error().what());
-    ASSERT_EQUAL(1u, hb.connection_errors.size());
-    ASSERT_EQUAL("conn: bad connection", hb.connection_errors.front());
-}
-
-void test_engine_disconnected() {
-    // engine.disconnected() aborts the connection and calls the local on_transport_error()
-    record_handler ha, hb;
-    engine_pair e(ha, hb, "disconnected");
-    e.a.connect(ha);
-    e.b.accept(hb);
-    while (!e.a.connection().active() || !e.b.connection().active())
-        e.process();
-
-    // Close a with an error condition. The AMQP connection is still open.
-    e.a.disconnected(proton::error_condition("oops", "engine failure"));
-    ASSERT(!e.a.dispatch());
-    ASSERT(!e.a.connection().closed());
-    ASSERT(e.a.connection().error().empty());
-    ASSERT_EQUAL(0u, ha.connection_errors.size());
-    ASSERT_EQUAL("oops: engine failure", e.a.transport().error().what());
-    ASSERT_EQUAL(1u, ha.transport_errors.size());
-    ASSERT_EQUAL("oops: engine failure", ha.transport_errors.front());
-
-    // In a real app the IO code would detect the abort and do this:
-    e.b.disconnected(proton::error_condition("broken", "it broke"));
-    ASSERT(!e.b.dispatch());
-    ASSERT(!e.b.connection().closed());
-    ASSERT(e.b.connection().error().empty());
-    ASSERT_EQUAL(0u, hb.connection_errors.size());
-    // Proton-C adds (connection aborted) if transport closes too early,
-    // and provides a default message if there is no user message.
-    ASSERT_EQUAL("broken: it broke (connection aborted)", e.b.transport().error().what());
-    ASSERT_EQUAL(1u, hb.transport_errors.size());
-    ASSERT_EQUAL("broken: it broke (connection aborted)", hb.transport_errors.front());
-}
-
-void test_no_container() {
-    // An engine with no container should throw, not crash.
-    connection_driver e;
-    try {
-        e.connection().container();
-        FAIL("expected error");
-    } catch (proton::error) {}
-    ASSERT(make_thread_safe<connection>(e.connection()).get());
-    ASSERT(!make_thread_safe<connection>(e.connection()).get()->event_loop());
-}
-
-}
-
-int main(int, char**) {
-    int failed = 0;
-    RUN_TEST(failed, test_engine_container_link_id());
-    RUN_TEST(failed, test_endpoint_close());
-    RUN_TEST(failed, test_engine_disconnected());
-    RUN_TEST(failed, test_no_container());
-    return failed;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/include/proton_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_bits.hpp b/proton-c/bindings/cpp/src/include/proton_bits.hpp
index 97d4bee..53f2230 100644
--- a/proton-c/bindings/cpp/src/include/proton_bits.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_bits.hpp
@@ -124,7 +124,7 @@ template <class T>
 class factory {
 public:
     static T wrap(typename wrapped<T>::type* t) { return t; }
-    static typename wrapped<T>::type* unwrap(T t) { return t.pn_object(); }
+    static typename wrapped<T>::type* unwrap(const T& t) { return t.pn_object(); }
 };
 
 // Get attachments for various proton-c types
@@ -142,7 +142,7 @@ template <class U>
 U make_wrapper(typename internal::wrapped<U>::type* t) { return internal::factory<U>::wrap(t); }
 
 template <class T>
-typename internal::wrapped<T>::type* unwrap(T t) {return internal::factory<T>::unwrap(t); }
+typename internal::wrapped<T>::type* unwrap(const T& t) { return internal::factory<T>::unwrap(t); }
 
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/include/proton_event.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_event.hpp b/proton-c/bindings/cpp/src/include/proton_event.hpp
index 00fdadf..374da85 100644
--- a/proton-c/bindings/cpp/src/include/proton_event.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_event.hpp
@@ -272,12 +272,17 @@ class proton_event
     {}
 
     pn_event_t* pn_event() const { return pn_event_; }
+
+    /** Return a reference to the container, throws proton::error if there is none. */
     class container& container() const {
         if (!container_)
             throw proton::error("event does not have a container");
         return *container_;
     }
 
+    /** Return a pointer to the container if there is one, NULL otherwise. */
+    class container* container_ptr() const { return container_; }
+
     /// Get type of event
     event_type type() const { return event_type(pn_event_type(pn_event_)); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/test_dummy_container.hpp b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
index 4af432a..daed435 100644
--- a/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
+++ b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
@@ -28,7 +28,6 @@ namespace test {
 
 using namespace proton;
 
-
 class dummy_container : public standard_container {
   public:
     dummy_container(const std::string cid="") :


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


[47/50] [abbrv] qpid-proton git commit: PROTON-1450: Rename AnnotationKey, correct ApplicationProperties

Posted by ac...@apache.org.
PROTON-1450: Rename AnnotationKey, correct ApplicationProperties

Renamed Key->AnnotationKey and constructors XXXKey() to AnnotationKeyXXX()
ApplicationProperties map keyed by string in accordance with AMQP spec.


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

Branch: refs/heads/go1
Commit: 4cf899be7058fb47148a1d384aeb2ee46c1641e0
Parents: da959b6
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jun 8 17:13:10 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 8 21:18:47 2017 -0400

----------------------------------------------------------------------
 .../go/src/qpid.apache.org/amqp/marshal.go      |  2 +-
 .../go/src/qpid.apache.org/amqp/marshal_test.go | 12 +++---
 .../go/src/qpid.apache.org/amqp/message.go      | 42 +++++++++++---------
 .../go/src/qpid.apache.org/amqp/message_test.go | 34 ++++++----------
 .../go/src/qpid.apache.org/amqp/types.go        | 14 +++----
 .../go/src/qpid.apache.org/amqp/types_test.go   |  4 +-
 .../go/src/qpid.apache.org/amqp/unmarshal.go    |  2 +-
 7 files changed, 53 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
index 04ecf04..dad3d25 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
@@ -209,7 +209,7 @@ func marshal(v interface{}, data *C.pn_data_t) {
 		marshal(v.Descriptor, data)
 		marshal(v.Value, data)
 		C.pn_data_exit(data)
-	case Key:
+	case AnnotationKey:
 		marshal(v.Get(), data)
 	default:
 		switch reflect.TypeOf(v).Kind() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
index 2eda33c..d8e0711 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
@@ -24,11 +24,11 @@ import (
 )
 
 func TestSymbolKey(t *testing.T) {
-	bytes, err := Marshal(SymbolKey("foo"), nil)
+	bytes, err := Marshal(AnnotationKeySymbol("foo"), nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	var k Key
+	var k AnnotationKey
 	if _, err := Unmarshal(bytes, &k); err != nil {
 		t.Error(err)
 	}
@@ -46,11 +46,11 @@ func TestSymbolKey(t *testing.T) {
 }
 
 func TestStringKey(t *testing.T) {
-	bytes, err := Marshal(StringKey("foo"), nil)
+	bytes, err := Marshal(AnnotationKeyString("foo"), nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	var k Key
+	var k AnnotationKey
 	if _, err := Unmarshal(bytes, &k); err != nil {
 		t.Error(err)
 	}
@@ -68,11 +68,11 @@ func TestStringKey(t *testing.T) {
 }
 
 func TestIntKey(t *testing.T) {
-	bytes, err := Marshal(IntKey(12345), nil)
+	bytes, err := Marshal(AnnotationKeyUint64(12345), nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	var k Key
+	var k AnnotationKey
 	if _, err := Unmarshal(bytes, &k); err != nil {
 		t.Error(err)
 	}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
index 9f4d7d1..f2270f0 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
@@ -119,18 +119,18 @@ type Message interface {
 
 	// Property map set by the application to be carried with the message.
 	// Values must be simple types (not maps, lists or sequences)
-	ApplicationProperties() map[Key]interface{}
-	SetApplicationProperties(map[Key]interface{})
+	ApplicationProperties() map[string]interface{}
+	SetApplicationProperties(map[string]interface{})
 
 	// Per-delivery annotations to provide delivery instructions.
 	// May be added or removed by intermediaries during delivery.
-	DeliveryAnnotations() map[Key]interface{}
-	SetDeliveryAnnotations(map[Key]interface{})
+	DeliveryAnnotations() map[AnnotationKey]interface{}
+	SetDeliveryAnnotations(map[AnnotationKey]interface{})
 
 	// Message annotations added as part of the bare message at creation, usually
 	// by an AMQP library. See ApplicationProperties() for adding application data.
-	MessageAnnotations() map[Key]interface{}
-	SetMessageAnnotations(map[Key]interface{})
+	MessageAnnotations() map[AnnotationKey]interface{}
+	SetMessageAnnotations(map[AnnotationKey]interface{})
 
 	// Inferred indicates how the message content
 	// is encoded into AMQP sections. If inferred is true then binary and
@@ -245,21 +245,27 @@ func (m *message) GroupId() string        { return C.GoString(C.pn_message_get_g
 func (m *message) GroupSequence() int32   { return int32(C.pn_message_get_group_sequence(m.pn)) }
 func (m *message) ReplyToGroupId() string { return C.GoString(C.pn_message_get_reply_to_group_id(m.pn)) }
 
-func getAnnotations(data *C.pn_data_t) (v map[Key]interface{}) {
+func getAnnotations(data *C.pn_data_t) (v map[AnnotationKey]interface{}) {
 	C.pn_data_rewind(data)
 	C.pn_data_next(data)
 	unmarshal(&v, data)
 	return v
 }
 
-func (m *message) DeliveryAnnotations() map[Key]interface{} {
+func (m *message) DeliveryAnnotations() map[AnnotationKey]interface{} {
 	return getAnnotations(C.pn_message_instructions(m.pn))
 }
-func (m *message) MessageAnnotations() map[Key]interface{} {
+func (m *message) MessageAnnotations() map[AnnotationKey]interface{} {
 	return getAnnotations(C.pn_message_annotations(m.pn))
 }
-func (m *message) ApplicationProperties() map[Key]interface{} {
-	return getAnnotations(C.pn_message_properties(m.pn))
+
+func (m *message) ApplicationProperties() map[string]interface{} {
+	var v map[string]interface{}
+	data := C.pn_message_properties(m.pn)
+	C.pn_data_rewind(data)
+	C.pn_data_next(data)
+	unmarshal(&v, data)
+	return v
 }
 
 // ==== message set methods
@@ -314,13 +320,13 @@ func (m *message) SetReplyToGroupId(s string) {
 	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_reply_to_group_id))
 }
 
-func (m *message) SetDeliveryAnnotations(v map[Key]interface{}) {
+func (m *message) SetDeliveryAnnotations(v map[AnnotationKey]interface{}) {
 	setData(v, C.pn_message_instructions(m.pn))
 }
-func (m *message) SetMessageAnnotations(v map[Key]interface{}) {
+func (m *message) SetMessageAnnotations(v map[AnnotationKey]interface{}) {
 	setData(v, C.pn_message_annotations(m.pn))
 }
-func (m *message) SetApplicationProperties(v map[Key]interface{}) {
+func (m *message) SetApplicationProperties(v map[string]interface{}) {
 	setData(v, C.pn_message_properties(m.pn))
 }
 
@@ -384,11 +390,11 @@ func (m *message) Properties() map[string]interface{} {
 	return oldGetAnnotations(C.pn_message_properties(m.pn))
 }
 
-// Convert old string-keyed annotations to a Key map
-func fixAnnotations(old map[string]interface{}) (annotations map[Key]interface{}) {
-	annotations = make(map[Key]interface{})
+// Convert old string-keyed annotations to an AnnotationKey map
+func fixAnnotations(old map[string]interface{}) (annotations map[AnnotationKey]interface{}) {
+	annotations = make(map[AnnotationKey]interface{})
 	for k, v := range old {
-		annotations[StringKey(k)] = v
+		annotations[AnnotationKeyString(k)] = v
 	}
 	return
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
index 3081cc5..bfebfa1 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
@@ -55,9 +55,9 @@ func TestDefaultMessage(t *testing.T) {
 		{m.ReplyToGroupId(), ""},
 		{m.MessageId(), nil},
 		{m.CorrelationId(), nil},
-		{m.DeliveryAnnotations(), map[Key]interface{}{}},
-		{m.MessageAnnotations(), map[Key]interface{}{}},
-		{m.ApplicationProperties(), map[Key]interface{}{}},
+		{m.DeliveryAnnotations(), map[AnnotationKey]interface{}{}},
+		{m.MessageAnnotations(), map[AnnotationKey]interface{}{}},
+		{m.ApplicationProperties(), map[string]interface{}{}},
 
 		// Deprecated
 		{m.Instructions(), map[string]interface{}{}},
@@ -91,9 +91,9 @@ func TestMessageRoundTrip(t *testing.T) {
 	m.SetReplyToGroupId("replytogroup")
 	m.SetMessageId("id")
 	m.SetCorrelationId("correlation")
-	m.SetDeliveryAnnotations(map[Key]interface{}{SymbolKey("instructions"): "foo"})
-	m.SetMessageAnnotations(map[Key]interface{}{SymbolKey("annotations"): "bar"})
-	m.SetApplicationProperties(map[Key]interface{}{SymbolKey("int"): int32(32), SymbolKey("bool"): true, IntKey(42): "42"})
+	m.SetDeliveryAnnotations(map[AnnotationKey]interface{}{AnnotationKeySymbol("instructions"): "foo"})
+	m.SetMessageAnnotations(map[AnnotationKey]interface{}{AnnotationKeySymbol("annotations"): "bar"})
+	m.SetApplicationProperties(map[string]interface{}{"int": int32(32), "bool": true})
 	m.Marshal("hello")
 
 	for _, data := range [][]interface{}{
@@ -113,9 +113,9 @@ func TestMessageRoundTrip(t *testing.T) {
 		{m.MessageId(), "id"},
 		{m.CorrelationId(), "correlation"},
 
-		{m.DeliveryAnnotations(), map[Key]interface{}{SymbolKey("instructions"): "foo"}},
-		{m.MessageAnnotations(), map[Key]interface{}{SymbolKey("annotations"): "bar"}},
-		{m.ApplicationProperties(), map[Key]interface{}{SymbolKey("int"): int32(32), SymbolKey("bool"): true, IntKey(42): "42"}},
+		{m.DeliveryAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("instructions"): "foo"}},
+		{m.MessageAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("annotations"): "bar"}},
+		{m.ApplicationProperties(), map[string]interface{}{"int": int32(32), "bool": true}},
 		{m.Body(), "hello"},
 
 		// Deprecated
@@ -129,16 +129,6 @@ func TestMessageRoundTrip(t *testing.T) {
 	if err := roundTrip(m); err != nil {
 		t.Error(err)
 	}
-
-	func() { // Expect a panic
-		defer func() {
-			if x, ok := recover().(*UnmarshalError); !ok {
-				t.Errorf("Expected UnmarshalError, got %#v", x)
-			}
-		}()
-		m.Properties()
-		t.Error("Expected panic")
-	}()
 }
 
 func TestDeprecated(t *testing.T) {
@@ -149,9 +139,9 @@ func TestDeprecated(t *testing.T) {
 	m.SetProperties(map[string]interface{}{"int": int32(32), "bool": true})
 
 	for _, data := range [][]interface{}{
-		{m.DeliveryAnnotations(), map[Key]interface{}{SymbolKey("instructions"): "foo"}},
-		{m.MessageAnnotations(), map[Key]interface{}{SymbolKey("annotations"): "bar"}},
-		{m.ApplicationProperties(), map[Key]interface{}{SymbolKey("int"): int32(32), SymbolKey("bool"): true}},
+		{m.DeliveryAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("instructions"): "foo"}},
+		{m.MessageAnnotations(), map[AnnotationKey]interface{}{AnnotationKeySymbol("annotations"): "bar"}},
+		{m.ApplicationProperties(), map[string]interface{}{"int": int32(32), "bool": true}},
 
 		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
 		{m.Annotations(), map[string]interface{}{"annotations": "bar"}},

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
index 6e2ebc8..9d41de6 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
@@ -195,21 +195,21 @@ func cLen(b []byte) C.size_t {
 	return C.size_t(len(b))
 }
 
-// Key is used as a map key for some AMQP "restricted" maps which are
+// AnnotationKey is used as a map key for AMQP annotation maps which are
 // allowed to have keys that are either symbol or ulong but no other type.
 //
-type Key struct {
+type AnnotationKey struct {
 	value interface{}
 }
 
-func SymbolKey(v Symbol) Key { return Key{v} }
-func IntKey(v uint64) Key    { return Key{v} }
-func StringKey(v string) Key { return Key{Symbol(v)} }
+func AnnotationKeySymbol(v Symbol) AnnotationKey { return AnnotationKey{v} }
+func AnnotationKeyUint64(v uint64) AnnotationKey { return AnnotationKey{v} }
+func AnnotationKeyString(v string) AnnotationKey { return AnnotationKey{Symbol(v)} }
 
 // Returns the value which must be Symbol, uint64 or nil
-func (k Key) Get() interface{} { return k.value }
+func (k AnnotationKey) Get() interface{} { return k.value }
 
-func (k Key) String() string { return fmt.Sprintf("%v", k.Get()) }
+func (k AnnotationKey) String() string { return fmt.Sprintf("%v", k.Get()) }
 
 // Described represents an AMQP described type, which is really
 // just a pair of AMQP values - the first is treated as a "descriptor",

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
index 096d27f..959a558 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
@@ -44,9 +44,9 @@ func checkUnmarshal(marshalled []byte, v interface{}) error {
 }
 
 func ExampleKey() {
-	var k Key = SymbolKey(Symbol("foo"))
+	var k AnnotationKey = AnnotationKeySymbol(Symbol("foo"))
 	fmt.Println(k.Get().(Symbol))
-	k = IntKey(42)
+	k = AnnotationKeyUint64(42)
 	fmt.Println(k.Get().(uint64))
 	// Output:
 	// foo

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4cf899be/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index b49727e..f679abc 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -455,7 +455,7 @@ func unmarshal(v interface{}, data *C.pn_data_t) {
 	case *interface{}:
 		getInterface(data, v)
 
-	case *Key:
+	case *AnnotationKey:
 		if pnType == C.PN_ULONG || pnType == C.PN_SYMBOL || pnType == C.PN_STRING {
 			unmarshal(&v.value, data)
 		} else {


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


[10/50] [abbrv] qpid-proton git commit: PROTON-1476: c and c++ example tests running on python 2.6

Posted by ac...@apache.org.
PROTON-1476: c and c++ example tests running on python 2.6

Using common exampletest.py 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/81ba5a3b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/81ba5a3b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/81ba5a3b

Branch: refs/heads/go1
Commit: 81ba5a3b38e450c7159caed1ffa82313d0df8409
Parents: beb38d2
Author: Alan Conway <ac...@redhat.com>
Authored: Thu May 11 10:50:09 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu May 11 12:50:39 2017 -0400

----------------------------------------------------------------------
 examples/c/proactor/CMakeLists.txt  |   3 +-
 examples/c/proactor/example_test.py |  88 ++++++++++
 examples/c/proactor/test.py         |  87 ----------
 examples/cpp/CMakeLists.txt         |  13 +-
 examples/cpp/example_test.py        | 284 +++++++++----------------------
 examples/exampletest.py             |  78 ++++++---
 6 files changed, 226 insertions(+), 327 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81ba5a3b/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index 11fb073..6ea8aaf 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -40,4 +40,5 @@ 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-example-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}/example_test.py -v)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81ba5a3b/examples/c/proactor/example_test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/example_test.py b/examples/c/proactor/example_test.py
new file mode 100644
index 0000000..38f7fc8
--- /dev/null
+++ b/examples/c/proactor/example_test.py
@@ -0,0 +1,88 @@
+#
+# 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
+#
+
+# This is a test script to run the examples and verify that they behave as expected.
+
+import unittest, sys, time
+from exampletest import *
+
+def python_cmd(name):
+    dir = os.path.dirname(__file__)
+    return [sys.executable, os.path.join(dir, "..", "..", "python", name)]
+
+def receive_expect(n):
+    return ''.join('{"sequence"=%s}\n'%i for i in xrange(1, n+1)) + "%s messages received\n"%n
+
+class Broker(object):
+    def __init__(self, test):
+        self.test = test
+
+    def __enter__(self):
+        with TestPort() as tp:
+            self.port = tp.port
+            self.host = tp.host
+            self.addr = tp.addr
+            self.proc = self.test.proc(["broker", "", self.port])
+            self.proc.wait_re("listening")
+            return self
+
+    def __exit__(self, *args):
+        b = getattr(self, "proc")
+        if b:
+            if b.poll() !=  None: # Broker crashed
+                raise ProcError(b, "broker crash")
+            b.kill()
+
+class CExampleTest(ExampleTestCase):
+
+    def test_send_receive(self):
+        """Send first then receive"""
+        with Broker(self) as b:
+            s = self.proc(["send", "", b.port])
+            self.assertEqual("10 messages sent and acknowledged\n", s.wait_exit())
+            r = self.proc(["receive", "", b.port])
+            self.assertEqual(receive_expect(10), r.wait_exit())
+
+    def test_receive_send(self):
+        """Start receiving  first, then send."""
+        with Broker(self) as b:
+            r = self.proc(["receive", "", b.port]);
+            s = self.proc(["send", "", b.port]);
+            self.assertEqual("10 messages sent and acknowledged\n", s.wait_exit())
+            self.assertEqual(receive_expect(10), r.wait_exit())
+
+    def test_send_direct(self):
+        """Send to direct server"""
+        with TestPort() as tp:
+            d = self.proc(["direct", "", tp.port])
+            d.wait_re("listening")
+            self.assertEqual("10 messages sent and acknowledged\n", self.proc(["send", "", tp.port]).wait_exit())
+            self.assertIn(receive_expect(10), d.wait_exit())
+
+    def test_receive_direct(self):
+        """Receive from direct server"""
+        with TestPort() as tp:
+            d = self.proc(["direct", "", tp.port])
+            d.wait_re("listening")
+            self.assertEqual(receive_expect(10), self.proc(["receive", "", tp.port]).wait_exit())
+            self.assertIn("10 messages sent and acknowledged\n", d.wait_exit())
+
+
+if __name__ == "__main__":
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81ba5a3b/examples/c/proactor/test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/test.py b/examples/c/proactor/test.py
deleted file mode 100644
index f62ea4e..0000000
--- a/examples/c/proactor/test.py
+++ /dev/null
@@ -1,87 +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
-#
-
-# This is a test script to run the examples and verify that they behave as expected.
-
-import unittest, sys, time
-from exampletest import *
-
-def python_cmd(name):
-    dir = os.path.dirname(__file__)
-    return [sys.executable, os.path.join(dir, "..", "..", "python", name)]
-
-def receive_expect(n):
-    return ''.join('{"sequence"=%s}\n'%i for i in xrange(1, n+1)) + "%s messages received\n"%n
-
-class Broker(object):
-    def __init__(self, test):
-        self.test = test
-
-    def __enter__(self):
-        with TestPort() as port:
-            self.port = port
-            self.proc = self.test.proc(["broker", "", self.port])
-            self.proc.wait_re("listening")
-            return self
-
-    def __exit__(self, *args):
-        b = getattr(self, "proc")
-        if b:
-            if b.poll() !=  None: # Broker crashed
-                raise ProcError(b, "broker crash")
-            b.kill()
-
-class CExampleTest(ExampleTestCase):
-
-    def test_send_receive(self):
-        """Send first then receive"""
-        with Broker(self) as b:
-            s = self.proc(["send", "", b.port])
-            self.assertEqual("10 messages sent and acknowledged\n", s.wait_out())
-            r = self.proc(["receive", "", b.port])
-            self.assertEqual(receive_expect(10), r.wait_out())
-
-    def test_receive_send(self):
-        """Start receiving  first, then send."""
-        with Broker(self) as b:
-            r = self.proc(["receive", "", b.port]);
-            s = self.proc(["send", "", b.port]);
-            self.assertEqual("10 messages sent and acknowledged\n", s.wait_out())
-            self.assertEqual(receive_expect(10), r.wait_out())
-
-    def test_send_direct(self):
-        """Send to direct server"""
-        with TestPort() as port:
-            d = self.proc(["direct", "", port])
-            d.wait_re("listening")
-            self.assertEqual("10 messages sent and acknowledged\n", self.proc(["send", "", port]).wait_out())
-            self.assertIn(receive_expect(10), d.wait_out())
-
-    def test_receive_direct(self):
-        """Receive from direct server"""
-        with TestPort() as port:
-            addr = "127.0.0.1:%s" % port
-            d = self.proc(["direct", "", port])
-            d.wait_re("listening")
-            self.assertEqual(receive_expect(10), self.proc(["receive", "", port]).wait_out())
-            self.assertIn("10 messages sent and acknowledged\n", d.wait_out())
-
-
-if __name__ == "__main__":
-    unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81ba5a3b/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index 304d899..236aac7 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -30,7 +30,7 @@ macro(add_cpp_test name)
   else(WIN32)
     set(test_path "$<TARGET_FILE_DIR:broker>:$ENV{PATH}")
   endif(WIN32)
-  set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py)
+  set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py ${EXAMPLE_ENV})
   add_test(NAME ${name} COMMAND ${run_env} "PATH=${test_path}" ${VALGRIND_ENV} -- ${ARGN})
 endmacro()
 
@@ -64,17 +64,6 @@ if(HAS_CPP11)
       scheduled_send)
     add_executable(${example} ${example}.cpp)
   endforeach()
-
-  # Linux-only multi-threaded examples (TODO make these portable)
-#   if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-#     set(container_src mt/epoll_container.cpp)
-#     foreach(example
-#         broker)
-#       add_executable(mt_${example} mt/${example}.cpp ${container_src})
-#       target_link_libraries(mt_${example} pthread)
-#     endforeach()
-#     add_cpp_test(cpp-example-mt ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v MtBrokerTest)
-#   endif()
 endif()
 
 add_cpp_test(cpp-example-container ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleTest)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81ba5a3b/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index e2052dc..a80ee5c 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -21,6 +21,7 @@
 
 import unittest
 import os, sys, socket, time, re, inspect
+from exampletest import *
 from  random import randrange
 from subprocess import Popen, PIPE, STDOUT, call
 from copy import copy
@@ -80,148 +81,6 @@ def ensureCanTestExtendedSASL():
   if not createdSASLDb:
     raise Skipped("Can't Test Extended SASL: Couldn't create auth db")
 
-def pick_addr():
-    """Pick a new host:port address."""
-    # TODO Conway 2015-07-14: need a safer way to pick ports.
-    p =  randrange(10000, 20000)
-    return "127.0.0.1:%s" % p
-
-class ProcError(Exception):
-    """An exception that captures failed process output"""
-    def __init__(self, proc, what="non-0 exit"):
-        out = proc.out.strip()
-        if out:
-            out = "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^\n" % out
-        else:
-            out = ", no output)"
-        super(Exception, self, ).__init__(
-            "%s %s, code=%s%s" % (proc.args, what, proc.returncode, out))
-
-class Proc(Popen):
-    """A example process that stores its stdout and can scan it for a 'ready' pattern'"""
-
-    if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
-        env_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
-    else:
-        env_args = []
-
-    def __init__(self, args, ready=None, timeout=30, skip_valgrind=False, **kwargs):
-        """Start an example process"""
-        args = list(args)
-        if platform.system() == "Windows":
-            args[0] += ".exe"
-        self.timeout = timeout
-        self.args = args
-        self.out = ""
-        if not skip_valgrind:
-            args = self.env_args + args
-        try:
-            Popen.__init__(self, args, stdout=PIPE, stderr=STDOUT,
-                           universal_newlines=True,  **kwargs)
-        except Exception as e:
-            raise ProcError(self, str(e))
-        # Start reader thread.
-        self.pattern = ready
-        self.ready = Event()
-        # Help with Python 2.5, 2.6, 2.7 changes to Event.wait(), Event.is_set
-        self.ready_set = False
-        self.error = None
-        self.thread = Thread(target=self.run_)
-        self.thread.daemon = True
-        self.thread.start()
-        if self.pattern:
-            self.wait_ready()
-
-    def run_(self):
-        try:
-            while True:
-                l = self.stdout.readline()
-                if not l: break
-                self.out += l
-                if self.pattern is not None:
-                    if re.search(self.pattern, l):
-                        self.ready_set = True
-                        self.ready.set()
-            if self.wait() != 0:
-                raise ProcError(self)
-        except Exception as e:
-            self.error = e
-        finally:
-            self.stdout.close()
-            self.ready_set = True
-            self.ready.set()
-
-    def safe_kill(self):
-        """Kill and clean up zombie but don't wait forever. No exceptions."""
-        try:
-            self.kill()
-            self.thread.join(self.timeout)
-        except: pass
-        return self.out
-
-    def check_(self):
-        if self.error:
-            raise self.error
-
-    def wait_ready(self):
-        """Wait for ready to appear in output"""
-        self.ready.wait(self.timeout)
-        if self.ready_set:
-            self.check_()
-            return self.out
-        else:
-            self.safe_kill()
-            raise ProcError(self, "timeout waiting for '%s'" % self.pattern)
-
-    def wait_exit(self):
-        """Wait for process to exit, return output. Raise ProcError on failure."""
-        self.thread.join(self.timeout)
-        if self.poll() is not None:
-            self.check_()
-            return self.out
-        else:
-            raise ProcError(self, "timeout waiting for exit")
-
-
-if hasattr(unittest.TestCase, 'setUpClass') and  hasattr(unittest.TestCase, 'tearDownClass'):
-    TestCase = unittest.TestCase
-else:
-    class TestCase(unittest.TestCase):
-        """
-        Roughly provides setUpClass and tearDownClass functionality for older python
-        versions in our test scenarios. If subclasses override setUp or tearDown
-        they *must* call the superclass.
-        """
-        def setUp(self):
-            if not hasattr(type(self), '_setup_class_count'):
-                type(self)._setup_class_count = len(
-                    inspect.getmembers(
-                        type(self),
-                        predicate=lambda m: inspect.ismethod(m) and m.__name__.startswith('test_')))
-                type(self).setUpClass()
-
-        def tearDown(self):
-            self.assertTrue(self._setup_class_count > 0)
-            self._setup_class_count -=  1
-            if self._setup_class_count == 0:
-                type(self).tearDownClass()
-
-
-class ExampleTestCase(TestCase):
-    """TestCase that manages started processes"""
-    def setUp(self):
-        super(ExampleTestCase, self).setUp()
-        self.procs = []
-
-    def tearDown(self):
-        for p in self.procs:
-            p.safe_kill()
-        super(ExampleTestCase, self).tearDown()
-
-    def proc(self, *args, **kwargs):
-        p = Proc(*args, **kwargs)
-        self.procs.append(p)
-        return p
 
 class BrokerTestCase(ExampleTestCase):
     """
@@ -231,14 +90,16 @@ class BrokerTestCase(ExampleTestCase):
 
     @classmethod
     def setUpClass(cls):
-        cls.addr = pick_addr() + "/examples"
         cls.broker = None       # In case Proc throws, create the attribute.
-        cls.broker = Proc([cls.broker_exe, "-a", cls.addr], ready="listening")
-        cls.broker.wait_ready()
+        with TestPort() as tp:
+            cls.addr = "%s:%s/example" % (tp.host, tp.port)
+            cls.broker = Proc([cls.broker_exe, "-a", tp.addr])
+            cls.broker.wait_re("listening")
 
     @classmethod
     def tearDownClass(cls):
-        if cls.broker: cls.broker.safe_kill()
+        if cls.broker:
+            cls.broker.kill()
 
     def tearDown(self):
         b = type(self).broker
@@ -267,7 +128,8 @@ class ContainerExampleTest(BrokerTestCase):
         self.assertEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit())
 
     def test_helloworld_direct(self):
-        self.assertEqual('Hello World!\n', self.proc(["helloworld_direct", pick_addr()]).wait_exit())
+        with TestPort() as tp:
+            self.assertEqual('Hello World!\n', self.proc(["helloworld_direct", tp.addr]).wait_exit())
 
     def test_simple_send_recv(self):
         self.assertEqual("all messages confirmed\n",
@@ -283,21 +145,22 @@ class ContainerExampleTest(BrokerTestCase):
 
 
     def test_simple_send_direct_recv(self):
-        addr = pick_addr()
-        recv = self.proc(["direct_recv", "-a", addr], "listening")
-        self.assertEqual("all messages confirmed\n",
-                         self.proc(["simple_send", "-a", addr]).wait_exit())
-        self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
+        with TestPort() as tp:
+            addr = "%s/examples" % tp.addr
+            recv = self.proc(["direct_recv", "-a", addr], "listening")
+            self.assertEqual("all messages confirmed\n",
+                             self.proc(["simple_send", "-a", addr]).wait_exit())
+            self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
 
     def test_simple_recv_direct_send(self):
-        addr = pick_addr()
-        send = self.proc(["direct_send", "-a", addr], "listening")
-        self.assertEqual(recv_expect("simple_recv", addr),
-                         self.proc(["simple_recv", "-a", addr]).wait_exit())
-
-        self.assertEqual(
-            "direct_send listening on %s\nall messages confirmed\n" % addr,
-            send.wait_exit())
+        with TestPort() as tp:
+            addr = "%s/examples" % tp.addr
+            send = self.proc(["direct_send", "-a", addr], "listening")
+            self.assertEqual(recv_expect("simple_recv", addr),
+                             self.proc(["simple_recv", "-a", addr]).wait_exit())
+            self.assertEqual(
+                "direct_send listening on %s\nall messages confirmed\n" % addr,
+                send.wait_exit())
 
     def test_request_response(self):
         server = self.proc(["server", "-a", self.addr], "connected")
@@ -305,10 +168,11 @@ class ContainerExampleTest(BrokerTestCase):
                          self.proc(["client", "-a", self.addr]).wait_exit())
 
     def test_request_response_direct(self):
-        addr = pick_addr()
-        server = self.proc(["server_direct", "-a", addr+"/examples"], "listening")
-        self.assertEqual(CLIENT_EXPECT,
-                         self.proc(["client", "-a", addr+"/examples"]).wait_exit())
+        with TestPort() as tp:
+            addr = "%s/examples" % tp.addr
+            server = self.proc(["server_direct", "-a", addr], "listening")
+            self.assertEqual(CLIENT_EXPECT,
+                             self.proc(["client", "-a", addr]).wait_exit())
 
     def test_flow_control(self):
         want="""success: Example 1: simple credit
@@ -316,7 +180,8 @@ success: Example 2: basic drain
 success: Example 3: drain without credit
 success: Exmaple 4: high/low watermark
 """
-        self.assertEqual(want, self.proc(["flow_control", "--address", pick_addr(), "--quiet"]).wait_exit())
+        with TestPort() as tp:
+            self.assertEqual(want, self.proc(["flow_control", "--address", tp.addr, "--quiet"]).wait_exit())
 
     def test_encode_decode(self):
         want="""
@@ -345,6 +210,21 @@ map{string(k1):int(42), symbol(k2):boolean(0)}
         self.maxDiff = None
         self.assertEqual(want, self.proc(["encode_decode"]).wait_exit())
 
+
+class ContainerExampleSSLTest(BrokerTestCase):
+    """Run the SSL container examples, verify they behave as expected."""
+
+    broker_exe = "broker"
+
+    def setUp(self):
+        if not SSL.present:
+            self.skip("SSL not available")
+        self.vg_args = Proc.vg_args
+        Proc.vg_args = []       # Disable
+
+    def tearDown(self):
+        Proc.vg_args = self.vg_args
+
     def ssl_certs_dir(self):
         """Absolute path to the test SSL certificates"""
         pn_root = dirname(dirname(dirname(sys.argv[0])))
@@ -352,30 +232,33 @@ map{string(k1):int(42), symbol(k2):boolean(0)}
 
     def test_ssl(self):
         # SSL without SASL, VERIFY_PEER_NAME
-        addr = "amqps://" + pick_addr() + "/examples"
-        # Disable valgrind when using OpenSSL
-        out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir()], skip_valgrind=True).wait_exit()
-        expect = "Outgoing client connection connected via SSL.  Server certificate identity CN=test_server\nHello World!"
-        expect_found = (out.find(expect) >= 0)
-        self.assertEqual(expect_found, True)
+        with TestPort() as tp:
+            addr = "amqps://%s/examples" % tp.addr
+            # Disable valgrind when using OpenSSL
+            out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir()], skip_valgrind=True).wait_exit()
+            expect = "Outgoing client connection connected via SSL.  Server certificate identity CN=test_server\nHello World!"
+            expect_found = (out.find(expect) >= 0)
+            self.assertEqual(expect_found, True)
 
     def test_ssl_no_name(self):
         # VERIFY_PEER
-        addr = "amqps://" + pick_addr() + "/examples"
-        # Disable valgrind when using OpenSSL
-        out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), "-v", "noname"], skip_valgrind=True).wait_exit()
-        expect = "Outgoing client connection connected via SSL.  Server certificate identity CN=test_server\nHello World!"
-        expect_found = (out.find(expect) >= 0)
-        self.assertEqual(expect_found, True)
+        with TestPort() as tp:
+            addr = "amqps://%s/examples" % tp.addr
+            # Disable valgrind when using OpenSSL
+            out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), "-v", "noname"], skip_valgrind=True).wait_exit()
+            expect = "Outgoing client connection connected via SSL.  Server certificate identity CN=test_server\nHello World!"
+            expect_found = (out.find(expect) >= 0)
+            self.assertEqual(expect_found, True)
 
     def test_ssl_bad_name(self):
         # VERIFY_PEER
-        addr = "amqps://" + pick_addr() + "/examples"
-        # Disable valgrind when using OpenSSL
-        out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), "-v", "fail"], skip_valgrind=True).wait_exit()
-        expect = "Expected failure of connection with wrong peer name"
-        expect_found = (out.find(expect) >= 0)
-        self.assertEqual(expect_found, True)
+        with TestPort() as tp:
+            addr = "amqps://%s/examples" % tp.addr
+            # Disable valgrind when using OpenSSL
+            out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), "-v", "fail"], skip_valgrind=True).wait_exit()
+            expect = "Expected failure of connection with wrong peer name"
+            expect_found = (out.find(expect) >= 0)
+            self.assertEqual(expect_found, True)
 
     def test_ssl_client_cert(self):
         # SSL with SASL EXTERNAL
@@ -383,11 +266,12 @@ map{string(k1):int(42), symbol(k2):boolean(0)}
 Outgoing client connection connected via SSL.  Server certificate identity CN=test_server
 Hello World!
 """
-        addr = "amqps://" + pick_addr() + "/examples"
-        # Disable valgrind when using OpenSSL
-        out = self.proc(["ssl_client_cert", addr, self.ssl_certs_dir()], skip_valgrind=True).wait_exit()
-        expect_found = (out.find(expect) >= 0)
-        self.assertEqual(expect_found, True)
+        with TestPort() as tp:
+            addr = "amqps://%s/examples" % tp.addr
+            # Disable valgrind when using OpenSSL
+            out = self.proc(["ssl_client_cert", addr, self.ssl_certs_dir()], skip_valgrind=True).wait_exit()
+            expect_found = (out.find(expect) >= 0)
+            self.assertEqual(expect_found, True)
 
     def test_scheduled_send_03(self):
         # Output should be a bunch of "send" lines but can't guarantee exactly how many.
@@ -424,19 +308,21 @@ class EngineTestCase(BrokerTestCase):
 
 
     def test_simple_send_direct_recv(self):
-        addr = pick_addr()
-        recv = self.proc(["direct_recv", "-a", addr], "listening")
-        self.assertEqual("all messages confirmed\n",
-                         self.proc(["simple_send", "-a", addr]).wait_exit())
-        self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
+        with TestPort() as tp:
+            addr = "%s/examples" % tp.addr
+            recv = self.proc(["direct_recv", "-a", addr], "listening")
+            self.assertEqual("all messages confirmed\n",
+                             self.proc(["simple_send", "-a", addr]).wait_exit())
+            self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
 
     def test_simple_recv_direct_send(self):
-        addr = pick_addr()
-        send = self.proc(["direct_send", "-a", addr], "listening")
-        self.assertEqual(recv_expect("simple_recv", addr),
-                         self.proc(["simple_recv", "-a", addr]).wait_exit())
-        self.assertEqual("direct_send listening on %s\nall messages confirmed\n" % addr,
-                         send.wait_exit())
+        with TestPort() as tp:
+            addr = "%s/examples" % tp.addr
+            send = self.proc(["direct_send", "-a", tp.addr], "listening")
+            self.assertEqual(recv_expect("simple_recv", addr),
+                             self.proc(["simple_recv", "-a", addr]).wait_exit())
+            self.assertEqual("direct_send listening on %s\nall messages confirmed\n" % addr,
+                             send.wait_exit())
 
     def test_request_response(self):
         server = self.proc(["server", "-a", self.addr], "connected")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81ba5a3b/examples/exampletest.py
----------------------------------------------------------------------
diff --git a/examples/exampletest.py b/examples/exampletest.py
index 71aa463..bb055a1 100644
--- a/examples/exampletest.py
+++ b/examples/exampletest.py
@@ -36,11 +36,12 @@ class TestPort(object):
     def __init__(self):
         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.sock.bind(('', 0))
-        self.port = socket.getnameinfo(self.sock.getsockname(), 0)[1]
+        self.sock.bind(('127.0.0.1', 0)) # Testing exampless is local only
+        self.host, self.port = socket.getnameinfo(self.sock.getsockname(), 0)
+        self.addr = "%s:%s" % (self.host, self.port)
 
     def __enter__(self):
-        return self.port
+        return self
 
     def __exit__(self, *args):
         self.close()
@@ -57,32 +58,36 @@ class ProcError(Exception):
         else:
             out = ", no output)"
         super(Exception, self, ).__init__(
-            "%s %s, code=%s%s" % (proc.args, what, proc.returncode, out))
+            "%s %s, code=%s%s" % (proc.args, what, getattr(proc, 'returncode', 'noreturn'), out))
 
 class NotFoundError(ProcError):
     pass
 
 class Proc(Popen):
-    """A example process that stores its output, optionally run with valgrind."""
+    """A example process that stores its stdout and can scan it for a 'ready' pattern'"""
 
     if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
-        env_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
+        vg_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
     else:
-        env_args = []
+        vg_args = []
 
     @property
     def out(self):
         self._out.seek(0)
-        return self._out.read()
+        # Normalize line endings, os.tmpfile() opens in binary mode.
+        return self._out.read().replace('\r\n','\n').replace('\r','\n')
 
-    def __init__(self, args, **kwargs):
+    def __init__(self, args, skip_valgrind=False, **kwargs):
         """Start an example process"""
         args = list(args)
-        self.args = args
+        if skip_valgrind:
+            self.args = args
+        else:
+            self.args = self.vg_args + args
         self.kwargs = kwargs
         self._out = os.tmpfile()
         try:
-            Popen.__init__(self, self.env_args + self.args, stdout=self._out, stderr=STDOUT, **kwargs)
+            Popen.__init__(self, self.args, stdout=self._out, stderr=STDOUT, **kwargs)
         except OSError, e:
             if e.errno == errno.ENOENT:
                 raise NotFoundError(self, str(e))
@@ -98,7 +103,7 @@ class Proc(Popen):
             pass                # Already exited.
         return self.out
 
-    def wait_out(self, timeout=DEFAULT_TIMEOUT, expect=0):
+    def wait_exit(self, timeout=DEFAULT_TIMEOUT, expect=0):
         """Wait for process to exit, return output. Raise ProcError  on failure."""
         t = threading.Thread(target=self.wait)
         t.start()
@@ -124,29 +129,46 @@ class Proc(Popen):
             time.sleep(0.01)    # Not very efficient
         raise ProcError(self, "gave up waiting for '%s' after %ss" % (regexp, timeout))
 
-# Work-around older python unittest that lacks setUpClass.
-if hasattr(unittest.TestCase, 'setUpClass') and  hasattr(unittest.TestCase, 'tearDownClass'):
-    TestCase = unittest.TestCase
-else:
-    class TestCase(unittest.TestCase):
-        """
-        Roughly provides setUpClass and tearDownClass functionality for older python
-        versions in our test scenarios. If subclasses override setUp or tearDown
-        they *must* call the superclass.
-        """
+def _tc_missing(attr):
+    return not hasattr(unittest.TestCase, attr)
+
+class TestCase(unittest.TestCase):
+    """
+    Roughly provides setUpClass() and tearDownClass() and other features missing
+    in python 2.6. If subclasses override setUp() or tearDown() they *must*
+    call the superclass.
+    """
+
+    if _tc_missing('setUpClass') and _tc_missing('tearDownClass'):
+
+        @classmethod
+        def setUpClass(cls):
+            pass
+
+        @classmethod
+        def tearDownClass(cls):
+            pass
+
         def setUp(self):
-            if not hasattr(type(self), '_setup_class_count'):
-                type(self)._setup_class_count = len(
-                    inspect.getmembers(
-                        type(self),
-                        predicate=lambda(m): inspect.ismethod(m) and m.__name__.startswith('test_')))
-                type(self).setUpClass()
+            super(TestCase, self).setUp()
+            cls = type(self)
+            if not hasattr(cls, '_setup_class_count'): # First time
+                def is_test(m):
+                    return inspect.ismethod(m) and m.__name__.startswith('test_')
+                cls._setup_class_count = len(inspect.getmembers(cls, predicate=is_test))
+                cls.setUpClass()
 
         def tearDown(self):
             self.assertTrue(self._setup_class_count > 0)
             self._setup_class_count -=  1
             if self._setup_class_count == 0:
                 type(self).tearDownClass()
+            super(TestCase, self).tearDown()
+
+    if _tc_missing('assertIn'):
+
+        def assertIn(self, a, b):
+            self.assertTrue(a in b, "%r not in %r" % (a, b))
 
 class ExampleTestCase(TestCase):
     """TestCase that manages started processes"""


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


[38/50] [abbrv] qpid-proton git commit: PROTON-1495: c libuv proactor bug with multiple listeners

Posted by ac...@apache.org.
PROTON-1495: c libuv proactor bug with multiple listeners

Listener was incorrectly overwriting the uv_tcp_t struct in an lsocket_t if it
there was a resolve failure. Once uv_tcp_init is called the uv_tcp_t must be
uv_closed and wait for the on_close() callback before freeing or re-using the 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/d4806000
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d4806000
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d4806000

Branch: refs/heads/go1
Commit: d4806000b3eb7e6b556c07819dd642ed9e0a3668
Parents: 54645b7
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Jun 5 12:50:19 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Jun 5 13:27:47 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/libuv.c | 92 +++++++++++++++++++++-----------------
 1 file changed, 52 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d4806000/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 8cd6dd7..e632f10 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -149,6 +149,7 @@ typedef struct lsocket_t {
   struct_type type;             /* Always T_LSOCKET */
   pn_listener_t *parent;
   uv_tcp_t tcp;
+  struct lsocket_t *next;
 } lsocket_t;
 
 PN_STRUCT_CLASSDEF(lsocket, CID_pn_listener_socket)
@@ -193,7 +194,7 @@ typedef enum {
   L_UNINIT,                     /**<< Not yet listening */
   L_LISTENING,                  /**<< Listening */
   L_CLOSE,                      /**<< Close requested  */
-  L_CLOSING,                    /**<< Socket close initiated, wait for close */
+  L_CLOSING,                    /**<< Socket close initiated, wait for all to close */
   L_CLOSED                      /**<< User saw PN_LISTENER_CLOSED, all done  */
 } listener_state;
 
@@ -201,10 +202,6 @@ typedef enum {
 struct pn_listener_t {
   work_t work;                  /* Must be first to allow casting */
 
-  size_t nsockets;
-  lsocket_t *sockets;
-  lsocket_t prealloc[1];       /* Pre-allocated socket array, allocate larger if needed */
-
   /* Only used by owner thread */
   pn_event_batch_t batch;
   pn_record_t *attachments;
@@ -213,6 +210,7 @@ struct pn_listener_t {
 
   /* Only used by leader */
   addr_t addr;
+  lsocket_t *lsockets;
 
   /* Locked for thread-safe access. uv_listen can't be stopped or cancelled so we can't
    * detach a listener from the UV loop to prevent concurrent access.
@@ -424,10 +422,15 @@ static void listener_close_lh(pn_listener_t* l) {
 static void on_close_lsocket(uv_handle_t *h) {
   lsocket_t* ls = (lsocket_t*)h->data;
   pn_listener_t *l = ls->parent;
-  uv_mutex_lock(&l->lock);
-  --l->nsockets;
-  listener_close_lh(l);
-  uv_mutex_unlock(&l->lock);
+  if (l) {
+    /* Remove from list */
+    lsocket_t **pp = &l->lsockets;
+    for (; *pp != ls; pp = &(*pp)->next)
+      ;
+    *pp = ls->next;
+    work_notify(&l->work);
+  }
+  free(ls);
 }
 
 static pconnection_t *get_pconnection(pn_connection_t* c) {
@@ -611,16 +614,27 @@ static bool leader_connect(pconnection_t *pc) {
   }
 }
 
-static int lsocket_init(lsocket_t *ls, pn_listener_t *l, struct addrinfo *ai) {
+static int lsocket(pn_listener_t *l, struct addrinfo *ai) {
+  lsocket_t *ls = (lsocket_t*)calloc(1, sizeof(lsocket_t));
   ls->type = T_LSOCKET;
-  ls->parent = l;
   ls->tcp.data = ls;
+  ls->parent = NULL;
+  ls->next = NULL;
   int err = uv_tcp_init(&l->work.proactor->loop, &ls->tcp);
-  if (!err) {
+  if (err) {
+    free(ls);                   /* Will never be closed */
+  } else {
     int flags = (ai->ai_family == AF_INET6) ? UV_TCP_IPV6ONLY : 0;
     err = uv_tcp_bind(&ls->tcp, ai->ai_addr, flags);
     if (!err) err = uv_listen((uv_stream_t*)&ls->tcp, l->backlog, on_connection);
-    if (err) uv_close((uv_handle_t*)&ls->tcp, NULL);
+    if (!err) {
+      /* Add to l->lsockets list */
+      ls->parent = l;
+      ls->next = l->lsockets;
+      l->lsockets = ls;
+    } else {
+      uv_close((uv_handle_t*)&ls->tcp, on_close_lsocket); /* Freed by on_close_lsocket */
+    }
   }
   return err;
 }
@@ -632,28 +646,18 @@ static void leader_listen_lh(pn_listener_t *l) {
   leader_inc(l->work.proactor);
   int err = leader_resolve(l->work.proactor, &l->addr, true);
   if (!err) {
-    /* Count addresses, allocate enough space */
-    size_t len = 0;
-    for (struct addrinfo *ai = l->addr.getaddrinfo.addrinfo; ai; ai = ai->ai_next) {
-      ++len;
-    }
-    assert(len > 0);            /* Guaranteed by getaddrinfo() */
-    l->sockets = (len > ARRAY_LEN(l->prealloc)) ? (lsocket_t*)calloc(len, sizeof(lsocket_t)) : l->prealloc;
     /* Find the working addresses */
-    l->nsockets = 0;
-    int first_err = 0;
     for (struct addrinfo *ai = l->addr.getaddrinfo.addrinfo; ai; ai = ai->ai_next) {
-      lsocket_t *ls = &l->sockets[l->nsockets];
-      int err2 = lsocket_init(ls, l, ai);
-      if (!err2) {
-        ++l->nsockets;                    /* Next socket */
-      } else if (!first_err) {
-        first_err = err2;
+      int err2 = lsocket(l, ai);
+      if (err2) {
+        err = err2;
       }
     }
     uv_freeaddrinfo(l->addr.getaddrinfo.addrinfo);
     l->addr.getaddrinfo.addrinfo = NULL;
-    if (l->nsockets == 0) err = first_err;
+    if (l->lsockets) {    /* Ignore errors if we got at least one good listening socket */
+      err = 0;
+    }
   }
   /* Always put an OPEN event for symmetry, even if we immediately close with err */
   pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_OPEN);
@@ -670,7 +674,11 @@ void pn_listener_free(pn_listener_t *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->sockets && l->sockets != l->prealloc) free(l->sockets);
+    while (l->lsockets) {
+      lsocket_t *ls = l->lsockets;
+      l->lsockets = ls->next;
+      free(ls);
+    }
     assert(!l->accept.front);
     free(l);
   }
@@ -707,13 +715,13 @@ static bool leader_process_listener(pn_listener_t *l) {
 
    case L_CLOSE:                /* Close requested, start closing lsockets */
     l->state = L_CLOSING;
-    for (size_t i = 0; i < l->nsockets; ++i) {
-      uv_safe_close((uv_handle_t*)&l->sockets[i].tcp, on_close_lsocket);
+    for (lsocket_t *ls = l->lsockets; ls; ls = ls->next) {
+      uv_safe_close((uv_handle_t*)&ls->tcp, on_close_lsocket);
     }
     /* NOTE: Fall through in case we have 0 sockets - e.g. resolver error */
 
    case L_CLOSING:              /* Closing - can we send PN_LISTENER_CLOSE? */
-    if (l->nsockets == 0) {
+    if (!l->lsockets) {
       l->state = L_CLOSED;
       pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
     }
@@ -940,9 +948,11 @@ static void on_proactor_disconnect(uv_handle_t* h, void* v) {
      }
      case T_LSOCKET: {
        pn_listener_t *l = ((lsocket_t*)h->data)->parent;
-       pn_condition_t *cond = l->work.proactor->disconnect_cond;
-       if (cond) {
-         pn_condition_copy(pn_listener_condition(l), cond);
+       if (l) {
+         pn_condition_t *cond = l->work.proactor->disconnect_cond;
+         if (cond) {
+           pn_condition_copy(pn_listener_condition(l), cond);
+         }
        }
        pn_listener_close(l);
        break;
@@ -995,7 +1005,7 @@ static pn_event_batch_t *leader_lead_lh(pn_proactor_t *p, uv_run_mode mode) {
     }
   }
   batch = get_batch_lh(p);      /* Check for work */
-  if (!batch) { /* No work, run the UV loop */
+  if (!batch) {                 /* No work, run the UV loop */
     uv_mutex_unlock(&p->lock);  /* Unlock to run UV loop */
     uv_run(&p->loop, mode);
     uv_mutex_lock(&p->lock);
@@ -1142,8 +1152,10 @@ static void on_proactor_free(uv_handle_t* h, void* v) {
   if (h->type == UV_TCP) {      /* Put the corresponding work item on the leader_q for cleanup */
     work_t *w = NULL;
     switch (*(struct_type*)h->data) {
-     case T_CONNECTION: w = (work_t*)h->data; break;
-     case T_LSOCKET: w = &((lsocket_t*)h->data)->parent->work; break;
+     case T_CONNECTION:
+      w = (work_t*)h->data; break;
+     case T_LSOCKET:
+      w = &((lsocket_t*)h->data)->parent->work; break;
      default: break;
     }
     if (w && w->next == work_unqueued) {
@@ -1317,5 +1329,5 @@ int pn_netaddr_str(const pn_netaddr_t* na, char *buf, size_t len) {
 }
 
 pn_millis_t pn_proactor_now(void) {
-    return uv_hrtime() / 1000000; // uv_hrtime returns time in nanoseconds
+  return uv_hrtime() / 1000000; // uv_hrtime returns time in nanoseconds
 }


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


[19/50] [abbrv] qpid-proton git commit: PROTON-1483: C epoll proactor, change timerfd accounting

Posted by ac...@apache.org.
PROTON-1483: C epoll proactor, change timerfd accounting


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

Branch: refs/heads/go1
Commit: a4e5c84d88eb32a1951e058836e5f509749a955b
Parents: d652405
Author: Clifford Jansen <cl...@apache.org>
Authored: Wed May 24 07:52:42 2017 -0700
Committer: Clifford Jansen <cl...@apache.org>
Committed: Wed May 24 07:54:31 2017 -0700

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 137 +++++++++++++++++++++++++------------
 1 file changed, 93 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a4e5c84d/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index a1ec1af..2f99cd9 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -117,24 +117,39 @@ typedef struct epoll_extended_t {
 
 /*
  * This timerfd logic assumes EPOLLONESHOT and there never being two
- * active timeout callbacks.  There can be multiple unclaimed expiries
- * processed in a single callback.
+ * active timeout callbacks.  There can be multiple (or zero)
+ * unclaimed expiries processed in a single callback.
+ *
+ * timerfd_set() documentation implies a crisp relationship between
+ * timer expiry count and oldt's return value, but a return value of
+ * zero is ambiguous.  It can lead to no EPOLLIN, EPOLLIN + expected
+ * read, or
+ *
+ *   event expiry (in kernel) -> EPOLLIN
+ *   cancel/settime(0) (thread A) (number of expiries resets to zero)
+ *   read(timerfd) -> -1, EAGAIN  (thread B servicing epoll event)
+ *
+ * The original implementation with counters to track expiry counts
+ * was abandoned in favor of "in doubt" transitions and resolution
+ * at shutdown.
  */
 
 typedef struct ptimer_t {
   pmutex mutex;
   int timerfd;
   epoll_extended_t epoll_io;
-  int pending_count;
-  int skip_count;
+  bool timer_active;
+  bool in_doubt;  // 0 or 1 callbacks are possible
+  bool shutting_down;
 } ptimer_t;
 
 static bool ptimer_init(ptimer_t *pt, struct psocket_t *ps) {
   pt->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
   if (pt->timerfd < 0) return false;
   pmutex_init(&pt->mutex);
-  pt->pending_count = 0;
-  pt->skip_count = 0;
+  pt->timer_active = false;
+  pt->in_doubt = false;
+  pt->shutting_down = false;
   epoll_type_t type = ps ? PCONNECTION_TIMER : PROACTOR_TIMER;
   pt->epoll_io.psocket = ps;
   pt->epoll_io.fd = pt->timerfd;
@@ -144,49 +159,74 @@ static bool ptimer_init(ptimer_t *pt, struct psocket_t *ps) {
   return true;
 }
 
-static void ptimer_set(ptimer_t *pt, uint64_t t_millis) {
-  // t_millis == 0 -> cancel
-  lock(&pt->mutex);
-  if (t_millis == 0 && pt->pending_count == 0) {
-    unlock(&pt->mutex);
-    return;  // nothing to cancel
-  }
+// Call with ptimer lock held
+static void ptimer_set_lh(ptimer_t *pt, uint64_t t_millis) {
   struct itimerspec newt, oldt;
   memset(&newt, 0, sizeof(newt));
   newt.it_value.tv_sec = t_millis / 1000;
   newt.it_value.tv_nsec = (t_millis % 1000) * 1000000;
 
   timerfd_settime(pt->timerfd, 0, &newt, &oldt);
-  if (oldt.it_value.tv_sec || oldt.it_value.tv_nsec) {
-    // old value cancelled
-    assert (pt->pending_count > 0);
-    pt->pending_count--;
-  } else if (pt->pending_count) {
-    // cancel instance waiting on this lock
-    pt->skip_count++;
-  }
-  if (t_millis)
-    pt->pending_count++;
-  assert(pt->pending_count >= 0);
+  if (pt->timer_active && oldt.it_value.tv_nsec == 0 && oldt.it_value.tv_sec == 0) {
+    // EPOLLIN is possible but not assured
+    pt->in_doubt = true;
+  }
+  pt->timer_active = t_millis;
+}
+
+static void ptimer_set(ptimer_t *pt, uint64_t t_millis) {
+  // t_millis == 0 -> cancel
+  lock(&pt->mutex);
+  if ((t_millis == 0 && !pt->timer_active) || pt->shutting_down) {
+    unlock(&pt->mutex);
+    return;  // nothing to do
+  }
+  ptimer_set_lh(pt, t_millis);
   unlock(&pt->mutex);
 }
 
-// Callback bookkeeping. Return number of uncancelled expiry events.
-static int ptimer_callback(ptimer_t *pt) {
+// Callback bookkeeping. Return true if there is an expired timer.
+static bool ptimer_callback(ptimer_t *pt) {
   lock(&pt->mutex);
-  uint64_t u_exp_count;
+  struct itimerspec current;
+  if (timerfd_gettime(pt->timerfd, &current) == 0) {
+    if (current.it_value.tv_nsec == 0 && current.it_value.tv_sec == 0)
+      pt->timer_active = false;
+  }
+  uint64_t u_exp_count = 0;
   ssize_t l = read(pt->timerfd, &u_exp_count, sizeof(uint64_t));
-  (void)l; /* Silence compiler complaints in release build */
-  assert(l == sizeof(uint64_t));
-  assert(u_exp_count < INT_MAX);  // or test and log it?
-  int exp_count = (int) u_exp_count;
-  assert(exp_count >= pt->skip_count);
-  assert(exp_count <= pt->pending_count);
-  exp_count -= pt->skip_count;
-  pt->skip_count = 0;
-  pt->pending_count -= exp_count;
+  if (l != sizeof(uint64_t)) {
+    if (l == -1) {
+      if (errno != EAGAIN) {
+        EPOLL_FATAL("timer read", errno);
+      }
+    }
+    else
+      EPOLL_FATAL("timer internal error", 0);
+  }
+  if (!pt->timer_active) {
+    // Expiry counter just cleared, timer not set, timerfd not armed
+    pt->in_doubt = false;
+  }
   unlock(&pt->mutex);
-  return (int) exp_count;
+  return (l == sizeof(uint64_t)) && u_exp_count > 0;
+}
+
+// Return true if timerfd has and will have no pollable expiries in the current armed state
+static bool ptimer_shutdown(ptimer_t *pt, bool currently_armed) {
+  lock(&pt->mutex);
+  if (currently_armed) {
+    ptimer_set_lh(pt, 0);
+    pt->shutting_down = true;
+    if (pt->in_doubt)
+      // Force at least one callback.  If two, second cannot proceed with unarmed timerfd.
+      ptimer_set_lh(pt, 1);
+  }
+  else
+    pt->shutting_down = true;
+  bool rv = !pt->in_doubt;
+  unlock(&pt->mutex);
+  return rv;
 }
 
 static void ptimer_finalize(ptimer_t *pt) {
@@ -626,7 +666,7 @@ static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bo
 // Call with lock held and closing == true (i.e. pn_connection_driver_finished() == true), timer cancelled.
 // Return true when all possible outstanding epoll events associated with this pconnection have been processed.
 static inline bool pconnection_is_final(pconnection_t *pc) {
-  return !pc->current_arm && !pc->timer.pending_count && !pc->context.wake_ops;
+  return !pc->current_arm && !pc->timer_armed && !pc->context.wake_ops;
 }
 
 static void pconnection_final_free(pconnection_t *pc) {
@@ -661,7 +701,13 @@ static void pconnection_begin_close(pconnection_t *pc) {
     stop_polling(&pc->psocket.epoll_io, pc->psocket.proactor->epollfd);
     pc->current_arm = 0;
     pn_connection_driver_close(&pc->driver);
-    ptimer_set(&pc->timer, 0);
+    if (ptimer_shutdown(&pc->timer, pc->timer_armed))
+      pc->timer_armed = false;  // disarmed in the sense that the timer will never fire again
+    else if (!pc->timer_armed) {
+      // In doubt.  One last callback to collect
+      rearm(pc->psocket.proactor, &pc->timer.epoll_io);
+      pc->timer_armed = true;
+    }
   }
 }
 
@@ -669,7 +715,7 @@ static void pconnection_forced_shutdown(pconnection_t *pc) {
   // Called by proactor_free, no competing threads, no epoll activity.
   pconnection_begin_close(pc);
   // pconnection_process will never be called again.  Zero everything.
-  pc->timer.pending_count = 0;
+  pc->timer_armed = false;
   pc->context.wake_ops = 0;
   pn_connection_t *c = pc->driver.connection;
   pn_collector_release(pn_connection_collector(c));
@@ -804,7 +850,7 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
 
   if (timeout) {
     timer_unarmed = true;
-    timer_fired = (ptimer_callback(&pc->timer) != 0);
+    timer_fired = ptimer_callback(&pc->timer) != 0;
   }
   lock(&pc->context.mutex);
 
@@ -889,11 +935,12 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
     pc->timer_armed = true;  // about to rearm outside the lock
     timer_unarmed = true;    // so we remember
   }
+  bool timer_shutting_down = pc->timer.shutting_down;
 
   unlock(&pc->context.mutex);
   pc->hog_count++; // working context doing work
 
-  if (timer_unarmed) {
+  if (timer_unarmed && !timer_shutting_down) {
     rearm(pc->psocket.proactor, &pc->timer.epoll_io);
     timer_unarmed = false;
   }
@@ -1552,7 +1599,8 @@ static pn_event_batch_t *proactor_process(pn_proactor_t *p, bool timeout) {
       return &p->batch;
     }
   }
-  bool rearm_timer = !p->timer_armed;
+  bool rearm_timer = !p->timer_armed && !p->timer.shutting_down;
+  p->timer_armed = true;
   unlock(&p->context.mutex);
   if (rearm_timer)
     rearm(p, &p->timer.epoll_io);
@@ -1701,7 +1749,8 @@ void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
   if (bp == p) {
     bool notify = false;
     lock(&p->context.mutex);
-    bool rearm_timer = !p->timer_armed;
+    bool rearm_timer = !p->timer_armed && !p->shutting_down;
+    p->timer_armed = true;
     p->context.working = false;
     proactor_update_batch(p);
     if (proactor_has_event(p))


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


[33/50] [abbrv] qpid-proton git commit: No-JIRA: really fix tox tests without breaking anything else!

Posted by ac...@apache.org.
No-JIRA: really fix tox tests without breaking anything else!


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

Branch: refs/heads/go1
Commit: 8d862beabd32bd22d4b315ff3a35bd937aa4b2a1
Parents: 4edd7fe
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 26 16:16:18 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri May 26 16:18:48 2017 -0400

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


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d862bea/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 1964b44..a38664b 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -375,8 +375,6 @@ set (qpid-proton-core
   src/core/transport.c
   src/core/message.c
   src/core/url-internal.c
-
-  src/core/max_align.h
 )
 
 set (qpid-proton-include-generated
@@ -406,6 +404,7 @@ set (qpid-proton-private-includes
   src/core/dispatcher.h
   src/core/data.h
   src/core/decoder.h
+  src/core/max_align.h
   src/core/url-internal.h
   src/reactor/io/windows/iocp.h
   src/reactor/selector.h


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


[44/50] [abbrv] qpid-proton git commit: NO-JIRA: Updated old FIXME comments, fixed racy test.

Posted by ac...@apache.org.
NO-JIRA: Updated old FIXME comments, fixed racy test.


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

Branch: refs/heads/go1
Commit: 11fa24dbfbd230c89efe05384aebbb086d645df8
Parents: 8c5a031
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jun 8 11:29:51 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 8 12:47:10 2017 -0400

----------------------------------------------------------------------
 examples/cpp/mt/epoll_container.cpp          |  6 +++---
 proton-c/bindings/cpp/src/container_impl.cpp |  2 +-
 proton-c/src/proactor/epoll.c                | 16 ++++++++++++----
 proton-c/src/proactor/libuv.c                |  2 +-
 proton-c/src/tests/proactor.c                |  3 ---
 5 files changed, 17 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/11fa24db/examples/cpp/mt/epoll_container.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/mt/epoll_container.cpp b/examples/cpp/mt/epoll_container.cpp
index 7646673..5643fcc 100644
--- a/examples/cpp/mt/epoll_container.cpp
+++ b/examples/cpp/mt/epoll_container.cpp
@@ -140,9 +140,9 @@ class epoll_container : public proton::io::container_impl_base {
         std::atomic<int> count_;
     };
 
-     // FIXME aconway 2016-06-07: Unfinished
-    void schedule(proton::duration, std::function<void()>) OVERRIDE { throw std::logic_error("FIXME"); }
-    void schedule(proton::duration, proton::void_function0&) OVERRIDE { throw std::logic_error("FIXME"); }
+     // TODO aconway 2016-06-07: Unfinished
+    void schedule(proton::duration, std::function<void()>) OVERRIDE { throw std::logic_error("not implemented"); }
+    void schedule(proton::duration, proton::void_function0&) OVERRIDE { throw std::logic_error("not implemented"); }
     atomic_link_namer link_namer;
 
   private:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/11fa24db/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 d58fc09..e0851a9 100644
--- a/proton-c/bindings/cpp/src/container_impl.cpp
+++ b/proton-c/bindings/cpp/src/container_impl.cpp
@@ -161,7 +161,7 @@ container::impl::~impl() {
         close_acceptor(i->second);
 }
 
-// FIXME aconway 2016-06-07: this is not thread safe. It is sufficient for using
+// TODO aconway 2016-06-07: this is not thread safe. It is sufficient for using
 // default_container::schedule() inside a handler but not for inject() from
 // another thread.
 bool event_loop::impl::inject(void_function0& f) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/11fa24db/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 69954d6..a0f6519 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -19,9 +19,9 @@
  *
  */
 
-/* Enable POSIX features for pthread.h */
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE
+/* Enable POSIX features beyond c99 for modern pthread and standard strerror_r() */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
 #endif
 /* Avoid GNU extensions, in particular the incompatible alternative strerror_r() */
 #undef _GNU_SOURCE
@@ -1251,7 +1251,7 @@ void pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *addr, in
     }
     assert(len > 0);            /* guaranteed by getaddrinfo */
     l->psockets = (psocket_t*)calloc(len, sizeof(psocket_t));
-    assert(l->psockets);      /* FIXME aconway 2017-05-05: memory safety */
+    assert(l->psockets);      /* TODO aconway 2017-05-05: memory safety */
     l->psockets_size = 0;
     /* Find working listen addresses */
     for (struct addrinfo *ai = addrinfo; ai; ai = ai->ai_next) {
@@ -1941,6 +1941,14 @@ const pn_netaddr_t *pn_netaddr_remote(pn_transport_t *t) {
   return pc ? &pc->remote : NULL;
 }
 
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
 int pn_netaddr_str(const pn_netaddr_t* na, char *buf, size_t len) {
   char host[NI_MAXHOST];
   char port[NI_MAXSERV];

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/11fa24db/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 146cd7a..7460194 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -1129,7 +1129,7 @@ void pn_proactor_cancel_timeout(pn_proactor_t *p) {
 
 void pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *addr) {
   pconnection_t *pc = pconnection(p, c, false);
-  assert(pc);                                  /* FIXME aconway 2017-03-31: memory safety */
+  assert(pc);                                  /* TODO aconway 2017-03-31: memory safety */
   pn_connection_open(pc->driver.connection);   /* Auto-open */
   parse_addr(&pc->addr, addr);
   work_start(&pc->work);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/11fa24db/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index 2764f79..c41110b 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -691,9 +691,6 @@ static void test_ssl(test_t *t) {
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
   TEST_COND_EMPTY(t, last_condition);
 
-  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts));
-  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts));
-
   PROACTOR_TEST_FREE(pts);
 }
 


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


[24/50] [abbrv] qpid-proton git commit: PROTON-1288: c++ provide convenient access to message/filter maps

Posted by ac...@apache.org.
PROTON-1288: c++ provide convenient access to message/filter maps

proton::map type to wrap map values for message properties/annotations and source filters.

Has the following features:

- type safe template for the standard AMQP 'restricted map' types
- simple get()/put() interface for simple check/set individual properties
- converts directly to/from a proton::value efficient pass-through, no re-coding
- converts directly to/from std:map, std::unordered_map etc.
- encode/decode only as required

Intended use: use proton::map directly for simple get()/put(), convert to a
standard map or sequence type for more complex use (iteration, preserving
encoded order etc.)


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

Branch: refs/heads/go1
Commit: 864519ddca6c45a10ec01598b3ff3b33e5591561
Parents: f2df847
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 24 13:03:11 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 15:37:11 2017 -0400

----------------------------------------------------------------------
 examples/cpp/CMakeLists.txt                     |   1 +
 examples/cpp/README.dox                         |   6 +
 examples/cpp/example_test.py                    |  41 ++-
 examples/cpp/message_properties.cpp             |  22 +-
 examples/exampletest.py                         |   5 +-
 proton-c/bindings/cpp/CMakeLists.txt            |   3 +-
 .../cpp/include/proton/codec/encoder.hpp        |  13 +
 .../cpp/include/proton/internal/cached_map.hpp  |  91 -------
 .../include/proton/internal/pn_unique_ptr.hpp   |   6 +
 .../cpp/include/proton/internal/type_traits.hpp |   1 -
 proton-c/bindings/cpp/include/proton/map.hpp    | 128 ++++++++++
 .../bindings/cpp/include/proton/message.hpp     |  28 +-
 proton-c/bindings/cpp/include/proton/source.hpp |   8 +-
 proton-c/bindings/cpp/include/proton/value.hpp  |   3 +-
 proton-c/bindings/cpp/src/cached_map.cpp        | 130 ----------
 .../bindings/cpp/src/connection_driver_test.cpp |  38 +++
 proton-c/bindings/cpp/src/include/test_bits.hpp |   1 +
 proton-c/bindings/cpp/src/map.cpp               | 254 +++++++++++++++++++
 proton-c/bindings/cpp/src/map_test.cpp          | 126 +++++++++
 proton-c/bindings/cpp/src/message.cpp           |  92 +++----
 proton-c/bindings/cpp/src/message_test.cpp      |  19 +-
 proton-c/bindings/cpp/src/node_options.cpp      |   3 +-
 proton-c/bindings/cpp/src/scalar_base.cpp       |   3 +-
 proton-c/bindings/cpp/src/source.cpp            |  26 +-
 proton-c/bindings/cpp/src/value.cpp             |   3 +
 25 files changed, 697 insertions(+), 354 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index 236aac7..ecd88cf 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -41,6 +41,7 @@ foreach(example
     helloworld_direct
     simple_recv
     simple_send
+    message_properties
     scheduled_send_03
     direct_recv
     direct_send

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/examples/cpp/README.dox
----------------------------------------------------------------------
diff --git a/examples/cpp/README.dox b/examples/cpp/README.dox
index 447d3ad..327dbef 100644
--- a/examples/cpp/README.dox
+++ b/examples/cpp/README.dox
@@ -50,6 +50,12 @@ on 127.0.0.1:5672. Simply prints out the body of received messages.
 
 */
 
+/** @example message_properties.cpp
+
+Shows how to set and examine message properties.
+
+*/
+
 /** @example direct_send.cpp
 
 Accepts an incoming connection and then sends like `simple_send`.  You can

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index f9a0825..5773142 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -125,53 +125,53 @@ class ContainerExampleTest(BrokerTestCase):
     broker_exe = "broker"
 
     def test_helloworld(self):
-        self.assertEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit())
+        self.assertMultiLineEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit())
 
     def test_helloworld_direct(self):
         with TestPort() as tp:
-            self.assertEqual('Hello World!\n', self.proc(["helloworld_direct", tp.addr]).wait_exit())
+            self.assertMultiLineEqual('Hello World!\n', self.proc(["helloworld_direct", tp.addr]).wait_exit())
 
     def test_simple_send_recv(self):
-        self.assertEqual("all messages confirmed\n",
+        self.assertMultiLineEqual("all messages confirmed\n",
                          self.proc(["simple_send", "-a", self.addr]).wait_exit())
-        self.assertEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
+        self.assertMultiLineEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
 
     def test_simple_recv_send(self):
         # Start receiver first, then run sender"""
         recv = self.proc(["simple_recv", "-a", self.addr])
-        self.assertEqual("all messages confirmed\n",
+        self.assertMultiLineEqual("all messages confirmed\n",
                          self.proc(["simple_send", "-a", self.addr]).wait_exit())
-        self.assertEqual(recv_expect("simple_recv", self.addr), recv.wait_exit())
+        self.assertMultiLineEqual(recv_expect("simple_recv", self.addr), recv.wait_exit())
 
 
     def test_simple_send_direct_recv(self):
         with TestPort() as tp:
             addr = "%s/examples" % tp.addr
             recv = self.proc(["direct_recv", "-a", addr], "listening")
-            self.assertEqual("all messages confirmed\n",
+            self.assertMultiLineEqual("all messages confirmed\n",
                              self.proc(["simple_send", "-a", addr]).wait_exit())
-            self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
+            self.assertMultiLineEqual(recv_expect("direct_recv", addr), recv.wait_exit())
 
     def test_simple_recv_direct_send(self):
         with TestPort() as tp:
             addr = "%s/examples" % tp.addr
             send = self.proc(["direct_send", "-a", addr], "listening")
-            self.assertEqual(recv_expect("simple_recv", addr),
+            self.assertMultiLineEqual(recv_expect("simple_recv", addr),
                              self.proc(["simple_recv", "-a", addr]).wait_exit())
-            self.assertEqual(
+            self.assertMultiLineEqual(
                 "direct_send listening on %s\nall messages confirmed\n" % addr,
                 send.wait_exit())
 
     def test_request_response(self):
         server = self.proc(["server", "-a", self.addr], "connected")
-        self.assertEqual(CLIENT_EXPECT,
+        self.assertMultiLineEqual(CLIENT_EXPECT,
                          self.proc(["client", "-a", self.addr]).wait_exit())
 
     def test_request_response_direct(self):
         with TestPort() as tp:
             addr = "%s/examples" % tp.addr
             server = self.proc(["server_direct", "-a", addr], "listening")
-            self.assertEqual(CLIENT_EXPECT,
+            self.assertMultiLineEqual(CLIENT_EXPECT,
                              self.proc(["client", "-a", addr]).wait_exit())
 
     def test_flow_control(self):
@@ -181,7 +181,7 @@ success: Example 3: drain without credit
 success: Exmaple 4: high/low watermark
 """
         with TestPort() as tp:
-            self.assertEqual(want, self.proc(["flow_control", "--address", tp.addr, "--quiet"]).wait_exit())
+            self.assertMultiLineEqual(want, self.proc(["flow_control", "--address", tp.addr, "--quiet"]).wait_exit())
 
     def test_encode_decode(self):
         want="""
@@ -208,7 +208,7 @@ list[int(42), boolean(0), symbol(x)]
 map{string(k1):int(42), symbol(k2):boolean(0)}
 """
         self.maxDiff = None
-        self.assertEqual(want, self.proc(["encode_decode"]).wait_exit())
+        self.assertMultiLineEqual(want, self.proc(["encode_decode"]).wait_exit())
 
     def test_scheduled_send_03(self):
         # Output should be a bunch of "send" lines but can't guarantee exactly how many.
@@ -224,6 +224,19 @@ map{string(k1):int(42), symbol(k2):boolean(0)}
         except ProcError:       # File not found, not a C++11 build.
             pass
 
+    def test_message_properties(self):
+        expect="""using put/get: short=123 string=foo symbol=sym
+using coerce: short(as long)=123
+props[short]=123
+props[string]=foo
+props[symbol]=sym
+short=42 string=bar
+expected conversion_error: "unexpected type, want: uint got: int"
+expected conversion_error: "unexpected type, want: uint got: string"
+"""
+        self.assertMultiLineEqual(expect, self.proc(["message_properties"]).wait_exit())
+
+
 
 class ContainerExampleSSLTest(BrokerTestCase):
     """Run the SSL container examples, verify they behave as expected."""

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/examples/cpp/message_properties.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/message_properties.cpp b/examples/cpp/message_properties.cpp
index 64d597b..cb5c6b8 100644
--- a/examples/cpp/message_properties.cpp
+++ b/examples/cpp/message_properties.cpp
@@ -31,7 +31,6 @@ int main(int argc, char **argv) {
         m.properties().put("short", int16_t(123));
         m.properties().put("string", "foo");
         m.properties().put("symbol", proton::symbol("sym"));
-        m.properties().put("bool", true);
 
         // Examining properties using proton::get()
 
@@ -53,25 +52,26 @@ int main(int argc, char **argv) {
                   << " short=" << i
                   << " string=" << s
                   << " symbol=" << m.properties().get("symbol")
-                  << " bool=" << m.properties().get("bool")
                   << std::endl;
 
-        // Converting properties to a compatible type
+        // Converting properties to a convertible type
         std::cout << "using coerce:"
-                  << " short(as int)=" <<  proton::coerce<int>(m.properties().get("short"))
-                  << " bool(as int)=" << proton::coerce<int>(m.properties().get("bool"))
+                  << " short(as long)="
+                  << proton::coerce<long>(m.properties().get("short"))
                   << std::endl;
 
-        // Extract the properties map for more complex map operations.
-        proton::property_std_map props;
-        proton::get(m.properties().value(), props);
-        for (proton::property_std_map::iterator i = props.begin(); i != props.end(); ++i) {
+        // Extract the properties as a std::map for more complex map operations.
+        // You can use other map and sequence types to hold a map, see @ref types_page
+        typedef std::map<std::string, proton::scalar> property_map;
+        property_map props;
+        proton::get(m.properties(), props);
+        for (property_map::iterator i = props.begin(); i != props.end(); ++i) {
             std::cout << "props[" << i->first << "]=" << i->second << std::endl;
         }
         props["string"] = "bar";
         props["short"] = 42;
-        // Update the properties in the message from props
-        m.properties().value() = props;
+        // Update the properties in the message from the modified props map
+        m.properties() = props;
 
         std::cout << "short=" << m.properties().get("short")
                   << " string=" << m.properties().get("string")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/examples/exampletest.py
----------------------------------------------------------------------
diff --git a/examples/exampletest.py b/examples/exampletest.py
index bb055a1..5c53616 100644
--- a/examples/exampletest.py
+++ b/examples/exampletest.py
@@ -166,10 +166,13 @@ class TestCase(unittest.TestCase):
             super(TestCase, self).tearDown()
 
     if _tc_missing('assertIn'):
-
         def assertIn(self, a, b):
             self.assertTrue(a in b, "%r not in %r" % (a, b))
 
+    if _tc_missing('assertMultiLineEqual'):
+        def assertMultiLineEqual(self, a, b):
+            self.assertEqual(a, b)
+
 class ExampleTestCase(TestCase):
     """TestCase that manages started processes"""
     def setUp(self):

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index 04cb568..d1c6fd1 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -29,7 +29,7 @@ add_definitions(${CXX_WARNING_FLAGS})
 set(qpid-proton-cpp-source
   src/binary.cpp
   src/byte_array.cpp
-  src/cached_map.cpp
+  src/map.cpp
   src/connection.cpp
   src/connection_options.cpp
   src/connector.cpp
@@ -176,6 +176,7 @@ add_cpp_test(connection_driver_test)
 add_cpp_test(thread_safe_test)
 add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
 add_cpp_test(message_test)
+add_cpp_test(map_test)
 add_cpp_test(scalar_test)
 add_cpp_test(value_test)
 add_cpp_test(container_test)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/codec/encoder.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/encoder.hpp b/proton-c/bindings/cpp/include/proton/codec/encoder.hpp
index 222e95b..2610021 100644
--- a/proton-c/bindings/cpp/include/proton/codec/encoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/encoder.hpp
@@ -194,6 +194,19 @@ template <> struct is_encodable<value> : public true_type {};
 
 using is_encodable_impl::is_encodable;
 
+// Metafunction to test if a class looks like an encodable map from K to T.
+template <class M, class K, class T, class Enable = void>
+struct is_encodable_map : public internal::false_type {};
+
+template <class M, class K, class T> struct is_encodable_map<
+    M, K, T, typename internal::enable_if<
+                 internal::is_same<K, typename M::key_type>::value &&
+                 internal::is_same<T, typename M::mapped_type>::value &&
+                 is_encodable<M>::value
+                 >::type
+    > : public internal::true_type {};
+
+
 /// @endcond
 
 } // codec

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/internal/cached_map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/cached_map.hpp b/proton-c/bindings/cpp/include/proton/internal/cached_map.hpp
deleted file mode 100644
index 4f388a1..0000000
--- a/proton-c/bindings/cpp/include/proton/internal/cached_map.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef PROTON_CPP_CACHED_MAP_H
-#define PROTON_CPP_CACHED_MAP_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 "./config.hpp"
-#include "./export.hpp"
-#include "./pn_unique_ptr.hpp"
-
-#include <cstddef>
-
-namespace proton {
-
-namespace codec {
-class decoder;
-class encoder;
-}
-
-namespace internal {
-
-template <class key_type, class value_type>
-class map_type_impl;
-
-/// A convenience class to view and manage AMQP map data contained in
-/// a proton::value.  An internal cache of the map data is created as
-/// needed.
-template <class K, class V>
-class cached_map;
-
-template <class K, class V>
-PN_CPP_EXTERN proton::codec::decoder& operator>>(proton::codec::decoder& d, cached_map<K,V>& m);
-template <class K, class V>
-PN_CPP_EXTERN proton::codec::encoder& operator<<(proton::codec::encoder& e, const cached_map<K,V>& m);
-
-template <class key_type, class value_type>
-class PN_CPP_CLASS_EXTERN cached_map {
-    typedef map_type_impl<key_type, value_type> map_type;
-
-  public:
-    PN_CPP_EXTERN cached_map();
-    PN_CPP_EXTERN cached_map(const cached_map& cm);
-    PN_CPP_EXTERN cached_map& operator=(const cached_map& cm);
-#if PN_CPP_HAS_RVALUE_REFERENCES
-    PN_CPP_EXTERN cached_map(cached_map&&);
-    PN_CPP_EXTERN cached_map& operator=(cached_map&&);
-#endif
-    PN_CPP_EXTERN ~cached_map();
-
-    PN_CPP_EXTERN value_type get(const key_type& k) const;
-    PN_CPP_EXTERN void put(const key_type& k, const value_type& v);
-    PN_CPP_EXTERN size_t erase(const key_type& k);
-    PN_CPP_EXTERN bool exists(const key_type& k) const;
-    PN_CPP_EXTERN size_t size();
-    PN_CPP_EXTERN void clear();
-    PN_CPP_EXTERN bool empty();
-
-  /// @cond INTERNAL
-  private:
-    pn_unique_ptr<map_type> map_;
- 
-    void make_cached_map();
-
-  friend PN_CPP_EXTERN proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cached_map<key_type, value_type>& m);
-  friend PN_CPP_EXTERN proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cached_map<key_type, value_type>& m);
-  /// @endcond
-};
-
-
-}
-}
-
-#endif // PROTON_CPP_CACHED_MAP_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/internal/pn_unique_ptr.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/pn_unique_ptr.hpp b/proton-c/bindings/cpp/include/proton/internal/pn_unique_ptr.hpp
index 323c701..a3416e5 100644
--- a/proton-c/bindings/cpp/include/proton/internal/pn_unique_ptr.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/pn_unique_ptr.hpp
@@ -29,6 +29,9 @@
 namespace proton {
 namespace internal {
 
+template <class T> class pn_unique_ptr;
+template <class T> void swap(pn_unique_ptr<T>& x, pn_unique_ptr<T>& y);
+
 /// A simple unique ownership pointer, used as a return value from
 /// functions that transfer ownership to the caller.
 ///
@@ -55,6 +58,7 @@ template <class T> class pn_unique_ptr {
     explicit operator bool() const { return get(); }
 #endif
     bool operator !() const { return !get(); }
+    void swap(pn_unique_ptr& x) { std::swap(ptr_, x.ptr_); }
 
 #if PN_CPP_HAS_UNIQUE_PTR
     operator std::unique_ptr<T>() { T *p = ptr_; ptr_ = 0; return std::unique_ptr<T>(p); }
@@ -64,6 +68,8 @@ template <class T> class pn_unique_ptr {
     T* ptr_;
 };
 
+template <class T> void swap(pn_unique_ptr<T>& x, pn_unique_ptr<T>& y) { x.swap(y); }
+
 } // internal
 } // proton
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp b/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
index 8abba55..bd16d29 100644
--- a/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
@@ -151,7 +151,6 @@ template <class T> struct is_unknown_integer {
 template<class T, class = typename enable_if<is_unknown_integer<T>::value>::type>
 struct known_integer : public integer_type<sizeof(T), is_signed<T>::value> {};
 
-
 // Helper base for SFINAE templates.
 struct sfinae {
     typedef char yes;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/map.hpp b/proton-c/bindings/cpp/include/proton/map.hpp
new file mode 100644
index 0000000..8399b16
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/map.hpp
@@ -0,0 +1,128 @@
+#ifndef PROTON_CPP_MAP_H
+#define PROTON_CPP_MAP_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 "./value.hpp"
+
+#include "internal/pn_unique_ptr.hpp"
+
+#include <cstddef>
+
+namespace proton {
+
+namespace codec {
+class decoder;
+class encoder;
+}
+
+template <class K, class T>
+class map_type_impl;
+
+template <class K, class T>
+class map;
+
+template <class K, class T>
+PN_CPP_EXTERN proton::codec::decoder& operator>>(proton::codec::decoder& d, map<K,T>& m);
+template <class K, class T>
+PN_CPP_EXTERN proton::codec::encoder& operator<<(proton::codec::encoder& e, const map<K,T>& m);
+template <class K, class T>
+PN_CPP_EXTERN void swap(map<K,T>&, map<K,T>&);
+
+/// Used to access standard AMQP property, annotation and filter maps attached
+/// to proton::message and proton::source.
+///
+/// Provides only basic get()/set() operations for convenience.  For more
+/// complicated use (iteration, preserving order etc.) you should convert to a
+/// standard C++ map type such as std::map. See @ref message_propreties.cpp
+/// and @ref types_page.
+///
+template <class K, class T>
+class PN_CPP_CLASS_EXTERN map {
+    template <class M, class U=void>
+        struct assignable_map :
+            public internal::enable_if<codec::is_encodable_map<M,K,T>::value, U> {};
+
+ public:
+    /// Create an empty map value
+    PN_CPP_EXTERN map();
+
+    PN_CPP_EXTERN map(const map& cm);
+    PN_CPP_EXTERN map& operator=(const map& cm);
+#if PN_CPP_HAS_RVALUE_REFERENCES
+    PN_CPP_EXTERN map(map&&);
+    PN_CPP_EXTERN map& operator=(map&&);
+#endif
+
+    PN_CPP_EXTERN ~map();
+
+    /// Type-safe assign from a compatible map type, e.g. std::map<K,T> - see @types_page
+    template <class M>
+    typename assignable_map<M, map&>::type operator=(const M& x) { value(x); return *this;}
+
+    /// Copy from a proton::value.
+    /// @throw proton::conversion_error if x does not contain a compatible map.
+    PN_CPP_EXTERN void value(const value& x);
+    /// Access as a proton::value
+    PN_CPP_EXTERN proton::value& value();
+    /// Access as a proton::value
+    PN_CPP_EXTERN const proton::value& value() const;
+
+    /// Get the map entry for key k, return T() if no such entry
+    PN_CPP_EXTERN T get(const K& k) const;
+    /// Put a map entry for key k.
+    PN_CPP_EXTERN void put(const K& k, const T& v);
+    /// Erase the map entry at k
+    PN_CPP_EXTERN size_t erase(const K& k);
+    /// True if there is a map entry for k
+    PN_CPP_EXTERN bool exists(const K& k) const;
+    /// Number of map entries
+    PN_CPP_EXTERN size_t size() const;
+    /// Clear the map value
+    PN_CPP_EXTERN void clear();
+    /// True if the map is empty
+    PN_CPP_EXTERN bool empty() const;
+
+    ///@cond INTERNAL
+    explicit map(pn_data_t*);
+    void reset(pn_data_t*);
+    ///@endcond
+
+ private:
+    typedef map_type_impl<K,T> map_type;
+    mutable internal::pn_unique_ptr<map_type> map_;
+    mutable proton::value value_;
+
+    void ensure() const;
+    const map_type& cache() const;
+    map_type& cache_update();
+    proton::value& flush() const;
+
+  friend PN_CPP_EXTERN proton::codec::decoder& operator>> <>(proton::codec::decoder&, map&);
+  friend PN_CPP_EXTERN proton::codec::encoder& operator<< <>(proton::codec::encoder&, const map&);
+  friend PN_CPP_EXTERN void swap<>(map&, map&);
+  /// @endcond
+};
+
+} // namespace proton
+
+#endif // PROTON_CPP_MAP_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index faf2f29..a25f7db 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -27,8 +27,8 @@
 #include "./duration.hpp"
 #include "./timestamp.hpp"
 #include "./value.hpp"
+#include "./map.hpp"
 
-#include "./internal/cached_map.hpp"
 #include "./internal/pn_unique_ptr.hpp"
 
 #include <proton/type_compat.h>
@@ -48,11 +48,11 @@ class message {
   public:
     /// **Experimental** - A map of string keys and AMQP scalar
     /// values.
-    class property_map : public internal::cached_map<std::string, scalar> {};
+    typedef map<std::string, scalar> property_map;
 
     /// **Experimental** - A map of AMQP annotation keys and AMQP
     /// values.
-    class annotation_map : public internal::cached_map<annotation_key, value> {};
+    typedef map<annotation_key, value> annotation_map;
 
     /// Create an empty message.
     PN_CPP_EXTERN message();
@@ -243,7 +243,7 @@ class message {
     /// acquired, by other recipients.
 
     // XXX The triple-not in the last sentence above is confusing.
-    
+
     PN_CPP_EXTERN bool first_acquirer() const;
 
     /// Set the first acquirer flag.
@@ -287,33 +287,25 @@ class message {
 
     /// @}
 
-    /// @name Extended attributes
+    /// @name **Experimental** - Application properties
     /// @{
 
     /// **Experimental** - Get the application properties map.  It can
     /// be modified in place.
     PN_CPP_EXTERN property_map& properties();
 
-    /// **Experimental** - Get the application properties map.  It can
-    /// be modified in place.
+    /// **Experimental** - examine the application properties map.
     PN_CPP_EXTERN const property_map& properties() const;
 
-    /// **Experimental** - Get the message annotations map.  It can be
-    /// modified in place.
+    /// @name **Experimental** - Annotations
+    ///
+    /// Normally used by messaging infrastructure, not applications.
+    /// @{
     PN_CPP_EXTERN annotation_map& message_annotations();
-
-    /// **Experimental** - Get the message annotations map.  It can be
-    /// modified in place.
     PN_CPP_EXTERN const annotation_map& message_annotations() const;
 
-    /// **Experimental** - Get the delivery annotations map.  It can
-    /// be modified in place.
     PN_CPP_EXTERN annotation_map& delivery_annotations();
-
-    /// **Experimental** - Get the delivery annotations map.  It can
-    /// be modified in place.
     PN_CPP_EXTERN const annotation_map& delivery_annotations() const;
-
     /// @}
 
     /// Default priority assigned to new messages.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/source.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/source.hpp b/proton-c/bindings/cpp/include/proton/source.hpp
index 321af9a..59963dd 100644
--- a/proton-c/bindings/cpp/include/proton/source.hpp
+++ b/proton-c/bindings/cpp/include/proton/source.hpp
@@ -24,7 +24,7 @@
 
 #include "./fwd.hpp"
 #include "./internal/export.hpp"
-#include "./internal/cached_map.hpp"
+#include "./map.hpp"
 #include "./symbol.hpp"
 #include "./terminus.hpp"
 #include "./value.hpp"
@@ -42,7 +42,7 @@ class source : public terminus {
   public:
     /// **Experimental** - A map of AMQP symbol keys and filter
     /// specifiers.
-    class filter_map : public internal::cached_map<symbol, value> {};
+    typedef map<symbol, value> filter_map;
 
     /// Create an empty source.
     source() : terminus() {}
@@ -69,13 +69,15 @@ class source : public terminus {
     PN_CPP_EXTERN enum distribution_mode distribution_mode() const;
 
     /// **Experimental** - Obtain the set of message filters.
-    PN_CPP_EXTERN filter_map filters() const;
+    PN_CPP_EXTERN const filter_map& filters() const;
 
   private:
     source(pn_terminus_t* t);
     source(const sender&);
     source(const receiver&);
 
+    filter_map filters_;
+
     /// @cond INTERNAL
   friend class proton::internal::factory<source>;
   friend class sender;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index 75927f7..bc7ed86 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -72,7 +72,7 @@ class value : public internal::value_base, private internal::comparable<value> {
 #endif
     /// @}
 
-    /// Construct from any allowed type T.
+    /// Copy from any allowed type T.
     template <class T> value(const T& x, typename assignable<T>::type* = 0) { *this = x; }
 
     /// Assign from any allowed type T.
@@ -88,7 +88,6 @@ class value : public internal::value_base, private internal::comparable<value> {
     /// True if the value is null
     PN_CPP_EXTERN bool empty() const;
 
-
     /// Reset the value to null/empty
     PN_CPP_EXTERN void clear();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/cached_map.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/cached_map.cpp b/proton-c/bindings/cpp/src/cached_map.cpp
deleted file mode 100644
index 5411aa1..0000000
--- a/proton-c/bindings/cpp/src/cached_map.cpp
+++ /dev/null
@@ -1,130 +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 "proton/internal/cached_map.hpp"
-
-#include "proton/annotation_key.hpp"
-#include "proton/scalar.hpp"
-#include "proton/value.hpp"
-#include "proton/codec/decoder.hpp"
-#include "proton/codec/encoder.hpp"
-#include "proton/codec/map.hpp"
-
-#include <map>
-#include <string>
-
-namespace proton {
-namespace internal {
-
- // use std::map as the actual cached_map implementation type
-template <class K, class V>
-class map_type_impl : public std::map<K, V> {};
-
-template <class K, class V>
-cached_map<K,V>::cached_map() {}
-template <class K, class V>
-cached_map<K,V>::cached_map(const cached_map& cm) { if ( !cm.map_ ) return;  map_.reset(new map_type(*cm.map_)); }
-template <class K, class V>
-cached_map<K,V>& cached_map<K,V>::operator=(const cached_map& cm) {
-    if (&cm != this) {
-        cached_map<K,V> t;
-        map_type *m = !cm.map_ ? 0 : new map_type(*cm.map_);
-        t.map_.reset(map_.release());
-        map_.reset(m);
-    }
-    return *this;
-}
-
-template <class K, class V>
-#if PN_CPP_HAS_RVALUE_REFERENCES
-cached_map<K,V>::cached_map(cached_map&& cm) : map_(std::move(cm.map_)) {}
-template <class K, class V>
-cached_map<K,V>& cached_map<K,V>::operator=(cached_map&& cm) { map_.reset(cm.map_.release()); return *this; }
-template <class K, class V>
-#endif
-cached_map<K,V>::~cached_map() {}
-
-template <class K, class V>
-V cached_map<K,V>::get(const K& k) const {
-  if ( !map_ ) return V();
-  typename map_type::const_iterator i = map_->find(k);
-  if ( i==map_->end() ) return V();
-  return i->second;
-}
-template <class K, class V>
-void cached_map<K,V>::put(const K& k, const V& v) {
-  if ( !map_ ) make_cached_map();
-  (*map_)[k] = v;
-}
-template <class K, class V>
-size_t cached_map<K,V>::erase(const K& k) {
-  if ( !map_ ) return 0;
-  return map_->erase(k);
-}
-template <class K, class V>
-bool cached_map<K,V>::exists(const K& k) const {
-  if ( !map_ ) return false;
-  return map_->count(k) > 0;
-}
-
-template <class K, class V>
-size_t cached_map<K,V>::size() {
-  if ( !map_ ) return 0;
-  return map_->size();
-}
-template <class K, class V>
-void cached_map<K,V>::clear() {
-  map_.reset();
-}
-template <class K, class V>
-bool cached_map<K,V>::empty() {
-  if ( !map_ ) return true;
-  return map_->empty();
-}
-
-template <class K, class V>
-void cached_map<K,V>::make_cached_map() { map_.reset(new map_type); }
-
-template <class K, class V>
-PN_CPP_EXTERN proton::codec::decoder& operator>>(proton::codec::decoder& d, cached_map<K,V>& m) {
-  if ( !m.map_ ) m.make_cached_map();
-  return d >> *(m.map_);
-}
-template <class K, class V>
-PN_CPP_EXTERN proton::codec::encoder& operator<<(proton::codec::encoder& e, const cached_map<K,V>& m) {
-  if ( !m.map_ ) return e;
-  return e << *(m.map_);
-}
-
-// Force the necessary template instantiations so that the library exports the correct symbols
-template class PN_CPP_CLASS_EXTERN cached_map<std::string, scalar>;
-template class PN_CPP_CLASS_EXTERN cached_map<annotation_key, value>;
-template class PN_CPP_CLASS_EXTERN cached_map<symbol, value>;
-
-template proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cached_map<std::string, scalar>& m);
-template proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cached_map<std::string, scalar>& m);
-template proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cached_map<annotation_key, value>& m);
-template proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cached_map<annotation_key, value>& m);
-template proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cached_map<symbol, value>& m);
-template proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cached_map<symbol, value>& m);
-
-}
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
index 372240b..760ac55 100644
--- a/proton-c/bindings/cpp/src/connection_driver_test.cpp
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -21,6 +21,7 @@
 #include "test_bits.hpp"
 #include "proton_bits.hpp"
 
+#include "proton/container.hpp"
 #include "proton/io/connection_driver.hpp"
 #include "proton/io/link_namer.hpp"
 #include "proton/link.hpp"
@@ -248,10 +249,47 @@ void test_no_container() {
     } catch (proton::error) {}
 }
 
+void test_link_filters() {
+    // Propagation of link properties
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+
+    source_options opts;
+    source::filter_map f;
+    f.put("xx", "xxx");
+    ASSERT_EQUAL(1U, f.size());
+    e.a.connection().open_sender("x", sender_options().source(source_options().filters(f)));
+
+    f.clear();
+    f.put("yy", "yyy");
+    ASSERT_EQUAL(1U, f.size());
+    e.a.connection().open_receiver("y", receiver_options().source(source_options().filters(f)));
+
+    while (ha.senders.size()+ha.receivers.size() < 2 ||
+           hb.senders.size()+hb.receivers.size() < 2)
+        e.process();
+
+    proton::sender ax = quick_pop(ha.senders);
+    proton::receiver ay = quick_pop(ha.receivers);
+    proton::receiver bx = quick_pop(hb.receivers);
+    proton::sender by = quick_pop(hb.senders);
+
+    // C++ binding only gives remote_source so only look at remote ends of links
+    f = by.source().filters();
+    ASSERT_EQUAL(1U, f.size());
+    ASSERT_EQUAL(value("yyy"), f.get("yy"));
+
+    f = bx.source().filters();
+    ASSERT_EQUAL(1U, f.size());
+    ASSERT_EQUAL(value("xxx"), bx.source().filters().get("xx"));
+}
+
+
 }
 
 int main(int, char**) {
     int failed = 0;
+    RUN_TEST(failed, test_link_filters());
     RUN_TEST(failed, test_driver_link_id());
     RUN_TEST(failed, test_endpoint_close());
     RUN_TEST(failed, test_driver_disconnected());

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/include/test_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/test_bits.hpp b/proton-c/bindings/cpp/src/include/test_bits.hpp
index 0cfbe1f..79a0a17 100644
--- a/proton-c/bindings/cpp/src/include/test_bits.hpp
+++ b/proton-c/bindings/cpp/src/include/test_bits.hpp
@@ -54,6 +54,7 @@ inline void assert_equalish(T want, T got, T delta, const std::string& what)
     test::assert_equal((WANT), (GOT), FAIL_MSG("failed ASSERT_EQUAL(" #WANT ", " #GOT ")"))
 #define ASSERT_EQUALISH(WANT, GOT, DELTA) \
     test::assert_equalish((WANT), (GOT), (DELTA), FAIL_MSG("failed ASSERT_EQUALISH(" #WANT ", " #GOT ")"))
+#define ASSERT_THROWS(WANT, EXPR) do { try { EXPR; FAIL("Expected " #WANT); } catch(const WANT&) {} } while(0)
 
 #define RUN_TEST(BAD_COUNT, TEST)                                       \
     do {                                                                \

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/map.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/map.cpp b/proton-c/bindings/cpp/src/map.cpp
new file mode 100644
index 0000000..6fc80fa
--- /dev/null
+++ b/proton-c/bindings/cpp/src/map.cpp
@@ -0,0 +1,254 @@
+/*
+ *
+ * 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/map.hpp"
+
+#include "proton/annotation_key.hpp"
+#include "proton/scalar.hpp"
+#include "proton/value.hpp"
+#include "proton/codec/decoder.hpp"
+#include "proton/codec/encoder.hpp"
+#include "proton/codec/map.hpp"
+
+#include <map>
+#include <string>
+
+// IMPLEMENTATION NOTES:
+// - either value_, map_ or both can hold the up-to-date data
+// - avoid encoding or decoding between map_ and value_ unless necessary
+//   - if (map.get()) then map_ is up to date
+//   - if (!value_.empty()) then value_ is up to date
+//   - if (map.get_() && !value_.empty()) then map_ and value_ have equivalent data
+//   - if (!map.get_() && value_.empty()) then that's equivalent to an empty map
+// - cache() ensures that *map_ is up to date
+// - flush() ensures value_ is up to date
+
+namespace proton {
+
+// use std::map as the actual map implementation type
+template <class K, class T>
+class map_type_impl : public std::map<K, T> {};
+
+template <class K, class T>
+map<K,T>::map() {}
+
+template <class K, class T>
+map<K,T>::map(const map& x) { *this = x; }
+
+template <class K, class T>
+map<K,T>::map(pn_data_t *d) : value_(d) {}
+
+template <class K, class T>
+PN_CPP_EXTERN void swap(map<K,T>& x, map<K,T>& y) {
+    using namespace std;
+    swap(x.map_, y.map_);
+    swap(x.value_, y.value_);
+}
+
+template <class K, class T>
+void map<K,T>::ensure() const {
+    if (!map_) {
+        map_.reset(new map<K,T>::map_type);
+    }
+}
+
+template <class K, class T>
+map<K,T>& map<K,T>::operator=(const map& x) {
+    if (&x != this) {
+        if (!x.value_.empty()) {
+            map_.reset();
+            value_ = x.value_;
+        } else if (x.map_.get()) {
+            value_.clear();
+            ensure();
+            *map_ = *x.map_;
+        } else {
+            clear();
+        }
+    }
+    return *this;
+}
+
+#if PN_CPP_HAS_RVALUE_REFERENCES
+template <class K, class T>
+map<K,T>::map(map&& x) :
+    map_(std::move(x.map_)), value_(std::move(x.value_)) {}
+
+template <class K, class T>
+map<K,T>& map<K,T>::operator=(map&& x) {
+    if (&x != this) {
+        map_.reset(x.map_.release());
+        value_ = std::move(x.value_);
+    }
+    return *this;
+}
+#endif
+
+template <class K, class T>
+map<K,T>::~map() {}
+
+// Make sure map_ is valid
+template <class K, class T>
+const typename map<K,T>::map_type& map<K,T>::cache() const {
+    if (!map_) {
+        ensure();
+        if (!value_.empty()) {
+            proton::get(value_, *map_);
+        }
+    }
+    return *map_;
+}
+
+// Make sure map_ is valid, and mark value_ invalid
+template <class K, class T>
+typename map<K,T>::map_type& map<K,T>::cache_update() {
+    cache();
+    value_.clear();
+    return *map_;
+}
+
+template <class K, class T>
+value& map<K,T>::flush() const {
+    if (value_.empty()) {
+        // Create an empty map if need be, value_ must hold a valid map (even if empty)
+        // it must not be an empty (NULL_TYPE) proton::value.
+        ensure();
+        value_ = *map_;
+    }
+    return value_;
+}
+
+template <class K, class T>
+void map<K,T>::value(const proton::value& x) {
+    value_.clear();
+    // Validate the value by decoding it into map_, throw if not a valid map value.
+    ensure();
+    proton::get(x, *map_);
+}
+
+template <class K, class T>
+proton::value& map<K,T>::value() { return flush(); }
+
+template <class K, class T>
+const proton::value& map<K,T>::value() const { return flush(); }
+
+template <class K, class T>
+T map<K,T>::get(const K& k) const {
+    if (this->empty()) return T();
+    typename map_type::const_iterator i = cache().find(k);
+    if (i == map_->end()) return T();
+    return i->second;
+}
+
+template <class K, class T>
+void map<K,T>::put(const K& k, const T& v) {
+    cache_update()[k] = v;
+}
+
+template <class K, class T>
+size_t map<K,T>::erase(const K& k) {
+    if (this->empty()) {
+        return 0;
+    } else {
+        return cache_update().erase(k);
+    }
+}
+
+template <class K, class T>
+bool map<K,T>::exists(const K& k) const {
+    return this->empty() ? 0 : cache().find(k) != cache().end();
+}
+
+template <class K, class T>
+size_t map<K,T>::size() const {
+    return this->empty() ? 0 : cache().size();
+}
+
+template <class K, class T>
+void map<K,T>::clear() {
+    if (map_.get()) {
+        map_->clear();
+    }
+    value_.clear();
+}
+
+template <class K, class T>
+bool map<K,T>::empty() const {
+    if (map_.get()) {
+        return map_->empty();
+    }
+    if (value_.empty()) {
+        return true;
+    }
+    // We must decode the non-empty value to see if it is an empty map.
+    return cache().empty();
+}
+
+// Point to a different underlying pn_data_t, no copy
+template <class K, class T>
+void map<K,T>::reset(pn_data_t *d) {
+    value_.reset(d);            // Points to d, not copy of d.
+    map_.reset();
+    // NOTE: for internal use. Don't verify that the data is valid here as that
+    // would forcibly decode message maps immediately, we want to decode on-demand.
+}
+
+template <class K, class T>
+PN_CPP_EXTERN proton::codec::decoder& operator>>(proton::codec::decoder& d, map<K,T>& m)
+{
+    // Decode to m.map_ rather than m.value_ to verify the data is of valid type.
+    m.value_.clear();
+    m.ensure();
+    d >> *m.map_;
+    return d;
+}
+
+template <class K, class T>
+PN_CPP_EXTERN proton::codec::encoder& operator<<(proton::codec::encoder& e, const map<K,T>& m)
+{
+    if (!m.value_.empty()) {
+        return e << m.value_;   // Copy the value
+    }
+    // Encode the (possibly empty) map_.
+    m.ensure();
+    return e << *(m.map_);
+}
+
+// Force the necessary template instantiations so that the library exports the correct symbols
+template class PN_CPP_CLASS_EXTERN map<std::string, scalar>;
+typedef map<std::string, scalar> cm1;
+template PN_CPP_EXTERN void swap<>(cm1&, cm1&);
+template PN_CPP_EXTERN proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cm1& m);
+template PN_CPP_EXTERN proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cm1& m);
+
+template class PN_CPP_CLASS_EXTERN map<annotation_key, value>;
+typedef map<annotation_key, value> cm2;
+template PN_CPP_EXTERN void swap<>(cm2&, cm2&);
+template PN_CPP_EXTERN proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cm2& m);
+template PN_CPP_EXTERN proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cm2& m);
+
+template class PN_CPP_CLASS_EXTERN map<symbol, value>;
+typedef map<symbol, value> cm3;
+template PN_CPP_EXTERN void swap<>(cm3&, cm3&);
+template PN_CPP_EXTERN proton::codec::decoder& operator>> <>(proton::codec::decoder& d, cm3& m);
+template PN_CPP_EXTERN proton::codec::encoder& operator<< <>(proton::codec::encoder& e, const cm3& m);
+
+} // namespace proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/map_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/map_test.cpp b/proton-c/bindings/cpp/src/map_test.cpp
new file mode 100644
index 0000000..680ae5f
--- /dev/null
+++ b/proton-c/bindings/cpp/src/map_test.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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/map.hpp"
+#include "test_bits.hpp"
+
+#include <string>
+#include <vector>
+
+namespace {
+
+using namespace std;
+using namespace proton;
+
+void test_empty() {
+    proton::map<string, scalar> m;
+    ASSERT_EQUAL(0U, m.size());
+    ASSERT(m.empty());
+    ASSERT_EQUAL(0U, m.erase("x"));
+    ASSERT(!m.exists("x"));
+
+    std::map<string, scalar> sm;
+    proton::get(m, sm);
+    ASSERT(sm.empty());
+}
+
+void test_use() {
+    proton::map<string, scalar> m;
+
+    m.put("x", "y");
+    ASSERT_EQUAL(scalar("y"), m.get("x"));
+    ASSERT(!m.empty());
+    ASSERT(m.exists("x"));
+    ASSERT_EQUAL(1U, m.size());
+
+    m.put("a", "b");
+    ASSERT_EQUAL(scalar("b"), m.get("a"));
+    ASSERT_EQUAL(2U, m.size());
+
+    ASSERT_EQUAL(1U, m.erase("x"));
+    ASSERT_EQUAL(1U, m.size());
+    ASSERT(!m.exists("x"));
+    ASSERT_EQUAL(scalar("b"), m.get("a"));
+
+    m.clear();
+    ASSERT(m.empty());
+}
+
+void test_cppmap() {
+    std::map<string, scalar> sm;
+    sm["a"] = 2;
+    sm["b"] = 3;
+    proton::map<string, scalar> m;
+    m = sm;
+    ASSERT_EQUAL(scalar(2), m.get("a"));
+    ASSERT_EQUAL(scalar(3), m.get("b"));
+    ASSERT_EQUAL(2U, m.size());
+
+    std::map<string, scalar> sm2;
+    proton::get(m, sm2);
+    ASSERT_EQUAL(2U, sm2.size());
+    ASSERT_EQUAL(scalar(2), sm2["a"]);
+    ASSERT_EQUAL(scalar(3), sm2["b"]);
+
+    // Round trip:
+    value v = m.value();
+    proton::map<string, scalar> m2;
+    m2.value(v);
+
+    // Use a vector as map storage
+    vector<pair<string, scalar> > vm;
+
+    vm.push_back(std::make_pair(string("x"), 8));
+    vm.push_back(std::make_pair(string("y"), 9));
+    m.value(vm);                // Can't use type-safe op=, not enabled
+    ASSERT_EQUAL(scalar(8), m.get("x"));
+    ASSERT_EQUAL(scalar(9), m.get("y"));
+    ASSERT_EQUAL(2U, m.size());
+
+    vm.clear();
+    proton::get(m, vm);
+    ASSERT_EQUAL(2U, vm.size());
+    ASSERT_EQUAL(string("x"), vm[0].first);
+    ASSERT_EQUAL(scalar(8), vm[0].second);
+}
+
+void test_value() {
+    proton::map<string, scalar> m;
+    value v;
+    v = "foo";
+    ASSERT_THROWS(conversion_error, m.value(v));
+    std::map<int, float> bad;
+    // Wrong type of map.
+    // Note we can't detect an empty map of bad type because AMQP maps allow
+    // mixed types, so there must be data to object to.
+    bad[1]=1.0;
+    ASSERT_THROWS(conversion_error, m.value(bad));
+}
+
+}
+
+int main(int, char**) {
+    int failed = 0;
+    RUN_TEST(failed, test_empty());
+    RUN_TEST(failed, test_use());
+    RUN_TEST(failed, test_cppmap());
+    RUN_TEST(failed, test_value());
+    return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index df7fae1..eb0695e 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -42,31 +42,32 @@
 namespace proton {
 
 struct message::impl {
-    value body_;
-    property_map application_properties_;
-    annotation_map message_annotations_;
-    annotation_map delivery_annotations_;
+    value body;
+    property_map properties;
+    annotation_map annotations;
+    annotation_map instructions;
 
     impl(pn_message_t *msg) {
-        body_.reset(pn_message_body(msg));
+        body.reset(pn_message_body(msg));
+        properties.reset(pn_message_properties(msg));
+        annotations.reset(pn_message_annotations(msg));
+        instructions.reset(pn_message_instructions(msg));
     }
 
     void clear() {
-        application_properties_.clear();
-        message_annotations_.clear();
-        delivery_annotations_.clear();
+        properties.clear();
+        annotations.clear();
+        instructions.clear();
     }
 
-  friend void swap(impl& x, impl& y) {
-      using std::swap;
-      swap(x.body_, y.body_);
-      swap(x.application_properties_, y.application_properties_);
-      swap(x.message_annotations_, y.message_annotations_);
-      swap(x.delivery_annotations_, y.delivery_annotations_);
-  }
+    // Encode cached maps back to the underlying pn_data_t
+    void flush() {
+        properties.value();
+        annotations.value();
+        instructions.value();
+    }
 };
 
-
 message::message() : pn_msg_(0) {}
 message::message(const message &m) : pn_msg_(0) { *this = m; }
 
@@ -88,9 +89,7 @@ message::~message() {
 }
 
 void swap(message& x, message& y) {
-    using std::swap;
-    swap(x.pn_msg_, y.pn_msg_);
-    swap(x.impl(), y.impl());
+    std::swap(x.pn_msg_, y.pn_msg_);
 }
 
 pn_message_t *message::pn_msg() const {
@@ -116,7 +115,12 @@ message& message::operator=(const message& m) {
     return *this;
 }
 
-void message::clear() { if (pn_msg_) pn_message_clear(pn_msg_); }
+void message::clear() {
+    if (pn_msg_) {
+        impl().clear();
+        pn_message_clear(pn_msg_);
+    }
+}
 
 namespace {
 void check(int err) {
@@ -238,65 +242,35 @@ void message::inferred(bool b) { pn_message_set_inferred(pn_msg(), b); }
 
 void message::body(const value& x) { body() = x; }
 
-const value& message::body() const { return impl().body_; }
-value& message::body() { return impl().body_; }
-
-// MAP CACHING: the properties and annotations maps can either be encoded in the
-// pn_message pn_data_t structures OR decoded as C++ map members of the message
-// but not both. At least one of the pn_data_t or the map member is always
-// empty, the non-empty one is the authority.
-
-// Decode a map on demand
-template<class M, class F> M& get_map(pn_message_t* msg, F get, M& map) {
-    codec::decoder d(make_wrapper(get(msg)));
-    if (map.empty() && !d.empty()) {
-        d.rewind();
-        d >> map;
-        d.clear();              // The map member is now the authority.
-    }
-    return map;
-}
-
-// Encode a map if necessary.
-template<class M, class F> M& put_map(pn_message_t* msg, F get, M& map) {
-    codec::encoder e(make_wrapper(get(msg)));
-    if (e.empty() && !map.empty()) {
-        e << map;
-        map.clear();            // The encoded pn_data_t  is now the authority.
-    }
-    return map;
-}
+const value& message::body() const { return impl().body; }
+value& message::body() { return impl().body; }
 
 message::property_map& message::properties() {
-    return get_map(pn_msg(), pn_message_properties, impl().application_properties_);
+    return impl().properties;
 }
 
 const message::property_map& message::properties() const {
-    return get_map(pn_msg(), pn_message_properties, impl().application_properties_);
+    return impl().properties;
 }
 
-
 message::annotation_map& message::message_annotations() {
-    return get_map(pn_msg(), pn_message_annotations, impl().message_annotations_);
+    return impl().annotations;
 }
 
 const message::annotation_map& message::message_annotations() const {
-    return get_map(pn_msg(), pn_message_annotations, impl().message_annotations_);
+    return impl().annotations;
 }
 
-
 message::annotation_map& message::delivery_annotations() {
-    return get_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_);
+    return impl().instructions;
 }
 
 const message::annotation_map& message::delivery_annotations() const {
-    return get_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_);
+    return impl().instructions;
 }
 
 void message::encode(std::vector<char> &s) const {
-    put_map(pn_msg(), pn_message_properties, impl().application_properties_);
-    put_map(pn_msg(), pn_message_annotations, impl().message_annotations_);
-    put_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_);
+    impl().flush();
     size_t sz = std::max(s.capacity(), size_t(512));
     while (true) {
         s.resize(sz);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/message_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message_test.cpp b/proton-c/bindings/cpp/src/message_test.cpp
index 4d4e239..eafea2e 100644
--- a/proton-c/bindings/cpp/src/message_test.cpp
+++ b/proton-c/bindings/cpp/src/message_test.cpp
@@ -139,14 +139,16 @@ void test_message_maps() {
 
     m.properties().put("foo", 12);
     m.delivery_annotations().put("bar", "xyz");
-
     m.message_annotations().put(23, "23");
+
     ASSERT_EQUAL(m.properties().get("foo"), scalar(12));
     ASSERT_EQUAL(m.delivery_annotations().get("bar"), scalar("xyz"));
     ASSERT_EQUAL(m.message_annotations().get(23), scalar("23"));
 
     message m2(m);
 
+    ASSERT_EQUAL(m.properties().get("foo"), scalar(12)); // Decoding shouldn't change it
+
     ASSERT_EQUAL(m2.properties().get("foo"), scalar(12));
     ASSERT_EQUAL(m2.delivery_annotations().get("bar"), scalar("xyz"));
     ASSERT_EQUAL(m2.message_annotations().get(23), scalar("23"));
@@ -155,13 +157,14 @@ void test_message_maps() {
     m.delivery_annotations().put(24, 1000);
     m.message_annotations().erase(23);
 
-    m2 = m;
-    ASSERT_EQUAL(1u, m2.properties().size());
-    ASSERT_EQUAL(m2.properties().get("foo"), scalar("newfoo"));
-    ASSERT_EQUAL(2u, m2.delivery_annotations().size());
-    ASSERT_EQUAL(m2.delivery_annotations().get("bar"), scalar("xyz"));
-    ASSERT_EQUAL(m2.delivery_annotations().get(24), scalar(1000));
-    ASSERT(m2.message_annotations().empty());
+    message m3 = m;
+    size_t size = m3.properties().size();
+    ASSERT_EQUAL(1u, size);
+    ASSERT_EQUAL(m3.properties().get("foo"), scalar("newfoo"));
+    ASSERT_EQUAL(2u, m3.delivery_annotations().size());
+    ASSERT_EQUAL(m3.delivery_annotations().get("bar"), scalar("xyz"));
+    ASSERT_EQUAL(m3.delivery_annotations().get(24), scalar(1000));
+    ASSERT(m3.message_annotations().empty());
 }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/node_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/node_options.cpp b/proton-c/bindings/cpp/src/node_options.cpp
index 5bb2f8e..894ce9c 100644
--- a/proton-c/bindings/cpp/src/node_options.cpp
+++ b/proton-c/bindings/cpp/src/node_options.cpp
@@ -103,8 +103,7 @@ class source_options::impl {
           pn_terminus_set_distribution_mode(unwrap(s), pn_distribution_mode_t(distribution_mode.value));
         if (filters.set && !filters.value.empty()) {
             // Applied at most once via source_option.  No need to clear.
-            codec::encoder e(make_wrapper(pn_terminus_filter(unwrap(s))));
-            e << filters.value;
+            value(pn_terminus_filter(unwrap(s))) = filters.value;
         }
     }
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/scalar_base.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_base.cpp b/proton-c/bindings/cpp/src/scalar_base.cpp
index 840a6e8..0d66cdc 100644
--- a/proton-c/bindings/cpp/src/scalar_base.cpp
+++ b/proton-c/bindings/cpp/src/scalar_base.cpp
@@ -147,8 +147,7 @@ bool operator<(const scalar_base& x, const scalar_base& y) {
 
 std::ostream& operator<<(std::ostream& o, const scalar_base& s) {
     switch (s.type()) {
-      case NULL_TYPE: return o; // NULL is empty, doesn't print (like empty string)
-        // Print byte types as integer, not char.
+      case NULL_TYPE: return o << "<null>";
       case BYTE: return o << static_cast<int>(internal::get<int8_t>(s));
       case UBYTE: return o << static_cast<unsigned int>(internal::get<uint8_t>(s));
         // Other types printed using normal C++ operator <<

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/source.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/source.cpp b/proton-c/bindings/cpp/src/source.cpp
index a407d0b..524428f 100644
--- a/proton-c/bindings/cpp/src/source.cpp
+++ b/proton-c/bindings/cpp/src/source.cpp
@@ -30,11 +30,21 @@
 namespace proton {
 
 // Set parent_ non-null when the local terminus is authoritative and may need to be looked up.
-source::source(pn_terminus_t *t) : terminus(make_wrapper(t)) {}
+source::source(pn_terminus_t *t) : terminus(make_wrapper(t)),
+                                   filters_(pn_terminus_filter(object_))
+{}
 
-source::source(const sender& snd) : terminus(make_wrapper(pn_link_remote_source(unwrap(snd)))) { parent_ = unwrap(snd); }
+source::source(const sender& snd) :
+    terminus(make_wrapper(pn_link_remote_source(unwrap(snd)))),
+    filters_(pn_terminus_filter(object_))
+{
+    parent_ = unwrap(snd);
+}
 
-source::source(const receiver& rcv) : terminus(make_wrapper(pn_link_remote_source(unwrap(rcv)))) {}
+source::source(const receiver& rcv) :
+    terminus(make_wrapper(pn_link_remote_source(unwrap(rcv)))),
+    filters_(pn_terminus_filter(object_))
+{}
 
 std::string source::address() const {
     pn_terminus_t *authoritative = object_;
@@ -47,14 +57,8 @@ enum source::distribution_mode source::distribution_mode() const {
   return (enum distribution_mode)pn_terminus_get_distribution_mode(object_);
 }
 
-source::filter_map source::filters() const {
-    codec::decoder d(make_wrapper(pn_terminus_filter(object_)));
-    filter_map map;
-    if (!d.empty()) {
-        d.rewind();
-        d >> map;
-    }
-    return map;
+const source::filter_map& source::filters() const {
+    return filters_;
 }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/864519dd/proton-c/bindings/cpp/src/value.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value.cpp b/proton-c/bindings/cpp/src/value.cpp
index edf9074..03fc224 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -183,6 +183,9 @@ bool operator<(const value& x, const value& y) {
 }
 
 std::ostream& operator<<(std::ostream& o, const value& x) {
+    if (x.empty()) {
+        return o << "<empty-value>";
+    }
     if (type_id_is_scalar(x.type()) || x.empty())
         return o << proton::get<scalar>(x); // Print as a scalar
     // Use pn_inspect for complex types.


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


[28/50] [abbrv] qpid-proton git commit: PROTON-1460: C epoll proactor, deterministic socket IO callbacks on close

Posted by ac...@apache.org.
PROTON-1460: C epoll proactor, deterministic socket IO callbacks on close


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

Branch: refs/heads/go1
Commit: d25089bf2834dc4f650697c39d09dfb95c5509a2
Parents: ec1d1a3
Author: Clifford Jansen <cl...@apache.org>
Authored: Wed May 24 23:48:34 2017 -0700
Committer: Clifford Jansen <cl...@apache.org>
Committed: Wed May 24 23:59:41 2017 -0700

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 55 +++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d25089bf/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 2f99cd9..c65fa44 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -682,6 +682,7 @@ static void pconnection_final_free(pconnection_t *pc) {
 
 // call without lock, but only if pconnection_is_final() is true
 static void pconnection_cleanup(pconnection_t *pc) {
+  stop_polling(&pc->psocket.epoll_io, pc->psocket.proactor->epollfd);
   if (pc->psocket.sockfd != -1)
     close(pc->psocket.sockfd);
   stop_polling(&pc->timer.epoll_io, pc->psocket.proactor->epollfd);
@@ -698,8 +699,16 @@ static void pconnection_cleanup(pconnection_t *pc) {
 static void pconnection_begin_close(pconnection_t *pc) {
   if (!pc->context.closing) {
     pc->context.closing = true;
-    stop_polling(&pc->psocket.epoll_io, pc->psocket.proactor->epollfd);
-    pc->current_arm = 0;
+    if (pc->current_arm != 0 && !pc->new_events) {
+      // Force io callback via hangup
+      if (pc->current_arm != (EPOLLIN | EPOLLOUT)) {
+        pc->current_arm = (EPOLLIN | EPOLLOUT);
+        pc->psocket.epoll_io.wanted = pc->current_arm;;
+        rearm(pc->psocket.proactor, &pc->psocket.epoll_io);
+      }
+      shutdown(pc->psocket.sockfd, SHUT_RDWR);
+    }
+
     pn_connection_driver_close(&pc->driver);
     if (ptimer_shutdown(&pc->timer, pc->timer_armed))
       pc->timer_armed = false;  // disarmed in the sense that the timer will never fire again
@@ -713,6 +722,8 @@ static void pconnection_begin_close(pconnection_t *pc) {
 
 static void pconnection_forced_shutdown(pconnection_t *pc) {
   // Called by proactor_free, no competing threads, no epoll activity.
+  pc->current_arm = 0;
+  pc->new_events = 0;
   pconnection_begin_close(pc);
   // pconnection_process will never be called again.  Zero everything.
   pc->timer_armed = false;
@@ -886,12 +897,6 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
 
   // Confirmed as working thread.  Review state and unlock ASAP.
 
-  if (pc->context.closing && pconnection_is_final(pc)) {
-    unlock(&pc->context.mutex);
-    pconnection_cleanup(pc);
-    return NULL;
-  }
-
  retry:
 
   if (pc->queued_disconnect) {  // From pn_proactor_disconnect()
@@ -919,28 +924,36 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
   }
 
   if (pc->new_events) {
-    if ((pc->new_events & (EPOLLHUP | EPOLLERR)) && !pconnection_rclosed(pc) && !pconnection_wclosed(pc))
-      pconnection_maybe_connect_lh(pc);
-    else
-      pconnection_connected_lh(pc); /* Non error event means we are connected */
-    if (pc->new_events & EPOLLOUT)
-      pc->write_blocked = false;
-    if (pc->new_events & EPOLLIN)
-      pc->read_blocked = false;
+    if (!pc->context.closing) {
+      if ((pc->new_events & (EPOLLHUP | EPOLLERR)) && !pconnection_rclosed(pc) && !pconnection_wclosed(pc))
+        pconnection_maybe_connect_lh(pc);
+      else
+        pconnection_connected_lh(pc); /* Non error event means we are connected */
+      if (pc->new_events & EPOLLOUT)
+          pc->write_blocked = false;
+      if (pc->new_events & EPOLLIN)
+          pc->read_blocked = false;
+    }
     pc->current_arm = 0;
     pc->new_events = 0;
   }
   bool unarmed = (pc->current_arm == 0);
-  if (!pc->timer_armed) {
+
+  if (pc->context.closing && pconnection_is_final(pc)) {
+    unlock(&pc->context.mutex);
+    pconnection_cleanup(pc);
+    return NULL;
+  }
+
+  if (!pc->timer_armed && !pc->timer.shutting_down) {
     pc->timer_armed = true;  // about to rearm outside the lock
     timer_unarmed = true;    // so we remember
   }
-  bool timer_shutting_down = pc->timer.shutting_down;
 
   unlock(&pc->context.mutex);
   pc->hog_count++; // working context doing work
 
-  if (timer_unarmed && !timer_shutting_down) {
+  if (timer_unarmed) {
     rearm(pc->psocket.proactor, &pc->timer.epoll_io);
     timer_unarmed = false;
   }
@@ -1279,7 +1292,6 @@ void pn_listener_free(pn_listener_t *l) {
   /* Note at this point either the listener has never been used (freed by user)
      or it has been closed, so all its sockets are closed.
   */
-  // TODO: do we need a QPID DeletionManager equivalent to be safe from inbound connection (accept) epoll events?
   if (l) {
     bool can_free = true;
     if (l->collector) pn_collector_free(l->collector);
@@ -1296,6 +1308,7 @@ void pn_listener_free(pn_listener_t *l) {
 }
 
 static void listener_begin_close(pn_listener_t* l) {
+  // TODO: switch to shutdown(sock, SHUT_RD) and wait for HUP callback per listener socket (analogous to pconnection)
   if (!l->context.closing) {
     l->context.closing = true;
     /* Close all listening sockets */
@@ -1338,7 +1351,7 @@ static pn_event_batch_t *listener_process(psocket_t *ps, uint32_t events) {
   pn_listener_t *l = psocket_listener(ps);
   lock(&l->context.mutex);
   if (events) {
-    l->armed = false;
+    l->armed = false;  // TODO: armed logic should be per socket not per aggregate listener
     if (events & EPOLLRDHUP) {
       /* Calls listener_begin_close which closes all the listener's sockets */
       psocket_error(ps, errno, "listener epoll");


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


[43/50] [abbrv] qpid-proton git commit: PROTON-1495: c epoll use gai_strerror for getaddrinfo errors.

Posted by ac...@apache.org.
PROTON-1495: c epoll use gai_strerror for getaddrinfo errors.


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

Branch: refs/heads/go1
Commit: 8c5a031c23cac50b406a9d7f40b45ce44bd68a5d
Parents: 8ef841c
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Jun 7 13:41:26 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jun 7 13:44:48 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 38 +++++++++++++++++++++++++-------------
 proton-c/src/proactor/libuv.c |  2 +-
 proton-c/src/tests/proactor.c | 16 +++++++++++++++-
 3 files changed, 41 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8c5a031c/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 0bb0b10..69954d6 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -592,9 +592,7 @@ static pn_event_t *log_event(void* p, pn_event_t *e) {
   return e;
 }
 
-static void psocket_error(psocket_t *ps, int err, const char* what) {
-  strerrorbuf msg;
-  pstrerror(err, msg);
+static void psocket_error_str(psocket_t *ps, const char *msg, const char* what) {
   if (!ps->listener) {
     pn_connection_driver_t *driver = &psocket_pconnection(ps)->driver;
     pn_connection_driver_bind(driver); /* Bind so errors will be reported */
@@ -607,6 +605,16 @@ static void psocket_error(psocket_t *ps, int err, const char* what) {
   }
 }
 
+static void psocket_error(psocket_t *ps, int err, const char* what) {
+  strerrorbuf msg;
+  pstrerror(err, msg);
+  psocket_error_str(ps, msg, what);
+}
+
+static void psocket_gai_error(psocket_t *ps, int gai_err, const char* what) {
+  psocket_error_str(ps, gai_strerror(gai_err), what);
+}
+
 static void rearm(pn_proactor_t *p, epoll_extended_t *ee) {
   struct epoll_event ev;
   ev.data.ptr = ee;
@@ -991,7 +999,7 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
       else if (errno == EWOULDBLOCK)
         pc->read_blocked = true;
       else if (!(errno == EAGAIN || errno == EINTR)) {
-        psocket_error(&pc->psocket, errno, pc->disconnected ? "Disconnected" : "on read from");
+        psocket_error(&pc->psocket, errno, pc->disconnected ? "disconnected" : "on read from");
       }
     }
   }
@@ -1145,12 +1153,13 @@ void pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *addr)
   pn_connection_open(pc->driver.connection); /* Auto-open */
 
   bool notify = false;
-  if (!pgetaddrinfo(pc->psocket.host, pc->psocket.port, 0, &pc->addrinfo)) {
+  int gai_error = pgetaddrinfo(pc->psocket.host, pc->psocket.port, 0, &pc->addrinfo);
+  if (!gai_error) {
     pc->ai = pc->addrinfo;
     pconnection_maybe_connect_lh(pc); /* Start connection attempts */
     notify = pc->disconnected;
   } else {
-    psocket_error(&pc->psocket, errno, "connect to ");
+    psocket_gai_error(&pc->psocket, gai_error, "connect to ");
     notify = wake(&pc->context);
   }
   unlock(&pc->context.mutex);
@@ -1233,7 +1242,8 @@ void pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *addr, in
   pni_parse_addr(addr, addr_buf, PN_MAX_ADDR, &host, &port);
 
   struct addrinfo *addrinfo = NULL;
-  if (!pgetaddrinfo(host, port, AI_PASSIVE | AI_ALL, &addrinfo)) {
+  int gai_err = pgetaddrinfo(host, port, AI_PASSIVE | AI_ALL, &addrinfo);
+  if (!gai_err) {
     /* Count addresses, allocate enough space for sockets */
     size_t len = 0;
     for (struct addrinfo *ai = addrinfo; ai; ai = ai->ai_next) {
@@ -1273,10 +1283,13 @@ void pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *addr, in
   bool notify = wake(&l->context);
 
   if (l->psockets_size == 0) { /* All failed, create dummy socket with an error */
-    int err = errno;
     l->psockets = (psocket_t*)calloc(sizeof(psocket_t), 1);
     psocket_init(l->psockets, p, l, addr);
-    psocket_error(l->psockets, err, "listen on");
+    if (gai_err) {
+      psocket_gai_error(l->psockets, gai_err, "listen on");
+    } else {
+      psocket_error(l->psockets, errno, "listen on");
+    }
   }
   proactor_add(&l->context);
   unlock(&l->context.mutex);
@@ -1453,8 +1466,7 @@ void pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
   }
 
   if (err) {
-    /* Error on one socket closes the entire listener */
-    psocket_error(&l->psockets[0], errno, "listener state on accept");
+    psocket_error(&l->psockets[0], errno, "listener accepting from");
     unlock(&l->context.mutex);
     return;
   }
@@ -1464,8 +1476,8 @@ void pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
   int newfd = accept(ps->sockfd, NULL, 0);
   if (newfd < 0) {
     err = errno;
-    psocket_error(&pc->psocket, err, "failed initialization on accept");
-    psocket_error(ps, err, "accept");
+    psocket_error(&pc->psocket, err, "accepting from");
+    psocket_error(ps, err, "accepting from");
   } else {
     lock(&pc->context.mutex);
     configure_socket(newfd);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8c5a031c/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index cf3daab..146cd7a 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -601,7 +601,7 @@ static bool leader_connect(pconnection_t *pc) {
   int err = pconnection_init(pc);
   if (!err) err = leader_resolve(pc->work.proactor, &pc->addr, false);
   if (err) {
-    pconnection_error(pc, err, "connect resolving");
+    pconnection_error(pc, err, "on connect resolving");
     return true;
   } else {
     try_connect(pc);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8c5a031c/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index 19cc7f3..2764f79 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -493,7 +493,7 @@ static void test_errors(test_t *t) {
   pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
   test_port_t port = test_port(localhost);          /* Hold a port */
 
-  /* Invalid connect/listen parameters */
+  /* Invalid connect/listen service name */
   pn_connection_t *c = pn_connection();
   pn_proactor_connect(client, c, "127.0.0.1:xxx");
   TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts));
@@ -507,6 +507,20 @@ static void test_errors(test_t *t) {
   TEST_STR_IN(t, "xxx", pn_condition_get_description(last_condition));
   TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
 
+  /* Invalid connect/listen host name */
+  c = pn_connection();
+  pn_proactor_connect(client, c, "nosuch.example.com:");
+  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts));
+  TEST_STR_IN(t, "nosuch", pn_condition_get_description(last_condition));
+  TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
+
+  l = pn_listener();
+  pn_proactor_listen(server, l, "nosuch.example.com:", 1);
+  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
+  TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, PROACTOR_TEST_RUN(pts));
+  TEST_STR_IN(t, "nosuch", pn_condition_get_description(last_condition));
+  TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
+
   /* Connect with no listener */
   c = pn_connection();
   pn_proactor_connect(client, c, port.host_port);


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


[36/50] [abbrv] qpid-proton git commit: PROTON-1456: Support for AMQP described types

Posted by ac...@apache.org.
PROTON-1456: Support for AMQP described types

Support AMQP described types, required for compliant AMQP 1.0 filters.

Added some extra encoding/decoding tests in types_test.go


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

Branch: refs/heads/go1
Commit: 4f724ace01f942c69e650c4e7c513c327d76cfbc
Parents: 110f851
Author: Alan Conway <ac...@redhat.com>
Authored: Tue May 30 16:02:51 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 31 17:18:29 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/go/CMakeLists.txt             |   1 +
 .../go/src/qpid.apache.org/amqp/interop_test.go |   8 -
 .../go/src/qpid.apache.org/amqp/marshal.go      |  19 +-
 .../go/src/qpid.apache.org/amqp/types.go        |  11 +-
 .../go/src/qpid.apache.org/amqp/types_test.go   | 163 ++++++++++++++++
 .../go/src/qpid.apache.org/amqp/unmarshal.go    | 185 ++++++++++++-------
 6 files changed, 306 insertions(+), 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4f724ace/proton-c/bindings/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/CMakeLists.txt b/proton-c/bindings/go/CMakeLists.txt
index d0ffe9b..7f814b9 100644
--- a/proton-c/bindings/go/CMakeLists.txt
+++ b/proton-c/bindings/go/CMakeLists.txt
@@ -23,6 +23,7 @@ message(STATUS "Found Go: ${GO_EXE} (${go_ver})")
 
 set(GO_BUILD_FLAGS "" CACHE STRING "Flags for 'go build'")
 set(GO_TEST_FLAGS "-v" CACHE STRING "Flags for 'go test'")
+set(GO_VET_FLAGS "-v" CACHE STRING "Flags for 'go test'")
 
 # Flags that differ for golang go and gcc go.
 if (go_ver MATCHES "gccgo")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4f724ace/proton-c/bindings/go/src/qpid.apache.org/amqp/interop_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/interop_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/interop_test.go
index b3e27bc..a5fb92e 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/interop_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/interop_test.go
@@ -24,7 +24,6 @@ package amqp
 
 import (
 	"bytes"
-	"fmt"
 	"io"
 	"io/ioutil"
 	"os"
@@ -33,13 +32,6 @@ import (
 	"testing"
 )
 
-func checkEqual(want interface{}, got interface{}) error {
-	if !reflect.DeepEqual(want, got) {
-		return fmt.Errorf("%#v != %#v", want, got)
-	}
-	return nil
-}
-
 func getReader(t *testing.T, name string) (r io.Reader) {
 	dir := os.Getenv("PN_INTEROP_DIR")
 	if dir == "" {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4f724ace/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
index a0a732e..04ecf04 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
@@ -87,17 +87,16 @@ Go types are encoded as follows
  +-------------------------------------+--------------------------------------------+
  |List                                 |list, may have mixed types  values          |
  +-------------------------------------+--------------------------------------------+
+ |Described                            |described type                              |
+ +-------------------------------------+--------------------------------------------+
 
-The following Go types cannot be marshaled: uintptr, function, interface, channel
-
-TODO
-
-Go types: array, slice, struct, complex64/128.
+The following Go types cannot be marshaled: uintptr, function, channel, array (use slice), struct
 
-AMQP types: decimal32/64/128, char, timestamp, uuid, array, multi-section message bodies.
+TODO: Not yet implemented:
 
-Described types.
+Go types: struct, complex64/128.
 
+AMQP types: decimal32/64/128, char, timestamp, uuid, array.
 */
 func Marshal(v interface{}, buffer []byte) (outbuf []byte, err error) {
 	defer func() {
@@ -204,6 +203,12 @@ func marshal(v interface{}, data *C.pn_data_t) {
 			marshal(val, data)
 		}
 		C.pn_data_exit(data)
+	case Described:
+		C.pn_data_put_described(data)
+		C.pn_data_enter(data)
+		marshal(v.Descriptor, data)
+		marshal(v.Value, data)
+		C.pn_data_exit(data)
 	case Key:
 		marshal(v.Get(), data)
 	default:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4f724ace/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
index 76f223f..6e2ebc8 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
@@ -83,7 +83,7 @@ func (t C.pn_type_t) String() string {
 	case C.PN_MAP:
 		return "map"
 	default:
-		return "no-data"
+		return fmt.Sprintf("<bad-type %v>", int(t))
 	}
 }
 
@@ -210,3 +210,12 @@ func StringKey(v string) Key { return Key{Symbol(v)} }
 func (k Key) Get() interface{} { return k.value }
 
 func (k Key) String() string { return fmt.Sprintf("%v", k.Get()) }
+
+// Described represents an AMQP described type, which is really
+// just a pair of AMQP values - the first is treated as a "descriptor",
+// and is normally a string or ulong providing information about the type.
+// The second is the "value" and can be any AMQP value.
+type Described struct {
+	Descriptor interface{}
+	Value      interface{}
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4f724ace/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
index b9c0596..096d27f 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
@@ -21,8 +21,28 @@ package amqp
 
 import (
 	"fmt"
+	"reflect"
+	"testing"
 )
 
+func checkEqual(want interface{}, got interface{}) error {
+	if !reflect.DeepEqual(want, got) {
+		return fmt.Errorf("%#v != %#v", want, got)
+	}
+	return nil
+}
+
+func checkUnmarshal(marshalled []byte, v interface{}) error {
+	got, err := Unmarshal(marshalled, v)
+	if err != nil {
+		return err
+	}
+	if got != len(marshalled) {
+		return fmt.Errorf("Wanted to Unmarshal %v bytes, got %v", len(marshalled), got)
+	}
+	return nil
+}
+
 func ExampleKey() {
 	var k Key = SymbolKey(Symbol("foo"))
 	fmt.Println(k.Get().(Symbol))
@@ -32,3 +52,146 @@ func ExampleKey() {
 	// foo
 	// 42
 }
+
+// Values that are unchanged by a marshal/unmarshal round-trip from interface{}
+// to interface{}
+var rtValues = []interface{}{
+	true,
+	int8(-8), int16(-16), int32(-32), int64(-64),
+	uint8(8), uint16(16), uint32(32), uint64(64),
+	float32(0.32), float64(0.64),
+	"string", Binary("Binary"), Symbol("symbol"),
+	nil,
+	Map{"V": "X"},
+	List{"V", int32(1)},
+	Described{"D", "V"},
+}
+
+// Go values that unmarshal as an equivalent value but a different type
+// if unmarshalled to interface{}.
+var oddValues = []interface{}{
+	int(-99), uint(99), // [u]int32|64
+	[]byte("byte"),            // amqp.Binary
+	map[string]int{"str": 99}, // amqp.Map
+	[]string{"a", "b"},        // amqp.List
+}
+
+var allValues = append(rtValues, oddValues...)
+
+// %v formatted representation of allValues
+var vstrings = []string{
+	// for rtValues
+	"true",
+	"-8", "-16", "-32", "-64",
+	"8", "16", "32", "64",
+	"0.32", "0.64",
+	"string", "Binary", "symbol",
+	"<nil>",
+	"map[V:X]",
+	"[V 1]",
+	"{D V}",
+	// for oddValues
+	"-99", "99",
+	"[98 121 116 101]", /*"byte"*/
+	"map[str:99]",
+	"[a b]",
+}
+
+// Round-trip encoding test
+func TestTypesRoundTrip(t *testing.T) {
+	for _, x := range rtValues {
+		marshalled, err := Marshal(x, nil)
+		if err != nil {
+			t.Error(err)
+		}
+		var v interface{}
+		if err := checkUnmarshal(marshalled, &v); err != nil {
+			t.Error(err)
+		}
+		if err := checkEqual(v, x); err != nil {
+			t.Error(t, err)
+		}
+	}
+}
+
+// Round trip from T to T where T is the type of the value.
+func TestTypesRoundTripAll(t *testing.T) {
+	for _, x := range allValues {
+		marshalled, err := Marshal(x, nil)
+		if err != nil {
+			t.Error(err)
+		}
+		if x == nil { // We can't create an instance of nil to unmarshal to.
+			continue
+		}
+		vp := reflect.New(reflect.TypeOf(x)) // v points to a Zero of the same type as x
+		if err := checkUnmarshal(marshalled, vp.Interface()); err != nil {
+			t.Error(err)
+		}
+		v := vp.Elem().Interface()
+		if err := checkEqual(v, x); err != nil {
+			t.Error(err)
+		}
+	}
+}
+
+func TestTypesPrint(t *testing.T) {
+	// Default %v representations of rtValues and oddValues
+	for i, x := range allValues {
+		if s := fmt.Sprintf("%v", x); vstrings[i] != s {
+			t.Errorf("printing %T: want %v, got %v", x, vstrings[i], s)
+		}
+	}
+}
+
+func TestDescribed(t *testing.T) {
+	want := Described{"D", "V"}
+	marshalled, _ := Marshal(want, nil)
+
+	// Unmarshal to Described type
+	var d Described
+	if err := checkUnmarshal(marshalled, &d); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual(want, d); err != nil {
+		t.Error(err)
+	}
+
+	// Unmarshal to interface{}
+	var i interface{}
+	if err := checkUnmarshal(marshalled, &i); err != nil {
+		t.Error(err)
+	}
+	if _, ok := i.(Described); !ok {
+		t.Errorf("Expected Described, got %T(%v)", i, i)
+	}
+	if err := checkEqual(want, i); err != nil {
+		t.Error(err)
+	}
+
+	// Unmarshal value only (drop descriptor) to the value type
+	var s string
+	if err := checkUnmarshal(marshalled, &s); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual(want.Value, s); err != nil {
+		t.Error(err)
+	}
+
+	// Nested described types
+	want = Described{Described{int64(123), true}, "foo"}
+	marshalled, _ = Marshal(want, nil)
+	if err := checkUnmarshal(marshalled, &d); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual(want, d); err != nil {
+		t.Error(err)
+	}
+	// Nested to interface
+	if err := checkUnmarshal(marshalled, &i); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual(want, i); err != nil {
+		t.Error(err)
+	}
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4f724ace/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index 96b8e05..b49727e 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -27,6 +27,7 @@ import (
 	"fmt"
 	"io"
 	"reflect"
+	"strings"
 	"unsafe"
 )
 
@@ -44,16 +45,23 @@ type UnmarshalError struct {
 
 func (e UnmarshalError) Error() string { return e.s }
 
-func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
+func newUnmarshalErrorMsg(pnType C.pn_type_t, v interface{}, msg string) *UnmarshalError {
+	if len(msg) > 0 && !strings.HasPrefix(msg, ":") {
+		msg = ": " + msg
+	}
 	e := &UnmarshalError{AMQPType: C.pn_type_t(pnType).String(), GoType: reflect.TypeOf(v)}
 	if e.GoType.Kind() != reflect.Ptr {
-		e.s = fmt.Sprintf("cannot unmarshal to type %s, not a pointer", e.GoType)
+		e.s = fmt.Sprintf("cannot unmarshal to type %s, not a pointer%s", e.GoType, msg)
 	} else {
-		e.s = fmt.Sprintf("cannot unmarshal AMQP %s to %s", e.AMQPType, e.GoType)
+		e.s = fmt.Sprintf("cannot unmarshal AMQP %s to %s%s", e.AMQPType, e.GoType, msg)
 	}
 	return e
 }
 
+func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
+	return newUnmarshalErrorMsg(pnType, v, "")
+}
+
 func newUnmarshalErrorData(data *C.pn_data_t, v interface{}) *UnmarshalError {
 	err := PnError(C.pn_data_error(data))
 	if err == nil {
@@ -130,68 +138,73 @@ func (d *Decoder) Decode(v interface{}) (err error) {
 }
 
 /*
-Unmarshal decodes AMQP-encoded bytes and stores the result in the value pointed to by v.
+Unmarshal decodes AMQP-encoded bytes and stores the result in the Go value pointed to by v.
 Types are converted as follows:
 
- +---------------------------+----------------------------------------------------------------------+
- |To Go types                |From AMQP types                                                       |
- +===========================+======================================================================+
- |bool                       |bool                                                                  |
- +---------------------------+----------------------------------------------------------------------+
- |int, int8, int16,          |Equivalent or smaller signed integer type: byte, short, int, long.    |
- |int32, int64               |                                                                      |
- +---------------------------+----------------------------------------------------------------------+
- |uint, uint8, uint16,       |Equivalent or smaller unsigned integer type: ubyte, ushort, uint,     |
- |uint32, uint64 types       |ulong                                                                 |
- +---------------------------+----------------------------------------------------------------------+
- |float32, float64           |Equivalent or smaller float or double.                                |
- +---------------------------+----------------------------------------------------------------------+
- |string, []byte             |string, symbol or binary.                                             |
- +---------------------------+----------------------------------------------------------------------+
- |Symbol                     |symbol                                                                |
- +---------------------------+----------------------------------------------------------------------+
- |map[K]T                    |map, provided all keys and values can unmarshal to types K, T         |
- +---------------------------+----------------------------------------------------------------------+
- |Map                        |map, any AMQP map                                                     |
- +---------------------------+----------------------------------------------------------------------+
- |interface{}                |Any AMQP value can be unmarshaled to an interface{} as follows:       |
- |                           +------------------------+---------------------------------------------+
- |                           |AMQP Type               |Go Type in interface{}                       |
- |                           +========================+=============================================+
- |                           |bool                    |bool                                         |
- |                           +------------------------+---------------------------------------------+
- |                           |byte,short,int,long     |int8,int16,int32,int64                       |
- |                           +------------------------+---------------------------------------------+
- |                           |ubyte,ushort,uint,ulong |uint8,uint16,uint32,uint64                   |
- |                           +------------------------+---------------------------------------------+
- |                           |float, double           |float32, float64                             |
- |                           +------------------------+---------------------------------------------+
- |                           |string                  |string                                       |
- |                           +------------------------+---------------------------------------------+
- |                           |symbol                  |Symbol                                       |
- |                           +------------------------+---------------------------------------------+
- |                           |binary                  |Binary                                       |
- |                           +------------------------+---------------------------------------------+
- |                           |nulll                   |nil                                          |
- |                           +------------------------+---------------------------------------------+
- |                           |map                     |Map                                          |
- |                           +------------------------+---------------------------------------------+
- |                           |list                    |List                                         |
- +---------------------------+------------------------+---------------------------------------------+
- |Key                        |symbol, ulong                                                         |
- +---------------------------+----------------------------------------------------------------------+
-
-The following Go types cannot be unmarshaled: uintptr, function, interface, channel.
-
-TODO
-
-Go types: array, struct.
-
-AMQP types: decimal32/64/128, char (round trip), timestamp, uuid, array, multi-section message bodies.
-
-AMQP maps with mixed/unhashable key types need an alternate representation.
-
-Described types.
+ +------------------------+-------------------------------------------------+
+ |To Go types             |From AMQP types                                  |
+ +========================+=================================================+
+ |bool                    |bool                                             |
+ +------------------------+-------------------------------------------------+
+ |int, int8, int16, int32,|Equivalent or smaller signed integer type: byte, |
+ |int64                   |short, int, long.                                |
+ +------------------------+-------------------------------------------------+
+ |uint, uint8, uint16,    |Equivalent or smaller unsigned integer type:     |
+ |uint32, uint64          |ubyte, ushort, uint, ulong                       |
+ +------------------------+-------------------------------------------------+
+ |float32, float64        |Equivalent or smaller float or double.           |
+ +------------------------+-------------------------------------------------+
+ |string, []byte          |string, symbol or binary.                        |
+ +------------------------+-------------------------------------------------+
+ |Symbol                  |symbol                                           |
+ +------------------------+-------------------------------------------------+
+ |map[K]T                 |map, provided all keys and values can unmarshal  |
+ |                        |to types K,T                                     |
+ +------------------------+-------------------------------------------------+
+ |Map                     |map, any AMQP map                                |
+ +------------------------+-------------------------------------------------+
+ |Described               |described type                                   |
+ +------------------------+-------------------------------------------------+
+
+An AMQP described type can unmarshal into the corresponding plain type, discarding the descriptor.
+For example an AMQP described string can unmarshal into a plain go string.
+Unmarshal into the Described type preserves the descriptor.
+
+Any AMQP type can unmarshal to an interface{}, the Go type used to unmarshal is chosen from the AMQP type as follows
+
+ +------------------------+-------------------------------------------------+
+ |AMQP Type               |Go Type in interface{}                           |
+ +========================+=================================================+
+ |bool                    |bool                                             |
+ +------------------------+-------------------------------------------------+
+ |byte,short,int,long     |int8,int16,int32,int64                           |
+ +------------------------+-------------------------------------------------+
+ |ubyte,ushort,uint,ulong |uint8,uint16,uint32,uint64                       |
+ +------------------------+-------------------------------------------------+
+ |float, double           |float32, float64                                 |
+ +------------------------+-------------------------------------------------+
+ |string                  |string                                           |
+ +------------------------+-------------------------------------------------+
+ |symbol                  |Symbol                                           |
+ +------------------------+-------------------------------------------------+
+ |binary                  |Binary                                           |
+ +------------------------+-------------------------------------------------+
+ |null                    |nil                                              |
+ +------------------------+-------------------------------------------------+
+ |map                     |Map                                              |
+ +------------------------+-------------------------------------------------+
+ |list                    |List                                             |
+ +------------------------+-------------------------------------------------+
+ |described type          |Described                                        |
+ +--------------------------------------------------------------------------+
+
+The following Go types cannot be unmarshaled: uintptr, function, interface, channel, array (use slice), struct
+
+TODO: Not yet implemented:
+
+AMQP types: decimal32/64/128, char (round trip), timestamp, uuid.
+
+AMQP maps with mixed key types, or key types that are not legal Go map keys.
 */
 func Unmarshal(bytes []byte, v interface{}) (n int, err error) {
 	defer recoverUnmarshal(&err)
@@ -227,6 +240,15 @@ func (d *Decoder) more() error {
 // Unmarshal from data into value pointed at by v.
 func unmarshal(v interface{}, data *C.pn_data_t) {
 	pnType := C.pn_data_type(data)
+
+	// Check for PN_DESCRIBED first, as described types can unmarshal into any of the Go types.
+	// Interfaces are handled in the switch below, even for described types.
+	if _, isInterface := v.(*interface{}); !isInterface && bool(C.pn_data_is_described(data)) {
+		getDescribed(data, v)
+		return
+	}
+
+	// Unmarshal based on the target type
 	switch v := v.(type) {
 	case *bool:
 		switch pnType {
@@ -440,7 +462,7 @@ func unmarshal(v interface{}, data *C.pn_data_t) {
 			panic(newUnmarshalError(pnType, v))
 		}
 
-	default:
+	default: // This is not one of the fixed well-known types, reflect for map and slice types
 		if reflect.TypeOf(v).Kind() != reflect.Ptr {
 			panic(newUnmarshalError(pnType, v))
 		}
@@ -508,8 +530,18 @@ func getInterface(data *C.pn_data_t, v *interface{}) {
 		l := make(List, 0)
 		unmarshal(&l, data)
 		*v = l
-	default: // No data (-1 or NULL)
+	case C.PN_DESCRIBED:
+		d := Described{}
+		unmarshal(&d, data)
+		*v = d
+	case C.PN_NULL:
 		*v = nil
+	case C.PN_INVALID:
+		// Allow decoding from an empty data object to an interface, treat it like NULL.
+		// This happens when optional values or properties are omitted from a message.
+		*v = nil
+	default: // Don't know how to handle this
+		panic(newUnmarshalError(pnType, v))
 	}
 }
 
@@ -558,6 +590,29 @@ func getList(data *C.pn_data_t, v interface{}) {
 	reflect.ValueOf(v).Elem().Set(listValue)
 }
 
+func getDescribed(data *C.pn_data_t, v interface{}) {
+	d, _ := v.(*Described)
+	pnType := C.pn_data_type(data)
+	if bool(C.pn_data_enter(data)) {
+		defer C.pn_data_exit(data)
+		if bool(C.pn_data_next(data)) {
+			if d != nil {
+				unmarshal(&d.Descriptor, data)
+			}
+			if bool(C.pn_data_next(data)) {
+				if d != nil {
+					unmarshal(&d.Value, data)
+				} else {
+					unmarshal(v, data)
+				}
+				return
+			}
+		}
+	}
+	// The pn_data cursor didn't move as expected
+	panic(newUnmarshalErrorMsg(pnType, v, "bad described value encoding"))
+}
+
 // decode from bytes.
 // Return bytes decoded or 0 if we could not decode a complete object.
 //


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


[09/50] [abbrv] qpid-proton git commit: PROTON-1476: fix strict-aliasing errors on gcc 4.4.7

Posted by ac...@apache.org.
PROTON-1476: fix strict-aliasing errors on gcc 4.4.7


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

Branch: refs/heads/go1
Commit: beb38d21f430d421493188f70921c568668f51d1
Parents: 24a2ed3
Author: Alan Conway <ac...@redhat.com>
Authored: Thu May 11 09:05:49 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu May 11 11:43:42 2017 -0400

----------------------------------------------------------------------
 proton-c/src/tests/test_tools.h | 57 ++++++++++++++----------------------
 1 file changed, 22 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/beb38d21/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 ec656f6..04ae0f1 100644
--- a/proton-c/src/tests/test_tools.h
+++ b/proton-c/src/tests/test_tools.h
@@ -23,6 +23,7 @@
 #include <proton/type_compat.h>
 #include <proton/condition.h>
 #include <proton/event.h>
+#include <proton/proactor.h>
 
 #include <errno.h>
 #include <stdarg.h>
@@ -253,43 +254,13 @@ void sock_close(sock_t sock) { close(sock); }
 #endif
 
 
-/* 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.
-*/
-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;    /* 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;
-}
-
-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;
-  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);
-}
 
 /* Combines a sock_t with the int and char* versions of the port for convenience */
 typedef struct test_port_t {
   sock_t sock;
   int port;                     /* port as integer */
-  char str[256];                /* port as string */
-  char host_port[256];          /* host:port string */
+  char str[PN_MAX_ADDR];	/* port as string */
+  char host_port[PN_MAX_ADDR];	/* host:port string */
 } test_port_t;
 
 /* Modifies tp->host_port to use host, returns the new tp->host_port */
@@ -298,11 +269,27 @@ const char *test_port_use_host(test_port_t *tp, const char *host) {
   return tp->host_port;
 }
 
-/* Create a test_port_t  */
+/* Create a socket and bind(INADDR_LOOPBACK:0) to get a free port.
+   Use SO_REUSEADDR so other processes can bind and listen on this port.
+   Use host to create the host_port address string.
+*/
 test_port_t test_port(const char* host) {
   test_port_t tp = {0};
-  tp.sock = sock_bind0();
-  tp.port = sock_port(tp.sock);
+  tp.sock = socket(AF_INET, SOCK_STREAM, 0);
+  TEST_ASSERT_ERRNO(tp.sock >= 0, errno);
+  int on = 1;
+  int err = setsockopt(tp.sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
+  TEST_ASSERT_ERRNO(!err, errno);
+  struct sockaddr_in addr = {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 */
+  err = bind(tp.sock, (struct sockaddr*)&addr, sizeof(addr));
+  TEST_ASSERT_ERRNO(!err, errno);
+  socklen_t len = sizeof(addr);
+  err = getsockname(tp.sock, (struct sockaddr*)&addr, &len); /* Get the bound port */
+  TEST_ASSERT_ERRNO(!err, errno);
+  tp.port = addr.sin_port;
   snprintf(tp.str, sizeof(tp.str), "%d", tp.port);
   test_port_use_host(&tp, host);
   return tp;


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


[31/50] [abbrv] qpid-proton git commit: PROTON-1288: c++ fix caching bug in proton::map

Posted by ac...@apache.org.
PROTON-1288: c++ fix caching bug in proton::map

Discovered using quiver tests: `quiver foo --impl=qpid-proton-cpp`

map::clear() did not invalidate the cache as required by message::encode()
to ensure that newly-decoded map values updated the caches correctly.
Simplified the cache logic.


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

Branch: refs/heads/go1
Commit: f66938024bbb85036aa30ad42e014b912435cacd
Parents: b86234c
Author: Alan Conway <ac...@redhat.com>
Authored: Thu May 25 22:35:34 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu May 25 22:35:34 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/cpp/include/proton/map.hpp    |  4 +-
 proton-c/bindings/cpp/include/proton/sender.hpp |  1 +
 .../bindings/cpp/src/connection_driver_test.cpp | 29 ++++++-
 proton-c/bindings/cpp/src/map.cpp               | 83 +++++++-------------
 proton-c/bindings/cpp/src/message_test.cpp      | 13 +++
 5 files changed, 70 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f6693802/proton-c/bindings/cpp/include/proton/map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/map.hpp b/proton-c/bindings/cpp/include/proton/map.hpp
index 9798fad..86e4de7 100644
--- a/proton-c/bindings/cpp/include/proton/map.hpp
+++ b/proton-c/bindings/cpp/include/proton/map.hpp
@@ -115,9 +115,7 @@ class PN_CPP_CLASS_EXTERN map {
     mutable internal::pn_unique_ptr<map_type> map_;
     mutable proton::value value_;
 
-    void ensure() const;
-    const map_type& cache() const;
-    map_type& cache_update();
+    map_type& cache() const;
     proton::value& flush() const;
 
   friend PN_CPP_EXTERN proton::codec::decoder& operator>> <>(proton::codec::decoder&, map&);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f6693802/proton-c/bindings/cpp/include/proton/sender.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/sender.hpp b/proton-c/bindings/cpp/include/proton/sender.hpp
index 8979bb4..f8c1e66 100644
--- a/proton-c/bindings/cpp/include/proton/sender.hpp
+++ b/proton-c/bindings/cpp/include/proton/sender.hpp
@@ -25,6 +25,7 @@
 #include "./fwd.hpp"
 #include "./internal/export.hpp"
 #include "./link.hpp"
+#include "./tracker.hpp"
 
 struct pn_link_t;
 struct pn_session_t;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f6693802/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
index f179601..a5771f9 100644
--- a/proton-c/bindings/cpp/src/connection_driver_test.cpp
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -25,8 +25,10 @@
 #include "proton/io/connection_driver.hpp"
 #include "proton/io/link_namer.hpp"
 #include "proton/link.hpp"
+#include "proton/message.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/receiver_options.hpp"
+#include "proton/sender.hpp"
 #include "proton/sender_options.hpp"
 #include "proton/source_options.hpp"
 #include "proton/types_fwd.hpp"
@@ -123,6 +125,7 @@ struct record_handler : public messaging_handler {
     std::deque<proton::sender> senders;
     std::deque<proton::session> sessions;
     std::deque<std::string> unhandled_errors, transport_errors, connection_errors;
+    std::deque<proton::message> messages;
 
     void on_receiver_open(receiver &l) PN_CPP_OVERRIDE {
         receivers.push_back(l);
@@ -147,6 +150,10 @@ struct record_handler : public messaging_handler {
     void on_error(const proton::error_condition& c) PN_CPP_OVERRIDE {
         unhandled_errors.push_back(c.what());
     }
+
+    void on_message(proton::delivery&, proton::message& m) PN_CPP_OVERRIDE {
+        messages.push_back(m);
+    }
 };
 
 struct namer : public io::link_namer {
@@ -307,16 +314,36 @@ void test_link_filters() {
     ASSERT_EQUAL(value("xxx"), bx.source().filters().get("xx"));
 }
 
+void test_message() {
+    // Verify a message arrives intact
+    record_handler ha, hb;
+    driver_pair d(ha, hb);
+
+    proton::sender s = d.a.connection().open_sender("x");
+    proton::message m("barefoot");
+    m.properties().put("x", "y");
+    m.message_annotations().put("a", "b");
+    s.send(m);
+
+    while (hb.messages.size() == 0)
+        d.process();
+
+    proton::message m2 = quick_pop(hb.messages);
+    ASSERT_EQUAL(value("barefoot"), m2.body());
+    ASSERT_EQUAL(value("y"), m2.properties().get("x"));
+    ASSERT_EQUAL(value("b"), m2.message_annotations().get("a"));
+}
 
 }
 
 int main(int argc, char** argv) {
     int failed = 0;
-    RUN_ARGV_TEST(failed, test_link_filters());
     RUN_ARGV_TEST(failed, test_driver_link_id());
     RUN_ARGV_TEST(failed, test_endpoint_close());
     RUN_ARGV_TEST(failed, test_driver_disconnected());
     RUN_ARGV_TEST(failed, test_no_container());
     RUN_ARGV_TEST(failed, test_spin_interrupt());
+    RUN_ARGV_TEST(failed, test_message());
+    RUN_ARGV_TEST(failed, test_link_filters());
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f6693802/proton-c/bindings/cpp/src/map.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/map.cpp b/proton-c/bindings/cpp/src/map.cpp
index 6fc80fa..29652d2 100644
--- a/proton-c/bindings/cpp/src/map.cpp
+++ b/proton-c/bindings/cpp/src/map.cpp
@@ -32,14 +32,9 @@
 #include <string>
 
 // IMPLEMENTATION NOTES:
-// - either value_, map_ or both can hold the up-to-date data
-// - avoid encoding or decoding between map_ and value_ unless necessary
-//   - if (map.get()) then map_ is up to date
-//   - if (!value_.empty()) then value_ is up to date
-//   - if (map.get_() && !value_.empty()) then map_ and value_ have equivalent data
-//   - if (!map.get_() && value_.empty()) then that's equivalent to an empty map
+// - if (map_.get()) then *map_ is the authority
 // - cache() ensures that *map_ is up to date
-// - flush() ensures value_ is up to date
+// - flush() ensures value_ is up to date and map_ is reset
 
 namespace proton {
 
@@ -64,24 +59,11 @@ PN_CPP_EXTERN void swap(map<K,T>& x, map<K,T>& y) {
 }
 
 template <class K, class T>
-void map<K,T>::ensure() const {
-    if (!map_) {
-        map_.reset(new map<K,T>::map_type);
-    }
-}
-
-template <class K, class T>
 map<K,T>& map<K,T>::operator=(const map& x) {
     if (&x != this) {
-        if (!x.value_.empty()) {
-            map_.reset();
+        map_.reset(x.map_.get() ? new map_type(*x.map_) : 0);
+        if (!map_) {
             value_ = x.value_;
-        } else if (x.map_.get()) {
-            value_.clear();
-            ensure();
-            *map_ = *x.map_;
-        } else {
-            clear();
         }
     }
     return *this;
@@ -107,41 +89,38 @@ map<K,T>::~map() {}
 
 // Make sure map_ is valid
 template <class K, class T>
-const typename map<K,T>::map_type& map<K,T>::cache() const {
+typename map<K,T>::map_type& map<K,T>::cache() const {
     if (!map_) {
-        ensure();
+        map_.reset(new map_type);
         if (!value_.empty()) {
-            proton::get(value_, *map_);
+            try {
+                proton::get(value_, *map_);
+            } catch (...) {     // Invalid value for the map, throw it away.
+                map_.reset();
+                value_.clear();
+                throw;
+            }
         }
     }
     return *map_;
 }
 
-// Make sure map_ is valid, and mark value_ invalid
-template <class K, class T>
-typename map<K,T>::map_type& map<K,T>::cache_update() {
-    cache();
-    value_.clear();
-    return *map_;
-}
-
 template <class K, class T>
 value& map<K,T>::flush() const {
-    if (value_.empty()) {
-        // Create an empty map if need be, value_ must hold a valid map (even if empty)
-        // it must not be an empty (NULL_TYPE) proton::value.
-        ensure();
+    if (map_.get()) {
         value_ = *map_;
+        map_.reset();
+    } else if (value_.empty()) {
+        // Must contain an empty map, not be an empty value.
+        codec::encoder(value_) << codec::start::map() << codec::finish();
     }
     return value_;
 }
 
 template <class K, class T>
 void map<K,T>::value(const proton::value& x) {
-    value_.clear();
-    // Validate the value by decoding it into map_, throw if not a valid map value.
-    ensure();
-    proton::get(x, *map_);
+    value_ = x;
+    cache();    // Validate the value by decoding to cache.
 }
 
 template <class K, class T>
@@ -160,7 +139,7 @@ T map<K,T>::get(const K& k) const {
 
 template <class K, class T>
 void map<K,T>::put(const K& k, const T& v) {
-    cache_update()[k] = v;
+    cache()[k] = v;
 }
 
 template <class K, class T>
@@ -168,7 +147,7 @@ size_t map<K,T>::erase(const K& k) {
     if (this->empty()) {
         return 0;
     } else {
-        return cache_update().erase(k);
+        return cache().erase(k);
     }
 }
 
@@ -184,9 +163,7 @@ size_t map<K,T>::size() const {
 
 template <class K, class T>
 void map<K,T>::clear() {
-    if (map_.get()) {
-        map_->clear();
-    }
+    map_.reset();               // Must invalidate the cache on clear()
     value_.clear();
 }
 
@@ -214,22 +191,16 @@ void map<K,T>::reset(pn_data_t *d) {
 template <class K, class T>
 PN_CPP_EXTERN proton::codec::decoder& operator>>(proton::codec::decoder& d, map<K,T>& m)
 {
-    // Decode to m.map_ rather than m.value_ to verify the data is of valid type.
-    m.value_.clear();
-    m.ensure();
-    d >> *m.map_;
+    m.map_.reset();
+    d >> m.value_;
+    m.cache();                  // Validate the value
     return d;
 }
 
 template <class K, class T>
 PN_CPP_EXTERN proton::codec::encoder& operator<<(proton::codec::encoder& e, const map<K,T>& m)
 {
-    if (!m.value_.empty()) {
-        return e << m.value_;   // Copy the value
-    }
-    // Encode the (possibly empty) map_.
-    m.ensure();
-    return e << *(m.map_);
+    return e << m.value();   // Copy the value
 }
 
 // Force the necessary template instantiations so that the library exports the correct symbols

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f6693802/proton-c/bindings/cpp/src/message_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message_test.cpp b/proton-c/bindings/cpp/src/message_test.cpp
index eafea2e..0d7229f 100644
--- a/proton-c/bindings/cpp/src/message_test.cpp
+++ b/proton-c/bindings/cpp/src/message_test.cpp
@@ -167,6 +167,18 @@ void test_message_maps() {
     ASSERT(m3.message_annotations().empty());
 }
 
+void test_message_reuse() {
+    message m1("one");
+    m1.properties().put("x", "y");
+
+    message m2("two");
+    m2.properties().put("a", "b");
+
+    m1.decode(m2.encode());     // Use m1 for a newly decoded message
+    ASSERT_EQUAL(value("two"), m1.body());
+    ASSERT_EQUAL(value("b"), m1.properties().get("a"));
+}
+
 }
 
 int main(int, char**) {
@@ -175,5 +187,6 @@ int main(int, char**) {
     RUN_TEST(failed, test_message_defaults());
     RUN_TEST(failed, test_message_body());
     RUN_TEST(failed, test_message_maps());
+    RUN_TEST(failed, test_message_reuse());
     return failed;
 }


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


[29/50] [abbrv] qpid-proton git commit: NO-JIRA: c++ connection_driver_test - interrupt hung tests

Posted by ac...@apache.org.
NO-JIRA: c++ connection_driver_test - interrupt hung tests

connection_driver_test throws an error after 1000 iterations with no events
to prevent faulty tests from hanging.


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

Branch: refs/heads/go1
Commit: 876daa72de9790f5e2bdf2423075401d80123cfb
Parents: d25089b
Author: Alan Conway <ac...@redhat.com>
Authored: Thu May 25 13:19:50 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu May 25 13:27:24 2017 -0400

----------------------------------------------------------------------
 .../cpp/include/proton/io/connection_driver.hpp |   3 +
 .../bindings/cpp/src/connection_driver_test.cpp | 122 +++++++++++--------
 proton-c/bindings/cpp/src/include/test_bits.hpp |  23 +++-
 .../bindings/cpp/src/io/connection_driver.cpp   |   4 +
 4 files changed, 102 insertions(+), 50 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/876daa72/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 759b1fc..56deb00 100644
--- a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
+++ b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
@@ -176,6 +176,9 @@ PN_CPP_CLASS_EXTERN connection_driver {
     ///
     PN_CPP_EXTERN void disconnected(const error_condition& = error_condition());
 
+    /// There are events to be dispatched by dispatch()
+    PN_CPP_EXTERN bool has_events() const;
+
     /// Dispatch all available events and call the corresponding \ref messaging_handler methods.
     ///
     /// Returns true if the engine is still active, false if it is finished and

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/876daa72/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
index 760ac55..f179601 100644
--- a/proton-c/bindings/cpp/src/connection_driver_test.cpp
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -46,13 +46,17 @@ using proton::io::mutable_buffer;
 
 typedef std::deque<char> byte_stream;
 
+static const int MAX_SPIN = 1000; // Give up after 1000 event-less dispatches
+
 /// In memory connection_driver that reads and writes from byte_streams
 struct in_memory_driver : public connection_driver {
 
     byte_stream& reads;
     byte_stream& writes;
+    int spinning;
 
-    in_memory_driver(byte_stream& rd, byte_stream& wr) : reads(rd), writes(wr) {}
+    in_memory_driver(byte_stream& rd, byte_stream& wr) :
+        reads(rd), writes(wr), spinning(0) {}
 
     void do_read() {
         mutable_buffer rbuf = read_buffer();
@@ -74,11 +78,19 @@ struct in_memory_driver : public connection_driver {
         }
     }
 
+    void check_idle() {
+        spinning = has_events() ? 0 : spinning+1;
+        if (spinning > MAX_SPIN)
+            throw test::error("no activity, interrupting test");
+    }
+
     void process() {
+        check_idle();
         if (!dispatch())
-            throw std::runtime_error("unexpected close: "+connection().error().what());
+            throw test::error("unexpected close: "+connection().error().what());
         do_read();
         do_write();
+        check_idle();
         dispatch();
     }
 };
@@ -145,50 +157,50 @@ struct namer : public io::link_namer {
 
 void test_driver_link_id() {
     record_handler ha, hb;
-    driver_pair e(ha, hb);
-    e.a.connect(ha);
-    e.b.accept(hb);
+    driver_pair d(ha, hb);
+    d.a.connect(ha);
+    d.b.accept(hb);
 
     namer na('x');
     namer nb('b');
-    connection ca = e.a.connection();
-    connection cb = e.b.connection();
+    connection ca = d.a.connection();
+    connection cb = d.b.connection();
     set_link_namer(ca, na);
     set_link_namer(cb, nb);
 
-    e.b.connection().open();
+    d.b.connection().open();
 
-    e.a.connection().open_sender("foo");
-    while (ha.senders.empty() || hb.receivers.empty()) e.process();
+    d.a.connection().open_sender("foo");
+    while (ha.senders.empty() || hb.receivers.empty()) d.process();
     sender s = quick_pop(ha.senders);
     ASSERT_EQUAL("x", s.name());
 
     ASSERT_EQUAL("x", quick_pop(hb.receivers).name());
 
-    e.a.connection().open_receiver("bar");
-    while (ha.receivers.empty() || hb.senders.empty()) e.process();
+    d.a.connection().open_receiver("bar");
+    while (ha.receivers.empty() || hb.senders.empty()) d.process();
     ASSERT_EQUAL("y", quick_pop(ha.receivers).name());
     ASSERT_EQUAL("y", quick_pop(hb.senders).name());
 
-    e.b.connection().open_receiver("");
-    while (ha.senders.empty() || hb.receivers.empty()) e.process();
+    d.b.connection().open_receiver("");
+    while (ha.senders.empty() || hb.receivers.empty()) d.process();
     ASSERT_EQUAL("b", quick_pop(ha.senders).name());
     ASSERT_EQUAL("b", quick_pop(hb.receivers).name());
 }
 
 void test_endpoint_close() {
     record_handler ha, hb;
-    driver_pair e(ha, hb);
-    e.a.connection().open_sender("x");
-    e.a.connection().open_receiver("y");
+    driver_pair d(ha, hb);
+    d.a.connection().open_sender("x");
+    d.a.connection().open_receiver("y");
     while (ha.senders.size()+ha.receivers.size() < 2 ||
-           hb.senders.size()+hb.receivers.size() < 2) e.process();
+           hb.senders.size()+hb.receivers.size() < 2) d.process();
     proton::link ax = quick_pop(ha.senders), ay = quick_pop(ha.receivers);
     proton::link bx = quick_pop(hb.receivers), by = quick_pop(hb.senders);
 
     // Close a link
     ax.close(proton::error_condition("err", "foo bar"));
-    while (!bx.closed()) e.process();
+    while (!bx.closed()) d.process();
     proton::error_condition c = bx.error();
     ASSERT_EQUAL("err", c.name());
     ASSERT_EQUAL("foo bar", c.description());
@@ -196,13 +208,13 @@ void test_endpoint_close() {
 
     // Close a link with an empty condition
     ay.close(proton::error_condition());
-    while (!by.closed()) e.process();
+    while (!by.closed()) d.process();
     ASSERT(by.error().empty());
 
     // Close a connection
-    connection ca = e.a.connection(), cb = e.b.connection();
+    connection ca = d.a.connection(), cb = d.b.connection();
     ca.close(proton::error_condition("conn", "bad connection"));
-    while (!cb.closed()) e.process();
+    while (!cb.closed()) d.process();
     ASSERT_EQUAL("conn: bad connection", cb.error().what());
     ASSERT_EQUAL(1u, hb.connection_errors.size());
     ASSERT_EQUAL("conn: bad connection", hb.connection_errors.front());
@@ -211,63 +223,74 @@ void test_endpoint_close() {
 void test_driver_disconnected() {
     // driver.disconnected() aborts the connection and calls the local on_transport_error()
     record_handler ha, hb;
-    driver_pair e(ha, hb);
-    e.a.connect(ha);
-    e.b.accept(hb);
-    while (!e.a.connection().active() || !e.b.connection().active())
-        e.process();
+    driver_pair d(ha, hb);
+    d.a.connect(ha);
+    d.b.accept(hb);
+    while (!d.a.connection().active() || !d.b.connection().active())
+        d.process();
 
     // Close a with an error condition. The AMQP connection is still open.
-    e.a.disconnected(proton::error_condition("oops", "driver failure"));
-    ASSERT(!e.a.dispatch());
-    ASSERT(!e.a.connection().closed());
-    ASSERT(e.a.connection().error().empty());
+    d.a.disconnected(proton::error_condition("oops", "driver failure"));
+    ASSERT(!d.a.dispatch());
+    ASSERT(!d.a.connection().closed());
+    ASSERT(d.a.connection().error().empty());
     ASSERT_EQUAL(0u, ha.connection_errors.size());
-    ASSERT_EQUAL("oops: driver failure", e.a.transport().error().what());
+    ASSERT_EQUAL("oops: driver failure", d.a.transport().error().what());
     ASSERT_EQUAL(1u, ha.transport_errors.size());
     ASSERT_EQUAL("oops: driver failure", ha.transport_errors.front());
 
     // In a real app the IO code would detect the abort and do this:
-    e.b.disconnected(proton::error_condition("broken", "it broke"));
-    ASSERT(!e.b.dispatch());
-    ASSERT(!e.b.connection().closed());
-    ASSERT(e.b.connection().error().empty());
+    d.b.disconnected(proton::error_condition("broken", "it broke"));
+    ASSERT(!d.b.dispatch());
+    ASSERT(!d.b.connection().closed());
+    ASSERT(d.b.connection().error().empty());
     ASSERT_EQUAL(0u, hb.connection_errors.size());
     // Proton-C adds (connection aborted) if transport closes too early,
     // and provides a default message if there is no user message.
-    ASSERT_EQUAL("broken: it broke (connection aborted)", e.b.transport().error().what());
+    ASSERT_EQUAL("broken: it broke (connection aborted)", d.b.transport().error().what());
     ASSERT_EQUAL(1u, hb.transport_errors.size());
     ASSERT_EQUAL("broken: it broke (connection aborted)", hb.transport_errors.front());
 }
 
 void test_no_container() {
     // An driver with no container should throw, not crash.
-    connection_driver e;
+    connection_driver d;
     try {
-        e.connection().container();
+        d.connection().container();
         FAIL("expected error");
     } catch (proton::error) {}
 }
 
+void test_spin_interrupt() {
+    // Check the test framework interrupts a spinning driver pair with nothing to do.
+    record_handler ha, hb;
+    driver_pair d(ha, hb);
+    try {
+        while (true)
+            d.process();
+        FAIL("expected exception");
+    } catch (test::error) {}
+}
+
 void test_link_filters() {
     // Propagation of link properties
     record_handler ha, hb;
-    driver_pair e(ha, hb);
+    driver_pair d(ha, hb);
 
     source_options opts;
     source::filter_map f;
     f.put("xx", "xxx");
     ASSERT_EQUAL(1U, f.size());
-    e.a.connection().open_sender("x", sender_options().source(source_options().filters(f)));
+    d.a.connection().open_sender("x", sender_options().source(source_options().filters(f)));
 
     f.clear();
     f.put("yy", "yyy");
     ASSERT_EQUAL(1U, f.size());
-    e.a.connection().open_receiver("y", receiver_options().source(source_options().filters(f)));
+    d.a.connection().open_receiver("y", receiver_options().source(source_options().filters(f)));
 
     while (ha.senders.size()+ha.receivers.size() < 2 ||
            hb.senders.size()+hb.receivers.size() < 2)
-        e.process();
+        d.process();
 
     proton::sender ax = quick_pop(ha.senders);
     proton::receiver ay = quick_pop(ha.receivers);
@@ -287,12 +310,13 @@ void test_link_filters() {
 
 }
 
-int main(int, char**) {
+int main(int argc, char** argv) {
     int failed = 0;
-    RUN_TEST(failed, test_link_filters());
-    RUN_TEST(failed, test_driver_link_id());
-    RUN_TEST(failed, test_endpoint_close());
-    RUN_TEST(failed, test_driver_disconnected());
-    RUN_TEST(failed, test_no_container());
+    RUN_ARGV_TEST(failed, test_link_filters());
+    RUN_ARGV_TEST(failed, test_driver_link_id());
+    RUN_ARGV_TEST(failed, test_endpoint_close());
+    RUN_ARGV_TEST(failed, test_driver_disconnected());
+    RUN_ARGV_TEST(failed, test_no_container());
+    RUN_ARGV_TEST(failed, test_spin_interrupt());
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/876daa72/proton-c/bindings/cpp/src/include/test_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/test_bits.hpp b/proton-c/bindings/cpp/src/include/test_bits.hpp
index 79a0a17..4e019f2 100644
--- a/proton-c/bindings/cpp/src/include/test_bits.hpp
+++ b/proton-c/bindings/cpp/src/include/test_bits.hpp
@@ -26,12 +26,17 @@
 #include <iostream>
 #include <iterator>
 #include <sstream>
+#include <cstring>
 #include <math.h>
 
 namespace test {
 
 struct fail : public std::logic_error {
-    fail(const std::string& what) : logic_error(what) {}
+    explicit fail(const std::string& what) : logic_error(what) {}
+};
+
+struct error : public std::logic_error {
+    explicit error(const std::string& what) : logic_error(what) {}
 };
 
 template <class T, class U>
@@ -59,6 +64,7 @@ inline void assert_equalish(T want, T got, T delta, const std::string& what)
 #define RUN_TEST(BAD_COUNT, TEST)                                       \
     do {                                                                \
         try {                                                           \
+            std::cout << "TEST: " << #TEST << std::endl;                \
             TEST;                                                       \
             break;                                                      \
         } catch(const test::fail& e) {                                        \
@@ -69,6 +75,21 @@ inline void assert_equalish(T want, T got, T delta, const std::string& what)
             ++BAD_COUNT;                                                \
     } while(0)
 
+/* Like RUN_TEST but only if one of the argv strings is found in the test EXPR */
+#define RUN_ARGV_TEST(BAD_COUNT, EXPR) do {     \
+    if (argc == 1) {                            \
+      RUN_TEST(BAD_COUNT, EXPR);                \
+    } else {                                    \
+      for (int i = 1; i < argc; ++i) {          \
+        if (strstr(#EXPR, argv[i])) {           \
+            RUN_TEST(BAD_COUNT, EXPR);          \
+          break;                                \
+        }                                       \
+      }                                         \
+    }                                           \
+  } while(0)
+
+
 template<class T> std::string str(const T& x) {
     std::ostringstream s; s << std::boolalpha << x; return s.str();
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/876daa72/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 c00ccf4..da8c2a4 100644
--- a/proton-c/bindings/cpp/src/io/connection_driver.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -98,6 +98,10 @@ void connection_driver::accept(const connection_options& opts) {
     configure(all, true);
 }
 
+bool connection_driver::has_events() const {
+    return driver_.collector && pn_collector_peek(driver_.collector);
+}
+
 bool connection_driver::dispatch() {
     pn_event_t* c_event;
     while ((c_event = pn_connection_driver_next_event(&driver_)) != NULL) {


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


[25/50] [abbrv] qpid-proton git commit: PROTON-1288: c++ documentation for maps and type conversions

Posted by ac...@apache.org.
PROTON-1288: c++ documentation for maps and type conversions

Also filled in some missing doxygen markers for header files.


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

Branch: refs/heads/go1
Commit: 16147e9318a90d8411ee3758418ff60d2dcb8356
Parents: 864519d
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 24 14:32:11 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 15:37:15 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/cpp/docs/headers.dox          |  52 +++++++++
 proton-c/bindings/cpp/docs/types.md             |  77 -------------
 .../cpp/include/proton/annotation_key.hpp       |   6 +-
 .../cpp/include/proton/codec/amqp_types.hpp     | 111 -------------------
 .../bindings/cpp/include/proton/codec/deque.hpp |   3 +
 .../cpp/include/proton/codec/forward_list.hpp   |   3 +
 .../bindings/cpp/include/proton/codec/list.hpp  |   3 +
 .../bindings/cpp/include/proton/codec/map.hpp   |   3 +
 .../cpp/include/proton/codec/unordered_map.hpp  |   3 +
 .../cpp/include/proton/codec/vector.hpp         |   3 +
 proton-c/bindings/cpp/include/proton/map.hpp    |  13 ++-
 .../bindings/cpp/include/proton/message_id.hpp  |  10 +-
 proton-c/bindings/cpp/include/proton/scalar.hpp |  10 +-
 proton-c/bindings/cpp/include/proton/types.hpp  |  94 +++++++++++++++-
 .../bindings/cpp/include/proton/types_fwd.hpp   |   4 +-
 proton-c/bindings/cpp/include/proton/value.hpp  |  13 ++-
 proton-c/bindings/cpp/src/messaging_adapter.cpp |  18 ++-
 proton-c/include/proton/message.h               |   4 +-
 18 files changed, 204 insertions(+), 226 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/docs/headers.dox
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/headers.dox b/proton-c/bindings/cpp/docs/headers.dox
new file mode 100644
index 0000000..0ff7220
--- /dev/null
+++ b/proton-c/bindings/cpp/docs/headers.dox
@@ -0,0 +1,52 @@
+/* List headers that lack their own @file marker so doxygen will link them properly.
+   Ideally the files themselves should have their own @file markup and comment,
+   if you update files that they can be removed from here.
+   */
+/// @file proton/annotation_key.hpp Key type for proton::message annotation maps.
+/// @file proton/binary.hpp Binary data type
+/// @file proton/byte_array.hpp
+/// @file proton/connection.hpp AMQP connection
+/// @file proton/connection_options.hpp Options to create a proton::connection
+/// @file proton/container.hpp AMQP container to manage connections and listeners
+/// @file proton/decimal.hpp Placeholder for the AMQP decimal data type.
+/// @file proton/delivery.hpp Delivery state of an AQMP messsage
+/// @file proton/delivery_mode.hpp Delivery mode of an AMQP message
+/// @file proton/duration.hpp Time duration data type
+/// @file proton/error_condition.hpp AMQP error condition
+/// @file proton/error.hpp Base exception type thrown by proton functions
+/// @file proton/event_loop.hpp
+/// @file proton/function.hpp
+/// @file proton/fwd.hpp
+/// @file proton/link.hpp
+/// @file proton/listener.hpp
+/// @file proton/listen_handler.hpp
+/// @file proton/map.hpp Template for AMQP property, annotation and filter maps.
+/// @file proton/message.hpp
+/// @file proton/message_id.hpp
+/// @file proton/messaging_handler.hpp
+/// @file proton/namespaces.hpp
+/// @file proton/receiver.hpp
+/// @file proton/receiver_options.hpp
+/// @file proton/reconnect_timer.hpp
+/// @file proton/sasl.hpp
+/// @file proton/scalar_base.hpp
+/// @file proton/scalar.hpp Run-time holder for any AMQP scalar value
+/// @file proton/sender.hpp
+/// @file proton/sender_options.hpp
+/// @file proton/session.hpp
+/// @file proton/session_options.hpp
+/// @file proton/source.hpp
+/// @file proton/source_options.hpp
+/// @file proton/ssl.hpp
+/// @file proton/symbol.hpp AMQP symbol (ASCII string) data type
+/// @file proton/target.hpp
+/// @file proton/target_options.hpp
+/// @file proton/terminus.hpp
+/// @file proton/thread_safe.hpp
+/// @file proton/timestamp.hpp
+/// @file proton/tracker.hpp
+/// @file proton/transfer.hpp
+/// @file proton/transport.hpp
+/// @file proton/url.hpp
+/// @file proton/uuid.hpp
+/// @file proton/value.hpp Run-time holder for any AMQP value

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/docs/types.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/types.md b/proton-c/bindings/cpp/docs/types.md
deleted file mode 100644
index 6a56be0..0000000
--- a/proton-c/bindings/cpp/docs/types.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# AMQP and C++ types {#types_page}
-
-An AMQP message body can hold binary data using any encoding you
-like. AMQP also defines its own encoding and types. The AMQP encoding
-is often used in message bodies because it is supported by AMQP
-libraries on many languages and platforms. You also need to use the
-AMQP types to set and examine message properties.
-
-## Scalar types
-
-Each type is identified by a proton::type_id.
-
-C++ type            | AMQP type_id         | Description
---------------------|----------------------|-----------------------
-bool                | proton::BOOLEAN      | Boolean true or false
-uint8_t             | proton::UBYTE        | 8-bit unsigned byte
-int8_t              | proton::BYTE         | 8-bit signed byte
-uint16_t            | proton::USHORT       | 16-bit unsigned integer
-int16_t             | proton::SHORT        | 16-bit signed integer
-uint32_t            | proton::UINT         | 32-bit unsigned integer
-int32_t             | proton::INT          | 32-bit signed integer
-uint64_t            | proton::ULONG        | 64-bit unsigned integer
-int64_t             | proton::LONG         | 64-bit signed integer
-wchar_t             | proton::CHAR         | 32-bit unicode code point
-float               | proton::FLOAT        | 32-bit binary floating point
-double              | proton::DOUBLE       | 64-bit binary floating point
-proton::timestamp   | proton::TIMESTAMP    | 64-bit signed milliseconds since 00:00:00 (UTC), 1 January 1970.
-proton::decimal32   | proton::DECIMAL32    | 32-bit decimal floating point
-proton::decimal64   | proton::DECIMAL64    | 64-bit decimal floating point
-proton::decimal128  | proton::DECIMAL128   | 128-bit decimal floating point
-proton::uuid        | proton::UUID         | 128-bit universally-unique identifier
-std::string         | proton::STRING       | UTF-8 encoded Unicode string
-proton::symbol      | proton::SYMBOL       | 7-bit ASCII encoded string
-proton::binary      | proton::BINARY       | Variable-length binary data
-
-proton::scalar is a holder that can accept a scalar value of any type.
-
-## Compound types
-
-C++ type            | AMQP type_id         | Description
---------------------|----------------------|-----------------------
-See below           | proton::ARRAY        | Sequence of values of the same type
-See below           | proton::LIST         | Sequence of values of mixed types
-See below           | proton::MAP          | Map of key-value pairs
-
-proton::value is a holder that can accept any AMQP value, scalar or
-compound.
-
-proton::ARRAY converts to and from C++ sequences: std::vector,
-std::deque, std::list, and std::forward_list.
-
-proton::LIST converts to and from sequences of proton::value or
-proton::scalar, which can hold mixed types of data.
-
-proton::MAP converts to and from std::map, std::unordered_map, and
-sequences of std::pair.
-
-When decoding, the encoded map types must be convertible to the element type of the
-C++ sequence or the key-value types of the C++ map.  Use proton::value as the
-element or key-value type to decode any ARRAY, LIST, or MAP.
-
-For example you can decode any AMQP MAP into:
-
-    std::map<proton::value, proton::value>
-
-You can decode any AMQP LIST or ARRAY into:
-
-    std::vector<proton::value>
-
-## Include files
-
-You can simply include proton/types.hpp to get all the type
-definitions and conversions. Alternatively, you can selectively
-include only what you need:
-
- - Include proton/types_fwd.hpp: forward declarations for all types.
- - Include individual `.hpp` files as per the table above.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/annotation_key.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/annotation_key.hpp b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
index 4995141..02f5420 100644
--- a/proton-c/bindings/cpp/include/proton/annotation_key.hpp
+++ b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
@@ -65,18 +65,18 @@ template <class T> T get(const annotation_key& x);
 
 /// Get the uint64_t value or throw conversion_error.
 ///
-/// @related annotation_key
+/// @relatedalso annotation_key
 template<> inline uint64_t get<uint64_t>(const annotation_key& x) { return internal::get<uint64_t>(x); }
 
 /// Get the @ref symbol value or throw conversion_error.
 ///
-/// @related annotation_key
+/// @relatedalso annotation_key
 template<> inline symbol get<symbol>(const annotation_key& x) { return internal::get<symbol>(x); }
 
 /// Get the @ref binary value or throw conversion_error.
 ///
 /// @copydoc scalar::coerce
-/// @related annotation_key
+/// @relatedalso annotation_key
 template<class T> T coerce(const annotation_key& x) { return internal::coerce<T>(x); }
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp b/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp
deleted file mode 100644
index 5456225..0000000
--- a/proton-c/bindings/cpp/include/proton/codec/amqp_types.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-#ifndef PROTON_CODEC_AMQP_TYPES_HPP
-#define PROTON_CODEC_AMQP_TYPES_HPP
-
-/*
- *
- * 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.
- *
- */
-
-/// @cond INTERNAL
-/// XXX Remove this entirely
-    
-namespace proton {
-namespace codec {
-
-/// @name Experimental - Typedefs for AMQP scalar types.
-///
-/// These typedefs associate AMQP scalar type names with the
-/// corresponding C++ types. They are provided as a convenience for
-/// those familiar with AMQP, but you do not need to use them.  You
-/// can use the C++ types directly.
-///
-/// The typedef names have a `_type` suffix to avoid ambiguity with
-/// C++ reserved and std library type names.
-///    
-/// @{
-
-// XXX Consider prefixing these with amqp_ and dropping _type, now
-// that they're in the codec namespace
-    
-/// True or false.
-typedef bool boolean_type;
-
-/// 8-bit unsigned byte 
-typedef uint8_t ubyte_type;
-
-/// 8-bit signed byte
-typedef int8_t byte_type;
-
-/// 16-bit unsigned short integer
-typedef uint16_t ushort_type;
-
-/// 16-bit signed short integer
-typedef int16_t short_type;
-
-/// 32-bit unsigned integer
-typedef uint32_t uint_type;
-
-/// 32-bit signed integer
-typedef int32_t int_type;
-
-/// 64-bit unsigned long integer
-typedef uint64_t ulong_type;
-
-/// 64-bit signed long integer
-typedef int64_t long_type;
-
-/// 32-bit unicode code point
-typedef wchar_t char_type;
-
-/// 32-bit binary floating point
-typedef float float_type;
-
-/// 64-bit binary floating point
-typedef double double_type;
-
-/// An AMQP string is unicode UTF-8 encoded.
-typedef std::string string_type;
-
-/// An AMQP symbol is ASCII 7-bit encoded.
-typedef proton::symbol symbol_type;
-
-/// An AMQP binary contains variable length raw binary data.
-typedef proton::binary binary_type;
-
-/// A timestamp in milliseconds since the epoch 00:00:00 (UTC), 1 January 1970.
-typedef proton::timestamp timestamp_type;
-
-/// A 16-byte universally unique identifier.
-typedef proton::uuid uuid_type;
-
-/// 32-bit decimal floating point
-typedef proton::decimal32 decimal32_type;
-
-/// 64-bit decimal floating point
-typedef proton::decimal64 decimal64_type;
-
-/// 128-bit decimal floating point
-typedef proton::decimal128 decimal128_type;
-
-} // codec
-} // proton
-
-/// @endcond
-
-#endif // PROTON_CODEC_AMQP_TYPES_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/deque.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/deque.hpp b/proton-c/bindings/cpp/include/proton/codec/deque.hpp
index 2f570a4..188da2a 100644
--- a/proton-c/bindings/cpp/include/proton/codec/deque.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/deque.hpp
@@ -20,6 +20,9 @@
  * under the License.
  */
 
+/// @file
+/// Enable conversions between proton::value and std::deque
+
 #include "./encoder.hpp"
 #include "./decoder.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/forward_list.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/forward_list.hpp b/proton-c/bindings/cpp/include/proton/codec/forward_list.hpp
index 0038b8f..4f09f3e 100644
--- a/proton-c/bindings/cpp/include/proton/codec/forward_list.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/forward_list.hpp
@@ -20,6 +20,9 @@
  * under the License.
  */
 
+/// @file
+/// Enable conversions between proton::value and std::forward_list
+
 #include "./encoder.hpp"
 #include "./decoder.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/list.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/list.hpp b/proton-c/bindings/cpp/include/proton/codec/list.hpp
index a2c71b8..e914a5b 100644
--- a/proton-c/bindings/cpp/include/proton/codec/list.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/list.hpp
@@ -22,6 +22,9 @@
  *
  */
 
+/// @file
+/// Enable conversions between proton::value and std::list
+
 #include "./encoder.hpp"
 #include "./decoder.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/map.hpp b/proton-c/bindings/cpp/include/proton/codec/map.hpp
index d3b0c4d..45f9df9 100644
--- a/proton-c/bindings/cpp/include/proton/codec/map.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/map.hpp
@@ -22,6 +22,9 @@
  *
  */
 
+/// @file
+/// Enable conversions between proton::value and std::map
+
 #include "./encoder.hpp"
 #include "./decoder.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/unordered_map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/unordered_map.hpp b/proton-c/bindings/cpp/include/proton/codec/unordered_map.hpp
index b081ff8..d26ec29 100644
--- a/proton-c/bindings/cpp/include/proton/codec/unordered_map.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/unordered_map.hpp
@@ -22,6 +22,9 @@
  *
  */
 
+/// @file
+/// Enable conversions between proton::value and std::unordered_map
+
 #include "./encoder.hpp"
 #include "./decoder.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/codec/vector.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/codec/vector.hpp b/proton-c/bindings/cpp/include/proton/codec/vector.hpp
index 4edae25..8674f56 100644
--- a/proton-c/bindings/cpp/include/proton/codec/vector.hpp
+++ b/proton-c/bindings/cpp/include/proton/codec/vector.hpp
@@ -22,6 +22,9 @@
  *
  */
 
+/// @file
+/// Enable conversions between proton::value and std::vector
+
 #include "./encoder.hpp"
 #include "./decoder.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/map.hpp b/proton-c/bindings/cpp/include/proton/map.hpp
index 8399b16..9798fad 100644
--- a/proton-c/bindings/cpp/include/proton/map.hpp
+++ b/proton-c/bindings/cpp/include/proton/map.hpp
@@ -41,10 +41,13 @@ class map_type_impl;
 template <class K, class T>
 class map;
 
+/// Decode from a proton::map
 template <class K, class T>
 PN_CPP_EXTERN proton::codec::decoder& operator>>(proton::codec::decoder& d, map<K,T>& m);
+/// Encode to a proton::map
 template <class K, class T>
 PN_CPP_EXTERN proton::codec::encoder& operator<<(proton::codec::encoder& e, const map<K,T>& m);
+/// Swap proton::map instances
 template <class K, class T>
 PN_CPP_EXTERN void swap(map<K,T>&, map<K,T>&);
 
@@ -53,7 +56,7 @@ PN_CPP_EXTERN void swap(map<K,T>&, map<K,T>&);
 ///
 /// Provides only basic get()/set() operations for convenience.  For more
 /// complicated use (iteration, preserving order etc.) you should convert to a
-/// standard C++ map type such as std::map. See @ref message_propreties.cpp
+/// standard C++ map type such as std::map. See @ref message_properties.cpp
 /// and @ref types_page.
 ///
 template <class K, class T>
@@ -63,19 +66,19 @@ class PN_CPP_CLASS_EXTERN map {
             public internal::enable_if<codec::is_encodable_map<M,K,T>::value, U> {};
 
  public:
-    /// Create an empty map value
+    /// @name Construct and assign
+    /// @{
     PN_CPP_EXTERN map();
-
     PN_CPP_EXTERN map(const map& cm);
     PN_CPP_EXTERN map& operator=(const map& cm);
 #if PN_CPP_HAS_RVALUE_REFERENCES
     PN_CPP_EXTERN map(map&&);
     PN_CPP_EXTERN map& operator=(map&&);
 #endif
-
+    ///@}
     PN_CPP_EXTERN ~map();
 
-    /// Type-safe assign from a compatible map type, e.g. std::map<K,T> - see @types_page
+    /// Type-safe assign from a compatible map, e.g. std::map<K,T> - see @ref types_page
     template <class M>
     typename assignable_map<M, map&>::type operator=(const M& x) { value(x); return *this;}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/message_id.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message_id.hpp b/proton-c/bindings/cpp/include/proton/message_id.hpp
index ee12a17..749337c 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -74,17 +74,17 @@ class message_id : public scalar_base {
 template <class T> T get(const message_id& x);
 /// @endcond
 
-/// Get the uint64_t value or throw conversion_error. @related message_id
+/// Get the uint64_t value or throw conversion_error. @relatedalso message_id
 template<> inline uint64_t get<uint64_t>(const message_id& x) { return internal::get<uint64_t>(x); }
-/// Get the @ref uuid value or throw conversion_error. @related message_id
+/// Get the @ref uuid value or throw conversion_error. @relatedalso message_id
 template<> inline uuid get<uuid>(const message_id& x) { return internal::get<uuid>(x); }
-/// Get the @ref binary value or throw conversion_error. @related message_id
+/// Get the @ref binary value or throw conversion_error. @relatedalso message_id
 template<> inline binary get<binary>(const message_id& x) { return internal::get<binary>(x); }
-/// Get the std::string value or throw conversion_error. @related message_id
+/// Get the std::string value or throw conversion_error. @relatedalso message_id
 template<> inline std::string get<std::string>(const message_id& x) { return internal::get<std::string>(x); }
 
 /// @copydoc scalar::coerce
-/// @related message_id
+/// @relatedalso message_id
 template<class T> T coerce(const message_id& x) { return internal::coerce<T>(x); }
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/scalar.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp
index 0559dd9..99236c3 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -51,32 +51,32 @@ class scalar : public scalar_base {
 /// This will succeed if and only if x contains a uint64_t value.
 ///
 /// @throw conversion_error if contained value is not of type T.
-/// @related scalar
+/// @relatedalso scalar
 template<class T> T get(const scalar& s) { return internal::get<T>(s); }
 
 /// Coerce the contained value to type T. For example:
 ///
-///      uint64_t i = get<uint64_t>(x)
+///      uint64_t i = coerce<uint64_t>(x)
 ///
 /// This will succeed if x contains any numeric value, but may lose
 /// precision if it contains a float or double value.
 ///
 /// @throw conversion_error if the value cannot be converted to T
 /// according to `std::is_convertible`
-/// @related scalar
+/// @relatedalso scalar
 template<class T> T coerce(const scalar& x) { return internal::coerce<T>(x); }
 
 
 /// Coerce the contained value to type T. For example:
 ///
-///      uint64_t i = get<uint64_t>(x)
+///      uint64_t i = coerce<uint64_t>(x)
 ///
 /// This will succeed if x contains any numeric value, but may lose
 /// precision if it contains a float or double value.
 ///
 /// @throw conversion_error if the value cannot be converted to T
 /// according to `std::is_convertible`
-/// @related scalar
+/// @relatedalso scalar
 template<class T> T coerce(scalar& x) { return internal::coerce<T>(x); }
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/types.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/types.hpp b/proton-c/bindings/cpp/include/proton/types.hpp
index d21cb8f..f541b13 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -29,14 +29,96 @@
 
 // TODO aconway 2016-03-15: described types, described arrays.
 
+/** @page types_page AMQP and C++ types
+
+An AMQP message body can hold binary data using any encoding you
+like. AMQP also defines its own encoding and types. The AMQP encoding
+is often used in message bodies because it is supported by AMQP
+libraries on many languages and platforms. You also need to use the
+AMQP types to set and examine message properties.
+
+## Scalar types
+
+Each type is identified by a proton::type_id.
+
+C++ type            | AMQP type_id         | Description
+--------------------|----------------------|-----------------------
+bool                | proton::BOOLEAN      | Boolean true or false
+uint8_t             | proton::UBYTE        | 8-bit unsigned byte
+int8_t              | proton::BYTE         | 8-bit signed byte
+uint16_t            | proton::USHORT       | 16-bit unsigned integer
+int16_t             | proton::SHORT        | 16-bit signed integer
+uint32_t            | proton::UINT         | 32-bit unsigned integer
+int32_t             | proton::INT          | 32-bit signed integer
+uint64_t            | proton::ULONG        | 64-bit unsigned integer
+int64_t             | proton::LONG         | 64-bit signed integer
+wchar_t             | proton::CHAR         | 32-bit unicode code point
+float               | proton::FLOAT        | 32-bit binary floating point
+double              | proton::DOUBLE       | 64-bit binary floating point
+proton::timestamp   | proton::TIMESTAMP    | 64-bit signed milliseconds since 00:00:00 (UTC), 1 January 1970.
+proton::decimal32   | proton::DECIMAL32    | 32-bit decimal floating point
+proton::decimal64   | proton::DECIMAL64    | 64-bit decimal floating point
+proton::decimal128  | proton::DECIMAL128   | 128-bit decimal floating point
+proton::uuid        | proton::UUID         | 128-bit universally-unique identifier
+std::string         | proton::STRING       | UTF-8 encoded Unicode string
+proton::symbol      | proton::SYMBOL       | 7-bit ASCII encoded string
+proton::binary      | proton::BINARY       | Variable-length binary data
+
+## Holder types
+
+proton::message::body() and other message-related data can contain different
+types of data at run-time. There are two "holder" types provided to hold
+run-time typed data:
+
+- proton::scalar can hold a scalar value of any type.
+- proton::value can hold any AMQP value, scalar or compound.
+
+You can set the value in a holder by assignment, and use the proton::get() and
+proton::coerce() templates extract data in a type-safe way. Holders also provide
+functions to query the type of value they contain.
+
+## Compound types
+
+C++ type            | AMQP type_id         | Description
+--------------------|----------------------|-----------------------
+See below           | proton::ARRAY        | Sequence of values of the same type
+See below           | proton::LIST         | Sequence of values of mixed types
+See below           | proton::MAP          | Map of key-value pairs
+
+A proton::value containing a proton::ARRAY can convert to and from C++ sequences
+of the corresponding C++ type: std::vector, std::deque, std::list, and
+std::forward_list.
+
+proton::LIST converts to and from sequences of proton::value or
+proton::scalar, which can hold mixed types of data.
+
+proton::MAP converts to and from std::map, std::unordered_map, and
+sequences of std::pair.
+
+For example you can decode a message body with any AMQP MAP as follows:
+
+    proton::message m = ...;
+    std::map<proton::value, proton::value> map;
+    proton::get(m.body(), map);
+
+You can encode a message body with a map of string to uint64_t like this:
+
+    std::unordered_map<std::string, uint64_t> map;
+    map["foo"] = 123;
+    m.body() = map;
+
+## Include files
+
+`proton/types.hpp` includes all available type definitions and
+conversions. Alternatively, you can selectively include the .hpp files you
+want, see @ref types.hpp.
+
+*/
+
 #include "./internal/config.hpp"
 
 #include "./annotation_key.hpp"
 #include "./binary.hpp"
-#include "./codec/deque.hpp"
-#include "./codec/list.hpp"
-#include "./codec/map.hpp"
-#include "./codec/vector.hpp"
 #include "./decimal.hpp"
 #include "./duration.hpp"
 #include "./message_id.hpp"
@@ -47,6 +129,10 @@
 #include "./uuid.hpp"
 #include "./value.hpp"
 
+#include "./codec/deque.hpp"
+#include "./codec/list.hpp"
+#include "./codec/map.hpp"
+#include "./codec/vector.hpp"
 #if PN_CPP_HAS_CPP11
 #include "./codec/forward_list.hpp"
 #include "./codec/unordered_map.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/types_fwd.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/types_fwd.hpp b/proton-c/bindings/cpp/include/proton/types_fwd.hpp
index ff53b0c..a2d2508 100644
--- a/proton-c/bindings/cpp/include/proton/types_fwd.hpp
+++ b/proton-c/bindings/cpp/include/proton/types_fwd.hpp
@@ -23,9 +23,7 @@
  */
 
 /// @file
-///
-/// Forward declarations for all the C++ types used by Proton to
-/// represent AMQP types.
+/// Forward declarations for all C++ types used by Proton to represent AMQP types.
 
 #include "./internal/config.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index bc7ed86..c1c0835 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -115,35 +115,36 @@ class value : public internal::value_base, private internal::comparable<value> {
     /// that may change in future so should not be parsed.
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const value&);
 
-    ///@cond INTERNAL - used to refer to existing pn_data_t* values as proton::value
+    ///@cond INTERNAL
+    /// Used to refer to existing pn_data_t* values as proton::value
     value(pn_data_t* d);          // Refer to existing pn_data_t
     void reset(pn_data_t* d = 0); // Refer to a new pn_data_t
     ///@endcond
 };
 
 /// @copydoc scalar::get
-/// @related proton::value
+/// @relatedalso proton::value
 template<class T> T get(const value& v) { T x; get(v, x); return x; }
 
 /// Like get(const value&) but assigns the value to a reference
 /// instead of returning it.  May be more efficient for complex values
 /// (arrays, maps, etc.)
 ///
-/// @related proton::value
+/// @relatedalso proton::value
 template<class T> void get(const value& v, T& x) { codec::decoder d(v, true); d >> x; }
 
-/// @related proton::value
+/// @relatedalso proton::value
 template<class T, class U> inline void get(const U& u, T& x) { const value v(u); get(v, x); }
 
 /// @copydoc scalar::coerce
-/// @related proton::value
+/// @relatedalso proton::value
 template<class T> T coerce(const value& v) { T x; coerce(v, x); return x; }
 
 /// Like coerce(const value&) but assigns the value to a reference
 /// instead of returning it.  May be more efficient for complex values
 /// (arrays, maps, etc.)
 ///
-/// @related proton::value
+/// @relatedalso proton::value
 template<class T> void coerce(const value& v, T& x) {
     codec::decoder d(v, false);
     if (type_id_is_scalar(v.type())) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/bindings/cpp/src/messaging_adapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/messaging_adapter.cpp b/proton-c/bindings/cpp/src/messaging_adapter.cpp
index de35989..a70703e 100644
--- a/proton-c/bindings/cpp/src/messaging_adapter.cpp
+++ b/proton-c/bindings/cpp/src/messaging_adapter.cpp
@@ -59,11 +59,13 @@ void credit_topup(pn_link_t *link) {
 }
 
 void messaging_adapter::on_reactor_init(proton_event &pe) {
-    delegate_.on_container_start(pe.container());
+    container* c = pe.container_ptr();
+    if (c) delegate_.on_container_start(*c);
 }
 
 void messaging_adapter::on_reactor_final(proton_event &pe) {
-    delegate_.on_container_stop(pe.container());
+    container* c = pe.container_ptr();
+    if (c) delegate_.on_container_stop(*c);
 }
 
 void messaging_adapter::on_link_flow(proton_event &pe) {
@@ -279,18 +281,24 @@ void messaging_adapter::on_link_local_open(proton_event &pe) {
 
 void messaging_adapter::on_link_remote_open(proton_event &pe) {
     pn_link_t *lnk = pn_event_link(pe.pn_event());
-    container& c = pe.container();
+    container* c = pe.container_ptr();
     if (pn_link_is_receiver(lnk)) {
       receiver r(make_wrapper<receiver>(lnk));
       delegate_.on_receiver_open(r);
       if (is_local_unititialised(pn_link_state(lnk))) {
-          r.open(c.receiver_options());
+          if (c)
+              r.open(c->receiver_options());
+          else
+              r.open();
       }
     } else {
       sender s(make_wrapper<sender>(lnk));
       delegate_.on_sender_open(s);
       if (is_local_unititialised(pn_link_state(lnk))) {
-          s.open(c.sender_options());
+          if (c)
+              s.open(c->sender_options());
+          else
+              s.open();
       }
     }
     credit_topup(lnk);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/16147e93/proton-c/include/proton/message.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/message.h b/proton-c/include/proton/message.h
index 4f71db2..b27ebcb 100644
--- a/proton-c/include/proton/message.h
+++ b/proton-c/include/proton/message.h
@@ -744,7 +744,7 @@ PN_EXTERN int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size);
  */
 PN_EXTERN int pn_message_data(pn_message_t *msg, pn_data_t *data);
 
-/** @cond INTERNAL @{ */
+/** @cond INTERNAL */
 
 /** Construct a message with extra storage */
 PN_EXTERN pn_message_t * pn_message_with_extra(size_t extra);
@@ -752,7 +752,7 @@ PN_EXTERN pn_message_t * pn_message_with_extra(size_t extra);
 /** Pointer to extra space allocated by pn_message_with_extra(). */
 PN_EXTERN void* pn_message_get_extra(pn_message_t *msg);
 
-/** @} */
+/** @endcond */
 
 
 /** @}


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


[13/50] [abbrv] qpid-proton git commit: NO-JIRA: [C++ binding] Fix check for C++11

Posted by ac...@apache.org.
NO-JIRA: [C++ binding] Fix check for C++11


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

Branch: refs/heads/go1
Commit: c4d16584a241e1d0cded416762f7b9b72a949e81
Parents: a22b178
Author: Andrew Stitcher <as...@apache.org>
Authored: Sun May 14 00:58:33 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Sun May 14 01:00:11 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/cpp/include/proton/internal/config.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c4d16584/proton-c/bindings/cpp/include/proton/internal/config.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/config.hpp b/proton-c/bindings/cpp/include/proton/internal/config.hpp
index 563a304..da7f480 100644
--- a/proton-c/bindings/cpp/include/proton/internal/config.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/config.hpp
@@ -34,7 +34,7 @@
 /// with -D on the compile line.
 
 #ifndef PN_CPP_HAS_CPP11
-#if defined(__cplusplus) && __cplusplus >= 201100
+#if defined(__cplusplus) && __cplusplus >= 201103
 #define PN_CPP_HAS_CPP11 1
 #else
 #define PN_CPP_HAS_CPP11 0


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


[17/50] [abbrv] qpid-proton git commit: NO-JIRA: Ensure _GNU_SOURCE & _POSIX_C_SOURCE are not redefined

Posted by ac...@apache.org.
NO-JIRA: Ensure _GNU_SOURCE & _POSIX_C_SOURCE are not redefined


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

Branch: refs/heads/go1
Commit: f7490003d3d88ee695cdbaaee887fb0c22a140a0
Parents: ed23bea
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 19 09:54:00 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri May 19 09:54:00 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 2 ++
 proton-c/src/proactor/libuv.c | 2 ++
 2 files changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f7490003/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index d79f0da..a1ec1af 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -20,7 +20,9 @@
  */
 
 /* Enable POSIX features for pthread.h */
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 
 #include "../core/log_private.h"
 #include "proactor-internal.h"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f7490003/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index 50f98fd..cf7a31b 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -20,7 +20,9 @@
  */
 
 /* Enable POSIX features for uv.h */
+#ifndef _POSIX_C_SOURCE
 #define _POSIX_C_SOURCE 200809L
+#endif
 
 #include "../core/log_private.h"
 #include "proactor-internal.h"


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


[46/50] [abbrv] qpid-proton git commit: NO-JIRA: Remove now unused Java option from appveyor build recipe

Posted by ac...@apache.org.
NO-JIRA: Remove now unused Java option from appveyor build recipe


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

Branch: refs/heads/go1
Commit: da959b6e3051ac97aebc425c309677858fcc2a6b
Parents: 087b94f
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Jun 8 16:27:54 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Thu Jun 8 16:27:54 2017 -0400

----------------------------------------------------------------------
 appveyor.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/da959b6e/appveyor.yml
----------------------------------------------------------------------
diff --git a/appveyor.yml b/appveyor.yml
index fe87f0d..8c61be0 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -8,7 +8,7 @@ cache:
 before_build:
 - mkdir BLD
 - cd BLD
-- cmake -G "Visual Studio 12" -DBUILD_PERL=no -DBUILD_JAVA=no ..
+- cmake -G "Visual Studio 12" -DBUILD_PERL=no ..
 - cd ..
 build:
   parallel: true


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


[18/50] [abbrv] qpid-proton git commit: PROTON-1488: Added command line parameters for configure URL and address

Posted by ac...@apache.org.
PROTON-1488: Added command line parameters for configure URL and address


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

Branch: refs/heads/go1
Commit: d6524051f9c9597c21402e83a8f243b51ca69426
Parents: f749000
Author: ppatierno <pp...@live.com>
Authored: Mon May 22 17:26:16 2017 +0200
Committer: Gordon Sim <gs...@redhat.com>
Committed: Tue May 23 13:33:06 2017 +0100

----------------------------------------------------------------------
 examples/python/server.py | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d6524051/examples/python/server.py
----------------------------------------------------------------------
diff --git a/examples/python/server.py b/examples/python/server.py
index 8cebaad..5d7650a 100755
--- a/examples/python/server.py
+++ b/examples/python/server.py
@@ -19,7 +19,8 @@
 #
 
 from __future__ import print_function
-from proton import Message
+import optparse
+from proton import Message, Url
 from proton.handlers import MessagingHandler
 from proton.reactor import Container
 
@@ -41,8 +42,15 @@ class Server(MessagingHandler):
         self.server.send(Message(address=event.message.reply_to, body=event.message.body.upper(),
                             correlation_id=event.message.correlation_id))
 
+parser = optparse.OptionParser(usage="usage: %prog [options]")
+parser.add_option("-a", "--address", default="localhost:5672/examples",
+                  help="address from which messages are received (default %default)")
+opts, args = parser.parse_args()
+
+url = Url(opts.address)
+
 try:
-    Container(Server("0.0.0.0:5672", "examples")).run()
+    Container(Server(url, url.path)).run()
 except KeyboardInterrupt: pass
 
 


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


[35/50] [abbrv] qpid-proton git commit: PROTON-1450: go binding amqp.Key and message map types.

Posted by ac...@apache.org.
PROTON-1450: go binding amqp.Key and message map types.

Add amqp.Key type for message maps with keys that can be ulong or symbol.

Add type-safe methods to deal with amqp.Message maps, old methods remain for
compatibility but are deprecated.


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

Branch: refs/heads/go1
Commit: 110f851add21f4f79de08a0af55d93226593c26c
Parents: 5f8738f
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Apr 27 17:16:19 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 31 17:17:50 2017 -0400

----------------------------------------------------------------------
 .../go/src/qpid.apache.org/amqp/marshal.go      |   2 +
 .../go/src/qpid.apache.org/amqp/marshal_test.go |  90 ++++++++++++++++
 .../go/src/qpid.apache.org/amqp/message.go      | 106 ++++++++++++++-----
 .../go/src/qpid.apache.org/amqp/message_test.go |  57 ++++++++--
 .../go/src/qpid.apache.org/amqp/types.go        |  18 ++++
 .../go/src/qpid.apache.org/amqp/types_test.go   |  34 ++++++
 .../go/src/qpid.apache.org/amqp/unmarshal.go    |   9 ++
 7 files changed, 285 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
index b6adf90..a0a732e 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
@@ -204,6 +204,8 @@ func marshal(v interface{}, data *C.pn_data_t) {
 			marshal(val, data)
 		}
 		C.pn_data_exit(data)
+	case Key:
+		marshal(v.Get(), data)
 	default:
 		switch reflect.TypeOf(v).Kind() {
 		case reflect.Map:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
new file mode 100644
index 0000000..2eda33c
--- /dev/null
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal_test.go
@@ -0,0 +1,90 @@
+/*
+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 amqp
+
+import (
+	"testing"
+)
+
+func TestSymbolKey(t *testing.T) {
+	bytes, err := Marshal(SymbolKey("foo"), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var k Key
+	if _, err := Unmarshal(bytes, &k); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual("foo", string(k.Get().(Symbol))); err != nil {
+		t.Error(err)
+	}
+	var sym Symbol
+	if _, err := Unmarshal(bytes, &sym); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual("foo", sym.String()); err != nil {
+		t.Error(err)
+	}
+
+}
+
+func TestStringKey(t *testing.T) {
+	bytes, err := Marshal(StringKey("foo"), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var k Key
+	if _, err := Unmarshal(bytes, &k); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual("foo", string(k.Get().(Symbol))); err != nil {
+		t.Error(err)
+	}
+	var s string
+	if _, err := Unmarshal(bytes, &s); err != nil {
+		t.Error(err)
+	}
+	if err := checkEqual("foo", s); err != nil {
+		t.Error(err)
+	}
+
+}
+
+func TestIntKey(t *testing.T) {
+	bytes, err := Marshal(IntKey(12345), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var k Key
+	if _, err := Unmarshal(bytes, &k); err != nil {
+		t.Error(err)
+	}
+	if 12345 != k.Get().(uint64) {
+		t.Errorf("(%T)%v != (%T)%v", 12345, k.Get().(uint64))
+	}
+	var n uint64
+	if _, err := Unmarshal(bytes, &n); err != nil {
+		t.Error(err)
+	}
+	if 12345 != n {
+		t.Errorf("%v != %v", 12345, k.Get().(uint64))
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
index 753682e..9f4d7d1 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
@@ -117,17 +117,20 @@ type Message interface {
 	ReplyToGroupId() string
 	SetReplyToGroupId(string)
 
-	// Instructions - AMQP delivery instructions.
-	Instructions() map[string]interface{}
-	SetInstructions(v map[string]interface{})
+	// Property map set by the application to be carried with the message.
+	// Values must be simple types (not maps, lists or sequences)
+	ApplicationProperties() map[Key]interface{}
+	SetApplicationProperties(map[Key]interface{})
 
-	// Annotations - AMQP annotations.
-	Annotations() map[string]interface{}
-	SetAnnotations(v map[string]interface{})
+	// Per-delivery annotations to provide delivery instructions.
+	// May be added or removed by intermediaries during delivery.
+	DeliveryAnnotations() map[Key]interface{}
+	SetDeliveryAnnotations(map[Key]interface{})
 
-	// Properties - Application properties.
-	Properties() map[string]interface{}
-	SetProperties(v map[string]interface{})
+	// Message annotations added as part of the bare message at creation, usually
+	// by an AMQP library. See ApplicationProperties() for adding application data.
+	MessageAnnotations() map[Key]interface{}
+	SetMessageAnnotations(map[Key]interface{})
 
 	// Inferred indicates how the message content
 	// is encoded into AMQP sections. If inferred is true then binary and
@@ -160,6 +163,18 @@ type Message interface {
 
 	// Copy the contents of another message to this one.
 	Copy(m Message) error
+
+	// Deprecated: use DeliveryAnnotations() for a more type-safe interface
+	Instructions() map[string]interface{}
+	SetInstructions(v map[string]interface{})
+
+	// Deprecated: use MessageAnnotations() for a more type-safe interface
+	Annotations() map[string]interface{}
+	SetAnnotations(v map[string]interface{})
+
+	// Deprecated: use ApplicationProperties() for a more type-safe interface
+	Properties() map[string]interface{}
+	SetProperties(v map[string]interface{})
 }
 
 type message struct{ pn *C.pn_message_t }
@@ -203,13 +218,6 @@ func rewindGet(data *C.pn_data_t) (v interface{}) {
 	return v
 }
 
-func rewindMap(data *C.pn_data_t) (v map[string]interface{}) {
-	C.pn_data_rewind(data)
-	C.pn_data_next(data)
-	unmarshal(&v, data)
-	return v
-}
-
 func (m *message) Inferred() bool  { return bool(C.pn_message_is_inferred(m.pn)) }
 func (m *message) Durable() bool   { return bool(C.pn_message_is_durable(m.pn)) }
 func (m *message) Priority() uint8 { return uint8(C.pn_message_get_priority(m.pn)) }
@@ -237,14 +245,21 @@ func (m *message) GroupId() string        { return C.GoString(C.pn_message_get_g
 func (m *message) GroupSequence() int32   { return int32(C.pn_message_get_group_sequence(m.pn)) }
 func (m *message) ReplyToGroupId() string { return C.GoString(C.pn_message_get_reply_to_group_id(m.pn)) }
 
-func (m *message) Instructions() map[string]interface{} {
-	return rewindMap(C.pn_message_instructions(m.pn))
+func getAnnotations(data *C.pn_data_t) (v map[Key]interface{}) {
+	C.pn_data_rewind(data)
+	C.pn_data_next(data)
+	unmarshal(&v, data)
+	return v
 }
-func (m *message) Annotations() map[string]interface{} {
-	return rewindMap(C.pn_message_annotations(m.pn))
+
+func (m *message) DeliveryAnnotations() map[Key]interface{} {
+	return getAnnotations(C.pn_message_instructions(m.pn))
 }
-func (m *message) Properties() map[string]interface{} {
-	return rewindMap(C.pn_message_properties(m.pn))
+func (m *message) MessageAnnotations() map[Key]interface{} {
+	return getAnnotations(C.pn_message_annotations(m.pn))
+}
+func (m *message) ApplicationProperties() map[Key]interface{} {
+	return getAnnotations(C.pn_message_properties(m.pn))
 }
 
 // ==== message set methods
@@ -299,11 +314,15 @@ func (m *message) SetReplyToGroupId(s string) {
 	C.msg_set_str(m.pn, C.CString(s), C.set_fn(C.pn_message_set_reply_to_group_id))
 }
 
-func (m *message) SetInstructions(v map[string]interface{}) {
+func (m *message) SetDeliveryAnnotations(v map[Key]interface{}) {
 	setData(v, C.pn_message_instructions(m.pn))
 }
-func (m *message) SetAnnotations(v map[string]interface{}) { setData(v, C.pn_message_annotations(m.pn)) }
-func (m *message) SetProperties(v map[string]interface{})  { setData(v, C.pn_message_properties(m.pn)) }
+func (m *message) SetMessageAnnotations(v map[Key]interface{}) {
+	setData(v, C.pn_message_annotations(m.pn))
+}
+func (m *message) SetApplicationProperties(v map[Key]interface{}) {
+	setData(v, C.pn_message_properties(m.pn))
+}
 
 // Marshal/Unmarshal body
 func (m *message) Marshal(v interface{})   { clearMarshal(v, C.pn_message_body(m.pn)) }
@@ -346,3 +365,40 @@ func (m *message) Encode(buffer []byte) ([]byte, error) {
 // TODO aconway 2015-09-14: Multi-section messages.
 
 // TODO aconway 2016-09-09: Message.String() use inspect.
+
+// ==== Deprecated functions
+func oldGetAnnotations(data *C.pn_data_t) (v map[string]interface{}) {
+	C.pn_data_rewind(data)
+	C.pn_data_next(data)
+	unmarshal(&v, data)
+	return v
+}
+
+func (m *message) Instructions() map[string]interface{} {
+	return oldGetAnnotations(C.pn_message_instructions(m.pn))
+}
+func (m *message) Annotations() map[string]interface{} {
+	return oldGetAnnotations(C.pn_message_annotations(m.pn))
+}
+func (m *message) Properties() map[string]interface{} {
+	return oldGetAnnotations(C.pn_message_properties(m.pn))
+}
+
+// Convert old string-keyed annotations to a Key map
+func fixAnnotations(old map[string]interface{}) (annotations map[Key]interface{}) {
+	annotations = make(map[Key]interface{})
+	for k, v := range old {
+		annotations[StringKey(k)] = v
+	}
+	return
+}
+
+func (m *message) SetInstructions(v map[string]interface{}) {
+	setData(fixAnnotations(v), C.pn_message_instructions(m.pn))
+}
+func (m *message) SetAnnotations(v map[string]interface{}) {
+	setData(fixAnnotations(v), C.pn_message_annotations(m.pn))
+}
+func (m *message) SetProperties(v map[string]interface{}) {
+	setData(fixAnnotations(v), C.pn_message_properties(m.pn))
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
index 7a6e5a8..3081cc5 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/message_test.go
@@ -55,6 +55,11 @@ func TestDefaultMessage(t *testing.T) {
 		{m.ReplyToGroupId(), ""},
 		{m.MessageId(), nil},
 		{m.CorrelationId(), nil},
+		{m.DeliveryAnnotations(), map[Key]interface{}{}},
+		{m.MessageAnnotations(), map[Key]interface{}{}},
+		{m.ApplicationProperties(), map[Key]interface{}{}},
+
+		// Deprecated
 		{m.Instructions(), map[string]interface{}{}},
 		{m.Annotations(), map[string]interface{}{}},
 		{m.Properties(), map[string]interface{}{}},
@@ -86,9 +91,9 @@ func TestMessageRoundTrip(t *testing.T) {
 	m.SetReplyToGroupId("replytogroup")
 	m.SetMessageId("id")
 	m.SetCorrelationId("correlation")
-	m.SetInstructions(map[string]interface{}{"instructions": "foo"})
-	m.SetAnnotations(map[string]interface{}{"annotations": "foo"})
-	m.SetProperties(map[string]interface{}{"int": int32(32), "bool": true, "string": "foo"})
+	m.SetDeliveryAnnotations(map[Key]interface{}{SymbolKey("instructions"): "foo"})
+	m.SetMessageAnnotations(map[Key]interface{}{SymbolKey("annotations"): "bar"})
+	m.SetApplicationProperties(map[Key]interface{}{SymbolKey("int"): int32(32), SymbolKey("bool"): true, IntKey(42): "42"})
 	m.Marshal("hello")
 
 	for _, data := range [][]interface{}{
@@ -107,10 +112,50 @@ func TestMessageRoundTrip(t *testing.T) {
 		{m.ReplyToGroupId(), "replytogroup"},
 		{m.MessageId(), "id"},
 		{m.CorrelationId(), "correlation"},
-		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
-		{m.Annotations(), map[string]interface{}{"annotations": "foo"}},
-		{m.Properties(), map[string]interface{}{"int": int32(32), "bool": true, "string": "foo"}},
+
+		{m.DeliveryAnnotations(), map[Key]interface{}{SymbolKey("instructions"): "foo"}},
+		{m.MessageAnnotations(), map[Key]interface{}{SymbolKey("annotations"): "bar"}},
+		{m.ApplicationProperties(), map[Key]interface{}{SymbolKey("int"): int32(32), SymbolKey("bool"): true, IntKey(42): "42"}},
 		{m.Body(), "hello"},
+
+		// Deprecated
+		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
+		{m.Annotations(), map[string]interface{}{"annotations": "bar"}},
+	} {
+		if err := checkEqual(data[0], data[1]); err != nil {
+			t.Error(err)
+		}
+	}
+	if err := roundTrip(m); err != nil {
+		t.Error(err)
+	}
+
+	func() { // Expect a panic
+		defer func() {
+			if x, ok := recover().(*UnmarshalError); !ok {
+				t.Errorf("Expected UnmarshalError, got %#v", x)
+			}
+		}()
+		m.Properties()
+		t.Error("Expected panic")
+	}()
+}
+
+func TestDeprecated(t *testing.T) {
+	m := NewMessage()
+
+	m.SetInstructions(map[string]interface{}{"instructions": "foo"})
+	m.SetAnnotations(map[string]interface{}{"annotations": "bar"})
+	m.SetProperties(map[string]interface{}{"int": int32(32), "bool": true})
+
+	for _, data := range [][]interface{}{
+		{m.DeliveryAnnotations(), map[Key]interface{}{SymbolKey("instructions"): "foo"}},
+		{m.MessageAnnotations(), map[Key]interface{}{SymbolKey("annotations"): "bar"}},
+		{m.ApplicationProperties(), map[Key]interface{}{SymbolKey("int"): int32(32), SymbolKey("bool"): true}},
+
+		{m.Instructions(), map[string]interface{}{"instructions": "foo"}},
+		{m.Annotations(), map[string]interface{}{"annotations": "bar"}},
+		{m.Properties(), map[string]interface{}{"int": int32(32), "bool": true}},
 	} {
 		if err := checkEqual(data[0], data[1]); err != nil {
 			t.Error(err)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
index 2852c23..76f223f 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
@@ -105,6 +105,7 @@ type List []interface{}
 // Symbol is a string that is encoded as an AMQP symbol
 type Symbol string
 
+func (s Symbol) String() string   { return string(s) }
 func (s Symbol) GoString() string { return fmt.Sprintf("s\"%s\"", s) }
 
 // Binary is a string that is encoded as an AMQP binary.
@@ -112,6 +113,7 @@ func (s Symbol) GoString() string { return fmt.Sprintf("s\"%s\"", s) }
 // a map key, AMQP frequently uses binary types as map keys. It can convert to and from []byte
 type Binary string
 
+func (b Binary) String() string   { return string(b) }
 func (b Binary) GoString() string { return fmt.Sprintf("b\"%s\"", b) }
 
 // GoString for Map prints values with their types, useful for debugging.
@@ -192,3 +194,19 @@ func cPtr(b []byte) *C.char {
 func cLen(b []byte) C.size_t {
 	return C.size_t(len(b))
 }
+
+// Key is used as a map key for some AMQP "restricted" maps which are
+// allowed to have keys that are either symbol or ulong but no other type.
+//
+type Key struct {
+	value interface{}
+}
+
+func SymbolKey(v Symbol) Key { return Key{v} }
+func IntKey(v uint64) Key    { return Key{v} }
+func StringKey(v string) Key { return Key{Symbol(v)} }
+
+// Returns the value which must be Symbol, uint64 or nil
+func (k Key) Get() interface{} { return k.value }
+
+func (k Key) String() string { return fmt.Sprintf("%v", k.Get()) }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
new file mode 100644
index 0000000..b9c0596
--- /dev/null
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types_test.go
@@ -0,0 +1,34 @@
+/*
+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 amqp
+
+import (
+	"fmt"
+)
+
+func ExampleKey() {
+	var k Key = SymbolKey(Symbol("foo"))
+	fmt.Println(k.Get().(Symbol))
+	k = IntKey(42)
+	fmt.Println(k.Get().(uint64))
+	// Output:
+	// foo
+	// 42
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/110f851a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index d56cbd2..96b8e05 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -178,6 +178,8 @@ Types are converted as follows:
  |                           +------------------------+---------------------------------------------+
  |                           |list                    |List                                         |
  +---------------------------+------------------------+---------------------------------------------+
+ |Key                        |symbol, ulong                                                         |
+ +---------------------------+----------------------------------------------------------------------+
 
 The following Go types cannot be unmarshaled: uintptr, function, interface, channel.
 
@@ -431,6 +433,13 @@ func unmarshal(v interface{}, data *C.pn_data_t) {
 	case *interface{}:
 		getInterface(data, v)
 
+	case *Key:
+		if pnType == C.PN_ULONG || pnType == C.PN_SYMBOL || pnType == C.PN_STRING {
+			unmarshal(&v.value, data)
+		} else {
+			panic(newUnmarshalError(pnType, v))
+		}
+
 	default:
 		if reflect.TypeOf(v).Kind() != reflect.Ptr {
 			panic(newUnmarshalError(pnType, v))


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


[08/50] [abbrv] qpid-proton git commit: PROTON-1474: Fix CMake config files and cmake files so that Proton C examples compile separately - This reverts commit ed9532e2ae08b04aa5690d43e9002431bd019c21.A - This introduces Core and Proactor package componen

Posted by ac...@apache.org.
PROTON-1474: Fix CMake config files and cmake files so that Proton C examples compile separately
- This reverts commit ed9532e2ae08b04aa5690d43e9002431bd019c21.A
- This introduces Core and Proactor package components to the Proton CMake config script


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

Branch: refs/heads/go1
Commit: 24a2ed32134e2ae5610be3eb46b9817a40ba969b
Parents: 180718f
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 5 18:13:34 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed May 10 20:05:18 2017 -0400

----------------------------------------------------------------------
 examples/ProtonConfig.cmake        | 23 +++++++++++++++++++++--
 examples/c/CMakeLists.txt          |  4 +++-
 examples/c/proactor/CMakeLists.txt | 12 +++++-------
 proton-c/CMakeLists.txt            |  8 +++-----
 proton-c/src/ProtonConfig.cmake.in | 25 +++++++++++++++++++------
 5 files changed, 51 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24a2ed32/examples/ProtonConfig.cmake
----------------------------------------------------------------------
diff --git a/examples/ProtonConfig.cmake b/examples/ProtonConfig.cmake
index fe8709c..e0a2ff8 100644
--- a/examples/ProtonConfig.cmake
+++ b/examples/ProtonConfig.cmake
@@ -28,8 +28,27 @@
 # tree build and installed in the appropriate place for cmake on that system.
 
 set (Proton_VERSION       ${PN_VERSION})
+
 set (Proton_INCLUDE_DIRS  ${CMAKE_SOURCE_DIR}/proton-c/include)
 set (Proton_LIBRARIES     qpid-proton)
-set (ProtonCore_LIBRARIES qpid-proton-core)
-set (ProtonProactor_LIBRARIES qpid-proton-proactor)
 set (Proton_FOUND True)
+
+set (Proton_Core_INCLUDE_DIRS  ${CMAKE_SOURCE_DIR}/proton-c/include)
+set (Proton_Core_LIBRARIES qpid-proton-core)
+set (Proton_Core_FOUND True)
+
+if (${HAS_PROACTOR})
+  set (Proton_Proactor_INCLUDE_DIRS  ${CMAKE_SOURCE_DIR}/proton-c/include)
+  set (Proton_Proactor_LIBRARIES qpid-proton-proactor)
+  set (Proton_Proactor_FOUND True)
+endif()
+
+# Check for all required components
+foreach(comp ${Proton_FIND_COMPONENTS})
+  if(NOT Proton_${comp}_FOUND)
+    if(Proton_FIND_REQUIRED_${comp})
+      set(Proton_FOUND FALSE)
+      set(Proton_NOT_FOUND_MESSAGE "Didn't find required component ${comp}")
+    endif()
+  endif()
+endforeach()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24a2ed32/examples/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index 0fed71b..c78e04c 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -21,6 +21,8 @@ find_package(Proton REQUIRED)
 include(CheckCCompilerFlag)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 
-add_subdirectory(proactor)
+if(Proton_Proactor_FOUND)
+  add_subdirectory(proactor)
+endif()
 add_subdirectory(messenger)
 add_subdirectory(reactor)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24a2ed32/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
index 9759a7c..11fb073 100644
--- a/examples/c/proactor/CMakeLists.txt
+++ b/examples/c/proactor/CMakeLists.txt
@@ -17,12 +17,13 @@
 # under the License.
 #
 
-find_package(Proton REQUIRED)
+find_package(Proton REQUIRED Core Proactor)
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+find_package(Threads REQUIRED)
+
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${Proton_INCLUDE_DIRS})
 
-if(HAS_PROACTOR)
-
 add_definitions(${COMPILE_LANGUAGE_FLAGS} ${COMPILE_WARNING_FLAGS} ${WERROR} ${COMPILE_PLATFORM_FLAGS} ${LINK_TIME_OPTIMIZATION})
 
 # Add a test with the correct environment to find test executables and valgrind.
@@ -30,16 +31,13 @@ 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 direct)
   add_executable(proactor-${name} ${name}.c)
-  target_link_libraries(proactor-${name} ${ProtonProactor_LIBRARIES} ${PLATFORM_LIBS})
+  target_link_libraries(proactor-${name} ${Proton_Proactor_LIBRARIES} ${Proton_Core_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
   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-example-proactor ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py -v)
-
-endif(HAS_PROACTOR)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24a2ed32/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 5589a11..33933b8 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -608,8 +608,9 @@ if (MSVC)
 endif(MSVC)
 
 if (qpid-proton-proactor)
-  set(HAS_PROACTOR 1)
-  set(HAS_PROACTOR 1 PARENT_SCOPE) # Visible to examples
+  # Bizarre CMake variable setting
+  set(HAS_PROACTOR True)
+  set(HAS_PROACTOR ${HAS_PROACTOR} PARENT_SCOPE)
   add_library (
     qpid-proton-proactor SHARED ${qpid-proton-proactor})
   target_link_libraries (qpid-proton-proactor  LINK_PUBLIC qpid-proton-core)
@@ -666,9 +667,6 @@ configure_lib(PROTONLIB qpid-proton)
 configure_lib(PROTONCORELIB qpid-proton-core)
 if(HAS_PROACTOR)
   configure_lib(PROTONPROACTORLIB qpid-proton-proactor)
-  # For ProtonConfig.in
-  set(PROTONPROACTOR_INCLUDE_DIRS ${INCLUDEDIR})
-  set(PROTONPROACTOR_LIBRARIES "optimized ${LIBDIR}/${PROTONPROACTORLIB} debug ${LIBDIR}/${PROTONPROACTORLIBDEBUG}")
 endif(HAS_PROACTOR)
 
 include(WriteBasicConfigVersionFile)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/24a2ed32/proton-c/src/ProtonConfig.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/ProtonConfig.cmake.in b/proton-c/src/ProtonConfig.cmake.in
index 5a09d68..5b23be0 100644
--- a/proton-c/src/ProtonConfig.cmake.in
+++ b/proton-c/src/ProtonConfig.cmake.in
@@ -26,12 +26,25 @@ set (Proton_VERSION       @PN_VERSION@)
 
 set (Proton_INCLUDE_DIRS  @INCLUDEDIR@)
 set (Proton_LIBRARIES     optimized @LIBDIR@/@PROTONLIB@ debug @LIBDIR@/@PROTONLIBDEBUG@)
+set (Proton_FOUND True)
 
-set (ProtonCore_INCLUDE_DIRS  @INCLUDEDIR@)
-set (ProtonCore_LIBRARIES     optimized @LIBDIR@/@PROTONCORELIB@ debug @LIBDIR@/@PROTONCORELIBDEBUG@)
+set (Proton_Core_INCLUDE_DIRS  @INCLUDEDIR@)
+set (Proton_Core_LIBRARIES     optimized @LIBDIR@/@PROTONCORELIB@ debug @LIBDIR@/@PROTONCORELIBDEBUG@)
+set (Proton_Core_FOUND True)
 
-set (ProtonProactor_INCLUDE_DIRS  @PROTONPROACTOR_INCLUDE_DIRS@)
-set (ProtonProactor_LIBRARIES     @PROTONPROACTOR_LIBRARIES@)
-set (ProtonProactor_FOUND         @HAS_PROACTOR@)
+set (HAS_PROACTOR @HAS_PROACTOR@)
+if (HAS_PROACTOR)
+  set (Proton_Proactor_INCLUDE_DIRS  @INCLUDEDIR@)
+  set (Proton_Proactor_LIBRARIES     optimized @LIBDIR@/@PROTONPROACTORLIB@ debug @LIBDIR@/@PROTONPROACTORLIBDEBUG@)
+  set (Proton_Proactor_FOUND True)
+endif()
 
-set (Proton_FOUND True)
+# Check for all required components
+foreach(comp ${Proton_FIND_COMPONENTS})
+  if(NOT Proton_${comp}_FOUND)
+    if(Proton_FIND_REQUIRED_${comp})
+      set(Proton_FOUND FALSE)
+      set(Proton_NOT_FOUND_MESSAGE "Didn't find required component ${comp}")
+    endif()
+  endif()
+endforeach()


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


[07/50] [abbrv] qpid-proton git commit: PROTON-1460: epoll - add -lpthread

Posted by ac...@apache.org.
PROTON-1460: epoll - add -lpthread

This was being picked up by accident via the SASL library.
Added explicitly for the epoll proactor in case SASL is not present.


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

Branch: refs/heads/go1
Commit: 180718f07e3856f666b8aa7538cc17fa15c29197
Parents: ea87505
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 10 17:00:22 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 10 17:00:22 2017 -0400

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


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/180718f0/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index e468cae..5589a11 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -487,7 +487,7 @@ if (PROACTOR STREQUAL "epoll" OR (NOT PROACTOR AND NOT BUILD_PROACTOR))
   if (HAVE_EPOLL)
     set (PROACTOR_OK epoll)
     set (qpid-proton-proactor src/proactor/epoll.c src/proactor/proactor-internal.c)
-    set (PROACTOR_LIBS "")
+    set (PROACTOR_LIBS -lpthread)
     set_source_files_properties (${qpid-proton-proactor} PROPERTIES
       COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LTO}"
       )


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


[41/50] [abbrv] qpid-proton git commit: PROTON-1493: c epoll proactor spinning on interruptfd

Posted by ac...@apache.org.
PROTON-1493: c epoll proactor spinning on interruptfd

Missing read() on interruptfd was causing the proactor to spin.


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

Branch: refs/heads/go1
Commit: cb5996ee5c714b28d0449caef21d1b50c8412d69
Parents: ad52e3a
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Jun 5 14:23:15 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jun 7 10:20:41 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/cb5996ee/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 3a0ea29..b6d2bd0 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -185,6 +185,16 @@ static void ptimer_set(ptimer_t *pt, uint64_t t_millis) {
   unlock(&pt->mutex);
 }
 
+/* Read from a timer or event FD */
+static uint64_t read_uint64(int fd) {
+  uint64_t result = 0;
+  ssize_t n = read(fd, &result, sizeof(result));
+  if (n != sizeof(result) && !(n < 0 && errno == EAGAIN)) {
+    EPOLL_FATAL("timerfd or eventfd read error", errno);
+  }
+  return result;
+}
+
 // Callback bookkeeping. Return true if there is an expired timer.
 static bool ptimer_callback(ptimer_t *pt) {
   lock(&pt->mutex);
@@ -193,23 +203,13 @@ static bool ptimer_callback(ptimer_t *pt) {
     if (current.it_value.tv_nsec == 0 && current.it_value.tv_sec == 0)
       pt->timer_active = false;
   }
-  uint64_t u_exp_count = 0;
-  ssize_t l = read(pt->timerfd, &u_exp_count, sizeof(uint64_t));
-  if (l != sizeof(uint64_t)) {
-    if (l == -1) {
-      if (errno != EAGAIN) {
-        EPOLL_FATAL("timer read", errno);
-      }
-    }
-    else
-      EPOLL_FATAL("timer internal error", 0);
-  }
+  uint64_t u_exp_count = read_uint64(pt->timerfd);
   if (!pt->timer_active) {
     // Expiry counter just cleared, timer not set, timerfd not armed
     pt->in_doubt = false;
   }
   unlock(&pt->mutex);
-  return (l == sizeof(uint64_t)) && u_exp_count > 0;
+  return u_exp_count > 0;
 }
 
 // Return true if timerfd has and will have no pollable expiries in the current armed state
@@ -444,9 +444,7 @@ static pcontext_t *wake_pop_front(pn_proactor_t *p) {
        * Can the read system call be made without holding the lock?
        * Note that if the reads/writes happen out of order, the wake
        * mechanism will hang. */
-      uint64_t ignored;
-      int err = read(p->eventfd, &ignored, sizeof(uint64_t));
-      (void)err; // TODO: check for error
+      (void)read_uint64(p->eventfd);
       p->wakes_in_progress = false;
     }
   }
@@ -1673,6 +1671,7 @@ static bool proactor_remove(pcontext_t *ctx) {
 
 static pn_event_batch_t *process_inbound_wake(pn_proactor_t *p, epoll_extended_t *ee) {
   if  (ee->fd == p->interruptfd) {        /* Interrupts have their own dedicated eventfd */
+    (void)read_uint64(p->interruptfd);
     rearm(p, &p->epoll_interrupt);
     return proactor_process(p, PN_PROACTOR_INTERRUPT);
   }


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


[34/50] [abbrv] qpid-proton git commit: PROTON-1493: c-proactor make pn_proactor_interrupt async-signal-safe

Posted by ac...@apache.org.
PROTON-1493: c-proactor make pn_proactor_interrupt async-signal-safe

pn_proactor_interrupt() will  often be used from signal handlers so must be
async-signal-safe. Updated the documentation and modified the implementations
of pn_proactor_interrupt() to use only async-signal-safe calls, no locks.


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

Branch: refs/heads/go1
Commit: 5f8738f573c3e9c39608714453b2425e3a105ec7
Parents: 8d862be
Author: Alan Conway <ac...@redhat.com>
Authored: Mon May 29 17:12:36 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 31 10:49:36 2017 -0400

----------------------------------------------------------------------
 INSTALL.md                         |  11 +++
 examples/c/proactor/broker.c       |   8 +--
 proton-c/include/proton/proactor.h |  11 +--
 proton-c/src/proactor/epoll.c      | 122 +++++++++++++++++---------------
 proton-c/src/proactor/libuv.c      |  37 +++++++---
 5 files changed, 112 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5f8738f5/INSTALL.md
----------------------------------------------------------------------
diff --git a/INSTALL.md b/INSTALL.md
index 8de93fe..e5e5db6 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -137,6 +137,17 @@ Note that if you wish to build debug version of proton for use with
 swig bindings on Windows, you must have the appropriate debug target
 libraries to link against.
 
+Other platforms
+---------------
+
+Proton can use the http://libuv.org IO library on any platform where
+it is available. Install the libuv library and header files and adapt
+the instructions for building on Linux.
+
+The libuv library is not required on Linux or Windows but if you wish
+you can use it instead of the default native IO by running cmake with
+`-Dproactor=libuv`
+
 Installing Language Bindings
 ----------------------------
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5f8738f5/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index 7d95e7f..d9285db 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -195,9 +195,8 @@ typedef struct broker_t {
 } broker_t;
 
 void broker_stop(broker_t *b) {
-  /* In this broker an interrupt stops a thread, stopping all threads stops the broker */
-  for (size_t i = 0; i < b->threads; ++i)
-    pn_proactor_interrupt(b->proactor);
+  /* Interrupt the proactor to stop the working threads. */
+  pn_proactor_interrupt(b->proactor);
 }
 
 /* Try to send if link is sender and has credit */
@@ -369,12 +368,13 @@ static void handle(broker_t* b, pn_event_t* e) {
 
  break;
 
-   case PN_PROACTOR_INACTIVE: /* listener and all connections closed */
+   case PN_PROACTOR_INACTIVE:   /* listener and all connections closed */
     broker_stop(b);
     break;
 
    case PN_PROACTOR_INTERRUPT:
     b->finished = true;
+    pn_proactor_interrupt(b->proactor); /* Pass along the interrupt to the other threads */
     break;
 
    default:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5f8738f5/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index 861afbe..9c7ce59 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -196,12 +196,13 @@ PNP_EXTERN void pn_proactor_done(pn_proactor_t *proactor, pn_event_batch_t *even
 /**
  * Return a @ref PN_PROACTOR_INTERRUPT event as soon as possible.
  *
- * Exactly one @ref PN_PROACTOR_INTERRUPT event is generated for each call to
- * pn_proactor_interrupt().  If threads are blocked in pn_proactor_wait(), one
- * of them will be interrupted, otherwise the interrupt will be returned by a
- * future call to pn_proactor_wait(). Calling pn_proactor_interrupt().
+ * At least one PN_PROACTOR_INTERRUPT event will be returned after this call.
+ * Interrupts can be "coalesced" - if several pn_proactor_interrupt() calls
+ * happen close together, there may be only one PN_PROACTOR_INTERRUPT event that
+ * occurs after all of them.
  *
- * @note Thread safe
+ * @note Thread-safe and async-signal-safe: can be called in a signal handler.
+ * This is the only pn_proactor function that is async-signal-safe.
  */
 PNP_EXTERN void pn_proactor_interrupt(pn_proactor_t *proactor);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5f8738f5/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 7490ecd..b258da3 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -302,11 +302,13 @@ static void stop_polling(epoll_extended_t *ee, int epollfd) {
  * thread.  Conversely, a thread must never stop working without
  * checking if it has newly arrived work.
  *
- * External wake operations, like pn_connection_wake() and
- * pn_proactor_interrupt(), are built on top of the internal wake
- * mechanism.  The former coalesces multiple wakes until event
- * delivery, the latter does not.  The WAKEABLE implementation can be
- * modeled on whichever is more suited.
+ * External wake operations, like pn_connection_wake() and are built on top of
+ * the internal wake mechanism.  The former coalesces multiple wakes until event
+ * delivery, the latter does not.  The WAKEABLE implementation can be modeled on
+ * whichever is more suited.
+ *
+ * pn_proactor_interrupt() must be async-signal-safe so it has a dedicated
+ * eventfd to allow a lock-free pn_proactor_interrupt() implementation.
  */
 typedef enum {
   PROACTOR,
@@ -360,10 +362,10 @@ struct pn_proactor_t {
   pn_collector_t *collector;
   pcontext_t *contexts;         /* in-use contexts for PN_PROACTOR_INACTIVE and cleanup */
   epoll_extended_t epoll_wake;
+  epoll_extended_t epoll_interrupt;
   pn_event_batch_t batch;
-  size_t interrupts;            /* total pending interrupts */
-  size_t deferred_interrupts;   /* interrupts for current batch */
   size_t disconnects_pending;   /* unfinished proactor disconnects*/
+  bool interrupt;
   bool inactive;
   bool timer_expired;
   bool timer_cancelled;
@@ -375,6 +377,8 @@ struct pn_proactor_t {
   bool wakes_in_progress;
   pcontext_t *wake_list_first;
   pcontext_t *wake_list_last;
+  // Interrupts have a dedicated eventfd because they must be async-signal safe.
+  int interruptfd;
 };
 
 static void rearm(pn_proactor_t *p, epoll_extended_t *ee);
@@ -1470,6 +1474,16 @@ void pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
 // proactor
 // ========================================================================
 
+/* Set up an epoll_extended_t to be used for wakeup or interrupts */
+static void epoll_wake_init(epoll_extended_t *ee, int eventfd, int epollfd) {
+  ee->psocket = NULL;
+  ee->fd = eventfd;
+  ee->type = WAKE;
+  ee->wanted = EPOLLIN;
+  ee->polling = false;
+  start_polling(ee, epollfd);  // TODO: check for error
+}
+
 pn_proactor_t *pn_proactor() {
   pn_proactor_t *p = (pn_proactor_t*)calloc(1, sizeof(*p));
   if (!p) return NULL;
@@ -1478,26 +1492,24 @@ pn_proactor_t *pn_proactor() {
   pmutex_init(&p->eventfd_mutex);
   ptimer_init(&p->timer, 0);
 
-  if ((p->epollfd = epoll_create(1)) >= 0)
+  if ((p->epollfd = epoll_create(1)) >= 0) {
     if ((p->eventfd = eventfd(0, EFD_NONBLOCK)) >= 0) {
-      if (p->timer.timerfd >= 0)
-        if ((p->collector = pn_collector()) != NULL) {
-          p->batch.next_event = &proactor_batch_next;
-          start_polling(&p->timer.epoll_io, p->epollfd);  // TODO: check for error
-          p->timer_armed = true;
-
-          p->epoll_wake.psocket = NULL;
-          p->epoll_wake.fd = p->eventfd;
-          p->epoll_wake.type = WAKE;
-          p->epoll_wake.wanted = EPOLLIN;
-          p->epoll_wake.polling = false;
-          start_polling(&p->epoll_wake, p->epollfd);  // TODO: check for error
-          return p;
-        }
+      if ((p->interruptfd = eventfd(0, EFD_NONBLOCK)) >= 0) {
+        if (p->timer.timerfd >= 0)
+          if ((p->collector = pn_collector()) != NULL) {
+            p->batch.next_event = &proactor_batch_next;
+            start_polling(&p->timer.epoll_io, p->epollfd);  // TODO: check for error
+            p->timer_armed = true;
+            epoll_wake_init(&p->epoll_wake, p->eventfd, p->epollfd);
+            epoll_wake_init(&p->epoll_interrupt, p->interruptfd, p->epollfd);
+            return p;
+          }
+      }
     }
-
+  }
   if (p->epollfd >= 0) close(p->epollfd);
   if (p->eventfd >= 0) close(p->eventfd);
+  if (p->interruptfd >= 0) close(p->eventfd);
   ptimer_finalize(&p->timer);
   if (p->collector) pn_free(p->collector);
   free (p);
@@ -1510,6 +1522,8 @@ void pn_proactor_free(pn_proactor_t *p) {
   p->epollfd = -1;
   close(p->eventfd);
   p->eventfd = -1;
+  close(p->interruptfd);
+  p->interruptfd = -1;
   ptimer_finalize(&p->timer);
   while (p->contexts) {
     pcontext_t *ctx = p->contexts;
@@ -1551,34 +1565,23 @@ static void proactor_add_event(pn_proactor_t *p, pn_event_type_t t) {
 static bool proactor_update_batch(pn_proactor_t *p) {
   if (proactor_has_event(p))
     return true;
-  if (p->deferred_interrupts > 0) {
-    // drain these first
-    --p->deferred_interrupts;
-    --p->interrupts;
-    proactor_add_event(p, PN_PROACTOR_INTERRUPT);
-    return true;
-  }
 
   if (p->timer_expired) {
     p->timer_expired = false;
     proactor_add_event(p, PN_PROACTOR_TIMEOUT);
     return true;
   }
-
-  int ec = 0;
-  if (p->interrupts > 0) {
-    --p->interrupts;
+  if (p->interrupt) {
+    p->interrupt = false;
     proactor_add_event(p, PN_PROACTOR_INTERRUPT);
-    ec++;
-    if (p->interrupts > 0)
-      p->deferred_interrupts = p->interrupts;
+    return true;
   }
-  if (p->inactive && ec == 0) {
+  if (p->inactive) {
     p->inactive = false;
-    ec++;
     proactor_add_event(p, PN_PROACTOR_INACTIVE);
+    return true;
   }
-  return ec > 0;
+  return false;
 }
 
 static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
@@ -1590,10 +1593,12 @@ static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
   return log_event(p, e);
 }
 
-static pn_event_batch_t *proactor_process(pn_proactor_t *p, bool timeout) {
-  bool timer_fired = timeout && ptimer_callback(&p->timer) != 0;
+static pn_event_batch_t *proactor_process(pn_proactor_t *p, pn_event_type_t event) {
+  bool timer_fired = (event == PN_PROACTOR_TIMEOUT) && ptimer_callback(&p->timer) != 0;
   lock(&p->context.mutex);
-  if (timeout) {
+  if (event == PN_PROACTOR_INTERRUPT) {
+    p->interrupt = true;
+  } else if (event == PN_PROACTOR_TIMEOUT) {
     p->timer_armed = false;
     if (timer_fired && !p->timer_cancelled)
       p->timer_expired = true;
@@ -1667,17 +1672,20 @@ static bool proactor_remove(pcontext_t *ctx) {
   return can_free;
 }
 
-static pn_event_batch_t *process_inbound_wake(pn_proactor_t *p) {
+static pn_event_batch_t *process_inbound_wake(pn_proactor_t *p, epoll_extended_t *ee) {
+  if  (ee->fd == p->interruptfd) {        /* Interrupts have their own dedicated eventfd */
+    return proactor_process(p, PN_PROACTOR_INTERRUPT);
+  }
   pcontext_t *ctx = wake_pop_front(p);
   if (ctx) {
     switch (ctx->type) {
-    case PROACTOR:
-      return proactor_process(p, false);
-    case PCONNECTION:
+     case PROACTOR:
+      return proactor_process(p, PN_EVENT_NONE);
+     case PCONNECTION:
       return pconnection_process((pconnection_t *) ctx->owner, 0, false, false);
-    case LISTENER:
-     return listener_process(&((pn_listener_t *) ctx->owner)->psockets[0], 0);
-    default:
+     case LISTENER:
+      return listener_process(&((pn_listener_t *) ctx->owner)->psockets[0], 0);
+     default:
       assert(ctx->type == WAKEABLE); // TODO: implement or remove
     }
   }
@@ -1710,9 +1718,9 @@ static pn_event_batch_t *proactor_do_epoll(struct pn_proactor_t* p, bool can_blo
     epoll_extended_t *ee = (epoll_extended_t *) ev.data.ptr;
 
     if (ee->type == WAKE) {
-      batch = process_inbound_wake(p);
+      batch = process_inbound_wake(p, ee);
     } else if (ee->type == PROACTOR_TIMER) {
-      batch = proactor_process(p, true);
+      batch = proactor_process(p, PN_PROACTOR_TIMEOUT);
     } else {
       pconnection_t *pc = psocket_pconnection(ee->psocket);
       if (pc) {
@@ -1772,11 +1780,11 @@ void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
 }
 
 void pn_proactor_interrupt(pn_proactor_t *p) {
-  lock(&p->context.mutex);
-  ++p->interrupts;
-  bool notify = wake(&p->context);
-  unlock(&p->context.mutex);
-  if (notify) wake_notify(&p->context);
+  if (p->interruptfd == -1)
+    return;
+  uint64_t increment = 1;
+  if (write(p->interruptfd, &increment, sizeof(uint64_t)) != sizeof(uint64_t))
+    EPOLL_FATAL("setting eventfd", errno);
 }
 
 void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5f8738f5/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index cf7a31b..8cd6dd7 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -52,7 +52,7 @@
   libuv functions are thread unsafe, we use a"leader-worker-follower" model as follows:
 
   - At most one thread at a time is the "leader". The leader runs the UV loop till there
-  are events to process and then becomes a "worker"n
+  are events to process and then becomes a "worker"
 
   - Concurrent "worker" threads process events for separate connections or listeners.
   When they run out of work they become "followers"
@@ -227,10 +227,13 @@ struct pn_listener_t {
 typedef enum { TM_NONE, TM_REQUEST, TM_PENDING, TM_FIRED } timeout_state_t;
 
 struct pn_proactor_t {
+  /* Notification */
+  uv_async_t notify;
+  uv_async_t interrupt;
+
   /* 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 */
@@ -241,7 +244,6 @@ struct pn_proactor_t {
   uv_mutex_t lock;
   work_queue_t worker_q;      /* ready for work, to be returned via pn_proactor_wait()  */
   work_queue_t leader_q;      /* waiting for attention by the leader thread */
-  size_t interrupt;           /* pending interrupts */
   timeout_state_t timeout_state;
   pn_millis_t timeout;
   size_t count;               /* connection/listener count for INACTIVE events */
@@ -250,12 +252,21 @@ struct pn_proactor_t {
   bool inactive;
   bool has_leader;
   bool batch_working;         /* batch is being processed in a worker thread */
+  bool need_interrupt;        /* Need a PN_PROACTOR_INTERRUPT event */
 };
 
 
 /* Notify the leader thread that there is something to do outside of uv_run() */
 static inline void notify(pn_proactor_t* p) {
-  uv_async_send(&p->async);
+  uv_async_send(&p->notify);
+}
+
+/* Set the interrupt flag in the leader thread to avoid race conditions. */
+void on_interrupt(uv_async_t *async) {
+  if (async->data) {
+    pn_proactor_t *p = (pn_proactor_t*)async->data;
+    p->need_interrupt = true;
+  }
 }
 
 /* Notify that this work item needs attention from the leader at the next opportunity */
@@ -814,8 +825,8 @@ static pn_event_batch_t *get_batch_lh(pn_proactor_t *p) {
       p->inactive = false;
       return proactor_batch_lh(p, PN_PROACTOR_INACTIVE);
     }
-    if (p->interrupt > 0) {
-      --p->interrupt;
+    if (p->need_interrupt) {
+      p->need_interrupt = false;
       return proactor_batch_lh(p, PN_PROACTOR_INTERRUPT);
     }
     if (p->timeout_state == TM_FIRED) {
@@ -1072,10 +1083,12 @@ pn_proactor_t *pn_event_proactor(pn_event_t *e) {
 }
 
 void pn_proactor_interrupt(pn_proactor_t *p) {
-  uv_mutex_lock(&p->lock);
-  ++p->interrupt;
-  uv_mutex_unlock(&p->lock);
-  notify(p);
+  /* NOTE: pn_proactor_interrupt must be async-signal-safe so we cannot use
+     locks to update shared proactor state here. Instead we use a dedicated
+     uv_async, the on_interrupt() callback will set the interrupt flag in the
+     safety of the leader thread.
+   */
+  uv_async_send(&p->interrupt);
 }
 
 void pn_proactor_disconnect(pn_proactor_t *p, pn_condition_t *cond) {
@@ -1155,7 +1168,9 @@ pn_proactor_t *pn_proactor() {
   uv_loop_init(&p->loop);
   uv_mutex_init(&p->lock);
   uv_cond_init(&p->cond);
-  uv_async_init(&p->loop, &p->async, NULL);
+  uv_async_init(&p->loop, &p->notify, NULL);
+  uv_async_init(&p->loop, &p->interrupt, on_interrupt);
+  p->interrupt.data = p;
   uv_timer_init(&p->loop, &p->timer);
   p->timer.data = p;
   p->disconnect_cond = pn_condition();


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


[14/50] [abbrv] qpid-proton git commit: PROTON-1460: epoll additional error checks

Posted by ac...@apache.org.
PROTON-1460: epoll additional error checks


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

Branch: refs/heads/go1
Commit: b0be770d752c5067fb806fb081f1693418b52d02
Parents: c4d1658
Author: Clifford Jansen <cl...@apache.org>
Authored: Sun May 14 18:21:44 2017 -0700
Committer: Clifford Jansen <cl...@apache.org>
Committed: Sun May 14 18:21:44 2017 -0700

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b0be770d/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index fae68e9..9fd7d06 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -54,7 +54,7 @@
 #include <time.h>
 
 // TODO: replace timerfd per connection with global lightweight timer mechanism.
-// logging in general, listener events in particular
+// logging in general
 // SIGPIPE?
 // Can some of the mutexes be spinlocks (any benefit over adaptive pthread mutex)?
 //   Maybe futex is even better?
@@ -64,6 +64,13 @@
 // looking for pending wakes before a kernel call to epoll_wait(), or there
 // could be several eventfds with random assignment of wakeables.
 
+/* Internal error, no recovery */
+#define EPOLL_FATAL(EXPR, SYSERRNO)                                   \
+  do {                                                                \
+    fprintf(stderr, "epoll proactor failure in %s:%d: %s: %s\n",      \
+            __FILE__, __LINE__ , #EXPR, strerror(SYSERRNO));          \
+    abort();                                                          \
+  } while (0)
 
 // ========================================================================
 // First define a proactor mutex (pmutex) and timer mechanism (ptimer) to taste.
@@ -103,6 +110,7 @@ typedef struct epoll_extended_t {
   int fd;
   epoll_type_t type;   // io/timer/wakeup
   uint32_t wanted;     // events to poll for
+  bool polling;
 } epoll_extended_t;
 
 /*
@@ -130,6 +138,7 @@ static bool ptimer_init(ptimer_t *pt, struct psocket_t *ps) {
   pt->epoll_io.fd = pt->timerfd;
   pt->epoll_io.type = type;
   pt->epoll_io.wanted = EPOLLIN;
+  pt->epoll_io.polling = false;
   return true;
 }
 
@@ -213,6 +222,9 @@ PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
 PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
 
 static bool start_polling(epoll_extended_t *ee, int epollfd) {
+  if (ee->polling)
+    return false;
+  ee->polling = true;
   struct epoll_event ev;
   ev.data.ptr = ee;
   ev.events = ee->wanted | EPOLLONESHOT;
@@ -221,13 +233,15 @@ static bool start_polling(epoll_extended_t *ee, int epollfd) {
 
 static void stop_polling(epoll_extended_t *ee, int epollfd) {
   // TODO: check for error, return bool or just log?
-  if (ee->fd == -1)
+  if (ee->fd == -1 || !ee->polling || epollfd == -1)
     return;
   struct epoll_event ev;
   ev.data.ptr = ee;
   ev.events = 0;
-  epoll_ctl(epollfd, EPOLL_CTL_DEL, ee->fd, &ev);  // TODO: check for error
+  if (epoll_ctl(epollfd, EPOLL_CTL_DEL, ee->fd, &ev) == -1)
+    EPOLL_FATAL("EPOLL_CTL_DEL", errno);
   ee->fd = -1;
+  ee->polling = false;
 }
 
 /*
@@ -362,9 +376,11 @@ static bool wake(pcontext_t *ctx) {
 
 // part2: make OS call without lock held
 static inline void wake_notify(pcontext_t *ctx) {
+  if (ctx->proactor->eventfd == -1)
+    return;
   uint64_t increment = 1;
-  int err = write(ctx->proactor->eventfd, &increment, sizeof(uint64_t));
-  (void)err;  // TODO: check for error
+  if (write(ctx->proactor->eventfd, &increment, sizeof(uint64_t)) != sizeof(uint64_t))
+    EPOLL_FATAL("setting eventfd", errno);
 }
 
 // call with no locks
@@ -407,6 +423,7 @@ static void psocket_init(psocket_t* ps, pn_proactor_t* p, pn_listener_t *listene
   ps->epoll_io.fd = -1;
   ps->epoll_io.type = listener ? LISTENER_IO : PCONNECTION_IO;
   ps->epoll_io.wanted = 0;
+  ps->epoll_io.polling = false;
   ps->proactor = p;
   ps->listener = listener;
   ps->sockfd = -1;
@@ -540,7 +557,8 @@ static void rearm(pn_proactor_t *p, epoll_extended_t *ee) {
   struct epoll_event ev;
   ev.data.ptr = ee;
   ev.events = ee->wanted | EPOLLONESHOT;
-  epoll_ctl(p->epollfd, EPOLL_CTL_MOD, ee->fd, &ev);  // TODO: check for error
+  if (epoll_ctl(p->epollfd, EPOLL_CTL_MOD, ee->fd, &ev) == -1)
+    EPOLL_FATAL("arming polled file descriptor", errno);
 }
 
 // ========================================================================
@@ -1007,6 +1025,7 @@ static void pconnection_start(pconnection_t *pc) {
   epoll_extended_t *ee = &pc->psocket.epoll_io;
   ee->fd = pc->psocket.sockfd;
   ee->wanted = EPOLLIN | EPOLLOUT;
+  ee->polling = false;
   start_polling(ee, efd);  // TODO: check for error
 }
 
@@ -1172,6 +1191,7 @@ void pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *addr, in
         ps->sockfd = fd;
         ps->epoll_io.fd = fd;
         ps->epoll_io.wanted = EPOLLIN;
+        ps->epoll_io.polling = false;
         start_polling(&ps->epoll_io, ps->proactor->epollfd);  // TODO: check for error
       }
     }
@@ -1413,6 +1433,7 @@ pn_proactor_t *pn_proactor() {
           p->epoll_wake.fd = p->eventfd;
           p->epoll_wake.type = WAKE;
           p->epoll_wake.wanted = EPOLLIN;
+          p->epoll_wake.polling = false;
           start_polling(&p->epoll_wake, p->epollfd);  // TODO: check for error
           return p;
         }
@@ -1429,7 +1450,9 @@ pn_proactor_t *pn_proactor() {
 void pn_proactor_free(pn_proactor_t *p) {
   //  No competing threads, not even a pending timer
   close(p->epollfd);
+  p->epollfd = -1;
   close(p->eventfd);
+  p->eventfd = -1;
   ptimer_finalize(&p->timer);
   while (p->contexts) {
     pcontext_t *ctx = p->contexts;


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


[27/50] [abbrv] qpid-proton git commit: NO-JIRA: Updated INSTALL.md ruby requirements for fedora >=25

Posted by ac...@apache.org.
NO-JIRA: Updated INSTALL.md ruby requirements for fedora >=25


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

Branch: refs/heads/go1
Commit: ec1d1a3fde6634b1f3aeffd3260b832812898d5c
Parents: 33609f5
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 24 20:10:33 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 20:10:33 2017 -0400

----------------------------------------------------------------------
 INSTALL.md | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec1d1a3f/INSTALL.md
----------------------------------------------------------------------
diff --git a/INSTALL.md b/INSTALL.md
index a4803ef..8de93fe 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -24,6 +24,7 @@ package for that language:
     $ yum install swig          # Required for all bindings
     $ yum install python-devel                               # Python
     $ yum install ruby-devel rubygem-rspec rubygem-simplecov # Ruby
+    $ yum install rubygem-test-unit  # Ruby on fedora >= 25
     $ yum install pphp-devel                                 # PHP
     $ yum install perl-devel                                 # Perl
 


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


[05/50] [abbrv] qpid-proton git commit: PROTON-1460: epoll - thread safe use of driver on connection disconnect

Posted by ac...@apache.org.
PROTON-1460: epoll - thread safe use of driver on connection disconnect


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

Branch: refs/heads/go1
Commit: 19f345acce3748020c7b2f13b2f0937ed35170ec
Parents: 9c69b7d
Author: Clifford Jansen <cl...@apache.org>
Authored: Tue May 9 13:06:41 2017 -0700
Committer: Clifford Jansen <cl...@apache.org>
Committed: Tue May 9 13:07:56 2017 -0700

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 45 ++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/19f345ac/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index cea9a68..fae68e9 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -425,6 +425,8 @@ typedef struct pconnection_t {
   bool server;                /* accept, not connect */
   bool tick_pending;
   bool timer_armed;
+  bool queued_disconnect;     /* deferred from pn_proactor_disconnect() */
+  pn_condition_t *disconnect_condition;
   ptimer_t timer;  // TODO: review one timerfd per connectoin
   // Following values only changed by (sole) working context:
   uint32_t current_arm;  // active epoll io events
@@ -580,6 +582,8 @@ static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bo
   pc->wake_count = 0;
   pc->tick_pending = false;
   pc->timer_armed = false;
+  pc->queued_disconnect = false;
+  pc->disconnect_condition = NULL;
 
   pc->current_arm = 0;
   pc->connected = false;
@@ -609,6 +613,7 @@ static void pconnection_final_free(pconnection_t *pc) {
   if (pc->addrinfo) {
     freeaddrinfo(pc->addrinfo);
   }
+  pn_condition_free(pc->disconnect_condition);
   pn_incref(pc);                /* Make sure we don't do a circular free */
   pn_connection_driver_destroy(&pc->driver);
   pn_decref(pc);
@@ -707,7 +712,7 @@ static inline void pconnection_rearm(pconnection_t *pc) {
 }
 
 static inline bool pconnection_work_pending(pconnection_t *pc) {
-  if (pc->new_events || pc->wake_count || pc->tick_pending)
+  if (pc->new_events || pc->wake_count || pc->tick_pending || pc->queued_disconnect)
     return true;
   if (!pc->read_blocked && !pconnection_rclosed(pc))
     return true;
@@ -823,6 +828,16 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
 
  retry:
 
+  if (pc->queued_disconnect) {  // From pn_proactor_disconnect()
+    pc->queued_disconnect = false;
+    if (!pc->context.closing) {
+      if (pc->disconnect_condition) {
+        pn_condition_copy(pn_transport_condition(pc->driver.transport), pc->disconnect_condition);
+      }
+      pn_connection_driver_close(&pc->driver);
+    }
+  }
+
   if (pconnection_has_event(pc)) {
     unlock(&pc->context.mutex);
     return &pc->batch;
@@ -1731,16 +1746,29 @@ void pn_proactor_disconnect(pn_proactor_t *p, pn_condition_t *cond) {
   bool notify = false;
   for (ctx = disconnecting_pcontexts; ctx; ctx = ctx ? ctx->next : NULL) {
     bool do_free = false;
+    bool ctx_notify = true;
     pmutex *ctx_mutex = NULL;
     pconnection_t *pc = pcontext_pconnection(ctx);
     if (pc) {
       ctx_mutex = &pc->context.mutex;
       lock(ctx_mutex);
       if (!ctx->closing) {
-        if (cond) {
-          pn_condition_copy(pn_transport_condition(pc->driver.transport), cond);
+        if (ctx->working) {
+          // Must defer
+          pc->queued_disconnect = true;
+          if (cond) {
+            if (!pc->disconnect_condition)
+              pc->disconnect_condition = pn_condition();
+            pn_condition_copy(pc->disconnect_condition, cond);
+          }
+        }
+        else {
+          // No conflicting working context.
+          if (cond) {
+            pn_condition_copy(pn_transport_condition(pc->driver.transport), cond);
+          }
+          pn_connection_driver_close(&pc->driver);
         }
-        pn_connection_driver_close(&pc->driver);
       }
     } else {
       pn_listener_t *l = pcontext_listener(ctx);
@@ -1758,16 +1786,15 @@ void pn_proactor_disconnect(pn_proactor_t *p, pn_condition_t *cond) {
     lock(&p->context.mutex);
     if (--ctx->disconnect_ops == 0) {
       do_free = true;
-      ctx = NULL;
+      ctx_notify = false;
       if (--p->disconnects_pending == 0 && !p->contexts) {
         p->inactive = true;
         notify = wake(&p->context);
       }
     } else {
       // If initiating the close, wake the pcontext to do the free.
-      if (ctx)
-        if (!wake(ctx))
-          ctx = NULL;  // Wake already pending.
+      if (ctx_notify)
+        ctx_notify = wake(ctx);
     }
     unlock(&p->context.mutex);
     unlock(ctx_mutex);
@@ -1776,7 +1803,7 @@ void pn_proactor_disconnect(pn_proactor_t *p, pn_condition_t *cond) {
       if (pc) pconnection_final_free(pc);
       else listener_final_free(pcontext_listener(ctx));
     } else {
-      if (ctx)
+      if (ctx_notify)
         wake_notify(ctx);
     }
   }


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


[02/50] [abbrv] qpid-proton git commit: PROTON-1460: epoll - don't issue wake events after transport closed

Posted by ac...@apache.org.
PROTON-1460: epoll - don't issue wake events after transport closed

The application may have deleted resources associated with the connection
after PN_TRANSPORT_CLOSED, so we should not issue PN_CONNECTION_WAKE even
if there is a wake call concurrently with closing the connection.


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

Branch: refs/heads/go1
Commit: 941c7d66be683217593d998be7c1dd91b46886a9
Parents: 4b33c42
Author: Alan Conway <ac...@redhat.com>
Authored: Mon May 8 20:20:57 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon May 8 20:20:57 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 13 ++++++-------
 proton-c/src/tests/proactor.c | 18 ++++++++++++++++--
 2 files changed, 22 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/941c7d66/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 3b71eac..9867cf8 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -634,7 +634,7 @@ static void pconnection_cleanup(pconnection_t *pc) {
 }
 
 // Call with lock held or from forced_shutdown
-void pconnection_begin_close(pconnection_t *pc) {
+static void pconnection_begin_close(pconnection_t *pc) {
   if (!pc->context.closing) {
     pc->context.closing = true;
     stop_polling(&pc->psocket.epoll_io, pc->psocket.proactor->epollfd);
@@ -736,7 +736,7 @@ static void pconnection_done(pconnection_t *pc) {
   pc->hog_count = 0;
   if (pconnection_has_event(pc) || pconnection_work_pending(pc)) {
     notify = wake(&pc->context);
-  } else if (pconnection_rclosed(pc) && pn_connection_driver_finished(&pc->driver)) {
+  } else if (pn_connection_driver_finished(&pc->driver)) {
     pconnection_begin_close(pc);
     if (pconnection_is_final(pc)) {
       unlock(&pc->context.mutex);
@@ -840,15 +840,14 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
     unlock(&pc->context.mutex);
     return &pc->batch;
   }
-
+  bool closed = pconnection_rclosed(pc) && pconnection_wclosed(pc);
   if (pc->wake_count) {
-    waking = true;
+    waking = !closed;
     pc->wake_count = 0;
   }
   if (pc->tick_pending) {
     pc->tick_pending = false;
-    if (!(pconnection_rclosed(pc) && pconnection_wclosed(pc)))
-      tick_required = true;
+    tick_required = !closed;
   }
 
   if (pc->new_events) {
@@ -956,7 +955,7 @@ static pn_event_batch_t *pconnection_process(pconnection_t *pc, uint32_t events,
 
   pc->context.working = false;
   pc->hog_count = 0;
-  if (pconnection_rclosed(pc) && pn_connection_driver_finished(&pc->driver)) {
+  if (pn_connection_driver_finished(&pc->driver)) {
     pconnection_begin_close(pc);
     if (pconnection_is_final(pc)) {
       unlock(&pc->context.mutex);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/941c7d66/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index 892ab2d..0a6df71 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -294,7 +294,7 @@ static pn_event_type_t open_wake_handler(test_t *t, pn_event_t *e) {
 
 /* Test waking up a connection that is idle */
 static void test_connection_wake(test_t *t) {
-  proactor_test_t pts[] =  { { open_wake_handler }, { common_handler } };
+  proactor_test_t pts[] =  { { open_wake_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
   pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
   test_port_t port = test_port(localhost);          /* Hold a port */
@@ -310,8 +310,22 @@ static void test_connection_wake(test_t *t) {
   pn_connection_wake(c);
   TEST_ETYPE_EQUAL(t, PN_CONNECTION_WAKE, PROACTOR_TEST_RUN(pts));
   TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts));
+  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts)); /* Both ends */
   /* The pn_connection_t is still valid so wake is legal but a no-op */
-  pn_connection_wake(c);
+  TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, PROACTOR_TEST_RUN(pts));
+  TEST_ETYPE_EQUAL(t, PN_EVENT_NONE, PROACTOR_TEST_GET(pts)); /* No more wake */
+
+  /* Verify we don't get a wake after close even if they happen together */
+  pn_connection_t *c2 = pn_connection();
+  pn_proactor_connect(client, c2, port.host_port);
+  TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, PROACTOR_TEST_RUN(pts));
+  pn_connection_wake(c2);
+  pn_proactor_disconnect(client, NULL);
+  pn_connection_wake(c2);
+
+  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, proactor_test_run(&pts[0], 1));
+  TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, proactor_test_run(&pts[0], 1));
+  TEST_ETYPE_EQUAL(t, PN_EVENT_NONE, proactor_test_get(&pts[0], 1)); /* No late wake */
 
   PROACTOR_TEST_FREE(pts);
   /* The pn_connection_t is still valid so wake is legal but a no-op */


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


[22/50] [abbrv] qpid-proton git commit: PROTON-1288: allocate extra storage with pn_message for internal use

Posted by ac...@apache.org.
PROTON-1288: allocate extra storage with pn_message for internal use

Allow extra space to be allocated in the same block used by pn_message_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/860b3229
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/860b3229
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/860b3229

Branch: refs/heads/go1
Commit: 860b32291fa31c343cc3dad63524a36ce9082a9c
Parents: d588798
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 17 13:43:33 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 14:38:25 2017 -0400

----------------------------------------------------------------------
 proton-c/include/proton/message.h | 11 ++++++++
 proton-c/src/core/max_align.h     | 47 ++++++++++++++++++++++++++++++++++
 proton-c/src/core/message.c       | 24 +++++++++++++++--
 3 files changed, 80 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/860b3229/proton-c/include/proton/message.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/message.h b/proton-c/include/proton/message.h
index 5c310b0..4f71db2 100644
--- a/proton-c/include/proton/message.h
+++ b/proton-c/include/proton/message.h
@@ -744,6 +744,17 @@ PN_EXTERN int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size);
  */
 PN_EXTERN int pn_message_data(pn_message_t *msg, pn_data_t *data);
 
+/** @cond INTERNAL @{ */
+
+/** Construct a message with extra storage */
+PN_EXTERN pn_message_t * pn_message_with_extra(size_t extra);
+
+/** Pointer to extra space allocated by pn_message_with_extra(). */
+PN_EXTERN void* pn_message_get_extra(pn_message_t *msg);
+
+/** @} */
+
+
 /** @}
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/860b3229/proton-c/src/core/max_align.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/max_align.h b/proton-c/src/core/max_align.h
new file mode 100644
index 0000000..ff9a6e5
--- /dev/null
+++ b/proton-c/src/core/max_align.h
@@ -0,0 +1,47 @@
+#ifndef MAX_ALIGN_H
+#define MAX_ALIGN_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 <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __STDC_VERSION__ >= 201112
+/* Use standard max_align_t for alignment on c11 */
+typedef max_align_t pn_max_align_t;
+#else
+/* Align on a union of likely largest types for older compilers */
+typedef union pn_max_align_t {
+  uint64_t i;
+  long double d;
+  void *v;
+  void (*fp)(void);
+} pn_max_align_t;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MAX_ALIGN_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/860b3229/proton-c/src/core/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/message.c b/proton-c/src/core/message.c
index f2fb20e..ecf8f43 100644
--- a/proton-c/src/core/message.c
+++ b/proton-c/src/core/message.c
@@ -20,6 +20,8 @@
  */
 
 #include "platform/platform_fmt.h"
+
+#include "max_align.h"
 #include "protocol.h"
 #include "util.h"
 
@@ -303,10 +305,10 @@ int pn_message_inspect(void *obj, pn_string_t *dst)
 #define pn_message_hashcode NULL
 #define pn_message_compare NULL
 
-pn_message_t *pn_message()
+static pn_message_t *pni_message_new(size_t size)
 {
   static const pn_class_t clazz = PN_CLASS(pn_message);
-  pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, sizeof(pn_message_t));
+  pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, size);
   msg->durable = false;
   msg->priority = PN_DEFAULT_PRIORITY;
   msg->ttl = 0;
@@ -337,6 +339,24 @@ pn_message_t *pn_message()
   return msg;
 }
 
+pn_message_t *pn_message() {
+  return pni_message_new(sizeof(pn_message_t));
+}
+
+/* Maximally aligned message to make extra storage safe for any type */
+typedef union {
+  pn_message_t m;
+  pn_max_align_t a;
+}  pni_aligned_message_t;
+
+pn_message_t *pn_message_with_extra(size_t extra) {
+  return pni_message_new(sizeof(pni_aligned_message_t) + extra);
+}
+
+void *pn_message_get_extra(pn_message_t *m) {
+  return ((char*)m) + sizeof(pni_aligned_message_t);
+}
+
 void pn_message_free(pn_message_t *msg)
 {
   pn_free(msg);


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


[12/50] [abbrv] qpid-proton git commit: PROTON-1479: Fix scheduled_send examples to send and close in a safe context

Posted by ac...@apache.org.
PROTON-1479: Fix scheduled_send examples to send and close in a safe 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/a22b1789
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/a22b1789
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/a22b1789

Branch: refs/heads/go1
Commit: a22b17896ab0bd0a065b1718a5bbbedc1eeca229
Parents: 2b5cfc8
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed May 3 23:42:56 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri May 12 18:34:42 2017 -0400

----------------------------------------------------------------------
 examples/cpp/scheduled_send.cpp    | 11 ++++--
 examples/cpp/scheduled_send_03.cpp | 62 +++++++++++++++++++++++----------
 2 files changed, 52 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a22b1789/examples/cpp/scheduled_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send.cpp b/examples/cpp/scheduled_send.cpp
index ef6cd27..de04c3b 100644
--- a/examples/cpp/scheduled_send.cpp
+++ b/examples/cpp/scheduled_send.cpp
@@ -23,6 +23,7 @@
 
 #include <proton/container.hpp>
 #include <proton/default_container.hpp>
+#include <proton/event_loop.hpp>
 #include <proton/message.hpp>
 #include <proton/messaging_handler.hpp>
 #include <proton/sender.hpp>
@@ -39,6 +40,7 @@ class scheduled_sender : public proton::messaging_handler {
     std::string url;
     proton::sender sender;
     proton::duration interval, timeout;
+    proton::event_loop* event_loop;
     bool ready, canceled;
 
   public:
@@ -51,12 +53,15 @@ class scheduled_sender : public proton::messaging_handler {
         canceled(false)         // Canceled.
     {}
 
+    // The awkward looking double lambda is necessary because the scheduled lambdas run in the container context
+    // and must arrange lambdas for send and close to happen in the connection context.
     void on_container_start(proton::container &c) OVERRIDE {
         sender = c.open_sender(url);
+        event_loop = &proton::make_thread_safe(sender).get()->event_loop();
         // Call this->cancel after timeout.
-        c.schedule(timeout, [this]() { this->cancel(); });
+        c.schedule(timeout, [this]() { this->event_loop->inject( [this]() { this->cancel(); }); });
          // Start regular ticks every interval.
-        c.schedule(interval, [this]() { this->tick(); });
+        c.schedule(interval, [this]() { this->event_loop->inject( [this]() { this->tick(); }); });
     }
 
     void cancel() {
@@ -67,7 +72,7 @@ class scheduled_sender : public proton::messaging_handler {
     void tick() {
         // Schedule the next tick unless we have been cancelled.
         if (!canceled)
-            sender.container().schedule(interval, [this]() { this->tick(); });
+            sender.container().schedule(interval, [this]() { this->event_loop->inject( [this]() { this->tick(); }); });
         if (sender.credit() > 0) // Only send if we have credit
             send();
         else

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a22b1789/examples/cpp/scheduled_send_03.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send_03.cpp b/examples/cpp/scheduled_send_03.cpp
index 92e5767..d106d29 100644
--- a/examples/cpp/scheduled_send_03.cpp
+++ b/examples/cpp/scheduled_send_03.cpp
@@ -25,6 +25,7 @@
 #include <proton/connection.hpp>
 #include <proton/default_container.hpp>
 #include <proton/duration.hpp>
+#include <proton/event_loop.hpp>
 #include <proton/function.hpp>
 #include <proton/message.hpp>
 #include <proton/messaging_handler.hpp>
@@ -41,24 +42,42 @@
 class scheduled_sender : public proton::messaging_handler {
   private:
     std::string url;
-    proton::sender sender;
     proton::duration interval, timeout;
+    proton::event_loop *event_loop;
     bool ready, canceled;
 
+    struct cancel_fn : public proton::void_function0 {
+        scheduled_sender* parent;
+        proton::sender sender;
+        cancel_fn(): parent(0) {}
+        cancel_fn(scheduled_sender& ss, proton::sender& s) : parent(&ss), sender(s) {}
+        void operator()() { if (parent) parent->cancel(sender); }
+    };
+
     struct tick_fn : public proton::void_function0 {
+        scheduled_sender* parent;
+        proton::sender sender;
+        tick_fn(): parent(0) {}
+        tick_fn(scheduled_sender& ss, proton::sender& s) : parent(&ss), sender(s) {}
+        void operator()() { if (parent) parent->tick(sender); }
+    };
+
+    struct defer_cancel_fn : public proton::void_function0 {
         scheduled_sender& parent;
-        tick_fn(scheduled_sender& ss) : parent(ss) {}
-        void operator()() { parent.tick(); }
+        defer_cancel_fn(scheduled_sender& ss) : parent(ss) {}
+        void operator()() { parent.event_loop->inject(parent.do_cancel); }
     };
 
-    struct cancel_fn : public proton::void_function0 {
+    struct defer_tick_fn : public proton::void_function0 {
         scheduled_sender& parent;
-        cancel_fn(scheduled_sender& ss) : parent(ss) {}
-        void operator()() { parent.cancel(); }
+        defer_tick_fn(scheduled_sender& ss) : parent(ss) {}
+        void operator()() { parent.event_loop->inject(parent.do_tick); }
     };
 
     tick_fn do_tick;
     cancel_fn do_cancel;
+    defer_tick_fn defer_tick;
+    defer_cancel_fn defer_cancel;
 
   public:
 
@@ -68,37 +87,44 @@ class scheduled_sender : public proton::messaging_handler {
         timeout(int(t*proton::duration::SECOND.milliseconds())), // Cancel after timeout.
         ready(true),            // Ready to send.
         canceled(false),         // Canceled.
-        do_tick(*this),
-        do_cancel(*this)
+        defer_tick(*this),
+        defer_cancel(*this)
     {}
 
     void on_container_start(proton::container &c) OVERRIDE {
-        sender = c.open_sender(url);
-        c.schedule(timeout, do_cancel); // Call this->cancel after timeout.
-        c.schedule(interval, do_tick); // Start regular ticks every interval.
+        c.open_sender(url);
+    }
+
+    void on_sender_open(proton::sender & s) OVERRIDE {
+        event_loop = &proton::make_thread_safe(s).get()->event_loop();
+
+        do_cancel = cancel_fn(*this, s);
+        do_tick = tick_fn(*this, s);
+        s.container().schedule(timeout, defer_cancel); // Call this->cancel after timeout.
+        s.container().schedule(interval, defer_tick); // Start regular ticks every interval.
     }
 
-    void cancel() {
+    void cancel(proton::sender& sender) {
         canceled = true;
         sender.connection().close();
     }
 
-    void tick() {
+    void tick(proton::sender& sender) {
         if (!canceled) {
-            sender.container().schedule(interval, do_tick); // Next tick
+            sender.container().schedule(interval, defer_tick); // Next tick
             if (sender.credit() > 0) // Only send if we have credit
-                send();
+                send(sender);
             else
                 ready = true; // Set the ready flag, send as soon as we get credit.
         }
     }
 
-    void on_sendable(proton::sender &) OVERRIDE {
+    void on_sendable(proton::sender &sender) OVERRIDE {
         if (ready)              // We have been ticked since the last send.
-            send();
+            send(sender);
     }
 
-    void send() {
+    void send(proton::sender& sender) {
         std::cout << "send" << std::endl;
         sender.send(proton::message("ping"));
         ready = false;


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


[40/50] [abbrv] qpid-proton git commit: PROTON-1495: c proactor error naming and formatting

Posted by ac...@apache.org.
PROTON-1495: c proactor error naming and formatting

Use consistent condition name "proton:io" for IO-related error conditions.
Consistent error formmatting for proactor implementations
receive.c example minor fix - missing return code


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

Branch: refs/heads/go1
Commit: ad52e3abb49da97436269ee78c07aba20ccaf742
Parents: 0850526
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jun 1 15:42:33 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jun 7 09:59:29 2017 -0400

----------------------------------------------------------------------
 examples/c/proactor/receive.c             |  1 +
 proton-c/src/proactor/epoll.c             |  5 ++---
 proton-c/src/proactor/libuv.c             | 13 +++++--------
 proton-c/src/proactor/proactor-internal.c | 10 ++++++++++
 proton-c/src/proactor/proactor-internal.h | 16 +++++++++++++++-
 5 files changed, 33 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ad52e3ab/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index ddf0a35..1b9e3f9 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -184,4 +184,5 @@ int main(int argc, char **argv) {
   pn_proactor_connect(app.proactor, pn_connection(), addr);
   run(&app);
   pn_proactor_free(app.proactor);
+  return exit_code;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ad52e3ab/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 3e5327e..3a0ea29 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -245,7 +245,6 @@ pn_timestamp_t pn_i_now2(void)
 // Proactor common code
 // ========================================================================
 
-const char *COND_NAME = "proactor";
 const char *AMQP_PORT = "5672";
 const char *AMQP_PORT_NAME = "amqp";
 
@@ -586,13 +585,13 @@ static void psocket_error(psocket_t *ps, int err, const char* what) {
   if (!ps->listener) {
     pn_connection_driver_t *driver = &psocket_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",
+    pn_connection_driver_errorf(driver, PNI_IO_CONDITION, "%s %s:%s: %s",
                                 what, ps->host, ps->port,
                                 strerror(err));
     pn_connection_driver_close(driver);
   } else {
     pn_listener_t *l = psocket_listener(ps);
-    pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
+    pn_condition_format(l->condition, PNI_IO_CONDITION, "%s %s:%s: %s",
                         what, ps->host, ps->port,
                         strerror(err));
     listener_begin_close(l);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ad52e3ab/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index e632f10..a851c4e 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -456,9 +456,8 @@ static void pconnection_set_error(pconnection_t *pc, int err, const char* what)
   pn_connection_driver_t *driver = &pc->driver;
   pn_connection_driver_bind(driver); /* Make sure we are bound so errors will be reported */
   if (!pn_condition_is_set(pn_transport_condition(driver->transport))) {
-    pn_connection_driver_errorf(driver, uv_err_name(err), "%s %s:%s: %s",
-                                what, pc->addr.host, pc->addr.port,
-                                uv_strerror(err));
+    pni_proactor_set_cond(pn_transport_condition(driver->transport),
+                                what, pc->addr.host , pc->addr.port, uv_strerror(err));
   }
 }
 
@@ -473,9 +472,7 @@ static void pconnection_error(pconnection_t *pc, int err, const char* what) {
 static void listener_error_lh(pn_listener_t *l, int err, const char* what) {
   assert(err);
   if (!pn_condition_is_set(l->condition)) {
-    pn_condition_format(l->condition, uv_err_name(err), "%s %s:%s: %s",
-                        what, l->addr.host, l->addr.port,
-                        uv_strerror(err));
+    pni_proactor_set_cond(l->condition, what, l->addr.host, l->addr.port, uv_strerror(err));
   }
   listener_close_lh(l);
 }
@@ -659,11 +656,11 @@ static void leader_listen_lh(pn_listener_t *l) {
       err = 0;
     }
   }
-  /* Always put an OPEN event for symmetry, even if we immediately close with err */
-  pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_OPEN);
   if (err) {
     listener_error_lh(l, err, "listening on");
   }
+  /* Always put an OPEN event for symmetry, even if we have an error. */
+  pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_OPEN);
 }
 
 void pn_listener_free(pn_listener_t *l) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ad52e3ab/proton-c/src/proactor/proactor-internal.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/proactor-internal.c b/proton-c/src/proactor/proactor-internal.c
index af7b057..3525c71 100644
--- a/proton-c/src/proactor/proactor-internal.c
+++ b/proton-c/src/proactor/proactor-internal.c
@@ -34,6 +34,8 @@ static const char *AMQP_PORT_NAME = "amqp";
 static const char *AMQPS_PORT = "5671";
 static const char *AMQPS_PORT_NAME = "amqps";
 
+const char *PNI_IO_CONDITION = "proton:io";
+
 int pn_proactor_addr(char *buf, size_t len, const char *host, const char *port) {
   return snprintf(buf, len, "%s:%s", host ? host : "", port ? port : "");
 }
@@ -64,3 +66,11 @@ int pni_parse_addr(const char *addr, char *buf, size_t len, const char **host, c
   }
   return 0;
 }
+
+static inline const char *nonull(const char *str) { return str ? str : ""; }
+
+void pni_proactor_set_cond(
+  pn_condition_t *cond, const char *what, const char *host, const char *port, const char *msg)
+{
+  pn_condition_format(cond, PNI_IO_CONDITION, "%s - %s %s:%s", msg, what, nonull(host), nonull(port));
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ad52e3ab/proton-c/src/proactor/proactor-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/proactor-internal.h b/proton-c/src/proactor/proactor-internal.h
index 894cb5b..5307a45 100644
--- a/proton-c/src/proactor/proactor-internal.h
+++ b/proton-c/src/proactor/proactor-internal.h
@@ -22,8 +22,11 @@
 
 #include <proton/type_compat.h>
 #include <proton/import_export.h>
+#include <proton/condition.h>
 
-/*
+/* NOTE PNP_EXTERN is for use by proton-internal tests  */
+
+/**
  * Parse a pn_proactor_addr string, copy data into buf as necessary.
  * Set *host and *port to point to the host and port strings.
  *
@@ -34,4 +37,15 @@
  */
 PNP_EXTERN int pni_parse_addr(const char *addr, char *buf, size_t len, const char **host, const char **port);
 
+/**
+ * Condition name for error conditions related to proton-IO.
+ */
+extern const char *PNI_IO_CONDITION;
+
+/**
+ * Format a proactor error condition with message "<what> (<host>:<port>): <msg>"
+ */
+void pni_proactor_set_cond(
+  pn_condition_t *cond, const char *what, const char *msg, const char *host, const char *port);
+
 #endif // PROACTOR_NETADDR_INTERNAL_H


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


[11/50] [abbrv] qpid-proton git commit: PROTON-1476: Reinstate C++ scheduled_send tests and remove unused mt tests

Posted by ac...@apache.org.
PROTON-1476: Reinstate C++ scheduled_send tests and remove unused mt tests


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

Branch: refs/heads/go1
Commit: 2b5cfc817cbdc3dea496a3da9bb66a8f0e4ab000
Parents: 81ba5a3
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 12 11:59:01 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri May 12 12:02:42 2017 -0400

----------------------------------------------------------------------
 examples/cpp/example_test.py | 74 ++++++++-------------------------------
 1 file changed, 14 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2b5cfc81/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index a80ee5c..f9a0825 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -210,6 +210,20 @@ map{string(k1):int(42), symbol(k2):boolean(0)}
         self.maxDiff = None
         self.assertEqual(want, self.proc(["encode_decode"]).wait_exit())
 
+    def test_scheduled_send_03(self):
+        # Output should be a bunch of "send" lines but can't guarantee exactly how many.
+        out = self.proc(["scheduled_send_03", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
+        self.assertTrue(len(out) > 0);
+        self.assertEqual(["send"]*len(out), out)
+
+    def test_scheduled_send(self):
+        try:
+            out = self.proc(["scheduled_send", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
+            self.assertTrue(len(out) > 0);
+            self.assertEqual(["send"]*len(out), out)
+        except ProcError:       # File not found, not a C++11 build.
+            pass
+
 
 class ContainerExampleSSLTest(BrokerTestCase):
     """Run the SSL container examples, verify they behave as expected."""
@@ -273,65 +287,5 @@ Hello World!
             expect_found = (out.find(expect) >= 0)
             self.assertEqual(expect_found, True)
 
-    def test_scheduled_send_03(self):
-        # Output should be a bunch of "send" lines but can't guarantee exactly how many.
-        out = self.proc(["scheduled_send_03", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
-        self.assertTrue(len(out) > 0);
-        self.assertEqual(["send"]*len(out), out)
-
-    def test_scheduled_send(self):
-        try:
-            out = self.proc(["scheduled_send", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
-            self.assertTrue(len(out) > 0);
-            self.assertEqual(["send"]*len(out), out)
-        except ProcError:       # File not found, not a C++11 build.
-            pass
-
-
-class EngineTestCase(BrokerTestCase):
-    """Run selected clients to test a connction_engine broker."""
-
-    def test_helloworld(self):
-        self.assertEqual('Hello World!\n',
-                         self.proc(["helloworld", self.addr]).wait_exit())
-
-    def test_simple_send_recv(self):
-        self.assertEqual("all messages confirmed\n",
-                         self.proc(["simple_send", "-a", self.addr]).wait_exit())
-        self.assertEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
-
-    def test_simple_recv_send(self):
-        # Start receiver first, then run sender"""
-        recv = self.proc(["simple_recv", "-a", self.addr])
-        self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit())
-        self.assertEqual(recv_expect("simple_recv", self.addr), recv.wait_exit())
-
-
-    def test_simple_send_direct_recv(self):
-        with TestPort() as tp:
-            addr = "%s/examples" % tp.addr
-            recv = self.proc(["direct_recv", "-a", addr], "listening")
-            self.assertEqual("all messages confirmed\n",
-                             self.proc(["simple_send", "-a", addr]).wait_exit())
-            self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
-
-    def test_simple_recv_direct_send(self):
-        with TestPort() as tp:
-            addr = "%s/examples" % tp.addr
-            send = self.proc(["direct_send", "-a", tp.addr], "listening")
-            self.assertEqual(recv_expect("simple_recv", addr),
-                             self.proc(["simple_recv", "-a", addr]).wait_exit())
-            self.assertEqual("direct_send listening on %s\nall messages confirmed\n" % addr,
-                             send.wait_exit())
-
-    def test_request_response(self):
-        server = self.proc(["server", "-a", self.addr], "connected")
-        self.assertEqual(CLIENT_EXPECT,
-                         self.proc(["client", "-a", self.addr]).wait_exit())
-
-
-class MtBrokerTest(EngineTestCase):
-    broker_exe = "mt_broker"
-
 if __name__ == "__main__":
     unittest.main()


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


[16/50] [abbrv] qpid-proton git commit: PROTON-1480: Fix hello_world_direct example not to call listener::stop more than once

Posted by ac...@apache.org.
PROTON-1480: Fix hello_world_direct example not to call listener::stop more than once


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

Branch: refs/heads/go1
Commit: ed23beaf21e44e85f430b6811484f13e2b88ca7d
Parents: adb17eb
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue May 16 15:45:19 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Tue May 16 17:42:51 2017 -0400

----------------------------------------------------------------------
 examples/cpp/helloworld_direct.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ed23beaf/examples/cpp/helloworld_direct.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld_direct.cpp b/examples/cpp/helloworld_direct.cpp
index b3a1af8..9331587 100644
--- a/examples/cpp/helloworld_direct.cpp
+++ b/examples/cpp/helloworld_direct.cpp
@@ -46,23 +46,23 @@ class hello_world_direct : public proton::messaging_handler {
         c.open_sender(url);
     }
 
+    // Send one message and close sender
     void on_sendable(proton::sender &s) OVERRIDE {
         proton::message m("Hello World!");
         s.send(m);
         s.close();
     }
 
+    // Receive one message and stop listener
     void on_message(proton::delivery &, proton::message &m) OVERRIDE {
         std::cout << m.body() << std::endl;
+        listener.stop();
     }
 
+    // After receiving acknowledgement close connection
     void on_tracker_accept(proton::tracker &t) OVERRIDE {
         t.connection().close();
     }
-
-    void on_connection_close(proton::connection&) OVERRIDE {
-        listener.stop();
-    }
 };
 
 int main(int argc, char **argv) {


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


[03/50] [abbrv] qpid-proton git commit: PROTON-1460: epoll - remove un-necessary event_cache fields

Posted by ac...@apache.org.
PROTON-1460: epoll - remove un-necessary event_cache fields

The event_cache was required to work around bug PROTON-1407 in
collector_peek()/collector_next() but that is fixed since commit 7368c34


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

Branch: refs/heads/go1
Commit: bfa8a71e3161a0f687fbe4b0584d6dc0ab3ccae4
Parents: 941c7d6
Author: Alan Conway <ac...@redhat.com>
Authored: Tue May 9 11:34:58 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue May 9 11:34:58 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c | 37 +++++++++----------------------------
 1 file changed, 9 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bfa8a71e/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index 9867cf8..cea9a68 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -304,7 +304,6 @@ struct pn_proactor_t {
   pn_collector_t *collector;
   pcontext_t *contexts;         /* in-use contexts for PN_PROACTOR_INACTIVE and cleanup */
   epoll_extended_t epoll_wake;
-  pn_event_t *cached_event;
   pn_event_batch_t batch;
   size_t interrupts;            /* total pending interrupts */
   size_t deferred_interrupts;   /* interrupts for current batch */
@@ -434,7 +433,6 @@ typedef struct pconnection_t {
   bool write_blocked;
   bool disconnected;
   int hog_count; // thread hogging limiter
-  pn_event_t *cached_event;
   pn_event_batch_t batch;
   pn_connection_driver_t driver;
   struct pn_netaddr_t local, remote; /* Actual addresses */
@@ -448,7 +446,6 @@ struct pn_listener_t {
   pcontext_t context;
   pn_condition_t *condition;
   pn_collector_t *collector;
-  pn_event_t *cached_event;
   pn_event_batch_t batch;
   pn_record_t *attachments;
   void *listener_context;
@@ -502,15 +499,15 @@ static inline pconnection_t *batch_pconnection(pn_event_batch_t *batch) {
 }
 
 static inline bool pconnection_has_event(pconnection_t *pc) {
-  return (pc->cached_event || (pc->cached_event = pn_connection_driver_next_event(&pc->driver)));
+  return pn_connection_driver_has_event(&pc->driver);
 }
 
 static inline bool listener_has_event(pn_listener_t *l) {
-  return (l->cached_event || (l->cached_event = pn_collector_next(l->collector)));
+  return pn_collector_peek(l->collector);
 }
 
 static inline bool proactor_has_event(pn_proactor_t *p) {
-  return (p->cached_event || (p->cached_event = pn_collector_next(p->collector)));
+  return pn_collector_peek(p->collector);
 }
 
 static pn_event_t *log_event(void* p, pn_event_t *e) {
@@ -590,7 +587,6 @@ static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bo
   pc->write_blocked = true;
   pc->disconnected = false;
   pc->hog_count = 0;;
-  pc->cached_event = NULL;
   pc->batch.next_event = pconnection_batch_next;
 
   if (server) {
@@ -651,27 +647,18 @@ static void pconnection_forced_shutdown(pconnection_t *pc) {
   pc->timer.pending_count = 0;
   pc->context.wake_ops = 0;
   pn_connection_t *c = pc->driver.connection;
-  pn_collector_t *col = pn_connection_collector(c);
-  if (pc->cached_event != NULL) {
-    pn_collector_pop(col);
-    pc->cached_event = NULL;
-  }
-  pn_collector_release(col);
+  pn_collector_release(pn_connection_collector(c));
   assert(pconnection_is_final(pc));
   pconnection_cleanup(pc);
 }
 
 static pn_event_t *pconnection_batch_next(pn_event_batch_t *batch) {
   pconnection_t *pc = batch_pconnection(batch);
-  pn_event_t *e = NULL;
-  if (pconnection_has_event(pc))
-    e = pc->cached_event;
-  else if (pc->hog_count < HOG_MAX) {
+  pn_event_t *e = pn_connection_driver_next_event(&pc->driver);
+  if (!e && pc->hog_count < HOG_MAX) {
     pconnection_process(pc, 0, false, true);  // top up
-    if (pconnection_has_event(pc))
-      e = pc->cached_event;
+    e = pn_connection_driver_next_event(&pc->driver);
   }
-  pc->cached_event = NULL;
   return e;
 }
 
@@ -1293,10 +1280,7 @@ static pn_event_batch_t *listener_process(psocket_t *ps, uint32_t events) {
 static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
   pn_listener_t *l = batch_listener(batch);
   lock(&l->context.mutex);
-  pn_event_t *e = NULL;
-  if (listener_has_event(l))
-    e = l->cached_event;
-  l->cached_event = NULL;
+  pn_event_t *e = pn_collector_next(l->collector);
   if (e && pn_event_type(e) == PN_LISTENER_CLOSE)
     l->close_dispatched = true;
   unlock(&l->context.mutex);
@@ -1504,13 +1488,10 @@ static bool proactor_update_batch(pn_proactor_t *p) {
 
 static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
   pn_proactor_t *p = batch_proactor(batch);
-  pn_event_t *e = NULL;
   lock(&p->context.mutex);
   proactor_update_batch(p);
-  if (proactor_has_event(p))
-    e = p->cached_event;
+  pn_event_t *e = pn_collector_next(p->collector);
   unlock(&p->context.mutex);
-  p->cached_event = NULL;
   return log_event(p, e);
 }
 


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


[21/50] [abbrv] qpid-proton git commit: PROTON-1288: c++ hide proton::message implementation details

Posted by ac...@apache.org.
PROTON-1288: c++ hide proton::message implementation details

Hide extra book-keeping types in extra storage allocated with the pn_message_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/48a5e47a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/48a5e47a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/48a5e47a

Branch: refs/heads/go1
Commit: 48a5e47a09268ddb19f925d8f66301718f42b87a
Parents: 860b322
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 17 13:52:13 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 14:38:25 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/message.hpp     |  6 +-
 proton-c/bindings/cpp/src/message.cpp           | 74 +++++++++++++-------
 2 files changed, 52 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/48a5e47a/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index ff60c99..faf2f29 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -321,13 +321,11 @@ class message {
 
     /// @cond INTERNAL
   private:
+    struct impl;
     pn_message_t *pn_msg() const;
+    struct impl& impl() const;
 
     mutable pn_message_t *pn_msg_;
-    mutable value body_;
-    mutable property_map application_properties_;
-    mutable annotation_map message_annotations_;
-    mutable annotation_map delivery_annotations_;
 
     /// Decode the message corresponding to a delivery from a link.
     void decode(proton::delivery);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/48a5e47a/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index 59f8329..df7fae1 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -41,6 +41,32 @@
 
 namespace proton {
 
+struct message::impl {
+    value body_;
+    property_map application_properties_;
+    annotation_map message_annotations_;
+    annotation_map delivery_annotations_;
+
+    impl(pn_message_t *msg) {
+        body_.reset(pn_message_body(msg));
+    }
+
+    void clear() {
+        application_properties_.clear();
+        message_annotations_.clear();
+        delivery_annotations_.clear();
+    }
+
+  friend void swap(impl& x, impl& y) {
+      using std::swap;
+      swap(x.body_, y.body_);
+      swap(x.application_properties_, y.application_properties_);
+      swap(x.message_annotations_, y.message_annotations_);
+      swap(x.delivery_annotations_, y.delivery_annotations_);
+  }
+};
+
+
 message::message() : pn_msg_(0) {}
 message::message(const message &m) : pn_msg_(0) { *this = m; }
 
@@ -55,28 +81,31 @@ message& message::operator=(message&& m) {
 message::message(const value& x) : pn_msg_(0) { body() = x; }
 
 message::~message() {
-    // Workaround proton bug: Must release all refs to body before calling pn_message_free()
-    body_.reset();
-    pn_message_free(pn_msg_);
+    if (pn_msg_) {
+        impl().~impl();               // destroy in-place
+        pn_message_free(pn_msg_);
+    }
 }
 
 void swap(message& x, message& y) {
     using std::swap;
     swap(x.pn_msg_, y.pn_msg_);
-    swap(x.body_, y.body_);
-    swap(x.application_properties_, y.application_properties_);
-    swap(x.message_annotations_, y.message_annotations_);
-    swap(x.delivery_annotations_, y.delivery_annotations_);
+    swap(x.impl(), y.impl());
 }
 
 pn_message_t *message::pn_msg() const {
     if (!pn_msg_) {
-        pn_msg_ = pn_message();
-        body_.reset(pn_message_body(pn_msg_));
+        pn_msg_ = pn_message_with_extra(sizeof(struct message::impl));
+        // Construct impl in extra storage allocated with pn_msg_
+        new (pn_message_get_extra(pn_msg_)) struct message::impl(pn_msg_);
     }
     return pn_msg_;
 }
 
+struct message::impl& message::impl() const {
+    return *(struct message::impl*)pn_message_get_extra(pn_msg());
+}
+
 message& message::operator=(const message& m) {
     if (&m != this) {
         // TODO aconway 2015-08-10: more efficient pn_message_copy function
@@ -209,8 +238,8 @@ void message::inferred(bool b) { pn_message_set_inferred(pn_msg(), b); }
 
 void message::body(const value& x) { body() = x; }
 
-const value& message::body() const { pn_msg(); return body_; }
-value& message::body() { pn_msg(); return body_; }
+const value& message::body() const { return impl().body_; }
+value& message::body() { return impl().body_; }
 
 // MAP CACHING: the properties and annotations maps can either be encoded in the
 // pn_message pn_data_t structures OR decoded as C++ map members of the message
@@ -239,35 +268,35 @@ template<class M, class F> M& put_map(pn_message_t* msg, F get, M& map) {
 }
 
 message::property_map& message::properties() {
-    return get_map(pn_msg(), pn_message_properties, application_properties_);
+    return get_map(pn_msg(), pn_message_properties, impl().application_properties_);
 }
 
 const message::property_map& message::properties() const {
-    return get_map(pn_msg(), pn_message_properties, application_properties_);
+    return get_map(pn_msg(), pn_message_properties, impl().application_properties_);
 }
 
 
 message::annotation_map& message::message_annotations() {
-    return get_map(pn_msg(), pn_message_annotations, message_annotations_);
+    return get_map(pn_msg(), pn_message_annotations, impl().message_annotations_);
 }
 
 const message::annotation_map& message::message_annotations() const {
-    return get_map(pn_msg(), pn_message_annotations, message_annotations_);
+    return get_map(pn_msg(), pn_message_annotations, impl().message_annotations_);
 }
 
 
 message::annotation_map& message::delivery_annotations() {
-    return get_map(pn_msg(), pn_message_instructions, delivery_annotations_);
+    return get_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_);
 }
 
 const message::annotation_map& message::delivery_annotations() const {
-    return get_map(pn_msg(), pn_message_instructions, delivery_annotations_);
+    return get_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_);
 }
 
 void message::encode(std::vector<char> &s) const {
-    put_map(pn_msg(), pn_message_properties, application_properties_);
-    put_map(pn_msg(), pn_message_annotations, message_annotations_);
-    put_map(pn_msg(), pn_message_instructions, delivery_annotations_);
+    put_map(pn_msg(), pn_message_properties, impl().application_properties_);
+    put_map(pn_msg(), pn_message_annotations, impl().message_annotations_);
+    put_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_);
     size_t sz = std::max(s.capacity(), size_t(512));
     while (true) {
         s.resize(sz);
@@ -293,10 +322,7 @@ std::vector<char> message::encode() const {
 void message::decode(const std::vector<char> &s) {
     if (s.empty())
         throw error("message decode: no data");
-    application_properties_.clear();
-    message_annotations_.clear();
-    delivery_annotations_.clear();
-    assert(!s.empty());
+    impl().clear();
     check(pn_message_decode(pn_msg(), &s[0], s.size()));
 }
 


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


[42/50] [abbrv] qpid-proton git commit: PROTON-1495: c epoll use strerror_r() instead of unsafe strerr()

Posted by ac...@apache.org.
PROTON-1495: c epoll use strerror_r() instead of unsafe strerr()


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

Branch: refs/heads/go1
Commit: 8ef841c53dab1762fdbe1bc7058cc290f3a4f439
Parents: cb5996e
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Jun 7 13:22:13 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jun 7 13:22:13 2017 -0400

----------------------------------------------------------------------
 proton-c/src/proactor/epoll.c             | 39 +++++++++++++++++---------
 proton-c/src/proactor/libuv.c             |  6 ++--
 proton-c/src/proactor/proactor-internal.c |  5 +++-
 3 files changed, 31 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8ef841c5/proton-c/src/proactor/epoll.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/epoll.c b/proton-c/src/proactor/epoll.c
index b6d2bd0..0bb0b10 100644
--- a/proton-c/src/proactor/epoll.c
+++ b/proton-c/src/proactor/epoll.c
@@ -20,12 +20,14 @@
  */
 
 /* Enable POSIX features for pthread.h */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
 #endif
+/* Avoid GNU extensions, in particular the incompatible alternative strerror_r() */
+#undef _GNU_SOURCE
 
 #include "../core/log_private.h"
-#include "proactor-internal.h"
+#include "./proactor-internal.h"
 
 #include <proton/condition.h>
 #include <proton/connection_driver.h>
@@ -66,12 +68,23 @@
 // looking for pending wakes before a kernel call to epoll_wait(), or there
 // could be several eventfds with random assignment of wakeables.
 
+
+typedef char strerrorbuf[1024];      /* used for pstrerror message buffer */
+
+/* Like strerror_r but provide a default message if strerror_r fails */
+static void pstrerror(int err, strerrorbuf msg) {
+  int e = strerror_r(err, msg, sizeof(strerrorbuf));
+  if (e) snprintf(msg, sizeof(strerrorbuf), "unknown error %d", err);
+}
+
 /* Internal error, no recovery */
-#define EPOLL_FATAL(EXPR, SYSERRNO)                                   \
-  do {                                                                \
-    fprintf(stderr, "epoll proactor failure in %s:%d: %s: %s\n",      \
-            __FILE__, __LINE__ , #EXPR, strerror(SYSERRNO));          \
-    abort();                                                          \
+#define EPOLL_FATAL(EXPR, SYSERRNO)                                     \
+  do {                                                                  \
+    strerrorbuf msg;                                                    \
+    pstrerror((SYSERRNO), msg);                                         \
+    fprintf(stderr, "epoll proactor failure in %s:%d: %s: %s\n",        \
+            __FILE__, __LINE__ , #EXPR, msg);                           \
+    abort();                                                            \
   } while (0)
 
 // ========================================================================
@@ -580,18 +593,16 @@ static pn_event_t *log_event(void* p, pn_event_t *e) {
 }
 
 static void psocket_error(psocket_t *ps, int err, const char* what) {
+  strerrorbuf msg;
+  pstrerror(err, msg);
   if (!ps->listener) {
     pn_connection_driver_t *driver = &psocket_pconnection(ps)->driver;
     pn_connection_driver_bind(driver); /* Bind so errors will be reported */
-    pn_connection_driver_errorf(driver, PNI_IO_CONDITION, "%s %s:%s: %s",
-                                what, ps->host, ps->port,
-                                strerror(err));
+    pni_proactor_set_cond(pn_transport_condition(driver->transport), what, ps->host, ps->port, msg);
     pn_connection_driver_close(driver);
   } else {
     pn_listener_t *l = psocket_listener(ps);
-    pn_condition_format(l->condition, PNI_IO_CONDITION, "%s %s:%s: %s",
-                        what, ps->host, ps->port,
-                        strerror(err));
+    pni_proactor_set_cond(l->condition, what, ps->host, ps->port, msg);
     listener_begin_close(l);
   }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8ef841c5/proton-c/src/proactor/libuv.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/libuv.c b/proton-c/src/proactor/libuv.c
index a851c4e..cf3daab 100644
--- a/proton-c/src/proactor/libuv.c
+++ b/proton-c/src/proactor/libuv.c
@@ -455,10 +455,8 @@ static inline void pconnection_bad_connect(pconnection_t *pc, int err) {
 static void pconnection_set_error(pconnection_t *pc, int err, const char* what) {
   pn_connection_driver_t *driver = &pc->driver;
   pn_connection_driver_bind(driver); /* Make sure we are bound so errors will be reported */
-  if (!pn_condition_is_set(pn_transport_condition(driver->transport))) {
-    pni_proactor_set_cond(pn_transport_condition(driver->transport),
-                                what, pc->addr.host , pc->addr.port, uv_strerror(err));
-  }
+  pni_proactor_set_cond(pn_transport_condition(driver->transport),
+                        what, pc->addr.host , pc->addr.port, uv_strerror(err));
 }
 
 /* Set the error condition and close the driver. */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8ef841c5/proton-c/src/proactor/proactor-internal.c
----------------------------------------------------------------------
diff --git a/proton-c/src/proactor/proactor-internal.c b/proton-c/src/proactor/proactor-internal.c
index 3525c71..0c82573 100644
--- a/proton-c/src/proactor/proactor-internal.c
+++ b/proton-c/src/proactor/proactor-internal.c
@@ -72,5 +72,8 @@ static inline const char *nonull(const char *str) { return str ? str : ""; }
 void pni_proactor_set_cond(
   pn_condition_t *cond, const char *what, const char *host, const char *port, const char *msg)
 {
-  pn_condition_format(cond, PNI_IO_CONDITION, "%s - %s %s:%s", msg, what, nonull(host), nonull(port));
+  if (!pn_condition_is_set(cond)) { /* Preserve older error information */
+    pn_condition_format(cond, PNI_IO_CONDITION, "%s - %s %s:%s",
+                        msg, what, nonull(host), nonull(port));
+  }
 }


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


[39/50] [abbrv] qpid-proton git commit: PROTON-1495: move examples/exampletest.py to tools/py/proctest.py

Posted by ac...@apache.org.
PROTON-1495: move examples/exampletest.py to tools/py/proctest.py

It is not an example but part of our test framework.
Want to use it for non-example tests as well.


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

Branch: refs/heads/go1
Commit: 08505261f4008c43b2399cb4a72bd887bbadd7df
Parents: d480600
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jun 2 09:33:43 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jun 7 09:59:23 2017 -0400

----------------------------------------------------------------------
 config.sh.in                        |   2 +-
 examples/CMakeLists.txt             |   4 +-
 examples/c/proactor/example_test.py |   4 +-
 examples/cpp/example_test.py        |   4 +-
 examples/exampletest.py             | 193 -----------------------------
 tools/py/proctest.py                | 204 +++++++++++++++++++++++++++++++
 6 files changed, 211 insertions(+), 200 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/08505261/config.sh.in
----------------------------------------------------------------------
diff --git a/config.sh.in b/config.sh.in
index 72d4ea9..d9debd3 100755
--- a/config.sh.in
+++ b/config.sh.in
@@ -39,7 +39,7 @@ RUBY_BINDINGS=$PROTON_BINDINGS/ruby
 PERL_BINDINGS=$PROTON_BINDINGS/perl
 
 # Python
-COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/proton-c/bindings/python:$PROTON_HOME/examples
+COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/proton-c/bindings/python:$PROTON_HOME/tools/py
 export PYTHONPATH=$COMMON_PYPATH:$PYTHON_BINDINGS
 
 # PHP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/08505261/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 4d744d2..8a8327a 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -29,8 +29,8 @@ macro(set_search_path result)  # args after result are directories or search pat
   file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
 endmacro()
 
-# Some non-python examples use exampletest.py to drive their self-tests.
-set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_CURRENT_SOURCE_DIR}" "$ENV{PYTHON_PATH}")
+# Add the tools directory for the 'proctest' module
+set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_SOURCE_DIR}/tools/py" "$ENV{PYTHON_PATH}")
 set(EXAMPLE_ENV "PYTHONPATH=${EXAMPLE_PYTHONPATH}")
 
 add_subdirectory(c)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/08505261/examples/c/proactor/example_test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/example_test.py b/examples/c/proactor/example_test.py
index 38f7fc8..02bb1fd 100644
--- a/examples/c/proactor/example_test.py
+++ b/examples/c/proactor/example_test.py
@@ -20,7 +20,7 @@
 # This is a test script to run the examples and verify that they behave as expected.
 
 import unittest, sys, time
-from exampletest import *
+from proctest import *
 
 def python_cmd(name):
     dir = os.path.dirname(__file__)
@@ -49,7 +49,7 @@ class Broker(object):
                 raise ProcError(b, "broker crash")
             b.kill()
 
-class CExampleTest(ExampleTestCase):
+class CExampleTest(ProcTestCase):
 
     def test_send_receive(self):
         """Send first then receive"""

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/08505261/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 5773142..0ae929c 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -21,7 +21,7 @@
 
 import unittest
 import os, sys, socket, time, re, inspect
-from exampletest import *
+from proctest import *
 from  random import randrange
 from subprocess import Popen, PIPE, STDOUT, call
 from copy import copy
@@ -82,7 +82,7 @@ def ensureCanTestExtendedSASL():
     raise Skipped("Can't Test Extended SASL: Couldn't create auth db")
 
 
-class BrokerTestCase(ExampleTestCase):
+class BrokerTestCase(ProcTestCase):
     """
     ExampleTest that starts a broker in setUpClass and kills it in tearDownClass.
     Subclasses must set `broker_exe` class variable with the name of the broker executable.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/08505261/examples/exampletest.py
----------------------------------------------------------------------
diff --git a/examples/exampletest.py b/examples/exampletest.py
deleted file mode 100644
index 5c53616..0000000
--- a/examples/exampletest.py
+++ /dev/null
@@ -1,193 +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
-#
-
-# A test library to make it easy to run unittest tests that start,
-# monitor, and report output from sub-processes. In particular
-# it helps with starting processes that listen on random ports.
-
-import unittest
-import os, sys, socket, time, re, inspect, errno, threading
-from  random import randrange
-from subprocess import Popen, PIPE, STDOUT
-from copy import copy
-import platform
-from os.path import dirname as dirname
-
-DEFAULT_TIMEOUT=10
-
-class TestPort(object):
-    """Get an unused port using bind(0) and SO_REUSEADDR and hold it till close()"""
-    def __init__(self):
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.sock.bind(('127.0.0.1', 0)) # Testing exampless is local only
-        self.host, self.port = socket.getnameinfo(self.sock.getsockname(), 0)
-        self.addr = "%s:%s" % (self.host, self.port)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, *args):
-        self.close()
-
-    def close(self):
-        self.sock.close()
-
-class ProcError(Exception):
-    """An exception that captures failed process output"""
-    def __init__(self, proc, what="bad exit status"):
-        out = proc.out.strip()
-        if out:
-            out = "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^\n" % out
-        else:
-            out = ", no output)"
-        super(Exception, self, ).__init__(
-            "%s %s, code=%s%s" % (proc.args, what, getattr(proc, 'returncode', 'noreturn'), out))
-
-class NotFoundError(ProcError):
-    pass
-
-class Proc(Popen):
-    """A example process that stores its stdout and can scan it for a 'ready' pattern'"""
-
-    if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
-        vg_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
-    else:
-        vg_args = []
-
-    @property
-    def out(self):
-        self._out.seek(0)
-        # Normalize line endings, os.tmpfile() opens in binary mode.
-        return self._out.read().replace('\r\n','\n').replace('\r','\n')
-
-    def __init__(self, args, skip_valgrind=False, **kwargs):
-        """Start an example process"""
-        args = list(args)
-        if skip_valgrind:
-            self.args = args
-        else:
-            self.args = self.vg_args + args
-        self.kwargs = kwargs
-        self._out = os.tmpfile()
-        try:
-            Popen.__init__(self, self.args, stdout=self._out, stderr=STDOUT, **kwargs)
-        except OSError, e:
-            if e.errno == errno.ENOENT:
-                raise NotFoundError(self, str(e))
-            raise ProcError(self, str(e))
-        except Exception, e:
-            raise ProcError(self, str(e))
-
-    def kill(self):
-        try:
-            if self.poll() is None:
-                Popen.kill(self)
-        except:
-            pass                # Already exited.
-        return self.out
-
-    def wait_exit(self, timeout=DEFAULT_TIMEOUT, expect=0):
-        """Wait for process to exit, return output. Raise ProcError  on failure."""
-        t = threading.Thread(target=self.wait)
-        t.start()
-        t.join(timeout)
-        if self.poll() is None:      # Still running
-            self.kill()
-            raise ProcError(self, "still running after %ss" % timeout)
-        if expect is not None and self.poll() != expect:
-            raise ProcError(self)
-        return self.out
-
-    def wait_re(self, regexp, timeout=DEFAULT_TIMEOUT):
-        """
-        Wait for regexp to appear in the output, returns the re.search match result.
-        The target process should flush() important output to ensure it appears.
-        """
-        if timeout:
-            deadline = time.time() + timeout
-        while timeout is None or time.time() < deadline:
-            match = re.search(regexp, self.out)
-            if match:
-                return match
-            time.sleep(0.01)    # Not very efficient
-        raise ProcError(self, "gave up waiting for '%s' after %ss" % (regexp, timeout))
-
-def _tc_missing(attr):
-    return not hasattr(unittest.TestCase, attr)
-
-class TestCase(unittest.TestCase):
-    """
-    Roughly provides setUpClass() and tearDownClass() and other features missing
-    in python 2.6. If subclasses override setUp() or tearDown() they *must*
-    call the superclass.
-    """
-
-    if _tc_missing('setUpClass') and _tc_missing('tearDownClass'):
-
-        @classmethod
-        def setUpClass(cls):
-            pass
-
-        @classmethod
-        def tearDownClass(cls):
-            pass
-
-        def setUp(self):
-            super(TestCase, self).setUp()
-            cls = type(self)
-            if not hasattr(cls, '_setup_class_count'): # First time
-                def is_test(m):
-                    return inspect.ismethod(m) and m.__name__.startswith('test_')
-                cls._setup_class_count = len(inspect.getmembers(cls, predicate=is_test))
-                cls.setUpClass()
-
-        def tearDown(self):
-            self.assertTrue(self._setup_class_count > 0)
-            self._setup_class_count -=  1
-            if self._setup_class_count == 0:
-                type(self).tearDownClass()
-            super(TestCase, self).tearDown()
-
-    if _tc_missing('assertIn'):
-        def assertIn(self, a, b):
-            self.assertTrue(a in b, "%r not in %r" % (a, b))
-
-    if _tc_missing('assertMultiLineEqual'):
-        def assertMultiLineEqual(self, a, b):
-            self.assertEqual(a, b)
-
-class ExampleTestCase(TestCase):
-    """TestCase that manages started processes"""
-    def setUp(self):
-        super(ExampleTestCase, self).setUp()
-        self.procs = []
-
-    def tearDown(self):
-        for p in self.procs:
-            p.kill()
-        super(ExampleTestCase, self).tearDown()
-
-    def proc(self, *args, **kwargs):
-        p = Proc(*args, **kwargs)
-        self.procs.append(p)
-        return p
-
-if __name__ == "__main__":
-    unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/08505261/tools/py/proctest.py
----------------------------------------------------------------------
diff --git a/tools/py/proctest.py b/tools/py/proctest.py
new file mode 100644
index 0000000..ba83c7d
--- /dev/null
+++ b/tools/py/proctest.py
@@ -0,0 +1,204 @@
+#
+# 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
+#
+
+"""Unit test library to simplify tests that start, monitor, check and report
+output from sub-processes. Provides safe port allocation for processes that
+listen on a port. Allows executables to be run under a debugging tool like
+valgrind.
+"""
+
+import unittest
+import os, sys, socket, time, re, inspect, errno, threading
+from  random import randrange
+from subprocess import Popen, PIPE, STDOUT
+from copy import copy
+import platform
+from os.path import dirname as dirname
+
+DEFAULT_TIMEOUT=10
+
+class TestPort(object):
+    """Get an unused port using bind(0) and SO_REUSEADDR and hold it till close()
+    Can be used as `with TestPort() as tp:` Provides tp.host, tp.port and tp.addr
+    (a "host:port" string)
+    """
+    def __init__(self):
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self.sock.bind(('127.0.0.1', 0)) # Testing exampless is local only
+        self.host, self.port = socket.getnameinfo(self.sock.getsockname(), 0)
+        self.addr = "%s:%s" % (self.host, self.port)
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        self.close()
+
+    def close(self):
+        self.sock.close()
+
+class ProcError(Exception):
+    """An exception that displays failed process output"""
+    def __init__(self, proc, what="bad exit status"):
+        self.out = proc.out.strip()
+        if self.out:
+            msgtail = "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^\n" % self.out
+        else:
+            msgtail = ", no output"
+        super(Exception, self, ).__init__(
+            "%s %s, code=%s%s" % (proc.args, what, getattr(proc, 'returncode', 'noreturn'), msgtail))
+
+class NotFoundError(ProcError):
+    pass
+
+class Proc(Popen):
+    """Subclass of suprocess.Popen that stores its output and can scan it for a
+    'ready' pattern' Use self.out to access output (combined stdout and stderr).
+    You can't set the Popen stdout and stderr arguments, they will be overwritten.
+    """
+
+    if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
+        vg_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
+    else:
+        vg_args = []
+
+    @property
+    def out(self):
+        self._out.seek(0)
+        # Normalize line endings, os.tmpfile() opens in binary mode.
+        return self._out.read().replace('\r\n','\n').replace('\r','\n')
+
+    def __init__(self, args, skip_valgrind=False, **kwargs):
+        """Start an example process"""
+        args = list(args)
+        if skip_valgrind:
+            self.args = args
+        else:
+            self.args = self.vg_args + args
+        self.kwargs = kwargs
+        self._out = os.tmpfile()
+        try:
+            Popen.__init__(self, self.args, stdout=self._out, stderr=STDOUT, **kwargs)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                raise NotFoundError(self, str(e))
+            raise ProcError(self, str(e))
+        except Exception, e:
+            raise ProcError(self, str(e))
+
+    def kill(self):
+        try:
+            if self.poll() is None:
+                Popen.kill(self)
+        except:
+            pass                # Already exited.
+        return self.out
+
+    def wait_exit(self, timeout=DEFAULT_TIMEOUT, expect=0):
+        """Wait for process to exit, return output. Raise ProcError  on failure."""
+        t = threading.Thread(target=self.wait)
+        t.start()
+        t.join(timeout)
+        if self.poll() is None:      # Still running
+            self.kill()
+            raise ProcError(self, "still running after %ss" % timeout)
+        if expect is not None and self.poll() != expect:
+            raise ProcError(self)
+        return self.out
+
+    def wait_re(self, regexp, timeout=DEFAULT_TIMEOUT):
+        """
+        Wait for regexp to appear in the output, returns the re.search match result.
+        The target process should flush() important output to ensure it appears.
+        """
+        if timeout:
+            deadline = time.time() + timeout
+        while timeout is None or time.time() < deadline:
+            match = re.search(regexp, self.out)
+            if match:
+                return match
+            if self.poll() is not None:
+                raise ProcError(self, "process exited while waiting for '%s'" % (regexp))
+            time.sleep(0.01)    # Not very efficient
+        raise ProcError(self, "gave up waiting for '%s' after %ss" % (regexp, timeout))
+
+def _tc_missing(attr):
+    return not hasattr(unittest.TestCase, attr)
+
+class ProcTestCase(unittest.TestCase):
+    """TestCase that manages started processes
+
+    Also roughly provides setUpClass() and tearDownClass() and other features
+    missing in python 2.6. If subclasses override setUp() or tearDown() they
+    *must* call the superclass.
+    """
+
+    def setUp(self):
+        super(ProcTestCase, self).setUp()
+        self.procs = []
+
+    def tearDown(self):
+        for p in self.procs:
+            p.kill()
+        super(ProcTestCase, self).tearDown()
+
+    def proc(self, *args, **kwargs):
+        """Return a Proc() that will be automatically killed on teardown"""
+        p = Proc(*args, **kwargs)
+        self.procs.append(p)
+        return p
+
+    if _tc_missing('setUpClass') and _tc_missing('tearDownClass'):
+
+        @classmethod
+        def setUpClass(cls):
+            pass
+
+        @classmethod
+        def tearDownClass(cls):
+            pass
+
+        def setUp(self):
+            super(ProcTestCase, self).setUp()
+            cls = type(self)
+            if not hasattr(cls, '_setup_class_count'): # First time
+                def is_test(m):
+                    return inspect.ismethod(m) and m.__name__.startswith('test_')
+                cls._setup_class_count = len(inspect.getmembers(cls, predicate=is_test))
+                cls.setUpClass()
+
+        def tearDown(self):
+            self.assertTrue(self._setup_class_count > 0)
+            self._setup_class_count -=  1
+            if self._setup_class_count == 0:
+                type(self).tearDownClass()
+            super(ProcTestCase, self).tearDown()
+
+    if _tc_missing('assertIn'):
+        def assertIn(self, a, b):
+            self.assertTrue(a in b, "%r not in %r" % (a, b))
+
+    if _tc_missing('assertMultiLineEqual'):
+        def assertMultiLineEqual(self, a, b):
+            self.assertEqual(a, b)
+
+from unittest import main
+if __name__ == "__main__":
+    main()


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


[49/50] [abbrv] qpid-proton git commit: Merge branch 'master' into go1

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/electron/link.go
----------------------------------------------------------------------
diff --cc electron/link.go
index 4f927c1,0000000..de8a995
mode 100644,000000..100644
--- a/electron/link.go
+++ b/electron/link.go
@@@ -1,285 -1,0 +1,307 @@@
 +/*
 +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/amqp"
 +	"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
 +
++	// Filter for the link
++	Filter() map[amqp.Symbol]interface{}
++
 +	// 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.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 } }
 +
 +// 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)
 +	}
 +}
 +
++// Filter returns a LinkOption that sets a filter.
++func Filter(m map[amqp.Symbol]interface{}) LinkOption {
++	return func(l *linkSettings) { l.filter = m }
++}
++
 +// 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
 +	sourceSettings TerminusSettings
 +	target         string
 +	targetSettings TerminusSettings
 +	linkName       string
 +	isSender       bool
 +	sndSettle      SndSettleMode
 +	rcvSettle      RcvSettleMode
 +	capacity       int
 +	prefetch       bool
++	filter         map[amqp.Symbol]interface{}
 +	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) SourceSettings() TerminusSettings { return l.sourceSettings }
- func (l *linkSettings) TargetSettings() TerminusSettings { return l.targetSettings }
++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) Filter() map[amqp.Symbol]interface{} { return l.filter }
++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)
++
++	if len(l.filter) > 0 {
++		if err := l.pLink.Source().Filter().Marshal(l.filter); err != nil {
++			panic(err) // Shouldn't happen
++		}
++	}
 +	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{
++	l := linkSettings{
 +		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,
 +	}
++	filter := l.pLink.RemoteSource().Filter()
++	if !filter.Empty() {
++		filter.Unmarshal(&l.filter) // TODO aconway 2017-06-08: ignoring errors
++	}
++	return l
 +}
 +
 +// 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/847a83cc/electron/link_test.go
----------------------------------------------------------------------
diff --cc electron/link_test.go
index 133faad,0000000..feb1f20
mode 100644,000000..100644
--- a/electron/link_test.go
+++ b/electron/link_test.go
@@@ -1,64 -1,0 +1,66 @@@
 +/*
 +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/amqp"
 +	"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}
++	filterMap := map[amqp.Symbol]interface{}{"int": int32(33), "str": "hello"}
 +	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()))
++				errorIf(t, checkEqual(filterMap, ep.Filter()))
 +			}
 +		}
 +	}()
 +
 +	// 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.Receiver(Source("two.source"), DurableSubscription("two"), Filter(filterMap))
 +	c.Close(nil)
 +	<-done
 +}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/847a83cc/proton/wrappers.go
----------------------------------------------------------------------
diff --cc proton/wrappers.go
index b6386b8,0000000..879ad53
mode 100644,000000..100644
--- a/proton/wrappers.go
+++ b/proton/wrappers.go
@@@ -1,431 -1,0 +1,450 @@@
 +/*
 +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.
 +*/
 +
 +// This file contains special-case wrapper functions or wrappers that don't follow
 +// the pattern of genwrap.go.
 +
 +package proton
 +
 +//#include <proton/codec.h>
 +//#include <proton/connection.h>
 +//#include <proton/delivery.h>
 +//#include <proton/event.h>
 +//#include <proton/link.h>
 +//#include <proton/link.h>
 +//#include <proton/object.h>
 +//#include <proton/sasl.h>
 +//#include <proton/session.h>
 +//#include <proton/transport.h>
 +//#include <stdlib.h>
 +import "C"
 +
 +import (
 +	"fmt"
 +	"qpid.apache.org/amqp"
 +	"reflect"
 +	"time"
 +	"unsafe"
 +)
 +
 +// TODO aconway 2015-05-05: Documentation for generated types.
 +
 +// CHandle holds an unsafe.Pointer to a proton C struct, the C type depends on the
 +// Go type implementing this interface. For low level, at-your-own-risk use only.
 +type CHandle interface {
 +	// CPtr returns the unsafe C pointer, equivalent to a C void*.
 +	CPtr() unsafe.Pointer
 +}
 +
 +// Incref increases the refcount of a proton value, which prevents the
 +// underlying C struct being freed until you call Decref().
 +//
 +// It can be useful to "pin" a proton value in memory while it is in use by
 +// goroutines other than the event loop goroutine. For example if you Incref() a
 +// Link, the underlying object is not freed when the link is closed, so means
 +// other goroutines can continue to safely use it as an index in a map or inject
 +// it into the event loop goroutine. There will of course be an error if you try
 +// to use a link after it is closed, but not a segmentation fault.
 +func Incref(c CHandle) {
 +	if p := c.CPtr(); p != nil {
 +		C.pn_incref(p)
 +	}
 +}
 +
 +// Decref decreases the refcount of a proton value, freeing the underlying C
 +// struct if this is the last reference.  Only call this if you previously
 +// called Incref() for this value.
 +func Decref(c CHandle) {
 +	if p := c.CPtr(); p != nil {
 +		C.pn_decref(p)
 +	}
 +}
 +
 +// Event is an AMQP protocol event.
 +type Event struct {
 +	pn         *C.pn_event_t
 +	eventType  EventType
 +	connection Connection
 +	transport  Transport
 +	session    Session
 +	link       Link
 +	delivery   Delivery
 +	injecter   Injecter
 +}
 +
 +func makeEvent(pn *C.pn_event_t, injecter Injecter) Event {
 +	return Event{
 +		pn:         pn,
 +		eventType:  EventType(C.pn_event_type(pn)),
 +		connection: Connection{C.pn_event_connection(pn)},
 +		transport:  Transport{C.pn_event_transport(pn)},
 +		session:    Session{C.pn_event_session(pn)},
 +		link:       Link{C.pn_event_link(pn)},
 +		delivery:   Delivery{C.pn_event_delivery(pn)},
 +		injecter:   injecter,
 +	}
 +}
 +func (e Event) IsNil() bool            { return e.eventType == EventType(0) }
 +func (e Event) Type() EventType        { return e.eventType }
 +func (e Event) Connection() Connection { return e.connection }
 +func (e Event) Transport() Transport   { return e.transport }
 +func (e Event) Session() Session       { return e.session }
 +func (e Event) Link() Link             { return e.link }
 +func (e Event) Delivery() Delivery     { return e.delivery }
 +func (e Event) String() string         { return e.Type().String() }
 +
 +// Injecter should not be used in a handler function, but it can be passed to
 +// other goroutines (via a channel or to a goroutine started by handler
 +// functions) to let them inject functions back into the handlers goroutine.
 +func (e Event) Injecter() Injecter { return e.injecter }
 +
- // Data holds a pointer to decoded AMQP data.
- // Use amqp.marshal/unmarshal to access it as Go data types.
- //
++// Data is an intermediate form of decoded AMQP data.
 +type Data struct{ pn *C.pn_data_t }
 +
- func NewData(p unsafe.Pointer) Data { return Data{(*C.pn_data_t)(p)} }
++func (d Data) Free()                { C.pn_data_free(d.pn) }
++func (d Data) CPtr() unsafe.Pointer { return unsafe.Pointer(d.pn) }
++func (d Data) Clear()               { C.pn_data_clear(d.pn) }
++func (d Data) Rewind()              { C.pn_data_rewind(d.pn) }
++func (d Data) Next()                { C.pn_data_next(d.pn) }
++func (d Data) Error() error         { return PnError(C.pn_data_error(d.pn)) }
++func (d Data) Empty() bool          { return C.pn_data_size(d.pn) == 0 }
++
++func (d Data) String() string {
++	str := C.pn_string(C.CString(""))
++	defer C.pn_free(unsafe.Pointer(str))
++	C.pn_inspect(unsafe.Pointer(d.pn), str)
++	return C.GoString(C.pn_string_get(str))
++}
 +
- func (d Data) Free()                   { C.pn_data_free(d.pn) }
- func (d Data) Pointer() unsafe.Pointer { return unsafe.Pointer(d.pn) }
- func (d Data) Clear()                  { C.pn_data_clear(d.pn) }
- func (d Data) Rewind()                 { C.pn_data_rewind(d.pn) }
- func (d Data) Error() error            { return PnError(C.pn_data_error(d.pn)) }
++// Unmarshal the value of d into value pointed at by ptr, see amqp.Unmarshal() for details
++func (d Data) Unmarshal(ptr interface{}) error {
++	d.Rewind()
++	d.Next()
++	err := amqp.UnmarshalUnsafe(d.CPtr(), ptr)
++	return err
++}
++
++// Marshal the value v into d, see amqp.Marshal() for details
++func (d Data) Marshal(v interface{}) error {
++	d.Clear()
++	return amqp.MarshalUnsafe(v, d.CPtr())
++}
 +
 +// State holds the state flags for an AMQP endpoint.
 +type State byte
 +
 +const (
 +	SLocalUninit  State = C.PN_LOCAL_UNINIT
 +	SLocalActive        = C.PN_LOCAL_ACTIVE
 +	SLocalClosed        = C.PN_LOCAL_CLOSED
 +	SRemoteUninit       = C.PN_REMOTE_UNINIT
 +	SRemoteActive       = C.PN_REMOTE_ACTIVE
 +	SRemoteClosed       = C.PN_REMOTE_CLOSED
 +)
 +
 +// Has is True if bits & state is non 0.
 +func (s State) Has(bits State) bool { return s&bits != 0 }
 +
 +func (s State) LocalUninit() bool  { return s.Has(SLocalUninit) }
 +func (s State) LocalActive() bool  { return s.Has(SLocalActive) }
 +func (s State) LocalClosed() bool  { return s.Has(SLocalClosed) }
 +func (s State) RemoteUninit() bool { return s.Has(SRemoteUninit) }
 +func (s State) RemoteActive() bool { return s.Has(SRemoteActive) }
 +func (s State) RemoteClosed() bool { return s.Has(SRemoteClosed) }
 +
 +// Return a State containig just the local flags
 +func (s State) Local() State { return State(s & C.PN_LOCAL_MASK) }
 +
 +// Return a State containig just the remote flags
 +func (s State) Remote() State { return State(s & C.PN_REMOTE_MASK) }
 +
 +// Endpoint is the common interface for Connection, Link and Session.
 +type Endpoint interface {
 +	// State is the open/closed state.
 +	State() State
 +	// Open an endpoint.
 +	Open()
 +	// Close an endpoint.
 +	Close()
 +	// Condition holds a local error condition.
 +	Condition() Condition
 +	// RemoteCondition holds a remote error condition.
 +	RemoteCondition() Condition
 +	// Human readable name
 +	String() string
 +	// Human readable endpoint type "sender-link", "session" etc.
 +	Type() string
 +}
 +
 +// CloseError sets an error condition (if err != nil) on an endpoint and closes
 +// the endpoint if not already closed
 +func CloseError(e Endpoint, err error) {
 +	if err != nil && !e.Condition().IsSet() {
 +		e.Condition().SetError(err)
 +	}
 +	e.Close()
 +}
 +
 +// EndpointError returns the remote error if there is one, the local error if not
 +// nil if there is no error.
 +func EndpointError(e Endpoint) error {
 +	err := e.RemoteCondition().Error()
 +	if err == nil {
 +		err = e.Condition().Error()
 +	}
 +	return err
 +}
 +
 +const (
 +	Received uint64 = C.PN_RECEIVED
 +	Accepted        = C.PN_ACCEPTED
 +	Rejected        = C.PN_REJECTED
 +	Released        = C.PN_RELEASED
 +	Modified        = C.PN_MODIFIED
 +)
 +
 +// SettleAs is equivalent to d.Update(disposition); d.Settle()
 +func (d Delivery) SettleAs(disposition uint64) {
 +	d.Update(disposition)
 +	d.Settle()
 +}
 +
 +// Accept accepts and settles a delivery.
 +func (d Delivery) Accept() { d.SettleAs(Accepted) }
 +
 +// Reject rejects and settles a delivery
 +func (d Delivery) Reject() { d.SettleAs(Rejected) }
 +
 +// Release releases and settles a delivery
 +// If delivered is true the delivery count for the message will be increased.
 +func (d Delivery) Release(delivered bool) {
 +	if delivered {
 +		d.SettleAs(Modified)
 +	} else {
 +		d.SettleAs(Released)
 +	}
 +}
 +
 +type DeliveryTag struct{ pn C.pn_delivery_tag_t }
 +
 +func (t DeliveryTag) String() string { return C.GoStringN(t.pn.start, C.int(t.pn.size)) }
 +
 +func (l Link) Recv(buf []byte) int {
 +	if len(buf) == 0 {
 +		return 0
 +	}
 +	return int(C.pn_link_recv(l.pn, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
 +}
 +
 +func (l Link) SendBytes(bytes []byte) int {
 +	return int(C.pn_link_send(l.pn, cPtr(bytes), cLen(bytes)))
 +}
 +
 +func pnTag(tag string) C.pn_delivery_tag_t {
 +	bytes := []byte(tag)
 +	return C.pn_dtag(cPtr(bytes), cLen(bytes))
 +}
 +
 +func (l Link) Delivery(tag string) Delivery {
 +	return Delivery{C.pn_delivery(l.pn, pnTag(tag))}
 +}
 +
 +func (l Link) Connection() Connection { return l.Session().Connection() }
 +
 +// Human-readable link description including name, source, target and direction.
 +func (l Link) String() string {
 +	switch {
 +	case l.IsNil():
 +		return fmt.Sprintf("<nil-link>")
 +	case l.IsSender():
 +		return fmt.Sprintf("%s(%s->%s)", l.Name(), l.Source().Address(), l.Target().Address())
 +	default:
 +		return fmt.Sprintf("%s(%s<-%s)", l.Name(), l.Target().Address(), l.Source().Address())
 +	}
 +}
 +
 +func (l Link) Type() string {
 +	if l.IsSender() {
 +		return "sender-link"
 +	} else {
 +		return "receiver-link"
 +	}
 +}
 +
 +// IsDrain calls pn_link_get_drain(), it conflicts with pn_link_drain() under the normal mapping.
 +func (l Link) IsDrain() bool {
 +	return bool(C.pn_link_get_drain(l.pn))
 +}
 +
 +func cPtr(b []byte) *C.char {
 +	if len(b) == 0 {
 +		return nil
 +	}
 +	return (*C.char)(unsafe.Pointer(&b[0]))
 +}
 +
 +func cLen(b []byte) C.size_t {
 +	return C.size_t(len(b))
 +}
 +
 +func (s Session) Sender(name string) Link {
 +	cname := C.CString(name)
 +	defer C.free(unsafe.Pointer(cname))
 +	return Link{C.pn_sender(s.pn, cname)}
 +}
 +
 +func (s Session) Receiver(name string) Link {
 +	cname := C.CString(name)
 +	defer C.free(unsafe.Pointer(cname))
 +	return Link{C.pn_receiver(s.pn, cname)}
 +}
 +
 +func (t Transport) String() string {
 +	return fmt.Sprintf("(Transport)(%p)", t.CPtr())
 +}
 +
 +// Unique (per process) string identifier for a connection, useful for debugging.
 +func (c Connection) String() string {
 +	// Use the transport address to match the default transport logs from PN_TRACE.
 +	return fmt.Sprintf("(Connection)(%p)", c.Transport().CPtr())
 +}
 +
 +func (c Connection) Type() string {
 +	return "connection"
 +}
 +
 +// Head functions don't follow the normal naming conventions so missed by the generator.
 +
 +func (c Connection) LinkHead(s State) Link {
 +	return Link{C.pn_link_head(c.pn, C.pn_state_t(s))}
 +}
 +
 +func (c Connection) SessionHead(s State) Session {
 +	return Session{C.pn_session_head(c.pn, C.pn_state_t(s))}
 +}
 +
 +func (c Connection) Links(state State) (links []Link) {
 +	for l := c.LinkHead(state); !l.IsNil(); l = l.Next(state) {
 +		links = append(links, l)
 +	}
 +	return
 +}
 +
 +func (c Connection) Sessions(state State) (sessions []Session) {
 +	for s := c.SessionHead(state); !s.IsNil(); s = s.Next(state) {
 +		sessions = append(sessions, s)
 +	}
 +	return
 +}
 +
 +// SetPassword takes []byte not string because it is impossible to erase a string
 +// from memory reliably. Proton will not keep the password in memory longer than
 +// needed, the caller should overwrite their copy on return.
 +//
 +// The password must not contain embedded nul characters, a trailing nul is ignored.
 +func (c Connection) SetPassword(password []byte) {
 +	if len(password) == 0 || password[len(password)-1] != 0 {
 +		password = append(password, 0) // Proton requires a terminating null.
 +	}
 +	C.pn_connection_set_password(c.pn, (*C.char)(unsafe.Pointer(&password[0])))
 +}
 +
 +func (s Session) String() string {
 +	return fmt.Sprintf("(Session)(%p)", s.pn) // TODO aconway 2016-09-12: should print channel number.
 +}
 +
 +func (s Session) Type() string { return "session" }
 +
 +// Error returns an instance of amqp.Error or nil.
 +func (c Condition) Error() error {
 +	if c.IsNil() || !c.IsSet() {
 +		return nil
 +	}
 +	return amqp.Error{Name: c.Name(), Description: c.Description()}
 +}
 +
 +// Set a Go error into a condition.
 +// If it is not an amqp.Condition use the error type as name, error string as description.
 +func (c Condition) SetError(err error) {
 +	if err != nil {
 +		if cond, ok := err.(amqp.Error); ok {
 +			c.SetName(cond.Name)
 +			c.SetDescription(cond.Description)
 +		} else {
 +			c.SetName(reflect.TypeOf(err).Name())
 +			c.SetDescription(err.Error())
 +		}
 +	}
 +}
 +
 +func (c Connection) Session() (Session, error) {
 +	s := Session{C.pn_session(c.pn)}
 +	if s.IsNil() {
 +		return s, Connection(c).Error()
 +	}
 +	return s, nil
 +}
 +
 +// pnTime converts Go time.Time to Proton millisecond Unix time.
 +//
 +// Note: t.isZero() is converted to C.pn_timestamp_t(0) and vice-versa. These
 +// are used as "not set" sentinel values by the Go and Proton APIs, so it is
 +// better to conserve the "zeroness" even though they don't represent the same
 +// time instant.
 +//
 +func pnTime(t time.Time) (pnt C.pn_timestamp_t) {
 +	if !t.IsZero() {
 +		pnt = C.pn_timestamp_t(t.Unix()*1000 + int64(t.Nanosecond())/int64(time.Millisecond))
 +	}
 +	return
 +}
 +
 +// goTime converts a pn_timestamp_t to a Go time.Time.
 +//
 +// Note: C.pn_timestamp_t(0) is converted to a zero time.Time and
 +// vice-versa. These are used as "not set" sentinel values by the Go and Proton
 +// APIs, so it is better to conserve the "zeroness" even though they don't
 +// represent the same time instant.
 +//
 +func goTime(pnt C.pn_timestamp_t) (t time.Time) {
 +	if pnt != 0 {
 +		t = time.Unix(int64(pnt/1000), int64(pnt%1000)*int64(time.Millisecond))
 +	}
 +	return
 +}
 +
 +// Special treatment for Transport.Head, return value is unsafe.Pointer not string
 +func (t Transport) Head() unsafe.Pointer {
 +	return unsafe.Pointer(C.pn_transport_head(t.pn))
 +}
 +
 +// Special treatment for Transport.Tail, return value is unsafe.Pointer not string
 +func (t Transport) Tail() unsafe.Pointer {
 +	return unsafe.Pointer(C.pn_transport_tail(t.pn))
 +}
 +
 +// Special treatment for Transport.Push, takes []byte instead of char*, size
 +func (t Transport) Push(bytes []byte) int {
 +	return int(C.pn_transport_push(t.pn, (*C.char)(unsafe.Pointer(&bytes[0])), C.size_t(len(bytes))))
 +}
 +
 +// Get the SASL object for the transport.
 +func (t Transport) SASL() SASL {
 +	return SASL{C.pn_sasl(t.pn)}
 +}


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


[20/50] [abbrv] qpid-proton git commit: PROTON-1288: remove un-necessary internal::value_ref class.

Posted by ac...@apache.org.
PROTON-1288: remove un-necessary internal::value_ref class.


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

Branch: refs/heads/go1
Commit: d588798b719d6c724958d456d24e7e354351386f
Parents: a4e5c84
Author: Alan Conway <ac...@redhat.com>
Authored: Fri May 19 14:59:09 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 14:38:01 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/message.hpp     |  2 +-
 proton-c/bindings/cpp/include/proton/value.hpp  | 37 +++-----------------
 proton-c/bindings/cpp/src/error_condition.cpp   |  2 +-
 proton-c/bindings/cpp/src/message.cpp           |  8 +++--
 proton-c/bindings/cpp/src/proton_bits.cpp       |  2 +-
 proton-c/bindings/cpp/src/terminus.cpp          |  2 +-
 proton-c/bindings/cpp/src/value.cpp             | 15 ++------
 7 files changed, 16 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index 85ccff6..ff60c99 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -324,7 +324,7 @@ class message {
     pn_message_t *pn_msg() const;
 
     mutable pn_message_t *pn_msg_;
-    mutable internal::value_ref body_;
+    mutable value body_;
     mutable property_map application_properties_;
     mutable annotation_map message_annotations_;
     mutable annotation_map delivery_annotations_;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index 3ac1763..75927f7 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -42,7 +42,6 @@ class value_base {
     internal::data& data();
     internal::data data_;
 
-  friend class value_ref;
   friend class codec::encoder;
   friend class codec::decoder;
 };
@@ -116,41 +115,13 @@ class value : public internal::value_base, private internal::comparable<value> {
     /// Complex types are printed in a non-standard human-readable format but
     /// that may change in future so should not be parsed.
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const value&);
-};
-
-namespace internal {
-
-// value_ref is a `pn_data_t* p` that can be returned as a value& and used to modify
-// the underlying value in-place.
-//
-// Classes with a value_ref member can return it as a value& in accessor functions.
-// It can also be used to copy a pn_data_t* p to a proton::value via: value(value_ref(p));
-// None of the constructors make copies, they just refer to the same value.
-//
-class value_ref : public value {
-  public:
-    value_ref(pn_data_t* = 0);
-    value_ref(const internal::data&);
-    value_ref(const value_base&);
-
-    // Use refer() not operator= to avoid confusion with value op=
-    void refer(pn_data_t*);
-    void refer(const internal::data&);
-    void refer(const value_base&);
 
-    // Reset to refer to nothing, release existing references. Equivalent to refer(0).
-    void reset();
-
-    // Assignments to value_ref means assigning to the value.
-    template <class T> value_ref& operator=(const T& x) {
-        static_cast<value&>(*this) = x;
-        return *this;
-    }
+    ///@cond INTERNAL - used to refer to existing pn_data_t* values as proton::value
+    value(pn_data_t* d);          // Refer to existing pn_data_t
+    void reset(pn_data_t* d = 0); // Refer to a new pn_data_t
+    ///@endcond
 };
 
-}
-
-
 /// @copydoc scalar::get
 /// @related proton::value
 template<class T> T get(const value& v) { T x; get(v, x); return x; }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/src/error_condition.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/error_condition.cpp b/proton-c/bindings/cpp/src/error_condition.cpp
index ead1cff..91e763a 100644
--- a/proton-c/bindings/cpp/src/error_condition.cpp
+++ b/proton-c/bindings/cpp/src/error_condition.cpp
@@ -31,7 +31,7 @@ namespace proton {
 error_condition::error_condition(pn_condition_t* c) :
     name_(str(pn_condition_get_name(c))),
     description_(str(pn_condition_get_description(c))),
-    properties_(internal::value_ref(pn_condition_info(c)))
+    properties_(value(pn_condition_info(c)))
 {}
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index eecfa3b..59f8329 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -70,8 +70,10 @@ void swap(message& x, message& y) {
 }
 
 pn_message_t *message::pn_msg() const {
-    if (!pn_msg_) pn_msg_ = pn_message();
-    body_.refer(pn_message_body(pn_msg_));
+    if (!pn_msg_) {
+        pn_msg_ = pn_message();
+        body_.reset(pn_message_body(pn_msg_));
+    }
     return pn_msg_;
 }
 
@@ -144,7 +146,7 @@ std::string message::reply_to() const {
 }
 
 void message::correlation_id(const message_id& id) {
-    internal::value_ref(pn_message_correlation_id(pn_msg())) = id;
+    value(pn_message_correlation_id(pn_msg())) = id;
 }
 
 message_id message::correlation_id() const {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/src/proton_bits.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_bits.cpp b/proton-c/bindings/cpp/src/proton_bits.cpp
index 18fc589..3e1b27f 100644
--- a/proton-c/bindings/cpp/src/proton_bits.cpp
+++ b/proton-c/bindings/cpp/src/proton_bits.cpp
@@ -70,7 +70,7 @@ void set_error_condition(const error_condition& e, pn_condition_t *c) {
     if (!e.description().empty()) {
         pn_condition_set_description(c, e.description().c_str());
     }
-    internal::value_ref(pn_condition_info(c)) = e.properties();
+    value(pn_condition_info(c)) = e.properties();
 }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/src/terminus.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/terminus.cpp b/proton-c/bindings/cpp/src/terminus.cpp
index 8065fe4..c751fd0 100644
--- a/proton-c/bindings/cpp/src/terminus.cpp
+++ b/proton-c/bindings/cpp/src/terminus.cpp
@@ -49,7 +49,7 @@ bool terminus::dynamic() const {
 }
 
 value terminus::node_properties() const {
-    return internal::value_ref(pn_terminus_properties(object_));
+    return value(pn_terminus_properties(object_));
 }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d588798b/proton-c/bindings/cpp/src/value.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value.cpp b/proton-c/bindings/cpp/src/value.cpp
index ceb3463..edf9074 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -34,6 +34,7 @@ using codec::encoder;
 using codec::start;
 
 value::value() {}
+value::value(pn_data_t *d) { data_ = make_wrapper(d); }
 value::value(const value& x) { *this = x; }
 #if PN_CPP_HAS_RVALUE_REFERENCES
 value::value(value&& x) { swap(*this, x); }
@@ -189,22 +190,12 @@ std::ostream& operator<<(std::ostream& o, const value& x) {
     return o << d;
 }
 
-namespace internal {
-value_ref::value_ref(pn_data_t* p) { refer(p); }
-value_ref::value_ref(const internal::data& d) { refer(d); }
-value_ref::value_ref(const value_base& v) { refer(v); }
-
-void value_ref::refer(pn_data_t* p) { data_ = make_wrapper(p); }
-void value_ref::refer(const internal::data& d) { data_ = d; }
-void value_ref::refer(const value_base& v) { data_ = v.data_; }
-
-void value_ref::reset() { refer(0); }
-} // namespace internal
-
 std::string to_string(const value& x) {
     std::ostringstream os;
     os << std::boolalpha << x;
     return os.str();
 }
 
+void value::reset(pn_data_t *d) { data_ = make_wrapper(d); }
+
 } // namespace proton


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


[26/50] [abbrv] qpid-proton git commit: NO-JIRA: fix tox tests - missing max_align.h file from source lists

Posted by ac...@apache.org.
NO-JIRA: fix tox tests - missing max_align.h file from source lists


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

Branch: refs/heads/go1
Commit: 33609f5c80b42fca6d6f42ec326580f84a6f5579
Parents: 16147e9
Author: Alan Conway <ac...@redhat.com>
Authored: Wed May 24 14:48:13 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 15:37:15 2017 -0400

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


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/33609f5c/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 33933b8..1964b44 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -375,6 +375,8 @@ set (qpid-proton-core
   src/core/transport.c
   src/core/message.c
   src/core/url-internal.c
+
+  src/core/max_align.h
 )
 
 set (qpid-proton-include-generated


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


[04/50] [abbrv] qpid-proton git commit: PROTON-1460: Added missing SOVERSION properties to proactor libraryc

Posted by ac...@apache.org.
PROTON-1460: Added missing SOVERSION properties to proactor libraryc


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

Branch: refs/heads/go1
Commit: 9c69b7d7edc71976ee552d2bd926c07b52ea8fcf
Parents: bfa8a71
Author: Alan Conway <ac...@redhat.com>
Authored: Tue May 9 14:17:24 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue May 9 14:17:24 2017 -0400

----------------------------------------------------------------------
 proton-c/CMakeLists.txt | 7 +++++++
 1 file changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c69b7d7/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 6c2211e..e468cae 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -615,6 +615,13 @@ if (qpid-proton-proactor)
   target_link_libraries (qpid-proton-proactor  LINK_PUBLIC qpid-proton-core)
   target_link_libraries (qpid-proton-proactor  LINK_PRIVATE ${PROACTOR_LIBS})
   list(APPEND LIB_TARGETS qpid-proton-proactor)
+  set_target_properties (
+    qpid-proton-proactor
+    PROPERTIES
+    VERSION   "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
+    SOVERSION "${PN_LIB_SOMAJOR}"
+    LINK_FLAGS "${CATCH_UNDEFINED} ${LTO}"
+    )
 endif()
 
 # Install executables and libraries


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