You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2016/11/14 18:28:22 UTC

[01/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Repository: qpid-proton
Updated Branches:
  refs/heads/master efd033c98 -> eac0bb663


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/selector.c b/proton-c/src/windows/selector.c
deleted file mode 100644
index f139aec..0000000
--- a/proton-c/src/windows/selector.c
+++ /dev/null
@@ -1,382 +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.
- *
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/object.h>
-#include <proton/io.h>
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <assert.h>
-#include "selectable.h"
-#include "util.h"
-#include "iocp.h"
-
-static void interests_update(iocpdesc_t *iocpd, int interests);
-static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t t);
-
-struct pn_selector_t {
-  iocp_t *iocp;
-  pn_list_t *selectables;
-  pn_list_t *iocp_descriptors;
-  size_t current;
-  iocpdesc_t *current_triggered;
-  pn_timestamp_t awoken;
-  pn_error_t *error;
-  iocpdesc_t *triggered_list_head;
-  iocpdesc_t *triggered_list_tail;
-  iocpdesc_t *deadlines_head;
-  iocpdesc_t *deadlines_tail;
-};
-
-void pn_selector_initialize(void *obj)
-{
-  pn_selector_t *selector = (pn_selector_t *) obj;
-  selector->iocp = NULL;
-  selector->selectables = pn_list(PN_WEAKREF, 0);
-  selector->iocp_descriptors = pn_list(PN_OBJECT, 0);
-  selector->current = 0;
-  selector->current_triggered = NULL;
-  selector->awoken = 0;
-  selector->error = pn_error();
-  selector->triggered_list_head = NULL;
-  selector->triggered_list_tail = NULL;
-  selector->deadlines_head = NULL;
-  selector->deadlines_tail = NULL;
-}
-
-void pn_selector_finalize(void *obj)
-{
-  pn_selector_t *selector = (pn_selector_t *) obj;
-  pn_free(selector->selectables);
-  pn_free(selector->iocp_descriptors);
-  pn_error_free(selector->error);
-  selector->iocp->selector = NULL;
-}
-
-#define pn_selector_hashcode NULL
-#define pn_selector_compare NULL
-#define pn_selector_inspect NULL
-
-pn_selector_t *pni_selector()
-{
-  static const pn_class_t clazz = PN_CLASS(pn_selector);
-  pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
-  return selector;
-}
-
-pn_selector_t *pni_selector_create(iocp_t *iocp)
-{
-  pn_selector_t *selector = pni_selector();
-  selector->iocp = iocp;
-  return selector;
-}
-
-void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
-{
-  assert(selector);
-  assert(selectable);
-  assert(pni_selectable_get_index(selectable) < 0);
-  pn_socket_t sock = pn_selectable_get_fd(selectable);
-  iocpdesc_t *iocpd = NULL;
-
-  if (pni_selectable_get_index(selectable) < 0) {
-    pn_list_add(selector->selectables, selectable);
-    pn_list_add(selector->iocp_descriptors, NULL);
-    size_t size = pn_list_size(selector->selectables);
-    pni_selectable_set_index(selectable, size - 1);
-  }
-
-  pn_selector_update(selector, selectable);
-}
-
-void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
-{
-  // A selectable's fd may switch from PN_INVALID_SCOKET to a working socket between
-  // update calls.  If a selectable without a valid socket has a deadline, we need
-  // a dummy iocpdesc_t to participate in the deadlines list.
-  int idx = pni_selectable_get_index(selectable);
-  assert(idx >= 0);
-  pn_timestamp_t deadline = pn_selectable_get_deadline(selectable);
-  pn_socket_t sock = pn_selectable_get_fd(selectable);
-  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
-
-  if (!iocpd && deadline && sock == PN_INVALID_SOCKET) {
-    iocpd = pni_deadline_desc(selector->iocp);
-    assert(iocpd);
-    pn_list_set(selector->iocp_descriptors, idx, iocpd);
-    pn_decref(iocpd);  // life is solely tied to iocp_descriptors list
-    iocpd->selector = selector;
-    iocpd->selectable = selectable;
-  }
-  else if (iocpd && iocpd->deadline_desc && sock != PN_INVALID_SOCKET) {
-    // Switching to a real socket.  Stop using a deadline descriptor.
-    deadlines_update(iocpd, 0);
-    // decref descriptor in list and pick up a real iocpd below
-    pn_list_set(selector->iocp_descriptors, idx, NULL);
-    iocpd = NULL;
-  }
-
-  // The selectables socket may be set long after it has been added
-  if (!iocpd && sock != PN_INVALID_SOCKET) {
-    iocpd = pni_iocpdesc_map_get(selector->iocp, sock);
-    if (!iocpd) {
-      // Socket created outside proton.  Hook it up to iocp.
-      iocpd = pni_iocpdesc_create(selector->iocp, sock, true);
-      assert(iocpd);
-      if (iocpd)
-        pni_iocpdesc_start(iocpd);
-    }
-    if (iocpd) {
-      pn_list_set(selector->iocp_descriptors, idx, iocpd);
-      iocpd->selector = selector;
-      iocpd->selectable = selectable;
-    }
-  }
-
-  if (iocpd) {
-    assert(sock == iocpd->socket || iocpd->closing);
-    int interests = PN_ERROR; // Always
-    if (pn_selectable_is_reading(selectable)) {
-      interests |= PN_READABLE;
-    }
-    if (pn_selectable_is_writing(selectable)) {
-      interests |= PN_WRITABLE;
-    }
-    if (deadline) {
-      interests |= PN_EXPIRED;
-    }
-    interests_update(iocpd, interests);
-    deadlines_update(iocpd, deadline);
-  }
-}
-
-void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
-{
-  assert(selector);
-  assert(selectable);
-
-  int idx = pni_selectable_get_index(selectable);
-  assert(idx >= 0);
-  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
-  if (iocpd) {
-    if (selector->current_triggered == iocpd)
-      selector->current_triggered = iocpd->triggered_list_next;
-    interests_update(iocpd, 0);
-    deadlines_update(iocpd, 0);
-    assert(selector->triggered_list_head != iocpd && !iocpd->triggered_list_prev);
-    assert(selector->deadlines_head != iocpd && !iocpd->deadlines_prev);
-    iocpd->selector = NULL;
-    iocpd->selectable = NULL;
-  }
-  pn_list_del(selector->selectables, idx, 1);
-  pn_list_del(selector->iocp_descriptors, idx, 1);
-  size_t size = pn_list_size(selector->selectables);
-  for (size_t i = idx; i < size; i++) {
-    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
-    pni_selectable_set_index(sel, i);
-  }
-
-  pni_selectable_set_index(selectable, -1);
-
-  if (selector->current >= (size_t) idx) {
-    selector->current--;
-  }
-}
-
-size_t pn_selector_size(pn_selector_t *selector) {
-  assert(selector);
-  return pn_list_size(selector->selectables);
-}
-
-int pn_selector_select(pn_selector_t *selector, int timeout)
-{
-  assert(selector);
-  pn_error_clear(selector->error);
-  pn_timestamp_t deadline = 0;
-  pn_timestamp_t now = pn_i_now();
-
-  if (timeout) {
-    if (selector->deadlines_head)
-      deadline = selector->deadlines_head->deadline;
-  }
-  if (deadline) {
-    int64_t delta = deadline - now;
-    if (delta < 0) {
-      delta = 0;
-    }
-    if (timeout < 0)
-      timeout = delta;
-    else if (timeout > delta)
-      timeout = delta;
-  }
-  deadline = (timeout >= 0) ? now + timeout : 0;
-
-  // Process all currently available completions, even if matched events available
-  pni_iocp_drain_completions(selector->iocp);
-  pni_zombie_check(selector->iocp, now);
-  // Loop until an interested event is matched, or until deadline
-  while (true) {
-    if (selector->triggered_list_head)
-      break;
-    if (deadline && deadline <= now)
-      break;
-    pn_timestamp_t completion_deadline = deadline;
-    pn_timestamp_t zd = pni_zombie_deadline(selector->iocp);
-    if (zd)
-      completion_deadline = completion_deadline ? pn_min(zd, completion_deadline) : zd;
-
-    int completion_timeout = (!completion_deadline) ? -1 : completion_deadline - now;
-    int rv = pni_iocp_wait_one(selector->iocp, completion_timeout, selector->error);
-    if (rv < 0)
-      return pn_error_code(selector->error);
-
-    now = pn_i_now();
-    if (zd && zd <= now) {
-      pni_zombie_check(selector->iocp, now);
-    }
-  }
-
-  selector->current = 0;
-  selector->awoken = now;
-  for (iocpdesc_t *iocpd = selector->deadlines_head; iocpd; iocpd = iocpd->deadlines_next) {
-    if (iocpd->deadline <= now)
-      pni_events_update(iocpd, iocpd->events | PN_EXPIRED);
-    else
-      break;
-  }
-  selector->current_triggered = selector->triggered_list_head;
-  return pn_error_code(selector->error);
-}
-
-pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
-{
-  if (selector->current_triggered) {
-    iocpdesc_t *iocpd = selector->current_triggered;
-    *events = iocpd->interests & iocpd->events;
-    selector->current_triggered = iocpd->triggered_list_next;
-    return iocpd->selectable;
-  }
-  return NULL;
-}
-
-void pn_selector_free(pn_selector_t *selector)
-{
-  assert(selector);
-  pn_free(selector);
-}
-
-
-static void triggered_list_add(pn_selector_t *selector, iocpdesc_t *iocpd)
-{
-  if (iocpd->triggered_list_prev || selector->triggered_list_head == iocpd)
-    return; // already in list
-  LL_ADD(selector, triggered_list, iocpd);
-}
-
-static void triggered_list_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
-{
-  if (!iocpd->triggered_list_prev && selector->triggered_list_head != iocpd)
-    return; // not in list
-  LL_REMOVE(selector, triggered_list, iocpd);
-  iocpd->triggered_list_prev = NULL;
-  iocpd->triggered_list_next = NULL;
-}
-
-
-void pni_events_update(iocpdesc_t *iocpd, int events)
-{
-  // If set, a poll error is permanent
-  if (iocpd->poll_error)
-    events |= PN_ERROR;
-  if (iocpd->events == events)
-    return;
-  iocpd->events = events;
-  if (iocpd->selector) {
-    if (iocpd->events & iocpd->interests)
-      triggered_list_add(iocpd->selector, iocpd);
-    else
-      triggered_list_remove(iocpd->selector, iocpd);
-  }
-}
-
-static void interests_update(iocpdesc_t *iocpd, int interests)
-{
-  int old_interests = iocpd->interests;
-  if (old_interests == interests)
-    return;
-  iocpd->interests = interests;
-  if (iocpd->selector) {
-    if (iocpd->events & iocpd->interests)
-      triggered_list_add(iocpd->selector, iocpd);
-    else
-      triggered_list_remove(iocpd->selector, iocpd);
-  }
-}
-
-static void deadlines_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
-{
-  if (!iocpd->deadlines_prev && selector->deadlines_head != iocpd)
-    return; // not in list
-  LL_REMOVE(selector, deadlines, iocpd);
-  iocpd->deadlines_prev = NULL;
-  iocpd->deadlines_next = NULL;
-}
-
-
-static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t deadline)
-{
-  if (deadline == iocpd->deadline)
-    return;
-
-  iocpd->deadline = deadline;
-  pn_selector_t *selector = iocpd->selector;
-  if (!deadline) {
-    deadlines_remove(selector, iocpd);
-    pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
-  } else {
-    if (iocpd->deadlines_prev || selector->deadlines_head == iocpd) {
-      deadlines_remove(selector, iocpd);
-      pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
-    }
-    iocpdesc_t *dl_iocpd = LL_HEAD(selector, deadlines);
-    while (dl_iocpd && dl_iocpd->deadline <= deadline)
-      dl_iocpd = dl_iocpd->deadlines_next;
-    if (dl_iocpd) {
-      // insert
-      iocpd->deadlines_prev = dl_iocpd->deadlines_prev;
-      iocpd->deadlines_next = dl_iocpd;
-      dl_iocpd->deadlines_prev = iocpd;
-      if (selector->deadlines_head == dl_iocpd)
-        selector->deadlines_head = iocpd;
-    } else {
-      LL_ADD(selector, deadlines, iocpd);  // append
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/write_pipeline.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/write_pipeline.c b/proton-c/src/windows/write_pipeline.c
deleted file mode 100644
index e14e714..0000000
--- a/proton-c/src/windows/write_pipeline.c
+++ /dev/null
@@ -1,312 +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 simple write buffer pool.  Each socket has a dedicated "primary"
- * buffer and can borrow from a shared pool with limited size tuning.
- * Could enhance e.g. with separate pools per network interface and fancier
- * memory tuning based on interface speed, system resources, and
- * number of connections, etc.
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/object.h>
-#include <proton/io.h>
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <assert.h>
-#include "selectable.h"
-#include "util.h"
-#include "iocp.h"
-
-// Max overlapped writes per socket
-#define IOCP_MAX_OWRITES 16
-// Write buffer size
-#define IOCP_WBUFSIZE 16384
-
-static void pipeline_log(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fflush(stderr);
-}
-
-void pni_shared_pool_create(iocp_t *iocp)
-{
-  // TODO: more pools (or larger one) when using multiple non-loopback interfaces
-  iocp->shared_pool_size = 16;
-  char *env = getenv("PNI_WRITE_BUFFERS"); // Internal: for debugging
-  if (env) {
-    int sz = atoi(env);
-    if (sz >= 0 && sz < 256) {
-      iocp->shared_pool_size = sz;
-    }
-  }
-  iocp->loopback_bufsize = 0;
-  env = getenv("PNI_LB_BUFSIZE"); // Internal: for debugging
-  if (env) {
-    int sz = atoi(env);
-    if (sz >= 0 && sz <= 128 * 1024) {
-      iocp->loopback_bufsize = sz;
-    }
-  }
-
-  if (iocp->shared_pool_size) {
-    iocp->shared_pool_memory = (char *) VirtualAlloc(NULL, IOCP_WBUFSIZE * iocp->shared_pool_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-    HRESULT status = GetLastError();
-    if (!iocp->shared_pool_memory) {
-      perror("Proton write buffer pool allocation failure\n");
-      iocp->shared_pool_size = 0;
-      iocp->shared_available_count = 0;
-      return;
-    }
-
-    iocp->shared_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
-    iocp->available_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
-    iocp->shared_available_count = iocp->shared_pool_size;
-    char *mem = iocp->shared_pool_memory;
-    for (int i = 0; i < iocp->shared_pool_size; i++) {
-      iocp->shared_results[i] = iocp->available_results[i] = pni_write_result(NULL, mem, IOCP_WBUFSIZE);
-      mem += IOCP_WBUFSIZE;
-    }
-  }
-}
-
-void pni_shared_pool_free(iocp_t *iocp)
-{
-  for (int i = 0; i < iocp->shared_pool_size; i++) {
-    write_result_t *result = iocp->shared_results[i];
-    if (result->in_use)
-      pipeline_log("Proton buffer pool leak\n");
-    else
-      free(result);
-  }
-  if (iocp->shared_pool_size) {
-    free(iocp->shared_results);
-    free(iocp->available_results);
-    if (iocp->shared_pool_memory) {
-      if (!VirtualFree(iocp->shared_pool_memory, 0, MEM_RELEASE)) {
-        perror("write buffers release failed");
-      }
-      iocp->shared_pool_memory = NULL;
-    }
-  }
-}
-
-static void shared_pool_push(write_result_t *result)
-{
-  iocp_t *iocp = result->base.iocpd->iocp;
-  assert(iocp->shared_available_count < iocp->shared_pool_size);
-  iocp->available_results[iocp->shared_available_count++] = result;
-}
-
-static write_result_t *shared_pool_pop(iocp_t *iocp)
-{
-  return iocp->shared_available_count ? iocp->available_results[--iocp->shared_available_count] : NULL;
-}
-
-struct write_pipeline_t {
-  iocpdesc_t *iocpd;
-  size_t pending_count;
-  write_result_t *primary;
-  size_t reserved_count;
-  size_t next_primary_index;
-  size_t depth;
-  bool is_writer;
-};
-
-#define write_pipeline_compare NULL
-#define write_pipeline_inspect NULL
-#define write_pipeline_hashcode NULL
-
-static void write_pipeline_initialize(void *object)
-{
-  write_pipeline_t *pl = (write_pipeline_t *) object;
-  pl->pending_count = 0;
-  const char *pribuf = (const char *) malloc(IOCP_WBUFSIZE);
-  pl->primary = pni_write_result(NULL, pribuf, IOCP_WBUFSIZE);
-  pl->depth = 0;
-  pl->is_writer = false;
-}
-
-static void write_pipeline_finalize(void *object)
-{
-  write_pipeline_t *pl = (write_pipeline_t *) object;
-  free((void *)pl->primary->buffer.start);
-  free(pl->primary);
-}
-
-write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd)
-{
-  static const pn_cid_t CID_write_pipeline = CID_pn_void;
-  static const pn_class_t clazz = PN_CLASS(write_pipeline);
-  write_pipeline_t *pipeline = (write_pipeline_t *) pn_class_new(&clazz, sizeof(write_pipeline_t));
-  pipeline->iocpd = iocpd;
-  pipeline->primary->base.iocpd = iocpd;
-  return pipeline;
-}
-
-static void confirm_as_writer(write_pipeline_t *pl)
-{
-  if (!pl->is_writer) {
-    iocp_t *iocp = pl->iocpd->iocp;
-    iocp->writer_count++;
-    pl->is_writer = true;
-  }
-}
-
-static void remove_as_writer(write_pipeline_t *pl)
-{
-  if (!pl->is_writer)
-    return;
-  iocp_t *iocp = pl->iocpd->iocp;
-  assert(iocp->writer_count);
-  pl->is_writer = false;
-  iocp->writer_count--;
-}
-
-/*
- * Optimal depth will depend on properties of the NIC, server, and driver.  For now,
- * just distinguish between loopback interfaces and the rest.  Optimizations in the
- * loopback stack allow decent performance with depth 1 and actually cause major
- * performance hiccups if set to large values.
- */
-static void set_depth(write_pipeline_t *pl)
-{
-  pl->depth = 1;
-  sockaddr_storage sa;
-  socklen_t salen = sizeof(sa);
-  char buf[INET6_ADDRSTRLEN];
-  DWORD buflen = sizeof(buf);
-
-  if (getsockname(pl->iocpd->socket,(sockaddr*) &sa, &salen) == 0 &&
-      getnameinfo((sockaddr*) &sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0) {
-    if ((sa.ss_family == AF_INET6 && strcmp(buf, "::1")) ||
-        (sa.ss_family == AF_INET && strncmp(buf, "127.", 4))) {
-      // not loopback
-      pl->depth = IOCP_MAX_OWRITES;
-    } else {
-      iocp_t *iocp = pl->iocpd->iocp;
-      if (iocp->loopback_bufsize) {
-        const char *p = (const char *) realloc((void *) pl->primary->buffer.start, iocp->loopback_bufsize);
-        if (p) {
-          pl->primary->buffer.start = p;
-          pl->primary->buffer.size = iocp->loopback_bufsize;
-        }
-      }
-    }
-  }
-}
-
-// Reserve as many buffers as possible for count bytes.
-size_t pni_write_pipeline_reserve(write_pipeline_t *pl, size_t count)
-{
-  if (pl->primary->in_use)
-    return 0;  // I.e. io->wouldblock
-  if (!pl->depth)
-    set_depth(pl);
-  if (pl->depth == 1) {
-    // always use the primary
-    pl->reserved_count = 1;
-    pl->next_primary_index = 0;
-    return 1;
-  }
-
-  iocp_t *iocp = pl->iocpd->iocp;
-  confirm_as_writer(pl);
-  size_t wanted = (count / IOCP_WBUFSIZE);
-  if (count % IOCP_WBUFSIZE)
-    wanted++;
-  size_t pending = pl->pending_count;
-  assert(pending < pl->depth);
-  size_t bufs = pn_min(wanted, pl->depth - pending);
-  // Can draw from shared pool or the primary... but share with others.
-  size_t writers = iocp->writer_count;
-  size_t shared_count = (iocp->shared_available_count + writers - 1) / writers;
-  bufs = pn_min(bufs, shared_count + 1);
-  pl->reserved_count = pending + bufs;
-
-  if (bufs == wanted &&
-      pl->reserved_count < (pl->depth / 2) &&
-      iocp->shared_available_count > (2 * writers + bufs)) {
-    // No shortage: keep the primary as spare for future use
-    pl->next_primary_index = pl->reserved_count;
-  } else if (bufs == 1) {
-    pl->next_primary_index = pending;
-  } else {
-    // let approx 1/3 drain before replenishing
-    pl->next_primary_index = ((pl->reserved_count + 2) / 3) - 1;
-    if (pl->next_primary_index < pending)
-      pl->next_primary_index = pending;
-  }
-  return bufs;
-}
-
-write_result_t *pni_write_pipeline_next(write_pipeline_t *pl)
-{
-  size_t sz = pl->pending_count;
-  if (sz >= pl->reserved_count)
-    return NULL;
-  write_result_t *result;
-  if (sz == pl->next_primary_index) {
-    result = pl->primary;
-  } else {
-    assert(pl->iocpd->iocp->shared_available_count > 0);
-    result = shared_pool_pop(pl->iocpd->iocp);
-  }
-
-  result->in_use = true;
-  pl->pending_count++;
-  return result;
-}
-
-void pni_write_pipeline_return(write_pipeline_t *pl, write_result_t *result)
-{
-  result->in_use = false;
-  pl->pending_count--;
-  pl->reserved_count = 0;
-  if (result != pl->primary)
-    shared_pool_push(result);
-  if (pl->pending_count == 0)
-    remove_as_writer(pl);
-}
-
-bool pni_write_pipeline_writable(write_pipeline_t *pl)
-{
-  // Only writable if not full and we can guarantee a buffer:
-  return pl->pending_count < pl->depth && !pl->primary->in_use;
-}
-
-size_t pni_write_pipeline_size(write_pipeline_t *pl)
-{
-  return pl->pending_count;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/tools/cmake/Modules/WindowsC99SymbolCheck.py
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/WindowsC99SymbolCheck.py b/tools/cmake/Modules/WindowsC99SymbolCheck.py
index 8e81ad9..7c2c9f2 100644
--- a/tools/cmake/Modules/WindowsC99SymbolCheck.py
+++ b/tools/cmake/Modules/WindowsC99SymbolCheck.py
@@ -53,7 +53,7 @@ def symcheck(objfile):
         m = re.search(r'UNDEF.*\b([a-zA-Z_]*snprintf)\b', line)
         if m :
             sym = m.group(1)
-            if re.match(r'_*pn_i_v?snprintf', sym) is None :
+            if re.match(r'_*pni_v?snprintf', sym) is None :
                 raise Exception('Unsafe use of C99 violating function in  ' + objfile + ' : ' + sym)
 
 def main():


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


[04/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
deleted file mode 100644
index cdecfd2..0000000
--- a/proton-c/src/transport/transport.c
+++ /dev/null
@@ -1,3018 +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 "engine/engine-internal.h"
-#include "framing/framing.h"
-#include "sasl/sasl-internal.h"
-#include "ssl/ssl-internal.h"
-
-#include "autodetect.h"
-#include "protocol.h"
-#include "dispatch_actions.h"
-#include "proton/event.h"
-#include "platform.h"
-#include "platform_fmt.h"
-#include "config.h"
-#include "log_private.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-static ssize_t transport_consume(pn_transport_t *transport);
-
-// delivery buffers
-
-/*
- * Call this any time anything happens that may affect channel_max:
- * i.e. when the app indicates a preference, or when we receive the
- * OPEN frame from the remote peer.  And call it to do the final
- * calculation just before we communicate our limit to the remote
- * peer by sending our OPEN frame.
- */
-static void pni_calculate_channel_max(pn_transport_t *transport) {
-  /*
-   * The application cannot make the limit larger than
-   * what this library will allow.
-   */
-  transport->channel_max = (PN_IMPL_CHANNEL_MAX < transport->local_channel_max)
-                           ? PN_IMPL_CHANNEL_MAX
-                           : transport->local_channel_max;
-
-  /*
-   * The remote peer's constraint is not valid until the
-   * peer's open frame has been received.
-   */
-  if(transport->open_rcvd) {
-    transport->channel_max = (transport->channel_max < transport->remote_channel_max)
-                             ? transport->channel_max
-                             : transport->remote_channel_max;
-  }
-}
-
-void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next)
-{
-  db->deliveries = pn_hash(PN_WEAKREF, 0, 0.75);
-  db->next = next;
-}
-
-void pn_delivery_map_free(pn_delivery_map_t *db)
-{
-  pn_free(db->deliveries);
-}
-
-static pn_delivery_t *pni_delivery_map_get(pn_delivery_map_t *db, pn_sequence_t id)
-{
-  return (pn_delivery_t *) pn_hash_get(db->deliveries, id);
-}
-
-static void pn_delivery_state_init(pn_delivery_state_t *ds, pn_delivery_t *delivery, pn_sequence_t id)
-{
-  ds->id = id;
-  ds->sent = false;
-  ds->init = true;
-}
-
-static pn_delivery_state_t *pni_delivery_map_push(pn_delivery_map_t *db, pn_delivery_t *delivery)
-{
-  pn_delivery_state_t *ds = &delivery->state;
-  pn_delivery_state_init(ds, delivery, db->next++);
-  pn_hash_put(db->deliveries, ds->id, delivery);
-  return ds;
-}
-
-void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery)
-{
-  if (delivery->state.init) {
-    delivery->state.init = false;
-    delivery->state.sent = false;
-    pn_hash_del(db->deliveries, delivery->state.id);
-  }
-}
-
-static void pni_delivery_map_clear(pn_delivery_map_t *dm)
-{
-  pn_hash_t *hash = dm->deliveries;
-  for (pn_handle_t entry = pn_hash_head(hash);
-       entry;
-       entry = pn_hash_next(hash, entry))
-  {
-    pn_delivery_t *dlv = (pn_delivery_t *) pn_hash_value(hash, entry);
-    pn_delivery_map_del(dm, dlv);
-  }
-  dm->next = 0;
-}
-
-static void pni_default_tracer(pn_transport_t *transport, const char *message)
-{
-  fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
-}
-
-static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );
-static ssize_t pn_io_layer_output_passthru(pn_transport_t *, unsigned int, char *, size_t );
-
-static ssize_t pn_io_layer_input_error(pn_transport_t *, unsigned int, const char *, size_t );
-static ssize_t pn_io_layer_output_error(pn_transport_t *, unsigned int, char *, size_t );
-
-static ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-
-static ssize_t pn_input_read_amqp_header(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_input_read_amqp(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_output_write_amqp_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-static ssize_t pn_output_write_amqp(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-static void pn_error_amqp(pn_transport_t *transport, unsigned int layer);
-static pn_timestamp_t pn_tick_amqp(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now);
-
-static ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
-static ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
-
-const pn_io_layer_t amqp_header_layer = {
-    pn_input_read_amqp_header,
-    pn_output_write_amqp_header,
-    NULL,
-    pn_tick_amqp,
-    NULL
-};
-
-const pn_io_layer_t amqp_write_header_layer = {
-    pn_input_read_amqp,
-    pn_output_write_amqp_header,
-    NULL,
-    pn_tick_amqp,
-    NULL
-};
-
-const pn_io_layer_t amqp_read_header_layer = {
-    pn_input_read_amqp_header,
-    pn_output_write_amqp,
-    pn_error_amqp,
-    pn_tick_amqp,
-    NULL
-};
-
-const pn_io_layer_t amqp_layer = {
-    pn_input_read_amqp,
-    pn_output_write_amqp,
-    pn_error_amqp,
-    pn_tick_amqp,
-    NULL
-};
-
-const pn_io_layer_t pni_setup_layer = {
-    pn_io_layer_input_setup,
-    pn_io_layer_output_setup,
-    NULL,
-    NULL,
-    NULL
-};
-
-const pn_io_layer_t pni_autodetect_layer = {
-    pn_io_layer_input_autodetect,
-    pn_io_layer_output_null,
-    NULL,
-    NULL,
-    NULL
-};
-
-const pn_io_layer_t pni_passthru_layer = {
-    pn_io_layer_input_passthru,
-    pn_io_layer_output_passthru,
-    NULL,
-    NULL,
-    NULL
-};
-
-const pn_io_layer_t pni_header_error_layer = {
-    pn_io_layer_input_error,
-    pn_output_write_amqp_header,
-    NULL,
-    NULL,
-    NULL
-};
-
-const pn_io_layer_t pni_error_layer = {
-    pn_io_layer_input_error,
-    pn_io_layer_output_error,
-    pn_error_amqp,
-    NULL,
-    NULL
-};
-
-/* Set up the transport protocol layers depending on what is configured */
-static void pn_io_layer_setup(pn_transport_t *transport, unsigned int layer)
-{
-  assert(layer == 0);
-  // Figure out if we are server or not
-  if (transport->server) {
-      transport->io_layers[layer++] = &pni_autodetect_layer;
-      return;
-  }
-  if (transport->ssl) {
-    transport->io_layers[layer++] = &ssl_layer;
-  }
-  if (transport->sasl) {
-    transport->io_layers[layer++] = &sasl_header_layer;
-  }
-  transport->io_layers[layer++] = &amqp_header_layer;
-}
-
-ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
-{
-  pn_io_layer_setup(transport, layer);
-  return transport->io_layers[layer]->process_input(transport, layer, bytes, available);
-}
-
-ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
-{
-  pn_io_layer_setup(transport, layer);
-  return transport->io_layers[layer]->process_output(transport, layer, bytes, available);
-}
-
-void pn_set_error_layer(pn_transport_t *transport)
-{
-  // Set every layer to the error layer in case we manually
-  // pass through (happens from SASL to AMQP)
-  for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
-    transport->io_layers[layer] = &pni_error_layer;
-  }
-}
-
-// Autodetect the layer by reading the protocol header
-ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
-{
-  const char* error;
-  bool eos = pn_transport_capacity(transport)==PN_EOS;
-  if (eos && available==0) {
-    pn_do_error(transport, "amqp:connection:framing-error", "No valid protocol header found");
-    pn_set_error_layer(transport);
-    return PN_EOS;
-  }
-  pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
-  if (transport->trace & PN_TRACE_DRV)
-      pn_transport_logf(transport, "%s detected", pni_protocol_name(protocol));
-  switch (protocol) {
-  case PNI_PROTOCOL_SSL:
-    if (!(transport->allowed_layers & LAYER_SSL)) {
-      error = "SSL protocol header not allowed (maybe detected twice)";
-      break;
-    }
-    transport->present_layers |= LAYER_SSL;
-    transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
-    if (!transport->ssl) {
-      pn_ssl(transport);
-    }
-    transport->io_layers[layer] = &ssl_layer;
-    transport->io_layers[layer+1] = &pni_autodetect_layer;
-    return ssl_layer.process_input(transport, layer, bytes, available);
-  case PNI_PROTOCOL_AMQP_SSL:
-    if (!(transport->allowed_layers & LAYER_AMQPSSL)) {
-      error = "AMQP SSL protocol header not allowed (maybe detected twice)";
-      break;
-    }
-    transport->present_layers |= LAYER_AMQPSSL;
-    transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
-    if (!transport->ssl) {
-      pn_ssl(transport);
-    }
-    transport->io_layers[layer] = &ssl_layer;
-    transport->io_layers[layer+1] = &pni_autodetect_layer;
-    return 8;
-  case PNI_PROTOCOL_AMQP_SASL:
-    if (!(transport->allowed_layers & LAYER_AMQPSASL)) {
-      error = "AMQP SASL protocol header not allowed (maybe detected twice)";
-      break;
-    }
-    transport->present_layers |= LAYER_AMQPSASL;
-    transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSSL;
-    if (!transport->sasl) {
-      pn_sasl(transport);
-    }
-    transport->io_layers[layer] = &sasl_write_header_layer;
-    transport->io_layers[layer+1] = &pni_autodetect_layer;
-    if (transport->trace & PN_TRACE_FRM)
-        pn_transport_logf(transport, "  <- %s", "SASL");
-    pni_sasl_set_external_security(transport, pn_ssl_get_ssf((pn_ssl_t*)transport), pn_ssl_get_remote_subject((pn_ssl_t*)transport));
-    return 8;
-  case PNI_PROTOCOL_AMQP1:
-    if (!(transport->allowed_layers & LAYER_AMQP1)) {
-      error = "AMQP1.0 protocol header not allowed (maybe detected twice)";
-      break;
-    }
-    transport->present_layers |= LAYER_AMQP1;
-    transport->allowed_layers = LAYER_NONE;
-    if (transport->auth_required && !pn_transport_is_authenticated(transport)) {
-      pn_do_error(transport, "amqp:connection:policy-error",
-                  "Client skipped authentication - forbidden");
-      pn_set_error_layer(transport);
-      return 8;
-    }
-    if (transport->encryption_required && !pn_transport_is_encrypted(transport)) {
-      pn_do_error(transport, "amqp:connection:policy-error",
-                  "Client connection unencryted - forbidden");
-      pn_set_error_layer(transport);
-      return 8;
-    }
-    transport->io_layers[layer] = &amqp_write_header_layer;
-    if (transport->trace & PN_TRACE_FRM)
-        pn_transport_logf(transport, "  <- %s", "AMQP");
-    return 8;
-  case PNI_PROTOCOL_INSUFFICIENT:
-    if (!eos) return 0;
-    error = "End of input stream before protocol detection";
-    break;
-  case PNI_PROTOCOL_AMQP_OTHER:
-    error = "Incompatible AMQP connection detected";
-    break;
-  case PNI_PROTOCOL_UNKNOWN:
-  default:
-    error = "Unknown protocol detected";
-    break;
-  }
-  transport->io_layers[layer] = &pni_header_error_layer;
-  char quoted[1024];
-  pn_quote_data(quoted, 1024, bytes, available);
-  pn_do_error(transport, "amqp:connection:framing-error",
-              "%s: '%s'%s", error, quoted,
-              !eos ? "" : " (connection aborted)");
-  return 0;
-}
-
-// We don't know what the output should be - do nothing
-ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
-{
-  return 0;
-}
-
-/** Pass through input handler */
-ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
-{
-    if (layer+1<PN_IO_LAYER_CT)
-        return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
-    return PN_EOS;
-}
-
-/** Pass through output handler */
-ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
-{
-    if (layer+1<PN_IO_LAYER_CT)
-        return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
-    return PN_EOS;
-}
-
-/** Input handler after detected error */
-ssize_t pn_io_layer_input_error(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
-{
-    return PN_EOS;
-}
-
-/** Output handler after detected error */
-ssize_t pn_io_layer_output_error(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
-{
-    return PN_EOS;
-}
-
-static void pn_transport_initialize(void *object)
-{
-  pn_transport_t *transport = (pn_transport_t *)object;
-  transport->freed = false;
-  transport->output_buf = NULL;
-  transport->output_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
-  transport->input_buf = NULL;
-  transport->input_size =  PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
-  transport->tracer = pni_default_tracer;
-  transport->sasl = NULL;
-  transport->ssl = NULL;
-
-  transport->scratch = pn_string(NULL);
-  transport->args = pn_data(16);
-  transport->output_args = pn_data(16);
-  transport->frame = pn_buffer(PN_TRANSPORT_INITIAL_FRAME_SIZE);
-  transport->input_frames_ct = 0;
-  transport->output_frames_ct = 0;
-
-  transport->connection = NULL;
-  transport->context = pn_record();
-
-  for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
-    transport->io_layers[layer] = NULL;
-  }
-
-  transport->allowed_layers = LAYER_AMQP1 | LAYER_AMQPSASL | LAYER_AMQPSSL | LAYER_SSL;
-  transport->present_layers = LAYER_NONE;
-
-  // Defer setting up the layers until the first data arrives or is sent
-  transport->io_layers[0] = &pni_setup_layer;
-
-  transport->open_sent = false;
-  transport->open_rcvd = false;
-  transport->close_sent = false;
-  transport->close_rcvd = false;
-  transport->tail_closed = false;
-  transport->head_closed = false;
-  transport->remote_container = NULL;
-  transport->remote_hostname = NULL;
-  transport->local_max_frame = PN_DEFAULT_MAX_FRAME_SIZE;
-  transport->remote_max_frame = (uint32_t) 0xffffffff;
-
-  /*
-   * We set the local limit on channels to 2^15, because
-   * parts of the code use the topmost bit (of a short)
-   * as a flag.
-   * The peer that this transport connects to may also
-   * place its own limit on max channel number, and the
-   * application may also set a limit.
-   * The maximum that we use will be the minimum of all
-   * these constraints.
-   */
-  // There is no constraint yet from remote peer,
-  // so set to max possible.
-  transport->remote_channel_max = 65535;
-  transport->local_channel_max  = PN_IMPL_CHANNEL_MAX;
-  transport->channel_max        = transport->local_channel_max;
-
-  transport->local_idle_timeout = 0;
-  transport->dead_remote_deadline = 0;
-  transport->last_bytes_input = 0;
-  transport->remote_idle_timeout = 0;
-  transport->keepalive_deadline = 0;
-  transport->last_bytes_output = 0;
-  transport->remote_offered_capabilities = pn_data(0);
-  transport->remote_desired_capabilities = pn_data(0);
-  transport->remote_properties = pn_data(0);
-  transport->disp_data = pn_data(0);
-  pn_condition_init(&transport->remote_condition);
-  pn_condition_init(&transport->condition);
-  transport->error = pn_error();
-
-  transport->local_channels = pn_hash(PN_WEAKREF, 0, 0.75);
-  transport->remote_channels = pn_hash(PN_WEAKREF, 0, 0.75);
-
-  transport->bytes_input = 0;
-  transport->bytes_output = 0;
-
-  transport->input_pending = 0;
-  transport->output_pending = 0;
-
-  transport->done_processing = false;
-
-  transport->posted_idle_timeout = false;
-
-  transport->server = false;
-  transport->halt = false;
-  transport->auth_required = false;
-  transport->authenticated = false;
-  transport->encryption_required = false;
-
-  transport->referenced = true;
-
-  transport->trace =
-    (pn_env_bool("PN_TRACE_RAW") ? PN_TRACE_RAW : PN_TRACE_OFF) |
-    (pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
-    (pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF) |
-    (pn_env_bool("PN_TRACE_EVT") ? PN_TRACE_EVT : PN_TRACE_OFF) ;
-}
-
-
-static pn_session_t *pni_channel_state(pn_transport_t *transport, uint16_t channel)
-{
-  return (pn_session_t *) pn_hash_get(transport->remote_channels, channel);
-}
-
-static void pni_map_remote_channel(pn_session_t *session, uint16_t channel)
-{
-  pn_transport_t *transport = session->connection->transport;
-  pn_hash_put(transport->remote_channels, channel, session);
-  session->state.remote_channel = channel;
-  pn_ep_incref(&session->endpoint);
-}
-
-void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state);
-
-static void pni_unmap_remote_channel(pn_session_t *ssn)
-{
-  // XXX: should really update link state also
-  pni_delivery_map_clear(&ssn->state.incoming);
-  pni_transport_unbind_handles(ssn->state.remote_handles, false);
-  pn_transport_t *transport = ssn->connection->transport;
-  uint16_t channel = ssn->state.remote_channel;
-  ssn->state.remote_channel = -2;
-  if (pn_hash_get(transport->remote_channels, channel)) {
-    pn_ep_decref(&ssn->endpoint);
-  }
-  // note: may free the session:
-  pn_hash_del(transport->remote_channels, channel);
-}
-
-static void pn_transport_incref(void *object)
-{
-  pn_transport_t *transport = (pn_transport_t *) object;
-  if (!transport->referenced) {
-    transport->referenced = true;
-    if (transport->connection) {
-      pn_incref(transport->connection);
-    } else {
-      pn_object_incref(object);
-    }
-  } else {
-    pn_object_incref(object);
-  }
-}
-
-static void pn_transport_finalize(void *object);
-#define pn_transport_new pn_object_new
-#define pn_transport_refcount pn_object_refcount
-#define pn_transport_decref pn_object_decref
-#define pn_transport_reify pn_object_reify
-#define pn_transport_hashcode NULL
-#define pn_transport_compare NULL
-#define pn_transport_inspect NULL
-
-pn_transport_t *pn_transport(void)
-{
-#define pn_transport_free pn_object_free
-  static const pn_class_t clazz = PN_METACLASS(pn_transport);
-#undef pn_transport_free
-  pn_transport_t *transport =
-    (pn_transport_t *) pn_class_new(&clazz, sizeof(pn_transport_t));
-  if (!transport) return NULL;
-
-  transport->output_buf = (char *) malloc(transport->output_size);
-  if (!transport->output_buf) {
-    pn_transport_free(transport);
-    return NULL;
-  }
-
-  transport->input_buf = (char *) malloc(transport->input_size);
-  if (!transport->input_buf) {
-    pn_transport_free(transport);
-    return NULL;
-  }
-
-  transport->capacity = 4*1024;
-  transport->available = 0;
-  transport->output = (char *) malloc(transport->capacity);
-  if (!transport->output) {
-    pn_transport_free(transport);
-    return NULL;
-  }
-
-  return transport;
-}
-
-void pn_transport_set_server(pn_transport_t *transport)
-{
-  assert(transport);
-  transport->server = true;
-}
-
-const char *pn_transport_get_user(pn_transport_t *transport)
-{
-  assert(transport);
-  // Client - just return whatever we gave to sasl
-  if (!transport->server) {
-    if (transport->sasl) return pn_sasl_get_user((pn_sasl_t *)transport);
-    return "anonymous";
-  }
-
-  // Server
-  // Not finished authentication yet
-  if (!(transport->present_layers & LAYER_AMQP1)) return 0;
-  // We have SASL so it takes precedence
-  if (transport->present_layers & LAYER_AMQPSASL) return pn_sasl_get_user((pn_sasl_t *)transport);
-  // No SASL but we may have a SSL remote_subject
-  if (transport->present_layers & (LAYER_AMQPSSL | LAYER_SSL)) return pn_ssl_get_remote_subject((pn_ssl_t *)transport);
-  // otherwise it's just an unauthenticated anonymous connection
-  return "anonymous";
-}
-
-void pn_transport_require_auth(pn_transport_t *transport, bool required)
-{
-  assert(transport);
-  transport->auth_required = required;
-}
-
-bool pn_transport_is_authenticated(pn_transport_t *transport)
-{
-  return transport && transport->authenticated;
-}
-
-void pn_transport_require_encryption(pn_transport_t *transport, bool required)
-{
-  assert(transport);
-  transport->encryption_required = required;
-}
-
-bool pn_transport_is_encrypted(pn_transport_t *transport)
-{
-    return transport && transport->ssl && pn_ssl_get_ssf((pn_ssl_t*)transport)>0;
-}
-
-void pn_transport_free(pn_transport_t *transport)
-{
-  if (!transport) return;
-  assert(!transport->freed);
-  transport->freed = true;
-  pn_decref(transport);
-}
-
-static void pn_transport_finalize(void *object)
-{
-  pn_transport_t *transport = (pn_transport_t *) object;
-
-  if (transport->referenced && transport->connection && pn_refcount(transport->connection) > 1) {
-    pn_object_incref(transport);
-    transport->referenced = false;
-    pn_decref(transport->connection);
-    return;
-  }
-
-  // once the application frees the transport, no further I/O
-  // processing can be done to the connection:
-  pn_transport_unbind(transport);
-  // we may have posted events, so stay alive until they are processed
-  if (pn_refcount(transport) > 0) return;
-
-  pn_ssl_free(transport);
-  pn_sasl_free(transport);
-  free(transport->remote_container);
-  free(transport->remote_hostname);
-  pn_free(transport->remote_offered_capabilities);
-  pn_free(transport->remote_desired_capabilities);
-  pn_free(transport->remote_properties);
-  pn_free(transport->disp_data);
-  pn_condition_tini(&transport->remote_condition);
-  pn_condition_tini(&transport->condition);
-  pn_error_free(transport->error);
-  pn_free(transport->local_channels);
-  pn_free(transport->remote_channels);
-  if (transport->input_buf) free(transport->input_buf);
-  if (transport->output_buf) free(transport->output_buf);
-  pn_free(transport->scratch);
-  pn_data_free(transport->args);
-  pn_data_free(transport->output_args);
-  pn_buffer_free(transport->frame);
-  pn_free(transport->context);
-  free(transport->output);
-}
-
-static void pni_post_remote_open_events(pn_transport_t *transport, pn_connection_t *connection) {
-    pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_REMOTE_OPEN);
-    if (transport->remote_idle_timeout) {
-      pn_collector_put(connection->collector, PN_OBJECT, transport, PN_TRANSPORT);
-    }
-}
-
-int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
-{
-  assert(transport);
-  assert(connection);
-
-  if (transport->connection) return PN_STATE_ERR;
-  if (connection->transport) return PN_STATE_ERR;
-
-  transport->connection = connection;
-  connection->transport = transport;
-
-  pn_incref(connection);
-
-  pn_connection_bound(connection);
-
-  // set the hostname/user/password
-  if (pn_string_size(connection->auth_user)) {
-    pn_sasl(transport);
-    pni_sasl_set_user_password(transport, pn_string_get(connection->auth_user), pn_string_get(connection->auth_password));
-  }
-
-  if (pn_string_size(connection->hostname)) {
-      if (transport->sasl) {
-          pni_sasl_set_remote_hostname(transport, pn_string_get(connection->hostname));
-      }
-
-      // be sure not to overwrite a hostname already set by the user via
-      // pn_ssl_set_peer_hostname() called before the bind
-      if (transport->ssl) {
-          size_t name_len = 0;
-          pn_ssl_get_peer_hostname((pn_ssl_t*) transport, NULL, &name_len);
-          if (name_len == 0) {
-              pn_ssl_set_peer_hostname((pn_ssl_t*) transport, pn_string_get(connection->hostname));
-          }
-      }
-  }
-
-  if (transport->open_rcvd) {
-    PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
-    pni_post_remote_open_events(transport, connection);
-    transport->halt = false;
-    transport_consume(transport);        // blech - testBindAfterOpen
-  }
-
-  return 0;
-}
-
-void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state)
-{
-  for (pn_handle_t h = pn_hash_head(handles); h; h = pn_hash_next(handles, h)) {
-    uintptr_t key = pn_hash_key(handles, h);
-    pn_link_t *link = (pn_link_t *) pn_hash_value(handles, h);
-    if (reset_state) {
-      pn_link_unbound(link);
-    }
-    pn_ep_decref(&link->endpoint);
-    pn_hash_del(handles, key);
-  }
-}
-
-void pni_transport_unbind_channels(pn_hash_t *channels)
-{
-  for (pn_handle_t h = pn_hash_head(channels); h; h = pn_hash_next(channels, h)) {
-    uintptr_t key = pn_hash_key(channels, h);
-    pn_session_t *ssn = (pn_session_t *) pn_hash_value(channels, h);
-    pni_delivery_map_clear(&ssn->state.incoming);
-    pni_delivery_map_clear(&ssn->state.outgoing);
-    pni_transport_unbind_handles(ssn->state.local_handles, true);
-    pni_transport_unbind_handles(ssn->state.remote_handles, true);
-    pn_session_unbound(ssn);
-    pn_ep_decref(&ssn->endpoint);
-    pn_hash_del(channels, key);
-  }
-}
-
-int pn_transport_unbind(pn_transport_t *transport)
-{
-  assert(transport);
-  if (!transport->connection) return 0;
-
-
-  pn_connection_t *conn = transport->connection;
-  transport->connection = NULL;
-  bool was_referenced = transport->referenced;
-
-  pn_collector_put(conn->collector, PN_OBJECT, conn, PN_CONNECTION_UNBOUND);
-
-  // XXX: what happens if the endpoints are freed before we get here?
-  pn_session_t *ssn = pn_session_head(conn, 0);
-  while (ssn) {
-    pni_delivery_map_clear(&ssn->state.incoming);
-    pni_delivery_map_clear(&ssn->state.outgoing);
-    ssn = pn_session_next(ssn, 0);
-  }
-
-  pn_endpoint_t *endpoint = conn->endpoint_head;
-  while (endpoint) {
-    pn_condition_clear(&endpoint->remote_condition);
-    pn_modified(conn, endpoint, true);
-    endpoint = endpoint->endpoint_next;
-  }
-
-  pni_transport_unbind_channels(transport->local_channels);
-  pni_transport_unbind_channels(transport->remote_channels);
-
-  pn_connection_unbound(conn);
-  if (was_referenced) {
-    pn_decref(conn);
-  }
-  return 0;
-}
-
-pn_error_t *pn_transport_error(pn_transport_t *transport)
-{
-  assert(transport);
-  if (pn_condition_is_set(&transport->condition)) {
-    pn_error_format(transport->error, PN_ERR, "%s: %s",
-                    pn_condition_get_name(&transport->condition),
-                    pn_condition_get_description(&transport->condition));
-  } else {
-    pn_error_clear(transport->error);
-  }
-  return transport->error;
-}
-
-pn_condition_t *pn_transport_condition(pn_transport_t *transport)
-{
-  assert(transport);
-  return &transport->condition;
-}
-
-static void pni_map_remote_handle(pn_link_t *link, uint32_t handle)
-{
-  link->state.remote_handle = handle;
-  pn_hash_put(link->session->state.remote_handles, handle, link);
-  pn_ep_incref(&link->endpoint);
-}
-
-static void pni_unmap_remote_handle(pn_link_t *link)
-{
-  uintptr_t handle = link->state.remote_handle;
-  link->state.remote_handle = -2;
-  if (pn_hash_get(link->session->state.remote_handles, handle)) {
-    pn_ep_decref(&link->endpoint);
-  }
-  // may delete link:
-  pn_hash_del(link->session->state.remote_handles, handle);
-}
-
-static pn_link_t *pni_handle_state(pn_session_t *ssn, uint32_t handle)
-{
-  return (pn_link_t *) pn_hash_get(ssn->state.remote_handles, handle);
-}
-
-bool pni_disposition_batchable(pn_disposition_t *disposition)
-{
-  switch (disposition->type) {
-  case PN_ACCEPTED:
-    return true;
-  case PN_RELEASED:
-    return true;
-  default:
-    return false;
-  }
-}
-
-static int pni_disposition_encode(pn_disposition_t *disposition, pn_data_t *data)
-{
-  pn_condition_t *cond = &disposition->condition;
-  switch (disposition->type) {
-  case PN_RECEIVED:
-    PN_RETURN_IF_ERROR(pn_data_put_list(data));
-    pn_data_enter(data);
-    PN_RETURN_IF_ERROR(pn_data_put_uint(data, disposition->section_number));
-    PN_RETURN_IF_ERROR(pn_data_put_ulong(data, disposition->section_offset));
-    pn_data_exit(data);
-    return 0;
-  case PN_ACCEPTED:
-  case PN_RELEASED:
-    return 0;
-  case PN_REJECTED:
-    return pn_data_fill(data, "[?DL[sSC]]", pn_condition_is_set(cond), ERROR,
-                 pn_condition_get_name(cond),
-                 pn_condition_get_description(cond),
-                 pn_condition_info(cond));
-  case PN_MODIFIED:
-    return pn_data_fill(data, "[ooC]",
-                 disposition->failed,
-                 disposition->undeliverable,
-                 disposition->annotations);
-  default:
-    return pn_data_copy(data, disposition->data);
-  }
-}
-
-
-void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
-                 pn_data_t *args, const char *payload, size_t size)
-{
-  if (transport->trace & PN_TRACE_FRM) {
-    pn_string_format(transport->scratch, "%u %s ", ch, dir == OUT ? "->" : "<-");
-    pn_inspect(args, transport->scratch);
-
-    if (pn_data_size(args)==0) {
-        pn_string_addf(transport->scratch, "(EMPTY FRAME)");
-    }
-
-    if (size) {
-      char buf[1024];
-      int e = pn_quote_data(buf, 1024, payload, size);
-      pn_string_addf(transport->scratch, " (%" PN_ZU ") \"%s\"%s", size, buf,
-                     e == PN_OVERFLOW ? "... (truncated)" : "");
-    }
-
-    pn_transport_log(transport, pn_string_get(transport->scratch));
-  }
-}
-
-int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...)
-{
-  pn_buffer_t *frame_buf = transport->frame;
-  va_list ap;
-  va_start(ap, fmt);
-  pn_data_clear(transport->output_args);
-  int err = pn_data_vfill(transport->output_args, fmt, ap);
-  va_end(ap);
-  if (err) {
-    pn_transport_logf(transport,
-                      "error posting frame: %s, %s: %s", fmt, pn_code(err),
-                      pn_error_text(pn_data_error(transport->output_args)));
-    return PN_ERR;
-  }
-
-  pn_do_trace(transport, ch, OUT, transport->output_args, NULL, 0);
-
- encode_performatives:
-  pn_buffer_clear( frame_buf );
-  pn_rwbytes_t buf = pn_buffer_memory( frame_buf );
-  buf.size = pn_buffer_available( frame_buf );
-
-  ssize_t wr = pn_data_encode( transport->output_args, buf.start, buf.size );
-  if (wr < 0) {
-    if (wr == PN_OVERFLOW) {
-      pn_buffer_ensure( frame_buf, pn_buffer_available( frame_buf ) * 2 );
-      goto encode_performatives;
-    }
-    pn_transport_logf(transport,
-                      "error posting frame: %s", pn_code(wr));
-    return PN_ERR;
-  }
-
-  pn_frame_t frame = {0,};
-  frame.type = type;
-  frame.channel = ch;
-  frame.payload = buf.start;
-  frame.size = wr;
-  size_t n;
-  while (!(n = pn_write_frame(transport->output + transport->available,
-                              transport->capacity - transport->available, frame))) {
-    transport->capacity *= 2;
-    transport->output = (char *) realloc(transport->output, transport->capacity);
-  }
-  transport->output_frames_ct += 1;
-  if (transport->trace & PN_TRACE_RAW) {
-    pn_string_set(transport->scratch, "RAW: \"");
-    pn_quote(transport->scratch, transport->output + transport->available, n);
-    pn_string_addf(transport->scratch, "\"");
-    pn_transport_log(transport, pn_string_get(transport->scratch));
-  }
-  transport->available += n;
-
-  return 0;
-}
-
-static int pni_post_amqp_transfer_frame(pn_transport_t *transport, uint16_t ch,
-                                        uint32_t handle,
-                                        pn_sequence_t id,
-                                        pn_bytes_t *payload,
-                                        const pn_bytes_t *tag,
-                                        uint32_t message_format,
-                                        bool settled,
-                                        bool more,
-                                        pn_sequence_t frame_limit,
-                                        uint64_t code,
-                                        pn_data_t* state)
-{
-  bool more_flag = more;
-  int framecount = 0;
-  pn_buffer_t *frame = transport->frame;
-
-  // create preformatives, assuming 'more' flag need not change
-
- compute_performatives:
-  pn_data_clear(transport->output_args);
-  int err = pn_data_fill(transport->output_args, "DL[IIzIoon?DLC]", TRANSFER,
-                         handle, id, tag->size, tag->start,
-                         message_format,
-                         settled, more_flag, (bool)code, code, state);
-  if (err) {
-    pn_transport_logf(transport,
-                      "error posting transfer frame: %s: %s", pn_code(err),
-                      pn_error_text(pn_data_error(transport->output_args)));
-    return PN_ERR;
-  }
-
-  do { // send as many frames as possible without changing the 'more' flag...
-
-  encode_performatives:
-    pn_buffer_clear( frame );
-    pn_rwbytes_t buf = pn_buffer_memory( frame );
-    buf.size = pn_buffer_available( frame );
-
-    ssize_t wr = pn_data_encode(transport->output_args, buf.start, buf.size);
-    if (wr < 0) {
-      if (wr == PN_OVERFLOW) {
-        pn_buffer_ensure( frame, pn_buffer_available( frame ) * 2 );
-        goto encode_performatives;
-      }
-      pn_transport_logf(transport, "error posting frame: %s", pn_code(wr));
-      return PN_ERR;
-    }
-    buf.size = wr;
-
-    // check if we need to break up the outbound frame
-    size_t available = payload->size;
-    if (transport->remote_max_frame) {
-      if ((available + buf.size) > transport->remote_max_frame - 8) {
-        available = transport->remote_max_frame - 8 - buf.size;
-        if (more_flag == false) {
-          more_flag = true;
-          goto compute_performatives;  // deal with flag change
-        }
-      } else if (more_flag == true && more == false) {
-        // caller has no more, and this is the last frame
-        more_flag = false;
-        goto compute_performatives;
-      }
-    }
-
-    if (pn_buffer_available( frame ) < (available + buf.size)) {
-      // not enough room for payload - try again...
-      pn_buffer_ensure( frame, available + buf.size );
-      goto encode_performatives;
-    }
-
-    pn_do_trace(transport, ch, OUT, transport->output_args, payload->start, available);
-
-    memmove( buf.start + buf.size, payload->start, available);
-    payload->start += available;
-    payload->size -= available;
-    buf.size += available;
-
-    pn_frame_t frame = {AMQP_FRAME_TYPE};
-    frame.channel = ch;
-    frame.payload = buf.start;
-    frame.size = buf.size;
-
-    size_t n;
-    while (!(n = pn_write_frame(transport->output + transport->available,
-                                transport->capacity - transport->available, frame))) {
-      transport->capacity *= 2;
-      transport->output = (char *) realloc(transport->output, transport->capacity);
-    }
-    transport->output_frames_ct += 1;
-    framecount++;
-    if (transport->trace & PN_TRACE_RAW) {
-      pn_string_set(transport->scratch, "RAW: \"");
-      pn_quote(transport->scratch, transport->output + transport->available, n);
-      pn_string_addf(transport->scratch, "\"");
-      pn_transport_log(transport, pn_string_get(transport->scratch));
-    }
-    transport->available += n;
-  } while (payload->size > 0 && framecount < frame_limit);
-
-  return framecount;
-}
-
-static int pni_post_close(pn_transport_t *transport, pn_condition_t *cond)
-{
-  if (!cond && transport->connection) {
-    cond = pn_connection_condition(transport->connection);
-  }
-  const char *condition = NULL;
-  const char *description = NULL;
-  pn_data_t *info = NULL;
-  if (pn_condition_is_set(cond)) {
-    condition = pn_condition_get_name(cond);
-    description = pn_condition_get_description(cond);
-    info = pn_condition_info(cond);
-  }
-
-  return pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[?DL[sSC]]", CLOSE,
-                       (bool) condition, ERROR, condition, description, info);
-}
-
-static pn_collector_t *pni_transport_collector(pn_transport_t *transport)
-{
-  if (transport->connection && transport->connection->collector) {
-    return transport->connection->collector;
-  } else {
-    return NULL;
-  }
-}
-
-static void pni_maybe_post_closed(pn_transport_t *transport)
-{
-  pn_collector_t *collector = pni_transport_collector(transport);
-  if (transport->head_closed && transport->tail_closed) {
-    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_CLOSED);
-  }
-}
-
-static void pni_close_tail(pn_transport_t *transport)
-{
-  if (!transport->tail_closed) {
-    transport->tail_closed = true;
-    pn_collector_t *collector = pni_transport_collector(transport);
-    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_TAIL_CLOSED);
-    pni_maybe_post_closed(transport);
-  }
-}
-
-int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  char buf[1024];
-  if (fmt) {
-    // XXX: result
-    vsnprintf(buf, 1024, fmt, ap);
-  } else {
-    buf[0] = '\0';
-  }
-  va_end(ap);
-  pn_condition_t *cond = &transport->condition;
-  if (!pn_condition_is_set(cond)) {
-    pn_condition_set_name(cond, condition);
-    if (fmt) {
-      pn_condition_set_description(cond, buf);
-    }
-  } else {
-    const char *first = pn_condition_get_description(cond);
-    if (first && fmt) {
-      char extended[2048];
-      snprintf(extended, 2048, "%s (%s)", first, buf);
-      pn_condition_set_description(cond, extended);
-    } else if (fmt) {
-      pn_condition_set_description(cond, buf);
-    }
-  }
-  pn_collector_t *collector = pni_transport_collector(transport);
-  pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_ERROR);
-  if (transport->trace & PN_TRACE_DRV) {
-    pn_transport_logf(transport, "ERROR %s %s", condition, buf);
-  }
-
-  for (int i = 0; i<PN_IO_LAYER_CT; ++i) {
-    if (transport->io_layers[i] && transport->io_layers[i]->handle_error)
-        transport->io_layers[i]->handle_error(transport, i);
-  }
-
-  pni_close_tail(transport);
-  return PN_ERR;
-}
-
-static char *pn_bytes_strdup(pn_bytes_t str)
-{
-  return pn_strndup(str.start, str.size);
-}
-
-int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_connection_t *conn = transport->connection;
-  bool container_q, hostname_q, remote_channel_max_q, remote_max_frame_q;
-  uint16_t remote_channel_max;
-  uint32_t remote_max_frame;
-  pn_bytes_t remote_container, remote_hostname;
-  pn_data_clear(transport->remote_offered_capabilities);
-  pn_data_clear(transport->remote_desired_capabilities);
-  pn_data_clear(transport->remote_properties);
-  int err = pn_data_scan(args, "D.[?S?S?I?HI..CCC]",
-                         &container_q, &remote_container,
-                         &hostname_q, &remote_hostname,
-                         &remote_max_frame_q, &remote_max_frame,
-                         &remote_channel_max_q, &remote_channel_max,
-                         &transport->remote_idle_timeout,
-                         transport->remote_offered_capabilities,
-                         transport->remote_desired_capabilities,
-                         transport->remote_properties);
-  if (err) return err;
-  /*
-   * The default value is already stored in the variable.
-   * But the scanner zeroes out values if it does not
-   * find them in the args, so don't give the variable
-   * directly to the scanner.
-   */
-  if (remote_channel_max_q) {
-    transport->remote_channel_max = remote_channel_max;
-  }
-
-  if (remote_max_frame_q) {
-    transport->remote_max_frame = remote_max_frame;
-  }
-
-  if (transport->remote_max_frame > 0) {
-    if (transport->remote_max_frame < AMQP_MIN_MAX_FRAME_SIZE) {
-      pn_transport_logf(transport, "Peer advertised bad max-frame (%u), forcing to %u",
-                        transport->remote_max_frame, AMQP_MIN_MAX_FRAME_SIZE);
-      transport->remote_max_frame = AMQP_MIN_MAX_FRAME_SIZE;
-    }
-  }
-  if (container_q) {
-    transport->remote_container = pn_bytes_strdup(remote_container);
-  } else {
-    transport->remote_container = NULL;
-  }
-  if (hostname_q) {
-    transport->remote_hostname = pn_bytes_strdup(remote_hostname);
-  } else {
-    transport->remote_hostname = NULL;
-  }
-
-  if (conn) {
-    PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
-    pni_post_remote_open_events(transport, conn);
-  } else {
-    transport->halt = true;
-  }
-  transport->open_rcvd = true;
-  pni_calculate_channel_max(transport);
-  return 0;
-}
-
-int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  bool reply;
-  uint16_t remote_channel;
-  pn_sequence_t next;
-  int err = pn_data_scan(args, "D.[?HI]", &reply, &remote_channel, &next);
-  if (err) return err;
-
-  // AMQP 1.0 section 2.7.1 - if the peer doesn't honor our channel_max --
-  // express our displeasure by closing the connection with a framing error.
-  if (remote_channel > transport->channel_max) {
-    pn_do_error(transport,
-                "amqp:connection:framing-error",
-                "remote channel %d is above negotiated channel_max %d.",
-                remote_channel,
-                transport->channel_max
-               );
-    return PN_TRANSPORT_ERROR;
-  }
-
-  pn_session_t *ssn;
-  if (reply) {
-    ssn = (pn_session_t *) pn_hash_get(transport->local_channels, remote_channel);
-  } else {
-    ssn = pn_session(transport->connection);
-  }
-  if (ssn == 0) {
-    pn_do_error(transport,
-                "amqp:connection:framing-error",
-                "remote channel is above negotiated channel_max %d.",
-                transport->channel_max
-               );
-    return PN_TRANSPORT_ERROR;
-  }
-  ssn->state.incoming_transfer_count = next;
-  pni_map_remote_channel(ssn, channel);
-  PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
-  pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_OPEN);
-  return 0;
-}
-
-pn_link_t *pn_find_link(pn_session_t *ssn, pn_bytes_t name, bool is_sender)
-{
-  pn_endpoint_type_t type = is_sender ? SENDER : RECEIVER;
-
-  for (size_t i = 0; i < pn_list_size(ssn->links); i++)
-  {
-    pn_link_t *link = (pn_link_t *) pn_list_get(ssn->links, i);
-    if (link->endpoint.type == type &&
-        // This function is used to locate the link object for an
-        // incoming attach. If a link object of the same name is found
-        // 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))
-    {
-      return link;
-    }
-  }
-  return NULL;
-}
-
-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))
-    return PN_EXPIRE_WITH_LINK;
-  if (!strncmp(symbol.start, "session-end", symbol.size))
-    return PN_EXPIRE_WITH_SESSION;
-  if (!strncmp(symbol.start, "connection-close", symbol.size))
-    return PN_EXPIRE_WITH_CONNECTION;
-  if (!strncmp(symbol.start, "never", symbol.size))
-    return PN_EXPIRE_NEVER;
-
-  return PN_EXPIRE_WITH_SESSION;
-}
-
-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))
-    return PN_DIST_MODE_MOVE;
-  if (!strncmp(symbol.start, "copy", symbol.size))
-    return PN_DIST_MODE_COPY;
-
-  return PN_DIST_MODE_UNSPECIFIED;
-}
-
-static const char *dist_mode2symbol(const pn_distribution_mode_t mode)
-{
-  switch (mode)
-  {
-  case PN_DIST_MODE_COPY:
-    return "copy";
-  case PN_DIST_MODE_MOVE:
-    return "move";
-  default:
-    return NULL;
-  }
-}
-
-int pn_terminus_set_address_bytes(pn_terminus_t *terminus, pn_bytes_t address)
-{
-  assert(terminus);
-  return pn_string_setn(terminus->address, address.start, address.size);
-}
-
-int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_bytes_t name;
-  uint32_t handle;
-  bool is_sender;
-  pn_bytes_t source, target;
-  pn_durability_t src_dr, tgt_dr;
-  pn_bytes_t src_exp, tgt_exp;
-  pn_seconds_t src_timeout, tgt_timeout;
-  bool src_dynamic, tgt_dynamic;
-  pn_sequence_t idc;
-  pn_bytes_t dist_mode;
-  bool snd_settle, rcv_settle;
-  uint8_t snd_settle_mode, rcv_settle_mode;
-  int err = pn_data_scan(args, "D.[SIo?B?BD.[SIsIo.s]D.[SIsIo]..I]", &name, &handle,
-                         &is_sender,
-                         &snd_settle, &snd_settle_mode,
-                         &rcv_settle, &rcv_settle_mode,
-                         &source, &src_dr, &src_exp, &src_timeout, &src_dynamic, &dist_mode,
-                         &target, &tgt_dr, &tgt_exp, &tgt_timeout, &tgt_dynamic,
-                         &idc);
-  if (err) return err;
-  char strbuf[128];      // avoid malloc for most link names
-  char *strheap = (name.size >= sizeof(strbuf)) ? (char *) malloc(name.size + 1) : NULL;
-  char *strname = strheap ? strheap : strbuf;
-  strncpy(strname, name.start, name.size);
-  strname[name.size] = '\0';
-
-  pn_session_t *ssn = pni_channel_state(transport, channel);
-  if (!ssn) {
-      pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
-      if (strheap) free(strheap);
-      return PN_EOS;
-  }
-  pn_link_t *link = pn_find_link(ssn, name, is_sender);
-  if (!link) {
-    if (is_sender) {
-      link = (pn_link_t *) pn_sender(ssn, strname);
-    } else {
-      link = (pn_link_t *) pn_receiver(ssn, strname);
-    }
-  }
-
-  if (strheap) {
-    free(strheap);
-  }
-
-  pni_map_remote_handle(link, handle);
-  PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_ACTIVE);
-  pn_terminus_t *rsrc = &link->remote_source;
-  if (source.start || src_dynamic) {
-    pn_terminus_set_type(rsrc, PN_SOURCE);
-    pn_terminus_set_address_bytes(rsrc, source);
-    pn_terminus_set_durability(rsrc, src_dr);
-    pn_terminus_set_expiry_policy(rsrc, symbol2policy(src_exp));
-    pn_terminus_set_timeout(rsrc, src_timeout);
-    pn_terminus_set_dynamic(rsrc, src_dynamic);
-    pn_terminus_set_distribution_mode(rsrc, symbol2dist_mode(dist_mode));
-  } else {
-    pn_terminus_set_type(rsrc, PN_UNSPECIFIED);
-  }
-  pn_terminus_t *rtgt = &link->remote_target;
-  if (target.start || tgt_dynamic) {
-    pn_terminus_set_type(rtgt, PN_TARGET);
-    pn_terminus_set_address_bytes(rtgt, target);
-    pn_terminus_set_durability(rtgt, tgt_dr);
-    pn_terminus_set_expiry_policy(rtgt, symbol2policy(tgt_exp));
-    pn_terminus_set_timeout(rtgt, tgt_timeout);
-    pn_terminus_set_dynamic(rtgt, tgt_dynamic);
-  } else {
-    uint64_t code = 0;
-    pn_data_clear(link->remote_target.capabilities);
-    err = pn_data_scan(args, "D.[.....D..DL[C]...]", &code,
-                       link->remote_target.capabilities);
-    if (err) return err;
-    if (code == COORDINATOR) {
-      pn_terminus_set_type(rtgt, PN_COORDINATOR);
-    } else if (code == TARGET) {
-      pn_terminus_set_type(rtgt, PN_TARGET);
-    } else {
-      pn_terminus_set_type(rtgt, PN_UNSPECIFIED);
-    }
-  }
-
-  if (snd_settle)
-    link->remote_snd_settle_mode = snd_settle_mode;
-  if (rcv_settle)
-    link->remote_rcv_settle_mode = rcv_settle_mode;
-
-  pn_data_clear(link->remote_source.properties);
-  pn_data_clear(link->remote_source.filter);
-  pn_data_clear(link->remote_source.outcomes);
-  pn_data_clear(link->remote_source.capabilities);
-  pn_data_clear(link->remote_target.properties);
-  pn_data_clear(link->remote_target.capabilities);
-
-  err = pn_data_scan(args, "D.[.....D.[.....C.C.CC]D.[.....CC]",
-                     link->remote_source.properties,
-                     link->remote_source.filter,
-                     link->remote_source.outcomes,
-                     link->remote_source.capabilities,
-                     link->remote_target.properties,
-                     link->remote_target.capabilities);
-  if (err) return err;
-
-  pn_data_rewind(link->remote_source.properties);
-  pn_data_rewind(link->remote_source.filter);
-  pn_data_rewind(link->remote_source.outcomes);
-  pn_data_rewind(link->remote_source.capabilities);
-  pn_data_rewind(link->remote_target.properties);
-  pn_data_rewind(link->remote_target.capabilities);
-
-  if (!is_sender) {
-    link->state.delivery_count = idc;
-  }
-
-  pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_OPEN);
-  return 0;
-}
-
-static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link);
-
-// free the delivery
-static void pn_full_settle(pn_delivery_map_t *db, pn_delivery_t *delivery)
-{
-  assert(!delivery->work);
-  pn_clear_tpwork(delivery);
-  pn_delivery_map_del(db, delivery);
-  pn_incref(delivery);
-  pn_decref(delivery);
-}
-
-int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  // XXX: multi transfer
-  uint32_t handle;
-  pn_bytes_t tag;
-  bool id_present;
-  pn_sequence_t id;
-  bool settled;
-  bool more;
-  bool has_type;
-  uint64_t type;
-  pn_data_clear(transport->disp_data);
-  int err = pn_data_scan(args, "D.[I?Iz.oo.D?LC]", &handle, &id_present, &id, &tag,
-                         &settled, &more, &has_type, &type, transport->disp_data);
-  if (err) return err;
-  pn_session_t *ssn = pni_channel_state(transport, channel);
-  if (!ssn) {
-    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
-  }
-
-  if (!ssn->state.incoming_window) {
-    return pn_do_error(transport, "amqp:session:window-violation", "incoming session window exceeded");
-  }
-
-  pn_link_t *link = pni_handle_state(ssn, handle);
-  if (!link) {
-    return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
-  }
-  pn_delivery_t *delivery;
-  if (link->unsettled_tail && !link->unsettled_tail->done) {
-    delivery = link->unsettled_tail;
-  } else {
-    pn_delivery_map_t *incoming = &ssn->state.incoming;
-
-    if (!ssn->state.incoming_init) {
-      incoming->next = id;
-      ssn->state.incoming_init = true;
-      ssn->incoming_deliveries++;
-    }
-
-    delivery = pn_delivery(link, pn_dtag(tag.start, tag.size));
-    pn_delivery_state_t *state = pni_delivery_map_push(incoming, delivery);
-    if (id_present && id != state->id) {
-      return pn_do_error(transport, "amqp:session:invalid-field",
-                         "sequencing error, expected delivery-id %u, got %u",
-                         state->id, id);
-    }
-    if (has_type) {
-      delivery->remote.type = type;
-      pn_data_copy(delivery->remote.data, transport->disp_data);
-    }
-
-    link->state.delivery_count++;
-    link->state.link_credit--;
-    link->queued++;
-
-    // XXX: need to fill in remote state: delivery->remote.state = ...;
-    delivery->remote.settled = settled;
-    if (settled) {
-      delivery->updated = true;
-      pn_work_update(transport->connection, delivery);
-    }
-  }
-
-  pn_buffer_append(delivery->bytes, payload->start, payload->size);
-  ssn->incoming_bytes += payload->size;
-  delivery->done = !more;
-
-  ssn->state.incoming_transfer_count++;
-  ssn->state.incoming_window--;
-
-  // XXX: need better policy for when to refresh window
-  if (!ssn->state.incoming_window && (int32_t) link->state.local_handle >= 0) {
-    pni_post_flow(transport, ssn, link);
-  }
-
-  pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
-  return 0;
-}
-
-int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_sequence_t onext, inext, delivery_count;
-  uint32_t iwin, owin, link_credit;
-  uint32_t handle;
-  bool inext_init, handle_init, dcount_init, drain;
-  int err = pn_data_scan(args, "D.[?IIII?I?II.o]", &inext_init, &inext, &iwin,
-                         &onext, &owin, &handle_init, &handle, &dcount_init,
-                         &delivery_count, &link_credit, &drain);
-  if (err) return err;
-
-  pn_session_t *ssn = pni_channel_state(transport, channel);
-  if (!ssn) {
-    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
-  }
-
-  if (inext_init) {
-    ssn->state.remote_incoming_window = inext + iwin - ssn->state.outgoing_transfer_count;
-  } else {
-    ssn->state.remote_incoming_window = iwin;
-  }
-
-  if (handle_init) {
-    pn_link_t *link = pni_handle_state(ssn, handle);
-    if (!link) {
-      return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
-    }
-    if (link->endpoint.type == SENDER) {
-      pn_sequence_t receiver_count;
-      if (dcount_init) {
-        receiver_count = delivery_count;
-      } else {
-        // our initial delivery count
-        receiver_count = 0;
-      }
-      pn_sequence_t old = link->state.link_credit;
-      link->state.link_credit = receiver_count + link_credit - link->state.delivery_count;
-      link->credit += link->state.link_credit - old;
-      link->drain = drain;
-      pn_delivery_t *delivery = pn_link_current(link);
-      if (delivery) pn_work_update(transport->connection, delivery);
-    } else {
-      pn_sequence_t delta = delivery_count - link->state.delivery_count;
-      if (delta > 0) {
-        link->state.delivery_count += delta;
-        link->state.link_credit -= delta;
-        link->credit -= delta;
-        link->drained += delta;
-      }
-    }
-
-    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
-  }
-
-  return 0;
-}
-
-#define SCAN_ERROR_DEFAULT ("D.[D.[sSC]")
-#define SCAN_ERROR_DETACH ("D.[..D.[sSC]")
-#define SCAN_ERROR_DISP ("[D.[sSC]")
-
-static int pn_scan_error(pn_data_t *data, pn_condition_t *condition, const char *fmt)
-{
-  pn_bytes_t cond;
-  pn_bytes_t desc;
-  pn_condition_clear(condition);
-  int err = pn_data_scan(data, fmt, &cond, &desc, condition->info);
-  if (err) return err;
-  pn_string_setn(condition->name, cond.start, cond.size);
-  pn_string_setn(condition->description, desc.start, desc.size);
-  pn_data_rewind(condition->info);
-  return 0;
-}
-
-int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  bool role;
-  pn_sequence_t first, last;
-  uint64_t type = 0;
-  bool last_init, settled, type_init;
-  pn_data_clear(transport->disp_data);
-  int err = pn_data_scan(args, "D.[oI?IoD?LC]", &role, &first, &last_init,
-                         &last, &settled, &type_init, &type,
-                         transport->disp_data);
-  if (err) return err;
-  if (!last_init) last = first;
-
-  pn_session_t *ssn = pni_channel_state(transport, channel);
-  if (!ssn) {
-    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
-  }
-
-  pn_delivery_map_t *deliveries;
-  if (role) {
-    deliveries = &ssn->state.outgoing;
-  } else {
-    deliveries = &ssn->state.incoming;
-  }
-
-  pn_data_rewind(transport->disp_data);
-  bool remote_data = (pn_data_next(transport->disp_data) &&
-                      pn_data_get_list(transport->disp_data) > 0);
-
-  for (pn_sequence_t id = first; id <= last; id++) {
-    pn_delivery_t *delivery = pni_delivery_map_get(deliveries, id);
-    pn_disposition_t *remote = &delivery->remote;
-    if (delivery) {
-      if (type_init) remote->type = type;
-      if (remote_data) {
-        switch (type) {
-        case PN_RECEIVED:
-          pn_data_rewind(transport->disp_data);
-          pn_data_next(transport->disp_data);
-          pn_data_enter(transport->disp_data);
-          if (pn_data_next(transport->disp_data))
-            remote->section_number = pn_data_get_uint(transport->disp_data);
-          if (pn_data_next(transport->disp_data))
-            remote->section_offset = pn_data_get_ulong(transport->disp_data);
-          break;
-        case PN_ACCEPTED:
-          break;
-        case PN_REJECTED:
-          err = pn_scan_error(transport->disp_data, &remote->condition, SCAN_ERROR_DISP);
-          if (err) return err;
-          break;
-        case PN_RELEASED:
-          break;
-        case PN_MODIFIED:
-          pn_data_rewind(transport->disp_data);
-          pn_data_next(transport->disp_data);
-          pn_data_enter(transport->disp_data);
-          if (pn_data_next(transport->disp_data))
-            remote->failed = pn_data_get_bool(transport->disp_data);
-          if (pn_data_next(transport->disp_data))
-            remote->undeliverable = pn_data_get_bool(transport->disp_data);
-          pn_data_narrow(transport->disp_data);
-          pn_data_clear(remote->data);
-          pn_data_appendn(remote->annotations, transport->disp_data, 1);
-          pn_data_widen(transport->disp_data);
-          break;
-        default:
-          pn_data_copy(remote->data, transport->disp_data);
-          break;
-        }
-      }
-      remote->settled = settled;
-      delivery->updated = true;
-      pn_work_update(transport->connection, delivery);
-
-      pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
-    }
-  }
-
-  return 0;
-}
-
-int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  uint32_t handle;
-  bool closed;
-  int err = pn_data_scan(args, "D.[Io]", &handle, &closed);
-  if (err) return err;
-
-  pn_session_t *ssn = pni_channel_state(transport, channel);
-  if (!ssn) {
-    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
-  }
-  pn_link_t *link = pni_handle_state(ssn, handle);
-  if (!link) {
-    return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
-  }
-
-  err = pn_scan_error(args, &link->endpoint.remote_condition, SCAN_ERROR_DETACH);
-  if (err) return err;
-
-  if (closed)
-  {
-    PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
-    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_CLOSE);
-  } else {
-    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_DETACH);
-  }
-
-  pni_unmap_remote_handle(link);
-  return 0;
-}
-
-int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_session_t *ssn = pni_channel_state(transport, channel);
-  if (!ssn) {
-    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
-  }
-  int err = pn_scan_error(args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
-  if (err) return err;
-  PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_CLOSE);
-  pni_unmap_remote_channel(ssn);
-  return 0;
-}
-
-int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_connection_t *conn = transport->connection;
-  int err = pn_scan_error(args, &transport->remote_condition, SCAN_ERROR_DEFAULT);
-  if (err) return err;
-  transport->close_rcvd = true;
-  PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
-  pn_collector_put(transport->connection->collector, PN_OBJECT, conn, PN_CONNECTION_REMOTE_CLOSE);
-  return 0;
-}
-
-// deprecated
-ssize_t pn_transport_input(pn_transport_t *transport, const char *bytes, size_t available)
-{
-  if (!transport) return PN_ARG_ERR;
-  if (available == 0) {
-    return pn_transport_close_tail(transport);
-  }
-  const size_t original = available;
-  ssize_t capacity = pn_transport_capacity(transport);
-  if (capacity < 0) return capacity;
-  while (available && capacity) {
-    char *dest = pn_transport_tail(transport);
-    assert(dest);
-    size_t count = pn_min( (size_t)capacity, available );
-    memmove( dest, bytes, count );
-    available -= count;
-    bytes += count;
-    int rc = pn_transport_process( transport, count );
-    if (rc < 0) return rc;
-    capacity = pn_transport_capacity(transport);
-    if (capacity < 0) return capacity;
-  }
-
-  return original - available;
-}
-
-// process pending input until none remaining or EOS
-static ssize_t transport_consume(pn_transport_t *transport)
-{
-  // This allows whatever is driving the I/O to set the error
-  // condition on the transport before doing pn_transport_close_head()
-  // or pn_transport_close_tail(). This allows all transport errors to
-  // flow to the app the same way, but provides cleaner error messages
-  // since we don't try to look for a protocol header when, e.g. the
-  // connection was refused.
-  if (!transport->bytes_input && transport->tail_closed &&
-      pn_condition_is_set(&transport->condition)) {
-    pn_do_error(transport, NULL, NULL);
-    return PN_EOS;
-  }
-
-  size_t consumed = 0;
-
-  while (transport->input_pending || transport->tail_closed) {
-    ssize_t n;
-    n = transport->io_layers[0]->
-      process_input( transport, 0,
-                     transport->input_buf + consumed,
-                     transport->input_pending );
-    if (n > 0) {
-      consumed += n;
-      transport->input_pending -= n;
-    } else if (n == 0) {
-      break;
-    } else {
-      assert(n == PN_EOS);
-      if (transport->trace & (PN_TRACE_RAW | PN_TRACE_FRM))
-        pn_transport_log(transport, "  <- EOS");
-      transport->input_pending = 0;  // XXX ???
-      return n;
-    }
-  }
-
-  if (transport->input_pending && consumed) {
-    memmove( transport->input_buf,  &transport->input_buf[consumed], transport->input_pending );
-  }
-
-  return consumed;
-}
-
-static int pni_process_conn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == CONNECTION)
-  {
-    if (!(endpoint->state & PN_LOCAL_UNINIT) && !transport->open_sent)
-    {
-      // as per the recommendation in the spec, advertise half our
-      // actual timeout to the remote
-      const pn_millis_t idle_timeout = transport->local_idle_timeout
-          ? (transport->local_idle_timeout/2)
-          : 0;
-      pn_connection_t *connection = (pn_connection_t *) endpoint;
-      const char *cid = pn_string_get(connection->container);
-      pni_calculate_channel_max(transport);
-      int err = pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[SS?I?H?InnCCC]", OPEN,
-                              cid ? cid : "",
-                              pn_string_get(connection->hostname),
-                              // if not zero, advertise our max frame size and idle timeout
-                              (bool)transport->local_max_frame, transport->local_max_frame,
-                              (bool)transport->channel_max, transport->channel_max,
-                              (bool)idle_timeout, idle_timeout,
-                              connection->offered_capabilities,
-                              connection->desired_capabilities,
-                              connection->properties);
-      if (err) return err;
-      transport->open_sent = true;
-    }
-  }
-
-  return 0;
-}
-
-static uint16_t allocate_alias(pn_hash_t *aliases, uint32_t max_index, int * valid)
-{
-  for (uint32_t i = 0; i <= max_index; i++) {
-    if (!pn_hash_get(aliases, i)) {
-      * valid = 1;
-      return i;
-    }
-  }
-
-  * valid = 0;
-  return 0;
-}
-
-static size_t pni_session_outgoing_window(pn_session_t *ssn)
-{
-  return ssn->outgoing_window;
-}
-
-static size_t pni_session_incoming_window(pn_session_t *ssn)
-{
-  uint32_t size = ssn->connection->transport->local_max_frame;
-  if (!size) {
-    return 2147483647; // biggest legal value
-  } else {
-    return (ssn->incoming_capacity - ssn->incoming_bytes)/size;
-  }
-}
-
-static int pni_map_local_channel(pn_session_t *ssn)
-{
-  pn_transport_t *transport = ssn->connection->transport;
-  pn_session_state_t *state = &ssn->state;
-  int valid;
-  uint16_t channel = allocate_alias(transport->local_channels, transport->channel_max, & valid);
-  if (!valid) {
-    return 0;
-  }
-  state->local_channel = channel;
-  pn_hash_put(transport->local_channels, channel, ssn);
-  pn_ep_incref(&ssn->endpoint);
-  return 1;
-}
-
-static int pni_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == SESSION && transport->open_sent)
-  {
-    pn_session_t *ssn = (pn_session_t *) endpoint;
-    pn_session_state_t *state = &ssn->state;
-    if (!(endpoint->state & PN_LOCAL_UNINIT) && state->local_channel == (uint16_t) -1)
-    {
-      if (! pni_map_local_channel(ssn)) {
-        pn_transport_logf(transport, "unable to find an open available channel within limit of %d", transport->channel_max );
-        return PN_ERR;
-      }
-      state->incoming_window = pni_session_incoming_window(ssn);
-      state->outgoing_window = pni_session_outgoing_window(ssn);
-      pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?HIII]", BEGIN,
-                    ((int16_t) state->remote_channel >= 0), state->remote_channel,
-                    state->outgoing_transfer_count,
-                    state->incoming_window,
-                    state->outgoing_window);
-    }
-  }
-
-  return 0;
-}
-
-static const char *expiry_symbol(pn_expiry_policy_t policy)
-{
-  switch (policy)
-  {
-  case PN_EXPIRE_WITH_LINK:
-    return "link-detach";
-  case PN_EXPIRE_WITH_SESSION:
-    return NULL;
-  case PN_EXPIRE_WITH_CONNECTION:
-    return "connection-close";
-  case PN_EXPIRE_NEVER:
-    return "never";
-  }
-  return NULL;
-}
-
-static int pni_map_local_handle(pn_link_t *link) {
-  pn_link_state_t *state = &link->state;
-  pn_session_state_t *ssn_state = &link->session->state;
-  int valid;
-  // XXX TODO MICK: once changes are made to handle_max, change this hardcoded value to something reasonable.
-  state->local_handle = allocate_alias(ssn_state->local_handles, 65536, & valid);
-  if ( ! valid )
-    return 0;
-  pn_hash_put(ssn_state->local_handles, state->local_handle, link);
-  pn_ep_incref(&link->endpoint);
-  return 1;
-}
-
-static int pni_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (transport->open_sent && (endpoint->type == SENDER ||
-                               endpoint->type == RECEIVER))
-  {
-    pn_link_t *link = (pn_link_t *) endpoint;
-    pn_session_state_t *ssn_state = &link->session->state;
-    pn_link_state_t *state = &link->state;
-    if (((int16_t) ssn_state->local_channel >= 0) &&
-        !(endpoint->state & PN_LOCAL_UNINIT) && state->local_handle == (uint32_t) -1)
-    {
-      pni_map_local_handle(link);
-      const pn_distribution_mode_t dist_mode = link->source.distribution_mode;
-      if (link->target.type == PN_COORDINATOR) {
-        int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
-                                "DL[SIoBB?DL[SIsIoC?sCnCC]DL[C]nnI]", ATTACH,
-                                pn_string_get(link->name),
-                                state->local_handle,
-                                endpoint->type == RECEIVER,
-                                link->snd_settle_mode,
-                                link->rcv_settle_mode,
-                                (bool) link->source.type, SOURCE,
-                                pn_string_get(link->source.address),
-                                link->source.durability,
-                                expiry_symbol(link->source.expiry_policy),
-                                link->source.timeout,
-                                link->source.dynamic,
-                                link->source.properties,
-                                (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
-                                link->source.filter,
-                                link->source.outcomes,
-                                link->source.capabilities,
-                                COORDINATOR, link->target.capabilities,
-                                0);
-        if (err) return err;
-      } else {
-        int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
-                                "DL[SIoBB?DL[SIsIoC?sCnCC]?DL[SIsIoCC]nnI]", ATTACH,
-                                pn_string_get(link->name),
-                                state->local_handle,
-                                endpoint->type == RECEIVER,
-                                link->snd_settle_mode,
-                                link->rcv_settle_mode,
-                                (bool) link->source.type, SOURCE,
-                                pn_string_get(link->source.address),
-                                link->source.durability,
-                                expiry_symbol(link->source.expiry_policy),
-                                link->source.timeout,
-                                link->source.dynamic,
-                                link->source.properties,
-                                (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
-                                link->source.filter,
-                                link->source.outcomes,
-                                link->source.capabilities,
-                                (bool) link->target.type, TARGET,
-                                pn_string_get(link->target.address),
-                                link->target.durability,
-                                expiry_symbol(link->target.expiry_policy),
-                                link->target.timeout,
-                                link->target.dynamic,
-                                link->target.properties,
-                                link->target.capabilities,
-                                0);
-        if (err) return err;
-      }
-    }
-  }
-
-  return 0;
-}
-
-static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link)
-{
-  ssn->state.incoming_window = pni_session_incoming_window(ssn);
-  ssn->state.outgoing_window = pni_session_outgoing_window(ssn);
-  bool linkq = (bool) link;
-  pn_link_state_t *state = &link->state;
-  return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[?IIII?I?I?In?o]", FLOW,
-                       (int16_t) ssn->state.remote_channel >= 0, ssn->state.incoming_transfer_count,
-                       ssn->state.incoming_window,
-                       ssn->state.outgoing_transfer_count,
-                       ssn->state.outgoing_window,
-                       linkq, linkq ? state->local_handle : 0,
-                       linkq, linkq ? state->delivery_count : 0,
-                       linkq, linkq ? state->link_credit : 0,
-                       linkq, linkq ? link->drain : false);
-}
-
-static int pni_process_flow_receiver(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == RECEIVER && endpoint->state & PN_LOCAL_ACTIVE)
-  {
-    pn_link_t *rcv = (pn_link_t *) endpoint;
-    pn_session_t *ssn = rcv->session;
-    pn_link_state_t *state = &rcv->state;
-    if ((int16_t) ssn->state.local_channel >= 0 &&
-        (int32_t) state->local_handle >= 0 &&
-        ((rcv->drain || state->link_credit != rcv->credit - rcv->queued) || !ssn->state.incoming_window)) {
-      state->link_credit = rcv->credit - rcv->queued;
-      return pni_post_flow(transport, ssn, rcv);
-    }
-  }
-
-  return 0;
-}
-
-static int pni_flush_disp(pn_transport_t *transport, pn_session_t *ssn)
-{
-  uint64_t code = ssn->state.disp_code;
-  bool settled = ssn->state.disp_settled;
-  if (ssn->state.disp) {
-    int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[oIIo?DL[]]", DISPOSITION,
-                            ssn->state.disp_type, ssn->state.disp_first, ssn->state.disp_last,
-                            settled, (bool)code, code);
-    if (err) return err;
-    ssn->state.disp_type = 0;
-    ssn->state.disp_code = 0;
-    ssn->state.disp_settled = 0;
-    ssn->state.disp_first = 0;
-    ssn->state.disp_last = 0;
-    ssn->state.disp = false;
-  }
-  return 0;
-}
-
-static int pni_post_disp(pn_transport_t *transport, pn_delivery_t *delivery)
-{
-  pn_link_t *link = delivery->link;
-  pn_session_t *ssn = link->session;
-  pn_session_state_t *ssn_state = &ssn->state;
-  pn_modified(transport->connection, &link->session->endpoint, false);
-  pn_delivery_state_t *state = &delivery->state;
-  assert(state->init);
-  bool role = (link->endpoint.type == RECEIVER);
-  uint64_t code = delivery->local.type;
-
-  if (!code && !delivery->local.settled) {
-    return 0;
-  }
-
-  if (!pni_disposition_batchable(&delivery->local)) {
-    pn_data_clear(transport->disp_data);
-    PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
-    return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel,
-      "DL[oIIo?DLC]", DISPOSITION,
-      role, state->id, state->id, delivery->local.settled,
-      (bool)code, code, transport->disp_data);
-  }
-
-  if (ssn_state->disp && code == ssn_state->disp_code &&
-      delivery->local.settled == ssn_state->disp_settled &&
-      ssn_state->disp_type == role) {
-    if (state->id == ssn_state->disp_first - 1) {
-      ssn_state->disp_first = state->id;
-      return 0;
-    } else if (state->id == ssn_state->disp_last + 1) {
-      ssn_state->disp_last = state->id;
-      return 0;
-    }
-  }
-
-  if (ssn_state->disp) {
-    int err = pni_flush_disp(transport, ssn);
-    if (err) return err;
-  }
-
-  ssn_state->disp_type = role;
-  ssn_state->disp_code = code;
-  ssn_state->disp_settled = delivery->local.settled;
-  ssn_state->disp_first = state->id;
-  ssn_state->disp_last = state->id;
-  ssn_state->disp = true;
-
-  return 0;
-}
-
-static int pni_process_tpwork_sender(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
-{
-  *settle = false;
-  pn_link_t *link = delivery->link;
-  pn_session_state_t *ssn_state = &link->session->state;
-  pn_link_state_t *link_state = &link->state;
-  bool xfr_posted = false;
-  if ((int16_t) ssn_state->local_channel >= 0 && (int32_t) link_state->local_handle >= 0) {
-    pn_delivery_state_t *state = &delivery->state;
-    if (!state->sent && (delivery->done || pn_buffer_size(delivery->bytes) > 0) &&
-        ssn_state->remote_incoming_window > 0 && link_state->link_credit > 0) {
-      if (!state->init) {
-        state = pni_delivery_map_push(&ssn_state->outgoing, delivery);
-      }
-
-      pn_bytes_t bytes = pn_buffer_bytes(delivery->bytes);
-      size_t full_size = bytes.size;
-      pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
-      pn_data_clear(transport->disp_data);
-      PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
-      int count = pni_post_amqp_transfer_frame(transport,
-                                              ssn_state->local_channel,
-                                              link_state->local_handle,
-                                              state->id, &bytes, &tag,
-                                              0, // message-format
-                                              delivery->local.settled,
-                                              !delivery->done,
-                                              ssn_state->remote_incoming_window,
-                                              delivery->local.type, transport->disp_data);
-      if (count < 0) return count;
-      xfr_posted = true;
-      ssn_state->outgoing_transfer_count += count;
-      ssn_state->remote_incoming_window -= count;
-
-      int sent = full_size - bytes.size;
-      pn_buffer_trim(delivery->bytes, sent, 0);
-      link->session->outgoing_bytes -= sent;
-      if (!pn_buffer_size(delivery->bytes) && delivery->done) {
-        state->sent = true;
-        link_state->delivery_count++;
-        link_state->link_credit--;
-        link->queued--;
-        link->session->outgoing_deliveries--;
-      }
-
-      pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
-    }
-  }
-
-  pn_delivery_state_t *state = delivery->state.init ? &delivery->state : NULL;
-  if ((int16_t) ssn_state->local_channel >= 0 && !delivery->remote.settled
-      && state && state->sent && !xfr_posted) {
-    int err = pni_post_disp(transport, delivery);
-    if (err) return err;
-  }
-
-  *settle = delivery->local.settled && state && state->sent;
-  return 0;
-}
-
-static int pni_process_tpwork_receiver(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
-{
-  *settle = false;
-  pn_link_t *link = delivery->link;
-  // XXX: need to prevent duplicate disposition sending
-  pn_session_t *ssn = link->session;
-  if ((int16_t) ssn->state.local_channel >= 0 && !delivery->remote.settled && delivery->state.init) {
-    int err = pni_post_disp(transport, delivery);
-    if (err) return err;
-  }
-
-  // XXX: need to centralize this policy and improve it
-  if (!ssn->state.incoming_window) {
-    int err = pni_post_flow(transport, ssn, link);
-    if (err) return err;
-  }
-
-  *settle = delivery->local.settled;
-  return 0;
-}
-
-static int pni_process_tpwork(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == CONNECTION && !transport->close_sent)
-  {
-    pn_connection_t *conn = (pn_connection_t *) endpoint;
-    pn_delivery_t *delivery = conn->tpwork_head;
-    while (delivery)
-    {
-      pn_delivery_t *tp_next = delivery->tpwork_next;
-      bool settle = false;
-
-      pn_link_t *link = delivery->link;
-      pn_delivery_map_t *dm = NULL;
-      if (pn_link_is_sender(link)) {
-        dm = &link->session->state.outgoing;
-        int err = pni_process_tpwork_sender(transport, delivery, &settle);
-        if (err) return err;
-      } else {
-        dm = &link->session->state.incoming;
-        int err = pni_process_tpwork_receiver(transport, delivery, &settle);
-        if (err) return err;
-      }
-
-      if (settle) {
-        pn_full_settle(dm, delivery);
-      } else if (!pn_delivery_buffered(delivery)) {
-        pn_clear_tpwork(delivery);
-      }
-
-      delivery = tp_next;
-    }
-  }
-
-  return 0;
-}
-
-static int pni_process_flush_disp(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == SESSION) {
-    pn_session_t *session = (pn_session_t *) endpoint;
-    pn_session_state_t *state = &session->state;
-    if ((int16_t) state->local_channel >= 0 && !transport->close_sent)
-    {
-      int err = pni_flush_disp(transport, session);
-      if (err) return err;
-    }
-  }
-
-  return 0;
-}
-
-static int pni_process_flow_sender(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == SENDER && endpoint->state & PN_LOCAL_ACTIVE)
-  {
-    pn_link_t *snd = (pn_link_t *) endpoint;
-    pn_session_t *ssn = snd->session;
-    pn_link_state_t *state = &snd->state;
-    if ((int16_t) ssn->state.local_channel >= 0 &&
-        (int32_t) state->local_handle >= 0 &&
-        snd->drain && snd->drained) {
-      pn_delivery_t *tail = snd->unsettled_tail;
-      if (!tail || !pn_delivery_buffered(tail)) {
-        state->delivery_count += state->link_credit;
-        state->link_credit = 0;
-        snd->drained = 0;
-        return pni_post_flow(transport, ssn, snd);
-      }
-    }
-  }
-
-  return 0;
-}
-
-static void pni_unmap_local_handle(pn_link_t *link) {
-  pn_link_state_t *state = &link->state;
-  uintptr_t handle = state->local_handle;
-  state->local_handle = -2;
-  if (pn_hash_get(link->session->state.local_handles, handle)) {
-    pn_ep_decref(&link->endpoint);
-  }
-  // may delete link
-  pn_hash_del(link->session->state.local_handles, handle);
-}
-
-static int pni_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == SENDER || endpoint->type == RECEIVER)
-  {
-    pn_link_t *link = (pn_link_t *) endpoint;
-    pn_session_t *session = link->session;
-    pn_session_state_t *ssn_state = &session->state;
-    pn_link_state_t *state = &link->state;
-    if (((endpoint->state & PN_LOCAL_CLOSED) || link->detached) && (int32_t) state->local_handle >= 0 &&
-        (int16_t) ssn_state->local_channel >= 0 && !transport->close_sent) {
-      if (pn_link_is_sender(link) && pn_link_queued(link) &&
-          (int32_t) state->remote_handle != -2 &&
-          (int16_t) ssn_state->remote_channel != -2 &&
-          !transport->close_rcvd) return 0;
-
-      const char *name = NULL;
-      const char *description = NULL;
-      pn_data_t *info = NULL;
-
-      if (pn_condition_is_set(&endpoint->condition)) {
-        name = pn_condition_get_name(&endpoint->condition);
-        description = pn_condition_get_description(&endpoint->condition);
-        info = pn_condition_info(&endpoint->condition);
-      }
-
-      int err =
-          pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
-                        "DL[Io?DL[sSC]]", DETACH, state->local_handle, !link->detached,
-                        (bool)name, ERROR, name, description, info);
-      if (err) return err;
-      pni_unmap_local_handle(link);
-    }
-
-    pn_clear_modified(transport->connection, endpoint);
-  }
-
-  return 0;
-}
-
-static bool pni_pointful_buffering(pn_transport_t *transport, pn_session_t *session)
-{
-  if (transport->close_rcvd) return false;
-  if (!transport->open_rcvd) return true;
-
-  pn_connection_t *conn = transport->connection;
-  pn_link_t *link = pn_link_head(conn, 0);
-  while (link) {
-    if (pn_link_is_sender(link) && pn_link_queued(link) > 0) {
-      pn_session_t *ssn = link->session;
-      if (session && session == ssn) {
-        if ((int32_t) link->state.remote_handle != -2 &&
-            (int16_t) session->state.remote_channel != -2) {
-          return true;
-        }
-      }
-    }
-    link = pn_link_next(link, 0);
-  }
-
-  return false;
-}
-
-static void pni_unmap_local_channel(pn_session_t *ssn) {
-  // XXX: should really update link state also
-  pni_delivery_map_clear(&ssn->state.outgoing);
-  pni_transport_unbind_handles(ssn->state.local_handles, false);
-  pn_transport_t *transport = ssn->connection->transport;
-  pn_session_state_t *state = &ssn->state;
-  uintptr_t channel = state->local_channel;
-  state->local_channel = -2;
-  if (pn_hash_get(transport->local_channels, channel)) {
-    pn_ep_decref(&ssn->endpoint);
-  }
-  // may delete session
-  pn_hash_del(transport->local_channels, channel);
-}
-
-static int pni_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == SESSION)
-  {
-    pn_session_t *session = (pn_session_t *) endpoint;
-    pn_session_state_t *state = &session->state;
-    if (endpoint->state & PN_LOCAL_CLOSED && (int16_t) state->local_channel >= 0
-        && !transport->close_sent)
-    {
-      if (pni_pointful_buffering(transport, session)) {
-        return 0;
-      }
-
-      const char *name = NULL;
-      const char *description = NULL;
-      pn_data_t *info = NULL;
-
-      if (pn_condition_is_set(&endpoint->condition)) {
-        name = pn_condition_get_name(&endpoint->condition);
-        description = pn_condition_get_description(&endpoint->condition);
-        info = pn_condition_info(&endpoint->condition);
-      }
-
-      int err = pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?DL[sSC]]", END,
-                              (bool) name, ERROR, name, description, info);
-      if (err) return err;
-      pni_unmap_local_channel(session);
-    }
-
-    pn_clear_modified(transport->connection, endpoint);
-  }
-  return 0;
-}
-
-static int pni_process_conn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
-{
-  if (endpoint->type == CONNECTION)
-  {
-    if (endpoint->state & PN_LOCAL_CLOSED && !transport->close_sent) {
-      if (pni_pointful_buffering(transport, NULL)) return 0;
-      int err = pni_post_close(transport, NULL);
-      if (err) return err;
-      transport->close_sent = true;
-    }
-
-    pn_clear_modified(transport->connection, endpoint);
-  }
-  return 0;
-}
-
-static int pni_phase(pn_transport_t *transport, int (*phase)(pn_transport_t *, pn_endpoint_t *))
-{
-  pn_connection_t *conn = transport->connection;
-  pn_endpoint_t *endpoint = conn->transport_head;
-  while (endpoint)
-  {
-    pn_endpoint_t *next = endpoint->transport_next;
-    int err = phase(transport, endpoint);
-    if (err) return err;
-    endpoint = next;
-  }
-  return 0;
-}
-
-static int pni_process(pn_transport_t *transport)
-{
-  int err;
-  if ((err = pni_phase(transport, pni_process_conn_setup))) return err;
-  if ((err = pni_phase(transport, pni_process_ssn_setup))) return err;
-  if ((err = pni_phase(transport, pni_process_link_setup))) return err;
-  if ((err = pni_phase(transport, pni_process_flow_receiver))) return err;
-
-  // XXX: this has to happen two times because we might settle stuff
-  // on the first pass and create space for more work to be done on the
-  // second pass
-  if ((err = pni_phase(transport, pni_process_tpwork))) return err;
-  if ((err = pni_phase(transport, pni_process_tpwork))) return err;
-
-  if ((err = pni_phase(transport, pni_process_flush_disp))) return err;
-
-  if ((err = pni_phase(transport, pni_process_flow_sender))) return err;
-  if ((err = pni_phase(transport, pni_process_link_teardown))) return err;
-  if ((err = pni_phase(transport, pni_process_ssn_teardown))) return err;
-  if ((err = pni_phase(transport, pni_process_conn_teardown))) return err;
-
-  if (transport->connection->tpwork_head) {
-    pn_modified(transport->connection, &transport->connection->endpoint, false);
-  }
-
-  return 0;
-}
-
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
-
-static void pn_error_amqp(pn_transport_t* transport, unsigned int layer)
-{
-  if (!transport->close_sent) {
-    if (!transport->open_sent) {
-      pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[S]", OPEN, "");
-    }
-
-    pni_post_close(transport, &transport->condition);
-    transport->close_sent = true;
-  }
-  transport->halt = true;
-  transport->done_processing = true;
-}
-
-static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
-{
-  bool eos = pn_transport_capacity(transport)==PN_EOS;
-  pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
-  switch (protocol) {
-  case PNI_PROTOCOL_AMQP1:
-    if (transport->io_layers[layer] == &amqp_read_header_layer) {
-      transport->io_layers[layer] = &amqp_layer;
-    } else {
-      transport->io_layers[layer] = &amqp_write_header_layer;
-    }
-    if (transport->trace & PN_TRACE_FRM)
-      pn_transport_logf(transport, "  <- %s", "AMQP");
-    return 8;
-  case PNI_PROTOCOL_INSUFFICIENT:
-    if (!eos) return 0;
-    /* Fallthru */
-  default:
-    break;
-  }
-  char quoted[1024];
-  pn_quote_data(quoted, 1024, bytes, available);
-  pn_do_error(transport, "amqp:connection:framing-error",
-              "%s header mismatch: %s ['%s']%s", "AMQP", pni_protocol_name(protocol), quoted,
-              !eos ? "" : " (connection aborted)");
-  return PN_EOS;
-}
-
-static ssize_t pn_input_read_amqp(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
-{
-  if (transport->close_rcvd) {
-    if (available > 0) {
-      pn_do_error(transport, "amqp:connection:framing-error", "data after close");
-      return PN_EOS;
-    }
-  }
-
-  if (!transport->close_rcvd && !available) {
-    pn_do_error(transport, "amqp:connection:framing-error", "connection aborted");
-    return PN_EOS;
-  }
-
-
-  ssize_t n = pn_dispatcher_input(transport, bytes, available, true, &transport->halt);
-  if (n < 0) {
-    //return pn_error_set(transport->error, n, "dispatch error");
-    return PN_EOS;
-  } else if (transport->close_rcvd) {
-    return PN_EOS;
-  } else {
-    return n;
-  }
-}
-
-/* process AMQP related timer events */
-static pn_timestamp_t pn_tick_amqp(pn_transport_t* transport, unsigned int layer, pn_timestamp_t now)
-{
-  pn_timestamp_t timeout = 0;
-
-  if (transport->local_idle_timeout) {
-    if (transport->dead_remote_deadline == 0 ||
-        transport->last_bytes_input != transport->bytes_input) {
-      transport->dead_remote_deadlin

<TRUNCATED>

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


[13/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/message.c b/proton-c/src/core/message.c
new file mode 100644
index 0000000..f2fb20e
--- /dev/null
+++ b/proton-c/src/core/message.c
@@ -0,0 +1,862 @@
+/*
+ *
+ * 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 "platform/platform_fmt.h"
+#include "protocol.h"
+#include "util.h"
+
+#include <proton/message.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include <proton/error.h>
+#include <proton/parser.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+// message
+
+struct pn_message_t {
+  pn_timestamp_t expiry_time;
+  pn_timestamp_t creation_time;
+  pn_data_t *id;
+  pn_string_t *user_id;
+  pn_string_t *address;
+  pn_string_t *subject;
+  pn_string_t *reply_to;
+  pn_data_t *correlation_id;
+  pn_string_t *content_type;
+  pn_string_t *content_encoding;
+  pn_string_t *group_id;
+  pn_string_t *reply_to_group_id;
+
+  pn_data_t *data;
+  pn_data_t *instructions;
+  pn_data_t *annotations;
+  pn_data_t *properties;
+  pn_data_t *body;
+
+  pn_error_t *error;
+
+  pn_sequence_t group_sequence;
+  pn_millis_t ttl;
+  uint32_t delivery_count;
+
+  uint8_t priority;
+
+  bool durable;
+  bool first_acquirer;
+  bool inferred;
+};
+
+void pn_message_finalize(void *obj)
+{
+  pn_message_t *msg = (pn_message_t *) obj;
+  pn_free(msg->user_id);
+  pn_free(msg->address);
+  pn_free(msg->subject);
+  pn_free(msg->reply_to);
+  pn_free(msg->content_type);
+  pn_free(msg->content_encoding);
+  pn_free(msg->group_id);
+  pn_free(msg->reply_to_group_id);
+  pn_data_free(msg->id);
+  pn_data_free(msg->correlation_id);
+  pn_data_free(msg->data);
+  pn_data_free(msg->instructions);
+  pn_data_free(msg->annotations);
+  pn_data_free(msg->properties);
+  pn_data_free(msg->body);
+  pn_error_free(msg->error);
+}
+
+int pn_message_inspect(void *obj, pn_string_t *dst)
+{
+  pn_message_t *msg = (pn_message_t *) obj;
+  int err = pn_string_addf(dst, "Message{");
+  if (err) return err;
+
+  bool comma = false;
+
+  if (pn_string_get(msg->address)) {
+    err = pn_string_addf(dst, "address=");
+    if (err) return err;
+    err = pn_inspect(msg->address, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->durable) {
+    err = pn_string_addf(dst, "durable=%i, ", msg->durable);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->priority != PN_DEFAULT_PRIORITY) {
+    err = pn_string_addf(dst, "priority=%i, ", msg->priority);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->ttl) {
+    err = pn_string_addf(dst, "ttl=%" PRIu32 ", ", msg->ttl);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->first_acquirer) {
+    err = pn_string_addf(dst, "first_acquirer=%i, ", msg->first_acquirer);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->delivery_count) {
+    err = pn_string_addf(dst, "delivery_count=%" PRIu32 ", ", msg->delivery_count);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->id)) {
+    err = pn_string_addf(dst, "id=");
+    if (err) return err;
+    err = pn_inspect(msg->id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->user_id)) {
+    err = pn_string_addf(dst, "user_id=");
+    if (err) return err;
+    err = pn_inspect(msg->user_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->subject)) {
+    err = pn_string_addf(dst, "subject=");
+    if (err) return err;
+    err = pn_inspect(msg->subject, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->reply_to)) {
+    err = pn_string_addf(dst, "reply_to=");
+    if (err) return err;
+    err = pn_inspect(msg->reply_to, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->correlation_id)) {
+    err = pn_string_addf(dst, "correlation_id=");
+    if (err) return err;
+    err = pn_inspect(msg->correlation_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->content_type)) {
+    err = pn_string_addf(dst, "content_type=");
+    if (err) return err;
+    err = pn_inspect(msg->content_type, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->content_encoding)) {
+    err = pn_string_addf(dst, "content_encoding=");
+    if (err) return err;
+    err = pn_inspect(msg->content_encoding, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->expiry_time) {
+    err = pn_string_addf(dst, "expiry_time=%" PRIi64 ", ", msg->expiry_time);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->creation_time) {
+    err = pn_string_addf(dst, "creation_time=%" PRIi64 ", ", msg->creation_time);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->group_id)) {
+    err = pn_string_addf(dst, "group_id=");
+    if (err) return err;
+    err = pn_inspect(msg->group_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->group_sequence) {
+    err = pn_string_addf(dst, "group_sequence=%" PRIi32 ", ", msg->group_sequence);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->reply_to_group_id)) {
+    err = pn_string_addf(dst, "reply_to_group_id=");
+    if (err) return err;
+    err = pn_inspect(msg->reply_to_group_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->inferred) {
+    err = pn_string_addf(dst, "inferred=%i, ", msg->inferred);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->instructions)) {
+    err = pn_string_addf(dst, "instructions=");
+    if (err) return err;
+    err = pn_inspect(msg->instructions, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->annotations)) {
+    err = pn_string_addf(dst, "annotations=");
+    if (err) return err;
+    err = pn_inspect(msg->annotations, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->properties)) {
+    err = pn_string_addf(dst, "properties=");
+    if (err) return err;
+    err = pn_inspect(msg->properties, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->body)) {
+    err = pn_string_addf(dst, "body=");
+    if (err) return err;
+    err = pn_inspect(msg->body, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (comma) {
+    int err = pn_string_resize(dst, pn_string_size(dst) - 2);
+    if (err) return err;
+  }
+
+  return pn_string_addf(dst, "}");
+}
+
+#define pn_message_initialize NULL
+#define pn_message_hashcode NULL
+#define pn_message_compare NULL
+
+pn_message_t *pn_message()
+{
+  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));
+  msg->durable = false;
+  msg->priority = PN_DEFAULT_PRIORITY;
+  msg->ttl = 0;
+  msg->first_acquirer = false;
+  msg->delivery_count = 0;
+  msg->id = pn_data(1);
+  msg->user_id = pn_string(NULL);
+  msg->address = pn_string(NULL);
+  msg->subject = pn_string(NULL);
+  msg->reply_to = pn_string(NULL);
+  msg->correlation_id = pn_data(1);
+  msg->content_type = pn_string(NULL);
+  msg->content_encoding = pn_string(NULL);
+  msg->expiry_time = 0;
+  msg->creation_time = 0;
+  msg->group_id = pn_string(NULL);
+  msg->group_sequence = 0;
+  msg->reply_to_group_id = pn_string(NULL);
+
+  msg->inferred = false;
+  msg->data = pn_data(16);
+  msg->instructions = pn_data(16);
+  msg->annotations = pn_data(16);
+  msg->properties = pn_data(16);
+  msg->body = pn_data(16);
+
+  msg->error = pn_error();
+  return msg;
+}
+
+void pn_message_free(pn_message_t *msg)
+{
+  pn_free(msg);
+}
+
+void pn_message_clear(pn_message_t *msg)
+{
+  msg->durable = false;
+  msg->priority = PN_DEFAULT_PRIORITY;
+  msg->ttl = 0;
+  msg->first_acquirer = false;
+  msg->delivery_count = 0;
+  pn_data_clear(msg->id);
+  pn_string_clear(msg->user_id);
+  pn_string_clear(msg->address);
+  pn_string_clear(msg->subject);
+  pn_string_clear(msg->reply_to);
+  pn_data_clear(msg->correlation_id);
+  pn_string_clear(msg->content_type);
+  pn_string_clear(msg->content_encoding);
+  msg->expiry_time = 0;
+  msg->creation_time = 0;
+  pn_string_clear(msg->group_id);
+  msg->group_sequence = 0;
+  pn_string_clear(msg->reply_to_group_id);
+  msg->inferred = false;
+  pn_data_clear(msg->data);
+  pn_data_clear(msg->instructions);
+  pn_data_clear(msg->annotations);
+  pn_data_clear(msg->properties);
+  pn_data_clear(msg->body);
+}
+
+int pn_message_errno(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_error_code(msg->error);
+}
+
+pn_error_t *pn_message_error(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->error;
+}
+
+bool pn_message_is_inferred(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->inferred;
+}
+
+int pn_message_set_inferred(pn_message_t *msg, bool inferred)
+{
+  assert(msg);
+  msg->inferred = inferred;
+  return 0;
+}
+
+bool pn_message_is_durable(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->durable;
+}
+int pn_message_set_durable(pn_message_t *msg, bool durable)
+{
+  assert(msg);
+  msg->durable = durable;
+  return 0;
+}
+
+
+uint8_t pn_message_get_priority(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->priority;
+}
+int pn_message_set_priority(pn_message_t *msg, uint8_t priority)
+{
+  assert(msg);
+  msg->priority = priority;
+  return 0;
+}
+
+pn_millis_t pn_message_get_ttl(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->ttl;
+}
+int pn_message_set_ttl(pn_message_t *msg, pn_millis_t ttl)
+{
+  assert(msg);
+  msg->ttl = ttl;
+  return 0;
+}
+
+bool pn_message_is_first_acquirer(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->first_acquirer;
+}
+int pn_message_set_first_acquirer(pn_message_t *msg, bool first)
+{
+  assert(msg);
+  msg->first_acquirer = first;
+  return 0;
+}
+
+uint32_t pn_message_get_delivery_count(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->delivery_count;
+}
+int pn_message_set_delivery_count(pn_message_t *msg, uint32_t count)
+{
+  assert(msg);
+  msg->delivery_count = count;
+  return 0;
+}
+
+pn_data_t *pn_message_id(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->id;
+}
+pn_atom_t pn_message_get_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_data_get_atom(msg->id);
+}
+int pn_message_set_id(pn_message_t *msg, pn_atom_t id)
+{
+  assert(msg);
+  pn_data_rewind(msg->id);
+  return pn_data_put_atom(msg->id, id);
+}
+
+static pn_bytes_t pn_string_get_bytes(pn_string_t *string)
+{
+  return pn_bytes(pn_string_size(string), (char *) pn_string_get(string));
+}
+
+static int pn_string_set_bytes(pn_string_t *string, pn_bytes_t bytes)
+{
+  return pn_string_setn(string, bytes.start, bytes.size);
+}
+
+pn_bytes_t pn_message_get_user_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get_bytes(msg->user_id);
+}
+int pn_message_set_user_id(pn_message_t *msg, pn_bytes_t user_id)
+{
+  assert(msg);
+  return pn_string_set_bytes(msg->user_id, user_id);
+}
+
+const char *pn_message_get_address(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->address);
+}
+int pn_message_set_address(pn_message_t *msg, const char *address)
+{
+  assert(msg);
+  return pn_string_set(msg->address, address);
+}
+
+const char *pn_message_get_subject(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->subject);
+}
+int pn_message_set_subject(pn_message_t *msg, const char *subject)
+{
+  assert(msg);
+  return pn_string_set(msg->subject, subject);
+}
+
+const char *pn_message_get_reply_to(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->reply_to);
+}
+int pn_message_set_reply_to(pn_message_t *msg, const char *reply_to)
+{
+  assert(msg);
+  return pn_string_set(msg->reply_to, reply_to);
+}
+
+pn_data_t *pn_message_correlation_id(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->correlation_id;
+}
+pn_atom_t pn_message_get_correlation_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_data_get_atom(msg->correlation_id);
+}
+int pn_message_set_correlation_id(pn_message_t *msg, pn_atom_t atom)
+{
+  assert(msg);
+  pn_data_rewind(msg->correlation_id);
+  return pn_data_put_atom(msg->correlation_id, atom);
+}
+
+const char *pn_message_get_content_type(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->content_type);
+}
+int pn_message_set_content_type(pn_message_t *msg, const char *type)
+{
+  assert(msg);
+  return pn_string_set(msg->content_type, type);
+}
+
+const char *pn_message_get_content_encoding(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->content_encoding);
+}
+int pn_message_set_content_encoding(pn_message_t *msg, const char *encoding)
+{
+  assert(msg);
+  return pn_string_set(msg->content_encoding, encoding);
+}
+
+pn_timestamp_t pn_message_get_expiry_time(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->expiry_time;
+}
+int pn_message_set_expiry_time(pn_message_t *msg, pn_timestamp_t time)
+{
+  assert(msg);
+  msg->expiry_time = time;
+  return 0;
+}
+
+pn_timestamp_t pn_message_get_creation_time(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->creation_time;
+}
+int pn_message_set_creation_time(pn_message_t *msg, pn_timestamp_t time)
+{
+  assert(msg);
+  msg->creation_time = time;
+  return 0;
+}
+
+const char *pn_message_get_group_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->group_id);
+}
+int pn_message_set_group_id(pn_message_t *msg, const char *group_id)
+{
+  assert(msg);
+  return pn_string_set(msg->group_id, group_id);
+}
+
+pn_sequence_t pn_message_get_group_sequence(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->group_sequence;
+}
+int pn_message_set_group_sequence(pn_message_t *msg, pn_sequence_t n)
+{
+  assert(msg);
+  msg->group_sequence = n;
+  return 0;
+}
+
+const char *pn_message_get_reply_to_group_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->reply_to_group_id);
+}
+int pn_message_set_reply_to_group_id(pn_message_t *msg, const char *reply_to_group_id)
+{
+  assert(msg);
+  return pn_string_set(msg->reply_to_group_id, reply_to_group_id);
+}
+
+int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size)
+{
+  assert(msg && bytes && size);
+
+  pn_message_clear(msg);
+
+  while (size) {
+    pn_data_clear(msg->data);
+    ssize_t used = pn_data_decode(msg->data, bytes, size);
+    if (used < 0)
+        return pn_error_format(msg->error, used, "data error: %s",
+                               pn_error_text(pn_data_error(msg->data)));
+    size -= used;
+    bytes += used;
+    bool scanned;
+    uint64_t desc;
+    int err = pn_data_scan(msg->data, "D?L.", &scanned, &desc);
+    if (err) return pn_error_format(msg->error, err, "data error: %s",
+                                    pn_error_text(pn_data_error(msg->data)));
+    if (!scanned) {
+      desc = 0;
+    }
+
+    pn_data_rewind(msg->data);
+    pn_data_next(msg->data);
+    pn_data_enter(msg->data);
+    pn_data_next(msg->data);
+
+    switch (desc) {
+    case HEADER:
+      err = pn_data_scan(msg->data, "D.[oBIoI]", &msg->durable, &msg->priority,
+                   &msg->ttl, &msg->first_acquirer, &msg->delivery_count);
+      if (err) return pn_error_format(msg->error, err, "data error: %s",
+                                      pn_error_text(pn_data_error(msg->data)));
+      break;
+    case PROPERTIES:
+      {
+        pn_bytes_t user_id, address, subject, reply_to, ctype, cencoding,
+          group_id, reply_to_group_id;
+        pn_data_clear(msg->id);
+        pn_data_clear(msg->correlation_id);
+        err = pn_data_scan(msg->data, "D.[CzSSSCssttSIS]", msg->id,
+                           &user_id, &address, &subject, &reply_to,
+                           msg->correlation_id, &ctype, &cencoding,
+                           &msg->expiry_time, &msg->creation_time, &group_id,
+                           &msg->group_sequence, &reply_to_group_id);
+        if (err) return pn_error_format(msg->error, err, "data error: %s",
+                                        pn_error_text(pn_data_error(msg->data)));
+        err = pn_string_set_bytes(msg->user_id, user_id);
+        if (err) return pn_error_format(msg->error, err, "error setting user_id");
+        err = pn_string_setn(msg->address, address.start, address.size);
+        if (err) return pn_error_format(msg->error, err, "error setting address");
+        err = pn_string_setn(msg->subject, subject.start, subject.size);
+        if (err) return pn_error_format(msg->error, err, "error setting subject");
+        err = pn_string_setn(msg->reply_to, reply_to.start, reply_to.size);
+        if (err) return pn_error_format(msg->error, err, "error setting reply_to");
+        err = pn_string_setn(msg->content_type, ctype.start, ctype.size);
+        if (err) return pn_error_format(msg->error, err, "error setting content_type");
+        err = pn_string_setn(msg->content_encoding, cencoding.start,
+                             cencoding.size);
+        if (err) return pn_error_format(msg->error, err, "error setting content_encoding");
+        err = pn_string_setn(msg->group_id, group_id.start, group_id.size);
+        if (err) return pn_error_format(msg->error, err, "error setting group_id");
+        err = pn_string_setn(msg->reply_to_group_id, reply_to_group_id.start,
+                             reply_to_group_id.size);
+        if (err) return pn_error_format(msg->error, err, "error setting reply_to_group_id");
+      }
+      break;
+    case DELIVERY_ANNOTATIONS:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->instructions, msg->data);
+      if (err) return err;
+      break;
+    case MESSAGE_ANNOTATIONS:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->annotations, msg->data);
+      if (err) return err;
+      break;
+    case APPLICATION_PROPERTIES:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->properties, msg->data);
+      if (err) return err;
+      break;
+    case DATA:
+    case AMQP_SEQUENCE:
+    case AMQP_VALUE:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->body, msg->data);
+      if (err) return err;
+      break;
+    case FOOTER:
+      break;
+    default:
+      err = pn_data_copy(msg->body, msg->data);
+      if (err) return err;
+      break;
+    }
+  }
+
+  pn_data_clear(msg->data);
+  return 0;
+}
+
+int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size)
+{
+  if (!msg || !bytes || !size || !*size) return PN_ARG_ERR;
+  pn_data_clear(msg->data);
+  pn_message_data(msg, msg->data);
+  size_t remaining = *size;
+  ssize_t encoded = pn_data_encode(msg->data, bytes, remaining);
+  if (encoded < 0) {
+    if (encoded == PN_OVERFLOW) {
+      return encoded;
+    } else {
+      return pn_error_format(msg->error, encoded, "data error: %s",
+                             pn_error_text(pn_data_error(msg->data)));
+    }
+  }
+  bytes += encoded;
+  remaining -= encoded;
+  *size -= remaining;
+  pn_data_clear(msg->data);
+  return 0;
+}
+
+int pn_message_data(pn_message_t *msg, pn_data_t *data)
+{
+  pn_data_clear(data);
+  int err = pn_data_fill(data, "DL[oB?IoI]", HEADER, msg->durable,
+                         msg->priority, msg->ttl, msg->ttl, msg->first_acquirer,
+                         msg->delivery_count);
+  if (err)
+    return pn_error_format(msg->error, err, "data error: %s",
+                           pn_error_text(pn_data_error(data)));
+
+  if (pn_data_size(msg->instructions)) {
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    pn_data_put_ulong(data, DELIVERY_ANNOTATIONS);
+    pn_data_rewind(msg->instructions);
+    err = pn_data_append(data, msg->instructions);
+    if (err)
+      return pn_error_format(msg->error, err, "data error: %s",
+                             pn_error_text(pn_data_error(data)));
+    pn_data_exit(data);
+  }
+
+  if (pn_data_size(msg->annotations)) {
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    pn_data_put_ulong(data, MESSAGE_ANNOTATIONS);
+    pn_data_rewind(msg->annotations);
+    err = pn_data_append(data, msg->annotations);
+    if (err)
+      return pn_error_format(msg->error, err, "data error: %s",
+                             pn_error_text(pn_data_error(data)));
+    pn_data_exit(data);
+  }
+
+  err = pn_data_fill(data, "DL[CzSSSCssttSIS]", PROPERTIES,
+                     msg->id,
+                     pn_string_size(msg->user_id), pn_string_get(msg->user_id),
+                     pn_string_get(msg->address),
+                     pn_string_get(msg->subject),
+                     pn_string_get(msg->reply_to),
+                     msg->correlation_id,
+                     pn_string_get(msg->content_type),
+                     pn_string_get(msg->content_encoding),
+                     msg->expiry_time,
+                     msg->creation_time,
+                     pn_string_get(msg->group_id),
+                     msg->group_sequence,
+                     pn_string_get(msg->reply_to_group_id));
+  if (err)
+    return pn_error_format(msg->error, err, "data error: %s",
+                           pn_error_text(pn_data_error(data)));
+
+  if (pn_data_size(msg->properties)) {
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    pn_data_put_ulong(data, APPLICATION_PROPERTIES);
+    pn_data_rewind(msg->properties);
+    err = pn_data_append(data, msg->properties);
+    if (err)
+      return pn_error_format(msg->error, err, "data error: %s",
+                             pn_data_error(data));
+    pn_data_exit(data);
+  }
+
+  if (pn_data_size(msg->body)) {
+    pn_data_rewind(msg->body);
+    pn_data_next(msg->body);
+    pn_type_t body_type = pn_data_type(msg->body);
+    pn_data_rewind(msg->body);
+
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    if (msg->inferred) {
+      switch (body_type) {
+      case PN_BINARY:
+        pn_data_put_ulong(data, DATA);
+        break;
+      case PN_LIST:
+        pn_data_put_ulong(data, AMQP_SEQUENCE);
+        break;
+      default:
+        pn_data_put_ulong(data, AMQP_VALUE);
+        break;
+      }
+    } else {
+      pn_data_put_ulong(data, AMQP_VALUE);
+    }
+    pn_data_append(data, msg->body);
+  }
+  return 0;
+}
+
+pn_data_t *pn_message_instructions(pn_message_t *msg)
+{
+  return msg ? msg->instructions : NULL;
+}
+
+pn_data_t *pn_message_annotations(pn_message_t *msg)
+{
+  return msg ? msg->annotations : NULL;
+}
+
+pn_data_t *pn_message_properties(pn_message_t *msg)
+{
+  return msg ? msg->properties : NULL;
+}
+
+pn_data_t *pn_message_body(pn_message_t *msg)
+{
+  return msg ? msg->body : NULL;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/iterator.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/iterator.c b/proton-c/src/core/object/iterator.c
new file mode 100644
index 0000000..61b3b8e
--- /dev/null
+++ b/proton-c/src/core/object/iterator.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_iterator_t {
+  pn_iterator_next_t next;
+  size_t size;
+  void *state;
+};
+
+static void pn_iterator_initialize(void *object)
+{
+  pn_iterator_t *it = (pn_iterator_t *) object;
+  it->next = NULL;
+  it->size = 0;
+  it->state = NULL;
+}
+
+static void pn_iterator_finalize(void *object)
+{
+  pn_iterator_t *it = (pn_iterator_t *) object;
+  free(it->state);
+}
+
+#define CID_pn_iterator CID_pn_object
+#define pn_iterator_hashcode NULL
+#define pn_iterator_compare NULL
+#define pn_iterator_inspect NULL
+
+pn_iterator_t *pn_iterator()
+{
+  static const pn_class_t clazz = PN_CLASS(pn_iterator);
+  pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t));
+  return it;
+}
+
+void  *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
+                         size_t size) {
+  assert(iterator);
+  assert(next);
+  iterator->next = next;
+  if (iterator->size < size) {
+    iterator->state = realloc(iterator->state, size);
+  }
+  return iterator->state;
+}
+
+void *pn_iterator_next(pn_iterator_t *iterator) {
+  assert(iterator);
+  if (iterator->next) {
+    void *result = iterator->next(iterator->state);
+    if (!result) iterator->next = NULL;
+    return result;
+  } else {
+    return NULL;
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/list.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/list.c b/proton-c/src/core/object/list.c
new file mode 100644
index 0000000..76c70d2
--- /dev/null
+++ b/proton-c/src/core/object/list.c
@@ -0,0 +1,267 @@
+/*
+ *
+ * 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/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_list_t {
+  const pn_class_t *clazz;
+  size_t capacity;
+  size_t size;
+  void **elements;
+};
+
+size_t pn_list_size(pn_list_t *list)
+{
+  assert(list);
+  return list->size;
+}
+
+void *pn_list_get(pn_list_t *list, int index)
+{
+  assert(list); assert(list->size);
+  return list->elements[index % list->size];
+}
+
+void pn_list_set(pn_list_t *list, int index, void *value)
+{
+  assert(list); assert(list->size);
+  void *old = list->elements[index % list->size];
+  pn_class_decref(list->clazz, old);
+  list->elements[index % list->size] = value;
+  pn_class_incref(list->clazz, value);
+}
+
+static void pni_list_ensure(pn_list_t *list, size_t capacity)
+{
+  assert(list);
+  if (list->capacity < capacity) {
+    size_t newcap = list->capacity;
+    while (newcap < capacity) { newcap *= 2; }
+    list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
+    assert(list->elements);
+    list->capacity = newcap;
+  }
+}
+
+int pn_list_add(pn_list_t *list, void *value)
+{
+  assert(list);
+  pni_list_ensure(list, list->size + 1);
+  list->elements[list->size++] = value;
+  pn_class_incref(list->clazz, value);
+  return 0;
+}
+
+void *pn_list_pop(pn_list_t *list)
+{
+  assert(list);
+  if (list->size) {
+    return list->elements[--list->size];
+  } else {
+    return NULL;
+  }
+}
+
+ssize_t pn_list_index(pn_list_t *list, void *value)
+{
+  for (size_t i = 0; i < list->size; i++) {
+    if (pn_class_equals(list->clazz, list->elements[i], value)) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+bool pn_list_remove(pn_list_t *list, void *value)
+{
+  assert(list);
+  ssize_t idx = pn_list_index(list, value);
+  if (idx < 0) {
+    return false;
+  } else {
+    pn_list_del(list, idx, 1);
+  }
+
+  return true;
+}
+
+void pn_list_del(pn_list_t *list, int index, int n)
+{
+  assert(list);
+  if (!list->size) { return; }
+  index %= list->size;
+
+  for (int i = 0; i < n; i++) {
+    pn_class_decref(list->clazz, list->elements[index + i]);
+  }
+
+  size_t slide = list->size - (index + n);
+  for (size_t i = 0; i < slide; i++) {
+    list->elements[index + i] = list->elements[index + n + i];
+  }
+
+  list->size -= n;
+}
+
+void pn_list_clear(pn_list_t *list)
+{
+  assert(list);
+  pn_list_del(list, 0, list->size);
+}
+
+void pn_list_minpush(pn_list_t *list, void *value)
+{
+  assert(list);
+  pn_list_add(list, value);
+  // we use one based indexing for the heap
+  void **heap = list->elements - 1;
+  int now = list->size;
+  while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) {
+    heap[now] = heap[now/2];
+    now /= 2;
+  }
+  heap[now] = value;
+}
+
+void *pn_list_minpop(pn_list_t *list)
+{
+  assert(list);
+  // we use one based indexing for the heap
+  void **heap = list->elements - 1;
+  void *min = heap[1];
+  void *last = pn_list_pop(list);
+  int size = pn_list_size(list);
+  int now, child;
+  for (now = 1; now*2 <= size; now = child) {
+    child = now*2;
+    if (child != size && pn_class_compare(list->clazz, heap[child], heap[child + 1]) > 0) {
+      child++;
+    }
+    if (pn_class_compare(list->clazz, last, heap[child]) > 0) {
+      heap[now] = heap[child];
+    } else {
+      break;
+    }
+  }
+  heap[now] = last;
+  return min;
+}
+
+typedef struct {
+  pn_list_t *list;
+  size_t index;
+} pni_list_iter_t;
+
+static void *pni_list_next(void *ctx)
+{
+  pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
+  if (iter->index < pn_list_size(iter->list)) {
+    return pn_list_get(iter->list, iter->index++);
+  } else {
+    return NULL;
+  }
+}
+
+void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
+{
+  pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
+  liter->list = list;
+  liter->index = 0;
+}
+
+static void pn_list_finalize(void *object)
+{
+  assert(object);
+  pn_list_t *list = (pn_list_t *) object;
+  for (size_t i = 0; i < list->size; i++) {
+    pn_class_decref(list->clazz, pn_list_get(list, i));
+  }
+  free(list->elements);
+}
+
+static uintptr_t pn_list_hashcode(void *object)
+{
+  assert(object);
+  pn_list_t *list = (pn_list_t *) object;
+  uintptr_t hash = 1;
+
+  for (size_t i = 0; i < list->size; i++) {
+    hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
+  }
+
+  return hash;
+}
+
+static intptr_t pn_list_compare(void *oa, void *ob)
+{
+  assert(oa); assert(ob);
+  pn_list_t *a = (pn_list_t *) oa;
+  pn_list_t *b = (pn_list_t *) ob;
+
+  size_t na = pn_list_size(a);
+  size_t nb = pn_list_size(b);
+  if (na != nb) {
+    return nb - na;
+  } else {
+    for (size_t i = 0; i < na; i++) {
+      intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
+      if (delta) return delta;
+    }
+  }
+
+  return 0;
+}
+
+static int pn_list_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_list_t *list = (pn_list_t *) obj;
+  int err = pn_string_addf(dst, "[");
+  if (err) return err;
+  size_t n = pn_list_size(list);
+  for (size_t i = 0; i < n; i++) {
+    if (i > 0) {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst);
+    if (err) return err;
+  }
+  return pn_string_addf(dst, "]");
+}
+
+#define pn_list_initialize NULL
+
+pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
+{
+  static const pn_class_t list_clazz = PN_CLASS(pn_list);
+
+  pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
+  list->clazz = clazz;
+  list->capacity = capacity ? capacity : 16;
+  list->elements = (void **) malloc(list->capacity * sizeof(void *));
+  list->size = 0;
+  return list;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/map.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/map.c b/proton-c/src/core/object/map.c
new file mode 100644
index 0000000..cd38f19
--- /dev/null
+++ b/proton-c/src/core/object/map.c
@@ -0,0 +1,461 @@
+/*
+ *
+ * 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/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define PNI_ENTRY_FREE (0)
+#define PNI_ENTRY_LINK (1)
+#define PNI_ENTRY_TAIL (2)
+
+typedef struct {
+  void *key;
+  void *value;
+  size_t next;
+  uint8_t state;
+} pni_entry_t;
+
+struct pn_map_t {
+  const pn_class_t *key;
+  const pn_class_t *value;
+  pni_entry_t *entries;
+  size_t capacity;
+  size_t addressable;
+  size_t size;
+  uintptr_t (*hashcode)(void *key);
+  bool (*equals)(void *a, void *b);
+  float load_factor;
+};
+
+static void pn_map_finalize(void *object)
+{
+  pn_map_t *map = (pn_map_t *) object;
+
+  for (size_t i = 0; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      pn_class_decref(map->key, map->entries[i].key);
+      pn_class_decref(map->value, map->entries[i].value);
+    }
+  }
+
+  free(map->entries);
+}
+
+static uintptr_t pn_map_hashcode(void *object)
+{
+  pn_map_t *map = (pn_map_t *) object;
+
+  uintptr_t hashcode = 0;
+
+  for (size_t i = 0; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      void *key = map->entries[i].key;
+      void *value = map->entries[i].value;
+      hashcode += pn_hashcode(key) ^ pn_hashcode(value);
+    }
+  }
+
+  return hashcode;
+}
+
+static void pni_map_allocate(pn_map_t *map)
+{
+  map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
+  if (map->entries != NULL) {
+    for (size_t i = 0; i < map->capacity; i++) {
+      map->entries[i].key = NULL;
+      map->entries[i].value = NULL;
+      map->entries[i].next = 0;
+      map->entries[i].state = PNI_ENTRY_FREE;
+    }
+  }
+  map->size = 0;
+}
+
+static int pn_map_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_map_t *map = (pn_map_t *) obj;
+  int err = pn_string_addf(dst, "{");
+  if (err) return err;
+  pn_handle_t entry = pn_map_head(map);
+  bool first = true;
+  while (entry) {
+    if (first) {
+      first = false;
+    } else {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_class_inspect(map->key, pn_map_key(map, entry), dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ": ");
+    if (err) return err;
+    err = pn_class_inspect(map->value, pn_map_value(map, entry), dst);
+    if (err) return err;
+    entry = pn_map_next(map, entry);
+  }
+  return pn_string_addf(dst, "}");
+}
+
+#define pn_map_initialize NULL
+#define pn_map_compare NULL
+
+pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
+                 size_t capacity, float load_factor)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_map);
+
+  pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t));
+  map->key = key;
+  map->value = value;
+  map->capacity = capacity ? capacity : 16;
+  map->addressable = (size_t) (map->capacity * 0.86);
+  if (!map->addressable) map->addressable = map->capacity;
+  map->load_factor = load_factor;
+  map->hashcode = pn_hashcode;
+  map->equals = pn_equals;
+  pni_map_allocate(map);
+  return map;
+}
+
+size_t pn_map_size(pn_map_t *map)
+{
+  assert(map);
+  return map->size;
+}
+
+static float pni_map_load(pn_map_t *map)
+{
+  return ((float) map->size) / ((float) map->addressable);
+}
+
+static bool pni_map_ensure(pn_map_t *map, size_t capacity)
+{
+  float load = pni_map_load(map);
+  if (capacity <= map->capacity && load <= map->load_factor) {
+    return false;
+  }
+
+  size_t oldcap = map->capacity;
+
+  while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
+    map->capacity *= 2;
+    map->addressable = (size_t) (0.86 * map->capacity);
+  }
+
+  pni_entry_t *entries = map->entries;
+  pni_map_allocate(map);
+
+  for (size_t i = 0; i < oldcap; i++) {
+    if (entries[i].state != PNI_ENTRY_FREE) {
+      void *key = entries[i].key;
+      void *value = entries[i].value;
+      pn_map_put(map, key, value);
+    }
+  }
+
+  for (size_t i = 0; i < oldcap; i++) {
+    if (entries[i].state != PNI_ENTRY_FREE) {
+      void *key = entries[i].key;
+      void *value = entries[i].value;
+      pn_class_decref(map->key, key);
+      pn_class_decref(map->value, value);
+    }
+  }
+
+  free(entries);
+  return true;
+}
+
+static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
+{
+  uintptr_t hashcode = map->hashcode(key);
+
+  pni_entry_t *entry = &map->entries[hashcode % map->addressable];
+  pni_entry_t *prev = NULL;
+
+  if (entry->state == PNI_ENTRY_FREE) {
+    if (create) {
+      entry->state = PNI_ENTRY_TAIL;
+      entry->key = key;
+      pn_class_incref(map->key, key);
+      map->size++;
+      return entry;
+    } else {
+      return NULL;
+    }
+  }
+
+  while (true) {
+    if (map->equals(entry->key, key)) {
+      if (pprev) *pprev = prev;
+      return entry;
+    }
+
+    if (entry->state == PNI_ENTRY_TAIL) {
+      break;
+    } else {
+      prev = entry;
+      entry = &map->entries[entry->next];
+    }
+  }
+
+  if (create) {
+    if (pni_map_ensure(map, map->size + 1)) {
+      // if we had to grow the table we need to start over
+      return pni_map_entry(map, key, pprev, create);
+    }
+
+    size_t empty = 0;
+    for (size_t i = 0; i < map->capacity; i++) {
+      size_t idx = map->capacity - i - 1;
+      if (map->entries[idx].state == PNI_ENTRY_FREE) {
+        empty = idx;
+        break;
+      }
+    }
+    entry->next = empty;
+    entry->state = PNI_ENTRY_LINK;
+    map->entries[empty].state = PNI_ENTRY_TAIL;
+    map->entries[empty].key = key;
+    pn_class_incref(map->key, key);
+    if (pprev) *pprev = entry;
+    map->size++;
+    return &map->entries[empty];
+  } else {
+    return NULL;
+  }
+}
+
+int pn_map_put(pn_map_t *map, void *key, void *value)
+{
+  assert(map);
+  pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
+  void *dref_val = entry->value;
+  entry->value = value;
+  pn_class_incref(map->value, value);
+  pn_class_decref(map->value, dref_val);
+  return 0;
+}
+
+void *pn_map_get(pn_map_t *map, void *key)
+{
+  assert(map);
+  pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
+  return entry ? entry->value : NULL;
+}
+
+static void pni_map_rehash(pn_map_t *map, size_t index)
+{
+  //reinsert entries in chain starting at index
+  assert(map);
+  size_t i = index;
+  bool complete = false;
+  while (!complete) {
+    pni_entry_t *entry = &map->entries[i];
+    assert(entry);
+    assert(entry->state != PNI_ENTRY_FREE);
+    size_t current = i;
+    if (entry->state == PNI_ENTRY_TAIL) {
+      complete = true;
+    } else {
+      assert(entry->state == PNI_ENTRY_LINK);
+      i = entry->next;
+    }
+    uintptr_t hashcode = map->hashcode(entry->key);
+    pni_entry_t *reloc = &map->entries[hashcode % map->addressable];
+    if (reloc->state == PNI_ENTRY_FREE) {
+      //correct addressable slot is available, copy into that...
+      reloc->state = PNI_ENTRY_TAIL;
+      reloc->key = entry->key;
+      reloc->value = entry->value;
+      //...then free the current entry
+      entry->key = NULL;
+      entry->value = NULL;
+      entry->state = PNI_ENTRY_FREE;
+      entry->next = 0;
+    } else {
+      //iterate to end of chain...
+      while (reloc->state == PNI_ENTRY_LINK) {
+        reloc = &map->entries[reloc->next];
+      }
+      assert(reloc->state == PNI_ENTRY_TAIL);
+      //... and append current entry
+      reloc->state = PNI_ENTRY_LINK;
+      reloc->next = current;
+      entry->state = PNI_ENTRY_TAIL;
+      entry->next = 0;
+    }
+  }
+}
+
+void pn_map_del(pn_map_t *map, void *key)
+{
+  assert(map);
+  pni_entry_t *prev = NULL;
+  pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
+  if (entry) {
+    uint8_t orig_state = entry->state;
+    size_t orig_next = entry->next;
+
+    void *dref_key = entry->key;
+    void *dref_value = entry->value;
+    if (prev) {
+      prev->next = 0;
+      prev->state = PNI_ENTRY_TAIL;
+    }
+    entry->state = PNI_ENTRY_FREE;
+    entry->next = 0;
+    entry->key = NULL;
+    entry->value = NULL;
+    map->size--;
+
+    if (orig_state == PNI_ENTRY_LINK) {
+      pni_map_rehash(map, orig_next);
+    }
+
+    // do this last as it may trigger further deletions
+    pn_class_decref(map->key, dref_key);
+    pn_class_decref(map->value, dref_value);
+  }
+}
+
+pn_handle_t pn_map_head(pn_map_t *map)
+{
+  assert(map);
+  for (size_t i = 0; i < map->capacity; i++)
+  {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      return (pn_handle_t)(i + 1);
+    }
+  }
+
+  return 0;
+}
+
+pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
+{
+  for (size_t i = (size_t)entry; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      return (pn_handle_t)(i + 1);
+    }
+  }
+
+  return 0;
+}
+
+void *pn_map_key(pn_map_t *map, pn_handle_t entry)
+{
+  assert(map);
+  assert(entry);
+  return map->entries[(size_t)entry - 1].key;
+}
+
+void *pn_map_value(pn_map_t *map, pn_handle_t entry)
+{
+  assert(map);
+  assert(entry);
+  return map->entries[(size_t)entry - 1].value;
+}
+
+struct pn_hash_t {
+  pn_map_t map;
+};
+
+static uintptr_t pni_identity_hashcode(void *obj)
+{
+  return (uintptr_t ) obj;
+}
+
+static bool pni_identity_equals(void *a, void *b)
+{
+  return a == b;
+}
+
+#define CID_pni_uintptr CID_pn_void
+static const pn_class_t *pni_uintptr_reify(void *object);
+#define pni_uintptr_new NULL
+#define pni_uintptr_free NULL
+#define pni_uintptr_initialize NULL
+static void pni_uintptr_incref(void *object) {}
+static void pni_uintptr_decref(void *object) {}
+static int pni_uintptr_refcount(void *object) { return -1; }
+#define pni_uintptr_finalize NULL
+#define pni_uintptr_hashcode NULL
+#define pni_uintptr_compare NULL
+#define pni_uintptr_inspect NULL
+
+static const pn_class_t PN_UINTPTR[] = {PN_METACLASS(pni_uintptr)};
+
+static const pn_class_t *pni_uintptr_reify(void *object)
+{
+  return PN_UINTPTR;
+}
+
+pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor)
+{
+  pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor);
+  hash->map.hashcode = pni_identity_hashcode;
+  hash->map.equals = pni_identity_equals;
+  return hash;
+}
+
+size_t pn_hash_size(pn_hash_t *hash)
+{
+  return pn_map_size(&hash->map);
+}
+
+int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
+{
+  return pn_map_put(&hash->map, (void *) key, value);
+}
+
+void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
+{
+  return pn_map_get(&hash->map, (void *) key);
+}
+
+void pn_hash_del(pn_hash_t *hash, uintptr_t key)
+{
+  pn_map_del(&hash->map, (void *) key);
+}
+
+pn_handle_t pn_hash_head(pn_hash_t *hash)
+{
+  return pn_map_head(&hash->map);
+}
+
+pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
+{
+  return pn_map_next(&hash->map, entry);
+}
+
+uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
+{
+  return (uintptr_t) pn_map_key(&hash->map, entry);
+}
+
+void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
+{
+  return pn_map_value(&hash->map, entry);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/object.c b/proton-c/src/core/object/object.c
new file mode 100644
index 0000000..b0c1b33
--- /dev/null
+++ b/proton-c/src/core/object/object.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * 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/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define pn_object_initialize NULL
+#define pn_object_finalize NULL
+#define pn_object_inspect NULL
+uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
+
+const pn_class_t PN_OBJECT[] = {PN_CLASS(pn_object)};
+
+#define pn_void_initialize NULL
+static void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
+static void pn_void_incref(void *object) {}
+static void pn_void_decref(void *object) {}
+static int pn_void_refcount(void *object) { return -1; }
+#define pn_void_finalize NULL
+static void pn_void_free(void *object) { free(object); }
+static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; }
+uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
+int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); }
+
+const pn_class_t PN_VOID[] = {PN_METACLASS(pn_void)};
+
+const char *pn_class_name(const pn_class_t *clazz)
+{
+  return clazz->name;
+}
+
+pn_cid_t pn_class_id(const pn_class_t *clazz)
+{
+  return clazz->cid;
+}
+
+void *pn_class_new(const pn_class_t *clazz, size_t size)
+{
+  assert(clazz);
+  void *object = clazz->newinst(clazz, size);
+  if (clazz->initialize) {
+    clazz->initialize(object);
+  }
+  return object;
+}
+
+void *pn_class_incref(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  if (object) {
+    clazz = clazz->reify(object);
+    clazz->incref(object);
+  }
+  return object;
+}
+
+int pn_class_refcount(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  clazz = clazz->reify(object);
+  return clazz->refcount(object);
+}
+
+int pn_class_decref(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+
+  if (object) {
+    clazz = clazz->reify(object);
+    clazz->decref(object);
+    int rc = clazz->refcount(object);
+    if (rc == 0) {
+      if (clazz->finalize) {
+        clazz->finalize(object);
+        // check the refcount again in case the finalizer created a
+        // new reference
+        rc = clazz->refcount(object);
+      }
+      if (rc == 0) {
+        clazz->free(object);
+        return 0;
+      }
+    } else {
+      return rc;
+    }
+  }
+
+  return 0;
+}
+
+void pn_class_free(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  if (object) {
+    clazz = clazz->reify(object);
+    int rc = clazz->refcount(object);
+    assert(rc == 1 || rc == -1);
+    if (rc == 1) {
+      rc = pn_class_decref(clazz, object);
+      assert(rc == 0);
+    } else {
+      if (clazz->finalize) {
+        clazz->finalize(object);
+      }
+      clazz->free(object);
+    }
+  }
+}
+
+const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  return clazz->reify(object);
+}
+
+uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+
+  if (!object) return 0;
+
+  clazz = clazz->reify(object);
+
+  if (clazz->hashcode) {
+    return clazz->hashcode(object);
+  } else {
+    return (uintptr_t) object;
+  }
+}
+
+intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b)
+{
+  assert(clazz);
+
+  if (a == b) return 0;
+
+  clazz = clazz->reify(a);
+
+  if (a && b && clazz->compare) {
+    return clazz->compare(a, b);
+  } else {
+    return (intptr_t) a - (intptr_t) b;
+  }
+}
+
+bool pn_class_equals(const pn_class_t *clazz, void *a, void *b)
+{
+  return pn_class_compare(clazz, a, b) == 0;
+}
+
+int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst)
+{
+  assert(clazz);
+
+  clazz = clazz->reify(object);
+
+  if (!pn_string_get(dst)) {
+    pn_string_set(dst, "");
+  }
+
+  if (object && clazz->inspect) {
+    return clazz->inspect(object, dst);
+  }
+
+  const char *name = clazz->name ? clazz->name : "<anon>";
+
+  return pn_string_addf(dst, "%s<%p>", name, object);
+}
+
+typedef struct {
+  const pn_class_t *clazz;
+  int refcount;
+} pni_head_t;
+
+#define pni_head(PTR) \
+  (((pni_head_t *) (PTR)) - 1)
+
+void *pn_object_new(const pn_class_t *clazz, size_t size)
+{
+  void *object = NULL;
+  pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
+  if (head != NULL) {
+    object = head + 1;
+    head->clazz = clazz;
+    head->refcount = 1;
+  }
+  return object;
+}
+
+const pn_class_t *pn_object_reify(void *object)
+{
+  if (object) {
+    return pni_head(object)->clazz;
+  } else {
+    return PN_OBJECT;
+  }
+}
+
+void pn_object_incref(void *object)
+{
+  if (object) {
+    pni_head(object)->refcount++;
+  }
+}
+
+int pn_object_refcount(void *object)
+{
+  assert(object);
+  return pni_head(object)->refcount;
+}
+
+void pn_object_decref(void *object)
+{
+  pni_head_t *head = pni_head(object);
+  assert(head->refcount > 0);
+  head->refcount--;
+}
+
+void pn_object_free(void *object)
+{
+  pni_head_t *head = pni_head(object);
+  free(head);
+}
+
+void *pn_incref(void *object)
+{
+  return pn_class_incref(PN_OBJECT, object);
+}
+
+int pn_decref(void *object)
+{
+  return pn_class_decref(PN_OBJECT, object);
+}
+
+int pn_refcount(void *object)
+{
+  return pn_class_refcount(PN_OBJECT, object);
+}
+
+void pn_free(void *object)
+{
+  pn_class_free(PN_OBJECT, object);
+}
+
+const pn_class_t *pn_class(void *object)
+{
+  return pn_class_reify(PN_OBJECT, object);
+}
+
+uintptr_t pn_hashcode(void *object)
+{
+  return pn_class_hashcode(PN_OBJECT, object);
+}
+
+intptr_t pn_compare(void *a, void *b)
+{
+  return pn_class_compare(PN_OBJECT, a, b);
+}
+
+bool pn_equals(void *a, void *b)
+{
+  return !pn_compare(a, b);
+}
+
+int pn_inspect(void *object, pn_string_t *dst)
+{
+  return pn_class_inspect(PN_OBJECT, object, dst);
+}
+
+#define pn_weakref_new NULL
+#define pn_weakref_initialize NULL
+#define pn_weakref_finalize NULL
+#define pn_weakref_free NULL
+
+static void pn_weakref_incref(void *object) {}
+static void pn_weakref_decref(void *object) {}
+static int pn_weakref_refcount(void *object) { return -1; }
+static const pn_class_t *pn_weakref_reify(void *object) {
+  return PN_WEAKREF;
+}
+static uintptr_t pn_weakref_hashcode(void *object) {
+  return pn_hashcode(object);
+}
+static intptr_t pn_weakref_compare(void *a, void *b) {
+  return pn_compare(a, b);
+}
+static int pn_weakref_inspect(void *object, pn_string_t *dst) {
+  return pn_inspect(object, dst);
+}
+
+const pn_class_t PN_WEAKREF[] = {PN_METACLASS(pn_weakref)};

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/record.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/record.c b/proton-c/src/core/object/record.c
new file mode 100644
index 0000000..6f4fe0a
--- /dev/null
+++ b/proton-c/src/core/object/record.c
@@ -0,0 +1,153 @@
+/*
+ *
+ * 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/object.h>
+#include <stdlib.h>
+#include <assert.h>
+
+typedef struct {
+  pn_handle_t key;
+  const pn_class_t *clazz;
+  void *value;
+} pni_field_t;
+
+struct pn_record_t {
+  size_t size;
+  size_t capacity;
+  pni_field_t *fields;
+};
+
+static void pn_record_initialize(void *object)
+{
+  pn_record_t *record = (pn_record_t *) object;
+  record->size = 0;
+  record->capacity = 0;
+  record->fields = NULL;
+}
+
+static void pn_record_finalize(void *object)
+{
+  pn_record_t *record = (pn_record_t *) object;
+  for (size_t i = 0; i < record->size; i++) {
+    pni_field_t *v = &record->fields[i];
+    pn_class_decref(v->clazz, v->value);
+  }
+  free(record->fields);
+}
+
+#define pn_record_hashcode NULL
+#define pn_record_compare NULL
+#define pn_record_inspect NULL
+
+pn_record_t *pn_record(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_record);
+  pn_record_t *record = (pn_record_t *) pn_class_new(&clazz, sizeof(pn_record_t));
+  pn_record_def(record, PN_LEGCTX, PN_VOID);
+  return record;
+}
+
+static pni_field_t *pni_record_find(pn_record_t *record, pn_handle_t key) {
+  for (size_t i = 0; i < record->size; i++) {
+    pni_field_t *field = &record->fields[i];
+    if (field->key == key) {
+      return field;
+    }
+  }
+  return NULL;
+}
+
+static pni_field_t *pni_record_create(pn_record_t *record) {
+  record->size++;
+  if (record->size > record->capacity) {
+    record->fields = (pni_field_t *) realloc(record->fields, record->size * sizeof(pni_field_t));
+    record->capacity = record->size;
+  }
+  pni_field_t *field = &record->fields[record->size - 1];
+  field->key = 0;
+  field->clazz = NULL;
+  field->value = NULL;
+  return field;
+}
+
+void pn_record_def(pn_record_t *record, pn_handle_t key, const pn_class_t *clazz)
+{
+  assert(record);
+  assert(clazz);
+
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    assert(field->clazz == clazz);
+  } else {
+    field = pni_record_create(record);
+    field->key = key;
+    field->clazz = clazz;
+  }
+}
+
+bool pn_record_has(pn_record_t *record, pn_handle_t key)
+{
+  assert(record);
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void *pn_record_get(pn_record_t *record, pn_handle_t key)
+{
+  assert(record);
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    return field->value;
+  } else {
+    return NULL;
+  }
+}
+
+void pn_record_set(pn_record_t *record, pn_handle_t key, void *value)
+{
+  assert(record);
+
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    void *old = field->value;
+    field->value = value;
+    pn_class_incref(field->clazz, value);
+    pn_class_decref(field->clazz, old);
+  }
+}
+
+void pn_record_clear(pn_record_t *record)
+{
+  assert(record);
+  for (size_t i = 0; i < record->size; i++) {
+    pni_field_t *field = &record->fields[i];
+    pn_class_decref(field->clazz, field->value);
+    field->key = 0;
+    field->clazz = NULL;
+    field->value = NULL;
+  }
+  record->size = 0;
+  pn_record_def(record, PN_LEGCTX, PN_VOID);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/object/string.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/object/string.c b/proton-c/src/core/object/string.c
new file mode 100644
index 0000000..13d0739
--- /dev/null
+++ b/proton-c/src/core/object/string.c
@@ -0,0 +1,269 @@
+/*
+ *
+ * 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 "platform/platform.h"
+
+#include <proton/error.h>
+#include <proton/object.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#define PNI_NULL_SIZE (-1)
+
+struct pn_string_t {
+  char *bytes;
+  ssize_t size;       // PNI_NULL_SIZE (-1) means null
+  size_t capacity;
+};
+
+static void pn_string_finalize(void *object)
+{
+  pn_string_t *string = (pn_string_t *) object;
+  free(string->bytes);
+}
+
+static uintptr_t pn_string_hashcode(void *object)
+{
+  pn_string_t *string = (pn_string_t *) object;
+  if (string->size == PNI_NULL_SIZE) {
+    return 0;
+  }
+
+  uintptr_t hashcode = 1;
+  for (ssize_t i = 0; i < string->size; i++) {
+    hashcode = hashcode * 31 + string->bytes[i];
+  }
+  return hashcode;
+}
+
+static intptr_t pn_string_compare(void *oa, void *ob)
+{
+  pn_string_t *a = (pn_string_t *) oa;
+  pn_string_t *b = (pn_string_t *) ob;
+  if (a->size != b->size) {
+    return b->size - a->size;
+  }
+
+  if (a->size == PNI_NULL_SIZE) {
+    return 0;
+  } else {
+    return memcmp(a->bytes, b->bytes, a->size);
+  }
+}
+
+static int pn_string_inspect(void *obj, pn_string_t *dst)
+{
+  pn_string_t *str = (pn_string_t *) obj;
+  if (str->size == PNI_NULL_SIZE) {
+    return pn_string_addf(dst, "null");
+  }
+
+  int err = pn_string_addf(dst, "\"");
+
+  for (int i = 0; i < str->size; i++) {
+    uint8_t c = str->bytes[i];
+    if (isprint(c)) {
+      err = pn_string_addf(dst, "%c", c);
+      if (err) return err;
+    } else {
+      err = pn_string_addf(dst, "\\x%.2x", c);
+      if (err) return err;
+    }
+  }
+
+  return pn_string_addf(dst, "\"");
+}
+
+pn_string_t *pn_string(const char *bytes)
+{
+  return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
+}
+
+#define pn_string_initialize NULL
+
+
+pn_string_t *pn_stringn(const char *bytes, size_t n)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_string);
+  pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t));
+  string->capacity = n ? n * sizeof(char) : 16;
+  string->bytes = (char *) malloc(string->capacity);
+  pn_string_setn(string, bytes, n);
+  return string;
+}
+
+const char *pn_string_get(pn_string_t *string)
+{
+  assert(string);
+  if (string->size == PNI_NULL_SIZE) {
+    return NULL;
+  } else {
+    return string->bytes;
+  }
+}
+
+size_t pn_string_size(pn_string_t *string)
+{
+  assert(string);
+  if (string->size == PNI_NULL_SIZE) {
+    return 0;
+  } else {
+    return string->size;
+  }
+}
+
+int pn_string_set(pn_string_t *string, const char *bytes)
+{
+  return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
+}
+
+int pn_string_grow(pn_string_t *string, size_t capacity)
+{
+  bool grow = false;
+  while (string->capacity < (capacity*sizeof(char) + 1)) {
+    string->capacity *= 2;
+    grow = true;
+  }
+
+  if (grow) {
+    char *growed = (char *) realloc(string->bytes, string->capacity);
+    if (growed) {
+      string->bytes = growed;
+    } else {
+      return PN_ERR;
+    }
+  }
+
+  return 0;
+}
+
+int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+{
+  int err = pn_string_grow(string, n);
+  if (err) return err;
+
+  if (bytes) {
+    memcpy(string->bytes, bytes, n*sizeof(char));
+    string->bytes[n] = '\0';
+    string->size = n;
+  } else {
+    string->size = PNI_NULL_SIZE;
+  }
+
+  return 0;
+}
+
+ssize_t pn_string_put(pn_string_t *string, char *dst)
+{
+  assert(string);
+  assert(dst);
+
+  if (string->size != PNI_NULL_SIZE) {
+    memcpy(dst, string->bytes, string->size + 1);
+  }
+
+  return string->size;
+}
+
+void pn_string_clear(pn_string_t *string)
+{
+  pn_string_set(string, NULL);
+}
+
+int pn_string_format(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  int err = pn_string_vformat(string, format, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
+{
+  pn_string_set(string, "");
+  return pn_string_vaddf(string, format, ap);
+}
+
+int pn_string_addf(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  int err = pn_string_vaddf(string, format, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
+{
+  va_list copy;
+
+  if (string->size == PNI_NULL_SIZE) {
+    return PN_ERR;
+  }
+
+  while (true) {
+    va_copy(copy, ap);
+    int err = pni_vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
+    va_end(copy);
+    if (err < 0) {
+      return err;
+    } else if ((size_t) err >= string->capacity - string->size) {
+      pn_string_grow(string, string->size + err);
+    } else {
+      string->size += err;
+      return 0;
+    }
+  }
+}
+
+char *pn_string_buffer(pn_string_t *string)
+{
+  assert(string);
+  return string->bytes;
+}
+
+size_t pn_string_capacity(pn_string_t *string)
+{
+  assert(string);
+  return string->capacity - 1;
+}
+
+int pn_string_resize(pn_string_t *string, size_t size)
+{
+  assert(string);
+  int err = pn_string_grow(string, size);
+  if (err) return err;
+  string->size = size;
+  string->bytes[size] = '\0';
+  return 0;
+}
+
+int pn_string_copy(pn_string_t *string, pn_string_t *src)
+{
+  assert(string);
+  return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
+}


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


[09/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/scanner.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/scanner.c b/proton-c/src/extra/scanner.c
new file mode 100644
index 0000000..beb7322
--- /dev/null
+++ b/proton-c/src/extra/scanner.c
@@ -0,0 +1,399 @@
+/*
+ *
+ * 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 "scanner.h"
+
+#include "platform/platform.h"
+
+#include <proton/error.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define ERROR_SIZE (1024)
+
+struct pn_scanner_t {
+  const char *input;
+  const char *position;
+  pn_token_t token;
+  char *atoms;
+  size_t size;
+  size_t capacity;
+  pn_error_t *error;
+};
+
+static const char *pni_token_type(pn_token_type_t type)
+{
+  switch (type)
+  {
+  case PN_TOK_LBRACE: return "LBRACE";
+  case PN_TOK_RBRACE: return "RBRACE";
+  case PN_TOK_LBRACKET: return "LBRACKET";
+  case PN_TOK_RBRACKET: return "RBRACKET";
+  case PN_TOK_EQUAL: return "EQUAL";
+  case PN_TOK_COMMA: return "COMMA";
+  case PN_TOK_POS: return "POS";
+  case PN_TOK_NEG: return "NEG";
+  case PN_TOK_DOT: return "DOT";
+  case PN_TOK_AT: return "AT";
+  case PN_TOK_DOLLAR: return "DOLLAR";
+  case PN_TOK_BINARY: return "BINARY";
+  case PN_TOK_STRING: return "STRING";
+  case PN_TOK_SYMBOL: return "SYMBOL";
+  case PN_TOK_ID: return "ID";
+  case PN_TOK_FLOAT: return "FLOAT";
+  case PN_TOK_INT: return "INT";
+  case PN_TOK_TRUE: return "TRUE";
+  case PN_TOK_FALSE: return "FALSE";
+  case PN_TOK_NULL: return "NULL";
+  case PN_TOK_EOS: return "EOS";
+  case PN_TOK_ERR: return "ERR";
+  default: return "<UNKNOWN>";
+  }
+}
+
+pn_scanner_t *pn_scanner()
+{
+  pn_scanner_t *scanner = (pn_scanner_t *) malloc(sizeof(pn_scanner_t));
+  if (scanner) {
+    scanner->input = NULL;
+    scanner->error = pn_error();
+  }
+  return scanner;
+}
+
+void pn_scanner_free(pn_scanner_t *scanner)
+{
+  if (scanner) {
+    pn_error_free(scanner->error);
+    free(scanner);
+  }
+}
+
+pn_token_t pn_scanner_token(pn_scanner_t *scanner)
+{
+  if (scanner) {
+    return scanner->token;
+  } else {
+    pn_token_t tok = {PN_TOK_ERR, 0, (size_t)0};
+    return tok;
+  }
+}
+
+void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col)
+{
+  *line = 1;
+  *col = 0;
+
+  for (const char *c = scanner->input; *c && c <= scanner->token.start; c++) {
+    if (*c == '\n') {
+      *line += 1;
+      *col = -1;
+    } else {
+      *col += 1;
+    }
+  }
+}
+
+int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  int err = pn_scanner_verr(scanner, code, fmt, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap)
+{
+  char error[ERROR_SIZE];
+
+  int line, col;
+  pn_scanner_line_info(scanner, &line, &col);
+  int size = scanner->token.size;
+  int ln = pni_snprintf(error, ERROR_SIZE,
+                    "input line %i column %i %s:'%.*s': ", line, col,
+                    pni_token_type(scanner->token.type),
+                    size, scanner->token.start);
+  if (ln >= ERROR_SIZE) {
+    return pn_scanner_err(scanner, code, "error info truncated");
+  } else if (ln < 0) {
+    error[0] = '\0';
+  }
+
+  int n = pni_snprintf(error + ln, ERROR_SIZE - ln, fmt, ap);
+
+  if (n >= ERROR_SIZE - ln) {
+    return pn_scanner_err(scanner, code, "error info truncated");
+  } else if (n < 0) {
+    error[0] = '\0';
+  }
+
+  return pn_error_set(scanner->error, code, error);
+}
+
+int pn_scanner_errno(pn_scanner_t *scanner)
+{
+  return pn_error_code(scanner->error);
+}
+
+const char *pn_scanner_error(pn_scanner_t *scanner)
+{
+  return pn_error_text(scanner->error);
+}
+
+static void pni_scanner_emit(pn_scanner_t *scanner, pn_token_type_t type, const char *start, size_t size)
+{
+  scanner->token.type = type;
+  scanner->token.start = start;
+  scanner->token.size = size;
+}
+
+static int pni_scanner_quoted(pn_scanner_t *scanner, const char *str, int start,
+                      pn_token_type_t type)
+{
+  bool escape = false;
+
+  for (int i = start; true; i++) {
+    char c = str[i];
+    if (escape) {
+      escape = false;
+    } else {
+      switch (c) {
+      case '\0':
+      case '"':
+        pni_scanner_emit(scanner, c ? type : PN_TOK_ERR,
+                        str, c ? i + 1 : i);
+        return c ? 0 : pn_scanner_err(scanner, PN_ERR, "missmatched quote");
+      case '\\':
+        escape = true;
+        break;
+      }
+    }
+  }
+}
+
+static int pni_scanner_binary(pn_scanner_t *scanner, const char *str)
+{
+  return pni_scanner_quoted(scanner, str, 2, PN_TOK_BINARY);
+}
+
+static int pni_scanner_string(pn_scanner_t *scanner, const char *str)
+{
+  return pni_scanner_quoted(scanner, str, 1, PN_TOK_STRING);
+}
+
+static int pni_scanner_alpha_end(pn_scanner_t *scanner, const char *str, int start)
+{
+  for (int i = start; true; i++) {
+    char c = str[i];
+    if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
+      return i;
+    }
+  }
+}
+
+static int pni_scanner_alpha(pn_scanner_t *scanner, const char *str)
+{
+  int n = pni_scanner_alpha_end(scanner, str, 0);
+  pn_token_type_t type;
+  if (!strncmp(str, "true", n)) {
+    type = PN_TOK_TRUE;
+  } else if (!strncmp(str, "false", n)) {
+    type = PN_TOK_FALSE;
+  } else if (!strncmp(str, "null", n)) {
+    type = PN_TOK_NULL;
+  } else {
+    type = PN_TOK_ID;
+  }
+
+  pni_scanner_emit(scanner, type, str, n);
+  return 0;
+}
+
+static int pni_scanner_symbol(pn_scanner_t *scanner, const char *str)
+{
+  char c = str[1];
+
+  if (c == '"') {
+    return pni_scanner_quoted(scanner, str, 2, PN_TOK_SYMBOL);
+  } else {
+    int n = pni_scanner_alpha_end(scanner, str, 1);
+    pni_scanner_emit(scanner, PN_TOK_SYMBOL, str, n);
+    return 0;
+  }
+}
+
+static int pni_scanner_number(pn_scanner_t *scanner, const char *str)
+{
+  bool dot = false;
+  bool exp = false;
+
+  int i = 0;
+
+  if (str[i] == '+' || str[i] == '-') {
+    i++;
+  }
+
+  for ( ; true; i++) {
+    char c = str[i];
+    switch (c) {
+    case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+    case '7': case '8': case '9':
+      continue;
+    case '.':
+      if (dot) {
+        pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
+        return 0;
+      } else {
+        dot = true;
+      }
+      continue;
+    case 'e':
+    case 'E':
+      if (exp) {
+        pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
+        return 0;
+      } else {
+        dot = true;
+        exp = true;
+        if (str[i+1] == '+' || str[i+1] == '-') {
+          i++;
+        }
+        continue;
+      }
+    default:
+      if (dot || exp) {
+        pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
+        return 0;
+      } else {
+        pni_scanner_emit(scanner, PN_TOK_INT, str, i);
+        return 0;
+      }
+    }
+  }
+}
+
+static int pni_scanner_single(pn_scanner_t *scanner, const char *str, pn_token_type_t type)
+{
+  pni_scanner_emit(scanner, type, str, 1);
+  return 0;
+}
+
+int pn_scanner_start(pn_scanner_t *scanner, const char *input)
+{
+  if (!scanner || !input) return PN_ARG_ERR;
+  scanner->input = input;
+  scanner->position = input;
+  return pn_scanner_scan(scanner);
+}
+
+int pn_scanner_scan(pn_scanner_t *scanner)
+{
+  const char *str = scanner->position;
+  char n;
+
+  for (char c; true; str++) {
+    c = *str;
+    switch (c)
+    {
+    case '{':
+      return pni_scanner_single(scanner, str, PN_TOK_LBRACE);
+    case '}':
+      return pni_scanner_single(scanner, str, PN_TOK_RBRACE);
+    case'[':
+      return pni_scanner_single(scanner, str, PN_TOK_LBRACKET);
+    case ']':
+      return pni_scanner_single(scanner, str, PN_TOK_RBRACKET);
+    case '=':
+      return pni_scanner_single(scanner, str, PN_TOK_EQUAL);
+    case ',':
+      return pni_scanner_single(scanner, str, PN_TOK_COMMA);
+    case '.':
+      n = *(str+1);
+      if ((n >= '0' && n <= '9')) {
+        return pni_scanner_number(scanner, str);
+      } else {
+        return pni_scanner_single(scanner, str, PN_TOK_DOT);
+      }
+    case '@':
+      return pni_scanner_single(scanner, str, PN_TOK_AT);
+    case '$':
+      return pni_scanner_single(scanner, str, PN_TOK_DOLLAR);
+    case '-':
+      n = *(str+1);
+      if ((n >= '0' && n <= '9') || n == '.') {
+        return pni_scanner_number(scanner, str);
+      } else {
+        return pni_scanner_single(scanner, str, PN_TOK_NEG);
+      }
+    case '+':
+      n = *(str+1);
+      if ((n >= '0' && n <= '9') || n == '.') {
+        return pni_scanner_number(scanner, str);
+      } else {
+        return pni_scanner_single(scanner, str, PN_TOK_POS);
+      }
+    case ' ': case '\t': case '\r': case '\v': case '\f': case '\n':
+      break;
+    case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+    case '7': case '8': case '9':
+      return pni_scanner_number(scanner, str);
+    case ':':
+      return pni_scanner_symbol(scanner, str);
+    case '"':
+      return pni_scanner_string(scanner, str);
+    case 'b':
+      if (str[1] == '"') {
+        return pni_scanner_binary(scanner, str);
+      }
+    case 'a': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
+    case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o':
+    case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v':
+    case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C':
+    case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
+    case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q':
+    case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+      return pni_scanner_alpha(scanner, str);
+    case '\0':
+      pni_scanner_emit(scanner, PN_TOK_EOS, str, 0);
+      return PN_EOS;
+    default:
+      pni_scanner_emit(scanner, PN_TOK_ERR, str, 1);
+      return pn_scanner_err(scanner, PN_ERR, "illegal character");
+    }
+  }
+}
+
+int pn_scanner_shift(pn_scanner_t *scanner)
+{
+  scanner->position = scanner->token.start + scanner->token.size;
+  int err = pn_scanner_scan(scanner);
+  if (err == PN_EOS) {
+    return 0;
+  } else {
+    return err;
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/scanner.h
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/scanner.h b/proton-c/src/extra/scanner.h
new file mode 100644
index 0000000..218babe
--- /dev/null
+++ b/proton-c/src/extra/scanner.h
@@ -0,0 +1,74 @@
+#ifndef PROTON_SCANNER_H
+#define PROTON_SCANNER_H 1
+
+/*
+ *
+ * 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/import_export.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+typedef enum {
+  PN_TOK_LBRACE,
+  PN_TOK_RBRACE,
+  PN_TOK_LBRACKET,
+  PN_TOK_RBRACKET,
+  PN_TOK_EQUAL,
+  PN_TOK_COMMA,
+  PN_TOK_POS,
+  PN_TOK_NEG,
+  PN_TOK_DOT,
+  PN_TOK_AT,
+  PN_TOK_DOLLAR,
+  PN_TOK_BINARY,
+  PN_TOK_STRING,
+  PN_TOK_SYMBOL,
+  PN_TOK_ID,
+  PN_TOK_FLOAT,
+  PN_TOK_INT,
+  PN_TOK_TRUE,
+  PN_TOK_FALSE,
+  PN_TOK_NULL,
+  PN_TOK_EOS,
+  PN_TOK_ERR
+} pn_token_type_t;
+
+typedef struct pn_scanner_t pn_scanner_t;
+
+typedef struct {
+  pn_token_type_t type;
+  const char *start;
+  size_t size;
+} pn_token_t;
+
+PN_EXTERN pn_scanner_t *pn_scanner(void);
+PN_EXTERN void pn_scanner_free(pn_scanner_t *scanner);
+PN_EXTERN pn_token_t pn_scanner_token(pn_scanner_t *scanner);
+PN_EXTERN int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...);
+PN_EXTERN int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap);
+PN_EXTERN void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col);
+PN_EXTERN int pn_scanner_errno(pn_scanner_t *scanner);
+PN_EXTERN const char *pn_scanner_error(pn_scanner_t *scanner);
+PN_EXTERN int pn_scanner_start(pn_scanner_t *scanner, const char *input);
+PN_EXTERN int pn_scanner_scan(pn_scanner_t *scanner);
+PN_EXTERN int pn_scanner_shift(pn_scanner_t *scanner);
+
+#endif /* scanner.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/url.c b/proton-c/src/extra/url.c
new file mode 100644
index 0000000..c1ce628
--- /dev/null
+++ b/proton-c/src/extra/url.c
@@ -0,0 +1,272 @@
+/*
+ *
+ * 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/url.h"
+#include "proton/object.h"
+
+#include "core/util.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+/** URL-encode src and append to dst. */
+static void pni_urlencode(pn_string_t *dst, const char* src) {
+    static const char *bad = "@:/";
+
+    if (!src) return;
+    const char *i = src;
+    const char *j = strpbrk(i, bad);
+    while (j) {
+        pn_string_addf(dst, "%.*s", (int)(j-i), i);
+        pn_string_addf(dst, "%%%02X", (int)*j);
+        i = j + 1;
+        j = strpbrk(i, bad);
+    }
+    pn_string_addf(dst, "%s", i);
+}
+
+// Low level url parser
+static void pni_urldecode(const char *src, char *dst)
+{
+  const char *in = src;
+  char *out = dst;
+  while (*in != '\0')
+  {
+    if ('%' == *in)
+    {
+      if ((in[1] != '\0') && (in[2] != '\0'))
+      {
+        char esc[3];
+        esc[0] = in[1];
+        esc[1] = in[2];
+        esc[2] = '\0';
+        unsigned long d = strtoul(esc, NULL, 16);
+        *out = (char)d;
+        in += 3;
+        out++;
+      }
+      else
+      {
+        *out = *in;
+        in++;
+        out++;
+      }
+    }
+    else
+    {
+      *out = *in;
+      in++;
+      out++;
+    }
+  }
+  *out = '\0';
+}
+
+void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path)
+{
+  if (!url) return;
+
+  char *slash = strchr(url, '/');
+
+  if (slash && slash>url) {
+    char *scheme_end = strstr(slash-1, "://");
+
+    if (scheme_end && scheme_end<slash) {
+      *scheme_end = '\0';
+      *scheme = url;
+      url = scheme_end + 3;
+      slash = strchr(url, '/');
+    }
+  }
+
+  if (slash) {
+    *slash = '\0';
+    *path = slash + 1;
+  }
+
+  char *at = strchr(url, '@');
+  if (at) {
+    *at = '\0';
+    char *up = url;
+    *user = up;
+    url = at + 1;
+    char *colon = strchr(up, ':');
+    if (colon) {
+      *colon = '\0';
+      *pass = colon + 1;
+    }
+  }
+
+  *host = url;
+  char *open = (*url == '[') ? url : 0;
+  if (open) {
+    char *close = strchr(open, ']');
+    if (close) {
+        *host = open + 1;
+        *close = '\0';
+        url = close + 1;
+    }
+  }
+
+  char *colon = strchr(url, ':');
+  if (colon) {
+    *colon = '\0';
+    *port = colon + 1;
+  }
+
+  if (*user) pni_urldecode(*user, *user);
+  if (*pass) pni_urldecode(*pass, *pass);
+}
+
+struct pn_url_t {
+    char *scheme;
+    char *username;
+    char *password;
+    char *host;
+    char *port;
+    char *path;
+    pn_string_t *str;
+};
+
+/** Internal use only, returns the pn_string_t. Public function is pn_url_str() */
+static pn_string_t *pn_url_string(pn_url_t* url)
+{
+    pn_url_str(url);               /* Make sure str is up to date */
+    return url->str;
+}
+
+static void pn_url_finalize(void *object)
+{
+    pn_url_t *url = (pn_url_t *) object;
+    pn_url_clear(url);
+    pn_free(url->str);
+}
+
+static uintptr_t pn_url_hashcode(void *object)
+{
+    pn_url_t *url = (pn_url_t *) object;
+    return pn_hashcode(pn_url_string(url));
+}
+
+static intptr_t pn_url_compare(void *oa, void *ob)
+{
+    pn_url_t *a = (pn_url_t *) oa;
+    pn_url_t *b = (pn_url_t *) ob;
+    return pn_compare(pn_url_string(a), pn_url_string(b));
+}
+
+
+static int pn_url_inspect(void *obj, pn_string_t *dst)
+{
+    pn_url_t *url = (pn_url_t *) obj;
+    int err = 0;
+    err = pn_string_addf(dst, "Url("); if (err) return err;
+    err = pn_inspect(pn_url_string(url), dst); if (err) return err;
+    return pn_string_addf(dst, ")");
+}
+
+#define pn_url_initialize NULL
+
+
+pn_url_t *pn_url() {
+    static const pn_class_t clazz = PN_CLASS(pn_url);
+    pn_url_t *url = (pn_url_t*) pn_class_new(&clazz, sizeof(pn_url_t));
+    if (!url) return NULL;
+    memset(url, 0, sizeof(*url));
+    url->str = pn_string(NULL);
+    return url;
+}
+
+/** Parse a string URL as a pn_url_t.
+ *@param[in] url A URL string.
+ *@return The parsed pn_url_t or NULL if url is not a valid URL string.
+ */
+pn_url_t *pn_url_parse(const char *str) {
+    if (!str || !*str)          /* Empty string or NULL is illegal. */
+        return NULL;
+
+    pn_url_t *url = pn_url();
+    char *str2 = pn_strdup(str);
+    pni_parse_url(str2, &url->scheme, &url->username, &url->password, &url->host, &url->port, &url->path);
+    url->scheme = pn_strdup(url->scheme);
+    url->username = pn_strdup(url->username);
+    url->password = pn_strdup(url->password);
+    url->host = (url->host && !*url->host) ? NULL : pn_strdup(url->host);
+    url->port = pn_strdup(url->port);
+    url->path = pn_strdup(url->path);
+
+    free(str2);
+    return url;
+}
+
+/** Free a URL */
+void pn_url_free(pn_url_t *url) { pn_free(url); }
+
+/** Clear the contents of the URL. */
+void pn_url_clear(pn_url_t *url) {
+    pn_url_set_scheme(url, NULL);
+    pn_url_set_username(url, NULL);
+    pn_url_set_password(url, NULL);
+    pn_url_set_host(url, NULL);
+    pn_url_set_port(url, NULL);
+    pn_url_set_path(url, NULL);
+    pn_string_clear(url->str);
+}
+
+/** Return the string form of a URL. */
+const char *pn_url_str(pn_url_t *url) {
+    if (pn_string_get(url->str) == NULL) {
+        pn_string_set(url->str, "");
+        if (url->scheme) pn_string_addf(url->str, "%s://", url->scheme);
+        if (url->username) pni_urlencode(url->str, url->username);
+        if (url->password) {
+            pn_string_addf(url->str, ":");
+            pni_urlencode(url->str, url->password);
+        }
+        if (url->username || url->password) pn_string_addf(url->str, "@");
+        if (url->host) {
+            if (strchr(url->host, ':')) pn_string_addf(url->str, "[%s]", url->host);
+            else pn_string_addf(url->str, "%s", url->host);
+        }
+        if (url->port) pn_string_addf(url->str, ":%s", url->port);
+        if (url->path) pn_string_addf(url->str, "/%s", url->path);
+    }
+    return pn_string_get(url->str);
+}
+
+const char *pn_url_get_scheme(pn_url_t *url) { return url->scheme; }
+const char *pn_url_get_username(pn_url_t *url) { return url->username; }
+const char *pn_url_get_password(pn_url_t *url) { return url->password; }
+const char *pn_url_get_host(pn_url_t *url) { return url->host; }
+const char *pn_url_get_port(pn_url_t *url) { return url->port; }
+const char *pn_url_get_path(pn_url_t *url) { return url->path; }
+
+#define SET(part) free(url->part); url->part = pn_strdup(part); pn_string_clear(url->str)
+void pn_url_set_scheme(pn_url_t *url, const char *scheme) { SET(scheme); }
+void pn_url_set_username(pn_url_t *url, const char *username) { SET(username); }
+void pn_url_set_password(pn_url_t *url, const char *password) { SET(password); }
+void pn_url_set_host(pn_url_t *url, const char *host) { SET(host); }
+void pn_url_set_port(pn_url_t *url, const char *port) { SET(port); }
+void pn_url_set_path(pn_url_t *url, const char *path) { SET(path); }
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/framing/framing.c
----------------------------------------------------------------------
diff --git a/proton-c/src/framing/framing.c b/proton-c/src/framing/framing.c
deleted file mode 100644
index 09bf4bb..0000000
--- a/proton-c/src/framing/framing.c
+++ /dev/null
@@ -1,103 +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 <stdio.h>
-#include <string.h>
-
-#include "framing.h"
-
-// TODO: These are near duplicates of code in codec.c - they should be
-// deduplicated.
-static inline void pn_i_write16(char *bytes, uint16_t value)
-{
-    bytes[0] = 0xFF & (value >> 8);
-    bytes[1] = 0xFF & (value     );
-}
-
-
-static inline void pn_i_write32(char *bytes, uint32_t value)
-{
-    bytes[0] = 0xFF & (value >> 24);
-    bytes[1] = 0xFF & (value >> 16);
-    bytes[2] = 0xFF & (value >>  8);
-    bytes[3] = 0xFF & (value      );
-}
-
-static inline uint16_t pn_i_read16(const char *bytes)
-{
-    uint16_t a = (uint8_t) bytes[0];
-    uint16_t b = (uint8_t) bytes[1];
-    uint16_t r = a << 8
-    | b;
-    return r;
-}
-
-static inline uint32_t pn_i_read32(const char *bytes)
-{
-    uint32_t a = (uint8_t) bytes[0];
-    uint32_t b = (uint8_t) bytes[1];
-    uint32_t c = (uint8_t) bytes[2];
-    uint32_t d = (uint8_t) bytes[3];
-    uint32_t r = a << 24
-    | b << 16
-    | c <<  8
-    | d;
-    return r;
-}
-
-
-ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max)
-{
-  if (available < AMQP_HEADER_SIZE) return 0;
-  uint32_t size = pn_i_read32(&bytes[0]);
-  if (max && size > max) return PN_ERR;
-  if (available < size) return 0;
-  unsigned int doff = 4 * (uint8_t)bytes[4];
-  if (doff < AMQP_HEADER_SIZE || doff > size) return PN_ERR;
-
-  frame->size = size - doff;
-  frame->ex_size = doff - AMQP_HEADER_SIZE;
-  frame->type = bytes[5];
-  frame->channel = pn_i_read16(&bytes[6]);
-  frame->extended = bytes + AMQP_HEADER_SIZE;
-  frame->payload = bytes + doff;
-
-  return size;
-}
-
-size_t pn_write_frame(char *bytes, size_t available, pn_frame_t frame)
-{
-  size_t size = AMQP_HEADER_SIZE + frame.ex_size + frame.size;
-  if (size <= available)
-  {
-    pn_i_write32(&bytes[0], size);
-    int doff = (frame.ex_size + AMQP_HEADER_SIZE - 1)/4 + 1;
-    bytes[4] = doff;
-    bytes[5] = frame.type;
-    pn_i_write16(&bytes[6], frame.channel);
-
-    memmove(bytes + AMQP_HEADER_SIZE, frame.extended, frame.ex_size);
-    memmove(bytes + 4*doff, frame.payload, frame.size);
-    return size;
-  } else {
-    return 0;
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/framing/framing.h
----------------------------------------------------------------------
diff --git a/proton-c/src/framing/framing.h b/proton-c/src/framing/framing.h
deleted file mode 100644
index 6033867..0000000
--- a/proton-c/src/framing/framing.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef PROTON_FRAMING_H
-#define PROTON_FRAMING_H 1
-
-/*
- *
- * 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/import_export.h>
-#include <proton/type_compat.h>
-#include <proton/error.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define AMQP_HEADER_SIZE (8)
-#define AMQP_MIN_MAX_FRAME_SIZE ((uint32_t)512) // minimum allowable max-frame
-
-typedef struct {
-  uint8_t type;
-  uint16_t channel;
-  size_t ex_size;
-  const char *extended;
-  size_t size;
-  const char *payload;
-} pn_frame_t;
-
-ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max);
-size_t pn_write_frame(char *bytes, size_t size, pn_frame_t frame);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* framing.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/handlers/iohandler.c
----------------------------------------------------------------------
diff --git a/proton-c/src/handlers/iohandler.c b/proton-c/src/handlers/iohandler.c
index 9154884..db18c0c 100644
--- a/proton-c/src/handlers/iohandler.c
+++ b/proton-c/src/handlers/iohandler.c
@@ -19,8 +19,11 @@
  *
  */
 
+#include "reactor/io.h"
+#include "reactor/reactor.h"
+#include "reactor/selector.h"
+
 #include <proton/handlers.h>
-#include <proton/selector.h>
 #include <proton/transport.h>
 #include <assert.h>
 
@@ -62,7 +65,7 @@ static void pn_iodispatch(pn_iohandler_t *handler, pn_event_t *event, pn_event_t
   pn_record_t *record = pn_reactor_attachments(reactor);
   pn_selector_t *selector = (pn_selector_t *) pn_record_get(record, PN_SELECTOR);
   if (!selector) {
-    selector = pn_io_selector(pn_reactor_io(reactor));
+    selector = pn_io_selector(pni_reactor_io(reactor));
     pn_record_def(record, PN_SELECTOR, PN_OBJECT);
     pn_record_set(record, PN_SELECTOR, selector);
     pn_decref(selector);

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

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/log.c
----------------------------------------------------------------------
diff --git a/proton-c/src/log.c b/proton-c/src/log.c
deleted file mode 100644
index b92a99a..0000000
--- a/proton-c/src/log.c
+++ /dev/null
@@ -1,70 +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/log.h>
-#include <proton/object.h>
-#include <stdio.h>
-#include "util.h"
-
-
-static void stderr_logger(const char *message) {
-    fprintf(stderr, "%s\n", message);
-}
-
-static pn_logger_t logger = stderr_logger;
-static int enabled_env  = -1;   /* Set from environment variable. */
-static int enabled_call = -1;   /* set by pn_log_enable */
-
-void pn_log_enable(bool value) {
-    enabled_call = value;
-}
-
-bool pn_log_enabled(void) {
-    if (enabled_call != -1) return enabled_call; /* Takes precedence */
-    if (enabled_env == -1) 
-        enabled_env = pn_env_bool("PN_TRACE_LOG");
-    return enabled_env;
-}
-
-void pn_log_logger(pn_logger_t new_logger) {
-    logger = new_logger;
-    if (!logger) pn_log_enable(false);
-}
-
-void pn_vlogf_impl(const char *fmt, va_list ap) {
-    pn_string_t *msg = pn_string("");
-    pn_string_vformat(msg, fmt, ap);
-    fprintf(stderr, "%s\n", pn_string_get(msg));
-}
-
-/**@internal
- *
- * Note: We check pn_log_enabled() in the pn_logf macro *before* calling
- * pn_logf_impl because evaluating the arguments to that call could have
- * side-effects with performance impact (e.g. calling functions to construct
- * complicated messages.) It is important that a disabled log statement results
- * in nothing more than a call to pn_log_enabled().
- */
-void pn_logf_impl(const char *fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  pn_vlogf_impl(fmt, ap);
-  va_end(ap);
-}
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/log_private.h
----------------------------------------------------------------------
diff --git a/proton-c/src/log_private.h b/proton-c/src/log_private.h
deleted file mode 100644
index 4725045..0000000
--- a/proton-c/src/log_private.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef LOG_PRIVATE_H
-#define LOG_PRIVATE_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.
- */
-
-/**@file
- *
- * Log messages that are not associated with a transport.
- */
-
-#include <proton/log.h>
-#include <stdarg.h>
-
-/** Log a printf style message */
-#define pn_logf(...)                            \
-    do {                                        \
-        if (pn_log_enabled())                   \
-            pn_logf_impl(__VA_ARGS__);          \
-    } while(0)
-
-/** va_list version of pn_logf */
-#define pn_vlogf(fmt, ap)                       \
-    do {                                        \
-        if (pn_log_enabled())                   \
-            pn_vlogf_impl(fmt, ap);             \
-    } while(0)
-
-/** Return true if logging is enabled. */
-bool pn_log_enabled(void);
-
-/**@internal*/
-void pn_logf_impl(const char* fmt, ...);
-/**@internal*/
-void pn_vlogf_impl(const char *fmt, va_list ap);
-
-
-
-#endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/message/message.c
----------------------------------------------------------------------
diff --git a/proton-c/src/message/message.c b/proton-c/src/message/message.c
deleted file mode 100644
index 15d9c6c..0000000
--- a/proton-c/src/message/message.c
+++ /dev/null
@@ -1,861 +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/message.h>
-#include <proton/object.h>
-#include <proton/codec.h>
-#include <proton/error.h>
-#include <proton/parser.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include "protocol.h"
-#include "util.h"
-#include "platform_fmt.h"
-
-// message
-
-struct pn_message_t {
-  pn_timestamp_t expiry_time;
-  pn_timestamp_t creation_time;
-  pn_data_t *id;
-  pn_string_t *user_id;
-  pn_string_t *address;
-  pn_string_t *subject;
-  pn_string_t *reply_to;
-  pn_data_t *correlation_id;
-  pn_string_t *content_type;
-  pn_string_t *content_encoding;
-  pn_string_t *group_id;
-  pn_string_t *reply_to_group_id;
-
-  pn_data_t *data;
-  pn_data_t *instructions;
-  pn_data_t *annotations;
-  pn_data_t *properties;
-  pn_data_t *body;
-
-  pn_error_t *error;
-
-  pn_sequence_t group_sequence;
-  pn_millis_t ttl;
-  uint32_t delivery_count;
-
-  uint8_t priority;
-
-  bool durable;
-  bool first_acquirer;
-  bool inferred;
-};
-
-void pn_message_finalize(void *obj)
-{
-  pn_message_t *msg = (pn_message_t *) obj;
-  pn_free(msg->user_id);
-  pn_free(msg->address);
-  pn_free(msg->subject);
-  pn_free(msg->reply_to);
-  pn_free(msg->content_type);
-  pn_free(msg->content_encoding);
-  pn_free(msg->group_id);
-  pn_free(msg->reply_to_group_id);
-  pn_data_free(msg->id);
-  pn_data_free(msg->correlation_id);
-  pn_data_free(msg->data);
-  pn_data_free(msg->instructions);
-  pn_data_free(msg->annotations);
-  pn_data_free(msg->properties);
-  pn_data_free(msg->body);
-  pn_error_free(msg->error);
-}
-
-int pn_message_inspect(void *obj, pn_string_t *dst)
-{
-  pn_message_t *msg = (pn_message_t *) obj;
-  int err = pn_string_addf(dst, "Message{");
-  if (err) return err;
-
-  bool comma = false;
-
-  if (pn_string_get(msg->address)) {
-    err = pn_string_addf(dst, "address=");
-    if (err) return err;
-    err = pn_inspect(msg->address, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->durable) {
-    err = pn_string_addf(dst, "durable=%i, ", msg->durable);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->priority != PN_DEFAULT_PRIORITY) {
-    err = pn_string_addf(dst, "priority=%i, ", msg->priority);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->ttl) {
-    err = pn_string_addf(dst, "ttl=%" PRIu32 ", ", msg->ttl);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->first_acquirer) {
-    err = pn_string_addf(dst, "first_acquirer=%i, ", msg->first_acquirer);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->delivery_count) {
-    err = pn_string_addf(dst, "delivery_count=%" PRIu32 ", ", msg->delivery_count);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_data_size(msg->id)) {
-    err = pn_string_addf(dst, "id=");
-    if (err) return err;
-    err = pn_inspect(msg->id, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->user_id)) {
-    err = pn_string_addf(dst, "user_id=");
-    if (err) return err;
-    err = pn_inspect(msg->user_id, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->subject)) {
-    err = pn_string_addf(dst, "subject=");
-    if (err) return err;
-    err = pn_inspect(msg->subject, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->reply_to)) {
-    err = pn_string_addf(dst, "reply_to=");
-    if (err) return err;
-    err = pn_inspect(msg->reply_to, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_data_size(msg->correlation_id)) {
-    err = pn_string_addf(dst, "correlation_id=");
-    if (err) return err;
-    err = pn_inspect(msg->correlation_id, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->content_type)) {
-    err = pn_string_addf(dst, "content_type=");
-    if (err) return err;
-    err = pn_inspect(msg->content_type, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->content_encoding)) {
-    err = pn_string_addf(dst, "content_encoding=");
-    if (err) return err;
-    err = pn_inspect(msg->content_encoding, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->expiry_time) {
-    err = pn_string_addf(dst, "expiry_time=%" PRIi64 ", ", msg->expiry_time);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->creation_time) {
-    err = pn_string_addf(dst, "creation_time=%" PRIi64 ", ", msg->creation_time);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->group_id)) {
-    err = pn_string_addf(dst, "group_id=");
-    if (err) return err;
-    err = pn_inspect(msg->group_id, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->group_sequence) {
-    err = pn_string_addf(dst, "group_sequence=%" PRIi32 ", ", msg->group_sequence);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_string_get(msg->reply_to_group_id)) {
-    err = pn_string_addf(dst, "reply_to_group_id=");
-    if (err) return err;
-    err = pn_inspect(msg->reply_to_group_id, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (msg->inferred) {
-    err = pn_string_addf(dst, "inferred=%i, ", msg->inferred);
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_data_size(msg->instructions)) {
-    err = pn_string_addf(dst, "instructions=");
-    if (err) return err;
-    err = pn_inspect(msg->instructions, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_data_size(msg->annotations)) {
-    err = pn_string_addf(dst, "annotations=");
-    if (err) return err;
-    err = pn_inspect(msg->annotations, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_data_size(msg->properties)) {
-    err = pn_string_addf(dst, "properties=");
-    if (err) return err;
-    err = pn_inspect(msg->properties, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (pn_data_size(msg->body)) {
-    err = pn_string_addf(dst, "body=");
-    if (err) return err;
-    err = pn_inspect(msg->body, dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    comma = true;
-  }
-
-  if (comma) {
-    int err = pn_string_resize(dst, pn_string_size(dst) - 2);
-    if (err) return err;
-  }
-
-  return pn_string_addf(dst, "}");
-}
-
-#define pn_message_initialize NULL
-#define pn_message_hashcode NULL
-#define pn_message_compare NULL
-
-pn_message_t *pn_message()
-{
-  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));
-  msg->durable = false;
-  msg->priority = PN_DEFAULT_PRIORITY;
-  msg->ttl = 0;
-  msg->first_acquirer = false;
-  msg->delivery_count = 0;
-  msg->id = pn_data(1);
-  msg->user_id = pn_string(NULL);
-  msg->address = pn_string(NULL);
-  msg->subject = pn_string(NULL);
-  msg->reply_to = pn_string(NULL);
-  msg->correlation_id = pn_data(1);
-  msg->content_type = pn_string(NULL);
-  msg->content_encoding = pn_string(NULL);
-  msg->expiry_time = 0;
-  msg->creation_time = 0;
-  msg->group_id = pn_string(NULL);
-  msg->group_sequence = 0;
-  msg->reply_to_group_id = pn_string(NULL);
-
-  msg->inferred = false;
-  msg->data = pn_data(16);
-  msg->instructions = pn_data(16);
-  msg->annotations = pn_data(16);
-  msg->properties = pn_data(16);
-  msg->body = pn_data(16);
-
-  msg->error = pn_error();
-  return msg;
-}
-
-void pn_message_free(pn_message_t *msg)
-{
-  pn_free(msg);
-}
-
-void pn_message_clear(pn_message_t *msg)
-{
-  msg->durable = false;
-  msg->priority = PN_DEFAULT_PRIORITY;
-  msg->ttl = 0;
-  msg->first_acquirer = false;
-  msg->delivery_count = 0;
-  pn_data_clear(msg->id);
-  pn_string_clear(msg->user_id);
-  pn_string_clear(msg->address);
-  pn_string_clear(msg->subject);
-  pn_string_clear(msg->reply_to);
-  pn_data_clear(msg->correlation_id);
-  pn_string_clear(msg->content_type);
-  pn_string_clear(msg->content_encoding);
-  msg->expiry_time = 0;
-  msg->creation_time = 0;
-  pn_string_clear(msg->group_id);
-  msg->group_sequence = 0;
-  pn_string_clear(msg->reply_to_group_id);
-  msg->inferred = false;
-  pn_data_clear(msg->data);
-  pn_data_clear(msg->instructions);
-  pn_data_clear(msg->annotations);
-  pn_data_clear(msg->properties);
-  pn_data_clear(msg->body);
-}
-
-int pn_message_errno(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_error_code(msg->error);
-}
-
-pn_error_t *pn_message_error(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->error;
-}
-
-bool pn_message_is_inferred(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->inferred;
-}
-
-int pn_message_set_inferred(pn_message_t *msg, bool inferred)
-{
-  assert(msg);
-  msg->inferred = inferred;
-  return 0;
-}
-
-bool pn_message_is_durable(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->durable;
-}
-int pn_message_set_durable(pn_message_t *msg, bool durable)
-{
-  assert(msg);
-  msg->durable = durable;
-  return 0;
-}
-
-
-uint8_t pn_message_get_priority(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->priority;
-}
-int pn_message_set_priority(pn_message_t *msg, uint8_t priority)
-{
-  assert(msg);
-  msg->priority = priority;
-  return 0;
-}
-
-pn_millis_t pn_message_get_ttl(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->ttl;
-}
-int pn_message_set_ttl(pn_message_t *msg, pn_millis_t ttl)
-{
-  assert(msg);
-  msg->ttl = ttl;
-  return 0;
-}
-
-bool pn_message_is_first_acquirer(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->first_acquirer;
-}
-int pn_message_set_first_acquirer(pn_message_t *msg, bool first)
-{
-  assert(msg);
-  msg->first_acquirer = first;
-  return 0;
-}
-
-uint32_t pn_message_get_delivery_count(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->delivery_count;
-}
-int pn_message_set_delivery_count(pn_message_t *msg, uint32_t count)
-{
-  assert(msg);
-  msg->delivery_count = count;
-  return 0;
-}
-
-pn_data_t *pn_message_id(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->id;
-}
-pn_atom_t pn_message_get_id(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_data_get_atom(msg->id);
-}
-int pn_message_set_id(pn_message_t *msg, pn_atom_t id)
-{
-  assert(msg);
-  pn_data_rewind(msg->id);
-  return pn_data_put_atom(msg->id, id);
-}
-
-static pn_bytes_t pn_string_get_bytes(pn_string_t *string)
-{
-  return pn_bytes(pn_string_size(string), (char *) pn_string_get(string));
-}
-
-static int pn_string_set_bytes(pn_string_t *string, pn_bytes_t bytes)
-{
-  return pn_string_setn(string, bytes.start, bytes.size);
-}
-
-pn_bytes_t pn_message_get_user_id(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get_bytes(msg->user_id);
-}
-int pn_message_set_user_id(pn_message_t *msg, pn_bytes_t user_id)
-{
-  assert(msg);
-  return pn_string_set_bytes(msg->user_id, user_id);
-}
-
-const char *pn_message_get_address(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->address);
-}
-int pn_message_set_address(pn_message_t *msg, const char *address)
-{
-  assert(msg);
-  return pn_string_set(msg->address, address);
-}
-
-const char *pn_message_get_subject(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->subject);
-}
-int pn_message_set_subject(pn_message_t *msg, const char *subject)
-{
-  assert(msg);
-  return pn_string_set(msg->subject, subject);
-}
-
-const char *pn_message_get_reply_to(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->reply_to);
-}
-int pn_message_set_reply_to(pn_message_t *msg, const char *reply_to)
-{
-  assert(msg);
-  return pn_string_set(msg->reply_to, reply_to);
-}
-
-pn_data_t *pn_message_correlation_id(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->correlation_id;
-}
-pn_atom_t pn_message_get_correlation_id(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_data_get_atom(msg->correlation_id);
-}
-int pn_message_set_correlation_id(pn_message_t *msg, pn_atom_t atom)
-{
-  assert(msg);
-  pn_data_rewind(msg->correlation_id);
-  return pn_data_put_atom(msg->correlation_id, atom);
-}
-
-const char *pn_message_get_content_type(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->content_type);
-}
-int pn_message_set_content_type(pn_message_t *msg, const char *type)
-{
-  assert(msg);
-  return pn_string_set(msg->content_type, type);
-}
-
-const char *pn_message_get_content_encoding(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->content_encoding);
-}
-int pn_message_set_content_encoding(pn_message_t *msg, const char *encoding)
-{
-  assert(msg);
-  return pn_string_set(msg->content_encoding, encoding);
-}
-
-pn_timestamp_t pn_message_get_expiry_time(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->expiry_time;
-}
-int pn_message_set_expiry_time(pn_message_t *msg, pn_timestamp_t time)
-{
-  assert(msg);
-  msg->expiry_time = time;
-  return 0;
-}
-
-pn_timestamp_t pn_message_get_creation_time(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->creation_time;
-}
-int pn_message_set_creation_time(pn_message_t *msg, pn_timestamp_t time)
-{
-  assert(msg);
-  msg->creation_time = time;
-  return 0;
-}
-
-const char *pn_message_get_group_id(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->group_id);
-}
-int pn_message_set_group_id(pn_message_t *msg, const char *group_id)
-{
-  assert(msg);
-  return pn_string_set(msg->group_id, group_id);
-}
-
-pn_sequence_t pn_message_get_group_sequence(pn_message_t *msg)
-{
-  assert(msg);
-  return msg->group_sequence;
-}
-int pn_message_set_group_sequence(pn_message_t *msg, pn_sequence_t n)
-{
-  assert(msg);
-  msg->group_sequence = n;
-  return 0;
-}
-
-const char *pn_message_get_reply_to_group_id(pn_message_t *msg)
-{
-  assert(msg);
-  return pn_string_get(msg->reply_to_group_id);
-}
-int pn_message_set_reply_to_group_id(pn_message_t *msg, const char *reply_to_group_id)
-{
-  assert(msg);
-  return pn_string_set(msg->reply_to_group_id, reply_to_group_id);
-}
-
-int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size)
-{
-  assert(msg && bytes && size);
-
-  pn_message_clear(msg);
-
-  while (size) {
-    pn_data_clear(msg->data);
-    ssize_t used = pn_data_decode(msg->data, bytes, size);
-    if (used < 0)
-        return pn_error_format(msg->error, used, "data error: %s",
-                               pn_error_text(pn_data_error(msg->data)));
-    size -= used;
-    bytes += used;
-    bool scanned;
-    uint64_t desc;
-    int err = pn_data_scan(msg->data, "D?L.", &scanned, &desc);
-    if (err) return pn_error_format(msg->error, err, "data error: %s",
-                                    pn_error_text(pn_data_error(msg->data)));
-    if (!scanned) {
-      desc = 0;
-    }
-
-    pn_data_rewind(msg->data);
-    pn_data_next(msg->data);
-    pn_data_enter(msg->data);
-    pn_data_next(msg->data);
-
-    switch (desc) {
-    case HEADER:
-      err = pn_data_scan(msg->data, "D.[oBIoI]", &msg->durable, &msg->priority,
-                   &msg->ttl, &msg->first_acquirer, &msg->delivery_count);
-      if (err) return pn_error_format(msg->error, err, "data error: %s",
-                                      pn_error_text(pn_data_error(msg->data)));
-      break;
-    case PROPERTIES:
-      {
-        pn_bytes_t user_id, address, subject, reply_to, ctype, cencoding,
-          group_id, reply_to_group_id;
-        pn_data_clear(msg->id);
-        pn_data_clear(msg->correlation_id);
-        err = pn_data_scan(msg->data, "D.[CzSSSCssttSIS]", msg->id,
-                           &user_id, &address, &subject, &reply_to,
-                           msg->correlation_id, &ctype, &cencoding,
-                           &msg->expiry_time, &msg->creation_time, &group_id,
-                           &msg->group_sequence, &reply_to_group_id);
-        if (err) return pn_error_format(msg->error, err, "data error: %s",
-                                        pn_error_text(pn_data_error(msg->data)));
-        err = pn_string_set_bytes(msg->user_id, user_id);
-        if (err) return pn_error_format(msg->error, err, "error setting user_id");
-        err = pn_string_setn(msg->address, address.start, address.size);
-        if (err) return pn_error_format(msg->error, err, "error setting address");
-        err = pn_string_setn(msg->subject, subject.start, subject.size);
-        if (err) return pn_error_format(msg->error, err, "error setting subject");
-        err = pn_string_setn(msg->reply_to, reply_to.start, reply_to.size);
-        if (err) return pn_error_format(msg->error, err, "error setting reply_to");
-        err = pn_string_setn(msg->content_type, ctype.start, ctype.size);
-        if (err) return pn_error_format(msg->error, err, "error setting content_type");
-        err = pn_string_setn(msg->content_encoding, cencoding.start,
-                             cencoding.size);
-        if (err) return pn_error_format(msg->error, err, "error setting content_encoding");
-        err = pn_string_setn(msg->group_id, group_id.start, group_id.size);
-        if (err) return pn_error_format(msg->error, err, "error setting group_id");
-        err = pn_string_setn(msg->reply_to_group_id, reply_to_group_id.start,
-                             reply_to_group_id.size);
-        if (err) return pn_error_format(msg->error, err, "error setting reply_to_group_id");
-      }
-      break;
-    case DELIVERY_ANNOTATIONS:
-      pn_data_narrow(msg->data);
-      err = pn_data_copy(msg->instructions, msg->data);
-      if (err) return err;
-      break;
-    case MESSAGE_ANNOTATIONS:
-      pn_data_narrow(msg->data);
-      err = pn_data_copy(msg->annotations, msg->data);
-      if (err) return err;
-      break;
-    case APPLICATION_PROPERTIES:
-      pn_data_narrow(msg->data);
-      err = pn_data_copy(msg->properties, msg->data);
-      if (err) return err;
-      break;
-    case DATA:
-    case AMQP_SEQUENCE:
-    case AMQP_VALUE:
-      pn_data_narrow(msg->data);
-      err = pn_data_copy(msg->body, msg->data);
-      if (err) return err;
-      break;
-    case FOOTER:
-      break;
-    default:
-      err = pn_data_copy(msg->body, msg->data);
-      if (err) return err;
-      break;
-    }
-  }
-
-  pn_data_clear(msg->data);
-  return 0;
-}
-
-int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size)
-{
-  if (!msg || !bytes || !size || !*size) return PN_ARG_ERR;
-  pn_data_clear(msg->data);
-  pn_message_data(msg, msg->data);
-  size_t remaining = *size;
-  ssize_t encoded = pn_data_encode(msg->data, bytes, remaining);
-  if (encoded < 0) {
-    if (encoded == PN_OVERFLOW) {
-      return encoded;
-    } else {
-      return pn_error_format(msg->error, encoded, "data error: %s",
-                             pn_error_text(pn_data_error(msg->data)));
-    }
-  }
-  bytes += encoded;
-  remaining -= encoded;
-  *size -= remaining;
-  pn_data_clear(msg->data);
-  return 0;
-}
-
-int pn_message_data(pn_message_t *msg, pn_data_t *data)
-{
-  pn_data_clear(data);
-  int err = pn_data_fill(data, "DL[oB?IoI]", HEADER, msg->durable,
-                         msg->priority, msg->ttl, msg->ttl, msg->first_acquirer,
-                         msg->delivery_count);
-  if (err)
-    return pn_error_format(msg->error, err, "data error: %s",
-                           pn_error_text(pn_data_error(data)));
-
-  if (pn_data_size(msg->instructions)) {
-    pn_data_put_described(data);
-    pn_data_enter(data);
-    pn_data_put_ulong(data, DELIVERY_ANNOTATIONS);
-    pn_data_rewind(msg->instructions);
-    err = pn_data_append(data, msg->instructions);
-    if (err)
-      return pn_error_format(msg->error, err, "data error: %s",
-                             pn_error_text(pn_data_error(data)));
-    pn_data_exit(data);
-  }
-
-  if (pn_data_size(msg->annotations)) {
-    pn_data_put_described(data);
-    pn_data_enter(data);
-    pn_data_put_ulong(data, MESSAGE_ANNOTATIONS);
-    pn_data_rewind(msg->annotations);
-    err = pn_data_append(data, msg->annotations);
-    if (err)
-      return pn_error_format(msg->error, err, "data error: %s",
-                             pn_error_text(pn_data_error(data)));
-    pn_data_exit(data);
-  }
-
-  err = pn_data_fill(data, "DL[CzSSSCssttSIS]", PROPERTIES,
-                     msg->id,
-                     pn_string_size(msg->user_id), pn_string_get(msg->user_id),
-                     pn_string_get(msg->address),
-                     pn_string_get(msg->subject),
-                     pn_string_get(msg->reply_to),
-                     msg->correlation_id,
-                     pn_string_get(msg->content_type),
-                     pn_string_get(msg->content_encoding),
-                     msg->expiry_time,
-                     msg->creation_time,
-                     pn_string_get(msg->group_id),
-                     msg->group_sequence,
-                     pn_string_get(msg->reply_to_group_id));
-  if (err)
-    return pn_error_format(msg->error, err, "data error: %s",
-                           pn_error_text(pn_data_error(data)));
-
-  if (pn_data_size(msg->properties)) {
-    pn_data_put_described(data);
-    pn_data_enter(data);
-    pn_data_put_ulong(data, APPLICATION_PROPERTIES);
-    pn_data_rewind(msg->properties);
-    err = pn_data_append(data, msg->properties);
-    if (err)
-      return pn_error_format(msg->error, err, "data error: %s",
-                             pn_data_error(data));
-    pn_data_exit(data);
-  }
-
-  if (pn_data_size(msg->body)) {
-    pn_data_rewind(msg->body);
-    pn_data_next(msg->body);
-    pn_type_t body_type = pn_data_type(msg->body);
-    pn_data_rewind(msg->body);
-
-    pn_data_put_described(data);
-    pn_data_enter(data);
-    if (msg->inferred) {
-      switch (body_type) {
-      case PN_BINARY:
-        pn_data_put_ulong(data, DATA);
-        break;
-      case PN_LIST:
-        pn_data_put_ulong(data, AMQP_SEQUENCE);
-        break;
-      default:
-        pn_data_put_ulong(data, AMQP_VALUE);
-        break;
-      }
-    } else {
-      pn_data_put_ulong(data, AMQP_VALUE);
-    }
-    pn_data_append(data, msg->body);
-  }
-  return 0;
-}
-
-pn_data_t *pn_message_instructions(pn_message_t *msg)
-{
-  return msg ? msg->instructions : NULL;
-}
-
-pn_data_t *pn_message_annotations(pn_message_t *msg)
-{
-  return msg ? msg->annotations : NULL;
-}
-
-pn_data_t *pn_message_properties(pn_message_t *msg)
-{
-  return msg ? msg->properties : NULL;
-}
-
-pn_data_t *pn_message_body(pn_message_t *msg)
-{
-  return msg ? msg->body : NULL;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/messenger.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/messenger.c b/proton-c/src/messenger/messenger.c
index 64be017..264a733 100644
--- a/proton-c/src/messenger/messenger.c
+++ b/proton-c/src/messenger/messenger.c
@@ -27,7 +27,6 @@
 #include <proton/object.h>
 #include <proton/sasl.h>
 #include <proton/session.h>
-#include <proton/selector.h>
 
 #include <assert.h>
 #include <ctype.h>
@@ -35,14 +34,17 @@
 #include <string.h>
 #include <stdio.h>
 
-#include "util.h"
-#include "platform.h"
-#include "platform_fmt.h"
+#include "core/log_private.h"
+#include "core/util.h"
+#include "platform/platform.h" // pn_i_getpid, pn_i_now, pni_snprintf
+#include "platform/platform_fmt.h"
 #include "store.h"
-#include "transform.h"
 #include "subscription.h"
-#include "selectable.h"
-#include "log_private.h"
+#include "transform.h"
+
+#include "reactor/io.h"
+#include "reactor/selectable.h"
+#include "reactor/selector.h"
 
 typedef struct pn_link_ctx_t pn_link_ctx_t;
 
@@ -980,7 +982,7 @@ static void pn_condition_report(const char *pfx, pn_condition_t *condition)
             pn_condition_redirect_port(condition));
   } else if (pn_condition_is_set(condition)) {
     char error[1024];
-    snprintf(error, 1024, "(%s) %s",
+    pni_snprintf(error, 1024, "(%s) %s",
              pn_condition_get_name(condition),
              pn_condition_get_description(condition));
     pn_error_report(pfx, error);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/store.c
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/store.c b/proton-c/src/messenger/store.c
index bdd7e24..44f24f1 100644
--- a/proton-c/src/messenger/store.c
+++ b/proton-c/src/messenger/store.c
@@ -28,7 +28,7 @@
 #endif
 #include <stdlib.h>
 #include <string.h>
-#include "util.h"
+#include "core/util.h"
 #include "store.h"
 
 typedef struct pni_stream_t pni_stream_t;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/store.h
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/store.h b/proton-c/src/messenger/store.h
index 2ca243b..22bb94e 100644
--- a/proton-c/src/messenger/store.h
+++ b/proton-c/src/messenger/store.h
@@ -22,7 +22,7 @@
  *
  */
 
-#include "buffer.h"
+#include "core/buffer.h"
 
 typedef struct pni_store_t pni_store_t;
 typedef struct pni_entry_t pni_entry_t;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/messenger/transform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/messenger/transform.h b/proton-c/src/messenger/transform.h
index c9350ef..3288f6c 100644
--- a/proton-c/src/messenger/transform.h
+++ b/proton-c/src/messenger/transform.h
@@ -22,8 +22,9 @@
  *
  */
 
+#include "core/buffer.h"
+
 #include <proton/object.h>
-#include "buffer.h"
 
 typedef struct pn_transform_t pn_transform_t;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/iterator.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/iterator.c b/proton-c/src/object/iterator.c
deleted file mode 100644
index 61b3b8e..0000000
--- a/proton-c/src/object/iterator.c
+++ /dev/null
@@ -1,78 +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/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-struct pn_iterator_t {
-  pn_iterator_next_t next;
-  size_t size;
-  void *state;
-};
-
-static void pn_iterator_initialize(void *object)
-{
-  pn_iterator_t *it = (pn_iterator_t *) object;
-  it->next = NULL;
-  it->size = 0;
-  it->state = NULL;
-}
-
-static void pn_iterator_finalize(void *object)
-{
-  pn_iterator_t *it = (pn_iterator_t *) object;
-  free(it->state);
-}
-
-#define CID_pn_iterator CID_pn_object
-#define pn_iterator_hashcode NULL
-#define pn_iterator_compare NULL
-#define pn_iterator_inspect NULL
-
-pn_iterator_t *pn_iterator()
-{
-  static const pn_class_t clazz = PN_CLASS(pn_iterator);
-  pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t));
-  return it;
-}
-
-void  *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
-                         size_t size) {
-  assert(iterator);
-  assert(next);
-  iterator->next = next;
-  if (iterator->size < size) {
-    iterator->state = realloc(iterator->state, size);
-  }
-  return iterator->state;
-}
-
-void *pn_iterator_next(pn_iterator_t *iterator) {
-  assert(iterator);
-  if (iterator->next) {
-    void *result = iterator->next(iterator->state);
-    if (!result) iterator->next = NULL;
-    return result;
-  } else {
-    return NULL;
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/list.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/list.c b/proton-c/src/object/list.c
deleted file mode 100644
index 76c70d2..0000000
--- a/proton-c/src/object/list.c
+++ /dev/null
@@ -1,267 +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/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-struct pn_list_t {
-  const pn_class_t *clazz;
-  size_t capacity;
-  size_t size;
-  void **elements;
-};
-
-size_t pn_list_size(pn_list_t *list)
-{
-  assert(list);
-  return list->size;
-}
-
-void *pn_list_get(pn_list_t *list, int index)
-{
-  assert(list); assert(list->size);
-  return list->elements[index % list->size];
-}
-
-void pn_list_set(pn_list_t *list, int index, void *value)
-{
-  assert(list); assert(list->size);
-  void *old = list->elements[index % list->size];
-  pn_class_decref(list->clazz, old);
-  list->elements[index % list->size] = value;
-  pn_class_incref(list->clazz, value);
-}
-
-static void pni_list_ensure(pn_list_t *list, size_t capacity)
-{
-  assert(list);
-  if (list->capacity < capacity) {
-    size_t newcap = list->capacity;
-    while (newcap < capacity) { newcap *= 2; }
-    list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
-    assert(list->elements);
-    list->capacity = newcap;
-  }
-}
-
-int pn_list_add(pn_list_t *list, void *value)
-{
-  assert(list);
-  pni_list_ensure(list, list->size + 1);
-  list->elements[list->size++] = value;
-  pn_class_incref(list->clazz, value);
-  return 0;
-}
-
-void *pn_list_pop(pn_list_t *list)
-{
-  assert(list);
-  if (list->size) {
-    return list->elements[--list->size];
-  } else {
-    return NULL;
-  }
-}
-
-ssize_t pn_list_index(pn_list_t *list, void *value)
-{
-  for (size_t i = 0; i < list->size; i++) {
-    if (pn_class_equals(list->clazz, list->elements[i], value)) {
-      return i;
-    }
-  }
-
-  return -1;
-}
-
-bool pn_list_remove(pn_list_t *list, void *value)
-{
-  assert(list);
-  ssize_t idx = pn_list_index(list, value);
-  if (idx < 0) {
-    return false;
-  } else {
-    pn_list_del(list, idx, 1);
-  }
-
-  return true;
-}
-
-void pn_list_del(pn_list_t *list, int index, int n)
-{
-  assert(list);
-  if (!list->size) { return; }
-  index %= list->size;
-
-  for (int i = 0; i < n; i++) {
-    pn_class_decref(list->clazz, list->elements[index + i]);
-  }
-
-  size_t slide = list->size - (index + n);
-  for (size_t i = 0; i < slide; i++) {
-    list->elements[index + i] = list->elements[index + n + i];
-  }
-
-  list->size -= n;
-}
-
-void pn_list_clear(pn_list_t *list)
-{
-  assert(list);
-  pn_list_del(list, 0, list->size);
-}
-
-void pn_list_minpush(pn_list_t *list, void *value)
-{
-  assert(list);
-  pn_list_add(list, value);
-  // we use one based indexing for the heap
-  void **heap = list->elements - 1;
-  int now = list->size;
-  while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) {
-    heap[now] = heap[now/2];
-    now /= 2;
-  }
-  heap[now] = value;
-}
-
-void *pn_list_minpop(pn_list_t *list)
-{
-  assert(list);
-  // we use one based indexing for the heap
-  void **heap = list->elements - 1;
-  void *min = heap[1];
-  void *last = pn_list_pop(list);
-  int size = pn_list_size(list);
-  int now, child;
-  for (now = 1; now*2 <= size; now = child) {
-    child = now*2;
-    if (child != size && pn_class_compare(list->clazz, heap[child], heap[child + 1]) > 0) {
-      child++;
-    }
-    if (pn_class_compare(list->clazz, last, heap[child]) > 0) {
-      heap[now] = heap[child];
-    } else {
-      break;
-    }
-  }
-  heap[now] = last;
-  return min;
-}
-
-typedef struct {
-  pn_list_t *list;
-  size_t index;
-} pni_list_iter_t;
-
-static void *pni_list_next(void *ctx)
-{
-  pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
-  if (iter->index < pn_list_size(iter->list)) {
-    return pn_list_get(iter->list, iter->index++);
-  } else {
-    return NULL;
-  }
-}
-
-void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
-{
-  pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
-  liter->list = list;
-  liter->index = 0;
-}
-
-static void pn_list_finalize(void *object)
-{
-  assert(object);
-  pn_list_t *list = (pn_list_t *) object;
-  for (size_t i = 0; i < list->size; i++) {
-    pn_class_decref(list->clazz, pn_list_get(list, i));
-  }
-  free(list->elements);
-}
-
-static uintptr_t pn_list_hashcode(void *object)
-{
-  assert(object);
-  pn_list_t *list = (pn_list_t *) object;
-  uintptr_t hash = 1;
-
-  for (size_t i = 0; i < list->size; i++) {
-    hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
-  }
-
-  return hash;
-}
-
-static intptr_t pn_list_compare(void *oa, void *ob)
-{
-  assert(oa); assert(ob);
-  pn_list_t *a = (pn_list_t *) oa;
-  pn_list_t *b = (pn_list_t *) ob;
-
-  size_t na = pn_list_size(a);
-  size_t nb = pn_list_size(b);
-  if (na != nb) {
-    return nb - na;
-  } else {
-    for (size_t i = 0; i < na; i++) {
-      intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
-      if (delta) return delta;
-    }
-  }
-
-  return 0;
-}
-
-static int pn_list_inspect(void *obj, pn_string_t *dst)
-{
-  assert(obj);
-  pn_list_t *list = (pn_list_t *) obj;
-  int err = pn_string_addf(dst, "[");
-  if (err) return err;
-  size_t n = pn_list_size(list);
-  for (size_t i = 0; i < n; i++) {
-    if (i > 0) {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-    }
-    err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst);
-    if (err) return err;
-  }
-  return pn_string_addf(dst, "]");
-}
-
-#define pn_list_initialize NULL
-
-pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
-{
-  static const pn_class_t list_clazz = PN_CLASS(pn_list);
-
-  pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
-  list->clazz = clazz;
-  list->capacity = capacity ? capacity : 16;
-  list->elements = (void **) malloc(list->capacity * sizeof(void *));
-  list->size = 0;
-  return list;
-}
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/map.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/map.c b/proton-c/src/object/map.c
deleted file mode 100644
index cd38f19..0000000
--- a/proton-c/src/object/map.c
+++ /dev/null
@@ -1,461 +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/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define PNI_ENTRY_FREE (0)
-#define PNI_ENTRY_LINK (1)
-#define PNI_ENTRY_TAIL (2)
-
-typedef struct {
-  void *key;
-  void *value;
-  size_t next;
-  uint8_t state;
-} pni_entry_t;
-
-struct pn_map_t {
-  const pn_class_t *key;
-  const pn_class_t *value;
-  pni_entry_t *entries;
-  size_t capacity;
-  size_t addressable;
-  size_t size;
-  uintptr_t (*hashcode)(void *key);
-  bool (*equals)(void *a, void *b);
-  float load_factor;
-};
-
-static void pn_map_finalize(void *object)
-{
-  pn_map_t *map = (pn_map_t *) object;
-
-  for (size_t i = 0; i < map->capacity; i++) {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      pn_class_decref(map->key, map->entries[i].key);
-      pn_class_decref(map->value, map->entries[i].value);
-    }
-  }
-
-  free(map->entries);
-}
-
-static uintptr_t pn_map_hashcode(void *object)
-{
-  pn_map_t *map = (pn_map_t *) object;
-
-  uintptr_t hashcode = 0;
-
-  for (size_t i = 0; i < map->capacity; i++) {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      void *key = map->entries[i].key;
-      void *value = map->entries[i].value;
-      hashcode += pn_hashcode(key) ^ pn_hashcode(value);
-    }
-  }
-
-  return hashcode;
-}
-
-static void pni_map_allocate(pn_map_t *map)
-{
-  map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
-  if (map->entries != NULL) {
-    for (size_t i = 0; i < map->capacity; i++) {
-      map->entries[i].key = NULL;
-      map->entries[i].value = NULL;
-      map->entries[i].next = 0;
-      map->entries[i].state = PNI_ENTRY_FREE;
-    }
-  }
-  map->size = 0;
-}
-
-static int pn_map_inspect(void *obj, pn_string_t *dst)
-{
-  assert(obj);
-  pn_map_t *map = (pn_map_t *) obj;
-  int err = pn_string_addf(dst, "{");
-  if (err) return err;
-  pn_handle_t entry = pn_map_head(map);
-  bool first = true;
-  while (entry) {
-    if (first) {
-      first = false;
-    } else {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-    }
-    err = pn_class_inspect(map->key, pn_map_key(map, entry), dst);
-    if (err) return err;
-    err = pn_string_addf(dst, ": ");
-    if (err) return err;
-    err = pn_class_inspect(map->value, pn_map_value(map, entry), dst);
-    if (err) return err;
-    entry = pn_map_next(map, entry);
-  }
-  return pn_string_addf(dst, "}");
-}
-
-#define pn_map_initialize NULL
-#define pn_map_compare NULL
-
-pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
-                 size_t capacity, float load_factor)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_map);
-
-  pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t));
-  map->key = key;
-  map->value = value;
-  map->capacity = capacity ? capacity : 16;
-  map->addressable = (size_t) (map->capacity * 0.86);
-  if (!map->addressable) map->addressable = map->capacity;
-  map->load_factor = load_factor;
-  map->hashcode = pn_hashcode;
-  map->equals = pn_equals;
-  pni_map_allocate(map);
-  return map;
-}
-
-size_t pn_map_size(pn_map_t *map)
-{
-  assert(map);
-  return map->size;
-}
-
-static float pni_map_load(pn_map_t *map)
-{
-  return ((float) map->size) / ((float) map->addressable);
-}
-
-static bool pni_map_ensure(pn_map_t *map, size_t capacity)
-{
-  float load = pni_map_load(map);
-  if (capacity <= map->capacity && load <= map->load_factor) {
-    return false;
-  }
-
-  size_t oldcap = map->capacity;
-
-  while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
-    map->capacity *= 2;
-    map->addressable = (size_t) (0.86 * map->capacity);
-  }
-
-  pni_entry_t *entries = map->entries;
-  pni_map_allocate(map);
-
-  for (size_t i = 0; i < oldcap; i++) {
-    if (entries[i].state != PNI_ENTRY_FREE) {
-      void *key = entries[i].key;
-      void *value = entries[i].value;
-      pn_map_put(map, key, value);
-    }
-  }
-
-  for (size_t i = 0; i < oldcap; i++) {
-    if (entries[i].state != PNI_ENTRY_FREE) {
-      void *key = entries[i].key;
-      void *value = entries[i].value;
-      pn_class_decref(map->key, key);
-      pn_class_decref(map->value, value);
-    }
-  }
-
-  free(entries);
-  return true;
-}
-
-static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
-{
-  uintptr_t hashcode = map->hashcode(key);
-
-  pni_entry_t *entry = &map->entries[hashcode % map->addressable];
-  pni_entry_t *prev = NULL;
-
-  if (entry->state == PNI_ENTRY_FREE) {
-    if (create) {
-      entry->state = PNI_ENTRY_TAIL;
-      entry->key = key;
-      pn_class_incref(map->key, key);
-      map->size++;
-      return entry;
-    } else {
-      return NULL;
-    }
-  }
-
-  while (true) {
-    if (map->equals(entry->key, key)) {
-      if (pprev) *pprev = prev;
-      return entry;
-    }
-
-    if (entry->state == PNI_ENTRY_TAIL) {
-      break;
-    } else {
-      prev = entry;
-      entry = &map->entries[entry->next];
-    }
-  }
-
-  if (create) {
-    if (pni_map_ensure(map, map->size + 1)) {
-      // if we had to grow the table we need to start over
-      return pni_map_entry(map, key, pprev, create);
-    }
-
-    size_t empty = 0;
-    for (size_t i = 0; i < map->capacity; i++) {
-      size_t idx = map->capacity - i - 1;
-      if (map->entries[idx].state == PNI_ENTRY_FREE) {
-        empty = idx;
-        break;
-      }
-    }
-    entry->next = empty;
-    entry->state = PNI_ENTRY_LINK;
-    map->entries[empty].state = PNI_ENTRY_TAIL;
-    map->entries[empty].key = key;
-    pn_class_incref(map->key, key);
-    if (pprev) *pprev = entry;
-    map->size++;
-    return &map->entries[empty];
-  } else {
-    return NULL;
-  }
-}
-
-int pn_map_put(pn_map_t *map, void *key, void *value)
-{
-  assert(map);
-  pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
-  void *dref_val = entry->value;
-  entry->value = value;
-  pn_class_incref(map->value, value);
-  pn_class_decref(map->value, dref_val);
-  return 0;
-}
-
-void *pn_map_get(pn_map_t *map, void *key)
-{
-  assert(map);
-  pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
-  return entry ? entry->value : NULL;
-}
-
-static void pni_map_rehash(pn_map_t *map, size_t index)
-{
-  //reinsert entries in chain starting at index
-  assert(map);
-  size_t i = index;
-  bool complete = false;
-  while (!complete) {
-    pni_entry_t *entry = &map->entries[i];
-    assert(entry);
-    assert(entry->state != PNI_ENTRY_FREE);
-    size_t current = i;
-    if (entry->state == PNI_ENTRY_TAIL) {
-      complete = true;
-    } else {
-      assert(entry->state == PNI_ENTRY_LINK);
-      i = entry->next;
-    }
-    uintptr_t hashcode = map->hashcode(entry->key);
-    pni_entry_t *reloc = &map->entries[hashcode % map->addressable];
-    if (reloc->state == PNI_ENTRY_FREE) {
-      //correct addressable slot is available, copy into that...
-      reloc->state = PNI_ENTRY_TAIL;
-      reloc->key = entry->key;
-      reloc->value = entry->value;
-      //...then free the current entry
-      entry->key = NULL;
-      entry->value = NULL;
-      entry->state = PNI_ENTRY_FREE;
-      entry->next = 0;
-    } else {
-      //iterate to end of chain...
-      while (reloc->state == PNI_ENTRY_LINK) {
-        reloc = &map->entries[reloc->next];
-      }
-      assert(reloc->state == PNI_ENTRY_TAIL);
-      //... and append current entry
-      reloc->state = PNI_ENTRY_LINK;
-      reloc->next = current;
-      entry->state = PNI_ENTRY_TAIL;
-      entry->next = 0;
-    }
-  }
-}
-
-void pn_map_del(pn_map_t *map, void *key)
-{
-  assert(map);
-  pni_entry_t *prev = NULL;
-  pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
-  if (entry) {
-    uint8_t orig_state = entry->state;
-    size_t orig_next = entry->next;
-
-    void *dref_key = entry->key;
-    void *dref_value = entry->value;
-    if (prev) {
-      prev->next = 0;
-      prev->state = PNI_ENTRY_TAIL;
-    }
-    entry->state = PNI_ENTRY_FREE;
-    entry->next = 0;
-    entry->key = NULL;
-    entry->value = NULL;
-    map->size--;
-
-    if (orig_state == PNI_ENTRY_LINK) {
-      pni_map_rehash(map, orig_next);
-    }
-
-    // do this last as it may trigger further deletions
-    pn_class_decref(map->key, dref_key);
-    pn_class_decref(map->value, dref_value);
-  }
-}
-
-pn_handle_t pn_map_head(pn_map_t *map)
-{
-  assert(map);
-  for (size_t i = 0; i < map->capacity; i++)
-  {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      return (pn_handle_t)(i + 1);
-    }
-  }
-
-  return 0;
-}
-
-pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
-{
-  for (size_t i = (size_t)entry; i < map->capacity; i++) {
-    if (map->entries[i].state != PNI_ENTRY_FREE) {
-      return (pn_handle_t)(i + 1);
-    }
-  }
-
-  return 0;
-}
-
-void *pn_map_key(pn_map_t *map, pn_handle_t entry)
-{
-  assert(map);
-  assert(entry);
-  return map->entries[(size_t)entry - 1].key;
-}
-
-void *pn_map_value(pn_map_t *map, pn_handle_t entry)
-{
-  assert(map);
-  assert(entry);
-  return map->entries[(size_t)entry - 1].value;
-}
-
-struct pn_hash_t {
-  pn_map_t map;
-};
-
-static uintptr_t pni_identity_hashcode(void *obj)
-{
-  return (uintptr_t ) obj;
-}
-
-static bool pni_identity_equals(void *a, void *b)
-{
-  return a == b;
-}
-
-#define CID_pni_uintptr CID_pn_void
-static const pn_class_t *pni_uintptr_reify(void *object);
-#define pni_uintptr_new NULL
-#define pni_uintptr_free NULL
-#define pni_uintptr_initialize NULL
-static void pni_uintptr_incref(void *object) {}
-static void pni_uintptr_decref(void *object) {}
-static int pni_uintptr_refcount(void *object) { return -1; }
-#define pni_uintptr_finalize NULL
-#define pni_uintptr_hashcode NULL
-#define pni_uintptr_compare NULL
-#define pni_uintptr_inspect NULL
-
-static const pn_class_t PN_UINTPTR[] = {PN_METACLASS(pni_uintptr)};
-
-static const pn_class_t *pni_uintptr_reify(void *object)
-{
-  return PN_UINTPTR;
-}
-
-pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor)
-{
-  pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor);
-  hash->map.hashcode = pni_identity_hashcode;
-  hash->map.equals = pni_identity_equals;
-  return hash;
-}
-
-size_t pn_hash_size(pn_hash_t *hash)
-{
-  return pn_map_size(&hash->map);
-}
-
-int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
-{
-  return pn_map_put(&hash->map, (void *) key, value);
-}
-
-void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
-{
-  return pn_map_get(&hash->map, (void *) key);
-}
-
-void pn_hash_del(pn_hash_t *hash, uintptr_t key)
-{
-  pn_map_del(&hash->map, (void *) key);
-}
-
-pn_handle_t pn_hash_head(pn_hash_t *hash)
-{
-  return pn_map_head(&hash->map);
-}
-
-pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
-{
-  return pn_map_next(&hash->map, entry);
-}
-
-uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
-{
-  return (uintptr_t) pn_map_key(&hash->map, entry);
-}
-
-void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
-{
-  return pn_map_value(&hash->map, entry);
-}


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


[06/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/selectable.h b/proton-c/src/reactor/selectable.h
new file mode 100644
index 0000000..7a5b80b
--- /dev/null
+++ b/proton-c/src/reactor/selectable.h
@@ -0,0 +1,36 @@
+#ifndef _PROTON_SRC_SELECTABLE_H
+#define _PROTON_SRC_SELECTABLE_H 1
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include <proton/selectable.h>
+
+void *pni_selectable_get_context(pn_selectable_t *selectable);
+void pni_selectable_set_context(pn_selectable_t *selectable, void *context);
+int pni_selectable_get_index(pn_selectable_t *selectable);
+void pni_selectable_set_index(pn_selectable_t *selectable, int index);
+
+#endif /* selectable.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/selector.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/selector.h b/proton-c/src/reactor/selector.h
new file mode 100644
index 0000000..2a1e31f
--- /dev/null
+++ b/proton-c/src/reactor/selector.h
@@ -0,0 +1,53 @@
+#ifndef PROTON_SELECTOR_H
+#define PROTON_SELECTOR_H 1
+
+/*
+ *
+ * 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/selectable.h>
+#include <proton/type_compat.h>
+
+#define PN_READABLE (1)
+#define PN_WRITABLE (2)
+#define PN_EXPIRED (4)
+#define PN_ERROR (8)
+
+/**
+ * A ::pn_selector_t provides a selection mechanism that allows
+ * efficient monitoring of a large number of Proton connections and
+ * listeners.
+ *
+ * External (non-Proton) sockets may also be monitored, either solely
+ * for event notification (read, write, and timer) or event
+ * notification and use with pn_io_t interfaces.
+ */
+typedef struct pn_selector_t pn_selector_t;
+
+pn_selector_t *pni_selector(void);
+void pn_selector_free(pn_selector_t *selector);
+void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable);
+void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable);
+void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable);
+size_t pn_selector_size(pn_selector_t *selector);
+int pn_selector_select(pn_selector_t *select, int timeout);
+pn_selectable_t *pn_selector_next(pn_selector_t *select, int *events);
+
+#endif /* selector.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/cyrus_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/cyrus_sasl.c b/proton-c/src/sasl/cyrus_sasl.c
index dfc13d0..0d81489 100644
--- a/proton-c/src/sasl/cyrus_sasl.c
+++ b/proton-c/src/sasl/cyrus_sasl.c
@@ -19,10 +19,10 @@
  *
  */
 
-#include "config.h"
+#include "core/config.h"
+#include "core/engine-internal.h"
 #include "sasl-internal.h"
 
-#include "engine/engine-internal.h"
 
 #include <sasl/sasl.h>
 #include <pthread.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/none_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/none_sasl.c b/proton-c/src/sasl/none_sasl.c
index d1ee67f..0408a8f 100644
--- a/proton-c/src/sasl/none_sasl.c
+++ b/proton-c/src/sasl/none_sasl.c
@@ -21,7 +21,7 @@
 
 #include "sasl-internal.h"
 
-#include "engine/engine-internal.h"
+#include "core/engine-internal.h"
 
 static const char ANONYMOUS[] = "ANONYMOUS";
 static const char EXTERNAL[] = "EXTERNAL";

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl-internal.h b/proton-c/src/sasl/sasl-internal.h
index 063cd0d..2873777 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -22,11 +22,12 @@
 #ifndef PROTON_SASL_INTERNAL_H
 #define PROTON_SASL_INTERNAL_H 1
 
-#include "buffer.h"
+#include "core/buffer.h"
+#include "core/engine-internal.h"
+
 #include "proton/types.h"
 #include "proton/sasl.h"
 
-#include "engine/engine-internal.h"
 
 // SASL APIs used by transport code
 void pn_sasl_free(pn_transport_t *transport);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 47dc76c..c917d58 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -21,13 +21,14 @@
 
 #include "sasl-internal.h"
 
-#include "dispatch_actions.h"
-#include "engine/engine-internal.h"
+#include "core/autodetect.h"
+#include "core/dispatch_actions.h"
+#include "core/engine-internal.h"
+#include "core/util.h"
 #include "protocol.h"
+
 #include "proton/ssl.h"
 #include "proton/types.h"
-#include "util.h"
-#include "transport/autodetect.h"
 
 #include <assert.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/scanner.c
----------------------------------------------------------------------
diff --git a/proton-c/src/scanner.c b/proton-c/src/scanner.c
deleted file mode 100644
index 9a058e9..0000000
--- a/proton-c/src/scanner.c
+++ /dev/null
@@ -1,397 +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/scanner.h>
-#include <proton/error.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "platform.h"
-
-#define ERROR_SIZE (1024)
-
-struct pn_scanner_t {
-  const char *input;
-  const char *position;
-  pn_token_t token;
-  char *atoms;
-  size_t size;
-  size_t capacity;
-  pn_error_t *error;
-};
-
-static const char *pni_token_type(pn_token_type_t type)
-{
-  switch (type)
-  {
-  case PN_TOK_LBRACE: return "LBRACE";
-  case PN_TOK_RBRACE: return "RBRACE";
-  case PN_TOK_LBRACKET: return "LBRACKET";
-  case PN_TOK_RBRACKET: return "RBRACKET";
-  case PN_TOK_EQUAL: return "EQUAL";
-  case PN_TOK_COMMA: return "COMMA";
-  case PN_TOK_POS: return "POS";
-  case PN_TOK_NEG: return "NEG";
-  case PN_TOK_DOT: return "DOT";
-  case PN_TOK_AT: return "AT";
-  case PN_TOK_DOLLAR: return "DOLLAR";
-  case PN_TOK_BINARY: return "BINARY";
-  case PN_TOK_STRING: return "STRING";
-  case PN_TOK_SYMBOL: return "SYMBOL";
-  case PN_TOK_ID: return "ID";
-  case PN_TOK_FLOAT: return "FLOAT";
-  case PN_TOK_INT: return "INT";
-  case PN_TOK_TRUE: return "TRUE";
-  case PN_TOK_FALSE: return "FALSE";
-  case PN_TOK_NULL: return "NULL";
-  case PN_TOK_EOS: return "EOS";
-  case PN_TOK_ERR: return "ERR";
-  default: return "<UNKNOWN>";
-  }
-}
-
-pn_scanner_t *pn_scanner()
-{
-  pn_scanner_t *scanner = (pn_scanner_t *) malloc(sizeof(pn_scanner_t));
-  if (scanner) {
-    scanner->input = NULL;
-    scanner->error = pn_error();
-  }
-  return scanner;
-}
-
-void pn_scanner_free(pn_scanner_t *scanner)
-{
-  if (scanner) {
-    pn_error_free(scanner->error);
-    free(scanner);
-  }
-}
-
-pn_token_t pn_scanner_token(pn_scanner_t *scanner)
-{
-  if (scanner) {
-    return scanner->token;
-  } else {
-    pn_token_t tok = {PN_TOK_ERR, 0, (size_t)0};
-    return tok;
-  }
-}
-
-void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col)
-{
-  *line = 1;
-  *col = 0;
-
-  for (const char *c = scanner->input; *c && c <= scanner->token.start; c++) {
-    if (*c == '\n') {
-      *line += 1;
-      *col = -1;
-    } else {
-      *col += 1;
-    }
-  }
-}
-
-int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  int err = pn_scanner_verr(scanner, code, fmt, ap);
-  va_end(ap);
-  return err;
-}
-
-int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap)
-{
-  char error[ERROR_SIZE];
-
-  int line, col;
-  pn_scanner_line_info(scanner, &line, &col);
-  int size = scanner->token.size;
-  int ln = snprintf(error, ERROR_SIZE,
-                    "input line %i column %i %s:'%.*s': ", line, col,
-                    pni_token_type(scanner->token.type),
-                    size, scanner->token.start);
-  if (ln >= ERROR_SIZE) {
-    return pn_scanner_err(scanner, code, "error info truncated");
-  } else if (ln < 0) {
-    error[0] = '\0';
-  }
-
-  int n = snprintf(error + ln, ERROR_SIZE - ln, fmt, ap);
-
-  if (n >= ERROR_SIZE - ln) {
-    return pn_scanner_err(scanner, code, "error info truncated");
-  } else if (n < 0) {
-    error[0] = '\0';
-  }
-
-  return pn_error_set(scanner->error, code, error);
-}
-
-int pn_scanner_errno(pn_scanner_t *scanner)
-{
-  return pn_error_code(scanner->error);
-}
-
-const char *pn_scanner_error(pn_scanner_t *scanner)
-{
-  return pn_error_text(scanner->error);
-}
-
-static void pni_scanner_emit(pn_scanner_t *scanner, pn_token_type_t type, const char *start, size_t size)
-{
-  scanner->token.type = type;
-  scanner->token.start = start;
-  scanner->token.size = size;
-}
-
-static int pni_scanner_quoted(pn_scanner_t *scanner, const char *str, int start,
-                      pn_token_type_t type)
-{
-  bool escape = false;
-
-  for (int i = start; true; i++) {
-    char c = str[i];
-    if (escape) {
-      escape = false;
-    } else {
-      switch (c) {
-      case '\0':
-      case '"':
-        pni_scanner_emit(scanner, c ? type : PN_TOK_ERR,
-                        str, c ? i + 1 : i);
-        return c ? 0 : pn_scanner_err(scanner, PN_ERR, "missmatched quote");
-      case '\\':
-        escape = true;
-        break;
-      }
-    }
-  }
-}
-
-static int pni_scanner_binary(pn_scanner_t *scanner, const char *str)
-{
-  return pni_scanner_quoted(scanner, str, 2, PN_TOK_BINARY);
-}
-
-static int pni_scanner_string(pn_scanner_t *scanner, const char *str)
-{
-  return pni_scanner_quoted(scanner, str, 1, PN_TOK_STRING);
-}
-
-static int pni_scanner_alpha_end(pn_scanner_t *scanner, const char *str, int start)
-{
-  for (int i = start; true; i++) {
-    char c = str[i];
-    if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
-      return i;
-    }
-  }
-}
-
-static int pni_scanner_alpha(pn_scanner_t *scanner, const char *str)
-{
-  int n = pni_scanner_alpha_end(scanner, str, 0);
-  pn_token_type_t type;
-  if (!strncmp(str, "true", n)) {
-    type = PN_TOK_TRUE;
-  } else if (!strncmp(str, "false", n)) {
-    type = PN_TOK_FALSE;
-  } else if (!strncmp(str, "null", n)) {
-    type = PN_TOK_NULL;
-  } else {
-    type = PN_TOK_ID;
-  }
-
-  pni_scanner_emit(scanner, type, str, n);
-  return 0;
-}
-
-static int pni_scanner_symbol(pn_scanner_t *scanner, const char *str)
-{
-  char c = str[1];
-
-  if (c == '"') {
-    return pni_scanner_quoted(scanner, str, 2, PN_TOK_SYMBOL);
-  } else {
-    int n = pni_scanner_alpha_end(scanner, str, 1);
-    pni_scanner_emit(scanner, PN_TOK_SYMBOL, str, n);
-    return 0;
-  }
-}
-
-static int pni_scanner_number(pn_scanner_t *scanner, const char *str)
-{
-  bool dot = false;
-  bool exp = false;
-
-  int i = 0;
-
-  if (str[i] == '+' || str[i] == '-') {
-    i++;
-  }
-
-  for ( ; true; i++) {
-    char c = str[i];
-    switch (c) {
-    case '0': case '1': case '2': case '3': case '4': case '5': case '6':
-    case '7': case '8': case '9':
-      continue;
-    case '.':
-      if (dot) {
-        pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
-        return 0;
-      } else {
-        dot = true;
-      }
-      continue;
-    case 'e':
-    case 'E':
-      if (exp) {
-        pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
-        return 0;
-      } else {
-        dot = true;
-        exp = true;
-        if (str[i+1] == '+' || str[i+1] == '-') {
-          i++;
-        }
-        continue;
-      }
-    default:
-      if (dot || exp) {
-        pni_scanner_emit(scanner, PN_TOK_FLOAT, str, i);
-        return 0;
-      } else {
-        pni_scanner_emit(scanner, PN_TOK_INT, str, i);
-        return 0;
-      }
-    }
-  }
-}
-
-static int pni_scanner_single(pn_scanner_t *scanner, const char *str, pn_token_type_t type)
-{
-  pni_scanner_emit(scanner, type, str, 1);
-  return 0;
-}
-
-int pn_scanner_start(pn_scanner_t *scanner, const char *input)
-{
-  if (!scanner || !input) return PN_ARG_ERR;
-  scanner->input = input;
-  scanner->position = input;
-  return pn_scanner_scan(scanner);
-}
-
-int pn_scanner_scan(pn_scanner_t *scanner)
-{
-  const char *str = scanner->position;
-  char n;
-
-  for (char c; true; str++) {
-    c = *str;
-    switch (c)
-    {
-    case '{':
-      return pni_scanner_single(scanner, str, PN_TOK_LBRACE);
-    case '}':
-      return pni_scanner_single(scanner, str, PN_TOK_RBRACE);
-    case'[':
-      return pni_scanner_single(scanner, str, PN_TOK_LBRACKET);
-    case ']':
-      return pni_scanner_single(scanner, str, PN_TOK_RBRACKET);
-    case '=':
-      return pni_scanner_single(scanner, str, PN_TOK_EQUAL);
-    case ',':
-      return pni_scanner_single(scanner, str, PN_TOK_COMMA);
-    case '.':
-      n = *(str+1);
-      if ((n >= '0' && n <= '9')) {
-        return pni_scanner_number(scanner, str);
-      } else {
-        return pni_scanner_single(scanner, str, PN_TOK_DOT);
-      }
-    case '@':
-      return pni_scanner_single(scanner, str, PN_TOK_AT);
-    case '$':
-      return pni_scanner_single(scanner, str, PN_TOK_DOLLAR);
-    case '-':
-      n = *(str+1);
-      if ((n >= '0' && n <= '9') || n == '.') {
-        return pni_scanner_number(scanner, str);
-      } else {
-        return pni_scanner_single(scanner, str, PN_TOK_NEG);
-      }
-    case '+':
-      n = *(str+1);
-      if ((n >= '0' && n <= '9') || n == '.') {
-        return pni_scanner_number(scanner, str);
-      } else {
-        return pni_scanner_single(scanner, str, PN_TOK_POS);
-      }
-    case ' ': case '\t': case '\r': case '\v': case '\f': case '\n':
-      break;
-    case '0': case '1': case '2': case '3': case '4': case '5': case '6':
-    case '7': case '8': case '9':
-      return pni_scanner_number(scanner, str);
-    case ':':
-      return pni_scanner_symbol(scanner, str);
-    case '"':
-      return pni_scanner_string(scanner, str);
-    case 'b':
-      if (str[1] == '"') {
-        return pni_scanner_binary(scanner, str);
-      }
-    case 'a': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
-    case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o':
-    case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v':
-    case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C':
-    case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
-    case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q':
-    case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
-    case 'Y': case 'Z':
-      return pni_scanner_alpha(scanner, str);
-    case '\0':
-      pni_scanner_emit(scanner, PN_TOK_EOS, str, 0);
-      return PN_EOS;
-    default:
-      pni_scanner_emit(scanner, PN_TOK_ERR, str, 1);
-      return pn_scanner_err(scanner, PN_ERR, "illegal character");
-    }
-  }
-}
-
-int pn_scanner_shift(pn_scanner_t *scanner)
-{
-  scanner->position = scanner->token.start + scanner->token.size;
-  int err = pn_scanner_scan(scanner);
-  if (err == PN_EOS) {
-    return 0;
-  } else {
-    return err;
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/selectable.c
----------------------------------------------------------------------
diff --git a/proton-c/src/selectable.c b/proton-c/src/selectable.c
deleted file mode 100644
index 88a60f7..0000000
--- a/proton-c/src/selectable.c
+++ /dev/null
@@ -1,297 +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/error.h>
-#include <proton/io.h>
-#include "selectable.h"
-#include <stdlib.h>
-#include <assert.h>
-
-pn_selectables_t *pn_selectables(void)
-{
-  return pn_iterator();
-}
-
-pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables)
-{
-  return (pn_selectable_t *) pn_iterator_next(selectables);
-}
-
-void pn_selectables_free(pn_selectables_t *selectables)
-{
-  pn_free(selectables);
-}
-
-struct pn_selectable_t {
-  pn_socket_t fd;
-  int index;
-  pn_record_t *attachments;
-  void (*readable)(pn_selectable_t *);
-  void (*writable)(pn_selectable_t *);
-  void (*error)(pn_selectable_t *);
-  void (*expired)(pn_selectable_t *);
-  void (*release) (pn_selectable_t *);
-  void (*finalize)(pn_selectable_t *);
-  pn_collector_t *collector;
-  pn_timestamp_t deadline;
-  bool reading;
-  bool writing;
-  bool registered;
-  bool terminal;
-};
-
-void pn_selectable_initialize(pn_selectable_t *sel)
-{
-  sel->fd = PN_INVALID_SOCKET;
-  sel->index = -1;
-  sel->attachments = pn_record();
-  sel->readable = NULL;
-  sel->writable = NULL;
-  sel->error = NULL;
-  sel->expired = NULL;
-  sel->release = NULL;
-  sel->finalize = NULL;
-  sel->collector = NULL;
-  sel->deadline = 0;
-  sel->reading = false;
-  sel->writing = false;
-  sel->registered = false;
-  sel->terminal = false;
-}
-
-void pn_selectable_finalize(pn_selectable_t *sel)
-{
-  if (sel->finalize) {
-    sel->finalize(sel);
-  }
-  pn_decref(sel->attachments);
-  pn_decref(sel->collector);
-}
-
-#define pn_selectable_hashcode NULL
-#define pn_selectable_inspect NULL
-#define pn_selectable_compare NULL
-
-PN_CLASSDEF(pn_selectable)
-
-pn_selectable_t *pn_selectable(void)
-{
-  return pn_selectable_new();
-}
-
-bool pn_selectable_is_reading(pn_selectable_t *sel) {
-  assert(sel);
-  return sel->reading;
-}
-
-void pn_selectable_set_reading(pn_selectable_t *sel, bool reading) {
-  assert(sel);
-  sel->reading = reading;
-}
-
-bool pn_selectable_is_writing(pn_selectable_t *sel) {
-  assert(sel);
-  return sel->writing;
-}
-
-void pn_selectable_set_writing(pn_selectable_t *sel, bool writing) {
-  assert(sel);
-  sel->writing = writing;
-}
-
-pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *sel) {
-  assert(sel);
-  return sel->deadline;
-}
-
-void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline) {
-  assert(sel);
-  sel->deadline = deadline;
-}
-
-void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *)) {
-  assert(sel);
-  sel->readable = readable;
-}
-
-void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *)) {
-  assert(sel);
-  sel->writable = writable;
-}
-
-void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *)) {
-  assert(sel);
-  sel->error = error;
-}
-
-void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *)) {
-  assert(sel);
-  sel->expired = expired;
-}
-
-void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *)) {
-  assert(sel);
-  sel->release = release;
-}
-
-void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *)) {
-  assert(sel);
-  sel->finalize = finalize;
-}
-
-pn_record_t *pn_selectable_attachments(pn_selectable_t *sel) {
-  return sel->attachments;
-}
-
-void *pni_selectable_get_context(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  return pn_record_get(selectable->attachments, PN_LEGCTX);
-}
-
-void pni_selectable_set_context(pn_selectable_t *selectable, void *context)
-{
-  assert(selectable);
-  pn_record_set(selectable->attachments, PN_LEGCTX, context);
-}
-
-int pni_selectable_get_index(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  return selectable->index;
-}
-
-void pni_selectable_set_index(pn_selectable_t *selectable, int index)
-{
-  assert(selectable);
-  selectable->index = index;
-}
-
-pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  return selectable->fd;
-}
-
-void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd)
-{
-  assert(selectable);
-  selectable->fd = fd;
-}
-
-void pn_selectable_readable(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  if (selectable->readable) {
-    selectable->readable(selectable);
-  }
-}
-
-void pn_selectable_writable(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  if (selectable->writable) {
-    selectable->writable(selectable);
-  }
-}
-
-void pn_selectable_error(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  if (selectable->error) {
-    selectable->error(selectable);
-  }
-}
-
-void pn_selectable_expired(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  if (selectable->expired) {
-    selectable->expired(selectable);
-  }
-}
-
-bool pn_selectable_is_registered(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  return selectable->registered;
-}
-
-void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered)
-{
-  assert(selectable);
-  selectable->registered = registered;
-}
-
-bool pn_selectable_is_terminal(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  return selectable->terminal;
-}
-
-void pn_selectable_terminate(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  selectable->terminal = true;
-}
-
-void pn_selectable_release(pn_selectable_t *selectable)
-{
-  assert(selectable);
-  if (selectable->release) {
-    selectable->release(selectable);
-  }
-}
-
-void pn_selectable_free(pn_selectable_t *selectable)
-{
-  pn_decref(selectable);
-}
-
-static void pni_readable(pn_selectable_t *selectable) {
-  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_READABLE);
-}
-
-static void pni_writable(pn_selectable_t *selectable) {
-  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_WRITABLE);
-}
-
-static void pni_error(pn_selectable_t *selectable) {
-  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_ERROR);
-}
-
-static void pni_expired(pn_selectable_t *selectable) {
-  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_EXPIRED);
-}
-
-void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector) {
-  assert(selectable);
-  pn_decref(selectable->collector);
-  selectable->collector = collector;
-  pn_incref(selectable->collector);
-
-  if (collector) {
-    pn_selectable_on_readable(selectable, pni_readable);
-    pn_selectable_on_writable(selectable, pni_writable);
-    pn_selectable_on_error(selectable, pni_error);
-    pn_selectable_on_expired(selectable, pni_expired);
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/src/selectable.h b/proton-c/src/selectable.h
deleted file mode 100644
index 7a5b80b..0000000
--- a/proton-c/src/selectable.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _PROTON_SRC_SELECTABLE_H
-#define _PROTON_SRC_SELECTABLE_H 1
-
-/*
- *
- * 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.
- *
- */
-
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-#include <proton/selectable.h>
-
-void *pni_selectable_get_context(pn_selectable_t *selectable);
-void pni_selectable_set_context(pn_selectable_t *selectable, void *context);
-int pni_selectable_get_index(pn_selectable_t *selectable);
-void pni_selectable_set_index(pn_selectable_t *selectable, int index);
-
-#endif /* selectable.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/openssl.c b/proton-c/src/ssl/openssl.c
index 48cb051..0d7c40b 100644
--- a/proton-c/src/ssl/openssl.c
+++ b/proton-c/src/ssl/openssl.c
@@ -19,11 +19,12 @@
  *
  */
 
+#include "platform/platform.h"
+#include "core/util.h"
+#include "core/engine-internal.h"
+
 #include <proton/ssl.h>
 #include <proton/engine.h>
-#include "engine/engine-internal.h"
-#include "platform.h"
-#include "util.h"
 
 // openssl on windows expects the user to have already included
 // winsock.h
@@ -749,7 +750,7 @@ bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
   if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) {
     const char *v = SSL_CIPHER_get_name(c);
     if (v) {
-      snprintf( buffer, size, "%s", v );
+      pni_snprintf( buffer, size, "%s", v );
       return true;
     }
   }
@@ -765,7 +766,7 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
   if (ssl->ssl && (c = SSL_get_current_cipher( ssl->ssl ))) {
     const char *v = SSL_CIPHER_get_version(c);
     if (v) {
-      snprintf( buffer, size, "%s", v );
+      pni_snprintf( buffer, size, "%s", v );
       return true;
     }
   }
@@ -1345,7 +1346,7 @@ int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t finger
         char *cursor = fingerprint;
 
         for (size_t i=0; i<len ; i++) {
-            cursor +=  snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]);
+            cursor +=  pni_snprintf((char *)cursor, fingerprint_length, "%02x", bytes[i]);
             fingerprint_length = fingerprint_length - 2;
         }
 


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


[08/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/object.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/object.c b/proton-c/src/object/object.c
deleted file mode 100644
index b0c1b33..0000000
--- a/proton-c/src/object/object.c
+++ /dev/null
@@ -1,312 +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/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define pn_object_initialize NULL
-#define pn_object_finalize NULL
-#define pn_object_inspect NULL
-uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; }
-intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
-
-const pn_class_t PN_OBJECT[] = {PN_CLASS(pn_object)};
-
-#define pn_void_initialize NULL
-static void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
-static void pn_void_incref(void *object) {}
-static void pn_void_decref(void *object) {}
-static int pn_void_refcount(void *object) { return -1; }
-#define pn_void_finalize NULL
-static void pn_void_free(void *object) { free(object); }
-static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; }
-uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; }
-intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
-int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); }
-
-const pn_class_t PN_VOID[] = {PN_METACLASS(pn_void)};
-
-const char *pn_class_name(const pn_class_t *clazz)
-{
-  return clazz->name;
-}
-
-pn_cid_t pn_class_id(const pn_class_t *clazz)
-{
-  return clazz->cid;
-}
-
-void *pn_class_new(const pn_class_t *clazz, size_t size)
-{
-  assert(clazz);
-  void *object = clazz->newinst(clazz, size);
-  if (clazz->initialize) {
-    clazz->initialize(object);
-  }
-  return object;
-}
-
-void *pn_class_incref(const pn_class_t *clazz, void *object)
-{
-  assert(clazz);
-  if (object) {
-    clazz = clazz->reify(object);
-    clazz->incref(object);
-  }
-  return object;
-}
-
-int pn_class_refcount(const pn_class_t *clazz, void *object)
-{
-  assert(clazz);
-  clazz = clazz->reify(object);
-  return clazz->refcount(object);
-}
-
-int pn_class_decref(const pn_class_t *clazz, void *object)
-{
-  assert(clazz);
-
-  if (object) {
-    clazz = clazz->reify(object);
-    clazz->decref(object);
-    int rc = clazz->refcount(object);
-    if (rc == 0) {
-      if (clazz->finalize) {
-        clazz->finalize(object);
-        // check the refcount again in case the finalizer created a
-        // new reference
-        rc = clazz->refcount(object);
-      }
-      if (rc == 0) {
-        clazz->free(object);
-        return 0;
-      }
-    } else {
-      return rc;
-    }
-  }
-
-  return 0;
-}
-
-void pn_class_free(const pn_class_t *clazz, void *object)
-{
-  assert(clazz);
-  if (object) {
-    clazz = clazz->reify(object);
-    int rc = clazz->refcount(object);
-    assert(rc == 1 || rc == -1);
-    if (rc == 1) {
-      rc = pn_class_decref(clazz, object);
-      assert(rc == 0);
-    } else {
-      if (clazz->finalize) {
-        clazz->finalize(object);
-      }
-      clazz->free(object);
-    }
-  }
-}
-
-const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object)
-{
-  assert(clazz);
-  return clazz->reify(object);
-}
-
-uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object)
-{
-  assert(clazz);
-
-  if (!object) return 0;
-
-  clazz = clazz->reify(object);
-
-  if (clazz->hashcode) {
-    return clazz->hashcode(object);
-  } else {
-    return (uintptr_t) object;
-  }
-}
-
-intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b)
-{
-  assert(clazz);
-
-  if (a == b) return 0;
-
-  clazz = clazz->reify(a);
-
-  if (a && b && clazz->compare) {
-    return clazz->compare(a, b);
-  } else {
-    return (intptr_t) a - (intptr_t) b;
-  }
-}
-
-bool pn_class_equals(const pn_class_t *clazz, void *a, void *b)
-{
-  return pn_class_compare(clazz, a, b) == 0;
-}
-
-int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst)
-{
-  assert(clazz);
-
-  clazz = clazz->reify(object);
-
-  if (!pn_string_get(dst)) {
-    pn_string_set(dst, "");
-  }
-
-  if (object && clazz->inspect) {
-    return clazz->inspect(object, dst);
-  }
-
-  const char *name = clazz->name ? clazz->name : "<anon>";
-
-  return pn_string_addf(dst, "%s<%p>", name, object);
-}
-
-typedef struct {
-  const pn_class_t *clazz;
-  int refcount;
-} pni_head_t;
-
-#define pni_head(PTR) \
-  (((pni_head_t *) (PTR)) - 1)
-
-void *pn_object_new(const pn_class_t *clazz, size_t size)
-{
-  void *object = NULL;
-  pni_head_t *head = (pni_head_t *) malloc(sizeof(pni_head_t) + size);
-  if (head != NULL) {
-    object = head + 1;
-    head->clazz = clazz;
-    head->refcount = 1;
-  }
-  return object;
-}
-
-const pn_class_t *pn_object_reify(void *object)
-{
-  if (object) {
-    return pni_head(object)->clazz;
-  } else {
-    return PN_OBJECT;
-  }
-}
-
-void pn_object_incref(void *object)
-{
-  if (object) {
-    pni_head(object)->refcount++;
-  }
-}
-
-int pn_object_refcount(void *object)
-{
-  assert(object);
-  return pni_head(object)->refcount;
-}
-
-void pn_object_decref(void *object)
-{
-  pni_head_t *head = pni_head(object);
-  assert(head->refcount > 0);
-  head->refcount--;
-}
-
-void pn_object_free(void *object)
-{
-  pni_head_t *head = pni_head(object);
-  free(head);
-}
-
-void *pn_incref(void *object)
-{
-  return pn_class_incref(PN_OBJECT, object);
-}
-
-int pn_decref(void *object)
-{
-  return pn_class_decref(PN_OBJECT, object);
-}
-
-int pn_refcount(void *object)
-{
-  return pn_class_refcount(PN_OBJECT, object);
-}
-
-void pn_free(void *object)
-{
-  pn_class_free(PN_OBJECT, object);
-}
-
-const pn_class_t *pn_class(void *object)
-{
-  return pn_class_reify(PN_OBJECT, object);
-}
-
-uintptr_t pn_hashcode(void *object)
-{
-  return pn_class_hashcode(PN_OBJECT, object);
-}
-
-intptr_t pn_compare(void *a, void *b)
-{
-  return pn_class_compare(PN_OBJECT, a, b);
-}
-
-bool pn_equals(void *a, void *b)
-{
-  return !pn_compare(a, b);
-}
-
-int pn_inspect(void *object, pn_string_t *dst)
-{
-  return pn_class_inspect(PN_OBJECT, object, dst);
-}
-
-#define pn_weakref_new NULL
-#define pn_weakref_initialize NULL
-#define pn_weakref_finalize NULL
-#define pn_weakref_free NULL
-
-static void pn_weakref_incref(void *object) {}
-static void pn_weakref_decref(void *object) {}
-static int pn_weakref_refcount(void *object) { return -1; }
-static const pn_class_t *pn_weakref_reify(void *object) {
-  return PN_WEAKREF;
-}
-static uintptr_t pn_weakref_hashcode(void *object) {
-  return pn_hashcode(object);
-}
-static intptr_t pn_weakref_compare(void *a, void *b) {
-  return pn_compare(a, b);
-}
-static int pn_weakref_inspect(void *object, pn_string_t *dst) {
-  return pn_inspect(object, dst);
-}
-
-const pn_class_t PN_WEAKREF[] = {PN_METACLASS(pn_weakref)};

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/record.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/record.c b/proton-c/src/object/record.c
deleted file mode 100644
index 6f4fe0a..0000000
--- a/proton-c/src/object/record.c
+++ /dev/null
@@ -1,153 +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/object.h>
-#include <stdlib.h>
-#include <assert.h>
-
-typedef struct {
-  pn_handle_t key;
-  const pn_class_t *clazz;
-  void *value;
-} pni_field_t;
-
-struct pn_record_t {
-  size_t size;
-  size_t capacity;
-  pni_field_t *fields;
-};
-
-static void pn_record_initialize(void *object)
-{
-  pn_record_t *record = (pn_record_t *) object;
-  record->size = 0;
-  record->capacity = 0;
-  record->fields = NULL;
-}
-
-static void pn_record_finalize(void *object)
-{
-  pn_record_t *record = (pn_record_t *) object;
-  for (size_t i = 0; i < record->size; i++) {
-    pni_field_t *v = &record->fields[i];
-    pn_class_decref(v->clazz, v->value);
-  }
-  free(record->fields);
-}
-
-#define pn_record_hashcode NULL
-#define pn_record_compare NULL
-#define pn_record_inspect NULL
-
-pn_record_t *pn_record(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_record);
-  pn_record_t *record = (pn_record_t *) pn_class_new(&clazz, sizeof(pn_record_t));
-  pn_record_def(record, PN_LEGCTX, PN_VOID);
-  return record;
-}
-
-static pni_field_t *pni_record_find(pn_record_t *record, pn_handle_t key) {
-  for (size_t i = 0; i < record->size; i++) {
-    pni_field_t *field = &record->fields[i];
-    if (field->key == key) {
-      return field;
-    }
-  }
-  return NULL;
-}
-
-static pni_field_t *pni_record_create(pn_record_t *record) {
-  record->size++;
-  if (record->size > record->capacity) {
-    record->fields = (pni_field_t *) realloc(record->fields, record->size * sizeof(pni_field_t));
-    record->capacity = record->size;
-  }
-  pni_field_t *field = &record->fields[record->size - 1];
-  field->key = 0;
-  field->clazz = NULL;
-  field->value = NULL;
-  return field;
-}
-
-void pn_record_def(pn_record_t *record, pn_handle_t key, const pn_class_t *clazz)
-{
-  assert(record);
-  assert(clazz);
-
-  pni_field_t *field = pni_record_find(record, key);
-  if (field) {
-    assert(field->clazz == clazz);
-  } else {
-    field = pni_record_create(record);
-    field->key = key;
-    field->clazz = clazz;
-  }
-}
-
-bool pn_record_has(pn_record_t *record, pn_handle_t key)
-{
-  assert(record);
-  pni_field_t *field = pni_record_find(record, key);
-  if (field) {
-    return true;
-  } else {
-    return false;
-  }
-}
-
-void *pn_record_get(pn_record_t *record, pn_handle_t key)
-{
-  assert(record);
-  pni_field_t *field = pni_record_find(record, key);
-  if (field) {
-    return field->value;
-  } else {
-    return NULL;
-  }
-}
-
-void pn_record_set(pn_record_t *record, pn_handle_t key, void *value)
-{
-  assert(record);
-
-  pni_field_t *field = pni_record_find(record, key);
-  if (field) {
-    void *old = field->value;
-    field->value = value;
-    pn_class_incref(field->clazz, value);
-    pn_class_decref(field->clazz, old);
-  }
-}
-
-void pn_record_clear(pn_record_t *record)
-{
-  assert(record);
-  for (size_t i = 0; i < record->size; i++) {
-    pni_field_t *field = &record->fields[i];
-    pn_class_decref(field->clazz, field->value);
-    field->key = 0;
-    field->clazz = NULL;
-    field->value = NULL;
-  }
-  record->size = 0;
-  pn_record_def(record, PN_LEGCTX, PN_VOID);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/object/string.c
----------------------------------------------------------------------
diff --git a/proton-c/src/object/string.c b/proton-c/src/object/string.c
deleted file mode 100644
index 7b900ca..0000000
--- a/proton-c/src/object/string.c
+++ /dev/null
@@ -1,270 +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 "platform.h"
-
-#include <proton/error.h>
-#include <proton/object.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-#define PNI_NULL_SIZE (-1)
-
-struct pn_string_t {
-  char *bytes;
-  ssize_t size;       // PNI_NULL_SIZE (-1) means null
-  size_t capacity;
-};
-
-static void pn_string_finalize(void *object)
-{
-  pn_string_t *string = (pn_string_t *) object;
-  free(string->bytes);
-}
-
-static uintptr_t pn_string_hashcode(void *object)
-{
-  pn_string_t *string = (pn_string_t *) object;
-  if (string->size == PNI_NULL_SIZE) {
-    return 0;
-  }
-
-  uintptr_t hashcode = 1;
-  for (ssize_t i = 0; i < string->size; i++) {
-    hashcode = hashcode * 31 + string->bytes[i];
-  }
-  return hashcode;
-}
-
-static intptr_t pn_string_compare(void *oa, void *ob)
-{
-  pn_string_t *a = (pn_string_t *) oa;
-  pn_string_t *b = (pn_string_t *) ob;
-  if (a->size != b->size) {
-    return b->size - a->size;
-  }
-
-  if (a->size == PNI_NULL_SIZE) {
-    return 0;
-  } else {
-    return memcmp(a->bytes, b->bytes, a->size);
-  }
-}
-
-static int pn_string_inspect(void *obj, pn_string_t *dst)
-{
-  pn_string_t *str = (pn_string_t *) obj;
-  if (str->size == PNI_NULL_SIZE) {
-    return pn_string_addf(dst, "null");
-  }
-
-  int err = pn_string_addf(dst, "\"");
-
-  for (int i = 0; i < str->size; i++) {
-    uint8_t c = str->bytes[i];
-    if (isprint(c)) {
-      err = pn_string_addf(dst, "%c", c);
-      if (err) return err;
-    } else {
-      err = pn_string_addf(dst, "\\x%.2x", c);
-      if (err) return err;
-    }
-  }
-
-  return pn_string_addf(dst, "\"");
-}
-
-pn_string_t *pn_string(const char *bytes)
-{
-  return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
-}
-
-#define pn_string_initialize NULL
-
-
-pn_string_t *pn_stringn(const char *bytes, size_t n)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_string);
-  pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t));
-  string->capacity = n ? n * sizeof(char) : 16;
-  string->bytes = (char *) malloc(string->capacity);
-  pn_string_setn(string, bytes, n);
-  return string;
-}
-
-const char *pn_string_get(pn_string_t *string)
-{
-  assert(string);
-  if (string->size == PNI_NULL_SIZE) {
-    return NULL;
-  } else {
-    return string->bytes;
-  }
-}
-
-size_t pn_string_size(pn_string_t *string)
-{
-  assert(string);
-  if (string->size == PNI_NULL_SIZE) {
-    return 0;
-  } else {
-    return string->size;
-  }
-}
-
-int pn_string_set(pn_string_t *string, const char *bytes)
-{
-  return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
-}
-
-int pn_string_grow(pn_string_t *string, size_t capacity)
-{
-  bool grow = false;
-  while (string->capacity < (capacity*sizeof(char) + 1)) {
-    string->capacity *= 2;
-    grow = true;
-  }
-
-  if (grow) {
-    char *growed = (char *) realloc(string->bytes, string->capacity);
-    if (growed) {
-      string->bytes = growed;
-    } else {
-      return PN_ERR;
-    }
-  }
-
-  return 0;
-}
-
-int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
-{
-  int err = pn_string_grow(string, n);
-  if (err) return err;
-
-  if (bytes) {
-    memcpy(string->bytes, bytes, n*sizeof(char));
-    string->bytes[n] = '\0';
-    string->size = n;
-  } else {
-    string->size = PNI_NULL_SIZE;
-  }
-
-  return 0;
-}
-
-ssize_t pn_string_put(pn_string_t *string, char *dst)
-{
-  assert(string);
-  assert(dst);
-
-  if (string->size != PNI_NULL_SIZE) {
-    memcpy(dst, string->bytes, string->size + 1);
-  }
-
-  return string->size;
-}
-
-void pn_string_clear(pn_string_t *string)
-{
-  pn_string_set(string, NULL);
-}
-
-int pn_string_format(pn_string_t *string, const char *format, ...)
-{
-  va_list ap;
-
-  va_start(ap, format);
-  int err = pn_string_vformat(string, format, ap);
-  va_end(ap);
-  return err;
-}
-
-int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
-{
-  pn_string_set(string, "");
-  return pn_string_vaddf(string, format, ap);
-}
-
-int pn_string_addf(pn_string_t *string, const char *format, ...)
-{
-  va_list ap;
-
-  va_start(ap, format);
-  int err = pn_string_vaddf(string, format, ap);
-  va_end(ap);
-  return err;
-}
-
-int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
-{
-  va_list copy;
-
-  if (string->size == PNI_NULL_SIZE) {
-    return PN_ERR;
-  }
-
-  while (true) {
-    va_copy(copy, ap);
-    int err = vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
-    va_end(copy);
-    if (err < 0) {
-      return err;
-    } else if ((size_t) err >= string->capacity - string->size) {
-      pn_string_grow(string, string->size + err);
-    } else {
-      string->size += err;
-      return 0;
-    }
-  }
-}
-
-char *pn_string_buffer(pn_string_t *string)
-{
-  assert(string);
-  return string->bytes;
-}
-
-size_t pn_string_capacity(pn_string_t *string)
-{
-  assert(string);
-  return string->capacity - 1;
-}
-
-int pn_string_resize(pn_string_t *string, size_t size)
-{
-  assert(string);
-  int err = pn_string_grow(string, size);
-  if (err) return err;
-  string->size = size;
-  string->bytes[size] = '\0';
-  return 0;
-}
-
-int pn_string_copy(pn_string_t *string, pn_string_t *src)
-{
-  assert(string);
-  return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/parser.c
----------------------------------------------------------------------
diff --git a/proton-c/src/parser.c b/proton-c/src/parser.c
deleted file mode 100644
index 87cb758..0000000
--- a/proton-c/src/parser.c
+++ /dev/null
@@ -1,420 +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/parser.h>
-#include <proton/scanner.h>
-#include <proton/error.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include "platform.h"
-
-struct pn_parser_t {
-  pn_scanner_t *scanner;
-  char *atoms;
-  size_t size;
-  size_t capacity;
-  int error_code;
-};
-
-pn_parser_t *pn_parser()
-{
-  pn_parser_t *parser = (pn_parser_t *) malloc(sizeof(pn_parser_t));
-  if (parser != NULL) {
-    parser->scanner = pn_scanner();
-    parser->atoms = NULL;
-    parser->size = 0;
-    parser->capacity = 0;
-  }
-  return parser;
-}
-
-static void pni_parser_ensure(pn_parser_t *parser, size_t size)
-{
-  while (parser->capacity - parser->size < size) {
-    parser->capacity = parser->capacity ? 2 * parser->capacity : 1024;
-    parser->atoms = (char *) realloc(parser->atoms, parser->capacity);
-  }
-}
-
-int pn_parser_err(pn_parser_t *parser, int code, const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  int err = pn_scanner_verr(parser->scanner, code, fmt, ap);
-  va_end(ap);
-  return err;
-}
-
-int pn_parser_errno(pn_parser_t *parser)
-{
-  return pn_scanner_errno(parser->scanner);
-}
-
-const char *pn_parser_error(pn_parser_t *parser)
-{
-  return pn_scanner_error(parser->scanner);
-}
-
-void pn_parser_free(pn_parser_t *parser)
-{
-  if (parser) {
-    pn_scanner_free(parser->scanner);
-    free(parser->atoms);
-    free(parser);
-  }
-}
-
-static int pni_parser_shift(pn_parser_t *parser)
-{
-  return pn_scanner_shift(parser->scanner);
-}
-
-static pn_token_t pni_parser_token(pn_parser_t *parser)
-{
-  return pn_scanner_token(parser->scanner);
-}
-
-static int pni_parser_value(pn_parser_t *parser, pn_data_t *data);
-
-static int pni_parser_descriptor(pn_parser_t *parser, pn_data_t *data)
-{
-  if (pni_parser_token(parser).type == PN_TOK_AT) {
-    int err = pni_parser_shift(parser);
-    if (err) return err;
-
-    err = pn_data_put_described(data);
-    if (err) return pn_parser_err(parser, err, "error writing described");
-    pn_data_enter(data);
-    for (int i = 0; i < 2; i++) {
-      err = pni_parser_value(parser, data);
-      if (err) return err;
-    }
-    pn_data_exit(data);
-    return 0;
-  } else {
-    return pn_parser_err(parser, PN_ERR, "expecting '@'");
-  }
-}
-
-static int pni_parser_map(pn_parser_t *parser, pn_data_t *data)
-{
-  if (pni_parser_token(parser).type == PN_TOK_LBRACE) {
-    int err = pni_parser_shift(parser);
-    if (err) return err;
-
-    err = pn_data_put_map(data);
-    if (err) return pn_parser_err(parser, err, "error writing map");
-
-    pn_data_enter(data);
-
-    if (pni_parser_token(parser).type != PN_TOK_RBRACE) {
-      while (true) {
-        err = pni_parser_value(parser, data);
-        if (err) return err;
-
-        if (pni_parser_token(parser).type == PN_TOK_EQUAL) {
-          err = pni_parser_shift(parser);
-          if (err) return err;
-        } else {
-          return pn_parser_err(parser, PN_ERR, "expecting '='");
-        }
-
-        err = pni_parser_value(parser, data);
-        if (err) return err;
-
-        if (pni_parser_token(parser).type == PN_TOK_COMMA) {
-          err = pni_parser_shift(parser);
-          if (err) return err;
-        } else {
-          break;
-        }
-      }
-    }
-
-    pn_data_exit(data);
-
-    if (pni_parser_token(parser).type == PN_TOK_RBRACE) {
-      return pni_parser_shift(parser);
-    } else {
-      return pn_parser_err(parser, PN_ERR, "expecting '}'");
-    }
-  } else {
-    return pn_parser_err(parser, PN_ERR, "expecting '{'");
-  }
-}
-
-static int pni_parser_list(pn_parser_t *parser, pn_data_t *data)
-{
-  int err;
-
-  if (pni_parser_token(parser).type == PN_TOK_LBRACKET) {
-    err = pni_parser_shift(parser);
-    if (err) return err;
-
-    err = pn_data_put_list(data);
-    if (err) return pn_parser_err(parser, err, "error writing list");
-
-    pn_data_enter(data);
-
-    if (pni_parser_token(parser).type != PN_TOK_RBRACKET) {
-      while (true) {
-        err = pni_parser_value(parser, data);
-        if (err) return err;
-
-        if (pni_parser_token(parser).type == PN_TOK_COMMA) {
-          err = pni_parser_shift(parser);
-          if (err) return err;
-        } else {
-          break;
-        }
-      }
-    }
-
-    pn_data_exit(data);
-
-    if (pni_parser_token(parser).type == PN_TOK_RBRACKET) {
-      return pni_parser_shift(parser);
-    } else {
-      return pn_parser_err(parser, PN_ERR, "expecting ']'");
-    }
-  } else {
-    return pn_parser_err(parser, PN_ERR, "expecting '['");
-  }
-}
-
-static void pni_parser_append_tok(pn_parser_t *parser, char *dst, int *idx)
-{
-  memcpy(dst + *idx, pni_parser_token(parser).start, pni_parser_token(parser).size);
-  *idx += pni_parser_token(parser).size;
-}
-
-static int pni_parser_number(pn_parser_t *parser, pn_data_t *data)
-{
-  bool dbl = false;
-  char number[1024];
-  int idx = 0;
-  int err;
-
-  bool negate = false;
-
-  if (pni_parser_token(parser).type == PN_TOK_NEG || pni_parser_token(parser).type == PN_TOK_POS) {
-    if (pni_parser_token(parser).type == PN_TOK_NEG)
-      negate = !negate;
-    err = pni_parser_shift(parser);
-    if (err) return err;
-  }
-
-  if (pni_parser_token(parser).type == PN_TOK_FLOAT || pni_parser_token(parser).type == PN_TOK_INT) {
-    dbl = pni_parser_token(parser).type == PN_TOK_FLOAT;
-    pni_parser_append_tok(parser, number, &idx);
-    err = pni_parser_shift(parser);
-    if (err) return err;
-  } else {
-    return pn_parser_err(parser, PN_ERR, "expecting FLOAT or INT");
-  }
-
-  number[idx] = '\0';
-
-  if (dbl) {
-    double value = atof(number);
-    if (negate) {
-      value = -value;
-    }
-    err = pn_data_put_double(data, value);
-    if (err) return pn_parser_err(parser, err, "error writing double");
-  } else {
-    int64_t value = pn_i_atoll(number);
-    if (negate) {
-      value = -value;
-    }
-    err = pn_data_put_long(data, value);
-    if (err) return pn_parser_err(parser, err, "error writing long");
-  }
-
-  return 0;
-}
-
-static int pni_parser_unquote(pn_parser_t *parser, char *dst, const char *src, size_t *n)
-{
-  size_t idx = 0;
-  bool escape = false;
-  int start, end;
-  if (src[0] != '"') {
-    if (src[1] == '"') {
-      start = 2;
-      end = *n - 1;
-    } else {
-      start = 1;
-      end = *n;
-    }
-  } else {
-    start = 1;
-    end = *n - 1;
-  }
-  for (int i = start; i < end; i++)
-  {
-    char c = src[i];
-    if (escape) {
-      switch (c) {
-      case '"':
-      case '\\':
-      case '/':
-        dst[idx++] = c;
-        escape = false;
-        break;
-      case 'b':
-        dst[idx++] = '\b';
-        break;
-      case 'f':
-        dst[idx++] = '\f';
-        break;
-      case 'n':
-        dst[idx++] = '\n';
-        break;
-      case 'r':
-        dst[idx++] = '\r';
-        break;
-      case 't':
-        dst[idx++] = '\t';
-        break;
-      case 'x':
-        {
-          char n1 = toupper(src[i+1]);
-          char n2 = n1 ? toupper(src[i+2]) : 0;
-          if (!n2) {
-            return pn_parser_err(parser, PN_ERR, "truncated escape code");
-          }
-          int d1 = isdigit(n1) ? n1 - '0' : n1 - 'A' + 10;
-          int d2 = isdigit(n2) ? n2 - '0' : n2 - 'A' + 10;
-          dst[idx++] = d1*16 + d2;
-          i += 2;
-        }
-        break;
-      // XXX: need to handle unicode escapes: 'u'
-      default:
-        return pn_parser_err(parser, PN_ERR, "unrecognized escape code");
-      }
-      escape = false;
-    } else {
-      switch (c)
-      {
-      case '\\':
-        escape = true;
-        break;
-      default:
-        dst[idx++] = c;
-        break;
-      }
-    }
-  }
-  dst[idx++] = '\0';
-  *n = idx;
-  return 0;
-}
-
-static int pni_parser_value(pn_parser_t *parser, pn_data_t *data)
-{
-  int err;
-  size_t n;
-  char *dst;
-
-  pn_token_t tok = pni_parser_token(parser);
-
-  switch (tok.type)
-  {
-  case PN_TOK_AT:
-    return pni_parser_descriptor(parser, data);
-  case PN_TOK_LBRACE:
-    return pni_parser_map(parser, data);
-  case PN_TOK_LBRACKET:
-    return pni_parser_list(parser, data);
-  case PN_TOK_BINARY:
-  case PN_TOK_SYMBOL:
-  case PN_TOK_STRING:
-    n = tok.size;
-    pni_parser_ensure(parser, n);
-    dst = parser->atoms + parser->size;
-    err = pni_parser_unquote(parser, dst, tok.start, &n);
-    if (err) return err;
-    parser->size += n;
-    switch (tok.type) {
-    case PN_TOK_BINARY:
-      err = pn_data_put_binary(data, pn_bytes(n - 1, dst));
-      break;
-    case PN_TOK_STRING:
-      err = pn_data_put_string(data, pn_bytes(n - 1, dst));
-      break;
-    case PN_TOK_SYMBOL:
-      err = pn_data_put_symbol(data, pn_bytes(n - 1, dst));
-      break;
-    default:
-      return pn_parser_err(parser, PN_ERR, "internal error");
-    }
-    if (err) return pn_parser_err(parser, err, "error writing string/binary/symbol");
-    return pni_parser_shift(parser);
-  case PN_TOK_POS:
-  case PN_TOK_NEG:
-  case PN_TOK_FLOAT:
-  case PN_TOK_INT:
-    return pni_parser_number(parser, data);
-  case PN_TOK_TRUE:
-    err = pn_data_put_bool(data, true);
-    if (err) return pn_parser_err(parser, err, "error writing boolean");
-    return pni_parser_shift(parser);
-  case PN_TOK_FALSE:
-    err = pn_data_put_bool(data, false);
-    if (err) return pn_parser_err(parser, err, "error writing boolean");
-    return pni_parser_shift(parser);
-  case PN_TOK_NULL:
-    err = pn_data_put_null(data);
-    if (err) return pn_parser_err(parser, err, "error writing null");
-    return pni_parser_shift(parser);
-  default:
-    return pn_parser_err(parser, PN_ERR, "expecting one of '[', '{', STRING, "
-                         "SYMBOL, BINARY, true, false, null, NUMBER");
-  }
-}
-
-static int pni_parser_parse_r(pn_parser_t *parser, pn_data_t *data)
-{
-  while (true) {
-    int err;
-    switch (pni_parser_token(parser).type)
-    {
-    case PN_TOK_EOS:
-      return 0;
-    case PN_TOK_ERR:
-      return PN_ERR;
-    default:
-      err = pni_parser_value(parser, data);
-      if (err) return err;
-    }
-  }
-}
-
-int pn_parser_parse(pn_parser_t *parser, const char *str, pn_data_t *data)
-{
-  int err = pn_scanner_start(parser->scanner, str);
-  if (err) return err;
-  parser->size = 0;
-  return pni_parser_parse_r(parser, data);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.c b/proton-c/src/platform.c
deleted file mode 100644
index 3a8cade..0000000
--- a/proton-c/src/platform.c
+++ /dev/null
@@ -1,134 +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 "platform.h"
-#include "util.h"
-
-#ifdef PN_WINAPI
-#include <windows.h>
-int pn_i_getpid() {
-  return (int) GetCurrentProcessId();
-}
-#else
-#include <unistd.h>
-int pn_i_getpid() {
-  return (int) getpid();
-}
-#endif
-
-/* Allow for systems that do not implement clock_gettime()*/
-#ifdef USE_CLOCK_GETTIME
-#include <time.h>
-pn_timestamp_t pn_i_now(void)
-{
-  struct timespec now;
-  if (clock_gettime(CLOCK_REALTIME, &now)) pni_fatal("clock_gettime() failed\n");
-  return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_nsec / 1000000);
-}
-#elif defined(USE_WIN_FILETIME)
-#include <windows.h>
-pn_timestamp_t pn_i_now(void)
-{
-  FILETIME now;
-  GetSystemTimeAsFileTime(&now);
-  ULARGE_INTEGER t;
-  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>
-pn_timestamp_t pn_i_now(void)
-{
-  struct timeval now;
-  if (gettimeofday(&now, NULL)) pni_fatal("gettimeofday failed\n");
-  return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
-}
-#endif
-
-#include <string.h>
-#include <stdio.h>
-static void pn_i_strerror(int errnum, char *buf, size_t buflen)
-{
-  // PROTON-1029 provide a simple default in case strerror fails
-  snprintf(buf, buflen, "errno: %d", errnum);
-#ifdef USE_STRERROR_R
-  strerror_r(errnum, buf, buflen);
-#elif USE_STRERROR_S
-  strerror_s(buf, buflen, errnum);
-#elif USE_OLD_STRERROR
-  strncpy(buf, strerror(errnum), buflen);
-#endif
-}
-
-int pn_i_error_from_errno(pn_error_t *error, const char *msg)
-{
-  char err[1024];
-  pn_i_strerror(errno, err, 1024);
-  int code = PN_ERR;
-  if (errno == EINTR)
-      code = PN_INTR;
-  return pn_error_format(error, code, "%s: %s", msg, err);
-}
-
-#ifdef USE_ATOLL
-#include <stdlib.h>
-int64_t pn_i_atoll(const char* num) {
-  return atoll(num);
-}
-#elif USE_ATOI64
-#include <stdlib.h>
-int64_t pn_i_atoll(const char* num) {
-  return _atoi64(num);
-}
-#else
-#error "Don't know how to convert int64_t values on this platform"
-#endif
-
-#ifdef _MSC_VER
-// [v]snprintf on Windows only matches C99 when no errors or overflow.
-int pn_i_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap) {
-  if (fmt == NULL)
-    return -1;
-  if ((buf == NULL) && (count > 0))
-    return -1;
-  if (count > 0) {
-    int n = vsnprintf_s(buf, count, _TRUNCATE, fmt, ap);
-    if (n >= 0)  // no overflow
-      return n;  // same as C99
-    buf[count-1] = '\0';
-  }
-  // separate call to get needed buffer size on overflow
-  int n = _vscprintf(fmt, ap);
-  if (n >= (int) count)
-    return n;
-  return -1;
-}
-
-int pn_i_snprintf(char *buf, size_t count, const char *fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  int n = pn_i_vsnprintf(buf, count, fmt, ap);
-  va_end(ap);
-  return n;
-}
-#endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform.h b/proton-c/src/platform.h
deleted file mode 100644
index 6a0bbc1..0000000
--- a/proton-c/src/platform.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef PROTON_PLATFORM_H
-#define PROTON_PLATFORM_H 1
-
-/*
- *
- * 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/types.h"
-#include "proton/error.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Get the current PID
- *
- * @return process id
- * @internal
- */
-int pn_i_getpid(void);
-
-
-/** Get the current time in pn_timestamp_t format.
- *
- * Returns current time in milliseconds since Unix Epoch,
- * as defined by AMQP 1.0
- *
- * @return current time
- * @internal
- */
-pn_timestamp_t pn_i_now(void);
-
-/** Generate system error message.
- *
- * Populate the proton error structure based on the last system error
- * code.
- *
- * @param[in] error the proton error structure
- * @param[in] msg the descriptive context message
- * @return error->code
- *
- * @internal
- */
-int pn_i_error_from_errno(pn_error_t *error, const char *msg);
-
-/** Provide C99 atoll functinality.
- *
- * @param[in] num the string representation of the number.
- * @return the integer value.
- *
- * @internal
- */
-int64_t pn_i_atoll(const char* num);
-
-#ifdef _MSC_VER
-/** Windows snprintf and vsnprintf substitutes.
- *
- * Provide the expected C99 behavior for these functions.
- */
-#include <stdio.h>
-
-#define snprintf pn_i_snprintf
-#define vsnprintf pn_i_vsnprintf
-
-int pn_i_snprintf(char *buf, size_t count, const char *fmt, ...);
-int pn_i_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap);
-
-#if !defined(S_ISDIR)
-# define S_ISDIR(X) ((X) & _S_IFDIR)
-#endif
-
-#endif
-
-#if defined _MSC_VER || defined _OPENVMS
-#if !defined(va_copy)
-#define va_copy(d,s) ((d) = (s))
-#endif
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* platform.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform/platform.c
----------------------------------------------------------------------
diff --git a/proton-c/src/platform/platform.c b/proton-c/src/platform/platform.c
new file mode 100644
index 0000000..393f75c
--- /dev/null
+++ b/proton-c/src/platform/platform.c
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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 "platform.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef PN_WINAPI
+#include <windows.h>
+int pn_i_getpid() {
+  return (int) GetCurrentProcessId();
+}
+#else
+#include <unistd.h>
+int pn_i_getpid() {
+  return (int) getpid();
+}
+#endif
+
+void pni_vfatal(const char *fmt, va_list ap)
+{
+  vfprintf(stderr, fmt, ap);
+  abort();
+}
+
+void pni_fatal(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  pni_vfatal(fmt, ap);
+  va_end(ap);
+}
+
+/* Allow for systems that do not implement clock_gettime()*/
+#ifdef USE_CLOCK_GETTIME
+#include <time.h>
+pn_timestamp_t pn_i_now(void)
+{
+  struct timespec now;
+  if (clock_gettime(CLOCK_REALTIME, &now)) pni_fatal("clock_gettime() failed\n");
+  return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_nsec / 1000000);
+}
+#elif defined(USE_WIN_FILETIME)
+#include <windows.h>
+pn_timestamp_t pn_i_now(void)
+{
+  FILETIME now;
+  GetSystemTimeAsFileTime(&now);
+  ULARGE_INTEGER t;
+  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>
+pn_timestamp_t pn_i_now(void)
+{
+  struct timeval now;
+  if (gettimeofday(&now, NULL)) pni_fatal("gettimeofday failed\n");
+  return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000);
+}
+#endif
+
+#include <string.h>
+#include <stdio.h>
+static void pn_i_strerror(int errnum, char *buf, size_t buflen)
+{
+  // PROTON-1029 provide a simple default in case strerror fails
+  pni_snprintf(buf, buflen, "errno: %d", errnum);
+#ifdef USE_STRERROR_R
+  strerror_r(errnum, buf, buflen);
+#elif USE_STRERROR_S
+  strerror_s(buf, buflen, errnum);
+#elif USE_OLD_STRERROR
+  strncpy(buf, strerror(errnum), buflen);
+#endif
+}
+
+int pn_i_error_from_errno(pn_error_t *error, const char *msg)
+{
+  char err[1024];
+  pn_i_strerror(errno, err, 1024);
+  int code = PN_ERR;
+  if (errno == EINTR)
+      code = PN_INTR;
+  return pn_error_format(error, code, "%s: %s", msg, err);
+}
+
+#ifdef USE_ATOLL
+#include <stdlib.h>
+int64_t pn_i_atoll(const char* num) {
+  return atoll(num);
+}
+#elif USE_ATOI64
+#include <stdlib.h>
+int64_t pn_i_atoll(const char* num) {
+  return _atoi64(num);
+}
+#else
+#error "Don't know how to convert int64_t values on this platform"
+#endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform/platform.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform/platform.h b/proton-c/src/platform/platform.h
new file mode 100644
index 0000000..d846cda
--- /dev/null
+++ b/proton-c/src/platform/platform.h
@@ -0,0 +1,93 @@
+#ifndef PROTON_PLATFORM_H
+#define PROTON_PLATFORM_H 1
+
+/*
+ *
+ * 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/types.h"
+#include "proton/error.h"
+
+/** Get the current PID
+ *
+ * @return process id
+ * @internal
+ */
+int pn_i_getpid(void);
+
+
+/** Get the current time in pn_timestamp_t format.
+ *
+ * Returns current time in milliseconds since Unix Epoch,
+ * as defined by AMQP 1.0
+ *
+ * @return current time
+ * @internal
+ */
+pn_timestamp_t pn_i_now(void);
+
+/** Generate system error message.
+ *
+ * Populate the proton error structure based on the last system error
+ * code.
+ *
+ * @param[in] error the proton error structure
+ * @param[in] msg the descriptive context message
+ * @return error->code
+ *
+ * @internal
+ */
+int pn_i_error_from_errno(pn_error_t *error, const char *msg);
+
+/** Provide C99 atoll functinality.
+ *
+ * @param[in] num the string representation of the number.
+ * @return the integer value.
+ *
+ * @internal
+ */
+int64_t pn_i_atoll(const char* num);
+
+int pni_snprintf(char *buf, size_t count, const char *fmt, ...);
+int pni_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap);
+
+#ifndef _MSC_VER
+
+#define pni_snprintf snprintf
+#define pni_vsnprintf vsnprintf
+
+#else
+
+#if !defined(S_ISDIR)
+# define S_ISDIR(X) ((X) & _S_IFDIR)
+#endif
+
+#endif
+
+#if defined _MSC_VER || defined _OPENVMS
+#if !defined(va_copy)
+#define va_copy(d,s) ((d) = (s))
+#endif
+#endif
+
+// Low level pretty rubbish URL parser
+void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path);
+
+#endif /* platform.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform/platform_fmt.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform/platform_fmt.h b/proton-c/src/platform/platform_fmt.h
new file mode 100644
index 0000000..17f95f3
--- /dev/null
+++ b/proton-c/src/platform/platform_fmt.h
@@ -0,0 +1,85 @@
+#ifndef _PROTON_SRC_PLATFORM_FMT_H
+#define _PROTON_SRC_PLATFORM_FMT_H 1
+
+/*
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Platform dependent type-specific format specifiers for PRIx and %z
+ * for use with printf.  PRIx defs are normally available in
+ * inttypes.h (C99), but extra steps are required for C++, and they
+ * are not available in Visual Studio at all.
+ * Visual studio uses "%I" for size_t instead of "%z".
+ */
+
+#ifndef __cplusplus
+
+// normal case
+#include <inttypes.h>
+#define PN_ZI "zi"
+#define PN_ZU "zu"
+
+#ifdef _OPENVMS
+
+#undef PN_ZI
+#undef PN_ZU
+#define PN_ZI "i"
+#define PN_ZU "u"
+#define PRIu64 "llu"
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "llu"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "lli"
+
+#endif /* _OPENVMS */
+
+#else
+
+#ifdef _MSC_VER
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "I64u"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "I64i"
+
+#define PN_ZI "Ii"
+#define PN_ZU "Iu"
+#else
+// Normal C++
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#define PN_ZI "zi"
+#define PN_ZU "zu"
+
+#endif /* _MSC_VER */
+
+#endif /* __cplusplus */
+
+#endif /* platform_fmt.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/platform_fmt.h
----------------------------------------------------------------------
diff --git a/proton-c/src/platform_fmt.h b/proton-c/src/platform_fmt.h
deleted file mode 100644
index 17f95f3..0000000
--- a/proton-c/src/platform_fmt.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef _PROTON_SRC_PLATFORM_FMT_H
-#define _PROTON_SRC_PLATFORM_FMT_H 1
-
-/*
- *
- * 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.
- *
- */
-
-/*
- * Platform dependent type-specific format specifiers for PRIx and %z
- * for use with printf.  PRIx defs are normally available in
- * inttypes.h (C99), but extra steps are required for C++, and they
- * are not available in Visual Studio at all.
- * Visual studio uses "%I" for size_t instead of "%z".
- */
-
-#ifndef __cplusplus
-
-// normal case
-#include <inttypes.h>
-#define PN_ZI "zi"
-#define PN_ZU "zu"
-
-#ifdef _OPENVMS
-
-#undef PN_ZI
-#undef PN_ZU
-#define PN_ZI "i"
-#define PN_ZU "u"
-#define PRIu64 "llu"
-#define PRIu8 "u"
-#define PRIu16 "u"
-#define PRIu32 "u"
-#define PRIu64 "llu"
-
-#define PRIi8 "i"
-#define PRIi16 "i"
-#define PRIi32 "i"
-#define PRIi64 "lli"
-
-#endif /* _OPENVMS */
-
-#else
-
-#ifdef _MSC_VER
-#define PRIu8 "u"
-#define PRIu16 "u"
-#define PRIu32 "u"
-#define PRIu64 "I64u"
-
-#define PRIi8 "i"
-#define PRIi16 "i"
-#define PRIi32 "i"
-#define PRIi64 "I64i"
-
-#define PN_ZI "Ii"
-#define PN_ZU "Iu"
-#else
-// Normal C++
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#define PN_ZI "zi"
-#define PN_ZU "zu"
-
-#endif /* _MSC_VER */
-
-#endif /* __cplusplus */
-
-#endif /* platform_fmt.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/io.c b/proton-c/src/posix/io.c
deleted file mode 100644
index 27d1a35..0000000
--- a/proton-c/src/posix/io.c
+++ /dev/null
@@ -1,342 +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/io.h>
-#include <proton/object.h>
-#include <proton/selector.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <assert.h>
-
-#include "platform.h"
-
-#define MAX_HOST (1024)
-#define MAX_SERV (64)
-
-struct pn_io_t {
-  char host[MAX_HOST];
-  char serv[MAX_SERV];
-  pn_error_t *error;
-  pn_selector_t *selector;
-  bool wouldblock;
-};
-
-void pn_io_initialize(void *obj)
-{
-  pn_io_t *io = (pn_io_t *) obj;
-  io->error = pn_error();
-  io->wouldblock = false;
-  io->selector = NULL;
-}
-
-void pn_io_finalize(void *obj)
-{
-  pn_io_t *io = (pn_io_t *) obj;
-  pn_error_free(io->error);
-}
-
-#define pn_io_hashcode NULL
-#define pn_io_compare NULL
-#define pn_io_inspect NULL
-
-pn_io_t *pn_io(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_io);
-  pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
-  return io;
-}
-
-void pn_io_free(pn_io_t *io)
-{
-  pn_free(io);
-}
-
-pn_error_t *pn_io_error(pn_io_t *io)
-{
-  assert(io);
-  return io->error;
-}
-
-int pn_pipe(pn_io_t *io, pn_socket_t *dest)
-{
-  int n = pipe(dest);
-  if (n) {
-    pn_i_error_from_errno(io->error, "pipe");
-  }
-
-  return n;
-}
-
-static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
-  // this would be nice, but doesn't appear to exist on linux
-  /*
-  int set = 1;
-  if (!setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int))) {
-    pn_i_error_from_errno(io->error, "setsockopt");
-  };
-  */
-
-  int flags = fcntl(sock, F_GETFL);
-  flags |= O_NONBLOCK;
-
-  if (fcntl(sock, F_SETFL, flags) < 0) {
-    pn_i_error_from_errno(io->error, "fcntl");
-  }
-
-  //
-  // Disable the Nagle algorithm on TCP connections.
-  //
-  // Note:  It would be more correct for the "level" argument to be SOL_TCP.  However, there
-  //        are portability issues with this macro so we use IPPROTO_TCP instead.
-  //
-  int tcp_nodelay = 1;
-  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &tcp_nodelay, sizeof(tcp_nodelay)) < 0) {
-    pn_i_error_from_errno(io->error, "setsockopt");
-  }
-}
-
-static inline int pn_create_socket(int af, int protocol);
-
-pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
-{
-  struct addrinfo *addr;
-  struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
-  int code = getaddrinfo(host, port, &hints, &addr);
-  if (code) {
-    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
-    return PN_INVALID_SOCKET;
-  }
-
-  pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
-  if (sock == PN_INVALID_SOCKET) {
-    freeaddrinfo(addr);
-    pn_i_error_from_errno(io->error, "pn_create_socket");
-    return PN_INVALID_SOCKET;
-  }
-
-  int optval = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
-    pn_i_error_from_errno(io->error, "setsockopt");
-    freeaddrinfo(addr);
-    close(sock);
-    return PN_INVALID_SOCKET;
-  }
-
-  if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
-    pn_i_error_from_errno(io->error, "bind");
-    freeaddrinfo(addr);
-    close(sock);
-    return PN_INVALID_SOCKET;
-  }
-
-  freeaddrinfo(addr);
-
-  if (listen(sock, 50) == -1) {
-    pn_i_error_from_errno(io->error, "listen");
-    close(sock);
-    return PN_INVALID_SOCKET;
-  }
-
-  return sock;
-}
-
-pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port)
-{
-  struct addrinfo *addr;
-  struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
-  int code = getaddrinfo(host, port, &hints, &addr);
-  if (code) {
-    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
-    return PN_INVALID_SOCKET;
-  }
-
-  pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
-  if (sock == PN_INVALID_SOCKET) {
-    pn_i_error_from_errno(io->error, "pn_create_socket");
-    freeaddrinfo(addr);
-    return PN_INVALID_SOCKET;
-  }
-
-  pn_configure_sock(io, sock);
-
-  if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
-    if (errno != EINPROGRESS) {
-      pn_i_error_from_errno(io->error, "connect");
-      freeaddrinfo(addr);
-      close(sock);
-      return PN_INVALID_SOCKET;
-    }
-  }
-
-  freeaddrinfo(addr);
-
-  return sock;
-}
-
-pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size)
-{
-  struct sockaddr_storage addr;
-  socklen_t addrlen = sizeof(addr);
-  *name = '\0';
-  pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen);
-  if (sock == PN_INVALID_SOCKET) {
-    pn_i_error_from_errno(io->error, "accept");
-    return sock;
-  } else {
-    int code;
-    if ((code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, MAX_HOST, io->serv, MAX_SERV, 0))) {
-      pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
-      if (close(sock) == -1)
-        pn_i_error_from_errno(io->error, "close");
-      return PN_INVALID_SOCKET;
-    } else {
-      pn_configure_sock(io, sock);
-      snprintf(name, size, "%s:%s", io->host, io->serv);
-      return sock;
-    }
-  }
-}
-
-/* Abstract away turning off SIGPIPE */
-#ifdef MSG_NOSIGNAL
-ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t len) {
-  ssize_t count = send(socket, buf, len, MSG_NOSIGNAL);
-  io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
-  if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
-  return count;
-}
-
-static inline int pn_create_socket(int af, int protocol) {
-  return socket(af, SOCK_STREAM, protocol);
-}
-#elif defined(SO_NOSIGPIPE)
-ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
-  ssize_t count = send(socket, buf, size, 0);
-  io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
-  if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
-  return count;
-}
-
-static inline int pn_create_socket(int af, int protocol) {
-  int sock;
-  sock = socket(af, SOCK_STREAM, protocol);
-  if (sock == -1) return sock;
-
-  int optval = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) == -1) {
-    close(sock);
-    return -1;
-  }
-  return sock;
-}
-#else
-
-#include <signal.h>
-
-static inline int pn_create_socket(int af, int protocol) {
-  return socket(af, SOCK_STREAM, protocol);
-}
-
-static ssize_t nosigpipe_send(int fd, const void *buffer, size_t size) {
-  sigset_t pendingSignals, oldSignals, newSignals;
-  ssize_t count;
-  int sendErrno, sigmaskErr;
-
-  sigpending(&pendingSignals);
-  int sigpipeIsPending = sigismember(&pendingSignals, SIGPIPE);
-  if (!sigpipeIsPending) {
-    sigemptyset(&newSignals);
-    sigaddset(&newSignals, SIGPIPE);
-    if (sigmaskErr = pthread_sigmask(SIG_BLOCK, (const sigset_t *)&newSignals, (sigset_t *)&oldSignals))
-    {
-      errno = sigmaskErr;
-      return -1;
-    }
-  }
-
-  count = send(fd, buffer, size, 0);
-  if (!sigpipeIsPending) {
-    sendErrno = errno;
-    if (count == -1 && errno == EPIPE) {
-      while (-1 == sigtimedwait(&newSignals, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
-        ; //do nothing
-    }
-    if (sigmaskErr = pthread_sigmask(SIG_SETMASK, (const sigset_t *)&oldSignals, (sigset_t *)NULL))
-    {
-      errno = sigmaskErr;
-      return -1;
-    }
-    errno = sendErrno;
-  }
-  return count;
-}
-
-ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
-  ssize_t count = nosigpipe_send(socket, buf, size);
-  io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
-  if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
-  return count;
-}
-#endif
-
-ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
-  ssize_t count = recv(socket, buf, size, 0);
-  io->wouldblock = count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK);
-  if (count < 0) { pn_i_error_from_errno(io->error, "recv"); }
-  return count;
-}
-
-ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
-{
-  return write(socket, buf, size);
-}
-
-ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
-  return read(socket, buf, size);
-}
-
-void pn_close(pn_io_t *io, pn_socket_t socket)
-{
-  close(socket);
-}
-
-bool pn_wouldblock(pn_io_t *io)
-{
-  return io->wouldblock;
-}
-
-pn_selector_t *pn_io_selector(pn_io_t *io)
-{
-  if (io->selector == NULL)
-    io->selector = pni_selector();
-  return io->selector;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/posix/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/posix/selector.c b/proton-c/src/posix/selector.c
deleted file mode 100644
index 7f72c84..0000000
--- a/proton-c/src/posix/selector.c
+++ /dev/null
@@ -1,211 +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/selector.h>
-#include <proton/error.h>
-#include <poll.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "platform.h"
-#include "selectable.h"
-#include "util.h"
-
-struct pn_selector_t {
-  struct pollfd *fds;
-  pn_timestamp_t *deadlines;
-  size_t capacity;
-  pn_list_t *selectables;
-  size_t current;
-  pn_timestamp_t awoken;
-  pn_error_t *error;
-};
-
-void pn_selector_initialize(void *obj)
-{
-  pn_selector_t *selector = (pn_selector_t *) obj;
-  selector->fds = NULL;
-  selector->deadlines = NULL;
-  selector->capacity = 0;
-  selector->selectables = pn_list(PN_WEAKREF, 0);
-  selector->current = 0;
-  selector->awoken = 0;
-  selector->error = pn_error();
-}
-
-void pn_selector_finalize(void *obj)
-{
-  pn_selector_t *selector = (pn_selector_t *) obj;
-  free(selector->fds);
-  free(selector->deadlines);
-  pn_free(selector->selectables);
-  pn_error_free(selector->error);
-}
-
-#define pn_selector_hashcode NULL
-#define pn_selector_compare NULL
-#define pn_selector_inspect NULL
-
-pn_selector_t *pni_selector(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_selector);
-  pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
-  return selector;
-}
-
-void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
-{
-  assert(selector);
-  assert(selectable);
-  assert(pni_selectable_get_index(selectable) < 0);
-
-  if (pni_selectable_get_index(selectable) < 0) {
-    pn_list_add(selector->selectables, selectable);
-    size_t size = pn_list_size(selector->selectables);
-
-    if (selector->capacity < size) {
-      selector->fds = (struct pollfd *) realloc(selector->fds, size*sizeof(struct pollfd));
-      selector->deadlines = (pn_timestamp_t *) realloc(selector->deadlines, size*sizeof(pn_timestamp_t));
-      selector->capacity = size;
-    }
-
-    pni_selectable_set_index(selectable, size - 1);
-  }
-
-  pn_selector_update(selector, selectable);
-}
-
-void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
-{
-  int idx = pni_selectable_get_index(selectable);
-  assert(idx >= 0);
-  selector->fds[idx].fd = pn_selectable_get_fd(selectable);
-  selector->fds[idx].events = 0;
-  selector->fds[idx].revents = 0;
-  if (pn_selectable_is_reading(selectable)) {
-    selector->fds[idx].events |= POLLIN;
-  }
-  if (pn_selectable_is_writing(selectable)) {
-    selector->fds[idx].events |= POLLOUT;
-  }
-  selector->deadlines[idx] = pn_selectable_get_deadline(selectable);
-}
-
-void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
-{
-  assert(selector);
-  assert(selectable);
-
-  int idx = pni_selectable_get_index(selectable);
-  assert(idx >= 0);
-  pn_list_del(selector->selectables, idx, 1);
-  size_t size = pn_list_size(selector->selectables);
-  for (size_t i = idx; i < size; i++) {
-    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
-    pni_selectable_set_index(sel, i);
-    selector->fds[i] = selector->fds[i + 1];
-  }
-
-  pni_selectable_set_index(selectable, -1);
-
-  if (selector->current >= (size_t) idx) {
-    selector->current--;
-  }
-}
-
-size_t pn_selector_size(pn_selector_t *selector) {
-  assert(selector);
-  return pn_list_size(selector->selectables);
-}
-
-int pn_selector_select(pn_selector_t *selector, int timeout)
-{
-  assert(selector);
-
-  size_t size = pn_list_size(selector->selectables);
-
-  if (timeout) {
-    pn_timestamp_t deadline = 0;
-    for (size_t i = 0; i < size; i++) {
-      pn_timestamp_t d = selector->deadlines[i];
-      if (d)
-        deadline = (deadline == 0) ? d : pn_min(deadline, d);
-    }
-
-    if (deadline) {
-      pn_timestamp_t now = pn_i_now();
-      int64_t delta = deadline - now;
-      if (delta < 0) {
-        timeout = 0;
-      } else if (delta < timeout) {
-        timeout = delta;
-      }
-    }
-  }
-
-  int error = 0;
-  int result = poll(selector->fds, size, timeout);
-  if (result == -1) {
-    error = pn_i_error_from_errno(selector->error, "poll");
-  } else {
-    selector->current = 0;
-    selector->awoken = pn_i_now();
-  }
-
-  return error;
-}
-
-pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
-{
-  pn_list_t *l = selector->selectables;
-  size_t size = pn_list_size(l);
-  while (selector->current < size) {
-    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(l, selector->current);
-    struct pollfd *pfd = &selector->fds[selector->current];
-    pn_timestamp_t deadline = selector->deadlines[selector->current];
-    int ev = 0;
-    if (pfd->revents & POLLIN) {
-      ev |= PN_READABLE;
-    }
-    if ((pfd->revents & POLLERR) ||
-        (pfd->revents & POLLHUP) ||
-        (pfd->revents & POLLNVAL)) {
-      ev |= PN_ERROR;
-    }
-    if (pfd->revents & POLLOUT) {
-      ev |= PN_WRITABLE;
-    }
-    if (deadline && selector->awoken >= deadline) {
-      ev |= PN_EXPIRED;
-    }
-    selector->current++;
-    if (ev) {
-      *events = ev;
-      return sel;
-    }
-  }
-  return NULL;
-}
-
-void pn_selector_free(pn_selector_t *selector)
-{
-  assert(selector);
-  pn_free(selector);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/acceptor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/acceptor.c b/proton-c/src/reactor/acceptor.c
index f56f7bd..a044748 100644
--- a/proton-c/src/reactor/acceptor.c
+++ b/proton-c/src/reactor/acceptor.c
@@ -19,13 +19,14 @@
  *
  */
 
-#include <proton/io.h>
 #include <proton/sasl.h>
-#include <proton/selector.h>
 #include <proton/transport.h>
 #include <proton/connection.h>
+
+#include "io.h"
 #include "reactor.h"
 #include "selectable.h"
+#include "selector.h"
 
 #include <string.h>
 
@@ -38,7 +39,7 @@ PN_HANDLE(PNI_ACCEPTOR_CONNECTION)
 void pni_acceptor_readable(pn_selectable_t *sel) {
   pn_reactor_t *reactor = (pn_reactor_t *) pni_selectable_get_context(sel);
   char name[1024];
-  pn_socket_t sock = pn_accept(pn_reactor_io(reactor), pn_selectable_get_fd(sel), name, 1024);
+  pn_socket_t sock = pn_accept(pni_reactor_io(reactor), pn_selectable_get_fd(sel), name, 1024);
   pn_handler_t *handler = (pn_handler_t *) pn_record_get(pn_selectable_attachments(sel), PNI_ACCEPTOR_HANDLER);
   if (!handler) { handler = pn_reactor_get_handler(reactor); }
   pn_record_t *record = pn_selectable_attachments(sel);
@@ -67,12 +68,12 @@ void pni_acceptor_readable(pn_selectable_t *sel) {
 void pni_acceptor_finalize(pn_selectable_t *sel) {
   pn_reactor_t *reactor = (pn_reactor_t *) pni_selectable_get_context(sel);
   if (pn_selectable_get_fd(sel) != PN_INVALID_SOCKET) {
-    pn_close(pn_reactor_io(reactor), pn_selectable_get_fd(sel));
+    pn_close(pni_reactor_io(reactor), pn_selectable_get_fd(sel));
   }
 }
 
 pn_acceptor_t *pn_reactor_acceptor(pn_reactor_t *reactor, const char *host, const char *port, pn_handler_t *handler) {
-  pn_socket_t socket = pn_listen(pn_reactor_io(reactor), host, port);
+  pn_socket_t socket = pn_listen(pni_reactor_io(reactor), host, port);
   if (socket == PN_INVALID_SOCKET) {
     return NULL;
   }
@@ -94,7 +95,7 @@ void pn_acceptor_close(pn_acceptor_t *acceptor) {
   if (!pn_selectable_is_terminal(sel)) {
     pn_reactor_t *reactor = (pn_reactor_t *) pni_selectable_get_context(sel);
     pn_socket_t socket = pn_selectable_get_fd(sel);
-    pn_close(pn_reactor_io(reactor), socket);
+    pn_close(pni_reactor_io(reactor), socket);
     pn_selectable_set_fd(sel, PN_INVALID_SOCKET);
     pn_selectable_terminate(sel);
     pn_reactor_update(reactor, sel);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/connection.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/connection.c b/proton-c/src/reactor/connection.c
index d73e386..4bc8b8d 100644
--- a/proton-c/src/reactor/connection.c
+++ b/proton-c/src/reactor/connection.c
@@ -28,6 +28,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#include "io.h"
 #include "selectable.h"
 #include "reactor.h"
 
@@ -187,12 +188,12 @@ void pni_handle_bound(pn_reactor_t *reactor, pn_event_t *event) {
       pn_transport_close_tail(transport);
       pn_transport_close_head(transport);
   } else {
-      pn_socket_t sock = pn_connect(pn_reactor_io(reactor), host, port);
+      pn_socket_t sock = pn_connect(pni_reactor_io(reactor), host, port);
       // invalid sockets are ignored by poll, so we need to do this manualy
       if (sock == PN_INVALID_SOCKET) {
           pn_condition_t *cond = pn_transport_condition(transport);
           pn_condition_set_name(cond, "proton:io");
-          pn_condition_set_description(cond, pn_error_text(pn_io_error(pn_reactor_io(reactor))));
+          pn_condition_set_description(cond, pn_error_text(pn_reactor_error(reactor)));
           pn_transport_close_tail(transport);
           pn_transport_close_head(transport);
       } else {
@@ -215,14 +216,14 @@ static void pni_connection_readable(pn_selectable_t *sel)
   pn_transport_t *transport = pni_transport(sel);
   ssize_t capacity = pn_transport_capacity(transport);
   if (capacity > 0) {
-    ssize_t n = pn_recv(pn_reactor_io(reactor), pn_selectable_get_fd(sel),
+    ssize_t n = pn_recv(pni_reactor_io(reactor), pn_selectable_get_fd(sel),
                         pn_transport_tail(transport), capacity);
     if (n <= 0) {
-      if (n == 0 || !pn_wouldblock(pn_reactor_io(reactor))) {
+      if (n == 0 || !pn_wouldblock(pni_reactor_io(reactor))) {
         if (n < 0) {
           pn_condition_t *cond = pn_transport_condition(transport);
           pn_condition_set_name(cond, "proton:io");
-          pn_condition_set_description(cond, pn_error_text(pn_io_error(pn_reactor_io(reactor))));
+          pn_condition_set_description(cond, pn_error_text(pn_reactor_error(reactor)));
         }
         pn_transport_close_tail(transport);
       }
@@ -246,14 +247,14 @@ static void pni_connection_writable(pn_selectable_t *sel)
   pn_transport_t *transport = pni_transport(sel);
   ssize_t pending = pn_transport_pending(transport);
   if (pending > 0) {
-    ssize_t n = pn_send(pn_reactor_io(reactor), pn_selectable_get_fd(sel),
+    ssize_t n = pn_send(pni_reactor_io(reactor), pn_selectable_get_fd(sel),
                         pn_transport_head(transport), pending);
     if (n < 0) {
-      if (!pn_wouldblock(pn_reactor_io(reactor))) {
+      if (!pn_wouldblock(pni_reactor_io(reactor))) {
         pn_condition_t *cond = pn_transport_condition(transport);
         if (!pn_condition_is_set(cond)) {
           pn_condition_set_name(cond, "proton:io");
-          pn_condition_set_description(cond, pn_error_text(pn_io_error(pn_reactor_io(reactor))));
+          pn_condition_set_description(cond, pn_error_text(pn_reactor_error(reactor)));
         }
         pn_transport_close_head(transport);
       }
@@ -296,7 +297,7 @@ static void pni_connection_finalize(pn_selectable_t *sel) {
   pn_record_t *record = pn_transport_attachments(transport);
   pn_record_set(record, PN_TRANCTX, NULL);
   pn_socket_t fd = pn_selectable_get_fd(sel);
-  pn_close(pn_reactor_io(reactor), fd);
+  pn_close(pni_reactor_io(reactor), fd);
 }
 
 pn_selectable_t *pn_reactor_selectable_transport(pn_reactor_t *reactor, pn_socket_t sock, pn_transport_t *transport) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io.h b/proton-c/src/reactor/io.h
new file mode 100644
index 0000000..24596ec
--- /dev/null
+++ b/proton-c/src/reactor/io.h
@@ -0,0 +1,70 @@
+#ifndef PROTON_IO_H
+#define PROTON_IO_H 1
+
+/*
+ *
+ * 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 "selector.h"
+
+#include <proton/import_export.h>
+#include <proton/error.h>
+#include <proton/type_compat.h>
+#include <stddef.h>
+
+/**
+ * A ::pn_io_t manages IO for a group of pn_socket_t handles.  A
+ * pn_io_t object may have zero or one pn_selector_t selectors
+ * associated with it (see ::pn_io_selector()).  If one is associated,
+ * all the pn_socket_t handles managed by a pn_io_t must use that
+ * pn_selector_t instance.
+ *
+ * The pn_io_t interface is single-threaded. All methods are intended
+ * to be used by one thread at a time, except that multiple threads
+ * may use:
+ *
+ *   ::pn_write()
+ *   ::pn_send()
+ *   ::pn_recv()
+ *   ::pn_close()
+ *   ::pn_selector_select()
+ *
+ * provided at most one thread is calling ::pn_selector_select() and
+ * the other threads are operating on separate pn_socket_t handles.
+ */
+typedef struct pn_io_t pn_io_t;
+
+pn_io_t *pn_io(void);
+void pn_io_free(pn_io_t *io);
+pn_error_t *pn_io_error(pn_io_t *io);
+pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port);
+pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port);
+
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size);
+void pn_close(pn_io_t *io, pn_socket_t socket);
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
+ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
+int pn_pipe(pn_io_t *io, pn_socket_t *dest);
+ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
+ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
+bool pn_wouldblock(pn_io_t *io);
+pn_selector_t *pn_io_selector(pn_io_t *io);
+
+#endif /* io.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/posix/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/posix/io.c b/proton-c/src/reactor/io/posix/io.c
new file mode 100644
index 0000000..5a0de3b
--- /dev/null
+++ b/proton-c/src/reactor/io/posix/io.c
@@ -0,0 +1,342 @@
+/*
+ *
+ * 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 "reactor/io.h"
+#include "reactor/selector.h"
+#include "platform/platform.h" // pn_i_error_from_errno
+
+#include <proton/object.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define MAX_HOST (1024)
+#define MAX_SERV (64)
+
+struct pn_io_t {
+  char host[MAX_HOST];
+  char serv[MAX_SERV];
+  pn_error_t *error;
+  pn_selector_t *selector;
+  bool wouldblock;
+};
+
+void pn_io_initialize(void *obj)
+{
+  pn_io_t *io = (pn_io_t *) obj;
+  io->error = pn_error();
+  io->wouldblock = false;
+  io->selector = NULL;
+}
+
+void pn_io_finalize(void *obj)
+{
+  pn_io_t *io = (pn_io_t *) obj;
+  pn_error_free(io->error);
+}
+
+#define pn_io_hashcode NULL
+#define pn_io_compare NULL
+#define pn_io_inspect NULL
+
+pn_io_t *pn_io(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_io);
+  pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
+  return io;
+}
+
+void pn_io_free(pn_io_t *io)
+{
+  pn_free(io);
+}
+
+pn_error_t *pn_io_error(pn_io_t *io)
+{
+  assert(io);
+  return io->error;
+}
+
+int pn_pipe(pn_io_t *io, pn_socket_t *dest)
+{
+  int n = pipe(dest);
+  if (n) {
+    pn_i_error_from_errno(io->error, "pipe");
+  }
+
+  return n;
+}
+
+static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
+  // this would be nice, but doesn't appear to exist on linux
+  /*
+  int set = 1;
+  if (!setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int))) {
+    pn_i_error_from_errno(io->error, "setsockopt");
+  };
+  */
+
+  int flags = fcntl(sock, F_GETFL);
+  flags |= O_NONBLOCK;
+
+  if (fcntl(sock, F_SETFL, flags) < 0) {
+    pn_i_error_from_errno(io->error, "fcntl");
+  }
+
+  //
+  // Disable the Nagle algorithm on TCP connections.
+  //
+  // Note:  It would be more correct for the "level" argument to be SOL_TCP.  However, there
+  //        are portability issues with this macro so we use IPPROTO_TCP instead.
+  //
+  int tcp_nodelay = 1;
+  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &tcp_nodelay, sizeof(tcp_nodelay)) < 0) {
+    pn_i_error_from_errno(io->error, "setsockopt");
+  }
+}
+
+static inline int pn_create_socket(int af, int protocol);
+
+pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
+{
+  struct addrinfo *addr;
+  struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
+  int code = getaddrinfo(host, port, &hints, &addr);
+  if (code) {
+    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
+    return PN_INVALID_SOCKET;
+  }
+
+  pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
+  if (sock == PN_INVALID_SOCKET) {
+    freeaddrinfo(addr);
+    pn_i_error_from_errno(io->error, "pn_create_socket");
+    return PN_INVALID_SOCKET;
+  }
+
+  int optval = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
+    pn_i_error_from_errno(io->error, "setsockopt");
+    freeaddrinfo(addr);
+    close(sock);
+    return PN_INVALID_SOCKET;
+  }
+
+  if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
+    pn_i_error_from_errno(io->error, "bind");
+    freeaddrinfo(addr);
+    close(sock);
+    return PN_INVALID_SOCKET;
+  }
+
+  freeaddrinfo(addr);
+
+  if (listen(sock, 50) == -1) {
+    pn_i_error_from_errno(io->error, "listen");
+    close(sock);
+    return PN_INVALID_SOCKET;
+  }
+
+  return sock;
+}
+
+pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port)
+{
+  struct addrinfo *addr;
+  struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
+  int code = getaddrinfo(host, port, &hints, &addr);
+  if (code) {
+    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
+    return PN_INVALID_SOCKET;
+  }
+
+  pn_socket_t sock = pn_create_socket(addr->ai_family, addr->ai_protocol);
+  if (sock == PN_INVALID_SOCKET) {
+    pn_i_error_from_errno(io->error, "pn_create_socket");
+    freeaddrinfo(addr);
+    return PN_INVALID_SOCKET;
+  }
+
+  pn_configure_sock(io, sock);
+
+  if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
+    if (errno != EINPROGRESS) {
+      pn_i_error_from_errno(io->error, "connect");
+      freeaddrinfo(addr);
+      close(sock);
+      return PN_INVALID_SOCKET;
+    }
+  }
+
+  freeaddrinfo(addr);
+
+  return sock;
+}
+
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size)
+{
+  struct sockaddr_storage addr;
+  socklen_t addrlen = sizeof(addr);
+  *name = '\0';
+  pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen);
+  if (sock == PN_INVALID_SOCKET) {
+    pn_i_error_from_errno(io->error, "accept");
+    return sock;
+  } else {
+    int code;
+    if ((code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, MAX_HOST, io->serv, MAX_SERV, 0))) {
+      pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
+      if (close(sock) == -1)
+        pn_i_error_from_errno(io->error, "close");
+      return PN_INVALID_SOCKET;
+    } else {
+      pn_configure_sock(io, sock);
+      pni_snprintf(name, size, "%s:%s", io->host, io->serv);
+      return sock;
+    }
+  }
+}
+
+/* Abstract away turning off SIGPIPE */
+#ifdef MSG_NOSIGNAL
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t len) {
+  ssize_t count = send(socket, buf, len, MSG_NOSIGNAL);
+  io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
+  if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
+  return count;
+}
+
+static inline int pn_create_socket(int af, int protocol) {
+  return socket(af, SOCK_STREAM, protocol);
+}
+#elif defined(SO_NOSIGPIPE)
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
+  ssize_t count = send(socket, buf, size, 0);
+  io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
+  if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
+  return count;
+}
+
+static inline int pn_create_socket(int af, int protocol) {
+  int sock;
+  sock = socket(af, SOCK_STREAM, protocol);
+  if (sock == -1) return sock;
+
+  int optval = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) == -1) {
+    close(sock);
+    return -1;
+  }
+  return sock;
+}
+#else
+
+#include <signal.h>
+
+static inline int pn_create_socket(int af, int protocol) {
+  return socket(af, SOCK_STREAM, protocol);
+}
+
+static ssize_t nosigpipe_send(int fd, const void *buffer, size_t size) {
+  sigset_t pendingSignals, oldSignals, newSignals;
+  ssize_t count;
+  int sendErrno, sigmaskErr;
+
+  sigpending(&pendingSignals);
+  int sigpipeIsPending = sigismember(&pendingSignals, SIGPIPE);
+  if (!sigpipeIsPending) {
+    sigemptyset(&newSignals);
+    sigaddset(&newSignals, SIGPIPE);
+    if (sigmaskErr = pthread_sigmask(SIG_BLOCK, (const sigset_t *)&newSignals, (sigset_t *)&oldSignals))
+    {
+      errno = sigmaskErr;
+      return -1;
+    }
+  }
+
+  count = send(fd, buffer, size, 0);
+  if (!sigpipeIsPending) {
+    sendErrno = errno;
+    if (count == -1 && errno == EPIPE) {
+      while (-1 == sigtimedwait(&newSignals, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
+        ; //do nothing
+    }
+    if (sigmaskErr = pthread_sigmask(SIG_SETMASK, (const sigset_t *)&oldSignals, (sigset_t *)NULL))
+    {
+      errno = sigmaskErr;
+      return -1;
+    }
+    errno = sendErrno;
+  }
+  return count;
+}
+
+ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size) {
+  ssize_t count = nosigpipe_send(socket, buf, size);
+  io->wouldblock = (errno == EAGAIN || errno == EWOULDBLOCK);
+  if (count < 0) { pn_i_error_from_errno(io->error, "send"); }
+  return count;
+}
+#endif
+
+ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+  ssize_t count = recv(socket, buf, size, 0);
+  io->wouldblock = count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK);
+  if (count < 0) { pn_i_error_from_errno(io->error, "recv"); }
+  return count;
+}
+
+ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
+{
+  return write(socket, buf, size);
+}
+
+ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+  return read(socket, buf, size);
+}
+
+void pn_close(pn_io_t *io, pn_socket_t socket)
+{
+  close(socket);
+}
+
+bool pn_wouldblock(pn_io_t *io)
+{
+  return io->wouldblock;
+}
+
+pn_selector_t *pn_io_selector(pn_io_t *io)
+{
+  if (io->selector == NULL)
+    io->selector = pni_selector();
+  return io->selector;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/posix/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/posix/selector.c b/proton-c/src/reactor/io/posix/selector.c
new file mode 100644
index 0000000..bf6882a
--- /dev/null
+++ b/proton-c/src/reactor/io/posix/selector.c
@@ -0,0 +1,214 @@
+/*
+ *
+ * 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 "core/util.h"
+#include "platform/platform.h" // pn_i_now, pn_i_error_from_errno
+#include "reactor/io.h"
+#include "reactor/selector.h"
+#include "reactor/selectable.h"
+
+#include <proton/error.h>
+
+#include <poll.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct pn_selector_t {
+  struct pollfd *fds;
+  pn_timestamp_t *deadlines;
+  size_t capacity;
+  pn_list_t *selectables;
+  size_t current;
+  pn_timestamp_t awoken;
+  pn_error_t *error;
+};
+
+void pn_selector_initialize(void *obj)
+{
+  pn_selector_t *selector = (pn_selector_t *) obj;
+  selector->fds = NULL;
+  selector->deadlines = NULL;
+  selector->capacity = 0;
+  selector->selectables = pn_list(PN_WEAKREF, 0);
+  selector->current = 0;
+  selector->awoken = 0;
+  selector->error = pn_error();
+}
+
+void pn_selector_finalize(void *obj)
+{
+  pn_selector_t *selector = (pn_selector_t *) obj;
+  free(selector->fds);
+  free(selector->deadlines);
+  pn_free(selector->selectables);
+  pn_error_free(selector->error);
+}
+
+#define pn_selector_hashcode NULL
+#define pn_selector_compare NULL
+#define pn_selector_inspect NULL
+
+pn_selector_t *pni_selector(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_selector);
+  pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
+  return selector;
+}
+
+void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+  assert(selector);
+  assert(selectable);
+  assert(pni_selectable_get_index(selectable) < 0);
+
+  if (pni_selectable_get_index(selectable) < 0) {
+    pn_list_add(selector->selectables, selectable);
+    size_t size = pn_list_size(selector->selectables);
+
+    if (selector->capacity < size) {
+      selector->fds = (struct pollfd *) realloc(selector->fds, size*sizeof(struct pollfd));
+      selector->deadlines = (pn_timestamp_t *) realloc(selector->deadlines, size*sizeof(pn_timestamp_t));
+      selector->capacity = size;
+    }
+
+    pni_selectable_set_index(selectable, size - 1);
+  }
+
+  pn_selector_update(selector, selectable);
+}
+
+void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+  int idx = pni_selectable_get_index(selectable);
+  assert(idx >= 0);
+  selector->fds[idx].fd = pn_selectable_get_fd(selectable);
+  selector->fds[idx].events = 0;
+  selector->fds[idx].revents = 0;
+  if (pn_selectable_is_reading(selectable)) {
+    selector->fds[idx].events |= POLLIN;
+  }
+  if (pn_selectable_is_writing(selectable)) {
+    selector->fds[idx].events |= POLLOUT;
+  }
+  selector->deadlines[idx] = pn_selectable_get_deadline(selectable);
+}
+
+void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+  assert(selector);
+  assert(selectable);
+
+  int idx = pni_selectable_get_index(selectable);
+  assert(idx >= 0);
+  pn_list_del(selector->selectables, idx, 1);
+  size_t size = pn_list_size(selector->selectables);
+  for (size_t i = idx; i < size; i++) {
+    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
+    pni_selectable_set_index(sel, i);
+    selector->fds[i] = selector->fds[i + 1];
+  }
+
+  pni_selectable_set_index(selectable, -1);
+
+  if (selector->current >= (size_t) idx) {
+    selector->current--;
+  }
+}
+
+size_t pn_selector_size(pn_selector_t *selector) {
+  assert(selector);
+  return pn_list_size(selector->selectables);
+}
+
+int pn_selector_select(pn_selector_t *selector, int timeout)
+{
+  assert(selector);
+
+  size_t size = pn_list_size(selector->selectables);
+
+  if (timeout) {
+    pn_timestamp_t deadline = 0;
+    for (size_t i = 0; i < size; i++) {
+      pn_timestamp_t d = selector->deadlines[i];
+      if (d)
+        deadline = (deadline == 0) ? d : pn_min(deadline, d);
+    }
+
+    if (deadline) {
+      pn_timestamp_t now = pn_i_now();
+      int64_t delta = deadline - now;
+      if (delta < 0) {
+        timeout = 0;
+      } else if (delta < timeout) {
+        timeout = delta;
+      }
+    }
+  }
+
+  int error = 0;
+  int result = poll(selector->fds, size, timeout);
+  if (result == -1) {
+    error = pn_i_error_from_errno(selector->error, "poll");
+  } else {
+    selector->current = 0;
+    selector->awoken = pn_i_now();
+  }
+
+  return error;
+}
+
+pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
+{
+  pn_list_t *l = selector->selectables;
+  size_t size = pn_list_size(l);
+  while (selector->current < size) {
+    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(l, selector->current);
+    struct pollfd *pfd = &selector->fds[selector->current];
+    pn_timestamp_t deadline = selector->deadlines[selector->current];
+    int ev = 0;
+    if (pfd->revents & POLLIN) {
+      ev |= PN_READABLE;
+    }
+    if ((pfd->revents & POLLERR) ||
+        (pfd->revents & POLLHUP) ||
+        (pfd->revents & POLLNVAL)) {
+      ev |= PN_ERROR;
+    }
+    if (pfd->revents & POLLOUT) {
+      ev |= PN_WRITABLE;
+    }
+    if (deadline && selector->awoken >= deadline) {
+      ev |= PN_EXPIRED;
+    }
+    selector->current++;
+    if (ev) {
+      *events = ev;
+      return sel;
+    }
+  }
+  return NULL;
+}
+
+void pn_selector_free(pn_selector_t *selector)
+{
+  assert(selector);
+  pn_free(selector);
+}


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


[12/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/transport.c b/proton-c/src/core/transport.c
new file mode 100644
index 0000000..e3b88b1
--- /dev/null
+++ b/proton-c/src/core/transport.c
@@ -0,0 +1,3019 @@
+/*
+ *
+ * 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 "engine-internal.h"
+#include "framing.h"
+#include "platform/platform.h"
+#include "platform/platform_fmt.h"
+#include "sasl/sasl-internal.h"
+#include "ssl/ssl-internal.h"
+
+#include "autodetect.h"
+#include "protocol.h"
+#include "dispatch_actions.h"
+#include "config.h"
+#include "log_private.h"
+
+#include "proton/event.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+static ssize_t transport_consume(pn_transport_t *transport);
+
+// delivery buffers
+
+/*
+ * Call this any time anything happens that may affect channel_max:
+ * i.e. when the app indicates a preference, or when we receive the
+ * OPEN frame from the remote peer.  And call it to do the final
+ * calculation just before we communicate our limit to the remote
+ * peer by sending our OPEN frame.
+ */
+static void pni_calculate_channel_max(pn_transport_t *transport) {
+  /*
+   * The application cannot make the limit larger than
+   * what this library will allow.
+   */
+  transport->channel_max = (PN_IMPL_CHANNEL_MAX < transport->local_channel_max)
+                           ? PN_IMPL_CHANNEL_MAX
+                           : transport->local_channel_max;
+
+  /*
+   * The remote peer's constraint is not valid until the
+   * peer's open frame has been received.
+   */
+  if(transport->open_rcvd) {
+    transport->channel_max = (transport->channel_max < transport->remote_channel_max)
+                             ? transport->channel_max
+                             : transport->remote_channel_max;
+  }
+}
+
+void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next)
+{
+  db->deliveries = pn_hash(PN_WEAKREF, 0, 0.75);
+  db->next = next;
+}
+
+void pn_delivery_map_free(pn_delivery_map_t *db)
+{
+  pn_free(db->deliveries);
+}
+
+static pn_delivery_t *pni_delivery_map_get(pn_delivery_map_t *db, pn_sequence_t id)
+{
+  return (pn_delivery_t *) pn_hash_get(db->deliveries, id);
+}
+
+static void pn_delivery_state_init(pn_delivery_state_t *ds, pn_delivery_t *delivery, pn_sequence_t id)
+{
+  ds->id = id;
+  ds->sent = false;
+  ds->init = true;
+}
+
+static pn_delivery_state_t *pni_delivery_map_push(pn_delivery_map_t *db, pn_delivery_t *delivery)
+{
+  pn_delivery_state_t *ds = &delivery->state;
+  pn_delivery_state_init(ds, delivery, db->next++);
+  pn_hash_put(db->deliveries, ds->id, delivery);
+  return ds;
+}
+
+void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery)
+{
+  if (delivery->state.init) {
+    delivery->state.init = false;
+    delivery->state.sent = false;
+    pn_hash_del(db->deliveries, delivery->state.id);
+  }
+}
+
+static void pni_delivery_map_clear(pn_delivery_map_t *dm)
+{
+  pn_hash_t *hash = dm->deliveries;
+  for (pn_handle_t entry = pn_hash_head(hash);
+       entry;
+       entry = pn_hash_next(hash, entry))
+  {
+    pn_delivery_t *dlv = (pn_delivery_t *) pn_hash_value(hash, entry);
+    pn_delivery_map_del(dm, dlv);
+  }
+  dm->next = 0;
+}
+
+static void pni_default_tracer(pn_transport_t *transport, const char *message)
+{
+  fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
+}
+
+static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );
+static ssize_t pn_io_layer_output_passthru(pn_transport_t *, unsigned int, char *, size_t );
+
+static ssize_t pn_io_layer_input_error(pn_transport_t *, unsigned int, const char *, size_t );
+static ssize_t pn_io_layer_output_error(pn_transport_t *, unsigned int, char *, size_t );
+
+static ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+
+static ssize_t pn_input_read_amqp_header(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_input_read_amqp(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_output_write_amqp_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+static ssize_t pn_output_write_amqp(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+static void pn_error_amqp(pn_transport_t *transport, unsigned int layer);
+static pn_timestamp_t pn_tick_amqp(pn_transport_t *transport, unsigned int layer, pn_timestamp_t now);
+
+static ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
+static ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available);
+
+const pn_io_layer_t amqp_header_layer = {
+    pn_input_read_amqp_header,
+    pn_output_write_amqp_header,
+    NULL,
+    pn_tick_amqp,
+    NULL
+};
+
+const pn_io_layer_t amqp_write_header_layer = {
+    pn_input_read_amqp,
+    pn_output_write_amqp_header,
+    NULL,
+    pn_tick_amqp,
+    NULL
+};
+
+const pn_io_layer_t amqp_read_header_layer = {
+    pn_input_read_amqp_header,
+    pn_output_write_amqp,
+    pn_error_amqp,
+    pn_tick_amqp,
+    NULL
+};
+
+const pn_io_layer_t amqp_layer = {
+    pn_input_read_amqp,
+    pn_output_write_amqp,
+    pn_error_amqp,
+    pn_tick_amqp,
+    NULL
+};
+
+const pn_io_layer_t pni_setup_layer = {
+    pn_io_layer_input_setup,
+    pn_io_layer_output_setup,
+    NULL,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t pni_autodetect_layer = {
+    pn_io_layer_input_autodetect,
+    pn_io_layer_output_null,
+    NULL,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t pni_passthru_layer = {
+    pn_io_layer_input_passthru,
+    pn_io_layer_output_passthru,
+    NULL,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t pni_header_error_layer = {
+    pn_io_layer_input_error,
+    pn_output_write_amqp_header,
+    NULL,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t pni_error_layer = {
+    pn_io_layer_input_error,
+    pn_io_layer_output_error,
+    pn_error_amqp,
+    NULL,
+    NULL
+};
+
+/* Set up the transport protocol layers depending on what is configured */
+static void pn_io_layer_setup(pn_transport_t *transport, unsigned int layer)
+{
+  assert(layer == 0);
+  // Figure out if we are server or not
+  if (transport->server) {
+      transport->io_layers[layer++] = &pni_autodetect_layer;
+      return;
+  }
+  if (transport->ssl) {
+    transport->io_layers[layer++] = &ssl_layer;
+  }
+  if (transport->sasl) {
+    transport->io_layers[layer++] = &sasl_header_layer;
+  }
+  transport->io_layers[layer++] = &amqp_header_layer;
+}
+
+ssize_t pn_io_layer_input_setup(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
+{
+  pn_io_layer_setup(transport, layer);
+  return transport->io_layers[layer]->process_input(transport, layer, bytes, available);
+}
+
+ssize_t pn_io_layer_output_setup(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
+{
+  pn_io_layer_setup(transport, layer);
+  return transport->io_layers[layer]->process_output(transport, layer, bytes, available);
+}
+
+void pn_set_error_layer(pn_transport_t *transport)
+{
+  // Set every layer to the error layer in case we manually
+  // pass through (happens from SASL to AMQP)
+  for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
+    transport->io_layers[layer] = &pni_error_layer;
+  }
+}
+
+// Autodetect the layer by reading the protocol header
+ssize_t pn_io_layer_input_autodetect(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available)
+{
+  const char* error;
+  bool eos = pn_transport_capacity(transport)==PN_EOS;
+  if (eos && available==0) {
+    pn_do_error(transport, "amqp:connection:framing-error", "No valid protocol header found");
+    pn_set_error_layer(transport);
+    return PN_EOS;
+  }
+  pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+  if (transport->trace & PN_TRACE_DRV)
+      pn_transport_logf(transport, "%s detected", pni_protocol_name(protocol));
+  switch (protocol) {
+  case PNI_PROTOCOL_SSL:
+    if (!(transport->allowed_layers & LAYER_SSL)) {
+      error = "SSL protocol header not allowed (maybe detected twice)";
+      break;
+    }
+    transport->present_layers |= LAYER_SSL;
+    transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
+    if (!transport->ssl) {
+      pn_ssl(transport);
+    }
+    transport->io_layers[layer] = &ssl_layer;
+    transport->io_layers[layer+1] = &pni_autodetect_layer;
+    return ssl_layer.process_input(transport, layer, bytes, available);
+  case PNI_PROTOCOL_AMQP_SSL:
+    if (!(transport->allowed_layers & LAYER_AMQPSSL)) {
+      error = "AMQP SSL protocol header not allowed (maybe detected twice)";
+      break;
+    }
+    transport->present_layers |= LAYER_AMQPSSL;
+    transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSASL;
+    if (!transport->ssl) {
+      pn_ssl(transport);
+    }
+    transport->io_layers[layer] = &ssl_layer;
+    transport->io_layers[layer+1] = &pni_autodetect_layer;
+    return 8;
+  case PNI_PROTOCOL_AMQP_SASL:
+    if (!(transport->allowed_layers & LAYER_AMQPSASL)) {
+      error = "AMQP SASL protocol header not allowed (maybe detected twice)";
+      break;
+    }
+    transport->present_layers |= LAYER_AMQPSASL;
+    transport->allowed_layers &= LAYER_AMQP1 | LAYER_AMQPSSL;
+    if (!transport->sasl) {
+      pn_sasl(transport);
+    }
+    transport->io_layers[layer] = &sasl_write_header_layer;
+    transport->io_layers[layer+1] = &pni_autodetect_layer;
+    if (transport->trace & PN_TRACE_FRM)
+        pn_transport_logf(transport, "  <- %s", "SASL");
+    pni_sasl_set_external_security(transport, pn_ssl_get_ssf((pn_ssl_t*)transport), pn_ssl_get_remote_subject((pn_ssl_t*)transport));
+    return 8;
+  case PNI_PROTOCOL_AMQP1:
+    if (!(transport->allowed_layers & LAYER_AMQP1)) {
+      error = "AMQP1.0 protocol header not allowed (maybe detected twice)";
+      break;
+    }
+    transport->present_layers |= LAYER_AMQP1;
+    transport->allowed_layers = LAYER_NONE;
+    if (transport->auth_required && !pn_transport_is_authenticated(transport)) {
+      pn_do_error(transport, "amqp:connection:policy-error",
+                  "Client skipped authentication - forbidden");
+      pn_set_error_layer(transport);
+      return 8;
+    }
+    if (transport->encryption_required && !pn_transport_is_encrypted(transport)) {
+      pn_do_error(transport, "amqp:connection:policy-error",
+                  "Client connection unencryted - forbidden");
+      pn_set_error_layer(transport);
+      return 8;
+    }
+    transport->io_layers[layer] = &amqp_write_header_layer;
+    if (transport->trace & PN_TRACE_FRM)
+        pn_transport_logf(transport, "  <- %s", "AMQP");
+    return 8;
+  case PNI_PROTOCOL_INSUFFICIENT:
+    if (!eos) return 0;
+    error = "End of input stream before protocol detection";
+    break;
+  case PNI_PROTOCOL_AMQP_OTHER:
+    error = "Incompatible AMQP connection detected";
+    break;
+  case PNI_PROTOCOL_UNKNOWN:
+  default:
+    error = "Unknown protocol detected";
+    break;
+  }
+  transport->io_layers[layer] = &pni_header_error_layer;
+  char quoted[1024];
+  pn_quote_data(quoted, 1024, bytes, available);
+  pn_do_error(transport, "amqp:connection:framing-error",
+              "%s: '%s'%s", error, quoted,
+              !eos ? "" : " (connection aborted)");
+  return 0;
+}
+
+// We don't know what the output should be - do nothing
+ssize_t pn_io_layer_output_null(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available)
+{
+  return 0;
+}
+
+/** Pass through input handler */
+ssize_t pn_io_layer_input_passthru(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
+{
+    if (layer+1<PN_IO_LAYER_CT)
+        return transport->io_layers[layer+1]->process_input(transport, layer+1, data, available);
+    return PN_EOS;
+}
+
+/** Pass through output handler */
+ssize_t pn_io_layer_output_passthru(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
+{
+    if (layer+1<PN_IO_LAYER_CT)
+        return transport->io_layers[layer+1]->process_output(transport, layer+1, data, available);
+    return PN_EOS;
+}
+
+/** Input handler after detected error */
+ssize_t pn_io_layer_input_error(pn_transport_t *transport, unsigned int layer, const char *data, size_t available)
+{
+    return PN_EOS;
+}
+
+/** Output handler after detected error */
+ssize_t pn_io_layer_output_error(pn_transport_t *transport, unsigned int layer, char *data, size_t available)
+{
+    return PN_EOS;
+}
+
+static void pn_transport_initialize(void *object)
+{
+  pn_transport_t *transport = (pn_transport_t *)object;
+  transport->freed = false;
+  transport->output_buf = NULL;
+  transport->output_size = PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
+  transport->input_buf = NULL;
+  transport->input_size =  PN_DEFAULT_MAX_FRAME_SIZE ? PN_DEFAULT_MAX_FRAME_SIZE : 16 * 1024;
+  transport->tracer = pni_default_tracer;
+  transport->sasl = NULL;
+  transport->ssl = NULL;
+
+  transport->scratch = pn_string(NULL);
+  transport->args = pn_data(16);
+  transport->output_args = pn_data(16);
+  transport->frame = pn_buffer(PN_TRANSPORT_INITIAL_FRAME_SIZE);
+  transport->input_frames_ct = 0;
+  transport->output_frames_ct = 0;
+
+  transport->connection = NULL;
+  transport->context = pn_record();
+
+  for (int layer=0; layer<PN_IO_LAYER_CT; ++layer) {
+    transport->io_layers[layer] = NULL;
+  }
+
+  transport->allowed_layers = LAYER_AMQP1 | LAYER_AMQPSASL | LAYER_AMQPSSL | LAYER_SSL;
+  transport->present_layers = LAYER_NONE;
+
+  // Defer setting up the layers until the first data arrives or is sent
+  transport->io_layers[0] = &pni_setup_layer;
+
+  transport->open_sent = false;
+  transport->open_rcvd = false;
+  transport->close_sent = false;
+  transport->close_rcvd = false;
+  transport->tail_closed = false;
+  transport->head_closed = false;
+  transport->remote_container = NULL;
+  transport->remote_hostname = NULL;
+  transport->local_max_frame = PN_DEFAULT_MAX_FRAME_SIZE;
+  transport->remote_max_frame = (uint32_t) 0xffffffff;
+
+  /*
+   * We set the local limit on channels to 2^15, because
+   * parts of the code use the topmost bit (of a short)
+   * as a flag.
+   * The peer that this transport connects to may also
+   * place its own limit on max channel number, and the
+   * application may also set a limit.
+   * The maximum that we use will be the minimum of all
+   * these constraints.
+   */
+  // There is no constraint yet from remote peer,
+  // so set to max possible.
+  transport->remote_channel_max = 65535;
+  transport->local_channel_max  = PN_IMPL_CHANNEL_MAX;
+  transport->channel_max        = transport->local_channel_max;
+
+  transport->local_idle_timeout = 0;
+  transport->dead_remote_deadline = 0;
+  transport->last_bytes_input = 0;
+  transport->remote_idle_timeout = 0;
+  transport->keepalive_deadline = 0;
+  transport->last_bytes_output = 0;
+  transport->remote_offered_capabilities = pn_data(0);
+  transport->remote_desired_capabilities = pn_data(0);
+  transport->remote_properties = pn_data(0);
+  transport->disp_data = pn_data(0);
+  pn_condition_init(&transport->remote_condition);
+  pn_condition_init(&transport->condition);
+  transport->error = pn_error();
+
+  transport->local_channels = pn_hash(PN_WEAKREF, 0, 0.75);
+  transport->remote_channels = pn_hash(PN_WEAKREF, 0, 0.75);
+
+  transport->bytes_input = 0;
+  transport->bytes_output = 0;
+
+  transport->input_pending = 0;
+  transport->output_pending = 0;
+
+  transport->done_processing = false;
+
+  transport->posted_idle_timeout = false;
+
+  transport->server = false;
+  transport->halt = false;
+  transport->auth_required = false;
+  transport->authenticated = false;
+  transport->encryption_required = false;
+
+  transport->referenced = true;
+
+  transport->trace =
+    (pn_env_bool("PN_TRACE_RAW") ? PN_TRACE_RAW : PN_TRACE_OFF) |
+    (pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
+    (pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF) |
+    (pn_env_bool("PN_TRACE_EVT") ? PN_TRACE_EVT : PN_TRACE_OFF) ;
+}
+
+
+static pn_session_t *pni_channel_state(pn_transport_t *transport, uint16_t channel)
+{
+  return (pn_session_t *) pn_hash_get(transport->remote_channels, channel);
+}
+
+static void pni_map_remote_channel(pn_session_t *session, uint16_t channel)
+{
+  pn_transport_t *transport = session->connection->transport;
+  pn_hash_put(transport->remote_channels, channel, session);
+  session->state.remote_channel = channel;
+  pn_ep_incref(&session->endpoint);
+}
+
+void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state);
+
+static void pni_unmap_remote_channel(pn_session_t *ssn)
+{
+  // XXX: should really update link state also
+  pni_delivery_map_clear(&ssn->state.incoming);
+  pni_transport_unbind_handles(ssn->state.remote_handles, false);
+  pn_transport_t *transport = ssn->connection->transport;
+  uint16_t channel = ssn->state.remote_channel;
+  ssn->state.remote_channel = -2;
+  if (pn_hash_get(transport->remote_channels, channel)) {
+    pn_ep_decref(&ssn->endpoint);
+  }
+  // note: may free the session:
+  pn_hash_del(transport->remote_channels, channel);
+}
+
+static void pn_transport_incref(void *object)
+{
+  pn_transport_t *transport = (pn_transport_t *) object;
+  if (!transport->referenced) {
+    transport->referenced = true;
+    if (transport->connection) {
+      pn_incref(transport->connection);
+    } else {
+      pn_object_incref(object);
+    }
+  } else {
+    pn_object_incref(object);
+  }
+}
+
+static void pn_transport_finalize(void *object);
+#define pn_transport_new pn_object_new
+#define pn_transport_refcount pn_object_refcount
+#define pn_transport_decref pn_object_decref
+#define pn_transport_reify pn_object_reify
+#define pn_transport_hashcode NULL
+#define pn_transport_compare NULL
+#define pn_transport_inspect NULL
+
+pn_transport_t *pn_transport(void)
+{
+#define pn_transport_free pn_object_free
+  static const pn_class_t clazz = PN_METACLASS(pn_transport);
+#undef pn_transport_free
+  pn_transport_t *transport =
+    (pn_transport_t *) pn_class_new(&clazz, sizeof(pn_transport_t));
+  if (!transport) return NULL;
+
+  transport->output_buf = (char *) malloc(transport->output_size);
+  if (!transport->output_buf) {
+    pn_transport_free(transport);
+    return NULL;
+  }
+
+  transport->input_buf = (char *) malloc(transport->input_size);
+  if (!transport->input_buf) {
+    pn_transport_free(transport);
+    return NULL;
+  }
+
+  transport->capacity = 4*1024;
+  transport->available = 0;
+  transport->output = (char *) malloc(transport->capacity);
+  if (!transport->output) {
+    pn_transport_free(transport);
+    return NULL;
+  }
+
+  return transport;
+}
+
+void pn_transport_set_server(pn_transport_t *transport)
+{
+  assert(transport);
+  transport->server = true;
+}
+
+const char *pn_transport_get_user(pn_transport_t *transport)
+{
+  assert(transport);
+  // Client - just return whatever we gave to sasl
+  if (!transport->server) {
+    if (transport->sasl) return pn_sasl_get_user((pn_sasl_t *)transport);
+    return "anonymous";
+  }
+
+  // Server
+  // Not finished authentication yet
+  if (!(transport->present_layers & LAYER_AMQP1)) return 0;
+  // We have SASL so it takes precedence
+  if (transport->present_layers & LAYER_AMQPSASL) return pn_sasl_get_user((pn_sasl_t *)transport);
+  // No SASL but we may have a SSL remote_subject
+  if (transport->present_layers & (LAYER_AMQPSSL | LAYER_SSL)) return pn_ssl_get_remote_subject((pn_ssl_t *)transport);
+  // otherwise it's just an unauthenticated anonymous connection
+  return "anonymous";
+}
+
+void pn_transport_require_auth(pn_transport_t *transport, bool required)
+{
+  assert(transport);
+  transport->auth_required = required;
+}
+
+bool pn_transport_is_authenticated(pn_transport_t *transport)
+{
+  return transport && transport->authenticated;
+}
+
+void pn_transport_require_encryption(pn_transport_t *transport, bool required)
+{
+  assert(transport);
+  transport->encryption_required = required;
+}
+
+bool pn_transport_is_encrypted(pn_transport_t *transport)
+{
+    return transport && transport->ssl && pn_ssl_get_ssf((pn_ssl_t*)transport)>0;
+}
+
+void pn_transport_free(pn_transport_t *transport)
+{
+  if (!transport) return;
+  assert(!transport->freed);
+  transport->freed = true;
+  pn_decref(transport);
+}
+
+static void pn_transport_finalize(void *object)
+{
+  pn_transport_t *transport = (pn_transport_t *) object;
+
+  if (transport->referenced && transport->connection && pn_refcount(transport->connection) > 1) {
+    pn_object_incref(transport);
+    transport->referenced = false;
+    pn_decref(transport->connection);
+    return;
+  }
+
+  // once the application frees the transport, no further I/O
+  // processing can be done to the connection:
+  pn_transport_unbind(transport);
+  // we may have posted events, so stay alive until they are processed
+  if (pn_refcount(transport) > 0) return;
+
+  pn_ssl_free(transport);
+  pn_sasl_free(transport);
+  free(transport->remote_container);
+  free(transport->remote_hostname);
+  pn_free(transport->remote_offered_capabilities);
+  pn_free(transport->remote_desired_capabilities);
+  pn_free(transport->remote_properties);
+  pn_free(transport->disp_data);
+  pn_condition_tini(&transport->remote_condition);
+  pn_condition_tini(&transport->condition);
+  pn_error_free(transport->error);
+  pn_free(transport->local_channels);
+  pn_free(transport->remote_channels);
+  if (transport->input_buf) free(transport->input_buf);
+  if (transport->output_buf) free(transport->output_buf);
+  pn_free(transport->scratch);
+  pn_data_free(transport->args);
+  pn_data_free(transport->output_args);
+  pn_buffer_free(transport->frame);
+  pn_free(transport->context);
+  free(transport->output);
+}
+
+static void pni_post_remote_open_events(pn_transport_t *transport, pn_connection_t *connection) {
+    pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_REMOTE_OPEN);
+    if (transport->remote_idle_timeout) {
+      pn_collector_put(connection->collector, PN_OBJECT, transport, PN_TRANSPORT);
+    }
+}
+
+int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
+{
+  assert(transport);
+  assert(connection);
+
+  if (transport->connection) return PN_STATE_ERR;
+  if (connection->transport) return PN_STATE_ERR;
+
+  transport->connection = connection;
+  connection->transport = transport;
+
+  pn_incref(connection);
+
+  pn_connection_bound(connection);
+
+  // set the hostname/user/password
+  if (pn_string_size(connection->auth_user)) {
+    pn_sasl(transport);
+    pni_sasl_set_user_password(transport, pn_string_get(connection->auth_user), pn_string_get(connection->auth_password));
+  }
+
+  if (pn_string_size(connection->hostname)) {
+      if (transport->sasl) {
+          pni_sasl_set_remote_hostname(transport, pn_string_get(connection->hostname));
+      }
+
+      // be sure not to overwrite a hostname already set by the user via
+      // pn_ssl_set_peer_hostname() called before the bind
+      if (transport->ssl) {
+          size_t name_len = 0;
+          pn_ssl_get_peer_hostname((pn_ssl_t*) transport, NULL, &name_len);
+          if (name_len == 0) {
+              pn_ssl_set_peer_hostname((pn_ssl_t*) transport, pn_string_get(connection->hostname));
+          }
+      }
+  }
+
+  if (transport->open_rcvd) {
+    PN_SET_REMOTE(connection->endpoint.state, PN_REMOTE_ACTIVE);
+    pni_post_remote_open_events(transport, connection);
+    transport->halt = false;
+    transport_consume(transport);        // blech - testBindAfterOpen
+  }
+
+  return 0;
+}
+
+void pni_transport_unbind_handles(pn_hash_t *handles, bool reset_state)
+{
+  for (pn_handle_t h = pn_hash_head(handles); h; h = pn_hash_next(handles, h)) {
+    uintptr_t key = pn_hash_key(handles, h);
+    pn_link_t *link = (pn_link_t *) pn_hash_value(handles, h);
+    if (reset_state) {
+      pn_link_unbound(link);
+    }
+    pn_ep_decref(&link->endpoint);
+    pn_hash_del(handles, key);
+  }
+}
+
+void pni_transport_unbind_channels(pn_hash_t *channels)
+{
+  for (pn_handle_t h = pn_hash_head(channels); h; h = pn_hash_next(channels, h)) {
+    uintptr_t key = pn_hash_key(channels, h);
+    pn_session_t *ssn = (pn_session_t *) pn_hash_value(channels, h);
+    pni_delivery_map_clear(&ssn->state.incoming);
+    pni_delivery_map_clear(&ssn->state.outgoing);
+    pni_transport_unbind_handles(ssn->state.local_handles, true);
+    pni_transport_unbind_handles(ssn->state.remote_handles, true);
+    pn_session_unbound(ssn);
+    pn_ep_decref(&ssn->endpoint);
+    pn_hash_del(channels, key);
+  }
+}
+
+int pn_transport_unbind(pn_transport_t *transport)
+{
+  assert(transport);
+  if (!transport->connection) return 0;
+
+
+  pn_connection_t *conn = transport->connection;
+  transport->connection = NULL;
+  bool was_referenced = transport->referenced;
+
+  pn_collector_put(conn->collector, PN_OBJECT, conn, PN_CONNECTION_UNBOUND);
+
+  // XXX: what happens if the endpoints are freed before we get here?
+  pn_session_t *ssn = pn_session_head(conn, 0);
+  while (ssn) {
+    pni_delivery_map_clear(&ssn->state.incoming);
+    pni_delivery_map_clear(&ssn->state.outgoing);
+    ssn = pn_session_next(ssn, 0);
+  }
+
+  pn_endpoint_t *endpoint = conn->endpoint_head;
+  while (endpoint) {
+    pn_condition_clear(&endpoint->remote_condition);
+    pn_modified(conn, endpoint, true);
+    endpoint = endpoint->endpoint_next;
+  }
+
+  pni_transport_unbind_channels(transport->local_channels);
+  pni_transport_unbind_channels(transport->remote_channels);
+
+  pn_connection_unbound(conn);
+  if (was_referenced) {
+    pn_decref(conn);
+  }
+  return 0;
+}
+
+pn_error_t *pn_transport_error(pn_transport_t *transport)
+{
+  assert(transport);
+  if (pn_condition_is_set(&transport->condition)) {
+    pn_error_format(transport->error, PN_ERR, "%s: %s",
+                    pn_condition_get_name(&transport->condition),
+                    pn_condition_get_description(&transport->condition));
+  } else {
+    pn_error_clear(transport->error);
+  }
+  return transport->error;
+}
+
+pn_condition_t *pn_transport_condition(pn_transport_t *transport)
+{
+  assert(transport);
+  return &transport->condition;
+}
+
+static void pni_map_remote_handle(pn_link_t *link, uint32_t handle)
+{
+  link->state.remote_handle = handle;
+  pn_hash_put(link->session->state.remote_handles, handle, link);
+  pn_ep_incref(&link->endpoint);
+}
+
+static void pni_unmap_remote_handle(pn_link_t *link)
+{
+  uintptr_t handle = link->state.remote_handle;
+  link->state.remote_handle = -2;
+  if (pn_hash_get(link->session->state.remote_handles, handle)) {
+    pn_ep_decref(&link->endpoint);
+  }
+  // may delete link:
+  pn_hash_del(link->session->state.remote_handles, handle);
+}
+
+static pn_link_t *pni_handle_state(pn_session_t *ssn, uint32_t handle)
+{
+  return (pn_link_t *) pn_hash_get(ssn->state.remote_handles, handle);
+}
+
+bool pni_disposition_batchable(pn_disposition_t *disposition)
+{
+  switch (disposition->type) {
+  case PN_ACCEPTED:
+    return true;
+  case PN_RELEASED:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static int pni_disposition_encode(pn_disposition_t *disposition, pn_data_t *data)
+{
+  pn_condition_t *cond = &disposition->condition;
+  switch (disposition->type) {
+  case PN_RECEIVED:
+    PN_RETURN_IF_ERROR(pn_data_put_list(data));
+    pn_data_enter(data);
+    PN_RETURN_IF_ERROR(pn_data_put_uint(data, disposition->section_number));
+    PN_RETURN_IF_ERROR(pn_data_put_ulong(data, disposition->section_offset));
+    pn_data_exit(data);
+    return 0;
+  case PN_ACCEPTED:
+  case PN_RELEASED:
+    return 0;
+  case PN_REJECTED:
+    return pn_data_fill(data, "[?DL[sSC]]", pn_condition_is_set(cond), ERROR,
+                 pn_condition_get_name(cond),
+                 pn_condition_get_description(cond),
+                 pn_condition_info(cond));
+  case PN_MODIFIED:
+    return pn_data_fill(data, "[ooC]",
+                 disposition->failed,
+                 disposition->undeliverable,
+                 disposition->annotations);
+  default:
+    return pn_data_copy(data, disposition->data);
+  }
+}
+
+
+void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
+                 pn_data_t *args, const char *payload, size_t size)
+{
+  if (transport->trace & PN_TRACE_FRM) {
+    pn_string_format(transport->scratch, "%u %s ", ch, dir == OUT ? "->" : "<-");
+    pn_inspect(args, transport->scratch);
+
+    if (pn_data_size(args)==0) {
+        pn_string_addf(transport->scratch, "(EMPTY FRAME)");
+    }
+
+    if (size) {
+      char buf[1024];
+      int e = pn_quote_data(buf, 1024, payload, size);
+      pn_string_addf(transport->scratch, " (%" PN_ZU ") \"%s\"%s", size, buf,
+                     e == PN_OVERFLOW ? "... (truncated)" : "");
+    }
+
+    pn_transport_log(transport, pn_string_get(transport->scratch));
+  }
+}
+
+int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...)
+{
+  pn_buffer_t *frame_buf = transport->frame;
+  va_list ap;
+  va_start(ap, fmt);
+  pn_data_clear(transport->output_args);
+  int err = pn_data_vfill(transport->output_args, fmt, ap);
+  va_end(ap);
+  if (err) {
+    pn_transport_logf(transport,
+                      "error posting frame: %s, %s: %s", fmt, pn_code(err),
+                      pn_error_text(pn_data_error(transport->output_args)));
+    return PN_ERR;
+  }
+
+  pn_do_trace(transport, ch, OUT, transport->output_args, NULL, 0);
+
+ encode_performatives:
+  pn_buffer_clear( frame_buf );
+  pn_rwbytes_t buf = pn_buffer_memory( frame_buf );
+  buf.size = pn_buffer_available( frame_buf );
+
+  ssize_t wr = pn_data_encode( transport->output_args, buf.start, buf.size );
+  if (wr < 0) {
+    if (wr == PN_OVERFLOW) {
+      pn_buffer_ensure( frame_buf, pn_buffer_available( frame_buf ) * 2 );
+      goto encode_performatives;
+    }
+    pn_transport_logf(transport,
+                      "error posting frame: %s", pn_code(wr));
+    return PN_ERR;
+  }
+
+  pn_frame_t frame = {0,};
+  frame.type = type;
+  frame.channel = ch;
+  frame.payload = buf.start;
+  frame.size = wr;
+  size_t n;
+  while (!(n = pn_write_frame(transport->output + transport->available,
+                              transport->capacity - transport->available, frame))) {
+    transport->capacity *= 2;
+    transport->output = (char *) realloc(transport->output, transport->capacity);
+  }
+  transport->output_frames_ct += 1;
+  if (transport->trace & PN_TRACE_RAW) {
+    pn_string_set(transport->scratch, "RAW: \"");
+    pn_quote(transport->scratch, transport->output + transport->available, n);
+    pn_string_addf(transport->scratch, "\"");
+    pn_transport_log(transport, pn_string_get(transport->scratch));
+  }
+  transport->available += n;
+
+  return 0;
+}
+
+static int pni_post_amqp_transfer_frame(pn_transport_t *transport, uint16_t ch,
+                                        uint32_t handle,
+                                        pn_sequence_t id,
+                                        pn_bytes_t *payload,
+                                        const pn_bytes_t *tag,
+                                        uint32_t message_format,
+                                        bool settled,
+                                        bool more,
+                                        pn_sequence_t frame_limit,
+                                        uint64_t code,
+                                        pn_data_t* state)
+{
+  bool more_flag = more;
+  int framecount = 0;
+  pn_buffer_t *frame = transport->frame;
+
+  // create preformatives, assuming 'more' flag need not change
+
+ compute_performatives:
+  pn_data_clear(transport->output_args);
+  int err = pn_data_fill(transport->output_args, "DL[IIzIoon?DLC]", TRANSFER,
+                         handle, id, tag->size, tag->start,
+                         message_format,
+                         settled, more_flag, (bool)code, code, state);
+  if (err) {
+    pn_transport_logf(transport,
+                      "error posting transfer frame: %s: %s", pn_code(err),
+                      pn_error_text(pn_data_error(transport->output_args)));
+    return PN_ERR;
+  }
+
+  do { // send as many frames as possible without changing the 'more' flag...
+
+  encode_performatives:
+    pn_buffer_clear( frame );
+    pn_rwbytes_t buf = pn_buffer_memory( frame );
+    buf.size = pn_buffer_available( frame );
+
+    ssize_t wr = pn_data_encode(transport->output_args, buf.start, buf.size);
+    if (wr < 0) {
+      if (wr == PN_OVERFLOW) {
+        pn_buffer_ensure( frame, pn_buffer_available( frame ) * 2 );
+        goto encode_performatives;
+      }
+      pn_transport_logf(transport, "error posting frame: %s", pn_code(wr));
+      return PN_ERR;
+    }
+    buf.size = wr;
+
+    // check if we need to break up the outbound frame
+    size_t available = payload->size;
+    if (transport->remote_max_frame) {
+      if ((available + buf.size) > transport->remote_max_frame - 8) {
+        available = transport->remote_max_frame - 8 - buf.size;
+        if (more_flag == false) {
+          more_flag = true;
+          goto compute_performatives;  // deal with flag change
+        }
+      } else if (more_flag == true && more == false) {
+        // caller has no more, and this is the last frame
+        more_flag = false;
+        goto compute_performatives;
+      }
+    }
+
+    if (pn_buffer_available( frame ) < (available + buf.size)) {
+      // not enough room for payload - try again...
+      pn_buffer_ensure( frame, available + buf.size );
+      goto encode_performatives;
+    }
+
+    pn_do_trace(transport, ch, OUT, transport->output_args, payload->start, available);
+
+    memmove( buf.start + buf.size, payload->start, available);
+    payload->start += available;
+    payload->size -= available;
+    buf.size += available;
+
+    pn_frame_t frame = {AMQP_FRAME_TYPE};
+    frame.channel = ch;
+    frame.payload = buf.start;
+    frame.size = buf.size;
+
+    size_t n;
+    while (!(n = pn_write_frame(transport->output + transport->available,
+                                transport->capacity - transport->available, frame))) {
+      transport->capacity *= 2;
+      transport->output = (char *) realloc(transport->output, transport->capacity);
+    }
+    transport->output_frames_ct += 1;
+    framecount++;
+    if (transport->trace & PN_TRACE_RAW) {
+      pn_string_set(transport->scratch, "RAW: \"");
+      pn_quote(transport->scratch, transport->output + transport->available, n);
+      pn_string_addf(transport->scratch, "\"");
+      pn_transport_log(transport, pn_string_get(transport->scratch));
+    }
+    transport->available += n;
+  } while (payload->size > 0 && framecount < frame_limit);
+
+  return framecount;
+}
+
+static int pni_post_close(pn_transport_t *transport, pn_condition_t *cond)
+{
+  if (!cond && transport->connection) {
+    cond = pn_connection_condition(transport->connection);
+  }
+  const char *condition = NULL;
+  const char *description = NULL;
+  pn_data_t *info = NULL;
+  if (pn_condition_is_set(cond)) {
+    condition = pn_condition_get_name(cond);
+    description = pn_condition_get_description(cond);
+    info = pn_condition_info(cond);
+  }
+
+  return pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[?DL[sSC]]", CLOSE,
+                       (bool) condition, ERROR, condition, description, info);
+}
+
+static pn_collector_t *pni_transport_collector(pn_transport_t *transport)
+{
+  if (transport->connection && transport->connection->collector) {
+    return transport->connection->collector;
+  } else {
+    return NULL;
+  }
+}
+
+static void pni_maybe_post_closed(pn_transport_t *transport)
+{
+  pn_collector_t *collector = pni_transport_collector(transport);
+  if (transport->head_closed && transport->tail_closed) {
+    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_CLOSED);
+  }
+}
+
+static void pni_close_tail(pn_transport_t *transport)
+{
+  if (!transport->tail_closed) {
+    transport->tail_closed = true;
+    pn_collector_t *collector = pni_transport_collector(transport);
+    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_TAIL_CLOSED);
+    pni_maybe_post_closed(transport);
+  }
+}
+
+int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  char buf[1024];
+  if (fmt) {
+    // XXX: result
+    pni_vsnprintf(buf, 1024, fmt, ap);
+  } else {
+    buf[0] = '\0';
+  }
+  va_end(ap);
+  pn_condition_t *cond = &transport->condition;
+  if (!pn_condition_is_set(cond)) {
+    pn_condition_set_name(cond, condition);
+    if (fmt) {
+      pn_condition_set_description(cond, buf);
+    }
+  } else {
+    const char *first = pn_condition_get_description(cond);
+    if (first && fmt) {
+      char extended[2048];
+      pni_snprintf(extended, 2048, "%s (%s)", first, buf);
+      pn_condition_set_description(cond, extended);
+    } else if (fmt) {
+      pn_condition_set_description(cond, buf);
+    }
+  }
+  pn_collector_t *collector = pni_transport_collector(transport);
+  pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT_ERROR);
+  if (transport->trace & PN_TRACE_DRV) {
+    pn_transport_logf(transport, "ERROR %s %s", condition, buf);
+  }
+
+  for (int i = 0; i<PN_IO_LAYER_CT; ++i) {
+    if (transport->io_layers[i] && transport->io_layers[i]->handle_error)
+        transport->io_layers[i]->handle_error(transport, i);
+  }
+
+  pni_close_tail(transport);
+  return PN_ERR;
+}
+
+static char *pn_bytes_strdup(pn_bytes_t str)
+{
+  return pn_strndup(str.start, str.size);
+}
+
+int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_connection_t *conn = transport->connection;
+  bool container_q, hostname_q, remote_channel_max_q, remote_max_frame_q;
+  uint16_t remote_channel_max;
+  uint32_t remote_max_frame;
+  pn_bytes_t remote_container, remote_hostname;
+  pn_data_clear(transport->remote_offered_capabilities);
+  pn_data_clear(transport->remote_desired_capabilities);
+  pn_data_clear(transport->remote_properties);
+  int err = pn_data_scan(args, "D.[?S?S?I?HI..CCC]",
+                         &container_q, &remote_container,
+                         &hostname_q, &remote_hostname,
+                         &remote_max_frame_q, &remote_max_frame,
+                         &remote_channel_max_q, &remote_channel_max,
+                         &transport->remote_idle_timeout,
+                         transport->remote_offered_capabilities,
+                         transport->remote_desired_capabilities,
+                         transport->remote_properties);
+  if (err) return err;
+  /*
+   * The default value is already stored in the variable.
+   * But the scanner zeroes out values if it does not
+   * find them in the args, so don't give the variable
+   * directly to the scanner.
+   */
+  if (remote_channel_max_q) {
+    transport->remote_channel_max = remote_channel_max;
+  }
+
+  if (remote_max_frame_q) {
+    transport->remote_max_frame = remote_max_frame;
+  }
+
+  if (transport->remote_max_frame > 0) {
+    if (transport->remote_max_frame < AMQP_MIN_MAX_FRAME_SIZE) {
+      pn_transport_logf(transport, "Peer advertised bad max-frame (%u), forcing to %u",
+                        transport->remote_max_frame, AMQP_MIN_MAX_FRAME_SIZE);
+      transport->remote_max_frame = AMQP_MIN_MAX_FRAME_SIZE;
+    }
+  }
+  if (container_q) {
+    transport->remote_container = pn_bytes_strdup(remote_container);
+  } else {
+    transport->remote_container = NULL;
+  }
+  if (hostname_q) {
+    transport->remote_hostname = pn_bytes_strdup(remote_hostname);
+  } else {
+    transport->remote_hostname = NULL;
+  }
+
+  if (conn) {
+    PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_ACTIVE);
+    pni_post_remote_open_events(transport, conn);
+  } else {
+    transport->halt = true;
+  }
+  transport->open_rcvd = true;
+  pni_calculate_channel_max(transport);
+  return 0;
+}
+
+int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  bool reply;
+  uint16_t remote_channel;
+  pn_sequence_t next;
+  int err = pn_data_scan(args, "D.[?HI]", &reply, &remote_channel, &next);
+  if (err) return err;
+
+  // AMQP 1.0 section 2.7.1 - if the peer doesn't honor our channel_max --
+  // express our displeasure by closing the connection with a framing error.
+  if (remote_channel > transport->channel_max) {
+    pn_do_error(transport,
+                "amqp:connection:framing-error",
+                "remote channel %d is above negotiated channel_max %d.",
+                remote_channel,
+                transport->channel_max
+               );
+    return PN_TRANSPORT_ERROR;
+  }
+
+  pn_session_t *ssn;
+  if (reply) {
+    ssn = (pn_session_t *) pn_hash_get(transport->local_channels, remote_channel);
+  } else {
+    ssn = pn_session(transport->connection);
+  }
+  if (ssn == 0) {
+    pn_do_error(transport,
+                "amqp:connection:framing-error",
+                "remote channel is above negotiated channel_max %d.",
+                transport->channel_max
+               );
+    return PN_TRANSPORT_ERROR;
+  }
+  ssn->state.incoming_transfer_count = next;
+  pni_map_remote_channel(ssn, channel);
+  PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_ACTIVE);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_OPEN);
+  return 0;
+}
+
+pn_link_t *pn_find_link(pn_session_t *ssn, pn_bytes_t name, bool is_sender)
+{
+  pn_endpoint_type_t type = is_sender ? SENDER : RECEIVER;
+
+  for (size_t i = 0; i < pn_list_size(ssn->links); i++)
+  {
+    pn_link_t *link = (pn_link_t *) pn_list_get(ssn->links, i);
+    if (link->endpoint.type == type &&
+        // This function is used to locate the link object for an
+        // incoming attach. If a link object of the same name is found
+        // 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))
+    {
+      return link;
+    }
+  }
+  return NULL;
+}
+
+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))
+    return PN_EXPIRE_WITH_LINK;
+  if (!strncmp(symbol.start, "session-end", symbol.size))
+    return PN_EXPIRE_WITH_SESSION;
+  if (!strncmp(symbol.start, "connection-close", symbol.size))
+    return PN_EXPIRE_WITH_CONNECTION;
+  if (!strncmp(symbol.start, "never", symbol.size))
+    return PN_EXPIRE_NEVER;
+
+  return PN_EXPIRE_WITH_SESSION;
+}
+
+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))
+    return PN_DIST_MODE_MOVE;
+  if (!strncmp(symbol.start, "copy", symbol.size))
+    return PN_DIST_MODE_COPY;
+
+  return PN_DIST_MODE_UNSPECIFIED;
+}
+
+static const char *dist_mode2symbol(const pn_distribution_mode_t mode)
+{
+  switch (mode)
+  {
+  case PN_DIST_MODE_COPY:
+    return "copy";
+  case PN_DIST_MODE_MOVE:
+    return "move";
+  default:
+    return NULL;
+  }
+}
+
+int pn_terminus_set_address_bytes(pn_terminus_t *terminus, pn_bytes_t address)
+{
+  assert(terminus);
+  return pn_string_setn(terminus->address, address.start, address.size);
+}
+
+int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_bytes_t name;
+  uint32_t handle;
+  bool is_sender;
+  pn_bytes_t source, target;
+  pn_durability_t src_dr, tgt_dr;
+  pn_bytes_t src_exp, tgt_exp;
+  pn_seconds_t src_timeout, tgt_timeout;
+  bool src_dynamic, tgt_dynamic;
+  pn_sequence_t idc;
+  pn_bytes_t dist_mode;
+  bool snd_settle, rcv_settle;
+  uint8_t snd_settle_mode, rcv_settle_mode;
+  int err = pn_data_scan(args, "D.[SIo?B?BD.[SIsIo.s]D.[SIsIo]..I]", &name, &handle,
+                         &is_sender,
+                         &snd_settle, &snd_settle_mode,
+                         &rcv_settle, &rcv_settle_mode,
+                         &source, &src_dr, &src_exp, &src_timeout, &src_dynamic, &dist_mode,
+                         &target, &tgt_dr, &tgt_exp, &tgt_timeout, &tgt_dynamic,
+                         &idc);
+  if (err) return err;
+  char strbuf[128];      // avoid malloc for most link names
+  char *strheap = (name.size >= sizeof(strbuf)) ? (char *) malloc(name.size + 1) : NULL;
+  char *strname = strheap ? strheap : strbuf;
+  strncpy(strname, name.start, name.size);
+  strname[name.size] = '\0';
+
+  pn_session_t *ssn = pni_channel_state(transport, channel);
+  if (!ssn) {
+      pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+      if (strheap) free(strheap);
+      return PN_EOS;
+  }
+  pn_link_t *link = pn_find_link(ssn, name, is_sender);
+  if (!link) {
+    if (is_sender) {
+      link = (pn_link_t *) pn_sender(ssn, strname);
+    } else {
+      link = (pn_link_t *) pn_receiver(ssn, strname);
+    }
+  }
+
+  if (strheap) {
+    free(strheap);
+  }
+
+  pni_map_remote_handle(link, handle);
+  PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_ACTIVE);
+  pn_terminus_t *rsrc = &link->remote_source;
+  if (source.start || src_dynamic) {
+    pn_terminus_set_type(rsrc, PN_SOURCE);
+    pn_terminus_set_address_bytes(rsrc, source);
+    pn_terminus_set_durability(rsrc, src_dr);
+    pn_terminus_set_expiry_policy(rsrc, symbol2policy(src_exp));
+    pn_terminus_set_timeout(rsrc, src_timeout);
+    pn_terminus_set_dynamic(rsrc, src_dynamic);
+    pn_terminus_set_distribution_mode(rsrc, symbol2dist_mode(dist_mode));
+  } else {
+    pn_terminus_set_type(rsrc, PN_UNSPECIFIED);
+  }
+  pn_terminus_t *rtgt = &link->remote_target;
+  if (target.start || tgt_dynamic) {
+    pn_terminus_set_type(rtgt, PN_TARGET);
+    pn_terminus_set_address_bytes(rtgt, target);
+    pn_terminus_set_durability(rtgt, tgt_dr);
+    pn_terminus_set_expiry_policy(rtgt, symbol2policy(tgt_exp));
+    pn_terminus_set_timeout(rtgt, tgt_timeout);
+    pn_terminus_set_dynamic(rtgt, tgt_dynamic);
+  } else {
+    uint64_t code = 0;
+    pn_data_clear(link->remote_target.capabilities);
+    err = pn_data_scan(args, "D.[.....D..DL[C]...]", &code,
+                       link->remote_target.capabilities);
+    if (err) return err;
+    if (code == COORDINATOR) {
+      pn_terminus_set_type(rtgt, PN_COORDINATOR);
+    } else if (code == TARGET) {
+      pn_terminus_set_type(rtgt, PN_TARGET);
+    } else {
+      pn_terminus_set_type(rtgt, PN_UNSPECIFIED);
+    }
+  }
+
+  if (snd_settle)
+    link->remote_snd_settle_mode = snd_settle_mode;
+  if (rcv_settle)
+    link->remote_rcv_settle_mode = rcv_settle_mode;
+
+  pn_data_clear(link->remote_source.properties);
+  pn_data_clear(link->remote_source.filter);
+  pn_data_clear(link->remote_source.outcomes);
+  pn_data_clear(link->remote_source.capabilities);
+  pn_data_clear(link->remote_target.properties);
+  pn_data_clear(link->remote_target.capabilities);
+
+  err = pn_data_scan(args, "D.[.....D.[.....C.C.CC]D.[.....CC]",
+                     link->remote_source.properties,
+                     link->remote_source.filter,
+                     link->remote_source.outcomes,
+                     link->remote_source.capabilities,
+                     link->remote_target.properties,
+                     link->remote_target.capabilities);
+  if (err) return err;
+
+  pn_data_rewind(link->remote_source.properties);
+  pn_data_rewind(link->remote_source.filter);
+  pn_data_rewind(link->remote_source.outcomes);
+  pn_data_rewind(link->remote_source.capabilities);
+  pn_data_rewind(link->remote_target.properties);
+  pn_data_rewind(link->remote_target.capabilities);
+
+  if (!is_sender) {
+    link->state.delivery_count = idc;
+  }
+
+  pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_OPEN);
+  return 0;
+}
+
+static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link);
+
+// free the delivery
+static void pn_full_settle(pn_delivery_map_t *db, pn_delivery_t *delivery)
+{
+  assert(!delivery->work);
+  pn_clear_tpwork(delivery);
+  pn_delivery_map_del(db, delivery);
+  pn_incref(delivery);
+  pn_decref(delivery);
+}
+
+int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  // XXX: multi transfer
+  uint32_t handle;
+  pn_bytes_t tag;
+  bool id_present;
+  pn_sequence_t id;
+  bool settled;
+  bool more;
+  bool has_type;
+  uint64_t type;
+  pn_data_clear(transport->disp_data);
+  int err = pn_data_scan(args, "D.[I?Iz.oo.D?LC]", &handle, &id_present, &id, &tag,
+                         &settled, &more, &has_type, &type, transport->disp_data);
+  if (err) return err;
+  pn_session_t *ssn = pni_channel_state(transport, channel);
+  if (!ssn) {
+    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+  }
+
+  if (!ssn->state.incoming_window) {
+    return pn_do_error(transport, "amqp:session:window-violation", "incoming session window exceeded");
+  }
+
+  pn_link_t *link = pni_handle_state(ssn, handle);
+  if (!link) {
+    return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
+  }
+  pn_delivery_t *delivery;
+  if (link->unsettled_tail && !link->unsettled_tail->done) {
+    delivery = link->unsettled_tail;
+  } else {
+    pn_delivery_map_t *incoming = &ssn->state.incoming;
+
+    if (!ssn->state.incoming_init) {
+      incoming->next = id;
+      ssn->state.incoming_init = true;
+      ssn->incoming_deliveries++;
+    }
+
+    delivery = pn_delivery(link, pn_dtag(tag.start, tag.size));
+    pn_delivery_state_t *state = pni_delivery_map_push(incoming, delivery);
+    if (id_present && id != state->id) {
+      return pn_do_error(transport, "amqp:session:invalid-field",
+                         "sequencing error, expected delivery-id %u, got %u",
+                         state->id, id);
+    }
+    if (has_type) {
+      delivery->remote.type = type;
+      pn_data_copy(delivery->remote.data, transport->disp_data);
+    }
+
+    link->state.delivery_count++;
+    link->state.link_credit--;
+    link->queued++;
+
+    // XXX: need to fill in remote state: delivery->remote.state = ...;
+    delivery->remote.settled = settled;
+    if (settled) {
+      delivery->updated = true;
+      pn_work_update(transport->connection, delivery);
+    }
+  }
+
+  pn_buffer_append(delivery->bytes, payload->start, payload->size);
+  ssn->incoming_bytes += payload->size;
+  delivery->done = !more;
+
+  ssn->state.incoming_transfer_count++;
+  ssn->state.incoming_window--;
+
+  // XXX: need better policy for when to refresh window
+  if (!ssn->state.incoming_window && (int32_t) link->state.local_handle >= 0) {
+    pni_post_flow(transport, ssn, link);
+  }
+
+  pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
+  return 0;
+}
+
+int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_sequence_t onext, inext, delivery_count;
+  uint32_t iwin, owin, link_credit;
+  uint32_t handle;
+  bool inext_init, handle_init, dcount_init, drain;
+  int err = pn_data_scan(args, "D.[?IIII?I?II.o]", &inext_init, &inext, &iwin,
+                         &onext, &owin, &handle_init, &handle, &dcount_init,
+                         &delivery_count, &link_credit, &drain);
+  if (err) return err;
+
+  pn_session_t *ssn = pni_channel_state(transport, channel);
+  if (!ssn) {
+    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+  }
+
+  if (inext_init) {
+    ssn->state.remote_incoming_window = inext + iwin - ssn->state.outgoing_transfer_count;
+  } else {
+    ssn->state.remote_incoming_window = iwin;
+  }
+
+  if (handle_init) {
+    pn_link_t *link = pni_handle_state(ssn, handle);
+    if (!link) {
+      return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
+    }
+    if (link->endpoint.type == SENDER) {
+      pn_sequence_t receiver_count;
+      if (dcount_init) {
+        receiver_count = delivery_count;
+      } else {
+        // our initial delivery count
+        receiver_count = 0;
+      }
+      pn_sequence_t old = link->state.link_credit;
+      link->state.link_credit = receiver_count + link_credit - link->state.delivery_count;
+      link->credit += link->state.link_credit - old;
+      link->drain = drain;
+      pn_delivery_t *delivery = pn_link_current(link);
+      if (delivery) pn_work_update(transport->connection, delivery);
+    } else {
+      pn_sequence_t delta = delivery_count - link->state.delivery_count;
+      if (delta > 0) {
+        link->state.delivery_count += delta;
+        link->state.link_credit -= delta;
+        link->credit -= delta;
+        link->drained += delta;
+      }
+    }
+
+    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
+  }
+
+  return 0;
+}
+
+#define SCAN_ERROR_DEFAULT ("D.[D.[sSC]")
+#define SCAN_ERROR_DETACH ("D.[..D.[sSC]")
+#define SCAN_ERROR_DISP ("[D.[sSC]")
+
+static int pn_scan_error(pn_data_t *data, pn_condition_t *condition, const char *fmt)
+{
+  pn_bytes_t cond;
+  pn_bytes_t desc;
+  pn_condition_clear(condition);
+  int err = pn_data_scan(data, fmt, &cond, &desc, condition->info);
+  if (err) return err;
+  pn_string_setn(condition->name, cond.start, cond.size);
+  pn_string_setn(condition->description, desc.start, desc.size);
+  pn_data_rewind(condition->info);
+  return 0;
+}
+
+int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  bool role;
+  pn_sequence_t first, last;
+  uint64_t type = 0;
+  bool last_init, settled, type_init;
+  pn_data_clear(transport->disp_data);
+  int err = pn_data_scan(args, "D.[oI?IoD?LC]", &role, &first, &last_init,
+                         &last, &settled, &type_init, &type,
+                         transport->disp_data);
+  if (err) return err;
+  if (!last_init) last = first;
+
+  pn_session_t *ssn = pni_channel_state(transport, channel);
+  if (!ssn) {
+    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+  }
+
+  pn_delivery_map_t *deliveries;
+  if (role) {
+    deliveries = &ssn->state.outgoing;
+  } else {
+    deliveries = &ssn->state.incoming;
+  }
+
+  pn_data_rewind(transport->disp_data);
+  bool remote_data = (pn_data_next(transport->disp_data) &&
+                      pn_data_get_list(transport->disp_data) > 0);
+
+  for (pn_sequence_t id = first; id <= last; id++) {
+    pn_delivery_t *delivery = pni_delivery_map_get(deliveries, id);
+    pn_disposition_t *remote = &delivery->remote;
+    if (delivery) {
+      if (type_init) remote->type = type;
+      if (remote_data) {
+        switch (type) {
+        case PN_RECEIVED:
+          pn_data_rewind(transport->disp_data);
+          pn_data_next(transport->disp_data);
+          pn_data_enter(transport->disp_data);
+          if (pn_data_next(transport->disp_data))
+            remote->section_number = pn_data_get_uint(transport->disp_data);
+          if (pn_data_next(transport->disp_data))
+            remote->section_offset = pn_data_get_ulong(transport->disp_data);
+          break;
+        case PN_ACCEPTED:
+          break;
+        case PN_REJECTED:
+          err = pn_scan_error(transport->disp_data, &remote->condition, SCAN_ERROR_DISP);
+          if (err) return err;
+          break;
+        case PN_RELEASED:
+          break;
+        case PN_MODIFIED:
+          pn_data_rewind(transport->disp_data);
+          pn_data_next(transport->disp_data);
+          pn_data_enter(transport->disp_data);
+          if (pn_data_next(transport->disp_data))
+            remote->failed = pn_data_get_bool(transport->disp_data);
+          if (pn_data_next(transport->disp_data))
+            remote->undeliverable = pn_data_get_bool(transport->disp_data);
+          pn_data_narrow(transport->disp_data);
+          pn_data_clear(remote->data);
+          pn_data_appendn(remote->annotations, transport->disp_data, 1);
+          pn_data_widen(transport->disp_data);
+          break;
+        default:
+          pn_data_copy(remote->data, transport->disp_data);
+          break;
+        }
+      }
+      remote->settled = settled;
+      delivery->updated = true;
+      pn_work_update(transport->connection, delivery);
+
+      pn_collector_put(transport->connection->collector, PN_OBJECT, delivery, PN_DELIVERY);
+    }
+  }
+
+  return 0;
+}
+
+int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  uint32_t handle;
+  bool closed;
+  int err = pn_data_scan(args, "D.[Io]", &handle, &closed);
+  if (err) return err;
+
+  pn_session_t *ssn = pni_channel_state(transport, channel);
+  if (!ssn) {
+    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+  }
+  pn_link_t *link = pni_handle_state(ssn, handle);
+  if (!link) {
+    return pn_do_error(transport, "amqp:invalid-field", "no such handle: %u", handle);
+  }
+
+  err = pn_scan_error(args, &link->endpoint.remote_condition, SCAN_ERROR_DETACH);
+  if (err) return err;
+
+  if (closed)
+  {
+    PN_SET_REMOTE(link->endpoint.state, PN_REMOTE_CLOSED);
+    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_CLOSE);
+  } else {
+    pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_REMOTE_DETACH);
+  }
+
+  pni_unmap_remote_handle(link);
+  return 0;
+}
+
+int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_session_t *ssn = pni_channel_state(transport, channel);
+  if (!ssn) {
+    return pn_do_error(transport, "amqp:not-allowed", "no such channel: %u", channel);
+  }
+  int err = pn_scan_error(args, &ssn->endpoint.remote_condition, SCAN_ERROR_DEFAULT);
+  if (err) return err;
+  PN_SET_REMOTE(ssn->endpoint.state, PN_REMOTE_CLOSED);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, ssn, PN_SESSION_REMOTE_CLOSE);
+  pni_unmap_remote_channel(ssn);
+  return 0;
+}
+
+int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_connection_t *conn = transport->connection;
+  int err = pn_scan_error(args, &transport->remote_condition, SCAN_ERROR_DEFAULT);
+  if (err) return err;
+  transport->close_rcvd = true;
+  PN_SET_REMOTE(conn->endpoint.state, PN_REMOTE_CLOSED);
+  pn_collector_put(transport->connection->collector, PN_OBJECT, conn, PN_CONNECTION_REMOTE_CLOSE);
+  return 0;
+}
+
+// deprecated
+ssize_t pn_transport_input(pn_transport_t *transport, const char *bytes, size_t available)
+{
+  if (!transport) return PN_ARG_ERR;
+  if (available == 0) {
+    return pn_transport_close_tail(transport);
+  }
+  const size_t original = available;
+  ssize_t capacity = pn_transport_capacity(transport);
+  if (capacity < 0) return capacity;
+  while (available && capacity) {
+    char *dest = pn_transport_tail(transport);
+    assert(dest);
+    size_t count = pn_min( (size_t)capacity, available );
+    memmove( dest, bytes, count );
+    available -= count;
+    bytes += count;
+    int rc = pn_transport_process( transport, count );
+    if (rc < 0) return rc;
+    capacity = pn_transport_capacity(transport);
+    if (capacity < 0) return capacity;
+  }
+
+  return original - available;
+}
+
+// process pending input until none remaining or EOS
+static ssize_t transport_consume(pn_transport_t *transport)
+{
+  // This allows whatever is driving the I/O to set the error
+  // condition on the transport before doing pn_transport_close_head()
+  // or pn_transport_close_tail(). This allows all transport errors to
+  // flow to the app the same way, but provides cleaner error messages
+  // since we don't try to look for a protocol header when, e.g. the
+  // connection was refused.
+  if (!transport->bytes_input && transport->tail_closed &&
+      pn_condition_is_set(&transport->condition)) {
+    pn_do_error(transport, NULL, NULL);
+    return PN_EOS;
+  }
+
+  size_t consumed = 0;
+
+  while (transport->input_pending || transport->tail_closed) {
+    ssize_t n;
+    n = transport->io_layers[0]->
+      process_input( transport, 0,
+                     transport->input_buf + consumed,
+                     transport->input_pending );
+    if (n > 0) {
+      consumed += n;
+      transport->input_pending -= n;
+    } else if (n == 0) {
+      break;
+    } else {
+      assert(n == PN_EOS);
+      if (transport->trace & (PN_TRACE_RAW | PN_TRACE_FRM))
+        pn_transport_log(transport, "  <- EOS");
+      transport->input_pending = 0;  // XXX ???
+      return n;
+    }
+  }
+
+  if (transport->input_pending && consumed) {
+    memmove( transport->input_buf,  &transport->input_buf[consumed], transport->input_pending );
+  }
+
+  return consumed;
+}
+
+static int pni_process_conn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == CONNECTION)
+  {
+    if (!(endpoint->state & PN_LOCAL_UNINIT) && !transport->open_sent)
+    {
+      // as per the recommendation in the spec, advertise half our
+      // actual timeout to the remote
+      const pn_millis_t idle_timeout = transport->local_idle_timeout
+          ? (transport->local_idle_timeout/2)
+          : 0;
+      pn_connection_t *connection = (pn_connection_t *) endpoint;
+      const char *cid = pn_string_get(connection->container);
+      pni_calculate_channel_max(transport);
+      int err = pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[SS?I?H?InnCCC]", OPEN,
+                              cid ? cid : "",
+                              pn_string_get(connection->hostname),
+                              // if not zero, advertise our max frame size and idle timeout
+                              (bool)transport->local_max_frame, transport->local_max_frame,
+                              (bool)transport->channel_max, transport->channel_max,
+                              (bool)idle_timeout, idle_timeout,
+                              connection->offered_capabilities,
+                              connection->desired_capabilities,
+                              connection->properties);
+      if (err) return err;
+      transport->open_sent = true;
+    }
+  }
+
+  return 0;
+}
+
+static uint16_t allocate_alias(pn_hash_t *aliases, uint32_t max_index, int * valid)
+{
+  for (uint32_t i = 0; i <= max_index; i++) {
+    if (!pn_hash_get(aliases, i)) {
+      * valid = 1;
+      return i;
+    }
+  }
+
+  * valid = 0;
+  return 0;
+}
+
+static size_t pni_session_outgoing_window(pn_session_t *ssn)
+{
+  return ssn->outgoing_window;
+}
+
+static size_t pni_session_incoming_window(pn_session_t *ssn)
+{
+  uint32_t size = ssn->connection->transport->local_max_frame;
+  if (!size) {
+    return 2147483647; // biggest legal value
+  } else {
+    return (ssn->incoming_capacity - ssn->incoming_bytes)/size;
+  }
+}
+
+static int pni_map_local_channel(pn_session_t *ssn)
+{
+  pn_transport_t *transport = ssn->connection->transport;
+  pn_session_state_t *state = &ssn->state;
+  int valid;
+  uint16_t channel = allocate_alias(transport->local_channels, transport->channel_max, & valid);
+  if (!valid) {
+    return 0;
+  }
+  state->local_channel = channel;
+  pn_hash_put(transport->local_channels, channel, ssn);
+  pn_ep_incref(&ssn->endpoint);
+  return 1;
+}
+
+static int pni_process_ssn_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == SESSION && transport->open_sent)
+  {
+    pn_session_t *ssn = (pn_session_t *) endpoint;
+    pn_session_state_t *state = &ssn->state;
+    if (!(endpoint->state & PN_LOCAL_UNINIT) && state->local_channel == (uint16_t) -1)
+    {
+      if (! pni_map_local_channel(ssn)) {
+        pn_transport_logf(transport, "unable to find an open available channel within limit of %d", transport->channel_max );
+        return PN_ERR;
+      }
+      state->incoming_window = pni_session_incoming_window(ssn);
+      state->outgoing_window = pni_session_outgoing_window(ssn);
+      pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?HIII]", BEGIN,
+                    ((int16_t) state->remote_channel >= 0), state->remote_channel,
+                    state->outgoing_transfer_count,
+                    state->incoming_window,
+                    state->outgoing_window);
+    }
+  }
+
+  return 0;
+}
+
+static const char *expiry_symbol(pn_expiry_policy_t policy)
+{
+  switch (policy)
+  {
+  case PN_EXPIRE_WITH_LINK:
+    return "link-detach";
+  case PN_EXPIRE_WITH_SESSION:
+    return NULL;
+  case PN_EXPIRE_WITH_CONNECTION:
+    return "connection-close";
+  case PN_EXPIRE_NEVER:
+    return "never";
+  }
+  return NULL;
+}
+
+static int pni_map_local_handle(pn_link_t *link) {
+  pn_link_state_t *state = &link->state;
+  pn_session_state_t *ssn_state = &link->session->state;
+  int valid;
+  // XXX TODO MICK: once changes are made to handle_max, change this hardcoded value to something reasonable.
+  state->local_handle = allocate_alias(ssn_state->local_handles, 65536, & valid);
+  if ( ! valid )
+    return 0;
+  pn_hash_put(ssn_state->local_handles, state->local_handle, link);
+  pn_ep_incref(&link->endpoint);
+  return 1;
+}
+
+static int pni_process_link_setup(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (transport->open_sent && (endpoint->type == SENDER ||
+                               endpoint->type == RECEIVER))
+  {
+    pn_link_t *link = (pn_link_t *) endpoint;
+    pn_session_state_t *ssn_state = &link->session->state;
+    pn_link_state_t *state = &link->state;
+    if (((int16_t) ssn_state->local_channel >= 0) &&
+        !(endpoint->state & PN_LOCAL_UNINIT) && state->local_handle == (uint32_t) -1)
+    {
+      pni_map_local_handle(link);
+      const pn_distribution_mode_t dist_mode = link->source.distribution_mode;
+      if (link->target.type == PN_COORDINATOR) {
+        int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
+                                "DL[SIoBB?DL[SIsIoC?sCnCC]DL[C]nnI]", ATTACH,
+                                pn_string_get(link->name),
+                                state->local_handle,
+                                endpoint->type == RECEIVER,
+                                link->snd_settle_mode,
+                                link->rcv_settle_mode,
+                                (bool) link->source.type, SOURCE,
+                                pn_string_get(link->source.address),
+                                link->source.durability,
+                                expiry_symbol(link->source.expiry_policy),
+                                link->source.timeout,
+                                link->source.dynamic,
+                                link->source.properties,
+                                (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
+                                link->source.filter,
+                                link->source.outcomes,
+                                link->source.capabilities,
+                                COORDINATOR, link->target.capabilities,
+                                0);
+        if (err) return err;
+      } else {
+        int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
+                                "DL[SIoBB?DL[SIsIoC?sCnCC]?DL[SIsIoCC]nnI]", ATTACH,
+                                pn_string_get(link->name),
+                                state->local_handle,
+                                endpoint->type == RECEIVER,
+                                link->snd_settle_mode,
+                                link->rcv_settle_mode,
+                                (bool) link->source.type, SOURCE,
+                                pn_string_get(link->source.address),
+                                link->source.durability,
+                                expiry_symbol(link->source.expiry_policy),
+                                link->source.timeout,
+                                link->source.dynamic,
+                                link->source.properties,
+                                (dist_mode != PN_DIST_MODE_UNSPECIFIED), dist_mode2symbol(dist_mode),
+                                link->source.filter,
+                                link->source.outcomes,
+                                link->source.capabilities,
+                                (bool) link->target.type, TARGET,
+                                pn_string_get(link->target.address),
+                                link->target.durability,
+                                expiry_symbol(link->target.expiry_policy),
+                                link->target.timeout,
+                                link->target.dynamic,
+                                link->target.properties,
+                                link->target.capabilities,
+                                0);
+        if (err) return err;
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int pni_post_flow(pn_transport_t *transport, pn_session_t *ssn, pn_link_t *link)
+{
+  ssn->state.incoming_window = pni_session_incoming_window(ssn);
+  ssn->state.outgoing_window = pni_session_outgoing_window(ssn);
+  bool linkq = (bool) link;
+  pn_link_state_t *state = &link->state;
+  return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[?IIII?I?I?In?o]", FLOW,
+                       (int16_t) ssn->state.remote_channel >= 0, ssn->state.incoming_transfer_count,
+                       ssn->state.incoming_window,
+                       ssn->state.outgoing_transfer_count,
+                       ssn->state.outgoing_window,
+                       linkq, linkq ? state->local_handle : 0,
+                       linkq, linkq ? state->delivery_count : 0,
+                       linkq, linkq ? state->link_credit : 0,
+                       linkq, linkq ? link->drain : false);
+}
+
+static int pni_process_flow_receiver(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == RECEIVER && endpoint->state & PN_LOCAL_ACTIVE)
+  {
+    pn_link_t *rcv = (pn_link_t *) endpoint;
+    pn_session_t *ssn = rcv->session;
+    pn_link_state_t *state = &rcv->state;
+    if ((int16_t) ssn->state.local_channel >= 0 &&
+        (int32_t) state->local_handle >= 0 &&
+        ((rcv->drain || state->link_credit != rcv->credit - rcv->queued) || !ssn->state.incoming_window)) {
+      state->link_credit = rcv->credit - rcv->queued;
+      return pni_post_flow(transport, ssn, rcv);
+    }
+  }
+
+  return 0;
+}
+
+static int pni_flush_disp(pn_transport_t *transport, pn_session_t *ssn)
+{
+  uint64_t code = ssn->state.disp_code;
+  bool settled = ssn->state.disp_settled;
+  if (ssn->state.disp) {
+    int err = pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel, "DL[oIIo?DL[]]", DISPOSITION,
+                            ssn->state.disp_type, ssn->state.disp_first, ssn->state.disp_last,
+                            settled, (bool)code, code);
+    if (err) return err;
+    ssn->state.disp_type = 0;
+    ssn->state.disp_code = 0;
+    ssn->state.disp_settled = 0;
+    ssn->state.disp_first = 0;
+    ssn->state.disp_last = 0;
+    ssn->state.disp = false;
+  }
+  return 0;
+}
+
+static int pni_post_disp(pn_transport_t *transport, pn_delivery_t *delivery)
+{
+  pn_link_t *link = delivery->link;
+  pn_session_t *ssn = link->session;
+  pn_session_state_t *ssn_state = &ssn->state;
+  pn_modified(transport->connection, &link->session->endpoint, false);
+  pn_delivery_state_t *state = &delivery->state;
+  assert(state->init);
+  bool role = (link->endpoint.type == RECEIVER);
+  uint64_t code = delivery->local.type;
+
+  if (!code && !delivery->local.settled) {
+    return 0;
+  }
+
+  if (!pni_disposition_batchable(&delivery->local)) {
+    pn_data_clear(transport->disp_data);
+    PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
+    return pn_post_frame(transport, AMQP_FRAME_TYPE, ssn->state.local_channel,
+      "DL[oIIo?DLC]", DISPOSITION,
+      role, state->id, state->id, delivery->local.settled,
+      (bool)code, code, transport->disp_data);
+  }
+
+  if (ssn_state->disp && code == ssn_state->disp_code &&
+      delivery->local.settled == ssn_state->disp_settled &&
+      ssn_state->disp_type == role) {
+    if (state->id == ssn_state->disp_first - 1) {
+      ssn_state->disp_first = state->id;
+      return 0;
+    } else if (state->id == ssn_state->disp_last + 1) {
+      ssn_state->disp_last = state->id;
+      return 0;
+    }
+  }
+
+  if (ssn_state->disp) {
+    int err = pni_flush_disp(transport, ssn);
+    if (err) return err;
+  }
+
+  ssn_state->disp_type = role;
+  ssn_state->disp_code = code;
+  ssn_state->disp_settled = delivery->local.settled;
+  ssn_state->disp_first = state->id;
+  ssn_state->disp_last = state->id;
+  ssn_state->disp = true;
+
+  return 0;
+}
+
+static int pni_process_tpwork_sender(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
+{
+  *settle = false;
+  pn_link_t *link = delivery->link;
+  pn_session_state_t *ssn_state = &link->session->state;
+  pn_link_state_t *link_state = &link->state;
+  bool xfr_posted = false;
+  if ((int16_t) ssn_state->local_channel >= 0 && (int32_t) link_state->local_handle >= 0) {
+    pn_delivery_state_t *state = &delivery->state;
+    if (!state->sent && (delivery->done || pn_buffer_size(delivery->bytes) > 0) &&
+        ssn_state->remote_incoming_window > 0 && link_state->link_credit > 0) {
+      if (!state->init) {
+        state = pni_delivery_map_push(&ssn_state->outgoing, delivery);
+      }
+
+      pn_bytes_t bytes = pn_buffer_bytes(delivery->bytes);
+      size_t full_size = bytes.size;
+      pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
+      pn_data_clear(transport->disp_data);
+      PN_RETURN_IF_ERROR(pni_disposition_encode(&delivery->local, transport->disp_data));
+      int count = pni_post_amqp_transfer_frame(transport,
+                                              ssn_state->local_channel,
+                                              link_state->local_handle,
+                                              state->id, &bytes, &tag,
+                                              0, // message-format
+                                              delivery->local.settled,
+                                              !delivery->done,
+                                              ssn_state->remote_incoming_window,
+                                              delivery->local.type, transport->disp_data);
+      if (count < 0) return count;
+      xfr_posted = true;
+      ssn_state->outgoing_transfer_count += count;
+      ssn_state->remote_incoming_window -= count;
+
+      int sent = full_size - bytes.size;
+      pn_buffer_trim(delivery->bytes, sent, 0);
+      link->session->outgoing_bytes -= sent;
+      if (!pn_buffer_size(delivery->bytes) && delivery->done) {
+        state->sent = true;
+        link_state->delivery_count++;
+        link_state->link_credit--;
+        link->queued--;
+        link->session->outgoing_deliveries--;
+      }
+
+      pn_collector_put(transport->connection->collector, PN_OBJECT, link, PN_LINK_FLOW);
+    }
+  }
+
+  pn_delivery_state_t *state = delivery->state.init ? &delivery->state : NULL;
+  if ((int16_t) ssn_state->local_channel >= 0 && !delivery->remote.settled
+      && state && state->sent && !xfr_posted) {
+    int err = pni_post_disp(transport, delivery);
+    if (err) return err;
+  }
+
+  *settle = delivery->local.settled && state && state->sent;
+  return 0;
+}
+
+static int pni_process_tpwork_receiver(pn_transport_t *transport, pn_delivery_t *delivery, bool *settle)
+{
+  *settle = false;
+  pn_link_t *link = delivery->link;
+  // XXX: need to prevent duplicate disposition sending
+  pn_session_t *ssn = link->session;
+  if ((int16_t) ssn->state.local_channel >= 0 && !delivery->remote.settled && delivery->state.init) {
+    int err = pni_post_disp(transport, delivery);
+    if (err) return err;
+  }
+
+  // XXX: need to centralize this policy and improve it
+  if (!ssn->state.incoming_window) {
+    int err = pni_post_flow(transport, ssn, link);
+    if (err) return err;
+  }
+
+  *settle = delivery->local.settled;
+  return 0;
+}
+
+static int pni_process_tpwork(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == CONNECTION && !transport->close_sent)
+  {
+    pn_connection_t *conn = (pn_connection_t *) endpoint;
+    pn_delivery_t *delivery = conn->tpwork_head;
+    while (delivery)
+    {
+      pn_delivery_t *tp_next = delivery->tpwork_next;
+      bool settle = false;
+
+      pn_link_t *link = delivery->link;
+      pn_delivery_map_t *dm = NULL;
+      if (pn_link_is_sender(link)) {
+        dm = &link->session->state.outgoing;
+        int err = pni_process_tpwork_sender(transport, delivery, &settle);
+        if (err) return err;
+      } else {
+        dm = &link->session->state.incoming;
+        int err = pni_process_tpwork_receiver(transport, delivery, &settle);
+        if (err) return err;
+      }
+
+      if (settle) {
+        pn_full_settle(dm, delivery);
+      } else if (!pn_delivery_buffered(delivery)) {
+        pn_clear_tpwork(delivery);
+      }
+
+      delivery = tp_next;
+    }
+  }
+
+  return 0;
+}
+
+static int pni_process_flush_disp(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == SESSION) {
+    pn_session_t *session = (pn_session_t *) endpoint;
+    pn_session_state_t *state = &session->state;
+    if ((int16_t) state->local_channel >= 0 && !transport->close_sent)
+    {
+      int err = pni_flush_disp(transport, session);
+      if (err) return err;
+    }
+  }
+
+  return 0;
+}
+
+static int pni_process_flow_sender(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == SENDER && endpoint->state & PN_LOCAL_ACTIVE)
+  {
+    pn_link_t *snd = (pn_link_t *) endpoint;
+    pn_session_t *ssn = snd->session;
+    pn_link_state_t *state = &snd->state;
+    if ((int16_t) ssn->state.local_channel >= 0 &&
+        (int32_t) state->local_handle >= 0 &&
+        snd->drain && snd->drained) {
+      pn_delivery_t *tail = snd->unsettled_tail;
+      if (!tail || !pn_delivery_buffered(tail)) {
+        state->delivery_count += state->link_credit;
+        state->link_credit = 0;
+        snd->drained = 0;
+        return pni_post_flow(transport, ssn, snd);
+      }
+    }
+  }
+
+  return 0;
+}
+
+static void pni_unmap_local_handle(pn_link_t *link) {
+  pn_link_state_t *state = &link->state;
+  uintptr_t handle = state->local_handle;
+  state->local_handle = -2;
+  if (pn_hash_get(link->session->state.local_handles, handle)) {
+    pn_ep_decref(&link->endpoint);
+  }
+  // may delete link
+  pn_hash_del(link->session->state.local_handles, handle);
+}
+
+static int pni_process_link_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == SENDER || endpoint->type == RECEIVER)
+  {
+    pn_link_t *link = (pn_link_t *) endpoint;
+    pn_session_t *session = link->session;
+    pn_session_state_t *ssn_state = &session->state;
+    pn_link_state_t *state = &link->state;
+    if (((endpoint->state & PN_LOCAL_CLOSED) || link->detached) && (int32_t) state->local_handle >= 0 &&
+        (int16_t) ssn_state->local_channel >= 0 && !transport->close_sent) {
+      if (pn_link_is_sender(link) && pn_link_queued(link) &&
+          (int32_t) state->remote_handle != -2 &&
+          (int16_t) ssn_state->remote_channel != -2 &&
+          !transport->close_rcvd) return 0;
+
+      const char *name = NULL;
+      const char *description = NULL;
+      pn_data_t *info = NULL;
+
+      if (pn_condition_is_set(&endpoint->condition)) {
+        name = pn_condition_get_name(&endpoint->condition);
+        description = pn_condition_get_description(&endpoint->condition);
+        info = pn_condition_info(&endpoint->condition);
+      }
+
+      int err =
+          pn_post_frame(transport, AMQP_FRAME_TYPE, ssn_state->local_channel,
+                        "DL[Io?DL[sSC]]", DETACH, state->local_handle, !link->detached,
+                        (bool)name, ERROR, name, description, info);
+      if (err) return err;
+      pni_unmap_local_handle(link);
+    }
+
+    pn_clear_modified(transport->connection, endpoint);
+  }
+
+  return 0;
+}
+
+static bool pni_pointful_buffering(pn_transport_t *transport, pn_session_t *session)
+{
+  if (transport->close_rcvd) return false;
+  if (!transport->open_rcvd) return true;
+
+  pn_connection_t *conn = transport->connection;
+  pn_link_t *link = pn_link_head(conn, 0);
+  while (link) {
+    if (pn_link_is_sender(link) && pn_link_queued(link) > 0) {
+      pn_session_t *ssn = link->session;
+      if (session && session == ssn) {
+        if ((int32_t) link->state.remote_handle != -2 &&
+            (int16_t) session->state.remote_channel != -2) {
+          return true;
+        }
+      }
+    }
+    link = pn_link_next(link, 0);
+  }
+
+  return false;
+}
+
+static void pni_unmap_local_channel(pn_session_t *ssn) {
+  // XXX: should really update link state also
+  pni_delivery_map_clear(&ssn->state.outgoing);
+  pni_transport_unbind_handles(ssn->state.local_handles, false);
+  pn_transport_t *transport = ssn->connection->transport;
+  pn_session_state_t *state = &ssn->state;
+  uintptr_t channel = state->local_channel;
+  state->local_channel = -2;
+  if (pn_hash_get(transport->local_channels, channel)) {
+    pn_ep_decref(&ssn->endpoint);
+  }
+  // may delete session
+  pn_hash_del(transport->local_channels, channel);
+}
+
+static int pni_process_ssn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == SESSION)
+  {
+    pn_session_t *session = (pn_session_t *) endpoint;
+    pn_session_state_t *state = &session->state;
+    if (endpoint->state & PN_LOCAL_CLOSED && (int16_t) state->local_channel >= 0
+        && !transport->close_sent)
+    {
+      if (pni_pointful_buffering(transport, session)) {
+        return 0;
+      }
+
+      const char *name = NULL;
+      const char *description = NULL;
+      pn_data_t *info = NULL;
+
+      if (pn_condition_is_set(&endpoint->condition)) {
+        name = pn_condition_get_name(&endpoint->condition);
+        description = pn_condition_get_description(&endpoint->condition);
+        info = pn_condition_info(&endpoint->condition);
+      }
+
+      int err = pn_post_frame(transport, AMQP_FRAME_TYPE, state->local_channel, "DL[?DL[sSC]]", END,
+                              (bool) name, ERROR, name, description, info);
+      if (err) return err;
+      pni_unmap_local_channel(session);
+    }
+
+    pn_clear_modified(transport->connection, endpoint);
+  }
+  return 0;
+}
+
+static int pni_process_conn_teardown(pn_transport_t *transport, pn_endpoint_t *endpoint)
+{
+  if (endpoint->type == CONNECTION)
+  {
+    if (endpoint->state & PN_LOCAL_CLOSED && !transport->close_sent) {
+      if (pni_pointful_buffering(transport, NULL)) return 0;
+      int err = pni_post_close(transport, NULL);
+      if (err) return err;
+      transport->close_sent = true;
+    }
+
+    pn_clear_modified(transport->connection, endpoint);
+  }
+  return 0;
+}
+
+static int pni_phase(pn_transport_t *transport, int (*phase)(pn_transport_t *, pn_endpoint_t *))
+{
+  pn_connection_t *conn = transport->connection;
+  pn_endpoint_t *endpoint = conn->transport_head;
+  while (endpoint)
+  {
+    pn_endpoint_t *next = endpoint->transport_next;
+    int err = phase(transport, endpoint);
+    if (err) return err;
+    endpoint = next;
+  }
+  return 0;
+}
+
+static int pni_process(pn_transport_t *transport)
+{
+  int err;
+  if ((err = pni_phase(transport, pni_process_conn_setup))) return err;
+  if ((err = pni_phase(transport, pni_process_ssn_setup))) return err;
+  if ((err = pni_phase(transport, pni_process_link_setup))) return err;
+  if ((err = pni_phase(transport, pni_process_flow_receiver))) return err;
+
+  // XXX: this has to happen two times because we might settle stuff
+  // on the first pass and create space for more work to be done on the
+  // second pass
+  if ((err = pni_phase(transport, pni_process_tpwork))) return err;
+  if ((err = pni_phase(transport, pni_process_tpwork))) return err;
+
+  if ((err = pni_phase(transport, pni_process_flush_disp))) return err;
+
+  if ((err = pni_phase(transport, pni_process_flow_sender))) return err;
+  if ((err = pni_phase(transport, pni_process_link_teardown))) return err;
+  if ((err = pni_phase(transport, pni_process_ssn_teardown))) return err;
+  if ((err = pni_phase(transport, pni_process_conn_teardown))) return err;
+
+  if (transport->connection->tpwork_head) {
+    pn_modified(transport->connection, &transport->connection->endpoint, false);
+  }
+
+  return 0;
+}
+
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
+static void pn_error_amqp(pn_transport_t* transport, unsigned int layer)
+{
+  if (!transport->close_sent) {
+    if (!transport->open_sent) {
+      pn_post_frame(transport, AMQP_FRAME_TYPE, 0, "DL[S]", OPEN, "");
+    }
+
+    pni_post_close(transport, &transport->condition);
+    transport->close_sent = true;
+  }
+  transport->halt = true;
+  transport->done_processing = true;
+}
+
+static ssize_t pn_input_read_amqp_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
+{
+  bool eos = pn_transport_capacity(transport)==PN_EOS;
+  pni_protocol_type_t protocol = pni_sniff_header(bytes, available);
+  switch (protocol) {
+  case PNI_PROTOCOL_AMQP1:
+    if (transport->io_layers[layer] == &amqp_read_header_layer) {
+      transport->io_layers[layer] = &amqp_layer;
+    } else {
+      transport->io_layers[layer] = &amqp_write_header_layer;
+    }
+    if (transport->trace & PN_TRACE_FRM)
+      pn_transport_logf(transport, "  <- %s", "AMQP");
+    return 8;
+  case PNI_PROTOCOL_INSUFFICIENT:
+    if (!eos) return 0;
+    /* Fallthru */
+  default:
+    break;
+  }
+  char quoted[1024];
+  pn_quote_data(quoted, 1024, bytes, available);
+  pn_do_error(transport, "amqp:connection:framing-error",
+              "%s header mismatch: %s ['%s']%s", "AMQP", pni_protocol_name(protocol), quoted,
+              !eos ? "" : " (connection aborted)");
+  return PN_EOS;
+}
+
+static ssize_t pn_input_read_amqp(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available)
+{
+  if (transport->close_rcvd) {
+    if (available > 0) {
+      pn_do_error(transport, "amqp:connection:framing-error", "data after close");
+      return PN_EOS;
+    }
+  }
+
+  if (!transport->close_rcvd && !available) {
+    pn_do_error(transport, "amqp:connection:framing-error", "connection aborted");
+    return PN_EOS;
+  }
+
+
+  ssize_t n = pn_dispatcher_input(transport, bytes, available, true, &transport->halt);
+  if (n < 0) {
+    //return pn_error_set(transport->error, n, "dispatch error");
+    return PN_EOS;
+  } else if (transport->close_rcvd) {
+    return PN_EOS;
+  } else {
+    return n;
+  }
+}
+
+/* process AMQP related timer events */
+static pn_timestamp_t pn_tick_amqp(pn_transport_t* transport, unsigned int layer, pn_timestamp_t now)
+{
+  pn_timestamp_t timeout = 0;
+
+  if (transport->local_idle_timeout) {
+    if (transport->dead_remote_deadline == 0 ||
+        transport->last_bytes_input != transport->bytes_input) {
+      transport->dead_remote_deadline = now + t

<TRUNCATED>

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


[07/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/io.c b/proton-c/src/reactor/io/windows/io.c
new file mode 100644
index 0000000..3ae6722
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/io.c
@@ -0,0 +1,459 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#define FD_SETSIZE 2048
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+
+#include "platform/platform.h"
+#include "iocp.h"
+#include "core/util.h"
+
+#include <proton/object.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+
+int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code)
+{
+  // Error code can be from GetLastError or WSAGetLastError,
+  char err[1024] = {0};
+  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
+                FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL);
+  return pn_error_format(error, PN_ERR, "%s: %s", msg, err);
+}
+
+static void io_log(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
+
+struct pn_io_t {
+  char host[NI_MAXHOST];
+  char serv[NI_MAXSERV];
+  pn_error_t *error;
+  bool trace;
+  bool wouldblock;
+  iocp_t *iocp;
+};
+
+void pn_io_initialize(void *obj)
+{
+  pn_io_t *io = (pn_io_t *) obj;
+  io->error = pn_error();
+  io->wouldblock = false;
+  io->trace = pn_env_bool("PN_TRACE_DRV");
+
+  /* Request WinSock 2.2 */
+  WORD wsa_ver = MAKEWORD(2, 2);
+  WSADATA unused;
+  int err = WSAStartup(wsa_ver, &unused);
+  if (err) {
+    pni_win32_error(io->error, "WSAStartup", WSAGetLastError());
+    fprintf(stderr, "Can't load WinSock: %s\n", pn_error_text(io->error));
+  }
+  io->iocp = pni_iocp();
+}
+
+void pn_io_finalize(void *obj)
+{
+  pn_io_t *io = (pn_io_t *) obj;
+  pn_error_free(io->error);
+  pn_free(io->iocp);
+  WSACleanup();
+}
+
+#define pn_io_hashcode NULL
+#define pn_io_compare NULL
+#define pn_io_inspect
+
+pn_io_t *pn_io(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_io);
+  pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
+  return io;
+}
+
+void pn_io_free(pn_io_t *io)
+{
+  pn_free(io);
+}
+
+pn_error_t *pn_io_error(pn_io_t *io)
+{
+  assert(io);
+  return io->error;
+}
+
+static void ensure_unique(pn_io_t *io, pn_socket_t new_socket)
+{
+  // A brand new socket can have the same HANDLE value as a previous
+  // one after a socketclose.  If the application closes one itself
+  // (i.e. not using pn_close), we don't find out about it until here.
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, new_socket);
+  if (iocpd) {
+    if (io->trace)
+      io_log("Stale external socket reference discarded\n");
+    // Re-use means former socket instance was closed
+    assert(iocpd->ops_in_progress == 0);
+    assert(iocpd->external);
+    // Clean up the straggler as best we can
+    pn_socket_t sock = iocpd->socket;
+    iocpd->socket = INVALID_SOCKET;
+    pni_iocpdesc_map_del(io->iocp, sock);  // may free the iocpdesc_t depending on refcount
+  }
+}
+
+
+/*
+ * This heavyweight surrogate pipe could be replaced with a normal Windows pipe
+ * now that select() is no longer used.  If interrupt semantics are all that is
+ * needed, a simple user space counter and reserved completion status would
+ * probably suffice.
+ */
+static int pni_socket_pair(pn_io_t *io, SOCKET sv[2]);
+
+int pn_pipe(pn_io_t *io, pn_socket_t *dest)
+{
+  int n = pni_socket_pair(io, dest);
+  if (n) {
+    pni_win32_error(io->error, "pipe", WSAGetLastError());
+  }
+  return n;
+}
+
+static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
+  //
+  // Disable the Nagle algorithm on TCP connections.
+  //
+  int flag = 1;
+  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) != 0) {
+    perror("setsockopt");
+  }
+
+  u_long nonblock = 1;
+  if (ioctlsocket(sock, FIONBIO, &nonblock)) {
+    perror("ioctlsocket");
+  }
+}
+
+static inline pn_socket_t pni_create_socket(int domain, int protocol);
+
+static const char *amqp_service(const char *port) {
+  // Help older Windows to know about amqp[s] ports
+  if (port) {
+    if (!strcmp("amqp", port)) return "5672";
+    if (!strcmp("amqps", port)) return "5671";
+  }
+  return port;
+}
+
+pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
+{
+  struct addrinfo *addr;
+  int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
+  if (code) {
+    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
+    return INVALID_SOCKET;
+  }
+
+  pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
+  if (sock == INVALID_SOCKET) {
+    pni_win32_error(io->error, "pni_create_socket", WSAGetLastError());
+    return INVALID_SOCKET;
+  }
+  ensure_unique(io, sock);
+
+  bool optval = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &optval,
+                 sizeof(optval)) == -1) {
+    pni_win32_error(io->error, "setsockopt", WSAGetLastError());
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+
+  if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
+    pni_win32_error(io->error, "bind", WSAGetLastError());
+    freeaddrinfo(addr);
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+  freeaddrinfo(addr);
+
+  if (listen(sock, 50) == -1) {
+    pni_win32_error(io->error, "listen", WSAGetLastError());
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+
+  if (io->iocp->selector) {
+    iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+    if (!iocpd) {
+      pn_i_error_from_errno(io->error, "register");
+      closesocket(sock);
+      return INVALID_SOCKET;
+    }
+    pni_iocpdesc_start(iocpd);
+  }
+
+  return sock;
+}
+
+pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port)
+{
+  // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets
+  const char *host = strcmp("0.0.0.0", hostarg) ? hostarg : "127.0.0.1";
+
+  struct addrinfo *addr;
+  int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
+  if (code) {
+    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
+    return INVALID_SOCKET;
+  }
+
+  pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
+  if (sock == INVALID_SOCKET) {
+    pni_win32_error(io->error, "proton pni_create_socket", WSAGetLastError());
+    freeaddrinfo(addr);
+    return INVALID_SOCKET;
+  }
+
+  ensure_unique(io, sock);
+  pn_configure_sock(io, sock);
+
+  if (io->iocp->selector) {
+    return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
+  } else {
+    if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
+      if (WSAGetLastError() != WSAEWOULDBLOCK) {
+	pni_win32_error(io->error, "connect", WSAGetLastError());
+	freeaddrinfo(addr);
+	closesocket(sock);
+	return INVALID_SOCKET;
+      }
+    }
+
+    freeaddrinfo(addr);
+    return sock;
+  }
+}
+
+pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size)
+{
+  struct sockaddr_storage addr;
+  socklen_t addrlen = sizeof(addr);
+  iocpdesc_t *listend = pni_iocpdesc_map_get(io->iocp, listen_sock);
+  pn_socket_t accept_sock;
+
+  *name = '\0';
+  if (listend)
+    accept_sock = pni_iocp_end_accept(listend, (struct sockaddr *) &addr, &addrlen, &io->wouldblock, io->error);
+  else {
+    // User supplied socket
+    accept_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen);
+    if (accept_sock == INVALID_SOCKET)
+      pni_win32_error(io->error, "sync accept", WSAGetLastError());
+  }
+
+  if (accept_sock == INVALID_SOCKET)
+    return accept_sock;
+
+  int code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
+                         io->serv, NI_MAXSERV, 0);
+  if (code)
+    code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
+                       io->serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
+  if (code) {
+    pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
+    pn_close(io, accept_sock);
+    return INVALID_SOCKET;
+  } else {
+    pn_configure_sock(io, accept_sock);
+    pni_snprintf(name, size, "%s:%s", io->host, io->serv);
+    if (listend) {
+      pni_iocpdesc_start(pni_iocpdesc_map_get(io->iocp, accept_sock));
+    }
+    return accept_sock;
+  }
+}
+
+static inline pn_socket_t pni_create_socket(int domain, int protocol) {
+  return socket(domain, SOCK_STREAM, protocol);
+}
+
+ssize_t pn_send(pn_io_t *io, pn_socket_t sockfd, const void *buf, size_t len) {
+  ssize_t count;
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, sockfd);
+  if (iocpd) {
+    count = pni_iocp_begin_write(iocpd, buf, len, &io->wouldblock, io->error);
+  } else {
+    count = send(sockfd, (const char *) buf, len, 0);
+    io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+  }
+  return count;
+}
+
+ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+  ssize_t count;
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
+  if (iocpd) {
+    count = pni_iocp_recv(iocpd, buf, size, &io->wouldblock, io->error);
+  } else {
+    count = recv(socket, (char *) buf, size, 0);
+    io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
+  }
+  return count;
+}
+
+ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
+{
+  // non-socket io is mapped to socket io for now.  See pn_pipe()
+  return pn_send(io, socket, buf, size);
+}
+
+ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
+{
+  return pn_recv(io, socket, buf, size);
+}
+
+void pn_close(pn_io_t *io, pn_socket_t socket)
+{
+  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
+  if (iocpd)
+    pni_iocp_begin_close(iocpd);
+  else {
+    closesocket(socket);
+  }
+}
+
+bool pn_wouldblock(pn_io_t *io)
+{
+  return io->wouldblock;
+}
+
+pn_selector_t *pn_io_selector(pn_io_t *io)
+{
+  if (io->iocp->selector == NULL)
+    io->iocp->selector = pni_selector_create(io->iocp);
+  return io->iocp->selector;
+}
+
+static void configure_pipe_socket(pn_io_t *io, pn_socket_t sock)
+{
+  u_long v = 1;
+  ioctlsocket (sock, FIONBIO, &v);
+  ensure_unique(io, sock);
+  iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
+  pni_iocpdesc_start(iocpd);
+}
+
+
+static int pni_socket_pair (pn_io_t *io, SOCKET sv[2]) {
+  // no socketpair on windows.  provide pipe() semantics using sockets
+  struct protoent * pe_tcp = getprotobyname("tcp");
+  if (pe_tcp == NULL) {
+    perror("getprotobyname");
+    return -1;
+  }
+
+  SOCKET sock = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto);
+  if (sock == INVALID_SOCKET) {
+    perror("socket");
+    return -1;
+  }
+
+  BOOL b = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &b, sizeof(b)) == -1) {
+    perror("setsockopt");
+    closesocket(sock);
+    return -1;
+  }
+  else {
+    struct sockaddr_in addr = {0};
+    addr.sin_family = AF_INET;
+    addr.sin_port = 0;
+    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+      perror("bind");
+      closesocket(sock);
+      return -1;
+    }
+  }
+
+  if (listen(sock, 50) == -1) {
+    perror("listen");
+    closesocket(sock);
+    return -1;
+  }
+
+  if ((sv[1] = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto)) == INVALID_SOCKET) {
+    perror("sock1");
+    closesocket(sock);
+    return -1;
+  }
+  else {
+    struct sockaddr addr = {0};
+    int l = sizeof(addr);
+    if (getsockname(sock, &addr, &l) == -1) {
+      perror("getsockname");
+      closesocket(sock);
+      return -1;
+    }
+
+    if (connect(sv[1], &addr, sizeof(addr)) == -1) {
+      int err = WSAGetLastError();
+      fprintf(stderr, "connect wsaerrr %d\n", err);
+      closesocket(sock);
+      closesocket(sv[1]);
+      return -1;
+    }
+
+    if ((sv[0] = accept(sock, &addr, &l)) == INVALID_SOCKET) {
+      perror("accept");
+      closesocket(sock);
+      closesocket(sv[1]);
+      return -1;
+    }
+  }
+
+  configure_pipe_socket(io, sv[0]);
+  configure_pipe_socket(io, sv[1]);
+  closesocket(sock);
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/iocp.c b/proton-c/src/reactor/io/windows/iocp.c
new file mode 100644
index 0000000..8a1a64a
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/iocp.c
@@ -0,0 +1,1179 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+
+#include "iocp.h"
+#include "platform/platform.h"
+#include "core/util.h"
+
+#include <proton/object.h>
+#include <proton/error.h>
+#include <proton/transport.h>
+
+#include <assert.h>
+
+/*
+ * Windows IO Completion Port support for Proton.
+ *
+ * Overlapped writes are used to avoid lengthy stalls between write
+ * completion and starting a new write.  Non-overlapped reads are used
+ * since Windows accumulates inbound traffic without stalling and
+ * managing read buffers would not avoid a memory copy at the pn_read
+ * boundary.
+ *
+ * A socket must not get a Windows closesocket() unless the
+ * application has called pn_close on the socket or a global
+ * pn_io_finalize().  On error, the internal accounting for
+ * write_closed or read_closed may be updated along with the external
+ * event notification.  A socket may be closed if it is never added to
+ * the iocpdesc_map or is on its way out of the map.
+ */
+
+// Max number of overlapped accepts per listener
+#define IOCP_MAX_ACCEPTS 10
+
+// AcceptEx squishes the local and remote addresses and optional data
+// all together when accepting the connection. Reserve enough for
+// IPv6 addresses, even if the socket is IPv4. The 16 bytes padding
+// per address is required by AcceptEx.
+#define IOCP_SOCKADDRMAXLEN (sizeof(sockaddr_in6) + 16)
+#define IOCP_SOCKADDRBUFLEN (2 * IOCP_SOCKADDRMAXLEN)
+
+static void iocp_log(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
+
+static void set_iocp_error_status(pn_error_t *error, int code, HRESULT status)
+{
+  char buf[512];
+  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+                    0, status, 0, buf, sizeof(buf), 0))
+    pn_error_set(error, code, buf);
+  else {
+    fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());
+  }
+}
+
+static void reap_check(iocpdesc_t *);
+static void bind_to_completion_port(iocpdesc_t *iocpd);
+static void iocp_shutdown(iocpdesc_t *iocpd);
+static void start_reading(iocpdesc_t *iocpd);
+static bool is_listener(iocpdesc_t *iocpd);
+static void release_sys_sendbuf(SOCKET s);
+
+static void iocpdesc_fail(iocpdesc_t *iocpd, HRESULT status, const char* text)
+{
+  pni_win32_error(iocpd->error, text, status);
+  if (iocpd->iocp->iocp_trace) {
+    iocp_log("connection terminated: %s\n", pn_error_text(iocpd->error));
+  }
+  iocpd->write_closed = true;
+  iocpd->read_closed = true;
+  iocpd->poll_error = true;
+  pni_events_update(iocpd, iocpd->events & ~(PN_READABLE | PN_WRITABLE));
+}
+
+// Helper functions to use specialized IOCP AcceptEx() and ConnectEx()
+static LPFN_ACCEPTEX lookup_accept_ex(SOCKET s)
+{
+  GUID guid = WSAID_ACCEPTEX;
+  DWORD bytes = 0;
+  LPFN_ACCEPTEX fn;
+  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+           &fn, sizeof(fn), &bytes, NULL, NULL);
+  assert(fn);
+  return fn;
+}
+
+static LPFN_CONNECTEX lookup_connect_ex(SOCKET s)
+{
+  GUID guid = WSAID_CONNECTEX;
+  DWORD bytes = 0;
+  LPFN_CONNECTEX fn;
+  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+           &fn, sizeof(fn), &bytes, NULL, NULL);
+  assert(fn);
+  return fn;
+}
+
+static LPFN_GETACCEPTEXSOCKADDRS lookup_get_accept_ex_sockaddrs(SOCKET s)
+{
+  GUID guid = WSAID_GETACCEPTEXSOCKADDRS;
+  DWORD bytes = 0;
+  LPFN_GETACCEPTEXSOCKADDRS fn;
+  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+           &fn, sizeof(fn), &bytes, NULL, NULL);
+  assert(fn);
+  return fn;
+}
+
+// match accept socket to listener socket
+static iocpdesc_t *create_same_type_socket(iocpdesc_t *iocpd)
+{
+  sockaddr_storage sa;
+  socklen_t salen = sizeof(sa);
+  if (getsockname(iocpd->socket, (sockaddr*)&sa, &salen) == -1)
+    return NULL;
+  SOCKET s = socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM
+  if (s == INVALID_SOCKET)
+    return NULL;
+  return pni_iocpdesc_create(iocpd->iocp, s, false);
+}
+
+static bool is_listener(iocpdesc_t *iocpd)
+{
+  return iocpd && iocpd->acceptor;
+}
+
+// === Async accept processing
+
+typedef struct {
+  iocp_result_t base;
+  iocpdesc_t *new_sock;
+  char address_buffer[IOCP_SOCKADDRBUFLEN];
+  DWORD unused;
+} accept_result_t;
+
+static accept_result_t *accept_result(iocpdesc_t *listen_sock) {
+  accept_result_t *result = (accept_result_t *)calloc(1, sizeof(accept_result_t));
+  if (result) {
+    result->base.type = IOCP_ACCEPT;
+    result->base.iocpd = listen_sock;
+  }
+  return result;
+}
+
+static void reset_accept_result(accept_result_t *result) {
+  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+  memset(&result->address_buffer, 0, IOCP_SOCKADDRBUFLEN);
+}
+
+struct pni_acceptor_t {
+  int accept_queue_size;
+  pn_list_t *accepts;
+  iocpdesc_t *listen_sock;
+  bool signalled;
+  LPFN_ACCEPTEX fn_accept_ex;
+  LPFN_GETACCEPTEXSOCKADDRS fn_get_accept_ex_sockaddrs;
+};
+
+#define pni_acceptor_compare NULL
+#define pni_acceptor_inspect NULL
+#define pni_acceptor_hashcode NULL
+
+static void pni_acceptor_initialize(void *object)
+{
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
+  acceptor->accepts = pn_list(PN_VOID, IOCP_MAX_ACCEPTS);
+}
+
+static void pni_acceptor_finalize(void *object)
+{
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
+  size_t len = pn_list_size(acceptor->accepts);
+  for (size_t i = 0; i < len; i++)
+    free(pn_list_get(acceptor->accepts, i));
+  pn_free(acceptor->accepts);
+}
+
+static pni_acceptor_t *pni_acceptor(iocpdesc_t *iocpd)
+{
+  static const pn_cid_t CID_pni_acceptor = CID_pn_void;
+  static const pn_class_t clazz = PN_CLASS(pni_acceptor);
+  pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_class_new(&clazz, sizeof(pni_acceptor_t));
+  acceptor->listen_sock = iocpd;
+  acceptor->accept_queue_size = 0;
+  acceptor->signalled = false;
+  pn_socket_t sock = acceptor->listen_sock->socket;
+  acceptor->fn_accept_ex = lookup_accept_ex(sock);
+  acceptor->fn_get_accept_ex_sockaddrs = lookup_get_accept_ex_sockaddrs(sock);
+  return acceptor;
+}
+
+static void begin_accept(pni_acceptor_t *acceptor, accept_result_t *result)
+{
+  if (acceptor->listen_sock->closing) {
+    if (result) {
+      free(result);
+      acceptor->accept_queue_size--;
+    }
+    if (acceptor->accept_queue_size == 0)
+      acceptor->signalled = true;
+    return;
+  }
+
+  if (result) {
+    reset_accept_result(result);
+  } else {
+    if (acceptor->accept_queue_size < IOCP_MAX_ACCEPTS &&
+        pn_list_size(acceptor->accepts) == acceptor->accept_queue_size ) {
+      result = accept_result(acceptor->listen_sock);
+      acceptor->accept_queue_size++;
+    } else {
+      // an async accept is still pending or max concurrent accepts already hit
+      return;
+    }
+  }
+
+  result->new_sock = create_same_type_socket(acceptor->listen_sock);
+  if (result->new_sock) {
+    // Not yet connected.
+    result->new_sock->read_closed = true;
+    result->new_sock->write_closed = true;
+
+    bool success = acceptor->fn_accept_ex(acceptor->listen_sock->socket, result->new_sock->socket,
+                     result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
+                     &result->unused, (LPOVERLAPPED) result);
+    if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+      result->base.status = WSAGetLastError();
+      pn_list_add(acceptor->accepts, result);
+      pni_events_update(acceptor->listen_sock, acceptor->listen_sock->events | PN_READABLE);
+    } else {
+      acceptor->listen_sock->ops_in_progress++;
+      // This socket is equally involved in the async operation.
+      result->new_sock->ops_in_progress++;
+    }
+  } else {
+    iocpdesc_fail(acceptor->listen_sock, WSAGetLastError(), "create accept socket");
+  }
+}
+
+static void complete_accept(accept_result_t *result, HRESULT status)
+{
+  result->new_sock->ops_in_progress--;
+  iocpdesc_t *ld = result->base.iocpd;
+  if (ld->read_closed) {
+    if (!result->new_sock->closing)
+      pni_iocp_begin_close(result->new_sock);
+    free(result);    // discard
+    reap_check(ld);
+  } else {
+    result->base.status = status;
+    pn_list_add(ld->acceptor->accepts, result);
+    pni_events_update(ld, ld->events | PN_READABLE);
+  }
+}
+
+pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error)
+{
+  if (!is_listener(ld)) {
+    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+    return INVALID_SOCKET;
+  }
+  if (ld->read_closed) {
+    set_iocp_error_status(error, PN_ERR, WSAENOTSOCK);
+    return INVALID_SOCKET;
+  }
+  if (pn_list_size(ld->acceptor->accepts) == 0) {
+    if (ld->events & PN_READABLE && ld->iocp->iocp_trace)
+      iocp_log("listen socket readable with no available accept completions\n");
+    *would_block = true;
+    return INVALID_SOCKET;
+  }
+
+  accept_result_t *result = (accept_result_t *) pn_list_get(ld->acceptor->accepts, 0);
+  pn_list_del(ld->acceptor->accepts, 0, 1);
+  if (!pn_list_size(ld->acceptor->accepts))
+    pni_events_update(ld, ld->events & ~PN_READABLE);  // No pending accepts
+
+  pn_socket_t accept_sock;
+  if (result->base.status) {
+    accept_sock = INVALID_SOCKET;
+    pni_win32_error(ld->error, "accept failure", result->base.status);
+    if (ld->iocp->iocp_trace)
+      iocp_log("%s\n", pn_error_text(ld->error));
+    // App never sees this socket so close it here.
+    pni_iocp_begin_close(result->new_sock);
+  } else {
+    accept_sock = result->new_sock->socket;
+    // AcceptEx special setsockopt:
+    setsockopt(accept_sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&ld->socket,
+                  sizeof (SOCKET));
+    if (addr && addrlen && *addrlen > 0) {
+      sockaddr_storage *local_addr = NULL;
+      sockaddr_storage *remote_addr = NULL;
+      int local_addrlen, remote_addrlen;
+      LPFN_GETACCEPTEXSOCKADDRS fn = ld->acceptor->fn_get_accept_ex_sockaddrs;
+      fn(result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
+         (SOCKADDR **) &local_addr, &local_addrlen, (SOCKADDR **) &remote_addr,
+         &remote_addrlen);
+      *addrlen = pn_min(*addrlen, remote_addrlen);
+      memmove(addr, remote_addr, *addrlen);
+    }
+  }
+
+  if (accept_sock != INVALID_SOCKET) {
+    // Connected.
+    result->new_sock->read_closed = false;
+    result->new_sock->write_closed = false;
+  }
+
+  // Done with the completion result, so reuse it
+  result->new_sock = NULL;
+  begin_accept(ld->acceptor, result);
+  return accept_sock;
+}
+
+
+// === Async connect processing
+
+typedef struct {
+  iocp_result_t base;
+  char address_buffer[IOCP_SOCKADDRBUFLEN];
+  struct addrinfo *addrinfo;
+} connect_result_t;
+
+#define connect_result_initialize NULL
+#define connect_result_compare NULL
+#define connect_result_inspect NULL
+#define connect_result_hashcode NULL
+
+static void connect_result_finalize(void *object)
+{
+  connect_result_t *result = (connect_result_t *) object;
+  // Do not release addrinfo until ConnectEx completes
+  if (result->addrinfo)
+    freeaddrinfo(result->addrinfo);
+}
+
+static connect_result_t *connect_result(iocpdesc_t *iocpd, struct addrinfo *addr) {
+  static const pn_cid_t CID_connect_result = CID_pn_void;
+  static const pn_class_t clazz = PN_CLASS(connect_result);
+  connect_result_t *result = (connect_result_t *) pn_class_new(&clazz, sizeof(connect_result_t));
+  if (result) {
+    memset(result, 0, sizeof(connect_result_t));
+    result->base.type = IOCP_CONNECT;
+    result->base.iocpd = iocpd;
+    result->addrinfo = addr;
+  }
+  return result;
+}
+
+pn_socket_t pni_iocp_begin_connect(iocp_t *iocp, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error)
+{
+  // addr lives for the duration of the async connect.  Caller has passed ownership here.
+  // See connect_result_finalize().
+  // Use of Windows-specific ConnectEx() requires our socket to be "loosely" pre-bound:
+  sockaddr_storage sa;
+  memset(&sa, 0, sizeof(sa));
+  sa.ss_family = addr->ai_family;
+  if (bind(sock, (SOCKADDR *) &sa, addr->ai_addrlen)) {
+    pni_win32_error(error, "begin async connection", WSAGetLastError());
+    if (iocp->iocp_trace)
+      iocp_log("%s\n", pn_error_text(error));
+    closesocket(sock);
+    freeaddrinfo(addr);
+    return INVALID_SOCKET;
+  }
+
+  iocpdesc_t *iocpd = pni_iocpdesc_create(iocp, sock, false);
+  bind_to_completion_port(iocpd);
+  LPFN_CONNECTEX fn_connect_ex = lookup_connect_ex(iocpd->socket);
+  connect_result_t *result = connect_result(iocpd, addr);
+  DWORD unused;
+  bool success = fn_connect_ex(iocpd->socket, result->addrinfo->ai_addr, result->addrinfo->ai_addrlen,
+                               NULL, 0, &unused, (LPOVERLAPPED) result);
+  if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
+    pni_win32_error(error, "ConnectEx failure", WSAGetLastError());
+    pn_free(result);
+    iocpd->write_closed = true;
+    iocpd->read_closed = true;
+    if (iocp->iocp_trace)
+      iocp_log("%s\n", pn_error_text(error));
+  } else {
+    iocpd->ops_in_progress++;
+  }
+  return sock;
+}
+
+static void complete_connect(connect_result_t *result, HRESULT status)
+{
+  iocpdesc_t *iocpd = result->base.iocpd;
+  if (iocpd->closing) {
+    pn_free(result);
+    reap_check(iocpd);
+    return;
+  }
+
+  if (status) {
+    iocpdesc_fail(iocpd, status, "Connect failure");
+    // Posix sets selectable events as follows:
+    pni_events_update(iocpd, PN_READABLE | PN_EXPIRED);
+  } else {
+    release_sys_sendbuf(iocpd->socket);
+    if (setsockopt(iocpd->socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT,  NULL, 0)) {
+      iocpdesc_fail(iocpd, WSAGetLastError(), "Internal connect failure (update context)");
+    } else {
+      pni_events_update(iocpd, PN_WRITABLE);
+      start_reading(iocpd);
+    }
+  }
+  pn_free(result);
+  return;
+}
+
+
+// === Async writes
+
+static bool write_in_progress(iocpdesc_t *iocpd)
+{
+  return pni_write_pipeline_size(iocpd->pipeline) != 0;
+}
+
+write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen)
+{
+  write_result_t *result = (write_result_t *) calloc(sizeof(write_result_t), 1);
+  if (result) {
+    result->base.type = IOCP_WRITE;
+    result->base.iocpd = iocpd;
+    result->buffer.start = buf;
+    result->buffer.size = buflen;
+  }
+  return result;
+}
+
+static int submit_write(write_result_t *result, const void *buf, size_t len)
+{
+  WSABUF wsabuf;
+  wsabuf.buf = (char *) buf;
+  wsabuf.len = len;
+  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+  return WSASend(result->base.iocpd->socket, &wsabuf, 1, NULL, 0,
+                 (LPOVERLAPPED) result, 0);
+}
+
+ssize_t pni_iocp_begin_write(iocpdesc_t *iocpd, const void *buf, size_t len, bool *would_block, pn_error_t *error)
+{
+  if (len == 0) return 0;
+  *would_block = false;
+  if (is_listener(iocpd)) {
+    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+    return INVALID_SOCKET;
+  }
+  if (iocpd->closing) {
+    set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
+    return SOCKET_ERROR;
+  }
+  if (iocpd->write_closed) {
+    assert(pn_error_code(iocpd->error));
+    pn_error_copy(error, iocpd->error);
+    if (iocpd->iocp->iocp_trace)
+      iocp_log("write error: %s\n", pn_error_text(error));
+    return SOCKET_ERROR;
+  }
+  if (len == 0) return 0;
+  if (!(iocpd->events & PN_WRITABLE)) {
+    *would_block = true;
+    return SOCKET_ERROR;
+  }
+
+  size_t written = 0;
+  size_t requested = len;
+  const char *outgoing = (const char *) buf;
+  size_t available = pni_write_pipeline_reserve(iocpd->pipeline, len);
+  if (!available) {
+    *would_block = true;
+    return SOCKET_ERROR;
+  }
+
+  for (size_t wr_count = 0; wr_count < available; wr_count++) {
+    write_result_t *result = pni_write_pipeline_next(iocpd->pipeline);
+    assert(result);
+    result->base.iocpd = iocpd;
+    ssize_t actual_len = pn_min(len, result->buffer.size);
+    result->requested = actual_len;
+    memmove((void *)result->buffer.start, outgoing, actual_len);
+    outgoing += actual_len;
+    written += actual_len;
+    len -= actual_len;
+
+    int werror = submit_write(result, result->buffer.start, actual_len);
+    if (werror && WSAGetLastError() != ERROR_IO_PENDING) {
+      pni_write_pipeline_return(iocpd->pipeline, result);
+      iocpdesc_fail(iocpd, WSAGetLastError(), "overlapped send");
+      return SOCKET_ERROR;
+    }
+    iocpd->ops_in_progress++;
+  }
+
+  if (!pni_write_pipeline_writable(iocpd->pipeline))
+    pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
+  return written;
+}
+
+/*
+ * Note: iocp write completion is not "bytes on the wire", it is "peer
+ * acked the sent bytes".  Completion can be seconds on a slow
+ * consuming peer.
+ */
+static void complete_write(write_result_t *result, DWORD xfer_count, HRESULT status)
+{
+  iocpdesc_t *iocpd = result->base.iocpd;
+  if (iocpd->closing) {
+    pni_write_pipeline_return(iocpd->pipeline, result);
+    if (!iocpd->write_closed && !write_in_progress(iocpd))
+      iocp_shutdown(iocpd);
+    reap_check(iocpd);
+    return;
+  }
+  if (status == 0 && xfer_count > 0) {
+    if (xfer_count != result->requested) {
+      // Is this recoverable?  How to preserve order if multiple overlapped writes?
+      pni_write_pipeline_return(iocpd->pipeline, result);
+      iocpdesc_fail(iocpd, WSA_OPERATION_ABORTED, "Partial overlapped write on socket");
+      return;
+    } else {
+      // Success.
+      pni_write_pipeline_return(iocpd->pipeline, result);
+      if (pni_write_pipeline_writable(iocpd->pipeline))
+        pni_events_update(iocpd, iocpd->events | PN_WRITABLE);
+      return;
+    }
+  }
+  // Other error
+  pni_write_pipeline_return(iocpd->pipeline, result);
+  if (status == WSAECONNABORTED || status == WSAECONNRESET || status == WSAENOTCONN
+      || status == ERROR_NETNAME_DELETED) {
+    iocpd->write_closed = true;
+    iocpd->poll_error = true;
+    pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
+    pni_win32_error(iocpd->error, "Remote close or timeout", status);
+  } else {
+    iocpdesc_fail(iocpd, status, "IOCP async write error");
+  }
+}
+
+
+// === Async reads
+
+struct read_result_t {
+  iocp_result_t base;
+  size_t drain_count;
+  char unused_buf[1];
+};
+
+static read_result_t *read_result(iocpdesc_t *iocpd)
+{
+  read_result_t *result = (read_result_t *) calloc(sizeof(read_result_t), 1);
+  if (result) {
+    result->base.type = IOCP_READ;
+    result->base.iocpd = iocpd;
+  }
+  return result;
+}
+
+static void begin_zero_byte_read(iocpdesc_t *iocpd)
+{
+  if (iocpd->read_in_progress) return;
+  if (iocpd->read_closed) {
+    pni_events_update(iocpd, iocpd->events | PN_READABLE);
+    return;
+  }
+
+  read_result_t *result = iocpd->read_result;
+  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
+  DWORD flags = 0;
+  WSABUF wsabuf;
+  wsabuf.buf = result->unused_buf;
+  wsabuf.len = 0;
+  int rc = WSARecv(iocpd->socket, &wsabuf, 1, NULL, &flags,
+                       &result->base.overlapped, 0);
+  if (rc && WSAGetLastError() != ERROR_IO_PENDING) {
+    iocpdesc_fail(iocpd, WSAGetLastError(), "IOCP read error");
+    return;
+  }
+  iocpd->ops_in_progress++;
+  iocpd->read_in_progress = true;
+}
+
+static void drain_until_closed(iocpdesc_t *iocpd) {
+  size_t max_drain = 16 * 1024;
+  char buf[512];
+  read_result_t *result = iocpd->read_result;
+  while (result->drain_count < max_drain) {
+    int rv = recv(iocpd->socket, buf, 512, 0);
+    if (rv > 0)
+      result->drain_count += rv;
+    else if (rv == 0) {
+      iocpd->read_closed = true;
+      return;
+    } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
+      // wait a little longer
+      start_reading(iocpd);
+      return;
+    }
+    else
+      break;
+  }
+  // Graceful close indication unlikely, force the issue
+  if (iocpd->iocp->iocp_trace)
+    if (result->drain_count >= max_drain)
+      iocp_log("graceful close on reader abandoned (too many chars)\n");
+    else
+      iocp_log("graceful close on reader abandoned: %d\n", WSAGetLastError());
+  iocpd->read_closed = true;
+}
+
+
+static void complete_read(read_result_t *result, DWORD xfer_count, HRESULT status)
+{
+  iocpdesc_t *iocpd = result->base.iocpd;
+  iocpd->read_in_progress = false;
+
+  if (iocpd->closing) {
+    // Application no longer reading, but we are looking for a zero length read
+    if (!iocpd->read_closed)
+      drain_until_closed(iocpd);
+    reap_check(iocpd);
+    return;
+  }
+
+  if (status == 0 && xfer_count == 0) {
+    // Success.
+    pni_events_update(iocpd, iocpd->events | PN_READABLE);
+  } else {
+    iocpdesc_fail(iocpd, status, "IOCP read complete error");
+  }
+}
+
+ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error)
+{
+  if (size == 0) return 0;
+  *would_block = false;
+  if (is_listener(iocpd)) {
+    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
+    return SOCKET_ERROR;
+  }
+  if (iocpd->closing) {
+    // Previous call to pn_close()
+    set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
+    return SOCKET_ERROR;
+  }
+  if (iocpd->read_closed) {
+    if (pn_error_code(iocpd->error))
+      pn_error_copy(error, iocpd->error);
+    else
+      set_iocp_error_status(error, PN_ERR, WSAENOTCONN);
+    return SOCKET_ERROR;
+  }
+
+  int count = recv(iocpd->socket, (char *) buf, size, 0);
+  if (count > 0) {
+    pni_events_update(iocpd, iocpd->events & ~PN_READABLE);
+    begin_zero_byte_read(iocpd);
+    return (ssize_t) count;
+  } else if (count == 0) {
+    iocpd->read_closed = true;
+    return 0;
+  }
+  if (WSAGetLastError() == WSAEWOULDBLOCK)
+    *would_block = true;
+  else {
+    set_iocp_error_status(error, PN_ERR, WSAGetLastError());
+    iocpd->read_closed = true;
+  }
+  return SOCKET_ERROR;
+}
+
+static void start_reading(iocpdesc_t *iocpd)
+{
+  begin_zero_byte_read(iocpd);
+}
+
+
+// === The iocp descriptor
+
+static void pni_iocpdesc_initialize(void *object)
+{
+  iocpdesc_t *iocpd = (iocpdesc_t *) object;
+  memset(iocpd, 0, sizeof(iocpdesc_t));
+  iocpd->socket = INVALID_SOCKET;
+}
+
+static void pni_iocpdesc_finalize(void *object)
+{
+  iocpdesc_t *iocpd = (iocpdesc_t *) object;
+  pn_free(iocpd->acceptor);
+  pn_error_free(iocpd->error);
+   if (iocpd->pipeline)
+    if (write_in_progress(iocpd))
+      iocp_log("iocp descriptor write leak\n");
+    else
+      pn_free(iocpd->pipeline);
+  if (iocpd->read_in_progress)
+    iocp_log("iocp descriptor read leak\n");
+  else
+    free(iocpd->read_result);
+}
+
+static uintptr_t pni_iocpdesc_hashcode(void *object)
+{
+  iocpdesc_t *iocpd = (iocpdesc_t *) object;
+  return iocpd->socket;
+}
+
+#define pni_iocpdesc_compare NULL
+#define pni_iocpdesc_inspect NULL
+
+// Reference counted in the iocpdesc map, zombie_list, selector.
+static iocpdesc_t *pni_iocpdesc(pn_socket_t s)
+{
+  static const pn_cid_t CID_pni_iocpdesc = CID_pn_void;
+  static pn_class_t clazz = PN_CLASS(pni_iocpdesc);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_class_new(&clazz, sizeof(iocpdesc_t));
+  assert(iocpd);
+  iocpd->socket = s;
+  return iocpd;
+}
+
+static bool is_listener_socket(pn_socket_t s)
+{
+  BOOL tval = false;
+  int tvalsz = sizeof(tval);
+  int code = getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&tval, &tvalsz);
+  return code == 0 && tval;
+}
+
+iocpdesc_t *pni_iocpdesc_create(iocp_t *iocp, pn_socket_t s, bool external) {
+  assert (s != INVALID_SOCKET);
+  assert(!pni_iocpdesc_map_get(iocp, s));
+  bool listening = is_listener_socket(s);
+  iocpdesc_t *iocpd = pni_iocpdesc(s);
+  iocpd->iocp = iocp;
+  if (iocpd) {
+    iocpd->external = external;
+    iocpd->error = pn_error();
+    if (listening) {
+      iocpd->acceptor = pni_acceptor(iocpd);
+    } else {
+      iocpd->pipeline = pni_write_pipeline(iocpd);
+      iocpd->read_result = read_result(iocpd);
+    }
+    pni_iocpdesc_map_push(iocpd);
+  }
+  return iocpd;
+}
+
+iocpdesc_t *pni_deadline_desc(iocp_t *iocp) {
+  // Non IO descriptor for selector deadlines.  Do not add to iocpdesc map or
+  // zombie list.  Selector responsible to free/decref object.
+  iocpdesc_t *iocpd = pni_iocpdesc(PN_INVALID_SOCKET);
+  iocpd->iocp = iocp;
+  iocpd->deadline_desc = true;
+  return iocpd;
+}
+
+// === Fast lookup of a socket's iocpdesc_t
+
+iocpdesc_t *pni_iocpdesc_map_get(iocp_t *iocp, pn_socket_t s) {
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_get(iocp->iocpdesc_map, s);
+  return iocpd;
+}
+
+void pni_iocpdesc_map_push(iocpdesc_t *iocpd) {
+  pn_hash_put(iocpd->iocp->iocpdesc_map, iocpd->socket, iocpd);
+  pn_decref(iocpd);
+  assert(pn_refcount(iocpd) == 1);
+}
+
+void pni_iocpdesc_map_del(iocp_t *iocp, pn_socket_t s) {
+  pn_hash_del(iocp->iocpdesc_map, (uintptr_t) s);
+}
+
+static void bind_to_completion_port(iocpdesc_t *iocpd)
+{
+  if (iocpd->bound) return;
+  if (!iocpd->iocp->completion_port) {
+    iocpdesc_fail(iocpd, WSAEINVAL, "Incomplete setup, no completion port.");
+    return;
+  }
+
+  if (CreateIoCompletionPort ((HANDLE) iocpd->socket, iocpd->iocp->completion_port, 0, 0))
+    iocpd->bound = true;
+  else {
+    iocpdesc_fail(iocpd, GetLastError(), "IOCP socket setup.");
+  }
+}
+
+static void release_sys_sendbuf(SOCKET s)
+{
+  // Set the socket's send buffer size to zero.
+  int sz = 0;
+  int status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char *)&sz, sizeof(int));
+  assert(status == 0);
+}
+
+void pni_iocpdesc_start(iocpdesc_t *iocpd)
+{
+  if (iocpd->bound) return;
+  bind_to_completion_port(iocpd);
+  if (is_listener(iocpd)) {
+    begin_accept(iocpd->acceptor, NULL);
+  }
+  else {
+    release_sys_sendbuf(iocpd->socket);
+    pni_events_update(iocpd, PN_WRITABLE);
+    start_reading(iocpd);
+  }
+}
+
+static void complete(iocp_result_t *result, bool success, DWORD num_transferred) {
+  result->iocpd->ops_in_progress--;
+  DWORD status = success ? 0 : GetLastError();
+
+  switch (result->type) {
+  case IOCP_ACCEPT:
+    complete_accept((accept_result_t *) result, status);
+    break;
+  case IOCP_CONNECT:
+    complete_connect((connect_result_t *) result, status);
+    break;
+  case IOCP_WRITE:
+    complete_write((write_result_t *) result, num_transferred, status);
+    break;
+  case IOCP_READ:
+    complete_read((read_result_t *) result, num_transferred, status);
+    break;
+  default:
+    assert(false);
+  }
+}
+
+void pni_iocp_drain_completions(iocp_t *iocp)
+{
+  while (true) {
+    DWORD timeout_ms = 0;
+    DWORD num_transferred = 0;
+    ULONG_PTR completion_key = 0;
+    OVERLAPPED *overlapped = 0;
+
+    bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
+                                               &completion_key, &overlapped, timeout_ms);
+    if (!overlapped)
+      return;  // timed out
+    iocp_result_t *result = (iocp_result_t *) overlapped;
+    complete(result, good_op, num_transferred);
+  }
+}
+
+// returns: -1 on error, 0 on timeout, 1 successful completion
+int pni_iocp_wait_one(iocp_t *iocp, int timeout, pn_error_t *error) {
+  DWORD win_timeout = (timeout < 0) ? INFINITE : (DWORD) timeout;
+  DWORD num_transferred = 0;
+  ULONG_PTR completion_key = 0;
+  OVERLAPPED *overlapped = 0;
+
+  bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
+                                            &completion_key, &overlapped, win_timeout);
+  if (!overlapped)
+    if (GetLastError() == WAIT_TIMEOUT)
+      return 0;
+    else {
+      if (error)
+        pni_win32_error(error, "GetQueuedCompletionStatus", GetLastError());
+      return -1;
+    }
+
+  iocp_result_t *result = (iocp_result_t *) overlapped;
+  complete(result, good_op, num_transferred);
+  return 1;
+}
+
+// === Close (graceful and otherwise)
+
+// zombie_list is for sockets transitioning out of iocp on their way to zero ops_in_progress
+// and fully closed.
+
+static void zombie_list_add(iocpdesc_t *iocpd)
+{
+  assert(iocpd->closing);
+  if (!iocpd->ops_in_progress) {
+    // No need to make a zombie.
+    if (iocpd->socket != INVALID_SOCKET) {
+      closesocket(iocpd->socket);
+      iocpd->socket = INVALID_SOCKET;
+      iocpd->read_closed = true;
+    }
+    return;
+  }
+  // Allow 2 seconds for graceful shutdown before releasing socket resource.
+  iocpd->reap_time = pn_i_now() + 2000;
+  pn_list_add(iocpd->iocp->zombie_list, iocpd);
+}
+
+static void reap_check(iocpdesc_t *iocpd)
+{
+  if (iocpd->closing && !iocpd->ops_in_progress) {
+    if (iocpd->socket != INVALID_SOCKET) {
+      closesocket(iocpd->socket);
+      iocpd->socket = INVALID_SOCKET;
+    }
+    pn_list_remove(iocpd->iocp->zombie_list, iocpd);
+    // iocpd is decref'ed and possibly released
+  }
+}
+
+pn_timestamp_t pni_zombie_deadline(iocp_t *iocp)
+{
+  if (pn_list_size(iocp->zombie_list)) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, 0);
+    return iocpd->reap_time;
+  }
+  return 0;
+}
+
+void pni_zombie_check(iocp_t *iocp, pn_timestamp_t now)
+{
+  pn_list_t *zl = iocp->zombie_list;
+  // Look for stale zombies that should have been reaped by "now"
+  for (size_t idx = 0; idx < pn_list_size(zl); idx++) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(zl, idx);
+    if (iocpd->reap_time > now)
+      return;
+    if (iocpd->socket == INVALID_SOCKET)
+      continue;
+    assert(iocpd->ops_in_progress > 0);
+    if (iocp->iocp_trace)
+      iocp_log("async close: graceful close timeout exceeded\n");
+    closesocket(iocpd->socket);
+    iocpd->socket = INVALID_SOCKET;
+    iocpd->read_closed = true;
+    // outstanding ops should complete immediately now
+  }
+}
+
+static void drain_zombie_completions(iocp_t *iocp)
+{
+  // No more pn_selector_select() from App, but zombies still need care and feeding
+  // until their outstanding async actions complete.
+  pni_iocp_drain_completions(iocp);
+
+  // Discard any that have no pending async IO
+  size_t sz = pn_list_size(iocp->zombie_list);
+  for (size_t idx = 0; idx < sz;) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, idx);
+    if (!iocpd->ops_in_progress) {
+      pn_list_del(iocp->zombie_list, idx, 1);
+      sz--;
+    } else {
+      idx++;
+    }
+  }
+
+  unsigned shutdown_grace = 2000;
+  char *override = getenv("PN_SHUTDOWN_GRACE");
+  if (override) {
+    int grace = atoi(override);
+    if (grace > 0 && grace < 60000)
+      shutdown_grace = (unsigned) grace;
+  }
+  pn_timestamp_t now = pn_i_now();
+  pn_timestamp_t deadline = now + shutdown_grace;
+
+  while (pn_list_size(iocp->zombie_list)) {
+    if (now >= deadline)
+      break;
+    int rv = pni_iocp_wait_one(iocp, deadline - now, NULL);
+    if (rv < 0) {
+      iocp_log("unexpected IOCP failure on Proton IO shutdown %d\n", GetLastError());
+      break;
+    }
+    now = pn_i_now();
+  }
+  if (now >= deadline && pn_list_size(iocp->zombie_list) && iocp->iocp_trace)
+    // Should only happen if really slow TCP handshakes, i.e. total network failure
+    iocp_log("network failure on Proton shutdown\n");
+}
+
+static pn_list_t *iocp_map_close_all(iocp_t *iocp)
+{
+  // Zombify stragglers, i.e. no pn_close() from the application.
+  pn_list_t *externals = pn_list(PN_OBJECT, 0);
+  for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
+       entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
+    // Just listeners first.
+    if (is_listener(iocpd)) {
+      if (iocpd->external) {
+        // Owned by application, just keep a temporary reference to it.
+        // iocp_result_t structs must not be free'd until completed or
+        // the completion port is closed.
+        if (iocpd->ops_in_progress)
+          pn_list_add(externals, iocpd);
+        pni_iocpdesc_map_del(iocp, iocpd->socket);
+      } else {
+        // Make it a zombie.
+        pni_iocp_begin_close(iocpd);
+      }
+    }
+  }
+  pni_iocp_drain_completions(iocp);
+
+  for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
+       entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
+    if (iocpd->external) {
+      iocpd->read_closed = true;   // Do not consume from read side
+      iocpd->write_closed = true;  // Do not shutdown write side
+      if (iocpd->ops_in_progress)
+        pn_list_add(externals, iocpd);
+      pni_iocpdesc_map_del(iocp, iocpd->socket);
+    } else {
+      // Make it a zombie.
+      pni_iocp_begin_close(iocpd);
+    }
+  }
+  return externals;
+}
+
+static void zombie_list_hard_close_all(iocp_t *iocp)
+{
+  pni_iocp_drain_completions(iocp);
+  size_t zs = pn_list_size(iocp->zombie_list);
+  for (size_t i = 0; i < zs; i++) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
+    if (iocpd->socket != INVALID_SOCKET) {
+      closesocket(iocpd->socket);
+      iocpd->socket = INVALID_SOCKET;
+      iocpd->read_closed = true;
+      iocpd->write_closed = true;
+    }
+  }
+  pni_iocp_drain_completions(iocp);
+
+  // Zombies should be all gone.  Do a sanity check.
+  zs = pn_list_size(iocp->zombie_list);
+  int remaining = 0;
+  int ops = 0;
+  for (size_t i = 0; i < zs; i++) {
+    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
+    remaining++;
+    ops += iocpd->ops_in_progress;
+  }
+  if (remaining)
+    iocp_log("Proton: %d unfinished close operations (ops count = %d)\n", remaining, ops);
+}
+
+static void iocp_shutdown(iocpdesc_t *iocpd)
+{
+  if (iocpd->socket == PN_INVALID_SOCKET)
+    return;    // Hard close in progress
+  if (shutdown(iocpd->socket, SD_SEND)) {
+    int err = WSAGetLastError();
+    if (err != WSAECONNABORTED && err != WSAECONNRESET && err != WSAENOTCONN)
+      if (iocpd->iocp->iocp_trace)
+        iocp_log("socket shutdown failed %d\n", err);
+  }
+  iocpd->write_closed = true;
+}
+
+void pni_iocp_begin_close(iocpdesc_t *iocpd)
+{
+  assert (!iocpd->closing);
+  if (is_listener(iocpd)) {
+    // Listening socket is easy.  Close the socket which will cancel async ops.
+    pn_socket_t old_sock = iocpd->socket;
+    iocpd->socket = INVALID_SOCKET;
+    iocpd->closing = true;
+    iocpd->read_closed = true;
+    iocpd->write_closed = true;
+    closesocket(old_sock);
+    // Pending accepts will now complete.  Zombie can die when all consumed.
+    zombie_list_add(iocpd);
+    pni_iocpdesc_map_del(iocpd->iocp, old_sock);  // may pn_free *iocpd
+  } else {
+    // Continue async operation looking for graceful close confirmation or timeout.
+    pn_socket_t old_sock = iocpd->socket;
+    iocpd->closing = true;
+    if (!iocpd->write_closed && !write_in_progress(iocpd))
+      iocp_shutdown(iocpd);
+    zombie_list_add(iocpd);
+    pni_iocpdesc_map_del(iocpd->iocp, old_sock);  // may pn_free *iocpd
+  }
+}
+
+
+// === iocp_t
+
+#define pni_iocp_hashcode NULL
+#define pni_iocp_compare NULL
+#define pni_iocp_inspect NULL
+
+void pni_iocp_initialize(void *obj)
+{
+  iocp_t *iocp = (iocp_t *) obj;
+  memset(iocp, 0, sizeof(iocp_t));
+  pni_shared_pool_create(iocp);
+  iocp->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+  assert(iocp->completion_port != NULL);
+  iocp->iocpdesc_map = pn_hash(PN_OBJECT, 0, 0.75);
+  iocp->zombie_list = pn_list(PN_OBJECT, 0);
+  iocp->iocp_trace = pn_env_bool("PN_TRACE_DRV");
+  iocp->selector = NULL;
+}
+
+void pni_iocp_finalize(void *obj)
+{
+  iocp_t *iocp = (iocp_t *) obj;
+  // Move sockets to closed state, except external sockets.
+  pn_list_t *externals = iocp_map_close_all(iocp);
+  // Now everything with ops_in_progress is in the zombie_list or the externals list.
+  assert(!pn_hash_head(iocp->iocpdesc_map));
+  pn_free(iocp->iocpdesc_map);
+
+  drain_zombie_completions(iocp);    // Last chance for graceful close
+  zombie_list_hard_close_all(iocp);
+  CloseHandle(iocp->completion_port);  // This cancels all our async ops
+  iocp->completion_port = NULL;
+
+  if (pn_list_size(externals) && iocp->iocp_trace)
+    iocp_log("%d external sockets not closed and removed from Proton IOCP control\n", pn_list_size(externals));
+
+  // Now safe to free everything that might be touched by a former async operation.
+  pn_free(externals);
+  pn_free(iocp->zombie_list);
+  pni_shared_pool_free(iocp);
+}
+
+iocp_t *pni_iocp()
+{
+  static const pn_cid_t CID_pni_iocp = CID_pn_void;
+  static const pn_class_t clazz = PN_CLASS(pni_iocp);
+  iocp_t *iocp = (iocp_t *) pn_class_new(&clazz, sizeof(iocp_t));
+  return iocp;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/iocp.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/iocp.h b/proton-c/src/reactor/io/windows/iocp.h
new file mode 100644
index 0000000..07f47be
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/iocp.h
@@ -0,0 +1,136 @@
+#ifndef PROTON_SRC_IOCP_H
+#define PROTON_SRC_IOCP_H 1
+
+/*
+ *
+ * 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/import_export.h>
+#include <proton/selectable.h>
+#include <proton/type_compat.h>
+
+typedef struct pni_acceptor_t pni_acceptor_t;
+typedef struct write_result_t write_result_t;
+typedef struct read_result_t read_result_t;
+typedef struct write_pipeline_t write_pipeline_t;
+typedef struct iocpdesc_t iocpdesc_t;
+
+
+// One per pn_io_t.
+
+struct iocp_t {
+  HANDLE completion_port;
+  pn_hash_t *iocpdesc_map;
+  pn_list_t *zombie_list;
+  int shared_pool_size;
+  char *shared_pool_memory;
+  write_result_t **shared_results;
+  write_result_t **available_results;
+  size_t shared_available_count;
+  size_t writer_count;
+  int loopback_bufsize;
+  bool iocp_trace;
+  pn_selector_t *selector;
+};
+
+
+// One for each socket.
+// This iocpdesc_t structure is ref counted by the iocpdesc_map, zombie_list,
+// selector->iocp_descriptors list.  It should remain ref counted in the
+// zombie_list until ops_in_progress == 0 or the completion port is closed.
+
+struct iocpdesc_t {
+  pn_socket_t socket;
+  iocp_t *iocp;
+  pni_acceptor_t *acceptor;
+  pn_error_t *error;
+  int ops_in_progress;
+  bool read_in_progress;
+  write_pipeline_t *pipeline;
+  read_result_t *read_result;
+  bool external;       // true if socket set up outside Proton
+  bool bound;          // associted with the completion port
+  bool closing;        // pn_close called by application
+  bool read_closed;    // EOF or read error
+  bool write_closed;   // shutdown sent or write error
+  bool poll_error;     // flag posix-like POLLERR/POLLHUP/POLLNVAL
+  bool deadline_desc;  // Socket-less deadline descriptor for selectors
+  pn_selector_t *selector;
+  pn_selectable_t *selectable;
+  int events;
+  int interests;
+  pn_timestamp_t deadline;
+  iocpdesc_t *triggered_list_next;
+  iocpdesc_t *triggered_list_prev;
+  iocpdesc_t *deadlines_next;
+  iocpdesc_t *deadlines_prev;
+  pn_timestamp_t reap_time;;
+};
+
+typedef enum { IOCP_ACCEPT, IOCP_CONNECT, IOCP_READ, IOCP_WRITE } iocp_type_t;
+
+typedef struct {
+  OVERLAPPED overlapped;
+  iocp_type_t type;
+  iocpdesc_t *iocpd;
+  HRESULT status;
+} iocp_result_t;
+
+struct write_result_t {
+  iocp_result_t base;
+  size_t requested;
+  bool in_use;
+  pn_bytes_t buffer;
+};
+
+iocpdesc_t *pni_iocpdesc_create(iocp_t *, pn_socket_t s, bool external);
+iocpdesc_t *pni_iocpdesc_map_get(iocp_t *, pn_socket_t s);
+iocpdesc_t *pni_deadline_desc(iocp_t *);
+void pni_iocpdesc_map_del(iocp_t *, pn_socket_t s);
+void pni_iocpdesc_map_push(iocpdesc_t *iocpd);
+void pni_iocpdesc_start(iocpdesc_t *iocpd);
+void pni_iocp_drain_completions(iocp_t *);
+int pni_iocp_wait_one(iocp_t *, int timeout, pn_error_t *);
+void pni_iocp_start_accepting(iocpdesc_t *iocpd);
+pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error);
+pn_socket_t pni_iocp_begin_connect(iocp_t *, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error);
+ssize_t pni_iocp_begin_write(iocpdesc_t *, const void *, size_t, bool *, pn_error_t *);
+ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error);
+void pni_iocp_begin_close(iocpdesc_t *iocpd);
+iocp_t *pni_iocp();
+
+void pni_events_update(iocpdesc_t *iocpd, int events);
+write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen);
+write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd);
+size_t pni_write_pipeline_size(write_pipeline_t *);
+bool pni_write_pipeline_writable(write_pipeline_t *);
+void pni_write_pipeline_return(write_pipeline_t *, write_result_t *);
+size_t pni_write_pipeline_reserve(write_pipeline_t *, size_t);
+write_result_t *pni_write_pipeline_next(write_pipeline_t *);
+void pni_shared_pool_create(iocp_t *);
+void pni_shared_pool_free(iocp_t *);
+void pni_zombie_check(iocp_t *, pn_timestamp_t);
+pn_timestamp_t pni_zombie_deadline(iocp_t *);
+
+pn_selector_t *pni_selector_create(iocp_t *iocp);
+
+int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code);
+
+#endif /* iocp.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/selector.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/selector.c b/proton-c/src/reactor/io/windows/selector.c
new file mode 100644
index 0000000..15da73b
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/selector.c
@@ -0,0 +1,384 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selectable.h"
+#include "reactor/selector.h"
+
+#include "iocp.h"
+#include "platform/platform.h"
+#include "core/util.h"
+
+#include <proton/object.h>
+#include <proton/error.h>
+#include <assert.h>
+
+static void interests_update(iocpdesc_t *iocpd, int interests);
+static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t t);
+
+struct pn_selector_t {
+  iocp_t *iocp;
+  pn_list_t *selectables;
+  pn_list_t *iocp_descriptors;
+  size_t current;
+  iocpdesc_t *current_triggered;
+  pn_timestamp_t awoken;
+  pn_error_t *error;
+  iocpdesc_t *triggered_list_head;
+  iocpdesc_t *triggered_list_tail;
+  iocpdesc_t *deadlines_head;
+  iocpdesc_t *deadlines_tail;
+};
+
+void pn_selector_initialize(void *obj)
+{
+  pn_selector_t *selector = (pn_selector_t *) obj;
+  selector->iocp = NULL;
+  selector->selectables = pn_list(PN_WEAKREF, 0);
+  selector->iocp_descriptors = pn_list(PN_OBJECT, 0);
+  selector->current = 0;
+  selector->current_triggered = NULL;
+  selector->awoken = 0;
+  selector->error = pn_error();
+  selector->triggered_list_head = NULL;
+  selector->triggered_list_tail = NULL;
+  selector->deadlines_head = NULL;
+  selector->deadlines_tail = NULL;
+}
+
+void pn_selector_finalize(void *obj)
+{
+  pn_selector_t *selector = (pn_selector_t *) obj;
+  pn_free(selector->selectables);
+  pn_free(selector->iocp_descriptors);
+  pn_error_free(selector->error);
+  selector->iocp->selector = NULL;
+}
+
+#define pn_selector_hashcode NULL
+#define pn_selector_compare NULL
+#define pn_selector_inspect NULL
+
+pn_selector_t *pni_selector()
+{
+  static const pn_class_t clazz = PN_CLASS(pn_selector);
+  pn_selector_t *selector = (pn_selector_t *) pn_class_new(&clazz, sizeof(pn_selector_t));
+  return selector;
+}
+
+pn_selector_t *pni_selector_create(iocp_t *iocp)
+{
+  pn_selector_t *selector = pni_selector();
+  selector->iocp = iocp;
+  return selector;
+}
+
+void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+  assert(selector);
+  assert(selectable);
+  assert(pni_selectable_get_index(selectable) < 0);
+  pn_socket_t sock = pn_selectable_get_fd(selectable);
+  iocpdesc_t *iocpd = NULL;
+
+  if (pni_selectable_get_index(selectable) < 0) {
+    pn_list_add(selector->selectables, selectable);
+    pn_list_add(selector->iocp_descriptors, NULL);
+    size_t size = pn_list_size(selector->selectables);
+    pni_selectable_set_index(selectable, size - 1);
+  }
+
+  pn_selector_update(selector, selectable);
+}
+
+void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+  // A selectable's fd may switch from PN_INVALID_SCOKET to a working socket between
+  // update calls.  If a selectable without a valid socket has a deadline, we need
+  // a dummy iocpdesc_t to participate in the deadlines list.
+  int idx = pni_selectable_get_index(selectable);
+  assert(idx >= 0);
+  pn_timestamp_t deadline = pn_selectable_get_deadline(selectable);
+  pn_socket_t sock = pn_selectable_get_fd(selectable);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
+
+  if (!iocpd && deadline && sock == PN_INVALID_SOCKET) {
+    iocpd = pni_deadline_desc(selector->iocp);
+    assert(iocpd);
+    pn_list_set(selector->iocp_descriptors, idx, iocpd);
+    pn_decref(iocpd);  // life is solely tied to iocp_descriptors list
+    iocpd->selector = selector;
+    iocpd->selectable = selectable;
+  }
+  else if (iocpd && iocpd->deadline_desc && sock != PN_INVALID_SOCKET) {
+    // Switching to a real socket.  Stop using a deadline descriptor.
+    deadlines_update(iocpd, 0);
+    // decref descriptor in list and pick up a real iocpd below
+    pn_list_set(selector->iocp_descriptors, idx, NULL);
+    iocpd = NULL;
+  }
+
+  // The selectables socket may be set long after it has been added
+  if (!iocpd && sock != PN_INVALID_SOCKET) {
+    iocpd = pni_iocpdesc_map_get(selector->iocp, sock);
+    if (!iocpd) {
+      // Socket created outside proton.  Hook it up to iocp.
+      iocpd = pni_iocpdesc_create(selector->iocp, sock, true);
+      assert(iocpd);
+      if (iocpd)
+        pni_iocpdesc_start(iocpd);
+    }
+    if (iocpd) {
+      pn_list_set(selector->iocp_descriptors, idx, iocpd);
+      iocpd->selector = selector;
+      iocpd->selectable = selectable;
+    }
+  }
+
+  if (iocpd) {
+    assert(sock == iocpd->socket || iocpd->closing);
+    int interests = PN_ERROR; // Always
+    if (pn_selectable_is_reading(selectable)) {
+      interests |= PN_READABLE;
+    }
+    if (pn_selectable_is_writing(selectable)) {
+      interests |= PN_WRITABLE;
+    }
+    if (deadline) {
+      interests |= PN_EXPIRED;
+    }
+    interests_update(iocpd, interests);
+    deadlines_update(iocpd, deadline);
+  }
+}
+
+void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable)
+{
+  assert(selector);
+  assert(selectable);
+
+  int idx = pni_selectable_get_index(selectable);
+  assert(idx >= 0);
+  iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(selector->iocp_descriptors, idx);
+  if (iocpd) {
+    if (selector->current_triggered == iocpd)
+      selector->current_triggered = iocpd->triggered_list_next;
+    interests_update(iocpd, 0);
+    deadlines_update(iocpd, 0);
+    assert(selector->triggered_list_head != iocpd && !iocpd->triggered_list_prev);
+    assert(selector->deadlines_head != iocpd && !iocpd->deadlines_prev);
+    iocpd->selector = NULL;
+    iocpd->selectable = NULL;
+  }
+  pn_list_del(selector->selectables, idx, 1);
+  pn_list_del(selector->iocp_descriptors, idx, 1);
+  size_t size = pn_list_size(selector->selectables);
+  for (size_t i = idx; i < size; i++) {
+    pn_selectable_t *sel = (pn_selectable_t *) pn_list_get(selector->selectables, i);
+    pni_selectable_set_index(sel, i);
+  }
+
+  pni_selectable_set_index(selectable, -1);
+
+  if (selector->current >= (size_t) idx) {
+    selector->current--;
+  }
+}
+
+size_t pn_selector_size(pn_selector_t *selector) {
+  assert(selector);
+  return pn_list_size(selector->selectables);
+}
+
+int pn_selector_select(pn_selector_t *selector, int timeout)
+{
+  assert(selector);
+  pn_error_clear(selector->error);
+  pn_timestamp_t deadline = 0;
+  pn_timestamp_t now = pn_i_now();
+
+  if (timeout) {
+    if (selector->deadlines_head)
+      deadline = selector->deadlines_head->deadline;
+  }
+  if (deadline) {
+    int64_t delta = deadline - now;
+    if (delta < 0) {
+      delta = 0;
+    }
+    if (timeout < 0)
+      timeout = delta;
+    else if (timeout > delta)
+      timeout = delta;
+  }
+  deadline = (timeout >= 0) ? now + timeout : 0;
+
+  // Process all currently available completions, even if matched events available
+  pni_iocp_drain_completions(selector->iocp);
+  pni_zombie_check(selector->iocp, now);
+  // Loop until an interested event is matched, or until deadline
+  while (true) {
+    if (selector->triggered_list_head)
+      break;
+    if (deadline && deadline <= now)
+      break;
+    pn_timestamp_t completion_deadline = deadline;
+    pn_timestamp_t zd = pni_zombie_deadline(selector->iocp);
+    if (zd)
+      completion_deadline = completion_deadline ? pn_min(zd, completion_deadline) : zd;
+
+    int completion_timeout = (!completion_deadline) ? -1 : completion_deadline - now;
+    int rv = pni_iocp_wait_one(selector->iocp, completion_timeout, selector->error);
+    if (rv < 0)
+      return pn_error_code(selector->error);
+
+    now = pn_i_now();
+    if (zd && zd <= now) {
+      pni_zombie_check(selector->iocp, now);
+    }
+  }
+
+  selector->current = 0;
+  selector->awoken = now;
+  for (iocpdesc_t *iocpd = selector->deadlines_head; iocpd; iocpd = iocpd->deadlines_next) {
+    if (iocpd->deadline <= now)
+      pni_events_update(iocpd, iocpd->events | PN_EXPIRED);
+    else
+      break;
+  }
+  selector->current_triggered = selector->triggered_list_head;
+  return pn_error_code(selector->error);
+}
+
+pn_selectable_t *pn_selector_next(pn_selector_t *selector, int *events)
+{
+  if (selector->current_triggered) {
+    iocpdesc_t *iocpd = selector->current_triggered;
+    *events = iocpd->interests & iocpd->events;
+    selector->current_triggered = iocpd->triggered_list_next;
+    return iocpd->selectable;
+  }
+  return NULL;
+}
+
+void pn_selector_free(pn_selector_t *selector)
+{
+  assert(selector);
+  pn_free(selector);
+}
+
+
+static void triggered_list_add(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+  if (iocpd->triggered_list_prev || selector->triggered_list_head == iocpd)
+    return; // already in list
+  LL_ADD(selector, triggered_list, iocpd);
+}
+
+static void triggered_list_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+  if (!iocpd->triggered_list_prev && selector->triggered_list_head != iocpd)
+    return; // not in list
+  LL_REMOVE(selector, triggered_list, iocpd);
+  iocpd->triggered_list_prev = NULL;
+  iocpd->triggered_list_next = NULL;
+}
+
+
+void pni_events_update(iocpdesc_t *iocpd, int events)
+{
+  // If set, a poll error is permanent
+  if (iocpd->poll_error)
+    events |= PN_ERROR;
+  if (iocpd->events == events)
+    return;
+  iocpd->events = events;
+  if (iocpd->selector) {
+    if (iocpd->events & iocpd->interests)
+      triggered_list_add(iocpd->selector, iocpd);
+    else
+      triggered_list_remove(iocpd->selector, iocpd);
+  }
+}
+
+static void interests_update(iocpdesc_t *iocpd, int interests)
+{
+  int old_interests = iocpd->interests;
+  if (old_interests == interests)
+    return;
+  iocpd->interests = interests;
+  if (iocpd->selector) {
+    if (iocpd->events & iocpd->interests)
+      triggered_list_add(iocpd->selector, iocpd);
+    else
+      triggered_list_remove(iocpd->selector, iocpd);
+  }
+}
+
+static void deadlines_remove(pn_selector_t *selector, iocpdesc_t *iocpd)
+{
+  if (!iocpd->deadlines_prev && selector->deadlines_head != iocpd)
+    return; // not in list
+  LL_REMOVE(selector, deadlines, iocpd);
+  iocpd->deadlines_prev = NULL;
+  iocpd->deadlines_next = NULL;
+}
+
+
+static void deadlines_update(iocpdesc_t *iocpd, pn_timestamp_t deadline)
+{
+  if (deadline == iocpd->deadline)
+    return;
+
+  iocpd->deadline = deadline;
+  pn_selector_t *selector = iocpd->selector;
+  if (!deadline) {
+    deadlines_remove(selector, iocpd);
+    pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
+  } else {
+    if (iocpd->deadlines_prev || selector->deadlines_head == iocpd) {
+      deadlines_remove(selector, iocpd);
+      pni_events_update(iocpd, iocpd->events & ~PN_EXPIRED);
+    }
+    iocpdesc_t *dl_iocpd = LL_HEAD(selector, deadlines);
+    while (dl_iocpd && dl_iocpd->deadline <= deadline)
+      dl_iocpd = dl_iocpd->deadlines_next;
+    if (dl_iocpd) {
+      // insert
+      iocpd->deadlines_prev = dl_iocpd->deadlines_prev;
+      iocpd->deadlines_next = dl_iocpd;
+      dl_iocpd->deadlines_prev = iocpd;
+      if (selector->deadlines_head == dl_iocpd)
+        selector->deadlines_head = iocpd;
+    } else {
+      LL_ADD(selector, deadlines, iocpd);  // append
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/io/windows/write_pipeline.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/io/windows/write_pipeline.c b/proton-c/src/reactor/io/windows/write_pipeline.c
new file mode 100644
index 0000000..905c7f6
--- /dev/null
+++ b/proton-c/src/reactor/io/windows/write_pipeline.c
@@ -0,0 +1,314 @@
+/*
+ *
+ * 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 simple write buffer pool.  Each socket has a dedicated "primary"
+ * buffer and can borrow from a shared pool with limited size tuning.
+ * Could enhance e.g. with separate pools per network interface and fancier
+ * memory tuning based on interface speed, system resources, and
+ * number of connections, etc.
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#if _WIN32_WINNT < 0x0501
+#error "Proton requires Windows API support for XP or later."
+#endif
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+
+#include "reactor/io.h"
+#include "reactor/selector.h"
+#include "reactor/selectable.h"
+
+#include "iocp.h"
+#include "core/util.h"
+
+#include <proton/error.h>
+#include <proton/object.h>
+
+#include <assert.h>
+
+// Max overlapped writes per socket
+#define IOCP_MAX_OWRITES 16
+// Write buffer size
+#define IOCP_WBUFSIZE 16384
+
+static void pipeline_log(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fflush(stderr);
+}
+
+void pni_shared_pool_create(iocp_t *iocp)
+{
+  // TODO: more pools (or larger one) when using multiple non-loopback interfaces
+  iocp->shared_pool_size = 16;
+  char *env = getenv("PNI_WRITE_BUFFERS"); // Internal: for debugging
+  if (env) {
+    int sz = atoi(env);
+    if (sz >= 0 && sz < 256) {
+      iocp->shared_pool_size = sz;
+    }
+  }
+  iocp->loopback_bufsize = 0;
+  env = getenv("PNI_LB_BUFSIZE"); // Internal: for debugging
+  if (env) {
+    int sz = atoi(env);
+    if (sz >= 0 && sz <= 128 * 1024) {
+      iocp->loopback_bufsize = sz;
+    }
+  }
+
+  if (iocp->shared_pool_size) {
+    iocp->shared_pool_memory = (char *) VirtualAlloc(NULL, IOCP_WBUFSIZE * iocp->shared_pool_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+    HRESULT status = GetLastError();
+    if (!iocp->shared_pool_memory) {
+      perror("Proton write buffer pool allocation failure\n");
+      iocp->shared_pool_size = 0;
+      iocp->shared_available_count = 0;
+      return;
+    }
+
+    iocp->shared_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
+    iocp->available_results = (write_result_t **) malloc(iocp->shared_pool_size * sizeof(write_result_t *));
+    iocp->shared_available_count = iocp->shared_pool_size;
+    char *mem = iocp->shared_pool_memory;
+    for (int i = 0; i < iocp->shared_pool_size; i++) {
+      iocp->shared_results[i] = iocp->available_results[i] = pni_write_result(NULL, mem, IOCP_WBUFSIZE);
+      mem += IOCP_WBUFSIZE;
+    }
+  }
+}
+
+void pni_shared_pool_free(iocp_t *iocp)
+{
+  for (int i = 0; i < iocp->shared_pool_size; i++) {
+    write_result_t *result = iocp->shared_results[i];
+    if (result->in_use)
+      pipeline_log("Proton buffer pool leak\n");
+    else
+      free(result);
+  }
+  if (iocp->shared_pool_size) {
+    free(iocp->shared_results);
+    free(iocp->available_results);
+    if (iocp->shared_pool_memory) {
+      if (!VirtualFree(iocp->shared_pool_memory, 0, MEM_RELEASE)) {
+        perror("write buffers release failed");
+      }
+      iocp->shared_pool_memory = NULL;
+    }
+  }
+}
+
+static void shared_pool_push(write_result_t *result)
+{
+  iocp_t *iocp = result->base.iocpd->iocp;
+  assert(iocp->shared_available_count < iocp->shared_pool_size);
+  iocp->available_results[iocp->shared_available_count++] = result;
+}
+
+static write_result_t *shared_pool_pop(iocp_t *iocp)
+{
+  return iocp->shared_available_count ? iocp->available_results[--iocp->shared_available_count] : NULL;
+}
+
+struct write_pipeline_t {
+  iocpdesc_t *iocpd;
+  size_t pending_count;
+  write_result_t *primary;
+  size_t reserved_count;
+  size_t next_primary_index;
+  size_t depth;
+  bool is_writer;
+};
+
+#define write_pipeline_compare NULL
+#define write_pipeline_inspect NULL
+#define write_pipeline_hashcode NULL
+
+static void write_pipeline_initialize(void *object)
+{
+  write_pipeline_t *pl = (write_pipeline_t *) object;
+  pl->pending_count = 0;
+  const char *pribuf = (const char *) malloc(IOCP_WBUFSIZE);
+  pl->primary = pni_write_result(NULL, pribuf, IOCP_WBUFSIZE);
+  pl->depth = 0;
+  pl->is_writer = false;
+}
+
+static void write_pipeline_finalize(void *object)
+{
+  write_pipeline_t *pl = (write_pipeline_t *) object;
+  free((void *)pl->primary->buffer.start);
+  free(pl->primary);
+}
+
+write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd)
+{
+  static const pn_cid_t CID_write_pipeline = CID_pn_void;
+  static const pn_class_t clazz = PN_CLASS(write_pipeline);
+  write_pipeline_t *pipeline = (write_pipeline_t *) pn_class_new(&clazz, sizeof(write_pipeline_t));
+  pipeline->iocpd = iocpd;
+  pipeline->primary->base.iocpd = iocpd;
+  return pipeline;
+}
+
+static void confirm_as_writer(write_pipeline_t *pl)
+{
+  if (!pl->is_writer) {
+    iocp_t *iocp = pl->iocpd->iocp;
+    iocp->writer_count++;
+    pl->is_writer = true;
+  }
+}
+
+static void remove_as_writer(write_pipeline_t *pl)
+{
+  if (!pl->is_writer)
+    return;
+  iocp_t *iocp = pl->iocpd->iocp;
+  assert(iocp->writer_count);
+  pl->is_writer = false;
+  iocp->writer_count--;
+}
+
+/*
+ * Optimal depth will depend on properties of the NIC, server, and driver.  For now,
+ * just distinguish between loopback interfaces and the rest.  Optimizations in the
+ * loopback stack allow decent performance with depth 1 and actually cause major
+ * performance hiccups if set to large values.
+ */
+static void set_depth(write_pipeline_t *pl)
+{
+  pl->depth = 1;
+  sockaddr_storage sa;
+  socklen_t salen = sizeof(sa);
+  char buf[INET6_ADDRSTRLEN];
+  DWORD buflen = sizeof(buf);
+
+  if (getsockname(pl->iocpd->socket,(sockaddr*) &sa, &salen) == 0 &&
+      getnameinfo((sockaddr*) &sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0) {
+    if ((sa.ss_family == AF_INET6 && strcmp(buf, "::1")) ||
+        (sa.ss_family == AF_INET && strncmp(buf, "127.", 4))) {
+      // not loopback
+      pl->depth = IOCP_MAX_OWRITES;
+    } else {
+      iocp_t *iocp = pl->iocpd->iocp;
+      if (iocp->loopback_bufsize) {
+        const char *p = (const char *) realloc((void *) pl->primary->buffer.start, iocp->loopback_bufsize);
+        if (p) {
+          pl->primary->buffer.start = p;
+          pl->primary->buffer.size = iocp->loopback_bufsize;
+        }
+      }
+    }
+  }
+}
+
+// Reserve as many buffers as possible for count bytes.
+size_t pni_write_pipeline_reserve(write_pipeline_t *pl, size_t count)
+{
+  if (pl->primary->in_use)
+    return 0;  // I.e. io->wouldblock
+  if (!pl->depth)
+    set_depth(pl);
+  if (pl->depth == 1) {
+    // always use the primary
+    pl->reserved_count = 1;
+    pl->next_primary_index = 0;
+    return 1;
+  }
+
+  iocp_t *iocp = pl->iocpd->iocp;
+  confirm_as_writer(pl);
+  size_t wanted = (count / IOCP_WBUFSIZE);
+  if (count % IOCP_WBUFSIZE)
+    wanted++;
+  size_t pending = pl->pending_count;
+  assert(pending < pl->depth);
+  size_t bufs = pn_min(wanted, pl->depth - pending);
+  // Can draw from shared pool or the primary... but share with others.
+  size_t writers = iocp->writer_count;
+  size_t shared_count = (iocp->shared_available_count + writers - 1) / writers;
+  bufs = pn_min(bufs, shared_count + 1);
+  pl->reserved_count = pending + bufs;
+
+  if (bufs == wanted &&
+      pl->reserved_count < (pl->depth / 2) &&
+      iocp->shared_available_count > (2 * writers + bufs)) {
+    // No shortage: keep the primary as spare for future use
+    pl->next_primary_index = pl->reserved_count;
+  } else if (bufs == 1) {
+    pl->next_primary_index = pending;
+  } else {
+    // let approx 1/3 drain before replenishing
+    pl->next_primary_index = ((pl->reserved_count + 2) / 3) - 1;
+    if (pl->next_primary_index < pending)
+      pl->next_primary_index = pending;
+  }
+  return bufs;
+}
+
+write_result_t *pni_write_pipeline_next(write_pipeline_t *pl)
+{
+  size_t sz = pl->pending_count;
+  if (sz >= pl->reserved_count)
+    return NULL;
+  write_result_t *result;
+  if (sz == pl->next_primary_index) {
+    result = pl->primary;
+  } else {
+    assert(pl->iocpd->iocp->shared_available_count > 0);
+    result = shared_pool_pop(pl->iocpd->iocp);
+  }
+
+  result->in_use = true;
+  pl->pending_count++;
+  return result;
+}
+
+void pni_write_pipeline_return(write_pipeline_t *pl, write_result_t *result)
+{
+  result->in_use = false;
+  pl->pending_count--;
+  pl->reserved_count = 0;
+  if (result != pl->primary)
+    shared_pool_push(result);
+  if (pl->pending_count == 0)
+    remove_as_writer(pl);
+}
+
+bool pni_write_pipeline_writable(write_pipeline_t *pl)
+{
+  // Only writable if not full and we can guarantee a buffer:
+  return pl->pending_count < pl->depth && !pl->primary->in_use;
+}
+
+size_t pni_write_pipeline_size(write_pipeline_t *pl)
+{
+  return pl->pending_count;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/reactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/reactor.c b/proton-c/src/reactor/reactor.c
index a83a881..abf5d1e 100644
--- a/proton-c/src/reactor/reactor.c
+++ b/proton-c/src/reactor/reactor.c
@@ -19,23 +19,24 @@
  *
  */
 
+#include "io.h"
+#include "reactor.h"
+#include "selectable.h"
+#include "platform/platform.h" // pn_i_now
+
 #include <proton/object.h>
 #include <proton/handlers.h>
-#include <proton/io.h>
 #include <proton/event.h>
 #include <proton/transport.h>
 #include <proton/connection.h>
 #include <proton/session.h>
 #include <proton/link.h>
 #include <proton/delivery.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 
-#include "reactor.h"
-#include "selectable.h"
-#include "platform.h"
-
 struct pn_reactor_t {
   pn_record_t *attachments;
   pn_io_t *io;
@@ -164,7 +165,7 @@ void pn_reactor_set_handler(pn_reactor_t *reactor, pn_handler_t *handler) {
   pn_incref(reactor->handler);
 }
 
-pn_io_t *pn_reactor_io(pn_reactor_t *reactor) {
+pn_io_t *pni_reactor_io(pn_reactor_t *reactor) {
   assert(reactor);
   return reactor->io;
 }
@@ -389,6 +390,16 @@ bool pn_reactor_quiesced(pn_reactor_t *reactor) {
   return pn_event_type(event) == PN_REACTOR_QUIESCED;
 }
 
+pn_handler_t *pn_event_root(pn_event_t *event)
+{
+  pn_handler_t *h = pn_record_get_handler(pn_event_attachments(event));
+  return h;
+}
+
+static void pni_event_set_root(pn_event_t *event, pn_handler_t *handler) {
+  pn_record_set_handler(pn_event_attachments(event), handler);
+}
+
 bool pn_reactor_process(pn_reactor_t *reactor) {
   assert(reactor);
   pn_reactor_mark(reactor);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/reactor.h
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/reactor.h b/proton-c/src/reactor/reactor.h
index 461e8b3..bfb397c 100644
--- a/proton-c/src/reactor/reactor.h
+++ b/proton-c/src/reactor/reactor.h
@@ -26,9 +26,9 @@
 #include <proton/url.h>
 
 void pni_record_init_reactor(pn_record_t *record, pn_reactor_t *reactor);
-void pni_event_set_root(pn_event_t *event, pn_handler_t *handler);
 void pni_reactor_set_connection_peer_address(pn_connection_t *connection,
                                              const char *host,
                                              const char *port);
+pn_io_t *pni_reactor_io(pn_reactor_t *reactor);
 
 #endif /* src/reactor.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/reactor/selectable.c
----------------------------------------------------------------------
diff --git a/proton-c/src/reactor/selectable.c b/proton-c/src/reactor/selectable.c
new file mode 100644
index 0000000..b42ad1f
--- /dev/null
+++ b/proton-c/src/reactor/selectable.c
@@ -0,0 +1,300 @@
+/*
+ *
+ * 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 "selectable.h"
+
+#include <proton/error.h>
+
+#include "io.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+pn_selectables_t *pn_selectables(void)
+{
+  return pn_iterator();
+}
+
+pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables)
+{
+  return (pn_selectable_t *) pn_iterator_next(selectables);
+}
+
+void pn_selectables_free(pn_selectables_t *selectables)
+{
+  pn_free(selectables);
+}
+
+struct pn_selectable_t {
+  pn_socket_t fd;
+  int index;
+  pn_record_t *attachments;
+  void (*readable)(pn_selectable_t *);
+  void (*writable)(pn_selectable_t *);
+  void (*error)(pn_selectable_t *);
+  void (*expired)(pn_selectable_t *);
+  void (*release) (pn_selectable_t *);
+  void (*finalize)(pn_selectable_t *);
+  pn_collector_t *collector;
+  pn_timestamp_t deadline;
+  bool reading;
+  bool writing;
+  bool registered;
+  bool terminal;
+};
+
+void pn_selectable_initialize(pn_selectable_t *sel)
+{
+  sel->fd = PN_INVALID_SOCKET;
+  sel->index = -1;
+  sel->attachments = pn_record();
+  sel->readable = NULL;
+  sel->writable = NULL;
+  sel->error = NULL;
+  sel->expired = NULL;
+  sel->release = NULL;
+  sel->finalize = NULL;
+  sel->collector = NULL;
+  sel->deadline = 0;
+  sel->reading = false;
+  sel->writing = false;
+  sel->registered = false;
+  sel->terminal = false;
+}
+
+void pn_selectable_finalize(pn_selectable_t *sel)
+{
+  if (sel->finalize) {
+    sel->finalize(sel);
+  }
+  pn_decref(sel->attachments);
+  pn_decref(sel->collector);
+}
+
+#define pn_selectable_hashcode NULL
+#define pn_selectable_inspect NULL
+#define pn_selectable_compare NULL
+
+PN_CLASSDEF(pn_selectable)
+
+pn_selectable_t *pn_selectable(void)
+{
+  return pn_selectable_new();
+}
+
+bool pn_selectable_is_reading(pn_selectable_t *sel) {
+  assert(sel);
+  return sel->reading;
+}
+
+void pn_selectable_set_reading(pn_selectable_t *sel, bool reading) {
+  assert(sel);
+  sel->reading = reading;
+}
+
+bool pn_selectable_is_writing(pn_selectable_t *sel) {
+  assert(sel);
+  return sel->writing;
+}
+
+void pn_selectable_set_writing(pn_selectable_t *sel, bool writing) {
+  assert(sel);
+  sel->writing = writing;
+}
+
+pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *sel) {
+  assert(sel);
+  return sel->deadline;
+}
+
+void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline) {
+  assert(sel);
+  sel->deadline = deadline;
+}
+
+void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *)) {
+  assert(sel);
+  sel->readable = readable;
+}
+
+void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *)) {
+  assert(sel);
+  sel->writable = writable;
+}
+
+void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *)) {
+  assert(sel);
+  sel->error = error;
+}
+
+void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *)) {
+  assert(sel);
+  sel->expired = expired;
+}
+
+void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *)) {
+  assert(sel);
+  sel->release = release;
+}
+
+void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *)) {
+  assert(sel);
+  sel->finalize = finalize;
+}
+
+pn_record_t *pn_selectable_attachments(pn_selectable_t *sel) {
+  return sel->attachments;
+}
+
+void *pni_selectable_get_context(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  return pn_record_get(selectable->attachments, PN_LEGCTX);
+}
+
+void pni_selectable_set_context(pn_selectable_t *selectable, void *context)
+{
+  assert(selectable);
+  pn_record_set(selectable->attachments, PN_LEGCTX, context);
+}
+
+int pni_selectable_get_index(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  return selectable->index;
+}
+
+void pni_selectable_set_index(pn_selectable_t *selectable, int index)
+{
+  assert(selectable);
+  selectable->index = index;
+}
+
+pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  return selectable->fd;
+}
+
+void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd)
+{
+  assert(selectable);
+  selectable->fd = fd;
+}
+
+void pn_selectable_readable(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  if (selectable->readable) {
+    selectable->readable(selectable);
+  }
+}
+
+void pn_selectable_writable(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  if (selectable->writable) {
+    selectable->writable(selectable);
+  }
+}
+
+void pn_selectable_error(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  if (selectable->error) {
+    selectable->error(selectable);
+  }
+}
+
+void pn_selectable_expired(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  if (selectable->expired) {
+    selectable->expired(selectable);
+  }
+}
+
+bool pn_selectable_is_registered(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  return selectable->registered;
+}
+
+void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered)
+{
+  assert(selectable);
+  selectable->registered = registered;
+}
+
+bool pn_selectable_is_terminal(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  return selectable->terminal;
+}
+
+void pn_selectable_terminate(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  selectable->terminal = true;
+}
+
+void pn_selectable_release(pn_selectable_t *selectable)
+{
+  assert(selectable);
+  if (selectable->release) {
+    selectable->release(selectable);
+  }
+}
+
+void pn_selectable_free(pn_selectable_t *selectable)
+{
+  pn_decref(selectable);
+}
+
+static void pni_readable(pn_selectable_t *selectable) {
+  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_READABLE);
+}
+
+static void pni_writable(pn_selectable_t *selectable) {
+  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_WRITABLE);
+}
+
+static void pni_error(pn_selectable_t *selectable) {
+  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_ERROR);
+}
+
+static void pni_expired(pn_selectable_t *selectable) {
+  pn_collector_put(selectable->collector, PN_OBJECT, selectable, PN_SELECTABLE_EXPIRED);
+}
+
+void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector) {
+  assert(selectable);
+  pn_decref(selectable->collector);
+  selectable->collector = collector;
+  pn_incref(selectable->collector);
+
+  if (collector) {
+    pn_selectable_on_readable(selectable, pni_readable);
+    pn_selectable_on_writable(selectable, pni_writable);
+    pn_selectable_on_error(selectable, pni_error);
+    pn_selectable_on_expired(selectable, pni_expired);
+  }
+}


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


[10/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/engine/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine.c b/proton-c/src/engine/engine.c
deleted file mode 100644
index cb1f479..0000000
--- a/proton-c/src/engine/engine.c
+++ /dev/null
@@ -1,2231 +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 "engine-internal.h"
-#include <stdlib.h>
-#include <string.h>
-#include "protocol.h"
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "platform.h"
-#include "platform_fmt.h"
-#include "transport/transport.h"
-
-
-static void pni_session_bound(pn_session_t *ssn);
-static void pni_link_bound(pn_link_t *link);
-
-
-// endpoints
-
-static pn_connection_t *pni_ep_get_connection(pn_endpoint_t *endpoint)
-{
-  switch (endpoint->type) {
-  case CONNECTION:
-    return (pn_connection_t *) endpoint;
-  case SESSION:
-    return ((pn_session_t *) endpoint)->connection;
-  case SENDER:
-  case RECEIVER:
-    return ((pn_link_t *) endpoint)->session->connection;
-  }
-
-  return NULL;
-}
-
-static pn_event_type_t endpoint_event(pn_endpoint_type_t type, bool open) {
-  switch (type) {
-  case CONNECTION:
-    return open ? PN_CONNECTION_LOCAL_OPEN : PN_CONNECTION_LOCAL_CLOSE;
-  case SESSION:
-    return open ? PN_SESSION_LOCAL_OPEN : PN_SESSION_LOCAL_CLOSE;
-  case SENDER:
-  case RECEIVER:
-    return open ? PN_LINK_LOCAL_OPEN : PN_LINK_LOCAL_CLOSE;
-  default:
-    assert(false);
-    return PN_EVENT_NONE;
-  }
-}
-
-static void pn_endpoint_open(pn_endpoint_t *endpoint)
-{
-  if (!(endpoint->state & PN_LOCAL_ACTIVE)) {
-    PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
-    pn_connection_t *conn = pni_ep_get_connection(endpoint);
-    pn_collector_put(conn->collector, PN_OBJECT, endpoint,
-                     endpoint_event(endpoint->type, true));
-    pn_modified(conn, endpoint, true);
-  }
-}
-
-static void pn_endpoint_close(pn_endpoint_t *endpoint)
-{
-  if (!(endpoint->state & PN_LOCAL_CLOSED)) {
-    PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
-    pn_connection_t *conn = pni_ep_get_connection(endpoint);
-    pn_collector_put(conn->collector, PN_OBJECT, endpoint,
-                     endpoint_event(endpoint->type, false));
-    pn_modified(conn, endpoint, true);
-  }
-}
-
-void pn_connection_reset(pn_connection_t *connection)
-{
-  assert(connection);
-  pn_endpoint_t *endpoint = &connection->endpoint;
-  endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
-}
-
-void pn_connection_open(pn_connection_t *connection)
-{
-  assert(connection);
-  pn_endpoint_open(&connection->endpoint);
-}
-
-void pn_connection_close(pn_connection_t *connection)
-{
-  assert(connection);
-  pn_endpoint_close(&connection->endpoint);
-}
-
-static void pni_endpoint_tini(pn_endpoint_t *endpoint);
-
-void pn_connection_release(pn_connection_t *connection)
-{
-  assert(!connection->endpoint.freed);
-  // free those endpoints that haven't been freed by the application
-  LL_REMOVE(connection, endpoint, &connection->endpoint);
-  while (connection->endpoint_head) {
-    pn_endpoint_t *ep = connection->endpoint_head;
-    switch (ep->type) {
-    case SESSION:
-      // note: this will free all child links:
-      pn_session_free((pn_session_t *)ep);
-      break;
-    case SENDER:
-    case RECEIVER:
-      pn_link_free((pn_link_t *)ep);
-      break;
-    default:
-      assert(false);
-    }
-  }
-  connection->endpoint.freed = true;
-  if (!connection->transport) {
-    // no transport available to consume transport work items,
-    // so manually clear them:
-    pn_ep_incref(&connection->endpoint);
-    pn_connection_unbound(connection);
-  }
-  pn_ep_decref(&connection->endpoint);
-}
-
-void pn_connection_free(pn_connection_t *connection) {
-  pn_connection_release(connection);
-  pn_decref(connection);
-}
-
-void pn_connection_bound(pn_connection_t *connection)
-{
-  pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_BOUND);
-  pn_ep_incref(&connection->endpoint);
-
-  size_t nsessions = pn_list_size(connection->sessions);
-  for (size_t i = 0; i < nsessions; i++) {
-    pni_session_bound((pn_session_t *) pn_list_get(connection->sessions, i));
-  }
-}
-
-// invoked when transport has been removed:
-void pn_connection_unbound(pn_connection_t *connection)
-{
-  connection->transport = NULL;
-  if (connection->endpoint.freed) {
-    // connection has been freed prior to unbinding, thus it
-    // cannot be re-assigned to a new transport.  Clear the
-    // transport work lists to allow the connection to be freed.
-    while (connection->transport_head) {
-        pn_clear_modified(connection, connection->transport_head);
-    }
-    while (connection->tpwork_head) {
-      pn_clear_tpwork(connection->tpwork_head);
-    }
-  }
-  pn_ep_decref(&connection->endpoint);
-}
-
-pn_record_t *pn_connection_attachments(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->context;
-}
-
-void *pn_connection_get_context(pn_connection_t *conn)
-{
-  // XXX: we should really assert on conn here, but this causes
-  // messenger tests to fail
-  return conn ? pn_record_get(conn->context, PN_LEGCTX) : NULL;
-}
-
-void pn_connection_set_context(pn_connection_t *conn, void *context)
-{
-  assert(conn);
-  pn_record_set(conn->context, PN_LEGCTX, context);
-}
-
-pn_transport_t *pn_connection_transport(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->transport;
-}
-
-void pn_condition_init(pn_condition_t *condition)
-{
-  condition->name = pn_string(NULL);
-  condition->description = pn_string(NULL);
-  condition->info = pn_data(0);
-}
-
-void pn_condition_tini(pn_condition_t *condition)
-{
-  pn_data_free(condition->info);
-  pn_free(condition->description);
-  pn_free(condition->name);
-}
-
-static void pni_add_session(pn_connection_t *conn, pn_session_t *ssn)
-{
-  pn_list_add(conn->sessions, ssn);
-  ssn->connection = conn;
-  pn_incref(conn);  // keep around until finalized
-  pn_ep_incref(&conn->endpoint);
-}
-
-static void pni_remove_session(pn_connection_t *conn, pn_session_t *ssn)
-{
-  if (pn_list_remove(conn->sessions, ssn)) {
-    pn_ep_decref(&conn->endpoint);
-    LL_REMOVE(conn, endpoint, &ssn->endpoint);
-  }
-}
-
-pn_connection_t *pn_session_connection(pn_session_t *session)
-{
-  if (!session) return NULL;
-  return session->connection;
-}
-
-void pn_session_open(pn_session_t *session)
-{
-  assert(session);
-  pn_endpoint_open(&session->endpoint);
-}
-
-void pn_session_close(pn_session_t *session)
-{
-  assert(session);
-  pn_endpoint_close(&session->endpoint);
-}
-
-void pn_session_free(pn_session_t *session)
-{
-  assert(!session->endpoint.freed);
-  while(pn_list_size(session->links)) {
-    pn_link_t *link = (pn_link_t *)pn_list_get(session->links, 0);
-    pn_link_free(link);
-  }
-  pni_remove_session(session->connection, session);
-  pn_list_add(session->connection->freed, session);
-  session->endpoint.freed = true;
-  pn_ep_decref(&session->endpoint);
-
-  // the finalize logic depends on endpoint.freed, so we incref/decref
-  // to give it a chance to rerun
-  pn_incref(session);
-  pn_decref(session);
-}
-
-pn_record_t *pn_session_attachments(pn_session_t *session)
-{
-  assert(session);
-  return session->context;
-}
-
-void *pn_session_get_context(pn_session_t *session)
-{
-  return session ? pn_record_get(session->context, PN_LEGCTX) : 0;
-}
-
-void pn_session_set_context(pn_session_t *session, void *context)
-{
-  assert(context);
-  pn_record_set(session->context, PN_LEGCTX, context);
-}
-
-
-static void pni_add_link(pn_session_t *ssn, pn_link_t *link)
-{
-  pn_list_add(ssn->links, link);
-  link->session = ssn;
-  pn_ep_incref(&ssn->endpoint);
-}
-
-static void pni_remove_link(pn_session_t *ssn, pn_link_t *link)
-{
-  if (pn_list_remove(ssn->links, link)) {
-    pn_ep_decref(&ssn->endpoint);
-    LL_REMOVE(ssn->connection, endpoint, &link->endpoint);
-  }
-}
-
-void pn_link_open(pn_link_t *link)
-{
-  assert(link);
-  pn_endpoint_open(&link->endpoint);
-}
-
-void pn_link_close(pn_link_t *link)
-{
-  assert(link);
-  pn_endpoint_close(&link->endpoint);
-}
-
-void pn_link_detach(pn_link_t *link)
-{
-  assert(link);
-  if (link->detached) return;
-
-  link->detached = true;
-  pn_collector_put(link->session->connection->collector, PN_OBJECT, link, PN_LINK_LOCAL_DETACH);
-  pn_modified(link->session->connection, &link->endpoint, true);
-
-}
-
-static void pni_terminus_free(pn_terminus_t *terminus)
-{
-  pn_free(terminus->address);
-  pn_free(terminus->properties);
-  pn_free(terminus->capabilities);
-  pn_free(terminus->outcomes);
-  pn_free(terminus->filter);
-}
-
-void pn_link_free(pn_link_t *link)
-{
-  assert(!link->endpoint.freed);
-  pni_remove_link(link->session, link);
-  pn_list_add(link->session->freed, link);
-  pn_delivery_t *delivery = link->unsettled_head;
-  while (delivery) {
-    pn_delivery_t *next = delivery->unsettled_next;
-    pn_delivery_settle(delivery);
-    delivery = next;
-  }
-  link->endpoint.freed = true;
-  pn_ep_decref(&link->endpoint);
-
-  // the finalize logic depends on endpoint.freed (modified above), so
-  // we incref/decref to give it a chance to rerun
-  pn_incref(link);
-  pn_decref(link);
-}
-
-void *pn_link_get_context(pn_link_t *link)
-{
-  assert(link);
-  return pn_record_get(link->context, PN_LEGCTX);
-}
-
-void pn_link_set_context(pn_link_t *link, void *context)
-{
-  assert(link);
-  pn_record_set(link->context, PN_LEGCTX, context);
-}
-
-pn_record_t *pn_link_attachments(pn_link_t *link)
-{
-  assert(link);
-  return link->context;
-}
-
-void pn_endpoint_init(pn_endpoint_t *endpoint, int type, pn_connection_t *conn)
-{
-  endpoint->type = (pn_endpoint_type_t) type;
-  endpoint->referenced = true;
-  endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
-  endpoint->error = pn_error();
-  pn_condition_init(&endpoint->condition);
-  pn_condition_init(&endpoint->remote_condition);
-  endpoint->endpoint_next = NULL;
-  endpoint->endpoint_prev = NULL;
-  endpoint->transport_next = NULL;
-  endpoint->transport_prev = NULL;
-  endpoint->modified = false;
-  endpoint->freed = false;
-  endpoint->refcount = 1;
-  //fprintf(stderr, "initting 0x%lx\n", (uintptr_t) endpoint);
-
-  LL_ADD(conn, endpoint, endpoint);
-}
-
-void pn_ep_incref(pn_endpoint_t *endpoint)
-{
-  endpoint->refcount++;
-}
-
-static pn_event_type_t pn_final_type(pn_endpoint_type_t type) {
-  switch (type) {
-  case CONNECTION:
-    return PN_CONNECTION_FINAL;
-  case SESSION:
-    return PN_SESSION_FINAL;
-  case SENDER:
-  case RECEIVER:
-    return PN_LINK_FINAL;
-  default:
-    assert(false);
-    return PN_EVENT_NONE;
-  }
-}
-
-static pn_endpoint_t *pn_ep_parent(pn_endpoint_t *endpoint) {
-  switch (endpoint->type) {
-  case CONNECTION:
-    return NULL;
-  case SESSION:
-    return &((pn_session_t *) endpoint)->connection->endpoint;
-  case SENDER:
-  case RECEIVER:
-    return &((pn_link_t *) endpoint)->session->endpoint;
-  default:
-    assert(false);
-    return NULL;
-  }
-}
-
-void pn_ep_decref(pn_endpoint_t *endpoint)
-{
-  assert(endpoint->refcount > 0);
-  endpoint->refcount--;
-  if (endpoint->refcount == 0) {
-    pn_connection_t *conn = pni_ep_get_connection(endpoint);
-    pn_collector_put(conn->collector, PN_OBJECT, endpoint, pn_final_type(endpoint->type));
-  }
-}
-
-static void pni_endpoint_tini(pn_endpoint_t *endpoint)
-{
-  pn_error_free(endpoint->error);
-  pn_condition_tini(&endpoint->remote_condition);
-  pn_condition_tini(&endpoint->condition);
-}
-
-static void pni_free_children(pn_list_t *children, pn_list_t *freed)
-{
-  while (pn_list_size(children) > 0) {
-    pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(children, 0);
-    assert(!endpoint->referenced);
-    pn_free(endpoint);
-  }
-
-  while (pn_list_size(freed) > 0) {
-    pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(freed, 0);
-    assert(!endpoint->referenced);
-    pn_free(endpoint);
-  }
-
-  pn_free(children);
-  pn_free(freed);
-}
-
-static void pn_connection_finalize(void *object)
-{
-  pn_connection_t *conn = (pn_connection_t *) object;
-  pn_endpoint_t *endpoint = &conn->endpoint;
-
-  if (conn->transport) {
-    assert(!conn->transport->referenced);
-    pn_free(conn->transport);
-  }
-
-  // freeing the transport could post events
-  if (pn_refcount(conn) > 0) {
-    return;
-  }
-
-  pni_free_children(conn->sessions, conn->freed);
-  pn_free(conn->context);
-  pn_decref(conn->collector);
-
-  pn_free(conn->container);
-  pn_free(conn->hostname);
-  pn_free(conn->auth_user);
-  pn_free(conn->auth_password);
-  pn_free(conn->offered_capabilities);
-  pn_free(conn->desired_capabilities);
-  pn_free(conn->properties);
-  pni_endpoint_tini(endpoint);
-  pn_free(conn->delivery_pool);
-}
-
-#define pn_connection_initialize NULL
-#define pn_connection_hashcode NULL
-#define pn_connection_compare NULL
-#define pn_connection_inspect NULL
-
-pn_connection_t *pn_connection(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_connection);
-  pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, sizeof(pn_connection_t));
-  if (!conn) return NULL;
-
-  conn->endpoint_head = NULL;
-  conn->endpoint_tail = NULL;
-  pn_endpoint_init(&conn->endpoint, CONNECTION, conn);
-  conn->transport_head = NULL;
-  conn->transport_tail = NULL;
-  conn->sessions = pn_list(PN_WEAKREF, 0);
-  conn->freed = pn_list(PN_WEAKREF, 0);
-  conn->transport = NULL;
-  conn->work_head = NULL;
-  conn->work_tail = NULL;
-  conn->tpwork_head = NULL;
-  conn->tpwork_tail = NULL;
-  conn->container = pn_string(NULL);
-  conn->hostname = pn_string(NULL);
-  conn->auth_user = pn_string(NULL);
-  conn->auth_password = pn_string(NULL);
-  conn->offered_capabilities = pn_data(0);
-  conn->desired_capabilities = pn_data(0);
-  conn->properties = pn_data(0);
-  conn->collector = NULL;
-  conn->context = pn_record();
-  conn->delivery_pool = pn_list(PN_OBJECT, 0);
-
-  return conn;
-}
-
-static const pn_event_type_t endpoint_init_event_map[] = {
-  PN_CONNECTION_INIT,  /* CONNECTION */
-  PN_SESSION_INIT,     /* SESSION */
-  PN_LINK_INIT,        /* SENDER */
-  PN_LINK_INIT};       /* RECEIVER */
-
-void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector)
-{
-  pn_decref(connection->collector);
-  connection->collector = collector;
-  pn_incref(connection->collector);
-  pn_endpoint_t *endpoint = connection->endpoint_head;
-  while (endpoint) {
-    pn_collector_put(connection->collector, PN_OBJECT, endpoint, endpoint_init_event_map[endpoint->type]);
-    endpoint = endpoint->endpoint_next;
-  }
-}
-
-pn_state_t pn_connection_state(pn_connection_t *connection)
-{
-  return connection ? connection->endpoint.state : 0;
-}
-
-pn_error_t *pn_connection_error(pn_connection_t *connection)
-{
-  return connection ? connection->endpoint.error : NULL;
-}
-
-const char *pn_connection_get_container(pn_connection_t *connection)
-{
-  assert(connection);
-  return pn_string_get(connection->container);
-}
-
-void pn_connection_set_container(pn_connection_t *connection, const char *container)
-{
-  assert(connection);
-  pn_string_set(connection->container, container);
-}
-
-const char *pn_connection_get_hostname(pn_connection_t *connection)
-{
-  assert(connection);
-  return pn_string_get(connection->hostname);
-}
-
-void pn_connection_set_hostname(pn_connection_t *connection, const char *hostname)
-{
-  assert(connection);
-  pn_string_set(connection->hostname, hostname);
-}
-
-const char *pn_connection_get_user(pn_connection_t *connection)
-{
-    assert(connection);
-    return pn_string_get(connection->auth_user);
-}
-
-void pn_connection_set_user(pn_connection_t *connection, const char *user)
-{
-    assert(connection);
-    pn_string_set(connection->auth_user, user);
-}
-
-void pn_connection_set_password(pn_connection_t *connection, const char *password)
-{
-    assert(connection);
-    // Make sure the previous password is erased, if there was one.
-    size_t n = pn_string_size(connection->auth_password);
-    const char* s = pn_string_get(connection->auth_password);
-    if (n > 0 && s) memset((void*)s, 0, n);
-    pn_string_set(connection->auth_password, password);
-}
-
-pn_data_t *pn_connection_offered_capabilities(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->offered_capabilities;
-}
-
-pn_data_t *pn_connection_desired_capabilities(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->desired_capabilities;
-}
-
-pn_data_t *pn_connection_properties(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->properties;
-}
-
-pn_data_t *pn_connection_remote_offered_capabilities(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->transport ? connection->transport->remote_offered_capabilities : NULL;
-}
-
-pn_data_t *pn_connection_remote_desired_capabilities(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->transport ? connection->transport->remote_desired_capabilities : NULL;
-}
-
-pn_data_t *pn_connection_remote_properties(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->transport ? connection->transport->remote_properties : NULL;
-}
-
-const char *pn_connection_remote_container(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->transport ? connection->transport->remote_container : NULL;
-}
-
-const char *pn_connection_remote_hostname(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->transport ? connection->transport->remote_hostname : NULL;
-}
-
-pn_delivery_t *pn_work_head(pn_connection_t *connection)
-{
-  assert(connection);
-  return connection->work_head;
-}
-
-pn_delivery_t *pn_work_next(pn_delivery_t *delivery)
-{
-  assert(delivery);
-
-  if (delivery->work)
-    return delivery->work_next;
-  else
-    return pn_work_head(delivery->link->session->connection);
-}
-
-static void pni_add_work(pn_connection_t *connection, pn_delivery_t *delivery)
-{
-  if (!delivery->work)
-  {
-    assert(!delivery->local.settled);   // never allow settled deliveries
-    LL_ADD(connection, work, delivery);
-    delivery->work = true;
-  }
-}
-
-static void pni_clear_work(pn_connection_t *connection, pn_delivery_t *delivery)
-{
-  if (delivery->work)
-  {
-    LL_REMOVE(connection, work, delivery);
-    delivery->work = false;
-  }
-}
-
-void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery)
-{
-  pn_link_t *link = pn_delivery_link(delivery);
-  pn_delivery_t *current = pn_link_current(link);
-  if (delivery->updated && !delivery->local.settled) {
-    pni_add_work(connection, delivery);
-  } else if (delivery == current) {
-    if (link->endpoint.type == SENDER) {
-      if (pn_link_credit(link) > 0) {
-        pni_add_work(connection, delivery);
-      } else {
-        pni_clear_work(connection, delivery);
-      }
-    } else {
-      pni_add_work(connection, delivery);
-    }
-  } else {
-    pni_clear_work(connection, delivery);
-  }
-}
-
-static void pni_add_tpwork(pn_delivery_t *delivery)
-{
-  pn_connection_t *connection = delivery->link->session->connection;
-  if (!delivery->tpwork)
-  {
-    LL_ADD(connection, tpwork, delivery);
-    delivery->tpwork = true;
-  }
-  pn_modified(connection, &connection->endpoint, true);
-}
-
-void pn_clear_tpwork(pn_delivery_t *delivery)
-{
-  pn_connection_t *connection = delivery->link->session->connection;
-  if (delivery->tpwork)
-  {
-    LL_REMOVE(connection, tpwork, delivery);
-    delivery->tpwork = false;
-    if (pn_refcount(delivery) > 0) {
-      pn_incref(delivery);
-      pn_decref(delivery);
-    }
-  }
-}
-
-void pn_dump(pn_connection_t *conn)
-{
-  pn_endpoint_t *endpoint = conn->transport_head;
-  while (endpoint)
-  {
-    printf("%p", (void *) endpoint);
-    endpoint = endpoint->transport_next;
-    if (endpoint)
-      printf(" -> ");
-  }
-  printf("\n");
-}
-
-void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit)
-{
-  if (!endpoint->modified) {
-    LL_ADD(connection, transport, endpoint);
-    endpoint->modified = true;
-  }
-
-  if (emit && connection->transport) {
-    pn_collector_put(connection->collector, PN_OBJECT, connection->transport,
-                     PN_TRANSPORT);
-  }
-}
-
-void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint)
-{
-  if (endpoint->modified) {
-    LL_REMOVE(connection, transport, endpoint);
-    endpoint->transport_next = NULL;
-    endpoint->transport_prev = NULL;
-    endpoint->modified = false;
-  }
-}
-
-static bool pni_matches(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
-{
-  if (endpoint->type != type) return false;
-
-  if (!state) return true;
-
-  int st = endpoint->state;
-  if ((state & PN_REMOTE_MASK) == 0 || (state & PN_LOCAL_MASK) == 0)
-    return st & state;
-  else
-    return st == state;
-}
-
-pn_endpoint_t *pn_find(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
-{
-  while (endpoint)
-  {
-    if (pni_matches(endpoint, type, state))
-      return endpoint;
-    endpoint = endpoint->endpoint_next;
-  }
-  return NULL;
-}
-
-pn_session_t *pn_session_head(pn_connection_t *conn, pn_state_t state)
-{
-  if (conn)
-    return (pn_session_t *) pn_find(conn->endpoint_head, SESSION, state);
-  else
-    return NULL;
-}
-
-pn_session_t *pn_session_next(pn_session_t *ssn, pn_state_t state)
-{
-  if (ssn)
-    return (pn_session_t *) pn_find(ssn->endpoint.endpoint_next, SESSION, state);
-  else
-    return NULL;
-}
-
-pn_link_t *pn_link_head(pn_connection_t *conn, pn_state_t state)
-{
-  if (!conn) return NULL;
-
-  pn_endpoint_t *endpoint = conn->endpoint_head;
-
-  while (endpoint)
-  {
-    if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
-      return (pn_link_t *) endpoint;
-    endpoint = endpoint->endpoint_next;
-  }
-
-  return NULL;
-}
-
-pn_link_t *pn_link_next(pn_link_t *link, pn_state_t state)
-{
-  if (!link) return NULL;
-
-  pn_endpoint_t *endpoint = link->endpoint.endpoint_next;
-
-  while (endpoint)
-  {
-    if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
-      return (pn_link_t *) endpoint;
-    endpoint = endpoint->endpoint_next;
-  }
-
-  return NULL;
-}
-
-static void pn_session_incref(void *object)
-{
-  pn_session_t *session = (pn_session_t *) object;
-  if (!session->endpoint.referenced) {
-    session->endpoint.referenced = true;
-    pn_incref(session->connection);
-  } else {
-    pn_object_incref(object);
-  }
-}
-
-static bool pn_ep_bound(pn_endpoint_t *endpoint)
-{
-  pn_connection_t *conn = pni_ep_get_connection(endpoint);
-  pn_session_t *ssn;
-  pn_link_t *lnk;
-
-  if (!conn->transport) return false;
-  if (endpoint->modified) return true;
-
-  switch (endpoint->type) {
-  case CONNECTION:
-    return ((pn_connection_t *)endpoint)->transport;
-  case SESSION:
-    ssn = (pn_session_t *) endpoint;
-    return (((int16_t) ssn->state.local_channel) >= 0 || ((int16_t) ssn->state.remote_channel) >= 0);
-  case SENDER:
-  case RECEIVER:
-    lnk = (pn_link_t *) endpoint;
-    return ((int32_t) lnk->state.local_handle) >= 0 || ((int32_t) lnk->state.remote_handle) >= 0;
-  default:
-    assert(false);
-    return false;
-  }
-}
-
-static bool pni_connection_live(pn_connection_t *conn) {
-  return pn_refcount(conn) > 1;
-}
-
-static bool pni_session_live(pn_session_t *ssn) {
-  return pni_connection_live(ssn->connection) || pn_refcount(ssn) > 1;
-}
-
-static bool pni_link_live(pn_link_t *link) {
-  return pni_session_live(link->session) || pn_refcount(link) > 1;
-}
-
-static bool pni_endpoint_live(pn_endpoint_t *endpoint) {
-  switch (endpoint->type) {
-  case CONNECTION:
-    return pni_connection_live((pn_connection_t *)endpoint);
-  case SESSION:
-    return pni_session_live((pn_session_t *) endpoint);
-  case SENDER:
-  case RECEIVER:
-    return pni_link_live((pn_link_t *) endpoint);
-  default:
-    assert(false);
-    return false;
-  }
-}
-
-static bool pni_preserve_child(pn_endpoint_t *endpoint)
-{
-  pn_connection_t *conn = pni_ep_get_connection(endpoint);
-  pn_endpoint_t *parent = pn_ep_parent(endpoint);
-  if (pni_endpoint_live(parent) && (!endpoint->freed || (pn_ep_bound(endpoint)))
-      && endpoint->referenced) {
-    pn_object_incref(endpoint);
-    endpoint->referenced = false;
-    pn_decref(parent);
-    return true;
-  } else {
-    LL_REMOVE(conn, transport, endpoint);
-    return false;
-  }
-}
-
-static void pn_session_finalize(void *object)
-{
-  pn_session_t *session = (pn_session_t *) object;
-  pn_endpoint_t *endpoint = &session->endpoint;
-
-  if (pni_preserve_child(endpoint)) {
-    return;
-  }
-
-  pn_free(session->context);
-  pni_free_children(session->links, session->freed);
-  pni_endpoint_tini(endpoint);
-  pn_delivery_map_free(&session->state.incoming);
-  pn_delivery_map_free(&session->state.outgoing);
-  pn_free(session->state.local_handles);
-  pn_free(session->state.remote_handles);
-  pni_remove_session(session->connection, session);
-  pn_list_remove(session->connection->freed, session);
-
-  if (session->connection->transport) {
-    pn_transport_t *transport = session->connection->transport;
-    pn_hash_del(transport->local_channels, session->state.local_channel);
-    pn_hash_del(transport->remote_channels, session->state.remote_channel);
-  }
-
-  if (endpoint->referenced) {
-    pn_decref(session->connection);
-  }
-}
-
-#define pn_session_new pn_object_new
-#define pn_session_refcount pn_object_refcount
-#define pn_session_decref pn_object_decref
-#define pn_session_reify pn_object_reify
-#define pn_session_initialize NULL
-#define pn_session_hashcode NULL
-#define pn_session_compare NULL
-#define pn_session_inspect NULL
-
-pn_session_t *pn_session(pn_connection_t *conn)
-{
-  assert(conn);
-
-
-  pn_transport_t * transport = pn_connection_transport(conn);
-
-  if(transport) {
-    // channel_max is an index, not a count.  
-    if(pn_hash_size(transport->local_channels) > (size_t)transport->channel_max) {
-      pn_transport_logf(transport, 
-                        "pn_session: too many sessions: %d  channel_max is %d",
-                        pn_hash_size(transport->local_channels),
-                        transport->channel_max);
-      return (pn_session_t *) 0;
-    }
-  }
-
-#define pn_session_free pn_object_free
-  static const pn_class_t clazz = PN_METACLASS(pn_session);
-#undef pn_session_free
-  pn_session_t *ssn = (pn_session_t *) pn_class_new(&clazz, sizeof(pn_session_t));
-  if (!ssn) return NULL;
-  pn_endpoint_init(&ssn->endpoint, SESSION, conn);
-  pni_add_session(conn, ssn);
-  ssn->links = pn_list(PN_WEAKREF, 0);
-  ssn->freed = pn_list(PN_WEAKREF, 0);
-  ssn->context = pn_record();
-  ssn->incoming_capacity = 1024*1024;
-  ssn->incoming_bytes = 0;
-  ssn->outgoing_bytes = 0;
-  ssn->incoming_deliveries = 0;
-  ssn->outgoing_deliveries = 0;
-  ssn->outgoing_window = 2147483647;
-
-  // begin transport state
-  memset(&ssn->state, 0, sizeof(ssn->state));
-  ssn->state.local_channel = (uint16_t)-1;
-  ssn->state.remote_channel = (uint16_t)-1;
-  pn_delivery_map_init(&ssn->state.incoming, 0);
-  pn_delivery_map_init(&ssn->state.outgoing, 0);
-  ssn->state.local_handles = pn_hash(PN_WEAKREF, 0, 0.75);
-  ssn->state.remote_handles = pn_hash(PN_WEAKREF, 0, 0.75);
-  // end transport state
-
-  pn_collector_put(conn->collector, PN_OBJECT, ssn, PN_SESSION_INIT);
-  if (conn->transport) {
-    pni_session_bound(ssn);
-  }
-  pn_decref(ssn);
-  return ssn;
-}
-
-static void pni_session_bound(pn_session_t *ssn)
-{
-  assert(ssn);
-  size_t nlinks = pn_list_size(ssn->links);
-  for (size_t i = 0; i < nlinks; i++) {
-    pni_link_bound((pn_link_t *) pn_list_get(ssn->links, i));
-  }
-}
-
-void pn_session_unbound(pn_session_t* ssn)
-{
-  assert(ssn);
-  ssn->state.local_channel = (uint16_t)-1;
-  ssn->state.remote_channel = (uint16_t)-1;
-  ssn->incoming_bytes = 0;
-  ssn->outgoing_bytes = 0;
-  ssn->incoming_deliveries = 0;
-  ssn->outgoing_deliveries = 0;
-}
-
-size_t pn_session_get_incoming_capacity(pn_session_t *ssn)
-{
-  assert(ssn);
-  return ssn->incoming_capacity;
-}
-
-void pn_session_set_incoming_capacity(pn_session_t *ssn, size_t capacity)
-{
-  assert(ssn);
-  // XXX: should this trigger a flow?
-  ssn->incoming_capacity = capacity;
-}
-
-size_t pn_session_get_outgoing_window(pn_session_t *ssn)
-{
-  assert(ssn);
-  return ssn->outgoing_window;
-}
-
-void pn_session_set_outgoing_window(pn_session_t *ssn, size_t window)
-{
-  assert(ssn);
-  ssn->outgoing_window = window;
-}
-
-size_t pn_session_outgoing_bytes(pn_session_t *ssn)
-{
-  assert(ssn);
-  return ssn->outgoing_bytes;
-}
-
-size_t pn_session_incoming_bytes(pn_session_t *ssn)
-{
-  assert(ssn);
-  return ssn->incoming_bytes;
-}
-
-pn_state_t pn_session_state(pn_session_t *session)
-{
-  return session->endpoint.state;
-}
-
-pn_error_t *pn_session_error(pn_session_t *session)
-{
-  return session->endpoint.error;
-}
-
-static void pni_terminus_init(pn_terminus_t *terminus, pn_terminus_type_t type)
-{
-  terminus->type = type;
-  terminus->address = pn_string(NULL);
-  terminus->durability = PN_NONDURABLE;
-  terminus->expiry_policy = PN_EXPIRE_WITH_SESSION;
-  terminus->timeout = 0;
-  terminus->dynamic = false;
-  terminus->distribution_mode = PN_DIST_MODE_UNSPECIFIED;
-  terminus->properties = pn_data(0);
-  terminus->capabilities = pn_data(0);
-  terminus->outcomes = pn_data(0);
-  terminus->filter = pn_data(0);
-}
-
-static void pn_link_incref(void *object)
-{
-  pn_link_t *link = (pn_link_t *) object;
-  if (!link->endpoint.referenced) {
-    link->endpoint.referenced = true;
-    pn_incref(link->session);
-  } else {
-    pn_object_incref(object);
-  }
-}
-
-static void pn_link_finalize(void *object)
-{
-  pn_link_t *link = (pn_link_t *) object;
-  pn_endpoint_t *endpoint = &link->endpoint;
-
-  if (pni_preserve_child(endpoint)) {
-    return;
-  }
-
-  while (link->unsettled_head) {
-    assert(!link->unsettled_head->referenced);
-    pn_free(link->unsettled_head);
-  }
-
-  pn_free(link->context);
-  pni_terminus_free(&link->source);
-  pni_terminus_free(&link->target);
-  pni_terminus_free(&link->remote_source);
-  pni_terminus_free(&link->remote_target);
-  pn_free(link->name);
-  pni_endpoint_tini(endpoint);
-  pni_remove_link(link->session, link);
-  pn_hash_del(link->session->state.local_handles, link->state.local_handle);
-  pn_hash_del(link->session->state.remote_handles, link->state.remote_handle);
-  pn_list_remove(link->session->freed, link);
-  if (endpoint->referenced) {
-    pn_decref(link->session);
-  }
-}
-
-#define pn_link_refcount pn_object_refcount
-#define pn_link_decref pn_object_decref
-#define pn_link_reify pn_object_reify
-#define pn_link_initialize NULL
-#define pn_link_hashcode NULL
-#define pn_link_compare NULL
-#define pn_link_inspect NULL
-
-pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
-{
-#define pn_link_new pn_object_new
-#define pn_link_free pn_object_free
-  static const pn_class_t clazz = PN_METACLASS(pn_link);
-#undef pn_link_new
-#undef pn_link_free
-  pn_link_t *link = (pn_link_t *) pn_class_new(&clazz, sizeof(pn_link_t));
-
-  pn_endpoint_init(&link->endpoint, type, session->connection);
-  pni_add_link(session, link);
-  pn_incref(session);  // keep session until link finalized
-  link->name = pn_string(name);
-  pni_terminus_init(&link->source, PN_SOURCE);
-  pni_terminus_init(&link->target, PN_TARGET);
-  pni_terminus_init(&link->remote_source, PN_UNSPECIFIED);
-  pni_terminus_init(&link->remote_target, PN_UNSPECIFIED);
-  link->unsettled_head = link->unsettled_tail = link->current = NULL;
-  link->unsettled_count = 0;
-  link->available = 0;
-  link->credit = 0;
-  link->queued = 0;
-  link->drain = false;
-  link->drain_flag_mode = true;
-  link->drained = 0;
-  link->context = pn_record();
-  link->snd_settle_mode = PN_SND_MIXED;
-  link->rcv_settle_mode = PN_RCV_FIRST;
-  link->remote_snd_settle_mode = PN_SND_MIXED;
-  link->remote_rcv_settle_mode = PN_RCV_FIRST;
-  link->detached = false;
-
-  // begin transport state
-  link->state.local_handle = -1;
-  link->state.remote_handle = -1;
-  link->state.delivery_count = 0;
-  link->state.link_credit = 0;
-  // end transport state
-
-  pn_collector_put(session->connection->collector, PN_OBJECT, link, PN_LINK_INIT);
-  if (session->connection->transport) {
-    pni_link_bound(link);
-  }
-  pn_decref(link);
-  return link;
-}
-
-static void pni_link_bound(pn_link_t *link)
-{
-}
-
-void pn_link_unbound(pn_link_t* link)
-{
-  assert(link);
-  link->state.local_handle = -1;
-  link->state.remote_handle = -1;
-  link->state.delivery_count = 0;
-  link->state.link_credit = 0;
-}
-
-pn_terminus_t *pn_link_source(pn_link_t *link)
-{
-  return link ? &link->source : NULL;
-}
-
-pn_terminus_t *pn_link_target(pn_link_t *link)
-{
-  return link ? &link->target : NULL;
-}
-
-pn_terminus_t *pn_link_remote_source(pn_link_t *link)
-{
-  return link ? &link->remote_source : NULL;
-}
-
-pn_terminus_t *pn_link_remote_target(pn_link_t *link)
-{
-  return link ? &link->remote_target : NULL;
-}
-
-int pn_terminus_set_type(pn_terminus_t *terminus, pn_terminus_type_t type)
-{
-  if (!terminus) return PN_ARG_ERR;
-  terminus->type = type;
-  return 0;
-}
-
-pn_terminus_type_t pn_terminus_get_type(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->type : (pn_terminus_type_t) 0;
-}
-
-const char *pn_terminus_get_address(pn_terminus_t *terminus)
-{
-  assert(terminus);
-  return pn_string_get(terminus->address);
-}
-
-int pn_terminus_set_address(pn_terminus_t *terminus, const char *address)
-{
-  assert(terminus);
-  return pn_string_set(terminus->address, address);
-}
-
-pn_durability_t pn_terminus_get_durability(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->durability : (pn_durability_t) 0;
-}
-
-int pn_terminus_set_durability(pn_terminus_t *terminus, pn_durability_t durability)
-{
-  if (!terminus) return PN_ARG_ERR;
-  terminus->durability = durability;
-  return 0;
-}
-
-pn_expiry_policy_t pn_terminus_get_expiry_policy(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->expiry_policy : (pn_expiry_policy_t) 0;
-}
-
-int pn_terminus_set_expiry_policy(pn_terminus_t *terminus, pn_expiry_policy_t expiry_policy)
-{
-  if (!terminus) return PN_ARG_ERR;
-  terminus->expiry_policy = expiry_policy;
-  return 0;
-}
-
-pn_seconds_t pn_terminus_get_timeout(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->timeout : 0;
-}
-
-int pn_terminus_set_timeout(pn_terminus_t *terminus, pn_seconds_t timeout)
-{
-  if (!terminus) return PN_ARG_ERR;
-  terminus->timeout = timeout;
-  return 0;
-}
-
-bool pn_terminus_is_dynamic(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->dynamic : false;
-}
-
-int pn_terminus_set_dynamic(pn_terminus_t *terminus, bool dynamic)
-{
-  if (!terminus) return PN_ARG_ERR;
-  terminus->dynamic = dynamic;
-  return 0;
-}
-
-pn_data_t *pn_terminus_properties(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->properties : NULL;
-}
-
-pn_data_t *pn_terminus_capabilities(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->capabilities : NULL;
-}
-
-pn_data_t *pn_terminus_outcomes(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->outcomes : NULL;
-}
-
-pn_data_t *pn_terminus_filter(pn_terminus_t *terminus)
-{
-  return terminus ? terminus->filter : NULL;
-}
-
-pn_distribution_mode_t pn_terminus_get_distribution_mode(const pn_terminus_t *terminus)
-{
-  return terminus ? terminus->distribution_mode : PN_DIST_MODE_UNSPECIFIED;
-}
-
-int pn_terminus_set_distribution_mode(pn_terminus_t *terminus, pn_distribution_mode_t m)
-{
-  if (!terminus) return PN_ARG_ERR;
-  terminus->distribution_mode = m;
-  return 0;
-}
-
-int pn_terminus_copy(pn_terminus_t *terminus, pn_terminus_t *src)
-{
-  if (!terminus || !src) {
-    return PN_ARG_ERR;
-  }
-
-  terminus->type = src->type;
-  int err = pn_terminus_set_address(terminus, pn_terminus_get_address(src));
-  if (err) return err;
-  terminus->durability = src->durability;
-  terminus->expiry_policy = src->expiry_policy;
-  terminus->timeout = src->timeout;
-  terminus->dynamic = src->dynamic;
-  terminus->distribution_mode = src->distribution_mode;
-  err = pn_data_copy(terminus->properties, src->properties);
-  if (err) return err;
-  err = pn_data_copy(terminus->capabilities, src->capabilities);
-  if (err) return err;
-  err = pn_data_copy(terminus->outcomes, src->outcomes);
-  if (err) return err;
-  err = pn_data_copy(terminus->filter, src->filter);
-  if (err) return err;
-  return 0;
-}
-
-pn_link_t *pn_sender(pn_session_t *session, const char *name)
-{
-  return pn_link_new(SENDER, session, name);
-}
-
-pn_link_t *pn_receiver(pn_session_t *session, const char *name)
-{
-  return pn_link_new(RECEIVER, session, name);
-}
-
-pn_state_t pn_link_state(pn_link_t *link)
-{
-  return link->endpoint.state;
-}
-
-pn_error_t *pn_link_error(pn_link_t *link)
-{
-  return link->endpoint.error;
-}
-
-const char *pn_link_name(pn_link_t *link)
-{
-  assert(link);
-  return pn_string_get(link->name);
-}
-
-bool pn_link_is_sender(pn_link_t *link)
-{
-  return link->endpoint.type == SENDER;
-}
-
-bool pn_link_is_receiver(pn_link_t *link)
-{
-  return link->endpoint.type == RECEIVER;
-}
-
-pn_session_t *pn_link_session(pn_link_t *link)
-{
-  assert(link);
-  return link->session;
-}
-
-static void pn_disposition_finalize(pn_disposition_t *ds)
-{
-  pn_free(ds->data);
-  pn_free(ds->annotations);
-  pn_condition_tini(&ds->condition);
-}
-
-static void pn_delivery_incref(void *object)
-{
-  pn_delivery_t *delivery = (pn_delivery_t *) object;
-  if (delivery->link && !delivery->referenced) {
-    delivery->referenced = true;
-    pn_incref(delivery->link);
-  } else {
-    pn_object_incref(object);
-  }
-}
-
-static bool pni_preserve_delivery(pn_delivery_t *delivery)
-{
-  pn_connection_t *conn = delivery->link->session->connection;
-  return !delivery->local.settled || (conn->transport && (delivery->state.init || delivery->tpwork));
-}
-
-static void pn_delivery_finalize(void *object)
-{
-  pn_delivery_t *delivery = (pn_delivery_t *) object;
-  pn_link_t *link = delivery->link;
-  //  assert(!delivery->state.init);
-
-  bool pooled = false;
-  bool referenced = true;
-  if (link) {
-    if (pni_link_live(link) && pni_preserve_delivery(delivery) && delivery->referenced) {
-      delivery->referenced = false;
-      pn_object_incref(delivery);
-      pn_decref(link);
-      return;
-    }
-    referenced = delivery->referenced;
-
-    pn_clear_tpwork(delivery);
-    LL_REMOVE(link, unsettled, delivery);
-    pn_delivery_map_del(pn_link_is_sender(link)
-                        ? &link->session->state.outgoing
-                        : &link->session->state.incoming,
-                        delivery);
-    pn_buffer_clear(delivery->tag);
-    pn_buffer_clear(delivery->bytes);
-    pn_record_clear(delivery->context);
-    delivery->settled = true;
-    pn_connection_t *conn = link->session->connection;
-    assert(pn_refcount(delivery) == 0);
-    if (pni_connection_live(conn)) {
-      pn_list_t *pool = link->session->connection->delivery_pool;
-      delivery->link = NULL;
-      pn_list_add(pool, delivery);
-      pooled = true;
-      assert(pn_refcount(delivery) == 1);
-    }
-  }
-
-  if (!pooled) {
-    pn_free(delivery->context);
-    pn_buffer_free(delivery->tag);
-    pn_buffer_free(delivery->bytes);
-    pn_disposition_finalize(&delivery->local);
-    pn_disposition_finalize(&delivery->remote);
-  }
-
-  if (referenced) {
-    pn_decref(link);
-  }
-}
-
-static void pn_disposition_init(pn_disposition_t *ds)
-{
-  ds->data = pn_data(0);
-  ds->annotations = pn_data(0);
-  pn_condition_init(&ds->condition);
-}
-
-static void pn_disposition_clear(pn_disposition_t *ds)
-{
-  ds->type = 0;
-  ds->section_number = 0;
-  ds->section_offset = 0;
-  ds->failed = false;
-  ds->undeliverable = false;
-  ds->settled = false;
-  pn_data_clear(ds->data);
-  pn_data_clear(ds->annotations);
-  pn_condition_clear(&ds->condition);
-}
-
-#define pn_delivery_new pn_object_new
-#define pn_delivery_refcount pn_object_refcount
-#define pn_delivery_decref pn_object_decref
-#define pn_delivery_free pn_object_free
-#define pn_delivery_reify pn_object_reify
-#define pn_delivery_initialize NULL
-#define pn_delivery_hashcode NULL
-#define pn_delivery_compare NULL
-#define pn_delivery_inspect NULL
-
-pn_delivery_tag_t pn_dtag(const char *bytes, size_t size) {
-  pn_delivery_tag_t dtag = {size, bytes};
-  return dtag;
-}
-
-pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
-{
-  assert(link);
-  pn_list_t *pool = link->session->connection->delivery_pool;
-  pn_delivery_t *delivery = (pn_delivery_t *) pn_list_pop(pool);
-  if (!delivery) {
-    static const pn_class_t clazz = PN_METACLASS(pn_delivery);
-    delivery = (pn_delivery_t *) pn_class_new(&clazz, sizeof(pn_delivery_t));
-    if (!delivery) return NULL;
-    delivery->tag = pn_buffer(16);
-    delivery->bytes = pn_buffer(64);
-    pn_disposition_init(&delivery->local);
-    pn_disposition_init(&delivery->remote);
-    delivery->context = pn_record();
-  } else {
-    assert(!delivery->state.init);
-  }
-  delivery->link = link;
-  pn_incref(delivery->link);  // keep link until finalized
-  pn_buffer_clear(delivery->tag);
-  pn_buffer_append(delivery->tag, tag.start, tag.size);
-  pn_disposition_clear(&delivery->local);
-  pn_disposition_clear(&delivery->remote);
-  delivery->updated = false;
-  delivery->settled = false;
-  LL_ADD(link, unsettled, delivery);
-  delivery->referenced = true;
-  delivery->work_next = NULL;
-  delivery->work_prev = NULL;
-  delivery->work = false;
-  delivery->tpwork_next = NULL;
-  delivery->tpwork_prev = NULL;
-  delivery->tpwork = false;
-  pn_buffer_clear(delivery->bytes);
-  delivery->done = false;
-  pn_record_clear(delivery->context);
-
-  // begin delivery state
-  delivery->state.init = false;
-  delivery->state.sent = false;
-  // end delivery state
-
-  if (!link->current)
-    link->current = delivery;
-
-  link->unsettled_count++;
-
-  pn_work_update(link->session->connection, delivery);
-
-  // XXX: could just remove incref above
-  pn_decref(delivery);
-
-  return delivery;
-}
-
-bool pn_delivery_buffered(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  if (delivery->settled) return false;
-  if (pn_link_is_sender(delivery->link)) {
-    pn_delivery_state_t *state = &delivery->state;
-    if (state->sent) {
-      return false;
-    } else {
-      return delivery->done || (pn_buffer_size(delivery->bytes) > 0);
-    }
-  } else {
-    return false;
-  }
-}
-
-int pn_link_unsettled(pn_link_t *link)
-{
-  return link->unsettled_count;
-}
-
-pn_delivery_t *pn_unsettled_head(pn_link_t *link)
-{
-  pn_delivery_t *d = link->unsettled_head;
-  while (d && d->local.settled) {
-    d = d->unsettled_next;
-  }
-  return d;
-}
-
-pn_delivery_t *pn_unsettled_next(pn_delivery_t *delivery)
-{
-  pn_delivery_t *d = delivery->unsettled_next;
-  while (d && d->local.settled) {
-    d = d->unsettled_next;
-  }
-  return d;
-}
-
-bool pn_delivery_current(pn_delivery_t *delivery)
-{
-  pn_link_t *link = delivery->link;
-  return pn_link_current(link) == delivery;
-}
-
-void pn_delivery_dump(pn_delivery_t *d)
-{
-  char tag[1024];
-  pn_bytes_t bytes = pn_buffer_bytes(d->tag);
-  pn_quote_data(tag, 1024, bytes.start, bytes.size);
-  printf("{tag=%s, local.type=%" PRIu64 ", remote.type=%" PRIu64 ", local.settled=%u, "
-         "remote.settled=%u, updated=%u, current=%u, writable=%u, readable=%u, "
-         "work=%u}",
-         tag, d->local.type, d->remote.type, d->local.settled,
-         d->remote.settled, d->updated, pn_delivery_current(d),
-         pn_delivery_writable(d), pn_delivery_readable(d), d->work);
-}
-
-void *pn_delivery_get_context(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return pn_record_get(delivery->context, PN_LEGCTX);
-}
-
-void pn_delivery_set_context(pn_delivery_t *delivery, void *context)
-{
-  assert(delivery);
-  pn_record_set(delivery->context, PN_LEGCTX, context);
-}
-
-pn_record_t *pn_delivery_attachments(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return delivery->context;
-}
-
-uint64_t pn_disposition_type(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->type;
-}
-
-pn_data_t *pn_disposition_data(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->data;
-}
-
-uint32_t pn_disposition_get_section_number(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->section_number;
-}
-
-void pn_disposition_set_section_number(pn_disposition_t *disposition, uint32_t section_number)
-{
-  assert(disposition);
-  disposition->section_number = section_number;
-}
-
-uint64_t pn_disposition_get_section_offset(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->section_offset;
-}
-
-void pn_disposition_set_section_offset(pn_disposition_t *disposition, uint64_t section_offset)
-{
-  assert(disposition);
-  disposition->section_offset = section_offset;
-}
-
-bool pn_disposition_is_failed(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->failed;
-}
-
-void pn_disposition_set_failed(pn_disposition_t *disposition, bool failed)
-{
-  assert(disposition);
-  disposition->failed = failed;
-}
-
-bool pn_disposition_is_undeliverable(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->undeliverable;
-}
-
-void pn_disposition_set_undeliverable(pn_disposition_t *disposition, bool undeliverable)
-{
-  assert(disposition);
-  disposition->undeliverable = undeliverable;
-}
-
-pn_data_t *pn_disposition_annotations(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return disposition->annotations;
-}
-
-pn_condition_t *pn_disposition_condition(pn_disposition_t *disposition)
-{
-  assert(disposition);
-  return &disposition->condition;
-}
-
-pn_delivery_tag_t pn_delivery_tag(pn_delivery_t *delivery)
-{
-  if (delivery) {
-    pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
-    return pn_dtag(tag.start, tag.size);
-  } else {
-    return pn_dtag(0, 0);
-  }
-}
-
-pn_delivery_t *pn_link_current(pn_link_t *link)
-{
-  if (!link) return NULL;
-  return link->current;
-}
-
-static void pni_advance_sender(pn_link_t *link)
-{
-  link->current->done = true;
-  link->queued++;
-  link->credit--;
-  link->session->outgoing_deliveries++;
-  pni_add_tpwork(link->current);
-  link->current = link->current->unsettled_next;
-}
-
-static void pni_advance_receiver(pn_link_t *link)
-{
-  link->credit--;
-  link->queued--;
-  link->session->incoming_deliveries--;
-
-  pn_delivery_t *current = link->current;
-  link->session->incoming_bytes -= pn_buffer_size(current->bytes);
-  pn_buffer_clear(current->bytes);
-
-  if (!link->session->state.incoming_window) {
-    pni_add_tpwork(current);
-  }
-
-  link->current = link->current->unsettled_next;
-}
-
-bool pn_link_advance(pn_link_t *link)
-{
-  if (link && link->current) {
-    pn_delivery_t *prev = link->current;
-    if (link->endpoint.type == SENDER) {
-      pni_advance_sender(link);
-    } else {
-      pni_advance_receiver(link);
-    }
-    pn_delivery_t *next = link->current;
-    pn_work_update(link->session->connection, prev);
-    if (next) pn_work_update(link->session->connection, next);
-    return prev != next;
-  } else {
-    return false;
-  }
-}
-
-int pn_link_credit(pn_link_t *link)
-{
-  return link ? link->credit : 0;
-}
-
-int pn_link_available(pn_link_t *link)
-{
-  return link ? link->available : 0;
-}
-
-int pn_link_queued(pn_link_t *link)
-{
-  return link ? link->queued : 0;
-}
-
-int pn_link_remote_credit(pn_link_t *link)
-{
-  assert(link);
-  return link->credit - link->queued;
-}
-
-bool pn_link_get_drain(pn_link_t *link)
-{
-  assert(link);
-  return link->drain;
-}
-
-pn_snd_settle_mode_t pn_link_snd_settle_mode(pn_link_t *link)
-{
-  return link ? (pn_snd_settle_mode_t)link->snd_settle_mode
-      : PN_SND_MIXED;
-}
-
-pn_rcv_settle_mode_t pn_link_rcv_settle_mode(pn_link_t *link)
-{
-  return link ? (pn_rcv_settle_mode_t)link->rcv_settle_mode
-      : PN_RCV_FIRST;
-}
-
-pn_snd_settle_mode_t pn_link_remote_snd_settle_mode(pn_link_t *link)
-{
-  return link ? (pn_snd_settle_mode_t)link->remote_snd_settle_mode
-      : PN_SND_MIXED;
-}
-
-pn_rcv_settle_mode_t pn_link_remote_rcv_settle_mode(pn_link_t *link)
-{
-  return link ? (pn_rcv_settle_mode_t)link->remote_rcv_settle_mode
-      : PN_RCV_FIRST;
-}
-void pn_link_set_snd_settle_mode(pn_link_t *link, pn_snd_settle_mode_t mode)
-{
-  if (link)
-    link->snd_settle_mode = (uint8_t)mode;
-}
-void pn_link_set_rcv_settle_mode(pn_link_t *link, pn_rcv_settle_mode_t mode)
-{
-  if (link)
-    link->rcv_settle_mode = (uint8_t)mode;
-}
-
-void pn_delivery_settle(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  if (!delivery->local.settled) {
-    pn_link_t *link = delivery->link;
-    if (pn_delivery_current(delivery)) {
-      pn_link_advance(link);
-    }
-
-    link->unsettled_count--;
-    delivery->local.settled = true;
-    pni_add_tpwork(delivery);
-    pn_work_update(delivery->link->session->connection, delivery);
-    pn_incref(delivery);
-    pn_decref(delivery);
-  }
-}
-
-void pn_link_offered(pn_link_t *sender, int credit)
-{
-  sender->available = credit;
-}
-
-ssize_t pn_link_send(pn_link_t *sender, const char *bytes, size_t n)
-{
-  pn_delivery_t *current = pn_link_current(sender);
-  if (!current) return PN_EOS;
-  if (!bytes || !n) return 0;
-  pn_buffer_append(current->bytes, bytes, n);
-  sender->session->outgoing_bytes += n;
-  pni_add_tpwork(current);
-  return n;
-}
-
-int pn_link_drained(pn_link_t *link)
-{
-  assert(link);
-  int drained = 0;
-
-  if (pn_link_is_sender(link)) {
-    if (link->drain && link->credit > 0) {
-      link->drained = link->credit;
-      link->credit = 0;
-      pn_modified(link->session->connection, &link->endpoint, true);
-      drained = link->drained;
-    }
-  } else {
-    drained = link->drained;
-    link->drained = 0;
-  }
-
-  return drained;
-}
-
-ssize_t pn_link_recv(pn_link_t *receiver, char *bytes, size_t n)
-{
-  if (!receiver) return PN_ARG_ERR;
-
-  pn_delivery_t *delivery = receiver->current;
-  if (delivery) {
-    size_t size = pn_buffer_get(delivery->bytes, 0, n, bytes);
-    pn_buffer_trim(delivery->bytes, size, 0);
-    if (size) {
-      receiver->session->incoming_bytes -= size;
-      if (!receiver->session->state.incoming_window) {
-        pni_add_tpwork(delivery);
-      }
-      return size;
-    } else {
-      return delivery->done ? PN_EOS : 0;
-    }
-  } else {
-    return PN_STATE_ERR;
-  }
-}
-
-void pn_link_flow(pn_link_t *receiver, int credit)
-{
-  assert(receiver);
-  assert(pn_link_is_receiver(receiver));
-  receiver->credit += credit;
-  pn_modified(receiver->session->connection, &receiver->endpoint, true);
-  if (!receiver->drain_flag_mode) {
-    pn_link_set_drain(receiver, false);
-    receiver->drain_flag_mode = false;
-  }
-}
-
-void pn_link_drain(pn_link_t *receiver, int credit)
-{
-  assert(receiver);
-  assert(pn_link_is_receiver(receiver));
-  pn_link_set_drain(receiver, true);
-  pn_link_flow(receiver, credit);
-  receiver->drain_flag_mode = false;
-}
-
-void pn_link_set_drain(pn_link_t *receiver, bool drain)
-{
-  assert(receiver);
-  assert(pn_link_is_receiver(receiver));
-  receiver->drain = drain;
-  pn_modified(receiver->session->connection, &receiver->endpoint, true);
-  receiver->drain_flag_mode = true;
-}
-
-bool pn_link_draining(pn_link_t *receiver)
-{
-  assert(receiver);
-  assert(pn_link_is_receiver(receiver));
-  return receiver->drain && (pn_link_credit(receiver) > pn_link_queued(receiver));
-}
-
-pn_link_t *pn_delivery_link(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return delivery->link;
-}
-
-pn_disposition_t *pn_delivery_local(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return &delivery->local;
-}
-
-uint64_t pn_delivery_local_state(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return delivery->local.type;
-}
-
-pn_disposition_t *pn_delivery_remote(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return &delivery->remote;
-}
-
-uint64_t pn_delivery_remote_state(pn_delivery_t *delivery)
-{
-  assert(delivery);
-  return delivery->remote.type;
-}
-
-bool pn_delivery_settled(pn_delivery_t *delivery)
-{
-  return delivery ? delivery->remote.settled : false;
-}
-
-bool pn_delivery_updated(pn_delivery_t *delivery)
-{
-  return delivery ? delivery->updated : false;
-}
-
-void pn_delivery_clear(pn_delivery_t *delivery)
-{
-  delivery->updated = false;
-  pn_work_update(delivery->link->session->connection, delivery);
-}
-
-void pn_delivery_update(pn_delivery_t *delivery, uint64_t state)
-{
-  if (!delivery) return;
-  delivery->local.type = state;
-  pni_add_tpwork(delivery);
-}
-
-bool pn_delivery_writable(pn_delivery_t *delivery)
-{
-  if (!delivery) return false;
-
-  pn_link_t *link = delivery->link;
-  return pn_link_is_sender(link) && pn_delivery_current(delivery) && pn_link_credit(link) > 0;
-}
-
-bool pn_delivery_readable(pn_delivery_t *delivery)
-{
-  if (delivery) {
-    pn_link_t *link = delivery->link;
-    return pn_link_is_receiver(link) && pn_delivery_current(delivery);
-  } else {
-    return false;
-  }
-}
-
-size_t pn_delivery_pending(pn_delivery_t *delivery)
-{
-  return pn_buffer_size(delivery->bytes);
-}
-
-bool pn_delivery_partial(pn_delivery_t *delivery)
-{
-  return !delivery->done;
-}
-
-pn_condition_t *pn_connection_condition(pn_connection_t *connection)
-{
-  assert(connection);
-  return &connection->endpoint.condition;
-}
-
-pn_condition_t *pn_connection_remote_condition(pn_connection_t *connection)
-{
-  assert(connection);
-  pn_transport_t *transport = connection->transport;
-  return transport ? &transport->remote_condition : NULL;
-}
-
-pn_condition_t *pn_session_condition(pn_session_t *session)
-{
-  assert(session);
-  return &session->endpoint.condition;
-}
-
-pn_condition_t *pn_session_remote_condition(pn_session_t *session)
-{
-  assert(session);
-  return &session->endpoint.remote_condition;
-}
-
-pn_condition_t *pn_link_condition(pn_link_t *link)
-{
-  assert(link);
-  return &link->endpoint.condition;
-}
-
-pn_condition_t *pn_link_remote_condition(pn_link_t *link)
-{
-  assert(link);
-  return &link->endpoint.remote_condition;
-}
-
-bool pn_condition_is_set(pn_condition_t *condition)
-{
-  return condition && pn_string_get(condition->name);
-}
-
-void pn_condition_clear(pn_condition_t *condition)
-{
-  assert(condition);
-  pn_string_clear(condition->name);
-  pn_string_clear(condition->description);
-  pn_data_clear(condition->info);
-}
-
-const char *pn_condition_get_name(pn_condition_t *condition)
-{
-  assert(condition);
-  return pn_string_get(condition->name);
-}
-
-int pn_condition_set_name(pn_condition_t *condition, const char *name)
-{
-  assert(condition);
-  return pn_string_set(condition->name, name);
-}
-
-const char *pn_condition_get_description(pn_condition_t *condition)
-{
-  assert(condition);
-  return pn_string_get(condition->description);
-}
-
-int pn_condition_set_description(pn_condition_t *condition, const char *description)
-{
-  assert(condition);
-  return pn_string_set(condition->description, description);
-}
-
-int pn_condition_vformat(pn_condition_t *condition, const char *name, const char *fmt, va_list ap)
-{
-  assert(condition);
-  int err = pn_condition_set_name(condition, name);
-  if (err)
-      return err;
-
-  char text[1024];
-  size_t n = vsnprintf(text, 1024, fmt, ap);
-  if (n >= sizeof(text))
-      text[sizeof(text)-1] = '\0';
-  err = pn_condition_set_description(condition, text);
-  return err;
-}
-
-int pn_condition_format(pn_condition_t *condition, const char *name, const char *fmt, ...)
-{
-  assert(condition);
-  va_list ap;
-  va_start(ap, fmt);
-  int err = pn_condition_vformat(condition, name, fmt, ap);
-  va_end(ap);
-  return err;
-}
-
-pn_data_t *pn_condition_info(pn_condition_t *condition)
-{
-  assert(condition);
-  return condition->info;
-}
-
-bool pn_condition_is_redirect(pn_condition_t *condition)
-{
-  const char *name = pn_condition_get_name(condition);
-  return name && (!strcmp(name, "amqp:connection:redirect") ||
-                  !strcmp(name, "amqp:link:redirect"));
-}
-
-const char *pn_condition_redirect_host(pn_condition_t *condition)
-{
-  pn_data_t *data = pn_condition_info(condition);
-  pn_data_rewind(data);
-  pn_data_next(data);
-  pn_data_enter(data);
-  pn_data_lookup(data, "network-host");
-  pn_bytes_t host = pn_data_get_bytes(data);
-  pn_data_rewind(data);
-  return host.start;
-}
-
-int pn_condition_redirect_port(pn_condition_t *condition)
-{
-  pn_data_t *data = pn_condition_info(condition);
-  pn_data_rewind(data);
-  pn_data_next(data);
-  pn_data_enter(data);
-  pn_data_lookup(data, "port");
-  int port = pn_data_get_int(data);
-  pn_data_rewind(data);
-  return port;
-}
-
-pn_connection_t *pn_event_connection(pn_event_t *event)
-{
-  pn_session_t *ssn;
-  pn_transport_t *transport;
-
-  switch (pn_class_id(pn_event_class(event))) {
-  case CID_pn_connection:
-    return (pn_connection_t *) pn_event_context(event);
-  case CID_pn_transport:
-    transport = pn_event_transport(event);
-    if (transport)
-      return transport->connection;
-    return NULL;
-  default:
-    ssn = pn_event_session(event);
-    if (ssn)
-     return pn_session_connection(ssn);
-  }
-  return NULL;
-}
-
-pn_session_t *pn_event_session(pn_event_t *event)
-{
-  pn_link_t *link;
-  switch (pn_class_id(pn_event_class(event))) {
-  case CID_pn_session:
-    return (pn_session_t *) pn_event_context(event);
-  default:
-    link = pn_event_link(event);
-    if (link)
-      return pn_link_session(link);
-  }
-  return NULL;
-}
-
-pn_link_t *pn_event_link(pn_event_t *event)
-{
-  pn_delivery_t *dlv;
-  switch (pn_class_id(pn_event_class(event))) {
-  case CID_pn_link:
-    return (pn_link_t *) pn_event_context(event);
-  default:
-    dlv = pn_event_delivery(event);
-    if (dlv)
-      return pn_delivery_link(dlv);
-  }
-  return NULL;
-}
-
-pn_delivery_t *pn_event_delivery(pn_event_t *event)
-{
-  switch (pn_class_id(pn_event_class(event))) {
-  case CID_pn_delivery:
-    return (pn_delivery_t *) pn_event_context(event);
-  default:
-    return NULL;
-  }
-}
-
-pn_transport_t *pn_event_transport(pn_event_t *event)
-{
-  switch (pn_class_id(pn_event_class(event))) {
-  case CID_pn_transport:
-    return (pn_transport_t *) pn_event_context(event);
-  default:
-    {
-      pn_connection_t *conn = pn_event_connection(event);
-      if (conn)
-        return pn_connection_transport(conn);
-      return NULL;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/error.c
----------------------------------------------------------------------
diff --git a/proton-c/src/error.c b/proton-c/src/error.c
deleted file mode 100644
index 9bef0fc..0000000
--- a/proton-c/src/error.c
+++ /dev/null
@@ -1,135 +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/error.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include "util.h"
-#include "platform.h"
-
-struct pn_error_t {
-  char *text;
-  pn_error_t *root;
-  int code;
-};
-
-pn_error_t *pn_error()
-{
-  pn_error_t *error = (pn_error_t *) malloc(sizeof(pn_error_t));
-  if (error != NULL) {
-    error->code = 0;
-    error->text = NULL;
-    error->root = NULL;
-  }
-  return error;
-}
-
-void pn_error_free(pn_error_t *error)
-{
-  if (error) {
-    free(error->text);
-    free(error);
-  }
-}
-
-void pn_error_clear(pn_error_t *error)
-{
-  if (error) {
-    error->code = 0;
-    free(error->text);
-    error->text = NULL;
-    error->root = NULL;
-  }
-}
-
-int pn_error_set(pn_error_t *error, int code, const char *text)
-{
-  assert(error);
-  pn_error_clear(error);
-  if (code) {
-    error->code = code;
-    error->text = pn_strdup(text);
-  }
-  return code;
-}
-
-int pn_error_vformat(pn_error_t *error, int code, const char *fmt, va_list ap)
-{
-  assert(error);
-  char text[1024];
-  int n = vsnprintf(text, 1024, fmt, ap);
-  if (n >= 1024) {
-    text[1023] = '\0';
-  }
-  return pn_error_set(error, code, text);
-}
-
-int pn_error_format(pn_error_t *error, int code, const char *fmt, ...)
-{
-  assert(error);
-  va_list ap;
-  va_start(ap, fmt);
-  int rcode = pn_error_vformat(error, code, fmt, ap);
-  va_end(ap);
-  return rcode;
-}
-
-int pn_error_code(pn_error_t *error)
-{
-  assert(error);
-  return error->code;
-}
-
-const char *pn_error_text(pn_error_t *error)
-{
-  assert(error);
-  return error->text;
-}
-
-int pn_error_copy(pn_error_t *error, pn_error_t *src)
-{
-  assert(error);
-  if (src) {
-    return pn_error_set(error, pn_error_code(src), pn_error_text(src));
-  } else {
-    pn_error_clear(error);
-    return 0;
-  }
-}
-
-const char *pn_code(int code)
-{
-  switch (code)
-  {
-  case 0: return "<ok>";
-  case PN_EOS: return "PN_EOS";
-  case PN_ERR: return "PN_ERR";
-  case PN_OVERFLOW: return "PN_OVERFLOW";
-  case PN_UNDERFLOW: return "PN_UNDERFLOW";
-  case PN_STATE_ERR: return "PN_STATE_ERR";
-  case PN_ARG_ERR: return "PN_ARG_ERR";
-  case PN_TIMEOUT: return "PN_TIMEOUT";
-  case PN_INTR: return "PN_INTR";
-  case PN_OUT_OF_MEMORY: return "PN_OUT_OF_MEMORY";
-  default: return "<unknown>";
-  }
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/events/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/events/event.c b/proton-c/src/events/event.c
deleted file mode 100644
index 5ad718e..0000000
--- a/proton-c/src/events/event.c
+++ /dev/null
@@ -1,388 +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 <stdio.h>
-#include <proton/object.h>
-#include <proton/event.h>
-#include <proton/reactor.h>
-#include <assert.h>
-
-struct pn_collector_t {
-  pn_list_t *pool;
-  pn_event_t *head;
-  pn_event_t *tail;
-  bool freed;
-};
-
-struct pn_event_t {
-  pn_list_t *pool;
-  const pn_class_t *clazz;
-  void *context;    // depends on clazz
-  pn_record_t *attachments;
-  pn_event_t *next;
-  pn_event_type_t type;
-};
-
-static void pn_collector_initialize(pn_collector_t *collector)
-{
-  collector->pool = pn_list(PN_OBJECT, 0);
-  collector->head = NULL;
-  collector->tail = NULL;
-  collector->freed = false;
-}
-
-static void pn_collector_drain(pn_collector_t *collector)
-{
-  assert(collector);
-
-  while (pn_collector_peek(collector)) {
-    pn_collector_pop(collector);
-  }
-
-  assert(!collector->head);
-  assert(!collector->tail);
-}
-
-static void pn_collector_shrink(pn_collector_t *collector)
-{
-  assert(collector);
-  pn_list_clear(collector->pool);
-}
-
-static void pn_collector_finalize(pn_collector_t *collector)
-{
-  pn_collector_drain(collector);
-  pn_decref(collector->pool);
-}
-
-static int pn_collector_inspect(pn_collector_t *collector, pn_string_t *dst)
-{
-  assert(collector);
-  int err = pn_string_addf(dst, "EVENTS[");
-  if (err) return err;
-  pn_event_t *event = collector->head;
-  bool first = true;
-  while (event) {
-    if (first) {
-      first = false;
-    } else {
-      err = pn_string_addf(dst, ", ");
-      if (err) return err;
-    }
-    err = pn_inspect(event, dst);
-    if (err) return err;
-    event = event->next;
-  }
-  return pn_string_addf(dst, "]");
-}
-
-#define pn_collector_hashcode NULL
-#define pn_collector_compare NULL
-
-PN_CLASSDEF(pn_collector)
-
-pn_collector_t *pn_collector(void)
-{
-  return pn_collector_new();
-}
-
-void pn_collector_free(pn_collector_t *collector)
-{
-  assert(collector);
-  pn_collector_release(collector);
-  pn_decref(collector);
-}
-
-void pn_collector_release(pn_collector_t *collector)
-{
-  assert(collector);
-  if (!collector->freed) {
-    collector->freed = true;
-    pn_collector_drain(collector);
-    pn_collector_shrink(collector);
-  }
-}
-
-pn_event_t *pn_event(void);
-
-pn_event_t *pn_collector_put(pn_collector_t *collector,
-                             const pn_class_t *clazz, void *context,
-                             pn_event_type_t type)
-{
-  if (!collector) {
-    return NULL;
-  }
-
-  assert(context);
-
-  if (collector->freed) {
-    return NULL;
-  }
-
-  pn_event_t *tail = collector->tail;
-  if (tail && tail->type == type && tail->context == context) {
-    return NULL;
-  }
-
-  clazz = clazz->reify(context);
-
-  pn_event_t *event = (pn_event_t *) pn_list_pop(collector->pool);
-
-  if (!event) {
-    event = pn_event();
-  }
-
-  event->pool = collector->pool;
-  pn_incref(event->pool);
-
-  if (tail) {
-    tail->next = event;
-    collector->tail = event;
-  } else {
-    collector->tail = event;
-    collector->head = event;
-  }
-
-  event->clazz = clazz;
-  event->context = context;
-  event->type = type;
-  pn_class_incref(clazz, event->context);
-
-  return event;
-}
-
-pn_event_t *pn_collector_peek(pn_collector_t *collector)
-{
-  return collector->head;
-}
-
-bool pn_collector_pop(pn_collector_t *collector)
-{
-  pn_event_t *event = collector->head;
-  if (event) {
-    collector->head = event->next;
-  } else {
-    return false;
-  }
-
-  if (!collector->head) {
-    collector->tail = NULL;
-  }
-
-  pn_decref(event);
-  return true;
-}
-
-bool pn_collector_more(pn_collector_t *collector)
-{
-  assert(collector);
-  return collector->head && collector->head->next;
-}
-
-static void pn_event_initialize(pn_event_t *event)
-{
-  event->pool = NULL;
-  event->type = PN_EVENT_NONE;
-  event->clazz = NULL;
-  event->context = NULL;
-  event->next = NULL;
-  event->attachments = pn_record();
-}
-
-static void pn_event_finalize(pn_event_t *event) {
-  // decref before adding to the free list
-  if (event->clazz && event->context) {
-    pn_class_decref(event->clazz, event->context);
-  }
-
-  pn_list_t *pool = event->pool;
-
-  if (pool && pn_refcount(pool) > 1) {
-    event->pool = NULL;
-    event->type = PN_EVENT_NONE;
-    event->clazz = NULL;
-    event->context = NULL;
-    event->next = NULL;
-    pn_record_clear(event->attachments);
-    pn_list_add(pool, event);
-  } else {
-    pn_decref(event->attachments);
-  }
-
-  pn_decref(pool);
-}
-
-static int pn_event_inspect(pn_event_t *event, pn_string_t *dst)
-{
-  assert(event);
-  assert(dst);
-  const char *name = pn_event_type_name(event->type);
-  int err;
-  if (name) {
-    err = pn_string_addf(dst, "(%s", pn_event_type_name(event->type));
-  } else {
-    err = pn_string_addf(dst, "(<%u>", (unsigned int) event->type);
-  }
-  if (err) return err;
-  if (event->context) {
-    err = pn_string_addf(dst, ", ");
-    if (err) return err;
-    err = pn_class_inspect(event->clazz, event->context, dst);
-    if (err) return err;
-  }
-
-  return pn_string_addf(dst, ")");
-}
-
-#define pn_event_hashcode NULL
-#define pn_event_compare NULL
-
-PN_CLASSDEF(pn_event)
-
-pn_event_t *pn_event(void)
-{
-  return pn_event_new();
-}
-
-pn_event_type_t pn_event_type(pn_event_t *event)
-{
-  return event->type;
-}
-
-const pn_class_t *pn_event_class(pn_event_t *event)
-{
-  assert(event);
-  return event->clazz;
-}
-
-void *pn_event_context(pn_event_t *event)
-{
-  assert(event);
-  return event->context;
-}
-
-pn_record_t *pn_event_attachments(pn_event_t *event)
-{
-  assert(event);
-  return event->attachments;
-}
-
-pn_handler_t *pn_event_root(pn_event_t *event)
-{
-  assert(event);
-  pn_handler_t *h = pn_record_get_handler(event->attachments);
-  return h;
-}
-
-void pni_event_set_root(pn_event_t *event, pn_handler_t *handler) {
-  pn_record_set_handler(event->attachments, handler);
-}
-
-const char *pn_event_type_name(pn_event_type_t type)
-{
-  switch (type) {
-  case PN_EVENT_NONE:
-    return "PN_EVENT_NONE";
-  case PN_REACTOR_INIT:
-    return "PN_REACTOR_INIT";
-  case PN_REACTOR_QUIESCED:
-    return "PN_REACTOR_QUIESCED";
-  case PN_REACTOR_FINAL:
-    return "PN_REACTOR_FINAL";
-  case PN_TIMER_TASK:
-    return "PN_TIMER_TASK";
-  case PN_CONNECTION_INIT:
-    return "PN_CONNECTION_INIT";
-  case PN_CONNECTION_BOUND:
-    return "PN_CONNECTION_BOUND";
-  case PN_CONNECTION_UNBOUND:
-    return "PN_CONNECTION_UNBOUND";
-  case PN_CONNECTION_REMOTE_OPEN:
-    return "PN_CONNECTION_REMOTE_OPEN";
-  case PN_CONNECTION_LOCAL_OPEN:
-    return "PN_CONNECTION_LOCAL_OPEN";
-  case PN_CONNECTION_REMOTE_CLOSE:
-    return "PN_CONNECTION_REMOTE_CLOSE";
-  case PN_CONNECTION_LOCAL_CLOSE:
-    return "PN_CONNECTION_LOCAL_CLOSE";
-  case PN_CONNECTION_FINAL:
-    return "PN_CONNECTION_FINAL";
-  case PN_SESSION_INIT:
-    return "PN_SESSION_INIT";
-  case PN_SESSION_REMOTE_OPEN:
-    return "PN_SESSION_REMOTE_OPEN";
-  case PN_SESSION_LOCAL_OPEN:
-    return "PN_SESSION_LOCAL_OPEN";
-  case PN_SESSION_REMOTE_CLOSE:
-    return "PN_SESSION_REMOTE_CLOSE";
-  case PN_SESSION_LOCAL_CLOSE:
-    return "PN_SESSION_LOCAL_CLOSE";
-  case PN_SESSION_FINAL:
-    return "PN_SESSION_FINAL";
-  case PN_LINK_INIT:
-    return "PN_LINK_INIT";
-  case PN_LINK_REMOTE_OPEN:
-    return "PN_LINK_REMOTE_OPEN";
-  case PN_LINK_LOCAL_OPEN:
-    return "PN_LINK_LOCAL_OPEN";
-  case PN_LINK_REMOTE_CLOSE:
-    return "PN_LINK_REMOTE_CLOSE";
-  case PN_LINK_LOCAL_DETACH:
-    return "PN_LINK_LOCAL_DETACH";
-  case PN_LINK_REMOTE_DETACH:
-    return "PN_LINK_REMOTE_DETACH";
-  case PN_LINK_LOCAL_CLOSE:
-    return "PN_LINK_LOCAL_CLOSE";
-  case PN_LINK_FLOW:
-    return "PN_LINK_FLOW";
-  case PN_LINK_FINAL:
-    return "PN_LINK_FINAL";
-  case PN_DELIVERY:
-    return "PN_DELIVERY";
-  case PN_TRANSPORT:
-    return "PN_TRANSPORT";
-  case PN_TRANSPORT_AUTHENTICATED:
-    return "PN_TRANSPORT_AUTHENTICATED";
-  case PN_TRANSPORT_ERROR:
-    return "PN_TRANSPORT_ERROR";
-  case PN_TRANSPORT_HEAD_CLOSED:
-    return "PN_TRANSPORT_HEAD_CLOSED";
-  case PN_TRANSPORT_TAIL_CLOSED:
-    return "PN_TRANSPORT_TAIL_CLOSED";
-  case PN_TRANSPORT_CLOSED:
-    return "PN_TRANSPORT_CLOSED";
-  case PN_SELECTABLE_INIT:
-    return "PN_SELECTABLE_INIT";
-  case PN_SELECTABLE_UPDATED:
-    return "PN_SELECTABLE_UPDATED";
-  case PN_SELECTABLE_READABLE:
-    return "PN_SELECTABLE_READABLE";
-  case PN_SELECTABLE_WRITABLE:
-    return "PN_SELECTABLE_WRITABLE";
-  case PN_SELECTABLE_ERROR:
-    return "PN_SELECTABLE_ERROR";
-  case PN_SELECTABLE_EXPIRED:
-    return "PN_SELECTABLE_EXPIRED";
-  case PN_SELECTABLE_FINAL:
-    return "PN_SELECTABLE_FINAL";
-  }
-
-  return NULL;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/extra/parser.c
----------------------------------------------------------------------
diff --git a/proton-c/src/extra/parser.c b/proton-c/src/extra/parser.c
new file mode 100644
index 0000000..36fb4fb
--- /dev/null
+++ b/proton-c/src/extra/parser.c
@@ -0,0 +1,423 @@
+/*
+ *
+ * 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/parser.h>
+
+#include "platform/platform.h"
+#include "scanner.h"
+
+#include <proton/error.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+struct pn_parser_t {
+  pn_scanner_t *scanner;
+  char *atoms;
+  size_t size;
+  size_t capacity;
+  int error_code;
+};
+
+pn_parser_t *pn_parser()
+{
+  pn_parser_t *parser = (pn_parser_t *) malloc(sizeof(pn_parser_t));
+  if (parser != NULL) {
+    parser->scanner = pn_scanner();
+    parser->atoms = NULL;
+    parser->size = 0;
+    parser->capacity = 0;
+  }
+  return parser;
+}
+
+static void pni_parser_ensure(pn_parser_t *parser, size_t size)
+{
+  while (parser->capacity - parser->size < size) {
+    parser->capacity = parser->capacity ? 2 * parser->capacity : 1024;
+    parser->atoms = (char *) realloc(parser->atoms, parser->capacity);
+  }
+}
+
+int pn_parser_err(pn_parser_t *parser, int code, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  int err = pn_scanner_verr(parser->scanner, code, fmt, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_parser_errno(pn_parser_t *parser)
+{
+  return pn_scanner_errno(parser->scanner);
+}
+
+const char *pn_parser_error(pn_parser_t *parser)
+{
+  return pn_scanner_error(parser->scanner);
+}
+
+void pn_parser_free(pn_parser_t *parser)
+{
+  if (parser) {
+    pn_scanner_free(parser->scanner);
+    free(parser->atoms);
+    free(parser);
+  }
+}
+
+static int pni_parser_shift(pn_parser_t *parser)
+{
+  return pn_scanner_shift(parser->scanner);
+}
+
+static pn_token_t pni_parser_token(pn_parser_t *parser)
+{
+  return pn_scanner_token(parser->scanner);
+}
+
+static int pni_parser_value(pn_parser_t *parser, pn_data_t *data);
+
+static int pni_parser_descriptor(pn_parser_t *parser, pn_data_t *data)
+{
+  if (pni_parser_token(parser).type == PN_TOK_AT) {
+    int err = pni_parser_shift(parser);
+    if (err) return err;
+
+    err = pn_data_put_described(data);
+    if (err) return pn_parser_err(parser, err, "error writing described");
+    pn_data_enter(data);
+    for (int i = 0; i < 2; i++) {
+      err = pni_parser_value(parser, data);
+      if (err) return err;
+    }
+    pn_data_exit(data);
+    return 0;
+  } else {
+    return pn_parser_err(parser, PN_ERR, "expecting '@'");
+  }
+}
+
+static int pni_parser_map(pn_parser_t *parser, pn_data_t *data)
+{
+  if (pni_parser_token(parser).type == PN_TOK_LBRACE) {
+    int err = pni_parser_shift(parser);
+    if (err) return err;
+
+    err = pn_data_put_map(data);
+    if (err) return pn_parser_err(parser, err, "error writing map");
+
+    pn_data_enter(data);
+
+    if (pni_parser_token(parser).type != PN_TOK_RBRACE) {
+      while (true) {
+        err = pni_parser_value(parser, data);
+        if (err) return err;
+
+        if (pni_parser_token(parser).type == PN_TOK_EQUAL) {
+          err = pni_parser_shift(parser);
+          if (err) return err;
+        } else {
+          return pn_parser_err(parser, PN_ERR, "expecting '='");
+        }
+
+        err = pni_parser_value(parser, data);
+        if (err) return err;
+
+        if (pni_parser_token(parser).type == PN_TOK_COMMA) {
+          err = pni_parser_shift(parser);
+          if (err) return err;
+        } else {
+          break;
+        }
+      }
+    }
+
+    pn_data_exit(data);
+
+    if (pni_parser_token(parser).type == PN_TOK_RBRACE) {
+      return pni_parser_shift(parser);
+    } else {
+      return pn_parser_err(parser, PN_ERR, "expecting '}'");
+    }
+  } else {
+    return pn_parser_err(parser, PN_ERR, "expecting '{'");
+  }
+}
+
+static int pni_parser_list(pn_parser_t *parser, pn_data_t *data)
+{
+  int err;
+
+  if (pni_parser_token(parser).type == PN_TOK_LBRACKET) {
+    err = pni_parser_shift(parser);
+    if (err) return err;
+
+    err = pn_data_put_list(data);
+    if (err) return pn_parser_err(parser, err, "error writing list");
+
+    pn_data_enter(data);
+
+    if (pni_parser_token(parser).type != PN_TOK_RBRACKET) {
+      while (true) {
+        err = pni_parser_value(parser, data);
+        if (err) return err;
+
+        if (pni_parser_token(parser).type == PN_TOK_COMMA) {
+          err = pni_parser_shift(parser);
+          if (err) return err;
+        } else {
+          break;
+        }
+      }
+    }
+
+    pn_data_exit(data);
+
+    if (pni_parser_token(parser).type == PN_TOK_RBRACKET) {
+      return pni_parser_shift(parser);
+    } else {
+      return pn_parser_err(parser, PN_ERR, "expecting ']'");
+    }
+  } else {
+    return pn_parser_err(parser, PN_ERR, "expecting '['");
+  }
+}
+
+static void pni_parser_append_tok(pn_parser_t *parser, char *dst, int *idx)
+{
+  memcpy(dst + *idx, pni_parser_token(parser).start, pni_parser_token(parser).size);
+  *idx += pni_parser_token(parser).size;
+}
+
+static int pni_parser_number(pn_parser_t *parser, pn_data_t *data)
+{
+  bool dbl = false;
+  char number[1024];
+  int idx = 0;
+  int err;
+
+  bool negate = false;
+
+  if (pni_parser_token(parser).type == PN_TOK_NEG || pni_parser_token(parser).type == PN_TOK_POS) {
+    if (pni_parser_token(parser).type == PN_TOK_NEG)
+      negate = !negate;
+    err = pni_parser_shift(parser);
+    if (err) return err;
+  }
+
+  if (pni_parser_token(parser).type == PN_TOK_FLOAT || pni_parser_token(parser).type == PN_TOK_INT) {
+    dbl = pni_parser_token(parser).type == PN_TOK_FLOAT;
+    pni_parser_append_tok(parser, number, &idx);
+    err = pni_parser_shift(parser);
+    if (err) return err;
+  } else {
+    return pn_parser_err(parser, PN_ERR, "expecting FLOAT or INT");
+  }
+
+  number[idx] = '\0';
+
+  if (dbl) {
+    double value = atof(number);
+    if (negate) {
+      value = -value;
+    }
+    err = pn_data_put_double(data, value);
+    if (err) return pn_parser_err(parser, err, "error writing double");
+  } else {
+    int64_t value = pn_i_atoll(number);
+    if (negate) {
+      value = -value;
+    }
+    err = pn_data_put_long(data, value);
+    if (err) return pn_parser_err(parser, err, "error writing long");
+  }
+
+  return 0;
+}
+
+static int pni_parser_unquote(pn_parser_t *parser, char *dst, const char *src, size_t *n)
+{
+  size_t idx = 0;
+  bool escape = false;
+  int start, end;
+  if (src[0] != '"') {
+    if (src[1] == '"') {
+      start = 2;
+      end = *n - 1;
+    } else {
+      start = 1;
+      end = *n;
+    }
+  } else {
+    start = 1;
+    end = *n - 1;
+  }
+  for (int i = start; i < end; i++)
+  {
+    char c = src[i];
+    if (escape) {
+      switch (c) {
+      case '"':
+      case '\\':
+      case '/':
+        dst[idx++] = c;
+        escape = false;
+        break;
+      case 'b':
+        dst[idx++] = '\b';
+        break;
+      case 'f':
+        dst[idx++] = '\f';
+        break;
+      case 'n':
+        dst[idx++] = '\n';
+        break;
+      case 'r':
+        dst[idx++] = '\r';
+        break;
+      case 't':
+        dst[idx++] = '\t';
+        break;
+      case 'x':
+        {
+          char n1 = toupper(src[i+1]);
+          char n2 = n1 ? toupper(src[i+2]) : 0;
+          if (!n2) {
+            return pn_parser_err(parser, PN_ERR, "truncated escape code");
+          }
+          int d1 = isdigit(n1) ? n1 - '0' : n1 - 'A' + 10;
+          int d2 = isdigit(n2) ? n2 - '0' : n2 - 'A' + 10;
+          dst[idx++] = d1*16 + d2;
+          i += 2;
+        }
+        break;
+      // XXX: need to handle unicode escapes: 'u'
+      default:
+        return pn_parser_err(parser, PN_ERR, "unrecognized escape code");
+      }
+      escape = false;
+    } else {
+      switch (c)
+      {
+      case '\\':
+        escape = true;
+        break;
+      default:
+        dst[idx++] = c;
+        break;
+      }
+    }
+  }
+  dst[idx++] = '\0';
+  *n = idx;
+  return 0;
+}
+
+static int pni_parser_value(pn_parser_t *parser, pn_data_t *data)
+{
+  int err;
+  size_t n;
+  char *dst;
+
+  pn_token_t tok = pni_parser_token(parser);
+
+  switch (tok.type)
+  {
+  case PN_TOK_AT:
+    return pni_parser_descriptor(parser, data);
+  case PN_TOK_LBRACE:
+    return pni_parser_map(parser, data);
+  case PN_TOK_LBRACKET:
+    return pni_parser_list(parser, data);
+  case PN_TOK_BINARY:
+  case PN_TOK_SYMBOL:
+  case PN_TOK_STRING:
+    n = tok.size;
+    pni_parser_ensure(parser, n);
+    dst = parser->atoms + parser->size;
+    err = pni_parser_unquote(parser, dst, tok.start, &n);
+    if (err) return err;
+    parser->size += n;
+    switch (tok.type) {
+    case PN_TOK_BINARY:
+      err = pn_data_put_binary(data, pn_bytes(n - 1, dst));
+      break;
+    case PN_TOK_STRING:
+      err = pn_data_put_string(data, pn_bytes(n - 1, dst));
+      break;
+    case PN_TOK_SYMBOL:
+      err = pn_data_put_symbol(data, pn_bytes(n - 1, dst));
+      break;
+    default:
+      return pn_parser_err(parser, PN_ERR, "internal error");
+    }
+    if (err) return pn_parser_err(parser, err, "error writing string/binary/symbol");
+    return pni_parser_shift(parser);
+  case PN_TOK_POS:
+  case PN_TOK_NEG:
+  case PN_TOK_FLOAT:
+  case PN_TOK_INT:
+    return pni_parser_number(parser, data);
+  case PN_TOK_TRUE:
+    err = pn_data_put_bool(data, true);
+    if (err) return pn_parser_err(parser, err, "error writing boolean");
+    return pni_parser_shift(parser);
+  case PN_TOK_FALSE:
+    err = pn_data_put_bool(data, false);
+    if (err) return pn_parser_err(parser, err, "error writing boolean");
+    return pni_parser_shift(parser);
+  case PN_TOK_NULL:
+    err = pn_data_put_null(data);
+    if (err) return pn_parser_err(parser, err, "error writing null");
+    return pni_parser_shift(parser);
+  default:
+    return pn_parser_err(parser, PN_ERR, "expecting one of '[', '{', STRING, "
+                         "SYMBOL, BINARY, true, false, null, NUMBER");
+  }
+}
+
+static int pni_parser_parse_r(pn_parser_t *parser, pn_data_t *data)
+{
+  while (true) {
+    int err;
+    switch (pni_parser_token(parser).type)
+    {
+    case PN_TOK_EOS:
+      return 0;
+    case PN_TOK_ERR:
+      return PN_ERR;
+    default:
+      err = pni_parser_value(parser, data);
+      if (err) return err;
+    }
+  }
+}
+
+int pn_parser_parse(pn_parser_t *parser, const char *str, pn_data_t *data)
+{
+  int err = pn_scanner_start(parser->scanner, str);
+  if (err) return err;
+  parser->size = 0;
+  return pni_parser_parse_r(parser, data);
+}


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


[19/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
PROTON-1350 PROTON-1351: Introduce proton-c core library
- Created new core proton library qpid-proton-core which only contains
  protocol processsing and no IO.
- Rearranged source tree to separate core protocol code and io/reactor/extra code
- Rearranged code so that compiler dependent code is isolated and platform (OS)
  dependent code is isolated

This is a large change, but the majority is moving files around and fixing up the header
includes. There is a small amount of internal API changing so support the core searation.


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

Branch: refs/heads/master
Commit: a58507161cb839d14ecd3c36477747de59725554
Parents: efd033c
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Nov 14 12:55:01 2016 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 14 12:55:01 2016 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt                         |  162 +-
 proton-c/bindings/python/proton/reactor.py      |    4 +-
 proton-c/bindings/python/setup.py               |   10 +-
 proton-c/bindings/ruby/lib/reactor/reactor.rb   |    6 +-
 proton-c/include/proton/cproton.i               |    2 -
 proton-c/include/proton/event.h                 |    5 -
 proton-c/include/proton/handlers.h              |    6 +-
 proton-c/include/proton/import_export.h         |   10 +-
 proton-c/include/proton/io.h                    |  114 -
 proton-c/include/proton/messenger.h             |  124 +-
 proton-c/include/proton/reactor.h               |  112 +-
 proton-c/include/proton/scanner.h               |   82 -
 proton-c/include/proton/selectable.h            |   89 +-
 proton-c/include/proton/selector.h              |   51 -
 proton-c/include/proton/types.h                 |    4 -
 proton-c/include/proton/url.h                   |   34 +-
 proton-c/src/ProtonConfig.cmake.in              |    3 +
 proton-c/src/buffer.c                           |  310 --
 proton-c/src/buffer.h                           |   54 -
 proton-c/src/codec/codec.c                      | 2142 -------------
 proton-c/src/codec/data.h                       |   75 -
 proton-c/src/codec/decoder.c                    |  497 ---
 proton-c/src/codec/decoder.h                    |   30 -
 proton-c/src/codec/encoder.c                    |  383 ---
 proton-c/src/codec/encoder.h                    |   31 -
 proton-c/src/codec/encodings.h.py               |   42 -
 proton-c/src/codec/types.xml                    |  125 -
 proton-c/src/compiler/msvc/snprintf.c           |   52 +
 proton-c/src/config.h                           |   32 -
 proton-c/src/core/autodetect.c                  |  135 +
 proton-c/src/core/autodetect.h                  |   40 +
 proton-c/src/core/buffer.c                      |  310 ++
 proton-c/src/core/buffer.h                      |   54 +
 proton-c/src/core/codec.c                       | 2141 +++++++++++++
 proton-c/src/core/config.h                      |   32 +
 proton-c/src/core/connection_engine.c           |  124 +
 proton-c/src/core/data.h                        |   75 +
 proton-c/src/core/decoder.c                     |  497 +++
 proton-c/src/core/decoder.h                     |   30 +
 proton-c/src/core/dispatch_actions.h            |   49 +
 proton-c/src/core/dispatcher.c                  |  158 +
 proton-c/src/core/dispatcher.h                  |   37 +
 proton-c/src/core/encoder.c                     |  383 +++
 proton-c/src/core/encoder.h                     |   31 +
 proton-c/src/core/engine-internal.h             |  375 +++
 proton-c/src/core/engine.c                      | 2231 +++++++++++++
 proton-c/src/core/error.c                       |  136 +
 proton-c/src/core/event.c                       |  377 +++
 proton-c/src/core/framing.c                     |  103 +
 proton-c/src/core/framing.h                     |   44 +
 proton-c/src/core/log.c                         |   71 +
 proton-c/src/core/log_private.h                 |   54 +
 proton-c/src/core/message.c                     |  862 +++++
 proton-c/src/core/object/iterator.c             |   78 +
 proton-c/src/core/object/list.c                 |  267 ++
 proton-c/src/core/object/map.c                  |  461 +++
 proton-c/src/core/object/object.c               |  312 ++
 proton-c/src/core/object/record.c               |  153 +
 proton-c/src/core/object/string.c               |  269 ++
 proton-c/src/core/transport.c                   | 3019 ++++++++++++++++++
 proton-c/src/core/transport.h                   |   31 +
 proton-c/src/core/types.c                       |   34 +
 proton-c/src/core/util.c                        |  165 +
 proton-c/src/core/util.h                        |  123 +
 proton-c/src/dispatch_actions.h                 |   49 -
 proton-c/src/dispatcher/dispatcher.c            |  158 -
 proton-c/src/dispatcher/dispatcher.h            |   37 -
 proton-c/src/encodings.h.py                     |   42 +
 proton-c/src/engine/connection_engine.c         |  124 -
 proton-c/src/engine/engine-internal.h           |  374 ---
 proton-c/src/engine/engine.c                    | 2231 -------------
 proton-c/src/error.c                            |  135 -
 proton-c/src/events/event.c                     |  388 ---
 proton-c/src/extra/parser.c                     |  423 +++
 proton-c/src/extra/scanner.c                    |  399 +++
 proton-c/src/extra/scanner.h                    |   74 +
 proton-c/src/extra/url.c                        |  272 ++
 proton-c/src/framing/framing.c                  |  103 -
 proton-c/src/framing/framing.h                  |   52 -
 proton-c/src/handlers/iohandler.c               |    7 +-
 proton-c/src/libqpid-proton-core.pc.in          |   30 +
 proton-c/src/log.c                              |   70 -
 proton-c/src/log_private.h                      |   54 -
 proton-c/src/message/message.c                  |  861 -----
 proton-c/src/messenger/messenger.c              |   18 +-
 proton-c/src/messenger/store.c                  |    2 +-
 proton-c/src/messenger/store.h                  |    2 +-
 proton-c/src/messenger/transform.h              |    3 +-
 proton-c/src/object/iterator.c                  |   78 -
 proton-c/src/object/list.c                      |  267 --
 proton-c/src/object/map.c                       |  461 ---
 proton-c/src/object/object.c                    |  312 --
 proton-c/src/object/record.c                    |  153 -
 proton-c/src/object/string.c                    |  270 --
 proton-c/src/parser.c                           |  420 ---
 proton-c/src/platform.c                         |  134 -
 proton-c/src/platform.h                         |  101 -
 proton-c/src/platform/platform.c                |  122 +
 proton-c/src/platform/platform.h                |   93 +
 proton-c/src/platform/platform_fmt.h            |   85 +
 proton-c/src/platform_fmt.h                     |   85 -
 proton-c/src/posix/io.c                         |  342 --
 proton-c/src/posix/selector.c                   |  211 --
 proton-c/src/reactor/acceptor.c                 |   13 +-
 proton-c/src/reactor/connection.c               |   19 +-
 proton-c/src/reactor/io.h                       |   70 +
 proton-c/src/reactor/io/posix/io.c              |  342 ++
 proton-c/src/reactor/io/posix/selector.c        |  214 ++
 proton-c/src/reactor/io/windows/io.c            |  459 +++
 proton-c/src/reactor/io/windows/iocp.c          | 1179 +++++++
 proton-c/src/reactor/io/windows/iocp.h          |  136 +
 proton-c/src/reactor/io/windows/selector.c      |  384 +++
 .../src/reactor/io/windows/write_pipeline.c     |  314 ++
 proton-c/src/reactor/reactor.c                  |   23 +-
 proton-c/src/reactor/reactor.h                  |    2 +-
 proton-c/src/reactor/selectable.c               |  300 ++
 proton-c/src/reactor/selectable.h               |   36 +
 proton-c/src/reactor/selector.h                 |   53 +
 proton-c/src/sasl/cyrus_sasl.c                  |    4 +-
 proton-c/src/sasl/none_sasl.c                   |    2 +-
 proton-c/src/sasl/sasl-internal.h               |    5 +-
 proton-c/src/sasl/sasl.c                        |    9 +-
 proton-c/src/scanner.c                          |  397 ---
 proton-c/src/selectable.c                       |  297 --
 proton-c/src/selectable.h                       |   36 -
 proton-c/src/ssl/openssl.c                      |   13 +-
 proton-c/src/ssl/schannel.c                     | 2239 +++++++++++++
 proton-c/src/ssl/ssl_stub.c                     |    2 +-
 proton-c/src/tests/data.c                       |    2 +-
 proton-c/src/transport/autodetect.c             |  135 -
 proton-c/src/transport/autodetect.h             |   40 -
 proton-c/src/transport/transport.c              | 3018 -----------------
 proton-c/src/transport/transport.h              |   31 -
 proton-c/src/types.c                            |   41 -
 proton-c/src/types.xml                          |  125 +
 proton-c/src/url.c                              |  186 --
 proton-c/src/util.c                             |  274 --
 proton-c/src/util.h                             |  126 -
 proton-c/src/windows/io.c                       |  457 ---
 proton-c/src/windows/iocp.c                     | 1176 -------
 proton-c/src/windows/iocp.h                     |  144 -
 proton-c/src/windows/schannel.c                 | 2239 -------------
 proton-c/src/windows/selector.c                 |  382 ---
 proton-c/src/windows/write_pipeline.c           |  312 --
 tools/cmake/Modules/WindowsC99SymbolCheck.py    |    2 +-
 145 files changed, 21103 insertions(+), 21029 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index cba043a..3cf01cd 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -81,8 +81,8 @@ set (env_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py)
 
 add_custom_command (
   OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
-  COMMAND ${env_py} PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
-  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py
+  COMMAND ${env_py} PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/encodings.h.py
   )
 
 add_custom_command (
@@ -93,11 +93,11 @@ add_custom_command (
 
 # Select IO impl
 if(PN_WINAPI)
-  set (pn_io_impl src/windows/io.c src/windows/iocp.c src/windows/write_pipeline.c)
-  set (pn_selector_impl src/windows/selector.c)
+  set (pn_io_impl src/reactor/io/windows/io.c src/reactor/io/windows/iocp.c src/reactor/io/windows/write_pipeline.c)
+  set (pn_selector_impl src/reactor/io/windows/selector.c)
 else(PN_WINAPI)
-  set (pn_io_impl src/posix/io.c)
-  set (pn_selector_impl src/posix/selector.c)
+  set (pn_io_impl src/reactor/io/posix/io.c)
+  set (pn_selector_impl src/reactor/io/posix/selector.c)
 endif(PN_WINAPI)
 
 # Link in SASL if present
@@ -124,7 +124,7 @@ if (SSL_IMPL STREQUAL openssl)
   include_directories (${OPENSSL_INCLUDE_DIR})
   set (SSL_LIB ${OPENSSL_LIBRARIES})
 elseif (SSL_IMPL STREQUAL schannel)
-  set (pn_ssl_impl src/windows/schannel.c)
+  set (pn_ssl_impl src/ssl/schannel.c)
   set (SSL_LIB Crypt32.lib Secur32.lib)
 else ()
   set (pn_ssl_impl src/ssl/ssl_stub.c)
@@ -281,6 +281,7 @@ if (MSVC)
         /wd4800
         /wd4996
     )
+    set (qpid-proton-platform src/compiler/msvc/snprintf.c)
 endif (MSVC)
 
 macro (pn_absolute_install_dir NAME VALUE PREFIX)
@@ -303,49 +304,61 @@ add_subdirectory(bindings)
 add_subdirectory(docs/api)
 add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
 
-set (qpid-proton-platform
+set (qpid-proton-platform-io
+  src/platform/platform.c
   ${pn_io_impl}
   ${pn_selector_impl}
-  src/platform.c
+  )
+
+set (qpid-proton-layers
   ${pn_sasl_impl}
   ${pn_ssl_impl}
   )
 
 set (qpid-proton-core
-  src/object/object.c
-  src/object/list.c
-  src/object/map.c
-  src/object/string.c
-  src/object/iterator.c
-  src/object/record.c
-
-  src/log.c
-  src/util.c
-  src/url.c
-  src/error.c
-  src/buffer.c
-  src/parser.c
-  src/scanner.c
-  src/types.c
-
-  src/framing/framing.c
-
-  src/codec/codec.c
-  src/codec/decoder.c
-  src/codec/encoder.c
-
-  src/dispatcher/dispatcher.c
-  src/engine/connection_engine.c
-  src/engine/engine.c
-  src/events/event.c
-  src/transport/autodetect.c
-  src/transport/transport.c
-  src/message/message.c
+  src/core/object/object.c
+  src/core/object/list.c
+  src/core/object/map.c
+  src/core/object/string.c
+  src/core/object/iterator.c
+  src/core/object/record.c
+
+  src/core/log.c
+  src/core/util.c
+  src/core/error.c
+  src/core/buffer.c
+  src/core/types.c
+
+  src/core/framing.c
+
+  src/core/codec.c
+  src/core/decoder.c
+  src/core/encoder.c
+
+  src/core/dispatcher.c
+  src/core/connection_engine.c
+  src/core/engine.c
+  src/core/event.c
+  src/core/autodetect.c
+  src/core/transport.c
+  src/core/message.c
+  )
+
+set (qpid-proton-include-generated
+  ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+  ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
+  )
+
+set (qpid-proton-extra
+  src/extra/parser.c
+  src/extra/scanner.c
+  src/extra/url.c
 
   src/reactor/reactor.c
   src/reactor/handler.c
   src/reactor/connection.c
   src/reactor/acceptor.c
+  src/reactor/selectable.c
   src/reactor/timer.c
 
   src/handlers/handshaker.c
@@ -356,12 +369,6 @@ set (qpid-proton-core
   src/messenger/subscription.c
   src/messenger/store.c
   src/messenger/transform.c
-  src/selectable.c
-  )
-
-set (qpid-proton-extra-deps
-  ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
-  ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
   )
 
 set (qpid-proton-include
@@ -374,39 +381,42 @@ set (qpid-proton-include
   include/proton/engine.h
   include/proton/error.h
   include/proton/event.h
-  include/proton/handlers.h
   include/proton/import_export.h
-  include/proton/io.h
   include/proton/link.h
   include/proton/log.h
   include/proton/message.h
-  include/proton/messenger.h
   include/proton/object.h
-  include/proton/parser.h
-  include/proton/reactor.h
   include/proton/sasl.h
-  include/proton/scanner.h
-  include/proton/selectable.h
-  include/proton/selector.h
   include/proton/session.h
   include/proton/ssl.h
   include/proton/terminus.h
   include/proton/transport.h
   include/proton/type_compat.h
   include/proton/types.h
+)
+
+set (qpid-proton-include-extra
+  include/proton/handlers.h
+  include/proton/messenger.h
+  include/proton/parser.h
+  include/proton/reactor.h
+  include/proton/selectable.h
   include/proton/url.h
 )
 
-source_group("API Header Files" FILES ${qpid-proton-include})
+source_group("API Header Files" FILES ${qpid-proton-include} ${qpid-proton-include-extra})
 
 set_source_files_properties (
   ${qpid-proton-core}
+  ${qpid-proton-layers}
+  ${qpid-proton-extra}
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LTO}"
   )
 
 set_source_files_properties (
   ${qpid-proton-platform}
+  ${qpid-proton-platform-io}
   PROPERTIES
   COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS} ${LTO}"
   COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
@@ -414,18 +424,47 @@ set_source_files_properties (
 
 if (BUILD_WITH_CXX)
   set_source_files_properties (
-    ${qpid-proton-core} ${qpid-proton-platform}
+    ${qpid-proton-core}
+    ${qpid-proton-layers}
+    ${qpid-proton-extra}
+    ${qpid-proton-platform}
+    ${qpid-proton-platform-io}
     PROPERTIES LANGUAGE CXX
     )
 endif (BUILD_WITH_CXX)
 
 add_library (
-  qpid-proton SHARED
+  qpid-proton-core SHARED
+  ${qpid-proton-core}
+  ${qpid-proton-layers}
+  ${qpid-proton-platform}
+  ${qpid-proton-include}
+  ${qpid-proton-include-generated}
+  )
+
+target_link_libraries (qpid-proton-core ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
 
+set_target_properties (
+  qpid-proton-core
+  PROPERTIES
+  VERSION   "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
+  SOVERSION "${PN_LIB_SOMAJOR}"
+  LINK_FLAGS "${CATCH_UNDEFINED} ${LTO}"
+  )
+
+add_library(
+  qpid-proton SHARED
+  # Proton Core
   ${qpid-proton-core}
+  ${qpid-proton-layers}
   ${qpid-proton-platform}
   ${qpid-proton-include}
-  ${qpid-proton-extra-deps}
+  ${qpid-proton-include-generated}
+
+  # Proton Reactor/Messenger
+  ${qpid-proton-extra}
+  ${qpid-proton-platform-io}
+  ${qpid-proton-include-extra}
   )
 
 target_link_libraries (qpid-proton ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
@@ -471,13 +510,24 @@ configure_file(
 install (FILES
   ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc
   DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton-core.pc.in
+  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton-core.pc @ONLY)
+install (FILES
+  ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton-core.pc
+  DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
 
 if (DEFINED CMAKE_IMPORT_LIBRARY_PREFIX)
 set(PROTONLIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_IMPORT_LIBRARY_SUFFIX})
 set(PROTONLIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
+set(PROTONCORELIB ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton-core${CMAKE_IMPORT_LIBRARY_SUFFIX})
+set(PROTONCORELIBDEBUG ${CMAKE_IMPORT_LIBRARY_PREFIX}qpid-proton-core${CMAKE_DEBUG_POSTFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX})
 else ()
 set(PROTONLIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_SHARED_LIBRARY_SUFFIX})
 set(PROTONLIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
+set(PROTONCORELIB ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton-core${CMAKE_SHARED_LIBRARY_SUFFIX})
+set(PROTONCORELIBDEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}qpid-proton-core${CMAKE_DEBUG_POSTFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
 endif ()
 
 include(WriteBasicConfigVersionFile)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/bindings/python/proton/reactor.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/reactor.py b/proton-c/bindings/python/proton/reactor.py
index ee9cfde..1a85bd3 100644
--- a/proton-c/bindings/python/proton/reactor.py
+++ b/proton-c/bindings/python/proton/reactor.py
@@ -138,7 +138,7 @@ class Reactor(Wrapper):
 
     def wakeup(self):
         n = pn_reactor_wakeup(self._impl)
-        if n: raise IOError(pn_error_text(pn_io_error(pn_reactor_io(self._impl))))
+        if n: raise IOError(pn_error_text(pn_reactor_error(self._impl)))
 
     def start(self):
         pn_reactor_start(self._impl)
@@ -176,7 +176,7 @@ class Reactor(Wrapper):
         if aimpl:
             return Acceptor(aimpl)
         else:
-            raise IOError("%s (%s:%s)" % (pn_error_text(pn_io_error(pn_reactor_io(self._impl))), host, port))
+            raise IOError("%s (%s:%s)" % pn_error_text(pn_reactor_error(self._impl)), host, port)
 
     def connection(self, handler=None):
         """Deprecated: use connection_to_host() instead

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/bindings/python/setup.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py b/proton-c/bindings/python/setup.py
index 1a74f0f..3606bed 100755
--- a/proton-c/bindings/python/setup.py
+++ b/proton-c/bindings/python/setup.py
@@ -194,8 +194,7 @@ class Configure(build_ext):
         # Generate `encodings.h` by calling the python
         # script found in the source dir.
         with open(os.path.join(build_include, 'encodings.h'), 'wb') as header:
-            subprocess.Popen([sys.executable,
-                              os.path.join(proton_src, 'codec', 'encodings.h.py')],
+            subprocess.Popen([sys.executable, os.path.join(proton_src, 'encodings.h.py')],
                               env=proton_envs, stdout=header)
 
         # Create a custom, temporary, version.h file mapping the
@@ -219,10 +218,9 @@ class Configure(build_ext):
         # we don't need.
 
         sources = []
-        for subdir in ['object', 'framing', 'codec', 'dispatcher',
-                       'engine', 'events', 'transport',
-                       'message', 'reactor', 'messenger',
-                       'handlers', 'posix']:
+        for subdir in ['core', 'core/object', 'compiler',
+                       'extra', 'message', 'reactor', 'messenger', 'handlers',
+                       'platform', 'reactor/io/posix']:
 
             sources.extend(glob.glob(os.path.join(proton_src, subdir, '*.c')))
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/bindings/ruby/lib/reactor/reactor.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/reactor/reactor.rb b/proton-c/bindings/ruby/lib/reactor/reactor.rb
index 1cf4f6c..a0ff7e0 100644
--- a/proton-c/bindings/ruby/lib/reactor/reactor.rb
+++ b/proton-c/bindings/ruby/lib/reactor/reactor.rb
@@ -128,8 +128,7 @@ module Qpid::Proton::Reactor
     def wakeup
       n = Cproton.pn_reactor_wakeup(@impl)
       unless n.zero?
-        io = Cproton.pn_reactor_io(@impl)
-        raise IOError.new(Cproton.pn_io_error(io))
+        raise IOError.new(Cproton.pn_reactor_error(@impl))
       end
     end
 
@@ -159,8 +158,7 @@ module Qpid::Proton::Reactor
       if !aimpl.nil?
         return Acceptor.new(aimpl)
       else
-        io = Cproton.pn_reactor_io(@impl)
-        io_error = Cproton.pn_io_error(io)
+        io_error = Cproton.pn_reactor_error(@impl)
         error_text = Cproton.pn_error_text(io_error)
         text = "(#{Cproton.pn_error_text(io_error)} (#{host}:#{port}))"
         raise IOError.new(text)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index 6129037..ffcf830 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -1014,8 +1014,6 @@ typedef unsigned long int uintptr_t;
 
 %include "proton/messenger.h"
 
-%include "proton/io.h"
-
 %include "proton/selectable.h"
 
 %include "proton/ssl.h"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 16d2bda..d10927b 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -415,11 +415,6 @@ PN_EXTERN const pn_class_t *pn_event_class(pn_event_t *event);
 PN_EXTERN void *pn_event_context(pn_event_t *event);
 
 /**
- * Get the root handler the current event was dispatched to.
- */
-PN_EXTERN pn_handler_t *pn_event_root(pn_event_t *event);
-
-/**
  * Get the connection associated with an event.
  *
  * @param[in] event an event object

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/handlers.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/handlers.h b/proton-c/include/proton/handlers.h
index f61e04c..a8a6f77 100644
--- a/proton-c/include/proton/handlers.h
+++ b/proton-c/include/proton/handlers.h
@@ -43,9 +43,9 @@ typedef pn_handler_t pn_handshaker_t;
 typedef pn_handler_t pn_iohandler_t;
 typedef pn_handler_t pn_flowcontroller_t;
 
-PN_EXTERN pn_handshaker_t *pn_handshaker(void);
-PN_EXTERN pn_iohandler_t *pn_iohandler(void);
-PN_EXTERN pn_flowcontroller_t *pn_flowcontroller(int window);
+PNX_EXTERN pn_handshaker_t *pn_handshaker(void);
+PNX_EXTERN pn_iohandler_t *pn_iohandler(void);
+PNX_EXTERN pn_flowcontroller_t *pn_flowcontroller(int window);
 
 /** @}
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/import_export.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/import_export.h b/proton-c/include/proton/import_export.h
index 4534d68..0010126 100644
--- a/proton-c/include/proton/import_export.h
+++ b/proton-c/include/proton/import_export.h
@@ -46,12 +46,18 @@
 
 
 // For core proton library symbols
-
-#ifdef qpid_proton_EXPORTS
+#if defined(qpid_proton_core_EXPORTS) || defined(qpid_proton_EXPORTS)
 #  define PN_EXTERN PN_EXPORT
 #else
 #  define PN_EXTERN PN_IMPORT
 #endif
 
+// For extra proton symbols
+#if defined(qpid_proton_EXPORTS)
+#  define PNX_EXTERN PN_EXPORT
+#else
+#  define PNX_EXTERN PN_IMPORT
+#endif
+
 
 #endif /* import_export.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/io.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/io.h b/proton-c/include/proton/io.h
deleted file mode 100644
index 19dfe53..0000000
--- a/proton-c/include/proton/io.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef PROTON_IO_H
-#define PROTON_IO_H 1
-
-/*
- *
- * 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/import_export.h>
-#include <proton/error.h>
-#include <proton/type_compat.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * A ::pn_socket_t provides an abstract handle to an IO stream.  The
- * pipe version is uni-directional.  The network socket version is
- * bi-directional.  Both are non-blocking.
- *
- * pn_socket_t handles from ::pn_pipe() may only be used with
- * ::pn_read(), ::pn_write(), ::pn_close() and pn_selector_select().
- *
- * pn_socket_t handles from ::pn_listen(), ::pn_accept() and
- * ::pn_connect() must perform further IO using Proton functions.
- * Mixing Proton io.h functions with native IO functions on the same
- * handles will result in undefined behavior.
- *
- * pn_socket_t handles may only be used with a single pn_io_t during
- * their lifetime.
- */
-#if defined(_WIN32) && ! defined(__CYGWIN__)
-#ifdef _WIN64
-typedef unsigned __int64 pn_socket_t;
-#else
-typedef unsigned int pn_socket_t;
-#endif
-#define PN_INVALID_SOCKET (pn_socket_t)(~0)
-#else
-typedef int pn_socket_t;
-#define PN_INVALID_SOCKET (-1)
-#endif
-
-/**
- * A ::pn_io_t manages IO for a group of pn_socket_t handles.  A
- * pn_io_t object may have zero or one pn_selector_t selectors
- * associated with it (see ::pn_io_selector()).  If one is associated,
- * all the pn_socket_t handles managed by a pn_io_t must use that
- * pn_selector_t instance.
- *
- * The pn_io_t interface is single-threaded. All methods are intended
- * to be used by one thread at a time, except that multiple threads
- * may use:
- *
- *   ::pn_write()
- *   ::pn_send()
- *   ::pn_recv()
- *   ::pn_close()
- *   ::pn_selector_select()
- *
- * provided at most one thread is calling ::pn_selector_select() and
- * the other threads are operating on separate pn_socket_t handles.
- */
-typedef struct pn_io_t pn_io_t;
-
-/**
- * A ::pn_selector_t provides a selection mechanism that allows
- * efficient monitoring of a large number of Proton connections and
- * listeners.
- *
- * External (non-Proton) sockets may also be monitored, either solely
- * for event notification (read, write, and timer) or event
- * notification and use with pn_io_t interfaces.
- */
-typedef struct pn_selector_t pn_selector_t;
-
-PN_EXTERN pn_io_t *pn_io(void);
-PN_EXTERN void pn_io_free(pn_io_t *io);
-PN_EXTERN pn_error_t *pn_io_error(pn_io_t *io);
-PN_EXTERN pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port);
-PN_EXTERN pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port);
-PN_EXTERN pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size);
-PN_EXTERN void pn_close(pn_io_t *io, pn_socket_t socket);
-PN_EXTERN ssize_t pn_send(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
-PN_EXTERN ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
-PN_EXTERN int pn_pipe(pn_io_t *io, pn_socket_t *dest);
-PN_EXTERN ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size);
-PN_EXTERN ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size);
-PN_EXTERN bool pn_wouldblock(pn_io_t *io);
-PN_EXTERN pn_selector_t *pn_io_selector(pn_io_t *io);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* io.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/messenger.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/messenger.h b/proton-c/include/proton/messenger.h
index 6d0f58b..8cba51d 100644
--- a/proton-c/include/proton/messenger.h
+++ b/proton-c/include/proton/messenger.h
@@ -195,7 +195,7 @@ typedef enum {
  *
  * @return pointer to a new ::pn_messenger_t
  */
-PN_EXTERN pn_messenger_t *pn_messenger(const char *name);
+PNX_EXTERN pn_messenger_t *pn_messenger(const char *name);
 
 /**
  * Get the name of a messenger.
@@ -203,7 +203,7 @@ PN_EXTERN pn_messenger_t *pn_messenger(const char *name);
  * @param[in] messenger a messenger object
  * @return the name of the messenger
  */
-PN_EXTERN const char *pn_messenger_name(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_name(pn_messenger_t *messenger);
 
 /**
  * Sets the path that will be used to get the certificate that will be
@@ -214,7 +214,7 @@ PN_EXTERN const char *pn_messenger_name(pn_messenger_t *messenger);
  * @param[in] certificate a path to a certificate file
  * @return an error code of zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_certificate(pn_messenger_t *messenger, const char *certificate);
+PNX_EXTERN int pn_messenger_set_certificate(pn_messenger_t *messenger, const char *certificate);
 
 /**
  * Get the certificate path. This value may be set by
@@ -223,7 +223,7 @@ PN_EXTERN int pn_messenger_set_certificate(pn_messenger_t *messenger, const char
  * @param[in] messenger the messenger
  * @return the certificate file path
  */
-PN_EXTERN const char *pn_messenger_get_certificate(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_certificate(pn_messenger_t *messenger);
 
 /**
  * Set path to the private key that was used to sign the certificate.
@@ -233,7 +233,7 @@ PN_EXTERN const char *pn_messenger_get_certificate(pn_messenger_t *messenger);
  * @param[in] private_key a path to a private key file
  * @return an error code of zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_private_key(pn_messenger_t *messenger, const char *private_key);
+PNX_EXTERN int pn_messenger_set_private_key(pn_messenger_t *messenger, const char *private_key);
 
 /**
  * Gets the private key file for a messenger.
@@ -241,7 +241,7 @@ PN_EXTERN int pn_messenger_set_private_key(pn_messenger_t *messenger, const char
  * @param[in] messenger a messenger object
  * @return the messenger's private key file path
  */
-PN_EXTERN const char *pn_messenger_get_private_key(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_private_key(pn_messenger_t *messenger);
 
 /**
  * Sets the private key password for a messenger.
@@ -251,7 +251,7 @@ PN_EXTERN const char *pn_messenger_get_private_key(pn_messenger_t *messenger);
  *
  * @return an error code of zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_password(pn_messenger_t *messenger, const char *password);
+PNX_EXTERN int pn_messenger_set_password(pn_messenger_t *messenger, const char *password);
 
 /**
  * Gets the private key file password for a messenger.
@@ -259,7 +259,7 @@ PN_EXTERN int pn_messenger_set_password(pn_messenger_t *messenger, const char *p
  * @param[in] messenger a messenger object
  * @return password for the private key file
  */
-PN_EXTERN const char *pn_messenger_get_password(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_password(pn_messenger_t *messenger);
 
 /**
  * Sets the trusted certificates database for a messenger.
@@ -272,7 +272,7 @@ PN_EXTERN const char *pn_messenger_get_password(pn_messenger_t *messenger);
  *
  * @return an error code of zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_trusted_certificates(pn_messenger_t *messenger, const char *cert_db);
+PNX_EXTERN int pn_messenger_set_trusted_certificates(pn_messenger_t *messenger, const char *cert_db);
 
 /**
  * Gets the trusted certificates database for a messenger.
@@ -280,7 +280,7 @@ PN_EXTERN int pn_messenger_set_trusted_certificates(pn_messenger_t *messenger, c
  * @param[in] messenger a messenger object
  * @return path to the trusted certificates database
  */
-PN_EXTERN const char *pn_messenger_get_trusted_certificates(pn_messenger_t *messenger);
+PNX_EXTERN const char *pn_messenger_get_trusted_certificates(pn_messenger_t *messenger);
 
 /**
  * Set the default timeout for a messenger.
@@ -294,7 +294,7 @@ PN_EXTERN const char *pn_messenger_get_trusted_certificates(pn_messenger_t *mess
  * @param[in] timeout a new timeout for the messenger, in milliseconds
  * @return an error code or zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_timeout(pn_messenger_t *messenger, int timeout);
+PNX_EXTERN int pn_messenger_set_timeout(pn_messenger_t *messenger, int timeout);
 
 /**
  * Gets the timeout for a messenger object.
@@ -304,7 +304,7 @@ PN_EXTERN int pn_messenger_set_timeout(pn_messenger_t *messenger, int timeout);
  * @param[in] messenger a messenger object
  * @return the timeout for the messenger, in milliseconds
  */
-PN_EXTERN int pn_messenger_get_timeout(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_timeout(pn_messenger_t *messenger);
 
 /**
  * Check if a messenger is in blocking mode.
@@ -312,7 +312,7 @@ PN_EXTERN int pn_messenger_get_timeout(pn_messenger_t *messenger);
  * @param[in] messenger a messenger object
  * @return true if blocking has been enabled, false otherwise
  */
-PN_EXTERN bool pn_messenger_is_blocking(pn_messenger_t *messenger);
+PNX_EXTERN bool pn_messenger_is_blocking(pn_messenger_t *messenger);
 
 /**
  * Enable or disable blocking behavior for a messenger during calls to
@@ -322,7 +322,7 @@ PN_EXTERN bool pn_messenger_is_blocking(pn_messenger_t *messenger);
  * @param[in] blocking the value of the blocking flag
  * @return an error code or zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_blocking(pn_messenger_t *messenger, bool blocking);
+PNX_EXTERN int pn_messenger_set_blocking(pn_messenger_t *messenger, bool blocking);
 
 /**
  * Check if a messenger is in passive mode.
@@ -336,7 +336,7 @@ PN_EXTERN int pn_messenger_set_blocking(pn_messenger_t *messenger, bool blocking
  * @param[in] messenger a messenger object
  * @return true if the messenger is in passive mode, false otherwise
  */
-PN_EXTERN bool pn_messenger_is_passive(pn_messenger_t *messenger);
+PNX_EXTERN bool pn_messenger_is_passive(pn_messenger_t *messenger);
 
 /**
  * Set the passive mode for a messenger.
@@ -348,14 +348,14 @@ PN_EXTERN bool pn_messenger_is_passive(pn_messenger_t *messenger);
  * passive mode
  * @return an error code or zero on success
  */
-PN_EXTERN int pn_messenger_set_passive(pn_messenger_t *messenger, bool passive);
+PNX_EXTERN int pn_messenger_set_passive(pn_messenger_t *messenger, bool passive);
 
 /** Frees a Messenger.
  *
  * @param[in] messenger the messenger to free (or NULL), no longer
  *                      valid on return
  */
-PN_EXTERN void pn_messenger_free(pn_messenger_t *messenger);
+PNX_EXTERN void pn_messenger_free(pn_messenger_t *messenger);
 
 /**
  * Get the code for a messenger's most recent error.
@@ -370,7 +370,7 @@ PN_EXTERN void pn_messenger_free(pn_messenger_t *messenger);
  * @return an error code or zero if there is no error
  * @see error.h
  */
-PN_EXTERN int pn_messenger_errno(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_errno(pn_messenger_t *messenger);
 
 /**
  * Get a messenger's error object.
@@ -383,7 +383,7 @@ PN_EXTERN int pn_messenger_errno(pn_messenger_t *messenger);
  * @return a pointer to the messenger's error descriptor
  * @see error.h
  */
-PN_EXTERN pn_error_t *pn_messenger_error(pn_messenger_t *messenger);
+PNX_EXTERN pn_error_t *pn_messenger_error(pn_messenger_t *messenger);
 
 /**
  * Get the size of a messenger's outgoing window.
@@ -400,7 +400,7 @@ PN_EXTERN pn_error_t *pn_messenger_error(pn_messenger_t *messenger);
  * @param[in] messenger a messenger object
  * @return the outgoing window for the messenger
  */
-PN_EXTERN int pn_messenger_get_outgoing_window(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_outgoing_window(pn_messenger_t *messenger);
 
 /**
  * Set the size of a messenger's outgoing window.
@@ -412,7 +412,7 @@ PN_EXTERN int pn_messenger_get_outgoing_window(pn_messenger_t *messenger);
  * @return an error or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_set_outgoing_window(pn_messenger_t *messenger, int window);
+PNX_EXTERN int pn_messenger_set_outgoing_window(pn_messenger_t *messenger, int window);
 
 /**
  * Get the size of a messenger's incoming window.
@@ -432,7 +432,7 @@ PN_EXTERN int pn_messenger_set_outgoing_window(pn_messenger_t *messenger, int wi
  * @param[in] messenger a messenger object
  * @return the incoming window for the messenger
  */
-PN_EXTERN int pn_messenger_get_incoming_window(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_incoming_window(pn_messenger_t *messenger);
 
 /**
  * Set the size of a messenger's incoming window.
@@ -444,7 +444,7 @@ PN_EXTERN int pn_messenger_get_incoming_window(pn_messenger_t *messenger);
  * @return an error or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_set_incoming_window(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_incoming_window(pn_messenger_t *messenger,
                                                int window);
 
 /**
@@ -455,7 +455,7 @@ PN_EXTERN int pn_messenger_set_incoming_window(pn_messenger_t *messenger,
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_start(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_start(pn_messenger_t *messenger);
 
 /**
  * Stops a messenger.
@@ -471,7 +471,7 @@ PN_EXTERN int pn_messenger_start(pn_messenger_t *messenger);
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_stop(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_stop(pn_messenger_t *messenger);
 
 /**
  * Returns true if a messenger is in the stopped state. This function
@@ -480,7 +480,7 @@ PN_EXTERN int pn_messenger_stop(pn_messenger_t *messenger);
  * @param[in] messenger the messenger to stop
  *
  */
-PN_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
+PNX_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
 
 /**
  * Subscribes a messenger to messages from the specified source.
@@ -489,7 +489,7 @@ PN_EXTERN bool pn_messenger_stopped(pn_messenger_t *messenger);
  * @param[in] source
  * @return a subscription
  */
-PN_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char *source);
+PNX_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, const char *source);
 
 /**
  * Subscribes a messenger to messages from the specified source with the given
@@ -501,7 +501,7 @@ PN_EXTERN pn_subscription_t *pn_messenger_subscribe(pn_messenger_t *messenger, c
  *            link is closed.
  * @return a subscription
  */
-PN_EXTERN pn_subscription_t *
+PNX_EXTERN pn_subscription_t *
 pn_messenger_subscribe_ttl(pn_messenger_t *messenger, const char *source,
                            pn_seconds_t timeout);
 
@@ -514,7 +514,7 @@ pn_messenger_subscribe_ttl(pn_messenger_t *messenger, const char *source,
  *            receiver
  * @return a link, or NULL if no link matches the address / sender parameters
  */
-PN_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
+PNX_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
                                            const char *address, bool sender);
 
 /**
@@ -525,7 +525,7 @@ PN_EXTERN pn_link_t *pn_messenger_get_link(pn_messenger_t *messenger,
  * @param[in] sub a subscription object
  * @return the subscription's application context
  */
-PN_EXTERN void *pn_subscription_get_context(pn_subscription_t *sub);
+PNX_EXTERN void *pn_subscription_get_context(pn_subscription_t *sub);
 
 /**
  * Set an application context for a subscription.
@@ -533,7 +533,7 @@ PN_EXTERN void *pn_subscription_get_context(pn_subscription_t *sub);
  * @param[in] sub a subscription object
  * @param[in] context the application context for the subscription
  */
-PN_EXTERN void pn_subscription_set_context(pn_subscription_t *sub, void *context);
+PNX_EXTERN void pn_subscription_set_context(pn_subscription_t *sub, void *context);
 
 /**
  * Get the source address of a subscription.
@@ -541,7 +541,7 @@ PN_EXTERN void pn_subscription_set_context(pn_subscription_t *sub, void *context
  * @param[in] sub a subscription object
  * @return the subscription's source address
  */
-PN_EXTERN const char *pn_subscription_address(pn_subscription_t *sub);
+PNX_EXTERN const char *pn_subscription_address(pn_subscription_t *sub);
 
 /**
  * Puts a message onto the messenger's outgoing queue. The message may
@@ -553,7 +553,7 @@ PN_EXTERN const char *pn_subscription_address(pn_subscription_t *sub);
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
+PNX_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
 
 /**
  * Track the status of a delivery.
@@ -566,7 +566,7 @@ PN_EXTERN int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg);
  * @param[in] tracker the tracker identifying the delivery
  * @return a status code for the delivery
  */
-PN_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_t tracker);
+PNX_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_t tracker);
 
 /**
  * Get delivery information about a delivery.
@@ -579,7 +579,7 @@ PN_EXTERN pn_status_t pn_messenger_status(pn_messenger_t *messenger, pn_tracker_
  * @param[in] tracker the tracker identifying the delivery
  * @return a pn_delivery_t representing the delivery.
  */
-PN_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
+PNX_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
                                                pn_tracker_t tracker);
 
 /**
@@ -594,7 +594,7 @@ PN_EXTERN pn_delivery_t *pn_messenger_delivery(pn_messenger_t *messenger,
  *
  * @return true if the delivery is still buffered
  */
-PN_EXTERN bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tracker);
+PNX_EXTERN bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tracker);
 
 /**
  * Frees a Messenger from tracking the status associated with a given
@@ -608,7 +608,7 @@ PN_EXTERN bool pn_messenger_buffered(pn_messenger_t *messenger, pn_tracker_t tra
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_settle(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
+PNX_EXTERN int pn_messenger_settle(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
 
 /**
  * Get a tracker for the outgoing message most recently given to
@@ -623,7 +623,7 @@ PN_EXTERN int pn_messenger_settle(pn_messenger_t *messenger, pn_tracker_t tracke
  * @return a pn_tracker_t or an undefined value if pn_messenger_get
  *         has never been called for the given messenger
  */
-PN_EXTERN pn_tracker_t pn_messenger_outgoing_tracker(pn_messenger_t *messenger);
+PNX_EXTERN pn_tracker_t pn_messenger_outgoing_tracker(pn_messenger_t *messenger);
 
 /**
  * Sends or receives any outstanding messages queued for a messenger.
@@ -635,7 +635,7 @@ PN_EXTERN pn_tracker_t pn_messenger_outgoing_tracker(pn_messenger_t *messenger);
  *
  * @return 0 if no work to do, < 0 if error, or 1 if work was done.
  */
-PN_EXTERN int pn_messenger_work(pn_messenger_t *messenger, int timeout);
+PNX_EXTERN int pn_messenger_work(pn_messenger_t *messenger, int timeout);
 
 /**
  * Interrupt a messenger object that may be blocking in another
@@ -648,7 +648,7 @@ PN_EXTERN int pn_messenger_work(pn_messenger_t *messenger, int timeout);
  *
  * @param[in] messenger the Messenger to interrupt
  */
-PN_EXTERN int pn_messenger_interrupt(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_interrupt(pn_messenger_t *messenger);
 
 /**
  * Send messages from a messenger's outgoing queue.
@@ -682,7 +682,7 @@ PN_EXTERN int pn_messenger_interrupt(pn_messenger_t *messenger);
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_send(pn_messenger_t *messenger, int n);
+PNX_EXTERN int pn_messenger_send(pn_messenger_t *messenger, int n);
 
 /**
  * Retrieve messages into a messenger's incoming queue.
@@ -708,7 +708,7 @@ PN_EXTERN int pn_messenger_send(pn_messenger_t *messenger, int n);
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_recv(pn_messenger_t *messenger, int limit);
+PNX_EXTERN int pn_messenger_recv(pn_messenger_t *messenger, int limit);
 
 /**
  * Get the capacity of the incoming message queue of a messenger.
@@ -720,7 +720,7 @@ PN_EXTERN int pn_messenger_recv(pn_messenger_t *messenger, int limit);
  *
  * @param[in] messenger the messenger
  */
-PN_EXTERN int pn_messenger_receiving(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_receiving(pn_messenger_t *messenger);
 
 /**
  * Get the next message from the head of a messenger's incoming queue.
@@ -736,7 +736,7 @@ PN_EXTERN int pn_messenger_receiving(pn_messenger_t *messenger);
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *message);
+PNX_EXTERN int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *message);
 
 /**
  * Get a tracker for the message most recently retrieved by
@@ -751,7 +751,7 @@ PN_EXTERN int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *message)
  * @return a pn_tracker_t or an undefined value if pn_messenger_get
  *         has never been called for the given messenger
  */
-PN_EXTERN pn_tracker_t pn_messenger_incoming_tracker(pn_messenger_t *messenger);
+PNX_EXTERN pn_tracker_t pn_messenger_incoming_tracker(pn_messenger_t *messenger);
 
 /**
  * Get the subscription of the message most recently retrieved by ::pn_messenger_get().
@@ -762,7 +762,7 @@ PN_EXTERN pn_tracker_t pn_messenger_incoming_tracker(pn_messenger_t *messenger);
  * @param[in] messenger a messenger object
  * @return a pn_subscription_t or NULL
  */
-PN_EXTERN pn_subscription_t *pn_messenger_incoming_subscription(pn_messenger_t *messenger);
+PNX_EXTERN pn_subscription_t *pn_messenger_incoming_subscription(pn_messenger_t *messenger);
 
 /**
  * Indicates that an accept or reject should operate cumulatively.
@@ -790,7 +790,7 @@ PN_EXTERN pn_subscription_t *pn_messenger_incoming_subscription(pn_messenger_t *
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
+PNX_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
 
 /**
  * Signal unsuccessful processing of message(s).
@@ -813,7 +813,7 @@ PN_EXTERN int pn_messenger_accept(pn_messenger_t *messenger, pn_tracker_t tracke
  * @return an error code or zero on success
  * @see error.h
  */
-PN_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
+PNX_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracker, int flags);
 
 /**
  * Get  link for the message referenced by the given tracker.
@@ -822,7 +822,7 @@ PN_EXTERN int pn_messenger_reject(pn_messenger_t *messenger, pn_tracker_t tracke
  * @param[in] tracker a tracker object
  * @return a pn_link_t or NULL if the link could not be determined.
  */
-PN_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
+PNX_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
                                                pn_tracker_t tracker);
 
 /**
@@ -832,7 +832,7 @@ PN_EXTERN pn_link_t *pn_messenger_tracker_link(pn_messenger_t *messenger,
  * @param[in] messenger a messenger object
  * @return the outgoing queue depth
  */
-PN_EXTERN int pn_messenger_outgoing(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_outgoing(pn_messenger_t *messenger);
 
 /**
  * Get the number of messages in the incoming message queue of a messenger.
@@ -840,7 +840,7 @@ PN_EXTERN int pn_messenger_outgoing(pn_messenger_t *messenger);
  * @param[in] messenger a messenger object
  * @return the incoming queue depth
  */
-PN_EXTERN int pn_messenger_incoming(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_incoming(pn_messenger_t *messenger);
 
 //! Adds a routing rule to a Messenger's internal routing table.
 //!
@@ -904,7 +904,7 @@ PN_EXTERN int pn_messenger_incoming(pn_messenger_t *messenger);
 //!
 //! @return an error code or zero on success
 //! @see error.h
-PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern,
+PNX_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern,
                                  const char *address);
 
 /**
@@ -929,7 +929,7 @@ PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char *pattern,
  * @param[in] address an address indicating outgoing address rewrite
  * @return an error code or zero on success
  */
-PN_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char *pattern,
+PNX_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char *pattern,
                                    const char *address);
 
 /**
@@ -960,7 +960,7 @@ PN_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char *patter
  * @param[in] messenger a messenger object
  * @return the next selectable, or NULL if there are none left
  */
-PN_EXTERN pn_selectable_t *pn_messenger_selectable(pn_messenger_t *messenger);
+PNX_EXTERN pn_selectable_t *pn_messenger_selectable(pn_messenger_t *messenger);
 
 /**
  * Get the nearest deadline for selectables associated with a messenger.
@@ -968,7 +968,7 @@ PN_EXTERN pn_selectable_t *pn_messenger_selectable(pn_messenger_t *messenger);
  * @param[in] messenger a messenger object
  * @return the nearest deadline
  */
-PN_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
+PNX_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
 
 /**
  * @}
@@ -991,7 +991,7 @@ PN_EXTERN pn_timestamp_t pn_messenger_deadline(pn_messenger_t *messenger);
  *
  * @return an error code of zero if there is no error
  */
-PN_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
                                      const int flags);
 
 /** Gets the flags for a Messenger.
@@ -999,7 +999,7 @@ PN_EXTERN int pn_messenger_set_flags(pn_messenger_t *messenger,
  * @param[in] messenger the messenger
  * @return The flags set for the messenger
  */
-PN_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
+PNX_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
 
 /**
  * Set the local sender settle mode for the underlying link.
@@ -1007,7 +1007,7 @@ PN_EXTERN int pn_messenger_get_flags(pn_messenger_t *messenger);
  * @param[in] messenger the messenger
  * @param[in] mode the sender settle mode
  */
-PN_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
                                                const pn_snd_settle_mode_t mode);
 
 /**
@@ -1016,7 +1016,7 @@ PN_EXTERN int pn_messenger_set_snd_settle_mode(pn_messenger_t *messenger,
  * @param[in] messenger the messenger
  * @param[in] mode the receiver settle mode
  */
-PN_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
+PNX_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
                                                const pn_rcv_settle_mode_t mode);
 
 /**
@@ -1025,7 +1025,7 @@ PN_EXTERN int pn_messenger_set_rcv_settle_mode(pn_messenger_t *messenger,
  * @param[in] messenger a messenger object
  * @param[in] tracer the tracer callback
  */
-PN_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
+PNX_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
                                        pn_tracer_t tracer);
 
 /**
@@ -1035,7 +1035,7 @@ PN_EXTERN void pn_messenger_set_tracer(pn_messenger_t *messenger,
  * @param[in] address of remote service whose idle timeout is required
  * @return the timeout in milliseconds or -1 if an error occurs
  */
-PN_EXTERN pn_millis_t
+PNX_EXTERN pn_millis_t
     pn_messenger_get_remote_idle_timeout(pn_messenger_t *messenger,
                                          const char *address);
 
@@ -1048,7 +1048,7 @@ PN_EXTERN pn_millis_t
  *             enum for valid values)
  * @return 0 if successful or -1 if an error occurs
  */
-PN_EXTERN int
+PNX_EXTERN int
 pn_messenger_set_ssl_peer_authentication_mode(pn_messenger_t *messenger,
                                               const pn_ssl_verify_mode_t mode);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/reactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/reactor.h b/proton-c/include/proton/reactor.h
index 78fe57b..bfd6de5 100644
--- a/proton-c/include/proton/reactor.h
+++ b/proton-c/include/proton/reactor.h
@@ -1,3 +1,4 @@
+
 #ifndef PROTON_REACTOR_H
 #define PROTON_REACTOR_H 1
 
@@ -24,6 +25,7 @@
 
 #include <proton/import_export.h>
 #include <proton/type_compat.h>
+#include <proton/error.h>
 #include <proton/event.h>
 #include <proton/selectable.h>
 #include <proton/ssl.h>
@@ -46,35 +48,34 @@ typedef struct pn_acceptor_t pn_acceptor_t;
 typedef struct pn_timer_t pn_timer_t;
 typedef struct pn_task_t pn_task_t;
 
-PN_EXTERN pn_handler_t *pn_handler(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t));
-PN_EXTERN pn_handler_t *pn_handler_new(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t), size_t size,
+PNX_EXTERN pn_handler_t *pn_handler(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t));
+PNX_EXTERN pn_handler_t *pn_handler_new(void (*dispatch)(pn_handler_t *, pn_event_t *, pn_event_type_t), size_t size,
                                        void (*finalize)(pn_handler_t *));
-PN_EXTERN void pn_handler_free(pn_handler_t *handler);
-PN_EXTERN void *pn_handler_mem(pn_handler_t *handler);
-PN_EXTERN void pn_handler_add(pn_handler_t *handler, pn_handler_t *child);
-PN_EXTERN void pn_handler_clear(pn_handler_t *handler);
-PN_EXTERN void pn_handler_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type);
-
-PN_EXTERN pn_reactor_t *pn_reactor(void);
-PN_EXTERN pn_record_t *pn_reactor_attachments(pn_reactor_t *reactor);
-PN_EXTERN pn_millis_t pn_reactor_get_timeout(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_set_timeout(pn_reactor_t *reactor, pn_millis_t timeout);
-PN_EXTERN pn_timestamp_t pn_reactor_mark(pn_reactor_t *reactor);
-PN_EXTERN pn_timestamp_t pn_reactor_now(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_yield(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_free(pn_reactor_t *reactor);
-PN_EXTERN pn_collector_t *pn_reactor_collector(pn_reactor_t *reactor);
-PN_EXTERN pn_handler_t *pn_reactor_get_global_handler(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_set_global_handler(pn_reactor_t *reactor, pn_handler_t *handler);
-PN_EXTERN pn_handler_t *pn_reactor_get_handler(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_set_handler(pn_reactor_t *reactor, pn_handler_t *handler);
-PN_EXTERN pn_io_t *pn_reactor_io(pn_reactor_t *reactor);
-PN_EXTERN pn_list_t *pn_reactor_children(pn_reactor_t *reactor);
-PN_EXTERN pn_selectable_t *pn_reactor_selectable(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_update(pn_reactor_t *reactor, pn_selectable_t *selectable);
-PN_EXTERN pn_acceptor_t *pn_reactor_acceptor(pn_reactor_t *reactor, const char *host, const char *port,
+PNX_EXTERN void pn_handler_free(pn_handler_t *handler);
+PNX_EXTERN void *pn_handler_mem(pn_handler_t *handler);
+PNX_EXTERN void pn_handler_add(pn_handler_t *handler, pn_handler_t *child);
+PNX_EXTERN void pn_handler_clear(pn_handler_t *handler);
+PNX_EXTERN void pn_handler_dispatch(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type);
+
+PNX_EXTERN pn_reactor_t *pn_reactor(void);
+PNX_EXTERN pn_record_t *pn_reactor_attachments(pn_reactor_t *reactor);
+PNX_EXTERN pn_millis_t pn_reactor_get_timeout(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_set_timeout(pn_reactor_t *reactor, pn_millis_t timeout);
+PNX_EXTERN pn_timestamp_t pn_reactor_mark(pn_reactor_t *reactor);
+PNX_EXTERN pn_timestamp_t pn_reactor_now(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_yield(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_free(pn_reactor_t *reactor);
+PNX_EXTERN pn_collector_t *pn_reactor_collector(pn_reactor_t *reactor);
+PNX_EXTERN pn_handler_t *pn_reactor_get_global_handler(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_set_global_handler(pn_reactor_t *reactor, pn_handler_t *handler);
+PNX_EXTERN pn_handler_t *pn_reactor_get_handler(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_set_handler(pn_reactor_t *reactor, pn_handler_t *handler);
+PNX_EXTERN pn_list_t *pn_reactor_children(pn_reactor_t *reactor);
+PNX_EXTERN pn_selectable_t *pn_reactor_selectable(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_update(pn_reactor_t *reactor, pn_selectable_t *selectable);
+PNX_EXTERN pn_acceptor_t *pn_reactor_acceptor(pn_reactor_t *reactor, const char *host, const char *port,
                                              pn_handler_t *handler);
-PN_EXTERN pn_error_t *pn_reactor_error(pn_reactor_t *reactor);
+PNX_EXTERN pn_error_t *pn_reactor_error(pn_reactor_t *reactor);
 
 /**
  * Create an outgoing connection that will be managed by the reactor.
@@ -89,7 +90,7 @@ PN_EXTERN pn_error_t *pn_reactor_error(pn_reactor_t *reactor);
  * this connection.
  * @return a connection object
  */
-PN_EXTERN pn_connection_t *pn_reactor_connection_to_host(pn_reactor_t *reactor,
+PNX_EXTERN pn_connection_t *pn_reactor_connection_to_host(pn_reactor_t *reactor,
                                                          const char *host,
                                                          const char *port,
                                                          pn_handler_t *handler);
@@ -108,7 +109,7 @@ PN_EXTERN pn_connection_t *pn_reactor_connection_to_host(pn_reactor_t *reactor,
  * @return a connection object
  * @deprecated Use ::pn_reactor_connection_to_host() instead.
  */
-PN_EXTERN pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor,
+PNX_EXTERN pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor,
                                                  pn_handler_t *handler);
 
 /**
@@ -122,7 +123,7 @@ PN_EXTERN pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor,
  * @param[in] host the network address or DNS name of the host to connect to.
  * @param[in] port the network port to use. Optional - default is "5672"
  */
-PN_EXTERN void pn_reactor_set_connection_host(pn_reactor_t *reactor,
+PNX_EXTERN void pn_reactor_set_connection_host(pn_reactor_t *reactor,
                                               pn_connection_t *connection,
                                               const char *host,
                                               const char *port);
@@ -145,37 +146,42 @@ PN_EXTERN void pn_reactor_set_connection_host(pn_reactor_t *reactor,
  * address available.  ::pn_url_parse() may be used to create a Proton pn_url_t
  * instance from the returned value.
  */
-PN_EXTERN const char *pn_reactor_get_connection_address(pn_reactor_t *reactor,
+PNX_EXTERN const char *pn_reactor_get_connection_address(pn_reactor_t *reactor,
                                                         pn_connection_t *connection);
 
-PN_EXTERN int pn_reactor_wakeup(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_start(pn_reactor_t *reactor);
-PN_EXTERN bool pn_reactor_quiesced(pn_reactor_t *reactor);
-PN_EXTERN bool pn_reactor_process(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_stop(pn_reactor_t *reactor);
-PN_EXTERN void pn_reactor_run(pn_reactor_t *reactor);
-PN_EXTERN pn_task_t *pn_reactor_schedule(pn_reactor_t *reactor, int delay, pn_handler_t *handler);
+PNX_EXTERN int pn_reactor_wakeup(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_start(pn_reactor_t *reactor);
+PNX_EXTERN bool pn_reactor_quiesced(pn_reactor_t *reactor);
+PNX_EXTERN bool pn_reactor_process(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_stop(pn_reactor_t *reactor);
+PNX_EXTERN void pn_reactor_run(pn_reactor_t *reactor);
+PNX_EXTERN pn_task_t *pn_reactor_schedule(pn_reactor_t *reactor, int delay, pn_handler_t *handler);
+
 
+PNX_EXTERN void pn_acceptor_set_ssl_domain(pn_acceptor_t *acceptor, pn_ssl_domain_t *domain);
+PNX_EXTERN void pn_acceptor_close(pn_acceptor_t *acceptor);
+PNX_EXTERN pn_acceptor_t *pn_connection_acceptor(pn_connection_t *connection);
 
-PN_EXTERN void pn_acceptor_set_ssl_domain(pn_acceptor_t *acceptor, pn_ssl_domain_t *domain);
-PN_EXTERN void pn_acceptor_close(pn_acceptor_t *acceptor);
-PN_EXTERN pn_acceptor_t *pn_connection_acceptor(pn_connection_t *connection);
+PNX_EXTERN pn_timer_t *pn_timer(pn_collector_t *collector);
+PNX_EXTERN pn_timestamp_t pn_timer_deadline(pn_timer_t *timer);
+PNX_EXTERN void pn_timer_tick(pn_timer_t *timer, pn_timestamp_t now);
+PNX_EXTERN pn_task_t *pn_timer_schedule(pn_timer_t *timer, pn_timestamp_t deadline);
+PNX_EXTERN int pn_timer_tasks(pn_timer_t *timer);
 
-PN_EXTERN pn_timer_t *pn_timer(pn_collector_t *collector);
-PN_EXTERN pn_timestamp_t pn_timer_deadline(pn_timer_t *timer);
-PN_EXTERN void pn_timer_tick(pn_timer_t *timer, pn_timestamp_t now);
-PN_EXTERN pn_task_t *pn_timer_schedule(pn_timer_t *timer, pn_timestamp_t deadline);
-PN_EXTERN int pn_timer_tasks(pn_timer_t *timer);
+PNX_EXTERN pn_record_t *pn_task_attachments(pn_task_t *task);
+PNX_EXTERN void pn_task_cancel(pn_task_t *task);
 
-PN_EXTERN pn_record_t *pn_task_attachments(pn_task_t *task);
-PN_EXTERN void pn_task_cancel(pn_task_t *task);
+PNX_EXTERN pn_reactor_t *pn_class_reactor(const pn_class_t *clazz, void *object);
+PNX_EXTERN pn_reactor_t *pn_object_reactor(void *object);
+PNX_EXTERN pn_reactor_t *pn_event_reactor(pn_event_t *event);
 
-PN_EXTERN pn_reactor_t *pn_class_reactor(const pn_class_t *clazz, void *object);
-PN_EXTERN pn_reactor_t *pn_object_reactor(void *object);
-PN_EXTERN pn_reactor_t *pn_event_reactor(pn_event_t *event);
+PNX_EXTERN pn_handler_t *pn_record_get_handler(pn_record_t *record);
+PNX_EXTERN void pn_record_set_handler(pn_record_t *record, pn_handler_t *handler);
 
-PN_EXTERN pn_handler_t *pn_record_get_handler(pn_record_t *record);
-PN_EXTERN void pn_record_set_handler(pn_record_t *record, pn_handler_t *handler);
+/**
+ * Get the root handler the current event was dispatched to.
+ */
+PNX_EXTERN pn_handler_t *pn_event_root(pn_event_t *event);
 
 /** @}
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/scanner.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/scanner.h b/proton-c/include/proton/scanner.h
deleted file mode 100644
index 10d7d32..0000000
--- a/proton-c/include/proton/scanner.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef PROTON_SCANNER_H
-#define PROTON_SCANNER_H 1
-
-/*
- *
- * 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/import_export.h>
-#include <stddef.h>
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-  PN_TOK_LBRACE,
-  PN_TOK_RBRACE,
-  PN_TOK_LBRACKET,
-  PN_TOK_RBRACKET,
-  PN_TOK_EQUAL,
-  PN_TOK_COMMA,
-  PN_TOK_POS,
-  PN_TOK_NEG,
-  PN_TOK_DOT,
-  PN_TOK_AT,
-  PN_TOK_DOLLAR,
-  PN_TOK_BINARY,
-  PN_TOK_STRING,
-  PN_TOK_SYMBOL,
-  PN_TOK_ID,
-  PN_TOK_FLOAT,
-  PN_TOK_INT,
-  PN_TOK_TRUE,
-  PN_TOK_FALSE,
-  PN_TOK_NULL,
-  PN_TOK_EOS,
-  PN_TOK_ERR
-} pn_token_type_t;
-
-typedef struct pn_scanner_t pn_scanner_t;
-
-typedef struct {
-  pn_token_type_t type;
-  const char *start;
-  size_t size;
-} pn_token_t;
-
-PN_EXTERN pn_scanner_t *pn_scanner(void);
-PN_EXTERN void pn_scanner_free(pn_scanner_t *scanner);
-PN_EXTERN pn_token_t pn_scanner_token(pn_scanner_t *scanner);
-PN_EXTERN int pn_scanner_err(pn_scanner_t *scanner, int code, const char *fmt, ...);
-PN_EXTERN int pn_scanner_verr(pn_scanner_t *scanner, int code, const char *fmt, va_list ap);
-PN_EXTERN void pn_scanner_line_info(pn_scanner_t *scanner, int *line, int *col);
-PN_EXTERN int pn_scanner_errno(pn_scanner_t *scanner);
-PN_EXTERN const char *pn_scanner_error(pn_scanner_t *scanner);
-PN_EXTERN int pn_scanner_start(pn_scanner_t *scanner, const char *input);
-PN_EXTERN int pn_scanner_scan(pn_scanner_t *scanner);
-PN_EXTERN int pn_scanner_shift(pn_scanner_t *scanner);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* scanner.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selectable.h b/proton-c/include/proton/selectable.h
index 7b0fa02..fbf3823 100644
--- a/proton-c/include/proton/selectable.h
+++ b/proton-c/include/proton/selectable.h
@@ -25,7 +25,6 @@
 #include <proton/import_export.h>
 #include <proton/object.h>
 #include <proton/event.h>
-#include <proton/io.h>
 #include <proton/type_compat.h>
 
 #ifdef __cplusplus
@@ -48,6 +47,34 @@ extern "C" {
 typedef pn_iterator_t pn_selectables_t;
 
 /**
+ * A ::pn_socket_t provides an abstract handle to an IO stream.  The
+ * pipe version is uni-directional.  The network socket version is
+ * bi-directional.  Both are non-blocking.
+ *
+ * pn_socket_t handles from ::pn_pipe() may only be used with
+ * ::pn_read(), ::pn_write(), ::pn_close() and pn_selector_select().
+ *
+ * pn_socket_t handles from ::pn_listen(), ::pn_accept() and
+ * ::pn_connect() must perform further IO using Proton functions.
+ * Mixing Proton io.h functions with native IO functions on the same
+ * handles will result in undefined behavior.
+ *
+ * pn_socket_t handles may only be used with a single pn_io_t during
+ * their lifetime.
+ */
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+#ifdef _WIN64
+typedef unsigned __int64 pn_socket_t;
+#else
+typedef unsigned int pn_socket_t;
+#endif
+#define PN_INVALID_SOCKET (pn_socket_t)(~0)
+#else
+typedef int pn_socket_t;
+#define PN_INVALID_SOCKET (-1)
+#endif
+
+/**
  * A selectable object provides an interface that can be used to
  * incorporate proton's I/O into third party event loops.
  *
@@ -72,7 +99,7 @@ typedef struct pn_selectable_t pn_selectable_t;
  *
  * @return a pointer to a new selectables iterator
  */
-PN_EXTERN pn_selectables_t *pn_selectables(void);
+PNX_EXTERN pn_selectables_t *pn_selectables(void);
 
 /**
  * Get the next selectable from an iterator.
@@ -80,25 +107,25 @@ PN_EXTERN pn_selectables_t *pn_selectables(void);
  * @param[in] selectables a selectable iterator
  * @return the next selectable from the iterator
  */
-PN_EXTERN pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables);
+PNX_EXTERN pn_selectable_t *pn_selectables_next(pn_selectables_t *selectables);
 
 /**
  * Free a selectables iterator.
  *
  * @param[in] selectables a selectables iterator (or NULL)
  */
-PN_EXTERN void pn_selectables_free(pn_selectables_t *selectables);
+PNX_EXTERN void pn_selectables_free(pn_selectables_t *selectables);
 
-PN_EXTERN pn_selectable_t *pn_selectable(void);
+PNX_EXTERN pn_selectable_t *pn_selectable(void);
 
-PN_EXTERN void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *));
-PN_EXTERN void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_readable(pn_selectable_t *sel, void (*readable)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_writable(pn_selectable_t *sel, void (*writable)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_expired(pn_selectable_t *sel, void (*expired)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_error(pn_selectable_t *sel, void (*error)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_release(pn_selectable_t *sel, void (*release)(pn_selectable_t *));
+PNX_EXTERN void pn_selectable_on_finalize(pn_selectable_t *sel, void (*finalize)(pn_selectable_t *));
 
-PN_EXTERN pn_record_t *pn_selectable_attachments(pn_selectable_t *sel);
+PNX_EXTERN pn_record_t *pn_selectable_attachments(pn_selectable_t *sel);
 
 /**
  * Get the file descriptor associated with a selectable.
@@ -106,7 +133,7 @@ PN_EXTERN pn_record_t *pn_selectable_attachments(pn_selectable_t *sel);
  * @param[in] selectable a selectable object
  * @return the file descriptor associated with the selectable
  */
-PN_EXTERN pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable);
+PNX_EXTERN pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable);
 
 /**
  * Set the file descriptor associated with a selectable.
@@ -114,7 +141,7 @@ PN_EXTERN pn_socket_t pn_selectable_get_fd(pn_selectable_t *selectable);
  * @param[in] selectable a selectable object
  * @param[in] fd the file descriptor
  */
-PN_EXTERN void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd);
+PNX_EXTERN void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd);
 
 /**
  * Check if a selectable is interested in readable events.
@@ -122,9 +149,9 @@ PN_EXTERN void pn_selectable_set_fd(pn_selectable_t *selectable, pn_socket_t fd)
  * @param[in] selectable a selectable object
  * @return true iff the selectable is interested in read events
  */
-PN_EXTERN bool pn_selectable_is_reading(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_reading(pn_selectable_t *selectable);
 
-PN_EXTERN void pn_selectable_set_reading(pn_selectable_t *sel, bool reading);
+PNX_EXTERN void pn_selectable_set_reading(pn_selectable_t *sel, bool reading);
 
 /**
  * Check if a selectable is interested in writable events.
@@ -132,9 +159,9 @@ PN_EXTERN void pn_selectable_set_reading(pn_selectable_t *sel, bool reading);
  * @param[in] selectable a selectable object
  * @return true iff the selectable is interested in writable events
  */
-PN_EXTERN bool pn_selectable_is_writing(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_writing(pn_selectable_t *selectable);
 
-  PN_EXTERN void pn_selectable_set_writing(pn_selectable_t *sel, bool writing);
+  PNX_EXTERN void pn_selectable_set_writing(pn_selectable_t *sel, bool writing);
 
 /**
  * Get the next deadline for a selectable.
@@ -146,37 +173,37 @@ PN_EXTERN bool pn_selectable_is_writing(pn_selectable_t *selectable);
  * @param[in] selectable a selectable object
  * @return the next deadline or zero
  */
-PN_EXTERN pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *selectable);
+PNX_EXTERN pn_timestamp_t pn_selectable_get_deadline(pn_selectable_t *selectable);
 
-PN_EXTERN void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline);
+PNX_EXTERN void pn_selectable_set_deadline(pn_selectable_t *sel, pn_timestamp_t deadline);
 
 /**
  * Notify a selectable that the file descriptor is readable.
  *
  * @param[in] selectable a selectable object
  */
-PN_EXTERN void pn_selectable_readable(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_readable(pn_selectable_t *selectable);
 
 /**
  * Notify a selectable that the file descriptor is writable.
  *
  * @param[in] selectable a selectable object
  */
-PN_EXTERN void pn_selectable_writable(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_writable(pn_selectable_t *selectable);
 
 /**
  * Notify a selectable that there is an error on the file descriptor.
  *
  * @param[in] selectable a selectable object
  */
-PN_EXTERN void pn_selectable_error(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_error(pn_selectable_t *selectable);
 
 /**
  * Notify a selectable that its deadline has expired.
  *
  * @param[in] selectable a selectable object
  */
-PN_EXTERN void pn_selectable_expired(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_expired(pn_selectable_t *selectable);
 
 /**
  * Check if a selectable is registered.
@@ -188,7 +215,7 @@ PN_EXTERN void pn_selectable_expired(pn_selectable_t *selectable);
  * @param[in] selectable
  * @return true if the selectable is registered
  */
-PN_EXTERN bool pn_selectable_is_registered(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_registered(pn_selectable_t *selectable);
 
 /**
  * Set the registered flag for a selectable.
@@ -198,7 +225,7 @@ PN_EXTERN bool pn_selectable_is_registered(pn_selectable_t *selectable);
  * @param[in] selectable a selectable object
  * @param[in] registered the registered flag
  */
-PN_EXTERN void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered);
+PNX_EXTERN void pn_selectable_set_registered(pn_selectable_t *selectable, bool registered);
 
 /**
  * Check if a selectable is in the terminal state.
@@ -212,23 +239,23 @@ PN_EXTERN void pn_selectable_set_registered(pn_selectable_t *selectable, bool re
  * @param[in] selectable a selectable object
  * @return true if the selectable is in the terminal state, false otherwise
  */
-PN_EXTERN bool pn_selectable_is_terminal(pn_selectable_t *selectable);
+PNX_EXTERN bool pn_selectable_is_terminal(pn_selectable_t *selectable);
 
 /**
  * Terminate a selectable.
  *
  * @param[in] selectable a selectable object
  */
-PN_EXTERN void pn_selectable_terminate(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_terminate(pn_selectable_t *selectable);
 
-PN_EXTERN void pn_selectable_release(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_release(pn_selectable_t *selectable);
 
 /**
  * Free a selectable object.
  *
  * @param[in] selectable a selectable object (or NULL)
  */
-PN_EXTERN void pn_selectable_free(pn_selectable_t *selectable);
+PNX_EXTERN void pn_selectable_free(pn_selectable_t *selectable);
 
 /**
  * Configure a selectable with a set of callbacks that emit readable,
@@ -237,7 +264,7 @@ PN_EXTERN void pn_selectable_free(pn_selectable_t *selectable);
  * @param[in] selectable a selectable objet
  * @param[in] collector a collector object
  */
-PN_EXTERN void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector);
+PNX_EXTERN void pn_selectable_collect(pn_selectable_t *selectable, pn_collector_t *collector);
 
 /**
  * @}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/selector.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selector.h b/proton-c/include/proton/selector.h
deleted file mode 100644
index c942393..0000000
--- a/proton-c/include/proton/selector.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef PROTON_SELECTOR_H
-#define PROTON_SELECTOR_H 1
-
-/*
- *
- * 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/import_export.h>
-#include <proton/selectable.h>
-#include <proton/type_compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PN_READABLE (1)
-#define PN_WRITABLE (2)
-#define PN_EXPIRED (4)
-#define PN_ERROR (8)
-
-pn_selector_t *pni_selector(void);
-PN_EXTERN void pn_selector_free(pn_selector_t *selector);
-PN_EXTERN void pn_selector_add(pn_selector_t *selector, pn_selectable_t *selectable);
-PN_EXTERN void pn_selector_update(pn_selector_t *selector, pn_selectable_t *selectable);
-PN_EXTERN void pn_selector_remove(pn_selector_t *selector, pn_selectable_t *selectable);
-PN_EXTERN size_t pn_selector_size(pn_selector_t *selector);
-PN_EXTERN int pn_selector_select(pn_selector_t *select, int timeout);
-PN_EXTERN pn_selectable_t *pn_selector_next(pn_selector_t *select, int *events);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* selector.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index 72db6f8..176af47 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -50,10 +50,6 @@ typedef uint32_t pn_seconds_t;
 
 typedef int64_t  pn_timestamp_t;
 
-/** Return a timestamp for the time now. */
-PN_EXTERN pn_timestamp_t pn_timestamp_now(void);
-
-
 typedef uint32_t pn_char_t;
 typedef uint32_t pn_decimal32_t;
 typedef uint64_t pn_decimal64_t;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/include/proton/url.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/url.h b/proton-c/include/proton/url.h
index 80634c1..2a68bc2 100644
--- a/proton-c/include/proton/url.h
+++ b/proton-c/include/proton/url.h
@@ -37,7 +37,7 @@ extern "C" {
 typedef struct pn_url_t pn_url_t;
 
 /** Create an empty URL */
-PN_EXTERN pn_url_t *pn_url(void);
+PNX_EXTERN pn_url_t *pn_url(void);
 
 /** Parse a string URL as a pn_url_t.
  *
@@ -56,13 +56,13 @@ PN_EXTERN pn_url_t *pn_url(void);
  *@param[in] url A URL string.
  *@return The parsed pn_url_t or NULL if url is not a valid URL string.
  */
-PN_EXTERN pn_url_t *pn_url_parse(const char *url);
+PNX_EXTERN pn_url_t *pn_url_parse(const char *url);
 
 /** Free a URL */
-PN_EXTERN void pn_url_free(pn_url_t *url);
+PNX_EXTERN void pn_url_free(pn_url_t *url);
 
 /** Clear the contents of the URL. */
-PN_EXTERN void pn_url_clear(pn_url_t *url);
+PNX_EXTERN void pn_url_clear(pn_url_t *url);
 
 /**
  * Return the string form of a URL.
@@ -70,7 +70,7 @@ PN_EXTERN void pn_url_clear(pn_url_t *url);
  *  The returned string is owned by the pn_url_t and will become invalid if it
  *  is modified.
  */
-PN_EXTERN const char *pn_url_str(pn_url_t *url);
+PNX_EXTERN const char *pn_url_str(pn_url_t *url);
 
 /**
  *@name Getters for parts of the URL.
@@ -79,12 +79,12 @@ PN_EXTERN const char *pn_url_str(pn_url_t *url);
  *
  *@{
  */
-PN_EXTERN const char *pn_url_get_scheme(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_username(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_password(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_host(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_port(pn_url_t *url);
-PN_EXTERN const char *pn_url_get_path(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_scheme(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_username(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_password(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_host(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_port(pn_url_t *url);
+PNX_EXTERN const char *pn_url_get_path(pn_url_t *url);
 ///@}
 
 /**
@@ -94,12 +94,12 @@ PN_EXTERN const char *pn_url_get_path(pn_url_t *url);
  *
  *@{
  */
-PN_EXTERN void pn_url_set_scheme(pn_url_t *url, const char *scheme);
-PN_EXTERN void pn_url_set_username(pn_url_t *url, const char *username);
-PN_EXTERN void pn_url_set_password(pn_url_t *url, const char *password);
-PN_EXTERN void pn_url_set_host(pn_url_t *url, const char *host);
-PN_EXTERN void pn_url_set_port(pn_url_t *url, const char *port);
-PN_EXTERN void pn_url_set_path(pn_url_t *url, const char *path);
+PNX_EXTERN void pn_url_set_scheme(pn_url_t *url, const char *scheme);
+PNX_EXTERN void pn_url_set_username(pn_url_t *url, const char *username);
+PNX_EXTERN void pn_url_set_password(pn_url_t *url, const char *password);
+PNX_EXTERN void pn_url_set_host(pn_url_t *url, const char *host);
+PNX_EXTERN void pn_url_set_port(pn_url_t *url, const char *port);
+PNX_EXTERN void pn_url_set_path(pn_url_t *url, const char *path);
 ///@}
 
 ///@}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ProtonConfig.cmake.in
----------------------------------------------------------------------
diff --git a/proton-c/src/ProtonConfig.cmake.in b/proton-c/src/ProtonConfig.cmake.in
index fce1a3a..5e50d7c 100644
--- a/proton-c/src/ProtonConfig.cmake.in
+++ b/proton-c/src/ProtonConfig.cmake.in
@@ -27,4 +27,7 @@ set (Proton_VERSION       @PN_VERSION@)
 set (Proton_INCLUDE_DIRS  @INCLUDEDIR@)
 set (Proton_LIBRARIES     optimized @LIBDIR@/@PROTONLIB@ debug @LIBDIR@/@PROTONLIBDEBUG@)
 
+set (ProtonCore_INCLUDE_DIRS  @INCLUDEDIR@)
+set (ProtonCore_LIBRARIES     optimized @LIBDIR@/@PROTONCORELIB@ debug @LIBDIR@/@PROTONCORELIBDEBUG@)
+
 set (Proton_FOUND True)


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


[05/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ssl/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/schannel.c b/proton-c/src/ssl/schannel.c
new file mode 100644
index 0000000..420e7c5
--- /dev/null
+++ b/proton-c/src/ssl/schannel.c
@@ -0,0 +1,2239 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/*
+ * SChannel is designed to encrypt and decrypt data in place.  So a
+ * given buffer is expected to sometimes contain encrypted data,
+ * sometimes decrypted data, and occasionally both.  Outgoing buffers
+ * need to reserve space for the TLS header and trailer.  Read
+ * operations need to ignore the same headers and trailers from
+ * incoming buffers.  Outgoing is simple because we choose record
+ * boundaries.  Incoming is complicated by handling incomplete TLS
+ * records, and buffering contiguous data for the app layer that may
+ * span many records.  A lazy double buffering system is used for
+ * the latter.
+ */
+
+#include <proton/ssl.h>
+#include <proton/engine.h>
+#include "core/engine-internal.h"
+#include "platform/platform.h"
+#include "core/util.h"
+#include "core/autodetect.h"
+
+#include <assert.h>
+
+// security.h needs to see this to distinguish from kernel use.
+#include <windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <Schnlsp.h>
+#include <WinInet.h>
+#undef SECURITY_WIN32
+
+
+/** @file
+ * SSL/TLS support API.
+ *
+ * This file contains an SChannel-based implemention of the SSL/TLS API for Windows platforms.
+ */
+
+static void ssl_log_error(const char *fmt, ...);
+static void ssl_log(pn_transport_t *transport, const char *fmt, ...);
+static void ssl_log_error_status(HRESULT status, const char *fmt, ...);
+static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error);
+
+/*
+ * win_credential_t: SChannel context that must accompany TLS connections.
+ *
+ * SChannel attempts session resumption for shared CredHandle objects.
+ * To mimic openssl behavior, server CredHandle handles must be shared
+ * by derived connections, client CredHandle handles must be unique
+ * when app's session_id is null and tracked for reuse otherwise
+ * (TODO).
+ *
+ * Ref counted by parent ssl_domain_t and each derived connection.
+ */
+struct win_credential_t {
+  pn_ssl_mode_t mode;
+  PCCERT_CONTEXT cert_context;  // Particulars of the certificate (if any)
+  CredHandle cred_handle;       // Bound session parameters, certificate, CAs, verification_mode
+  HCERTSTORE trust_store;       // Store of root CAs for validating
+  HCERTSTORE server_CA_certs;   // CAs advertised by server (may be a duplicate of the trust_store)
+  char *trust_store_name;
+};
+
+#define win_credential_compare NULL
+#define win_credential_inspect NULL
+#define win_credential_hashcode NULL
+
+static void win_credential_initialize(void *object)
+{
+  win_credential_t *c = (win_credential_t *) object;
+  SecInvalidateHandle(&c->cred_handle);
+  c->cert_context = 0;
+  c->trust_store = 0;
+  c->server_CA_certs = 0;
+  c->trust_store_name = 0;
+}
+
+static void win_credential_finalize(void *object)
+{
+  win_credential_t *c = (win_credential_t *) object;
+  if (SecIsValidHandle(&c->cred_handle))
+    FreeCredentialsHandle(&c->cred_handle);
+  if (c->cert_context)
+    CertFreeCertificateContext(c->cert_context);
+  if (c->trust_store)
+    CertCloseStore(c->trust_store, 0);
+  if (c->server_CA_certs)
+    CertCloseStore(c->server_CA_certs, 0);
+  free(c->trust_store_name);
+}
+
+static win_credential_t *win_credential(pn_ssl_mode_t m)
+{
+  static const pn_cid_t CID_win_credential = CID_pn_void;
+  static const pn_class_t clazz = PN_CLASS(win_credential);
+  win_credential_t *c = (win_credential_t *) pn_class_new(&clazz, sizeof(win_credential_t));
+  c->mode = m;
+  return c;
+}
+
+static int win_credential_load_cert(win_credential_t *cred, const char *store_name, const char *cert_name, const char *passwd)
+{
+  if (!store_name)
+    return -2;
+
+  int ec = 0;
+  HCERTSTORE cert_store = open_cert_db(store_name, passwd, &ec);
+  if (!cert_store)
+    return ec;
+
+  // find friendly name that matches cert_name, or sole certificate
+  PCCERT_CONTEXT tmpctx = NULL;
+  PCCERT_CONTEXT found_ctx = NULL;
+  int cert_count = 0;
+  int name_len = cert_name ? strlen(cert_name) : 0;
+  char *fn = name_len ? (char *) malloc(name_len + 1) : 0;
+  while (tmpctx = CertEnumCertificatesInStore(cert_store, tmpctx)) {
+    cert_count++;
+    if (cert_name) {
+      DWORD len = CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
+                                    0, NULL, NULL, 0);
+      if (len != name_len + 1)
+        continue;
+      CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
+                        0, NULL, fn, len);
+      if (!strcmp(cert_name, fn)) {
+        found_ctx = tmpctx;
+        tmpctx= NULL;
+        break;
+      }
+    } else {
+      // Test for single certificate
+      if (cert_count == 1) {
+        found_ctx = CertDuplicateCertificateContext(tmpctx);
+      } else {
+        ssl_log_error("Multiple certificates to choose from certificate store %s\n", store_name);
+        found_ctx = NULL;
+        break;
+      }
+    }
+  }
+
+  if (tmpctx) {
+    CertFreeCertificateContext(tmpctx);
+    tmpctx = false;
+  }
+  if (!found_ctx && cert_name && cert_count == 1)
+    ssl_log_error("Could not find certificate %s in store %s\n", cert_name, store_name);
+  cred->cert_context = found_ctx;
+
+  free(fn);
+  CertCloseStore(cert_store, 0);
+  return found_ctx ? 0 : -8;
+}
+
+
+static CredHandle win_credential_cred_handle(win_credential_t *cred, pn_ssl_verify_mode_t verify_mode,
+                                             const char *session_id, SECURITY_STATUS *status)
+{
+  if (cred->mode == PN_SSL_MODE_SERVER && SecIsValidHandle(&cred->cred_handle)) {
+    *status = SEC_E_OK;
+    return cred->cred_handle;  // Server always reuses cached value
+  }
+  // TODO: if (is_client && session_id != NULL) create or use cached value based on
+  // session_id+server_host_name (per domain? reclaimed after X hours?)
+
+  CredHandle tmp_handle;
+  SecInvalidateHandle(&tmp_handle);
+  TimeStamp expiry;  // Not used
+  SCHANNEL_CRED descriptor;
+  memset(&descriptor, 0, sizeof(descriptor));
+
+  descriptor.dwVersion = SCHANNEL_CRED_VERSION;
+  descriptor.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
+  if (cred->cert_context != NULL) {
+    // assign the certificate into the credentials
+    descriptor.paCred = &cred->cert_context;
+    descriptor.cCreds = 1;
+  }
+
+  if (cred->mode == PN_SSL_MODE_SERVER) {
+    descriptor.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
+    if (cred->server_CA_certs) {
+      descriptor.hRootStore = cred->server_CA_certs;
+    }
+  }
+
+  ULONG direction = (cred->mode == PN_SSL_MODE_SERVER) ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND;
+  *status = AcquireCredentialsHandle(NULL, UNISP_NAME, direction, NULL,
+                                               &descriptor, NULL, NULL, &tmp_handle, &expiry);
+  if (cred->mode == PN_SSL_MODE_SERVER && *status == SEC_E_OK)
+    cred->cred_handle = tmp_handle;
+
+  return tmp_handle;
+}
+
+static bool win_credential_has_certificate(win_credential_t *cred)
+{
+  if (!cred) return false;
+  return (cred->cert_context != NULL);
+}
+
+#define SSL_DATA_SIZE 16384
+#define SSL_BUF_SIZE (SSL_DATA_SIZE + 5 + 2048 + 32)
+
+typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
+typedef struct pn_ssl_session_t pn_ssl_session_t;
+
+struct pn_ssl_domain_t {
+  int ref_count;
+  pn_ssl_mode_t mode;
+  bool has_ca_db;       // true when CA database configured
+  pn_ssl_verify_mode_t verify_mode;
+  bool allow_unsecured;
+  win_credential_t *cred;
+};
+
+typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
+               RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;
+
+struct pni_ssl_t {
+  pn_ssl_domain_t  *domain;
+  const char    *session_id;
+  const char *peer_hostname;
+  ssl_state_t state;
+
+  bool protocol_detected;
+  bool queued_shutdown;
+  bool ssl_closed;            // shutdown complete, or SSL error
+  ssize_t app_input_closed;   // error code returned by upper layer process input
+  ssize_t app_output_closed;  // error code returned by upper layer process output
+
+  // OpenSSL hides the protocol envelope bytes, SChannel has them in-line.
+  char *sc_outbuf;     // SChannel output buffer
+  size_t sc_out_size;
+  size_t sc_out_count;
+  char *network_outp;   // network ready bytes within sc_outbuf
+  size_t network_out_pending;
+
+  char *sc_inbuf;      // SChannel input buffer
+  size_t sc_in_size;
+  size_t sc_in_count;
+  bool sc_in_incomplete;
+
+  char *inbuf_extra;    // Still encrypted data from following Record(s)
+  size_t extra_count;
+
+  char *in_data;          // Just the plaintext data part of sc_inbuf, decrypted in place
+  size_t in_data_size;
+  size_t in_data_count;
+  bool decrypting;
+  size_t max_data_size;  // computed in the handshake
+
+  pn_bytes_t app_inbytes; // Virtual decrypted datastream, presented to app layer
+
+  pn_buffer_t *inbuf2;    // Second input buf if longer contiguous bytes needed
+  bool double_buffered;
+
+  bool sc_input_shutdown;
+
+  CredHandle cred_handle;
+  CtxtHandle ctxt_handle;
+  SecPkgContext_StreamSizes sc_sizes;
+  pn_ssl_verify_mode_t verify_mode;
+  win_credential_t *cred;
+  char *subject;
+};
+
+static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl)
+{
+  // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+  return ((pn_transport_t *)ssl);
+}
+
+static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl)
+{
+  // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+  return ssl ? ((pn_transport_t *)ssl)->ssl : NULL;
+}
+
+struct pn_ssl_session_t {
+  const char       *id;
+// TODO
+  pn_ssl_session_t *ssn_cache_next;
+  pn_ssl_session_t *ssn_cache_prev;
+};
+
+
+static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
+static void ssl_session_free( pn_ssl_session_t *);
+static size_t buffered_output( pn_transport_t *transport );
+static void start_ssl_shutdown(pn_transport_t *transport);
+static void rewind_sc_inbuf(pni_ssl_t *ssl);
+static bool grow_inbuf2(pn_transport_t *ssl, size_t minimum_size);
+static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing);
+
+// @todo: used to avoid littering the code with calls to printf...
+static void ssl_log_error(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fflush(stderr);
+}
+
+// @todo: used to avoid littering the code with calls to printf...
+static void ssl_log(pn_transport_t *transport, const char *fmt, ...)
+{
+  if (PN_TRACE_DRV & transport->trace) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fflush(stderr);
+  }
+}
+
+static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
+{
+  char buf[512];
+  va_list ap;
+
+  if (fmt) {
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+  }
+
+  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+                    0, status, 0, buf, sizeof(buf), 0))
+    ssl_log_error(" : %s\n", buf);
+  else
+    fprintf(stderr, "pn internal Windows error: %x for %x\n", GetLastError(), status);
+
+  fflush(stderr);
+}
+
+static void ssl_log_clear_data(pn_transport_t *transport, const char *data, size_t len)
+{
+  if (PN_TRACE_RAW & transport->trace) {
+    fprintf(stderr, "SSL decrypted data: \"");
+    pn_fprint_data( stderr, data, len );
+    fprintf(stderr, "\"\n");
+  }
+}
+
+static size_t _pni_min(size_t a, size_t b)
+{
+  return (a < b) ? a : b;
+}
+
+// unrecoverable SSL failure occured, notify transport and generate error code.
+static int ssl_failed(pn_transport_t *transport, const char *reason)
+{
+  char buf[512] = "Unknown error.";
+  if (!reason) {
+    HRESULT status = GetLastError();
+
+    FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
+                  0, status, 0, buf, sizeof(buf), 0);
+    reason = buf;
+  }
+  pni_ssl_t *ssl = transport->ssl;
+  ssl->ssl_closed = true;
+  ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
+  ssl->state = SSL_CLOSED;
+  pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
+  return PN_EOS;
+}
+
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
+{
+// TODO:
+  return NULL;
+}
+
+static void ssl_session_free( pn_ssl_session_t *ssn)
+{
+  if (ssn) {
+    if (ssn->id) free( (void *)ssn->id );
+    free( ssn );
+  }
+}
+
+
+/** Public API - visible to application code */
+
+bool pn_ssl_present(void)
+{
+  return true;
+}
+
+pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
+{
+  pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
+  if (!domain) return NULL;
+
+  domain->ref_count = 1;
+  domain->mode = mode;
+  switch(mode) {
+  case PN_SSL_MODE_CLIENT:
+  case PN_SSL_MODE_SERVER:
+    break;
+
+  default:
+    ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
+    free(domain);
+    return NULL;
+  }
+  domain->cred = win_credential(mode);
+  return domain;
+}
+
+void pn_ssl_domain_free( pn_ssl_domain_t *domain )
+{
+  if (!domain) return;
+
+  if (--domain->ref_count == 0) {
+    pn_decref(domain->cred);
+    free(domain);
+  }
+}
+
+
+int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
+                               const char *certificate_file,
+                               const char *private_key_file,
+                               const char *password)
+{
+  if (!domain) return -1;
+
+  if (win_credential_has_certificate(domain->cred)) {
+    // Need a new win_credential_t to hold new certificate
+    pn_decref(domain->cred);
+    domain->cred = win_credential(domain->mode);
+    if (!domain->cred)
+      return -1;
+  }
+  return win_credential_load_cert(domain->cred, certificate_file, private_key_file, password);
+}
+
+
+int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
+                                    const char *certificate_db)
+{
+  if (!domain || !certificate_db) return -1;
+
+  int ec = 0;
+  HCERTSTORE store = open_cert_db(certificate_db, NULL, &ec);
+  if (!store)
+    return ec;
+
+  if (domain->has_ca_db) {
+    win_credential_t *new_cred = win_credential(domain->mode);
+    if (!new_cred)
+      return -1;
+    new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
+    pn_decref(domain->cred);
+    domain->cred = new_cred;
+  }
+
+  domain->cred->trust_store = store;
+  domain->cred->trust_store_name = pn_strdup(certificate_db);
+  domain->has_ca_db = true;
+  return 0;
+}
+
+
+int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
+                                          const pn_ssl_verify_mode_t mode,
+                                          const char *trusted_CAs)
+{
+  if (!domain) return -1;
+  if (!domain->has_ca_db && (mode == PN_SSL_VERIFY_PEER || mode == PN_SSL_VERIFY_PEER_NAME)) {
+    ssl_log_error("Error: cannot verify peer without a trusted CA configured.\n"
+                  "       Use pn_ssl_domain_set_trusted_ca_db()\n");
+    return -1;
+  }
+
+  HCERTSTORE store = 0;
+  bool changed = domain->verify_mode && mode != domain->verify_mode;
+
+  switch (mode) {
+  case PN_SSL_VERIFY_PEER:
+  case PN_SSL_VERIFY_PEER_NAME:
+    if (domain->mode == PN_SSL_MODE_SERVER) {
+      if (!trusted_CAs) {
+        ssl_log_error("Error: a list of trusted CAs must be provided.");
+        return -1;
+      }
+      if (!win_credential_has_certificate(domain->cred)) {
+        ssl_log_error("Error: Server cannot verify peer without configuring a certificate.\n"
+                   "       Use pn_ssl_domain_set_credentials()");
+        return -1;
+      }
+      int ec = 0;
+      if (!strcmp(trusted_CAs, domain->cred->trust_store_name)) {
+        store = open_cert_db(trusted_CAs, NULL, &ec);
+        if (!store)
+          return ec;
+      } else {
+        store = CertDuplicateStore(domain->cred->trust_store);
+      }
+
+      if (domain->cred->server_CA_certs) {
+        // Already have one
+        changed = true;
+        win_credential_t *new_cred = win_credential(domain->mode);
+        if (!new_cred) {
+          CertCloseStore(store, 0);
+          return -1;
+        }
+        new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
+        new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
+        new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
+        pn_decref(domain->cred);
+        domain->cred = new_cred;
+      }
+
+      domain->cred->server_CA_certs = store;
+    }
+    break;
+
+  case PN_SSL_ANONYMOUS_PEER:   // hippie free love mode... :)
+    break;
+
+  default:
+    ssl_log_error("Invalid peer authentication mode given.\n");
+    return -1;
+  }
+
+  if (changed) {
+    win_credential_t *new_cred = win_credential(domain->mode);
+    if (!new_cred) {
+      CertCloseStore(store, 0);
+      return -1;
+    }
+    new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
+    new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
+    new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
+    pn_decref(domain->cred);
+    domain->cred = new_cred;
+  }
+
+  domain->verify_mode = mode;
+  domain->cred->server_CA_certs = store;
+
+  return 0;
+}
+
+const pn_io_layer_t ssl_layer = {
+    process_input_ssl,
+    process_output_ssl,
+    NULL,
+    NULL,
+    buffered_output
+};
+
+const pn_io_layer_t ssl_input_closed_layer = {
+    process_input_done,
+    process_output_ssl,
+    NULL,
+    NULL,
+    buffered_output
+};
+
+const pn_io_layer_t ssl_output_closed_layer = {
+    process_input_ssl,
+    process_output_done,
+    NULL,
+    NULL,
+    buffered_output
+};
+
+const pn_io_layer_t ssl_closed_layer = {
+    process_input_done,
+    process_output_done,
+    NULL,
+    NULL,
+    buffered_output
+};
+
+int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
+{
+  pn_transport_t *transport = get_transport_internal(ssl0);
+  pni_ssl_t *ssl = transport->ssl;
+  if (!ssl || !domain || ssl->domain) return -1;
+  if (ssl->state != CREATED) return -1;
+
+  ssl->domain = domain;
+  domain->ref_count++;
+  if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
+    ssl->session_id = pn_strdup(session_id);
+
+  // If SSL doesn't specifically allow skipping encryption, require SSL
+  // TODO: This is a probably a stop-gap until allow_unsecured is removed
+  if (!domain->allow_unsecured) transport->encryption_required = true;
+
+  ssl->cred = domain->cred;
+  pn_incref(domain->cred);
+
+  SECURITY_STATUS status = SEC_E_OK;
+  ssl->cred_handle = win_credential_cred_handle(ssl->cred, ssl->verify_mode,
+                                                ssl->session_id, &status);
+  if (status != SEC_E_OK) {
+    ssl_log_error_status(status, "Credentials handle failure");
+    return -1;
+  }
+
+  ssl->state = (domain->mode == PN_SSL_MODE_CLIENT) ? CLIENT_HELLO : NEGOTIATING;
+  ssl->verify_mode = domain->verify_mode;
+  return 0;
+}
+
+
+int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
+{
+  if (!domain) return -1;
+  if (domain->mode != PN_SSL_MODE_SERVER) {
+    ssl_log_error("Cannot permit unsecured clients - not a server.\n");
+    return -1;
+  }
+  domain->allow_unsecured = true;
+  return 0;
+}
+
+
+// TODO: This is just an untested guess
+int pn_ssl_get_ssf(pn_ssl_t *ssl0)
+{
+  SecPkgContext_ConnectionInfo info;
+
+  pni_ssl_t *ssl = get_ssl_internal(ssl0);
+  if (ssl &&
+      ssl->state == RUNNING &&
+      SecIsValidHandle(&ssl->ctxt_handle) &&
+      QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
+    return info.dwCipherStrength;
+  }
+  return 0;
+}
+
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
+{
+  pni_ssl_t *ssl = get_ssl_internal(ssl0);
+  if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
+    return false;
+  *buffer = '\0';
+  SecPkgContext_ConnectionInfo info;
+  if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
+    // TODO: come up with string for all permutations?
+    pni_snprintf( buffer, size, "%x_%x:%x_%x:%x_%x",
+              info.aiExch, info.dwExchStrength,
+              info.aiCipher, info.dwCipherStrength,
+              info.aiHash, info.dwHashStrength);
+    return true;
+  }
+  return false;
+}
+
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
+{
+  pni_ssl_t *ssl = get_ssl_internal(ssl0);
+  if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
+    return false;
+  *buffer = '\0';
+  SecPkgContext_ConnectionInfo info;
+  if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
+    if (info.dwProtocol & (SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER))
+      pni_snprintf(buffer, size, "%s", "TLSv1");
+    // TLSV1.1 and TLSV1.2 are supported as of XP-SP3, but not defined until VS2010
+    else if ((info.dwProtocol & 0x300))
+      pni_snprintf(buffer, size, "%s", "TLSv1.1");
+    else if ((info.dwProtocol & 0xC00))
+      pni_snprintf(buffer, size, "%s", "TLSv1.2");
+    else {
+      ssl_log_error("unexpected protocol %x\n", info.dwProtocol);
+      return false;
+    }
+    return true;
+  }
+  return false;
+}
+
+
+void pn_ssl_free( pn_transport_t *transport)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  if (!ssl) return;
+  ssl_log( transport, "SSL socket freed.\n" );
+  // clean up Windows per TLS session data before releasing the domain count
+  if (SecIsValidHandle(&ssl->ctxt_handle))
+    DeleteSecurityContext(&ssl->ctxt_handle);
+  if (ssl->cred) {
+    if (ssl->domain->mode == PN_SSL_MODE_CLIENT && ssl->session_id == NULL) {
+      // Responsible for unshared handle
+      if (SecIsValidHandle(&ssl->cred_handle))
+        FreeCredentialsHandle(&ssl->cred_handle);
+    }
+    pn_decref(ssl->cred);
+  }
+
+  if (ssl->domain) pn_ssl_domain_free(ssl->domain);
+  if (ssl->session_id) free((void *)ssl->session_id);
+  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+  if (ssl->sc_inbuf) free((void *)ssl->sc_inbuf);
+  if (ssl->sc_outbuf) free((void *)ssl->sc_outbuf);
+  if (ssl->inbuf2) pn_buffer_free(ssl->inbuf2);
+  if (ssl->subject) free(ssl->subject);
+
+  free(ssl);
+}
+
+pn_ssl_t *pn_ssl(pn_transport_t *transport)
+{
+  if (!transport) return NULL;
+  if (transport->ssl) return (pn_ssl_t *)transport;
+
+  pni_ssl_t *ssl = (pni_ssl_t *) calloc(1, sizeof(pni_ssl_t));
+  if (!ssl) return NULL;
+  ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;
+
+  ssl->sc_outbuf = (char *)malloc(ssl->sc_out_size);
+  if (!ssl->sc_outbuf) {
+    free(ssl);
+    return NULL;
+  }
+  ssl->sc_inbuf = (char *)malloc(ssl->sc_in_size);
+  if (!ssl->sc_inbuf) {
+    free(ssl->sc_outbuf);
+    free(ssl);
+    return NULL;
+  }
+
+  ssl->inbuf2 = pn_buffer(0);
+  if (!ssl->inbuf2) {
+    free(ssl->sc_inbuf);
+    free(ssl->sc_outbuf);
+    free(ssl);
+    return NULL;
+  }
+
+  transport->ssl = ssl;
+
+  // Set up hostname from any bound connection
+  if (transport->connection) {
+    if (pn_string_size(transport->connection->hostname)) {
+      pn_ssl_set_peer_hostname((pn_ssl_t *) transport, pn_string_get(transport->connection->hostname));
+    }
+  }
+
+  SecInvalidateHandle(&ssl->cred_handle);
+  SecInvalidateHandle(&ssl->ctxt_handle);
+  ssl->state = CREATED;
+  ssl->decrypting = true;
+
+  return (pn_ssl_t *)transport;
+}
+
+
+pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
+{
+  // TODO
+  return PN_SSL_RESUME_UNKNOWN;
+}
+
+
+int pn_ssl_set_peer_hostname( pn_ssl_t *ssl0, const char *hostname )
+{
+  pni_ssl_t *ssl = get_ssl_internal(ssl0);
+  if (!ssl) return -1;
+
+  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+  ssl->peer_hostname = NULL;
+  if (hostname) {
+    ssl->peer_hostname = pn_strdup(hostname);
+    if (!ssl->peer_hostname) return -2;
+  }
+  return 0;
+}
+
+int pn_ssl_get_peer_hostname( pn_ssl_t *ssl0, char *hostname, size_t *bufsize )
+{
+  pni_ssl_t *ssl = get_ssl_internal(ssl0);
+  if (!ssl) return -1;
+  if (!ssl->peer_hostname) {
+    *bufsize = 0;
+    if (hostname) *hostname = '\0';
+    return 0;
+  }
+  unsigned len = strlen(ssl->peer_hostname);
+  if (hostname) {
+    if (len >= *bufsize) return -1;
+    strcpy( hostname, ssl->peer_hostname );
+  }
+  *bufsize = len;
+  return 0;
+}
+
+const char* pn_ssl_get_remote_subject(pn_ssl_t *ssl0)
+{
+  // RFC 2253 compliant, but differs from openssl's subject string with space separators and
+  // ordering of multicomponent RDNs.  Made to work as similarly as possible with choice of flags.
+  pni_ssl_t *ssl = get_ssl_internal(ssl0);
+  if (!ssl || !SecIsValidHandle(&ssl->ctxt_handle))
+    return NULL;
+  if (!ssl->subject) {
+    SECURITY_STATUS status;
+    PCCERT_CONTEXT peer_cc = 0;
+    status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
+    if (status != SEC_E_OK) {
+      ssl_log_error_status(status, "can't obtain remote certificate subject");
+      return NULL;
+    }
+    DWORD flags = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
+    DWORD strlen = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
+                                 flags, NULL, 0);
+    if (strlen > 0) {
+      ssl->subject = (char*) malloc(strlen);
+      if (ssl->subject) {
+        DWORD len = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
+                                  flags, ssl->subject, strlen);
+        if (len != strlen) {
+          free(ssl->subject);
+          ssl->subject = NULL;
+          ssl_log_error("pn_ssl_get_remote_subject failure in CertNameToStr");
+        }
+      }
+    }
+    CertFreeCertificateContext(peer_cc);
+  }
+  return ssl->subject;
+}
+
+
+/** SChannel specific: */
+
+const char *tls_version_check(pni_ssl_t *ssl)
+{
+  SecPkgContext_ConnectionInfo info;
+  QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info);
+  // Ascending bit patterns denote newer SSL/TLS protocol versions.
+  // SP_PROT_TLS1_0_SERVER is not defined until VS2010.
+  return (info.dwProtocol < SP_PROT_TLS1_SERVER) ?
+    "peer does not support TLS 1.0 security" : NULL;
+}
+
+static void ssl_encrypt(pn_transport_t *transport, char *app_data, size_t count)
+{
+  pni_ssl_t *ssl = transport->ssl;
+
+  // Get SChannel to encrypt exactly one Record.
+  SecBuffer buffs[4];
+  buffs[0].cbBuffer = ssl->sc_sizes.cbHeader;
+  buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
+  buffs[0].pvBuffer = ssl->sc_outbuf;
+  buffs[1].cbBuffer = count;
+  buffs[1].BufferType = SECBUFFER_DATA;
+  buffs[1].pvBuffer = app_data;
+  buffs[2].cbBuffer = ssl->sc_sizes.cbTrailer;
+  buffs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+  buffs[2].pvBuffer = &app_data[count];
+  buffs[3].cbBuffer = 0;
+  buffs[3].BufferType = SECBUFFER_EMPTY;
+  buffs[3].pvBuffer = 0;
+  SecBufferDesc buff_desc;
+  buff_desc.ulVersion = SECBUFFER_VERSION;
+  buff_desc.cBuffers = 4;
+  buff_desc.pBuffers = buffs;
+  SECURITY_STATUS status = EncryptMessage(&ssl->ctxt_handle, 0, &buff_desc, 0);
+  assert(status == SEC_E_OK);
+
+  // EncryptMessage encrypts the data in place. The header and trailer
+  // areas were reserved previously and must now be included in the updated
+  // count of bytes to write to the peer.
+  ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
+  ssl->network_outp = ssl->sc_outbuf;
+  ssl->network_out_pending = ssl->sc_out_count;
+  ssl_log(transport, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
+}
+
+// Returns true if decryption succeeded (even for empty content)
+static bool ssl_decrypt(pn_transport_t *transport)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  // Get SChannel to decrypt input.  May have an incomplete Record,
+  // exactly one, or more than one.  Check also for session ending,
+  // session renegotiation.
+
+  SecBuffer recv_buffs[4];
+  recv_buffs[0].cbBuffer = ssl->sc_in_count;
+  recv_buffs[0].BufferType = SECBUFFER_DATA;
+  recv_buffs[0].pvBuffer = ssl->sc_inbuf;
+  recv_buffs[1].BufferType = SECBUFFER_EMPTY;
+  recv_buffs[2].BufferType = SECBUFFER_EMPTY;
+  recv_buffs[3].BufferType = SECBUFFER_EMPTY;
+  SecBufferDesc buff_desc;
+  buff_desc.ulVersion = SECBUFFER_VERSION;
+  buff_desc.cBuffers = 4;
+  buff_desc.pBuffers = recv_buffs;
+  SECURITY_STATUS status = DecryptMessage(&ssl->ctxt_handle, &buff_desc, 0, NULL);
+
+  if (status == SEC_E_INCOMPLETE_MESSAGE) {
+    // Less than a full Record, come back later with more network data
+    ssl->sc_in_incomplete = true;
+    return false;
+  }
+
+  ssl->decrypting = false;
+
+  if (status != SEC_E_OK) {
+    rewind_sc_inbuf(ssl);
+    switch (status) {
+    case SEC_I_CONTEXT_EXPIRED:
+      // TLS shutdown alert record.  Ignore all subsequent input.
+      ssl->state = SHUTTING_DOWN;
+      ssl->sc_input_shutdown = true;
+      return false;
+
+    case SEC_I_RENEGOTIATE:
+      ssl_log_error("unexpected TLS renegotiation\n");
+      // TODO.  Fall through for now.
+    default:
+      ssl_failed(transport, 0);
+      return false;
+    }
+  }
+
+  ssl->decrypting = false;
+  // have a decrypted Record and possible (still-encrypted) data of
+  // one (or more) later Recordss.  Adjust pointers accordingly.
+  for (int i = 0; i < 4; i++) {
+    switch (recv_buffs[i].BufferType) {
+    case SECBUFFER_DATA:
+      ssl->in_data = (char *) recv_buffs[i].pvBuffer;
+      ssl->in_data_size = ssl->in_data_count = recv_buffs[i].cbBuffer;
+      break;
+    case SECBUFFER_EXTRA:
+      ssl->inbuf_extra = (char *)recv_buffs[i].pvBuffer;
+      ssl->extra_count = recv_buffs[i].cbBuffer;
+      break;
+    default:
+      // SECBUFFER_STREAM_HEADER:
+      // SECBUFFER_STREAM_TRAILER:
+      break;
+    }
+  }
+  return true;
+}
+
+static void client_handshake_init(pn_transport_t *transport)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  // Tell SChannel to create the first handshake token (ClientHello)
+  // and place it in sc_outbuf
+  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
+  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_EXTENDED_ERROR;
+  ULONG ctxt_attrs;
+
+  SecBuffer send_buffs[2];
+  send_buffs[0].cbBuffer = ssl->sc_out_size;
+  send_buffs[0].BufferType = SECBUFFER_TOKEN;
+  send_buffs[0].pvBuffer = ssl->sc_outbuf;
+  send_buffs[1].cbBuffer = 0;
+  send_buffs[1].BufferType = SECBUFFER_EMPTY;
+  send_buffs[1].pvBuffer = 0;
+  SecBufferDesc send_buff_desc;
+  send_buff_desc.ulVersion = SECBUFFER_VERSION;
+  send_buff_desc.cBuffers = 2;
+  send_buff_desc.pBuffers = send_buffs;
+  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
+                               NULL, host, ctxt_requested, 0, 0, NULL, 0,
+                               &ssl->ctxt_handle, &send_buff_desc,
+                               &ctxt_attrs, NULL);
+
+  if (status == SEC_I_CONTINUE_NEEDED) {
+    ssl->sc_out_count = send_buffs[0].cbBuffer;
+    ssl->network_out_pending = ssl->sc_out_count;
+    // the token is the whole quantity to send
+    ssl->network_outp = ssl->sc_outbuf;
+    ssl_log(transport, "Sending client hello %d bytes\n", ssl->network_out_pending);
+  } else {
+    ssl_log_error_status(status, "InitializeSecurityContext failed");
+    ssl_failed(transport, 0);
+  }
+}
+
+static void client_handshake( pn_transport_t* transport) {
+  pni_ssl_t *ssl = transport->ssl;
+  // Feed SChannel ongoing responses from the server until the handshake is complete.
+  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
+  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
+  ULONG ctxt_attrs;
+  size_t max = 0;
+
+  // token_buffs describe the buffer that's coming in. It should have
+  // a token from the SSL server, or empty if sending final shutdown alert.
+  bool shutdown = ssl->state == SHUTTING_DOWN;
+  SecBuffer token_buffs[2];
+  token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
+  token_buffs[0].BufferType = SECBUFFER_TOKEN;
+  token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
+  token_buffs[1].cbBuffer = 0;
+  token_buffs[1].BufferType = SECBUFFER_EMPTY;
+  token_buffs[1].pvBuffer = 0;
+  SecBufferDesc token_buff_desc;
+  token_buff_desc.ulVersion = SECBUFFER_VERSION;
+  token_buff_desc.cBuffers = 2;
+  token_buff_desc.pBuffers = token_buffs;
+
+  // send_buffs will hold information to forward to the peer.
+  SecBuffer send_buffs[2];
+  send_buffs[0].cbBuffer = ssl->sc_out_size;
+  send_buffs[0].BufferType = SECBUFFER_TOKEN;
+  send_buffs[0].pvBuffer = ssl->sc_outbuf;
+  send_buffs[1].cbBuffer = 0;
+  send_buffs[1].BufferType = SECBUFFER_EMPTY;
+  send_buffs[1].pvBuffer = 0;
+  SecBufferDesc send_buff_desc;
+  send_buff_desc.ulVersion = SECBUFFER_VERSION;
+  send_buff_desc.cBuffers = 2;
+  send_buff_desc.pBuffers = send_buffs;
+
+  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
+                               &ssl->ctxt_handle, host, ctxt_requested, 0, 0,
+                               &token_buff_desc, 0, NULL, &send_buff_desc,
+                               &ctxt_attrs, NULL);
+  switch (status) {
+  case SEC_E_INCOMPLETE_MESSAGE:
+    // Not enough - get more data from the server then try again.
+    // Leave input buffers untouched.
+    ssl_log(transport, "client handshake: incomplete record\n");
+    ssl->sc_in_incomplete = true;
+    return;
+
+  case SEC_I_CONTINUE_NEEDED:
+    // Successful handshake step, requiring data to be sent to peer.
+    ssl->sc_out_count = send_buffs[0].cbBuffer;
+    // the token is the whole quantity to send
+    ssl->network_out_pending = ssl->sc_out_count;
+    ssl->network_outp = ssl->sc_outbuf;
+    ssl_log(transport, "client handshake token %d bytes\n", ssl->network_out_pending);
+    break;
+
+  case SEC_E_OK:
+    // Handshake complete.
+    if (shutdown) {
+      if (send_buffs[0].cbBuffer > 0) {
+        ssl->sc_out_count = send_buffs[0].cbBuffer;
+        // the token is the whole quantity to send
+        ssl->network_out_pending = ssl->sc_out_count;
+        ssl->network_outp = ssl->sc_outbuf;
+        ssl_log(transport, "client shutdown token %d bytes\n", ssl->network_out_pending);
+      } else {
+        ssl->state = SSL_CLOSED;
+      }
+      // we didn't touch sc_inbuf, no need to reset
+      return;
+    }
+    if (send_buffs[0].cbBuffer != 0) {
+      ssl_failed(transport, "unexpected final server token");
+      break;
+    }
+    if (const char *err = tls_version_check(ssl)) {
+      ssl_failed(transport, err);
+      break;
+    }
+    if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
+      bool tracing = PN_TRACE_DRV & transport->trace;
+      HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, ssl->peer_hostname, tracing);
+      if (ec) {
+        if (ssl->peer_hostname)
+          ssl_log_error_status(ec, "certificate verification failed for host %s\n", ssl->peer_hostname);
+        else
+          ssl_log_error_status(ec, "certificate verification failed\n");
+        ssl_failed(transport, "TLS certificate verification error");
+        break;
+      }
+    }
+
+    if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
+      // This seems to work but not documented, plus logic differs from decrypt message
+      // since the pvBuffer value is not set.  Grrr.
+      ssl->extra_count = token_buffs[1].cbBuffer;
+      ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+    }
+
+    QueryContextAttributes(&ssl->ctxt_handle,
+                             SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
+    max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
+    if (max > ssl->sc_out_size) {
+      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+      ssl->state = SHUTTING_DOWN;
+      ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+      start_ssl_shutdown(transport);
+      pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
+      break;
+    }
+
+    ssl->state = RUNNING;
+    ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
+    ssl_log(transport, "client handshake successful %d max record size\n", max);
+    break;
+
+  case SEC_I_CONTEXT_EXPIRED:
+    // ended before we got going
+  default:
+    ssl_log(transport, "client handshake failed %d\n", (int) status);
+    ssl_failed(transport, 0);
+    break;
+  }
+
+  if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
+      !ssl->ssl_closed) {
+    // remaining data after the consumed TLS record(s)
+    ssl->extra_count = token_buffs[1].cbBuffer;
+    ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+  }
+
+  ssl->decrypting = false;
+  rewind_sc_inbuf(ssl);
+}
+
+
+static void server_handshake(pn_transport_t* transport)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  if (!ssl->protocol_detected) {
+    // SChannel fails less aggressively than openssl on client hello, causing hangs
+    // waiting for more bytes.  Help out here.
+    pni_protocol_type_t type = pni_sniff_header(ssl->sc_inbuf, ssl->sc_in_count);
+    if (type == PNI_PROTOCOL_INSUFFICIENT) {
+      ssl_log(transport, "server handshake: incomplete record\n");
+      ssl->sc_in_incomplete = true;
+      return;
+    } else {
+      ssl->protocol_detected = true;
+      if (type != PNI_PROTOCOL_SSL) {
+        ssl_failed(transport, "bad client hello");
+        ssl->decrypting = false;
+        rewind_sc_inbuf(ssl);
+        return;
+      }
+    }
+  }
+
+  // Feed SChannel ongoing handshake records from the client until the handshake is complete.
+  ULONG ctxt_requested = ASC_REQ_STREAM | ASC_REQ_EXTENDED_ERROR;
+  if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME)
+    ctxt_requested |= ASC_REQ_MUTUAL_AUTH;
+  ULONG ctxt_attrs;
+  size_t max = 0;
+
+  // token_buffs describe the buffer that's coming in. It should have
+  // a token from the SSL client except if shutting down or renegotiating.
+  bool shutdown = ssl->state == SHUTTING_DOWN;
+  SecBuffer token_buffs[2];
+  token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
+  token_buffs[0].BufferType = SECBUFFER_TOKEN;
+  token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
+  token_buffs[1].cbBuffer = 0;
+  token_buffs[1].BufferType = SECBUFFER_EMPTY;
+  token_buffs[1].pvBuffer = 0;
+  SecBufferDesc token_buff_desc;
+  token_buff_desc.ulVersion = SECBUFFER_VERSION;
+  token_buff_desc.cBuffers = 2;
+  token_buff_desc.pBuffers = token_buffs;
+
+  // send_buffs will hold information to forward to the peer.
+  SecBuffer send_buffs[2];
+  send_buffs[0].cbBuffer = ssl->sc_out_size;
+  send_buffs[0].BufferType = SECBUFFER_TOKEN;
+  send_buffs[0].pvBuffer = ssl->sc_outbuf;
+  send_buffs[1].cbBuffer = 0;
+  send_buffs[1].BufferType = SECBUFFER_EMPTY;
+  send_buffs[1].pvBuffer = 0;
+  SecBufferDesc send_buff_desc;
+  send_buff_desc.ulVersion = SECBUFFER_VERSION;
+  send_buff_desc.cBuffers = 2;
+  send_buff_desc.pBuffers = send_buffs;
+  PCtxtHandle ctxt_handle_ptr = (SecIsValidHandle(&ssl->ctxt_handle)) ? &ssl->ctxt_handle : 0;
+
+  SECURITY_STATUS status = AcceptSecurityContext(&ssl->cred_handle, ctxt_handle_ptr,
+                               &token_buff_desc, ctxt_requested, 0, &ssl->ctxt_handle,
+                               &send_buff_desc, &ctxt_attrs, NULL);
+
+  bool outbound_token = false;
+  switch(status) {
+  case SEC_E_INCOMPLETE_MESSAGE:
+    // Not enough - get more data from the client then try again.
+    // Leave input buffers untouched.
+    ssl_log(transport, "server handshake: incomplete record\n");
+    ssl->sc_in_incomplete = true;
+    return;
+
+  case SEC_I_CONTINUE_NEEDED:
+    outbound_token = true;
+    break;
+
+  case SEC_E_OK:
+    // Handshake complete.
+    if (shutdown) {
+      if (send_buffs[0].cbBuffer > 0) {
+        ssl->sc_out_count = send_buffs[0].cbBuffer;
+        // the token is the whole quantity to send
+        ssl->network_out_pending = ssl->sc_out_count;
+        ssl->network_outp = ssl->sc_outbuf;
+        ssl_log(transport, "server shutdown token %d bytes\n", ssl->network_out_pending);
+      } else {
+        ssl->state = SSL_CLOSED;
+      }
+      // we didn't touch sc_inbuf, no need to reset
+      return;
+    }
+    if (const char *err = tls_version_check(ssl)) {
+      ssl_failed(transport, err);
+      break;
+    }
+    // Handshake complete.
+
+    if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
+      bool tracing = PN_TRACE_DRV & transport->trace;
+      HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, NULL, tracing);
+      if (ec) {
+        ssl_log_error_status(ec, "certificate verification failed\n");
+        ssl_failed(transport, "certificate verification error");
+        break;
+      }
+    }
+
+    QueryContextAttributes(&ssl->ctxt_handle,
+                             SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
+    max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
+    if (max > ssl->sc_out_size) {
+      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+      ssl->state = SHUTTING_DOWN;
+      ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
+      start_ssl_shutdown(transport);
+      pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
+      break;
+    }
+
+    if (send_buffs[0].cbBuffer != 0)
+      outbound_token = true;
+
+    ssl->state = RUNNING;
+    ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
+    ssl_log(transport, "server handshake successful %d max record size\n", max);
+    break;
+
+  case SEC_I_CONTEXT_EXPIRED:
+    // ended before we got going
+  default:
+    ssl_log(transport, "server handshake failed %d\n", (int) status);
+    ssl_failed(transport, 0);
+    break;
+  }
+
+  if (outbound_token) {
+    // Successful handshake step, requiring data to be sent to peer.
+    assert(ssl->network_out_pending == 0);
+    ssl->sc_out_count = send_buffs[0].cbBuffer;
+    // the token is the whole quantity to send
+    ssl->network_out_pending = ssl->sc_out_count;
+    ssl->network_outp = ssl->sc_outbuf;
+    ssl_log(transport, "server handshake token %d bytes\n", ssl->network_out_pending);
+  }
+
+  if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
+      !ssl->ssl_closed) {
+    // remaining data after the consumed TLS record(s)
+    ssl->extra_count = token_buffs[1].cbBuffer;
+    ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
+  }
+
+  ssl->decrypting = false;
+  rewind_sc_inbuf(ssl);
+}
+
+static void ssl_handshake(pn_transport_t* transport) {
+  if (transport->ssl->domain->mode == PN_SSL_MODE_CLIENT)
+    client_handshake(transport);
+  else {
+    server_handshake(transport);
+  }
+}
+
+static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
+  pni_ssl_t *ssl = transport->ssl;
+  size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
+  size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;
+
+  while (new_capacity < minimum_size)
+    new_capacity *= 2;
+
+  uint32_t max_frame = pn_transport_get_max_frame(transport);
+  if (max_frame != 0) {
+    if (old_capacity >= max_frame) {
+      //  already big enough
+      ssl_log(transport, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
+      ssl_failed(transport, "TLS: transport maximimum frame size error");
+      return false;
+    }
+  }
+
+  size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
+  int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
+  if (err) {
+    ssl_log(transport, "TLS memory allocation failed for %d bytes\n", max_frame);
+    ssl_failed(transport, "TLS memory allocation failed");
+    return false;
+  }
+  return true;
+}
+
+
+// Peer initiated a session end by sending us a shutdown alert (and we should politely
+// reciprocate), or else we are initiating the session end (and will not bother to wait
+// for the peer shutdown alert). Stop processing input immediately, and stop processing
+// output once this is sent.
+
+static void start_ssl_shutdown(pn_transport_t *transport)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  assert(ssl->network_out_pending == 0);
+  if (ssl->queued_shutdown)
+    return;
+  ssl->queued_shutdown = true;
+  ssl_log(transport, "Shutting down SSL connection...\n");
+
+  DWORD shutdown = SCHANNEL_SHUTDOWN;
+  SecBuffer shutBuff;
+  shutBuff.cbBuffer = sizeof(DWORD);
+  shutBuff.BufferType = SECBUFFER_TOKEN;
+  shutBuff.pvBuffer = &shutdown;
+  SecBufferDesc desc;
+  desc.ulVersion = SECBUFFER_VERSION;
+  desc.cBuffers = 1;
+  desc.pBuffers = &shutBuff;
+  ApplyControlToken(&ssl->ctxt_handle, &desc);
+
+  // Next handshake will generate the shudown alert token
+  ssl_handshake(transport);
+}
+
+static void rewind_sc_inbuf(pni_ssl_t *ssl)
+{
+  // Decrypted bytes have been drained or double buffered.  Prepare for the next SSL Record.
+  assert(ssl->in_data_count == 0);
+  if (ssl->decrypting)
+    return;
+  ssl->decrypting = true;
+  if (ssl->inbuf_extra) {
+    // A previous read picked up more than one Record.  Move it to the beginning.
+    memmove(ssl->sc_inbuf, ssl->inbuf_extra, ssl->extra_count);
+    ssl->sc_in_count = ssl->extra_count;
+    ssl->inbuf_extra = 0;
+    ssl->extra_count = 0;
+  } else {
+    ssl->sc_in_count = 0;
+  }
+}
+
+static void app_inbytes_add(pn_transport_t *transport)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  if (!ssl->app_inbytes.start) {
+    ssl->app_inbytes.start = ssl->in_data;
+    ssl->app_inbytes.size = ssl->in_data_count;
+    return;
+  }
+
+  if (ssl->double_buffered) {
+    if (pn_buffer_available(ssl->inbuf2) == 0) {
+      if (!grow_inbuf2(transport, 1024))
+        // could not add room
+        return;
+    }
+    size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+    pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+    ssl->in_data += count;
+    ssl->in_data_count -= count;
+    ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+  } else {
+    assert(ssl->app_inbytes.size == 0);
+    ssl->app_inbytes.start = ssl->in_data;
+    ssl->app_inbytes.size = ssl->in_data_count;
+  }
+}
+
+
+static void app_inbytes_progress(pn_transport_t *transport, size_t minimum)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  // Make more decrypted data available, if possible.  Otherwise, move
+  // unread bytes to front of inbuf2 to make room for next bulk decryption.
+  // SSL may have chopped up data that app layer expects to be
+  // contiguous.  Start, continue or stop double buffering here.
+  if (ssl->double_buffered) {
+    if (ssl->app_inbytes.size == 0) {
+      // no straggler bytes, optimistically stop for now
+      ssl->double_buffered = false;
+      pn_buffer_clear(ssl->inbuf2);
+      ssl->app_inbytes.start = ssl->in_data;
+      ssl->app_inbytes.size = ssl->in_data_count;
+    } else {
+      pn_bytes_t ib2 = pn_buffer_bytes(ssl->inbuf2);
+      assert(ssl->app_inbytes.size <= ib2.size);
+      size_t consumed = ib2.size - ssl->app_inbytes.size;
+      if (consumed > 0) {
+        memmove((void *)ib2.start, ib2.start + consumed, ssl->app_inbytes.size);
+        pn_buffer_trim(ssl->inbuf2, 0, consumed);
+      }
+      if (!pn_buffer_available(ssl->inbuf2)) {
+        if (!grow_inbuf2(transport, minimum))
+          // could not add room
+          return;
+      }
+      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+      ssl->in_data += count;
+      ssl->in_data_count -= count;
+      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+    }
+  } else {
+    if (ssl->app_inbytes.size) {
+      // start double buffering the left over bytes
+      ssl->double_buffered = true;
+      pn_buffer_clear(ssl->inbuf2);
+      if (!pn_buffer_available(ssl->inbuf2)) {
+        if (!grow_inbuf2(transport, minimum))
+          // could not add room
+          return;
+      }
+      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
+      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
+      ssl->in_data += count;
+      ssl->in_data_count -= count;
+      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
+    } else {
+      // already pointing at all available bytes until next decrypt
+    }
+  }
+  if (ssl->in_data_count == 0)
+    rewind_sc_inbuf(ssl);
+}
+
+
+static void app_inbytes_advance(pn_transport_t *transport, size_t consumed)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  if (consumed == 0) {
+    // more contiguous bytes required
+    app_inbytes_progress(transport, ssl->app_inbytes.size + 1);
+    return;
+  }
+  assert(consumed <= ssl->app_inbytes.size);
+  ssl->app_inbytes.start += consumed;
+  ssl->app_inbytes.size -= consumed;
+  if (!ssl->double_buffered) {
+    ssl->in_data += consumed;
+    ssl->in_data_count -= consumed;
+  }
+  if (ssl->app_inbytes.size == 0)
+    app_inbytes_progress(transport, 0);
+}
+
+static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t error)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  if (ssl->app_input_closed)
+    return;
+  if (ssl->state == RUNNING && !error) {
+    // Signal end of stream
+    ssl->app_input_closed = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, 0);
+  }
+  if (!ssl->app_input_closed)
+    ssl->app_input_closed = error ? error : PN_ERR;
+
+  if (ssl->app_output_closed) {
+    // both sides of app closed, and no more app output pending:
+    ssl->state = SHUTTING_DOWN;
+    if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
+      start_ssl_shutdown(transport);
+    }
+  }
+}
+
+
+// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.
+
+static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  ssl_log( transport, "process_input_ssl( data size=%d )\n",available );
+  ssize_t consumed = 0;
+  ssize_t forwarded = 0;
+  bool new_app_input;
+
+  if (available == 0) {
+    // No more inbound network data
+    read_closed(transport, layer, 0);
+    return 0;
+  }
+
+  do {
+    if (ssl->sc_input_shutdown) {
+      // TLS protocol shutdown detected on input, so we are done.
+      read_closed(transport, layer, 0);
+      return PN_EOS;
+    }
+
+    // sc_inbuf should be ready for new or additional network encrypted bytes.
+    // i.e. no straggling decrypted bytes pending.
+    assert(ssl->in_data_count == 0 && ssl->decrypting);
+    new_app_input = false;
+    size_t count;
+
+    if (ssl->state != RUNNING) {
+      count = _pni_min(ssl->sc_in_size - ssl->sc_in_count, available);
+    } else {
+      // look for TLS record boundaries
+      if (ssl->sc_in_count < 5) {
+        ssl->sc_in_incomplete = true;
+        size_t hc = _pni_min(available, 5 - ssl->sc_in_count);
+        memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, hc);
+        ssl->sc_in_count += hc;
+        input_data += hc;
+        available -= hc;
+        consumed += hc;
+        if (ssl->sc_in_count < 5 || available == 0)
+          break;
+      }
+
+      // Top up sc_inbuf from network input_data hoping for a complete TLS Record
+      // We try to guess the length as an optimization, but let SChannel
+      // ultimately decide if there is spoofing going on.
+      unsigned char low = (unsigned char) ssl->sc_inbuf[4];
+      unsigned char high = (unsigned char) ssl->sc_inbuf[3];
+      size_t rec_len = high * 256 + low + 5;
+      if (rec_len < 5 || rec_len == ssl->sc_in_count || rec_len > ssl->sc_in_size)
+        rec_len = ssl->sc_in_size;
+
+      count = _pni_min(rec_len - ssl->sc_in_count, available);
+    }
+
+    if (count > 0) {
+      memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, count);
+      ssl->sc_in_count += count;
+      input_data += count;
+      available -= count;
+      consumed += count;
+      ssl->sc_in_incomplete = false;
+    }
+
+    // Try to decrypt another TLS Record.
+
+    if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
+      if (ssl->state == NEGOTIATING) {
+        ssl_handshake(transport);
+      } else {
+        if (ssl_decrypt(transport)) {
+          // Ignore TLS Record with 0 length data (does not mean EOS)
+          if (ssl->in_data_size > 0) {
+            new_app_input = true;
+            app_inbytes_add(transport);
+          } else {
+            assert(ssl->decrypting == false);
+            rewind_sc_inbuf(ssl);
+          }
+        }
+        ssl_log(transport, "Next decryption, %d left over\n", available);
+      }
+    }
+
+    if (ssl->state == SHUTTING_DOWN) {
+      if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
+        start_ssl_shutdown(transport);
+      }
+    } else if (ssl->state == SSL_CLOSED) {
+      return PN_EOS;
+    }
+
+    // Consume or discard the decrypted bytes
+    if (new_app_input && (ssl->state == RUNNING || ssl->state == SHUTTING_DOWN)) {
+      // present app_inbytes to io_next only if it has new content
+      while (ssl->app_inbytes.size > 0) {
+        if (!ssl->app_input_closed) {
+          ssize_t count = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, ssl->app_inbytes.size);
+          if (count > 0) {
+            forwarded += count;
+            // advance() can increase app_inbytes.size if double buffered
+            app_inbytes_advance(transport, count);
+            ssl_log(transport, "Application consumed %d bytes from peer\n", (int) count);
+          } else if (count == 0) {
+            size_t old_size = ssl->app_inbytes.size;
+            app_inbytes_advance(transport, 0);
+            if (ssl->app_inbytes.size == old_size) {
+              break;  // no additional contiguous decrypted data available, get more network data
+            }
+          } else {
+            // count < 0
+            ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)\n",
+                 (int) count, (int)ssl->app_inbytes.size);
+            app_inbytes_advance(transport, ssl->app_inbytes.size);    // discard
+            read_closed(transport, layer, count);
+          }
+        } else {
+          ssl_log(transport, "Input closed discard %d bytes\n",
+               (int)ssl->app_inbytes.size);
+          app_inbytes_advance(transport, ssl->app_inbytes.size);      // discard
+        }
+      }
+    }
+  } while (available || (ssl->sc_in_count && !ssl->sc_in_incomplete));
+
+  if (ssl->state >= SHUTTING_DOWN) {
+    if (ssl->app_input_closed || ssl->sc_input_shutdown) {
+      // Next layer doesn't want more bytes, or it can't process without more data than it has seen so far
+      // but the ssl stream has ended
+      consumed = ssl->app_input_closed ? ssl->app_input_closed : PN_EOS;
+      if (transport->io_layers[layer]==&ssl_output_closed_layer) {
+        transport->io_layers[layer] = &ssl_closed_layer;
+      } else {
+        transport->io_layers[layer] = &ssl_input_closed_layer;
+      }
+    }
+  }
+  ssl_log(transport, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
+  return consumed;
+}
+
+static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
+{
+  pni_ssl_t *ssl = transport->ssl;
+  if (!ssl) return PN_EOS;
+  ssl_log( transport, "process_output_ssl( max_len=%d )\n",max_len );
+
+  ssize_t written = 0;
+  ssize_t total_app_bytes = 0;
+  bool work_pending;
+
+  if (ssl->state == CLIENT_HELLO) {
+    // output buffers eclusively for internal handshake use until negotiation complete
+    client_handshake_init(transport);
+    if (ssl->state == SSL_CLOSED)
+      return PN_EOS;
+    ssl->state = NEGOTIATING;
+  }
+
+  do {
+    work_pending = false;
+
+    if (ssl->network_out_pending > 0) {
+      size_t wcount = _pni_min(ssl->network_out_pending, max_len);
+      memmove(buffer, ssl->network_outp, wcount);
+      ssl->network_outp += wcount;
+      ssl->network_out_pending -= wcount;
+      buffer += wcount;
+      max_len -= wcount;
+      written += wcount;
+    }
+
+    if (ssl->network_out_pending == 0 && ssl->state == RUNNING  && !ssl->app_output_closed) {
+      // refill the buffer with app data and encrypt it
+
+      char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
+      char *app_outp = app_data;
+      size_t remaining = ssl->max_data_size;
+      ssize_t app_bytes;
+      do {
+        app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, app_outp, remaining);
+        if (app_bytes > 0) {
+          app_outp += app_bytes;
+          remaining -= app_bytes;
+          ssl_log( transport, "Gathered %d bytes from app to send to peer\n", app_bytes );
+        } else {
+          if (app_bytes < 0) {
+            ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)\n",
+                 (int) app_bytes, (int) ssl->network_out_pending);
+            ssl->app_output_closed = app_bytes;
+            if (ssl->app_input_closed)
+              ssl->state = SHUTTING_DOWN;
+          } else if (total_app_bytes == 0 && ssl->app_input_closed) {
+            // We've drained all the App layer can provide
+            ssl_log(transport, "Application layer blocked on input, closing\n");
+            ssl->state = SHUTTING_DOWN;
+            ssl->app_output_closed = PN_ERR;
+          }
+        }
+      } while (app_bytes > 0);
+      if (app_outp > app_data) {
+        work_pending = (max_len > 0);
+        ssl_encrypt(transport, app_data, app_outp - app_data);
+      }
+    }
+
+    if (ssl->network_out_pending == 0) {
+      if (ssl->state == SHUTTING_DOWN) {
+        if (!ssl->queued_shutdown) {
+          start_ssl_shutdown(transport);
+          work_pending = true;
+        } else {
+          ssl->state = SSL_CLOSED;
+        }
+      }
+      else if (ssl->state == NEGOTIATING && ssl->app_input_closed) {
+        ssl->app_output_closed = PN_EOS;
+        ssl->state = SSL_CLOSED;
+      }
+    }
+  } while (work_pending);
+
+  if (written == 0 && ssl->state == SSL_CLOSED) {
+    written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
+    if (transport->io_layers[layer]==&ssl_input_closed_layer) {
+      transport->io_layers[layer] = &ssl_closed_layer;
+    } else {
+      transport->io_layers[layer] = &ssl_output_closed_layer;
+    }
+  }
+  ssl_log(transport, "process_output_ssl() returning %d\n", (int) written);
+  return written;
+}
+
+
+static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
+{
+  return PN_EOS;
+}
+
+static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
+{
+  return PN_EOS;
+}
+
+// return # output bytes sitting in this layer
+static size_t buffered_output(pn_transport_t *transport)
+{
+  size_t count = 0;
+  pni_ssl_t *ssl = transport->ssl;
+  if (ssl) {
+    count += ssl->network_out_pending;
+    if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
+      count++;
+  }
+  return count;
+}
+
+static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error) {
+  *error = 0;
+  DWORD sys_store_type = 0;
+  HCERTSTORE cert_store = 0;
+
+  if (store_name) {
+    if (strncmp(store_name, "ss:", 3) == 0) {
+      store_name += 3;
+      sys_store_type = CERT_SYSTEM_STORE_CURRENT_USER;
+    }
+    else if (strncmp(store_name, "lmss:", 5) == 0) {
+      store_name += 5;
+      sys_store_type = CERT_SYSTEM_STORE_LOCAL_MACHINE;
+    }
+  }
+
+  if (sys_store_type) {
+    // Opening a system store, names are not case sensitive.
+    // Map confusing GUI name to actual registry store name.
+    if (!pn_strcasecmp(store_name, "personal")) store_name= "my";
+    cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
+                               CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG |
+                               sys_store_type, store_name);
+    if (!cert_store) {
+      ssl_log_error_status(GetLastError(), "Failed to open system certificate store %s", store_name);
+      *error = -3;
+      return NULL;
+    }
+  } else {
+    // PKCS#12 file
+    HANDLE cert_file = CreateFile(store_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+                                  FILE_ATTRIBUTE_NORMAL, NULL);
+    if (INVALID_HANDLE_VALUE == cert_file) {
+      HRESULT status = GetLastError();
+      ssl_log_error_status(status, "Failed to open the file holding the private key: %s", store_name);
+      *error = -4;
+      return NULL;
+    }
+    DWORD nread = 0L;
+    const DWORD file_size = GetFileSize(cert_file, NULL);
+    char *buf = NULL;
+    if (INVALID_FILE_SIZE != file_size)
+      buf = (char *) malloc(file_size);
+    if (!buf || !ReadFile(cert_file, buf, file_size, &nread, NULL)
+        || file_size != nread) {
+      HRESULT status = GetLastError();
+      CloseHandle(cert_file);
+      free(buf);
+      ssl_log_error_status(status, "Reading the private key from file failed %s", store_name);
+      *error = -5;
+      return NULL;
+    }
+    CloseHandle(cert_file);
+
+    CRYPT_DATA_BLOB blob;
+    blob.cbData = nread;
+    blob.pbData = (BYTE *) buf;
+
+    wchar_t *pwUCS2 = NULL;
+    int pwlen = 0;
+    if (passwd) {
+      // convert passwd to null terminated wchar_t (Windows UCS2)
+      pwlen = strlen(passwd);
+      pwUCS2 = (wchar_t *) calloc(pwlen + 1, sizeof(wchar_t));
+      int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, passwd, pwlen, &pwUCS2[0], pwlen);
+      if (!nwc) {
+        ssl_log_error_status(GetLastError(), "Error converting password from UTF8");
+        free(buf);
+        free(pwUCS2);
+        *error = -6;
+        return NULL;
+      }
+    }
+
+    cert_store = PFXImportCertStore(&blob, pwUCS2, 0);
+    if (pwUCS2) {
+      SecureZeroMemory(pwUCS2, pwlen * sizeof(wchar_t));
+      free(pwUCS2);
+    }
+    if (cert_store == NULL) {
+      ssl_log_error_status(GetLastError(), "Failed to import the file based certificate store");
+      free(buf);
+      *error = -7;
+      return NULL;
+    }
+
+    free(buf);
+  }
+
+  return cert_store;
+}
+
+static bool store_contains(HCERTSTORE store, PCCERT_CONTEXT cert)
+{
+  DWORD find_type = CERT_FIND_EXISTING; // Require exact match
+  PCCERT_CONTEXT tcert = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                                                    0, find_type, cert, 0);
+  if (tcert) {
+    CertFreeCertificateContext(tcert);
+    return true;
+  }
+  return false;
+}
+
+/* Match the DNS name pattern from the peer certificate against our configured peer
+   hostname */
+static bool match_dns_pattern(const char *hostname, const char *pattern, int plen)
+{
+  int slen = (int) strlen(hostname);
+  if (memchr( pattern, '*', plen ) == NULL)
+    return (plen == slen &&
+            pn_strncasecmp( pattern, hostname, plen ) == 0);
+
+  /* dns wildcarded pattern - RFC2818 */
+  char plabel[64];   /* max label length < 63 - RFC1034 */
+  char slabel[64];
+
+  while (plen > 0 && slen > 0) {
+    const char *cptr;
+    int len;
+
+    cptr = (const char *) memchr( pattern, '.', plen );
+    len = (cptr) ? cptr - pattern : plen;
+    if (len > (int) sizeof(plabel) - 1) return false;
+    memcpy( plabel, pattern, len );
+    plabel[len] = 0;
+    if (cptr) ++len;    // skip matching '.'
+    pattern += len;
+    plen -= len;
+
+    cptr = (const char *) memchr( hostname, '.', slen );
+    len = (cptr) ? cptr - hostname : slen;
+    if (len > (int) sizeof(slabel) - 1) return false;
+    memcpy( slabel, hostname, len );
+    slabel[len] = 0;
+    if (cptr) ++len;    // skip matching '.'
+    hostname += len;
+    slen -= len;
+
+    char *star = strchr( plabel, '*' );
+    if (!star) {
+      if (pn_strcasecmp( plabel, slabel )) return false;
+    } else {
+      *star = '\0';
+      char *prefix = plabel;
+      int prefix_len = strlen(prefix);
+      char *suffix = star + 1;
+      int suffix_len = strlen(suffix);
+      if (prefix_len && pn_strncasecmp( prefix, slabel, prefix_len )) return false;
+      if (suffix_len && pn_strncasecmp( suffix,
+                                     slabel + (strlen(slabel) - suffix_len),
+                                     suffix_len )) return false;
+    }
+  }
+
+  return plen == slen;
+}
+
+// Caller must free the returned buffer
+static char* wide_to_utf8(LPWSTR wstring)
+{
+  int len = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, 0, 0, 0, 0);
+  if (!len) {
+    ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
+    return NULL;
+  }
+  char *p = (char *) malloc(len);
+  if (!p) return NULL;
+  if (WideCharToMultiByte(CP_UTF8, 0, wstring, -1, p, len, 0, 0))
+    return p;
+  ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
+  free (p);
+  return NULL;
+}
+
+static bool server_name_matches(const char *server_name, CERT_EXTENSION *alt_name_ext, PCCERT_CONTEXT cert)
+{
+  // As for openssl.c: alt names first, then CN
+  bool matched = false;
+
+  if (alt_name_ext) {
+    CERT_ALT_NAME_INFO* alt_name_info = NULL;
+    DWORD size = 0;
+    if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME2,
+                            alt_name_ext->Value.pbData, alt_name_ext->Value.cbData,
+                            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+                            0, &alt_name_info, &size)) {
+      ssl_log_error_status(GetLastError(), "Alternative name match internal error");
+      return false;
+    }
+
+    int name_ct = alt_name_info->cAltEntry;
+    for (int i = 0; !matched && i < name_ct; ++i) {
+      if (alt_name_info->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) {
+        char *alt_name = wide_to_utf8(alt_name_info->rgAltEntry[i].pwszDNSName);
+        if (alt_name) {
+          matched = match_dns_pattern(server_name, (const char *) alt_name, strlen(alt_name));
+          free(alt_name);
+        }
+      }
+    }
+    LocalFree(&alt_name_info);
+  }
+
+  if (!matched) {
+    PCERT_INFO info = cert->pCertInfo;
+    DWORD len = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, 0, 0);
+    char *name = (char *) malloc(len);
+    if (name) {
+      int count = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, name, len);
+      if (count)
+        matched = match_dns_pattern(server_name, (const char *) name, strlen(name));
+      free(name);
+    }
+  }
+  return matched;
+}
+
+const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subject_subfield field)
+{
+    return NULL;
+}
+
+int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0,
+                                          char *fingerprint,
+                                          size_t fingerprint_length,
+                                          pn_ssl_hash_alg hash_alg)
+{
+    return -1;
+}
+
+static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing)
+{
+  // Free/release the following before return:
+  PCCERT_CONTEXT peer_cc = 0;
+  PCCERT_CONTEXT trust_anchor = 0;
+  PCCERT_CHAIN_CONTEXT chain_context = 0;
+  wchar_t *nameUCS2 = 0;
+
+  if (server_name && strlen(server_name) > 255) {
+    ssl_log_error("invalid server name: %s\n", server_name);
+    return WSAENAMETOOLONG;
+  }
+
+  // Get peer's certificate.
+  SECURITY_STATUS status;
+  status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
+  if (status != SEC_E_OK) {
+    ssl_log_error_status(status, "can't obtain remote peer certificate information");
+    return status;
+  }
+
+  // Build the peer's certificate chain.  Multiple chains may be built but we
+  // care about rgpChain[0], which is the best.  Custom root stores are not
+  // allowed until W8/server 2012: see CERT_CHAIN_ENGINE_CONFIG.  For now, we
+  // manually override to taste.
+
+  // Chain verification functions give false reports for CRL if the trust anchor
+  // is not in the official root store.  We ignore CRL completely if it doesn't
+  // apply to any untrusted certs in the chain, and defer to SChannel's veto
+  // otherwise.  To rely on CRL, the CA must be in both the official system
+  // trusted root store and the Proton cred->trust_store.  To defeat CRL, the
+  // most distal cert with CRL must be placed in the Proton cred->trust_store.
+  // Similarly, certificate usage checking is overly strict at times.
+
+  CERT_CHAIN_PARA desc;
+  memset(&desc, 0, sizeof(desc));
+  desc.cbSize = sizeof(desc);
+
+  LPSTR usages[] = { szOID_PKIX_KP_SERVER_AUTH };
+  DWORD n_usages = sizeof(usages) / sizeof(LPSTR);
+  desc.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+  desc.RequestedUsage.Usage.cUsageIdentifier = n_usages;
+  desc.RequestedUsage.Usage.rgpszUsageIdentifier = usages;
+
+  if(!CertGetCertificateChain(0, peer_cc, 0, peer_cc->hCertStore, &desc,
+                             CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
+                             CERT_CHAIN_CACHE_END_CERT,
+                             0, &chain_context)){
+    HRESULT st = GetLastError();
+    ssl_log_error_status(st, "Basic certificate chain check failed");
+    CertFreeCertificateContext(peer_cc);
+    return st;
+  }
+  if (chain_context->cChain < 1 || chain_context->rgpChain[0]->cElement < 1) {
+    ssl_log_error("empty chain with status %x %x\n", chain_context->TrustStatus.dwErrorStatus,
+                 chain_context->TrustStatus.dwInfoStatus);
+    return SEC_E_CERT_UNKNOWN;
+  }
+
+  int chain_len = chain_context->rgpChain[0]->cElement;
+  PCCERT_CONTEXT leaf_cert = chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
+  PCCERT_CONTEXT trunk_cert = chain_context->rgpChain[0]->rgpElement[chain_len - 1]->pCertContext;
+  if (tracing)
+    // See doc for CERT_CHAIN_POLICY_STATUS for bit field error and info status values
+    ssl_log_error("status for complete chain: error bits %x info bits %x\n",
+                  chain_context->TrustStatus.dwErrorStatus, chain_context->TrustStatus.dwInfoStatus);
+
+  // Supplement with checks against Proton's trusted_ca_db, custom revocation and usage.
+  HRESULT error = 0;
+  do {
+    // Do not return from this do loop.  Set error = SEC_E_XXX and break.
+    bool revocable = false;  // unless we see any untrusted certs that could be
+    for (int i = 0; i < chain_len; i++) {
+      CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[i];
+      PCCERT_CONTEXT cc = ce->pCertContext;
+      if (cc->pCertInfo->dwVersion != CERT_V3) {
+        if (tracing)
+          ssl_log_error("certificate chain element %d is not version 3\n", i);
+        error = SEC_E_CERT_WRONG_USAGE; // A fossil
+        break;
+      }
+
+      if (!trust_anchor && store_contains(root_store, cc))
+        trust_anchor = CertDuplicateCertificateContext(cc);
+
+      int n_ext = cc->pCertInfo->cExtension;
+      for (int ii = 0; ii < n_ext && !revocable && !trust_anchor; ii++) {
+        CERT_EXTENSION *p = &cc->pCertInfo->rgExtension[ii];
+        // rfc 5280 extensions for revocation
+        if (!strcmp(p->pszObjId, szOID_AUTHORITY_INFO_ACCESS) ||
+            !strcmp(p->pszObjId, szOID_CRL_DIST_POINTS) ||
+            !strcmp(p->pszObjId, szOID_FRESHEST_CRL)) {
+          revocable = true;
+        }
+      }
+
+      if (tracing) {
+        char name[512];
+        const char *is_anchor = (cc == trust_anchor) ? " trust anchor" : "";
+        if (!CertNameToStr(cc->dwCertEncodingType, &cc->pCertInfo->Subject,
+                           CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, name, sizeof(name)))
+          strcpy(name, "[too long]");
+        ssl_log_error("element %d (name: %s)%s error bits %x info bits %x\n", i, name, is_anchor,
+                      ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
+      }
+    }
+    if (error)
+      break;
+
+    if (!trust_anchor) {
+      // We don't trust any of the certs in the chain, see if the last cert
+      // is issued by a Proton trusted CA.
+      DWORD flags = CERT_STORE_NO_ISSUER_FLAG || CERT_STORE_SIGNATURE_FLAG ||
+        CERT_STORE_TIME_VALIDITY_FLAG;
+      trust_anchor = CertGetIssuerCertificateFromStore(root_store, trunk_cert, 0, &flags);
+      if (trust_anchor) {
+        if (tracing) {
+          if (flags & CERT_STORE_SIGNATURE_FLAG)
+            ssl_log_error("root certificate signature failure\n");
+          if (flags & CERT_STORE_TIME_VALIDITY_FLAG)
+            ssl_log_error("root certificate time validity failure\n");
+        }
+        if (flags) {
+          CertFreeCertificateContext(trust_anchor);
+          trust_anchor = 0;
+        }
+      }
+    }
+    if (!trust_anchor) {
+      error = SEC_E_UNTRUSTED_ROOT;
+      break;
+    }
+
+    bool strict_usage = false;
+    CERT_EXTENSION *leaf_alt_names = 0;
+    if (leaf_cert != trust_anchor) {
+      int n_ext = leaf_cert->pCertInfo->cExtension;
+      for (int ii = 0; ii < n_ext; ii++) {
+        CERT_EXTENSION *p = &leaf_cert->pCertInfo->rgExtension[ii];
+        if (!strcmp(p->pszObjId, szOID_ENHANCED_KEY_USAGE))
+          strict_usage = true;
+        if (!strcmp(p->pszObjId, szOID_SUBJECT_ALT_NAME2))
+          if (p->Value.pbData)
+            leaf_alt_names = p;
+      }
+    }
+
+    if (server_name) {
+      int len = strlen(server_name);
+      nameUCS2 = (wchar_t *) calloc(len + 1, sizeof(wchar_t));
+      int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, server_name, len, &nameUCS2[0], len);
+      if (!nwc) {
+        error = GetLastError();
+        ssl_log_error_status(error, "Error converting server name from UTF8");
+        break;
+      }
+    }
+
+    // SSL-specific parameters (ExtraPolicy below)
+    SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_desc;
+    memset(&ssl_desc, 0, sizeof(ssl_desc));
+    ssl_desc.cbSize = sizeof(ssl_desc);
+    ssl_desc.pwszServerName = nameUCS2;
+    ssl_desc.dwAuthType = nameUCS2 ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
+    ssl_desc.fdwChecks = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+    if (server_name)
+      ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
+    if (!revocable)
+      ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_REVOCATION;
+    if (!strict_usage)
+      ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_WRONG_USAGE;
+
+    // General certificate chain parameters
+    CERT_CHAIN_POLICY_PARA chain_desc;
+    memset(&chain_desc, 0, sizeof(chain_desc));
+    chain_desc.cbSize = sizeof(chain_desc);
+    chain_desc.dwFlags = CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG;
+    if (!revocable)
+      chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
+    if (!strict_usage)
+      chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
+    chain_desc.pvExtraPolicyPara = &ssl_desc;
+
+    CERT_CHAIN_POLICY_STATUS chain_status;
+    memset(&chain_status, 0, sizeof(chain_status));
+    chain_status.cbSize = sizeof(chain_status);
+
+    if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context,
+                                          &chain_desc, &chain_status)) {
+      error = GetLastError();
+      // Failure to complete the check, does not (in)validate the cert.
+      ssl_log_error_status(error, "Supplemental certificate chain check failed");
+      break;
+    }
+
+    if (chain_status.dwError) {
+      error = chain_status.dwError;
+      if (tracing) {
+        ssl_log_error_status(chain_status.dwError, "Certificate chain verification error");
+        if (chain_status.lChainIndex == 0 && chain_status.lElementIndex != -1) {
+          int idx = chain_status.lElementIndex;
+          CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[idx];
+          ssl_log_error("  chain failure at %d error/info: %x %x\n", idx,
+                        ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
+        }
+      }
+      break;
+    }
+
+    if (server_name && ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME &&
+        !server_name_matches(server_name, leaf_alt_names, leaf_cert)) {
+      error = SEC_E_WRONG_PRINCIPAL;
+      break;
+    }
+    else if (ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME && !server_name) {
+      ssl_log_error("Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
+      error = SEC_E_WRONG_PRINCIPAL;
+      break;
+    }
+  } while (0);
+
+  if (tracing && !error)
+    ssl_log_error("peer certificate authenticated\n");
+
+  // Lots to clean up.
+  if (peer_cc)
+    CertFreeCertificateContext(peer_cc);
+  if (trust_anchor)
+    CertFreeCertificateContext(trust_anchor);
+  if (chain_context)
+    CertFreeCertificateChain(chain_context);
+  free(nameUCS2);
+  return error;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/ssl/ssl_stub.c
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl_stub.c b/proton-c/src/ssl/ssl_stub.c
index c836b59..db2d983 100644
--- a/proton-c/src/ssl/ssl_stub.c
+++ b/proton-c/src/ssl/ssl_stub.c
@@ -22,7 +22,7 @@
 #include <proton/ssl.h>
 #include <proton/error.h>
 #include <proton/transport.h>
-#include "engine/engine-internal.h"
+#include "core/engine-internal.h"
 
 
 /** @file

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/tests/data.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/data.c b/proton-c/src/tests/data.c
index 8fb8217..10e7039 100644
--- a/proton-c/src/tests/data.c
+++ b/proton-c/src/tests/data.c
@@ -22,7 +22,7 @@
 #undef NDEBUG                   /* Make sure that assert() is enabled even in a release build. */
 
 #include <proton/codec.h>
-#include "../codec/data.h"
+#include "core/data.h"
 #include <assert.h>
 #include <stdio.h>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/autodetect.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/autodetect.c b/proton-c/src/transport/autodetect.c
deleted file mode 100644
index 00f6d98..0000000
--- a/proton-c/src/transport/autodetect.c
+++ /dev/null
@@ -1,135 +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 "autodetect.h"
-
-#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
-#define SSL_HEADER  ("AMQP\x02\x01\x00\x00")
-#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
-
-#define SASL_HEADER_LEN 8
-
-/*
- * SSLv2 Client Hello format
- * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
- *
- * Bytes 0-1: RECORD-LENGTH
- * Byte    2: MSG-CLIENT-HELLO (1)
- * Byte    3: CLIENT-VERSION-MSB
- * Byte    4: CLIENT-VERSION-LSB
- *
- * Allowed versions:
- * 2.0 - SSLv2
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- *
- * The version sent in the Client-Hello is the latest version supported by
- * the client. NSS may send version 3.x in an SSLv2 header for
- * maximum compatibility.
- */
-/*
- * SSLv3/TLS Client Hello format
- * RFC 2246
- *
- * Byte    0: ContentType (handshake - 22)
- * Bytes 1-2: ProtocolVersion {major, minor}
- *
- * Allowed versions:
- * 3.0 - SSLv3
- * 3.1 - TLS 1.0
- * 3.2 - TLS 1.1
- * 3.3 - TLS 1.2
- */
-/*
- * AMQP 1.0 Header
- *
- * Bytes 0-3: "AMQP"
- * Byte    4: 0==AMQP, 2==SSL, 3==SASL
- * Byte    5: 1
- * Bytes 6-7: 0
- */
-/*
- * AMQP Pre 1.0 Header
- *
- * Bytes 0-3: 'AMQP'
- * Byte    4: 1
- * Byte    5: 1
- * Byte    6: 0 (major version)
- * Byte    7: Minor version
- */
-pni_protocol_type_t pni_sniff_header(const char *buf, size_t len)
-{
-  if (len < 3) return PNI_PROTOCOL_INSUFFICIENT;
-  bool isSSL3Handshake = buf[0]==22 &&            // handshake
-                         buf[1]==3  && buf[2]<=3; // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
-  if (isSSL3Handshake) return PNI_PROTOCOL_SSL;
-
-  bool isFirst3AMQP = buf[0]=='A' && buf[1]=='M' && buf[2]=='Q';
-  bool isFirst3SSL2CLientHello = buf[2]==1;       // Client Hello
-  if (!isFirst3AMQP && !isFirst3SSL2CLientHello) return PNI_PROTOCOL_UNKNOWN;
-
-
-  if (len < 4) return PNI_PROTOCOL_INSUFFICIENT;
-  bool isAMQP = isFirst3AMQP && buf[3]=='P';
-  bool isFirst4SSL2ClientHello = isFirst3SSL2CLientHello && (buf[3]==2 || buf[3]==3);
-  if (!isAMQP && !isFirst4SSL2ClientHello) return PNI_PROTOCOL_UNKNOWN;
-
-  if (len < 5) return PNI_PROTOCOL_INSUFFICIENT;
-  bool isSSL2Handshake = buf[2] == 1 &&   // MSG-CLIENT-HELLO
-      ((buf[3] == 3 && buf[4] <= 3) ||    // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
-       (buf[3] == 2 && buf[4] == 0));     // SSL 2
-  if (isSSL2Handshake) return PNI_PROTOCOL_SSL;
-
-  bool isFirst5OldAMQP = isAMQP && buf[4]==1;
-  bool isFirst5AMQP = isAMQP && (buf[4]==0 || buf[4]==2 || buf[4]==3);
-  if (!isFirst5AMQP && !isFirst5OldAMQP) return PNI_PROTOCOL_UNKNOWN;
-
-  if (len < 6) return PNI_PROTOCOL_INSUFFICIENT;
-
-  // Both old and new versions of AMQP have 1 in byte 5
-  if (buf[5]!=1) return PNI_PROTOCOL_UNKNOWN;
-
-  // From here on it must be some sort of AMQP
-  if (len < 8) return PNI_PROTOCOL_INSUFFICIENT;
-  if (buf[6]==0 && buf[7]==0) {
-    // AM<QP 1.0
-      if (buf[4]==0) return PNI_PROTOCOL_AMQP1;
-      if (buf[4]==2) return PNI_PROTOCOL_AMQP_SSL;
-      if (buf[4]==3) return PNI_PROTOCOL_AMQP_SASL;
-  }
-  return PNI_PROTOCOL_AMQP_OTHER;
-}
-
-const char* pni_protocol_name(pni_protocol_type_t p)
-{
-  static const char* names[] = {
-  "Insufficient data to determine protocol",
-  "Unknown protocol",
-  "SSL/TLS connection",
-  "AMQP TLS layer",
-  "AMQP SASL layer",
-  "AMQP 1.0 layer",
-  "Pre standard AMQP connection"
-  };
-  return names[p];
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/autodetect.h
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/autodetect.h b/proton-c/src/transport/autodetect.h
deleted file mode 100644
index 12cb7d8..0000000
--- a/proton-c/src/transport/autodetect.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef PROTON_AUTODETECT_H
-#define PROTON_AUTODETECT_H 1
-
-/*
- *
- * 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/types.h"
-
-typedef enum {
-  PNI_PROTOCOL_INSUFFICIENT,
-  PNI_PROTOCOL_UNKNOWN,
-  PNI_PROTOCOL_SSL,
-  PNI_PROTOCOL_AMQP_SSL,
-  PNI_PROTOCOL_AMQP_SASL,
-  PNI_PROTOCOL_AMQP1,
-  PNI_PROTOCOL_AMQP_OTHER
-} pni_protocol_type_t;
-
-pni_protocol_type_t pni_sniff_header(const char *data, size_t len);
-const char* pni_protocol_name(pni_protocol_type_t p);
-
-#endif


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


[18/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/buffer.c
----------------------------------------------------------------------
diff --git a/proton-c/src/buffer.c b/proton-c/src/buffer.c
deleted file mode 100644
index c3015f4..0000000
--- a/proton-c/src/buffer.c
+++ /dev/null
@@ -1,310 +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/error.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "buffer.h"
-#include "util.h"
-
-struct pn_buffer_t {
-  size_t capacity;
-  size_t start;
-  size_t size;
-  char *bytes;
-};
-
-pn_buffer_t *pn_buffer(size_t capacity)
-{
-  pn_buffer_t *buf = (pn_buffer_t *) malloc(sizeof(pn_buffer_t));
-  if (buf != NULL) {
-    buf->capacity = capacity;
-    buf->start = 0;
-    buf->size = 0;
-    if (capacity > 0) {
-        buf->bytes = (char *)malloc(capacity);
-        if (buf->bytes == NULL) {
-            free(buf);
-            buf = NULL;
-        }
-    }
-    else {
-        buf->bytes = NULL;
-    }
-  }
-  return buf;
-}
-
-void pn_buffer_free(pn_buffer_t *buf)
-{
-  if (buf) {
-    free(buf->bytes);
-    free(buf);
-  }
-}
-
-size_t pn_buffer_size(pn_buffer_t *buf)
-{
-  return buf->size;
-}
-
-size_t pn_buffer_capacity(pn_buffer_t *buf)
-{
-  return buf->capacity;
-}
-
-size_t pn_buffer_available(pn_buffer_t *buf)
-{
-  return buf->capacity - buf->size;
-}
-
-static size_t pni_buffer_head(pn_buffer_t *buf)
-{
-  return buf->start;
-}
-
-static size_t pni_buffer_tail(pn_buffer_t *buf)
-{
-  size_t tail = buf->start + buf->size;
-  if (tail >= buf->capacity)
-    tail -= buf->capacity;
-  return tail;
-}
-
-static bool pni_buffer_wrapped(pn_buffer_t *buf)
-{
-  return buf->size && pni_buffer_head(buf) >= pni_buffer_tail(buf);
-}
-
-static size_t pni_buffer_tail_space(pn_buffer_t *buf)
-{
-  if (pni_buffer_wrapped(buf)) {
-    return pn_buffer_available(buf);
-  } else {
-    return buf->capacity - pni_buffer_tail(buf);
-  }
-}
-
-static size_t pni_buffer_head_space(pn_buffer_t *buf)
-{
-  if (pni_buffer_wrapped(buf)) {
-    return pn_buffer_available(buf);
-  } else {
-    return pni_buffer_head(buf);
-  }
-}
-
-static size_t pni_buffer_head_size(pn_buffer_t *buf)
-{
-  if (pni_buffer_wrapped(buf)) {
-    return buf->capacity - pni_buffer_head(buf);
-  } else {
-    return pni_buffer_tail(buf) - pni_buffer_head(buf);
-  }
-}
-
-static size_t pni_buffer_tail_size(pn_buffer_t *buf)
-{
-  if (pni_buffer_wrapped(buf)) {
-    return pni_buffer_tail(buf);
-  } else {
-    return 0;
-  }
-}
-
-int pn_buffer_ensure(pn_buffer_t *buf, size_t size)
-{
-  size_t old_capacity = buf->capacity;
-  size_t old_head = pni_buffer_head(buf);
-  bool wrapped = pni_buffer_wrapped(buf);
-
-  while (pn_buffer_available(buf) < size) {
-    buf->capacity = 2*(buf->capacity ? buf->capacity : 16);
-  }
-
-  if (buf->capacity != old_capacity) {
-    char* new_bytes = (char *)realloc(buf->bytes, buf->capacity);
-    if (new_bytes) {
-      buf->bytes = new_bytes;
-
-      if (wrapped) {
-          size_t n = old_capacity - old_head;
-          memmove(buf->bytes + buf->capacity - n, buf->bytes + old_head, n);
-          buf->start = buf->capacity - n;
-      }
-    }
-  }
-
-  return 0;
-}
-
-int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size)
-{
-  int err = pn_buffer_ensure(buf, size);
-  if (err) return err;
-
-  size_t tail = pni_buffer_tail(buf);
-  size_t tail_space = pni_buffer_tail_space(buf);
-  size_t n = pn_min(tail_space, size);
-
-  memmove(buf->bytes + tail, bytes, n);
-  memmove(buf->bytes, bytes + n, size - n);
-
-  buf->size += size;
-
-  return 0;
-}
-
-int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size)
-{
-  int err = pn_buffer_ensure(buf, size);
-  if (err) return err;
-
-  size_t head = pni_buffer_head(buf);
-  size_t head_space = pni_buffer_head_space(buf);
-  size_t n = pn_min(head_space, size);
-
-  memmove(buf->bytes + head - n, bytes + size - n, n);
-  memmove(buf->bytes + buf->capacity - (size - n), bytes, size - n);
-
-  if (buf->start >= size) {
-    buf->start -= size;
-  } else {
-    buf->start = buf->capacity - (size - buf->start);
-  }
-
-  buf->size += size;
-
-  return 0;
-}
-
-static size_t pni_buffer_index(pn_buffer_t *buf, size_t index)
-{
-  size_t result = buf->start + index;
-  if (result >= buf->capacity) result -= buf->capacity;
-  return result;
-}
-
-size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst)
-{
-  size = pn_min(size, buf->size);
-  size_t start = pni_buffer_index(buf, offset);
-  size_t stop = pni_buffer_index(buf, offset + size);
-
-  if (size == 0) return 0;
-
-  size_t sz1;
-  size_t sz2;
-
-  if (start >= stop) {
-    sz1 = buf->capacity - start;
-    sz2 = stop;
-  } else {
-    sz1 = stop - start;
-    sz2 = 0;
-  }
-
-  memmove(dst, buf->bytes + start, sz1);
-  memmove(dst + sz1, buf->bytes, sz2);
-
-  return sz1 + sz2;
-}
-
-int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right)
-{
-  if (left + right > buf->size) return PN_ARG_ERR;
-
-  buf->start += left;
-  if (buf->start >= buf->capacity)
-    buf->start -= buf->capacity;
-
-  buf->size -= left + right;
-
-  return 0;
-}
-
-void pn_buffer_clear(pn_buffer_t *buf)
-{
-  buf->start = 0;
-  buf->size = 0;
-}
-
-static void pn_buffer_rotate (pn_buffer_t *buf, size_t sz) {
-  if (sz == 0) return;
-
-  unsigned c = 0, v = 0;
-  for (; c < buf->capacity; v++) {
-    unsigned t = v, tp = v + sz;
-    char tmp = buf->bytes[v];
-    c++;
-    while (tp != v) {
-      buf->bytes[t] = buf->bytes[tp];
-      t = tp;
-      tp += sz;
-      if (tp >= buf->capacity) tp -= buf->capacity;
-      c++;
-    }
-    buf->bytes[t] = tmp;
-  }
-}
-
-int pn_buffer_defrag(pn_buffer_t *buf)
-{
-  pn_buffer_rotate(buf, buf->start);
-  buf->start = 0;
-  return 0;
-}
-
-pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf)
-{
-  if (buf) {
-    pn_buffer_defrag(buf);
-    return pn_bytes(buf->size, buf->bytes);
-  } else {
-    return pn_bytes(0, NULL);
-  }
-}
-
-pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf)
-{
-  if (buf) {
-    pn_buffer_defrag(buf);
-    pn_rwbytes_t r = {buf->size, buf->bytes};
-    return r;
-  } else {
-    pn_rwbytes_t r = {0, NULL};
-    return r;
-  }
-}
-
-int pn_buffer_print(pn_buffer_t *buf)
-{
-  printf("pn_buffer(\"");
-  pn_print_data(buf->bytes + pni_buffer_head(buf), pni_buffer_head_size(buf));
-  pn_print_data(buf->bytes, pni_buffer_tail_size(buf));
-  printf("\")");
-  return 0;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/buffer.h
----------------------------------------------------------------------
diff --git a/proton-c/src/buffer.h b/proton-c/src/buffer.h
deleted file mode 100644
index da557ef..0000000
--- a/proton-c/src/buffer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef PROTON_BUFFER_H
-#define PROTON_BUFFER_H 1
-
-/*
- *
- * 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/import_export.h>
-#include <proton/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct pn_buffer_t pn_buffer_t;
-
-pn_buffer_t *pn_buffer(size_t capacity);
-void pn_buffer_free(pn_buffer_t *buf);
-size_t pn_buffer_size(pn_buffer_t *buf);
-size_t pn_buffer_capacity(pn_buffer_t *buf);
-size_t pn_buffer_available(pn_buffer_t *buf);
-int pn_buffer_ensure(pn_buffer_t *buf, size_t size);
-int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size);
-int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size);
-size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst);
-int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right);
-void pn_buffer_clear(pn_buffer_t *buf);
-int pn_buffer_defrag(pn_buffer_t *buf);
-pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf);
-pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf);
-int pn_buffer_print(pn_buffer_t *buf);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* buffer.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/codec.c b/proton-c/src/codec/codec.c
deleted file mode 100644
index 2a4532c..0000000
--- a/proton-c/src/codec/codec.c
+++ /dev/null
@@ -1,2142 +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/object.h>
-#include <proton/codec.h>
-#include <proton/error.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include "encodings.h"
-#define DEFINE_FIELDS
-#include "protocol.h"
-#include "platform.h"
-#include "platform_fmt.h"
-#include "util.h"
-#include "decoder.h"
-#include "encoder.h"
-#include "data.h"
-#include "log_private.h"
-
-const char *pn_type_name(pn_type_t type)
-{
-  switch (type)
-  {
-  case PN_NULL: return "PN_NULL";
-  case PN_BOOL: return "PN_BOOL";
-  case PN_UBYTE: return "PN_UBYTE";
-  case PN_BYTE: return "PN_BYTE";
-  case PN_USHORT: return "PN_USHORT";
-  case PN_SHORT: return "PN_SHORT";
-  case PN_UINT: return "PN_UINT";
-  case PN_INT: return "PN_INT";
-  case PN_CHAR: return "PN_CHAR";
-  case PN_ULONG: return "PN_ULONG";
-  case PN_LONG: return "PN_LONG";
-  case PN_TIMESTAMP: return "PN_TIMESTAMP";
-  case PN_FLOAT: return "PN_FLOAT";
-  case PN_DOUBLE: return "PN_DOUBLE";
-  case PN_DECIMAL32: return "PN_DECIMAL32";
-  case PN_DECIMAL64: return "PN_DECIMAL64";
-  case PN_DECIMAL128: return "PN_DECIMAL128";
-  case PN_UUID: return "PN_UUID";
-  case PN_BINARY: return "PN_BINARY";
-  case PN_STRING: return "PN_STRING";
-  case PN_SYMBOL: return "PN_SYMBOL";
-  case PN_DESCRIBED: return "PN_DESCRIBED";
-  case PN_ARRAY: return "PN_ARRAY";
-  case PN_LIST: return "PN_LIST";
-  case PN_MAP: return "PN_MAP";
-  default: break;
-  }
-
-  return "<UNKNOWN>";
-}
-
-static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type)
-{
-  memset(atom, 0, sizeof(pn_atom_t));
-  atom->type = type;
-}
-
-// data
-
-static void pn_data_finalize(void *object)
-{
-  pn_data_t *data = (pn_data_t *) object;
-  free(data->nodes);
-  pn_buffer_free(data->buf);
-  pn_free(data->str);
-  pn_error_free(data->error);
-  pn_free(data->decoder);
-  pn_free(data->encoder);
-}
-
-static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
-{
-  if (!node) return NULL;
-  if (node->atom.type != PN_DESCRIBED) return NULL;
-
-  pni_node_t *descriptor = pn_data_node(data, node->down);
-
-  if (!descriptor || descriptor->atom.type != PN_ULONG) {
-    return NULL;
-  }
-
-  if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) {
-    const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
-    return (f->name_index!=0) ? f : NULL;
-  } else {
-    return NULL;
-  }
-}
-
-static int pni_node_index(pn_data_t *data, pni_node_t *node)
-{
-  int count = 0;
-  while (node) {
-    node = pn_data_node(data, node->prev);
-    count++;
-  }
-  return count - 1;
-}
-
-int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
-{
-  switch (atom->type) {
-  case PN_NULL:
-    return pn_string_addf(str, "null");
-  case PN_BOOL:
-    return pn_string_addf(str, atom->u.as_bool ? "true" : "false");
-  case PN_UBYTE:
-    return pn_string_addf(str, "%" PRIu8, atom->u.as_ubyte);
-  case PN_BYTE:
-    return pn_string_addf(str, "%" PRIi8, atom->u.as_byte);
-  case PN_USHORT:
-    return pn_string_addf(str, "%" PRIu16, atom->u.as_ushort);
-  case PN_SHORT:
-    return pn_string_addf(str, "%" PRIi16, atom->u.as_short);
-  case PN_UINT:
-    return pn_string_addf(str, "%" PRIu32, atom->u.as_uint);
-  case PN_INT:
-    return pn_string_addf(str, "%" PRIi32, atom->u.as_int);
-  case PN_CHAR:
-    return pn_string_addf(str, "%c",  atom->u.as_char);
-  case PN_ULONG:
-    return pn_string_addf(str, "%" PRIu64, atom->u.as_ulong);
-  case PN_LONG:
-    return pn_string_addf(str, "%" PRIi64, atom->u.as_long);
-  case PN_TIMESTAMP:
-    return pn_string_addf(str, "%" PRIi64, atom->u.as_timestamp);
-  case PN_FLOAT:
-    return pn_string_addf(str, "%g", atom->u.as_float);
-  case PN_DOUBLE:
-    return pn_string_addf(str, "%g", atom->u.as_double);
-  case PN_DECIMAL32:
-    return pn_string_addf(str, "D32(%" PRIu32 ")", atom->u.as_decimal32);
-  case PN_DECIMAL64:
-    return pn_string_addf(str, "D64(%" PRIu64 ")", atom->u.as_decimal64);
-  case PN_DECIMAL128:
-    return pn_string_addf(str, "D128(%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
-                          "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
-                          "%02hhx%02hhx)",
-                          atom->u.as_decimal128.bytes[0],
-                          atom->u.as_decimal128.bytes[1],
-                          atom->u.as_decimal128.bytes[2],
-                          atom->u.as_decimal128.bytes[3],
-                          atom->u.as_decimal128.bytes[4],
-                          atom->u.as_decimal128.bytes[5],
-                          atom->u.as_decimal128.bytes[6],
-                          atom->u.as_decimal128.bytes[7],
-                          atom->u.as_decimal128.bytes[8],
-                          atom->u.as_decimal128.bytes[9],
-                          atom->u.as_decimal128.bytes[10],
-                          atom->u.as_decimal128.bytes[11],
-                          atom->u.as_decimal128.bytes[12],
-                          atom->u.as_decimal128.bytes[13],
-                          atom->u.as_decimal128.bytes[14],
-                          atom->u.as_decimal128.bytes[15]);
-  case PN_UUID:
-    return pn_string_addf(str, "UUID(%02hhx%02hhx%02hhx%02hhx-"
-                          "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
-                          "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx)",
-                          atom->u.as_uuid.bytes[0],
-                          atom->u.as_uuid.bytes[1],
-                          atom->u.as_uuid.bytes[2],
-                          atom->u.as_uuid.bytes[3],
-                          atom->u.as_uuid.bytes[4],
-                          atom->u.as_uuid.bytes[5],
-                          atom->u.as_uuid.bytes[6],
-                          atom->u.as_uuid.bytes[7],
-                          atom->u.as_uuid.bytes[8],
-                          atom->u.as_uuid.bytes[9],
-                          atom->u.as_uuid.bytes[10],
-                          atom->u.as_uuid.bytes[11],
-                          atom->u.as_uuid.bytes[12],
-                          atom->u.as_uuid.bytes[13],
-                          atom->u.as_uuid.bytes[14],
-                          atom->u.as_uuid.bytes[15]);
-  case PN_BINARY:
-  case PN_STRING:
-  case PN_SYMBOL:
-    {
-      int err;
-      const char *pfx;
-      pn_bytes_t bin = atom->u.as_bytes;
-      bool quote;
-      switch (atom->type) {
-      case PN_BINARY:
-        pfx = "b";
-        quote = true;
-        break;
-      case PN_STRING:
-        pfx = "";
-        quote = true;
-        break;
-      case PN_SYMBOL:
-        pfx = ":";
-        quote = false;
-        for (unsigned i = 0; i < bin.size; i++) {
-          if (!isalpha(bin.start[i])) {
-            quote = true;
-            break;
-          }
-        }
-        break;
-      default:
-        assert(false);
-        return PN_ERR;
-      }
-
-      if ((err = pn_string_addf(str, "%s", pfx))) return err;
-      if (quote) if ((err = pn_string_addf(str, "\""))) return err;
-      if ((err = pn_quote(str, bin.start, bin.size))) return err;
-      if (quote) if ((err = pn_string_addf(str, "\""))) return err;
-      return 0;
-    }
-  case PN_LIST:
-    return pn_string_addf(str, "<list>");
-  case PN_MAP:
-    return pn_string_addf(str, "<map>");
-  case PN_ARRAY:
-    return pn_string_addf(str, "<array>");
-  case PN_DESCRIBED:
-    return pn_string_addf(str, "<described>");
-  default:
-    return pn_string_addf(str, "<undefined: %i>", atom->type);
-  }
-}
-
-int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
-{
-  pn_string_t *str = (pn_string_t *) ctx;
-  pn_atom_t *atom = (pn_atom_t *) &node->atom;
-
-  pni_node_t *parent = pn_data_node(data, node->parent);
-  const pn_fields_t *fields = pni_node_fields(data, parent);
-  pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
-  const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
-  int index = pni_node_index(data, node);
-
-  int err;
-
-  if (grandfields) {
-    if (atom->type == PN_NULL) {
-      return 0;
-    }
-    const char *name = (index < grandfields->field_count)
-        ? FIELD_STRINGPOOL.STRING0+FIELD_FIELDS[grandfields->first_field_index+index]
-        : NULL;
-    if (name) {
-      err = pn_string_addf(str, "%s=", name);
-      if (err) return err;
-    }
-  }
-
-  switch (atom->type) {
-  case PN_DESCRIBED:
-    return pn_string_addf(str, "@");
-  case PN_ARRAY:
-    // XXX: need to fix for described arrays
-    return pn_string_addf(str, "@%s[", pn_type_name(node->type));
-  case PN_LIST:
-    return pn_string_addf(str, "[");
-  case PN_MAP:
-    return pn_string_addf(str, "{");
-  default:
-    if (fields && index == 0) {
-      err = pn_string_addf(str, "%s", FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]);
-      if (err) return err;
-      err = pn_string_addf(str, "(");
-      if (err) return err;
-      err = pni_inspect_atom(atom, str);
-      if (err) return err;
-      return pn_string_addf(str, ")");
-    } else {
-      return pni_inspect_atom(atom, str);
-    }
-  }
-}
-
-pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node)
-{
-  while (node) {
-    node = pn_data_node(data, node->next);
-    if (node && node->atom.type != PN_NULL) {
-      return node;
-    }
-  }
-
-  return NULL;
-}
-
-int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node)
-{
-  pn_string_t *str = (pn_string_t *) ctx;
-  pni_node_t *parent = pn_data_node(data, node->parent);
-  pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
-  const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
-  pni_node_t *next = pn_data_node(data, node->next);
-  int err;
-
-  switch (node->atom.type) {
-  case PN_ARRAY:
-  case PN_LIST:
-    err = pn_string_addf(str, "]");
-    if (err) return err;
-    break;
-  case PN_MAP:
-    err = pn_string_addf(str, "}");
-    if (err) return err;
-    break;
-  default:
-    break;
-  }
-
-  if (!grandfields || node->atom.type != PN_NULL) {
-    if (next) {
-      int index = pni_node_index(data, node);
-      if (parent && parent->atom.type == PN_MAP && (index % 2) == 0) {
-        err = pn_string_addf(str, "=");
-      } else if (parent && parent->atom.type == PN_DESCRIBED && index == 0) {
-        err = pn_string_addf(str, " ");
-        if (err) return err;
-      } else {
-        if (!grandfields || pni_next_nonnull(data, node)) {
-          err = pn_string_addf(str, ", ");
-          if (err) return err;
-        }
-      }
-    }
-  }
-
-  return 0;
-}
-
-static int pn_data_inspect(void *obj, pn_string_t *dst)
-{
-  pn_data_t *data = (pn_data_t *) obj;
-
-  return pni_data_traverse(data, pni_inspect_enter, pni_inspect_exit, dst);
-}
-
-#define pn_data_initialize NULL
-#define pn_data_hashcode NULL
-#define pn_data_compare NULL
-
-pn_data_t *pn_data(size_t capacity)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_data);
-  pn_data_t *data = (pn_data_t *) pn_class_new(&clazz, sizeof(pn_data_t));
-  data->capacity = capacity;
-  data->size = 0;
-  data->nodes = capacity ? (pni_node_t *) malloc(capacity * sizeof(pni_node_t)) : NULL;
-  data->buf = pn_buffer(64);
-  data->parent = 0;
-  data->current = 0;
-  data->base_parent = 0;
-  data->base_current = 0;
-  data->decoder = pn_decoder();
-  data->encoder = pn_encoder();
-  data->error = pn_error();
-  data->str = pn_string(NULL);
-  return data;
-}
-
-void pn_data_free(pn_data_t *data)
-{
-  pn_free(data);
-}
-
-int pn_data_errno(pn_data_t *data)
-{
-  return pn_error_code(data->error);
-}
-
-pn_error_t *pn_data_error(pn_data_t *data)
-{
-  return data->error;
-}
-
-size_t pn_data_size(pn_data_t *data)
-{
-  return data ? data->size : 0;
-}
-
-void pn_data_clear(pn_data_t *data)
-{
-  if (data) {
-    data->size = 0;
-    data->parent = 0;
-    data->current = 0;
-    data->base_parent = 0;
-    data->base_current = 0;
-    pn_buffer_clear(data->buf);
-  }
-}
-
-static int pni_data_grow(pn_data_t *data)
-{
-  size_t capacity = data->capacity ? data->capacity : 2;
-  if (capacity >= PNI_NID_MAX) return PN_OUT_OF_MEMORY;
-  else if (capacity < PNI_NID_MAX/2) capacity *= 2;
-  else capacity = PNI_NID_MAX;
-
-  pni_node_t *new_nodes = (pni_node_t *)realloc(data->nodes, capacity * sizeof(pni_node_t));
-  if (new_nodes == NULL) return PN_OUT_OF_MEMORY;
-  data->capacity = capacity;
-  data->nodes = new_nodes;
-  return 0;
-}
-
-static ssize_t pni_data_intern(pn_data_t *data, const char *start, size_t size)
-{
-  size_t offset = pn_buffer_size(data->buf);
-  int err = pn_buffer_append(data->buf, start, size);
-  if (err) return err;
-  err = pn_buffer_append(data->buf, "\0", 1);
-  if (err) return err;
-  return offset;
-}
-
-static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node)
-{
-  switch (node->atom.type) {
-  case PN_BINARY:
-  case PN_STRING:
-  case PN_SYMBOL:
-    return &node->atom.u.as_bytes;
-  default: return NULL;
-  }
-}
-
-static void pni_data_rebase(pn_data_t *data, char *base)
-{
-  for (unsigned i = 0; i < data->size; i++) {
-    pni_node_t *node = &data->nodes[i];
-    if (node->data) {
-      pn_bytes_t *bytes = pni_data_bytes(data, node);
-      bytes->start = base + node->data_offset;
-    }
-  }
-}
-
-static int pni_data_intern_node(pn_data_t *data, pni_node_t *node)
-{
-  pn_bytes_t *bytes = pni_data_bytes(data, node);
-  if (!bytes) return 0;
-  size_t oldcap = pn_buffer_capacity(data->buf);
-  ssize_t offset = pni_data_intern(data, bytes->start, bytes->size);
-  if (offset < 0) return offset;
-  node->data = true;
-  node->data_offset = offset;
-  node->data_size = bytes->size;
-  pn_rwbytes_t buf = pn_buffer_memory(data->buf);
-  bytes->start = buf.start + offset;
-
-  if (pn_buffer_capacity(data->buf) != oldcap) {
-    pni_data_rebase(data, buf.start);
-  }
-
-  return 0;
-}
-
-int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap)
-{
-  int err = 0;
-  const char *begin = fmt;
-  while (*fmt) {
-    char code = *(fmt++);
-    if (!code) return 0;
-
-    switch (code) {
-    case 'n':
-      err = pn_data_put_null(data);
-      break;
-    case 'o':
-      err = pn_data_put_bool(data, va_arg(ap, int));
-      break;
-    case 'B':
-      err = pn_data_put_ubyte(data, va_arg(ap, unsigned int));
-      break;
-    case 'b':
-      err = pn_data_put_byte(data, va_arg(ap, int));
-      break;
-    case 'H':
-      err = pn_data_put_ushort(data, va_arg(ap, unsigned int));
-      break;
-    case 'h':
-      err = pn_data_put_short(data, va_arg(ap, int));
-      break;
-    case 'I':
-      err = pn_data_put_uint(data, va_arg(ap, uint32_t));
-      break;
-    case 'i':
-      err = pn_data_put_int(data, va_arg(ap, uint32_t));
-      break;
-    case 'L':
-      err = pn_data_put_ulong(data, va_arg(ap, uint64_t));
-      break;
-    case 'l':
-      err = pn_data_put_long(data, va_arg(ap, int64_t));
-      break;
-    case 't':
-      err = pn_data_put_timestamp(data, va_arg(ap, pn_timestamp_t));
-      break;
-    case 'f':
-      err = pn_data_put_float(data, va_arg(ap, double));
-      break;
-    case 'd':
-      err = pn_data_put_double(data, va_arg(ap, double));
-      break;
-    case 'z':
-      {
-	// For maximum portability, caller must pass these as two separate args, not a single struct
-        size_t size = va_arg(ap, size_t);
-        char *start = va_arg(ap, char *);
-        if (start) {
-          err = pn_data_put_binary(data, pn_bytes(size, start));
-        } else {
-          err = pn_data_put_null(data);
-        }
-      }
-      break;
-    case 'S':
-    case 's':
-      {
-        char *start = va_arg(ap, char *);
-        size_t size;
-        if (start) {
-          size = strlen(start);
-          if (code == 'S') {
-            err = pn_data_put_string(data, pn_bytes(size, start));
-          } else {
-            err = pn_data_put_symbol(data, pn_bytes(size, start));
-          }
-        } else {
-          err = pn_data_put_null(data);
-        }
-      }
-      break;
-    case 'D':
-      err = pn_data_put_described(data);
-      pn_data_enter(data);
-      break;
-    case 'T':
-      {
-        pni_node_t *parent = pn_data_node(data, data->parent);
-        if (parent->atom.type == PN_ARRAY) {
-          parent->type = (pn_type_t) va_arg(ap, int);
-        } else {
-          return pn_error_format(data->error, PN_ERR, "naked type");
-        }
-      }
-      break;
-    case '@':
-      {
-        bool described;
-        if (*(fmt + 1) == 'D') {
-          fmt++;
-          described = true;
-        } else {
-          described = false;
-        }
-        err = pn_data_put_array(data, described, (pn_type_t) 0);
-        pn_data_enter(data);
-      }
-      break;
-    case '[':
-      if (fmt < (begin + 2) || *(fmt - 2) != 'T') {
-        err = pn_data_put_list(data);
-        if (err) return err;
-        pn_data_enter(data);
-      }
-      break;
-    case '{':
-      err = pn_data_put_map(data);
-      if (err) return err;
-      pn_data_enter(data);
-      break;
-    case '}':
-    case ']':
-      if (!pn_data_exit(data))
-        return pn_error_format(data->error, PN_ERR, "exit failed");
-      break;
-    case '?':
-      if (!va_arg(ap, int)) {
-        err = pn_data_put_null(data);
-        if (err) return err;
-        pn_data_enter(data);
-      }
-      break;
-    case '*':
-      {
-        int count = va_arg(ap, int);
-        void *ptr = va_arg(ap, void *);
-
-        char c = *(fmt++);
-
-        switch (c)
-        {
-        case 's':
-          {
-            char **sptr = (char **) ptr;
-            for (int i = 0; i < count; i++)
-            {
-              char *sym = *(sptr++);
-              err = pn_data_fill(data, "s", sym);
-              if (err) return err;
-            }
-          }
-          break;
-        default:
-          pn_logf("unrecognized * code: 0x%.2X '%c'", code, code);
-          return PN_ARG_ERR;
-        }
-      }
-      break;
-    case 'C':
-      {
-        pn_data_t *src = va_arg(ap, pn_data_t *);
-        if (src && pn_data_size(src) > 0) {
-          err = pn_data_appendn(data, src, 1);
-          if (err) return err;
-        } else {
-          err = pn_data_put_null(data);
-          if (err) return err;
-        }
-      }
-      break;
-    default:
-      pn_logf("unrecognized fill code: 0x%.2X '%c'", code, code);
-      return PN_ARG_ERR;
-    }
-
-    if (err) return err;
-
-    pni_node_t *parent = pn_data_node(data, data->parent);
-    while (parent) {
-      if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
-        pn_data_exit(data);
-        parent = pn_data_node(data, data->parent);
-      } else if (parent->atom.type == PN_NULL && parent->children == 1) {
-        pn_data_exit(data);
-        pni_node_t *current = pn_data_node(data, data->current);
-        current->down = 0;
-        current->children = 0;
-        parent = pn_data_node(data, data->parent);
-      } else {
-        break;
-      }
-    }
-  }
-
-  return 0;
-}
-
-
-int pn_data_fill(pn_data_t *data, const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  int err = pn_data_vfill(data, fmt, ap);
-  va_end(ap);
-  return err;
-}
-
-static bool pn_scan_next(pn_data_t *data, pn_type_t *type, bool suspend)
-{
-  if (suspend) return false;
-  bool found = pn_data_next(data);
-  if (found) {
-    *type = pn_data_type(data);
-    return true;
-  } else {
-    pni_node_t *parent = pn_data_node(data, data->parent);
-    if (parent && parent->atom.type == PN_DESCRIBED) {
-      pn_data_exit(data);
-      return pn_scan_next(data, type, suspend);
-    } else {
-      *type = PN_INVALID;
-      return false;
-    }
-  }
-}
-
-static pni_node_t *pni_data_peek(pn_data_t *data);
-
-int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap)
-{
-  pn_data_rewind(data);
-  bool *scanarg = NULL;
-  bool at = false;
-  int level = 0;
-  int count_level = -1;
-  int resume_count = 0;
-
-  while (*fmt) {
-    char code = *(fmt++);
-
-    bool found = false;
-    pn_type_t type;
-
-    bool scanned = false;
-    bool suspend = resume_count > 0;
-
-    switch (code) {
-    case 'n':
-      found = pn_scan_next(data, &type, suspend);
-      if (found && type == PN_NULL) {
-        scanned = true;
-      } else {
-        scanned = false;
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'o':
-      {
-        bool *value = va_arg(ap, bool *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_BOOL) {
-          *value = pn_data_get_bool(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'B':
-      {
-        uint8_t *value = va_arg(ap, uint8_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_UBYTE) {
-          *value = pn_data_get_ubyte(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'b':
-      {
-        int8_t *value = va_arg(ap, int8_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_BYTE) {
-          *value = pn_data_get_byte(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'H':
-      {
-        uint16_t *value = va_arg(ap, uint16_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_USHORT) {
-          *value = pn_data_get_ushort(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'h':
-      {
-        int16_t *value = va_arg(ap, int16_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_SHORT) {
-          *value = pn_data_get_short(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'I':
-      {
-        uint32_t *value = va_arg(ap, uint32_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_UINT) {
-          *value = pn_data_get_uint(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'i':
-      {
-        int32_t *value = va_arg(ap, int32_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_INT) {
-          *value = pn_data_get_int(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'c':
-      {
-        pn_char_t *value = va_arg(ap, pn_char_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_CHAR) {
-          *value = pn_data_get_char(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'L':
-      {
-        uint64_t *value = va_arg(ap, uint64_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_ULONG) {
-          *value = pn_data_get_ulong(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'l':
-      {
-        int64_t *value = va_arg(ap, int64_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_LONG) {
-          *value = pn_data_get_long(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 't':
-      {
-        pn_timestamp_t *value = va_arg(ap, pn_timestamp_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_TIMESTAMP) {
-          *value = pn_data_get_timestamp(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'f':
-      {
-        float *value = va_arg(ap, float *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_FLOAT) {
-          *value = pn_data_get_float(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'd':
-      {
-        double *value = va_arg(ap, double *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_DOUBLE) {
-          *value = pn_data_get_double(data);
-          scanned = true;
-        } else {
-          *value = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'z':
-      {
-        pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_BINARY) {
-          *bytes = pn_data_get_binary(data);
-          scanned = true;
-        } else {
-          bytes->start = 0;
-          bytes->size = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'S':
-      {
-        pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_STRING) {
-          *bytes = pn_data_get_string(data);
-          scanned = true;
-        } else {
-          bytes->start = 0;
-          bytes->size = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 's':
-      {
-        pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_SYMBOL) {
-          *bytes = pn_data_get_symbol(data);
-          scanned = true;
-        } else {
-          bytes->start = 0;
-          bytes->size = 0;
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case 'D':
-      found = pn_scan_next(data, &type, suspend);
-      if (found && type == PN_DESCRIBED) {
-        pn_data_enter(data);
-        scanned = true;
-      } else {
-        if (!suspend) {
-          resume_count = 3;
-          count_level = level;
-        }
-        scanned = false;
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case '@':
-      found = pn_scan_next(data, &type, suspend);
-      if (found && type == PN_ARRAY) {
-        pn_data_enter(data);
-        scanned = true;
-        at = true;
-      } else {
-        if (!suspend) {
-          resume_count = 3;
-          count_level = level;
-        }
-        scanned = false;
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case '[':
-      if (at) {
-        scanned = true;
-        at = false;
-      } else {
-        found = pn_scan_next(data, &type, suspend);
-        if (found && type == PN_LIST) {
-          pn_data_enter(data);
-          scanned = true;
-        } else {
-          if (!suspend) {
-            resume_count = 1;
-            count_level = level;
-          }
-          scanned = false;
-        }
-      }
-      level++;
-      break;
-    case '{':
-      found = pn_scan_next(data, &type, suspend);
-      if (found && type == PN_MAP) {
-        pn_data_enter(data);
-        scanned = true;
-      } else {
-        if (resume_count) {
-          resume_count = 1;
-          count_level = level;
-        }
-        scanned = false;
-      }
-      level++;
-      break;
-    case ']':
-    case '}':
-      level--;
-      if (!suspend && !pn_data_exit(data))
-        return pn_error_format(data->error, PN_ERR, "exit failed");
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case '.':
-      found = pn_scan_next(data, &type, suspend);
-      scanned = found;
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    case '?':
-      if (!*fmt || *fmt == '?')
-        return pn_error_format(data->error, PN_ARG_ERR, "codes must follow a ?");
-      scanarg = va_arg(ap, bool *);
-      break;
-    case 'C':
-      {
-        pn_data_t *dst = va_arg(ap, pn_data_t *);
-        if (!suspend) {
-          size_t old = pn_data_size(dst);
-          pni_node_t *next = pni_data_peek(data);
-          if (next && next->atom.type != PN_NULL) {
-            pn_data_narrow(data);
-            int err = pn_data_appendn(dst, data, 1);
-            pn_data_widen(data);
-            if (err) return err;
-            scanned = pn_data_size(dst) > old;
-          } else {
-            scanned = false;
-          }
-          pn_data_next(data);
-        } else {
-          scanned = false;
-        }
-      }
-      if (resume_count && level == count_level) resume_count--;
-      break;
-    default:
-      return pn_error_format(data->error, PN_ARG_ERR, "unrecognized scan code: 0x%.2X '%c'", code, code);
-    }
-
-    if (scanarg && code != '?') {
-      *scanarg = scanned;
-      scanarg = NULL;
-    }
-  }
-
-  return 0;
-}
-
-int pn_data_scan(pn_data_t *data, const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  int err = pn_data_vscan(data, fmt, ap);
-  va_end(ap);
-  return err;
-}
-
-static int pni_data_inspectify(pn_data_t *data)
-{
-  int err = pn_string_set(data->str, "");
-  if (err) return err;
-  return pn_data_inspect(data, data->str);
-}
-
-int pn_data_print(pn_data_t *data)
-{
-  int err = pni_data_inspectify(data);
-  if (err) return err;
-  printf("%s", pn_string_get(data->str));
-  return 0;
-}
-
-int pn_data_format(pn_data_t *data, char *bytes, size_t *size)
-{
-  int err = pni_data_inspectify(data);
-  if (err) return err;
-  if (pn_string_size(data->str) >= *size) {
-    return PN_OVERFLOW;
-  } else {
-    pn_string_put(data->str, bytes);
-    *size = pn_string_size(data->str);
-    return 0;
-  }
-}
-
-static size_t pni_data_id(pn_data_t *data, pni_node_t *node)
-{
-  return node - data->nodes + 1;
-}
-
-static pni_node_t *pni_data_new(pn_data_t *data)
-{
-  if ((data->capacity <= data->size) && (pni_data_grow(data) != 0)) return NULL;
-  pni_node_t *node = pn_data_node(data, ++(data->size));
-  node->next = 0;
-  node->down = 0;
-  node->children = 0;
-  return node;
-}
-
-void pn_data_rewind(pn_data_t *data)
-{
-  data->parent = data->base_parent;
-  data->current = data->base_current;
-}
-
-static pni_node_t *pni_data_current(pn_data_t *data)
-{
-  return pn_data_node(data, data->current);
-}
-
-void pn_data_narrow(pn_data_t *data)
-{
-  data->base_parent = data->parent;
-  data->base_current = data->current;
-}
-
-void pn_data_widen(pn_data_t *data)
-{
-  data->base_parent = 0;
-  data->base_current = 0;
-}
-
-pn_handle_t pn_data_point(pn_data_t *data)
-{
-  if (data->current) {
-    return (pn_handle_t)(uintptr_t)data->current;
-  } else {
-    return (pn_handle_t)(uintptr_t)-data->parent;
-  }
-}
-
-bool pn_data_restore(pn_data_t *data, pn_handle_t point)
-{
-  pn_shandle_t spoint = (pn_shandle_t) point;
-  if (spoint <= 0 && ((size_t) (-spoint)) <= data->size) {
-    data->parent = -((pn_shandle_t) point);
-    data->current = 0;
-    return true;
-  } else if (spoint && spoint <= data->size) {
-    data->current = spoint;
-    pni_node_t *current = pni_data_current(data);
-    data->parent = current->parent;
-    return true;
-  } else {
-    return false;
-  }
-}
-
-static pni_node_t *pni_data_peek(pn_data_t *data)
-{
-  pni_node_t *current = pni_data_current(data);
-  if (current) {
-    return pn_data_node(data, current->next);
-  }
-
-  pni_node_t *parent = pn_data_node(data, data->parent);
-  if (parent) {
-    return pn_data_node(data, parent->down);
-  }
-
-  return NULL;
-}
-
-bool pn_data_next(pn_data_t *data)
-{
-  pni_node_t *current = pni_data_current(data);
-  pni_node_t *parent = pn_data_node(data, data->parent);
-  size_t next;
-
-  if (current) {
-    next = current->next;
-  } else if (parent && parent->down) {
-    next = parent->down;
-  } else if (!parent && data->size) {
-    next = 1;
-  } else {
-    return false;
-  }
-
-  if (next) {
-    data->current = next;
-    return true;
-  } else {
-    return false;
-  }
-}
-
-bool pn_data_prev(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->prev) {
-    data->current = node->prev;
-    return true;
-  } else {
-    return false;
-  }
-}
-
-int pni_data_traverse(pn_data_t *data,
-                      int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
-                      int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
-                      void *ctx)
-{
-  pni_node_t *node = data->size ? pn_data_node(data, 1) : NULL;
-  while (node) {
-    pni_node_t *parent = pn_data_node(data, node->parent);
-
-    int err = enter(ctx, data, node);
-    if (err) return err;
-
-    size_t next = 0;
-    if (node->down) {
-      next = node->down;
-    } else if (node->next) {
-      err = exit(ctx, data, node);
-      if (err) return err;
-      next = node->next;
-    } else {
-      err = exit(ctx, data, node);
-      if (err) return err;
-      while (parent) {
-        err = exit(ctx, data, parent);
-        if (err) return err;
-        if (parent->next) {
-          next = parent->next;
-          break;
-        } else {
-          parent = pn_data_node(data, parent->parent);
-        }
-      }
-    }
-
-    node = pn_data_node(data, next);
-  }
-
-  return 0;
-}
-
-pn_type_t pn_data_type(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node) {
-    return node->atom.type;
-  } else {
-    return PN_INVALID;
-  }
-}
-
-pn_type_t pni_data_parent_type(pn_data_t *data)
-{
-  pni_node_t *node = pn_data_node(data, data->parent);
-  if (node) {
-    return node->atom.type;
-  } else {
-    return PN_INVALID;
-  }
-}
-
-size_t pn_data_siblings(pn_data_t *data)
-{
-  pni_node_t *node = pn_data_node(data, data->parent);
-  if (node) {
-    return node->children;
-  } else {
-    return 0;
-  }
-}
-
-bool pn_data_enter(pn_data_t *data)
-{
-  if (data->current) {
-    data->parent = data->current;
-    data->current = 0;
-    return true;
-  } else {
-    return false;
-  }
-}
-
-bool pn_data_exit(pn_data_t *data)
-{
-  if (data->parent) {
-    pni_node_t *parent = pn_data_node(data, data->parent);
-    data->current = data->parent;
-    data->parent = parent->parent;
-    return true;
-  } else {
-    return false;
-  }
-}
-
-bool pn_data_lookup(pn_data_t *data, const char *name)
-{
-  while (pn_data_next(data)) {
-    pn_type_t type = pn_data_type(data);
-
-    switch (type) {
-    case PN_STRING:
-    case PN_SYMBOL:
-      {
-        pn_bytes_t bytes = pn_data_get_bytes(data);
-        if (strlen(name) == bytes.size && !strncmp(name, bytes.start, bytes.size)) {
-          return pn_data_next(data);
-        }
-      }
-      break;
-    default:
-      break;
-    }
-
-    // skip the value
-    pn_data_next(data);
-  }
-
-  return false;
-}
-
-void pn_data_dump(pn_data_t *data)
-{
-  printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", (size_t) data->current, (size_t) data->parent);
-  for (unsigned i = 0; i < data->size; i++)
-  {
-    pni_node_t *node = &data->nodes[i];
-    pn_string_set(data->str, "");
-    pni_inspect_atom((pn_atom_t *) &node->atom, data->str);
-    printf("Node %i: prev=%" PN_ZI ", next=%" PN_ZI ", parent=%" PN_ZI ", down=%" PN_ZI 
-           ", children=%" PN_ZI ", type=%s (%s)\n",
-           i + 1, (size_t) node->prev,
-           (size_t) node->next,
-           (size_t) node->parent,
-           (size_t) node->down,
-           (size_t) node->children,
-           pn_type_name(node->atom.type), pn_string_get(data->str));
-  }
-}
-
-static pni_node_t *pni_data_add(pn_data_t *data)
-{
-  pni_node_t *current = pni_data_current(data);
-  pni_node_t *parent = pn_data_node(data, data->parent);
-  pni_node_t *node;
-
-  if (current) {
-    if (current->next) {
-      node = pn_data_node(data, current->next);
-    } else {
-      node = pni_data_new(data);
-      if (!node) return NULL;
-
-      // refresh the pointers in case we grew
-      current = pni_data_current(data);
-      parent = pn_data_node(data, data->parent);
-      node->prev = data->current;
-      current->next = pni_data_id(data, node);
-      node->parent = data->parent;
-      if (parent) {
-        if (!parent->down) {
-          parent->down = pni_data_id(data, node);
-        }
-        parent->children++;
-      }
-    }
-  } else if (parent) {
-    if (parent->down) {
-      node = pn_data_node(data, parent->down);
-    } else {
-      node = pni_data_new(data);
-      if (!node) return NULL;
-
-      // refresh the pointers in case we grew
-      parent = pn_data_node(data, data->parent);
-      node->prev = 0;
-      node->parent = data->parent;
-      parent->down = pni_data_id(data, node);
-      parent->children++;
-    }
-  } else if (data->size) {
-    node = pn_data_node(data, 1);
-  } else {
-    node = pni_data_new(data);
-    if (!node) return NULL;
-
-    node->prev = 0;
-    node->parent = 0;
-  }
-
-  node->down = 0;
-  node->children = 0;
-  node->data = false;
-  node->data_offset = 0;
-  node->data_size = 0;
-  data->current = pni_data_id(data, node);
-  return node;
-}
-
-ssize_t pn_data_encode(pn_data_t *data, char *bytes, size_t size)
-{
-  return pn_encoder_encode(data->encoder, data, bytes, size);
-}
-
-ssize_t pn_data_encoded_size(pn_data_t *data)
-{
-  return pn_encoder_size(data->encoder, data);
-}
-
-ssize_t pn_data_decode(pn_data_t *data, const char *bytes, size_t size)
-{
-  return pn_decoder_decode(data->decoder, bytes, size, data);
-}
-
-int pn_data_put_list(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_LIST;
-  return 0;
-}
-
-int pn_data_put_map(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_MAP;
-  return 0;
-}
-
-int pn_data_put_array(pn_data_t *data, bool described, pn_type_t type)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_ARRAY;
-  node->described = described;
-  node->type = type;
-  return 0;
-}
-
-void pni_data_set_array_type(pn_data_t *data, pn_type_t type)
-{
-  pni_node_t *array = pni_data_current(data);
-  if (array) array->type = type;
-}
-
-int pn_data_put_described(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DESCRIBED;
-  return 0;
-}
-
-int pn_data_put_null(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  pni_atom_init(&node->atom, PN_NULL);
-  return 0;
-}
-
-int pn_data_put_bool(pn_data_t *data, bool b)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_BOOL;
-  node->atom.u.as_bool = b;
-  return 0;
-}
-
-int pn_data_put_ubyte(pn_data_t *data, uint8_t ub)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_UBYTE;
-  node->atom.u.as_ubyte = ub;
-  return 0;
-}
-
-int pn_data_put_byte(pn_data_t *data, int8_t b)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_BYTE;
-  node->atom.u.as_byte = b;
-  return 0;
-}
-
-int pn_data_put_ushort(pn_data_t *data, uint16_t us)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_USHORT;
-  node->atom.u.as_ushort = us;
-  return 0;
-}
-
-int pn_data_put_short(pn_data_t *data, int16_t s)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_SHORT;
-  node->atom.u.as_short = s;
-  return 0;
-}
-
-int pn_data_put_uint(pn_data_t *data, uint32_t ui)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_UINT;
-  node->atom.u.as_uint = ui;
-  return 0;
-}
-
-int pn_data_put_int(pn_data_t *data, int32_t i)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_INT;
-  node->atom.u.as_int = i;
-  return 0;
-}
-
-int pn_data_put_char(pn_data_t *data, pn_char_t c)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_CHAR;
-  node->atom.u.as_char = c;
-  return 0;
-}
-
-int pn_data_put_ulong(pn_data_t *data, uint64_t ul)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_ULONG;
-  node->atom.u.as_ulong = ul;
-  return 0;
-}
-
-int pn_data_put_long(pn_data_t *data, int64_t l)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_LONG;
-  node->atom.u.as_long = l;
-  return 0;
-}
-
-int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t t)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_TIMESTAMP;
-  node->atom.u.as_timestamp = t;
-  return 0;
-}
-
-int pn_data_put_float(pn_data_t *data, float f)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_FLOAT;
-  node->atom.u.as_float = f;
-  return 0;
-}
-
-int pn_data_put_double(pn_data_t *data, double d)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DOUBLE;
-  node->atom.u.as_double = d;
-  return 0;
-}
-
-int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t d)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DECIMAL32;
-  node->atom.u.as_decimal32 = d;
-  return 0;
-}
-
-int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t d)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DECIMAL64;
-  node->atom.u.as_decimal64 = d;
-  return 0;
-}
-
-int pn_data_put_decimal128(pn_data_t *data, pn_decimal128_t d)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_DECIMAL128;
-  memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16);
-  return 0;
-}
-
-int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_UUID;
-  memmove(node->atom.u.as_uuid.bytes, u.bytes, 16);
-  return 0;
-}
-
-int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_BINARY;
-  node->atom.u.as_bytes = bytes;
-  return pni_data_intern_node(data, node);
-}
-
-int pn_data_put_string(pn_data_t *data, pn_bytes_t string)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_STRING;
-  node->atom.u.as_bytes = string;
-  return pni_data_intern_node(data, node);
-}
-
-int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom.type = PN_SYMBOL;
-  node->atom.u.as_bytes = symbol;
-  return pni_data_intern_node(data, node);
-}
-
-int pn_data_put_atom(pn_data_t *data, pn_atom_t atom)
-{
-  pni_node_t *node = pni_data_add(data);
-  if (node == NULL) return PN_OUT_OF_MEMORY;
-  node->atom = atom;
-  return pni_data_intern_node(data, node);
-}
-
-size_t pn_data_get_list(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_LIST) {
-    return node->children;
-  } else {
-    return 0;
-  }
-}
-
-size_t pn_data_get_map(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_MAP) {
-    return node->children;
-  } else {
-    return 0;
-  }
-}
-
-size_t pn_data_get_array(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ARRAY) {
-    if (node->described) {
-      return node->children - 1;
-    } else {
-      return node->children;
-    }
-  } else {
-    return 0;
-  }
-}
-
-bool pn_data_is_array_described(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ARRAY) {
-    return node->described;
-  } else {
-    return false;
-  }
-}
-
-pn_type_t pn_data_get_array_type(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ARRAY) {
-    return node->type;
-  } else {
-    return PN_INVALID;
-  }
-}
-
-bool pn_data_is_described(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  return node && node->atom.type == PN_DESCRIBED;
-}
-
-bool pn_data_is_null(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  return node && node->atom.type == PN_NULL;
-}
-
-bool pn_data_get_bool(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_BOOL) {
-    return node->atom.u.as_bool;
-  } else {
-    return false;
-  }
-}
-
-uint8_t pn_data_get_ubyte(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_UBYTE) {
-    return node->atom.u.as_ubyte;
-  } else {
-    return 0;
-  }
-}
-
-int8_t pn_data_get_byte(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_BYTE) {
-    return node->atom.u.as_byte;
-  } else {
-    return 0;
-  }
-}
-
-uint16_t pn_data_get_ushort(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_USHORT) {
-    return node->atom.u.as_ushort;
-  } else {
-    return 0;
-  }
-}
-
-int16_t pn_data_get_short(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_SHORT) {
-    return node->atom.u.as_short;
-  } else {
-    return 0;
-  }
-}
-
-uint32_t pn_data_get_uint(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_UINT) {
-    return node->atom.u.as_uint;
-  } else {
-    return 0;
-  }
-}
-
-int32_t pn_data_get_int(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_INT) {
-    return node->atom.u.as_int;
-  } else {
-    return 0;
-  }
-}
-
-pn_char_t pn_data_get_char(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_CHAR) {
-    return node->atom.u.as_char;
-  } else {
-    return 0;
-  }
-}
-
-uint64_t pn_data_get_ulong(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_ULONG) {
-    return node->atom.u.as_ulong;
-  } else {
-    return 0;
-  }
-}
-
-int64_t pn_data_get_long(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_LONG) {
-    return node->atom.u.as_long;
-  } else {
-    return 0;
-  }
-}
-
-pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_TIMESTAMP) {
-    return node->atom.u.as_timestamp;
-  } else {
-    return 0;
-  }
-}
-
-float pn_data_get_float(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_FLOAT) {
-    return node->atom.u.as_float;
-  } else {
-    return 0;
-  }
-}
-
-double pn_data_get_double(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DOUBLE) {
-    return node->atom.u.as_double;
-  } else {
-    return 0;
-  }
-}
-
-pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DECIMAL32) {
-    return node->atom.u.as_decimal32;
-  } else {
-    return 0;
-  }
-}
-
-pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DECIMAL64) {
-    return node->atom.u.as_decimal64;
-  } else {
-    return 0;
-  }
-}
-
-pn_decimal128_t pn_data_get_decimal128(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_DECIMAL128) {
-    return node->atom.u.as_decimal128;
-  } else {
-    pn_decimal128_t t = {{0}};
-    return t;
-  }
-}
-
-pn_uuid_t pn_data_get_uuid(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_UUID) {
-    return node->atom.u.as_uuid;
-  } else {
-    pn_uuid_t t = {{0}};
-    return t;
-  }
-}
-
-pn_bytes_t pn_data_get_binary(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_BINARY) {
-    return node->atom.u.as_bytes;
-  } else {
-    pn_bytes_t t = {0};
-    return t;
-  }
-}
-
-pn_bytes_t pn_data_get_string(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_STRING) {
-    return node->atom.u.as_bytes;
-  } else {
-    pn_bytes_t t = {0};
-    return t;
-  }
-}
-
-pn_bytes_t pn_data_get_symbol(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && node->atom.type == PN_SYMBOL) {
-    return node->atom.u.as_bytes;
-  } else {
-    pn_bytes_t t = {0};
-    return t;
-  }
-}
-
-pn_bytes_t pn_data_get_bytes(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node && (node->atom.type == PN_BINARY ||
-               node->atom.type == PN_STRING ||
-               node->atom.type == PN_SYMBOL)) {
-    return node->atom.u.as_bytes;
-  } else {
-    pn_bytes_t t = {0};
-    return t;
-  }
-}
-
-pn_atom_t pn_data_get_atom(pn_data_t *data)
-{
-  pni_node_t *node = pni_data_current(data);
-  if (node) {
-    return *((pn_atom_t *) &node->atom);
-  } else {
-    pn_atom_t t = {PN_NULL, {0,}};
-    return t;
-  }
-}
-
-int pn_data_copy(pn_data_t *data, pn_data_t *src)
-{
-  pn_data_clear(data);
-  int err = pn_data_append(data, src);
-  pn_data_rewind(data);
-  return err;
-}
-
-int pn_data_append(pn_data_t *data, pn_data_t *src)
-{
-  return pn_data_appendn(data, src, -1);
-}
-
-int pn_data_appendn(pn_data_t *data, pn_data_t *src, int limit)
-{
-  int err = 0;
-  int level = 0, count = 0;
-  bool stop = false;
-  pn_handle_t point = pn_data_point(src);
-  pn_data_rewind(src);
-
-  while (true) {
-    while (!pn_data_next(src)) {
-      if (level > 0) {
-        pn_data_exit(data);
-        pn_data_exit(src);
-        level--;
-        continue;
-      }
-
-      if (!pn_data_next(src)) {
-        stop = true;
-      }
-      break;
-    }
-
-    if (stop) break;
-
-    if (level == 0 && count == limit)
-      break;
-
-    pn_type_t type = pn_data_type(src);
-    switch (type) {
-    case PN_NULL:
-      err = pn_data_put_null(data);
-      if (level == 0) count++;
-      break;
-    case PN_BOOL:
-      err = pn_data_put_bool(data, pn_data_get_bool(src));
-      if (level == 0) count++;
-      break;
-    case PN_UBYTE:
-      err = pn_data_put_ubyte(data, pn_data_get_ubyte(src));
-      if (level == 0) count++;
-      break;
-    case PN_BYTE:
-      err = pn_data_put_byte(data, pn_data_get_byte(src));
-      if (level == 0) count++;
-      break;
-    case PN_USHORT:
-      err = pn_data_put_ushort(data, pn_data_get_ushort(src));
-      if (level == 0) count++;
-      break;
-    case PN_SHORT:
-      err = pn_data_put_short(data, pn_data_get_short(src));
-      if (level == 0) count++;
-      break;
-    case PN_UINT:
-      err = pn_data_put_uint(data, pn_data_get_uint(src));
-      if (level == 0) count++;
-      break;
-    case PN_INT:
-      err = pn_data_put_int(data, pn_data_get_int(src));
-      if (level == 0) count++;
-      break;
-    case PN_CHAR:
-      err = pn_data_put_char(data, pn_data_get_char(src));
-      if (level == 0) count++;
-      break;
-    case PN_ULONG:
-      err = pn_data_put_ulong(data, pn_data_get_ulong(src));
-      if (level == 0) count++;
-      break;
-    case PN_LONG:
-      err = pn_data_put_long(data, pn_data_get_long(src));
-      if (level == 0) count++;
-      break;
-    case PN_TIMESTAMP:
-      err = pn_data_put_timestamp(data, pn_data_get_timestamp(src));
-      if (level == 0) count++;
-      break;
-    case PN_FLOAT:
-      err = pn_data_put_float(data, pn_data_get_float(src));
-      if (level == 0) count++;
-      break;
-    case PN_DOUBLE:
-      err = pn_data_put_double(data, pn_data_get_double(src));
-      if (level == 0) count++;
-      break;
-    case PN_DECIMAL32:
-      err = pn_data_put_decimal32(data, pn_data_get_decimal32(src));
-      if (level == 0) count++;
-      break;
-    case PN_DECIMAL64:
-      err = pn_data_put_decimal64(data, pn_data_get_decimal64(src));
-      if (level == 0) count++;
-      break;
-    case PN_DECIMAL128:
-      err = pn_data_put_decimal128(data, pn_data_get_decimal128(src));
-      if (level == 0) count++;
-      break;
-    case PN_UUID:
-      err = pn_data_put_uuid(data, pn_data_get_uuid(src));
-      if (level == 0) count++;
-      break;
-    case PN_BINARY:
-      err = pn_data_put_binary(data, pn_data_get_binary(src));
-      if (level == 0) count++;
-      break;
-    case PN_STRING:
-      err = pn_data_put_string(data, pn_data_get_string(src));
-      if (level == 0) count++;
-      break;
-    case PN_SYMBOL:
-      err = pn_data_put_symbol(data, pn_data_get_symbol(src));
-      if (level == 0) count++;
-      break;
-    case PN_DESCRIBED:
-      err = pn_data_put_described(data);
-      if (level == 0) count++;
-      if (err) { pn_data_restore(src, point); return err; }
-      pn_data_enter(data);
-      pn_data_enter(src);
-      level++;
-      break;
-    case PN_ARRAY:
-      err = pn_data_put_array(data, pn_data_is_array_described(src),
-                              pn_data_get_array_type(src));
-      if (level == 0) count++;
-      if (err) { pn_data_restore(src, point); return err; }
-      pn_data_enter(data);
-      pn_data_enter(src);
-      level++;
-      break;
-    case PN_LIST:
-      err = pn_data_put_list(data);
-      if (level == 0) count++;
-      if (err) { pn_data_restore(src, point); return err; }
-      pn_data_enter(data);
-      pn_data_enter(src);
-      level++;
-      break;
-    case PN_MAP:
-      err = pn_data_put_map(data);
-      if (level == 0) count++;
-      if (err) { pn_data_restore(src, point); return err; }
-      pn_data_enter(data);
-      pn_data_enter(src);
-      level++;
-      break;
-    default:
-      break;
-    }
-
-    if (err) { pn_data_restore(src, point); return err; }
-  }
-
-  pn_data_restore(src, point);
-
-  return 0;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/data.h b/proton-c/src/codec/data.h
deleted file mode 100644
index 94dc7d6..0000000
--- a/proton-c/src/codec/data.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef _PROTON_DATA_H
-#define _PROTON_DATA_H 1
-
-/*
- *
- * 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/codec.h>
-#include "buffer.h"
-#include "decoder.h"
-#include "encoder.h"
-
-typedef uint16_t pni_nid_t;
-#define PNI_NID_MAX ((pni_nid_t)-1)
-
-typedef struct {
-  char *start;
-  size_t data_offset;
-  size_t data_size;
-  pn_atom_t atom;
-  pn_type_t type;
-  pni_nid_t next;
-  pni_nid_t prev;
-  pni_nid_t down;
-  pni_nid_t parent;
-  pni_nid_t children;
-  // for arrays
-  bool described;
-  bool data;
-  bool small;
-} pni_node_t;
-
-struct pn_data_t {
-  pni_node_t *nodes;
-  pn_buffer_t *buf;
-  pn_decoder_t *decoder;
-  pn_encoder_t *encoder;
-  pn_error_t *error;
-  pn_string_t *str;
-  pni_nid_t capacity;
-  pni_nid_t size;
-  pni_nid_t parent;
-  pni_nid_t current;
-  pni_nid_t base_parent;
-  pni_nid_t base_current;
-};
-
-static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd) 
-{
-  return nd ? (data->nodes + nd - 1) : NULL;
-}
-
-int pni_data_traverse(pn_data_t *data,
-                      int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
-                      int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
-                      void *ctx);
-
-#endif /* data.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.c b/proton-c/src/codec/decoder.c
deleted file mode 100644
index b0c8d79..0000000
--- a/proton-c/src/codec/decoder.c
+++ /dev/null
@@ -1,497 +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/error.h>
-#include <proton/object.h>
-#include <proton/codec.h>
-#include "encodings.h"
-#include "decoder.h"
-
-#include <string.h>
-
-struct pn_decoder_t {
-  const char *input;
-  size_t size;
-  const char *position;
-  pn_error_t *error;
-};
-
-static void pn_decoder_initialize(void *obj)
-{
-  pn_decoder_t *decoder = (pn_decoder_t *) obj;
-  decoder->input = NULL;
-  decoder->size = 0;
-  decoder->position = NULL;
-  decoder->error = pn_error();
-}
-
-static void pn_decoder_finalize(void *obj) {
-  pn_decoder_t *decoder = (pn_decoder_t *) obj;
-  pn_error_free(decoder->error);
-}
-
-#define pn_decoder_hashcode NULL
-#define pn_decoder_compare NULL
-#define pn_decoder_inspect NULL
-
-pn_decoder_t *pn_decoder()
-{
-  static const pn_class_t clazz = PN_CLASS(pn_decoder);
-  return (pn_decoder_t *) pn_class_new(&clazz, sizeof(pn_decoder_t));
-}
-
-static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)
-{
-  uint8_t r = decoder->position[0];
-  decoder->position++;
-  return r;
-}
-
-static inline uint16_t pn_decoder_readf16(pn_decoder_t *decoder)
-{
-  uint16_t a = (uint8_t) decoder->position[0];
-  uint16_t b = (uint8_t) decoder->position[1];
-  uint16_t r = a << 8
-    | b;
-  decoder->position += 2;
-  return r;
-}
-
-static inline uint32_t pn_decoder_readf32(pn_decoder_t *decoder)
-{
-  uint32_t a = (uint8_t) decoder->position[0];
-  uint32_t b = (uint8_t) decoder->position[1];
-  uint32_t c = (uint8_t) decoder->position[2];
-  uint32_t d = (uint8_t) decoder->position[3];
-  uint32_t r = a << 24
-    | b << 16
-    | c <<  8
-    | d;
-  decoder->position += 4;
-  return r;
-}
-
-static inline uint64_t pn_decoder_readf64(pn_decoder_t *decoder)
-{
-  uint64_t a = pn_decoder_readf32(decoder);
-  uint64_t b = pn_decoder_readf32(decoder);
-  return a << 32 | b;
-}
-
-static inline void pn_decoder_readf128(pn_decoder_t *decoder, void *dst)
-{
-  memmove(dst, decoder->position, 16);
-  decoder->position += 16;
-}
-
-static inline size_t pn_decoder_remaining(pn_decoder_t *decoder)
-{
-  return decoder->input + decoder->size - decoder->position;
-}
-
-typedef union {
-  uint32_t i;
-  uint32_t a[2];
-  uint64_t l;
-  float f;
-  double d;
-} conv_t;
-
-static inline pn_type_t pn_code2type(uint8_t code)
-{
-  switch (code)
-  {
-  case PNE_DESCRIPTOR:
-    return (pn_type_t) PN_ARG_ERR;
-  case PNE_NULL:
-    return PN_NULL;
-  case PNE_TRUE:
-  case PNE_FALSE:
-  case PNE_BOOLEAN:
-    return PN_BOOL;
-  case PNE_UBYTE:
-    return PN_UBYTE;
-  case PNE_BYTE:
-    return PN_BYTE;
-  case PNE_USHORT:
-    return PN_USHORT;
-  case PNE_SHORT:
-    return PN_SHORT;
-  case PNE_UINT0:
-  case PNE_SMALLUINT:
-  case PNE_UINT:
-    return PN_UINT;
-  case PNE_SMALLINT:
-  case PNE_INT:
-    return PN_INT;
-  case PNE_UTF32:
-    return PN_CHAR;
-  case PNE_FLOAT:
-    return PN_FLOAT;
-  case PNE_LONG:
-  case PNE_SMALLLONG:
-    return PN_LONG;
-  case PNE_MS64:
-    return PN_TIMESTAMP;
-  case PNE_DOUBLE:
-    return PN_DOUBLE;
-  case PNE_DECIMAL32:
-    return PN_DECIMAL32;
-  case PNE_DECIMAL64:
-    return PN_DECIMAL64;
-  case PNE_DECIMAL128:
-    return PN_DECIMAL128;
-  case PNE_UUID:
-    return PN_UUID;
-  case PNE_ULONG0:
-  case PNE_SMALLULONG:
-  case PNE_ULONG:
-    return PN_ULONG;
-  case PNE_VBIN8:
-  case PNE_VBIN32:
-    return PN_BINARY;
-  case PNE_STR8_UTF8:
-  case PNE_STR32_UTF8:
-    return PN_STRING;
-  case PNE_SYM8:
-  case PNE_SYM32:
-    return PN_SYMBOL;
-  case PNE_LIST0:
-  case PNE_LIST8:
-  case PNE_LIST32:
-    return PN_LIST;
-  case PNE_ARRAY8:
-  case PNE_ARRAY32:
-    return PN_ARRAY;
-  case PNE_MAP8:
-  case PNE_MAP32:
-    return PN_MAP;
-  default:
-    return (pn_type_t) PN_ARG_ERR;
-  }
-}
-
-static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code);
-static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data);
-void pni_data_set_array_type(pn_data_t *data, pn_type_t type);
-
-static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
-{
-  int err;
-  conv_t conv;
-  pn_decimal128_t dec128;
-  pn_uuid_t uuid;
-  size_t size;
-  size_t count;
-
-  switch (code)
-  {
-  case PNE_NULL:
-    err = pn_data_put_null(data);
-    break;
-  case PNE_TRUE:
-    err = pn_data_put_bool(data, true);
-    break;
-  case PNE_FALSE:
-    err = pn_data_put_bool(data, false);
-    break;
-  case PNE_BOOLEAN:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
-    break;
-  case PNE_UBYTE:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
-    break;
-  case PNE_BYTE:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
-    break;
-  case PNE_USHORT:
-    if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
-    err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
-    break;
-  case PNE_SHORT:
-    if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
-    err = pn_data_put_short(data, pn_decoder_readf16(decoder));
-    break;
-  case PNE_UINT:
-    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
-    err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
-    break;
-  case PNE_UINT0:
-    err = pn_data_put_uint(data, 0);
-    break;
-  case PNE_SMALLUINT:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
-    break;
-  case PNE_SMALLINT:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
-    break;
-  case PNE_INT:
-    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
-    err = pn_data_put_int(data, pn_decoder_readf32(decoder));
-    break;
-  case PNE_UTF32:
-    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
-    err = pn_data_put_char(data, pn_decoder_readf32(decoder));
-    break;
-  case PNE_FLOAT:
-    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
-    // XXX: this assumes the platform uses IEEE floats
-    conv.i = pn_decoder_readf32(decoder);
-    err = pn_data_put_float(data, conv.f);
-    break;
-  case PNE_DECIMAL32:
-    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
-    err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
-    break;
-  case PNE_ULONG:
-    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
-    err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
-    break;
-  case PNE_LONG:
-    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
-    err = pn_data_put_long(data, pn_decoder_readf64(decoder));
-    break;
-  case PNE_MS64:
-    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
-    err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
-    break;
-  case PNE_DOUBLE:
-    // XXX: this assumes the platform uses IEEE floats
-    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
-    conv.l = pn_decoder_readf64(decoder);
-    err = pn_data_put_double(data, conv.d);
-    break;
-  case PNE_DECIMAL64:
-    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
-    err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
-    break;
-  case PNE_ULONG0:
-    err = pn_data_put_ulong(data, 0);
-    break;
-  case PNE_SMALLULONG:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
-    break;
-  case PNE_SMALLLONG:
-    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-    err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
-    break;
-  case PNE_DECIMAL128:
-    if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
-    pn_decoder_readf128(decoder, &dec128);
-    err = pn_data_put_decimal128(data, dec128);
-    break;
-  case PNE_UUID:
-    if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
-    pn_decoder_readf128(decoder, &uuid);
-    err = pn_data_put_uuid(data, uuid);
-    break;
-  case PNE_VBIN8:
-  case PNE_STR8_UTF8:
-  case PNE_SYM8:
-  case PNE_VBIN32:
-  case PNE_STR32_UTF8:
-  case PNE_SYM32:
-    switch (code & 0xF0)
-    {
-    case 0xA0:
-      if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
-      size = pn_decoder_readf8(decoder);
-      break;
-    case 0xB0:
-      if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
-      size = pn_decoder_readf32(decoder);
-      break;
-    default:
-      return PN_ARG_ERR;
-    }
-
-    if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
-
-    {
-      char *start = (char *) decoder->position;
-      pn_bytes_t bytes = {size, start};
-      switch (code & 0x0F)
-      {
-      case 0x0:
-        err = pn_data_put_binary(data, bytes);
-        break;
-      case 0x1:
-        err = pn_data_put_string(data, bytes);
-        break;
-      case 0x3:
-        err = pn_data_put_symbol(data, bytes);
-        break;
-      default:
-        return PN_ARG_ERR;
-      }
-    }
-
-    decoder->position += size;
-    break;
-  case PNE_LIST0:
-    err = pn_data_put_list(data);
-    break;
-  case PNE_ARRAY8:
-  case PNE_ARRAY32:
-  case PNE_LIST8:
-  case PNE_LIST32:
-  case PNE_MAP8:
-  case PNE_MAP32:
-    switch (code)
-    {
-    case PNE_ARRAY8:
-    case PNE_LIST8:
-    case PNE_MAP8:
-      if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
-      size = pn_decoder_readf8(decoder);
-      count = pn_decoder_readf8(decoder);
-      break;
-    case PNE_ARRAY32:
-    case PNE_LIST32:
-    case PNE_MAP32:
-      size = pn_decoder_readf32(decoder);
-      count = pn_decoder_readf32(decoder);
-      break;
-    default:
-      return PN_ARG_ERR;
-    }
-
-    switch (code)
-    {
-    case PNE_ARRAY8:
-    case PNE_ARRAY32:
-      {
-        uint8_t next = *decoder->position;
-        bool described = (next == PNE_DESCRIPTOR);
-        err = pn_data_put_array(data, described, (pn_type_t) 0);
-        if (err) return err;
-
-        pn_data_enter(data);
-        uint8_t acode;
-        int e = pni_decoder_decode_type(decoder, data, &acode);
-        if (e) return e;
-        pn_type_t type = pn_code2type(acode);
-        if ((int)type < 0) return (int)type;
-        for (size_t i = 0; i < count; i++)
-        {
-          e = pni_decoder_decode_value(decoder, data, acode);
-          if (e) return e;
-        }
-        pn_data_exit(data);
-
-        pni_data_set_array_type(data, type);
-      }
-      return 0;
-    case PNE_LIST8:
-    case PNE_LIST32:
-      err = pn_data_put_list(data);
-      if (err) return err;
-      break;
-    case PNE_MAP8:
-    case PNE_MAP32:
-      err = pn_data_put_map(data);
-      if (err) return err;
-      break;
-    default:
-      return PN_ARG_ERR;
-    }
-
-    pn_data_enter(data);
-    for (size_t i = 0; i < count; i++)
-    {
-      int e = pni_decoder_single(decoder, data);
-      if (e) return e;
-    }
-    pn_data_exit(data);
-
-    return 0;
-  default:
-    return pn_error_format(decoder->error, PN_ARG_ERR, "unrecognized typecode: %u", code);
-  }
-
-  return err;
-}
-
-pn_type_t pni_data_parent_type(pn_data_t *data);
-
-static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code)
-{
-  int err;
-
-  if (!pn_decoder_remaining(decoder)) {
-    return PN_UNDERFLOW;
-  }
-
-  uint8_t next = *decoder->position++;
-
-  if (next == PNE_DESCRIPTOR) {
-    if (pni_data_parent_type(data) != PN_ARRAY) {
-      err = pn_data_put_described(data);
-      if (err) return err;
-      // pni_decoder_single has the corresponding exit
-      pn_data_enter(data);
-    }
-    err = pni_decoder_single(decoder, data);
-    if (err) return err;
-    err = pni_decoder_decode_type(decoder, data, code);
-    if (err) return err;
-  } else {
-    *code = next;
-  }
-
-  return 0;
-}
-
-size_t pn_data_siblings(pn_data_t *data);
-
-int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data)
-{
-  uint8_t code;
-  int err = pni_decoder_decode_type(decoder, data, &code);
-  if (err) return err;
-  err = pni_decoder_decode_value(decoder, data, code);
-  if (err) return err;
-  if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
-    pn_data_exit(data);
-  }
-  return 0;
-}
-
-ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst)
-{
-  decoder->input = src;
-  decoder->size = size;
-  decoder->position = src;
-
-  int err = pni_decoder_single(decoder, dst);
-
-  if (err == PN_UNDERFLOW) 
-      return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode");
-  if (err) return err;
-
-  return decoder->position - decoder->input;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/decoder.h b/proton-c/src/codec/decoder.h
deleted file mode 100644
index b7de898..0000000
--- a/proton-c/src/codec/decoder.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _PROTON_DECODER_H
-#define _PROTON_DECODER_H 1
-
-/*
- *
- * 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.
- *
- */
-
-typedef struct pn_decoder_t pn_decoder_t;
-
-pn_decoder_t *pn_decoder(void);
-ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst);
-
-#endif /* decoder.h */


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


[20/20] qpid-proton git commit: PROTON-1351: Make go binding only depend on qpid-proton-core

Posted by as...@apache.org.
PROTON-1351: Make go binding only depend on qpid-proton-core


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

Branch: refs/heads/master
Commit: eac0bb663dd16bd9f43126038e22a0b4d0247c78
Parents: a585071
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Nov 14 12:55:28 2016 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Mon Nov 14 12:55:28 2016 -0500

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


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/CMakeLists.txt b/proton-c/bindings/go/CMakeLists.txt
index 269f9bf..16c633b 100644
--- a/proton-c/bindings/go/CMakeLists.txt
+++ b/proton-c/bindings/go/CMakeLists.txt
@@ -58,7 +58,7 @@ set(GO_TEST ${GO} test ${GO_BUILD_FLAGS} ${GO_RPATH_FLAGS} ${GO_TEST_FLAGS} CACH
 # done.
 add_custom_target(go-build ALL
   COMMAND ${GO_INSTALL} qpid.apache.org/...
-  DEPENDS qpid-proton
+  DEPENDS qpid-proton-core
   WORKING_DIRECTORY $ENV{PWD})
 
 add_test(

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

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

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/eac0bb66/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
index 083f701..27bc5ec 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/proton/doc.go
@@ -58,7 +58,7 @@ applications.
 */
 package proton
 
-// #cgo LDFLAGS: -lqpid-proton
+// #cgo LDFLAGS: -lqpid-proton-core
 import "C"
 
 // This file is just for the package comment.

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


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


[02/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/schannel.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/schannel.c b/proton-c/src/windows/schannel.c
deleted file mode 100644
index 0201034..0000000
--- a/proton-c/src/windows/schannel.c
+++ /dev/null
@@ -1,2239 +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.
- *
- */
-
-/*
- * SChannel is designed to encrypt and decrypt data in place.  So a
- * given buffer is expected to sometimes contain encrypted data,
- * sometimes decrypted data, and occasionally both.  Outgoing buffers
- * need to reserve space for the TLS header and trailer.  Read
- * operations need to ignore the same headers and trailers from
- * incoming buffers.  Outgoing is simple because we choose record
- * boundaries.  Incoming is complicated by handling incomplete TLS
- * records, and buffering contiguous data for the app layer that may
- * span many records.  A lazy double buffering system is used for
- * the latter.
- */
-
-#include <proton/ssl.h>
-#include <proton/engine.h>
-#include "engine/engine-internal.h"
-#include "platform.h"
-#include "util.h"
-#include "transport/autodetect.h"
-
-#include <assert.h>
-
-// security.h needs to see this to distinguish from kernel use.
-#include <windows.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <Schnlsp.h>
-#include <WinInet.h>
-#undef SECURITY_WIN32
-
-
-/** @file
- * SSL/TLS support API.
- *
- * This file contains an SChannel-based implemention of the SSL/TLS API for Windows platforms.
- */
-
-static void ssl_log_error(const char *fmt, ...);
-static void ssl_log(pn_transport_t *transport, const char *fmt, ...);
-static void ssl_log_error_status(HRESULT status, const char *fmt, ...);
-static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error);
-
-/*
- * win_credential_t: SChannel context that must accompany TLS connections.
- *
- * SChannel attempts session resumption for shared CredHandle objects.
- * To mimic openssl behavior, server CredHandle handles must be shared
- * by derived connections, client CredHandle handles must be unique
- * when app's session_id is null and tracked for reuse otherwise
- * (TODO).
- *
- * Ref counted by parent ssl_domain_t and each derived connection.
- */
-struct win_credential_t {
-  pn_ssl_mode_t mode;
-  PCCERT_CONTEXT cert_context;  // Particulars of the certificate (if any)
-  CredHandle cred_handle;       // Bound session parameters, certificate, CAs, verification_mode
-  HCERTSTORE trust_store;       // Store of root CAs for validating
-  HCERTSTORE server_CA_certs;   // CAs advertised by server (may be a duplicate of the trust_store)
-  char *trust_store_name;
-};
-
-#define win_credential_compare NULL
-#define win_credential_inspect NULL
-#define win_credential_hashcode NULL
-
-static void win_credential_initialize(void *object)
-{
-  win_credential_t *c = (win_credential_t *) object;
-  SecInvalidateHandle(&c->cred_handle);
-  c->cert_context = 0;
-  c->trust_store = 0;
-  c->server_CA_certs = 0;
-  c->trust_store_name = 0;
-}
-
-static void win_credential_finalize(void *object)
-{
-  win_credential_t *c = (win_credential_t *) object;
-  if (SecIsValidHandle(&c->cred_handle))
-    FreeCredentialsHandle(&c->cred_handle);
-  if (c->cert_context)
-    CertFreeCertificateContext(c->cert_context);
-  if (c->trust_store)
-    CertCloseStore(c->trust_store, 0);
-  if (c->server_CA_certs)
-    CertCloseStore(c->server_CA_certs, 0);
-  free(c->trust_store_name);
-}
-
-static win_credential_t *win_credential(pn_ssl_mode_t m)
-{
-  static const pn_cid_t CID_win_credential = CID_pn_void;
-  static const pn_class_t clazz = PN_CLASS(win_credential);
-  win_credential_t *c = (win_credential_t *) pn_class_new(&clazz, sizeof(win_credential_t));
-  c->mode = m;
-  return c;
-}
-
-static int win_credential_load_cert(win_credential_t *cred, const char *store_name, const char *cert_name, const char *passwd)
-{
-  if (!store_name)
-    return -2;
-
-  int ec = 0;
-  HCERTSTORE cert_store = open_cert_db(store_name, passwd, &ec);
-  if (!cert_store)
-    return ec;
-
-  // find friendly name that matches cert_name, or sole certificate
-  PCCERT_CONTEXT tmpctx = NULL;
-  PCCERT_CONTEXT found_ctx = NULL;
-  int cert_count = 0;
-  int name_len = cert_name ? strlen(cert_name) : 0;
-  char *fn = name_len ? (char *) malloc(name_len + 1) : 0;
-  while (tmpctx = CertEnumCertificatesInStore(cert_store, tmpctx)) {
-    cert_count++;
-    if (cert_name) {
-      DWORD len = CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
-                                    0, NULL, NULL, 0);
-      if (len != name_len + 1)
-        continue;
-      CertGetNameString(tmpctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
-                        0, NULL, fn, len);
-      if (!strcmp(cert_name, fn)) {
-        found_ctx = tmpctx;
-        tmpctx= NULL;
-        break;
-      }
-    } else {
-      // Test for single certificate
-      if (cert_count == 1) {
-        found_ctx = CertDuplicateCertificateContext(tmpctx);
-      } else {
-        ssl_log_error("Multiple certificates to choose from certificate store %s\n", store_name);
-        found_ctx = NULL;
-        break;
-      }
-    }
-  }
-
-  if (tmpctx) {
-    CertFreeCertificateContext(tmpctx);
-    tmpctx = false;
-  }
-  if (!found_ctx && cert_name && cert_count == 1)
-    ssl_log_error("Could not find certificate %s in store %s\n", cert_name, store_name);
-  cred->cert_context = found_ctx;
-
-  free(fn);
-  CertCloseStore(cert_store, 0);
-  return found_ctx ? 0 : -8;
-}
-
-
-static CredHandle win_credential_cred_handle(win_credential_t *cred, pn_ssl_verify_mode_t verify_mode,
-                                             const char *session_id, SECURITY_STATUS *status)
-{
-  if (cred->mode == PN_SSL_MODE_SERVER && SecIsValidHandle(&cred->cred_handle)) {
-    *status = SEC_E_OK;
-    return cred->cred_handle;  // Server always reuses cached value
-  }
-  // TODO: if (is_client && session_id != NULL) create or use cached value based on
-  // session_id+server_host_name (per domain? reclaimed after X hours?)
-
-  CredHandle tmp_handle;
-  SecInvalidateHandle(&tmp_handle);
-  TimeStamp expiry;  // Not used
-  SCHANNEL_CRED descriptor;
-  memset(&descriptor, 0, sizeof(descriptor));
-
-  descriptor.dwVersion = SCHANNEL_CRED_VERSION;
-  descriptor.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
-  if (cred->cert_context != NULL) {
-    // assign the certificate into the credentials
-    descriptor.paCred = &cred->cert_context;
-    descriptor.cCreds = 1;
-  }
-
-  if (cred->mode == PN_SSL_MODE_SERVER) {
-    descriptor.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
-    if (cred->server_CA_certs) {
-      descriptor.hRootStore = cred->server_CA_certs;
-    }
-  }
-
-  ULONG direction = (cred->mode == PN_SSL_MODE_SERVER) ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND;
-  *status = AcquireCredentialsHandle(NULL, UNISP_NAME, direction, NULL,
-                                               &descriptor, NULL, NULL, &tmp_handle, &expiry);
-  if (cred->mode == PN_SSL_MODE_SERVER && *status == SEC_E_OK)
-    cred->cred_handle = tmp_handle;
-
-  return tmp_handle;
-}
-
-static bool win_credential_has_certificate(win_credential_t *cred)
-{
-  if (!cred) return false;
-  return (cred->cert_context != NULL);
-}
-
-#define SSL_DATA_SIZE 16384
-#define SSL_BUF_SIZE (SSL_DATA_SIZE + 5 + 2048 + 32)
-
-typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
-typedef struct pn_ssl_session_t pn_ssl_session_t;
-
-struct pn_ssl_domain_t {
-  int ref_count;
-  pn_ssl_mode_t mode;
-  bool has_ca_db;       // true when CA database configured
-  pn_ssl_verify_mode_t verify_mode;
-  bool allow_unsecured;
-  win_credential_t *cred;
-};
-
-typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
-               RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;
-
-struct pni_ssl_t {
-  pn_ssl_domain_t  *domain;
-  const char    *session_id;
-  const char *peer_hostname;
-  ssl_state_t state;
-
-  bool protocol_detected;
-  bool queued_shutdown;
-  bool ssl_closed;            // shutdown complete, or SSL error
-  ssize_t app_input_closed;   // error code returned by upper layer process input
-  ssize_t app_output_closed;  // error code returned by upper layer process output
-
-  // OpenSSL hides the protocol envelope bytes, SChannel has them in-line.
-  char *sc_outbuf;     // SChannel output buffer
-  size_t sc_out_size;
-  size_t sc_out_count;
-  char *network_outp;   // network ready bytes within sc_outbuf
-  size_t network_out_pending;
-
-  char *sc_inbuf;      // SChannel input buffer
-  size_t sc_in_size;
-  size_t sc_in_count;
-  bool sc_in_incomplete;
-
-  char *inbuf_extra;    // Still encrypted data from following Record(s)
-  size_t extra_count;
-
-  char *in_data;          // Just the plaintext data part of sc_inbuf, decrypted in place
-  size_t in_data_size;
-  size_t in_data_count;
-  bool decrypting;
-  size_t max_data_size;  // computed in the handshake
-
-  pn_bytes_t app_inbytes; // Virtual decrypted datastream, presented to app layer
-
-  pn_buffer_t *inbuf2;    // Second input buf if longer contiguous bytes needed
-  bool double_buffered;
-
-  bool sc_input_shutdown;
-
-  CredHandle cred_handle;
-  CtxtHandle ctxt_handle;
-  SecPkgContext_StreamSizes sc_sizes;
-  pn_ssl_verify_mode_t verify_mode;
-  win_credential_t *cred;
-  char *subject;
-};
-
-static inline pn_transport_t *get_transport_internal(pn_ssl_t *ssl)
-{
-  // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-  return ((pn_transport_t *)ssl);
-}
-
-static inline pni_ssl_t *get_ssl_internal(pn_ssl_t *ssl)
-{
-  // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-  return ssl ? ((pn_transport_t *)ssl)->ssl : NULL;
-}
-
-struct pn_ssl_session_t {
-  const char       *id;
-// TODO
-  pn_ssl_session_t *ssn_cache_next;
-  pn_ssl_session_t *ssn_cache_prev;
-};
-
-
-static ssize_t process_input_ssl( pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
-static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len);
-static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len);
-static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
-static void ssl_session_free( pn_ssl_session_t *);
-static size_t buffered_output( pn_transport_t *transport );
-static void start_ssl_shutdown(pn_transport_t *transport);
-static void rewind_sc_inbuf(pni_ssl_t *ssl);
-static bool grow_inbuf2(pn_transport_t *ssl, size_t minimum_size);
-static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing);
-
-// @todo: used to avoid littering the code with calls to printf...
-static void ssl_log_error(const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  va_end(ap);
-  fflush(stderr);
-}
-
-// @todo: used to avoid littering the code with calls to printf...
-static void ssl_log(pn_transport_t *transport, const char *fmt, ...)
-{
-  if (PN_TRACE_DRV & transport->trace) {
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fflush(stderr);
-  }
-}
-
-static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
-{
-  char buf[512];
-  va_list ap;
-
-  if (fmt) {
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-  }
-
-  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
-                    0, status, 0, buf, sizeof(buf), 0))
-    ssl_log_error(" : %s\n", buf);
-  else
-    fprintf(stderr, "pn internal Windows error: %x for %x\n", GetLastError(), status);
-
-  fflush(stderr);
-}
-
-static void ssl_log_clear_data(pn_transport_t *transport, const char *data, size_t len)
-{
-  if (PN_TRACE_RAW & transport->trace) {
-    fprintf(stderr, "SSL decrypted data: \"");
-    pn_fprint_data( stderr, data, len );
-    fprintf(stderr, "\"\n");
-  }
-}
-
-static size_t _pni_min(size_t a, size_t b)
-{
-  return (a < b) ? a : b;
-}
-
-// unrecoverable SSL failure occured, notify transport and generate error code.
-static int ssl_failed(pn_transport_t *transport, const char *reason)
-{
-  char buf[512] = "Unknown error.";
-  if (!reason) {
-    HRESULT status = GetLastError();
-
-    FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
-                  0, status, 0, buf, sizeof(buf), 0);
-    reason = buf;
-  }
-  pni_ssl_t *ssl = transport->ssl;
-  ssl->ssl_closed = true;
-  ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
-  ssl->state = SSL_CLOSED;
-  pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
-  return PN_EOS;
-}
-
-static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
-{
-// TODO:
-  return NULL;
-}
-
-static void ssl_session_free( pn_ssl_session_t *ssn)
-{
-  if (ssn) {
-    if (ssn->id) free( (void *)ssn->id );
-    free( ssn );
-  }
-}
-
-
-/** Public API - visible to application code */
-
-bool pn_ssl_present(void)
-{
-  return true;
-}
-
-pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
-{
-  pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
-  if (!domain) return NULL;
-
-  domain->ref_count = 1;
-  domain->mode = mode;
-  switch(mode) {
-  case PN_SSL_MODE_CLIENT:
-  case PN_SSL_MODE_SERVER:
-    break;
-
-  default:
-    ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
-    free(domain);
-    return NULL;
-  }
-  domain->cred = win_credential(mode);
-  return domain;
-}
-
-void pn_ssl_domain_free( pn_ssl_domain_t *domain )
-{
-  if (!domain) return;
-
-  if (--domain->ref_count == 0) {
-    pn_decref(domain->cred);
-    free(domain);
-  }
-}
-
-
-int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
-                               const char *certificate_file,
-                               const char *private_key_file,
-                               const char *password)
-{
-  if (!domain) return -1;
-
-  if (win_credential_has_certificate(domain->cred)) {
-    // Need a new win_credential_t to hold new certificate
-    pn_decref(domain->cred);
-    domain->cred = win_credential(domain->mode);
-    if (!domain->cred)
-      return -1;
-  }
-  return win_credential_load_cert(domain->cred, certificate_file, private_key_file, password);
-}
-
-
-int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
-                                    const char *certificate_db)
-{
-  if (!domain || !certificate_db) return -1;
-
-  int ec = 0;
-  HCERTSTORE store = open_cert_db(certificate_db, NULL, &ec);
-  if (!store)
-    return ec;
-
-  if (domain->has_ca_db) {
-    win_credential_t *new_cred = win_credential(domain->mode);
-    if (!new_cred)
-      return -1;
-    new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
-    pn_decref(domain->cred);
-    domain->cred = new_cred;
-  }
-
-  domain->cred->trust_store = store;
-  domain->cred->trust_store_name = pn_strdup(certificate_db);
-  domain->has_ca_db = true;
-  return 0;
-}
-
-
-int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
-                                          const pn_ssl_verify_mode_t mode,
-                                          const char *trusted_CAs)
-{
-  if (!domain) return -1;
-  if (!domain->has_ca_db && (mode == PN_SSL_VERIFY_PEER || mode == PN_SSL_VERIFY_PEER_NAME)) {
-    ssl_log_error("Error: cannot verify peer without a trusted CA configured.\n"
-                  "       Use pn_ssl_domain_set_trusted_ca_db()\n");
-    return -1;
-  }
-
-  HCERTSTORE store = 0;
-  bool changed = domain->verify_mode && mode != domain->verify_mode;
-
-  switch (mode) {
-  case PN_SSL_VERIFY_PEER:
-  case PN_SSL_VERIFY_PEER_NAME:
-    if (domain->mode == PN_SSL_MODE_SERVER) {
-      if (!trusted_CAs) {
-        ssl_log_error("Error: a list of trusted CAs must be provided.");
-        return -1;
-      }
-      if (!win_credential_has_certificate(domain->cred)) {
-        ssl_log_error("Error: Server cannot verify peer without configuring a certificate.\n"
-                   "       Use pn_ssl_domain_set_credentials()");
-        return -1;
-      }
-      int ec = 0;
-      if (!strcmp(trusted_CAs, domain->cred->trust_store_name)) {
-        store = open_cert_db(trusted_CAs, NULL, &ec);
-        if (!store)
-          return ec;
-      } else {
-        store = CertDuplicateStore(domain->cred->trust_store);
-      }
-
-      if (domain->cred->server_CA_certs) {
-        // Already have one
-        changed = true;
-        win_credential_t *new_cred = win_credential(domain->mode);
-        if (!new_cred) {
-          CertCloseStore(store, 0);
-          return -1;
-        }
-        new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
-        new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
-        new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
-        pn_decref(domain->cred);
-        domain->cred = new_cred;
-      }
-
-      domain->cred->server_CA_certs = store;
-    }
-    break;
-
-  case PN_SSL_ANONYMOUS_PEER:   // hippie free love mode... :)
-    break;
-
-  default:
-    ssl_log_error("Invalid peer authentication mode given.\n");
-    return -1;
-  }
-
-  if (changed) {
-    win_credential_t *new_cred = win_credential(domain->mode);
-    if (!new_cred) {
-      CertCloseStore(store, 0);
-      return -1;
-    }
-    new_cred->cert_context = CertDuplicateCertificateContext(domain->cred->cert_context);
-    new_cred->trust_store = CertDuplicateStore(domain->cred->trust_store);
-    new_cred->trust_store_name = pn_strdup(domain->cred->trust_store_name);
-    pn_decref(domain->cred);
-    domain->cred = new_cred;
-  }
-
-  domain->verify_mode = mode;
-  domain->cred->server_CA_certs = store;
-
-  return 0;
-}
-
-const pn_io_layer_t ssl_layer = {
-    process_input_ssl,
-    process_output_ssl,
-    NULL,
-    NULL,
-    buffered_output
-};
-
-const pn_io_layer_t ssl_input_closed_layer = {
-    process_input_done,
-    process_output_ssl,
-    NULL,
-    NULL,
-    buffered_output
-};
-
-const pn_io_layer_t ssl_output_closed_layer = {
-    process_input_ssl,
-    process_output_done,
-    NULL,
-    NULL,
-    buffered_output
-};
-
-const pn_io_layer_t ssl_closed_layer = {
-    process_input_done,
-    process_output_done,
-    NULL,
-    NULL,
-    buffered_output
-};
-
-int pn_ssl_init(pn_ssl_t *ssl0, pn_ssl_domain_t *domain, const char *session_id)
-{
-  pn_transport_t *transport = get_transport_internal(ssl0);
-  pni_ssl_t *ssl = transport->ssl;
-  if (!ssl || !domain || ssl->domain) return -1;
-  if (ssl->state != CREATED) return -1;
-
-  ssl->domain = domain;
-  domain->ref_count++;
-  if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
-    ssl->session_id = pn_strdup(session_id);
-
-  // If SSL doesn't specifically allow skipping encryption, require SSL
-  // TODO: This is a probably a stop-gap until allow_unsecured is removed
-  if (!domain->allow_unsecured) transport->encryption_required = true;
-
-  ssl->cred = domain->cred;
-  pn_incref(domain->cred);
-
-  SECURITY_STATUS status = SEC_E_OK;
-  ssl->cred_handle = win_credential_cred_handle(ssl->cred, ssl->verify_mode,
-                                                ssl->session_id, &status);
-  if (status != SEC_E_OK) {
-    ssl_log_error_status(status, "Credentials handle failure");
-    return -1;
-  }
-
-  ssl->state = (domain->mode == PN_SSL_MODE_CLIENT) ? CLIENT_HELLO : NEGOTIATING;
-  ssl->verify_mode = domain->verify_mode;
-  return 0;
-}
-
-
-int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
-{
-  if (!domain) return -1;
-  if (domain->mode != PN_SSL_MODE_SERVER) {
-    ssl_log_error("Cannot permit unsecured clients - not a server.\n");
-    return -1;
-  }
-  domain->allow_unsecured = true;
-  return 0;
-}
-
-
-// TODO: This is just an untested guess
-int pn_ssl_get_ssf(pn_ssl_t *ssl0)
-{
-  SecPkgContext_ConnectionInfo info;
-
-  pni_ssl_t *ssl = get_ssl_internal(ssl0);
-  if (ssl &&
-      ssl->state == RUNNING &&
-      SecIsValidHandle(&ssl->ctxt_handle) &&
-      QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
-    return info.dwCipherStrength;
-  }
-  return 0;
-}
-
-bool pn_ssl_get_cipher_name(pn_ssl_t *ssl0, char *buffer, size_t size )
-{
-  pni_ssl_t *ssl = get_ssl_internal(ssl0);
-  if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
-    return false;
-  *buffer = '\0';
-  SecPkgContext_ConnectionInfo info;
-  if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
-    // TODO: come up with string for all permutations?
-    snprintf( buffer, size, "%x_%x:%x_%x:%x_%x",
-              info.aiExch, info.dwExchStrength,
-              info.aiCipher, info.dwCipherStrength,
-              info.aiHash, info.dwHashStrength);
-    return true;
-  }
-  return false;
-}
-
-bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
-{
-  pni_ssl_t *ssl = get_ssl_internal(ssl0);
-  if (ssl->state != RUNNING || !SecIsValidHandle(&ssl->ctxt_handle))
-    return false;
-  *buffer = '\0';
-  SecPkgContext_ConnectionInfo info;
-  if (QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info) == SEC_E_OK) {
-    if (info.dwProtocol & (SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER))
-      snprintf(buffer, size, "%s", "TLSv1");
-    // TLSV1.1 and TLSV1.2 are supported as of XP-SP3, but not defined until VS2010
-    else if ((info.dwProtocol & 0x300))
-      snprintf(buffer, size, "%s", "TLSv1.1");
-    else if ((info.dwProtocol & 0xC00))
-      snprintf(buffer, size, "%s", "TLSv1.2");
-    else {
-      ssl_log_error("unexpected protocol %x\n", info.dwProtocol);
-      return false;
-    }
-    return true;
-  }
-  return false;
-}
-
-
-void pn_ssl_free( pn_transport_t *transport)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  if (!ssl) return;
-  ssl_log( transport, "SSL socket freed.\n" );
-  // clean up Windows per TLS session data before releasing the domain count
-  if (SecIsValidHandle(&ssl->ctxt_handle))
-    DeleteSecurityContext(&ssl->ctxt_handle);
-  if (ssl->cred) {
-    if (ssl->domain->mode == PN_SSL_MODE_CLIENT && ssl->session_id == NULL) {
-      // Responsible for unshared handle
-      if (SecIsValidHandle(&ssl->cred_handle))
-        FreeCredentialsHandle(&ssl->cred_handle);
-    }
-    pn_decref(ssl->cred);
-  }
-
-  if (ssl->domain) pn_ssl_domain_free(ssl->domain);
-  if (ssl->session_id) free((void *)ssl->session_id);
-  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
-  if (ssl->sc_inbuf) free((void *)ssl->sc_inbuf);
-  if (ssl->sc_outbuf) free((void *)ssl->sc_outbuf);
-  if (ssl->inbuf2) pn_buffer_free(ssl->inbuf2);
-  if (ssl->subject) free(ssl->subject);
-
-  free(ssl);
-}
-
-pn_ssl_t *pn_ssl(pn_transport_t *transport)
-{
-  if (!transport) return NULL;
-  if (transport->ssl) return (pn_ssl_t *)transport;
-
-  pni_ssl_t *ssl = (pni_ssl_t *) calloc(1, sizeof(pni_ssl_t));
-  if (!ssl) return NULL;
-  ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;
-
-  ssl->sc_outbuf = (char *)malloc(ssl->sc_out_size);
-  if (!ssl->sc_outbuf) {
-    free(ssl);
-    return NULL;
-  }
-  ssl->sc_inbuf = (char *)malloc(ssl->sc_in_size);
-  if (!ssl->sc_inbuf) {
-    free(ssl->sc_outbuf);
-    free(ssl);
-    return NULL;
-  }
-
-  ssl->inbuf2 = pn_buffer(0);
-  if (!ssl->inbuf2) {
-    free(ssl->sc_inbuf);
-    free(ssl->sc_outbuf);
-    free(ssl);
-    return NULL;
-  }
-
-  transport->ssl = ssl;
-
-  // Set up hostname from any bound connection
-  if (transport->connection) {
-    if (pn_string_size(transport->connection->hostname)) {
-      pn_ssl_set_peer_hostname((pn_ssl_t *) transport, pn_string_get(transport->connection->hostname));
-    }
-  }
-
-  SecInvalidateHandle(&ssl->cred_handle);
-  SecInvalidateHandle(&ssl->ctxt_handle);
-  ssl->state = CREATED;
-  ssl->decrypting = true;
-
-  return (pn_ssl_t *)transport;
-}
-
-
-pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
-{
-  // TODO
-  return PN_SSL_RESUME_UNKNOWN;
-}
-
-
-int pn_ssl_set_peer_hostname( pn_ssl_t *ssl0, const char *hostname )
-{
-  pni_ssl_t *ssl = get_ssl_internal(ssl0);
-  if (!ssl) return -1;
-
-  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
-  ssl->peer_hostname = NULL;
-  if (hostname) {
-    ssl->peer_hostname = pn_strdup(hostname);
-    if (!ssl->peer_hostname) return -2;
-  }
-  return 0;
-}
-
-int pn_ssl_get_peer_hostname( pn_ssl_t *ssl0, char *hostname, size_t *bufsize )
-{
-  pni_ssl_t *ssl = get_ssl_internal(ssl0);
-  if (!ssl) return -1;
-  if (!ssl->peer_hostname) {
-    *bufsize = 0;
-    if (hostname) *hostname = '\0';
-    return 0;
-  }
-  unsigned len = strlen(ssl->peer_hostname);
-  if (hostname) {
-    if (len >= *bufsize) return -1;
-    strcpy( hostname, ssl->peer_hostname );
-  }
-  *bufsize = len;
-  return 0;
-}
-
-const char* pn_ssl_get_remote_subject(pn_ssl_t *ssl0)
-{
-  // RFC 2253 compliant, but differs from openssl's subject string with space separators and
-  // ordering of multicomponent RDNs.  Made to work as similarly as possible with choice of flags.
-  pni_ssl_t *ssl = get_ssl_internal(ssl0);
-  if (!ssl || !SecIsValidHandle(&ssl->ctxt_handle))
-    return NULL;
-  if (!ssl->subject) {
-    SECURITY_STATUS status;
-    PCCERT_CONTEXT peer_cc = 0;
-    status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
-    if (status != SEC_E_OK) {
-      ssl_log_error_status(status, "can't obtain remote certificate subject");
-      return NULL;
-    }
-    DWORD flags = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
-    DWORD strlen = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
-                                 flags, NULL, 0);
-    if (strlen > 0) {
-      ssl->subject = (char*) malloc(strlen);
-      if (ssl->subject) {
-        DWORD len = CertNameToStr(peer_cc->dwCertEncodingType, &peer_cc->pCertInfo->Subject,
-                                  flags, ssl->subject, strlen);
-        if (len != strlen) {
-          free(ssl->subject);
-          ssl->subject = NULL;
-          ssl_log_error("pn_ssl_get_remote_subject failure in CertNameToStr");
-        }
-      }
-    }
-    CertFreeCertificateContext(peer_cc);
-  }
-  return ssl->subject;
-}
-
-
-/** SChannel specific: */
-
-const char *tls_version_check(pni_ssl_t *ssl)
-{
-  SecPkgContext_ConnectionInfo info;
-  QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info);
-  // Ascending bit patterns denote newer SSL/TLS protocol versions.
-  // SP_PROT_TLS1_0_SERVER is not defined until VS2010.
-  return (info.dwProtocol < SP_PROT_TLS1_SERVER) ?
-    "peer does not support TLS 1.0 security" : NULL;
-}
-
-static void ssl_encrypt(pn_transport_t *transport, char *app_data, size_t count)
-{
-  pni_ssl_t *ssl = transport->ssl;
-
-  // Get SChannel to encrypt exactly one Record.
-  SecBuffer buffs[4];
-  buffs[0].cbBuffer = ssl->sc_sizes.cbHeader;
-  buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
-  buffs[0].pvBuffer = ssl->sc_outbuf;
-  buffs[1].cbBuffer = count;
-  buffs[1].BufferType = SECBUFFER_DATA;
-  buffs[1].pvBuffer = app_data;
-  buffs[2].cbBuffer = ssl->sc_sizes.cbTrailer;
-  buffs[2].BufferType = SECBUFFER_STREAM_TRAILER;
-  buffs[2].pvBuffer = &app_data[count];
-  buffs[3].cbBuffer = 0;
-  buffs[3].BufferType = SECBUFFER_EMPTY;
-  buffs[3].pvBuffer = 0;
-  SecBufferDesc buff_desc;
-  buff_desc.ulVersion = SECBUFFER_VERSION;
-  buff_desc.cBuffers = 4;
-  buff_desc.pBuffers = buffs;
-  SECURITY_STATUS status = EncryptMessage(&ssl->ctxt_handle, 0, &buff_desc, 0);
-  assert(status == SEC_E_OK);
-
-  // EncryptMessage encrypts the data in place. The header and trailer
-  // areas were reserved previously and must now be included in the updated
-  // count of bytes to write to the peer.
-  ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
-  ssl->network_outp = ssl->sc_outbuf;
-  ssl->network_out_pending = ssl->sc_out_count;
-  ssl_log(transport, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
-}
-
-// Returns true if decryption succeeded (even for empty content)
-static bool ssl_decrypt(pn_transport_t *transport)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  // Get SChannel to decrypt input.  May have an incomplete Record,
-  // exactly one, or more than one.  Check also for session ending,
-  // session renegotiation.
-
-  SecBuffer recv_buffs[4];
-  recv_buffs[0].cbBuffer = ssl->sc_in_count;
-  recv_buffs[0].BufferType = SECBUFFER_DATA;
-  recv_buffs[0].pvBuffer = ssl->sc_inbuf;
-  recv_buffs[1].BufferType = SECBUFFER_EMPTY;
-  recv_buffs[2].BufferType = SECBUFFER_EMPTY;
-  recv_buffs[3].BufferType = SECBUFFER_EMPTY;
-  SecBufferDesc buff_desc;
-  buff_desc.ulVersion = SECBUFFER_VERSION;
-  buff_desc.cBuffers = 4;
-  buff_desc.pBuffers = recv_buffs;
-  SECURITY_STATUS status = DecryptMessage(&ssl->ctxt_handle, &buff_desc, 0, NULL);
-
-  if (status == SEC_E_INCOMPLETE_MESSAGE) {
-    // Less than a full Record, come back later with more network data
-    ssl->sc_in_incomplete = true;
-    return false;
-  }
-
-  ssl->decrypting = false;
-
-  if (status != SEC_E_OK) {
-    rewind_sc_inbuf(ssl);
-    switch (status) {
-    case SEC_I_CONTEXT_EXPIRED:
-      // TLS shutdown alert record.  Ignore all subsequent input.
-      ssl->state = SHUTTING_DOWN;
-      ssl->sc_input_shutdown = true;
-      return false;
-
-    case SEC_I_RENEGOTIATE:
-      ssl_log_error("unexpected TLS renegotiation\n");
-      // TODO.  Fall through for now.
-    default:
-      ssl_failed(transport, 0);
-      return false;
-    }
-  }
-
-  ssl->decrypting = false;
-  // have a decrypted Record and possible (still-encrypted) data of
-  // one (or more) later Recordss.  Adjust pointers accordingly.
-  for (int i = 0; i < 4; i++) {
-    switch (recv_buffs[i].BufferType) {
-    case SECBUFFER_DATA:
-      ssl->in_data = (char *) recv_buffs[i].pvBuffer;
-      ssl->in_data_size = ssl->in_data_count = recv_buffs[i].cbBuffer;
-      break;
-    case SECBUFFER_EXTRA:
-      ssl->inbuf_extra = (char *)recv_buffs[i].pvBuffer;
-      ssl->extra_count = recv_buffs[i].cbBuffer;
-      break;
-    default:
-      // SECBUFFER_STREAM_HEADER:
-      // SECBUFFER_STREAM_TRAILER:
-      break;
-    }
-  }
-  return true;
-}
-
-static void client_handshake_init(pn_transport_t *transport)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  // Tell SChannel to create the first handshake token (ClientHello)
-  // and place it in sc_outbuf
-  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
-  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_EXTENDED_ERROR;
-  ULONG ctxt_attrs;
-
-  SecBuffer send_buffs[2];
-  send_buffs[0].cbBuffer = ssl->sc_out_size;
-  send_buffs[0].BufferType = SECBUFFER_TOKEN;
-  send_buffs[0].pvBuffer = ssl->sc_outbuf;
-  send_buffs[1].cbBuffer = 0;
-  send_buffs[1].BufferType = SECBUFFER_EMPTY;
-  send_buffs[1].pvBuffer = 0;
-  SecBufferDesc send_buff_desc;
-  send_buff_desc.ulVersion = SECBUFFER_VERSION;
-  send_buff_desc.cBuffers = 2;
-  send_buff_desc.pBuffers = send_buffs;
-  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
-                               NULL, host, ctxt_requested, 0, 0, NULL, 0,
-                               &ssl->ctxt_handle, &send_buff_desc,
-                               &ctxt_attrs, NULL);
-
-  if (status == SEC_I_CONTINUE_NEEDED) {
-    ssl->sc_out_count = send_buffs[0].cbBuffer;
-    ssl->network_out_pending = ssl->sc_out_count;
-    // the token is the whole quantity to send
-    ssl->network_outp = ssl->sc_outbuf;
-    ssl_log(transport, "Sending client hello %d bytes\n", ssl->network_out_pending);
-  } else {
-    ssl_log_error_status(status, "InitializeSecurityContext failed");
-    ssl_failed(transport, 0);
-  }
-}
-
-static void client_handshake( pn_transport_t* transport) {
-  pni_ssl_t *ssl = transport->ssl;
-  // Feed SChannel ongoing responses from the server until the handshake is complete.
-  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
-  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
-  ULONG ctxt_attrs;
-  size_t max = 0;
-
-  // token_buffs describe the buffer that's coming in. It should have
-  // a token from the SSL server, or empty if sending final shutdown alert.
-  bool shutdown = ssl->state == SHUTTING_DOWN;
-  SecBuffer token_buffs[2];
-  token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
-  token_buffs[0].BufferType = SECBUFFER_TOKEN;
-  token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
-  token_buffs[1].cbBuffer = 0;
-  token_buffs[1].BufferType = SECBUFFER_EMPTY;
-  token_buffs[1].pvBuffer = 0;
-  SecBufferDesc token_buff_desc;
-  token_buff_desc.ulVersion = SECBUFFER_VERSION;
-  token_buff_desc.cBuffers = 2;
-  token_buff_desc.pBuffers = token_buffs;
-
-  // send_buffs will hold information to forward to the peer.
-  SecBuffer send_buffs[2];
-  send_buffs[0].cbBuffer = ssl->sc_out_size;
-  send_buffs[0].BufferType = SECBUFFER_TOKEN;
-  send_buffs[0].pvBuffer = ssl->sc_outbuf;
-  send_buffs[1].cbBuffer = 0;
-  send_buffs[1].BufferType = SECBUFFER_EMPTY;
-  send_buffs[1].pvBuffer = 0;
-  SecBufferDesc send_buff_desc;
-  send_buff_desc.ulVersion = SECBUFFER_VERSION;
-  send_buff_desc.cBuffers = 2;
-  send_buff_desc.pBuffers = send_buffs;
-
-  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
-                               &ssl->ctxt_handle, host, ctxt_requested, 0, 0,
-                               &token_buff_desc, 0, NULL, &send_buff_desc,
-                               &ctxt_attrs, NULL);
-  switch (status) {
-  case SEC_E_INCOMPLETE_MESSAGE:
-    // Not enough - get more data from the server then try again.
-    // Leave input buffers untouched.
-    ssl_log(transport, "client handshake: incomplete record\n");
-    ssl->sc_in_incomplete = true;
-    return;
-
-  case SEC_I_CONTINUE_NEEDED:
-    // Successful handshake step, requiring data to be sent to peer.
-    ssl->sc_out_count = send_buffs[0].cbBuffer;
-    // the token is the whole quantity to send
-    ssl->network_out_pending = ssl->sc_out_count;
-    ssl->network_outp = ssl->sc_outbuf;
-    ssl_log(transport, "client handshake token %d bytes\n", ssl->network_out_pending);
-    break;
-
-  case SEC_E_OK:
-    // Handshake complete.
-    if (shutdown) {
-      if (send_buffs[0].cbBuffer > 0) {
-        ssl->sc_out_count = send_buffs[0].cbBuffer;
-        // the token is the whole quantity to send
-        ssl->network_out_pending = ssl->sc_out_count;
-        ssl->network_outp = ssl->sc_outbuf;
-        ssl_log(transport, "client shutdown token %d bytes\n", ssl->network_out_pending);
-      } else {
-        ssl->state = SSL_CLOSED;
-      }
-      // we didn't touch sc_inbuf, no need to reset
-      return;
-    }
-    if (send_buffs[0].cbBuffer != 0) {
-      ssl_failed(transport, "unexpected final server token");
-      break;
-    }
-    if (const char *err = tls_version_check(ssl)) {
-      ssl_failed(transport, err);
-      break;
-    }
-    if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
-      bool tracing = PN_TRACE_DRV & transport->trace;
-      HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, ssl->peer_hostname, tracing);
-      if (ec) {
-        if (ssl->peer_hostname)
-          ssl_log_error_status(ec, "certificate verification failed for host %s\n", ssl->peer_hostname);
-        else
-          ssl_log_error_status(ec, "certificate verification failed\n");
-        ssl_failed(transport, "TLS certificate verification error");
-        break;
-      }
-    }
-
-    if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
-      // This seems to work but not documented, plus logic differs from decrypt message
-      // since the pvBuffer value is not set.  Grrr.
-      ssl->extra_count = token_buffs[1].cbBuffer;
-      ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
-    }
-
-    QueryContextAttributes(&ssl->ctxt_handle,
-                             SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
-    max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
-    if (max > ssl->sc_out_size) {
-      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
-      ssl->state = SHUTTING_DOWN;
-      ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
-      start_ssl_shutdown(transport);
-      pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
-      break;
-    }
-
-    ssl->state = RUNNING;
-    ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
-    ssl_log(transport, "client handshake successful %d max record size\n", max);
-    break;
-
-  case SEC_I_CONTEXT_EXPIRED:
-    // ended before we got going
-  default:
-    ssl_log(transport, "client handshake failed %d\n", (int) status);
-    ssl_failed(transport, 0);
-    break;
-  }
-
-  if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
-      !ssl->ssl_closed) {
-    // remaining data after the consumed TLS record(s)
-    ssl->extra_count = token_buffs[1].cbBuffer;
-    ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
-  }
-
-  ssl->decrypting = false;
-  rewind_sc_inbuf(ssl);
-}
-
-
-static void server_handshake(pn_transport_t* transport)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  if (!ssl->protocol_detected) {
-    // SChannel fails less aggressively than openssl on client hello, causing hangs
-    // waiting for more bytes.  Help out here.
-    pni_protocol_type_t type = pni_sniff_header(ssl->sc_inbuf, ssl->sc_in_count);
-    if (type == PNI_PROTOCOL_INSUFFICIENT) {
-      ssl_log(transport, "server handshake: incomplete record\n");
-      ssl->sc_in_incomplete = true;
-      return;
-    } else {
-      ssl->protocol_detected = true;
-      if (type != PNI_PROTOCOL_SSL) {
-        ssl_failed(transport, "bad client hello");
-        ssl->decrypting = false;
-        rewind_sc_inbuf(ssl);
-        return;
-      }
-    }
-  }
-
-  // Feed SChannel ongoing handshake records from the client until the handshake is complete.
-  ULONG ctxt_requested = ASC_REQ_STREAM | ASC_REQ_EXTENDED_ERROR;
-  if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME)
-    ctxt_requested |= ASC_REQ_MUTUAL_AUTH;
-  ULONG ctxt_attrs;
-  size_t max = 0;
-
-  // token_buffs describe the buffer that's coming in. It should have
-  // a token from the SSL client except if shutting down or renegotiating.
-  bool shutdown = ssl->state == SHUTTING_DOWN;
-  SecBuffer token_buffs[2];
-  token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
-  token_buffs[0].BufferType = SECBUFFER_TOKEN;
-  token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
-  token_buffs[1].cbBuffer = 0;
-  token_buffs[1].BufferType = SECBUFFER_EMPTY;
-  token_buffs[1].pvBuffer = 0;
-  SecBufferDesc token_buff_desc;
-  token_buff_desc.ulVersion = SECBUFFER_VERSION;
-  token_buff_desc.cBuffers = 2;
-  token_buff_desc.pBuffers = token_buffs;
-
-  // send_buffs will hold information to forward to the peer.
-  SecBuffer send_buffs[2];
-  send_buffs[0].cbBuffer = ssl->sc_out_size;
-  send_buffs[0].BufferType = SECBUFFER_TOKEN;
-  send_buffs[0].pvBuffer = ssl->sc_outbuf;
-  send_buffs[1].cbBuffer = 0;
-  send_buffs[1].BufferType = SECBUFFER_EMPTY;
-  send_buffs[1].pvBuffer = 0;
-  SecBufferDesc send_buff_desc;
-  send_buff_desc.ulVersion = SECBUFFER_VERSION;
-  send_buff_desc.cBuffers = 2;
-  send_buff_desc.pBuffers = send_buffs;
-  PCtxtHandle ctxt_handle_ptr = (SecIsValidHandle(&ssl->ctxt_handle)) ? &ssl->ctxt_handle : 0;
-
-  SECURITY_STATUS status = AcceptSecurityContext(&ssl->cred_handle, ctxt_handle_ptr,
-                               &token_buff_desc, ctxt_requested, 0, &ssl->ctxt_handle,
-                               &send_buff_desc, &ctxt_attrs, NULL);
-
-  bool outbound_token = false;
-  switch(status) {
-  case SEC_E_INCOMPLETE_MESSAGE:
-    // Not enough - get more data from the client then try again.
-    // Leave input buffers untouched.
-    ssl_log(transport, "server handshake: incomplete record\n");
-    ssl->sc_in_incomplete = true;
-    return;
-
-  case SEC_I_CONTINUE_NEEDED:
-    outbound_token = true;
-    break;
-
-  case SEC_E_OK:
-    // Handshake complete.
-    if (shutdown) {
-      if (send_buffs[0].cbBuffer > 0) {
-        ssl->sc_out_count = send_buffs[0].cbBuffer;
-        // the token is the whole quantity to send
-        ssl->network_out_pending = ssl->sc_out_count;
-        ssl->network_outp = ssl->sc_outbuf;
-        ssl_log(transport, "server shutdown token %d bytes\n", ssl->network_out_pending);
-      } else {
-        ssl->state = SSL_CLOSED;
-      }
-      // we didn't touch sc_inbuf, no need to reset
-      return;
-    }
-    if (const char *err = tls_version_check(ssl)) {
-      ssl_failed(transport, err);
-      break;
-    }
-    // Handshake complete.
-
-    if (ssl->verify_mode == PN_SSL_VERIFY_PEER || ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME) {
-      bool tracing = PN_TRACE_DRV & transport->trace;
-      HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, NULL, tracing);
-      if (ec) {
-        ssl_log_error_status(ec, "certificate verification failed\n");
-        ssl_failed(transport, "certificate verification error");
-        break;
-      }
-    }
-
-    QueryContextAttributes(&ssl->ctxt_handle,
-                             SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
-    max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
-    if (max > ssl->sc_out_size) {
-      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
-      ssl->state = SHUTTING_DOWN;
-      ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
-      start_ssl_shutdown(transport);
-      pn_do_error(transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
-      break;
-    }
-
-    if (send_buffs[0].cbBuffer != 0)
-      outbound_token = true;
-
-    ssl->state = RUNNING;
-    ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
-    ssl_log(transport, "server handshake successful %d max record size\n", max);
-    break;
-
-  case SEC_I_CONTEXT_EXPIRED:
-    // ended before we got going
-  default:
-    ssl_log(transport, "server handshake failed %d\n", (int) status);
-    ssl_failed(transport, 0);
-    break;
-  }
-
-  if (outbound_token) {
-    // Successful handshake step, requiring data to be sent to peer.
-    assert(ssl->network_out_pending == 0);
-    ssl->sc_out_count = send_buffs[0].cbBuffer;
-    // the token is the whole quantity to send
-    ssl->network_out_pending = ssl->sc_out_count;
-    ssl->network_outp = ssl->sc_outbuf;
-    ssl_log(transport, "server handshake token %d bytes\n", ssl->network_out_pending);
-  }
-
-  if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
-      !ssl->ssl_closed) {
-    // remaining data after the consumed TLS record(s)
-    ssl->extra_count = token_buffs[1].cbBuffer;
-    ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
-  }
-
-  ssl->decrypting = false;
-  rewind_sc_inbuf(ssl);
-}
-
-static void ssl_handshake(pn_transport_t* transport) {
-  if (transport->ssl->domain->mode == PN_SSL_MODE_CLIENT)
-    client_handshake(transport);
-  else {
-    server_handshake(transport);
-  }
-}
-
-static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
-  pni_ssl_t *ssl = transport->ssl;
-  size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
-  size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;
-
-  while (new_capacity < minimum_size)
-    new_capacity *= 2;
-
-  uint32_t max_frame = pn_transport_get_max_frame(transport);
-  if (max_frame != 0) {
-    if (old_capacity >= max_frame) {
-      //  already big enough
-      ssl_log(transport, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
-      ssl_failed(transport, "TLS: transport maximimum frame size error");
-      return false;
-    }
-  }
-
-  size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
-  int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
-  if (err) {
-    ssl_log(transport, "TLS memory allocation failed for %d bytes\n", max_frame);
-    ssl_failed(transport, "TLS memory allocation failed");
-    return false;
-  }
-  return true;
-}
-
-
-// Peer initiated a session end by sending us a shutdown alert (and we should politely
-// reciprocate), or else we are initiating the session end (and will not bother to wait
-// for the peer shutdown alert). Stop processing input immediately, and stop processing
-// output once this is sent.
-
-static void start_ssl_shutdown(pn_transport_t *transport)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  assert(ssl->network_out_pending == 0);
-  if (ssl->queued_shutdown)
-    return;
-  ssl->queued_shutdown = true;
-  ssl_log(transport, "Shutting down SSL connection...\n");
-
-  DWORD shutdown = SCHANNEL_SHUTDOWN;
-  SecBuffer shutBuff;
-  shutBuff.cbBuffer = sizeof(DWORD);
-  shutBuff.BufferType = SECBUFFER_TOKEN;
-  shutBuff.pvBuffer = &shutdown;
-  SecBufferDesc desc;
-  desc.ulVersion = SECBUFFER_VERSION;
-  desc.cBuffers = 1;
-  desc.pBuffers = &shutBuff;
-  ApplyControlToken(&ssl->ctxt_handle, &desc);
-
-  // Next handshake will generate the shudown alert token
-  ssl_handshake(transport);
-}
-
-static void rewind_sc_inbuf(pni_ssl_t *ssl)
-{
-  // Decrypted bytes have been drained or double buffered.  Prepare for the next SSL Record.
-  assert(ssl->in_data_count == 0);
-  if (ssl->decrypting)
-    return;
-  ssl->decrypting = true;
-  if (ssl->inbuf_extra) {
-    // A previous read picked up more than one Record.  Move it to the beginning.
-    memmove(ssl->sc_inbuf, ssl->inbuf_extra, ssl->extra_count);
-    ssl->sc_in_count = ssl->extra_count;
-    ssl->inbuf_extra = 0;
-    ssl->extra_count = 0;
-  } else {
-    ssl->sc_in_count = 0;
-  }
-}
-
-static void app_inbytes_add(pn_transport_t *transport)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  if (!ssl->app_inbytes.start) {
-    ssl->app_inbytes.start = ssl->in_data;
-    ssl->app_inbytes.size = ssl->in_data_count;
-    return;
-  }
-
-  if (ssl->double_buffered) {
-    if (pn_buffer_available(ssl->inbuf2) == 0) {
-      if (!grow_inbuf2(transport, 1024))
-        // could not add room
-        return;
-    }
-    size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
-    pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
-    ssl->in_data += count;
-    ssl->in_data_count -= count;
-    ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
-  } else {
-    assert(ssl->app_inbytes.size == 0);
-    ssl->app_inbytes.start = ssl->in_data;
-    ssl->app_inbytes.size = ssl->in_data_count;
-  }
-}
-
-
-static void app_inbytes_progress(pn_transport_t *transport, size_t minimum)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  // Make more decrypted data available, if possible.  Otherwise, move
-  // unread bytes to front of inbuf2 to make room for next bulk decryption.
-  // SSL may have chopped up data that app layer expects to be
-  // contiguous.  Start, continue or stop double buffering here.
-  if (ssl->double_buffered) {
-    if (ssl->app_inbytes.size == 0) {
-      // no straggler bytes, optimistically stop for now
-      ssl->double_buffered = false;
-      pn_buffer_clear(ssl->inbuf2);
-      ssl->app_inbytes.start = ssl->in_data;
-      ssl->app_inbytes.size = ssl->in_data_count;
-    } else {
-      pn_bytes_t ib2 = pn_buffer_bytes(ssl->inbuf2);
-      assert(ssl->app_inbytes.size <= ib2.size);
-      size_t consumed = ib2.size - ssl->app_inbytes.size;
-      if (consumed > 0) {
-        memmove((void *)ib2.start, ib2.start + consumed, ssl->app_inbytes.size);
-        pn_buffer_trim(ssl->inbuf2, 0, consumed);
-      }
-      if (!pn_buffer_available(ssl->inbuf2)) {
-        if (!grow_inbuf2(transport, minimum))
-          // could not add room
-          return;
-      }
-      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
-      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
-      ssl->in_data += count;
-      ssl->in_data_count -= count;
-      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
-    }
-  } else {
-    if (ssl->app_inbytes.size) {
-      // start double buffering the left over bytes
-      ssl->double_buffered = true;
-      pn_buffer_clear(ssl->inbuf2);
-      if (!pn_buffer_available(ssl->inbuf2)) {
-        if (!grow_inbuf2(transport, minimum))
-          // could not add room
-          return;
-      }
-      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
-      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
-      ssl->in_data += count;
-      ssl->in_data_count -= count;
-      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
-    } else {
-      // already pointing at all available bytes until next decrypt
-    }
-  }
-  if (ssl->in_data_count == 0)
-    rewind_sc_inbuf(ssl);
-}
-
-
-static void app_inbytes_advance(pn_transport_t *transport, size_t consumed)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  if (consumed == 0) {
-    // more contiguous bytes required
-    app_inbytes_progress(transport, ssl->app_inbytes.size + 1);
-    return;
-  }
-  assert(consumed <= ssl->app_inbytes.size);
-  ssl->app_inbytes.start += consumed;
-  ssl->app_inbytes.size -= consumed;
-  if (!ssl->double_buffered) {
-    ssl->in_data += consumed;
-    ssl->in_data_count -= consumed;
-  }
-  if (ssl->app_inbytes.size == 0)
-    app_inbytes_progress(transport, 0);
-}
-
-static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t error)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  if (ssl->app_input_closed)
-    return;
-  if (ssl->state == RUNNING && !error) {
-    // Signal end of stream
-    ssl->app_input_closed = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, 0);
-  }
-  if (!ssl->app_input_closed)
-    ssl->app_input_closed = error ? error : PN_ERR;
-
-  if (ssl->app_output_closed) {
-    // both sides of app closed, and no more app output pending:
-    ssl->state = SHUTTING_DOWN;
-    if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
-      start_ssl_shutdown(transport);
-    }
-  }
-}
-
-
-// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.
-
-static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  ssl_log( transport, "process_input_ssl( data size=%d )\n",available );
-  ssize_t consumed = 0;
-  ssize_t forwarded = 0;
-  bool new_app_input;
-
-  if (available == 0) {
-    // No more inbound network data
-    read_closed(transport, layer, 0);
-    return 0;
-  }
-
-  do {
-    if (ssl->sc_input_shutdown) {
-      // TLS protocol shutdown detected on input, so we are done.
-      read_closed(transport, layer, 0);
-      return PN_EOS;
-    }
-
-    // sc_inbuf should be ready for new or additional network encrypted bytes.
-    // i.e. no straggling decrypted bytes pending.
-    assert(ssl->in_data_count == 0 && ssl->decrypting);
-    new_app_input = false;
-    size_t count;
-
-    if (ssl->state != RUNNING) {
-      count = _pni_min(ssl->sc_in_size - ssl->sc_in_count, available);
-    } else {
-      // look for TLS record boundaries
-      if (ssl->sc_in_count < 5) {
-        ssl->sc_in_incomplete = true;
-        size_t hc = _pni_min(available, 5 - ssl->sc_in_count);
-        memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, hc);
-        ssl->sc_in_count += hc;
-        input_data += hc;
-        available -= hc;
-        consumed += hc;
-        if (ssl->sc_in_count < 5 || available == 0)
-          break;
-      }
-
-      // Top up sc_inbuf from network input_data hoping for a complete TLS Record
-      // We try to guess the length as an optimization, but let SChannel
-      // ultimately decide if there is spoofing going on.
-      unsigned char low = (unsigned char) ssl->sc_inbuf[4];
-      unsigned char high = (unsigned char) ssl->sc_inbuf[3];
-      size_t rec_len = high * 256 + low + 5;
-      if (rec_len < 5 || rec_len == ssl->sc_in_count || rec_len > ssl->sc_in_size)
-        rec_len = ssl->sc_in_size;
-
-      count = _pni_min(rec_len - ssl->sc_in_count, available);
-    }
-
-    if (count > 0) {
-      memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, count);
-      ssl->sc_in_count += count;
-      input_data += count;
-      available -= count;
-      consumed += count;
-      ssl->sc_in_incomplete = false;
-    }
-
-    // Try to decrypt another TLS Record.
-
-    if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
-      if (ssl->state == NEGOTIATING) {
-        ssl_handshake(transport);
-      } else {
-        if (ssl_decrypt(transport)) {
-          // Ignore TLS Record with 0 length data (does not mean EOS)
-          if (ssl->in_data_size > 0) {
-            new_app_input = true;
-            app_inbytes_add(transport);
-          } else {
-            assert(ssl->decrypting == false);
-            rewind_sc_inbuf(ssl);
-          }
-        }
-        ssl_log(transport, "Next decryption, %d left over\n", available);
-      }
-    }
-
-    if (ssl->state == SHUTTING_DOWN) {
-      if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
-        start_ssl_shutdown(transport);
-      }
-    } else if (ssl->state == SSL_CLOSED) {
-      return PN_EOS;
-    }
-
-    // Consume or discard the decrypted bytes
-    if (new_app_input && (ssl->state == RUNNING || ssl->state == SHUTTING_DOWN)) {
-      // present app_inbytes to io_next only if it has new content
-      while (ssl->app_inbytes.size > 0) {
-        if (!ssl->app_input_closed) {
-          ssize_t count = transport->io_layers[layer+1]->process_input(transport, layer+1, ssl->app_inbytes.start, ssl->app_inbytes.size);
-          if (count > 0) {
-            forwarded += count;
-            // advance() can increase app_inbytes.size if double buffered
-            app_inbytes_advance(transport, count);
-            ssl_log(transport, "Application consumed %d bytes from peer\n", (int) count);
-          } else if (count == 0) {
-            size_t old_size = ssl->app_inbytes.size;
-            app_inbytes_advance(transport, 0);
-            if (ssl->app_inbytes.size == old_size) {
-              break;  // no additional contiguous decrypted data available, get more network data
-            }
-          } else {
-            // count < 0
-            ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)\n",
-                 (int) count, (int)ssl->app_inbytes.size);
-            app_inbytes_advance(transport, ssl->app_inbytes.size);    // discard
-            read_closed(transport, layer, count);
-          }
-        } else {
-          ssl_log(transport, "Input closed discard %d bytes\n",
-               (int)ssl->app_inbytes.size);
-          app_inbytes_advance(transport, ssl->app_inbytes.size);      // discard
-        }
-      }
-    }
-  } while (available || (ssl->sc_in_count && !ssl->sc_in_incomplete));
-
-  if (ssl->state >= SHUTTING_DOWN) {
-    if (ssl->app_input_closed || ssl->sc_input_shutdown) {
-      // Next layer doesn't want more bytes, or it can't process without more data than it has seen so far
-      // but the ssl stream has ended
-      consumed = ssl->app_input_closed ? ssl->app_input_closed : PN_EOS;
-      if (transport->io_layers[layer]==&ssl_output_closed_layer) {
-        transport->io_layers[layer] = &ssl_closed_layer;
-      } else {
-        transport->io_layers[layer] = &ssl_input_closed_layer;
-      }
-    }
-  }
-  ssl_log(transport, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
-  return consumed;
-}
-
-static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer, char *buffer, size_t max_len)
-{
-  pni_ssl_t *ssl = transport->ssl;
-  if (!ssl) return PN_EOS;
-  ssl_log( transport, "process_output_ssl( max_len=%d )\n",max_len );
-
-  ssize_t written = 0;
-  ssize_t total_app_bytes = 0;
-  bool work_pending;
-
-  if (ssl->state == CLIENT_HELLO) {
-    // output buffers eclusively for internal handshake use until negotiation complete
-    client_handshake_init(transport);
-    if (ssl->state == SSL_CLOSED)
-      return PN_EOS;
-    ssl->state = NEGOTIATING;
-  }
-
-  do {
-    work_pending = false;
-
-    if (ssl->network_out_pending > 0) {
-      size_t wcount = _pni_min(ssl->network_out_pending, max_len);
-      memmove(buffer, ssl->network_outp, wcount);
-      ssl->network_outp += wcount;
-      ssl->network_out_pending -= wcount;
-      buffer += wcount;
-      max_len -= wcount;
-      written += wcount;
-    }
-
-    if (ssl->network_out_pending == 0 && ssl->state == RUNNING  && !ssl->app_output_closed) {
-      // refill the buffer with app data and encrypt it
-
-      char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
-      char *app_outp = app_data;
-      size_t remaining = ssl->max_data_size;
-      ssize_t app_bytes;
-      do {
-        app_bytes = transport->io_layers[layer+1]->process_output(transport, layer+1, app_outp, remaining);
-        if (app_bytes > 0) {
-          app_outp += app_bytes;
-          remaining -= app_bytes;
-          ssl_log( transport, "Gathered %d bytes from app to send to peer\n", app_bytes );
-        } else {
-          if (app_bytes < 0) {
-            ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)\n",
-                 (int) app_bytes, (int) ssl->network_out_pending);
-            ssl->app_output_closed = app_bytes;
-            if (ssl->app_input_closed)
-              ssl->state = SHUTTING_DOWN;
-          } else if (total_app_bytes == 0 && ssl->app_input_closed) {
-            // We've drained all the App layer can provide
-            ssl_log(transport, "Application layer blocked on input, closing\n");
-            ssl->state = SHUTTING_DOWN;
-            ssl->app_output_closed = PN_ERR;
-          }
-        }
-      } while (app_bytes > 0);
-      if (app_outp > app_data) {
-        work_pending = (max_len > 0);
-        ssl_encrypt(transport, app_data, app_outp - app_data);
-      }
-    }
-
-    if (ssl->network_out_pending == 0) {
-      if (ssl->state == SHUTTING_DOWN) {
-        if (!ssl->queued_shutdown) {
-          start_ssl_shutdown(transport);
-          work_pending = true;
-        } else {
-          ssl->state = SSL_CLOSED;
-        }
-      }
-      else if (ssl->state == NEGOTIATING && ssl->app_input_closed) {
-        ssl->app_output_closed = PN_EOS;
-        ssl->state = SSL_CLOSED;
-      }
-    }
-  } while (work_pending);
-
-  if (written == 0 && ssl->state == SSL_CLOSED) {
-    written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
-    if (transport->io_layers[layer]==&ssl_input_closed_layer) {
-      transport->io_layers[layer] = &ssl_closed_layer;
-    } else {
-      transport->io_layers[layer] = &ssl_output_closed_layer;
-    }
-  }
-  ssl_log(transport, "process_output_ssl() returning %d\n", (int) written);
-  return written;
-}
-
-
-static ssize_t process_input_done(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t len)
-{
-  return PN_EOS;
-}
-
-static ssize_t process_output_done(pn_transport_t *transport, unsigned int layer, char *input_data, size_t len)
-{
-  return PN_EOS;
-}
-
-// return # output bytes sitting in this layer
-static size_t buffered_output(pn_transport_t *transport)
-{
-  size_t count = 0;
-  pni_ssl_t *ssl = transport->ssl;
-  if (ssl) {
-    count += ssl->network_out_pending;
-    if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
-      count++;
-  }
-  return count;
-}
-
-static HCERTSTORE open_cert_db(const char *store_name, const char *passwd, int *error) {
-  *error = 0;
-  DWORD sys_store_type = 0;
-  HCERTSTORE cert_store = 0;
-
-  if (store_name) {
-    if (strncmp(store_name, "ss:", 3) == 0) {
-      store_name += 3;
-      sys_store_type = CERT_SYSTEM_STORE_CURRENT_USER;
-    }
-    else if (strncmp(store_name, "lmss:", 5) == 0) {
-      store_name += 5;
-      sys_store_type = CERT_SYSTEM_STORE_LOCAL_MACHINE;
-    }
-  }
-
-  if (sys_store_type) {
-    // Opening a system store, names are not case sensitive.
-    // Map confusing GUI name to actual registry store name.
-    if (!pn_strcasecmp(store_name, "personal")) store_name= "my";
-    cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
-                               CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG |
-                               sys_store_type, store_name);
-    if (!cert_store) {
-      ssl_log_error_status(GetLastError(), "Failed to open system certificate store %s", store_name);
-      *error = -3;
-      return NULL;
-    }
-  } else {
-    // PKCS#12 file
-    HANDLE cert_file = CreateFile(store_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
-                                  FILE_ATTRIBUTE_NORMAL, NULL);
-    if (INVALID_HANDLE_VALUE == cert_file) {
-      HRESULT status = GetLastError();
-      ssl_log_error_status(status, "Failed to open the file holding the private key: %s", store_name);
-      *error = -4;
-      return NULL;
-    }
-    DWORD nread = 0L;
-    const DWORD file_size = GetFileSize(cert_file, NULL);
-    char *buf = NULL;
-    if (INVALID_FILE_SIZE != file_size)
-      buf = (char *) malloc(file_size);
-    if (!buf || !ReadFile(cert_file, buf, file_size, &nread, NULL)
-        || file_size != nread) {
-      HRESULT status = GetLastError();
-      CloseHandle(cert_file);
-      free(buf);
-      ssl_log_error_status(status, "Reading the private key from file failed %s", store_name);
-      *error = -5;
-      return NULL;
-    }
-    CloseHandle(cert_file);
-
-    CRYPT_DATA_BLOB blob;
-    blob.cbData = nread;
-    blob.pbData = (BYTE *) buf;
-
-    wchar_t *pwUCS2 = NULL;
-    int pwlen = 0;
-    if (passwd) {
-      // convert passwd to null terminated wchar_t (Windows UCS2)
-      pwlen = strlen(passwd);
-      pwUCS2 = (wchar_t *) calloc(pwlen + 1, sizeof(wchar_t));
-      int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, passwd, pwlen, &pwUCS2[0], pwlen);
-      if (!nwc) {
-        ssl_log_error_status(GetLastError(), "Error converting password from UTF8");
-        free(buf);
-        free(pwUCS2);
-        *error = -6;
-        return NULL;
-      }
-    }
-
-    cert_store = PFXImportCertStore(&blob, pwUCS2, 0);
-    if (pwUCS2) {
-      SecureZeroMemory(pwUCS2, pwlen * sizeof(wchar_t));
-      free(pwUCS2);
-    }
-    if (cert_store == NULL) {
-      ssl_log_error_status(GetLastError(), "Failed to import the file based certificate store");
-      free(buf);
-      *error = -7;
-      return NULL;
-    }
-
-    free(buf);
-  }
-
-  return cert_store;
-}
-
-static bool store_contains(HCERTSTORE store, PCCERT_CONTEXT cert)
-{
-  DWORD find_type = CERT_FIND_EXISTING; // Require exact match
-  PCCERT_CONTEXT tcert = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
-                                                    0, find_type, cert, 0);
-  if (tcert) {
-    CertFreeCertificateContext(tcert);
-    return true;
-  }
-  return false;
-}
-
-/* Match the DNS name pattern from the peer certificate against our configured peer
-   hostname */
-static bool match_dns_pattern(const char *hostname, const char *pattern, int plen)
-{
-  int slen = (int) strlen(hostname);
-  if (memchr( pattern, '*', plen ) == NULL)
-    return (plen == slen &&
-            pn_strncasecmp( pattern, hostname, plen ) == 0);
-
-  /* dns wildcarded pattern - RFC2818 */
-  char plabel[64];   /* max label length < 63 - RFC1034 */
-  char slabel[64];
-
-  while (plen > 0 && slen > 0) {
-    const char *cptr;
-    int len;
-
-    cptr = (const char *) memchr( pattern, '.', plen );
-    len = (cptr) ? cptr - pattern : plen;
-    if (len > (int) sizeof(plabel) - 1) return false;
-    memcpy( plabel, pattern, len );
-    plabel[len] = 0;
-    if (cptr) ++len;    // skip matching '.'
-    pattern += len;
-    plen -= len;
-
-    cptr = (const char *) memchr( hostname, '.', slen );
-    len = (cptr) ? cptr - hostname : slen;
-    if (len > (int) sizeof(slabel) - 1) return false;
-    memcpy( slabel, hostname, len );
-    slabel[len] = 0;
-    if (cptr) ++len;    // skip matching '.'
-    hostname += len;
-    slen -= len;
-
-    char *star = strchr( plabel, '*' );
-    if (!star) {
-      if (pn_strcasecmp( plabel, slabel )) return false;
-    } else {
-      *star = '\0';
-      char *prefix = plabel;
-      int prefix_len = strlen(prefix);
-      char *suffix = star + 1;
-      int suffix_len = strlen(suffix);
-      if (prefix_len && pn_strncasecmp( prefix, slabel, prefix_len )) return false;
-      if (suffix_len && pn_strncasecmp( suffix,
-                                     slabel + (strlen(slabel) - suffix_len),
-                                     suffix_len )) return false;
-    }
-  }
-
-  return plen == slen;
-}
-
-// Caller must free the returned buffer
-static char* wide_to_utf8(LPWSTR wstring)
-{
-  int len = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, 0, 0, 0, 0);
-  if (!len) {
-    ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
-    return NULL;
-  }
-  char *p = (char *) malloc(len);
-  if (!p) return NULL;
-  if (WideCharToMultiByte(CP_UTF8, 0, wstring, -1, p, len, 0, 0))
-    return p;
-  ssl_log_error_status(GetLastError(), "converting UCS2 to UTF8");
-  free (p);
-  return NULL;
-}
-
-static bool server_name_matches(const char *server_name, CERT_EXTENSION *alt_name_ext, PCCERT_CONTEXT cert)
-{
-  // As for openssl.c: alt names first, then CN
-  bool matched = false;
-
-  if (alt_name_ext) {
-    CERT_ALT_NAME_INFO* alt_name_info = NULL;
-    DWORD size = 0;
-    if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME2,
-                            alt_name_ext->Value.pbData, alt_name_ext->Value.cbData,
-                            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
-                            0, &alt_name_info, &size)) {
-      ssl_log_error_status(GetLastError(), "Alternative name match internal error");
-      return false;
-    }
-
-    int name_ct = alt_name_info->cAltEntry;
-    for (int i = 0; !matched && i < name_ct; ++i) {
-      if (alt_name_info->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) {
-        char *alt_name = wide_to_utf8(alt_name_info->rgAltEntry[i].pwszDNSName);
-        if (alt_name) {
-          matched = match_dns_pattern(server_name, (const char *) alt_name, strlen(alt_name));
-          free(alt_name);
-        }
-      }
-    }
-    LocalFree(&alt_name_info);
-  }
-
-  if (!matched) {
-    PCERT_INFO info = cert->pCertInfo;
-    DWORD len = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, 0, 0);
-    char *name = (char *) malloc(len);
-    if (name) {
-      int count = CertGetNameString(cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, name, len);
-      if (count)
-        matched = match_dns_pattern(server_name, (const char *) name, strlen(name));
-      free(name);
-    }
-  }
-  return matched;
-}
-
-const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subject_subfield field)
-{
-    return NULL;
-}
-
-int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0,
-                                          char *fingerprint,
-                                          size_t fingerprint_length,
-                                          pn_ssl_hash_alg hash_alg)
-{
-    return -1;
-}
-
-static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *server_name, bool tracing)
-{
-  // Free/release the following before return:
-  PCCERT_CONTEXT peer_cc = 0;
-  PCCERT_CONTEXT trust_anchor = 0;
-  PCCERT_CHAIN_CONTEXT chain_context = 0;
-  wchar_t *nameUCS2 = 0;
-
-  if (server_name && strlen(server_name) > 255) {
-    ssl_log_error("invalid server name: %s\n", server_name);
-    return WSAENAMETOOLONG;
-  }
-
-  // Get peer's certificate.
-  SECURITY_STATUS status;
-  status = QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &peer_cc);
-  if (status != SEC_E_OK) {
-    ssl_log_error_status(status, "can't obtain remote peer certificate information");
-    return status;
-  }
-
-  // Build the peer's certificate chain.  Multiple chains may be built but we
-  // care about rgpChain[0], which is the best.  Custom root stores are not
-  // allowed until W8/server 2012: see CERT_CHAIN_ENGINE_CONFIG.  For now, we
-  // manually override to taste.
-
-  // Chain verification functions give false reports for CRL if the trust anchor
-  // is not in the official root store.  We ignore CRL completely if it doesn't
-  // apply to any untrusted certs in the chain, and defer to SChannel's veto
-  // otherwise.  To rely on CRL, the CA must be in both the official system
-  // trusted root store and the Proton cred->trust_store.  To defeat CRL, the
-  // most distal cert with CRL must be placed in the Proton cred->trust_store.
-  // Similarly, certificate usage checking is overly strict at times.
-
-  CERT_CHAIN_PARA desc;
-  memset(&desc, 0, sizeof(desc));
-  desc.cbSize = sizeof(desc);
-
-  LPSTR usages[] = { szOID_PKIX_KP_SERVER_AUTH };
-  DWORD n_usages = sizeof(usages) / sizeof(LPSTR);
-  desc.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
-  desc.RequestedUsage.Usage.cUsageIdentifier = n_usages;
-  desc.RequestedUsage.Usage.rgpszUsageIdentifier = usages;
-
-  if(!CertGetCertificateChain(0, peer_cc, 0, peer_cc->hCertStore, &desc,
-                             CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT |
-                             CERT_CHAIN_CACHE_END_CERT,
-                             0, &chain_context)){
-    HRESULT st = GetLastError();
-    ssl_log_error_status(st, "Basic certificate chain check failed");
-    CertFreeCertificateContext(peer_cc);
-    return st;
-  }
-  if (chain_context->cChain < 1 || chain_context->rgpChain[0]->cElement < 1) {
-    ssl_log_error("empty chain with status %x %x\n", chain_context->TrustStatus.dwErrorStatus,
-                 chain_context->TrustStatus.dwInfoStatus);
-    return SEC_E_CERT_UNKNOWN;
-  }
-
-  int chain_len = chain_context->rgpChain[0]->cElement;
-  PCCERT_CONTEXT leaf_cert = chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
-  PCCERT_CONTEXT trunk_cert = chain_context->rgpChain[0]->rgpElement[chain_len - 1]->pCertContext;
-  if (tracing)
-    // See doc for CERT_CHAIN_POLICY_STATUS for bit field error and info status values
-    ssl_log_error("status for complete chain: error bits %x info bits %x\n",
-                  chain_context->TrustStatus.dwErrorStatus, chain_context->TrustStatus.dwInfoStatus);
-
-  // Supplement with checks against Proton's trusted_ca_db, custom revocation and usage.
-  HRESULT error = 0;
-  do {
-    // Do not return from this do loop.  Set error = SEC_E_XXX and break.
-    bool revocable = false;  // unless we see any untrusted certs that could be
-    for (int i = 0; i < chain_len; i++) {
-      CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[i];
-      PCCERT_CONTEXT cc = ce->pCertContext;
-      if (cc->pCertInfo->dwVersion != CERT_V3) {
-        if (tracing)
-          ssl_log_error("certificate chain element %d is not version 3\n", i);
-        error = SEC_E_CERT_WRONG_USAGE; // A fossil
-        break;
-      }
-
-      if (!trust_anchor && store_contains(root_store, cc))
-        trust_anchor = CertDuplicateCertificateContext(cc);
-
-      int n_ext = cc->pCertInfo->cExtension;
-      for (int ii = 0; ii < n_ext && !revocable && !trust_anchor; ii++) {
-        CERT_EXTENSION *p = &cc->pCertInfo->rgExtension[ii];
-        // rfc 5280 extensions for revocation
-        if (!strcmp(p->pszObjId, szOID_AUTHORITY_INFO_ACCESS) ||
-            !strcmp(p->pszObjId, szOID_CRL_DIST_POINTS) ||
-            !strcmp(p->pszObjId, szOID_FRESHEST_CRL)) {
-          revocable = true;
-        }
-      }
-
-      if (tracing) {
-        char name[512];
-        const char *is_anchor = (cc == trust_anchor) ? " trust anchor" : "";
-        if (!CertNameToStr(cc->dwCertEncodingType, &cc->pCertInfo->Subject,
-                           CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, name, sizeof(name)))
-          strcpy(name, "[too long]");
-        ssl_log_error("element %d (name: %s)%s error bits %x info bits %x\n", i, name, is_anchor,
-                      ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
-      }
-    }
-    if (error)
-      break;
-
-    if (!trust_anchor) {
-      // We don't trust any of the certs in the chain, see if the last cert
-      // is issued by a Proton trusted CA.
-      DWORD flags = CERT_STORE_NO_ISSUER_FLAG || CERT_STORE_SIGNATURE_FLAG ||
-        CERT_STORE_TIME_VALIDITY_FLAG;
-      trust_anchor = CertGetIssuerCertificateFromStore(root_store, trunk_cert, 0, &flags);
-      if (trust_anchor) {
-        if (tracing) {
-          if (flags & CERT_STORE_SIGNATURE_FLAG)
-            ssl_log_error("root certificate signature failure\n");
-          if (flags & CERT_STORE_TIME_VALIDITY_FLAG)
-            ssl_log_error("root certificate time validity failure\n");
-        }
-        if (flags) {
-          CertFreeCertificateContext(trust_anchor);
-          trust_anchor = 0;
-        }
-      }
-    }
-    if (!trust_anchor) {
-      error = SEC_E_UNTRUSTED_ROOT;
-      break;
-    }
-
-    bool strict_usage = false;
-    CERT_EXTENSION *leaf_alt_names = 0;
-    if (leaf_cert != trust_anchor) {
-      int n_ext = leaf_cert->pCertInfo->cExtension;
-      for (int ii = 0; ii < n_ext; ii++) {
-        CERT_EXTENSION *p = &leaf_cert->pCertInfo->rgExtension[ii];
-        if (!strcmp(p->pszObjId, szOID_ENHANCED_KEY_USAGE))
-          strict_usage = true;
-        if (!strcmp(p->pszObjId, szOID_SUBJECT_ALT_NAME2))
-          if (p->Value.pbData)
-            leaf_alt_names = p;
-      }
-    }
-
-    if (server_name) {
-      int len = strlen(server_name);
-      nameUCS2 = (wchar_t *) calloc(len + 1, sizeof(wchar_t));
-      int nwc = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, server_name, len, &nameUCS2[0], len);
-      if (!nwc) {
-        error = GetLastError();
-        ssl_log_error_status(error, "Error converting server name from UTF8");
-        break;
-      }
-    }
-
-    // SSL-specific parameters (ExtraPolicy below)
-    SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_desc;
-    memset(&ssl_desc, 0, sizeof(ssl_desc));
-    ssl_desc.cbSize = sizeof(ssl_desc);
-    ssl_desc.pwszServerName = nameUCS2;
-    ssl_desc.dwAuthType = nameUCS2 ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
-    ssl_desc.fdwChecks = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
-    if (server_name)
-      ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
-    if (!revocable)
-      ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_REVOCATION;
-    if (!strict_usage)
-      ssl_desc.fdwChecks |= SECURITY_FLAG_IGNORE_WRONG_USAGE;
-
-    // General certificate chain parameters
-    CERT_CHAIN_POLICY_PARA chain_desc;
-    memset(&chain_desc, 0, sizeof(chain_desc));
-    chain_desc.cbSize = sizeof(chain_desc);
-    chain_desc.dwFlags = CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG;
-    if (!revocable)
-      chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
-    if (!strict_usage)
-      chain_desc.dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
-    chain_desc.pvExtraPolicyPara = &ssl_desc;
-
-    CERT_CHAIN_POLICY_STATUS chain_status;
-    memset(&chain_status, 0, sizeof(chain_status));
-    chain_status.cbSize = sizeof(chain_status);
-
-    if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context,
-                                          &chain_desc, &chain_status)) {
-      error = GetLastError();
-      // Failure to complete the check, does not (in)validate the cert.
-      ssl_log_error_status(error, "Supplemental certificate chain check failed");
-      break;
-    }
-
-    if (chain_status.dwError) {
-      error = chain_status.dwError;
-      if (tracing) {
-        ssl_log_error_status(chain_status.dwError, "Certificate chain verification error");
-        if (chain_status.lChainIndex == 0 && chain_status.lElementIndex != -1) {
-          int idx = chain_status.lElementIndex;
-          CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[idx];
-          ssl_log_error("  chain failure at %d error/info: %x %x\n", idx,
-                        ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
-        }
-      }
-      break;
-    }
-
-    if (server_name && ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME &&
-        !server_name_matches(server_name, leaf_alt_names, leaf_cert)) {
-      error = SEC_E_WRONG_PRINCIPAL;
-      break;
-    }
-    else if (ssl->verify_mode == PN_SSL_VERIFY_PEER_NAME && !server_name) {
-      ssl_log_error("Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!");
-      error = SEC_E_WRONG_PRINCIPAL;
-      break;
-    }
-  } while (0);
-
-  if (tracing && !error)
-    ssl_log_error("peer certificate authenticated\n");
-
-  // Lots to clean up.
-  if (peer_cc)
-    CertFreeCertificateContext(peer_cc);
-  if (trust_anchor)
-    CertFreeCertificateContext(trust_anchor);
-  if (chain_context)
-    CertFreeCertificateChain(chain_context);
-  free(nameUCS2);
-  return error;
-}


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


[16/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/codec.c b/proton-c/src/core/codec.c
new file mode 100644
index 0000000..67769ad
--- /dev/null
+++ b/proton-c/src/core/codec.c
@@ -0,0 +1,2141 @@
+/*
+ *
+ * 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/object.h>
+#include <proton/codec.h>
+#include <proton/error.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "encodings.h"
+#define DEFINE_FIELDS
+#include "protocol.h"
+#include "platform/platform_fmt.h"
+#include "util.h"
+#include "decoder.h"
+#include "encoder.h"
+#include "data.h"
+#include "log_private.h"
+
+const char *pn_type_name(pn_type_t type)
+{
+  switch (type)
+  {
+  case PN_NULL: return "PN_NULL";
+  case PN_BOOL: return "PN_BOOL";
+  case PN_UBYTE: return "PN_UBYTE";
+  case PN_BYTE: return "PN_BYTE";
+  case PN_USHORT: return "PN_USHORT";
+  case PN_SHORT: return "PN_SHORT";
+  case PN_UINT: return "PN_UINT";
+  case PN_INT: return "PN_INT";
+  case PN_CHAR: return "PN_CHAR";
+  case PN_ULONG: return "PN_ULONG";
+  case PN_LONG: return "PN_LONG";
+  case PN_TIMESTAMP: return "PN_TIMESTAMP";
+  case PN_FLOAT: return "PN_FLOAT";
+  case PN_DOUBLE: return "PN_DOUBLE";
+  case PN_DECIMAL32: return "PN_DECIMAL32";
+  case PN_DECIMAL64: return "PN_DECIMAL64";
+  case PN_DECIMAL128: return "PN_DECIMAL128";
+  case PN_UUID: return "PN_UUID";
+  case PN_BINARY: return "PN_BINARY";
+  case PN_STRING: return "PN_STRING";
+  case PN_SYMBOL: return "PN_SYMBOL";
+  case PN_DESCRIBED: return "PN_DESCRIBED";
+  case PN_ARRAY: return "PN_ARRAY";
+  case PN_LIST: return "PN_LIST";
+  case PN_MAP: return "PN_MAP";
+  default: break;
+  }
+
+  return "<UNKNOWN>";
+}
+
+static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type)
+{
+  memset(atom, 0, sizeof(pn_atom_t));
+  atom->type = type;
+}
+
+// data
+
+static void pn_data_finalize(void *object)
+{
+  pn_data_t *data = (pn_data_t *) object;
+  free(data->nodes);
+  pn_buffer_free(data->buf);
+  pn_free(data->str);
+  pn_error_free(data->error);
+  pn_free(data->decoder);
+  pn_free(data->encoder);
+}
+
+static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
+{
+  if (!node) return NULL;
+  if (node->atom.type != PN_DESCRIBED) return NULL;
+
+  pni_node_t *descriptor = pn_data_node(data, node->down);
+
+  if (!descriptor || descriptor->atom.type != PN_ULONG) {
+    return NULL;
+  }
+
+  if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) {
+    const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
+    return (f->name_index!=0) ? f : NULL;
+  } else {
+    return NULL;
+  }
+}
+
+static int pni_node_index(pn_data_t *data, pni_node_t *node)
+{
+  int count = 0;
+  while (node) {
+    node = pn_data_node(data, node->prev);
+    count++;
+  }
+  return count - 1;
+}
+
+int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
+{
+  switch (atom->type) {
+  case PN_NULL:
+    return pn_string_addf(str, "null");
+  case PN_BOOL:
+    return pn_string_addf(str, atom->u.as_bool ? "true" : "false");
+  case PN_UBYTE:
+    return pn_string_addf(str, "%" PRIu8, atom->u.as_ubyte);
+  case PN_BYTE:
+    return pn_string_addf(str, "%" PRIi8, atom->u.as_byte);
+  case PN_USHORT:
+    return pn_string_addf(str, "%" PRIu16, atom->u.as_ushort);
+  case PN_SHORT:
+    return pn_string_addf(str, "%" PRIi16, atom->u.as_short);
+  case PN_UINT:
+    return pn_string_addf(str, "%" PRIu32, atom->u.as_uint);
+  case PN_INT:
+    return pn_string_addf(str, "%" PRIi32, atom->u.as_int);
+  case PN_CHAR:
+    return pn_string_addf(str, "%c",  atom->u.as_char);
+  case PN_ULONG:
+    return pn_string_addf(str, "%" PRIu64, atom->u.as_ulong);
+  case PN_LONG:
+    return pn_string_addf(str, "%" PRIi64, atom->u.as_long);
+  case PN_TIMESTAMP:
+    return pn_string_addf(str, "%" PRIi64, atom->u.as_timestamp);
+  case PN_FLOAT:
+    return pn_string_addf(str, "%g", atom->u.as_float);
+  case PN_DOUBLE:
+    return pn_string_addf(str, "%g", atom->u.as_double);
+  case PN_DECIMAL32:
+    return pn_string_addf(str, "D32(%" PRIu32 ")", atom->u.as_decimal32);
+  case PN_DECIMAL64:
+    return pn_string_addf(str, "D64(%" PRIu64 ")", atom->u.as_decimal64);
+  case PN_DECIMAL128:
+    return pn_string_addf(str, "D128(%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+                          "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+                          "%02hhx%02hhx)",
+                          atom->u.as_decimal128.bytes[0],
+                          atom->u.as_decimal128.bytes[1],
+                          atom->u.as_decimal128.bytes[2],
+                          atom->u.as_decimal128.bytes[3],
+                          atom->u.as_decimal128.bytes[4],
+                          atom->u.as_decimal128.bytes[5],
+                          atom->u.as_decimal128.bytes[6],
+                          atom->u.as_decimal128.bytes[7],
+                          atom->u.as_decimal128.bytes[8],
+                          atom->u.as_decimal128.bytes[9],
+                          atom->u.as_decimal128.bytes[10],
+                          atom->u.as_decimal128.bytes[11],
+                          atom->u.as_decimal128.bytes[12],
+                          atom->u.as_decimal128.bytes[13],
+                          atom->u.as_decimal128.bytes[14],
+                          atom->u.as_decimal128.bytes[15]);
+  case PN_UUID:
+    return pn_string_addf(str, "UUID(%02hhx%02hhx%02hhx%02hhx-"
+                          "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
+                          "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx)",
+                          atom->u.as_uuid.bytes[0],
+                          atom->u.as_uuid.bytes[1],
+                          atom->u.as_uuid.bytes[2],
+                          atom->u.as_uuid.bytes[3],
+                          atom->u.as_uuid.bytes[4],
+                          atom->u.as_uuid.bytes[5],
+                          atom->u.as_uuid.bytes[6],
+                          atom->u.as_uuid.bytes[7],
+                          atom->u.as_uuid.bytes[8],
+                          atom->u.as_uuid.bytes[9],
+                          atom->u.as_uuid.bytes[10],
+                          atom->u.as_uuid.bytes[11],
+                          atom->u.as_uuid.bytes[12],
+                          atom->u.as_uuid.bytes[13],
+                          atom->u.as_uuid.bytes[14],
+                          atom->u.as_uuid.bytes[15]);
+  case PN_BINARY:
+  case PN_STRING:
+  case PN_SYMBOL:
+    {
+      int err;
+      const char *pfx;
+      pn_bytes_t bin = atom->u.as_bytes;
+      bool quote;
+      switch (atom->type) {
+      case PN_BINARY:
+        pfx = "b";
+        quote = true;
+        break;
+      case PN_STRING:
+        pfx = "";
+        quote = true;
+        break;
+      case PN_SYMBOL:
+        pfx = ":";
+        quote = false;
+        for (unsigned i = 0; i < bin.size; i++) {
+          if (!isalpha(bin.start[i])) {
+            quote = true;
+            break;
+          }
+        }
+        break;
+      default:
+        assert(false);
+        return PN_ERR;
+      }
+
+      if ((err = pn_string_addf(str, "%s", pfx))) return err;
+      if (quote) if ((err = pn_string_addf(str, "\""))) return err;
+      if ((err = pn_quote(str, bin.start, bin.size))) return err;
+      if (quote) if ((err = pn_string_addf(str, "\""))) return err;
+      return 0;
+    }
+  case PN_LIST:
+    return pn_string_addf(str, "<list>");
+  case PN_MAP:
+    return pn_string_addf(str, "<map>");
+  case PN_ARRAY:
+    return pn_string_addf(str, "<array>");
+  case PN_DESCRIBED:
+    return pn_string_addf(str, "<described>");
+  default:
+    return pn_string_addf(str, "<undefined: %i>", atom->type);
+  }
+}
+
+int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+  pn_string_t *str = (pn_string_t *) ctx;
+  pn_atom_t *atom = (pn_atom_t *) &node->atom;
+
+  pni_node_t *parent = pn_data_node(data, node->parent);
+  const pn_fields_t *fields = pni_node_fields(data, parent);
+  pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
+  const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+  int index = pni_node_index(data, node);
+
+  int err;
+
+  if (grandfields) {
+    if (atom->type == PN_NULL) {
+      return 0;
+    }
+    const char *name = (index < grandfields->field_count)
+        ? FIELD_STRINGPOOL.STRING0+FIELD_FIELDS[grandfields->first_field_index+index]
+        : NULL;
+    if (name) {
+      err = pn_string_addf(str, "%s=", name);
+      if (err) return err;
+    }
+  }
+
+  switch (atom->type) {
+  case PN_DESCRIBED:
+    return pn_string_addf(str, "@");
+  case PN_ARRAY:
+    // XXX: need to fix for described arrays
+    return pn_string_addf(str, "@%s[", pn_type_name(node->type));
+  case PN_LIST:
+    return pn_string_addf(str, "[");
+  case PN_MAP:
+    return pn_string_addf(str, "{");
+  default:
+    if (fields && index == 0) {
+      err = pn_string_addf(str, "%s", FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]);
+      if (err) return err;
+      err = pn_string_addf(str, "(");
+      if (err) return err;
+      err = pni_inspect_atom(atom, str);
+      if (err) return err;
+      return pn_string_addf(str, ")");
+    } else {
+      return pni_inspect_atom(atom, str);
+    }
+  }
+}
+
+pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node)
+{
+  while (node) {
+    node = pn_data_node(data, node->next);
+    if (node && node->atom.type != PN_NULL) {
+      return node;
+    }
+  }
+
+  return NULL;
+}
+
+int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+  pn_string_t *str = (pn_string_t *) ctx;
+  pni_node_t *parent = pn_data_node(data, node->parent);
+  pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
+  const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+  pni_node_t *next = pn_data_node(data, node->next);
+  int err;
+
+  switch (node->atom.type) {
+  case PN_ARRAY:
+  case PN_LIST:
+    err = pn_string_addf(str, "]");
+    if (err) return err;
+    break;
+  case PN_MAP:
+    err = pn_string_addf(str, "}");
+    if (err) return err;
+    break;
+  default:
+    break;
+  }
+
+  if (!grandfields || node->atom.type != PN_NULL) {
+    if (next) {
+      int index = pni_node_index(data, node);
+      if (parent && parent->atom.type == PN_MAP && (index % 2) == 0) {
+        err = pn_string_addf(str, "=");
+      } else if (parent && parent->atom.type == PN_DESCRIBED && index == 0) {
+        err = pn_string_addf(str, " ");
+        if (err) return err;
+      } else {
+        if (!grandfields || pni_next_nonnull(data, node)) {
+          err = pn_string_addf(str, ", ");
+          if (err) return err;
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int pn_data_inspect(void *obj, pn_string_t *dst)
+{
+  pn_data_t *data = (pn_data_t *) obj;
+
+  return pni_data_traverse(data, pni_inspect_enter, pni_inspect_exit, dst);
+}
+
+#define pn_data_initialize NULL
+#define pn_data_hashcode NULL
+#define pn_data_compare NULL
+
+pn_data_t *pn_data(size_t capacity)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_data);
+  pn_data_t *data = (pn_data_t *) pn_class_new(&clazz, sizeof(pn_data_t));
+  data->capacity = capacity;
+  data->size = 0;
+  data->nodes = capacity ? (pni_node_t *) malloc(capacity * sizeof(pni_node_t)) : NULL;
+  data->buf = pn_buffer(64);
+  data->parent = 0;
+  data->current = 0;
+  data->base_parent = 0;
+  data->base_current = 0;
+  data->decoder = pn_decoder();
+  data->encoder = pn_encoder();
+  data->error = pn_error();
+  data->str = pn_string(NULL);
+  return data;
+}
+
+void pn_data_free(pn_data_t *data)
+{
+  pn_free(data);
+}
+
+int pn_data_errno(pn_data_t *data)
+{
+  return pn_error_code(data->error);
+}
+
+pn_error_t *pn_data_error(pn_data_t *data)
+{
+  return data->error;
+}
+
+size_t pn_data_size(pn_data_t *data)
+{
+  return data ? data->size : 0;
+}
+
+void pn_data_clear(pn_data_t *data)
+{
+  if (data) {
+    data->size = 0;
+    data->parent = 0;
+    data->current = 0;
+    data->base_parent = 0;
+    data->base_current = 0;
+    pn_buffer_clear(data->buf);
+  }
+}
+
+static int pni_data_grow(pn_data_t *data)
+{
+  size_t capacity = data->capacity ? data->capacity : 2;
+  if (capacity >= PNI_NID_MAX) return PN_OUT_OF_MEMORY;
+  else if (capacity < PNI_NID_MAX/2) capacity *= 2;
+  else capacity = PNI_NID_MAX;
+
+  pni_node_t *new_nodes = (pni_node_t *)realloc(data->nodes, capacity * sizeof(pni_node_t));
+  if (new_nodes == NULL) return PN_OUT_OF_MEMORY;
+  data->capacity = capacity;
+  data->nodes = new_nodes;
+  return 0;
+}
+
+static ssize_t pni_data_intern(pn_data_t *data, const char *start, size_t size)
+{
+  size_t offset = pn_buffer_size(data->buf);
+  int err = pn_buffer_append(data->buf, start, size);
+  if (err) return err;
+  err = pn_buffer_append(data->buf, "\0", 1);
+  if (err) return err;
+  return offset;
+}
+
+static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node)
+{
+  switch (node->atom.type) {
+  case PN_BINARY:
+  case PN_STRING:
+  case PN_SYMBOL:
+    return &node->atom.u.as_bytes;
+  default: return NULL;
+  }
+}
+
+static void pni_data_rebase(pn_data_t *data, char *base)
+{
+  for (unsigned i = 0; i < data->size; i++) {
+    pni_node_t *node = &data->nodes[i];
+    if (node->data) {
+      pn_bytes_t *bytes = pni_data_bytes(data, node);
+      bytes->start = base + node->data_offset;
+    }
+  }
+}
+
+static int pni_data_intern_node(pn_data_t *data, pni_node_t *node)
+{
+  pn_bytes_t *bytes = pni_data_bytes(data, node);
+  if (!bytes) return 0;
+  size_t oldcap = pn_buffer_capacity(data->buf);
+  ssize_t offset = pni_data_intern(data, bytes->start, bytes->size);
+  if (offset < 0) return offset;
+  node->data = true;
+  node->data_offset = offset;
+  node->data_size = bytes->size;
+  pn_rwbytes_t buf = pn_buffer_memory(data->buf);
+  bytes->start = buf.start + offset;
+
+  if (pn_buffer_capacity(data->buf) != oldcap) {
+    pni_data_rebase(data, buf.start);
+  }
+
+  return 0;
+}
+
+int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap)
+{
+  int err = 0;
+  const char *begin = fmt;
+  while (*fmt) {
+    char code = *(fmt++);
+    if (!code) return 0;
+
+    switch (code) {
+    case 'n':
+      err = pn_data_put_null(data);
+      break;
+    case 'o':
+      err = pn_data_put_bool(data, va_arg(ap, int));
+      break;
+    case 'B':
+      err = pn_data_put_ubyte(data, va_arg(ap, unsigned int));
+      break;
+    case 'b':
+      err = pn_data_put_byte(data, va_arg(ap, int));
+      break;
+    case 'H':
+      err = pn_data_put_ushort(data, va_arg(ap, unsigned int));
+      break;
+    case 'h':
+      err = pn_data_put_short(data, va_arg(ap, int));
+      break;
+    case 'I':
+      err = pn_data_put_uint(data, va_arg(ap, uint32_t));
+      break;
+    case 'i':
+      err = pn_data_put_int(data, va_arg(ap, uint32_t));
+      break;
+    case 'L':
+      err = pn_data_put_ulong(data, va_arg(ap, uint64_t));
+      break;
+    case 'l':
+      err = pn_data_put_long(data, va_arg(ap, int64_t));
+      break;
+    case 't':
+      err = pn_data_put_timestamp(data, va_arg(ap, pn_timestamp_t));
+      break;
+    case 'f':
+      err = pn_data_put_float(data, va_arg(ap, double));
+      break;
+    case 'd':
+      err = pn_data_put_double(data, va_arg(ap, double));
+      break;
+    case 'z':
+      {
+	// For maximum portability, caller must pass these as two separate args, not a single struct
+        size_t size = va_arg(ap, size_t);
+        char *start = va_arg(ap, char *);
+        if (start) {
+          err = pn_data_put_binary(data, pn_bytes(size, start));
+        } else {
+          err = pn_data_put_null(data);
+        }
+      }
+      break;
+    case 'S':
+    case 's':
+      {
+        char *start = va_arg(ap, char *);
+        size_t size;
+        if (start) {
+          size = strlen(start);
+          if (code == 'S') {
+            err = pn_data_put_string(data, pn_bytes(size, start));
+          } else {
+            err = pn_data_put_symbol(data, pn_bytes(size, start));
+          }
+        } else {
+          err = pn_data_put_null(data);
+        }
+      }
+      break;
+    case 'D':
+      err = pn_data_put_described(data);
+      pn_data_enter(data);
+      break;
+    case 'T':
+      {
+        pni_node_t *parent = pn_data_node(data, data->parent);
+        if (parent->atom.type == PN_ARRAY) {
+          parent->type = (pn_type_t) va_arg(ap, int);
+        } else {
+          return pn_error_format(data->error, PN_ERR, "naked type");
+        }
+      }
+      break;
+    case '@':
+      {
+        bool described;
+        if (*(fmt + 1) == 'D') {
+          fmt++;
+          described = true;
+        } else {
+          described = false;
+        }
+        err = pn_data_put_array(data, described, (pn_type_t) 0);
+        pn_data_enter(data);
+      }
+      break;
+    case '[':
+      if (fmt < (begin + 2) || *(fmt - 2) != 'T') {
+        err = pn_data_put_list(data);
+        if (err) return err;
+        pn_data_enter(data);
+      }
+      break;
+    case '{':
+      err = pn_data_put_map(data);
+      if (err) return err;
+      pn_data_enter(data);
+      break;
+    case '}':
+    case ']':
+      if (!pn_data_exit(data))
+        return pn_error_format(data->error, PN_ERR, "exit failed");
+      break;
+    case '?':
+      if (!va_arg(ap, int)) {
+        err = pn_data_put_null(data);
+        if (err) return err;
+        pn_data_enter(data);
+      }
+      break;
+    case '*':
+      {
+        int count = va_arg(ap, int);
+        void *ptr = va_arg(ap, void *);
+
+        char c = *(fmt++);
+
+        switch (c)
+        {
+        case 's':
+          {
+            char **sptr = (char **) ptr;
+            for (int i = 0; i < count; i++)
+            {
+              char *sym = *(sptr++);
+              err = pn_data_fill(data, "s", sym);
+              if (err) return err;
+            }
+          }
+          break;
+        default:
+          pn_logf("unrecognized * code: 0x%.2X '%c'", code, code);
+          return PN_ARG_ERR;
+        }
+      }
+      break;
+    case 'C':
+      {
+        pn_data_t *src = va_arg(ap, pn_data_t *);
+        if (src && pn_data_size(src) > 0) {
+          err = pn_data_appendn(data, src, 1);
+          if (err) return err;
+        } else {
+          err = pn_data_put_null(data);
+          if (err) return err;
+        }
+      }
+      break;
+    default:
+      pn_logf("unrecognized fill code: 0x%.2X '%c'", code, code);
+      return PN_ARG_ERR;
+    }
+
+    if (err) return err;
+
+    pni_node_t *parent = pn_data_node(data, data->parent);
+    while (parent) {
+      if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
+        pn_data_exit(data);
+        parent = pn_data_node(data, data->parent);
+      } else if (parent->atom.type == PN_NULL && parent->children == 1) {
+        pn_data_exit(data);
+        pni_node_t *current = pn_data_node(data, data->current);
+        current->down = 0;
+        current->children = 0;
+        parent = pn_data_node(data, data->parent);
+      } else {
+        break;
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+int pn_data_fill(pn_data_t *data, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  int err = pn_data_vfill(data, fmt, ap);
+  va_end(ap);
+  return err;
+}
+
+static bool pn_scan_next(pn_data_t *data, pn_type_t *type, bool suspend)
+{
+  if (suspend) return false;
+  bool found = pn_data_next(data);
+  if (found) {
+    *type = pn_data_type(data);
+    return true;
+  } else {
+    pni_node_t *parent = pn_data_node(data, data->parent);
+    if (parent && parent->atom.type == PN_DESCRIBED) {
+      pn_data_exit(data);
+      return pn_scan_next(data, type, suspend);
+    } else {
+      *type = PN_INVALID;
+      return false;
+    }
+  }
+}
+
+static pni_node_t *pni_data_peek(pn_data_t *data);
+
+int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap)
+{
+  pn_data_rewind(data);
+  bool *scanarg = NULL;
+  bool at = false;
+  int level = 0;
+  int count_level = -1;
+  int resume_count = 0;
+
+  while (*fmt) {
+    char code = *(fmt++);
+
+    bool found = false;
+    pn_type_t type;
+
+    bool scanned = false;
+    bool suspend = resume_count > 0;
+
+    switch (code) {
+    case 'n':
+      found = pn_scan_next(data, &type, suspend);
+      if (found && type == PN_NULL) {
+        scanned = true;
+      } else {
+        scanned = false;
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'o':
+      {
+        bool *value = va_arg(ap, bool *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_BOOL) {
+          *value = pn_data_get_bool(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'B':
+      {
+        uint8_t *value = va_arg(ap, uint8_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_UBYTE) {
+          *value = pn_data_get_ubyte(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'b':
+      {
+        int8_t *value = va_arg(ap, int8_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_BYTE) {
+          *value = pn_data_get_byte(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'H':
+      {
+        uint16_t *value = va_arg(ap, uint16_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_USHORT) {
+          *value = pn_data_get_ushort(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'h':
+      {
+        int16_t *value = va_arg(ap, int16_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_SHORT) {
+          *value = pn_data_get_short(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'I':
+      {
+        uint32_t *value = va_arg(ap, uint32_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_UINT) {
+          *value = pn_data_get_uint(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'i':
+      {
+        int32_t *value = va_arg(ap, int32_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_INT) {
+          *value = pn_data_get_int(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'c':
+      {
+        pn_char_t *value = va_arg(ap, pn_char_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_CHAR) {
+          *value = pn_data_get_char(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'L':
+      {
+        uint64_t *value = va_arg(ap, uint64_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_ULONG) {
+          *value = pn_data_get_ulong(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'l':
+      {
+        int64_t *value = va_arg(ap, int64_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_LONG) {
+          *value = pn_data_get_long(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 't':
+      {
+        pn_timestamp_t *value = va_arg(ap, pn_timestamp_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_TIMESTAMP) {
+          *value = pn_data_get_timestamp(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'f':
+      {
+        float *value = va_arg(ap, float *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_FLOAT) {
+          *value = pn_data_get_float(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'd':
+      {
+        double *value = va_arg(ap, double *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_DOUBLE) {
+          *value = pn_data_get_double(data);
+          scanned = true;
+        } else {
+          *value = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'z':
+      {
+        pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_BINARY) {
+          *bytes = pn_data_get_binary(data);
+          scanned = true;
+        } else {
+          bytes->start = 0;
+          bytes->size = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'S':
+      {
+        pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_STRING) {
+          *bytes = pn_data_get_string(data);
+          scanned = true;
+        } else {
+          bytes->start = 0;
+          bytes->size = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 's':
+      {
+        pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_SYMBOL) {
+          *bytes = pn_data_get_symbol(data);
+          scanned = true;
+        } else {
+          bytes->start = 0;
+          bytes->size = 0;
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case 'D':
+      found = pn_scan_next(data, &type, suspend);
+      if (found && type == PN_DESCRIBED) {
+        pn_data_enter(data);
+        scanned = true;
+      } else {
+        if (!suspend) {
+          resume_count = 3;
+          count_level = level;
+        }
+        scanned = false;
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case '@':
+      found = pn_scan_next(data, &type, suspend);
+      if (found && type == PN_ARRAY) {
+        pn_data_enter(data);
+        scanned = true;
+        at = true;
+      } else {
+        if (!suspend) {
+          resume_count = 3;
+          count_level = level;
+        }
+        scanned = false;
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case '[':
+      if (at) {
+        scanned = true;
+        at = false;
+      } else {
+        found = pn_scan_next(data, &type, suspend);
+        if (found && type == PN_LIST) {
+          pn_data_enter(data);
+          scanned = true;
+        } else {
+          if (!suspend) {
+            resume_count = 1;
+            count_level = level;
+          }
+          scanned = false;
+        }
+      }
+      level++;
+      break;
+    case '{':
+      found = pn_scan_next(data, &type, suspend);
+      if (found && type == PN_MAP) {
+        pn_data_enter(data);
+        scanned = true;
+      } else {
+        if (resume_count) {
+          resume_count = 1;
+          count_level = level;
+        }
+        scanned = false;
+      }
+      level++;
+      break;
+    case ']':
+    case '}':
+      level--;
+      if (!suspend && !pn_data_exit(data))
+        return pn_error_format(data->error, PN_ERR, "exit failed");
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case '.':
+      found = pn_scan_next(data, &type, suspend);
+      scanned = found;
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    case '?':
+      if (!*fmt || *fmt == '?')
+        return pn_error_format(data->error, PN_ARG_ERR, "codes must follow a ?");
+      scanarg = va_arg(ap, bool *);
+      break;
+    case 'C':
+      {
+        pn_data_t *dst = va_arg(ap, pn_data_t *);
+        if (!suspend) {
+          size_t old = pn_data_size(dst);
+          pni_node_t *next = pni_data_peek(data);
+          if (next && next->atom.type != PN_NULL) {
+            pn_data_narrow(data);
+            int err = pn_data_appendn(dst, data, 1);
+            pn_data_widen(data);
+            if (err) return err;
+            scanned = pn_data_size(dst) > old;
+          } else {
+            scanned = false;
+          }
+          pn_data_next(data);
+        } else {
+          scanned = false;
+        }
+      }
+      if (resume_count && level == count_level) resume_count--;
+      break;
+    default:
+      return pn_error_format(data->error, PN_ARG_ERR, "unrecognized scan code: 0x%.2X '%c'", code, code);
+    }
+
+    if (scanarg && code != '?') {
+      *scanarg = scanned;
+      scanarg = NULL;
+    }
+  }
+
+  return 0;
+}
+
+int pn_data_scan(pn_data_t *data, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  int err = pn_data_vscan(data, fmt, ap);
+  va_end(ap);
+  return err;
+}
+
+static int pni_data_inspectify(pn_data_t *data)
+{
+  int err = pn_string_set(data->str, "");
+  if (err) return err;
+  return pn_data_inspect(data, data->str);
+}
+
+int pn_data_print(pn_data_t *data)
+{
+  int err = pni_data_inspectify(data);
+  if (err) return err;
+  printf("%s", pn_string_get(data->str));
+  return 0;
+}
+
+int pn_data_format(pn_data_t *data, char *bytes, size_t *size)
+{
+  int err = pni_data_inspectify(data);
+  if (err) return err;
+  if (pn_string_size(data->str) >= *size) {
+    return PN_OVERFLOW;
+  } else {
+    pn_string_put(data->str, bytes);
+    *size = pn_string_size(data->str);
+    return 0;
+  }
+}
+
+static size_t pni_data_id(pn_data_t *data, pni_node_t *node)
+{
+  return node - data->nodes + 1;
+}
+
+static pni_node_t *pni_data_new(pn_data_t *data)
+{
+  if ((data->capacity <= data->size) && (pni_data_grow(data) != 0)) return NULL;
+  pni_node_t *node = pn_data_node(data, ++(data->size));
+  node->next = 0;
+  node->down = 0;
+  node->children = 0;
+  return node;
+}
+
+void pn_data_rewind(pn_data_t *data)
+{
+  data->parent = data->base_parent;
+  data->current = data->base_current;
+}
+
+static pni_node_t *pni_data_current(pn_data_t *data)
+{
+  return pn_data_node(data, data->current);
+}
+
+void pn_data_narrow(pn_data_t *data)
+{
+  data->base_parent = data->parent;
+  data->base_current = data->current;
+}
+
+void pn_data_widen(pn_data_t *data)
+{
+  data->base_parent = 0;
+  data->base_current = 0;
+}
+
+pn_handle_t pn_data_point(pn_data_t *data)
+{
+  if (data->current) {
+    return (pn_handle_t)(uintptr_t)data->current;
+  } else {
+    return (pn_handle_t)(uintptr_t)-data->parent;
+  }
+}
+
+bool pn_data_restore(pn_data_t *data, pn_handle_t point)
+{
+  pn_shandle_t spoint = (pn_shandle_t) point;
+  if (spoint <= 0 && ((size_t) (-spoint)) <= data->size) {
+    data->parent = -((pn_shandle_t) point);
+    data->current = 0;
+    return true;
+  } else if (spoint && spoint <= data->size) {
+    data->current = spoint;
+    pni_node_t *current = pni_data_current(data);
+    data->parent = current->parent;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static pni_node_t *pni_data_peek(pn_data_t *data)
+{
+  pni_node_t *current = pni_data_current(data);
+  if (current) {
+    return pn_data_node(data, current->next);
+  }
+
+  pni_node_t *parent = pn_data_node(data, data->parent);
+  if (parent) {
+    return pn_data_node(data, parent->down);
+  }
+
+  return NULL;
+}
+
+bool pn_data_next(pn_data_t *data)
+{
+  pni_node_t *current = pni_data_current(data);
+  pni_node_t *parent = pn_data_node(data, data->parent);
+  size_t next;
+
+  if (current) {
+    next = current->next;
+  } else if (parent && parent->down) {
+    next = parent->down;
+  } else if (!parent && data->size) {
+    next = 1;
+  } else {
+    return false;
+  }
+
+  if (next) {
+    data->current = next;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool pn_data_prev(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->prev) {
+    data->current = node->prev;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+int pni_data_traverse(pn_data_t *data,
+                      int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
+                      int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
+                      void *ctx)
+{
+  pni_node_t *node = data->size ? pn_data_node(data, 1) : NULL;
+  while (node) {
+    pni_node_t *parent = pn_data_node(data, node->parent);
+
+    int err = enter(ctx, data, node);
+    if (err) return err;
+
+    size_t next = 0;
+    if (node->down) {
+      next = node->down;
+    } else if (node->next) {
+      err = exit(ctx, data, node);
+      if (err) return err;
+      next = node->next;
+    } else {
+      err = exit(ctx, data, node);
+      if (err) return err;
+      while (parent) {
+        err = exit(ctx, data, parent);
+        if (err) return err;
+        if (parent->next) {
+          next = parent->next;
+          break;
+        } else {
+          parent = pn_data_node(data, parent->parent);
+        }
+      }
+    }
+
+    node = pn_data_node(data, next);
+  }
+
+  return 0;
+}
+
+pn_type_t pn_data_type(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node) {
+    return node->atom.type;
+  } else {
+    return PN_INVALID;
+  }
+}
+
+pn_type_t pni_data_parent_type(pn_data_t *data)
+{
+  pni_node_t *node = pn_data_node(data, data->parent);
+  if (node) {
+    return node->atom.type;
+  } else {
+    return PN_INVALID;
+  }
+}
+
+size_t pn_data_siblings(pn_data_t *data)
+{
+  pni_node_t *node = pn_data_node(data, data->parent);
+  if (node) {
+    return node->children;
+  } else {
+    return 0;
+  }
+}
+
+bool pn_data_enter(pn_data_t *data)
+{
+  if (data->current) {
+    data->parent = data->current;
+    data->current = 0;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool pn_data_exit(pn_data_t *data)
+{
+  if (data->parent) {
+    pni_node_t *parent = pn_data_node(data, data->parent);
+    data->current = data->parent;
+    data->parent = parent->parent;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool pn_data_lookup(pn_data_t *data, const char *name)
+{
+  while (pn_data_next(data)) {
+    pn_type_t type = pn_data_type(data);
+
+    switch (type) {
+    case PN_STRING:
+    case PN_SYMBOL:
+      {
+        pn_bytes_t bytes = pn_data_get_bytes(data);
+        if (strlen(name) == bytes.size && !strncmp(name, bytes.start, bytes.size)) {
+          return pn_data_next(data);
+        }
+      }
+      break;
+    default:
+      break;
+    }
+
+    // skip the value
+    pn_data_next(data);
+  }
+
+  return false;
+}
+
+void pn_data_dump(pn_data_t *data)
+{
+  printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", (size_t) data->current, (size_t) data->parent);
+  for (unsigned i = 0; i < data->size; i++)
+  {
+    pni_node_t *node = &data->nodes[i];
+    pn_string_set(data->str, "");
+    pni_inspect_atom((pn_atom_t *) &node->atom, data->str);
+    printf("Node %i: prev=%" PN_ZI ", next=%" PN_ZI ", parent=%" PN_ZI ", down=%" PN_ZI 
+           ", children=%" PN_ZI ", type=%s (%s)\n",
+           i + 1, (size_t) node->prev,
+           (size_t) node->next,
+           (size_t) node->parent,
+           (size_t) node->down,
+           (size_t) node->children,
+           pn_type_name(node->atom.type), pn_string_get(data->str));
+  }
+}
+
+static pni_node_t *pni_data_add(pn_data_t *data)
+{
+  pni_node_t *current = pni_data_current(data);
+  pni_node_t *parent = pn_data_node(data, data->parent);
+  pni_node_t *node;
+
+  if (current) {
+    if (current->next) {
+      node = pn_data_node(data, current->next);
+    } else {
+      node = pni_data_new(data);
+      if (!node) return NULL;
+
+      // refresh the pointers in case we grew
+      current = pni_data_current(data);
+      parent = pn_data_node(data, data->parent);
+      node->prev = data->current;
+      current->next = pni_data_id(data, node);
+      node->parent = data->parent;
+      if (parent) {
+        if (!parent->down) {
+          parent->down = pni_data_id(data, node);
+        }
+        parent->children++;
+      }
+    }
+  } else if (parent) {
+    if (parent->down) {
+      node = pn_data_node(data, parent->down);
+    } else {
+      node = pni_data_new(data);
+      if (!node) return NULL;
+
+      // refresh the pointers in case we grew
+      parent = pn_data_node(data, data->parent);
+      node->prev = 0;
+      node->parent = data->parent;
+      parent->down = pni_data_id(data, node);
+      parent->children++;
+    }
+  } else if (data->size) {
+    node = pn_data_node(data, 1);
+  } else {
+    node = pni_data_new(data);
+    if (!node) return NULL;
+
+    node->prev = 0;
+    node->parent = 0;
+  }
+
+  node->down = 0;
+  node->children = 0;
+  node->data = false;
+  node->data_offset = 0;
+  node->data_size = 0;
+  data->current = pni_data_id(data, node);
+  return node;
+}
+
+ssize_t pn_data_encode(pn_data_t *data, char *bytes, size_t size)
+{
+  return pn_encoder_encode(data->encoder, data, bytes, size);
+}
+
+ssize_t pn_data_encoded_size(pn_data_t *data)
+{
+  return pn_encoder_size(data->encoder, data);
+}
+
+ssize_t pn_data_decode(pn_data_t *data, const char *bytes, size_t size)
+{
+  return pn_decoder_decode(data->decoder, bytes, size, data);
+}
+
+int pn_data_put_list(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_LIST;
+  return 0;
+}
+
+int pn_data_put_map(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_MAP;
+  return 0;
+}
+
+int pn_data_put_array(pn_data_t *data, bool described, pn_type_t type)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_ARRAY;
+  node->described = described;
+  node->type = type;
+  return 0;
+}
+
+void pni_data_set_array_type(pn_data_t *data, pn_type_t type)
+{
+  pni_node_t *array = pni_data_current(data);
+  if (array) array->type = type;
+}
+
+int pn_data_put_described(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_DESCRIBED;
+  return 0;
+}
+
+int pn_data_put_null(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  pni_atom_init(&node->atom, PN_NULL);
+  return 0;
+}
+
+int pn_data_put_bool(pn_data_t *data, bool b)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_BOOL;
+  node->atom.u.as_bool = b;
+  return 0;
+}
+
+int pn_data_put_ubyte(pn_data_t *data, uint8_t ub)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_UBYTE;
+  node->atom.u.as_ubyte = ub;
+  return 0;
+}
+
+int pn_data_put_byte(pn_data_t *data, int8_t b)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_BYTE;
+  node->atom.u.as_byte = b;
+  return 0;
+}
+
+int pn_data_put_ushort(pn_data_t *data, uint16_t us)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_USHORT;
+  node->atom.u.as_ushort = us;
+  return 0;
+}
+
+int pn_data_put_short(pn_data_t *data, int16_t s)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_SHORT;
+  node->atom.u.as_short = s;
+  return 0;
+}
+
+int pn_data_put_uint(pn_data_t *data, uint32_t ui)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_UINT;
+  node->atom.u.as_uint = ui;
+  return 0;
+}
+
+int pn_data_put_int(pn_data_t *data, int32_t i)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_INT;
+  node->atom.u.as_int = i;
+  return 0;
+}
+
+int pn_data_put_char(pn_data_t *data, pn_char_t c)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_CHAR;
+  node->atom.u.as_char = c;
+  return 0;
+}
+
+int pn_data_put_ulong(pn_data_t *data, uint64_t ul)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_ULONG;
+  node->atom.u.as_ulong = ul;
+  return 0;
+}
+
+int pn_data_put_long(pn_data_t *data, int64_t l)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_LONG;
+  node->atom.u.as_long = l;
+  return 0;
+}
+
+int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t t)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_TIMESTAMP;
+  node->atom.u.as_timestamp = t;
+  return 0;
+}
+
+int pn_data_put_float(pn_data_t *data, float f)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_FLOAT;
+  node->atom.u.as_float = f;
+  return 0;
+}
+
+int pn_data_put_double(pn_data_t *data, double d)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_DOUBLE;
+  node->atom.u.as_double = d;
+  return 0;
+}
+
+int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t d)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_DECIMAL32;
+  node->atom.u.as_decimal32 = d;
+  return 0;
+}
+
+int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t d)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_DECIMAL64;
+  node->atom.u.as_decimal64 = d;
+  return 0;
+}
+
+int pn_data_put_decimal128(pn_data_t *data, pn_decimal128_t d)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_DECIMAL128;
+  memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16);
+  return 0;
+}
+
+int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_UUID;
+  memmove(node->atom.u.as_uuid.bytes, u.bytes, 16);
+  return 0;
+}
+
+int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_BINARY;
+  node->atom.u.as_bytes = bytes;
+  return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_string(pn_data_t *data, pn_bytes_t string)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_STRING;
+  node->atom.u.as_bytes = string;
+  return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom.type = PN_SYMBOL;
+  node->atom.u.as_bytes = symbol;
+  return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_atom(pn_data_t *data, pn_atom_t atom)
+{
+  pni_node_t *node = pni_data_add(data);
+  if (node == NULL) return PN_OUT_OF_MEMORY;
+  node->atom = atom;
+  return pni_data_intern_node(data, node);
+}
+
+size_t pn_data_get_list(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_LIST) {
+    return node->children;
+  } else {
+    return 0;
+  }
+}
+
+size_t pn_data_get_map(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_MAP) {
+    return node->children;
+  } else {
+    return 0;
+  }
+}
+
+size_t pn_data_get_array(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_ARRAY) {
+    if (node->described) {
+      return node->children - 1;
+    } else {
+      return node->children;
+    }
+  } else {
+    return 0;
+  }
+}
+
+bool pn_data_is_array_described(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_ARRAY) {
+    return node->described;
+  } else {
+    return false;
+  }
+}
+
+pn_type_t pn_data_get_array_type(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_ARRAY) {
+    return node->type;
+  } else {
+    return PN_INVALID;
+  }
+}
+
+bool pn_data_is_described(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  return node && node->atom.type == PN_DESCRIBED;
+}
+
+bool pn_data_is_null(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  return node && node->atom.type == PN_NULL;
+}
+
+bool pn_data_get_bool(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_BOOL) {
+    return node->atom.u.as_bool;
+  } else {
+    return false;
+  }
+}
+
+uint8_t pn_data_get_ubyte(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_UBYTE) {
+    return node->atom.u.as_ubyte;
+  } else {
+    return 0;
+  }
+}
+
+int8_t pn_data_get_byte(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_BYTE) {
+    return node->atom.u.as_byte;
+  } else {
+    return 0;
+  }
+}
+
+uint16_t pn_data_get_ushort(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_USHORT) {
+    return node->atom.u.as_ushort;
+  } else {
+    return 0;
+  }
+}
+
+int16_t pn_data_get_short(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_SHORT) {
+    return node->atom.u.as_short;
+  } else {
+    return 0;
+  }
+}
+
+uint32_t pn_data_get_uint(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_UINT) {
+    return node->atom.u.as_uint;
+  } else {
+    return 0;
+  }
+}
+
+int32_t pn_data_get_int(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_INT) {
+    return node->atom.u.as_int;
+  } else {
+    return 0;
+  }
+}
+
+pn_char_t pn_data_get_char(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_CHAR) {
+    return node->atom.u.as_char;
+  } else {
+    return 0;
+  }
+}
+
+uint64_t pn_data_get_ulong(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_ULONG) {
+    return node->atom.u.as_ulong;
+  } else {
+    return 0;
+  }
+}
+
+int64_t pn_data_get_long(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_LONG) {
+    return node->atom.u.as_long;
+  } else {
+    return 0;
+  }
+}
+
+pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_TIMESTAMP) {
+    return node->atom.u.as_timestamp;
+  } else {
+    return 0;
+  }
+}
+
+float pn_data_get_float(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_FLOAT) {
+    return node->atom.u.as_float;
+  } else {
+    return 0;
+  }
+}
+
+double pn_data_get_double(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_DOUBLE) {
+    return node->atom.u.as_double;
+  } else {
+    return 0;
+  }
+}
+
+pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_DECIMAL32) {
+    return node->atom.u.as_decimal32;
+  } else {
+    return 0;
+  }
+}
+
+pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_DECIMAL64) {
+    return node->atom.u.as_decimal64;
+  } else {
+    return 0;
+  }
+}
+
+pn_decimal128_t pn_data_get_decimal128(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_DECIMAL128) {
+    return node->atom.u.as_decimal128;
+  } else {
+    pn_decimal128_t t = {{0}};
+    return t;
+  }
+}
+
+pn_uuid_t pn_data_get_uuid(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_UUID) {
+    return node->atom.u.as_uuid;
+  } else {
+    pn_uuid_t t = {{0}};
+    return t;
+  }
+}
+
+pn_bytes_t pn_data_get_binary(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_BINARY) {
+    return node->atom.u.as_bytes;
+  } else {
+    pn_bytes_t t = {0};
+    return t;
+  }
+}
+
+pn_bytes_t pn_data_get_string(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_STRING) {
+    return node->atom.u.as_bytes;
+  } else {
+    pn_bytes_t t = {0};
+    return t;
+  }
+}
+
+pn_bytes_t pn_data_get_symbol(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && node->atom.type == PN_SYMBOL) {
+    return node->atom.u.as_bytes;
+  } else {
+    pn_bytes_t t = {0};
+    return t;
+  }
+}
+
+pn_bytes_t pn_data_get_bytes(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node && (node->atom.type == PN_BINARY ||
+               node->atom.type == PN_STRING ||
+               node->atom.type == PN_SYMBOL)) {
+    return node->atom.u.as_bytes;
+  } else {
+    pn_bytes_t t = {0};
+    return t;
+  }
+}
+
+pn_atom_t pn_data_get_atom(pn_data_t *data)
+{
+  pni_node_t *node = pni_data_current(data);
+  if (node) {
+    return *((pn_atom_t *) &node->atom);
+  } else {
+    pn_atom_t t = {PN_NULL, {0,}};
+    return t;
+  }
+}
+
+int pn_data_copy(pn_data_t *data, pn_data_t *src)
+{
+  pn_data_clear(data);
+  int err = pn_data_append(data, src);
+  pn_data_rewind(data);
+  return err;
+}
+
+int pn_data_append(pn_data_t *data, pn_data_t *src)
+{
+  return pn_data_appendn(data, src, -1);
+}
+
+int pn_data_appendn(pn_data_t *data, pn_data_t *src, int limit)
+{
+  int err = 0;
+  int level = 0, count = 0;
+  bool stop = false;
+  pn_handle_t point = pn_data_point(src);
+  pn_data_rewind(src);
+
+  while (true) {
+    while (!pn_data_next(src)) {
+      if (level > 0) {
+        pn_data_exit(data);
+        pn_data_exit(src);
+        level--;
+        continue;
+      }
+
+      if (!pn_data_next(src)) {
+        stop = true;
+      }
+      break;
+    }
+
+    if (stop) break;
+
+    if (level == 0 && count == limit)
+      break;
+
+    pn_type_t type = pn_data_type(src);
+    switch (type) {
+    case PN_NULL:
+      err = pn_data_put_null(data);
+      if (level == 0) count++;
+      break;
+    case PN_BOOL:
+      err = pn_data_put_bool(data, pn_data_get_bool(src));
+      if (level == 0) count++;
+      break;
+    case PN_UBYTE:
+      err = pn_data_put_ubyte(data, pn_data_get_ubyte(src));
+      if (level == 0) count++;
+      break;
+    case PN_BYTE:
+      err = pn_data_put_byte(data, pn_data_get_byte(src));
+      if (level == 0) count++;
+      break;
+    case PN_USHORT:
+      err = pn_data_put_ushort(data, pn_data_get_ushort(src));
+      if (level == 0) count++;
+      break;
+    case PN_SHORT:
+      err = pn_data_put_short(data, pn_data_get_short(src));
+      if (level == 0) count++;
+      break;
+    case PN_UINT:
+      err = pn_data_put_uint(data, pn_data_get_uint(src));
+      if (level == 0) count++;
+      break;
+    case PN_INT:
+      err = pn_data_put_int(data, pn_data_get_int(src));
+      if (level == 0) count++;
+      break;
+    case PN_CHAR:
+      err = pn_data_put_char(data, pn_data_get_char(src));
+      if (level == 0) count++;
+      break;
+    case PN_ULONG:
+      err = pn_data_put_ulong(data, pn_data_get_ulong(src));
+      if (level == 0) count++;
+      break;
+    case PN_LONG:
+      err = pn_data_put_long(data, pn_data_get_long(src));
+      if (level == 0) count++;
+      break;
+    case PN_TIMESTAMP:
+      err = pn_data_put_timestamp(data, pn_data_get_timestamp(src));
+      if (level == 0) count++;
+      break;
+    case PN_FLOAT:
+      err = pn_data_put_float(data, pn_data_get_float(src));
+      if (level == 0) count++;
+      break;
+    case PN_DOUBLE:
+      err = pn_data_put_double(data, pn_data_get_double(src));
+      if (level == 0) count++;
+      break;
+    case PN_DECIMAL32:
+      err = pn_data_put_decimal32(data, pn_data_get_decimal32(src));
+      if (level == 0) count++;
+      break;
+    case PN_DECIMAL64:
+      err = pn_data_put_decimal64(data, pn_data_get_decimal64(src));
+      if (level == 0) count++;
+      break;
+    case PN_DECIMAL128:
+      err = pn_data_put_decimal128(data, pn_data_get_decimal128(src));
+      if (level == 0) count++;
+      break;
+    case PN_UUID:
+      err = pn_data_put_uuid(data, pn_data_get_uuid(src));
+      if (level == 0) count++;
+      break;
+    case PN_BINARY:
+      err = pn_data_put_binary(data, pn_data_get_binary(src));
+      if (level == 0) count++;
+      break;
+    case PN_STRING:
+      err = pn_data_put_string(data, pn_data_get_string(src));
+      if (level == 0) count++;
+      break;
+    case PN_SYMBOL:
+      err = pn_data_put_symbol(data, pn_data_get_symbol(src));
+      if (level == 0) count++;
+      break;
+    case PN_DESCRIBED:
+      err = pn_data_put_described(data);
+      if (level == 0) count++;
+      if (err) { pn_data_restore(src, point); return err; }
+      pn_data_enter(data);
+      pn_data_enter(src);
+      level++;
+      break;
+    case PN_ARRAY:
+      err = pn_data_put_array(data, pn_data_is_array_described(src),
+                              pn_data_get_array_type(src));
+      if (level == 0) count++;
+      if (err) { pn_data_restore(src, point); return err; }
+      pn_data_enter(data);
+      pn_data_enter(src);
+      level++;
+      break;
+    case PN_LIST:
+      err = pn_data_put_list(data);
+      if (level == 0) count++;
+      if (err) { pn_data_restore(src, point); return err; }
+      pn_data_enter(data);
+      pn_data_enter(src);
+      level++;
+      break;
+    case PN_MAP:
+      err = pn_data_put_map(data);
+      if (level == 0) count++;
+      if (err) { pn_data_restore(src, point); return err; }
+      pn_data_enter(data);
+      pn_data_enter(src);
+      level++;
+      break;
+    default:
+      break;
+    }
+
+    if (err) { pn_data_restore(src, point); return err; }
+  }
+
+  pn_data_restore(src, point);
+
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/config.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/config.h b/proton-c/src/core/config.h
new file mode 100644
index 0000000..5a2e7bc
--- /dev/null
+++ b/proton-c/src/core/config.h
@@ -0,0 +1,32 @@
+/*
+* 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.
+*
+*/
+
+#ifndef  _PROTON_SRC_CONFIG_H 
+#define  _PROTON_SRC_CONFIG_H 
+
+#ifndef PN_TRANSPORT_INITIAL_FRAME_SIZE
+# define PN_TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */
+#endif
+
+#ifndef PN_SASL_MAX_BUFFSIZE
+# define PN_SASL_MAX_BUFFSIZE (32768) /* bytes */
+#endif
+
+#endif /*  _PROTON_SRC_CONFIG_H */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/connection_engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_engine.c b/proton-c/src/core/connection_engine.c
new file mode 100644
index 0000000..5d184a1
--- /dev/null
+++ b/proton-c/src/core/connection_engine.c
@@ -0,0 +1,124 @@
+/*
+ * 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 "engine-internal.h"
+
+#include <proton/connection.h>
+#include <proton/connection_engine.h>
+#include <proton/transport.h>
+#include <string.h>
+
+int pn_connection_engine_init(pn_connection_engine_t* e) {
+    memset(e, 0, sizeof(*e));
+    e->connection = pn_connection();
+    e->transport = pn_transport();
+    e->collector = pn_collector();
+    if (!e->connection || !e->transport || !e->collector) {
+        pn_connection_engine_final(e);
+        return PN_OUT_OF_MEMORY;
+    }
+    pn_connection_collect(e->connection, e->collector);
+    return PN_OK;
+}
+
+void pn_connection_engine_final(pn_connection_engine_t* e) {
+    if (e->transport && e->connection) {
+        pn_transport_unbind(e->transport);
+        pn_decref(e->transport);
+    }
+    if (e->collector)
+        pn_collector_free(e->collector); /* Break cycle with connection */
+    if (e->connection)
+        pn_decref(e->connection);
+    memset(e, 0, sizeof(*e));
+}
+
+pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t* e) {
+    ssize_t cap = pn_transport_capacity(e->transport);
+    if (cap > 0)
+        return pn_rwbytes(cap, pn_transport_tail(e->transport));
+    else
+        return pn_rwbytes(0, 0);
+}
+
+void pn_connection_engine_read_done(pn_connection_engine_t* e, size_t n) {
+    if (n > 0)
+        pn_transport_process(e->transport, n);
+}
+
+void pn_connection_engine_read_close(pn_connection_engine_t* e) {
+    pn_transport_close_tail(e->transport);
+}
+
+pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t* e) {
+    ssize_t pending = pn_transport_pending(e->transport);
+    if (pending > 0)
+        return pn_bytes(pending, pn_transport_head(e->transport));
+    else
+        return pn_bytes(0, 0);
+}
+
+void pn_connection_engine_write_done(pn_connection_engine_t* e, size_t n) {
+    if (n > 0)
+        pn_transport_pop(e->transport, n);
+}
+
+void pn_connection_engine_write_close(pn_connection_engine_t* e){
+    pn_transport_close_head(e->transport);
+}
+
+void pn_connection_engine_disconnected(pn_connection_engine_t* e) {
+    pn_connection_engine_read_close(e);
+    pn_connection_engine_write_close(e);
+}
+
+static void log_event(pn_connection_engine_t *engine, pn_event_t* event) {
+    if (event && engine->transport->trace & PN_TRACE_EVT) {
+        pn_string_t *str = pn_string(NULL);
+        pn_inspect(event, str);
+        pn_transport_log(engine->transport, pn_string_get(str));
+        pn_free(str);
+    }
+}
+
+pn_event_t* pn_connection_engine_dispatch(pn_connection_engine_t* e) {
+    if (e->event) {             /* Already returned */
+        if (pn_event_type(e->event) == PN_CONNECTION_INIT)
+            pn_transport_bind(e->transport, e->connection);
+        pn_collector_pop(e->collector);
+    }
+    e->event = pn_collector_peek(e->collector);
+    log_event(e, e->event);
+    return e->event;
+}
+
+bool pn_connection_engine_finished(pn_connection_engine_t* e) {
+    return pn_transport_closed(e->transport) && (pn_collector_peek(e->collector) == NULL);
+}
+
+pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t* e) {
+    return e->connection;
+}
+
+pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t* e) {
+    return e->transport;
+}
+
+pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t* e) {
+    return pn_transport_condition(e->transport);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/data.h b/proton-c/src/core/data.h
new file mode 100644
index 0000000..94dc7d6
--- /dev/null
+++ b/proton-c/src/core/data.h
@@ -0,0 +1,75 @@
+#ifndef _PROTON_DATA_H
+#define _PROTON_DATA_H 1
+
+/*
+ *
+ * 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/codec.h>
+#include "buffer.h"
+#include "decoder.h"
+#include "encoder.h"
+
+typedef uint16_t pni_nid_t;
+#define PNI_NID_MAX ((pni_nid_t)-1)
+
+typedef struct {
+  char *start;
+  size_t data_offset;
+  size_t data_size;
+  pn_atom_t atom;
+  pn_type_t type;
+  pni_nid_t next;
+  pni_nid_t prev;
+  pni_nid_t down;
+  pni_nid_t parent;
+  pni_nid_t children;
+  // for arrays
+  bool described;
+  bool data;
+  bool small;
+} pni_node_t;
+
+struct pn_data_t {
+  pni_node_t *nodes;
+  pn_buffer_t *buf;
+  pn_decoder_t *decoder;
+  pn_encoder_t *encoder;
+  pn_error_t *error;
+  pn_string_t *str;
+  pni_nid_t capacity;
+  pni_nid_t size;
+  pni_nid_t parent;
+  pni_nid_t current;
+  pni_nid_t base_parent;
+  pni_nid_t base_current;
+};
+
+static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd) 
+{
+  return nd ? (data->nodes + nd - 1) : NULL;
+}
+
+int pni_data_traverse(pn_data_t *data,
+                      int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
+                      int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
+                      void *ctx);
+
+#endif /* data.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.c b/proton-c/src/core/decoder.c
new file mode 100644
index 0000000..b0c8d79
--- /dev/null
+++ b/proton-c/src/core/decoder.c
@@ -0,0 +1,497 @@
+/*
+ *
+ * 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/error.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include "encodings.h"
+#include "decoder.h"
+
+#include <string.h>
+
+struct pn_decoder_t {
+  const char *input;
+  size_t size;
+  const char *position;
+  pn_error_t *error;
+};
+
+static void pn_decoder_initialize(void *obj)
+{
+  pn_decoder_t *decoder = (pn_decoder_t *) obj;
+  decoder->input = NULL;
+  decoder->size = 0;
+  decoder->position = NULL;
+  decoder->error = pn_error();
+}
+
+static void pn_decoder_finalize(void *obj) {
+  pn_decoder_t *decoder = (pn_decoder_t *) obj;
+  pn_error_free(decoder->error);
+}
+
+#define pn_decoder_hashcode NULL
+#define pn_decoder_compare NULL
+#define pn_decoder_inspect NULL
+
+pn_decoder_t *pn_decoder()
+{
+  static const pn_class_t clazz = PN_CLASS(pn_decoder);
+  return (pn_decoder_t *) pn_class_new(&clazz, sizeof(pn_decoder_t));
+}
+
+static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)
+{
+  uint8_t r = decoder->position[0];
+  decoder->position++;
+  return r;
+}
+
+static inline uint16_t pn_decoder_readf16(pn_decoder_t *decoder)
+{
+  uint16_t a = (uint8_t) decoder->position[0];
+  uint16_t b = (uint8_t) decoder->position[1];
+  uint16_t r = a << 8
+    | b;
+  decoder->position += 2;
+  return r;
+}
+
+static inline uint32_t pn_decoder_readf32(pn_decoder_t *decoder)
+{
+  uint32_t a = (uint8_t) decoder->position[0];
+  uint32_t b = (uint8_t) decoder->position[1];
+  uint32_t c = (uint8_t) decoder->position[2];
+  uint32_t d = (uint8_t) decoder->position[3];
+  uint32_t r = a << 24
+    | b << 16
+    | c <<  8
+    | d;
+  decoder->position += 4;
+  return r;
+}
+
+static inline uint64_t pn_decoder_readf64(pn_decoder_t *decoder)
+{
+  uint64_t a = pn_decoder_readf32(decoder);
+  uint64_t b = pn_decoder_readf32(decoder);
+  return a << 32 | b;
+}
+
+static inline void pn_decoder_readf128(pn_decoder_t *decoder, void *dst)
+{
+  memmove(dst, decoder->position, 16);
+  decoder->position += 16;
+}
+
+static inline size_t pn_decoder_remaining(pn_decoder_t *decoder)
+{
+  return decoder->input + decoder->size - decoder->position;
+}
+
+typedef union {
+  uint32_t i;
+  uint32_t a[2];
+  uint64_t l;
+  float f;
+  double d;
+} conv_t;
+
+static inline pn_type_t pn_code2type(uint8_t code)
+{
+  switch (code)
+  {
+  case PNE_DESCRIPTOR:
+    return (pn_type_t) PN_ARG_ERR;
+  case PNE_NULL:
+    return PN_NULL;
+  case PNE_TRUE:
+  case PNE_FALSE:
+  case PNE_BOOLEAN:
+    return PN_BOOL;
+  case PNE_UBYTE:
+    return PN_UBYTE;
+  case PNE_BYTE:
+    return PN_BYTE;
+  case PNE_USHORT:
+    return PN_USHORT;
+  case PNE_SHORT:
+    return PN_SHORT;
+  case PNE_UINT0:
+  case PNE_SMALLUINT:
+  case PNE_UINT:
+    return PN_UINT;
+  case PNE_SMALLINT:
+  case PNE_INT:
+    return PN_INT;
+  case PNE_UTF32:
+    return PN_CHAR;
+  case PNE_FLOAT:
+    return PN_FLOAT;
+  case PNE_LONG:
+  case PNE_SMALLLONG:
+    return PN_LONG;
+  case PNE_MS64:
+    return PN_TIMESTAMP;
+  case PNE_DOUBLE:
+    return PN_DOUBLE;
+  case PNE_DECIMAL32:
+    return PN_DECIMAL32;
+  case PNE_DECIMAL64:
+    return PN_DECIMAL64;
+  case PNE_DECIMAL128:
+    return PN_DECIMAL128;
+  case PNE_UUID:
+    return PN_UUID;
+  case PNE_ULONG0:
+  case PNE_SMALLULONG:
+  case PNE_ULONG:
+    return PN_ULONG;
+  case PNE_VBIN8:
+  case PNE_VBIN32:
+    return PN_BINARY;
+  case PNE_STR8_UTF8:
+  case PNE_STR32_UTF8:
+    return PN_STRING;
+  case PNE_SYM8:
+  case PNE_SYM32:
+    return PN_SYMBOL;
+  case PNE_LIST0:
+  case PNE_LIST8:
+  case PNE_LIST32:
+    return PN_LIST;
+  case PNE_ARRAY8:
+  case PNE_ARRAY32:
+    return PN_ARRAY;
+  case PNE_MAP8:
+  case PNE_MAP32:
+    return PN_MAP;
+  default:
+    return (pn_type_t) PN_ARG_ERR;
+  }
+}
+
+static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code);
+static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data);
+void pni_data_set_array_type(pn_data_t *data, pn_type_t type);
+
+static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
+{
+  int err;
+  conv_t conv;
+  pn_decimal128_t dec128;
+  pn_uuid_t uuid;
+  size_t size;
+  size_t count;
+
+  switch (code)
+  {
+  case PNE_NULL:
+    err = pn_data_put_null(data);
+    break;
+  case PNE_TRUE:
+    err = pn_data_put_bool(data, true);
+    break;
+  case PNE_FALSE:
+    err = pn_data_put_bool(data, false);
+    break;
+  case PNE_BOOLEAN:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
+    break;
+  case PNE_UBYTE:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
+    break;
+  case PNE_BYTE:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
+    break;
+  case PNE_USHORT:
+    if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+    err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
+    break;
+  case PNE_SHORT:
+    if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+    err = pn_data_put_short(data, pn_decoder_readf16(decoder));
+    break;
+  case PNE_UINT:
+    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+    err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
+    break;
+  case PNE_UINT0:
+    err = pn_data_put_uint(data, 0);
+    break;
+  case PNE_SMALLUINT:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
+    break;
+  case PNE_SMALLINT:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
+    break;
+  case PNE_INT:
+    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+    err = pn_data_put_int(data, pn_decoder_readf32(decoder));
+    break;
+  case PNE_UTF32:
+    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+    err = pn_data_put_char(data, pn_decoder_readf32(decoder));
+    break;
+  case PNE_FLOAT:
+    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+    // XXX: this assumes the platform uses IEEE floats
+    conv.i = pn_decoder_readf32(decoder);
+    err = pn_data_put_float(data, conv.f);
+    break;
+  case PNE_DECIMAL32:
+    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+    err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
+    break;
+  case PNE_ULONG:
+    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+    err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
+    break;
+  case PNE_LONG:
+    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+    err = pn_data_put_long(data, pn_decoder_readf64(decoder));
+    break;
+  case PNE_MS64:
+    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+    err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
+    break;
+  case PNE_DOUBLE:
+    // XXX: this assumes the platform uses IEEE floats
+    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+    conv.l = pn_decoder_readf64(decoder);
+    err = pn_data_put_double(data, conv.d);
+    break;
+  case PNE_DECIMAL64:
+    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+    err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
+    break;
+  case PNE_ULONG0:
+    err = pn_data_put_ulong(data, 0);
+    break;
+  case PNE_SMALLULONG:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
+    break;
+  case PNE_SMALLLONG:
+    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+    err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
+    break;
+  case PNE_DECIMAL128:
+    if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
+    pn_decoder_readf128(decoder, &dec128);
+    err = pn_data_put_decimal128(data, dec128);
+    break;
+  case PNE_UUID:
+    if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
+    pn_decoder_readf128(decoder, &uuid);
+    err = pn_data_put_uuid(data, uuid);
+    break;
+  case PNE_VBIN8:
+  case PNE_STR8_UTF8:
+  case PNE_SYM8:
+  case PNE_VBIN32:
+  case PNE_STR32_UTF8:
+  case PNE_SYM32:
+    switch (code & 0xF0)
+    {
+    case 0xA0:
+      if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+      size = pn_decoder_readf8(decoder);
+      break;
+    case 0xB0:
+      if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+      size = pn_decoder_readf32(decoder);
+      break;
+    default:
+      return PN_ARG_ERR;
+    }
+
+    if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
+
+    {
+      char *start = (char *) decoder->position;
+      pn_bytes_t bytes = {size, start};
+      switch (code & 0x0F)
+      {
+      case 0x0:
+        err = pn_data_put_binary(data, bytes);
+        break;
+      case 0x1:
+        err = pn_data_put_string(data, bytes);
+        break;
+      case 0x3:
+        err = pn_data_put_symbol(data, bytes);
+        break;
+      default:
+        return PN_ARG_ERR;
+      }
+    }
+
+    decoder->position += size;
+    break;
+  case PNE_LIST0:
+    err = pn_data_put_list(data);
+    break;
+  case PNE_ARRAY8:
+  case PNE_ARRAY32:
+  case PNE_LIST8:
+  case PNE_LIST32:
+  case PNE_MAP8:
+  case PNE_MAP32:
+    switch (code)
+    {
+    case PNE_ARRAY8:
+    case PNE_LIST8:
+    case PNE_MAP8:
+      if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+      size = pn_decoder_readf8(decoder);
+      count = pn_decoder_readf8(decoder);
+      break;
+    case PNE_ARRAY32:
+    case PNE_LIST32:
+    case PNE_MAP32:
+      size = pn_decoder_readf32(decoder);
+      count = pn_decoder_readf32(decoder);
+      break;
+    default:
+      return PN_ARG_ERR;
+    }
+
+    switch (code)
+    {
+    case PNE_ARRAY8:
+    case PNE_ARRAY32:
+      {
+        uint8_t next = *decoder->position;
+        bool described = (next == PNE_DESCRIPTOR);
+        err = pn_data_put_array(data, described, (pn_type_t) 0);
+        if (err) return err;
+
+        pn_data_enter(data);
+        uint8_t acode;
+        int e = pni_decoder_decode_type(decoder, data, &acode);
+        if (e) return e;
+        pn_type_t type = pn_code2type(acode);
+        if ((int)type < 0) return (int)type;
+        for (size_t i = 0; i < count; i++)
+        {
+          e = pni_decoder_decode_value(decoder, data, acode);
+          if (e) return e;
+        }
+        pn_data_exit(data);
+
+        pni_data_set_array_type(data, type);
+      }
+      return 0;
+    case PNE_LIST8:
+    case PNE_LIST32:
+      err = pn_data_put_list(data);
+      if (err) return err;
+      break;
+    case PNE_MAP8:
+    case PNE_MAP32:
+      err = pn_data_put_map(data);
+      if (err) return err;
+      break;
+    default:
+      return PN_ARG_ERR;
+    }
+
+    pn_data_enter(data);
+    for (size_t i = 0; i < count; i++)
+    {
+      int e = pni_decoder_single(decoder, data);
+      if (e) return e;
+    }
+    pn_data_exit(data);
+
+    return 0;
+  default:
+    return pn_error_format(decoder->error, PN_ARG_ERR, "unrecognized typecode: %u", code);
+  }
+
+  return err;
+}
+
+pn_type_t pni_data_parent_type(pn_data_t *data);
+
+static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code)
+{
+  int err;
+
+  if (!pn_decoder_remaining(decoder)) {
+    return PN_UNDERFLOW;
+  }
+
+  uint8_t next = *decoder->position++;
+
+  if (next == PNE_DESCRIPTOR) {
+    if (pni_data_parent_type(data) != PN_ARRAY) {
+      err = pn_data_put_described(data);
+      if (err) return err;
+      // pni_decoder_single has the corresponding exit
+      pn_data_enter(data);
+    }
+    err = pni_decoder_single(decoder, data);
+    if (err) return err;
+    err = pni_decoder_decode_type(decoder, data, code);
+    if (err) return err;
+  } else {
+    *code = next;
+  }
+
+  return 0;
+}
+
+size_t pn_data_siblings(pn_data_t *data);
+
+int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data)
+{
+  uint8_t code;
+  int err = pni_decoder_decode_type(decoder, data, &code);
+  if (err) return err;
+  err = pni_decoder_decode_value(decoder, data, code);
+  if (err) return err;
+  if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
+    pn_data_exit(data);
+  }
+  return 0;
+}
+
+ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst)
+{
+  decoder->input = src;
+  decoder->size = size;
+  decoder->position = src;
+
+  int err = pni_decoder_single(decoder, dst);
+
+  if (err == PN_UNDERFLOW) 
+      return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode");
+  if (err) return err;
+
+  return decoder->position - decoder->input;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.h b/proton-c/src/core/decoder.h
new file mode 100644
index 0000000..b7de898
--- /dev/null
+++ b/proton-c/src/core/decoder.h
@@ -0,0 +1,30 @@
+#ifndef _PROTON_DECODER_H
+#define _PROTON_DECODER_H 1
+
+/*
+ *
+ * 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.
+ *
+ */
+
+typedef struct pn_decoder_t pn_decoder_t;
+
+pn_decoder_t *pn_decoder(void);
+ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst);
+
+#endif /* decoder.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatch_actions.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatch_actions.h b/proton-c/src/core/dispatch_actions.h
new file mode 100644
index 0000000..ea2d8b2
--- /dev/null
+++ b/proton-c/src/core/dispatch_actions.h
@@ -0,0 +1,49 @@
+#ifndef _PROTON_DISPATCH_ACTIONS_H
+#define _PROTON_DISPATCH_ACTIONS_H 1
+
+/*
+ *
+ * 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 "dispatcher.h"
+
+#define AMQP_FRAME_TYPE (0)
+#define SASL_FRAME_TYPE (1)
+
+
+/* AMQP actions */
+int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+/* SASL actions */
+int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+#endif // _PROTON_DISPATCH_ACTIONS_H


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


[15/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatcher.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatcher.c b/proton-c/src/core/dispatcher.c
new file mode 100644
index 0000000..36f8cc9
--- /dev/null
+++ b/proton-c/src/core/dispatcher.c
@@ -0,0 +1,158 @@
+/*
+ *
+ * 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 "dispatcher.h"
+
+#include "framing.h"
+#include "protocol.h"
+#include "engine-internal.h"
+
+#include "dispatch_actions.h"
+
+int pni_bad_frame(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
+  pn_transport_logf(transport, "Error dispatching frame: type: %d: Unknown performative", frame_type);
+  return PN_ERR;
+}
+
+int pni_bad_frame_type(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
+    pn_transport_logf(transport, "Error dispatching frame: Unknown frame type: %d", frame_type);
+    return PN_ERR;
+}
+
+// We could use a table based approach here if we needed to dynamically
+// add new performatives
+static inline int pni_dispatch_action(pn_transport_t* transport, uint64_t lcode, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_action_t *action;
+  switch (frame_type) {
+  case AMQP_FRAME_TYPE:
+    /* Regular AMQP fames */
+    switch (lcode) {
+    case OPEN:            action = pn_do_open; break;
+    case BEGIN:           action = pn_do_begin; break;
+    case ATTACH:          action = pn_do_attach; break;
+    case FLOW:            action = pn_do_flow; break;
+    case TRANSFER:        action = pn_do_transfer; break;
+    case DISPOSITION:     action = pn_do_disposition; break;
+    case DETACH:          action = pn_do_detach; break;
+    case END:             action = pn_do_end; break;
+    case CLOSE:           action = pn_do_close; break;
+    default:              action = pni_bad_frame; break;
+    };
+    break;
+  case SASL_FRAME_TYPE:
+    /* SASL frames */
+    switch (lcode) {
+    case SASL_MECHANISMS: action = pn_do_mechanisms; break;
+    case SASL_INIT:       action = pn_do_init; break;
+    case SASL_CHALLENGE:  action = pn_do_challenge; break;
+    case SASL_RESPONSE:   action = pn_do_response; break;
+    case SASL_OUTCOME:    action = pn_do_outcome; break;
+    default:              action = pni_bad_frame; break;
+    };
+    break;
+  default:              action = pni_bad_frame_type; break;
+  };
+  return action(transport, frame_type, channel, args, payload);
+}
+
+static int pni_dispatch_frame(pn_transport_t * transport, pn_data_t *args, pn_frame_t frame)
+{
+  if (frame.size == 0) { // ignore null frames
+    if (transport->trace & PN_TRACE_FRM)
+      pn_transport_logf(transport, "%u <- (EMPTY FRAME)", frame.channel);
+    return 0;
+  }
+
+  ssize_t dsize = pn_data_decode(args, frame.payload, frame.size);
+  if (dsize < 0) {
+    pn_string_format(transport->scratch,
+                     "Error decoding frame: %s %s\n", pn_code(dsize),
+                     pn_error_text(pn_data_error(args)));
+    pn_quote(transport->scratch, frame.payload, frame.size);
+    pn_transport_log(transport, pn_string_get(transport->scratch));
+    return dsize;
+  }
+
+  uint8_t frame_type = frame.type;
+  uint16_t channel = frame.channel;
+  // XXX: assuming numeric -
+  // if we get a symbol we should map it to the numeric value and dispatch on that
+  uint64_t lcode;
+  bool scanned;
+  int e = pn_data_scan(args, "D?L.", &scanned, &lcode);
+  if (e) {
+    pn_transport_log(transport, "Scan error");
+    return e;
+  }
+  if (!scanned) {
+    pn_transport_log(transport, "Error dispatching frame");
+    return PN_ERR;
+  }
+  size_t payload_size = frame.size - dsize;
+  const char *payload_mem = payload_size ? frame.payload + dsize : NULL;
+  pn_bytes_t payload = {payload_size, payload_mem};
+
+  pn_do_trace(transport, channel, IN, args, payload_mem, payload_size);
+
+  int err = pni_dispatch_action(transport, lcode, frame_type, channel, args, &payload);
+
+  pn_data_clear(args);
+
+  return err;
+}
+
+ssize_t pn_dispatcher_input(pn_transport_t *transport, const char *bytes, size_t available, bool batch, bool *halt)
+{
+  size_t read = 0;
+
+  while (available && !*halt) {
+    pn_frame_t frame;
+
+    ssize_t n = pn_read_frame(&frame, bytes + read, available, transport->local_max_frame);
+    if (n > 0) {
+      read += n;
+      available -= n;
+      transport->input_frames_ct += 1;
+      int e = pni_dispatch_frame(transport, transport->args, frame);
+      if (e) return e;
+    } else if (n < 0) {
+      pn_do_error(transport, "amqp:connection:framing-error", "malformed frame");
+      return n;
+    } else {
+      break;
+    }
+
+    if (!batch) break;
+  }
+
+  return read;
+}
+
+ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size)
+{
+    int n = transport->available < size ? transport->available : size;
+    memmove(bytes, transport->output, n);
+    memmove(transport->output, transport->output + n, transport->available - n);
+    transport->available -= n;
+    // XXX: need to check for errors
+    return n;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatcher.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatcher.h b/proton-c/src/core/dispatcher.h
new file mode 100644
index 0000000..29881b5
--- /dev/null
+++ b/proton-c/src/core/dispatcher.h
@@ -0,0 +1,37 @@
+#ifndef _PROTON_DISPATCHER_H
+#define _PROTON_DISPATCHER_H 1
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include "proton/codec.h"
+#include "proton/types.h"
+
+typedef int (pn_action_t)(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+ssize_t pn_dispatcher_input(pn_transport_t* transport, const char* bytes, size_t available, bool batch, bool* halt);
+ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size);
+
+#endif /* dispatcher.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/encoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/encoder.c b/proton-c/src/core/encoder.c
new file mode 100644
index 0000000..f8145fc
--- /dev/null
+++ b/proton-c/src/core/encoder.c
@@ -0,0 +1,383 @@
+/*
+ *
+ * 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/error.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include "encodings.h"
+#include "encoder.h"
+
+#include <string.h>
+
+#include "data.h"
+
+struct pn_encoder_t {
+  char *output;
+  size_t size;
+  char *position;
+  pn_error_t *error;
+};
+
+static void pn_encoder_initialize(void *obj)
+{
+  pn_encoder_t *encoder = (pn_encoder_t *) obj;
+  encoder->output = NULL;
+  encoder->size = 0;
+  encoder->position = NULL;
+  encoder->error = pn_error();
+}
+
+static void pn_encoder_finalize(void *obj) {
+  pn_encoder_t *encoder = (pn_encoder_t *) obj;
+  pn_error_free(encoder->error);
+}
+
+#define pn_encoder_hashcode NULL
+#define pn_encoder_compare NULL
+#define pn_encoder_inspect NULL
+
+pn_encoder_t *pn_encoder()
+{
+  static const pn_class_t clazz = PN_CLASS(pn_encoder);
+  return (pn_encoder_t *) pn_class_new(&clazz, sizeof(pn_encoder_t));
+}
+
+static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type)
+{
+  switch (type)
+  {
+  case PN_NULL: return PNE_NULL;
+  case PN_BOOL: return PNE_BOOLEAN;
+  case PN_UBYTE: return PNE_UBYTE;
+  case PN_BYTE: return PNE_BYTE;
+  case PN_USHORT: return PNE_USHORT;
+  case PN_SHORT: return PNE_SHORT;
+  case PN_UINT: return PNE_UINT;
+  case PN_INT: return PNE_INT;
+  case PN_CHAR: return PNE_UTF32;
+  case PN_FLOAT: return PNE_FLOAT;
+  case PN_LONG: return PNE_LONG;
+  case PN_TIMESTAMP: return PNE_MS64;
+  case PN_DOUBLE: return PNE_DOUBLE;
+  case PN_DECIMAL32: return PNE_DECIMAL32;
+  case PN_DECIMAL64: return PNE_DECIMAL64;
+  case PN_DECIMAL128: return PNE_DECIMAL128;
+  case PN_UUID: return PNE_UUID;
+  case PN_ULONG: return PNE_ULONG;
+  case PN_BINARY: return PNE_VBIN32;
+  case PN_STRING: return PNE_STR32_UTF8;
+  case PN_SYMBOL: return PNE_SYM32;
+  case PN_LIST: return PNE_LIST32;
+  case PN_ARRAY: return PNE_ARRAY32;
+  case PN_MAP: return PNE_MAP32;
+  case PN_DESCRIBED: return PNE_DESCRIPTOR;
+  default:
+    return pn_error_format(encoder->error, PN_ERR, "not a value type: %u\n", type);
+  }
+}
+
+static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node)
+{
+  switch (node->atom.type) {
+  case PN_LONG:
+    if (-128 <= node->atom.u.as_long && node->atom.u.as_long <= 127) {
+      return PNE_SMALLLONG;
+    } else {
+      return PNE_LONG;
+    }
+  case PN_INT:
+    if (-128 <= node->atom.u.as_int && node->atom.u.as_int <= 127) {
+      return PNE_SMALLINT;
+    } else {
+      return PNE_INT;
+    }
+  case PN_ULONG:
+    if (node->atom.u.as_ulong < 256) {
+      return PNE_SMALLULONG;
+    } else {
+      return PNE_ULONG;
+    }
+  case PN_UINT:
+    if (node->atom.u.as_uint < 256) {
+      return PNE_SMALLUINT;
+    } else {
+      return PNE_UINT;
+    }
+  case PN_BOOL:
+    if (node->atom.u.as_bool) {
+      return PNE_TRUE;
+    } else {
+      return PNE_FALSE;
+    }
+  case PN_STRING:
+    if (node->atom.u.as_bytes.size < 256) {
+      return PNE_STR8_UTF8;
+    } else {
+      return PNE_STR32_UTF8;
+    }
+  case PN_SYMBOL:
+    if (node->atom.u.as_bytes.size < 256) {
+      return PNE_SYM8;
+    } else {
+      return PNE_SYM32;
+    }
+  case PN_BINARY:
+    if (node->atom.u.as_bytes.size < 256) {
+      return PNE_VBIN8;
+    } else {
+      return PNE_VBIN32;
+    }
+  default:
+    return pn_type2code(encoder, node->atom.type);
+  }
+}
+
+static size_t pn_encoder_remaining(pn_encoder_t *encoder) {
+  char * end = encoder->output + encoder->size;
+  if (end > encoder->position)
+    return end - encoder->position;
+  else
+    return 0;
+}
+
+static inline void pn_encoder_writef8(pn_encoder_t *encoder, uint8_t value)
+{
+  if (pn_encoder_remaining(encoder)) {
+    encoder->position[0] = value;
+  }
+  encoder->position++;
+}
+
+static inline void pn_encoder_writef16(pn_encoder_t *encoder, uint16_t value)
+{
+  if (pn_encoder_remaining(encoder) >= 2) {
+    encoder->position[0] = 0xFF & (value >> 8);
+    encoder->position[1] = 0xFF & (value     );
+  }
+  encoder->position += 2;
+}
+
+static inline void pn_encoder_writef32(pn_encoder_t *encoder, uint32_t value)
+{
+  if (pn_encoder_remaining(encoder) >= 4) {
+    encoder->position[0] = 0xFF & (value >> 24);
+    encoder->position[1] = 0xFF & (value >> 16);
+    encoder->position[2] = 0xFF & (value >>  8);
+    encoder->position[3] = 0xFF & (value      );
+  }
+  encoder->position += 4;
+}
+
+static inline void pn_encoder_writef64(pn_encoder_t *encoder, uint64_t value) {
+  if (pn_encoder_remaining(encoder) >= 8) {
+    encoder->position[0] = 0xFF & (value >> 56);
+    encoder->position[1] = 0xFF & (value >> 48);
+    encoder->position[2] = 0xFF & (value >> 40);
+    encoder->position[3] = 0xFF & (value >> 32);
+    encoder->position[4] = 0xFF & (value >> 24);
+    encoder->position[5] = 0xFF & (value >> 16);
+    encoder->position[6] = 0xFF & (value >>  8);
+    encoder->position[7] = 0xFF & (value      );
+  }
+  encoder->position += 8;
+}
+
+static inline void pn_encoder_writef128(pn_encoder_t *encoder, char *value) {
+  if (pn_encoder_remaining(encoder) >= 16) {
+    memmove(encoder->position, value, 16);
+  }
+  encoder->position += 16;
+}
+
+static inline void pn_encoder_writev8(pn_encoder_t *encoder, const pn_bytes_t *value)
+{
+  pn_encoder_writef8(encoder, value->size);
+  if (pn_encoder_remaining(encoder) >= value->size)
+    memmove(encoder->position, value->start, value->size);
+  encoder->position += value->size;
+}
+
+static inline void pn_encoder_writev32(pn_encoder_t *encoder, const pn_bytes_t *value)
+{
+  pn_encoder_writef32(encoder, value->size);
+  if (pn_encoder_remaining(encoder) >= value->size)
+    memmove(encoder->position, value->start, value->size);
+  encoder->position += value->size;
+}
+
+/* True if node is an element of an array - not the descriptor. */
+static bool pn_is_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
+  return (parent && parent->atom.type == PN_ARRAY) /* In array */
+    && !(parent->described && !node->prev); /* Not the descriptor */
+}
+
+/** True if node is the first element of an array, not the descriptor.
+ *@pre pn_is_in_array(data, parent, node)
+ */
+static bool pn_is_first_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
+  if (!node->prev) return !parent->described; /* First node */
+  return parent->described && (!pn_data_node(data, node->prev)->prev);
+}
+
+typedef union {
+  uint32_t i;
+  uint32_t a[2];
+  uint64_t l;
+  float f;
+  double d;
+} conv_t;
+
+static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+  pn_encoder_t *encoder = (pn_encoder_t *) ctx;
+  pni_node_t *parent = pn_data_node(data, node->parent);
+  pn_atom_t *atom = &node->atom;
+  uint8_t code;
+  conv_t c;
+
+  /** In an array we don't write the code before each element, only the first. */
+  if (pn_is_in_array(data, parent, node)) {
+    code = pn_type2code(encoder, parent->type);
+    if (pn_is_first_in_array(data, parent, node)) {
+      pn_encoder_writef8(encoder, code);
+    }
+  } else {
+    code = pn_node2code(encoder, node);
+    pn_encoder_writef8(encoder, code);
+  }
+
+  switch (code) {
+  case PNE_DESCRIPTOR:
+  case PNE_NULL:
+  case PNE_TRUE:
+  case PNE_FALSE: return 0;
+  case PNE_BOOLEAN: pn_encoder_writef8(encoder, atom->u.as_bool); return 0;
+  case PNE_UBYTE: pn_encoder_writef8(encoder, atom->u.as_ubyte); return 0;
+  case PNE_BYTE: pn_encoder_writef8(encoder, atom->u.as_byte); return 0;
+  case PNE_USHORT: pn_encoder_writef16(encoder, atom->u.as_ushort); return 0;
+  case PNE_SHORT: pn_encoder_writef16(encoder, atom->u.as_short); return 0;
+  case PNE_UINT0: return 0;
+  case PNE_SMALLUINT: pn_encoder_writef8(encoder, atom->u.as_uint); return 0;
+  case PNE_UINT: pn_encoder_writef32(encoder, atom->u.as_uint); return 0;
+  case PNE_SMALLINT: pn_encoder_writef8(encoder, atom->u.as_int); return 0;
+  case PNE_INT: pn_encoder_writef32(encoder, atom->u.as_int); return 0;
+  case PNE_UTF32: pn_encoder_writef32(encoder, atom->u.as_char); return 0;
+  case PNE_ULONG: pn_encoder_writef64(encoder, atom->u.as_ulong); return 0;
+  case PNE_SMALLULONG: pn_encoder_writef8(encoder, atom->u.as_ulong); return 0;
+  case PNE_LONG: pn_encoder_writef64(encoder, atom->u.as_long); return 0;
+  case PNE_SMALLLONG: pn_encoder_writef8(encoder, atom->u.as_long); return 0;
+  case PNE_MS64: pn_encoder_writef64(encoder, atom->u.as_timestamp); return 0;
+  case PNE_FLOAT: c.f = atom->u.as_float; pn_encoder_writef32(encoder, c.i); return 0;
+  case PNE_DOUBLE: c.d = atom->u.as_double; pn_encoder_writef64(encoder, c.l); return 0;
+  case PNE_DECIMAL32: pn_encoder_writef32(encoder, atom->u.as_decimal32); return 0;
+  case PNE_DECIMAL64: pn_encoder_writef64(encoder, atom->u.as_decimal64); return 0;
+  case PNE_DECIMAL128: pn_encoder_writef128(encoder, atom->u.as_decimal128.bytes); return 0;
+  case PNE_UUID: pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); return 0;
+  case PNE_VBIN8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
+  case PNE_VBIN32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+  case PNE_STR8_UTF8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
+  case PNE_STR32_UTF8: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+  case PNE_SYM8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
+  case PNE_SYM32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
+  case PNE_ARRAY32:
+    node->start = encoder->position;
+    node->small = false;
+    // we'll backfill the size on exit
+    encoder->position += 4;
+    pn_encoder_writef32(encoder, node->described ? node->children - 1 : node->children);
+    if (node->described)
+      pn_encoder_writef8(encoder, 0);
+    return 0;
+  case PNE_LIST32:
+  case PNE_MAP32:
+    node->start = encoder->position;
+    node->small = false;
+    // we'll backfill the size later
+    encoder->position += 4;
+    pn_encoder_writef32(encoder, node->children);
+    return 0;
+  default:
+    return pn_error_format(data->error, PN_ERR, "unrecognized encoding: %u", code);
+  }
+}
+
+#include <stdio.h>
+
+static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+  pn_encoder_t *encoder = (pn_encoder_t *) ctx;
+  char *pos;
+
+  switch (node->atom.type) {
+  case PN_ARRAY:
+    if ((node->described && node->children == 1) || (!node->described && node->children == 0)) {
+      pn_encoder_writef8(encoder, pn_type2code(encoder, node->type));
+    }
+  // Fallthrough
+  case PN_LIST:
+  case PN_MAP:
+    pos = encoder->position;
+    encoder->position = node->start;
+    if (node->small) {
+      // backfill size
+      size_t size = pos - node->start - 1;
+      pn_encoder_writef8(encoder, size);
+    } else {
+      // backfill size
+      size_t size = pos - node->start - 4;
+      pn_encoder_writef32(encoder, size);
+    }
+    encoder->position = pos;
+    return 0;
+  default:
+    return 0;
+  }
+}
+
+ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size)
+{
+  encoder->output = dst;
+  encoder->position = dst;
+  encoder->size = size;
+
+  int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
+  if (err) return err;
+  size_t encoded = encoder->position - encoder->output;
+  if (encoded > size) {
+      pn_error_format(pn_data_error(src), PN_OVERFLOW, "not enough space to encode");
+      return PN_OVERFLOW;
+  }
+  return (ssize_t)encoded;
+}
+
+ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src)
+{
+  encoder->output = 0;
+  encoder->position = 0;
+  encoder->size = 0;
+
+  pn_handle_t save = pn_data_point(src);
+  int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
+  pn_data_restore(src, save);
+
+  if (err) return err;
+  return encoder->position - encoder->output;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/encoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/encoder.h b/proton-c/src/core/encoder.h
new file mode 100644
index 0000000..20876cb
--- /dev/null
+++ b/proton-c/src/core/encoder.h
@@ -0,0 +1,31 @@
+#ifndef _PROTON_ENCODER_H
+#define _PROTON_ENCODER_H 1
+
+/*
+ *
+ * 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.
+ *
+ */
+
+typedef struct pn_encoder_t pn_encoder_t;
+
+pn_encoder_t *pn_encoder(void);
+ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size);
+ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src);
+
+#endif /* encoder.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine-internal.h b/proton-c/src/core/engine-internal.h
new file mode 100644
index 0000000..fdaf272
--- /dev/null
+++ b/proton-c/src/core/engine-internal.h
@@ -0,0 +1,375 @@
+#ifndef _PROTON_ENGINE_INTERNAL_H
+#define _PROTON_ENGINE_INTERNAL_H 1
+
+/*
+ *
+ * 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/object.h>
+#include <proton/engine.h>
+#include <proton/types.h>
+
+#include "buffer.h"
+#include "dispatcher.h"
+#include "util.h"
+
+typedef enum pn_endpoint_type_t {CONNECTION, SESSION, SENDER, RECEIVER} pn_endpoint_type_t;
+
+typedef struct pn_endpoint_t pn_endpoint_t;
+
+struct pn_condition_t {
+  pn_string_t *name;
+  pn_string_t *description;
+  pn_data_t *info;
+};
+
+struct pn_endpoint_t {
+  pn_endpoint_type_t type;
+  pn_state_t state;
+  pn_error_t *error;
+  pn_condition_t condition;
+  pn_condition_t remote_condition;
+  pn_endpoint_t *endpoint_next;
+  pn_endpoint_t *endpoint_prev;
+  pn_endpoint_t *transport_next;
+  pn_endpoint_t *transport_prev;
+  int refcount; // when this hits zero we generate a final event
+  bool modified;
+  bool freed;
+  bool referenced;
+};
+
+typedef struct {
+  pn_sequence_t id;
+  bool sent;
+  bool init;
+} pn_delivery_state_t;
+
+typedef struct {
+  pn_sequence_t next;
+  pn_hash_t *deliveries;
+} pn_delivery_map_t;
+
+typedef struct {
+  // XXX: stop using negative numbers
+  uint32_t local_handle;
+  uint32_t remote_handle;
+  pn_sequence_t delivery_count;
+  pn_sequence_t link_credit;
+} pn_link_state_t;
+
+typedef struct {
+  // XXX: stop using negative numbers
+  uint16_t local_channel;
+  uint16_t remote_channel;
+  bool incoming_init;
+  pn_delivery_map_t incoming;
+  pn_delivery_map_t outgoing;
+  pn_sequence_t incoming_transfer_count;
+  pn_sequence_t incoming_window;
+  pn_sequence_t remote_incoming_window;
+  pn_sequence_t outgoing_transfer_count;
+  pn_sequence_t outgoing_window;
+  pn_hash_t *local_handles;
+  pn_hash_t *remote_handles;
+
+  uint64_t disp_code;
+  bool disp_settled;
+  bool disp_type;
+  pn_sequence_t disp_first;
+  pn_sequence_t disp_last;
+  bool disp;
+} pn_session_state_t;
+
+typedef struct pn_io_layer_t {
+  ssize_t (*process_input)(struct pn_transport_t *transport, unsigned int layer, const char *, size_t);
+  ssize_t (*process_output)(struct pn_transport_t *transport, unsigned int layer, char *, size_t);
+  void (*handle_error)(struct pn_transport_t* transport, unsigned int layer);
+  pn_timestamp_t (*process_tick)(struct pn_transport_t *transport, unsigned int layer, pn_timestamp_t);
+  size_t (*buffered_output)(struct pn_transport_t *transport);  // how much output is held
+} pn_io_layer_t;
+
+extern const pn_io_layer_t pni_passthru_layer;
+extern const pn_io_layer_t ssl_layer;
+extern const pn_io_layer_t sasl_header_layer;
+extern const pn_io_layer_t sasl_write_header_layer;
+
+// Bit flag defines for the protocol layers
+typedef uint8_t pn_io_layer_flags_t;
+#define LAYER_NONE     0
+#define LAYER_AMQP1    1
+#define LAYER_AMQPSASL 2
+#define LAYER_AMQPSSL  4
+#define LAYER_SSL      8
+
+typedef struct pni_sasl_t pni_sasl_t;
+typedef struct pni_ssl_t pni_ssl_t;
+
+struct pn_transport_t {
+  pn_tracer_t tracer;
+  pni_sasl_t *sasl;
+  pni_ssl_t *ssl;
+  pn_connection_t *connection;  // reference counted
+  char *remote_container;
+  char *remote_hostname;
+  pn_data_t *remote_offered_capabilities;
+  pn_data_t *remote_desired_capabilities;
+  pn_data_t *remote_properties;
+  pn_data_t *disp_data;
+  //#define PN_DEFAULT_MAX_FRAME_SIZE (16*1024)
+#define PN_DEFAULT_MAX_FRAME_SIZE (0)  /* for now, allow unlimited size */
+  uint32_t   local_max_frame;
+  uint32_t   remote_max_frame;
+  pn_condition_t remote_condition;
+  pn_condition_t condition;
+  pn_error_t *error;
+
+#define PN_IO_LAYER_CT 3
+  const pn_io_layer_t *io_layers[PN_IO_LAYER_CT];
+
+  /* dead remote detection */
+  pn_millis_t local_idle_timeout;
+  pn_millis_t remote_idle_timeout;
+  pn_timestamp_t dead_remote_deadline;
+  uint64_t last_bytes_input;
+
+  /* keepalive */
+  pn_timestamp_t keepalive_deadline;
+  uint64_t last_bytes_output;
+
+  pn_hash_t *local_channels;
+  pn_hash_t *remote_channels;
+
+
+  /* scratch area */
+  pn_string_t *scratch;
+  pn_data_t *args;
+  pn_data_t *output_args;
+  pn_buffer_t *frame;  // frame under construction
+  // Temporary
+  size_t capacity;
+  size_t available; /* number of raw bytes pending output */
+  char *output;
+
+  /* statistics */
+  uint64_t bytes_input;
+  uint64_t bytes_output;
+  uint64_t output_frames_ct;
+  uint64_t input_frames_ct;
+
+  /* output buffered for send */
+  size_t output_size;
+  size_t output_pending;
+  char *output_buf;
+
+  /* input from peer */
+  size_t input_size;
+  size_t input_pending;
+  char *input_buf;
+
+  pn_record_t *context;
+
+  pn_trace_t trace;
+
+  /*
+   * The maximum channel number can be constrained in several ways:
+   *   1. an unchangeable limit imposed by this library code
+   *   2. a limit imposed by the remote peer when the connection is opened,
+   *      which this app must honor
+   *   3. a limit imposed by this app, which may be raised and lowered
+   *      until the OPEN frame is sent.
+   * These constraints are all summed up in channel_max, below.
+   */
+  #define PN_IMPL_CHANNEL_MAX  32767
+  uint16_t local_channel_max;
+  uint16_t remote_channel_max;
+  uint16_t channel_max;
+
+  pn_io_layer_flags_t allowed_layers;
+  pn_io_layer_flags_t present_layers;
+
+  bool freed;
+  bool open_sent;
+  bool open_rcvd;
+  bool close_sent;
+  bool close_rcvd;
+  bool tail_closed;      // input stream closed by driver
+  bool head_closed;
+  bool done_processing; // if true, don't call pn_process again
+  bool posted_idle_timeout;
+  bool server;
+  bool halt;
+  bool auth_required;
+  bool authenticated;
+  bool encryption_required;
+
+  bool referenced;
+};
+
+struct pn_connection_t {
+  pn_endpoint_t endpoint;
+  pn_endpoint_t *endpoint_head;
+  pn_endpoint_t *endpoint_tail;
+  pn_endpoint_t *transport_head;  // reference counted
+  pn_endpoint_t *transport_tail;
+  pn_list_t *sessions;
+  pn_list_t *freed;
+  pn_transport_t *transport;
+  pn_delivery_t *work_head;
+  pn_delivery_t *work_tail;
+  pn_delivery_t *tpwork_head;  // reference counted
+  pn_delivery_t *tpwork_tail;
+  pn_string_t *container;
+  pn_string_t *hostname;
+  pn_string_t *auth_user;
+  pn_string_t *auth_password;
+  pn_data_t *offered_capabilities;
+  pn_data_t *desired_capabilities;
+  pn_data_t *properties;
+  pn_collector_t *collector;
+  pn_record_t *context;
+  pn_list_t *delivery_pool;
+};
+
+struct pn_session_t {
+  pn_endpoint_t endpoint;
+  pn_connection_t *connection;  // reference counted
+  pn_list_t *links;
+  pn_list_t *freed;
+  pn_record_t *context;
+  size_t incoming_capacity;
+  pn_sequence_t incoming_bytes;
+  pn_sequence_t outgoing_bytes;
+  pn_sequence_t incoming_deliveries;
+  pn_sequence_t outgoing_deliveries;
+  pn_sequence_t outgoing_window;
+  pn_session_state_t state;
+};
+
+struct pn_terminus_t {
+  pn_string_t *address;
+  pn_data_t *properties;
+  pn_data_t *capabilities;
+  pn_data_t *outcomes;
+  pn_data_t *filter;
+  pn_durability_t durability;
+  pn_expiry_policy_t expiry_policy;
+  pn_seconds_t timeout;
+  pn_terminus_type_t type;
+  pn_distribution_mode_t distribution_mode;
+  bool dynamic;
+};
+
+struct pn_link_t {
+  pn_endpoint_t endpoint;
+  pn_terminus_t source;
+  pn_terminus_t target;
+  pn_terminus_t remote_source;
+  pn_terminus_t remote_target;
+  pn_link_state_t state;
+  pn_string_t *name;
+  pn_session_t *session;  // reference counted
+  pn_delivery_t *unsettled_head;
+  pn_delivery_t *unsettled_tail;
+  pn_delivery_t *current;
+  pn_record_t *context;
+  size_t unsettled_count;
+  pn_sequence_t available;
+  pn_sequence_t credit;
+  pn_sequence_t queued;
+  int drained; // number of drained credits
+  uint8_t snd_settle_mode;
+  uint8_t rcv_settle_mode;
+  uint8_t remote_snd_settle_mode;
+  uint8_t remote_rcv_settle_mode;
+  bool drain_flag_mode; // receiver only
+  bool drain;
+  bool detached;
+};
+
+struct pn_disposition_t {
+  pn_condition_t condition;
+  uint64_t type;
+  pn_data_t *data;
+  pn_data_t *annotations;
+  uint64_t section_offset;
+  uint32_t section_number;
+  bool failed;
+  bool undeliverable;
+  bool settled;
+};
+
+struct pn_delivery_t {
+  pn_disposition_t local;
+  pn_disposition_t remote;
+  pn_link_t *link;  // reference counted
+  pn_buffer_t *tag;
+  pn_delivery_t *unsettled_next;
+  pn_delivery_t *unsettled_prev;
+  pn_delivery_t *work_next;
+  pn_delivery_t *work_prev;
+  pn_delivery_t *tpwork_next;
+  pn_delivery_t *tpwork_prev;
+  pn_delivery_state_t state;
+  pn_buffer_t *bytes;
+  pn_record_t *context;
+  bool updated;
+  bool settled; // tracks whether we're in the unsettled list or not
+  bool work;
+  bool tpwork;
+  bool done;
+  bool referenced;
+};
+
+#define PN_SET_LOCAL(OLD, NEW)                                          \
+  (OLD) = ((OLD) & PN_REMOTE_MASK) | (NEW)
+
+#define PN_SET_REMOTE(OLD, NEW)                                         \
+  (OLD) = ((OLD) & PN_LOCAL_MASK) | (NEW)
+
+void pn_link_dump(pn_link_t *link);
+
+void pn_dump(pn_connection_t *conn);
+void pn_transport_sasl_init(pn_transport_t *transport);
+
+void pn_condition_init(pn_condition_t *condition);
+void pn_condition_tini(pn_condition_t *condition);
+void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit);
+void pn_real_settle(pn_delivery_t *delivery);  // will free delivery if link is freed
+void pn_clear_tpwork(pn_delivery_t *delivery);
+void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery);
+void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint);
+void pn_connection_bound(pn_connection_t *conn);
+void pn_connection_unbound(pn_connection_t *conn);
+int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...);
+void pn_set_error_layer(pn_transport_t *transport);
+void pn_session_unbound(pn_session_t* ssn);
+void pn_link_unbound(pn_link_t* link);
+void pn_ep_incref(pn_endpoint_t *endpoint);
+void pn_ep_decref(pn_endpoint_t *endpoint);
+
+int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...);
+
+typedef enum {IN, OUT} pn_dir_t;
+
+void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
+                 pn_data_t *args, const char *payload, size_t size);
+
+#endif /* engine-internal.h */


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


[14/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine.c b/proton-c/src/core/engine.c
new file mode 100644
index 0000000..e238d5c
--- /dev/null
+++ b/proton-c/src/core/engine.c
@@ -0,0 +1,2231 @@
+/*
+ *
+ * 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 "engine-internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include "protocol.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "platform/platform.h"
+#include "platform/platform_fmt.h"
+#include "transport.h"
+
+
+static void pni_session_bound(pn_session_t *ssn);
+static void pni_link_bound(pn_link_t *link);
+
+
+// endpoints
+
+static pn_connection_t *pni_ep_get_connection(pn_endpoint_t *endpoint)
+{
+  switch (endpoint->type) {
+  case CONNECTION:
+    return (pn_connection_t *) endpoint;
+  case SESSION:
+    return ((pn_session_t *) endpoint)->connection;
+  case SENDER:
+  case RECEIVER:
+    return ((pn_link_t *) endpoint)->session->connection;
+  }
+
+  return NULL;
+}
+
+static pn_event_type_t endpoint_event(pn_endpoint_type_t type, bool open) {
+  switch (type) {
+  case CONNECTION:
+    return open ? PN_CONNECTION_LOCAL_OPEN : PN_CONNECTION_LOCAL_CLOSE;
+  case SESSION:
+    return open ? PN_SESSION_LOCAL_OPEN : PN_SESSION_LOCAL_CLOSE;
+  case SENDER:
+  case RECEIVER:
+    return open ? PN_LINK_LOCAL_OPEN : PN_LINK_LOCAL_CLOSE;
+  default:
+    assert(false);
+    return PN_EVENT_NONE;
+  }
+}
+
+static void pn_endpoint_open(pn_endpoint_t *endpoint)
+{
+  if (!(endpoint->state & PN_LOCAL_ACTIVE)) {
+    PN_SET_LOCAL(endpoint->state, PN_LOCAL_ACTIVE);
+    pn_connection_t *conn = pni_ep_get_connection(endpoint);
+    pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+                     endpoint_event(endpoint->type, true));
+    pn_modified(conn, endpoint, true);
+  }
+}
+
+static void pn_endpoint_close(pn_endpoint_t *endpoint)
+{
+  if (!(endpoint->state & PN_LOCAL_CLOSED)) {
+    PN_SET_LOCAL(endpoint->state, PN_LOCAL_CLOSED);
+    pn_connection_t *conn = pni_ep_get_connection(endpoint);
+    pn_collector_put(conn->collector, PN_OBJECT, endpoint,
+                     endpoint_event(endpoint->type, false));
+    pn_modified(conn, endpoint, true);
+  }
+}
+
+void pn_connection_reset(pn_connection_t *connection)
+{
+  assert(connection);
+  pn_endpoint_t *endpoint = &connection->endpoint;
+  endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
+}
+
+void pn_connection_open(pn_connection_t *connection)
+{
+  assert(connection);
+  pn_endpoint_open(&connection->endpoint);
+}
+
+void pn_connection_close(pn_connection_t *connection)
+{
+  assert(connection);
+  pn_endpoint_close(&connection->endpoint);
+}
+
+static void pni_endpoint_tini(pn_endpoint_t *endpoint);
+
+void pn_connection_release(pn_connection_t *connection)
+{
+  assert(!connection->endpoint.freed);
+  // free those endpoints that haven't been freed by the application
+  LL_REMOVE(connection, endpoint, &connection->endpoint);
+  while (connection->endpoint_head) {
+    pn_endpoint_t *ep = connection->endpoint_head;
+    switch (ep->type) {
+    case SESSION:
+      // note: this will free all child links:
+      pn_session_free((pn_session_t *)ep);
+      break;
+    case SENDER:
+    case RECEIVER:
+      pn_link_free((pn_link_t *)ep);
+      break;
+    default:
+      assert(false);
+    }
+  }
+  connection->endpoint.freed = true;
+  if (!connection->transport) {
+    // no transport available to consume transport work items,
+    // so manually clear them:
+    pn_ep_incref(&connection->endpoint);
+    pn_connection_unbound(connection);
+  }
+  pn_ep_decref(&connection->endpoint);
+}
+
+void pn_connection_free(pn_connection_t *connection) {
+  pn_connection_release(connection);
+  pn_decref(connection);
+}
+
+void pn_connection_bound(pn_connection_t *connection)
+{
+  pn_collector_put(connection->collector, PN_OBJECT, connection, PN_CONNECTION_BOUND);
+  pn_ep_incref(&connection->endpoint);
+
+  size_t nsessions = pn_list_size(connection->sessions);
+  for (size_t i = 0; i < nsessions; i++) {
+    pni_session_bound((pn_session_t *) pn_list_get(connection->sessions, i));
+  }
+}
+
+// invoked when transport has been removed:
+void pn_connection_unbound(pn_connection_t *connection)
+{
+  connection->transport = NULL;
+  if (connection->endpoint.freed) {
+    // connection has been freed prior to unbinding, thus it
+    // cannot be re-assigned to a new transport.  Clear the
+    // transport work lists to allow the connection to be freed.
+    while (connection->transport_head) {
+        pn_clear_modified(connection, connection->transport_head);
+    }
+    while (connection->tpwork_head) {
+      pn_clear_tpwork(connection->tpwork_head);
+    }
+  }
+  pn_ep_decref(&connection->endpoint);
+}
+
+pn_record_t *pn_connection_attachments(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->context;
+}
+
+void *pn_connection_get_context(pn_connection_t *conn)
+{
+  // XXX: we should really assert on conn here, but this causes
+  // messenger tests to fail
+  return conn ? pn_record_get(conn->context, PN_LEGCTX) : NULL;
+}
+
+void pn_connection_set_context(pn_connection_t *conn, void *context)
+{
+  assert(conn);
+  pn_record_set(conn->context, PN_LEGCTX, context);
+}
+
+pn_transport_t *pn_connection_transport(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->transport;
+}
+
+void pn_condition_init(pn_condition_t *condition)
+{
+  condition->name = pn_string(NULL);
+  condition->description = pn_string(NULL);
+  condition->info = pn_data(0);
+}
+
+void pn_condition_tini(pn_condition_t *condition)
+{
+  pn_data_free(condition->info);
+  pn_free(condition->description);
+  pn_free(condition->name);
+}
+
+static void pni_add_session(pn_connection_t *conn, pn_session_t *ssn)
+{
+  pn_list_add(conn->sessions, ssn);
+  ssn->connection = conn;
+  pn_incref(conn);  // keep around until finalized
+  pn_ep_incref(&conn->endpoint);
+}
+
+static void pni_remove_session(pn_connection_t *conn, pn_session_t *ssn)
+{
+  if (pn_list_remove(conn->sessions, ssn)) {
+    pn_ep_decref(&conn->endpoint);
+    LL_REMOVE(conn, endpoint, &ssn->endpoint);
+  }
+}
+
+pn_connection_t *pn_session_connection(pn_session_t *session)
+{
+  if (!session) return NULL;
+  return session->connection;
+}
+
+void pn_session_open(pn_session_t *session)
+{
+  assert(session);
+  pn_endpoint_open(&session->endpoint);
+}
+
+void pn_session_close(pn_session_t *session)
+{
+  assert(session);
+  pn_endpoint_close(&session->endpoint);
+}
+
+void pn_session_free(pn_session_t *session)
+{
+  assert(!session->endpoint.freed);
+  while(pn_list_size(session->links)) {
+    pn_link_t *link = (pn_link_t *)pn_list_get(session->links, 0);
+    pn_link_free(link);
+  }
+  pni_remove_session(session->connection, session);
+  pn_list_add(session->connection->freed, session);
+  session->endpoint.freed = true;
+  pn_ep_decref(&session->endpoint);
+
+  // the finalize logic depends on endpoint.freed, so we incref/decref
+  // to give it a chance to rerun
+  pn_incref(session);
+  pn_decref(session);
+}
+
+pn_record_t *pn_session_attachments(pn_session_t *session)
+{
+  assert(session);
+  return session->context;
+}
+
+void *pn_session_get_context(pn_session_t *session)
+{
+  return session ? pn_record_get(session->context, PN_LEGCTX) : 0;
+}
+
+void pn_session_set_context(pn_session_t *session, void *context)
+{
+  assert(context);
+  pn_record_set(session->context, PN_LEGCTX, context);
+}
+
+
+static void pni_add_link(pn_session_t *ssn, pn_link_t *link)
+{
+  pn_list_add(ssn->links, link);
+  link->session = ssn;
+  pn_ep_incref(&ssn->endpoint);
+}
+
+static void pni_remove_link(pn_session_t *ssn, pn_link_t *link)
+{
+  if (pn_list_remove(ssn->links, link)) {
+    pn_ep_decref(&ssn->endpoint);
+    LL_REMOVE(ssn->connection, endpoint, &link->endpoint);
+  }
+}
+
+void pn_link_open(pn_link_t *link)
+{
+  assert(link);
+  pn_endpoint_open(&link->endpoint);
+}
+
+void pn_link_close(pn_link_t *link)
+{
+  assert(link);
+  pn_endpoint_close(&link->endpoint);
+}
+
+void pn_link_detach(pn_link_t *link)
+{
+  assert(link);
+  if (link->detached) return;
+
+  link->detached = true;
+  pn_collector_put(link->session->connection->collector, PN_OBJECT, link, PN_LINK_LOCAL_DETACH);
+  pn_modified(link->session->connection, &link->endpoint, true);
+
+}
+
+static void pni_terminus_free(pn_terminus_t *terminus)
+{
+  pn_free(terminus->address);
+  pn_free(terminus->properties);
+  pn_free(terminus->capabilities);
+  pn_free(terminus->outcomes);
+  pn_free(terminus->filter);
+}
+
+void pn_link_free(pn_link_t *link)
+{
+  assert(!link->endpoint.freed);
+  pni_remove_link(link->session, link);
+  pn_list_add(link->session->freed, link);
+  pn_delivery_t *delivery = link->unsettled_head;
+  while (delivery) {
+    pn_delivery_t *next = delivery->unsettled_next;
+    pn_delivery_settle(delivery);
+    delivery = next;
+  }
+  link->endpoint.freed = true;
+  pn_ep_decref(&link->endpoint);
+
+  // the finalize logic depends on endpoint.freed (modified above), so
+  // we incref/decref to give it a chance to rerun
+  pn_incref(link);
+  pn_decref(link);
+}
+
+void *pn_link_get_context(pn_link_t *link)
+{
+  assert(link);
+  return pn_record_get(link->context, PN_LEGCTX);
+}
+
+void pn_link_set_context(pn_link_t *link, void *context)
+{
+  assert(link);
+  pn_record_set(link->context, PN_LEGCTX, context);
+}
+
+pn_record_t *pn_link_attachments(pn_link_t *link)
+{
+  assert(link);
+  return link->context;
+}
+
+void pn_endpoint_init(pn_endpoint_t *endpoint, int type, pn_connection_t *conn)
+{
+  endpoint->type = (pn_endpoint_type_t) type;
+  endpoint->referenced = true;
+  endpoint->state = PN_LOCAL_UNINIT | PN_REMOTE_UNINIT;
+  endpoint->error = pn_error();
+  pn_condition_init(&endpoint->condition);
+  pn_condition_init(&endpoint->remote_condition);
+  endpoint->endpoint_next = NULL;
+  endpoint->endpoint_prev = NULL;
+  endpoint->transport_next = NULL;
+  endpoint->transport_prev = NULL;
+  endpoint->modified = false;
+  endpoint->freed = false;
+  endpoint->refcount = 1;
+  //fprintf(stderr, "initting 0x%lx\n", (uintptr_t) endpoint);
+
+  LL_ADD(conn, endpoint, endpoint);
+}
+
+void pn_ep_incref(pn_endpoint_t *endpoint)
+{
+  endpoint->refcount++;
+}
+
+static pn_event_type_t pn_final_type(pn_endpoint_type_t type) {
+  switch (type) {
+  case CONNECTION:
+    return PN_CONNECTION_FINAL;
+  case SESSION:
+    return PN_SESSION_FINAL;
+  case SENDER:
+  case RECEIVER:
+    return PN_LINK_FINAL;
+  default:
+    assert(false);
+    return PN_EVENT_NONE;
+  }
+}
+
+static pn_endpoint_t *pn_ep_parent(pn_endpoint_t *endpoint) {
+  switch (endpoint->type) {
+  case CONNECTION:
+    return NULL;
+  case SESSION:
+    return &((pn_session_t *) endpoint)->connection->endpoint;
+  case SENDER:
+  case RECEIVER:
+    return &((pn_link_t *) endpoint)->session->endpoint;
+  default:
+    assert(false);
+    return NULL;
+  }
+}
+
+void pn_ep_decref(pn_endpoint_t *endpoint)
+{
+  assert(endpoint->refcount > 0);
+  endpoint->refcount--;
+  if (endpoint->refcount == 0) {
+    pn_connection_t *conn = pni_ep_get_connection(endpoint);
+    pn_collector_put(conn->collector, PN_OBJECT, endpoint, pn_final_type(endpoint->type));
+  }
+}
+
+static void pni_endpoint_tini(pn_endpoint_t *endpoint)
+{
+  pn_error_free(endpoint->error);
+  pn_condition_tini(&endpoint->remote_condition);
+  pn_condition_tini(&endpoint->condition);
+}
+
+static void pni_free_children(pn_list_t *children, pn_list_t *freed)
+{
+  while (pn_list_size(children) > 0) {
+    pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(children, 0);
+    assert(!endpoint->referenced);
+    pn_free(endpoint);
+  }
+
+  while (pn_list_size(freed) > 0) {
+    pn_endpoint_t *endpoint = (pn_endpoint_t *) pn_list_get(freed, 0);
+    assert(!endpoint->referenced);
+    pn_free(endpoint);
+  }
+
+  pn_free(children);
+  pn_free(freed);
+}
+
+static void pn_connection_finalize(void *object)
+{
+  pn_connection_t *conn = (pn_connection_t *) object;
+  pn_endpoint_t *endpoint = &conn->endpoint;
+
+  if (conn->transport) {
+    assert(!conn->transport->referenced);
+    pn_free(conn->transport);
+  }
+
+  // freeing the transport could post events
+  if (pn_refcount(conn) > 0) {
+    return;
+  }
+
+  pni_free_children(conn->sessions, conn->freed);
+  pn_free(conn->context);
+  pn_decref(conn->collector);
+
+  pn_free(conn->container);
+  pn_free(conn->hostname);
+  pn_free(conn->auth_user);
+  pn_free(conn->auth_password);
+  pn_free(conn->offered_capabilities);
+  pn_free(conn->desired_capabilities);
+  pn_free(conn->properties);
+  pni_endpoint_tini(endpoint);
+  pn_free(conn->delivery_pool);
+}
+
+#define pn_connection_initialize NULL
+#define pn_connection_hashcode NULL
+#define pn_connection_compare NULL
+#define pn_connection_inspect NULL
+
+pn_connection_t *pn_connection(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_connection);
+  pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, sizeof(pn_connection_t));
+  if (!conn) return NULL;
+
+  conn->endpoint_head = NULL;
+  conn->endpoint_tail = NULL;
+  pn_endpoint_init(&conn->endpoint, CONNECTION, conn);
+  conn->transport_head = NULL;
+  conn->transport_tail = NULL;
+  conn->sessions = pn_list(PN_WEAKREF, 0);
+  conn->freed = pn_list(PN_WEAKREF, 0);
+  conn->transport = NULL;
+  conn->work_head = NULL;
+  conn->work_tail = NULL;
+  conn->tpwork_head = NULL;
+  conn->tpwork_tail = NULL;
+  conn->container = pn_string(NULL);
+  conn->hostname = pn_string(NULL);
+  conn->auth_user = pn_string(NULL);
+  conn->auth_password = pn_string(NULL);
+  conn->offered_capabilities = pn_data(0);
+  conn->desired_capabilities = pn_data(0);
+  conn->properties = pn_data(0);
+  conn->collector = NULL;
+  conn->context = pn_record();
+  conn->delivery_pool = pn_list(PN_OBJECT, 0);
+
+  return conn;
+}
+
+static const pn_event_type_t endpoint_init_event_map[] = {
+  PN_CONNECTION_INIT,  /* CONNECTION */
+  PN_SESSION_INIT,     /* SESSION */
+  PN_LINK_INIT,        /* SENDER */
+  PN_LINK_INIT};       /* RECEIVER */
+
+void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector)
+{
+  pn_decref(connection->collector);
+  connection->collector = collector;
+  pn_incref(connection->collector);
+  pn_endpoint_t *endpoint = connection->endpoint_head;
+  while (endpoint) {
+    pn_collector_put(connection->collector, PN_OBJECT, endpoint, endpoint_init_event_map[endpoint->type]);
+    endpoint = endpoint->endpoint_next;
+  }
+}
+
+pn_state_t pn_connection_state(pn_connection_t *connection)
+{
+  return connection ? connection->endpoint.state : 0;
+}
+
+pn_error_t *pn_connection_error(pn_connection_t *connection)
+{
+  return connection ? connection->endpoint.error : NULL;
+}
+
+const char *pn_connection_get_container(pn_connection_t *connection)
+{
+  assert(connection);
+  return pn_string_get(connection->container);
+}
+
+void pn_connection_set_container(pn_connection_t *connection, const char *container)
+{
+  assert(connection);
+  pn_string_set(connection->container, container);
+}
+
+const char *pn_connection_get_hostname(pn_connection_t *connection)
+{
+  assert(connection);
+  return pn_string_get(connection->hostname);
+}
+
+void pn_connection_set_hostname(pn_connection_t *connection, const char *hostname)
+{
+  assert(connection);
+  pn_string_set(connection->hostname, hostname);
+}
+
+const char *pn_connection_get_user(pn_connection_t *connection)
+{
+    assert(connection);
+    return pn_string_get(connection->auth_user);
+}
+
+void pn_connection_set_user(pn_connection_t *connection, const char *user)
+{
+    assert(connection);
+    pn_string_set(connection->auth_user, user);
+}
+
+void pn_connection_set_password(pn_connection_t *connection, const char *password)
+{
+    assert(connection);
+    // Make sure the previous password is erased, if there was one.
+    size_t n = pn_string_size(connection->auth_password);
+    const char* s = pn_string_get(connection->auth_password);
+    if (n > 0 && s) memset((void*)s, 0, n);
+    pn_string_set(connection->auth_password, password);
+}
+
+pn_data_t *pn_connection_offered_capabilities(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->offered_capabilities;
+}
+
+pn_data_t *pn_connection_desired_capabilities(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->desired_capabilities;
+}
+
+pn_data_t *pn_connection_properties(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->properties;
+}
+
+pn_data_t *pn_connection_remote_offered_capabilities(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->transport ? connection->transport->remote_offered_capabilities : NULL;
+}
+
+pn_data_t *pn_connection_remote_desired_capabilities(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->transport ? connection->transport->remote_desired_capabilities : NULL;
+}
+
+pn_data_t *pn_connection_remote_properties(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->transport ? connection->transport->remote_properties : NULL;
+}
+
+const char *pn_connection_remote_container(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->transport ? connection->transport->remote_container : NULL;
+}
+
+const char *pn_connection_remote_hostname(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->transport ? connection->transport->remote_hostname : NULL;
+}
+
+pn_delivery_t *pn_work_head(pn_connection_t *connection)
+{
+  assert(connection);
+  return connection->work_head;
+}
+
+pn_delivery_t *pn_work_next(pn_delivery_t *delivery)
+{
+  assert(delivery);
+
+  if (delivery->work)
+    return delivery->work_next;
+  else
+    return pn_work_head(delivery->link->session->connection);
+}
+
+static void pni_add_work(pn_connection_t *connection, pn_delivery_t *delivery)
+{
+  if (!delivery->work)
+  {
+    assert(!delivery->local.settled);   // never allow settled deliveries
+    LL_ADD(connection, work, delivery);
+    delivery->work = true;
+  }
+}
+
+static void pni_clear_work(pn_connection_t *connection, pn_delivery_t *delivery)
+{
+  if (delivery->work)
+  {
+    LL_REMOVE(connection, work, delivery);
+    delivery->work = false;
+  }
+}
+
+void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery)
+{
+  pn_link_t *link = pn_delivery_link(delivery);
+  pn_delivery_t *current = pn_link_current(link);
+  if (delivery->updated && !delivery->local.settled) {
+    pni_add_work(connection, delivery);
+  } else if (delivery == current) {
+    if (link->endpoint.type == SENDER) {
+      if (pn_link_credit(link) > 0) {
+        pni_add_work(connection, delivery);
+      } else {
+        pni_clear_work(connection, delivery);
+      }
+    } else {
+      pni_add_work(connection, delivery);
+    }
+  } else {
+    pni_clear_work(connection, delivery);
+  }
+}
+
+static void pni_add_tpwork(pn_delivery_t *delivery)
+{
+  pn_connection_t *connection = delivery->link->session->connection;
+  if (!delivery->tpwork)
+  {
+    LL_ADD(connection, tpwork, delivery);
+    delivery->tpwork = true;
+  }
+  pn_modified(connection, &connection->endpoint, true);
+}
+
+void pn_clear_tpwork(pn_delivery_t *delivery)
+{
+  pn_connection_t *connection = delivery->link->session->connection;
+  if (delivery->tpwork)
+  {
+    LL_REMOVE(connection, tpwork, delivery);
+    delivery->tpwork = false;
+    if (pn_refcount(delivery) > 0) {
+      pn_incref(delivery);
+      pn_decref(delivery);
+    }
+  }
+}
+
+void pn_dump(pn_connection_t *conn)
+{
+  pn_endpoint_t *endpoint = conn->transport_head;
+  while (endpoint)
+  {
+    printf("%p", (void *) endpoint);
+    endpoint = endpoint->transport_next;
+    if (endpoint)
+      printf(" -> ");
+  }
+  printf("\n");
+}
+
+void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit)
+{
+  if (!endpoint->modified) {
+    LL_ADD(connection, transport, endpoint);
+    endpoint->modified = true;
+  }
+
+  if (emit && connection->transport) {
+    pn_collector_put(connection->collector, PN_OBJECT, connection->transport,
+                     PN_TRANSPORT);
+  }
+}
+
+void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint)
+{
+  if (endpoint->modified) {
+    LL_REMOVE(connection, transport, endpoint);
+    endpoint->transport_next = NULL;
+    endpoint->transport_prev = NULL;
+    endpoint->modified = false;
+  }
+}
+
+static bool pni_matches(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
+{
+  if (endpoint->type != type) return false;
+
+  if (!state) return true;
+
+  int st = endpoint->state;
+  if ((state & PN_REMOTE_MASK) == 0 || (state & PN_LOCAL_MASK) == 0)
+    return st & state;
+  else
+    return st == state;
+}
+
+pn_endpoint_t *pn_find(pn_endpoint_t *endpoint, pn_endpoint_type_t type, pn_state_t state)
+{
+  while (endpoint)
+  {
+    if (pni_matches(endpoint, type, state))
+      return endpoint;
+    endpoint = endpoint->endpoint_next;
+  }
+  return NULL;
+}
+
+pn_session_t *pn_session_head(pn_connection_t *conn, pn_state_t state)
+{
+  if (conn)
+    return (pn_session_t *) pn_find(conn->endpoint_head, SESSION, state);
+  else
+    return NULL;
+}
+
+pn_session_t *pn_session_next(pn_session_t *ssn, pn_state_t state)
+{
+  if (ssn)
+    return (pn_session_t *) pn_find(ssn->endpoint.endpoint_next, SESSION, state);
+  else
+    return NULL;
+}
+
+pn_link_t *pn_link_head(pn_connection_t *conn, pn_state_t state)
+{
+  if (!conn) return NULL;
+
+  pn_endpoint_t *endpoint = conn->endpoint_head;
+
+  while (endpoint)
+  {
+    if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
+      return (pn_link_t *) endpoint;
+    endpoint = endpoint->endpoint_next;
+  }
+
+  return NULL;
+}
+
+pn_link_t *pn_link_next(pn_link_t *link, pn_state_t state)
+{
+  if (!link) return NULL;
+
+  pn_endpoint_t *endpoint = link->endpoint.endpoint_next;
+
+  while (endpoint)
+  {
+    if (pni_matches(endpoint, SENDER, state) || pni_matches(endpoint, RECEIVER, state))
+      return (pn_link_t *) endpoint;
+    endpoint = endpoint->endpoint_next;
+  }
+
+  return NULL;
+}
+
+static void pn_session_incref(void *object)
+{
+  pn_session_t *session = (pn_session_t *) object;
+  if (!session->endpoint.referenced) {
+    session->endpoint.referenced = true;
+    pn_incref(session->connection);
+  } else {
+    pn_object_incref(object);
+  }
+}
+
+static bool pn_ep_bound(pn_endpoint_t *endpoint)
+{
+  pn_connection_t *conn = pni_ep_get_connection(endpoint);
+  pn_session_t *ssn;
+  pn_link_t *lnk;
+
+  if (!conn->transport) return false;
+  if (endpoint->modified) return true;
+
+  switch (endpoint->type) {
+  case CONNECTION:
+    return ((pn_connection_t *)endpoint)->transport;
+  case SESSION:
+    ssn = (pn_session_t *) endpoint;
+    return (((int16_t) ssn->state.local_channel) >= 0 || ((int16_t) ssn->state.remote_channel) >= 0);
+  case SENDER:
+  case RECEIVER:
+    lnk = (pn_link_t *) endpoint;
+    return ((int32_t) lnk->state.local_handle) >= 0 || ((int32_t) lnk->state.remote_handle) >= 0;
+  default:
+    assert(false);
+    return false;
+  }
+}
+
+static bool pni_connection_live(pn_connection_t *conn) {
+  return pn_refcount(conn) > 1;
+}
+
+static bool pni_session_live(pn_session_t *ssn) {
+  return pni_connection_live(ssn->connection) || pn_refcount(ssn) > 1;
+}
+
+static bool pni_link_live(pn_link_t *link) {
+  return pni_session_live(link->session) || pn_refcount(link) > 1;
+}
+
+static bool pni_endpoint_live(pn_endpoint_t *endpoint) {
+  switch (endpoint->type) {
+  case CONNECTION:
+    return pni_connection_live((pn_connection_t *)endpoint);
+  case SESSION:
+    return pni_session_live((pn_session_t *) endpoint);
+  case SENDER:
+  case RECEIVER:
+    return pni_link_live((pn_link_t *) endpoint);
+  default:
+    assert(false);
+    return false;
+  }
+}
+
+static bool pni_preserve_child(pn_endpoint_t *endpoint)
+{
+  pn_connection_t *conn = pni_ep_get_connection(endpoint);
+  pn_endpoint_t *parent = pn_ep_parent(endpoint);
+  if (pni_endpoint_live(parent) && (!endpoint->freed || (pn_ep_bound(endpoint)))
+      && endpoint->referenced) {
+    pn_object_incref(endpoint);
+    endpoint->referenced = false;
+    pn_decref(parent);
+    return true;
+  } else {
+    LL_REMOVE(conn, transport, endpoint);
+    return false;
+  }
+}
+
+static void pn_session_finalize(void *object)
+{
+  pn_session_t *session = (pn_session_t *) object;
+  pn_endpoint_t *endpoint = &session->endpoint;
+
+  if (pni_preserve_child(endpoint)) {
+    return;
+  }
+
+  pn_free(session->context);
+  pni_free_children(session->links, session->freed);
+  pni_endpoint_tini(endpoint);
+  pn_delivery_map_free(&session->state.incoming);
+  pn_delivery_map_free(&session->state.outgoing);
+  pn_free(session->state.local_handles);
+  pn_free(session->state.remote_handles);
+  pni_remove_session(session->connection, session);
+  pn_list_remove(session->connection->freed, session);
+
+  if (session->connection->transport) {
+    pn_transport_t *transport = session->connection->transport;
+    pn_hash_del(transport->local_channels, session->state.local_channel);
+    pn_hash_del(transport->remote_channels, session->state.remote_channel);
+  }
+
+  if (endpoint->referenced) {
+    pn_decref(session->connection);
+  }
+}
+
+#define pn_session_new pn_object_new
+#define pn_session_refcount pn_object_refcount
+#define pn_session_decref pn_object_decref
+#define pn_session_reify pn_object_reify
+#define pn_session_initialize NULL
+#define pn_session_hashcode NULL
+#define pn_session_compare NULL
+#define pn_session_inspect NULL
+
+pn_session_t *pn_session(pn_connection_t *conn)
+{
+  assert(conn);
+
+
+  pn_transport_t * transport = pn_connection_transport(conn);
+
+  if(transport) {
+    // channel_max is an index, not a count.  
+    if(pn_hash_size(transport->local_channels) > (size_t)transport->channel_max) {
+      pn_transport_logf(transport, 
+                        "pn_session: too many sessions: %d  channel_max is %d",
+                        pn_hash_size(transport->local_channels),
+                        transport->channel_max);
+      return (pn_session_t *) 0;
+    }
+  }
+
+#define pn_session_free pn_object_free
+  static const pn_class_t clazz = PN_METACLASS(pn_session);
+#undef pn_session_free
+  pn_session_t *ssn = (pn_session_t *) pn_class_new(&clazz, sizeof(pn_session_t));
+  if (!ssn) return NULL;
+  pn_endpoint_init(&ssn->endpoint, SESSION, conn);
+  pni_add_session(conn, ssn);
+  ssn->links = pn_list(PN_WEAKREF, 0);
+  ssn->freed = pn_list(PN_WEAKREF, 0);
+  ssn->context = pn_record();
+  ssn->incoming_capacity = 1024*1024;
+  ssn->incoming_bytes = 0;
+  ssn->outgoing_bytes = 0;
+  ssn->incoming_deliveries = 0;
+  ssn->outgoing_deliveries = 0;
+  ssn->outgoing_window = 2147483647;
+
+  // begin transport state
+  memset(&ssn->state, 0, sizeof(ssn->state));
+  ssn->state.local_channel = (uint16_t)-1;
+  ssn->state.remote_channel = (uint16_t)-1;
+  pn_delivery_map_init(&ssn->state.incoming, 0);
+  pn_delivery_map_init(&ssn->state.outgoing, 0);
+  ssn->state.local_handles = pn_hash(PN_WEAKREF, 0, 0.75);
+  ssn->state.remote_handles = pn_hash(PN_WEAKREF, 0, 0.75);
+  // end transport state
+
+  pn_collector_put(conn->collector, PN_OBJECT, ssn, PN_SESSION_INIT);
+  if (conn->transport) {
+    pni_session_bound(ssn);
+  }
+  pn_decref(ssn);
+  return ssn;
+}
+
+static void pni_session_bound(pn_session_t *ssn)
+{
+  assert(ssn);
+  size_t nlinks = pn_list_size(ssn->links);
+  for (size_t i = 0; i < nlinks; i++) {
+    pni_link_bound((pn_link_t *) pn_list_get(ssn->links, i));
+  }
+}
+
+void pn_session_unbound(pn_session_t* ssn)
+{
+  assert(ssn);
+  ssn->state.local_channel = (uint16_t)-1;
+  ssn->state.remote_channel = (uint16_t)-1;
+  ssn->incoming_bytes = 0;
+  ssn->outgoing_bytes = 0;
+  ssn->incoming_deliveries = 0;
+  ssn->outgoing_deliveries = 0;
+}
+
+size_t pn_session_get_incoming_capacity(pn_session_t *ssn)
+{
+  assert(ssn);
+  return ssn->incoming_capacity;
+}
+
+void pn_session_set_incoming_capacity(pn_session_t *ssn, size_t capacity)
+{
+  assert(ssn);
+  // XXX: should this trigger a flow?
+  ssn->incoming_capacity = capacity;
+}
+
+size_t pn_session_get_outgoing_window(pn_session_t *ssn)
+{
+  assert(ssn);
+  return ssn->outgoing_window;
+}
+
+void pn_session_set_outgoing_window(pn_session_t *ssn, size_t window)
+{
+  assert(ssn);
+  ssn->outgoing_window = window;
+}
+
+size_t pn_session_outgoing_bytes(pn_session_t *ssn)
+{
+  assert(ssn);
+  return ssn->outgoing_bytes;
+}
+
+size_t pn_session_incoming_bytes(pn_session_t *ssn)
+{
+  assert(ssn);
+  return ssn->incoming_bytes;
+}
+
+pn_state_t pn_session_state(pn_session_t *session)
+{
+  return session->endpoint.state;
+}
+
+pn_error_t *pn_session_error(pn_session_t *session)
+{
+  return session->endpoint.error;
+}
+
+static void pni_terminus_init(pn_terminus_t *terminus, pn_terminus_type_t type)
+{
+  terminus->type = type;
+  terminus->address = pn_string(NULL);
+  terminus->durability = PN_NONDURABLE;
+  terminus->expiry_policy = PN_EXPIRE_WITH_SESSION;
+  terminus->timeout = 0;
+  terminus->dynamic = false;
+  terminus->distribution_mode = PN_DIST_MODE_UNSPECIFIED;
+  terminus->properties = pn_data(0);
+  terminus->capabilities = pn_data(0);
+  terminus->outcomes = pn_data(0);
+  terminus->filter = pn_data(0);
+}
+
+static void pn_link_incref(void *object)
+{
+  pn_link_t *link = (pn_link_t *) object;
+  if (!link->endpoint.referenced) {
+    link->endpoint.referenced = true;
+    pn_incref(link->session);
+  } else {
+    pn_object_incref(object);
+  }
+}
+
+static void pn_link_finalize(void *object)
+{
+  pn_link_t *link = (pn_link_t *) object;
+  pn_endpoint_t *endpoint = &link->endpoint;
+
+  if (pni_preserve_child(endpoint)) {
+    return;
+  }
+
+  while (link->unsettled_head) {
+    assert(!link->unsettled_head->referenced);
+    pn_free(link->unsettled_head);
+  }
+
+  pn_free(link->context);
+  pni_terminus_free(&link->source);
+  pni_terminus_free(&link->target);
+  pni_terminus_free(&link->remote_source);
+  pni_terminus_free(&link->remote_target);
+  pn_free(link->name);
+  pni_endpoint_tini(endpoint);
+  pni_remove_link(link->session, link);
+  pn_hash_del(link->session->state.local_handles, link->state.local_handle);
+  pn_hash_del(link->session->state.remote_handles, link->state.remote_handle);
+  pn_list_remove(link->session->freed, link);
+  if (endpoint->referenced) {
+    pn_decref(link->session);
+  }
+}
+
+#define pn_link_refcount pn_object_refcount
+#define pn_link_decref pn_object_decref
+#define pn_link_reify pn_object_reify
+#define pn_link_initialize NULL
+#define pn_link_hashcode NULL
+#define pn_link_compare NULL
+#define pn_link_inspect NULL
+
+pn_link_t *pn_link_new(int type, pn_session_t *session, const char *name)
+{
+#define pn_link_new pn_object_new
+#define pn_link_free pn_object_free
+  static const pn_class_t clazz = PN_METACLASS(pn_link);
+#undef pn_link_new
+#undef pn_link_free
+  pn_link_t *link = (pn_link_t *) pn_class_new(&clazz, sizeof(pn_link_t));
+
+  pn_endpoint_init(&link->endpoint, type, session->connection);
+  pni_add_link(session, link);
+  pn_incref(session);  // keep session until link finalized
+  link->name = pn_string(name);
+  pni_terminus_init(&link->source, PN_SOURCE);
+  pni_terminus_init(&link->target, PN_TARGET);
+  pni_terminus_init(&link->remote_source, PN_UNSPECIFIED);
+  pni_terminus_init(&link->remote_target, PN_UNSPECIFIED);
+  link->unsettled_head = link->unsettled_tail = link->current = NULL;
+  link->unsettled_count = 0;
+  link->available = 0;
+  link->credit = 0;
+  link->queued = 0;
+  link->drain = false;
+  link->drain_flag_mode = true;
+  link->drained = 0;
+  link->context = pn_record();
+  link->snd_settle_mode = PN_SND_MIXED;
+  link->rcv_settle_mode = PN_RCV_FIRST;
+  link->remote_snd_settle_mode = PN_SND_MIXED;
+  link->remote_rcv_settle_mode = PN_RCV_FIRST;
+  link->detached = false;
+
+  // begin transport state
+  link->state.local_handle = -1;
+  link->state.remote_handle = -1;
+  link->state.delivery_count = 0;
+  link->state.link_credit = 0;
+  // end transport state
+
+  pn_collector_put(session->connection->collector, PN_OBJECT, link, PN_LINK_INIT);
+  if (session->connection->transport) {
+    pni_link_bound(link);
+  }
+  pn_decref(link);
+  return link;
+}
+
+static void pni_link_bound(pn_link_t *link)
+{
+}
+
+void pn_link_unbound(pn_link_t* link)
+{
+  assert(link);
+  link->state.local_handle = -1;
+  link->state.remote_handle = -1;
+  link->state.delivery_count = 0;
+  link->state.link_credit = 0;
+}
+
+pn_terminus_t *pn_link_source(pn_link_t *link)
+{
+  return link ? &link->source : NULL;
+}
+
+pn_terminus_t *pn_link_target(pn_link_t *link)
+{
+  return link ? &link->target : NULL;
+}
+
+pn_terminus_t *pn_link_remote_source(pn_link_t *link)
+{
+  return link ? &link->remote_source : NULL;
+}
+
+pn_terminus_t *pn_link_remote_target(pn_link_t *link)
+{
+  return link ? &link->remote_target : NULL;
+}
+
+int pn_terminus_set_type(pn_terminus_t *terminus, pn_terminus_type_t type)
+{
+  if (!terminus) return PN_ARG_ERR;
+  terminus->type = type;
+  return 0;
+}
+
+pn_terminus_type_t pn_terminus_get_type(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->type : (pn_terminus_type_t) 0;
+}
+
+const char *pn_terminus_get_address(pn_terminus_t *terminus)
+{
+  assert(terminus);
+  return pn_string_get(terminus->address);
+}
+
+int pn_terminus_set_address(pn_terminus_t *terminus, const char *address)
+{
+  assert(terminus);
+  return pn_string_set(terminus->address, address);
+}
+
+pn_durability_t pn_terminus_get_durability(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->durability : (pn_durability_t) 0;
+}
+
+int pn_terminus_set_durability(pn_terminus_t *terminus, pn_durability_t durability)
+{
+  if (!terminus) return PN_ARG_ERR;
+  terminus->durability = durability;
+  return 0;
+}
+
+pn_expiry_policy_t pn_terminus_get_expiry_policy(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->expiry_policy : (pn_expiry_policy_t) 0;
+}
+
+int pn_terminus_set_expiry_policy(pn_terminus_t *terminus, pn_expiry_policy_t expiry_policy)
+{
+  if (!terminus) return PN_ARG_ERR;
+  terminus->expiry_policy = expiry_policy;
+  return 0;
+}
+
+pn_seconds_t pn_terminus_get_timeout(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->timeout : 0;
+}
+
+int pn_terminus_set_timeout(pn_terminus_t *terminus, pn_seconds_t timeout)
+{
+  if (!terminus) return PN_ARG_ERR;
+  terminus->timeout = timeout;
+  return 0;
+}
+
+bool pn_terminus_is_dynamic(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->dynamic : false;
+}
+
+int pn_terminus_set_dynamic(pn_terminus_t *terminus, bool dynamic)
+{
+  if (!terminus) return PN_ARG_ERR;
+  terminus->dynamic = dynamic;
+  return 0;
+}
+
+pn_data_t *pn_terminus_properties(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->properties : NULL;
+}
+
+pn_data_t *pn_terminus_capabilities(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->capabilities : NULL;
+}
+
+pn_data_t *pn_terminus_outcomes(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->outcomes : NULL;
+}
+
+pn_data_t *pn_terminus_filter(pn_terminus_t *terminus)
+{
+  return terminus ? terminus->filter : NULL;
+}
+
+pn_distribution_mode_t pn_terminus_get_distribution_mode(const pn_terminus_t *terminus)
+{
+  return terminus ? terminus->distribution_mode : PN_DIST_MODE_UNSPECIFIED;
+}
+
+int pn_terminus_set_distribution_mode(pn_terminus_t *terminus, pn_distribution_mode_t m)
+{
+  if (!terminus) return PN_ARG_ERR;
+  terminus->distribution_mode = m;
+  return 0;
+}
+
+int pn_terminus_copy(pn_terminus_t *terminus, pn_terminus_t *src)
+{
+  if (!terminus || !src) {
+    return PN_ARG_ERR;
+  }
+
+  terminus->type = src->type;
+  int err = pn_terminus_set_address(terminus, pn_terminus_get_address(src));
+  if (err) return err;
+  terminus->durability = src->durability;
+  terminus->expiry_policy = src->expiry_policy;
+  terminus->timeout = src->timeout;
+  terminus->dynamic = src->dynamic;
+  terminus->distribution_mode = src->distribution_mode;
+  err = pn_data_copy(terminus->properties, src->properties);
+  if (err) return err;
+  err = pn_data_copy(terminus->capabilities, src->capabilities);
+  if (err) return err;
+  err = pn_data_copy(terminus->outcomes, src->outcomes);
+  if (err) return err;
+  err = pn_data_copy(terminus->filter, src->filter);
+  if (err) return err;
+  return 0;
+}
+
+pn_link_t *pn_sender(pn_session_t *session, const char *name)
+{
+  return pn_link_new(SENDER, session, name);
+}
+
+pn_link_t *pn_receiver(pn_session_t *session, const char *name)
+{
+  return pn_link_new(RECEIVER, session, name);
+}
+
+pn_state_t pn_link_state(pn_link_t *link)
+{
+  return link->endpoint.state;
+}
+
+pn_error_t *pn_link_error(pn_link_t *link)
+{
+  return link->endpoint.error;
+}
+
+const char *pn_link_name(pn_link_t *link)
+{
+  assert(link);
+  return pn_string_get(link->name);
+}
+
+bool pn_link_is_sender(pn_link_t *link)
+{
+  return link->endpoint.type == SENDER;
+}
+
+bool pn_link_is_receiver(pn_link_t *link)
+{
+  return link->endpoint.type == RECEIVER;
+}
+
+pn_session_t *pn_link_session(pn_link_t *link)
+{
+  assert(link);
+  return link->session;
+}
+
+static void pn_disposition_finalize(pn_disposition_t *ds)
+{
+  pn_free(ds->data);
+  pn_free(ds->annotations);
+  pn_condition_tini(&ds->condition);
+}
+
+static void pn_delivery_incref(void *object)
+{
+  pn_delivery_t *delivery = (pn_delivery_t *) object;
+  if (delivery->link && !delivery->referenced) {
+    delivery->referenced = true;
+    pn_incref(delivery->link);
+  } else {
+    pn_object_incref(object);
+  }
+}
+
+static bool pni_preserve_delivery(pn_delivery_t *delivery)
+{
+  pn_connection_t *conn = delivery->link->session->connection;
+  return !delivery->local.settled || (conn->transport && (delivery->state.init || delivery->tpwork));
+}
+
+static void pn_delivery_finalize(void *object)
+{
+  pn_delivery_t *delivery = (pn_delivery_t *) object;
+  pn_link_t *link = delivery->link;
+  //  assert(!delivery->state.init);
+
+  bool pooled = false;
+  bool referenced = true;
+  if (link) {
+    if (pni_link_live(link) && pni_preserve_delivery(delivery) && delivery->referenced) {
+      delivery->referenced = false;
+      pn_object_incref(delivery);
+      pn_decref(link);
+      return;
+    }
+    referenced = delivery->referenced;
+
+    pn_clear_tpwork(delivery);
+    LL_REMOVE(link, unsettled, delivery);
+    pn_delivery_map_del(pn_link_is_sender(link)
+                        ? &link->session->state.outgoing
+                        : &link->session->state.incoming,
+                        delivery);
+    pn_buffer_clear(delivery->tag);
+    pn_buffer_clear(delivery->bytes);
+    pn_record_clear(delivery->context);
+    delivery->settled = true;
+    pn_connection_t *conn = link->session->connection;
+    assert(pn_refcount(delivery) == 0);
+    if (pni_connection_live(conn)) {
+      pn_list_t *pool = link->session->connection->delivery_pool;
+      delivery->link = NULL;
+      pn_list_add(pool, delivery);
+      pooled = true;
+      assert(pn_refcount(delivery) == 1);
+    }
+  }
+
+  if (!pooled) {
+    pn_free(delivery->context);
+    pn_buffer_free(delivery->tag);
+    pn_buffer_free(delivery->bytes);
+    pn_disposition_finalize(&delivery->local);
+    pn_disposition_finalize(&delivery->remote);
+  }
+
+  if (referenced) {
+    pn_decref(link);
+  }
+}
+
+static void pn_disposition_init(pn_disposition_t *ds)
+{
+  ds->data = pn_data(0);
+  ds->annotations = pn_data(0);
+  pn_condition_init(&ds->condition);
+}
+
+static void pn_disposition_clear(pn_disposition_t *ds)
+{
+  ds->type = 0;
+  ds->section_number = 0;
+  ds->section_offset = 0;
+  ds->failed = false;
+  ds->undeliverable = false;
+  ds->settled = false;
+  pn_data_clear(ds->data);
+  pn_data_clear(ds->annotations);
+  pn_condition_clear(&ds->condition);
+}
+
+#define pn_delivery_new pn_object_new
+#define pn_delivery_refcount pn_object_refcount
+#define pn_delivery_decref pn_object_decref
+#define pn_delivery_free pn_object_free
+#define pn_delivery_reify pn_object_reify
+#define pn_delivery_initialize NULL
+#define pn_delivery_hashcode NULL
+#define pn_delivery_compare NULL
+#define pn_delivery_inspect NULL
+
+pn_delivery_tag_t pn_dtag(const char *bytes, size_t size) {
+  pn_delivery_tag_t dtag = {size, bytes};
+  return dtag;
+}
+
+pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
+{
+  assert(link);
+  pn_list_t *pool = link->session->connection->delivery_pool;
+  pn_delivery_t *delivery = (pn_delivery_t *) pn_list_pop(pool);
+  if (!delivery) {
+    static const pn_class_t clazz = PN_METACLASS(pn_delivery);
+    delivery = (pn_delivery_t *) pn_class_new(&clazz, sizeof(pn_delivery_t));
+    if (!delivery) return NULL;
+    delivery->tag = pn_buffer(16);
+    delivery->bytes = pn_buffer(64);
+    pn_disposition_init(&delivery->local);
+    pn_disposition_init(&delivery->remote);
+    delivery->context = pn_record();
+  } else {
+    assert(!delivery->state.init);
+  }
+  delivery->link = link;
+  pn_incref(delivery->link);  // keep link until finalized
+  pn_buffer_clear(delivery->tag);
+  pn_buffer_append(delivery->tag, tag.start, tag.size);
+  pn_disposition_clear(&delivery->local);
+  pn_disposition_clear(&delivery->remote);
+  delivery->updated = false;
+  delivery->settled = false;
+  LL_ADD(link, unsettled, delivery);
+  delivery->referenced = true;
+  delivery->work_next = NULL;
+  delivery->work_prev = NULL;
+  delivery->work = false;
+  delivery->tpwork_next = NULL;
+  delivery->tpwork_prev = NULL;
+  delivery->tpwork = false;
+  pn_buffer_clear(delivery->bytes);
+  delivery->done = false;
+  pn_record_clear(delivery->context);
+
+  // begin delivery state
+  delivery->state.init = false;
+  delivery->state.sent = false;
+  // end delivery state
+
+  if (!link->current)
+    link->current = delivery;
+
+  link->unsettled_count++;
+
+  pn_work_update(link->session->connection, delivery);
+
+  // XXX: could just remove incref above
+  pn_decref(delivery);
+
+  return delivery;
+}
+
+bool pn_delivery_buffered(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  if (delivery->settled) return false;
+  if (pn_link_is_sender(delivery->link)) {
+    pn_delivery_state_t *state = &delivery->state;
+    if (state->sent) {
+      return false;
+    } else {
+      return delivery->done || (pn_buffer_size(delivery->bytes) > 0);
+    }
+  } else {
+    return false;
+  }
+}
+
+int pn_link_unsettled(pn_link_t *link)
+{
+  return link->unsettled_count;
+}
+
+pn_delivery_t *pn_unsettled_head(pn_link_t *link)
+{
+  pn_delivery_t *d = link->unsettled_head;
+  while (d && d->local.settled) {
+    d = d->unsettled_next;
+  }
+  return d;
+}
+
+pn_delivery_t *pn_unsettled_next(pn_delivery_t *delivery)
+{
+  pn_delivery_t *d = delivery->unsettled_next;
+  while (d && d->local.settled) {
+    d = d->unsettled_next;
+  }
+  return d;
+}
+
+bool pn_delivery_current(pn_delivery_t *delivery)
+{
+  pn_link_t *link = delivery->link;
+  return pn_link_current(link) == delivery;
+}
+
+void pn_delivery_dump(pn_delivery_t *d)
+{
+  char tag[1024];
+  pn_bytes_t bytes = pn_buffer_bytes(d->tag);
+  pn_quote_data(tag, 1024, bytes.start, bytes.size);
+  printf("{tag=%s, local.type=%" PRIu64 ", remote.type=%" PRIu64 ", local.settled=%u, "
+         "remote.settled=%u, updated=%u, current=%u, writable=%u, readable=%u, "
+         "work=%u}",
+         tag, d->local.type, d->remote.type, d->local.settled,
+         d->remote.settled, d->updated, pn_delivery_current(d),
+         pn_delivery_writable(d), pn_delivery_readable(d), d->work);
+}
+
+void *pn_delivery_get_context(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return pn_record_get(delivery->context, PN_LEGCTX);
+}
+
+void pn_delivery_set_context(pn_delivery_t *delivery, void *context)
+{
+  assert(delivery);
+  pn_record_set(delivery->context, PN_LEGCTX, context);
+}
+
+pn_record_t *pn_delivery_attachments(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return delivery->context;
+}
+
+uint64_t pn_disposition_type(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->type;
+}
+
+pn_data_t *pn_disposition_data(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->data;
+}
+
+uint32_t pn_disposition_get_section_number(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->section_number;
+}
+
+void pn_disposition_set_section_number(pn_disposition_t *disposition, uint32_t section_number)
+{
+  assert(disposition);
+  disposition->section_number = section_number;
+}
+
+uint64_t pn_disposition_get_section_offset(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->section_offset;
+}
+
+void pn_disposition_set_section_offset(pn_disposition_t *disposition, uint64_t section_offset)
+{
+  assert(disposition);
+  disposition->section_offset = section_offset;
+}
+
+bool pn_disposition_is_failed(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->failed;
+}
+
+void pn_disposition_set_failed(pn_disposition_t *disposition, bool failed)
+{
+  assert(disposition);
+  disposition->failed = failed;
+}
+
+bool pn_disposition_is_undeliverable(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->undeliverable;
+}
+
+void pn_disposition_set_undeliverable(pn_disposition_t *disposition, bool undeliverable)
+{
+  assert(disposition);
+  disposition->undeliverable = undeliverable;
+}
+
+pn_data_t *pn_disposition_annotations(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return disposition->annotations;
+}
+
+pn_condition_t *pn_disposition_condition(pn_disposition_t *disposition)
+{
+  assert(disposition);
+  return &disposition->condition;
+}
+
+pn_delivery_tag_t pn_delivery_tag(pn_delivery_t *delivery)
+{
+  if (delivery) {
+    pn_bytes_t tag = pn_buffer_bytes(delivery->tag);
+    return pn_dtag(tag.start, tag.size);
+  } else {
+    return pn_dtag(0, 0);
+  }
+}
+
+pn_delivery_t *pn_link_current(pn_link_t *link)
+{
+  if (!link) return NULL;
+  return link->current;
+}
+
+static void pni_advance_sender(pn_link_t *link)
+{
+  link->current->done = true;
+  link->queued++;
+  link->credit--;
+  link->session->outgoing_deliveries++;
+  pni_add_tpwork(link->current);
+  link->current = link->current->unsettled_next;
+}
+
+static void pni_advance_receiver(pn_link_t *link)
+{
+  link->credit--;
+  link->queued--;
+  link->session->incoming_deliveries--;
+
+  pn_delivery_t *current = link->current;
+  link->session->incoming_bytes -= pn_buffer_size(current->bytes);
+  pn_buffer_clear(current->bytes);
+
+  if (!link->session->state.incoming_window) {
+    pni_add_tpwork(current);
+  }
+
+  link->current = link->current->unsettled_next;
+}
+
+bool pn_link_advance(pn_link_t *link)
+{
+  if (link && link->current) {
+    pn_delivery_t *prev = link->current;
+    if (link->endpoint.type == SENDER) {
+      pni_advance_sender(link);
+    } else {
+      pni_advance_receiver(link);
+    }
+    pn_delivery_t *next = link->current;
+    pn_work_update(link->session->connection, prev);
+    if (next) pn_work_update(link->session->connection, next);
+    return prev != next;
+  } else {
+    return false;
+  }
+}
+
+int pn_link_credit(pn_link_t *link)
+{
+  return link ? link->credit : 0;
+}
+
+int pn_link_available(pn_link_t *link)
+{
+  return link ? link->available : 0;
+}
+
+int pn_link_queued(pn_link_t *link)
+{
+  return link ? link->queued : 0;
+}
+
+int pn_link_remote_credit(pn_link_t *link)
+{
+  assert(link);
+  return link->credit - link->queued;
+}
+
+bool pn_link_get_drain(pn_link_t *link)
+{
+  assert(link);
+  return link->drain;
+}
+
+pn_snd_settle_mode_t pn_link_snd_settle_mode(pn_link_t *link)
+{
+  return link ? (pn_snd_settle_mode_t)link->snd_settle_mode
+      : PN_SND_MIXED;
+}
+
+pn_rcv_settle_mode_t pn_link_rcv_settle_mode(pn_link_t *link)
+{
+  return link ? (pn_rcv_settle_mode_t)link->rcv_settle_mode
+      : PN_RCV_FIRST;
+}
+
+pn_snd_settle_mode_t pn_link_remote_snd_settle_mode(pn_link_t *link)
+{
+  return link ? (pn_snd_settle_mode_t)link->remote_snd_settle_mode
+      : PN_SND_MIXED;
+}
+
+pn_rcv_settle_mode_t pn_link_remote_rcv_settle_mode(pn_link_t *link)
+{
+  return link ? (pn_rcv_settle_mode_t)link->remote_rcv_settle_mode
+      : PN_RCV_FIRST;
+}
+void pn_link_set_snd_settle_mode(pn_link_t *link, pn_snd_settle_mode_t mode)
+{
+  if (link)
+    link->snd_settle_mode = (uint8_t)mode;
+}
+void pn_link_set_rcv_settle_mode(pn_link_t *link, pn_rcv_settle_mode_t mode)
+{
+  if (link)
+    link->rcv_settle_mode = (uint8_t)mode;
+}
+
+void pn_delivery_settle(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  if (!delivery->local.settled) {
+    pn_link_t *link = delivery->link;
+    if (pn_delivery_current(delivery)) {
+      pn_link_advance(link);
+    }
+
+    link->unsettled_count--;
+    delivery->local.settled = true;
+    pni_add_tpwork(delivery);
+    pn_work_update(delivery->link->session->connection, delivery);
+    pn_incref(delivery);
+    pn_decref(delivery);
+  }
+}
+
+void pn_link_offered(pn_link_t *sender, int credit)
+{
+  sender->available = credit;
+}
+
+ssize_t pn_link_send(pn_link_t *sender, const char *bytes, size_t n)
+{
+  pn_delivery_t *current = pn_link_current(sender);
+  if (!current) return PN_EOS;
+  if (!bytes || !n) return 0;
+  pn_buffer_append(current->bytes, bytes, n);
+  sender->session->outgoing_bytes += n;
+  pni_add_tpwork(current);
+  return n;
+}
+
+int pn_link_drained(pn_link_t *link)
+{
+  assert(link);
+  int drained = 0;
+
+  if (pn_link_is_sender(link)) {
+    if (link->drain && link->credit > 0) {
+      link->drained = link->credit;
+      link->credit = 0;
+      pn_modified(link->session->connection, &link->endpoint, true);
+      drained = link->drained;
+    }
+  } else {
+    drained = link->drained;
+    link->drained = 0;
+  }
+
+  return drained;
+}
+
+ssize_t pn_link_recv(pn_link_t *receiver, char *bytes, size_t n)
+{
+  if (!receiver) return PN_ARG_ERR;
+
+  pn_delivery_t *delivery = receiver->current;
+  if (delivery) {
+    size_t size = pn_buffer_get(delivery->bytes, 0, n, bytes);
+    pn_buffer_trim(delivery->bytes, size, 0);
+    if (size) {
+      receiver->session->incoming_bytes -= size;
+      if (!receiver->session->state.incoming_window) {
+        pni_add_tpwork(delivery);
+      }
+      return size;
+    } else {
+      return delivery->done ? PN_EOS : 0;
+    }
+  } else {
+    return PN_STATE_ERR;
+  }
+}
+
+void pn_link_flow(pn_link_t *receiver, int credit)
+{
+  assert(receiver);
+  assert(pn_link_is_receiver(receiver));
+  receiver->credit += credit;
+  pn_modified(receiver->session->connection, &receiver->endpoint, true);
+  if (!receiver->drain_flag_mode) {
+    pn_link_set_drain(receiver, false);
+    receiver->drain_flag_mode = false;
+  }
+}
+
+void pn_link_drain(pn_link_t *receiver, int credit)
+{
+  assert(receiver);
+  assert(pn_link_is_receiver(receiver));
+  pn_link_set_drain(receiver, true);
+  pn_link_flow(receiver, credit);
+  receiver->drain_flag_mode = false;
+}
+
+void pn_link_set_drain(pn_link_t *receiver, bool drain)
+{
+  assert(receiver);
+  assert(pn_link_is_receiver(receiver));
+  receiver->drain = drain;
+  pn_modified(receiver->session->connection, &receiver->endpoint, true);
+  receiver->drain_flag_mode = true;
+}
+
+bool pn_link_draining(pn_link_t *receiver)
+{
+  assert(receiver);
+  assert(pn_link_is_receiver(receiver));
+  return receiver->drain && (pn_link_credit(receiver) > pn_link_queued(receiver));
+}
+
+pn_link_t *pn_delivery_link(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return delivery->link;
+}
+
+pn_disposition_t *pn_delivery_local(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return &delivery->local;
+}
+
+uint64_t pn_delivery_local_state(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return delivery->local.type;
+}
+
+pn_disposition_t *pn_delivery_remote(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return &delivery->remote;
+}
+
+uint64_t pn_delivery_remote_state(pn_delivery_t *delivery)
+{
+  assert(delivery);
+  return delivery->remote.type;
+}
+
+bool pn_delivery_settled(pn_delivery_t *delivery)
+{
+  return delivery ? delivery->remote.settled : false;
+}
+
+bool pn_delivery_updated(pn_delivery_t *delivery)
+{
+  return delivery ? delivery->updated : false;
+}
+
+void pn_delivery_clear(pn_delivery_t *delivery)
+{
+  delivery->updated = false;
+  pn_work_update(delivery->link->session->connection, delivery);
+}
+
+void pn_delivery_update(pn_delivery_t *delivery, uint64_t state)
+{
+  if (!delivery) return;
+  delivery->local.type = state;
+  pni_add_tpwork(delivery);
+}
+
+bool pn_delivery_writable(pn_delivery_t *delivery)
+{
+  if (!delivery) return false;
+
+  pn_link_t *link = delivery->link;
+  return pn_link_is_sender(link) && pn_delivery_current(delivery) && pn_link_credit(link) > 0;
+}
+
+bool pn_delivery_readable(pn_delivery_t *delivery)
+{
+  if (delivery) {
+    pn_link_t *link = delivery->link;
+    return pn_link_is_receiver(link) && pn_delivery_current(delivery);
+  } else {
+    return false;
+  }
+}
+
+size_t pn_delivery_pending(pn_delivery_t *delivery)
+{
+  return pn_buffer_size(delivery->bytes);
+}
+
+bool pn_delivery_partial(pn_delivery_t *delivery)
+{
+  return !delivery->done;
+}
+
+pn_condition_t *pn_connection_condition(pn_connection_t *connection)
+{
+  assert(connection);
+  return &connection->endpoint.condition;
+}
+
+pn_condition_t *pn_connection_remote_condition(pn_connection_t *connection)
+{
+  assert(connection);
+  pn_transport_t *transport = connection->transport;
+  return transport ? &transport->remote_condition : NULL;
+}
+
+pn_condition_t *pn_session_condition(pn_session_t *session)
+{
+  assert(session);
+  return &session->endpoint.condition;
+}
+
+pn_condition_t *pn_session_remote_condition(pn_session_t *session)
+{
+  assert(session);
+  return &session->endpoint.remote_condition;
+}
+
+pn_condition_t *pn_link_condition(pn_link_t *link)
+{
+  assert(link);
+  return &link->endpoint.condition;
+}
+
+pn_condition_t *pn_link_remote_condition(pn_link_t *link)
+{
+  assert(link);
+  return &link->endpoint.remote_condition;
+}
+
+bool pn_condition_is_set(pn_condition_t *condition)
+{
+  return condition && pn_string_get(condition->name);
+}
+
+void pn_condition_clear(pn_condition_t *condition)
+{
+  assert(condition);
+  pn_string_clear(condition->name);
+  pn_string_clear(condition->description);
+  pn_data_clear(condition->info);
+}
+
+const char *pn_condition_get_name(pn_condition_t *condition)
+{
+  assert(condition);
+  return pn_string_get(condition->name);
+}
+
+int pn_condition_set_name(pn_condition_t *condition, const char *name)
+{
+  assert(condition);
+  return pn_string_set(condition->name, name);
+}
+
+const char *pn_condition_get_description(pn_condition_t *condition)
+{
+  assert(condition);
+  return pn_string_get(condition->description);
+}
+
+int pn_condition_set_description(pn_condition_t *condition, const char *description)
+{
+  assert(condition);
+  return pn_string_set(condition->description, description);
+}
+
+int pn_condition_vformat(pn_condition_t *condition, const char *name, const char *fmt, va_list ap)
+{
+  assert(condition);
+  int err = pn_condition_set_name(condition, name);
+  if (err)
+      return err;
+
+  char text[1024];
+  size_t n = pni_vsnprintf(text, 1024, fmt, ap);
+  if (n >= sizeof(text))
+      text[sizeof(text)-1] = '\0';
+  err = pn_condition_set_description(condition, text);
+  return err;
+}
+
+int pn_condition_format(pn_condition_t *condition, const char *name, const char *fmt, ...)
+{
+  assert(condition);
+  va_list ap;
+  va_start(ap, fmt);
+  int err = pn_condition_vformat(condition, name, fmt, ap);
+  va_end(ap);
+  return err;
+}
+
+pn_data_t *pn_condition_info(pn_condition_t *condition)
+{
+  assert(condition);
+  return condition->info;
+}
+
+bool pn_condition_is_redirect(pn_condition_t *condition)
+{
+  const char *name = pn_condition_get_name(condition);
+  return name && (!strcmp(name, "amqp:connection:redirect") ||
+                  !strcmp(name, "amqp:link:redirect"));
+}
+
+const char *pn_condition_redirect_host(pn_condition_t *condition)
+{
+  pn_data_t *data = pn_condition_info(condition);
+  pn_data_rewind(data);
+  pn_data_next(data);
+  pn_data_enter(data);
+  pn_data_lookup(data, "network-host");
+  pn_bytes_t host = pn_data_get_bytes(data);
+  pn_data_rewind(data);
+  return host.start;
+}
+
+int pn_condition_redirect_port(pn_condition_t *condition)
+{
+  pn_data_t *data = pn_condition_info(condition);
+  pn_data_rewind(data);
+  pn_data_next(data);
+  pn_data_enter(data);
+  pn_data_lookup(data, "port");
+  int port = pn_data_get_int(data);
+  pn_data_rewind(data);
+  return port;
+}
+
+pn_connection_t *pn_event_connection(pn_event_t *event)
+{
+  pn_session_t *ssn;
+  pn_transport_t *transport;
+
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_connection:
+    return (pn_connection_t *) pn_event_context(event);
+  case CID_pn_transport:
+    transport = pn_event_transport(event);
+    if (transport)
+      return transport->connection;
+    return NULL;
+  default:
+    ssn = pn_event_session(event);
+    if (ssn)
+     return pn_session_connection(ssn);
+  }
+  return NULL;
+}
+
+pn_session_t *pn_event_session(pn_event_t *event)
+{
+  pn_link_t *link;
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_session:
+    return (pn_session_t *) pn_event_context(event);
+  default:
+    link = pn_event_link(event);
+    if (link)
+      return pn_link_session(link);
+  }
+  return NULL;
+}
+
+pn_link_t *pn_event_link(pn_event_t *event)
+{
+  pn_delivery_t *dlv;
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_link:
+    return (pn_link_t *) pn_event_context(event);
+  default:
+    dlv = pn_event_delivery(event);
+    if (dlv)
+      return pn_delivery_link(dlv);
+  }
+  return NULL;
+}
+
+pn_delivery_t *pn_event_delivery(pn_event_t *event)
+{
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_delivery:
+    return (pn_delivery_t *) pn_event_context(event);
+  default:
+    return NULL;
+  }
+}
+
+pn_transport_t *pn_event_transport(pn_event_t *event)
+{
+  switch (pn_class_id(pn_event_class(event))) {
+  case CID_pn_transport:
+    return (pn_transport_t *) pn_event_context(event);
+  default:
+    {
+      pn_connection_t *conn = pn_event_connection(event);
+      if (conn)
+        return pn_connection_transport(conn);
+      return NULL;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/error.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/error.c b/proton-c/src/core/error.c
new file mode 100644
index 0000000..70d36fa
--- /dev/null
+++ b/proton-c/src/core/error.c
@@ -0,0 +1,136 @@
+/*
+ *
+ * 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 "platform/platform.h"
+#include "util.h"
+
+#include <proton/error.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct pn_error_t {
+  char *text;
+  pn_error_t *root;
+  int code;
+};
+
+pn_error_t *pn_error()
+{
+  pn_error_t *error = (pn_error_t *) malloc(sizeof(pn_error_t));
+  if (error != NULL) {
+    error->code = 0;
+    error->text = NULL;
+    error->root = NULL;
+  }
+  return error;
+}
+
+void pn_error_free(pn_error_t *error)
+{
+  if (error) {
+    free(error->text);
+    free(error);
+  }
+}
+
+void pn_error_clear(pn_error_t *error)
+{
+  if (error) {
+    error->code = 0;
+    free(error->text);
+    error->text = NULL;
+    error->root = NULL;
+  }
+}
+
+int pn_error_set(pn_error_t *error, int code, const char *text)
+{
+  assert(error);
+  pn_error_clear(error);
+  if (code) {
+    error->code = code;
+    error->text = pn_strdup(text);
+  }
+  return code;
+}
+
+int pn_error_vformat(pn_error_t *error, int code, const char *fmt, va_list ap)
+{
+  assert(error);
+  char text[1024];
+  int n = pni_vsnprintf(text, 1024, fmt, ap);
+  if (n >= 1024) {
+    text[1023] = '\0';
+  }
+  return pn_error_set(error, code, text);
+}
+
+int pn_error_format(pn_error_t *error, int code, const char *fmt, ...)
+{
+  assert(error);
+  va_list ap;
+  va_start(ap, fmt);
+  int rcode = pn_error_vformat(error, code, fmt, ap);
+  va_end(ap);
+  return rcode;
+}
+
+int pn_error_code(pn_error_t *error)
+{
+  assert(error);
+  return error->code;
+}
+
+const char *pn_error_text(pn_error_t *error)
+{
+  assert(error);
+  return error->text;
+}
+
+int pn_error_copy(pn_error_t *error, pn_error_t *src)
+{
+  assert(error);
+  if (src) {
+    return pn_error_set(error, pn_error_code(src), pn_error_text(src));
+  } else {
+    pn_error_clear(error);
+    return 0;
+  }
+}
+
+const char *pn_code(int code)
+{
+  switch (code)
+  {
+  case 0: return "<ok>";
+  case PN_EOS: return "PN_EOS";
+  case PN_ERR: return "PN_ERR";
+  case PN_OVERFLOW: return "PN_OVERFLOW";
+  case PN_UNDERFLOW: return "PN_UNDERFLOW";
+  case PN_STATE_ERR: return "PN_STATE_ERR";
+  case PN_ARG_ERR: return "PN_ARG_ERR";
+  case PN_TIMEOUT: return "PN_TIMEOUT";
+  case PN_INTR: return "PN_INTR";
+  case PN_OUT_OF_MEMORY: return "PN_OUT_OF_MEMORY";
+  default: return "<unknown>";
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/event.c b/proton-c/src/core/event.c
new file mode 100644
index 0000000..c13f287
--- /dev/null
+++ b/proton-c/src/core/event.c
@@ -0,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.
+ *
+ */
+#include <stdio.h>
+#include <proton/object.h>
+#include <proton/event.h>
+#include <proton/reactor.h>
+#include <assert.h>
+
+struct pn_collector_t {
+  pn_list_t *pool;
+  pn_event_t *head;
+  pn_event_t *tail;
+  bool freed;
+};
+
+struct pn_event_t {
+  pn_list_t *pool;
+  const pn_class_t *clazz;
+  void *context;    // depends on clazz
+  pn_record_t *attachments;
+  pn_event_t *next;
+  pn_event_type_t type;
+};
+
+static void pn_collector_initialize(pn_collector_t *collector)
+{
+  collector->pool = pn_list(PN_OBJECT, 0);
+  collector->head = NULL;
+  collector->tail = NULL;
+  collector->freed = false;
+}
+
+static void pn_collector_drain(pn_collector_t *collector)
+{
+  assert(collector);
+
+  while (pn_collector_peek(collector)) {
+    pn_collector_pop(collector);
+  }
+
+  assert(!collector->head);
+  assert(!collector->tail);
+}
+
+static void pn_collector_shrink(pn_collector_t *collector)
+{
+  assert(collector);
+  pn_list_clear(collector->pool);
+}
+
+static void pn_collector_finalize(pn_collector_t *collector)
+{
+  pn_collector_drain(collector);
+  pn_decref(collector->pool);
+}
+
+static int pn_collector_inspect(pn_collector_t *collector, pn_string_t *dst)
+{
+  assert(collector);
+  int err = pn_string_addf(dst, "EVENTS[");
+  if (err) return err;
+  pn_event_t *event = collector->head;
+  bool first = true;
+  while (event) {
+    if (first) {
+      first = false;
+    } else {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_inspect(event, dst);
+    if (err) return err;
+    event = event->next;
+  }
+  return pn_string_addf(dst, "]");
+}
+
+#define pn_collector_hashcode NULL
+#define pn_collector_compare NULL
+
+PN_CLASSDEF(pn_collector)
+
+pn_collector_t *pn_collector(void)
+{
+  return pn_collector_new();
+}
+
+void pn_collector_free(pn_collector_t *collector)
+{
+  assert(collector);
+  pn_collector_release(collector);
+  pn_decref(collector);
+}
+
+void pn_collector_release(pn_collector_t *collector)
+{
+  assert(collector);
+  if (!collector->freed) {
+    collector->freed = true;
+    pn_collector_drain(collector);
+    pn_collector_shrink(collector);
+  }
+}
+
+pn_event_t *pn_event(void);
+
+pn_event_t *pn_collector_put(pn_collector_t *collector,
+                             const pn_class_t *clazz, void *context,
+                             pn_event_type_t type)
+{
+  if (!collector) {
+    return NULL;
+  }
+
+  assert(context);
+
+  if (collector->freed) {
+    return NULL;
+  }
+
+  pn_event_t *tail = collector->tail;
+  if (tail && tail->type == type && tail->context == context) {
+    return NULL;
+  }
+
+  clazz = clazz->reify(context);
+
+  pn_event_t *event = (pn_event_t *) pn_list_pop(collector->pool);
+
+  if (!event) {
+    event = pn_event();
+  }
+
+  event->pool = collector->pool;
+  pn_incref(event->pool);
+
+  if (tail) {
+    tail->next = event;
+    collector->tail = event;
+  } else {
+    collector->tail = event;
+    collector->head = event;
+  }
+
+  event->clazz = clazz;
+  event->context = context;
+  event->type = type;
+  pn_class_incref(clazz, event->context);
+
+  return event;
+}
+
+pn_event_t *pn_collector_peek(pn_collector_t *collector)
+{
+  return collector->head;
+}
+
+bool pn_collector_pop(pn_collector_t *collector)
+{
+  pn_event_t *event = collector->head;
+  if (event) {
+    collector->head = event->next;
+  } else {
+    return false;
+  }
+
+  if (!collector->head) {
+    collector->tail = NULL;
+  }
+
+  pn_decref(event);
+  return true;
+}
+
+bool pn_collector_more(pn_collector_t *collector)
+{
+  assert(collector);
+  return collector->head && collector->head->next;
+}
+
+static void pn_event_initialize(pn_event_t *event)
+{
+  event->pool = NULL;
+  event->type = PN_EVENT_NONE;
+  event->clazz = NULL;
+  event->context = NULL;
+  event->next = NULL;
+  event->attachments = pn_record();
+}
+
+static void pn_event_finalize(pn_event_t *event) {
+  // decref before adding to the free list
+  if (event->clazz && event->context) {
+    pn_class_decref(event->clazz, event->context);
+  }
+
+  pn_list_t *pool = event->pool;
+
+  if (pool && pn_refcount(pool) > 1) {
+    event->pool = NULL;
+    event->type = PN_EVENT_NONE;
+    event->clazz = NULL;
+    event->context = NULL;
+    event->next = NULL;
+    pn_record_clear(event->attachments);
+    pn_list_add(pool, event);
+  } else {
+    pn_decref(event->attachments);
+  }
+
+  pn_decref(pool);
+}
+
+static int pn_event_inspect(pn_event_t *event, pn_string_t *dst)
+{
+  assert(event);
+  assert(dst);
+  const char *name = pn_event_type_name(event->type);
+  int err;
+  if (name) {
+    err = pn_string_addf(dst, "(%s", pn_event_type_name(event->type));
+  } else {
+    err = pn_string_addf(dst, "(<%u>", (unsigned int) event->type);
+  }
+  if (err) return err;
+  if (event->context) {
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    err = pn_class_inspect(event->clazz, event->context, dst);
+    if (err) return err;
+  }
+
+  return pn_string_addf(dst, ")");
+}
+
+#define pn_event_hashcode NULL
+#define pn_event_compare NULL
+
+PN_CLASSDEF(pn_event)
+
+pn_event_t *pn_event(void)
+{
+  return pn_event_new();
+}
+
+pn_event_type_t pn_event_type(pn_event_t *event)
+{
+  return event->type;
+}
+
+const pn_class_t *pn_event_class(pn_event_t *event)
+{
+  assert(event);
+  return event->clazz;
+}
+
+void *pn_event_context(pn_event_t *event)
+{
+  assert(event);
+  return event->context;
+}
+
+pn_record_t *pn_event_attachments(pn_event_t *event)
+{
+  assert(event);
+  return event->attachments;
+}
+
+const char *pn_event_type_name(pn_event_type_t type)
+{
+  switch (type) {
+  case PN_EVENT_NONE:
+    return "PN_EVENT_NONE";
+  case PN_REACTOR_INIT:
+    return "PN_REACTOR_INIT";
+  case PN_REACTOR_QUIESCED:
+    return "PN_REACTOR_QUIESCED";
+  case PN_REACTOR_FINAL:
+    return "PN_REACTOR_FINAL";
+  case PN_TIMER_TASK:
+    return "PN_TIMER_TASK";
+  case PN_CONNECTION_INIT:
+    return "PN_CONNECTION_INIT";
+  case PN_CONNECTION_BOUND:
+    return "PN_CONNECTION_BOUND";
+  case PN_CONNECTION_UNBOUND:
+    return "PN_CONNECTION_UNBOUND";
+  case PN_CONNECTION_REMOTE_OPEN:
+    return "PN_CONNECTION_REMOTE_OPEN";
+  case PN_CONNECTION_LOCAL_OPEN:
+    return "PN_CONNECTION_LOCAL_OPEN";
+  case PN_CONNECTION_REMOTE_CLOSE:
+    return "PN_CONNECTION_REMOTE_CLOSE";
+  case PN_CONNECTION_LOCAL_CLOSE:
+    return "PN_CONNECTION_LOCAL_CLOSE";
+  case PN_CONNECTION_FINAL:
+    return "PN_CONNECTION_FINAL";
+  case PN_SESSION_INIT:
+    return "PN_SESSION_INIT";
+  case PN_SESSION_REMOTE_OPEN:
+    return "PN_SESSION_REMOTE_OPEN";
+  case PN_SESSION_LOCAL_OPEN:
+    return "PN_SESSION_LOCAL_OPEN";
+  case PN_SESSION_REMOTE_CLOSE:
+    return "PN_SESSION_REMOTE_CLOSE";
+  case PN_SESSION_LOCAL_CLOSE:
+    return "PN_SESSION_LOCAL_CLOSE";
+  case PN_SESSION_FINAL:
+    return "PN_SESSION_FINAL";
+  case PN_LINK_INIT:
+    return "PN_LINK_INIT";
+  case PN_LINK_REMOTE_OPEN:
+    return "PN_LINK_REMOTE_OPEN";
+  case PN_LINK_LOCAL_OPEN:
+    return "PN_LINK_LOCAL_OPEN";
+  case PN_LINK_REMOTE_CLOSE:
+    return "PN_LINK_REMOTE_CLOSE";
+  case PN_LINK_LOCAL_DETACH:
+    return "PN_LINK_LOCAL_DETACH";
+  case PN_LINK_REMOTE_DETACH:
+    return "PN_LINK_REMOTE_DETACH";
+  case PN_LINK_LOCAL_CLOSE:
+    return "PN_LINK_LOCAL_CLOSE";
+  case PN_LINK_FLOW:
+    return "PN_LINK_FLOW";
+  case PN_LINK_FINAL:
+    return "PN_LINK_FINAL";
+  case PN_DELIVERY:
+    return "PN_DELIVERY";
+  case PN_TRANSPORT:
+    return "PN_TRANSPORT";
+  case PN_TRANSPORT_AUTHENTICATED:
+    return "PN_TRANSPORT_AUTHENTICATED";
+  case PN_TRANSPORT_ERROR:
+    return "PN_TRANSPORT_ERROR";
+  case PN_TRANSPORT_HEAD_CLOSED:
+    return "PN_TRANSPORT_HEAD_CLOSED";
+  case PN_TRANSPORT_TAIL_CLOSED:
+    return "PN_TRANSPORT_TAIL_CLOSED";
+  case PN_TRANSPORT_CLOSED:
+    return "PN_TRANSPORT_CLOSED";
+  case PN_SELECTABLE_INIT:
+    return "PN_SELECTABLE_INIT";
+  case PN_SELECTABLE_UPDATED:
+    return "PN_SELECTABLE_UPDATED";
+  case PN_SELECTABLE_READABLE:
+    return "PN_SELECTABLE_READABLE";
+  case PN_SELECTABLE_WRITABLE:
+    return "PN_SELECTABLE_WRITABLE";
+  case PN_SELECTABLE_ERROR:
+    return "PN_SELECTABLE_ERROR";
+  case PN_SELECTABLE_EXPIRED:
+    return "PN_SELECTABLE_EXPIRED";
+  case PN_SELECTABLE_FINAL:
+    return "PN_SELECTABLE_FINAL";
+  }
+
+  return NULL;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/framing.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/framing.c b/proton-c/src/core/framing.c
new file mode 100644
index 0000000..09bf4bb
--- /dev/null
+++ b/proton-c/src/core/framing.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "framing.h"
+
+// TODO: These are near duplicates of code in codec.c - they should be
+// deduplicated.
+static inline void pn_i_write16(char *bytes, uint16_t value)
+{
+    bytes[0] = 0xFF & (value >> 8);
+    bytes[1] = 0xFF & (value     );
+}
+
+
+static inline void pn_i_write32(char *bytes, uint32_t value)
+{
+    bytes[0] = 0xFF & (value >> 24);
+    bytes[1] = 0xFF & (value >> 16);
+    bytes[2] = 0xFF & (value >>  8);
+    bytes[3] = 0xFF & (value      );
+}
+
+static inline uint16_t pn_i_read16(const char *bytes)
+{
+    uint16_t a = (uint8_t) bytes[0];
+    uint16_t b = (uint8_t) bytes[1];
+    uint16_t r = a << 8
+    | b;
+    return r;
+}
+
+static inline uint32_t pn_i_read32(const char *bytes)
+{
+    uint32_t a = (uint8_t) bytes[0];
+    uint32_t b = (uint8_t) bytes[1];
+    uint32_t c = (uint8_t) bytes[2];
+    uint32_t d = (uint8_t) bytes[3];
+    uint32_t r = a << 24
+    | b << 16
+    | c <<  8
+    | d;
+    return r;
+}
+
+
+ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max)
+{
+  if (available < AMQP_HEADER_SIZE) return 0;
+  uint32_t size = pn_i_read32(&bytes[0]);
+  if (max && size > max) return PN_ERR;
+  if (available < size) return 0;
+  unsigned int doff = 4 * (uint8_t)bytes[4];
+  if (doff < AMQP_HEADER_SIZE || doff > size) return PN_ERR;
+
+  frame->size = size - doff;
+  frame->ex_size = doff - AMQP_HEADER_SIZE;
+  frame->type = bytes[5];
+  frame->channel = pn_i_read16(&bytes[6]);
+  frame->extended = bytes + AMQP_HEADER_SIZE;
+  frame->payload = bytes + doff;
+
+  return size;
+}
+
+size_t pn_write_frame(char *bytes, size_t available, pn_frame_t frame)
+{
+  size_t size = AMQP_HEADER_SIZE + frame.ex_size + frame.size;
+  if (size <= available)
+  {
+    pn_i_write32(&bytes[0], size);
+    int doff = (frame.ex_size + AMQP_HEADER_SIZE - 1)/4 + 1;
+    bytes[4] = doff;
+    bytes[5] = frame.type;
+    pn_i_write16(&bytes[6], frame.channel);
+
+    memmove(bytes + AMQP_HEADER_SIZE, frame.extended, frame.ex_size);
+    memmove(bytes + 4*doff, frame.payload, frame.size);
+    return size;
+  } else {
+    return 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/framing.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/framing.h b/proton-c/src/core/framing.h
new file mode 100644
index 0000000..ecb88a4
--- /dev/null
+++ b/proton-c/src/core/framing.h
@@ -0,0 +1,44 @@
+#ifndef PROTON_FRAMING_H
+#define PROTON_FRAMING_H 1
+
+/*
+ *
+ * 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/import_export.h>
+#include <proton/type_compat.h>
+#include <proton/error.h>
+
+#define AMQP_HEADER_SIZE (8)
+#define AMQP_MIN_MAX_FRAME_SIZE ((uint32_t)512) // minimum allowable max-frame
+
+typedef struct {
+  uint8_t type;
+  uint16_t channel;
+  size_t ex_size;
+  const char *extended;
+  size_t size;
+  const char *payload;
+} pn_frame_t;
+
+ssize_t pn_read_frame(pn_frame_t *frame, const char *bytes, size_t available, uint32_t max);
+size_t pn_write_frame(char *bytes, size_t size, pn_frame_t frame);
+
+#endif /* framing.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/log.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/log.c b/proton-c/src/core/log.c
new file mode 100644
index 0000000..ff96ff0
--- /dev/null
+++ b/proton-c/src/core/log.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/log.h>
+#include <proton/object.h>
+#include <stdio.h>
+#include "log_private.h"
+#include "util.h"
+
+
+static void stderr_logger(const char *message) {
+    fprintf(stderr, "%s\n", message);
+}
+
+static pn_logger_t logger = stderr_logger;
+static int enabled_env  = -1;   /* Set from environment variable. */
+static int enabled_call = -1;   /* set by pn_log_enable */
+
+void pn_log_enable(bool value) {
+    enabled_call = value;
+}
+
+bool pn_log_enabled(void) {
+    if (enabled_call != -1) return enabled_call; /* Takes precedence */
+    if (enabled_env == -1) 
+        enabled_env = pn_env_bool("PN_TRACE_LOG");
+    return enabled_env;
+}
+
+void pn_log_logger(pn_logger_t new_logger) {
+    logger = new_logger;
+    if (!logger) pn_log_enable(false);
+}
+
+void pn_vlogf_impl(const char *fmt, va_list ap) {
+    pn_string_t *msg = pn_string("");
+    pn_string_vformat(msg, fmt, ap);
+    fprintf(stderr, "%s\n", pn_string_get(msg));
+}
+
+/**@internal
+ *
+ * Note: We check pn_log_enabled() in the pn_logf macro *before* calling
+ * pn_logf_impl because evaluating the arguments to that call could have
+ * side-effects with performance impact (e.g. calling functions to construct
+ * complicated messages.) It is important that a disabled log statement results
+ * in nothing more than a call to pn_log_enabled().
+ */
+void pn_logf_impl(const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  pn_vlogf_impl(fmt, ap);
+  va_end(ap);
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/log_private.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/log_private.h b/proton-c/src/core/log_private.h
new file mode 100644
index 0000000..4725045
--- /dev/null
+++ b/proton-c/src/core/log_private.h
@@ -0,0 +1,54 @@
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_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.
+ */
+
+/**@file
+ *
+ * Log messages that are not associated with a transport.
+ */
+
+#include <proton/log.h>
+#include <stdarg.h>
+
+/** Log a printf style message */
+#define pn_logf(...)                            \
+    do {                                        \
+        if (pn_log_enabled())                   \
+            pn_logf_impl(__VA_ARGS__);          \
+    } while(0)
+
+/** va_list version of pn_logf */
+#define pn_vlogf(fmt, ap)                       \
+    do {                                        \
+        if (pn_log_enabled())                   \
+            pn_vlogf_impl(fmt, ap);             \
+    } while(0)
+
+/** Return true if logging is enabled. */
+bool pn_log_enabled(void);
+
+/**@internal*/
+void pn_logf_impl(const char* fmt, ...);
+/**@internal*/
+void pn_vlogf_impl(const char *fmt, va_list ap);
+
+
+
+#endif


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


[17/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/encoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encoder.c b/proton-c/src/codec/encoder.c
deleted file mode 100644
index f8145fc..0000000
--- a/proton-c/src/codec/encoder.c
+++ /dev/null
@@ -1,383 +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/error.h>
-#include <proton/object.h>
-#include <proton/codec.h>
-#include "encodings.h"
-#include "encoder.h"
-
-#include <string.h>
-
-#include "data.h"
-
-struct pn_encoder_t {
-  char *output;
-  size_t size;
-  char *position;
-  pn_error_t *error;
-};
-
-static void pn_encoder_initialize(void *obj)
-{
-  pn_encoder_t *encoder = (pn_encoder_t *) obj;
-  encoder->output = NULL;
-  encoder->size = 0;
-  encoder->position = NULL;
-  encoder->error = pn_error();
-}
-
-static void pn_encoder_finalize(void *obj) {
-  pn_encoder_t *encoder = (pn_encoder_t *) obj;
-  pn_error_free(encoder->error);
-}
-
-#define pn_encoder_hashcode NULL
-#define pn_encoder_compare NULL
-#define pn_encoder_inspect NULL
-
-pn_encoder_t *pn_encoder()
-{
-  static const pn_class_t clazz = PN_CLASS(pn_encoder);
-  return (pn_encoder_t *) pn_class_new(&clazz, sizeof(pn_encoder_t));
-}
-
-static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type)
-{
-  switch (type)
-  {
-  case PN_NULL: return PNE_NULL;
-  case PN_BOOL: return PNE_BOOLEAN;
-  case PN_UBYTE: return PNE_UBYTE;
-  case PN_BYTE: return PNE_BYTE;
-  case PN_USHORT: return PNE_USHORT;
-  case PN_SHORT: return PNE_SHORT;
-  case PN_UINT: return PNE_UINT;
-  case PN_INT: return PNE_INT;
-  case PN_CHAR: return PNE_UTF32;
-  case PN_FLOAT: return PNE_FLOAT;
-  case PN_LONG: return PNE_LONG;
-  case PN_TIMESTAMP: return PNE_MS64;
-  case PN_DOUBLE: return PNE_DOUBLE;
-  case PN_DECIMAL32: return PNE_DECIMAL32;
-  case PN_DECIMAL64: return PNE_DECIMAL64;
-  case PN_DECIMAL128: return PNE_DECIMAL128;
-  case PN_UUID: return PNE_UUID;
-  case PN_ULONG: return PNE_ULONG;
-  case PN_BINARY: return PNE_VBIN32;
-  case PN_STRING: return PNE_STR32_UTF8;
-  case PN_SYMBOL: return PNE_SYM32;
-  case PN_LIST: return PNE_LIST32;
-  case PN_ARRAY: return PNE_ARRAY32;
-  case PN_MAP: return PNE_MAP32;
-  case PN_DESCRIBED: return PNE_DESCRIPTOR;
-  default:
-    return pn_error_format(encoder->error, PN_ERR, "not a value type: %u\n", type);
-  }
-}
-
-static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node)
-{
-  switch (node->atom.type) {
-  case PN_LONG:
-    if (-128 <= node->atom.u.as_long && node->atom.u.as_long <= 127) {
-      return PNE_SMALLLONG;
-    } else {
-      return PNE_LONG;
-    }
-  case PN_INT:
-    if (-128 <= node->atom.u.as_int && node->atom.u.as_int <= 127) {
-      return PNE_SMALLINT;
-    } else {
-      return PNE_INT;
-    }
-  case PN_ULONG:
-    if (node->atom.u.as_ulong < 256) {
-      return PNE_SMALLULONG;
-    } else {
-      return PNE_ULONG;
-    }
-  case PN_UINT:
-    if (node->atom.u.as_uint < 256) {
-      return PNE_SMALLUINT;
-    } else {
-      return PNE_UINT;
-    }
-  case PN_BOOL:
-    if (node->atom.u.as_bool) {
-      return PNE_TRUE;
-    } else {
-      return PNE_FALSE;
-    }
-  case PN_STRING:
-    if (node->atom.u.as_bytes.size < 256) {
-      return PNE_STR8_UTF8;
-    } else {
-      return PNE_STR32_UTF8;
-    }
-  case PN_SYMBOL:
-    if (node->atom.u.as_bytes.size < 256) {
-      return PNE_SYM8;
-    } else {
-      return PNE_SYM32;
-    }
-  case PN_BINARY:
-    if (node->atom.u.as_bytes.size < 256) {
-      return PNE_VBIN8;
-    } else {
-      return PNE_VBIN32;
-    }
-  default:
-    return pn_type2code(encoder, node->atom.type);
-  }
-}
-
-static size_t pn_encoder_remaining(pn_encoder_t *encoder) {
-  char * end = encoder->output + encoder->size;
-  if (end > encoder->position)
-    return end - encoder->position;
-  else
-    return 0;
-}
-
-static inline void pn_encoder_writef8(pn_encoder_t *encoder, uint8_t value)
-{
-  if (pn_encoder_remaining(encoder)) {
-    encoder->position[0] = value;
-  }
-  encoder->position++;
-}
-
-static inline void pn_encoder_writef16(pn_encoder_t *encoder, uint16_t value)
-{
-  if (pn_encoder_remaining(encoder) >= 2) {
-    encoder->position[0] = 0xFF & (value >> 8);
-    encoder->position[1] = 0xFF & (value     );
-  }
-  encoder->position += 2;
-}
-
-static inline void pn_encoder_writef32(pn_encoder_t *encoder, uint32_t value)
-{
-  if (pn_encoder_remaining(encoder) >= 4) {
-    encoder->position[0] = 0xFF & (value >> 24);
-    encoder->position[1] = 0xFF & (value >> 16);
-    encoder->position[2] = 0xFF & (value >>  8);
-    encoder->position[3] = 0xFF & (value      );
-  }
-  encoder->position += 4;
-}
-
-static inline void pn_encoder_writef64(pn_encoder_t *encoder, uint64_t value) {
-  if (pn_encoder_remaining(encoder) >= 8) {
-    encoder->position[0] = 0xFF & (value >> 56);
-    encoder->position[1] = 0xFF & (value >> 48);
-    encoder->position[2] = 0xFF & (value >> 40);
-    encoder->position[3] = 0xFF & (value >> 32);
-    encoder->position[4] = 0xFF & (value >> 24);
-    encoder->position[5] = 0xFF & (value >> 16);
-    encoder->position[6] = 0xFF & (value >>  8);
-    encoder->position[7] = 0xFF & (value      );
-  }
-  encoder->position += 8;
-}
-
-static inline void pn_encoder_writef128(pn_encoder_t *encoder, char *value) {
-  if (pn_encoder_remaining(encoder) >= 16) {
-    memmove(encoder->position, value, 16);
-  }
-  encoder->position += 16;
-}
-
-static inline void pn_encoder_writev8(pn_encoder_t *encoder, const pn_bytes_t *value)
-{
-  pn_encoder_writef8(encoder, value->size);
-  if (pn_encoder_remaining(encoder) >= value->size)
-    memmove(encoder->position, value->start, value->size);
-  encoder->position += value->size;
-}
-
-static inline void pn_encoder_writev32(pn_encoder_t *encoder, const pn_bytes_t *value)
-{
-  pn_encoder_writef32(encoder, value->size);
-  if (pn_encoder_remaining(encoder) >= value->size)
-    memmove(encoder->position, value->start, value->size);
-  encoder->position += value->size;
-}
-
-/* True if node is an element of an array - not the descriptor. */
-static bool pn_is_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
-  return (parent && parent->atom.type == PN_ARRAY) /* In array */
-    && !(parent->described && !node->prev); /* Not the descriptor */
-}
-
-/** True if node is the first element of an array, not the descriptor.
- *@pre pn_is_in_array(data, parent, node)
- */
-static bool pn_is_first_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) {
-  if (!node->prev) return !parent->described; /* First node */
-  return parent->described && (!pn_data_node(data, node->prev)->prev);
-}
-
-typedef union {
-  uint32_t i;
-  uint32_t a[2];
-  uint64_t l;
-  float f;
-  double d;
-} conv_t;
-
-static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node)
-{
-  pn_encoder_t *encoder = (pn_encoder_t *) ctx;
-  pni_node_t *parent = pn_data_node(data, node->parent);
-  pn_atom_t *atom = &node->atom;
-  uint8_t code;
-  conv_t c;
-
-  /** In an array we don't write the code before each element, only the first. */
-  if (pn_is_in_array(data, parent, node)) {
-    code = pn_type2code(encoder, parent->type);
-    if (pn_is_first_in_array(data, parent, node)) {
-      pn_encoder_writef8(encoder, code);
-    }
-  } else {
-    code = pn_node2code(encoder, node);
-    pn_encoder_writef8(encoder, code);
-  }
-
-  switch (code) {
-  case PNE_DESCRIPTOR:
-  case PNE_NULL:
-  case PNE_TRUE:
-  case PNE_FALSE: return 0;
-  case PNE_BOOLEAN: pn_encoder_writef8(encoder, atom->u.as_bool); return 0;
-  case PNE_UBYTE: pn_encoder_writef8(encoder, atom->u.as_ubyte); return 0;
-  case PNE_BYTE: pn_encoder_writef8(encoder, atom->u.as_byte); return 0;
-  case PNE_USHORT: pn_encoder_writef16(encoder, atom->u.as_ushort); return 0;
-  case PNE_SHORT: pn_encoder_writef16(encoder, atom->u.as_short); return 0;
-  case PNE_UINT0: return 0;
-  case PNE_SMALLUINT: pn_encoder_writef8(encoder, atom->u.as_uint); return 0;
-  case PNE_UINT: pn_encoder_writef32(encoder, atom->u.as_uint); return 0;
-  case PNE_SMALLINT: pn_encoder_writef8(encoder, atom->u.as_int); return 0;
-  case PNE_INT: pn_encoder_writef32(encoder, atom->u.as_int); return 0;
-  case PNE_UTF32: pn_encoder_writef32(encoder, atom->u.as_char); return 0;
-  case PNE_ULONG: pn_encoder_writef64(encoder, atom->u.as_ulong); return 0;
-  case PNE_SMALLULONG: pn_encoder_writef8(encoder, atom->u.as_ulong); return 0;
-  case PNE_LONG: pn_encoder_writef64(encoder, atom->u.as_long); return 0;
-  case PNE_SMALLLONG: pn_encoder_writef8(encoder, atom->u.as_long); return 0;
-  case PNE_MS64: pn_encoder_writef64(encoder, atom->u.as_timestamp); return 0;
-  case PNE_FLOAT: c.f = atom->u.as_float; pn_encoder_writef32(encoder, c.i); return 0;
-  case PNE_DOUBLE: c.d = atom->u.as_double; pn_encoder_writef64(encoder, c.l); return 0;
-  case PNE_DECIMAL32: pn_encoder_writef32(encoder, atom->u.as_decimal32); return 0;
-  case PNE_DECIMAL64: pn_encoder_writef64(encoder, atom->u.as_decimal64); return 0;
-  case PNE_DECIMAL128: pn_encoder_writef128(encoder, atom->u.as_decimal128.bytes); return 0;
-  case PNE_UUID: pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); return 0;
-  case PNE_VBIN8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
-  case PNE_VBIN32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
-  case PNE_STR8_UTF8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
-  case PNE_STR32_UTF8: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
-  case PNE_SYM8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0;
-  case PNE_SYM32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0;
-  case PNE_ARRAY32:
-    node->start = encoder->position;
-    node->small = false;
-    // we'll backfill the size on exit
-    encoder->position += 4;
-    pn_encoder_writef32(encoder, node->described ? node->children - 1 : node->children);
-    if (node->described)
-      pn_encoder_writef8(encoder, 0);
-    return 0;
-  case PNE_LIST32:
-  case PNE_MAP32:
-    node->start = encoder->position;
-    node->small = false;
-    // we'll backfill the size later
-    encoder->position += 4;
-    pn_encoder_writef32(encoder, node->children);
-    return 0;
-  default:
-    return pn_error_format(data->error, PN_ERR, "unrecognized encoding: %u", code);
-  }
-}
-
-#include <stdio.h>
-
-static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node)
-{
-  pn_encoder_t *encoder = (pn_encoder_t *) ctx;
-  char *pos;
-
-  switch (node->atom.type) {
-  case PN_ARRAY:
-    if ((node->described && node->children == 1) || (!node->described && node->children == 0)) {
-      pn_encoder_writef8(encoder, pn_type2code(encoder, node->type));
-    }
-  // Fallthrough
-  case PN_LIST:
-  case PN_MAP:
-    pos = encoder->position;
-    encoder->position = node->start;
-    if (node->small) {
-      // backfill size
-      size_t size = pos - node->start - 1;
-      pn_encoder_writef8(encoder, size);
-    } else {
-      // backfill size
-      size_t size = pos - node->start - 4;
-      pn_encoder_writef32(encoder, size);
-    }
-    encoder->position = pos;
-    return 0;
-  default:
-    return 0;
-  }
-}
-
-ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size)
-{
-  encoder->output = dst;
-  encoder->position = dst;
-  encoder->size = size;
-
-  int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
-  if (err) return err;
-  size_t encoded = encoder->position - encoder->output;
-  if (encoded > size) {
-      pn_error_format(pn_data_error(src), PN_OVERFLOW, "not enough space to encode");
-      return PN_OVERFLOW;
-  }
-  return (ssize_t)encoded;
-}
-
-ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src)
-{
-  encoder->output = 0;
-  encoder->position = 0;
-  encoder->size = 0;
-
-  pn_handle_t save = pn_data_point(src);
-  int err = pni_data_traverse(src, pni_encoder_enter, pni_encoder_exit, encoder);
-  pn_data_restore(src, save);
-
-  if (err) return err;
-  return encoder->position - encoder->output;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/encoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encoder.h b/proton-c/src/codec/encoder.h
deleted file mode 100644
index 20876cb..0000000
--- a/proton-c/src/codec/encoder.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _PROTON_ENCODER_H
-#define _PROTON_ENCODER_H 1
-
-/*
- *
- * 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.
- *
- */
-
-typedef struct pn_encoder_t pn_encoder_t;
-
-pn_encoder_t *pn_encoder(void);
-ssize_t pn_encoder_encode(pn_encoder_t *encoder, pn_data_t *src, char *dst, size_t size);
-ssize_t pn_encoder_size(pn_encoder_t *encoder, pn_data_t *src);
-
-#endif /* encoder.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/encodings.h.py
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/encodings.h.py b/proton-c/src/codec/encodings.h.py
deleted file mode 100755
index 9f08c6c..0000000
--- a/proton-c/src/codec/encodings.h.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/python
-#
-# 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 __future__ import print_function
-import mllib, optparse, os, sys
-
-xml = os.path.join(os.path.dirname(__file__), "types.xml")
-doc = mllib.xml_parse(xml)
-
-print("/* generated from %s */" % xml)
-print("#ifndef _PROTON_ENCODINGS_H")
-print("#define _PROTON_ENCODINGS_H 1")
-print()
-print("#define PNE_DESCRIPTOR          (0x00)")
-
-for enc in doc.query["amqp/section/type/encoding"]:
-  name = enc["@name"] or enc.parent["@name"]
-  # XXX: a bit hacky
-  if name == "ieee-754":
-    name = enc.parent["@name"]
-  cname = "PNE_" + name.replace("-", "_").upper()
-  print("#define %s%s(%s)" % (cname, " "*(20-len(cname)), enc["@code"]))
-
-print()
-print("#endif /* encodings.h */")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/codec/types.xml
----------------------------------------------------------------------
diff --git a/proton-c/src/codec/types.xml b/proton-c/src/codec/types.xml
deleted file mode 100644
index 4aa9c0f..0000000
--- a/proton-c/src/codec/types.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-Copyright Bank of America, N.A., Barclays Bank PLC, Cisco Systems, Credit
-Suisse, Deutsche Boerse, Envoy Technologies Inc., Goldman Sachs, HCL
-Technologies Ltd, IIT Software GmbH, iMatix Corporation, INETCO Systems Limited,
-Informatica Corporation, JPMorgan Chase & Co., Kaazing Corporation, N.A,
-Microsoft Corporation, my-Channels, Novell, Progress Software, Red Hat Inc.,
-Software AG, Solace Systems Inc., StormMQ Ltd., Tervela Inc., TWIST Process
-Innovations Ltd, VMware, Inc., and WS02 Inc. 2006-2011. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-2. 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.
-3. The name of the author may not be used to endorse or promote products
-derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
--->
-
-<amqp name="types" xmlns="http://www.amqp.org/schema/amqp.xsd">
-  <section name="encodings">
-    <type name="null" class="primitive">
-      <encoding code="0x40" category="fixed" width="0"/>
-    </type>
-    <type name="boolean" class="primitive">
-      <encoding code="0x56" category="fixed" width="1"/>
-      <encoding name="true" code="0x41" category="fixed" width="0"/>
-      <encoding name="false" code="0x42" category="fixed" width="0"/>
-    </type>
-    <type name="ubyte" class="primitive">
-      <encoding code="0x50" category="fixed" width="1"/>
-    </type>
-    <type name="ushort" class="primitive">
-      <encoding code="0x60" category="fixed" width="2"/>
-    </type>
-    <type name="uint" class="primitive">
-      <encoding code="0x70" category="fixed" width="4"/>
-      <encoding name="smalluint" code="0x52" category="fixed" width="1"/>
-      <encoding name="uint0" code="0x43" category="fixed" width="0"/>
-    </type>
-    <type name="ulong" class="primitive">
-      <encoding code="0x80" category="fixed" width="8"/>
-      <encoding name="smallulong" code="0x53" category="fixed" width="1"/>
-      <encoding name="ulong0" code="0x44" category="fixed" width="0"/>
-    </type>
-    <type name="byte" class="primitive">
-      <encoding code="0x51" category="fixed" width="1"/>
-    </type>
-    <type name="short" class="primitive">
-      <encoding code="0x61" category="fixed" width="2"/>
-    </type>
-    <type name="int" class="primitive">
-      <encoding code="0x71" category="fixed" width="4"/>
-      <encoding name="smallint" code="0x54" category="fixed" width="1"/>
-    </type>
-    <type name="long" class="primitive">
-      <encoding code="0x81" category="fixed" width="8"/>
-      <encoding name="smalllong" code="0x55" category="fixed" width="1"/>
-    </type>
-    <type name="float" class="primitive">
-      <encoding name="ieee-754" code="0x72" category="fixed" width="4"/>
-    </type>
-    <type name="double" class="primitive">
-      <encoding name="ieee-754" code="0x82" category="fixed" width="8"/>
-    </type>
-    <type name="decimal32" class="primitive">
-      <encoding name="ieee-754" code="0x74" category="fixed" width="4"/>
-    </type>
-    <type name="decimal64" class="primitive">
-      <encoding name="ieee-754" code="0x84" category="fixed" width="8"/>
-    </type>
-    <type name="decimal128" class="primitive">
-      <encoding name="ieee-754" code="0x94" category="fixed" width="16"/>
-    </type>
-    <type name="char" class="primitive">
-      <encoding name="utf32" code="0x73" category="fixed" width="4"/>
-    </type>
-    <type name="timestamp" class="primitive">
-      <encoding name="ms64" code="0x83" category="fixed" width="8"/>
-    </type>
-    <type name="uuid" class="primitive">
-      <encoding code="0x98" category="fixed" width="16"/>
-    </type>
-    <type name="binary" class="primitive">
-      <encoding name="vbin8" code="0xa0" category="variable" width="1"/>
-      <encoding name="vbin32" code="0xb0" category="variable" width="4"/>
-    </type>
-    <type name="string" class="primitive">
-      <encoding name="str8-utf8" code="0xa1" category="variable" width="1"/>
-      <encoding name="str32-utf8" code="0xb1" category="variable" width="4"/>
-    </type>
-    <type name="symbol" class="primitive">
-      <encoding name="sym8" code="0xa3" category="variable" width="1"/>
-      <encoding name="sym32" code="0xb3" category="variable" width="4"/>
-    </type>
-    <type name="list" class="primitive">
-      <encoding name="list0" code="0x45" category="fixed" width="0"/>
-      <encoding name="list8" code="0xc0" category="compound" width="1"/>
-      <encoding name="list32" code="0xd0" category="compound" width="4"/>
-    </type>
-    <type name="map" class="primitive">
-      <encoding name="map8" code="0xc1" category="compound" width="1"/>
-      <encoding name="map32" code="0xd1" category="compound" width="4"/>
-    </type>
-    <type name="array" class="primitive">
-      <encoding name="array8" code="0xe0" category="array" width="1"/>
-      <encoding name="array32" code="0xf0" category="array" width="4"/>
-    </type>
-  </section>
-</amqp>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/compiler/msvc/snprintf.c
----------------------------------------------------------------------
diff --git a/proton-c/src/compiler/msvc/snprintf.c b/proton-c/src/compiler/msvc/snprintf.c
new file mode 100644
index 0000000..f9c14eb
--- /dev/null
+++ b/proton-c/src/compiler/msvc/snprintf.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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 "platform/platform.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+// [v]snprintf on Windows only matches C99 when no errors or overflow.
+int pni_vsnprintf(char *buf, size_t count, const char *fmt, va_list ap) {
+  if (fmt == NULL)
+    return -1;
+  if ((buf == NULL) && (count > 0))
+    return -1;
+  if (count > 0) {
+    int n = vsnprintf_s(buf, count, _TRUNCATE, fmt, ap);
+    if (n >= 0)  // no overflow
+      return n;  // same as C99
+    buf[count-1] = '\0';
+  }
+  // separate call to get needed buffer size on overflow
+  int n = _vscprintf(fmt, ap);
+  if (n >= (int) count)
+    return n;
+  return -1;
+}
+
+int pni_snprintf(char *buf, size_t count, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  int n = pni_vsnprintf(buf, count, fmt, ap);
+  va_end(ap);
+  return n;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/config.h
----------------------------------------------------------------------
diff --git a/proton-c/src/config.h b/proton-c/src/config.h
deleted file mode 100644
index 5a2e7bc..0000000
--- a/proton-c/src/config.h
+++ /dev/null
@@ -1,32 +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.
-*
-*/
-
-#ifndef  _PROTON_SRC_CONFIG_H 
-#define  _PROTON_SRC_CONFIG_H 
-
-#ifndef PN_TRANSPORT_INITIAL_FRAME_SIZE
-# define PN_TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */
-#endif
-
-#ifndef PN_SASL_MAX_BUFFSIZE
-# define PN_SASL_MAX_BUFFSIZE (32768) /* bytes */
-#endif
-
-#endif /*  _PROTON_SRC_CONFIG_H */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/autodetect.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/autodetect.c b/proton-c/src/core/autodetect.c
new file mode 100644
index 0000000..00f6d98
--- /dev/null
+++ b/proton-c/src/core/autodetect.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * 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 "autodetect.h"
+
+#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
+#define SSL_HEADER  ("AMQP\x02\x01\x00\x00")
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
+
+#define SASL_HEADER_LEN 8
+
+/*
+ * SSLv2 Client Hello format
+ * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
+ *
+ * Bytes 0-1: RECORD-LENGTH
+ * Byte    2: MSG-CLIENT-HELLO (1)
+ * Byte    3: CLIENT-VERSION-MSB
+ * Byte    4: CLIENT-VERSION-LSB
+ *
+ * Allowed versions:
+ * 2.0 - SSLv2
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ *
+ * The version sent in the Client-Hello is the latest version supported by
+ * the client. NSS may send version 3.x in an SSLv2 header for
+ * maximum compatibility.
+ */
+/*
+ * SSLv3/TLS Client Hello format
+ * RFC 2246
+ *
+ * Byte    0: ContentType (handshake - 22)
+ * Bytes 1-2: ProtocolVersion {major, minor}
+ *
+ * Allowed versions:
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ */
+/*
+ * AMQP 1.0 Header
+ *
+ * Bytes 0-3: "AMQP"
+ * Byte    4: 0==AMQP, 2==SSL, 3==SASL
+ * Byte    5: 1
+ * Bytes 6-7: 0
+ */
+/*
+ * AMQP Pre 1.0 Header
+ *
+ * Bytes 0-3: 'AMQP'
+ * Byte    4: 1
+ * Byte    5: 1
+ * Byte    6: 0 (major version)
+ * Byte    7: Minor version
+ */
+pni_protocol_type_t pni_sniff_header(const char *buf, size_t len)
+{
+  if (len < 3) return PNI_PROTOCOL_INSUFFICIENT;
+  bool isSSL3Handshake = buf[0]==22 &&            // handshake
+                         buf[1]==3  && buf[2]<=3; // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+  if (isSSL3Handshake) return PNI_PROTOCOL_SSL;
+
+  bool isFirst3AMQP = buf[0]=='A' && buf[1]=='M' && buf[2]=='Q';
+  bool isFirst3SSL2CLientHello = buf[2]==1;       // Client Hello
+  if (!isFirst3AMQP && !isFirst3SSL2CLientHello) return PNI_PROTOCOL_UNKNOWN;
+
+
+  if (len < 4) return PNI_PROTOCOL_INSUFFICIENT;
+  bool isAMQP = isFirst3AMQP && buf[3]=='P';
+  bool isFirst4SSL2ClientHello = isFirst3SSL2CLientHello && (buf[3]==2 || buf[3]==3);
+  if (!isAMQP && !isFirst4SSL2ClientHello) return PNI_PROTOCOL_UNKNOWN;
+
+  if (len < 5) return PNI_PROTOCOL_INSUFFICIENT;
+  bool isSSL2Handshake = buf[2] == 1 &&   // MSG-CLIENT-HELLO
+      ((buf[3] == 3 && buf[4] <= 3) ||    // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+       (buf[3] == 2 && buf[4] == 0));     // SSL 2
+  if (isSSL2Handshake) return PNI_PROTOCOL_SSL;
+
+  bool isFirst5OldAMQP = isAMQP && buf[4]==1;
+  bool isFirst5AMQP = isAMQP && (buf[4]==0 || buf[4]==2 || buf[4]==3);
+  if (!isFirst5AMQP && !isFirst5OldAMQP) return PNI_PROTOCOL_UNKNOWN;
+
+  if (len < 6) return PNI_PROTOCOL_INSUFFICIENT;
+
+  // Both old and new versions of AMQP have 1 in byte 5
+  if (buf[5]!=1) return PNI_PROTOCOL_UNKNOWN;
+
+  // From here on it must be some sort of AMQP
+  if (len < 8) return PNI_PROTOCOL_INSUFFICIENT;
+  if (buf[6]==0 && buf[7]==0) {
+    // AM<QP 1.0
+      if (buf[4]==0) return PNI_PROTOCOL_AMQP1;
+      if (buf[4]==2) return PNI_PROTOCOL_AMQP_SSL;
+      if (buf[4]==3) return PNI_PROTOCOL_AMQP_SASL;
+  }
+  return PNI_PROTOCOL_AMQP_OTHER;
+}
+
+const char* pni_protocol_name(pni_protocol_type_t p)
+{
+  static const char* names[] = {
+  "Insufficient data to determine protocol",
+  "Unknown protocol",
+  "SSL/TLS connection",
+  "AMQP TLS layer",
+  "AMQP SASL layer",
+  "AMQP 1.0 layer",
+  "Pre standard AMQP connection"
+  };
+  return names[p];
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/autodetect.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/autodetect.h b/proton-c/src/core/autodetect.h
new file mode 100644
index 0000000..12cb7d8
--- /dev/null
+++ b/proton-c/src/core/autodetect.h
@@ -0,0 +1,40 @@
+#ifndef PROTON_AUTODETECT_H
+#define PROTON_AUTODETECT_H 1
+
+/*
+ *
+ * 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/types.h"
+
+typedef enum {
+  PNI_PROTOCOL_INSUFFICIENT,
+  PNI_PROTOCOL_UNKNOWN,
+  PNI_PROTOCOL_SSL,
+  PNI_PROTOCOL_AMQP_SSL,
+  PNI_PROTOCOL_AMQP_SASL,
+  PNI_PROTOCOL_AMQP1,
+  PNI_PROTOCOL_AMQP_OTHER
+} pni_protocol_type_t;
+
+pni_protocol_type_t pni_sniff_header(const char *data, size_t len);
+const char* pni_protocol_name(pni_protocol_type_t p);
+
+#endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/buffer.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/buffer.c b/proton-c/src/core/buffer.c
new file mode 100644
index 0000000..c3015f4
--- /dev/null
+++ b/proton-c/src/core/buffer.c
@@ -0,0 +1,310 @@
+/*
+ *
+ * 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/error.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "buffer.h"
+#include "util.h"
+
+struct pn_buffer_t {
+  size_t capacity;
+  size_t start;
+  size_t size;
+  char *bytes;
+};
+
+pn_buffer_t *pn_buffer(size_t capacity)
+{
+  pn_buffer_t *buf = (pn_buffer_t *) malloc(sizeof(pn_buffer_t));
+  if (buf != NULL) {
+    buf->capacity = capacity;
+    buf->start = 0;
+    buf->size = 0;
+    if (capacity > 0) {
+        buf->bytes = (char *)malloc(capacity);
+        if (buf->bytes == NULL) {
+            free(buf);
+            buf = NULL;
+        }
+    }
+    else {
+        buf->bytes = NULL;
+    }
+  }
+  return buf;
+}
+
+void pn_buffer_free(pn_buffer_t *buf)
+{
+  if (buf) {
+    free(buf->bytes);
+    free(buf);
+  }
+}
+
+size_t pn_buffer_size(pn_buffer_t *buf)
+{
+  return buf->size;
+}
+
+size_t pn_buffer_capacity(pn_buffer_t *buf)
+{
+  return buf->capacity;
+}
+
+size_t pn_buffer_available(pn_buffer_t *buf)
+{
+  return buf->capacity - buf->size;
+}
+
+static size_t pni_buffer_head(pn_buffer_t *buf)
+{
+  return buf->start;
+}
+
+static size_t pni_buffer_tail(pn_buffer_t *buf)
+{
+  size_t tail = buf->start + buf->size;
+  if (tail >= buf->capacity)
+    tail -= buf->capacity;
+  return tail;
+}
+
+static bool pni_buffer_wrapped(pn_buffer_t *buf)
+{
+  return buf->size && pni_buffer_head(buf) >= pni_buffer_tail(buf);
+}
+
+static size_t pni_buffer_tail_space(pn_buffer_t *buf)
+{
+  if (pni_buffer_wrapped(buf)) {
+    return pn_buffer_available(buf);
+  } else {
+    return buf->capacity - pni_buffer_tail(buf);
+  }
+}
+
+static size_t pni_buffer_head_space(pn_buffer_t *buf)
+{
+  if (pni_buffer_wrapped(buf)) {
+    return pn_buffer_available(buf);
+  } else {
+    return pni_buffer_head(buf);
+  }
+}
+
+static size_t pni_buffer_head_size(pn_buffer_t *buf)
+{
+  if (pni_buffer_wrapped(buf)) {
+    return buf->capacity - pni_buffer_head(buf);
+  } else {
+    return pni_buffer_tail(buf) - pni_buffer_head(buf);
+  }
+}
+
+static size_t pni_buffer_tail_size(pn_buffer_t *buf)
+{
+  if (pni_buffer_wrapped(buf)) {
+    return pni_buffer_tail(buf);
+  } else {
+    return 0;
+  }
+}
+
+int pn_buffer_ensure(pn_buffer_t *buf, size_t size)
+{
+  size_t old_capacity = buf->capacity;
+  size_t old_head = pni_buffer_head(buf);
+  bool wrapped = pni_buffer_wrapped(buf);
+
+  while (pn_buffer_available(buf) < size) {
+    buf->capacity = 2*(buf->capacity ? buf->capacity : 16);
+  }
+
+  if (buf->capacity != old_capacity) {
+    char* new_bytes = (char *)realloc(buf->bytes, buf->capacity);
+    if (new_bytes) {
+      buf->bytes = new_bytes;
+
+      if (wrapped) {
+          size_t n = old_capacity - old_head;
+          memmove(buf->bytes + buf->capacity - n, buf->bytes + old_head, n);
+          buf->start = buf->capacity - n;
+      }
+    }
+  }
+
+  return 0;
+}
+
+int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size)
+{
+  int err = pn_buffer_ensure(buf, size);
+  if (err) return err;
+
+  size_t tail = pni_buffer_tail(buf);
+  size_t tail_space = pni_buffer_tail_space(buf);
+  size_t n = pn_min(tail_space, size);
+
+  memmove(buf->bytes + tail, bytes, n);
+  memmove(buf->bytes, bytes + n, size - n);
+
+  buf->size += size;
+
+  return 0;
+}
+
+int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size)
+{
+  int err = pn_buffer_ensure(buf, size);
+  if (err) return err;
+
+  size_t head = pni_buffer_head(buf);
+  size_t head_space = pni_buffer_head_space(buf);
+  size_t n = pn_min(head_space, size);
+
+  memmove(buf->bytes + head - n, bytes + size - n, n);
+  memmove(buf->bytes + buf->capacity - (size - n), bytes, size - n);
+
+  if (buf->start >= size) {
+    buf->start -= size;
+  } else {
+    buf->start = buf->capacity - (size - buf->start);
+  }
+
+  buf->size += size;
+
+  return 0;
+}
+
+static size_t pni_buffer_index(pn_buffer_t *buf, size_t index)
+{
+  size_t result = buf->start + index;
+  if (result >= buf->capacity) result -= buf->capacity;
+  return result;
+}
+
+size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst)
+{
+  size = pn_min(size, buf->size);
+  size_t start = pni_buffer_index(buf, offset);
+  size_t stop = pni_buffer_index(buf, offset + size);
+
+  if (size == 0) return 0;
+
+  size_t sz1;
+  size_t sz2;
+
+  if (start >= stop) {
+    sz1 = buf->capacity - start;
+    sz2 = stop;
+  } else {
+    sz1 = stop - start;
+    sz2 = 0;
+  }
+
+  memmove(dst, buf->bytes + start, sz1);
+  memmove(dst + sz1, buf->bytes, sz2);
+
+  return sz1 + sz2;
+}
+
+int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right)
+{
+  if (left + right > buf->size) return PN_ARG_ERR;
+
+  buf->start += left;
+  if (buf->start >= buf->capacity)
+    buf->start -= buf->capacity;
+
+  buf->size -= left + right;
+
+  return 0;
+}
+
+void pn_buffer_clear(pn_buffer_t *buf)
+{
+  buf->start = 0;
+  buf->size = 0;
+}
+
+static void pn_buffer_rotate (pn_buffer_t *buf, size_t sz) {
+  if (sz == 0) return;
+
+  unsigned c = 0, v = 0;
+  for (; c < buf->capacity; v++) {
+    unsigned t = v, tp = v + sz;
+    char tmp = buf->bytes[v];
+    c++;
+    while (tp != v) {
+      buf->bytes[t] = buf->bytes[tp];
+      t = tp;
+      tp += sz;
+      if (tp >= buf->capacity) tp -= buf->capacity;
+      c++;
+    }
+    buf->bytes[t] = tmp;
+  }
+}
+
+int pn_buffer_defrag(pn_buffer_t *buf)
+{
+  pn_buffer_rotate(buf, buf->start);
+  buf->start = 0;
+  return 0;
+}
+
+pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf)
+{
+  if (buf) {
+    pn_buffer_defrag(buf);
+    return pn_bytes(buf->size, buf->bytes);
+  } else {
+    return pn_bytes(0, NULL);
+  }
+}
+
+pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf)
+{
+  if (buf) {
+    pn_buffer_defrag(buf);
+    pn_rwbytes_t r = {buf->size, buf->bytes};
+    return r;
+  } else {
+    pn_rwbytes_t r = {0, NULL};
+    return r;
+  }
+}
+
+int pn_buffer_print(pn_buffer_t *buf)
+{
+  printf("pn_buffer(\"");
+  pn_print_data(buf->bytes + pni_buffer_head(buf), pni_buffer_head_size(buf));
+  pn_print_data(buf->bytes, pni_buffer_tail_size(buf));
+  printf("\")");
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/buffer.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/buffer.h b/proton-c/src/core/buffer.h
new file mode 100644
index 0000000..da557ef
--- /dev/null
+++ b/proton-c/src/core/buffer.h
@@ -0,0 +1,54 @@
+#ifndef PROTON_BUFFER_H
+#define PROTON_BUFFER_H 1
+
+/*
+ *
+ * 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/import_export.h>
+#include <proton/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pn_buffer_t pn_buffer_t;
+
+pn_buffer_t *pn_buffer(size_t capacity);
+void pn_buffer_free(pn_buffer_t *buf);
+size_t pn_buffer_size(pn_buffer_t *buf);
+size_t pn_buffer_capacity(pn_buffer_t *buf);
+size_t pn_buffer_available(pn_buffer_t *buf);
+int pn_buffer_ensure(pn_buffer_t *buf, size_t size);
+int pn_buffer_append(pn_buffer_t *buf, const char *bytes, size_t size);
+int pn_buffer_prepend(pn_buffer_t *buf, const char *bytes, size_t size);
+size_t pn_buffer_get(pn_buffer_t *buf, size_t offset, size_t size, char *dst);
+int pn_buffer_trim(pn_buffer_t *buf, size_t left, size_t right);
+void pn_buffer_clear(pn_buffer_t *buf);
+int pn_buffer_defrag(pn_buffer_t *buf);
+pn_bytes_t pn_buffer_bytes(pn_buffer_t *buf);
+pn_rwbytes_t pn_buffer_memory(pn_buffer_t *buf);
+int pn_buffer_print(pn_buffer_t *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* buffer.h */


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


[11/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/transport.h b/proton-c/src/core/transport.h
new file mode 100644
index 0000000..66ebc51
--- /dev/null
+++ b/proton-c/src/core/transport.h
@@ -0,0 +1,31 @@
+#ifndef _PROTON_TRANSPORT_INTERNAL_H
+#define _PROTON_TRANSPORT_INTERNAL_H 1
+
+/*
+ *
+ * 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.
+ *
+ */
+
+void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next);
+void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery);
+void pn_delivery_map_free(pn_delivery_map_t *db);
+void pn_unmap_handle(pn_session_t *ssn, pn_link_t *link);
+void pn_unmap_channel(pn_transport_t *transport, pn_session_t *ssn);
+
+#endif /* transport.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/types.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/types.c b/proton-c/src/core/types.c
new file mode 100644
index 0000000..dbd18d0
--- /dev/null
+++ b/proton-c/src/core/types.c
@@ -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.
+ *
+ */
+
+#include <proton/types.h>
+
+pn_bytes_t pn_bytes(size_t size, const char *start)
+{
+  pn_bytes_t bytes = {size, start};
+  return bytes;
+}
+
+pn_rwbytes_t pn_rwbytes(size_t size, char *start)
+{
+  pn_rwbytes_t bytes = {size, start};
+  return bytes;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.c b/proton-c/src/core/util.c
new file mode 100644
index 0000000..62eec9a
--- /dev/null
+++ b/proton-c/src/core/util.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <proton/type_compat.h>
+#include <ctype.h>
+#include <string.h>
+#include <proton/error.h>
+#include <proton/types.h>
+#include "util.h"
+
+ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size)
+{
+  int idx = 0;
+  for (unsigned i = 0; i < size; i++)
+  {
+    uint8_t c = src[i];
+    if (isprint(c)) {
+      if (idx < (int) (capacity - 1)) {
+        dst[idx++] = c;
+      } else {
+        if (idx > 0) {
+          dst[idx - 1] = '\0';
+        }
+        return PN_OVERFLOW;
+      }
+    } else {
+      if (idx < (int) (capacity - 4)) {
+        idx += sprintf(dst + idx, "\\x%.2x", c);
+      } else {
+        if (idx > 0) {
+          dst[idx - 1] = '\0';
+        }
+        return PN_OVERFLOW;
+      }
+    }
+  }
+
+  dst[idx] = '\0';
+  return idx;
+}
+
+int pn_quote(pn_string_t *dst, const char *src, size_t size)
+{
+  while (true) {
+    size_t str_size = pn_string_size(dst);
+    char *str = pn_string_buffer(dst) + str_size;
+    size_t capacity = pn_string_capacity(dst) - str_size;
+    ssize_t ssize = pn_quote_data(str, capacity, src, size);
+    if (ssize == PN_OVERFLOW) {
+      int err = pn_string_grow(dst, (str_size + capacity) ? 2*(str_size + capacity) : 16);
+      if (err) return err;
+    } else if (ssize >= 0) {
+      return pn_string_resize(dst, str_size + ssize);
+    } else {
+      return ssize;
+    }
+  }
+}
+
+void pn_fprint_data(FILE *stream, const char *bytes, size_t size)
+{
+  char buf[256];
+  ssize_t n = pn_quote_data(buf, 256, bytes, size);
+  if (n >= 0) {
+    fputs(buf, stream);
+  } else {
+    if (n == PN_OVERFLOW) {
+      fputs(buf, stream);
+      fputs("... (truncated)", stream);
+    }
+    else
+      fprintf(stderr, "pn_quote_data: %s\n", pn_code(n));
+  }
+}
+
+void pn_print_data(const char *bytes, size_t size)
+{
+  pn_fprint_data(stdout, bytes, size);
+}
+
+int pn_strcasecmp(const char *a, const char *b)
+{
+  int diff;
+  while (*b) {
+    char aa = *a++, bb = *b++;
+    diff = tolower(aa)-tolower(bb);
+    if ( diff!=0 ) return diff;
+  }
+  return *a;
+}
+
+int pn_strncasecmp(const char* a, const char* b, size_t len)
+{
+  int diff = 0;
+  while (*b && len > 0) {
+    char aa = *a++, bb = *b++;
+    diff = tolower(aa)-tolower(bb);
+    if ( diff!=0 ) return diff;
+    --len;
+  };
+  return len==0 ? diff : *a;
+}
+
+bool pn_env_bool(const char *name)
+{
+  char *v = getenv(name);
+  return v && (!pn_strcasecmp(v, "true") || !pn_strcasecmp(v, "1") ||
+               !pn_strcasecmp(v, "yes")  || !pn_strcasecmp(v, "on"));
+}
+
+char *pn_strdup(const char *src)
+{
+  if (!src) return NULL;
+  char *dest = (char *) malloc(strlen(src)+1);
+  if (!dest) return NULL;
+  return strcpy(dest, src);
+}
+
+char *pn_strndup(const char *src, size_t n)
+{
+  if (src) {
+    unsigned size = 0;
+    for (const char *c = src; size < n && *c; c++) {
+      size++;
+    }
+
+    char *dest = (char *) malloc(size + 1);
+    if (!dest) return NULL;
+    strncpy(dest, src, n);
+    dest[size] = '\0';
+    return dest;
+  } else {
+    return NULL;
+  }
+}
+
+// which timestamp will expire next, or zero if none set
+pn_timestamp_t pn_timestamp_min( pn_timestamp_t a, pn_timestamp_t b )
+{
+  if (a && b) return pn_min(a, b);
+  if (a) return a;
+  return b;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.h b/proton-c/src/core/util.h
new file mode 100644
index 0000000..b54f689
--- /dev/null
+++ b/proton-c/src/core/util.h
@@ -0,0 +1,123 @@
+#ifndef _PROTON_SRC_UTIL_H
+#define _PROTON_SRC_UTIL_H 1
+
+/*
+ *
+ * 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 <errno.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <proton/types.h>
+#include <proton/object.h>
+
+ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size);
+int pn_quote(pn_string_t *dst, const char *src, size_t size);
+void pn_fprint_data(FILE *stream, const char *bytes, size_t size);
+void pn_print_data(const char *bytes, size_t size);
+bool pn_env_bool(const char *name);
+pn_timestamp_t pn_timestamp_min(pn_timestamp_t a, pn_timestamp_t b);
+
+char *pn_strdup(const char *src);
+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);
+
+#define DIE_IFR(EXPR, STRERR)                                           \
+  do {                                                                  \
+    int __code__ = (EXPR);                                              \
+    if (__code__) {                                                     \
+      fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__,       \
+              #EXPR, STRERR(__code__), __code__);                       \
+      exit(-1);                                                         \
+    }                                                                   \
+  } while (0)
+
+#define DIE_IFE(EXPR)                                                   \
+  do {                                                                  \
+    if ((EXPR) == -1) {                                                 \
+      int __code__ = errno;                                             \
+      fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__,       \
+              #EXPR, strerror(__code__), __code__);                     \
+      exit(-1);                                                         \
+    }                                                                   \
+  } while (0)
+
+
+#define LL_HEAD(ROOT, LIST) ((ROOT)-> LIST ## _head)
+#define LL_TAIL(ROOT, LIST) ((ROOT)-> LIST ## _tail)
+#define LL_ADD(ROOT, LIST, NODE)                              \
+  {                                                           \
+    (NODE)-> LIST ## _next = NULL;                            \
+    (NODE)-> LIST ## _prev = (ROOT)-> LIST ## _tail;          \
+    if (LL_TAIL(ROOT, LIST))                                  \
+      LL_TAIL(ROOT, LIST)-> LIST ## _next = (NODE);           \
+    LL_TAIL(ROOT, LIST) = (NODE);                             \
+    if (!LL_HEAD(ROOT, LIST)) LL_HEAD(ROOT, LIST) = (NODE);   \
+  }
+
+#define LL_POP(ROOT, LIST, TYPE)                              \
+  {                                                           \
+    if (LL_HEAD(ROOT, LIST)) {                                \
+      TYPE *_old = LL_HEAD(ROOT, LIST);                       \
+      LL_HEAD(ROOT, LIST) = LL_HEAD(ROOT, LIST)-> LIST ## _next; \
+      _old-> LIST ## _next = NULL;                            \
+      if (_old == LL_TAIL(ROOT, LIST)) {                      \
+        LL_TAIL(ROOT, LIST) = NULL;                           \
+      } else {                                                \
+        LL_HEAD(ROOT, LIST)-> LIST ## _prev = NULL;           \
+      }                                                       \
+    }                                                         \
+  }
+
+#define LL_REMOVE(ROOT, LIST, NODE)                                    \
+  {                                                                    \
+    if ((NODE)-> LIST ## _prev)                                        \
+      (NODE)-> LIST ## _prev-> LIST ## _next = (NODE)-> LIST ## _next; \
+    if ((NODE)-> LIST ## _next)                                        \
+      (NODE)-> LIST ## _next-> LIST ## _prev = (NODE)-> LIST ## _prev; \
+    if ((NODE) == LL_HEAD(ROOT, LIST))                                 \
+      LL_HEAD(ROOT, LIST) = (NODE)-> LIST ## _next;                    \
+    if ((NODE) == LL_TAIL(ROOT, LIST))                                 \
+      LL_TAIL(ROOT, LIST) = (NODE)-> LIST ## _prev;                    \
+  }
+
+#define pn_min(X,Y) ((X) > (Y) ? (Y) : (X))
+#define pn_max(X,Y) ((X) < (Y) ? (Y) : (X))
+
+#define PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE)                 \
+  while ((CAPACITY) < (COUNT)) {                                \
+    (CAPACITY) = (CAPACITY) ? 2 * (CAPACITY) : 16;              \
+    (ARRAY) = (TYPE *) realloc((ARRAY), (CAPACITY) * sizeof (TYPE));    \
+  }                                                             \
+
+#define PN_ENSUREZ(ARRAY, CAPACITY, COUNT, TYPE)           \
+  {                                                        \
+    size_t _old_capacity = (CAPACITY);                     \
+    PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE);               \
+    memset((ARRAY) + _old_capacity, 0,                     \
+           sizeof(TYPE)*((CAPACITY) - _old_capacity));     \
+  }
+
+#endif /* util.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/dispatch_actions.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatch_actions.h b/proton-c/src/dispatch_actions.h
deleted file mode 100644
index bae8438..0000000
--- a/proton-c/src/dispatch_actions.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _PROTON_DISPATCH_ACTIONS_H
-#define _PROTON_DISPATCH_ACTIONS_H 1
-
-/*
- *
- * 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 "dispatcher/dispatcher.h"
-
-#define AMQP_FRAME_TYPE (0)
-#define SASL_FRAME_TYPE (1)
-
-
-/* AMQP actions */
-int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-
-/* SASL actions */
-int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-
-#endif // _PROTON_DISPATCH_ACTIONS_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/dispatcher/dispatcher.c
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.c b/proton-c/src/dispatcher/dispatcher.c
deleted file mode 100644
index 0bd3f7b..0000000
--- a/proton-c/src/dispatcher/dispatcher.c
+++ /dev/null
@@ -1,158 +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 "dispatcher.h"
-
-#include "framing/framing.h"
-#include "protocol.h"
-#include "engine/engine-internal.h"
-
-#include "dispatch_actions.h"
-
-int pni_bad_frame(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
-  pn_transport_logf(transport, "Error dispatching frame: type: %d: Unknown performative", frame_type);
-  return PN_ERR;
-}
-
-int pni_bad_frame_type(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload) {
-    pn_transport_logf(transport, "Error dispatching frame: Unknown frame type: %d", frame_type);
-    return PN_ERR;
-}
-
-// We could use a table based approach here if we needed to dynamically
-// add new performatives
-static inline int pni_dispatch_action(pn_transport_t* transport, uint64_t lcode, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_action_t *action;
-  switch (frame_type) {
-  case AMQP_FRAME_TYPE:
-    /* Regular AMQP fames */
-    switch (lcode) {
-    case OPEN:            action = pn_do_open; break;
-    case BEGIN:           action = pn_do_begin; break;
-    case ATTACH:          action = pn_do_attach; break;
-    case FLOW:            action = pn_do_flow; break;
-    case TRANSFER:        action = pn_do_transfer; break;
-    case DISPOSITION:     action = pn_do_disposition; break;
-    case DETACH:          action = pn_do_detach; break;
-    case END:             action = pn_do_end; break;
-    case CLOSE:           action = pn_do_close; break;
-    default:              action = pni_bad_frame; break;
-    };
-    break;
-  case SASL_FRAME_TYPE:
-    /* SASL frames */
-    switch (lcode) {
-    case SASL_MECHANISMS: action = pn_do_mechanisms; break;
-    case SASL_INIT:       action = pn_do_init; break;
-    case SASL_CHALLENGE:  action = pn_do_challenge; break;
-    case SASL_RESPONSE:   action = pn_do_response; break;
-    case SASL_OUTCOME:    action = pn_do_outcome; break;
-    default:              action = pni_bad_frame; break;
-    };
-    break;
-  default:              action = pni_bad_frame_type; break;
-  };
-  return action(transport, frame_type, channel, args, payload);
-}
-
-static int pni_dispatch_frame(pn_transport_t * transport, pn_data_t *args, pn_frame_t frame)
-{
-  if (frame.size == 0) { // ignore null frames
-    if (transport->trace & PN_TRACE_FRM)
-      pn_transport_logf(transport, "%u <- (EMPTY FRAME)", frame.channel);
-    return 0;
-  }
-
-  ssize_t dsize = pn_data_decode(args, frame.payload, frame.size);
-  if (dsize < 0) {
-    pn_string_format(transport->scratch,
-                     "Error decoding frame: %s %s\n", pn_code(dsize),
-                     pn_error_text(pn_data_error(args)));
-    pn_quote(transport->scratch, frame.payload, frame.size);
-    pn_transport_log(transport, pn_string_get(transport->scratch));
-    return dsize;
-  }
-
-  uint8_t frame_type = frame.type;
-  uint16_t channel = frame.channel;
-  // XXX: assuming numeric -
-  // if we get a symbol we should map it to the numeric value and dispatch on that
-  uint64_t lcode;
-  bool scanned;
-  int e = pn_data_scan(args, "D?L.", &scanned, &lcode);
-  if (e) {
-    pn_transport_log(transport, "Scan error");
-    return e;
-  }
-  if (!scanned) {
-    pn_transport_log(transport, "Error dispatching frame");
-    return PN_ERR;
-  }
-  size_t payload_size = frame.size - dsize;
-  const char *payload_mem = payload_size ? frame.payload + dsize : NULL;
-  pn_bytes_t payload = {payload_size, payload_mem};
-
-  pn_do_trace(transport, channel, IN, args, payload_mem, payload_size);
-
-  int err = pni_dispatch_action(transport, lcode, frame_type, channel, args, &payload);
-
-  pn_data_clear(args);
-
-  return err;
-}
-
-ssize_t pn_dispatcher_input(pn_transport_t *transport, const char *bytes, size_t available, bool batch, bool *halt)
-{
-  size_t read = 0;
-
-  while (available && !*halt) {
-    pn_frame_t frame;
-
-    ssize_t n = pn_read_frame(&frame, bytes + read, available, transport->local_max_frame);
-    if (n > 0) {
-      read += n;
-      available -= n;
-      transport->input_frames_ct += 1;
-      int e = pni_dispatch_frame(transport, transport->args, frame);
-      if (e) return e;
-    } else if (n < 0) {
-      pn_do_error(transport, "amqp:connection:framing-error", "malformed frame");
-      return n;
-    } else {
-      break;
-    }
-
-    if (!batch) break;
-  }
-
-  return read;
-}
-
-ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size)
-{
-    int n = transport->available < size ? transport->available : size;
-    memmove(bytes, transport->output, n);
-    memmove(transport->output, transport->output + n, transport->available - n);
-    transport->available -= n;
-    // XXX: need to check for errors
-    return n;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/dispatcher/dispatcher.h
----------------------------------------------------------------------
diff --git a/proton-c/src/dispatcher/dispatcher.h b/proton-c/src/dispatcher/dispatcher.h
deleted file mode 100644
index 29881b5..0000000
--- a/proton-c/src/dispatcher/dispatcher.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _PROTON_DISPATCHER_H
-#define _PROTON_DISPATCHER_H 1
-
-/*
- *
- * 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.
- *
- */
-
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-#include "proton/codec.h"
-#include "proton/types.h"
-
-typedef int (pn_action_t)(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
-
-ssize_t pn_dispatcher_input(pn_transport_t* transport, const char* bytes, size_t available, bool batch, bool* halt);
-ssize_t pn_dispatcher_output(pn_transport_t *transport, char *bytes, size_t size);
-
-#endif /* dispatcher.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/encodings.h.py
----------------------------------------------------------------------
diff --git a/proton-c/src/encodings.h.py b/proton-c/src/encodings.h.py
new file mode 100644
index 0000000..9f08c6c
--- /dev/null
+++ b/proton-c/src/encodings.h.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+#
+# 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 __future__ import print_function
+import mllib, optparse, os, sys
+
+xml = os.path.join(os.path.dirname(__file__), "types.xml")
+doc = mllib.xml_parse(xml)
+
+print("/* generated from %s */" % xml)
+print("#ifndef _PROTON_ENCODINGS_H")
+print("#define _PROTON_ENCODINGS_H 1")
+print()
+print("#define PNE_DESCRIPTOR          (0x00)")
+
+for enc in doc.query["amqp/section/type/encoding"]:
+  name = enc["@name"] or enc.parent["@name"]
+  # XXX: a bit hacky
+  if name == "ieee-754":
+    name = enc.parent["@name"]
+  cname = "PNE_" + name.replace("-", "_").upper()
+  print("#define %s%s(%s)" % (cname, " "*(20-len(cname)), enc["@code"]))
+
+print()
+print("#endif /* encodings.h */")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/engine/connection_engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/connection_engine.c b/proton-c/src/engine/connection_engine.c
deleted file mode 100644
index 5d184a1..0000000
--- a/proton-c/src/engine/connection_engine.c
+++ /dev/null
@@ -1,124 +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 "engine-internal.h"
-
-#include <proton/connection.h>
-#include <proton/connection_engine.h>
-#include <proton/transport.h>
-#include <string.h>
-
-int pn_connection_engine_init(pn_connection_engine_t* e) {
-    memset(e, 0, sizeof(*e));
-    e->connection = pn_connection();
-    e->transport = pn_transport();
-    e->collector = pn_collector();
-    if (!e->connection || !e->transport || !e->collector) {
-        pn_connection_engine_final(e);
-        return PN_OUT_OF_MEMORY;
-    }
-    pn_connection_collect(e->connection, e->collector);
-    return PN_OK;
-}
-
-void pn_connection_engine_final(pn_connection_engine_t* e) {
-    if (e->transport && e->connection) {
-        pn_transport_unbind(e->transport);
-        pn_decref(e->transport);
-    }
-    if (e->collector)
-        pn_collector_free(e->collector); /* Break cycle with connection */
-    if (e->connection)
-        pn_decref(e->connection);
-    memset(e, 0, sizeof(*e));
-}
-
-pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t* e) {
-    ssize_t cap = pn_transport_capacity(e->transport);
-    if (cap > 0)
-        return pn_rwbytes(cap, pn_transport_tail(e->transport));
-    else
-        return pn_rwbytes(0, 0);
-}
-
-void pn_connection_engine_read_done(pn_connection_engine_t* e, size_t n) {
-    if (n > 0)
-        pn_transport_process(e->transport, n);
-}
-
-void pn_connection_engine_read_close(pn_connection_engine_t* e) {
-    pn_transport_close_tail(e->transport);
-}
-
-pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t* e) {
-    ssize_t pending = pn_transport_pending(e->transport);
-    if (pending > 0)
-        return pn_bytes(pending, pn_transport_head(e->transport));
-    else
-        return pn_bytes(0, 0);
-}
-
-void pn_connection_engine_write_done(pn_connection_engine_t* e, size_t n) {
-    if (n > 0)
-        pn_transport_pop(e->transport, n);
-}
-
-void pn_connection_engine_write_close(pn_connection_engine_t* e){
-    pn_transport_close_head(e->transport);
-}
-
-void pn_connection_engine_disconnected(pn_connection_engine_t* e) {
-    pn_connection_engine_read_close(e);
-    pn_connection_engine_write_close(e);
-}
-
-static void log_event(pn_connection_engine_t *engine, pn_event_t* event) {
-    if (event && engine->transport->trace & PN_TRACE_EVT) {
-        pn_string_t *str = pn_string(NULL);
-        pn_inspect(event, str);
-        pn_transport_log(engine->transport, pn_string_get(str));
-        pn_free(str);
-    }
-}
-
-pn_event_t* pn_connection_engine_dispatch(pn_connection_engine_t* e) {
-    if (e->event) {             /* Already returned */
-        if (pn_event_type(e->event) == PN_CONNECTION_INIT)
-            pn_transport_bind(e->transport, e->connection);
-        pn_collector_pop(e->collector);
-    }
-    e->event = pn_collector_peek(e->collector);
-    log_event(e, e->event);
-    return e->event;
-}
-
-bool pn_connection_engine_finished(pn_connection_engine_t* e) {
-    return pn_transport_closed(e->transport) && (pn_collector_peek(e->collector) == NULL);
-}
-
-pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t* e) {
-    return e->connection;
-}
-
-pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t* e) {
-    return e->transport;
-}
-
-pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t* e) {
-    return pn_transport_condition(e->transport);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
deleted file mode 100644
index 761a840..0000000
--- a/proton-c/src/engine/engine-internal.h
+++ /dev/null
@@ -1,374 +0,0 @@
-#ifndef _PROTON_ENGINE_INTERNAL_H
-#define _PROTON_ENGINE_INTERNAL_H 1
-
-/*
- *
- * 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/object.h>
-#include <proton/engine.h>
-#include <proton/types.h>
-#include "buffer.h"
-#include "dispatcher/dispatcher.h"
-#include "util.h"
-
-typedef enum pn_endpoint_type_t {CONNECTION, SESSION, SENDER, RECEIVER} pn_endpoint_type_t;
-
-typedef struct pn_endpoint_t pn_endpoint_t;
-
-struct pn_condition_t {
-  pn_string_t *name;
-  pn_string_t *description;
-  pn_data_t *info;
-};
-
-struct pn_endpoint_t {
-  pn_endpoint_type_t type;
-  pn_state_t state;
-  pn_error_t *error;
-  pn_condition_t condition;
-  pn_condition_t remote_condition;
-  pn_endpoint_t *endpoint_next;
-  pn_endpoint_t *endpoint_prev;
-  pn_endpoint_t *transport_next;
-  pn_endpoint_t *transport_prev;
-  int refcount; // when this hits zero we generate a final event
-  bool modified;
-  bool freed;
-  bool referenced;
-};
-
-typedef struct {
-  pn_sequence_t id;
-  bool sent;
-  bool init;
-} pn_delivery_state_t;
-
-typedef struct {
-  pn_sequence_t next;
-  pn_hash_t *deliveries;
-} pn_delivery_map_t;
-
-typedef struct {
-  // XXX: stop using negative numbers
-  uint32_t local_handle;
-  uint32_t remote_handle;
-  pn_sequence_t delivery_count;
-  pn_sequence_t link_credit;
-} pn_link_state_t;
-
-typedef struct {
-  // XXX: stop using negative numbers
-  uint16_t local_channel;
-  uint16_t remote_channel;
-  bool incoming_init;
-  pn_delivery_map_t incoming;
-  pn_delivery_map_t outgoing;
-  pn_sequence_t incoming_transfer_count;
-  pn_sequence_t incoming_window;
-  pn_sequence_t remote_incoming_window;
-  pn_sequence_t outgoing_transfer_count;
-  pn_sequence_t outgoing_window;
-  pn_hash_t *local_handles;
-  pn_hash_t *remote_handles;
-
-  uint64_t disp_code;
-  bool disp_settled;
-  bool disp_type;
-  pn_sequence_t disp_first;
-  pn_sequence_t disp_last;
-  bool disp;
-} pn_session_state_t;
-
-typedef struct pn_io_layer_t {
-  ssize_t (*process_input)(struct pn_transport_t *transport, unsigned int layer, const char *, size_t);
-  ssize_t (*process_output)(struct pn_transport_t *transport, unsigned int layer, char *, size_t);
-  void (*handle_error)(struct pn_transport_t* transport, unsigned int layer);
-  pn_timestamp_t (*process_tick)(struct pn_transport_t *transport, unsigned int layer, pn_timestamp_t);
-  size_t (*buffered_output)(struct pn_transport_t *transport);  // how much output is held
-} pn_io_layer_t;
-
-extern const pn_io_layer_t pni_passthru_layer;
-extern const pn_io_layer_t ssl_layer;
-extern const pn_io_layer_t sasl_header_layer;
-extern const pn_io_layer_t sasl_write_header_layer;
-
-// Bit flag defines for the protocol layers
-typedef uint8_t pn_io_layer_flags_t;
-#define LAYER_NONE     0
-#define LAYER_AMQP1    1
-#define LAYER_AMQPSASL 2
-#define LAYER_AMQPSSL  4
-#define LAYER_SSL      8
-
-typedef struct pni_sasl_t pni_sasl_t;
-typedef struct pni_ssl_t pni_ssl_t;
-
-struct pn_transport_t {
-  pn_tracer_t tracer;
-  pni_sasl_t *sasl;
-  pni_ssl_t *ssl;
-  pn_connection_t *connection;  // reference counted
-  char *remote_container;
-  char *remote_hostname;
-  pn_data_t *remote_offered_capabilities;
-  pn_data_t *remote_desired_capabilities;
-  pn_data_t *remote_properties;
-  pn_data_t *disp_data;
-  //#define PN_DEFAULT_MAX_FRAME_SIZE (16*1024)
-#define PN_DEFAULT_MAX_FRAME_SIZE (0)  /* for now, allow unlimited size */
-  uint32_t   local_max_frame;
-  uint32_t   remote_max_frame;
-  pn_condition_t remote_condition;
-  pn_condition_t condition;
-  pn_error_t *error;
-
-#define PN_IO_LAYER_CT 3
-  const pn_io_layer_t *io_layers[PN_IO_LAYER_CT];
-
-  /* dead remote detection */
-  pn_millis_t local_idle_timeout;
-  pn_millis_t remote_idle_timeout;
-  pn_timestamp_t dead_remote_deadline;
-  uint64_t last_bytes_input;
-
-  /* keepalive */
-  pn_timestamp_t keepalive_deadline;
-  uint64_t last_bytes_output;
-
-  pn_hash_t *local_channels;
-  pn_hash_t *remote_channels;
-
-
-  /* scratch area */
-  pn_string_t *scratch;
-  pn_data_t *args;
-  pn_data_t *output_args;
-  pn_buffer_t *frame;  // frame under construction
-  // Temporary
-  size_t capacity;
-  size_t available; /* number of raw bytes pending output */
-  char *output;
-
-  /* statistics */
-  uint64_t bytes_input;
-  uint64_t bytes_output;
-  uint64_t output_frames_ct;
-  uint64_t input_frames_ct;
-
-  /* output buffered for send */
-  size_t output_size;
-  size_t output_pending;
-  char *output_buf;
-
-  /* input from peer */
-  size_t input_size;
-  size_t input_pending;
-  char *input_buf;
-
-  pn_record_t *context;
-
-  pn_trace_t trace;
-
-  /*
-   * The maximum channel number can be constrained in several ways:
-   *   1. an unchangeable limit imposed by this library code
-   *   2. a limit imposed by the remote peer when the connection is opened,
-   *      which this app must honor
-   *   3. a limit imposed by this app, which may be raised and lowered
-   *      until the OPEN frame is sent.
-   * These constraints are all summed up in channel_max, below.
-   */
-  #define PN_IMPL_CHANNEL_MAX  32767
-  uint16_t local_channel_max;
-  uint16_t remote_channel_max;
-  uint16_t channel_max;
-
-  pn_io_layer_flags_t allowed_layers;
-  pn_io_layer_flags_t present_layers;
-
-  bool freed;
-  bool open_sent;
-  bool open_rcvd;
-  bool close_sent;
-  bool close_rcvd;
-  bool tail_closed;      // input stream closed by driver
-  bool head_closed;
-  bool done_processing; // if true, don't call pn_process again
-  bool posted_idle_timeout;
-  bool server;
-  bool halt;
-  bool auth_required;
-  bool authenticated;
-  bool encryption_required;
-
-  bool referenced;
-};
-
-struct pn_connection_t {
-  pn_endpoint_t endpoint;
-  pn_endpoint_t *endpoint_head;
-  pn_endpoint_t *endpoint_tail;
-  pn_endpoint_t *transport_head;  // reference counted
-  pn_endpoint_t *transport_tail;
-  pn_list_t *sessions;
-  pn_list_t *freed;
-  pn_transport_t *transport;
-  pn_delivery_t *work_head;
-  pn_delivery_t *work_tail;
-  pn_delivery_t *tpwork_head;  // reference counted
-  pn_delivery_t *tpwork_tail;
-  pn_string_t *container;
-  pn_string_t *hostname;
-  pn_string_t *auth_user;
-  pn_string_t *auth_password;
-  pn_data_t *offered_capabilities;
-  pn_data_t *desired_capabilities;
-  pn_data_t *properties;
-  pn_collector_t *collector;
-  pn_record_t *context;
-  pn_list_t *delivery_pool;
-};
-
-struct pn_session_t {
-  pn_endpoint_t endpoint;
-  pn_connection_t *connection;  // reference counted
-  pn_list_t *links;
-  pn_list_t *freed;
-  pn_record_t *context;
-  size_t incoming_capacity;
-  pn_sequence_t incoming_bytes;
-  pn_sequence_t outgoing_bytes;
-  pn_sequence_t incoming_deliveries;
-  pn_sequence_t outgoing_deliveries;
-  pn_sequence_t outgoing_window;
-  pn_session_state_t state;
-};
-
-struct pn_terminus_t {
-  pn_string_t *address;
-  pn_data_t *properties;
-  pn_data_t *capabilities;
-  pn_data_t *outcomes;
-  pn_data_t *filter;
-  pn_durability_t durability;
-  pn_expiry_policy_t expiry_policy;
-  pn_seconds_t timeout;
-  pn_terminus_type_t type;
-  pn_distribution_mode_t distribution_mode;
-  bool dynamic;
-};
-
-struct pn_link_t {
-  pn_endpoint_t endpoint;
-  pn_terminus_t source;
-  pn_terminus_t target;
-  pn_terminus_t remote_source;
-  pn_terminus_t remote_target;
-  pn_link_state_t state;
-  pn_string_t *name;
-  pn_session_t *session;  // reference counted
-  pn_delivery_t *unsettled_head;
-  pn_delivery_t *unsettled_tail;
-  pn_delivery_t *current;
-  pn_record_t *context;
-  size_t unsettled_count;
-  pn_sequence_t available;
-  pn_sequence_t credit;
-  pn_sequence_t queued;
-  int drained; // number of drained credits
-  uint8_t snd_settle_mode;
-  uint8_t rcv_settle_mode;
-  uint8_t remote_snd_settle_mode;
-  uint8_t remote_rcv_settle_mode;
-  bool drain_flag_mode; // receiver only
-  bool drain;
-  bool detached;
-};
-
-struct pn_disposition_t {
-  pn_condition_t condition;
-  uint64_t type;
-  pn_data_t *data;
-  pn_data_t *annotations;
-  uint64_t section_offset;
-  uint32_t section_number;
-  bool failed;
-  bool undeliverable;
-  bool settled;
-};
-
-struct pn_delivery_t {
-  pn_disposition_t local;
-  pn_disposition_t remote;
-  pn_link_t *link;  // reference counted
-  pn_buffer_t *tag;
-  pn_delivery_t *unsettled_next;
-  pn_delivery_t *unsettled_prev;
-  pn_delivery_t *work_next;
-  pn_delivery_t *work_prev;
-  pn_delivery_t *tpwork_next;
-  pn_delivery_t *tpwork_prev;
-  pn_delivery_state_t state;
-  pn_buffer_t *bytes;
-  pn_record_t *context;
-  bool updated;
-  bool settled; // tracks whether we're in the unsettled list or not
-  bool work;
-  bool tpwork;
-  bool done;
-  bool referenced;
-};
-
-#define PN_SET_LOCAL(OLD, NEW)                                          \
-  (OLD) = ((OLD) & PN_REMOTE_MASK) | (NEW)
-
-#define PN_SET_REMOTE(OLD, NEW)                                         \
-  (OLD) = ((OLD) & PN_LOCAL_MASK) | (NEW)
-
-void pn_link_dump(pn_link_t *link);
-
-void pn_dump(pn_connection_t *conn);
-void pn_transport_sasl_init(pn_transport_t *transport);
-
-void pn_condition_init(pn_condition_t *condition);
-void pn_condition_tini(pn_condition_t *condition);
-void pn_modified(pn_connection_t *connection, pn_endpoint_t *endpoint, bool emit);
-void pn_real_settle(pn_delivery_t *delivery);  // will free delivery if link is freed
-void pn_clear_tpwork(pn_delivery_t *delivery);
-void pn_work_update(pn_connection_t *connection, pn_delivery_t *delivery);
-void pn_clear_modified(pn_connection_t *connection, pn_endpoint_t *endpoint);
-void pn_connection_bound(pn_connection_t *conn);
-void pn_connection_unbound(pn_connection_t *conn);
-int pn_do_error(pn_transport_t *transport, const char *condition, const char *fmt, ...);
-void pn_set_error_layer(pn_transport_t *transport);
-void pn_session_unbound(pn_session_t* ssn);
-void pn_link_unbound(pn_link_t* link);
-void pn_ep_incref(pn_endpoint_t *endpoint);
-void pn_ep_decref(pn_endpoint_t *endpoint);
-
-int pn_post_frame(pn_transport_t *transport, uint8_t type, uint16_t ch, const char *fmt, ...);
-
-typedef enum {IN, OUT} pn_dir_t;
-
-void pn_do_trace(pn_transport_t *transport, uint16_t ch, pn_dir_t dir,
-                 pn_data_t *args, const char *payload, size_t size);
-
-#endif /* engine-internal.h */


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


[03/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce proton-c core library - Created new core proton library qpid-proton-core which only contains protocol processsing and no IO. - Rearranged source tree to separate core protocol code and

Posted by as...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/transport/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.h b/proton-c/src/transport/transport.h
deleted file mode 100644
index 66ebc51..0000000
--- a/proton-c/src/transport/transport.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _PROTON_TRANSPORT_INTERNAL_H
-#define _PROTON_TRANSPORT_INTERNAL_H 1
-
-/*
- *
- * 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.
- *
- */
-
-void pn_delivery_map_init(pn_delivery_map_t *db, pn_sequence_t next);
-void pn_delivery_map_del(pn_delivery_map_t *db, pn_delivery_t *delivery);
-void pn_delivery_map_free(pn_delivery_map_t *db);
-void pn_unmap_handle(pn_session_t *ssn, pn_link_t *link);
-void pn_unmap_channel(pn_transport_t *transport, pn_session_t *ssn);
-
-#endif /* transport.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/types.c
----------------------------------------------------------------------
diff --git a/proton-c/src/types.c b/proton-c/src/types.c
deleted file mode 100644
index 4f8048d..0000000
--- a/proton-c/src/types.c
+++ /dev/null
@@ -1,41 +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 "platform.h"
-#include <proton/types.h>
-#include <stdlib.h>
-#include <string.h>
-
-pn_bytes_t pn_bytes(size_t size, const char *start)
-{
-  pn_bytes_t bytes = {size, start};
-  return bytes;
-}
-
-pn_rwbytes_t pn_rwbytes(size_t size, char *start)
-{
-  pn_rwbytes_t bytes = {size, start};
-  return bytes;
-}
-
-pn_timestamp_t pn_timestamp_now() {
-  return pn_i_now();
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/types.xml
----------------------------------------------------------------------
diff --git a/proton-c/src/types.xml b/proton-c/src/types.xml
new file mode 100644
index 0000000..4aa9c0f
--- /dev/null
+++ b/proton-c/src/types.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+
+<!--
+Copyright Bank of America, N.A., Barclays Bank PLC, Cisco Systems, Credit
+Suisse, Deutsche Boerse, Envoy Technologies Inc., Goldman Sachs, HCL
+Technologies Ltd, IIT Software GmbH, iMatix Corporation, INETCO Systems Limited,
+Informatica Corporation, JPMorgan Chase & Co., Kaazing Corporation, N.A,
+Microsoft Corporation, my-Channels, Novell, Progress Software, Red Hat Inc.,
+Software AG, Solace Systems Inc., StormMQ Ltd., Tervela Inc., TWIST Process
+Innovations Ltd, VMware, Inc., and WS02 Inc. 2006-2011. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+-->
+
+<amqp name="types" xmlns="http://www.amqp.org/schema/amqp.xsd">
+  <section name="encodings">
+    <type name="null" class="primitive">
+      <encoding code="0x40" category="fixed" width="0"/>
+    </type>
+    <type name="boolean" class="primitive">
+      <encoding code="0x56" category="fixed" width="1"/>
+      <encoding name="true" code="0x41" category="fixed" width="0"/>
+      <encoding name="false" code="0x42" category="fixed" width="0"/>
+    </type>
+    <type name="ubyte" class="primitive">
+      <encoding code="0x50" category="fixed" width="1"/>
+    </type>
+    <type name="ushort" class="primitive">
+      <encoding code="0x60" category="fixed" width="2"/>
+    </type>
+    <type name="uint" class="primitive">
+      <encoding code="0x70" category="fixed" width="4"/>
+      <encoding name="smalluint" code="0x52" category="fixed" width="1"/>
+      <encoding name="uint0" code="0x43" category="fixed" width="0"/>
+    </type>
+    <type name="ulong" class="primitive">
+      <encoding code="0x80" category="fixed" width="8"/>
+      <encoding name="smallulong" code="0x53" category="fixed" width="1"/>
+      <encoding name="ulong0" code="0x44" category="fixed" width="0"/>
+    </type>
+    <type name="byte" class="primitive">
+      <encoding code="0x51" category="fixed" width="1"/>
+    </type>
+    <type name="short" class="primitive">
+      <encoding code="0x61" category="fixed" width="2"/>
+    </type>
+    <type name="int" class="primitive">
+      <encoding code="0x71" category="fixed" width="4"/>
+      <encoding name="smallint" code="0x54" category="fixed" width="1"/>
+    </type>
+    <type name="long" class="primitive">
+      <encoding code="0x81" category="fixed" width="8"/>
+      <encoding name="smalllong" code="0x55" category="fixed" width="1"/>
+    </type>
+    <type name="float" class="primitive">
+      <encoding name="ieee-754" code="0x72" category="fixed" width="4"/>
+    </type>
+    <type name="double" class="primitive">
+      <encoding name="ieee-754" code="0x82" category="fixed" width="8"/>
+    </type>
+    <type name="decimal32" class="primitive">
+      <encoding name="ieee-754" code="0x74" category="fixed" width="4"/>
+    </type>
+    <type name="decimal64" class="primitive">
+      <encoding name="ieee-754" code="0x84" category="fixed" width="8"/>
+    </type>
+    <type name="decimal128" class="primitive">
+      <encoding name="ieee-754" code="0x94" category="fixed" width="16"/>
+    </type>
+    <type name="char" class="primitive">
+      <encoding name="utf32" code="0x73" category="fixed" width="4"/>
+    </type>
+    <type name="timestamp" class="primitive">
+      <encoding name="ms64" code="0x83" category="fixed" width="8"/>
+    </type>
+    <type name="uuid" class="primitive">
+      <encoding code="0x98" category="fixed" width="16"/>
+    </type>
+    <type name="binary" class="primitive">
+      <encoding name="vbin8" code="0xa0" category="variable" width="1"/>
+      <encoding name="vbin32" code="0xb0" category="variable" width="4"/>
+    </type>
+    <type name="string" class="primitive">
+      <encoding name="str8-utf8" code="0xa1" category="variable" width="1"/>
+      <encoding name="str32-utf8" code="0xb1" category="variable" width="4"/>
+    </type>
+    <type name="symbol" class="primitive">
+      <encoding name="sym8" code="0xa3" category="variable" width="1"/>
+      <encoding name="sym32" code="0xb3" category="variable" width="4"/>
+    </type>
+    <type name="list" class="primitive">
+      <encoding name="list0" code="0x45" category="fixed" width="0"/>
+      <encoding name="list8" code="0xc0" category="compound" width="1"/>
+      <encoding name="list32" code="0xd0" category="compound" width="4"/>
+    </type>
+    <type name="map" class="primitive">
+      <encoding name="map8" code="0xc1" category="compound" width="1"/>
+      <encoding name="map32" code="0xd1" category="compound" width="4"/>
+    </type>
+    <type name="array" class="primitive">
+      <encoding name="array8" code="0xe0" category="array" width="1"/>
+      <encoding name="array32" code="0xf0" category="array" width="4"/>
+    </type>
+  </section>
+</amqp>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/url.c
----------------------------------------------------------------------
diff --git a/proton-c/src/url.c b/proton-c/src/url.c
deleted file mode 100644
index 566e91e..0000000
--- a/proton-c/src/url.c
+++ /dev/null
@@ -1,186 +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/url.h"
-#include "proton/object.h"
-#include "util.h"
-#include "platform.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-static char* copy(const char* str) {
-    if (str ==  NULL) return NULL;
-    char *str2 = (char*)malloc(strlen(str)+1);
-    if (str2) strcpy(str2, str);
-    return str2;
-}
-
-struct pn_url_t {
-    char *scheme;
-    char *username;
-    char *password;
-    char *host;
-    char *port;
-    char *path;
-    pn_string_t *str;
-};
-
-/** Internal use only, returns the pn_string_t. Public function is pn_url_str() */
-static pn_string_t *pn_url_string(pn_url_t* url)
-{
-    pn_url_str(url);               /* Make sure str is up to date */
-    return url->str;
-}
-
-static void pn_url_finalize(void *object)
-{
-    pn_url_t *url = (pn_url_t *) object;
-    pn_url_clear(url);
-    pn_free(url->str);
-}
-
-static uintptr_t pn_url_hashcode(void *object)
-{
-    pn_url_t *url = (pn_url_t *) object;
-    return pn_hashcode(pn_url_string(url));
-}
-
-static intptr_t pn_url_compare(void *oa, void *ob)
-{
-    pn_url_t *a = (pn_url_t *) oa;
-    pn_url_t *b = (pn_url_t *) ob;
-    return pn_compare(pn_url_string(a), pn_url_string(b));
-}
-
-
-static int pn_url_inspect(void *obj, pn_string_t *dst)
-{
-    pn_url_t *url = (pn_url_t *) obj;
-    int err = 0;
-    err = pn_string_addf(dst, "Url("); if (err) return err;
-    err = pn_inspect(pn_url_string(url), dst); if (err) return err;
-    return pn_string_addf(dst, ")");
-}
-
-#define pn_url_initialize NULL
-
-
-pn_url_t *pn_url() {
-    static const pn_class_t clazz = PN_CLASS(pn_url);
-    pn_url_t *url = (pn_url_t*) pn_class_new(&clazz, sizeof(pn_url_t));
-    if (!url) return NULL;
-    memset(url, 0, sizeof(*url));
-    url->str = pn_string(NULL);
-    return url;
-}
-
-/** Parse a string URL as a pn_url_t.
- *@param[in] url A URL string.
- *@return The parsed pn_url_t or NULL if url is not a valid URL string.
- */
-pn_url_t *pn_url_parse(const char *str) {
-    if (!str || !*str)          /* Empty string or NULL is illegal. */
-        return NULL;
-
-    pn_url_t *url = pn_url();
-    char *str2 = copy(str);
-    pni_parse_url(str2, &url->scheme, &url->username, &url->password, &url->host, &url->port, &url->path);
-    url->scheme = copy(url->scheme);
-    url->username = copy(url->username);
-    url->password = copy(url->password);
-    url->host = (url->host && !*url->host) ? NULL : copy(url->host);
-    url->port = copy(url->port);
-    url->path = copy(url->path);
-
-    free(str2);
-    return url;
-}
-
-/** Free a URL */
-void pn_url_free(pn_url_t *url) { pn_free(url); }
-
-/** Clear the contents of the URL. */
-void pn_url_clear(pn_url_t *url) {
-    pn_url_set_scheme(url, NULL);
-    pn_url_set_username(url, NULL);
-    pn_url_set_password(url, NULL);
-    pn_url_set_host(url, NULL);
-    pn_url_set_port(url, NULL);
-    pn_url_set_path(url, NULL);
-    pn_string_clear(url->str);
-}
-
-/** URL-encode src and append to dst. */
-static void pni_urlencode(pn_string_t *dst, const char* src) {
-    static const char *bad = "@:/";
-
-    if (!src) return;
-    const char *i = src;
-    const char *j = strpbrk(i, bad);
-    while (j) {
-        pn_string_addf(dst, "%.*s", (int)(j-i), i);
-        pn_string_addf(dst, "%%%02X", (int)*j);
-        i = j + 1;
-        j = strpbrk(i, bad);
-    }
-    pn_string_addf(dst, "%s", i);
-}
-
-
-/** Return the string form of a URL. */
-const char *pn_url_str(pn_url_t *url) {
-    if (pn_string_get(url->str) == NULL) {
-        pn_string_set(url->str, "");
-        if (url->scheme) pn_string_addf(url->str, "%s://", url->scheme);
-        if (url->username) pni_urlencode(url->str, url->username);
-        if (url->password) {
-            pn_string_addf(url->str, ":");
-            pni_urlencode(url->str, url->password);
-        }
-        if (url->username || url->password) pn_string_addf(url->str, "@");
-        if (url->host) {
-            if (strchr(url->host, ':')) pn_string_addf(url->str, "[%s]", url->host);
-            else pn_string_addf(url->str, "%s", url->host);
-        }
-        if (url->port) pn_string_addf(url->str, ":%s", url->port);
-        if (url->path) pn_string_addf(url->str, "/%s", url->path);
-    }
-    return pn_string_get(url->str);
-}
-
-const char *pn_url_get_scheme(pn_url_t *url) { return url->scheme; }
-const char *pn_url_get_username(pn_url_t *url) { return url->username; }
-const char *pn_url_get_password(pn_url_t *url) { return url->password; }
-const char *pn_url_get_host(pn_url_t *url) { return url->host; }
-const char *pn_url_get_port(pn_url_t *url) { return url->port; }
-const char *pn_url_get_path(pn_url_t *url) { return url->path; }
-
-#define SET(part) free(url->part); url->part = copy(part); pn_string_clear(url->str)
-void pn_url_set_scheme(pn_url_t *url, const char *scheme) { SET(scheme); }
-void pn_url_set_username(pn_url_t *url, const char *username) { SET(username); }
-void pn_url_set_password(pn_url_t *url, const char *password) { SET(password); }
-void pn_url_set_host(pn_url_t *url, const char *host) { SET(host); }
-void pn_url_set_port(pn_url_t *url, const char *port) { SET(port); }
-void pn_url_set_path(pn_url_t *url, const char *path) { SET(path); }
-
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/util.c
----------------------------------------------------------------------
diff --git a/proton-c/src/util.c b/proton-c/src/util.c
deleted file mode 100644
index 47fbc34..0000000
--- a/proton-c/src/util.c
+++ /dev/null
@@ -1,274 +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 <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <proton/type_compat.h>
-#include <ctype.h>
-#include <string.h>
-#include <proton/error.h>
-#include <proton/types.h>
-#include "util.h"
-
-ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size)
-{
-  int idx = 0;
-  for (unsigned i = 0; i < size; i++)
-  {
-    uint8_t c = src[i];
-    if (isprint(c)) {
-      if (idx < (int) (capacity - 1)) {
-        dst[idx++] = c;
-      } else {
-        if (idx > 0) {
-          dst[idx - 1] = '\0';
-        }
-        return PN_OVERFLOW;
-      }
-    } else {
-      if (idx < (int) (capacity - 4)) {
-        idx += sprintf(dst + idx, "\\x%.2x", c);
-      } else {
-        if (idx > 0) {
-          dst[idx - 1] = '\0';
-        }
-        return PN_OVERFLOW;
-      }
-    }
-  }
-
-  dst[idx] = '\0';
-  return idx;
-}
-
-int pn_quote(pn_string_t *dst, const char *src, size_t size)
-{
-  while (true) {
-    size_t str_size = pn_string_size(dst);
-    char *str = pn_string_buffer(dst) + str_size;
-    size_t capacity = pn_string_capacity(dst) - str_size;
-    ssize_t ssize = pn_quote_data(str, capacity, src, size);
-    if (ssize == PN_OVERFLOW) {
-      int err = pn_string_grow(dst, (str_size + capacity) ? 2*(str_size + capacity) : 16);
-      if (err) return err;
-    } else if (ssize >= 0) {
-      return pn_string_resize(dst, str_size + ssize);
-    } else {
-      return ssize;
-    }
-  }
-}
-
-void pn_fprint_data(FILE *stream, const char *bytes, size_t size)
-{
-  char buf[256];
-  ssize_t n = pn_quote_data(buf, 256, bytes, size);
-  if (n >= 0) {
-    fputs(buf, stream);
-  } else {
-    if (n == PN_OVERFLOW) {
-      fputs(buf, stream);
-      fputs("... (truncated)", stream);
-    }
-    else
-      fprintf(stderr, "pn_quote_data: %s\n", pn_code(n));
-  }
-}
-
-void pn_print_data(const char *bytes, size_t size)
-{
-  pn_fprint_data(stdout, bytes, size);
-}
-
-void pni_urldecode(const char *src, char *dst)
-{
-  const char *in = src;
-  char *out = dst;
-  while (*in != '\0')
-  {
-    if ('%' == *in)
-    {
-      if ((in[1] != '\0') && (in[2] != '\0'))
-      {
-        char esc[3];
-        esc[0] = in[1];
-        esc[1] = in[2];
-        esc[2] = '\0';
-        unsigned long d = strtoul(esc, NULL, 16);
-        *out = (char)d;
-        in += 3;
-        out++;
-      }
-      else
-      {
-        *out = *in;
-        in++;
-        out++;
-      }
-    }
-    else
-    {
-      *out = *in;
-      in++;
-      out++;
-    }
-  }
-  *out = '\0';
-}
-
-void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path)
-{
-  if (!url) return;
-
-  char *slash = strchr(url, '/');
-
-  if (slash && slash>url) {
-    char *scheme_end = strstr(slash-1, "://");
-
-    if (scheme_end && scheme_end<slash) {
-      *scheme_end = '\0';
-      *scheme = url;
-      url = scheme_end + 3;
-      slash = strchr(url, '/');
-    }
-  }
-
-  if (slash) {
-    *slash = '\0';
-    *path = slash + 1;
-  }
-
-  char *at = strchr(url, '@');
-  if (at) {
-    *at = '\0';
-    char *up = url;
-    *user = up;
-    url = at + 1;
-    char *colon = strchr(up, ':');
-    if (colon) {
-      *colon = '\0';
-      *pass = colon + 1;
-    }
-  }
-
-  *host = url;
-  char *open = (*url == '[') ? url : 0;
-  if (open) {
-    char *close = strchr(open, ']');
-    if (close) {
-        *host = open + 1;
-        *close = '\0';
-        url = close + 1;
-    }
-  }
-
-  char *colon = strchr(url, ':');
-  if (colon) {
-    *colon = '\0';
-    *port = colon + 1;
-  }
-
-  if (*user) pni_urldecode(*user, *user);
-  if (*pass) pni_urldecode(*pass, *pass);
-}
-
-void pni_vfatal(const char *fmt, va_list ap)
-{
-  vfprintf(stderr, fmt, ap);
-  abort();
-}
-
-void pni_fatal(const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  pni_vfatal(fmt, ap);
-  va_end(ap);
-}
-
-int pn_strcasecmp(const char *a, const char *b)
-{
-  int diff;
-  while (*b) {
-    char aa = *a++, bb = *b++;
-    diff = tolower(aa)-tolower(bb);
-    if ( diff!=0 ) return diff;
-  }
-  return *a;
-}
-
-int pn_strncasecmp(const char* a, const char* b, size_t len)
-{
-  int diff = 0;
-  while (*b && len > 0) {
-    char aa = *a++, bb = *b++;
-    diff = tolower(aa)-tolower(bb);
-    if ( diff!=0 ) return diff;
-    --len;
-  };
-  return len==0 ? diff : *a;
-}
-
-bool pn_env_bool(const char *name)
-{
-  char *v = getenv(name);
-  return v && (!pn_strcasecmp(v, "true") || !pn_strcasecmp(v, "1") ||
-               !pn_strcasecmp(v, "yes")  || !pn_strcasecmp(v, "on"));
-}
-
-char *pn_strdup(const char *src)
-{
-  if (src) {
-    char *dest = (char *) malloc((strlen(src)+1)*sizeof(char));
-    if (!dest) return NULL;
-    return strcpy(dest, src);
-  } else {
-    return NULL;
-  }
-}
-
-char *pn_strndup(const char *src, size_t n)
-{
-  if (src) {
-    unsigned size = 0;
-    for (const char *c = src; size < n && *c; c++) {
-      size++;
-    }
-
-    char *dest = (char *) malloc(size + 1);
-    if (!dest) return NULL;
-    strncpy(dest, src, n);
-    dest[size] = '\0';
-    return dest;
-  } else {
-    return NULL;
-  }
-}
-
-// which timestamp will expire next, or zero if none set
-pn_timestamp_t pn_timestamp_min( pn_timestamp_t a, pn_timestamp_t b )
-{
-  if (a && b) return pn_min(a, b);
-  if (a) return a;
-  return b;
-}
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/util.h b/proton-c/src/util.h
deleted file mode 100644
index ec59a07..0000000
--- a/proton-c/src/util.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef _PROTON_SRC_UTIL_H
-#define _PROTON_SRC_UTIL_H 1
-
-/*
- *
- * 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 <errno.h>
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <proton/types.h>
-#include <proton/object.h>
-
-void pni_parse_url(char *url, char **scheme, char **user, char **pass, char **host, char **port, char **path);
-void pni_fatal(const char *fmt, ...);
-void pni_vfatal(const char *fmt, va_list ap);
-ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size);
-int pn_quote(pn_string_t *dst, const char *src, size_t size);
-void pn_fprint_data(FILE *stream, const char *bytes, size_t size);
-void pn_print_data(const char *bytes, size_t size);
-bool pn_env_bool(const char *name);
-pn_timestamp_t pn_timestamp_min(pn_timestamp_t a, pn_timestamp_t b);
-
-char *pn_strdup(const char *src);
-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);
-
-#define DIE_IFR(EXPR, STRERR)                                           \
-  do {                                                                  \
-    int __code__ = (EXPR);                                              \
-    if (__code__) {                                                     \
-      fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__,       \
-              #EXPR, STRERR(__code__), __code__);                       \
-      exit(-1);                                                         \
-    }                                                                   \
-  } while (0)
-
-#define DIE_IFE(EXPR)                                                   \
-  do {                                                                  \
-    if ((EXPR) == -1) {                                                 \
-      int __code__ = errno;                                             \
-      fprintf(stderr, "%s:%d: %s: %s (%d)\n", __FILE__, __LINE__,       \
-              #EXPR, strerror(__code__), __code__);                     \
-      exit(-1);                                                         \
-    }                                                                   \
-  } while (0)
-
-
-#define LL_HEAD(ROOT, LIST) ((ROOT)-> LIST ## _head)
-#define LL_TAIL(ROOT, LIST) ((ROOT)-> LIST ## _tail)
-#define LL_ADD(ROOT, LIST, NODE)                              \
-  {                                                           \
-    (NODE)-> LIST ## _next = NULL;                            \
-    (NODE)-> LIST ## _prev = (ROOT)-> LIST ## _tail;          \
-    if (LL_TAIL(ROOT, LIST))                                  \
-      LL_TAIL(ROOT, LIST)-> LIST ## _next = (NODE);           \
-    LL_TAIL(ROOT, LIST) = (NODE);                             \
-    if (!LL_HEAD(ROOT, LIST)) LL_HEAD(ROOT, LIST) = (NODE);   \
-  }
-
-#define LL_POP(ROOT, LIST, TYPE)                              \
-  {                                                           \
-    if (LL_HEAD(ROOT, LIST)) {                                \
-      TYPE *_old = LL_HEAD(ROOT, LIST);                       \
-      LL_HEAD(ROOT, LIST) = LL_HEAD(ROOT, LIST)-> LIST ## _next; \
-      _old-> LIST ## _next = NULL;                            \
-      if (_old == LL_TAIL(ROOT, LIST)) {                      \
-        LL_TAIL(ROOT, LIST) = NULL;                           \
-      } else {                                                \
-        LL_HEAD(ROOT, LIST)-> LIST ## _prev = NULL;           \
-      }                                                       \
-    }                                                         \
-  }
-
-#define LL_REMOVE(ROOT, LIST, NODE)                                    \
-  {                                                                    \
-    if ((NODE)-> LIST ## _prev)                                        \
-      (NODE)-> LIST ## _prev-> LIST ## _next = (NODE)-> LIST ## _next; \
-    if ((NODE)-> LIST ## _next)                                        \
-      (NODE)-> LIST ## _next-> LIST ## _prev = (NODE)-> LIST ## _prev; \
-    if ((NODE) == LL_HEAD(ROOT, LIST))                                 \
-      LL_HEAD(ROOT, LIST) = (NODE)-> LIST ## _next;                    \
-    if ((NODE) == LL_TAIL(ROOT, LIST))                                 \
-      LL_TAIL(ROOT, LIST) = (NODE)-> LIST ## _prev;                    \
-  }
-
-#define pn_min(X,Y) ((X) > (Y) ? (Y) : (X))
-#define pn_max(X,Y) ((X) < (Y) ? (Y) : (X))
-
-#define PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE)                 \
-  while ((CAPACITY) < (COUNT)) {                                \
-    (CAPACITY) = (CAPACITY) ? 2 * (CAPACITY) : 16;              \
-    (ARRAY) = (TYPE *) realloc((ARRAY), (CAPACITY) * sizeof (TYPE));    \
-  }                                                             \
-
-#define PN_ENSUREZ(ARRAY, CAPACITY, COUNT, TYPE)           \
-  {                                                        \
-    size_t _old_capacity = (CAPACITY);                     \
-    PN_ENSURE(ARRAY, CAPACITY, COUNT, TYPE);               \
-    memset((ARRAY) + _old_capacity, 0,                     \
-           sizeof(TYPE)*((CAPACITY) - _old_capacity));     \
-  }
-
-#endif /* util.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/io.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/io.c b/proton-c/src/windows/io.c
deleted file mode 100644
index 4a87fd2..0000000
--- a/proton-c/src/windows/io.c
+++ /dev/null
@@ -1,457 +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.
- *
- */
-
-#define FD_SETSIZE 2048
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <mswsock.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/io.h>
-#include <proton/object.h>
-#include <proton/selector.h>
-#include "iocp.h"
-#include "util.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <assert.h>
-
-int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code)
-{
-  // Error code can be from GetLastError or WSAGetLastError,
-  char err[1024] = {0};
-  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
-                FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL);
-  return pn_error_format(error, PN_ERR, "%s: %s", msg, err);
-}
-
-static void io_log(const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  va_end(ap);
-  fflush(stderr);
-}
-
-struct pn_io_t {
-  char host[NI_MAXHOST];
-  char serv[NI_MAXSERV];
-  pn_error_t *error;
-  bool trace;
-  bool wouldblock;
-  iocp_t *iocp;
-};
-
-void pn_io_initialize(void *obj)
-{
-  pn_io_t *io = (pn_io_t *) obj;
-  io->error = pn_error();
-  io->wouldblock = false;
-  io->trace = pn_env_bool("PN_TRACE_DRV");
-
-  /* Request WinSock 2.2 */
-  WORD wsa_ver = MAKEWORD(2, 2);
-  WSADATA unused;
-  int err = WSAStartup(wsa_ver, &unused);
-  if (err) {
-    pni_win32_error(io->error, "WSAStartup", WSAGetLastError());
-    fprintf(stderr, "Can't load WinSock: %s\n", pn_error_text(io->error));
-  }
-  io->iocp = pni_iocp();
-}
-
-void pn_io_finalize(void *obj)
-{
-  pn_io_t *io = (pn_io_t *) obj;
-  pn_error_free(io->error);
-  pn_free(io->iocp);
-  WSACleanup();
-}
-
-#define pn_io_hashcode NULL
-#define pn_io_compare NULL
-#define pn_io_inspect
-
-pn_io_t *pn_io(void)
-{
-  static const pn_class_t clazz = PN_CLASS(pn_io);
-  pn_io_t *io = (pn_io_t *) pn_class_new(&clazz, sizeof(pn_io_t));
-  return io;
-}
-
-void pn_io_free(pn_io_t *io)
-{
-  pn_free(io);
-}
-
-pn_error_t *pn_io_error(pn_io_t *io)
-{
-  assert(io);
-  return io->error;
-}
-
-static void ensure_unique(pn_io_t *io, pn_socket_t new_socket)
-{
-  // A brand new socket can have the same HANDLE value as a previous
-  // one after a socketclose.  If the application closes one itself
-  // (i.e. not using pn_close), we don't find out about it until here.
-  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, new_socket);
-  if (iocpd) {
-    if (io->trace)
-      io_log("Stale external socket reference discarded\n");
-    // Re-use means former socket instance was closed
-    assert(iocpd->ops_in_progress == 0);
-    assert(iocpd->external);
-    // Clean up the straggler as best we can
-    pn_socket_t sock = iocpd->socket;
-    iocpd->socket = INVALID_SOCKET;
-    pni_iocpdesc_map_del(io->iocp, sock);  // may free the iocpdesc_t depending on refcount
-  }
-}
-
-
-/*
- * This heavyweight surrogate pipe could be replaced with a normal Windows pipe
- * now that select() is no longer used.  If interrupt semantics are all that is
- * needed, a simple user space counter and reserved completion status would
- * probably suffice.
- */
-static int pni_socket_pair(pn_io_t *io, SOCKET sv[2]);
-
-int pn_pipe(pn_io_t *io, pn_socket_t *dest)
-{
-  int n = pni_socket_pair(io, dest);
-  if (n) {
-    pni_win32_error(io->error, "pipe", WSAGetLastError());
-  }
-  return n;
-}
-
-static void pn_configure_sock(pn_io_t *io, pn_socket_t sock) {
-  //
-  // Disable the Nagle algorithm on TCP connections.
-  //
-  int flag = 1;
-  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) != 0) {
-    perror("setsockopt");
-  }
-
-  u_long nonblock = 1;
-  if (ioctlsocket(sock, FIONBIO, &nonblock)) {
-    perror("ioctlsocket");
-  }
-}
-
-static inline pn_socket_t pni_create_socket(int domain, int protocol);
-
-static const char *amqp_service(const char *port) {
-  // Help older Windows to know about amqp[s] ports
-  if (port) {
-    if (!strcmp("amqp", port)) return "5672";
-    if (!strcmp("amqps", port)) return "5671";
-  }
-  return port;
-}
-
-pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port)
-{
-  struct addrinfo *addr;
-  int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
-  if (code) {
-    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code));
-    return INVALID_SOCKET;
-  }
-
-  pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
-  if (sock == INVALID_SOCKET) {
-    pni_win32_error(io->error, "pni_create_socket", WSAGetLastError());
-    return INVALID_SOCKET;
-  }
-  ensure_unique(io, sock);
-
-  bool optval = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &optval,
-                 sizeof(optval)) == -1) {
-    pni_win32_error(io->error, "setsockopt", WSAGetLastError());
-    closesocket(sock);
-    return INVALID_SOCKET;
-  }
-
-  if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
-    pni_win32_error(io->error, "bind", WSAGetLastError());
-    freeaddrinfo(addr);
-    closesocket(sock);
-    return INVALID_SOCKET;
-  }
-  freeaddrinfo(addr);
-
-  if (listen(sock, 50) == -1) {
-    pni_win32_error(io->error, "listen", WSAGetLastError());
-    closesocket(sock);
-    return INVALID_SOCKET;
-  }
-
-  if (io->iocp->selector) {
-    iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
-    if (!iocpd) {
-      pn_i_error_from_errno(io->error, "register");
-      closesocket(sock);
-      return INVALID_SOCKET;
-    }
-    pni_iocpdesc_start(iocpd);
-  }
-
-  return sock;
-}
-
-pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port)
-{
-  // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets
-  const char *host = strcmp("0.0.0.0", hostarg) ? hostarg : "127.0.0.1";
-
-  struct addrinfo *addr;
-  int code = getaddrinfo(host, amqp_service(port), NULL, &addr);
-  if (code) {
-    pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
-    return INVALID_SOCKET;
-  }
-
-  pn_socket_t sock = pni_create_socket(addr->ai_family, addr->ai_protocol);
-  if (sock == INVALID_SOCKET) {
-    pni_win32_error(io->error, "proton pni_create_socket", WSAGetLastError());
-    freeaddrinfo(addr);
-    return INVALID_SOCKET;
-  }
-
-  ensure_unique(io, sock);
-  pn_configure_sock(io, sock);
-
-  if (io->iocp->selector) {
-    return pni_iocp_begin_connect(io->iocp, sock, addr, io->error);
-  } else {
-    if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
-      if (WSAGetLastError() != WSAEWOULDBLOCK) {
-	pni_win32_error(io->error, "connect", WSAGetLastError());
-	freeaddrinfo(addr);
-	closesocket(sock);
-	return INVALID_SOCKET;
-      }
-    }
-
-    freeaddrinfo(addr);
-    return sock;
-  }
-}
-
-pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size)
-{
-  struct sockaddr_storage addr;
-  socklen_t addrlen = sizeof(addr);
-  iocpdesc_t *listend = pni_iocpdesc_map_get(io->iocp, listen_sock);
-  pn_socket_t accept_sock;
-
-  *name = '\0';
-  if (listend)
-    accept_sock = pni_iocp_end_accept(listend, (struct sockaddr *) &addr, &addrlen, &io->wouldblock, io->error);
-  else {
-    // User supplied socket
-    accept_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen);
-    if (accept_sock == INVALID_SOCKET)
-      pni_win32_error(io->error, "sync accept", WSAGetLastError());
-  }
-
-  if (accept_sock == INVALID_SOCKET)
-    return accept_sock;
-
-  int code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
-                         io->serv, NI_MAXSERV, 0);
-  if (code)
-    code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST,
-                       io->serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
-  if (code) {
-    pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code));
-    pn_close(io, accept_sock);
-    return INVALID_SOCKET;
-  } else {
-    pn_configure_sock(io, accept_sock);
-    snprintf(name, size, "%s:%s", io->host, io->serv);
-    if (listend) {
-      pni_iocpdesc_start(pni_iocpdesc_map_get(io->iocp, accept_sock));
-    }
-    return accept_sock;
-  }
-}
-
-static inline pn_socket_t pni_create_socket(int domain, int protocol) {
-  return socket(domain, SOCK_STREAM, protocol);
-}
-
-ssize_t pn_send(pn_io_t *io, pn_socket_t sockfd, const void *buf, size_t len) {
-  ssize_t count;
-  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, sockfd);
-  if (iocpd) {
-    count = pni_iocp_begin_write(iocpd, buf, len, &io->wouldblock, io->error);
-  } else {
-    count = send(sockfd, (const char *) buf, len, 0);
-    io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
-  }
-  return count;
-}
-
-ssize_t pn_recv(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
-  ssize_t count;
-  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
-  if (iocpd) {
-    count = pni_iocp_recv(iocpd, buf, size, &io->wouldblock, io->error);
-  } else {
-    count = recv(socket, (char *) buf, size, 0);
-    io->wouldblock = count < 0 && WSAGetLastError() == WSAEWOULDBLOCK;
-  }
-  return count;
-}
-
-ssize_t pn_write(pn_io_t *io, pn_socket_t socket, const void *buf, size_t size)
-{
-  // non-socket io is mapped to socket io for now.  See pn_pipe()
-  return pn_send(io, socket, buf, size);
-}
-
-ssize_t pn_read(pn_io_t *io, pn_socket_t socket, void *buf, size_t size)
-{
-  return pn_recv(io, socket, buf, size);
-}
-
-void pn_close(pn_io_t *io, pn_socket_t socket)
-{
-  iocpdesc_t *iocpd = pni_iocpdesc_map_get(io->iocp, socket);
-  if (iocpd)
-    pni_iocp_begin_close(iocpd);
-  else {
-    closesocket(socket);
-  }
-}
-
-bool pn_wouldblock(pn_io_t *io)
-{
-  return io->wouldblock;
-}
-
-pn_selector_t *pn_io_selector(pn_io_t *io)
-{
-  if (io->iocp->selector == NULL)
-    io->iocp->selector = pni_selector_create(io->iocp);
-  return io->iocp->selector;
-}
-
-static void configure_pipe_socket(pn_io_t *io, pn_socket_t sock)
-{
-  u_long v = 1;
-  ioctlsocket (sock, FIONBIO, &v);
-  ensure_unique(io, sock);
-  iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false);
-  pni_iocpdesc_start(iocpd);
-}
-
-
-static int pni_socket_pair (pn_io_t *io, SOCKET sv[2]) {
-  // no socketpair on windows.  provide pipe() semantics using sockets
-  struct protoent * pe_tcp = getprotobyname("tcp");
-  if (pe_tcp == NULL) {
-    perror("getprotobyname");
-    return -1;
-  }
-
-  SOCKET sock = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto);
-  if (sock == INVALID_SOCKET) {
-    perror("socket");
-    return -1;
-  }
-
-  BOOL b = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &b, sizeof(b)) == -1) {
-    perror("setsockopt");
-    closesocket(sock);
-    return -1;
-  }
-  else {
-    struct sockaddr_in addr = {0};
-    addr.sin_family = AF_INET;
-    addr.sin_port = 0;
-    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-
-    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-      perror("bind");
-      closesocket(sock);
-      return -1;
-    }
-  }
-
-  if (listen(sock, 50) == -1) {
-    perror("listen");
-    closesocket(sock);
-    return -1;
-  }
-
-  if ((sv[1] = socket(AF_INET, SOCK_STREAM, pe_tcp->p_proto)) == INVALID_SOCKET) {
-    perror("sock1");
-    closesocket(sock);
-    return -1;
-  }
-  else {
-    struct sockaddr addr = {0};
-    int l = sizeof(addr);
-    if (getsockname(sock, &addr, &l) == -1) {
-      perror("getsockname");
-      closesocket(sock);
-      return -1;
-    }
-
-    if (connect(sv[1], &addr, sizeof(addr)) == -1) {
-      int err = WSAGetLastError();
-      fprintf(stderr, "connect wsaerrr %d\n", err);
-      closesocket(sock);
-      closesocket(sv[1]);
-      return -1;
-    }
-
-    if ((sv[0] = accept(sock, &addr, &l)) == INVALID_SOCKET) {
-      perror("accept");
-      closesocket(sock);
-      closesocket(sv[1]);
-      return -1;
-    }
-  }
-
-  configure_pipe_socket(io, sv[0]);
-  configure_pipe_socket(io, sv[1]);
-  closesocket(sock);
-  return 0;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/iocp.c
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.c b/proton-c/src/windows/iocp.c
deleted file mode 100644
index d1abc9a..0000000
--- a/proton-c/src/windows/iocp.c
+++ /dev/null
@@ -1,1176 +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.
- *
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#if _WIN32_WINNT < 0x0501
-#error "Proton requires Windows API support for XP or later."
-#endif
-#include <winsock2.h>
-#include <mswsock.h>
-#include <Ws2tcpip.h>
-
-#include "platform.h"
-#include <proton/object.h>
-#include <proton/io.h>
-#include <proton/selector.h>
-#include <proton/error.h>
-#include <proton/transport.h>
-#include "iocp.h"
-#include "util.h"
-#include <assert.h>
-
-/*
- * Windows IO Completion Port support for Proton.
- *
- * Overlapped writes are used to avoid lengthy stalls between write
- * completion and starting a new write.  Non-overlapped reads are used
- * since Windows accumulates inbound traffic without stalling and
- * managing read buffers would not avoid a memory copy at the pn_read
- * boundary.
- *
- * A socket must not get a Windows closesocket() unless the
- * application has called pn_close on the socket or a global
- * pn_io_finalize().  On error, the internal accounting for
- * write_closed or read_closed may be updated along with the external
- * event notification.  A socket may be closed if it is never added to
- * the iocpdesc_map or is on its way out of the map.
- */
-
-// Max number of overlapped accepts per listener
-#define IOCP_MAX_ACCEPTS 10
-
-// AcceptEx squishes the local and remote addresses and optional data
-// all together when accepting the connection. Reserve enough for
-// IPv6 addresses, even if the socket is IPv4. The 16 bytes padding
-// per address is required by AcceptEx.
-#define IOCP_SOCKADDRMAXLEN (sizeof(sockaddr_in6) + 16)
-#define IOCP_SOCKADDRBUFLEN (2 * IOCP_SOCKADDRMAXLEN)
-
-static void iocp_log(const char *fmt, ...)
-{
-  va_list ap;
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  va_end(ap);
-  fflush(stderr);
-}
-
-static void set_iocp_error_status(pn_error_t *error, int code, HRESULT status)
-{
-  char buf[512];
-  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
-                    0, status, 0, buf, sizeof(buf), 0))
-    pn_error_set(error, code, buf);
-  else {
-    fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());
-  }
-}
-
-static void reap_check(iocpdesc_t *);
-static void bind_to_completion_port(iocpdesc_t *iocpd);
-static void iocp_shutdown(iocpdesc_t *iocpd);
-static void start_reading(iocpdesc_t *iocpd);
-static bool is_listener(iocpdesc_t *iocpd);
-static void release_sys_sendbuf(SOCKET s);
-
-static void iocpdesc_fail(iocpdesc_t *iocpd, HRESULT status, const char* text)
-{
-  pni_win32_error(iocpd->error, text, status);
-  if (iocpd->iocp->iocp_trace) {
-    iocp_log("connection terminated: %s\n", pn_error_text(iocpd->error));
-  }
-  iocpd->write_closed = true;
-  iocpd->read_closed = true;
-  iocpd->poll_error = true;
-  pni_events_update(iocpd, iocpd->events & ~(PN_READABLE | PN_WRITABLE));
-}
-
-// Helper functions to use specialized IOCP AcceptEx() and ConnectEx()
-static LPFN_ACCEPTEX lookup_accept_ex(SOCKET s)
-{
-  GUID guid = WSAID_ACCEPTEX;
-  DWORD bytes = 0;
-  LPFN_ACCEPTEX fn;
-  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
-           &fn, sizeof(fn), &bytes, NULL, NULL);
-  assert(fn);
-  return fn;
-}
-
-static LPFN_CONNECTEX lookup_connect_ex(SOCKET s)
-{
-  GUID guid = WSAID_CONNECTEX;
-  DWORD bytes = 0;
-  LPFN_CONNECTEX fn;
-  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
-           &fn, sizeof(fn), &bytes, NULL, NULL);
-  assert(fn);
-  return fn;
-}
-
-static LPFN_GETACCEPTEXSOCKADDRS lookup_get_accept_ex_sockaddrs(SOCKET s)
-{
-  GUID guid = WSAID_GETACCEPTEXSOCKADDRS;
-  DWORD bytes = 0;
-  LPFN_GETACCEPTEXSOCKADDRS fn;
-  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
-           &fn, sizeof(fn), &bytes, NULL, NULL);
-  assert(fn);
-  return fn;
-}
-
-// match accept socket to listener socket
-static iocpdesc_t *create_same_type_socket(iocpdesc_t *iocpd)
-{
-  sockaddr_storage sa;
-  socklen_t salen = sizeof(sa);
-  if (getsockname(iocpd->socket, (sockaddr*)&sa, &salen) == -1)
-    return NULL;
-  SOCKET s = socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM
-  if (s == INVALID_SOCKET)
-    return NULL;
-  return pni_iocpdesc_create(iocpd->iocp, s, false);
-}
-
-static bool is_listener(iocpdesc_t *iocpd)
-{
-  return iocpd && iocpd->acceptor;
-}
-
-// === Async accept processing
-
-typedef struct {
-  iocp_result_t base;
-  iocpdesc_t *new_sock;
-  char address_buffer[IOCP_SOCKADDRBUFLEN];
-  DWORD unused;
-} accept_result_t;
-
-static accept_result_t *accept_result(iocpdesc_t *listen_sock) {
-  accept_result_t *result = (accept_result_t *)calloc(1, sizeof(accept_result_t));
-  if (result) {
-    result->base.type = IOCP_ACCEPT;
-    result->base.iocpd = listen_sock;
-  }
-  return result;
-}
-
-static void reset_accept_result(accept_result_t *result) {
-  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
-  memset(&result->address_buffer, 0, IOCP_SOCKADDRBUFLEN);
-}
-
-struct pni_acceptor_t {
-  int accept_queue_size;
-  pn_list_t *accepts;
-  iocpdesc_t *listen_sock;
-  bool signalled;
-  LPFN_ACCEPTEX fn_accept_ex;
-  LPFN_GETACCEPTEXSOCKADDRS fn_get_accept_ex_sockaddrs;
-};
-
-#define pni_acceptor_compare NULL
-#define pni_acceptor_inspect NULL
-#define pni_acceptor_hashcode NULL
-
-static void pni_acceptor_initialize(void *object)
-{
-  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
-  acceptor->accepts = pn_list(PN_VOID, IOCP_MAX_ACCEPTS);
-}
-
-static void pni_acceptor_finalize(void *object)
-{
-  pni_acceptor_t *acceptor = (pni_acceptor_t *) object;
-  size_t len = pn_list_size(acceptor->accepts);
-  for (size_t i = 0; i < len; i++)
-    free(pn_list_get(acceptor->accepts, i));
-  pn_free(acceptor->accepts);
-}
-
-static pni_acceptor_t *pni_acceptor(iocpdesc_t *iocpd)
-{
-  static const pn_cid_t CID_pni_acceptor = CID_pn_void;
-  static const pn_class_t clazz = PN_CLASS(pni_acceptor);
-  pni_acceptor_t *acceptor = (pni_acceptor_t *) pn_class_new(&clazz, sizeof(pni_acceptor_t));
-  acceptor->listen_sock = iocpd;
-  acceptor->accept_queue_size = 0;
-  acceptor->signalled = false;
-  pn_socket_t sock = acceptor->listen_sock->socket;
-  acceptor->fn_accept_ex = lookup_accept_ex(sock);
-  acceptor->fn_get_accept_ex_sockaddrs = lookup_get_accept_ex_sockaddrs(sock);
-  return acceptor;
-}
-
-static void begin_accept(pni_acceptor_t *acceptor, accept_result_t *result)
-{
-  if (acceptor->listen_sock->closing) {
-    if (result) {
-      free(result);
-      acceptor->accept_queue_size--;
-    }
-    if (acceptor->accept_queue_size == 0)
-      acceptor->signalled = true;
-    return;
-  }
-
-  if (result) {
-    reset_accept_result(result);
-  } else {
-    if (acceptor->accept_queue_size < IOCP_MAX_ACCEPTS &&
-        pn_list_size(acceptor->accepts) == acceptor->accept_queue_size ) {
-      result = accept_result(acceptor->listen_sock);
-      acceptor->accept_queue_size++;
-    } else {
-      // an async accept is still pending or max concurrent accepts already hit
-      return;
-    }
-  }
-
-  result->new_sock = create_same_type_socket(acceptor->listen_sock);
-  if (result->new_sock) {
-    // Not yet connected.
-    result->new_sock->read_closed = true;
-    result->new_sock->write_closed = true;
-
-    bool success = acceptor->fn_accept_ex(acceptor->listen_sock->socket, result->new_sock->socket,
-                     result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
-                     &result->unused, (LPOVERLAPPED) result);
-    if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
-      result->base.status = WSAGetLastError();
-      pn_list_add(acceptor->accepts, result);
-      pni_events_update(acceptor->listen_sock, acceptor->listen_sock->events | PN_READABLE);
-    } else {
-      acceptor->listen_sock->ops_in_progress++;
-      // This socket is equally involved in the async operation.
-      result->new_sock->ops_in_progress++;
-    }
-  } else {
-    iocpdesc_fail(acceptor->listen_sock, WSAGetLastError(), "create accept socket");
-  }
-}
-
-static void complete_accept(accept_result_t *result, HRESULT status)
-{
-  result->new_sock->ops_in_progress--;
-  iocpdesc_t *ld = result->base.iocpd;
-  if (ld->read_closed) {
-    if (!result->new_sock->closing)
-      pni_iocp_begin_close(result->new_sock);
-    free(result);    // discard
-    reap_check(ld);
-  } else {
-    result->base.status = status;
-    pn_list_add(ld->acceptor->accepts, result);
-    pni_events_update(ld, ld->events | PN_READABLE);
-  }
-}
-
-pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error)
-{
-  if (!is_listener(ld)) {
-    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
-    return INVALID_SOCKET;
-  }
-  if (ld->read_closed) {
-    set_iocp_error_status(error, PN_ERR, WSAENOTSOCK);
-    return INVALID_SOCKET;
-  }
-  if (pn_list_size(ld->acceptor->accepts) == 0) {
-    if (ld->events & PN_READABLE && ld->iocp->iocp_trace)
-      iocp_log("listen socket readable with no available accept completions\n");
-    *would_block = true;
-    return INVALID_SOCKET;
-  }
-
-  accept_result_t *result = (accept_result_t *) pn_list_get(ld->acceptor->accepts, 0);
-  pn_list_del(ld->acceptor->accepts, 0, 1);
-  if (!pn_list_size(ld->acceptor->accepts))
-    pni_events_update(ld, ld->events & ~PN_READABLE);  // No pending accepts
-
-  pn_socket_t accept_sock;
-  if (result->base.status) {
-    accept_sock = INVALID_SOCKET;
-    pni_win32_error(ld->error, "accept failure", result->base.status);
-    if (ld->iocp->iocp_trace)
-      iocp_log("%s\n", pn_error_text(ld->error));
-    // App never sees this socket so close it here.
-    pni_iocp_begin_close(result->new_sock);
-  } else {
-    accept_sock = result->new_sock->socket;
-    // AcceptEx special setsockopt:
-    setsockopt(accept_sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&ld->socket,
-                  sizeof (SOCKET));
-    if (addr && addrlen && *addrlen > 0) {
-      sockaddr_storage *local_addr = NULL;
-      sockaddr_storage *remote_addr = NULL;
-      int local_addrlen, remote_addrlen;
-      LPFN_GETACCEPTEXSOCKADDRS fn = ld->acceptor->fn_get_accept_ex_sockaddrs;
-      fn(result->address_buffer, 0, IOCP_SOCKADDRMAXLEN, IOCP_SOCKADDRMAXLEN,
-         (SOCKADDR **) &local_addr, &local_addrlen, (SOCKADDR **) &remote_addr,
-         &remote_addrlen);
-      *addrlen = pn_min(*addrlen, remote_addrlen);
-      memmove(addr, remote_addr, *addrlen);
-    }
-  }
-
-  if (accept_sock != INVALID_SOCKET) {
-    // Connected.
-    result->new_sock->read_closed = false;
-    result->new_sock->write_closed = false;
-  }
-
-  // Done with the completion result, so reuse it
-  result->new_sock = NULL;
-  begin_accept(ld->acceptor, result);
-  return accept_sock;
-}
-
-
-// === Async connect processing
-
-typedef struct {
-  iocp_result_t base;
-  char address_buffer[IOCP_SOCKADDRBUFLEN];
-  struct addrinfo *addrinfo;
-} connect_result_t;
-
-#define connect_result_initialize NULL
-#define connect_result_compare NULL
-#define connect_result_inspect NULL
-#define connect_result_hashcode NULL
-
-static void connect_result_finalize(void *object)
-{
-  connect_result_t *result = (connect_result_t *) object;
-  // Do not release addrinfo until ConnectEx completes
-  if (result->addrinfo)
-    freeaddrinfo(result->addrinfo);
-}
-
-static connect_result_t *connect_result(iocpdesc_t *iocpd, struct addrinfo *addr) {
-  static const pn_cid_t CID_connect_result = CID_pn_void;
-  static const pn_class_t clazz = PN_CLASS(connect_result);
-  connect_result_t *result = (connect_result_t *) pn_class_new(&clazz, sizeof(connect_result_t));
-  if (result) {
-    memset(result, 0, sizeof(connect_result_t));
-    result->base.type = IOCP_CONNECT;
-    result->base.iocpd = iocpd;
-    result->addrinfo = addr;
-  }
-  return result;
-}
-
-pn_socket_t pni_iocp_begin_connect(iocp_t *iocp, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error)
-{
-  // addr lives for the duration of the async connect.  Caller has passed ownership here.
-  // See connect_result_finalize().
-  // Use of Windows-specific ConnectEx() requires our socket to be "loosely" pre-bound:
-  sockaddr_storage sa;
-  memset(&sa, 0, sizeof(sa));
-  sa.ss_family = addr->ai_family;
-  if (bind(sock, (SOCKADDR *) &sa, addr->ai_addrlen)) {
-    pni_win32_error(error, "begin async connection", WSAGetLastError());
-    if (iocp->iocp_trace)
-      iocp_log("%s\n", pn_error_text(error));
-    closesocket(sock);
-    freeaddrinfo(addr);
-    return INVALID_SOCKET;
-  }
-
-  iocpdesc_t *iocpd = pni_iocpdesc_create(iocp, sock, false);
-  bind_to_completion_port(iocpd);
-  LPFN_CONNECTEX fn_connect_ex = lookup_connect_ex(iocpd->socket);
-  connect_result_t *result = connect_result(iocpd, addr);
-  DWORD unused;
-  bool success = fn_connect_ex(iocpd->socket, result->addrinfo->ai_addr, result->addrinfo->ai_addrlen,
-                               NULL, 0, &unused, (LPOVERLAPPED) result);
-  if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
-    pni_win32_error(error, "ConnectEx failure", WSAGetLastError());
-    pn_free(result);
-    iocpd->write_closed = true;
-    iocpd->read_closed = true;
-    if (iocp->iocp_trace)
-      iocp_log("%s\n", pn_error_text(error));
-  } else {
-    iocpd->ops_in_progress++;
-  }
-  return sock;
-}
-
-static void complete_connect(connect_result_t *result, HRESULT status)
-{
-  iocpdesc_t *iocpd = result->base.iocpd;
-  if (iocpd->closing) {
-    pn_free(result);
-    reap_check(iocpd);
-    return;
-  }
-
-  if (status) {
-    iocpdesc_fail(iocpd, status, "Connect failure");
-    // Posix sets selectable events as follows:
-    pni_events_update(iocpd, PN_READABLE | PN_EXPIRED);
-  } else {
-    release_sys_sendbuf(iocpd->socket);
-    if (setsockopt(iocpd->socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT,  NULL, 0)) {
-      iocpdesc_fail(iocpd, WSAGetLastError(), "Internal connect failure (update context)");
-    } else {
-      pni_events_update(iocpd, PN_WRITABLE);
-      start_reading(iocpd);
-    }
-  }
-  pn_free(result);
-  return;
-}
-
-
-// === Async writes
-
-static bool write_in_progress(iocpdesc_t *iocpd)
-{
-  return pni_write_pipeline_size(iocpd->pipeline) != 0;
-}
-
-write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen)
-{
-  write_result_t *result = (write_result_t *) calloc(sizeof(write_result_t), 1);
-  if (result) {
-    result->base.type = IOCP_WRITE;
-    result->base.iocpd = iocpd;
-    result->buffer.start = buf;
-    result->buffer.size = buflen;
-  }
-  return result;
-}
-
-static int submit_write(write_result_t *result, const void *buf, size_t len)
-{
-  WSABUF wsabuf;
-  wsabuf.buf = (char *) buf;
-  wsabuf.len = len;
-  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
-  return WSASend(result->base.iocpd->socket, &wsabuf, 1, NULL, 0,
-                 (LPOVERLAPPED) result, 0);
-}
-
-ssize_t pni_iocp_begin_write(iocpdesc_t *iocpd, const void *buf, size_t len, bool *would_block, pn_error_t *error)
-{
-  if (len == 0) return 0;
-  *would_block = false;
-  if (is_listener(iocpd)) {
-    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
-    return INVALID_SOCKET;
-  }
-  if (iocpd->closing) {
-    set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
-    return SOCKET_ERROR;
-  }
-  if (iocpd->write_closed) {
-    assert(pn_error_code(iocpd->error));
-    pn_error_copy(error, iocpd->error);
-    if (iocpd->iocp->iocp_trace)
-      iocp_log("write error: %s\n", pn_error_text(error));
-    return SOCKET_ERROR;
-  }
-  if (len == 0) return 0;
-  if (!(iocpd->events & PN_WRITABLE)) {
-    *would_block = true;
-    return SOCKET_ERROR;
-  }
-
-  size_t written = 0;
-  size_t requested = len;
-  const char *outgoing = (const char *) buf;
-  size_t available = pni_write_pipeline_reserve(iocpd->pipeline, len);
-  if (!available) {
-    *would_block = true;
-    return SOCKET_ERROR;
-  }
-
-  for (size_t wr_count = 0; wr_count < available; wr_count++) {
-    write_result_t *result = pni_write_pipeline_next(iocpd->pipeline);
-    assert(result);
-    result->base.iocpd = iocpd;
-    ssize_t actual_len = pn_min(len, result->buffer.size);
-    result->requested = actual_len;
-    memmove((void *)result->buffer.start, outgoing, actual_len);
-    outgoing += actual_len;
-    written += actual_len;
-    len -= actual_len;
-
-    int werror = submit_write(result, result->buffer.start, actual_len);
-    if (werror && WSAGetLastError() != ERROR_IO_PENDING) {
-      pni_write_pipeline_return(iocpd->pipeline, result);
-      iocpdesc_fail(iocpd, WSAGetLastError(), "overlapped send");
-      return SOCKET_ERROR;
-    }
-    iocpd->ops_in_progress++;
-  }
-
-  if (!pni_write_pipeline_writable(iocpd->pipeline))
-    pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
-  return written;
-}
-
-/*
- * Note: iocp write completion is not "bytes on the wire", it is "peer
- * acked the sent bytes".  Completion can be seconds on a slow
- * consuming peer.
- */
-static void complete_write(write_result_t *result, DWORD xfer_count, HRESULT status)
-{
-  iocpdesc_t *iocpd = result->base.iocpd;
-  if (iocpd->closing) {
-    pni_write_pipeline_return(iocpd->pipeline, result);
-    if (!iocpd->write_closed && !write_in_progress(iocpd))
-      iocp_shutdown(iocpd);
-    reap_check(iocpd);
-    return;
-  }
-  if (status == 0 && xfer_count > 0) {
-    if (xfer_count != result->requested) {
-      // Is this recoverable?  How to preserve order if multiple overlapped writes?
-      pni_write_pipeline_return(iocpd->pipeline, result);
-      iocpdesc_fail(iocpd, WSA_OPERATION_ABORTED, "Partial overlapped write on socket");
-      return;
-    } else {
-      // Success.
-      pni_write_pipeline_return(iocpd->pipeline, result);
-      if (pni_write_pipeline_writable(iocpd->pipeline))
-        pni_events_update(iocpd, iocpd->events | PN_WRITABLE);
-      return;
-    }
-  }
-  // Other error
-  pni_write_pipeline_return(iocpd->pipeline, result);
-  if (status == WSAECONNABORTED || status == WSAECONNRESET || status == WSAENOTCONN
-      || status == ERROR_NETNAME_DELETED) {
-    iocpd->write_closed = true;
-    iocpd->poll_error = true;
-    pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE);
-    pni_win32_error(iocpd->error, "Remote close or timeout", status);
-  } else {
-    iocpdesc_fail(iocpd, status, "IOCP async write error");
-  }
-}
-
-
-// === Async reads
-
-struct read_result_t {
-  iocp_result_t base;
-  size_t drain_count;
-  char unused_buf[1];
-};
-
-static read_result_t *read_result(iocpdesc_t *iocpd)
-{
-  read_result_t *result = (read_result_t *) calloc(sizeof(read_result_t), 1);
-  if (result) {
-    result->base.type = IOCP_READ;
-    result->base.iocpd = iocpd;
-  }
-  return result;
-}
-
-static void begin_zero_byte_read(iocpdesc_t *iocpd)
-{
-  if (iocpd->read_in_progress) return;
-  if (iocpd->read_closed) {
-    pni_events_update(iocpd, iocpd->events | PN_READABLE);
-    return;
-  }
-
-  read_result_t *result = iocpd->read_result;
-  memset(&result->base.overlapped, 0, sizeof (OVERLAPPED));
-  DWORD flags = 0;
-  WSABUF wsabuf;
-  wsabuf.buf = result->unused_buf;
-  wsabuf.len = 0;
-  int rc = WSARecv(iocpd->socket, &wsabuf, 1, NULL, &flags,
-                       &result->base.overlapped, 0);
-  if (rc && WSAGetLastError() != ERROR_IO_PENDING) {
-    iocpdesc_fail(iocpd, WSAGetLastError(), "IOCP read error");
-    return;
-  }
-  iocpd->ops_in_progress++;
-  iocpd->read_in_progress = true;
-}
-
-static void drain_until_closed(iocpdesc_t *iocpd) {
-  size_t max_drain = 16 * 1024;
-  char buf[512];
-  read_result_t *result = iocpd->read_result;
-  while (result->drain_count < max_drain) {
-    int rv = recv(iocpd->socket, buf, 512, 0);
-    if (rv > 0)
-      result->drain_count += rv;
-    else if (rv == 0) {
-      iocpd->read_closed = true;
-      return;
-    } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
-      // wait a little longer
-      start_reading(iocpd);
-      return;
-    }
-    else
-      break;
-  }
-  // Graceful close indication unlikely, force the issue
-  if (iocpd->iocp->iocp_trace)
-    if (result->drain_count >= max_drain)
-      iocp_log("graceful close on reader abandoned (too many chars)\n");
-    else
-      iocp_log("graceful close on reader abandoned: %d\n", WSAGetLastError());
-  iocpd->read_closed = true;
-}
-
-
-static void complete_read(read_result_t *result, DWORD xfer_count, HRESULT status)
-{
-  iocpdesc_t *iocpd = result->base.iocpd;
-  iocpd->read_in_progress = false;
-
-  if (iocpd->closing) {
-    // Application no longer reading, but we are looking for a zero length read
-    if (!iocpd->read_closed)
-      drain_until_closed(iocpd);
-    reap_check(iocpd);
-    return;
-  }
-
-  if (status == 0 && xfer_count == 0) {
-    // Success.
-    pni_events_update(iocpd, iocpd->events | PN_READABLE);
-  } else {
-    iocpdesc_fail(iocpd, status, "IOCP read complete error");
-  }
-}
-
-ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error)
-{
-  if (size == 0) return 0;
-  *would_block = false;
-  if (is_listener(iocpd)) {
-    set_iocp_error_status(error, PN_ERR, WSAEOPNOTSUPP);
-    return SOCKET_ERROR;
-  }
-  if (iocpd->closing) {
-    // Previous call to pn_close()
-    set_iocp_error_status(error, PN_ERR, WSAESHUTDOWN);
-    return SOCKET_ERROR;
-  }
-  if (iocpd->read_closed) {
-    if (pn_error_code(iocpd->error))
-      pn_error_copy(error, iocpd->error);
-    else
-      set_iocp_error_status(error, PN_ERR, WSAENOTCONN);
-    return SOCKET_ERROR;
-  }
-
-  int count = recv(iocpd->socket, (char *) buf, size, 0);
-  if (count > 0) {
-    pni_events_update(iocpd, iocpd->events & ~PN_READABLE);
-    begin_zero_byte_read(iocpd);
-    return (ssize_t) count;
-  } else if (count == 0) {
-    iocpd->read_closed = true;
-    return 0;
-  }
-  if (WSAGetLastError() == WSAEWOULDBLOCK)
-    *would_block = true;
-  else {
-    set_iocp_error_status(error, PN_ERR, WSAGetLastError());
-    iocpd->read_closed = true;
-  }
-  return SOCKET_ERROR;
-}
-
-static void start_reading(iocpdesc_t *iocpd)
-{
-  begin_zero_byte_read(iocpd);
-}
-
-
-// === The iocp descriptor
-
-static void pni_iocpdesc_initialize(void *object)
-{
-  iocpdesc_t *iocpd = (iocpdesc_t *) object;
-  memset(iocpd, 0, sizeof(iocpdesc_t));
-  iocpd->socket = INVALID_SOCKET;
-}
-
-static void pni_iocpdesc_finalize(void *object)
-{
-  iocpdesc_t *iocpd = (iocpdesc_t *) object;
-  pn_free(iocpd->acceptor);
-  pn_error_free(iocpd->error);
-   if (iocpd->pipeline)
-    if (write_in_progress(iocpd))
-      iocp_log("iocp descriptor write leak\n");
-    else
-      pn_free(iocpd->pipeline);
-  if (iocpd->read_in_progress)
-    iocp_log("iocp descriptor read leak\n");
-  else
-    free(iocpd->read_result);
-}
-
-static uintptr_t pni_iocpdesc_hashcode(void *object)
-{
-  iocpdesc_t *iocpd = (iocpdesc_t *) object;
-  return iocpd->socket;
-}
-
-#define pni_iocpdesc_compare NULL
-#define pni_iocpdesc_inspect NULL
-
-// Reference counted in the iocpdesc map, zombie_list, selector.
-static iocpdesc_t *pni_iocpdesc(pn_socket_t s)
-{
-  static const pn_cid_t CID_pni_iocpdesc = CID_pn_void;
-  static pn_class_t clazz = PN_CLASS(pni_iocpdesc);
-  iocpdesc_t *iocpd = (iocpdesc_t *) pn_class_new(&clazz, sizeof(iocpdesc_t));
-  assert(iocpd);
-  iocpd->socket = s;
-  return iocpd;
-}
-
-static bool is_listener_socket(pn_socket_t s)
-{
-  BOOL tval = false;
-  int tvalsz = sizeof(tval);
-  int code = getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&tval, &tvalsz);
-  return code == 0 && tval;
-}
-
-iocpdesc_t *pni_iocpdesc_create(iocp_t *iocp, pn_socket_t s, bool external) {
-  assert (s != INVALID_SOCKET);
-  assert(!pni_iocpdesc_map_get(iocp, s));
-  bool listening = is_listener_socket(s);
-  iocpdesc_t *iocpd = pni_iocpdesc(s);
-  iocpd->iocp = iocp;
-  if (iocpd) {
-    iocpd->external = external;
-    iocpd->error = pn_error();
-    if (listening) {
-      iocpd->acceptor = pni_acceptor(iocpd);
-    } else {
-      iocpd->pipeline = pni_write_pipeline(iocpd);
-      iocpd->read_result = read_result(iocpd);
-    }
-    pni_iocpdesc_map_push(iocpd);
-  }
-  return iocpd;
-}
-
-iocpdesc_t *pni_deadline_desc(iocp_t *iocp) {
-  // Non IO descriptor for selector deadlines.  Do not add to iocpdesc map or
-  // zombie list.  Selector responsible to free/decref object.
-  iocpdesc_t *iocpd = pni_iocpdesc(PN_INVALID_SOCKET);
-  iocpd->iocp = iocp;
-  iocpd->deadline_desc = true;
-  return iocpd;
-}
-
-// === Fast lookup of a socket's iocpdesc_t
-
-iocpdesc_t *pni_iocpdesc_map_get(iocp_t *iocp, pn_socket_t s) {
-  iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_get(iocp->iocpdesc_map, s);
-  return iocpd;
-}
-
-void pni_iocpdesc_map_push(iocpdesc_t *iocpd) {
-  pn_hash_put(iocpd->iocp->iocpdesc_map, iocpd->socket, iocpd);
-  pn_decref(iocpd);
-  assert(pn_refcount(iocpd) == 1);
-}
-
-void pni_iocpdesc_map_del(iocp_t *iocp, pn_socket_t s) {
-  pn_hash_del(iocp->iocpdesc_map, (uintptr_t) s);
-}
-
-static void bind_to_completion_port(iocpdesc_t *iocpd)
-{
-  if (iocpd->bound) return;
-  if (!iocpd->iocp->completion_port) {
-    iocpdesc_fail(iocpd, WSAEINVAL, "Incomplete setup, no completion port.");
-    return;
-  }
-
-  if (CreateIoCompletionPort ((HANDLE) iocpd->socket, iocpd->iocp->completion_port, 0, 0))
-    iocpd->bound = true;
-  else {
-    iocpdesc_fail(iocpd, GetLastError(), "IOCP socket setup.");
-  }
-}
-
-static void release_sys_sendbuf(SOCKET s)
-{
-  // Set the socket's send buffer size to zero.
-  int sz = 0;
-  int status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char *)&sz, sizeof(int));
-  assert(status == 0);
-}
-
-void pni_iocpdesc_start(iocpdesc_t *iocpd)
-{
-  if (iocpd->bound) return;
-  bind_to_completion_port(iocpd);
-  if (is_listener(iocpd)) {
-    begin_accept(iocpd->acceptor, NULL);
-  }
-  else {
-    release_sys_sendbuf(iocpd->socket);
-    pni_events_update(iocpd, PN_WRITABLE);
-    start_reading(iocpd);
-  }
-}
-
-static void complete(iocp_result_t *result, bool success, DWORD num_transferred) {
-  result->iocpd->ops_in_progress--;
-  DWORD status = success ? 0 : GetLastError();
-
-  switch (result->type) {
-  case IOCP_ACCEPT:
-    complete_accept((accept_result_t *) result, status);
-    break;
-  case IOCP_CONNECT:
-    complete_connect((connect_result_t *) result, status);
-    break;
-  case IOCP_WRITE:
-    complete_write((write_result_t *) result, num_transferred, status);
-    break;
-  case IOCP_READ:
-    complete_read((read_result_t *) result, num_transferred, status);
-    break;
-  default:
-    assert(false);
-  }
-}
-
-void pni_iocp_drain_completions(iocp_t *iocp)
-{
-  while (true) {
-    DWORD timeout_ms = 0;
-    DWORD num_transferred = 0;
-    ULONG_PTR completion_key = 0;
-    OVERLAPPED *overlapped = 0;
-
-    bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
-                                               &completion_key, &overlapped, timeout_ms);
-    if (!overlapped)
-      return;  // timed out
-    iocp_result_t *result = (iocp_result_t *) overlapped;
-    complete(result, good_op, num_transferred);
-  }
-}
-
-// returns: -1 on error, 0 on timeout, 1 successful completion
-int pni_iocp_wait_one(iocp_t *iocp, int timeout, pn_error_t *error) {
-  DWORD win_timeout = (timeout < 0) ? INFINITE : (DWORD) timeout;
-  DWORD num_transferred = 0;
-  ULONG_PTR completion_key = 0;
-  OVERLAPPED *overlapped = 0;
-
-  bool good_op = GetQueuedCompletionStatus (iocp->completion_port, &num_transferred,
-                                            &completion_key, &overlapped, win_timeout);
-  if (!overlapped)
-    if (GetLastError() == WAIT_TIMEOUT)
-      return 0;
-    else {
-      if (error)
-        pni_win32_error(error, "GetQueuedCompletionStatus", GetLastError());
-      return -1;
-    }
-
-  iocp_result_t *result = (iocp_result_t *) overlapped;
-  complete(result, good_op, num_transferred);
-  return 1;
-}
-
-// === Close (graceful and otherwise)
-
-// zombie_list is for sockets transitioning out of iocp on their way to zero ops_in_progress
-// and fully closed.
-
-static void zombie_list_add(iocpdesc_t *iocpd)
-{
-  assert(iocpd->closing);
-  if (!iocpd->ops_in_progress) {
-    // No need to make a zombie.
-    if (iocpd->socket != INVALID_SOCKET) {
-      closesocket(iocpd->socket);
-      iocpd->socket = INVALID_SOCKET;
-      iocpd->read_closed = true;
-    }
-    return;
-  }
-  // Allow 2 seconds for graceful shutdown before releasing socket resource.
-  iocpd->reap_time = pn_i_now() + 2000;
-  pn_list_add(iocpd->iocp->zombie_list, iocpd);
-}
-
-static void reap_check(iocpdesc_t *iocpd)
-{
-  if (iocpd->closing && !iocpd->ops_in_progress) {
-    if (iocpd->socket != INVALID_SOCKET) {
-      closesocket(iocpd->socket);
-      iocpd->socket = INVALID_SOCKET;
-    }
-    pn_list_remove(iocpd->iocp->zombie_list, iocpd);
-    // iocpd is decref'ed and possibly released
-  }
-}
-
-pn_timestamp_t pni_zombie_deadline(iocp_t *iocp)
-{
-  if (pn_list_size(iocp->zombie_list)) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, 0);
-    return iocpd->reap_time;
-  }
-  return 0;
-}
-
-void pni_zombie_check(iocp_t *iocp, pn_timestamp_t now)
-{
-  pn_list_t *zl = iocp->zombie_list;
-  // Look for stale zombies that should have been reaped by "now"
-  for (size_t idx = 0; idx < pn_list_size(zl); idx++) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(zl, idx);
-    if (iocpd->reap_time > now)
-      return;
-    if (iocpd->socket == INVALID_SOCKET)
-      continue;
-    assert(iocpd->ops_in_progress > 0);
-    if (iocp->iocp_trace)
-      iocp_log("async close: graceful close timeout exceeded\n");
-    closesocket(iocpd->socket);
-    iocpd->socket = INVALID_SOCKET;
-    iocpd->read_closed = true;
-    // outstanding ops should complete immediately now
-  }
-}
-
-static void drain_zombie_completions(iocp_t *iocp)
-{
-  // No more pn_selector_select() from App, but zombies still need care and feeding
-  // until their outstanding async actions complete.
-  pni_iocp_drain_completions(iocp);
-
-  // Discard any that have no pending async IO
-  size_t sz = pn_list_size(iocp->zombie_list);
-  for (size_t idx = 0; idx < sz;) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, idx);
-    if (!iocpd->ops_in_progress) {
-      pn_list_del(iocp->zombie_list, idx, 1);
-      sz--;
-    } else {
-      idx++;
-    }
-  }
-
-  unsigned shutdown_grace = 2000;
-  char *override = getenv("PN_SHUTDOWN_GRACE");
-  if (override) {
-    int grace = atoi(override);
-    if (grace > 0 && grace < 60000)
-      shutdown_grace = (unsigned) grace;
-  }
-  pn_timestamp_t now = pn_i_now();
-  pn_timestamp_t deadline = now + shutdown_grace;
-
-  while (pn_list_size(iocp->zombie_list)) {
-    if (now >= deadline)
-      break;
-    int rv = pni_iocp_wait_one(iocp, deadline - now, NULL);
-    if (rv < 0) {
-      iocp_log("unexpected IOCP failure on Proton IO shutdown %d\n", GetLastError());
-      break;
-    }
-    now = pn_i_now();
-  }
-  if (now >= deadline && pn_list_size(iocp->zombie_list) && iocp->iocp_trace)
-    // Should only happen if really slow TCP handshakes, i.e. total network failure
-    iocp_log("network failure on Proton shutdown\n");
-}
-
-static pn_list_t *iocp_map_close_all(iocp_t *iocp)
-{
-  // Zombify stragglers, i.e. no pn_close() from the application.
-  pn_list_t *externals = pn_list(PN_OBJECT, 0);
-  for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
-       entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
-    // Just listeners first.
-    if (is_listener(iocpd)) {
-      if (iocpd->external) {
-        // Owned by application, just keep a temporary reference to it.
-        // iocp_result_t structs must not be free'd until completed or
-        // the completion port is closed.
-        if (iocpd->ops_in_progress)
-          pn_list_add(externals, iocpd);
-        pni_iocpdesc_map_del(iocp, iocpd->socket);
-      } else {
-        // Make it a zombie.
-        pni_iocp_begin_close(iocpd);
-      }
-    }
-  }
-  pni_iocp_drain_completions(iocp);
-
-  for (pn_handle_t entry = pn_hash_head(iocp->iocpdesc_map); entry;
-       entry = pn_hash_next(iocp->iocpdesc_map, entry)) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_hash_value(iocp->iocpdesc_map, entry);
-    if (iocpd->external) {
-      iocpd->read_closed = true;   // Do not consume from read side
-      iocpd->write_closed = true;  // Do not shutdown write side
-      if (iocpd->ops_in_progress)
-        pn_list_add(externals, iocpd);
-      pni_iocpdesc_map_del(iocp, iocpd->socket);
-    } else {
-      // Make it a zombie.
-      pni_iocp_begin_close(iocpd);
-    }
-  }
-  return externals;
-}
-
-static void zombie_list_hard_close_all(iocp_t *iocp)
-{
-  pni_iocp_drain_completions(iocp);
-  size_t zs = pn_list_size(iocp->zombie_list);
-  for (size_t i = 0; i < zs; i++) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
-    if (iocpd->socket != INVALID_SOCKET) {
-      closesocket(iocpd->socket);
-      iocpd->socket = INVALID_SOCKET;
-      iocpd->read_closed = true;
-      iocpd->write_closed = true;
-    }
-  }
-  pni_iocp_drain_completions(iocp);
-
-  // Zombies should be all gone.  Do a sanity check.
-  zs = pn_list_size(iocp->zombie_list);
-  int remaining = 0;
-  int ops = 0;
-  for (size_t i = 0; i < zs; i++) {
-    iocpdesc_t *iocpd = (iocpdesc_t *) pn_list_get(iocp->zombie_list, i);
-    remaining++;
-    ops += iocpd->ops_in_progress;
-  }
-  if (remaining)
-    iocp_log("Proton: %d unfinished close operations (ops count = %d)\n", remaining, ops);
-}
-
-static void iocp_shutdown(iocpdesc_t *iocpd)
-{
-  if (iocpd->socket == PN_INVALID_SOCKET)
-    return;    // Hard close in progress
-  if (shutdown(iocpd->socket, SD_SEND)) {
-    int err = WSAGetLastError();
-    if (err != WSAECONNABORTED && err != WSAECONNRESET && err != WSAENOTCONN)
-      if (iocpd->iocp->iocp_trace)
-        iocp_log("socket shutdown failed %d\n", err);
-  }
-  iocpd->write_closed = true;
-}
-
-void pni_iocp_begin_close(iocpdesc_t *iocpd)
-{
-  assert (!iocpd->closing);
-  if (is_listener(iocpd)) {
-    // Listening socket is easy.  Close the socket which will cancel async ops.
-    pn_socket_t old_sock = iocpd->socket;
-    iocpd->socket = INVALID_SOCKET;
-    iocpd->closing = true;
-    iocpd->read_closed = true;
-    iocpd->write_closed = true;
-    closesocket(old_sock);
-    // Pending accepts will now complete.  Zombie can die when all consumed.
-    zombie_list_add(iocpd);
-    pni_iocpdesc_map_del(iocpd->iocp, old_sock);  // may pn_free *iocpd
-  } else {
-    // Continue async operation looking for graceful close confirmation or timeout.
-    pn_socket_t old_sock = iocpd->socket;
-    iocpd->closing = true;
-    if (!iocpd->write_closed && !write_in_progress(iocpd))
-      iocp_shutdown(iocpd);
-    zombie_list_add(iocpd);
-    pni_iocpdesc_map_del(iocpd->iocp, old_sock);  // may pn_free *iocpd
-  }
-}
-
-
-// === iocp_t
-
-#define pni_iocp_hashcode NULL
-#define pni_iocp_compare NULL
-#define pni_iocp_inspect NULL
-
-void pni_iocp_initialize(void *obj)
-{
-  iocp_t *iocp = (iocp_t *) obj;
-  memset(iocp, 0, sizeof(iocp_t));
-  pni_shared_pool_create(iocp);
-  iocp->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
-  assert(iocp->completion_port != NULL);
-  iocp->iocpdesc_map = pn_hash(PN_OBJECT, 0, 0.75);
-  iocp->zombie_list = pn_list(PN_OBJECT, 0);
-  iocp->iocp_trace = pn_env_bool("PN_TRACE_DRV");
-  iocp->selector = NULL;
-}
-
-void pni_iocp_finalize(void *obj)
-{
-  iocp_t *iocp = (iocp_t *) obj;
-  // Move sockets to closed state, except external sockets.
-  pn_list_t *externals = iocp_map_close_all(iocp);
-  // Now everything with ops_in_progress is in the zombie_list or the externals list.
-  assert(!pn_hash_head(iocp->iocpdesc_map));
-  pn_free(iocp->iocpdesc_map);
-
-  drain_zombie_completions(iocp);    // Last chance for graceful close
-  zombie_list_hard_close_all(iocp);
-  CloseHandle(iocp->completion_port);  // This cancels all our async ops
-  iocp->completion_port = NULL;
-
-  if (pn_list_size(externals) && iocp->iocp_trace)
-    iocp_log("%d external sockets not closed and removed from Proton IOCP control\n", pn_list_size(externals));
-
-  // Now safe to free everything that might be touched by a former async operation.
-  pn_free(externals);
-  pn_free(iocp->zombie_list);
-  pni_shared_pool_free(iocp);
-}
-
-iocp_t *pni_iocp()
-{
-  static const pn_cid_t CID_pni_iocp = CID_pn_void;
-  static const pn_class_t clazz = PN_CLASS(pni_iocp);
-  iocp_t *iocp = (iocp_t *) pn_class_new(&clazz, sizeof(iocp_t));
-  return iocp;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/windows/iocp.h
----------------------------------------------------------------------
diff --git a/proton-c/src/windows/iocp.h b/proton-c/src/windows/iocp.h
deleted file mode 100644
index 0e052e5..0000000
--- a/proton-c/src/windows/iocp.h
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef PROTON_SRC_IOCP_H
-#define PROTON_SRC_IOCP_H 1
-
-/*
- *
- * 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/import_export.h>
-#include <proton/selectable.h>
-#include <proton/type_compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct pni_acceptor_t pni_acceptor_t;
-typedef struct write_result_t write_result_t;
-typedef struct read_result_t read_result_t;
-typedef struct write_pipeline_t write_pipeline_t;
-typedef struct iocpdesc_t iocpdesc_t;
-
-
-// One per pn_io_t.
-
-struct iocp_t {
-  HANDLE completion_port;
-  pn_hash_t *iocpdesc_map;
-  pn_list_t *zombie_list;
-  int shared_pool_size;
-  char *shared_pool_memory;
-  write_result_t **shared_results;
-  write_result_t **available_results;
-  size_t shared_available_count;
-  size_t writer_count;
-  int loopback_bufsize;
-  bool iocp_trace;
-  pn_selector_t *selector;
-};
-
-
-// One for each socket.
-// This iocpdesc_t structure is ref counted by the iocpdesc_map, zombie_list,
-// selector->iocp_descriptors list.  It should remain ref counted in the
-// zombie_list until ops_in_progress == 0 or the completion port is closed.
-
-struct iocpdesc_t {
-  pn_socket_t socket;
-  iocp_t *iocp;
-  pni_acceptor_t *acceptor;
-  pn_error_t *error;
-  int ops_in_progress;
-  bool read_in_progress;
-  write_pipeline_t *pipeline;
-  read_result_t *read_result;
-  bool external;       // true if socket set up outside Proton
-  bool bound;          // associted with the completion port
-  bool closing;        // pn_close called by application
-  bool read_closed;    // EOF or read error
-  bool write_closed;   // shutdown sent or write error
-  bool poll_error;     // flag posix-like POLLERR/POLLHUP/POLLNVAL
-  bool deadline_desc;  // Socket-less deadline descriptor for selectors
-  pn_selector_t *selector;
-  pn_selectable_t *selectable;
-  int events;
-  int interests;
-  pn_timestamp_t deadline;
-  iocpdesc_t *triggered_list_next;
-  iocpdesc_t *triggered_list_prev;
-  iocpdesc_t *deadlines_next;
-  iocpdesc_t *deadlines_prev;
-  pn_timestamp_t reap_time;;
-};
-
-typedef enum { IOCP_ACCEPT, IOCP_CONNECT, IOCP_READ, IOCP_WRITE } iocp_type_t;
-
-typedef struct {
-  OVERLAPPED overlapped;
-  iocp_type_t type;
-  iocpdesc_t *iocpd;
-  HRESULT status;
-} iocp_result_t;
-
-struct write_result_t {
-  iocp_result_t base;
-  size_t requested;
-  bool in_use;
-  pn_bytes_t buffer;
-};
-
-iocpdesc_t *pni_iocpdesc_create(iocp_t *, pn_socket_t s, bool external);
-iocpdesc_t *pni_iocpdesc_map_get(iocp_t *, pn_socket_t s);
-iocpdesc_t *pni_deadline_desc(iocp_t *);
-void pni_iocpdesc_map_del(iocp_t *, pn_socket_t s);
-void pni_iocpdesc_map_push(iocpdesc_t *iocpd);
-void pni_iocpdesc_start(iocpdesc_t *iocpd);
-void pni_iocp_drain_completions(iocp_t *);
-int pni_iocp_wait_one(iocp_t *, int timeout, pn_error_t *);
-void pni_iocp_start_accepting(iocpdesc_t *iocpd);
-pn_socket_t pni_iocp_end_accept(iocpdesc_t *ld, sockaddr *addr, socklen_t *addrlen, bool *would_block, pn_error_t *error);
-pn_socket_t pni_iocp_begin_connect(iocp_t *, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error);
-ssize_t pni_iocp_begin_write(iocpdesc_t *, const void *, size_t, bool *, pn_error_t *);
-ssize_t pni_iocp_recv(iocpdesc_t *iocpd, void *buf, size_t size, bool *would_block, pn_error_t *error);
-void pni_iocp_begin_close(iocpdesc_t *iocpd);
-iocp_t *pni_iocp();
-
-void pni_events_update(iocpdesc_t *iocpd, int events);
-write_result_t *pni_write_result(iocpdesc_t *iocpd, const char *buf, size_t buflen);
-write_pipeline_t *pni_write_pipeline(iocpdesc_t *iocpd);
-size_t pni_write_pipeline_size(write_pipeline_t *);
-bool pni_write_pipeline_writable(write_pipeline_t *);
-void pni_write_pipeline_return(write_pipeline_t *, write_result_t *);
-size_t pni_write_pipeline_reserve(write_pipeline_t *, size_t);
-write_result_t *pni_write_pipeline_next(write_pipeline_t *);
-void pni_shared_pool_create(iocp_t *);
-void pni_shared_pool_free(iocp_t *);
-void pni_zombie_check(iocp_t *, pn_timestamp_t);
-pn_timestamp_t pni_zombie_deadline(iocp_t *);
-
-pn_selector_t *pni_selector_create(iocp_t *iocp);
-
-int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* iocp.h */


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