qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject [08/89] [abbrv] [partial] qpid-proton git commit: PROTON-1728: Reorganize the source tree
Date Tue, 03 Jul 2018 22:12:57 GMT
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/reactor.c
----------------------------------------------------------------------
diff --git a/c/tests/reactor.c b/c/tests/reactor.c
new file mode 100644
index 0000000..900d6a3
--- /dev/null
+++ b/c/tests/reactor.c
@@ -0,0 +1,578 @@
+/*
+ *
+ * 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/reactor.h>
+#include <proton/handlers.h>
+#include <proton/event.h>
+#include <proton/connection.h>
+#include <proton/session.h>
+#include <proton/link.h>
+#include <proton/delivery.h>
+#include <proton/url.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define assert(E) ((E) ? 0 : (abort(), 0))
+
+
+static void test_reactor(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_free(reactor);
+}
+
+static void test_reactor_free(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_reactor_free(reactor);
+}
+
+static void test_reactor_run(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  // run should exit if there is nothing left to do
+  pn_reactor_run(reactor);
+  pn_free(reactor);
+}
+
+static void test_reactor_run_free(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  // run should exit if there is nothing left to do
+  pn_reactor_run(reactor);
+  pn_reactor_free(reactor);
+}
+
+typedef struct {
+  pn_reactor_t *reactor;
+  pn_list_t *events;
+} pni_test_handler_t;
+
+pni_test_handler_t *thmem(pn_handler_t *handler) {
+  return (pni_test_handler_t *) pn_handler_mem(handler);
+}
+
+void test_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  pni_test_handler_t *th = thmem(handler);
+  pn_reactor_t *reactor = pn_event_reactor(event);
+  assert(reactor == th->reactor);
+  pn_list_add(th->events, (void *) type);
+}
+
+pn_handler_t *test_handler(pn_reactor_t *reactor, pn_list_t *events) {
+  pn_handler_t *handler = pn_handler_new(test_dispatch, sizeof(pni_test_handler_t), NULL);
+  thmem(handler)->reactor = reactor;
+  thmem(handler)->events = events;
+  return handler;
+}
+
+
+void root_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  pni_test_handler_t *th = thmem(handler);
+  pn_reactor_t *reactor = pn_event_reactor(event);
+  assert(reactor == th->reactor);
+  pn_list_add(th->events, pn_event_root(event));
+}
+
+pn_handler_t *test_root(pn_reactor_t *reactor, pn_list_t *events) {
+  pn_handler_t *handler = pn_handler_new(root_dispatch, sizeof(pni_test_handler_t), NULL);
+  thmem(handler)->reactor = reactor;
+  thmem(handler)->events = events;
+  return handler;
+}
+
+#define END PN_EVENT_NONE
+
+void expect(pn_list_t *events, ...) {
+  va_list ap;
+
+  va_start(ap, events);
+  size_t idx = 0;
+  while (true) {
+    pn_event_type_t expected = (pn_event_type_t) va_arg(ap, int);
+    if (expected == END) {
+      assert(idx == pn_list_size(events));
+      break;
+    }
+    assert(idx < pn_list_size(events));
+    pn_event_type_t actual = (pn_event_type_t)(size_t) pn_list_get(events, idx++);
+    assert(expected == actual);
+  }
+  va_end(ap);
+}
+
+static void test_reactor_handler(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *handler = pn_reactor_get_handler(reactor);
+  assert(handler);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_handler_t *th = test_handler(reactor, events);
+  pn_handler_add(handler, th);
+  pn_decref(th);
+  pn_free(reactor);
+  expect(events, END);
+  pn_free(events);
+}
+
+static void test_reactor_handler_free(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *handler = pn_reactor_get_handler(reactor);
+  assert(handler);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_handler_add(handler, test_handler(reactor, events));
+  pn_reactor_free(reactor);
+  expect(events, END);
+  pn_free(events);
+}
+
+static void test_reactor_handler_run(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *handler = pn_reactor_get_handler(reactor);
+  assert(handler);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_handler_t *th = test_handler(reactor, events);
+  pn_handler_add(handler, th);
+  pn_reactor_run(reactor);
+  expect(events, PN_REACTOR_INIT, PN_SELECTABLE_INIT, PN_SELECTABLE_UPDATED, PN_SELECTABLE_FINAL, PN_REACTOR_FINAL, END);
+  pn_free(reactor);
+  pn_free(th);
+  pn_free(events);
+}
+
+static void test_reactor_handler_run_free(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *handler = pn_reactor_get_handler(reactor);
+  assert(handler);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_handler_add(handler, test_handler(reactor, events));
+  pn_reactor_run(reactor);
+  expect(events, PN_REACTOR_INIT, PN_SELECTABLE_INIT, PN_SELECTABLE_UPDATED, PN_SELECTABLE_FINAL, PN_REACTOR_FINAL, END);
+  pn_reactor_free(reactor);
+  pn_free(events);
+}
+
+static void test_reactor_event_root(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *handler = pn_reactor_get_handler(reactor);
+  assert(handler);
+  pn_list_t *roots = pn_list(PN_VOID, 0);
+  pn_handler_t *th = test_root(reactor, roots);
+  pn_handler_add(handler, th);
+  pn_reactor_run(reactor);
+  expect(roots, handler, handler, handler, handler, handler, END);
+  pn_free(reactor);
+  pn_free(th);
+  pn_free(roots);
+}
+
+static void test_reactor_connection(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_list_t *cevents = pn_list(PN_VOID, 0);
+  pn_handler_t *tch = test_handler(reactor, cevents);
+  pn_connection_t *connection = pn_reactor_connection(reactor, tch);
+  assert(connection);
+  pn_reactor_set_connection_host(reactor, connection, "127.0.0.1", "5672");
+  pn_url_t *url = pn_url_parse(pn_reactor_get_connection_address(reactor, connection));
+  assert(strcmp(pn_url_get_host(url), "127.0.0.1") == 0);
+  assert(strcmp(pn_url_get_port(url), "5672") == 0);
+  pn_decref(url);
+  pn_handler_t *root = pn_reactor_get_handler(reactor);
+  pn_list_t *revents = pn_list(PN_VOID, 0);
+  pn_handler_add(root, test_handler(reactor, revents));
+  pn_reactor_run(reactor);
+  expect(revents, PN_REACTOR_INIT, PN_SELECTABLE_INIT, PN_SELECTABLE_UPDATED, PN_SELECTABLE_FINAL, PN_REACTOR_FINAL,
+         END);
+  expect(cevents, PN_CONNECTION_INIT, END);
+  pn_reactor_free(reactor);
+  pn_handler_free(tch);
+  pn_free(cevents);
+  pn_free(revents);
+}
+
+static void test_reactor_connection_factory(void)
+{
+  pn_reactor_t *reactor = pn_reactor();
+  pn_connection_t *conn;
+  const char *addr;
+  // use host as connection hostname default
+  conn = pn_reactor_connection_to_host(reactor, "a.test.com", "5678", NULL);
+  pn_connection_set_hostname(conn, "virt.host");
+  addr = pn_reactor_get_connection_address(reactor, conn);
+  assert(addr && strcmp(addr, "a.test.com:5678") == 0);
+  assert(strcmp(pn_connection_get_hostname(conn), "virt.host") == 0);
+  // verify the host address can be changed:
+  pn_reactor_set_connection_host(reactor, conn, "a.different.com", "9999");
+  addr = pn_reactor_get_connection_address(reactor, conn);
+  assert(addr && strcmp(addr, "a.different.com:9999") == 0);
+  assert(strcmp(pn_connection_get_hostname(conn), "virt.host") == 0);
+  pn_reactor_free(reactor);
+}
+
+static void test_reactor_acceptor(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_acceptor_t *acceptor = pn_reactor_acceptor(reactor, "0.0.0.0", "5678", NULL);
+  assert(acceptor);
+  pn_reactor_free(reactor);
+}
+
+pn_acceptor_t **tram(pn_handler_t *h) {
+  return (pn_acceptor_t **) pn_handler_mem(h);
+}
+
+static void tra_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  switch (type) {
+  case PN_REACTOR_INIT:
+    {
+      pn_acceptor_t *acceptor = *tram(handler);
+      pn_acceptor_close(acceptor);
+    }
+    break;
+  default:
+    break;
+  }
+}
+
+static pn_handler_t *tra_handler(pn_acceptor_t *acceptor) {
+  pn_handler_t *handler = pn_handler_new(tra_dispatch, sizeof(pn_acceptor_t *), NULL);
+  *tram(handler) = acceptor;
+  return handler;
+}
+
+static void test_reactor_acceptor_run(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *root = pn_reactor_get_handler(reactor);
+  assert(root);
+  pn_acceptor_t *acceptor = pn_reactor_acceptor(reactor, "0.0.0.0", "5678", NULL);
+  assert(acceptor);
+  pn_handler_add(root, tra_handler(acceptor));
+  pn_reactor_run(reactor);
+  pn_reactor_free(reactor);
+}
+
+typedef struct {
+  pn_reactor_t *reactor;
+  pn_acceptor_t *acceptor;
+  pn_list_t *events;
+} server_t;
+
+static server_t *smem(pn_handler_t *handler) {
+  return (server_t *) pn_handler_mem(handler);
+}
+
+static void server_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  server_t *srv = smem(handler);
+  pn_list_add(srv->events, (void *) pn_event_type(event));
+  switch (type) {
+  case PN_CONNECTION_REMOTE_OPEN:
+    pn_connection_open(pn_event_connection(event));
+    break;
+  case PN_CONNECTION_REMOTE_CLOSE:
+    pn_acceptor_close(srv->acceptor);
+    pn_connection_close(pn_event_connection(event));
+    pn_connection_release(pn_event_connection(event));
+    break;
+  default:
+    break;
+  }
+}
+
+typedef struct {
+  pn_list_t *events;
+} client_t;
+
+static client_t *cmem(pn_handler_t *handler) {
+  return (client_t *) pn_handler_mem(handler);
+}
+
+static void client_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  client_t *cli = cmem(handler);
+  pn_list_add(cli->events, (void *) type);
+  pn_connection_t *conn = pn_event_connection(event);
+  switch (pn_event_type(event)) {
+  case PN_CONNECTION_INIT:
+    pn_connection_set_hostname(conn, "some.org");
+    pn_connection_open(conn);
+    break;
+  case PN_CONNECTION_REMOTE_OPEN:
+    pn_connection_close(conn);
+    break;
+  case PN_CONNECTION_REMOTE_CLOSE:
+    pn_connection_release(conn);
+    break;
+  default:
+    break;
+  }
+}
+
+static void test_reactor_connect(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  pn_handler_t *sh = pn_handler_new(server_dispatch, sizeof(server_t), NULL);
+  server_t *srv = smem(sh);
+  pn_acceptor_t *acceptor = pn_reactor_acceptor(reactor, "0.0.0.0", "5678", sh);
+  srv->reactor = reactor;
+  srv->acceptor = acceptor;
+  srv->events = pn_list(PN_VOID, 0);
+  pn_handler_t *ch = pn_handler_new(client_dispatch, sizeof(client_t), NULL);
+  client_t *cli = cmem(ch);
+  cli->events = pn_list(PN_VOID, 0);
+  pn_connection_t *conn = pn_reactor_connection_to_host(reactor,
+                                                        "127.0.0.1",
+                                                        "5678",
+                                                        ch);
+  assert(conn);
+  pn_url_t *url = pn_url_parse(pn_reactor_get_connection_address(reactor, conn));
+  assert(strcmp(pn_url_get_host(url), "127.0.0.1") == 0);
+  assert(strcmp(pn_url_get_port(url), "5678") == 0);
+  pn_decref(url);
+  pn_reactor_run(reactor);
+  expect(srv->events, PN_CONNECTION_INIT, PN_CONNECTION_BOUND,
+         PN_CONNECTION_REMOTE_OPEN,
+         PN_CONNECTION_LOCAL_OPEN, PN_TRANSPORT,
+         PN_CONNECTION_REMOTE_CLOSE, PN_TRANSPORT_TAIL_CLOSED,
+         PN_CONNECTION_LOCAL_CLOSE, PN_TRANSPORT,
+         PN_TRANSPORT_HEAD_CLOSED, PN_TRANSPORT_CLOSED,
+         PN_CONNECTION_UNBOUND, PN_CONNECTION_FINAL, END);
+  pn_free(srv->events);
+  pn_decref(sh);
+  expect(cli->events, PN_CONNECTION_INIT, PN_CONNECTION_LOCAL_OPEN,
+         PN_CONNECTION_BOUND,
+         PN_CONNECTION_REMOTE_OPEN, PN_CONNECTION_LOCAL_CLOSE,
+         PN_TRANSPORT, PN_TRANSPORT_HEAD_CLOSED,
+         PN_CONNECTION_REMOTE_CLOSE, PN_TRANSPORT_TAIL_CLOSED,
+         PN_TRANSPORT_CLOSED, PN_CONNECTION_UNBOUND,
+         PN_CONNECTION_FINAL, END);
+  pn_free(cli->events);
+  pn_decref(ch);
+  pn_reactor_free(reactor);
+}
+
+static void test_reactor_bad_domain(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  assert(reactor);
+  pn_handler_t *ch = pn_handler_new(client_dispatch, sizeof(client_t), NULL);
+  client_t *cli = cmem(ch);
+  cli->events = pn_list(PN_VOID, 0);
+  pn_connection_t *connection = pn_reactor_connection_to_host(reactor, "somebogusdomain", "5672", ch);
+  assert(connection);
+  pn_reactor_run(reactor);
+
+  expect(cli->events, PN_CONNECTION_INIT, PN_CONNECTION_LOCAL_OPEN,
+         PN_CONNECTION_BOUND, PN_TRANSPORT_TAIL_CLOSED,
+         PN_TRANSPORT_ERROR, PN_TRANSPORT_HEAD_CLOSED,
+         PN_TRANSPORT_CLOSED, PN_CONNECTION_UNBOUND,
+         END);
+
+  pn_free(cli->events);
+  pn_decref(ch);
+  pn_reactor_free(reactor);
+}
+
+typedef struct {
+  int received;
+} sink_t;
+
+static sink_t *sink(pn_handler_t *handler) {
+  return (sink_t *) pn_handler_mem(handler);
+}
+
+void sink_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  sink_t *snk = sink(handler);
+  pn_delivery_t *dlv = pn_event_delivery(event);
+  switch (type) {
+  case PN_DELIVERY:
+    if (!pn_delivery_partial(dlv)) {
+      pn_delivery_settle(dlv);
+      snk->received++;
+    }
+    break;
+  default:
+    break;
+  }
+}
+
+typedef struct {
+  int remaining;
+} source_t;
+
+static source_t *source(pn_handler_t *handler) {
+  return (source_t *) pn_handler_mem(handler);
+}
+
+
+void source_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) {
+  source_t *src = source(handler);
+  pn_connection_t *conn = pn_event_connection(event);
+  switch (type) {
+  case PN_CONNECTION_INIT:
+    {
+      pn_session_t *ssn = pn_session(conn);
+      pn_link_t *snd = pn_sender(ssn, "sender");
+      pn_connection_open(conn);
+      pn_session_open(ssn);
+      pn_link_open(snd);
+    }
+    break;
+  case PN_LINK_FLOW:
+    {
+      pn_link_t *link = pn_event_link(event);
+      while (pn_link_credit(link) > 0 && src->remaining > 0) {
+        pn_delivery_t *dlv = pn_delivery(link, pn_dtag("", 0));
+        assert(dlv);
+        pn_delivery_settle(dlv);
+        src->remaining--;
+      }
+
+      if (!src->remaining) {
+        pn_connection_close(conn);
+      }
+    }
+    break;
+  case PN_CONNECTION_REMOTE_CLOSE:
+    pn_connection_release(conn);
+    break;
+  default:
+    break;
+  }
+}
+
+static void test_reactor_transfer(int count, int window) {
+  pn_reactor_t *reactor = pn_reactor();
+
+  pn_handler_t *sh = pn_handler_new(server_dispatch, sizeof(server_t), NULL);
+  server_t *srv = smem(sh);
+  pn_acceptor_t *acceptor = pn_reactor_acceptor(reactor, "0.0.0.0", "5678", sh);
+  srv->reactor = reactor;
+  srv->acceptor = acceptor;
+  srv->events = pn_list(PN_VOID, 0);
+  pn_handler_add(sh, pn_handshaker());
+  // XXX: a window of 1 doesn't work unless the flowcontroller is
+  // added after the thing that settles the delivery
+  pn_handler_add(sh, pn_flowcontroller(window));
+  pn_handler_t *snk = pn_handler_new(sink_dispatch, sizeof(sink_t), NULL);
+  sink(snk)->received = 0;
+  pn_handler_add(sh, snk);
+
+  pn_handler_t *ch = pn_handler_new(source_dispatch, sizeof(source_t), NULL);
+  source_t *src = source(ch);
+  src->remaining = count;
+  pn_connection_t *conn = NULL;
+  // Using the connection's hostname to set the connection address is
+  // deprecated. Once support is dropped the conditional code can be removed:
+  #if 0
+  conn = pn_reactor_connection(reactor, ch);
+  assert(conn);
+  pn_reactor_connection_set_address(reactor, conn, "127.0.0.1", "5678");
+  #else
+  // This is deprecated:
+  conn = pn_reactor_connection(reactor, ch);
+  pn_connection_set_hostname(conn, "127.0.0.1:5678");
+  #endif
+
+  pn_reactor_run(reactor);
+
+  assert(sink(snk)->received == count);
+
+  pn_free(srv->events);
+  pn_reactor_free(reactor);
+  pn_handler_free(sh);
+  pn_handler_free(ch);
+}
+
+static void test_reactor_schedule(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  pn_handler_t *root = pn_reactor_get_handler(reactor);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_handler_add(root, test_handler(reactor, events));
+  pn_reactor_schedule(reactor, 0, NULL);
+  pn_reactor_run(reactor);
+  pn_reactor_free(reactor);
+  expect(events, PN_REACTOR_INIT, PN_SELECTABLE_INIT, PN_SELECTABLE_UPDATED, PN_REACTOR_QUIESCED,
+         PN_TIMER_TASK, PN_SELECTABLE_UPDATED, PN_SELECTABLE_FINAL, PN_REACTOR_FINAL, END);
+  pn_free(events);
+}
+
+static void test_reactor_schedule_handler(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  pn_handler_t *root = pn_reactor_get_handler(reactor);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_list_t *tevents = pn_list(PN_VOID, 0);
+  pn_handler_add(root, test_handler(reactor, events));
+  pn_handler_t *th = test_handler(reactor, tevents);
+  pn_reactor_schedule(reactor, 0, th);
+  pn_reactor_run(reactor);
+  pn_reactor_free(reactor);
+  pn_handler_free(th);
+  expect(events, PN_REACTOR_INIT, PN_SELECTABLE_INIT, PN_SELECTABLE_UPDATED, PN_REACTOR_QUIESCED, PN_SELECTABLE_UPDATED,
+         PN_SELECTABLE_FINAL, PN_REACTOR_FINAL, END);
+  expect(tevents, PN_TIMER_TASK, END);
+  pn_free(events);
+  pn_free(tevents);
+}
+
+static void test_reactor_schedule_cancel(void) {
+  pn_reactor_t *reactor = pn_reactor();
+  pn_handler_t *root = pn_reactor_get_handler(reactor);
+  pn_list_t *events = pn_list(PN_VOID, 0);
+  pn_handler_add(root, test_handler(reactor, events));
+  pn_task_t *task = pn_reactor_schedule(reactor, 0, NULL);
+  pn_task_cancel(task);
+  pn_reactor_run(reactor);
+  pn_reactor_free(reactor);
+  expect(events, PN_REACTOR_INIT, PN_SELECTABLE_INIT, PN_SELECTABLE_UPDATED,
+         PN_SELECTABLE_FINAL, PN_REACTOR_FINAL, END);
+  pn_free(events);
+}
+
+int main(int argc, char **argv)
+{
+  test_reactor_event_root();
+  test_reactor();
+  test_reactor_free();
+  test_reactor_run();
+  test_reactor_run_free();
+  test_reactor_handler();
+  test_reactor_handler_free();
+  test_reactor_handler_run();
+  test_reactor_handler_run_free();
+  test_reactor_connection();
+  test_reactor_connection_factory();
+  test_reactor_bad_domain();
+  test_reactor_acceptor();
+  test_reactor_acceptor_run();
+  test_reactor_connect();
+  for (int i = 0; i < 64; i++) {
+    test_reactor_transfer(i, 2);
+  }
+  test_reactor_transfer(1024, 64);
+  test_reactor_transfer(4*1024, 1024);
+  test_reactor_schedule();
+  test_reactor_schedule_handler();
+  test_reactor_schedule_cancel();
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/refcount.c
----------------------------------------------------------------------
diff --git a/c/tests/refcount.c b/c/tests/refcount.c
new file mode 100644
index 0000000..487f115
--- /dev/null
+++ b/c/tests/refcount.c
@@ -0,0 +1,393 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/connection.h>
+#include <proton/event.h>
+#include <proton/session.h>
+#include <proton/link.h>
+#include <proton/delivery.h>
+#include <proton/transport.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define assert(E) ((E) ? 0 : (abort(), 0))
+
+/**
+ * The decref order tests validate that whenever the last pointer to a
+ * child object, e.g. a session or a link, is about to go away, the
+ * parent object takes ownership of that reference if the child object
+ * has not been freed, this avoids reference cycles but allows
+ * navigation from parents to children.
+ **/
+
+#define SETUP_CSL                               \
+  pn_connection_t *conn = pn_connection();      \
+  pn_session_t *ssn = pn_session(conn);         \
+  pn_incref(ssn);                               \
+  pn_link_t *lnk = pn_sender(ssn, "sender");    \
+  pn_incref(lnk);                               \
+                                                \
+  assert(pn_refcount(conn) == 2);               \
+  assert(pn_refcount(ssn) == 2);                \
+  assert(pn_refcount(lnk) == 1);
+
+static void test_decref_order_csl(void) {
+  SETUP_CSL;
+
+  pn_decref(conn);
+  assert(pn_refcount(conn) == 1); // session keeps alive
+  pn_decref(ssn);
+  assert(pn_refcount(ssn) == 1); // link keeps alive
+  pn_decref(lnk);
+  // all gone now (requires valgrind to validate)
+}
+
+static void test_decref_order_cls(void) {
+  SETUP_CSL;
+
+  pn_decref(conn);
+  assert(pn_refcount(conn) == 1); // session keeps alive
+  pn_decref(lnk);
+  assert(pn_refcount(lnk) == 1); // session takes over ownership
+  pn_decref(ssn);
+  // all gone now (requires valgrind to validate)
+}
+
+static void test_decref_order_lcs(void) {
+  SETUP_CSL;
+
+  pn_decref(lnk);
+  assert(pn_refcount(lnk) == 1); // session takes over ownership
+  pn_decref(conn);
+  assert(pn_refcount(conn) == 1); // session keeps alive
+  pn_decref(ssn);
+  // all gone now (requires valgrind to validate)
+}
+
+static void test_decref_order_scl(void) {
+  SETUP_CSL;
+
+  pn_decref(ssn);
+  assert(pn_refcount(ssn) == 1); // link keeps alive
+  pn_decref(conn);
+  assert(pn_refcount(conn) == 1); // session keeps alive
+  pn_decref(lnk);
+  // all gone now (requires valgrind to validate)
+}
+
+static void test_decref_order_slc(void) {
+  SETUP_CSL;
+
+  pn_decref(ssn);
+  assert(pn_refcount(ssn) == 1); // link keeps alive
+  pn_decref(lnk);
+  assert(pn_refcount(ssn) == 1); // connection takes over ownership
+  assert(pn_refcount(lnk) == 1); // session takes over ownership
+  pn_decref(conn);
+  // all gone now (requires valgrind to validate)
+}
+
+static void test_decref_order_lsc(void) {
+  SETUP_CSL;
+
+  pn_decref(lnk);
+  assert(pn_refcount(lnk) == 1); // session takes over ownership
+  assert(pn_refcount(ssn) == 1);
+  pn_decref(ssn);
+  assert(pn_refcount(lnk) == 1);
+  assert(pn_refcount(ssn) == 1); // connection takes over ownership
+  pn_decref(conn);
+  // all gone now (requires valgrind to validate)
+}
+
+/**
+ * The incref order tests verify that once ownership of the last
+ * pointer to a child is taken over by a parent, it is reassigned when
+ * the child is increfed.
+ **/
+
+#define SETUP_INCREF_ORDER                      \
+  SETUP_CSL;                                    \
+  pn_decref(lnk);                               \
+  pn_decref(ssn);                               \
+  assert(pn_refcount(lnk) == 1);                \
+  assert(pn_refcount(ssn) == 1);                \
+  assert(pn_refcount(conn) == 1);
+
+static void test_incref_order_sl(void) {
+  SETUP_INCREF_ORDER;
+
+  pn_incref(ssn);
+  assert(pn_refcount(conn) == 2);
+  assert(pn_refcount(ssn) == 1);
+  assert(pn_refcount(lnk) == 1);
+  pn_incref(lnk);
+  assert(pn_refcount(conn) == 2);
+  assert(pn_refcount(ssn) == 2);
+  assert(pn_refcount(lnk) == 1);
+
+  pn_decref(conn);
+  pn_decref(ssn);
+  pn_decref(lnk);
+}
+
+static void test_incref_order_ls(void) {
+  SETUP_INCREF_ORDER;
+
+  pn_incref(lnk);
+  assert(pn_refcount(conn) == 2);
+  assert(pn_refcount(ssn) == 1);
+  assert(pn_refcount(lnk) == 1);
+  pn_incref(ssn);
+  assert(pn_refcount(conn) == 2);
+  assert(pn_refcount(ssn) == 2);
+  assert(pn_refcount(lnk) == 1);
+
+  pn_decref(conn);
+  pn_decref(ssn);
+  pn_decref(lnk);
+}
+
+static void swap(int array[], int i, int j) {
+  int a = array[i];
+  int b = array[j];
+  array[j] = a;
+  array[i] = b;
+}
+
+static void setup(void **objects) {
+  pn_connection_t *conn = pn_connection();
+  pn_session_t *ssn = pn_session(conn);
+  pn_incref(ssn);
+  pn_link_t *lnk = pn_sender(ssn, "sender");
+  pn_incref(lnk);
+  pn_delivery_t *dlv = pn_delivery(lnk, pn_dtag("dtag", 4));
+  pn_incref(dlv);
+
+  assert(pn_refcount(conn) == 2);
+  assert(pn_refcount(ssn) == 2);
+  assert(pn_refcount(lnk) == 2);
+  assert(pn_refcount(dlv) == 1);
+
+  objects[0] = conn;
+  objects[1] = ssn;
+  objects[2] = lnk;
+  objects[3] = dlv;
+}
+
+static bool decreffed(int *indexes, void **objects, int step, void *object) {
+  for (int i = 0; i <= step; i++) {
+    if (object == objects[indexes[i]]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool live_descendent(int *indexes, void **objects, int step, int objidx) {
+  for (int i = objidx + 1; i < 4; i++) {
+    if (!decreffed(indexes, objects, step, objects[i])) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static void assert_refcount(void *object, int expected) {
+  int rc = pn_refcount(object);
+  //printf("pn_refcount(%s) = %d\n", pn_object_reify(object)->name, rc);
+  assert(rc == expected);
+}
+
+static void test_decref_order(int *indexes, void **objects) {
+  setup(objects);
+
+  //printf("-----------\n");
+  for (int i = 0; i < 3; i++) {
+    int idx = indexes[i];
+    void *obj = objects[idx];
+    //printf("decreffing %s\n", pn_object_reify(obj)->name);
+    pn_decref(obj);
+    for (int j = 0; j <= i; j++) {
+      // everything we've decreffed already should have a refcount of
+      // 1 because it has been preserved by its parent
+      assert_refcount(objects[indexes[j]], 1);
+    }
+    for (int j = i+1; j < 4; j++) {
+      // everything we haven't decreffed yet should have a refcount of
+      // 2 unless it has a descendant that has not been decrefed (or
+      // it has no child) in which case it should have a refcount of 1
+      int idx = indexes[j];
+      void *obj = objects[idx];
+      assert(!decreffed(indexes, objects, i, obj));
+      if (live_descendent(indexes, objects, i, idx)) {
+        assert_refcount(obj, 2);
+      } else {
+        assert_refcount(obj, 1);
+      }
+    }
+  }
+
+  void *last = objects[indexes[3]];
+  //printf("decreffing %s\n", pn_object_reify(last)->name);
+  pn_decref(last);
+  // all should be gone now, need to run with valgrind to check
+}
+
+static void permute(int n, int *indexes, void **objects) {
+  int j;
+  if (n == 1) {
+    test_decref_order(indexes, objects);
+  } else {
+    for (int i = 1; i <= n; i++) {
+      permute(n-1, indexes, objects);
+      if ((n % 2) == 1) {
+        j = 1;
+      } else {
+        j = i;
+      }
+      swap(indexes, j-1, n-1);
+    }
+  }
+}
+
+static void test_decref_permutations(void) {
+  void *objects[4];
+  int indexes[4] = {0, 1, 2, 3};
+  permute(4, indexes, objects);
+}
+
+static void test_transport(void) {
+  pn_transport_t *transport = pn_transport();
+  assert(pn_refcount(transport) == 1);
+  pn_incref(transport);
+  assert(pn_refcount(transport) == 2);
+  pn_decref(transport);
+  assert(pn_refcount(transport) == 1);
+  pn_free(transport);
+}
+
+static void test_connection_transport(void) {
+  pn_connection_t *connection = pn_connection();
+  assert(pn_refcount(connection) == 1);
+  pn_transport_t *transport = pn_transport();
+  assert(pn_refcount(transport) == 1);
+  pn_transport_bind(transport, connection);
+  assert(pn_refcount(connection) == 2);
+  pn_decref(transport);
+  assert(pn_refcount(transport) == 1); // preserved by the bind
+  assert(pn_refcount(connection) == 1);
+  pn_free(connection);
+}
+
+static void test_transport_connection(void) {
+  pn_transport_t *transport = pn_transport();
+  assert(pn_refcount(transport) == 1);
+  pn_connection_t *connection = pn_connection();
+  assert(pn_refcount(connection) == 1);
+  pn_transport_bind(transport, connection);
+  assert(pn_refcount(connection) == 2);
+  pn_decref(connection);
+  assert(pn_refcount(connection) == 1);
+  assert(pn_refcount(transport) == 1);
+  pn_free(transport);
+}
+
+static void drain(pn_collector_t *collector) {
+  while (pn_collector_next(collector))
+    ;
+}
+
+static void test_collector_connection_transport(void) {
+  pn_collector_t *collector = pn_collector();
+  assert(pn_refcount(collector) == 1);
+  pn_connection_t *connection = pn_connection();
+  assert(pn_refcount(connection) == 1);
+  pn_connection_collect(connection, collector);
+  assert(pn_refcount(collector) == 2);
+  assert(pn_refcount(connection) == 2);
+  drain(collector);
+  assert(pn_refcount(connection) == 1);
+  pn_transport_t *transport = pn_transport();
+  assert(pn_refcount(transport) == 1);
+  pn_transport_bind(transport, connection);
+  assert(pn_refcount(transport) == 1);
+  assert(pn_refcount(connection) == 3);
+  drain(collector);
+  assert(pn_refcount(connection) == 2);
+  pn_decref(transport);
+  assert(pn_refcount(transport) == 1); // preserved by the bind
+  assert(pn_refcount(connection) == 1);
+  pn_free(connection);
+  assert(pn_refcount(transport) == 1); // events
+  assert(pn_refcount(connection) == 1); // events
+  pn_collector_free(collector);
+}
+
+static void test_collector_transport_connection(void) {
+  pn_collector_t *collector = pn_collector();
+  assert(pn_refcount(collector) == 1);
+  pn_transport_t *transport = pn_transport();
+  assert(pn_refcount(transport) == 1);
+  pn_connection_t *connection = pn_connection();
+  assert(pn_refcount(connection) == 1);
+  pn_connection_collect(connection, collector);
+  assert(pn_refcount(collector) == 2);
+  assert(pn_refcount(connection) == 2);
+  drain(collector);
+  assert(pn_refcount(connection) == 1);
+  pn_transport_bind(transport, connection);
+  assert(pn_refcount(connection) == 3);
+  assert(pn_refcount(transport) == 1);
+  drain(collector);
+  assert(pn_refcount(connection) == 2);
+  assert(pn_refcount(transport) == 1);
+  pn_decref(connection);
+  assert(pn_refcount(connection) == 1);
+  assert(pn_refcount(transport) == 1);
+  pn_free(transport);
+  assert(pn_refcount(connection) == 1);
+  assert(pn_refcount(transport) == 1);
+  pn_collector_free(collector);
+}
+
+int main(int argc, char **argv)
+{
+  test_decref_order_csl();
+  test_decref_order_cls();
+  test_decref_order_lcs();
+  test_decref_order_scl();
+  test_decref_order_slc();
+  test_decref_order_lsc();
+
+  test_incref_order_sl();
+  test_incref_order_ls();
+
+  test_decref_permutations();
+
+  test_transport();
+  test_connection_transport();
+  test_transport_connection();
+  test_collector_connection_transport();
+  test_collector_transport_connection();
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/README.txt
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/README.txt b/c/tests/ssl-certs/README.txt
new file mode 100644
index 0000000..9a8a4f9
--- /dev/null
+++ b/c/tests/ssl-certs/README.txt
@@ -0,0 +1,24 @@
+This directory contains basic self signed test certificates for use by
+proton examples.
+
+The ".pem" files are in the format expected by proton implementations
+using OpenSSL.  The ".p12" file are for Windows implementations using
+SChannel.
+
+The commands used to generate the certificates follow.
+
+
+make_pn_cert()
+{
+  name=$1
+  subject=$2
+  passwd=$3
+  # create the pem files
+  openssl req -newkey rsa:2048 -keyout $name-private-key.pem -out $name-certificate.pem -subj $subject -passout pass:$passwd -x509 -days 3650
+  # create the p12 files
+  openssl pkcs12 -export -out $name-full.p12 -passin pass:$passwd -passout pass:$passwd -inkey $name-private-key.pem -in $name-certificate.pem -name $name
+  openssl pkcs12 -export -out $name-certificate.p12 -in $name-certificate.pem -name $name -nokeys -passout pass:
+}
+
+make_pn_cert tserver /CN=test_server/OU=proton_test tserverpw
+make_pn_cert tclient /CN=test_client/OU=proton_test tclientpw

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tclient-certificate.p12
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tclient-certificate.p12 b/c/tests/ssl-certs/tclient-certificate.p12
new file mode 100644
index 0000000..4d0e000
Binary files /dev/null and b/c/tests/ssl-certs/tclient-certificate.p12 differ

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tclient-certificate.pem
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tclient-certificate.pem b/c/tests/ssl-certs/tclient-certificate.pem
new file mode 100644
index 0000000..8088e2e
--- /dev/null
+++ b/c/tests/ssl-certs/tclient-certificate.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKzCCAhOgAwIBAgIJAIV7frIjftgcMA0GCSqGSIb3DQEBCwUAMCwxFDASBgNV
+BAMMC3Rlc3RfY2xpZW50MRQwEgYDVQQLDAtwcm90b25fdGVzdDAeFw0xNTExMjcx
+ODEwMzlaFw0yNTExMjQxODEwMzlaMCwxFDASBgNVBAMMC3Rlc3RfY2xpZW50MRQw
+EgYDVQQLDAtwcm90b25fdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAPCIS4qUdOtQplUxZ6WW0LXcvosqFP6qOiCARLSEWpR3B8bq213rzefwwfcM
+4TtMr88bP+huLKmlyMfwpl8yB88eXkscPgaAce2zk24urWkFXKSQ6GPitWBLGqBa
+V+W0wJ4mfW7MwefVslWfGXI381QEUlBHjkFG30AtzMMTRj2GK2JqUlRXZPljGyB7
+WcXwxcoS+HkKV7FtHWSkLAzyXwQ9vsCUEYdWTUaGXfCUNRSRV7h1LIANbu03NxV0
+XdEl7WXcr7tuTw3axeUGhRFVhLegrxKLuZTTno4aAJnEr8uaDzjxvXnv3Ne2igvy
+gRfZgOMx+XrZEob9OpAoRghQt4cCAwEAAaNQME4wHQYDVR0OBBYEFE4vbyiM0RjG
+TLMLLGGhMZE/5x1GMB8GA1UdIwQYMBaAFE4vbyiM0RjGTLMLLGGhMZE/5x1GMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAErr/rvLS9Ig0UCMwh1J1lA9
+/gvXf93iIK/SjrFIAqYRmfZxg4husfoes8t2hFUeuqoH05TuSOoXG8p8DpgTSGmF
+jAFe+T90vJZTm0oqZkkkI/hdzjGQoHURRp9/O2Z/lm39KSKGVAN5pUWCUDi/G5iS
+P9LZPJN6a5syXMrR6x62IPxAXowlpXkRghKClF3zPOaOBTzT1V27EkI8IEgC+p45
+246EooLnw8ibB+ucNc3KHNzpgKGVd/622+I+Q5eg9AT9PLFttP+R2ECsrVDDPYuA
+p0qaSnwgeozj/d6K3FOgKKEKbzBmpWgkv0jdcVk18aPMHypI/RDtZ/+3ET2Ksi8=
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tclient-full.p12
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tclient-full.p12 b/c/tests/ssl-certs/tclient-full.p12
new file mode 100644
index 0000000..ad2d7d3
Binary files /dev/null and b/c/tests/ssl-certs/tclient-full.p12 differ

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tclient-private-key.pem
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tclient-private-key.pem b/c/tests/ssl-certs/tclient-private-key.pem
new file mode 100644
index 0000000..e5c114d
--- /dev/null
+++ b/c/tests/ssl-certs/tclient-private-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQICy6ghWp45z4CAggA
+MBQGCCqGSIb3DQMHBAiVdDoo4NIghQSCBMixGm1bm/omMxsaKnIPO7zm5dyLexJ+
+yTFpmh2KV7kQqmpzCyIOdoG6K8YqFnie2XdFWm3S8faRHoMq54bDmyEWIxfQPq5f
+I1iYFbIZkbnhUvK53RActsEUMf0locS4xylU7VQK3XTAwp0TVip3Lp3ehEMEdcXL
+iUWibGsoTPKcY9MIWGXZAJXsEXoeHt6k2hHo1G4E0/Bi6mLW1LY/cxZCjHTGD6qI
+Kt54SCCDvinqVa+rixw6yX9F14EA6bhALami8e+Ccd3lqHOyYlXcBaSS1ezCg6ig
+oNK97mC+gEGy1KlkZDKWXclFoOCBXRBe4DByre6Rlq3yeI9L42bvAuSBSmf5QT5g
+73Yl8vjEAKR65awBT09dPuKu7t+Fb6vkwF8/t+uyj9IuL+42UuXhMLK3ohf+6DbU
+8/zB4y3GXI80QmWM0+Wx4n6khFhPFLHt2q0Sn6V9PG1vtHyiq50oSCoyrPQLaecp
+hefnMCFBYTcT3JUwmoVGGy0boIAwL7T4aGsMt7QhwOx5tU35tKFxyY7m4fX14AKo
+2EIy+TPQwCGkGf3Puy/Pc9VA8IAxB5+WwSrjk+NeCv88eIX7gy43k4rCr+OmD9FF
+wknr3xoP3KYhNXjdZ4Ep/1UHSK+JAtzzbNLQjDcqN+gQPg/yUX6ih0j5K3Wvh9bK
+E/DvzbpJroUZPgzR+8z5O68CfsD+OIdpHBFTKqAFmzvUuqpADpr998LdCjD+lW+V
+xZZgZa8KEblwgiH3fdGbYl46Ho1zrZisf439DbqyybAuBIQB4NSZcL/MAgVGO17k
+QDpVElWZWYrFm4CFTcvS2HvIzRmbefF5m5oJedsN7Q6WQCp+3gnwYx1xIOknd7pW
+N4AHNnqjscSj9yACj/EiBVKAKNnC5H7ZGZTsaAjMETZyjLXfI2AZ3Fviz4zFR+oz
+NkAfFB6WUpRpl7H02FzrzYT7XkkLcXd6H6g+mv2iDa9uKWk/PS2QlqnJt8/dHEHD
+JKTG331yDK5GHlKAVGF3nP5BwFGgTQMuSoeiOervMXPUwDpQ8OaYkuaRej0cZLgT
+kAF9sUjqdsoYNcXDFHALp6y5g8qYkfrxrlIbKs82zIsmB5I+dtZbUaD3a0zAUrmW
+5Xm3Pc9dVP0EXKwfHz6zqPReEw2yYLisB5IoHd4M2wa3GzHBdra1ij4QTmvd3o7e
+buGFoX8KJQAcig0zpbYkoDP2gPhIh9rY4unVPQNX1Q8/wRsiJAZZsYvZY+A+SmuZ
+bwSwk+8ZJRsFzdYYYhQeRytD5cDAIQiClcI5Yj4T9dWQV/gf0N/wIBDNTMp0jJAy
+1l7PuXTfGZodNJWZH0oqsrNoWbn/k67NildvvofIKX+h09Nxszr670Pvj0qoHd5/
+CWq30lnxoJBUgbikFOz6ZuuHi/ZiCXL+haH+v8hJKN5ptRKnyYJQHchRB/IOGRoT
+5lmWxo8a7K+yXhp0VBDHJfw3685ms0xQX8Xj4X3MEuN64zd0fB1JmhtP12ydK85J
+ABawNKlRQPw5weckwtCviXQX+vX25S/xu3xA6IuqlHyqL/1t3DICzuxeOyT2mZxD
+tKQxEgNihPvu32vn9m74qA3adEaxuWPRkPZuTeITHOkMTZolvqYX/5olBsSgYwka
+7/g=
+-----END ENCRYPTED PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tserver-certificate.p12
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tserver-certificate.p12 b/c/tests/ssl-certs/tserver-certificate.p12
new file mode 100644
index 0000000..f38b67d
Binary files /dev/null and b/c/tests/ssl-certs/tserver-certificate.p12 differ

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tserver-certificate.pem
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tserver-certificate.pem b/c/tests/ssl-certs/tserver-certificate.pem
new file mode 100644
index 0000000..86231f3
--- /dev/null
+++ b/c/tests/ssl-certs/tserver-certificate.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKzCCAhOgAwIBAgIJAPnYOOQCJ3kDMA0GCSqGSIb3DQEBCwUAMCwxFDASBgNV
+BAMMC3Rlc3Rfc2VydmVyMRQwEgYDVQQLDAtwcm90b25fdGVzdDAeFw0xNTExMjcx
+ODEwMzlaFw0yNTExMjQxODEwMzlaMCwxFDASBgNVBAMMC3Rlc3Rfc2VydmVyMRQw
+EgYDVQQLDAtwcm90b25fdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKJNB78lgw4KtXDAvXocTLud6mbn6zgfB6ETIF+kcrukOH9DnPxjLBBM4Lig
+sp1+kmeudFK5/X8riDrvIW52b/rlEBLgLB+oDtI74m6OTbBs9L+FUFYOuxApetQF
+qoJy2vf9pWfy4uku24vCpeo7eVLi6ypu4lXE3LR+Km3FruHI1NKonHBMhwXSOWqF
+pYM6/4IZJ4fbV0+eU0Jrx+05s6XHg5vone2BVJKxeSIBje+zWnNnh8+qG0Z70Jgp
+aMetME5KGnLNgD1okpH0vb3lwjvuqkkx4WswGVZGbLLkSqqBpXPyM9fCFVy5aKSL
+DBq7IABQtO67O2nBzK3OyigHrUUCAwEAAaNQME4wHQYDVR0OBBYEFGV1PY0FCFbJ
+gpcDVKI6JGiRTt3kMB8GA1UdIwQYMBaAFGV1PY0FCFbJgpcDVKI6JGiRTt3kMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIx1TOTGWnnbpan4bse7wuvH
+GYSNDJhoTVS+X1TC63xukJD1JBAsCNTqg/ZV6lN3XEl7vvOXfGoCiyXM6a9XOKUo
+gSDtMrIr+wTh6Ss1yRO8QcCJmxH5JDXNu1ojtwsjFW/vneI4IL9kwpDsSlMQEX/E
+EkkQwtAx/Cvfe7pecZL4qSeykJOUMTts9H8fCAZqEiRZBA3ugJxqF8jwLP3DoFVQ
+6QZzKDY6CSPqfMnVb5i0MAIYVDpau+e3N9dgQpZD22F/zbua0OVbfAPdiRMnYxML
+FT4sxLnh+5YVqwpVWbEKp4onHe2Fq6YIvAxUYAJ3SBA2C8O2RAVKWxf1jko3jYI=
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tserver-full.p12
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tserver-full.p12 b/c/tests/ssl-certs/tserver-full.p12
new file mode 100644
index 0000000..d4a0e40
Binary files /dev/null and b/c/tests/ssl-certs/tserver-full.p12 differ

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl-certs/tserver-private-key.pem
----------------------------------------------------------------------
diff --git a/c/tests/ssl-certs/tserver-private-key.pem b/c/tests/ssl-certs/tserver-private-key.pem
new file mode 100644
index 0000000..91dcf0e
--- /dev/null
+++ b/c/tests/ssl-certs/tserver-private-key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI1cT0c2J3GcQCAggA
+MBQGCCqGSIb3DQMHBAi1hxSX2LJ+EgSCBMheHJ0iXr5A36Natjk/LcAEeKUMT9s+
+sMzoQceCWe8qMlQluWksr9iDdZ4JRIE8cpK8dbmx4dLY/SShUzdlhJHCSa4zZBHq
+8cZ/jGUF/RF1rqdgjK589eUq+uOl3/gXKzG/SxBqayy6PSn12kX3qnvmlkXCmtwU
+lg+iBm5wRcJ0MyVHaJkyA8sW8gr186C/VAau6Yu0crQXN7NRo9snrd4ewuYMIEhZ
+hgaG9XsYQWB1bPhAaKj80CZGxsQbJyTwcbKKkB3IY4WXx8mmhuiNl+vKT3HBJ9Ju
+YB6tgIjs8CJ4X2P4aU3yNJwG1QldgHSqmFGQ19bcZAw3s3kzwjdzRf4H2V16XOBd
+zQ5AEs/ffVMzMIAfkb1gYwgunZ2CVwwDJ2mi1RcgkX+Og2aFQc+fxXcVOnDcGLxV
+6fuCuZ2lsXfoiIyRh9kj3L75N12GtVUvgBdnMuOc1wPw6XnGQtDwt0acJpdexLMG
+k0j57r/gcgzTcmF3qNM+y9L/HLssgrJkvVJw2Np5gmtIyfDocsDUWUbClS4dTpYf
+oTngUTU+vWtHBuaUnb+f5/WJaRS/S7mmR8usbVG3i9WnEr/vlPJpbJFSjW2S6u/H
+7cFxKUmmBZsSuEv/EKt9a+Sh62kprOChm4myqfCI1/gvNKfUZC6m0Vp8zf+2LgAq
+2RgbMuqysMjWUtV4kDRZT7oCYckUDwsCHdbLES3nmVrtBk2ShMKHBpDp8/GoRuiV
+jdV7/EjKM/M1kXtFYYe3z7Mxv++lKYIJ7bNwVrQ8nrhce/VwHw6D5emWXNCJXhKZ
+FW7EM2ZOZ9eaKOlCsIi8sbjV6Yie9IY6HJKKmi3CpO0Tv5kLBdHkru8vGCSFm3O1
+n7wz7Ys5FBSlZ19X0NwQSCQX1Q4w+tido6i1SCRX0qJEdTNGuGwVXMHCf4/1zyHV
+hj8vnxh8fzo79LFrwlTTgwLg1Mr8sEUFFDJ/raJ1AhFXi8n24trtNR8EHxRW8wtD
+CLCKaqkEqfBiFXK/Yq3RrefCayPHiD+DaNsI8BwefMGpED3vD8YYCjAzXNPh/CSF
+sc1i1jWMzbJhzOoFSPNXhlfusbUFMFQ/6olatmH47SY6HBBOL3DDP5uQ0jw8P454
+QBjlMOpEZmZxO6TcEtJwu0vzgog4rQ5g3NWy6SIpjWehNwTynLt7yM3R5WTI6cZs
+0GTv/rqo2/SUoNsFmnGIUwj/DrBe4XOAq1nS2ZlEctxKhBsKH0hMFp6D1rXOzrgl
+bwcq+oistoB0TLcThShyNgSqzW1znQ1n5SVUk9b5rRhSttJxn3yOMewH0i3v8bPo
+HOhP5kaGjblPsCYyhlL/SNVF0OXEGTwLNey7FQdWFOwVwTRRXe7k+uGZ2d5hg+Jn
+It/trDZ1RDYbVmB7/Qy73c16J4mvhOUJ2de5ZciFBjkidbiiUKLj9xnjK9k9Sauo
+MKhNnDMAEU5VDQM3xNe5BRdX8dFLwfF5H64sU3nROF83aUnDgvfFEowYPnCuPYfm
+m4aQHfoBSg4j3v1OeOwktcl+Q2TjxPHfWhbWeRBfxOTqQ/suYhnQChuFSK/qyo9K
+ccgotqghhunRsWMoZT25H7AZM6yKb1sMz/0oyMRIKeGqoYh+ULM5XLY0xNYd4/xU
+WtQ=
+-----END ENCRYPTED PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/ssl.c
----------------------------------------------------------------------
diff --git a/c/tests/ssl.c b/c/tests/ssl.c
new file mode 100644
index 0000000..9acb362
--- /dev/null
+++ b/c/tests/ssl.c
@@ -0,0 +1,71 @@
+/*
+ * 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/ssl.h>
+
+#include "test_tools.h"
+
+static void test_ssl_protocols(test_t *t)
+{
+  pn_ssl_domain_t *sd = pn_ssl_domain(PN_SSL_MODE_CLIENT);
+
+  // Error no protocol set
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "")==PN_ARG_ERR);
+  // Unknown protocol
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "blah")==PN_ARG_ERR);
+  // Unknown protocol with known protocl prefix
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1.x")==PN_ARG_ERR);
+
+  // known protocols
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1")==0);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1.1")==0);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1.2")==0);
+
+  // Multiple protocols
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1 TLSv1.1 TLSv1.2")==0);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1 TLSv1.1")==0);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1.1 TLSv1.2")==0);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1 TLSv1.2")==0);
+
+  // Illegal separators
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1/TLSv1.1 TLSv1.2")==PN_ARG_ERR);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1-TLSv1.1 TLSv1.2")==PN_ARG_ERR);
+
+  // Legal separators
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1,TLSv1.1;TLSv1.2  ; ")==0);
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1;TLSv1.1 TLSv1.2,,,,")==0);
+
+  // Known followed by unknown protocols
+  TEST_CHECK(t, pn_ssl_domain_set_protocols(sd, "TLSv1 TLSv1.x;TLSv1_2")==PN_ARG_ERR);
+
+  pn_ssl_domain_free(sd);
+}
+
+int main(int argc, char **argv) {
+  int failed = 0;
+  // Don't run these tests if ssl functionality wasn't compiled
+  if (!pn_ssl_present()) {
+    fprintf(stderr, "No SSL implementation to test\n");
+    return failed;
+  }
+#if !defined(_WIN32)
+  RUN_ARGV_TEST(failed, t, test_ssl_protocols(&t));
+#endif
+  return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/test_config.h.in
----------------------------------------------------------------------
diff --git a/c/tests/test_config.h.in b/c/tests/test_config.h.in
new file mode 100644
index 0000000..d1d3a18
--- /dev/null
+++ b/c/tests/test_config.h.in
@@ -0,0 +1,26 @@
+#ifndef TESTS_TEST_CONFIG_H
+#define TESTS_TEST_CONFIG_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.
+ */
+
+/* Make source tree locations available to tests */
+#define CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@"
+
+#endif // TESTS_TEST_CONFIG_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/test_handler.h
----------------------------------------------------------------------
diff --git a/c/tests/test_handler.h b/c/tests/test_handler.h
new file mode 100644
index 0000000..108d0d9
--- /dev/null
+++ b/c/tests/test_handler.h
@@ -0,0 +1,170 @@
+#ifndef TESTS_TEST_DRIVER_H
+#define TESTS_TEST_DRIVER_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 "test_tools.h"
+#include <proton/ssl.h>
+
+/* C event handlers for tests */
+
+#define MAX_EVENT_LOG 2048         /* Max number of event types stored per proactor_test */
+
+struct test_handler_t;
+
+/* Returns 0 if the test should continue processing events, non-0 if processing should pause here */
+typedef pn_event_type_t (*test_handler_fn)(struct test_handler_t*, pn_event_t*);
+
+/* A handler that logs event types and delegates to another handler */
+typedef struct test_handler_t {
+  test_t *t;
+  test_handler_fn f;
+  pn_event_type_t log[MAX_EVENT_LOG]; /* Log of event types */
+  size_t log_size;                    /* Number of events in the log */
+  void *context;                      /* Generic test context */
+  /* Specific context slots for proton objects commonly used by handlers  */
+  pn_connection_t *connection;
+  pn_session_t *session;
+  pn_link_t *link;
+  pn_link_t *sender;
+  pn_link_t *receiver;
+  pn_delivery_t *delivery;
+  pn_ssl_domain_t *ssl_domain;
+} test_handler_t;
+
+void test_handler_init(test_handler_t *th, test_t *t, test_handler_fn f) {
+  memset(th, 0, sizeof(*th));
+  th->t = t;
+  th->f = f;
+}
+
+/* Save event type in the handler log */
+void test_handler_log(test_handler_t *th, pn_event_t *e) {
+  TEST_ASSERT(th->log_size < MAX_EVENT_LOG);
+  th->log[th->log_size++] = pn_event_type(e);
+}
+
+/* Keep at most n events in the handler's log, remove old events if necessary */
+void test_handler_clear(test_handler_t *th, size_t n) {
+  if (n == 0) {
+    th->log_size = 0;
+  } else if (n < th->log_size) {
+    memmove(th->log, th->log + th->log_size - n, n * sizeof(pn_event_type_t));
+    th->log_size = n;
+  }
+}
+
+void test_etypes_expect_(test_t *t, pn_event_type_t *etypes, size_t size, const char* file, int line, ...) {
+  va_list ap;
+  va_start(ap, line);             /* ap is null terminated */
+  pn_event_type_t want = (pn_event_type_t)va_arg(ap, int);
+  size_t i = 0;
+  while (want && i < size && want == etypes[i]) {
+    ++i;
+    want = (pn_event_type_t)va_arg(ap, int);
+  }
+  if (i < size || want) {
+    test_errorf_(t, NULL, file, line, "event mismatch");
+    fprintf(stderr, "after:");
+    for (size_t j = 0; j < i; ++j) { /* These events matched */
+      fprintf(stderr, " %s", pn_event_type_name(etypes[j]));
+    }
+    fprintf(stderr, "\n want:");
+    for (; want; want = (pn_event_type_t)va_arg(ap, int)) {
+      fprintf(stderr, " %s", pn_event_type_name(want));
+    }
+    fprintf(stderr, "\n  got:");
+    for (; i < size; ++i) {
+      fprintf(stderr, " %s", pn_event_type_name(etypes[i]));
+    }
+    fprintf(stderr, "\n");
+  }
+  va_end(ap);
+}
+
+#define TEST_HANDLER_EXPECT(TH, ...) do {                               \
+    test_etypes_expect_((TH)->t, (TH)->log, (TH)->log_size, __FILE__, __LINE__, __VA_ARGS__); \
+    test_handler_clear((TH), 0);                                         \
+  } while(0)
+
+#define TEST_HANDLER_EXPECT_LAST(TH, ETYPE) do {                        \
+    test_handler_clear((TH), 1);                                        \
+    test_etypes_expect_((TH)->t, (TH)->log, (TH)->log_size, __FILE__, __LINE__, ETYPE, 0); \
+    test_handler_clear((TH), 0);                                         \
+  } while(0)
+
+/* A pn_connection_driver_t with a test_handler */
+typedef struct test_connection_driver_t {
+  test_handler_t handler;
+  pn_connection_driver_t driver;
+} test_connection_driver_t;
+
+void test_connection_driver_init(test_connection_driver_t *d, test_t *t, test_handler_fn f, void* context)
+{
+  test_handler_init(&d->handler, t, f);
+  d->handler.context = context;
+  pn_connection_driver_init(&d->driver, NULL, NULL);
+}
+
+void test_connection_driver_destroy(test_connection_driver_t *d) {
+  pn_connection_driver_destroy(&d->driver);
+}
+
+pn_event_type_t test_connection_driver_handle(test_connection_driver_t *d) {
+  for (pn_event_t *e = pn_connection_driver_next_event(&d->driver);
+       e;
+       e = pn_connection_driver_next_event(&d->driver))
+  {
+    test_handler_log(&d->handler, e);
+    pn_event_type_t et = d->handler.f ? d->handler.f(&d->handler, e) : PN_EVENT_NONE;
+    if (et) return et;
+  }
+  return PN_EVENT_NONE;
+}
+
+/* Transfer data from one driver to another in memory */
+static int test_connection_drivers_xfer(test_connection_driver_t *dst, test_connection_driver_t *src)
+{
+  pn_bytes_t wb = pn_connection_driver_write_buffer(&src->driver);
+  pn_rwbytes_t rb =  pn_connection_driver_read_buffer(&dst->driver);
+  size_t size = rb.size < wb.size ? rb.size : wb.size;
+  if (size) {
+    memcpy(rb.start, wb.start, size);
+    pn_connection_driver_write_done(&src->driver, size);
+    pn_connection_driver_read_done(&dst->driver, size);
+  }
+  return size;
+}
+
+/* Run a pair of test drivers till there is nothing to do or one of their handlers returns non-0
+   In that case return that driver
+*/
+test_connection_driver_t* test_connection_drivers_run(test_connection_driver_t *a, test_connection_driver_t *b)
+{
+  int data = 0;
+  do {
+    if (test_connection_driver_handle(a)) return a;
+    if (test_connection_driver_handle(b)) return b;
+    data = test_connection_drivers_xfer(a, b) + test_connection_drivers_xfer(b, a);
+  } while (data || pn_connection_driver_has_event(&a->driver) || pn_connection_driver_has_event(&b->driver));
+  return NULL;
+}
+
+#endif // TESTS_TEST_DRIVER_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/test_tools.h
----------------------------------------------------------------------
diff --git a/c/tests/test_tools.h b/c/tests/test_tools.h
new file mode 100644
index 0000000..d046a43
--- /dev/null
+++ b/c/tests/test_tools.h
@@ -0,0 +1,239 @@
+#ifndef TESTS_TEST_TOOLS_H
+#define TESTS_TEST_TOOLS_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/condition.h>
+#include <proton/connection_driver.h>
+#include <proton/delivery.h>
+#include <proton/event.h>
+#include <proton/link.h>
+#include <proton/message.h>
+#include <proton/proactor.h>
+#include <proton/transport.h>
+#include <proton/type_compat.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Handy way to make pn_bytes: PN_BYTES_LITERAL(FOO) => pn_bytes("FOO",3) */
+#define PN_BYTES_LITERAL(X) (pn_bytes(sizeof(#X)-1, #X))
+
+/* A struct to collect the results of a test, created by RUN_TEST macro. */
+typedef struct test_t {
+  const char* name;
+  int errors;
+  uintptr_t data;               /* Test can store some non-error data here */
+} test_t;
+
+/* Internal, use macros. Print error message and increase the t->errors count.
+   All output from test macros goes to stderr so it interleaves with PN_TRACE logs.
+*/
+void test_vlogf_(test_t *t, const char *prefix, const char* expr,
+                 const char* file, int line, const char *fmt, va_list ap)
+{
+  fprintf(stderr, "%s:%d", file, line);
+  if (prefix && *prefix) fprintf(stderr, ": %s", prefix);
+  if (expr && *expr) fprintf(stderr, ": %s", expr);
+  if (fmt && *fmt) {
+    fprintf(stderr, ": ");
+    vfprintf(stderr, fmt, ap);
+  }
+  if (t) fprintf(stderr, " [%s]", t->name);
+  fprintf(stderr, "\n");
+  fflush(stderr);
+}
+
+void test_logf_(test_t *t, const char *prefix, const char* expr,
+                const char* file, int line, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  test_vlogf_(t, prefix, expr, file, line, fmt, ap);
+  va_end(ap);
+}
+
+void test_errorf_(test_t *t, const char* expr,
+                  const char* file, int line, const char *fmt, ...) {
+  ++t->errors;
+  va_list ap;
+  va_start(ap, fmt);
+  test_vlogf_(t, "error", expr, file, line, fmt, ap);
+  va_end(ap);
+}
+
+bool test_check_(test_t *t, bool expr, const char *sexpr,
+                 const char *file, int line, const char* fmt, ...) {
+  if (!expr) {
+    ++t->errors;
+    va_list ap;
+    va_start(ap, fmt);
+    test_vlogf_(t, "check failed", sexpr, file, line, fmt, ap);
+    va_end(ap);
+  }
+  return expr;
+}
+
+/* Call via TEST_ASSERT macros */
+void assert_fail_(const char* expr, const char* file, int line, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  test_vlogf_(NULL, "assertion failed", expr, file, line, fmt, ap);
+  va_end(ap);
+  abort();
+}
+
+/* Unconditional assert (does not depend on NDEBUG) for tests. */
+#define TEST_ASSERT(expr)                                               \
+  ((expr) ?  (void)0 : assert_fail_(#expr, __FILE__, __LINE__, NULL))
+
+/* Unconditional assert with printf-style message (does not depend on NDEBUG) for tests. */
+#define TEST_ASSERTF(expr, ...)                                         \
+  ((expr) ?  (void)0 : assert_fail_(#expr, __FILE__, __LINE__, __VA_ARGS__))
+
+/* Like TEST_ASSERT but includes  errno string for err */
+/* TODO aconway 2017-02-16: not thread safe, replace with safe strerror_r or similar */
+#define TEST_ASSERT_ERRNO(expr, err)            \
+  TEST_ASSERTF((expr), "%s", strerror(err))
+
+
+/* Print a message but don't mark the test as having an error */
+#define TEST_LOGF(TEST, ...)                                            \
+  test_logf_((TEST), "info", NULL, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Print an error with printf-style message, increment TEST->errors */
+#define TEST_ERRORF(TEST, ...)                                  \
+  test_errorf_((TEST), NULL, __FILE__, __LINE__, __VA_ARGS__)
+
+/* If EXPR is false, print and record an error for t including #EXPR  */
+#define TEST_CHECKF(TEST, EXPR, ...)                                    \
+  test_check_((TEST), (EXPR), #EXPR, __FILE__, __LINE__, __VA_ARGS__)
+
+/* If EXPR is false, print and record an error for t including EXPR  */
+#define TEST_CHECK(TEST, EXPR)                                  \
+  test_check_((TEST), (EXPR), #EXPR, __FILE__, __LINE__, "")
+
+/* If EXPR is false, print and record an error for t NOT including #EXPR  */
+#define TEST_CHECKNF(TEST, EXPR, ...)                                   \
+  test_check_((TEST), (EXPR), NULL, __FILE__, __LINE__, __VA_ARGS__)
+
+bool test_etype_equal_(test_t *t, pn_event_type_t want, pn_event_type_t got, const char *file, int line) {
+  return test_check_(t, want == got, NULL, file, line, "want %s got %s",
+                     pn_event_type_name(want),
+                     pn_event_type_name(got));
+}
+#define TEST_ETYPE_EQUAL(TEST, WANT, GOT) test_etype_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
+
+bool test_int_equal_(test_t *t, int want, int got, const char *file, int line) {
+  return test_check_(t, want == got, NULL, file, line, "want %d, got %d", want, got);
+}
+#define TEST_INT_EQUAL(TEST, WANT, GOT) test_int_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
+
+bool test_str_equal_(test_t *t, const char* want, const char* got, const char *file, int line) {
+  return test_check_(t, !strcmp(want, got), NULL, file, line, "want '%s', got '%s'", want, got);
+}
+#define TEST_STR_EQUAL(TEST, WANT, GOT) test_str_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
+
+#define TEST_STR_IN(TEST, WANT, GOT)                                    \
+  test_check_((TEST), strstr((GOT), (WANT)), NULL, __FILE__, __LINE__, "'%s' not in '%s'", (WANT), (GOT))
+
+#define TEST_COND_EMPTY(TEST, C)                                        \
+  TEST_CHECKNF((TEST), (!(C) || !pn_condition_is_set(C)), "Unexpected condition - %s:%s", \
+              pn_condition_get_name(C), pn_condition_get_description(C))
+
+#define TEST_COND_DESC(TEST, WANT, C)                                   \
+  (TEST_CHECKNF(t, pn_condition_is_set((C)), "No condition, expected :%s", (WANT)) ? \
+   TEST_STR_IN(t, (WANT), pn_condition_get_description(C)) : 0);
+
+#define TEST_COND_NAME(TEST, WANT, C)                                   \
+  (TEST_CHECKNF(t, pn_condition_is_set((C)), "No condition, expected %s:", (WANT)) ? \
+   TEST_STR_EQUAL(t, (WANT), pn_condition_get_name(C)) : 0);
+
+/* T is name of a test_t variable, EXPR is the test expression (which should update T)
+   FAILED is incremented if the test has errors
+*/
+#define RUN_TEST(FAILED, T, EXPR) do {                                  \
+    fprintf(stderr, "TEST: %s\n", #EXPR);                               \
+    fflush(stdout);                                                     \
+    test_t T = { #EXPR, 0 };                                            \
+    (EXPR);                                                             \
+    if (T.errors) {                                                     \
+      fprintf(stderr, "FAIL: %s (%d errors)\n", #EXPR, T.errors);       \
+      ++(FAILED);                                                       \
+    }                                                                   \
+  } while(0)
+
+/* Like RUN_TEST but only if one of the argv strings is found in the test EXPR */
+#define RUN_ARGV_TEST(FAILED, T, EXPR) do {     \
+    if (argc == 1) {                            \
+      RUN_TEST(FAILED, T, EXPR);                \
+    } else {                                    \
+      for (int i = 1; i < argc; ++i) {          \
+        if (strstr(#EXPR, argv[i])) {           \
+          RUN_TEST(FAILED, T, EXPR);            \
+          break;                                \
+        }                                       \
+      }                                         \
+    }                                           \
+  } while(0)
+
+/* Ensure buf has at least size bytes, use realloc if need be */
+void rwbytes_ensure(pn_rwbytes_t *buf, size_t size) {
+  if (buf->start == NULL || buf->size < size) {
+    buf->start = (char*)realloc(buf->start, size);
+    buf->size = size;
+  }
+}
+
+static const size_t BUF_MIN = 1024;
+
+/* Encode message m into buffer buf, return the size.
+ * The buffer is expanded using realloc() if needed.
+ */
+size_t message_encode(pn_message_t* m, pn_rwbytes_t *buf) {
+  int err = 0;
+  rwbytes_ensure(buf, BUF_MIN);
+  size_t size = buf->size;
+  while ((err = pn_message_encode(m, buf->start, &size)) != 0) {
+    if (err == PN_OVERFLOW) {
+      rwbytes_ensure(buf, buf->size * 2);
+      size = buf->size;
+    } else {
+      TEST_ASSERTF(err == 0, "encoding: %s %s", pn_code(err), pn_error_text(pn_message_error(m)));
+    }
+  }
+  return size;
+}
+
+/* Decode message from delivery d into message m.
+ * Use buf to hold intermediate message data, expand with realloc() if needed.
+ */
+void message_decode(pn_message_t *m, pn_delivery_t *d, pn_rwbytes_t *buf) {
+  pn_link_t *l = pn_delivery_link(d);
+  ssize_t size = pn_delivery_pending(d);
+  rwbytes_ensure(buf, size);
+  TEST_ASSERT(size == pn_link_recv(l, buf->start, size));
+  pn_message_clear(m);
+  TEST_ASSERTF(!pn_message_decode(m, buf->start, size), "decode: %s", pn_error_text(pn_message_error(m)));
+}
+
+#endif // TESTS_TEST_TOOLS_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tests/valgrind.supp
----------------------------------------------------------------------
diff --git a/c/tests/valgrind.supp b/c/tests/valgrind.supp
new file mode 100644
index 0000000..282a18c
--- /dev/null
+++ b/c/tests/valgrind.supp
@@ -0,0 +1,131 @@
+{
+   SSL does a number of uninitialized accesses (expected) 1
+   Memcheck:Cond
+   fun:BN_bin2bn
+   obj:*
+   obj:*
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 2
+   Memcheck:Cond
+   fun:BN_num_bits_word
+   fun:BN_num_bits
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 3
+   Memcheck:Value8
+   fun:BN_num_bits_word
+   fun:BN_num_bits
+   fun:BN_mod_exp_mont_consttime
+   obj:*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 4
+   Memcheck:Value8
+   fun:BN_mod_exp_mont_consttime
+   obj:*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (FreeBSD version)
+   Memcheck:Value8
+   fun:BN_num_bits_word
+   fun:BN_num_bits
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*libcrypto.so*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (FreeBSD version)
+   Memcheck:Value8
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*libcrypto.so*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 5
+   Memcheck:Value4
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*
+   obj:*
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 6
+   Memcheck:Value4
+   fun:BN_num_bits_word
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*
+   obj:*
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 7
+   Memcheck:Cond
+   fun:ASN1_STRING_set
+   fun:ASN1_mbstring_ncopy
+   fun:ASN1_mbstring_copy
+}
+
+{
+   Since we can never safely uninitialize SSL, allow this
+   Memcheck:Leak
+   fun:_vgrZU_libcZdsoZa_realloc
+   fun:CRYPTO_realloc
+   fun:lh_insert
+   obj:/lib64/libcrypto.so.0.9.8e
+   fun:ERR_load_strings
+   fun:ERR_load_X509V3_strings
+   fun:ERR_load_crypto_strings
+   fun:SSL_load_error_strings
+}
+
+{
+   Since we can never safely uninitialize SSL, allow this
+   Memcheck:Leak
+   fun:_vgrZU_libcZdsoZa_malloc
+   fun:CRYPTO_malloc
+   fun:lh_new
+   fun:OBJ_NAME_init
+   fun:OBJ_NAME_add
+   fun:EVP_add_cipher
+   fun:SSL_library_init
+}
+
+{
+   Since we can never safely uninitialize SSL, allow this
+   Memcheck:Leak
+   fun:malloc
+   obj:*
+   fun:CRYPTO_malloc
+}
+
+{
+   Known memory leak in cyrus-sasl (fixed in 2.1.26)
+   Memcheck:Leak
+   fun:malloc
+   fun:*
+   fun:sasl_config_init
+   fun:sasl_server_init
+}
+
+{
+   Known bug in glibc which tries to free ipv6 related static when getaddrinfo used
+   Memcheck:Free
+   fun:free
+   fun:__libc_freeres
+   fun:_vgnU_freeres
+   fun:__run_exit_handlers
+   fun:exit
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c/tools/CMakeLists.txt b/c/tools/CMakeLists.txt
new file mode 100644
index 0000000..7a577cb
--- /dev/null
+++ b/c/tools/CMakeLists.txt
@@ -0,0 +1,53 @@
+#
+# 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(CheckIncludeFiles)
+
+include_directories (${PN_C_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+CHECK_INCLUDE_FILES("inttypes.h" INTTYPES_AVAILABLE)
+if (INTTYPES_AVAILABLE)
+  list(APPEND PLATFORM_DEFINITIONS "USE_INTTYPES")
+else (INTTYPES_AVAILABLE)
+  if (CMAKE_COMPILER_IS_GNUCC)
+    # since inttypes.h provides portable printf format macros
+    set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format")
+  endif (CMAKE_COMPILER_IS_GNUCC)
+endif (INTTYPES_AVAILABLE)
+
+add_executable(msgr-recv msgr-recv.c msgr-common.c)
+add_executable(msgr-send msgr-send.c msgr-common.c)
+add_executable(reactor-recv reactor-recv.c msgr-common.c)
+add_executable(reactor-send reactor-send.c msgr-common.c)
+
+target_link_libraries(msgr-recv qpid-proton)
+target_link_libraries(msgr-send qpid-proton)
+target_link_libraries(reactor-recv qpid-proton)
+target_link_libraries(reactor-send qpid-proton)
+
+set_target_properties (
+  msgr-recv msgr-send reactor-recv reactor-send
+  PROPERTIES
+  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS}"
+  COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
+)
+
+if (BUILD_WITH_CXX)
+  set_source_files_properties (msgr-recv.c msgr-send.c msgr-common.c reactor-recv.c reactor-send.c PROPERTIES LANGUAGE CXX)
+endif (BUILD_WITH_CXX)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/README.txt
----------------------------------------------------------------------
diff --git a/c/tools/README.txt b/c/tools/README.txt
new file mode 100644
index 0000000..7552489
--- /dev/null
+++ b/c/tools/README.txt
@@ -0,0 +1,14 @@
+This directory contains applications built using proton.  These
+applications are used by the testbed for soak tests.  See the
+"soak.py" file for the tests that utilize these applications.
+
+These applications can be used standalone to generate or consume
+message traffic.
+
+Contents:
+
+msgr-send - this Messenger-based application generates message
+   traffic, and can be configured to consume responses.
+
+msgr-recv - this Messenger-based application consumes message traffic,
+   and can be configured to forward or reply to received messages.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/include/pncompat/internal/LICENSE.txt
----------------------------------------------------------------------
diff --git a/c/tools/include/pncompat/internal/LICENSE.txt b/c/tools/include/pncompat/internal/LICENSE.txt
new file mode 100644
index 0000000..2c1799c
--- /dev/null
+++ b/c/tools/include/pncompat/internal/LICENSE.txt
@@ -0,0 +1,32 @@
+Free Getopt
+Copyright (c)2002-2003 Mark K. Kim
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the original author of this software nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/include/pncompat/internal/getopt.c
----------------------------------------------------------------------
diff --git a/c/tools/include/pncompat/internal/getopt.c b/c/tools/include/pncompat/internal/getopt.c
new file mode 100644
index 0000000..5f24dd8
--- /dev/null
+++ b/c/tools/include/pncompat/internal/getopt.c
@@ -0,0 +1,250 @@
+/*****************************************************************************
+* getopt.c - competent and free getopt library.
+* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $
+*
+* Copyright (c)2002-2003 Mark K. Kim
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+*   * Redistributions of source code must retain the above copyright
+*     notice, this list of conditions and the following disclaimer.
+*
+*   * Redistributions in binary form must reproduce the above copyright
+*     notice, this list of conditions and the following disclaimer in
+*     the documentation and/or other materials provided with the
+*     distribution.
+*
+*   * Neither the original author of this software nor the names of its
+*     contributors may be used to endorse or promote products derived
+*     from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+
+static const char* ID = "$Id: getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $";
+
+
+char* optarg = NULL;
+int optind = 0;
+int opterr = 1;
+int optopt = '?';
+
+
+static char** prev_argv = NULL;        /* Keep a copy of argv and argc to */
+static int prev_argc = 0;              /*    tell if getopt params change */
+static int argv_index = 0;             /* Option we're checking */
+static int argv_index2 = 0;            /* Option argument we're checking */
+static int opt_offset = 0;             /* Index into compounded "-option" */
+static int dashdash = 0;               /* True if "--" option reached */
+static int nonopt = 0;                 /* How many nonopts we've found */
+
+static void increment_index()
+{
+	/* Move onto the next option */
+	if(argv_index < argv_index2)
+	{
+		while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-'
+				&& argv_index < argv_index2+1);
+	}
+	else argv_index++;
+	opt_offset = 1;
+}
+
+
+/*
+* Permutes argv[] so that the argument currently being processed is moved
+* to the end.
+*/
+static int permute_argv_once()
+{
+	/* Movability check */
+	if(argv_index + nonopt >= prev_argc) return 1;
+	/* Move the current option to the end, bring the others to front */
+	else
+	{
+		char* tmp = prev_argv[argv_index];
+
+		/* Move the data */
+		memmove(&prev_argv[argv_index], &prev_argv[argv_index+1],
+				sizeof(char**) * (prev_argc - argv_index - 1));
+		prev_argv[prev_argc - 1] = tmp;
+
+		nonopt++;
+		return 0;
+	}
+}
+
+
+int getopt(int argc, char** argv, char* optstr)
+{
+	int c = 0;
+
+	/* If we have new argv, reinitialize */
+	if(prev_argv != argv || prev_argc != argc)
+	{
+		/* Initialize variables */
+		prev_argv = argv;
+		prev_argc = argc;
+		argv_index = 1;
+		argv_index2 = 1;
+		opt_offset = 1;
+		dashdash = 0;
+		nonopt = 0;
+	}
+
+	/* Jump point in case we want to ignore the current argv_index */
+	getopt_top:
+
+	/* Misc. initializations */
+	optarg = NULL;
+
+	/* Dash-dash check */
+	if(argv[argv_index] && !strcmp(argv[argv_index], "--"))
+	{
+		dashdash = 1;
+		increment_index();
+	}
+
+	/* If we're at the end of argv, that's it. */
+	if(argv[argv_index] == NULL)
+	{
+		c = -1;
+	}
+	/* Are we looking at a string? Single dash is also a string */
+	else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-"))
+	{
+		/* If we want a string... */
+		if(optstr[0] == '-')
+		{
+			c = 1;
+			optarg = argv[argv_index];
+			increment_index();
+		}
+		/* If we really don't want it (we're in POSIX mode), we're done */
+		else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT"))
+		{
+			c = -1;
+
+			/* Everything else is a non-opt argument */
+			nonopt = argc - argv_index;
+		}
+		/* If we mildly don't want it, then move it back */
+		else
+		{
+			if(!permute_argv_once()) goto getopt_top;
+			else c = -1;
+		}
+	}
+	/* Otherwise we're looking at an option */
+	else
+	{
+		char* opt_ptr = NULL;
+
+		/* Grab the option */
+		c = argv[argv_index][opt_offset++];
+
+		/* Is the option in the optstr? */
+		if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c);
+		else opt_ptr = strchr(optstr, c);
+		/* Invalid argument */
+		if(!opt_ptr)
+		{
+			if(opterr)
+			{
+				fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
+			}
+
+			optopt = c;
+			c = '?';
+
+			/* Move onto the next option */
+			increment_index();
+		}
+		/* Option takes argument */
+		else if(opt_ptr[1] == ':')
+		{
+			/* ie, -oARGUMENT, -xxxoARGUMENT, etc. */
+			if(argv[argv_index][opt_offset] != '\0')
+			{
+				optarg = &argv[argv_index][opt_offset];
+				increment_index();
+			}
+			/* ie, -o ARGUMENT (only if it's a required argument) */
+			else if(opt_ptr[2] != ':')
+			{
+				/* One of those "you're not expected to understand this" moment */
+				if(argv_index2 < argv_index) argv_index2 = argv_index;
+				while(argv[++argv_index2] && argv[argv_index2][0] == '-');
+				optarg = argv[argv_index2];
+
+				/* Don't cross into the non-option argument list */
+				if(argv_index2 + nonopt >= prev_argc) optarg = NULL;
+
+				/* Move onto the next option */
+				increment_index();
+			}
+			else
+			{
+				/* Move onto the next option */
+				increment_index();
+			}
+
+			/* In case we got no argument for an option with required argument */
+			if(optarg == NULL && opt_ptr[2] != ':')
+			{
+				optopt = c;
+				c = '?';
+
+				if(opterr)
+				{
+					fprintf(stderr,"%s: option requires an argument -- %c\n",
+							argv[0], optopt);
+				}
+			}
+		}
+		/* Option does not take argument */
+		else
+		{
+			/* Next argv_index */
+			if(argv[argv_index][opt_offset] == '\0')
+			{
+				increment_index();
+			}
+		}
+	}
+
+	/* Calculate optind */
+	if(c == -1)
+	{
+		optind = argc - nonopt;
+	}
+	else
+	{
+		optind = argv_index;
+	}
+
+	return c;
+}
+
+
+/* vim:ts=3
+*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/include/pncompat/internal/getopt.h
----------------------------------------------------------------------
diff --git a/c/tools/include/pncompat/internal/getopt.h b/c/tools/include/pncompat/internal/getopt.h
new file mode 100644
index 0000000..d4c0932
--- /dev/null
+++ b/c/tools/include/pncompat/internal/getopt.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+* getopt.h - competent and free getopt library.
+* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $
+*
+* Copyright (c)2002-2003 Mark K. Kim
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+*   * Redistributions of source code must retain the above copyright
+*     notice, this list of conditions and the following disclaimer.
+*
+*   * Redistributions in binary form must reproduce the above copyright
+*     notice, this list of conditions and the following disclaimer in
+*     the documentation and/or other materials provided with the
+*     distribution.
+*
+*   * Neither the original author of this software nor the names of its
+*     contributors may be used to endorse or promote products derived
+*     from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGE.
+*/
+#ifndef GETOPT_H_
+#define GETOPT_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern char* optarg;
+extern int optind;
+extern int opterr;
+extern int optopt;
+
+int getopt(int argc, char** argv, char* optstr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* GETOPT_H_ */
+
+
+/* vim:ts=3
+*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/include/pncompat/misc_defs.h
----------------------------------------------------------------------
diff --git a/c/tools/include/pncompat/misc_defs.h b/c/tools/include/pncompat/misc_defs.h
new file mode 100644
index 0000000..90b0d4e
--- /dev/null
+++ b/c/tools/include/pncompat/misc_defs.h
@@ -0,0 +1,50 @@
+#ifndef PNCOMAPT_MISC_DEFS_H
+#define PNCOMAPT_MISC_DEFS_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.
+ *
+ */
+
+#if defined(qpid_proton_EXPORTS)
+#error This include file is not for use in the main proton library
+#endif
+
+/*
+ * Platform neutral definitions. Only intended for use by Proton
+ * examples and test/debug programs.
+ *
+ * This file and any related support files may change or be removed
+ * at any time.
+ */
+
+// getopt()
+
+#include <proton/types.h>
+
+#if defined(__IBMC__)
+#  include <stdlib.h>
+#elif !defined(_WIN32) || defined (__CYGWIN__)
+#  include <getopt.h>
+#else
+#  include "internal/getopt.h"
+#endif
+
+pn_timestamp_t time_now(void);
+
+#endif /* PNCOMPAT_MISC_DEFS_H */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/tools/include/pncompat/misc_funcs.inc
----------------------------------------------------------------------
diff --git a/c/tools/include/pncompat/misc_funcs.inc b/c/tools/include/pncompat/misc_funcs.inc
new file mode 100644
index 0000000..821aaf4
--- /dev/null
+++ b/c/tools/include/pncompat/misc_funcs.inc
@@ -0,0 +1,68 @@
+/*
+ * 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 provides the functions for "misc_defs.h" in the form of
+ * included code, as opposed to a separate library or object
+ * dependency.  In the absence of portable "pragma weak" compiler
+ * directives, this provides a simple workaround.
+ *
+ * Usage for a single compilation unit:
+ *
+ *  #include "pncompat/misc_funcs.inc"
+ *
+ * Usage for multiple combined compilation units: chose one to include
+ * "pncompat/misc_funcs.inc" as above and in each other unit needing the
+ * definitions use
+ *
+ *  #include "pncompat/misc_defs.h"
+ *
+ */
+
+#include "misc_defs.h"
+
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+#include "pncompat/internal/getopt.c"
+#endif
+
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+#include <windows.h>
+pn_timestamp_t time_now(void)
+{
+  FILETIME now;
+  ULARGE_INTEGER t;
+  GetSystemTimeAsFileTime(&now);
+  t.u.HighPart = now.dwHighDateTime;
+  t.u.LowPart = now.dwLowDateTime;
+  // Convert to milliseconds and adjust base epoch
+  return t.QuadPart / 10000 - 11644473600000;
+}
+#else
+#include <sys/time.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+pn_timestamp_t time_now(void)
+{
+  struct timeval now;
+  if (gettimeofday(&now, NULL)) {fprintf(stderr, "gettimeofday failed\n"); abort();}
+  return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
+}
+#endif


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


Mime
View raw message