You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2016/11/25 21:00:57 UTC

[01/48] qpid-proton git commit: PROTON-1346: IOException doesn't necessarily catch java.nio.channels.UnresolvedAddressException which is thrown when server is unavailable. This will cause reactor to fail and require a client restart. changing to Exceptio

Repository: qpid-proton
Updated Branches:
  refs/heads/go1 d5c247084 -> 0889192a3


PROTON-1346: IOException doesn't necessarily catch java.nio.channels.UnresolvedAddressException which is thrown when
server is unavailable. This will cause reactor to fail and require a client restart. changing to Exception
and close transport, so client can recover from failure even if 1 server is down without stopping reactor

This closes #86


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

Branch: refs/heads/go1
Commit: 6afca2def4858fb4a069c224b2f2041f933e8fe5
Parents: d234168
Author: Shibi <ss...@paypal.com>
Authored: Mon Nov 7 11:16:21 2016 -0800
Committer: Robert Gemmell <ro...@apache.org>
Committed: Tue Nov 8 11:57:22 2016 +0000

----------------------------------------------------------------------
 .../main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6afca2de/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
index 32d1f84..178a27b 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
@@ -154,7 +154,7 @@ public class IOHandler extends BaseHandler {
             socketChannel.configureBlocking(false);
             socketChannel.connect(new InetSocketAddress(hostname, port));
             socket = socketChannel.socket();
-        } catch(IOException ioException) {
+        } catch(Exception ioException) {
             ErrorCondition condition = new ErrorCondition();
             condition.setCondition(Symbol.getSymbol("proton:io"));
             condition.setDescription(ioException.getMessage());


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


[08/48] 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 ac...@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


[42/48] qpid-proton git commit: NO-JIRA: Delete dead code - cdriver jython shim

Posted by ac...@apache.org.
NO-JIRA: Delete dead code - cdriver jython shim


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

Branch: refs/heads/go1
Commit: 468b719da05222da77f72f25a026aea46352a372
Parents: 331e3b9
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Nov 21 14:34:30 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 23 11:08:08 2016 -0500

----------------------------------------------------------------------
 tests/java/shim/cdriver.py | 69 -----------------------------------------
 tests/java/shim/cproton.py |  1 -
 2 files changed, 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/468b719d/tests/java/shim/cdriver.py
----------------------------------------------------------------------
diff --git a/tests/java/shim/cdriver.py b/tests/java/shim/cdriver.py
deleted file mode 100644
index a7a20f0..0000000
--- a/tests/java/shim/cdriver.py
+++ /dev/null
@@ -1,69 +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.
-#
-from org.apache.qpid.proton import Proton
-
-# from proton/driver.h
-
-def pn_driver():
-  return Proton.driver()
-
-def pn_driver_wait(drv, t):
-  drv.doWait(t)
-
-def pn_driver_listener(drv):
-  return drv.listener()
-
-def pn_driver_connector(drv):
-  return drv.connector()
-
-def pn_listener(drv, host, port, ctx):
-  return drv.createListener(host, int(port), ctx)
-
-def pn_listener_context(l):
-  return l.getContext()
-
-def pn_listener_set_context(l, v):
-  l.setContext(v)
-
-def pn_listener_accept(l):
-  return l.accept()
-
-def pn_connector(drv, host, port, ctx):
-  return drv.createConnector(host, int(port), ctx)
-
-def pn_connector_context(c):
-  return c.getContext()
-
-def pn_connector_set_context(c, v):
-  c.setContext(v)
-
-def pn_connector_set_connection(c, conn):
-  c.setConnection(conn.impl)
-
-def pn_connector_connection(c):
-  return wrap(c.getConnection(), pn_connection_wrapper)
-
-def pn_connector_transport(c):
-  return wrap(c.getTransport(), pn_transport_wrapper)
-
-def pn_connector_process(c):
-  return c.process()
-
-def pn_connector_closed(c):
-  return c.isClosed()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/468b719d/tests/java/shim/cproton.py
----------------------------------------------------------------------
diff --git a/tests/java/shim/cproton.py b/tests/java/shim/cproton.py
index 0840273..d5ed574 100644
--- a/tests/java/shim/cproton.py
+++ b/tests/java/shim/cproton.py
@@ -35,7 +35,6 @@ from ccodec import *
 from cengine import *
 from csasl import *
 from cssl import *
-from cdriver import *
 from cmessenger import *
 from cmessage import *
 from curl import *


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


[46/48] qpid-proton git commit: PROTON-1356: remove un-necessary codec_shim.h

Posted by ac...@apache.org.
PROTON-1356: remove un-necessary codec_shim.h

PROTON-1356 reports problems with `go get`, with an error in types.go line 33,
pn_types_t not recognized. Not clear if this solves the problem, but types.go
was depending on a codec_shim.h file in the go package, which should have
included the pn_types_t definition. This shim is no longer needed and has been
removed.


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

Branch: refs/heads/go1
Commit: 2bcfd36f7a3a2eee523ad718c5a33f964b84dc6f
Parents: 451b3b4
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Nov 25 15:09:42 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Nov 25 15:09:42 2016 -0500

----------------------------------------------------------------------
 .../go/src/qpid.apache.org/amqp/codec_shim.h    | 33 --------------------
 .../go/src/qpid.apache.org/amqp/marshal.go      |  2 +-
 .../go/src/qpid.apache.org/amqp/message.go      |  2 +-
 .../go/src/qpid.apache.org/amqp/types.go        |  2 +-
 .../go/src/qpid.apache.org/amqp/unmarshal.go    |  2 +-
 5 files changed, 4 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2bcfd36f/proton-c/bindings/go/src/qpid.apache.org/amqp/codec_shim.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/codec_shim.h b/proton-c/bindings/go/src/qpid.apache.org/amqp/codec_shim.h
deleted file mode 100644
index b2f9f1c..0000000
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/codec_shim.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef CODEC_SHIM_H
-#define CODEC_SHIM_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.
- */
-
-/** Stubs to allow the go binding to work with multiple versions of proton. */
-
-#include <proton/codec.h>
-#include <proton/version.h>
-
-#if PN_VERSION_MAJOR == 0 && PN_VERSION_MINOR <= 10
-
-#define PN_INVALID ((pn_type_t)-1)
-
-#endif
-
-#endif // CODEC_SHIM_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2bcfd36f/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
index 3b4a59e..bce7323 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/marshal.go
@@ -19,7 +19,7 @@ under the License.
 
 package amqp
 
-//#include "codec_shim.h"
+// #include <proton/codec.h>
 import "C"
 
 import (

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2bcfd36f/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
index 48a209a..753682e 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/message.go
@@ -19,7 +19,7 @@ under the License.
 
 package amqp
 
-// #include "codec_shim.h"
+// #include <proton/codec.h>
 // #include <proton/types.h>
 // #include <proton/message.h>
 // #include <stdlib.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2bcfd36f/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
index d927cc5..bc0859a 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
@@ -19,7 +19,7 @@ under the License.
 
 package amqp
 
-//#include "codec_shim.h"
+// #include <proton/codec.h>
 import "C"
 
 import (

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2bcfd36f/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index 6942174..95d4343 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -19,7 +19,7 @@ under the License.
 
 package amqp
 
-// #include "codec_shim.h"
+// #include <proton/codec.h>
 import "C"
 
 import (


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


[35/48] qpid-proton git commit: PROTON-1344: proactor listener/conneciton configuration

Posted by ac...@apache.org.
PROTON-1344: proactor listener/conneciton configuration

Dropped extra bytes mechanism, may be re-introduced later.

Added context and attachments to pn_listener_t, consistent with pn_connection_t
Configure connection/listener before calling proactor connect/listen.
Added PN_LISTENER_ACCEPT event so accepted connections can be configured.


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

Branch: refs/heads/go1
Commit: aadfcbbb7a7b75eb442df4d4de8ef97eb2e7a754
Parents: f2c8a3a
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 17 00:14:12 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Nov 17 11:22:50 2016 -0500

----------------------------------------------------------------------
 examples/c/proactor/broker.c         |  33 ++--
 examples/c/proactor/libuv_proactor.c | 246 +++++++++++++++++-------------
 examples/c/proactor/receive.c        |   2 +-
 examples/c/proactor/send.c           |   2 +-
 proton-c/include/proton/connection.h |  12 --
 proton-c/include/proton/event.h      |  12 +-
 proton-c/include/proton/extra.h      |  69 ---------
 proton-c/include/proton/listener.h   |  43 +++++-
 proton-c/include/proton/proactor.h   |  32 ++--
 proton-c/src/core/engine.c           |  16 +-
 10 files changed, 226 insertions(+), 241 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index 66381fc..ca52336 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -158,6 +158,15 @@ typedef struct broker_data_t {
   bool check_queues;          /* Check senders on the connection for available data in queues. */
 } broker_data_t;
 
+/* Use the context pointer as a boolean flag to indicate we need to check queues */
+void pn_connection_set_check_queues(pn_connection_t *c, bool check) {
+  pn_connection_set_context(c, (void*)check);
+}
+
+bool pn_connection_get_check_queues(pn_connection_t *c) {
+  return (bool)pn_connection_get_context(c);
+}
+
 /* Put a message on the queue, called in receiver dispatch loop.
    If the queue was previously empty, notify waiting senders.
 */
@@ -168,8 +177,7 @@ static void queue_receive(pn_proactor_t *d, queue_t *q, pn_rwbytes_t m) {
   if (q->messages.len == 1) { /* Was empty, notify waiting connections */
     for (size_t i = 0; i < q->waiting.len; ++i) {
       pn_connection_t *c = q->waiting.data[i];
-      broker_data_t *bd = (broker_data_t*)pn_connection_get_extra(c).start;
-      bd->check_queues = true;
+      pn_connection_set_check_queues(c, true);
       pn_connection_wake(c); /* Wake the connection */
     }
     q->waiting.len = 0;
@@ -215,7 +223,6 @@ queue_t* queues_get(queues_t *qs, const char* name) {
 /* The broker implementation */
 typedef struct broker_t {
   pn_proactor_t *proactor;
-  pn_listener_t *listener;
   queues_t queues;
   const char *container_id;     /* AMQP container-id */
   size_t threads;
@@ -226,7 +233,6 @@ typedef struct broker_t {
 void broker_init(broker_t *b, const char *container_id, size_t threads, pn_millis_t heartbeat) {
   memset(b, 0, sizeof(*b));
   b->proactor = pn_proactor();
-  b->listener = NULL;
   queues_init(&b->queues);
   b->container_id = container_id;
   b->threads = threads;
@@ -300,10 +306,14 @@ static void handle(broker_t* b, pn_event_t* e) {
 
   switch (pn_event_type(e)) {
 
-   case PN_CONNECTION_INIT: {
+   case PN_LISTENER_ACCEPT:
+    pn_listener_accept(pn_event_listener(e), pn_connection());
+    break;
+
+   case PN_CONNECTION_INIT: 
      pn_connection_set_container(c, b->container_id);
      break;
-   }
+
    case PN_CONNECTION_BOUND: {
      /* Turn off security */
      pn_transport_t *t = pn_connection_transport(c);
@@ -316,9 +326,8 @@ static void handle(broker_t* b, pn_event_t* e) {
      break;
    }
    case PN_CONNECTION_WAKE: {
-     broker_data_t *bd = (broker_data_t*)pn_connection_get_extra(c).start;
-     if (bd->check_queues) {
-       bd->check_queues = false;
+     if (pn_connection_get_check_queues(c)) {
+       pn_connection_set_check_queues(c, false);
        int flags = PN_LOCAL_ACTIVE&PN_REMOTE_ACTIVE;
        for (pn_link_t *l = pn_link_head(c, flags); l != NULL; l = pn_link_next(l, flags))
          link_send(b, l);
@@ -456,11 +465,7 @@ int main(int argc, char **argv) {
   */
   const char *host = url ? pn_url_get_host(url) : "::";
   const char *port = url ? pn_url_get_port(url) : "amqp";
-
-  /* Initial broker_data value copied to each accepted connection */
-  broker_data_t bd = { false };
-  b.listener = pn_proactor_listen(b.proactor, host, port, 16,
-                                  pn_bytes(sizeof(bd), (char*)&bd));
+  pn_proactor_listen(b.proactor, pn_listener(), host, port, 16);
   printf("listening on '%s:%s' %zd threads\n", host, port, b.threads);
 
   if (url) pn_url_free(url);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
index a26c311..9770166 100644
--- a/examples/c/proactor/libuv_proactor.c
+++ b/examples/c/proactor/libuv_proactor.c
@@ -24,7 +24,6 @@
 #include <proton/condition.h>
 #include <proton/connection_driver.h>
 #include <proton/engine.h>
-#include <proton/extra.h>
 #include <proton/message.h>
 #include <proton/object.h>
 #include <proton/proactor.h>
@@ -142,13 +141,15 @@ struct pn_listener_t {
   psocket_t psocket;
 
   /* Only used by owner thread */
+  pconnection_t *accepting;     /* accept in progress */
   pn_condition_t *condition;
   pn_collector_t *collector;
   pn_event_batch_t batch;
+  pn_record_t *attachments;
+  void *context;
   size_t backlog;
 };
 
-PN_EXTRA_DECLARE(pn_listener_t);
 
 typedef struct queue { psocket_t *front, *back; } queue;
 
@@ -222,24 +223,26 @@ static void to_leader(psocket_t *ps) {
 
 /* Detach from IO and put ps on the worker queue */
 static void leader_to_worker(psocket_t *ps) {
-  pconnection_t *pc = as_pconnection_t(ps);
-  /* Don't detach if there are no events yet. */
-  if (pc && pn_connection_driver_has_event(&pc->driver)) {
-    if (pc->writing) {
-      pc->writing  = 0;
-      uv_cancel((uv_req_t*)&pc->write);
-    }
-    if (pc->reading) {
-      pc->reading = false;
-      uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
-    }
-    if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
-      uv_timer_stop(&pc->timer);
+  if (ps->is_conn) {
+    pconnection_t *pc = as_pconnection_t(ps);
+    /* Don't detach if there are no events yet. */
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      if (pc->writing) {
+        pc->writing  = 0;
+        uv_cancel((uv_req_t*)&pc->write);
+      }
+      if (pc->reading) {
+        pc->reading = false;
+        uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
+      }
+      if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
+        uv_timer_stop(&pc->timer);
+      }
     }
+  } else {
+    pn_listener_t *l = as_listener(ps);
+    uv_read_stop((uv_stream_t*)&l->psocket.tcp);
   }
-
-  /* Nothing to do for a listener, on_accept doesn't touch worker state. */
-
   uv_mutex_lock(&ps->proactor->lock);
   push_lh(&ps->proactor->worker_q, ps);
   uv_mutex_unlock(&ps->proactor->lock);
@@ -275,15 +278,12 @@ static void worker_requeue(psocket_t* ps) {
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
-static pconnection_t *new_pconnection_t(pn_proactor_t *p, bool server, const char *host, const char *port, pn_bytes_t extra) {
+static pconnection_t *new_pconnection_t(pn_proactor_t *p, pn_connection_t *c, bool server, const char *host, const char *port) {
   pconnection_t *pc = (pconnection_t*)calloc(1, sizeof(*pc));
   if (!pc) return NULL;
-  if (pn_connection_driver_init(&pc->driver, pn_connection_with_extra(extra.size), NULL) != 0) {
+  if (pn_connection_driver_init(&pc->driver, c, NULL) != 0) {
     return NULL;
   }
-  if (extra.start && extra.size) {
-    memcpy(pn_connection_get_extra(pc->driver.connection).start, extra.start, extra.size);
-  }
   psocket_init(&pc->psocket, p,  true, host, port);
   if (server) {
     pn_transport_set_server(pc->driver.transport);
@@ -312,26 +312,6 @@ static inline pconnection_t *batch_pconnection(pn_event_batch_t *batch) {
   return d ? (pconnection_t*)((char*)d - offsetof(pconnection_t, driver)) : NULL;
 }
 
-pn_listener_t *new_listener(pn_proactor_t *p, const char *host, const char *port, int backlog, pn_bytes_t extra) {
-  pn_listener_t *l = (pn_listener_t*)calloc(1, PN_EXTRA_SIZEOF(pn_listener_t, extra.size));
-  if (!l) {
-    return NULL;
-  }
-  l->collector = pn_collector();
-  if (!l->collector) {
-    free(l);
-    return NULL;
-  }
-  if (extra.start && extra.size) {
-    memcpy(pn_listener_get_extra(l).start, extra.start, extra.size);
-  }
-  psocket_init(&l->psocket, p, false, host, port);
-  l->condition = pn_condition();
-  l->batch.next_event = listener_batch_next;
-  l->backlog = backlog;
-  return l;
-}
-
 static void leader_count(pn_proactor_t *p, int change) {
   uv_mutex_lock(&p->lock);
   p->count += change;
@@ -456,24 +436,23 @@ static void on_connect(uv_connect_t *connect, int err) {
 }
 
 static void on_accept(uv_stream_t* server, int err) {
-  pn_listener_t* l = (pn_listener_t*)server->data;
-  if (!err) {
-    pn_rwbytes_t v =  pn_listener_get_extra(l);
-    pconnection_t *pc = new_pconnection_t(l->psocket.proactor, true,
-                          fixstr(l->psocket.host),
-                          fixstr(l->psocket.port),
-                          pn_bytes(v.size, v.start));
-    if (pc) {
-      int err2 = leader_init(&pc->psocket);
-      if (!err2) err2 = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
-      leader_connect_accept(pc, err2, "on accept");
-    } else {
-      err = UV_ENOMEM;
-    }
-  }
+  pn_listener_t *l = (pn_listener_t*) server->data;
   if (err) {
     leader_error(&l->psocket, err, "on accept");
   }
+  pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_ACCEPT);
+  leader_to_worker(&l->psocket); /* Let user call pn_listener_accept */
+}
+
+static void leader_accept(psocket_t *ps) {
+  pn_listener_t * l = as_listener(ps);
+  pconnection_t *pc = l->accepting;
+  l->accepting = NULL;
+  if (pc) {
+    int err = leader_init(&pc->psocket);
+    if (!err) err = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
+    leader_connect_accept(pc, err, "on accept");
+  }
 }
 
 static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
@@ -570,31 +549,39 @@ static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
 }
 
 static void leader_rewatch(psocket_t *ps) {
-  pconnection_t *pc = as_pconnection_t(ps);
-
-  if (pc->timer.data) {         /* uv-initialized */
-    on_tick(&pc->timer);        /* Re-enable ticks if required */
-  }
-  pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
-  pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
-
-  /* Ticks and checking buffers can generate events, process before proceeding */
-  if (pn_connection_driver_has_event(&pc->driver)) {
-    leader_to_worker(ps);
-  } else {                      /* Re-watch for IO */
-    if (wbuf.size > 0 && !pc->writing) {
-      pc->writing = wbuf.size;
-      uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
-      pc->write.data = ps;
-      uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
-    } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
-      pc->shutdown.data = ps;
-      uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
+  int err = 0;
+  if (ps->is_conn) {
+    pconnection_t *pc = as_pconnection_t(ps);
+    if (pc->timer.data) {         /* uv-initialized */
+      on_tick(&pc->timer);        /* Re-enable ticks if required */
     }
-    if (rbuf.size > 0 && !pc->reading) {
-      pc->reading = true;
-      uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
+    pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
+    pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
+
+    /* Ticks and checking buffers can generate events, process before proceeding */
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      leader_to_worker(ps);
+    } else {                      /* Re-watch for IO */
+      if (wbuf.size > 0 && !pc->writing) {
+        pc->writing = wbuf.size;
+        uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
+        pc->write.data = ps;
+        uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
+      } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
+        pc->shutdown.data = ps;
+        uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
+      }
+      if (rbuf.size > 0 && !pc->reading) {
+        pc->reading = true;
+        err = uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
+      }
     }
+  } else {
+    pn_listener_t *l = as_listener(ps);
+    err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
+  }
+  if (err) {
+    leader_error(ps, err, "rewatch");
   }
 }
 
@@ -668,6 +655,11 @@ void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
     }
     return;
   }
+  pn_listener_t *l = batch_listener(batch);
+  if (l) {
+    owner_to_leader(&l->psocket, leader_rewatch);
+    return;
+  }
   pn_proactor_t *bp = batch_proactor(batch);
   if (bp == p) {
     uv_mutex_lock(&p->lock);
@@ -676,7 +668,6 @@ void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
     uv_mutex_unlock(&p->lock);
     return;
   }
-  /* Nothing extra to do for listener, it is always in the UV loop. */
 }
 
 /* Run follower/leader loop till we can return an event and be a worker */
@@ -742,8 +733,8 @@ void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
   uv_mutex_unlock(&p->lock);
 }
 
-int pn_proactor_connect(pn_proactor_t *p, const char *host, const char *port, pn_bytes_t extra) {
-  pconnection_t *pc = new_pconnection_t(p, false, host, port, extra);
+int pn_proactor_connect(pn_proactor_t *p, pn_connection_t *c, const char *host, const char *port) {
+  pconnection_t *pc = new_pconnection_t(p, c, false, host, port);
   if (!pc) {
     return PN_OUT_OF_MEMORY;
   }
@@ -752,12 +743,12 @@ int pn_proactor_connect(pn_proactor_t *p, const char *host, const char *port, pn
   return 0;
 }
 
-pn_rwbytes_t pn_listener_get_extra(pn_listener_t *l) { return PN_EXTRA_GET(pn_listener_t, l); }
-
-pn_listener_t *pn_proactor_listen(pn_proactor_t *p, const char *host, const char *port, int backlog, pn_bytes_t extra) {
-  pn_listener_t *l = new_listener(p, host, port, backlog, extra);
-  if (l)  owner_to_leader(&l->psocket, leader_listen);
-  return l;
+int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *host, const char *port, int backlog)
+{
+  psocket_init(&l->psocket, p, false, host, port);
+  l->backlog = backlog;
+  owner_to_leader(&l->psocket, leader_listen);
+  return 0;
 }
 
 pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
@@ -765,10 +756,6 @@ pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
   return pc ? pc->psocket.proactor : NULL;
 }
 
-pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
-  return l ? l->psocket.proactor : NULL;
-}
-
 void leader_wake_connection(psocket_t *ps) {
   pconnection_t *pc = as_pconnection_t(ps);
   pn_connection_t *c = pc->driver.connection;
@@ -780,15 +767,6 @@ void pn_connection_wake(pn_connection_t* c) {
   wakeup(&get_pconnection_t(c)->psocket, leader_wake_connection);
 }
 
-void pn_listener_close(pn_listener_t* l) {
-  wakeup(&l->psocket, leader_close);
-}
-
-/* Only called when condition is closed by error. */
-pn_condition_t* pn_listener_condition(pn_listener_t* l) {
-  return l->condition;
-}
-
 pn_proactor_t *pn_proactor() {
   pn_proactor_t *p = (pn_proactor_t*)calloc(1, sizeof(*p));
   p->collector = pn_collector();
@@ -831,3 +809,65 @@ static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
 static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
   return pn_collector_next(batch_proactor(batch)->collector);
 }
+
+pn_listener_t *pn_listener() {
+  pn_listener_t *l = (pn_listener_t*)calloc(1, sizeof(pn_listener_t));
+  if (l) {
+    l->batch.next_event = listener_batch_next;
+    l->collector = pn_collector();
+    l->condition = pn_condition();
+    l->attachments = pn_record();
+    if (!l->condition || !l->collector || !l->attachments) {
+      pn_listener_free(l);
+      return NULL;
+    }
+  }
+  return l;
+}
+
+void pn_listener_free(pn_listener_t *l) {
+  if (l) {
+    if (!l->collector) pn_collector_free(l->collector);
+    if (!l->condition) pn_condition_free(l->condition);
+    if (!l->attachments) pn_free(l->attachments);
+    free(l);
+  }
+}
+
+void pn_listener_close(pn_listener_t* l) {
+  wakeup(&l->psocket, leader_close);
+}
+
+pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
+  return l ? l->psocket.proactor : NULL;
+}
+
+pn_condition_t* pn_listener_condition(pn_listener_t* l) {
+  return l->condition;
+}
+
+void *pn_listener_get_context(pn_listener_t *l) {
+  return l->context;
+}
+
+void pn_listener_set_context(pn_listener_t *l, void *context) {
+  l->context = context;
+}
+
+pn_record_t *pn_listener_attachments(pn_listener_t *l) {
+  return l->attachments;
+}
+
+int pn_listener_accept(pn_listener_t *l, pn_connection_t *c) {
+  if (l->accepting) {
+    return PN_STATE_ERR;        /* Only one at a time */
+  }
+  l->accepting = new_pconnection_t(
+      l->psocket.proactor, c, true, l->psocket.host, l->psocket.port);
+  if (!l->accepting) {
+    return UV_ENOMEM;
+  }
+  owner_to_leader(&l->psocket, leader_accept);
+  return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index 88e3456..b8edcd6 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -187,7 +187,7 @@ int main(int argc, char **argv) {
 
   /* Create the proactor and connect */
   app.proactor = pn_proactor();
-  pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
+  pn_proactor_connect(app.proactor, pn_connection(), host, port);
   if (url) pn_url_free(url);
 
   do {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index 42facb0..d611b3d 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -216,7 +216,7 @@ int main(int argc, char **argv) {
 
   /* Create the proactor and connect */
   app.proactor = pn_proactor();
-  pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
+  pn_proactor_connect(app.proactor, pn_connection(), host, port);
   if (url) pn_url_free(url);
 
   do {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/proton-c/include/proton/connection.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection.h b/proton-c/include/proton/connection.h
index 70fad73..5b966cd 100644
--- a/proton-c/include/proton/connection.h
+++ b/proton-c/include/proton/connection.h
@@ -156,7 +156,6 @@ PN_EXTERN pn_collector_t* pn_connection_collector(pn_connection_t *connection);
 
 
 /**
- * @deprecated
  * Get the application context that is associated with a connection
  * object.
  *
@@ -169,7 +168,6 @@ PN_EXTERN pn_collector_t* pn_connection_collector(pn_connection_t *connection);
 PN_EXTERN void *pn_connection_get_context(pn_connection_t *connection);
 
 /**
- * @deprecated
  * Set a new application context for a connection object.
  *
  * The application context for a connection object may be retrieved
@@ -485,16 +483,6 @@ PN_EXTERN pn_data_t *pn_connection_remote_properties(pn_connection_t *connection
  */
 PN_EXTERN pn_transport_t *pn_connection_transport(pn_connection_t *connection);
 
-/**
- * Create a connection with `size` bytes of extra aligned storage in the same heap block.
- */
-PN_EXTERN pn_connection_t* pn_connection_with_extra(size_t size);
-
-/**
- * Get the start and size of extra storage allocated by pn_connection_extra()
- */
-PN_EXTERN pn_rwbytes_t pn_connection_get_extra(pn_connection_t *connection);
-
 /** @}
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 31d4bdd..7793f1c 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -323,19 +323,25 @@ typedef enum {
   PN_CONNECTION_WAKE,
 
   /**
-   * pn_listener_close() was called or an error occurred, see pn_listener_condition()
+   * Indicates the listener is ready to call pn_listener_accept() 
+   * Events of this type point to the @ref pn_listener_t.
+   */
+  PN_LISTENER_ACCEPT,
+
+  /**
+   * Indicates the listener has closed. pn_listener_condition() provides error information.
    * Events of this type point to the @ref pn_listener_t.
    */
   PN_LISTENER_CLOSE,
 
   /**
-   * pn_proactor_interrupt() was called to interrupt a proactor thread
+   * Indicates pn_proactor_interrupt() was called to interrupt a proactor thread
    * Events of this type point to the @ref pn_proactor_t.
    */
   PN_PROACTOR_INTERRUPT,
 
   /**
-   * pn_proactor_set_timeout() time limit expired.
+   * Timeout set by pn_proactor_set_timeout() time limit expired.
    * Events of this type point to the @ref pn_proactor_t.
    */
   PN_PROACTOR_TIMEOUT,

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/proton-c/include/proton/extra.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/extra.h b/proton-c/include/proton/extra.h
deleted file mode 100644
index ea2e1ef..0000000
--- a/proton-c/include/proton/extra.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef EXTRA_H
-#define EXTRA_H
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <proton/type_compat.h>
-#include <proton/types.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-/**
- * @cond INTERNAL
- * Support for allocating extra aligned memory after a type.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * extra_t contains a size and is maximally aligned so the memory immediately
- * after it can store any type of value.
- */
-typedef union pn_extra_t {
-  size_t size;
-#if __STDC_VERSION__ >= 201112
-  max_align_t max;
-#else
-/* Not standard but fairly safe */
-  uint64_t i;
-  long double d;
-  void *v;
-  void (*fp)(void);
-#endif
-} pn_extra_t;
-
-static inline pn_rwbytes_t pn_extra_rwbytes(pn_extra_t *x) {
-    return pn_rwbytes(x->size, (char*)(x+1));
-}
-
-/* Declare private helper struct for T */
-#define PN_EXTRA_DECLARE(T) typedef struct T##__extra { T base; pn_extra_t extra; } T##__extra
-#define PN_EXTRA_SIZEOF(T, N) (sizeof(T##__extra)+(N))
-#define PN_EXTRA_GET(T, P) pn_extra_rwbytes(&((T##__extra*)(P))->extra)
-
-#ifdef __cplusplus
-}
-#endif
-
-/** @endcond */
-
-#endif // EXTRA_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index f55479b..5e60649 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -40,30 +40,57 @@ typedef struct pn_proactor_t pn_proactor_t;
 typedef struct pn_condition_t pn_condition_t;
 
 /**
- * Listener accepts connections, see pn_proactor_listen()
+ * A listener accepts connections.
  */
 typedef struct pn_listener_t pn_listener_t;
 
 /**
- * The proactor that created the listener.
+ * Create a listener.
  */
-pn_proactor_t *pn_listener_proactor(pn_listener_t *c);
+PN_EXTERN pn_listener_t *pn_listener(void);
+
+/**
+ * Free a listener
+ */
+PN_EXTERN void pn_listener_free(pn_listener_t*);
+
+/**
+ * Asynchronously accept a connection using the listener.
+ *
+ * @param[in] connection the listener takes ownership, do not free.
+ */
+PN_EXTERN int pn_listener_accept(pn_listener_t*, pn_connection_t *connection);
 
 /**
  * Get the error condition for a listener.
  */
-pn_condition_t *pn_listener_condition(pn_listener_t *l);
+PN_EXTERN pn_condition_t *pn_listener_condition(pn_listener_t *l);
 
 /**
- * Get the user-provided value associated with the listener in pn_proactor_listen()
- * The start address is aligned so you can cast it to any type.
+ * Get the application context that is associated with a listener.
  */
-pn_rwbytes_t pn_listener_get_extra(pn_listener_t*);
+PN_EXTERN void *pn_listener_get_context(pn_listener_t *listener);
+
+/**
+ * Set a new application context for a listener.
+ */
+PN_EXTERN void pn_listener_set_context(pn_listener_t *listener, void *context);
+
+/**
+ * Get the attachments that are associated with a listener object.
+ */
+PN_EXTERN pn_record_t *pn_listener_attachments(pn_listener_t *listener);
 
 /**
  * Close the listener (thread safe).
  */
-void pn_listener_close(pn_listener_t *l);
+PN_EXTERN void pn_listener_close(pn_listener_t *l);
+
+/**
+ * The proactor associated with a listener.
+ */
+PN_EXTERN pn_proactor_t *pn_listener_proactor(pn_listener_t *c);
+
 
 /**
  *@}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index e23a24f..9d39c9c 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -68,30 +68,30 @@ pn_proactor_t *pn_proactor(void);
 void pn_proactor_free(pn_proactor_t*);
 
 /**
- * Asynchronous connect: a connection and transport will be created, the
- * relevant events will be returned by pn_proactor_wait()
+ * Connect connection to host/port. Connection and transport events will be
+ * returned by pn_proactor_wait()
  *
- * Errors are indicated by PN_TRANSPORT_ERROR/PN_TRANSPORT_CLOSE events.
+ * @param[in] connection the proactor takes ownership do not free.
+ * @param[in] host the address to listen on
+ * @param[in] port the port to connect to
  *
- * @param extra bytes to copy to pn_connection_get_extra() on the new connection, @ref
- * pn_rwbytes_null for nothing.
- *
- * @return error if the connect cannot be initiated e.g. an allocation failure.
- * IO errors will be returned as transport events via pn_proactor_wait()
+ * @return error on immediate error, e.g. an allocation failure.
+ * Other errors are indicated by connection or transport events via pn_proactor_wait()
  */
-int pn_proactor_connect(pn_proactor_t*, const char *host, const char *port, pn_bytes_t extra);
+int pn_proactor_connect(pn_proactor_t*, pn_connection_t *connection, const char *host, const char *port);
 
 /**
- * Asynchronous listen: start listening, connections will be returned by pn_proactor_wait()
- * An error are indicated by PN_LISTENER_ERROR event.
+ * Start listening with listener.
+ * pn_proactor_wait() will return a PN_LISTENER_ACCEPT event when a connection can be accepted.
  *
- * @param extra bytes to copy to pn_connection_get_extra() on the new connection, @ref
- * pn_rwbytes_null for nothing.
+ * @param[in] listener proactor takes ownership of listener, do not free.
+ * @param[in] host the address to listen on
+ * @param[in] port the port to listen on
  *
- * @return error if the connect cannot be initiated e.g. an allocation failure.
- * IO errors will be returned as transport events via pn_proactor_wait()
+ * @return error on immediate error, e.g. an allocation failure.
+ * Other errors are indicated by pn_listener_condition() on the PN_LISTENER_CLOSE event.
  */
-pn_listener_t *pn_proactor_listen(pn_proactor_t *, const char *host, const char *port, int backlog, pn_bytes_t extra);
+int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *listener, const char *host, const char *port, int backlog);
 
 /**
  * Wait for events to handle. Call pn_proactor_done() after handling events.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/aadfcbbb/proton-c/src/core/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine.c b/proton-c/src/core/engine.c
index 2836a43..99d311b 100644
--- a/proton-c/src/core/engine.c
+++ b/proton-c/src/core/engine.c
@@ -32,9 +32,6 @@
 #include "platform/platform_fmt.h"
 #include "transport.h"
 
-#include <proton/extra.h>
-
-
 static void pni_session_bound(pn_session_t *ssn);
 static void pni_link_bound(pn_link_t *link);
 
@@ -511,15 +508,10 @@ static void pn_connection_finalize(void *object)
 #define pn_connection_compare NULL
 #define pn_connection_inspect NULL
 
-PN_EXTRA_DECLARE(pn_connection_t);
-
-pn_rwbytes_t pn_connection_get_extra(pn_connection_t *c) { return PN_EXTRA_GET(pn_connection_t, c); }
-
-pn_connection_t *pn_connection_with_extra(size_t extra)
+pn_connection_t *pn_connection()
 {
   static const pn_class_t clazz = PN_CLASS(pn_connection);
-  size_t size = PN_EXTRA_SIZEOF(pn_connection_t, extra);
-  pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, size);
+  pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, sizeof(pn_connection_t));
   if (!conn) return NULL;
 
   conn->endpoint_head = NULL;
@@ -548,10 +540,6 @@ pn_connection_t *pn_connection_with_extra(size_t extra)
   return conn;
 }
 
-pn_connection_t *pn_connection(void) {
-  return pn_connection_with_extra(0);
-}
-
 static const pn_event_type_t endpoint_init_event_map[] = {
   PN_CONNECTION_INIT,  /* CONNECTION */
   PN_SESSION_INIT,     /* SESSION */


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


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

Posted by ac...@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/go1
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


[07/48] 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 ac...@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


[43/48] qpid-proton git commit: PROTON-1344: removed unused pn_listener_free, update proactor doc.

Posted by ac...@apache.org.
PROTON-1344: removed unused pn_listener_free, update proactor doc.


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

Branch: refs/heads/go1
Commit: 6af49b819edb0d7d3aaa9968fc5ee1651f77f492
Parents: 468b719
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 23 11:07:44 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 23 11:08:08 2016 -0500

----------------------------------------------------------------------
 examples/c/proactor/libuv_proactor.c | 18 +++++++++---------
 proton-c/include/proton/listener.h   | 11 ++++++-----
 proton-c/include/proton/proactor.h   | 31 ++++++++++++++++++++-----------
 3 files changed, 35 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6af49b81/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
index 9770166..42bbfab 100644
--- a/examples/c/proactor/libuv_proactor.c
+++ b/examples/c/proactor/libuv_proactor.c
@@ -810,6 +810,15 @@ static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
   return pn_collector_next(batch_proactor(batch)->collector);
 }
 
+static void pn_listener_free(pn_listener_t *l) {
+  if (l) {
+    if (!l->collector) pn_collector_free(l->collector);
+    if (!l->condition) pn_condition_free(l->condition);
+    if (!l->attachments) pn_free(l->attachments);
+    free(l);
+  }
+}
+
 pn_listener_t *pn_listener() {
   pn_listener_t *l = (pn_listener_t*)calloc(1, sizeof(pn_listener_t));
   if (l) {
@@ -825,15 +834,6 @@ pn_listener_t *pn_listener() {
   return l;
 }
 
-void pn_listener_free(pn_listener_t *l) {
-  if (l) {
-    if (!l->collector) pn_collector_free(l->collector);
-    if (!l->condition) pn_condition_free(l->condition);
-    if (!l->attachments) pn_free(l->attachments);
-    free(l);
-  }
-}
-
 void pn_listener_close(pn_listener_t* l) {
   wakeup(&l->psocket, leader_close);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6af49b81/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index cd3d95f..dda1638 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -48,15 +48,16 @@ typedef struct pn_listener_t pn_listener_t;
 
 /**
  * Create a listener.
+ *
+ * You can use pn_listener_set_context() or pn_listener_attachments() to set
+ * application data that can be accessed when accepting connections.
+ *
+ * You must pass the returned listener to pn_proactor_listen(), the proactor
+ * will free the listener when it is no longer active.
  */
 PN_EXTERN pn_listener_t *pn_listener(void);
 
 /**
- * Free a listener
- */
-PN_EXTERN void pn_listener_free(pn_listener_t*);
-
-/**
  * Asynchronously accept a connection using the listener.
  *
  * @param[in] connection the listener takes ownership, do not free.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6af49b81/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index cd44526..fdb723b 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -62,7 +62,8 @@ typedef struct pn_proactor_t pn_proactor_t;
 pn_proactor_t *pn_proactor(void);
 
 /**
- * Free the proactor.
+ * Free the proactor. Abort any open network connections and clean up all
+ * associated resources.
  */
 void pn_proactor_free(pn_proactor_t*);
 
@@ -97,7 +98,7 @@ int pn_proactor_listen(pn_proactor_t *, pn_listener_t *listener, const char *hos
  * Wait for events to handle.
  *
  * Handle events in the returned batch by calling pn_event_batch_next() until it
- * returns NULL. You must call pn_proactor_done() to when you are finished.
+ * returns NULL. You must call pn_proactor_done() when you are finished with the batch.
  *
  * If you call pn_proactor_done() before finishing the batch, the remaining
  * events will be returned again by another call pn_proactor_wait().  This is
@@ -108,21 +109,28 @@ int pn_proactor_listen(pn_proactor_t *, pn_listener_t *listener, const char *hos
  * handled in sequence, but batches returned by separate calls to
  * pn_proactor_wait() can be handled concurrently.
  */
-pn_event_batch_t *pn_proactor_wait(pn_proactor_t* d);
+pn_event_batch_t *pn_proactor_wait(pn_proactor_t *d);
 
 /**
- * Call when done handling events.
+ * Call when done handling a batch of events.
  *
  * Must be called exactly once to match each call to pn_proactor_wait().
  *
- * Thread safe: may be called from any thread provided the exactly once rules is
+ * Thread safe: may be called from any thread provided the exactly once rule is
  * respected.
  */
-void pn_proactor_done(pn_proactor_t* d, pn_event_batch_t *events);
+void pn_proactor_done(pn_proactor_t *d, pn_event_batch_t *events);
 
 /**
- * Cause PN_PROACTOR_INTERRUPT to be returned to exactly one thread calling wait()
- * for each call to pn_proactor_interrupt(). Thread safe.
+ * Cause PN_PROACTOR_INTERRUPT to be returned to exactly one call of
+ * pn_proactor_wait().
+ *
+ * If threads are blocked in pn_proactor_wait(), one of them will be
+ * interrupted, otherwise the interrupt will be returned by a future call to
+ * pn_proactor_wait(). Calling pn_proactor_interrupt() N times will return
+ * PN_PROACTOR_INTERRUPT to N current or future calls of pn_proactor_wait()
+ *
+ * Thread safe.
  */
 void pn_proactor_interrupt(pn_proactor_t* d);
 
@@ -131,8 +139,9 @@ void pn_proactor_interrupt(pn_proactor_t* d);
  * timeout milliseconds. Thread safe.
  *
  * Note calling pn_proactor_set_timeout() again before the PN_PROACTOR_TIMEOUT is
- * delivered will cancel the previous timeout and deliver an event only after
- * the new timeout.
+  *delivered will cancel the previous timeout and deliver an event only after
+ * the new timeout. ::pn_proactor_set_timeout(0) will cancel the timeout
+ * without setting a new one.
  */
 void pn_proactor_set_timeout(pn_proactor_t* d, pn_millis_t timeout);
 
@@ -140,7 +149,7 @@ void pn_proactor_set_timeout(pn_proactor_t* d, pn_millis_t timeout);
  * Cause a PN_CONNECTION_WAKE event to be returned by the proactor, even if
  * there are no IO events pending for the connection.
  *
- * Thread safe: this is the only pn_connection_ function that can be
+ * **Thread safe**: this is the only pn_connection_ function that can be
  * called concurrently.
  *
  * Wakes can be "coalesced" - if several pn_connection_wake() calls happen


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


[38/48] qpid-proton git commit: PROTON-1355: Set ssl.peer_hostname to virtual_host if specified

Posted by ac...@apache.org.
PROTON-1355: Set ssl.peer_hostname to virtual_host if specified


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

Branch: refs/heads/go1
Commit: 2eac44b53f26c474a42f28be789a3d20fe909307
Parents: f45cdce
Author: Ulf Lilleengen <lu...@redhat.com>
Authored: Fri Nov 18 09:52:02 2016 +0100
Committer: Gordon Sim <gs...@redhat.com>
Committed: Fri Nov 18 10:41:17 2016 +0000

----------------------------------------------------------------------
 proton-c/bindings/python/proton/reactor.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2eac44b5/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 1a85bd3..3562aa9 100644
--- a/proton-c/bindings/python/proton/reactor.py
+++ b/proton-c/bindings/python/proton/reactor.py
@@ -565,7 +565,7 @@ class Connector(Handler):
             if not self.ssl_domain:
                 raise SSLUnavailable("amqps: SSL libraries not found")
             self.ssl = SSL(transport, self.ssl_domain)
-            self.ssl.peer_hostname = url.host
+            self.ssl.peer_hostname = self.virtual_host if self.virtual_host != None else url.host
 
     def on_connection_local_open(self, event):
         self._connect(event.connection, event.reactor)


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


[45/48] qpid-proton git commit: PROTON-1361: mark proton-j Messsenger and related driver as deprecated

Posted by ac...@apache.org.
PROTON-1361: mark proton-j Messsenger and related driver as deprecated


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

Branch: refs/heads/go1
Commit: 451b3b4cf0b4834faefea8a58e6f890f65974af8
Parents: 8c306f2
Author: Robert Gemmell <ro...@apache.org>
Authored: Thu Nov 24 12:46:51 2016 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Thu Nov 24 12:46:51 2016 +0000

----------------------------------------------------------------------
 .../java/org/apache/qpid/proton/example/Recv.java     |  2 ++
 .../java/org/apache/qpid/proton/example/Send.java     |  2 ++
 .../src/main/java/org/apache/qpid/proton/Proton.java  | 14 +++++++++++++-
 .../java/org/apache/qpid/proton/driver/Connector.java |  3 +++
 .../java/org/apache/qpid/proton/driver/Driver.java    |  9 ++++++++-
 .../java/org/apache/qpid/proton/driver/Listener.java  |  2 ++
 .../apache/qpid/proton/driver/impl/ConnectorImpl.java |  1 +
 .../apache/qpid/proton/driver/impl/DriverImpl.java    |  1 +
 .../apache/qpid/proton/driver/impl/ListenerImpl.java  |  1 +
 .../org/apache/qpid/proton/messenger/Messenger.java   |  8 +++++++-
 .../qpid/proton/messenger/MessengerException.java     |  4 ++++
 .../java/org/apache/qpid/proton/messenger/Status.java |  4 ++++
 .../org/apache/qpid/proton/messenger/Tracker.java     |  4 ++++
 .../apache/qpid/proton/messenger/impl/Address.java    |  8 +++++++-
 .../qpid/proton/messenger/impl/MessengerImpl.java     | 11 ++++++-----
 .../org/apache/qpid/proton/messenger/impl/Store.java  |  3 +++
 .../apache/qpid/proton/messenger/impl/StoreEntry.java |  3 +++
 .../qpid/proton/messenger/impl/TrackerImpl.java       |  3 +++
 .../apache/qpid/proton/messenger/impl/Transform.java  |  2 +-
 .../apache/qpid/proton/reactor/impl/AcceptorImpl.java |  1 +
 .../apache/qpid/proton/reactor/impl/IOHandler.java    |  1 +
 .../apache/qpid/proton/reactor/impl/ReactorImpl.java  |  1 +
 .../qpid/proton/messenger/impl/AddressTest.java       |  1 +
 23 files changed, 79 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Recv.java
----------------------------------------------------------------------
diff --git a/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Recv.java b/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Recv.java
index 769eca8..3934cff 100644
--- a/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Recv.java
+++ b/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Recv.java
@@ -36,7 +36,9 @@ import java.util.logging.Logger;
  * Based closely qpid src/proton/examples/messenger/py/recv.py
  * @author mberkowitz@sf.org
  * @since 8/4/2013
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
  */
+@Deprecated
 public class Recv {
     private static Logger tracer = Logger.getLogger("proton.example");
     private boolean verbose = false;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Send.java
----------------------------------------------------------------------
diff --git a/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Send.java b/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Send.java
index 56bce55..6f4a919 100644
--- a/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Send.java
+++ b/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Send.java
@@ -36,7 +36,9 @@ import java.util.logging.Logger;
  * Based closely qpid src/proton/examples/messenger/py/send.py
  * @author mberkowitz@sf.org
  * @since 8/4/2013
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
  */
+@Deprecated
 public class Send {
 
     private static Logger tracer = Logger.getLogger("proton.example");

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/Proton.java b/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
index b64225a..38f39e0 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/Proton.java
@@ -43,6 +43,7 @@ import org.apache.qpid.proton.message.Message;
 import org.apache.qpid.proton.messenger.Messenger;
 import org.apache.qpid.proton.reactor.Reactor;
 
+@SuppressWarnings("deprecation")
 public final class Proton
 {
 
@@ -95,17 +96,28 @@ public final class Proton
                                       applicationProperties, body, footer);
     }
 
-
+    /**
+     * @deprecated Messenger will be removed from upcoming proton-j releases.
+     */
+    @Deprecated
     public static Messenger messenger()
     {
         return Messenger.Factory.create();
     }
 
+    /**
+     * @deprecated  Messenger will be removed from upcoming proton-j releases.
+     */
+    @Deprecated
     public static Messenger messenger(String name)
     {
         return Messenger.Factory.create(name);
     }
 
+    /**
+     * @deprecated Messenger and its driver will be removed from upcoming proton-j releases.
+     */
+    @Deprecated
     public static Driver driver() throws IOException
     {
         return Driver.Factory.create();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/driver/Connector.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/Connector.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/Connector.java
index b03d5c5..619b1cf 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/Connector.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/Connector.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.proton.driver;
 
 import java.io.IOException;
+
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.Sasl;
 import org.apache.qpid.proton.engine.Transport;
@@ -36,7 +37,9 @@ import org.apache.qpid.proton.engine.Transport;
  * Implementations are not necessarily thread-safe.
  *
  * @param <C> application supplied context
+ * @deprecated Messenger and its connector will be removed from upcoming proton-j releases.
  */
+@Deprecated
 public interface Connector<C>
 {
     /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
index dd00fc5..3d8ada3 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/Driver.java
@@ -24,6 +24,7 @@ package org.apache.qpid.proton.driver;
 import java.io.IOException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.ServerSocketChannel;
+
 import org.apache.qpid.proton.driver.impl.DriverImpl;
 
 /**
@@ -39,10 +40,16 @@ import org.apache.qpid.proton.driver.impl.DriverImpl;
  * AMQP over SASL over TCP.
  *
  * Unless otherwise stated, methods on Driver implementations are not necessarily thread-safe.
+ *
+ * @deprecated Messenger and its driver will be removed from upcoming proton-j releases.
  */
+@Deprecated
 public interface Driver
 {
-
+    /**
+     * @deprecated Messenger and its driver will be removed from upcoming proton-j releases.
+     */
+    @Deprecated
     public static final class Factory
     {
         public static Driver create() throws IOException {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/driver/Listener.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/Listener.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/Listener.java
index dd10016..7541d4d 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/Listener.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/Listener.java
@@ -24,7 +24,9 @@ package org.apache.qpid.proton.driver;
  * Server API.
  *
  * @param <C> application supplied context
+ * @deprecated Messenger and its listener will be removed from upcoming proton-j releases.
  */
+@Deprecated
 public interface Listener<C>
 {
     /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
index e3e43c4..18cad9a 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ConnectorImpl.java
@@ -33,6 +33,7 @@ import org.apache.qpid.proton.engine.Sasl;
 import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
 
+@SuppressWarnings("deprecation")
 class ConnectorImpl<C> implements Connector<C>
 {
     private static int DEFAULT_BUFFER_SIZE = 64 * 1024;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
index bfdd017..6264d7a 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
@@ -42,6 +42,7 @@ import org.apache.qpid.proton.driver.Connector;
 import org.apache.qpid.proton.driver.Driver;
 import org.apache.qpid.proton.driver.Listener;
 
+@SuppressWarnings("deprecation")
 public class DriverImpl implements Driver
 {
     private Selector _selector;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ListenerImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ListenerImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ListenerImpl.java
index 431b06e..a7dd936 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ListenerImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/driver/impl/ListenerImpl.java
@@ -29,6 +29,7 @@ import java.util.logging.Logger;
 import org.apache.qpid.proton.driver.Connector;
 import org.apache.qpid.proton.driver.Listener;
 
+@SuppressWarnings("deprecation")
 class ListenerImpl<C> implements Listener<C>
 {
     private C _context;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
index 6d3f362..bd19259 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
@@ -24,7 +24,6 @@ import java.io.IOException;
 
 import org.apache.qpid.proton.TimeoutException;
 import org.apache.qpid.proton.message.Message;
-
 import org.apache.qpid.proton.messenger.impl.MessengerImpl;
 
 /**
@@ -68,10 +67,17 @@ import org.apache.qpid.proton.messenger.impl.MessengerImpl;
  *
  *  Similarly, the get method will decode the content in the incoming
  *  message queue into the supplied Message object.
+ *
+ *  @deprecated Messenger will be removed from upcoming proton-j releases.
 */
+@Deprecated
 public interface Messenger
 {
 
+    /**
+     * @deprecated Messenger will be removed from upcoming proton-j releases.
+     */
+    @Deprecated
     public static final class Factory
     {
         public static Messenger create() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerException.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerException.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerException.java
index 0f3aabf..c6f3570 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerException.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/MessengerException.java
@@ -23,6 +23,10 @@ package org.apache.qpid.proton.messenger;
 
 import org.apache.qpid.proton.ProtonException;
 
+/**
+ * @deprecated  Messenger will be removed from upcoming proton-j releases.
+ */
+@Deprecated
 public class MessengerException extends ProtonException
 {
     public MessengerException()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/Status.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Status.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Status.java
index 3cb7fc9..ae7ca95 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Status.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Status.java
@@ -20,6 +20,10 @@
 */
 package org.apache.qpid.proton.messenger;
 
+/**
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
+ */
+@Deprecated
 public enum Status
 {
     UNKNOWN,

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/Tracker.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Tracker.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Tracker.java
index d0d9e39..974b1b6 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/Tracker.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/Tracker.java
@@ -20,5 +20,9 @@
 */
 package org.apache.qpid.proton.messenger;
 
+/**
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
+ */
+@Deprecated
 public interface Tracker { }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
index 6ae75a7..27b0d39 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Address.java
@@ -24,8 +24,8 @@ package org.apache.qpid.proton.messenger.impl;
 /**
  * Address
  *
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
  */
-
 public class Address
 {
 
@@ -49,11 +49,17 @@ public class Address
         _name = null;
     }
 
+    /**
+     * @deprecated Messenger will be removed from upcoming proton-j releases.
+     */
     public Address()
     {
         clear();
     }
 
+    /**
+     * @deprecated Messenger will be removed from upcoming proton-j releases.
+     */
     public Address(String address)
     {
         clear();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
index 44239c5..e7c9d9e 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
@@ -54,9 +54,12 @@ import org.apache.qpid.proton.amqp.messaging.Source;
 import org.apache.qpid.proton.amqp.messaging.Target;
 import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
 import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
-
 import org.apache.qpid.proton.amqp.Binary;
 
+/**
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
+ */
+@Deprecated
 public class MessengerImpl implements Messenger
 {
     private enum LinkCreditMode
@@ -103,8 +106,7 @@ public class MessengerImpl implements Messenger
 
 
     /**
-     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
-     * Client code outside this module should use {@link Messenger.Factory#create()} instead
+     * @deprecated Messenger will be removed from upcoming proton-j releases.
      */
     @Deprecated public MessengerImpl()
     {
@@ -112,8 +114,7 @@ public class MessengerImpl implements Messenger
     }
 
     /**
-     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
-     * Client code outside this module should use a {@link Messenger.Factory#create(String)} instead
+     * @deprecated Messenger will be removed from upcoming proton-j releases.
      */
     @Deprecated public MessengerImpl(String name)
     {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Store.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Store.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Store.java
index 5d60879..b60e8ed 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Store.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Store.java
@@ -33,6 +33,9 @@ import org.apache.qpid.proton.engine.Delivery;
 import org.apache.qpid.proton.amqp.messaging.Accepted;
 import org.apache.qpid.proton.amqp.messaging.Rejected;
 
+/**
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
+ */
 class Store
 {
     private static final Accepted ACCEPTED = Accepted.getInstance();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/StoreEntry.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/StoreEntry.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/StoreEntry.java
index 3cbb10a..1687b94 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/StoreEntry.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/StoreEntry.java
@@ -30,6 +30,9 @@ import org.apache.qpid.proton.amqp.messaging.Released;
 import org.apache.qpid.proton.amqp.messaging.Received;
 import org.apache.qpid.proton.amqp.transport.DeliveryState;
 
+/**
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
+ */
 class StoreEntry
 {
     private Store  _store;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerImpl.java
index 7f9736a..2d8b584 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerImpl.java
@@ -22,6 +22,9 @@ package org.apache.qpid.proton.messenger.impl;
 
 import org.apache.qpid.proton.messenger.Tracker;
 
+/**
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
+ */
 class TrackerImpl implements Tracker
 {
     public enum Type {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Transform.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Transform.java b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Transform.java
index d85e221..c3a08ea 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Transform.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/messenger/impl/Transform.java
@@ -29,8 +29,8 @@ import java.util.regex.Pattern;
 /**
  * Transform
  *
+ * @deprecated Messenger will be removed from upcoming proton-j releases.
  */
-
 class Transform
 {
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/AcceptorImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/AcceptorImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/AcceptorImpl.java
index bae61bc..c5abbd8 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/AcceptorImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/AcceptorImpl.java
@@ -42,6 +42,7 @@ import org.apache.qpid.proton.reactor.Selectable;
 import org.apache.qpid.proton.reactor.Selectable.Callback;
 import org.apache.qpid.proton.messenger.impl.Address;
 
+@SuppressWarnings("deprecation")
 public class AcceptorImpl implements Acceptor {
 
     private Record attachments = new RecordImpl();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
index f407fd0..2dd7e1a 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
@@ -47,6 +47,7 @@ import org.apache.qpid.proton.reactor.Acceptor;
 import org.apache.qpid.proton.reactor.impl.AcceptorImpl;
 import org.apache.qpid.proton.messenger.impl.Address;
 
+@SuppressWarnings("deprecation")
 public class IOHandler extends BaseHandler {
 
     // pni_handle_quiesced from connection.c

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/ReactorImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/ReactorImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/ReactorImpl.java
index 7448648..30c8df9 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/ReactorImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/ReactorImpl.java
@@ -53,6 +53,7 @@ import org.apache.qpid.proton.reactor.Selector;
 import org.apache.qpid.proton.reactor.Task;
 import org.apache.qpid.proton.messenger.impl.Address;
 
+@SuppressWarnings("deprecation")
 public class ReactorImpl implements Reactor, Extendable {
     public static final ExtendableAccessor<Event, Handler> ROOT = new ExtendableAccessor<>(Handler.class);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/451b3b4c/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java b/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
index f741519..77154b6 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/messenger/impl/AddressTest.java
@@ -22,6 +22,7 @@ import org.junit.Test;
 
 public class AddressTest {
 
+    @SuppressWarnings("deprecation")
     private void testParse(String url, String scheme, String user, String pass, String host, String port, String name)
     {
         Address address = new Address(url);


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


[02/48] qpid-proton git commit: PROTON-1346: update the name for clarity

Posted by ac...@apache.org.
PROTON-1346: update the name for clarity


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

Branch: refs/heads/go1
Commit: efd033c98f6fdc1bebcc92e6d3d3c858bcbb5edf
Parents: 6afca2d
Author: Robert Gemmell <ro...@apache.org>
Authored: Tue Nov 8 12:01:36 2016 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Tue Nov 8 12:01:36 2016 +0000

----------------------------------------------------------------------
 .../main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/efd033c9/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
index 178a27b..f407fd0 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java
@@ -154,10 +154,10 @@ public class IOHandler extends BaseHandler {
             socketChannel.configureBlocking(false);
             socketChannel.connect(new InetSocketAddress(hostname, port));
             socket = socketChannel.socket();
-        } catch(Exception ioException) {
+        } catch(Exception exception) {
             ErrorCondition condition = new ErrorCondition();
             condition.setCondition(Symbol.getSymbol("proton:io"));
-            condition.setDescription(ioException.getMessage());
+            condition.setDescription(exception.getMessage());
             transport.setCondition(condition);
             transport.close_tail();
             transport.close_head();


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


[20/48] 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 ac...@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


[06/48] 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 ac...@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


[09/48] 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 ac...@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


[37/48] qpid-proton git commit: NO-JIRA: C API documentation - module descriptions.

Posted by ac...@apache.org.
NO-JIRA: C API documentation - module descriptions.

Added missing module descriptions.
Rewrote some descriptions to be more informative and less repetative.
E.g. "Link API for proton Engine" -> "One-way message link"


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

Branch: refs/heads/go1
Commit: f45cdced118908f5da29a63d3d7dd6e6068d6115
Parents: bbeb096
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 17 14:16:45 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Nov 17 14:16:45 2016 -0500

----------------------------------------------------------------------
 proton-c/docs/api/index.md                  | 24 +++++++++++-------------
 proton-c/include/proton/codec.h             |  4 ++--
 proton-c/include/proton/condition.h         |  9 +++++----
 proton-c/include/proton/connection.h        |  3 ++-
 proton-c/include/proton/connection_driver.h |  6 ++++--
 proton-c/include/proton/delivery.h          |  4 ++--
 proton-c/include/proton/disposition.h       |  4 ++--
 proton-c/include/proton/engine.h            |  8 +++++---
 proton-c/include/proton/event.h             |  4 ++--
 proton-c/include/proton/handlers.h          |  1 +
 proton-c/include/proton/link.h              |  7 ++++---
 proton-c/include/proton/listener.h          |  4 +++-
 proton-c/include/proton/message.h           |  6 ++++--
 proton-c/include/proton/messenger.h         |  1 +
 proton-c/include/proton/proactor.h          |  5 ++---
 proton-c/include/proton/reactor.h           |  1 +
 proton-c/include/proton/sasl.h              |  8 +++++---
 proton-c/include/proton/selectable.h        |  1 +
 proton-c/include/proton/session.h           |  6 ++++--
 proton-c/include/proton/ssl.h               | 10 +++++++---
 proton-c/include/proton/terminus.h          |  7 ++++---
 proton-c/include/proton/transport.h         |  6 ++++--
 proton-c/include/proton/types.h             |  4 ++++
 proton-c/include/proton/url.h               |  8 +++++---
 24 files changed, 85 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/docs/api/index.md
----------------------------------------------------------------------
diff --git a/proton-c/docs/api/index.md b/proton-c/docs/api/index.md
index 6a72d6b..fada41c 100644
--- a/proton-c/docs/api/index.md
+++ b/proton-c/docs/api/index.md
@@ -1,21 +1,19 @@
 Proton Documentation            {#index}
 ====================
 
-The @ref engine is an AMQP "protocol engine".  It provides functions to
-manipulate AMQP endpoints and messages and generates [events](@ref event) for
-the application to handle.  The @ref engine has no dependencies on IO or
-threading libraries.
+The @ref engine is a collection of types and functions representing AMQP
+concepts.  Together they form a "protocol engine" API to create AMQP connections
+and links, handle AMQP @ref event "events" and send and receive messages.
 
-The @ref proactor is a proactive, asynchronous framework to
-build single or multi-threaded Proton C applications. It manages the IO
-transport layer so you can write portable, event-driven AMQP code using the
-@ref engine API.
+The @ref proactor is a portable, proactive, asynchronous API for single or
+multi-threaded applications. It associates the @ref engine API with network
+connections (@ref transport "transports") and allows one or more threads to
+handle @ref event "events".
 
-**Low-level integration**: The @ref connection_driver provides
-a simple bytes in/bytes out interface to the @ref engine for a single
-connection.  You can use this to integrate proton with special IO libraries or
-external event loops. It is also possible to write your own implementation of the
-@ref proactor if you want to transparently replace proton's IO layer.
+**Low-level integration**: The @ref connection\_driver provides a low-level SPI
+to feed byte-streams from any source to the @ref engine. You can use it to
+integrate proton directly with a foreign event loop or IO library, or to
+implement your own @ref proactor to transparently replace proton's IO layer.
 
 **Old APIs**: The @ref messenger and @ref reactor APIs are
 older APIs that were limited to single-threaded applications.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/codec.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/codec.h b/proton-c/include/proton/codec.h
index 3f7e5ac..d8995fe 100644
--- a/proton-c/include/proton/codec.h
+++ b/proton-c/include/proton/codec.h
@@ -35,10 +35,10 @@ extern "C" {
 
 /**
  * @file
- *
- * Data API for proton.
+ * AMQP data encoding and decoding
  *
  * @defgroup data Data
+ * AMQP data encoding and decoding
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/condition.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/condition.h b/proton-c/include/proton/condition.h
index ae2beff..0f0774b 100644
--- a/proton-c/include/proton/condition.h
+++ b/proton-c/include/proton/condition.h
@@ -31,12 +31,13 @@
 extern "C" {
 #endif
 
-/** @file
- *
- * The Condition API for the proton Engine.
+/**
+ * @file
+ * Error condition
  *
  * @defgroup condition Condition
- * @ingroup connection
+ * Error condition
+ * @ingroup engine
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/connection.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection.h b/proton-c/include/proton/connection.h
index 5b966cd..19e882f 100644
--- a/proton-c/include/proton/connection.h
+++ b/proton-c/include/proton/connection.h
@@ -38,9 +38,10 @@ extern "C" {
 /**
  * @file
  *
- * Connection API for the proton @ref engine
+ * AMQP protocol connection
  *
  * @defgroup connection Connection
+ * AMQP protocol connection
  * @ingroup engine
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/connection_driver.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection_driver.h b/proton-c/include/proton/connection_driver.h
index 8a5132b..af08160 100644
--- a/proton-c/include/proton/connection_driver.h
+++ b/proton-c/include/proton/connection_driver.h
@@ -22,11 +22,13 @@
 
 /**
  * @file
+ * **Experimental**: Low-level IO integration
  *
  * @defgroup connection_driver Connection Driver
  *
- * **Experimental**: Toolkit for integrating proton with arbitrary network or IO
- * transports via a bytes-in, bytes-out interface.
+ * **Experimental**: Low-level IO integration
+ *
+ * Associate an @ref engine with AMQP byte-streams from any source.
  *
  * - process AMQP-encoded bytes from some input byte stream
  * - generate ::pn_event_t events for your application to handle

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/delivery.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/delivery.h b/proton-c/include/proton/delivery.h
index 2642bd7..4225352 100644
--- a/proton-c/include/proton/delivery.h
+++ b/proton-c/include/proton/delivery.h
@@ -33,10 +33,10 @@ extern "C" {
 
 /**
  * @file
- *
- * Delivery API for the proton Engine.
+ * Track message delivery
  *
  * @defgroup delivery Delivery
+ * Track message delivery
  * @ingroup engine
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/disposition.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/disposition.h b/proton-c/include/proton/disposition.h
index 202f996..530b738 100644
--- a/proton-c/include/proton/disposition.h
+++ b/proton-c/include/proton/disposition.h
@@ -33,10 +33,10 @@ extern "C" {
 
 /**
  * @file
- *
- * Disposition API for the proton Engine.
+ * Outcome of message delivery
  *
  * @defgroup disposition Disposition
+ * Outcome of message delivery
  * @ingroup delivery
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/engine.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/engine.h b/proton-c/include/proton/engine.h
index 8f8719e..b24265e 100644
--- a/proton-c/include/proton/engine.h
+++ b/proton-c/include/proton/engine.h
@@ -22,12 +22,14 @@
  *
  */
 
-/** @file
+/**
+ * @file
  *
- * The proton Engine API. The Engine API provides a complete
- * implementation of AMQP as a Protocol Engine.
+ * The AMQP protocol engine
  *
  * @defgroup engine Engine
+ *
+ * Types and functions that implement the AMQP protocol
  */
 
 #include <proton/condition.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 7793f1c..2280dc8 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -33,10 +33,10 @@ extern "C" {
 
 /**
  * @file
- *
- * Event API for the proton Engine.
+ * AMQP and transport events
  *
  * @defgroup event Event
+ * AMQP and transport events
  * @ingroup engine
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/handlers.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/handlers.h b/proton-c/include/proton/handlers.h
index a8a6f77..bfa68fc 100644
--- a/proton-c/include/proton/handlers.h
+++ b/proton-c/include/proton/handlers.h
@@ -36,6 +36,7 @@ extern "C" {
  * Reactor API for proton.
  *
  * @defgroup handlers Handlers
+ * Reactor API for proton.
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/link.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/link.h b/proton-c/include/proton/link.h
index 1ac2270..3ab811c 100644
--- a/proton-c/include/proton/link.h
+++ b/proton-c/include/proton/link.h
@@ -36,10 +36,10 @@ extern "C" {
 
 /**
  * @file
- *
- * Link API for the proton Engine.
+ * One-way message link
  *
  * @defgroup link Link
+ * One-way message link
  * @ingroup engine
  * @{
  */
@@ -566,6 +566,7 @@ PN_EXTERN pn_delivery_t *pn_unsettled_next(pn_delivery_t *delivery);
 
 /**
  * @defgroup sender Sender
+ * Sending link
  * @{
  */
 
@@ -592,9 +593,9 @@ PN_EXTERN ssize_t pn_link_send(pn_link_t *sender, const char *bytes, size_t n);
 
 /** @} */
 
-// receiver
 /**
  * @defgroup receiver Receiver
+ * Receiving link
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index 4244e69..cd3d95f 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -29,9 +29,11 @@ extern "C" {
 /**
  * @file
  *
- * Listener API for the proton @ref proactor
+ * Listener for the @ref proactor
  *
  * @defgroup listener Listener
+ * Listen for incoming connections with a @ref proactor
+ *
  * @ingroup proactor
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/message.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/message.h b/proton-c/include/proton/message.h
index 837b95e..8741996 100644
--- a/proton-c/include/proton/message.h
+++ b/proton-c/include/proton/message.h
@@ -32,10 +32,12 @@
 extern "C" {
 #endif
 
-/** @file
- * Message API for encoding/decoding AMQP Messages.
+/**
+ * @file
+ * Encode/decode AMQP Messages
  *
  * @defgroup message Message
+ * Encode/decode AMQP Messages
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/messenger.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/messenger.h b/proton-c/include/proton/messenger.h
index 8cba51d..198b6c6 100644
--- a/proton-c/include/proton/messenger.h
+++ b/proton-c/include/proton/messenger.h
@@ -40,6 +40,7 @@ extern "C" {
  * receiving AMQP messages.
  *
  * @defgroup messenger Messenger
+ * **Deprecated**
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index 8a2680b..cd44526 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -33,11 +33,10 @@ typedef struct pn_condition_t pn_condition_t;
 /**
  * @file
  *
- * **Experimental**: Proactor API for the the proton @ref engine
- *
+ * **Experimental**: Multi-threaded IO
  * @defgroup proactor Proactor
  *
- * **Experimental**: Proactor API for portable, multi-threaded, asynchronous applications.
+ * **Experimental**: Multi-threaded IO
  *
  * The proactor associates a @ref connection with a @ref transport, either
  * by making an outgoing connection or accepting an incoming one.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/reactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/reactor.h b/proton-c/include/proton/reactor.h
index bfd6de5..b61ea7a 100644
--- a/proton-c/include/proton/reactor.h
+++ b/proton-c/include/proton/reactor.h
@@ -40,6 +40,7 @@ extern "C" {
  * Reactor API for proton.
  *
  * @defgroup reactor Reactor
+ * Reactor API for proton.
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/sasl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/sasl.h b/proton-c/include/proton/sasl.h
index 354982f..e8e0d96 100644
--- a/proton-c/include/proton/sasl.h
+++ b/proton-c/include/proton/sasl.h
@@ -30,16 +30,18 @@
 extern "C" {
 #endif
 
-/** @file
- * API for the SASL Secure Transport Layer.
+/**
+ * @file
+ * SASL Secure Transport Layer.
  *
+ * @defgroup sasl SASL
+ * SASL Secure Transport Layer.
  * The SASL layer is responsible for establishing an authenticated
  * and/or encrypted tunnel over which AMQP frames are passed between
  * peers. The peer acting as the SASL Client must provide
  * authentication credentials. The peer acting as the SASL Server must
  * provide authentication against the received credentials.
  *
- * @defgroup sasl SASL
  * @ingroup transport
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selectable.h b/proton-c/include/proton/selectable.h
index 5eff58d..c6e7489 100644
--- a/proton-c/include/proton/selectable.h
+++ b/proton-c/include/proton/selectable.h
@@ -38,6 +38,7 @@ extern "C" {
  * party event loops.
  *
  * @defgroup selectable Selectable
+ * **Deprecated**
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/session.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/session.h b/proton-c/include/proton/session.h
index 94d2869..34f0cfd 100644
--- a/proton-c/include/proton/session.h
+++ b/proton-c/include/proton/session.h
@@ -34,10 +34,12 @@
 extern "C" {
 #endif
 
-/** @file
- * Session API for the proton Engine.
+/**
+ *   @file
+ * Serialized session
  *
  * @defgroup session Session
+ * Serialized session
  * @ingroup engine
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/ssl.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/ssl.h b/proton-c/include/proton/ssl.h
index 8fdae08..420459a 100644
--- a/proton-c/include/proton/ssl.h
+++ b/proton-c/include/proton/ssl.h
@@ -30,7 +30,13 @@
 extern "C" {
 #endif
 
-/** @file
+/**
+ * @file
+ * API for using SSL with the Transport Layer.
+ *
+ * @defgroup ssl SSL
+ * @ingroup transport
+ *
  * API for using SSL with the Transport Layer.
  *
  * A Transport may be configured to use SSL for encryption and/or authentication.  A
@@ -68,8 +74,6 @@ extern "C" {
  * Support for SSL Client Session resume is provided (see ::pn_ssl_init,
  * ::pn_ssl_resume_status).
  *
- * @defgroup ssl SSL
- * @ingroup transport
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/terminus.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/terminus.h b/proton-c/include/proton/terminus.h
index b4bf6f8..43d4d98 100644
--- a/proton-c/include/proton/terminus.h
+++ b/proton-c/include/proton/terminus.h
@@ -31,11 +31,12 @@
 extern "C" {
 #endif
 
-/** @file
- *
- * Terminus API for the proton Engine.
+/**
+ * @file
+ * Message terminus (source or target)
  *
  * @defgroup terminus Terminus
+ * Message terminus (source or target)
  * @ingroup link
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/transport.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/transport.h b/proton-c/include/proton/transport.h
index 5c8494c..9683a42 100644
--- a/proton-c/include/proton/transport.h
+++ b/proton-c/include/proton/transport.h
@@ -33,10 +33,12 @@ extern "C" {
 
 /**
  * @file
- *
- * Transport API for the proton Engine.
+ * Network transport
  *
  * @defgroup transport Transport
+ * Network transport
+ *
+ * State of a network connection being used as a transport for an AMQP connection.
  * @ingroup engine
  * @{
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index 378719c..190f089 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -29,8 +29,10 @@
 
 /**
  * @file
+ * AMQP type system
  *
  * @defgroup types Types
+ * AMQP type system
  * @{
  */
 
@@ -40,6 +42,7 @@ extern "C" {
 
 /**
  * @defgroup primitives Primitive Types
+ * Primitive types
  * @{
  */
 
@@ -83,6 +86,7 @@ static const pn_bytes_t pn_rwbytes_null = { 0, NULL };
 
 /**
  * @defgroup abstract Abstract Types
+ * Abstract types
  * @{
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f45cdced/proton-c/include/proton/url.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/url.h b/proton-c/include/proton/url.h
index 2a68bc2..4ff9536 100644
--- a/proton-c/include/proton/url.h
+++ b/proton-c/include/proton/url.h
@@ -26,11 +26,13 @@ extern "C" {
 #endif
 
 
-/** @file
- * URL API for parsing URLs.
+/**
+ * @file
+ * Parsing URLs.
  *
  * @defgroup url URL
- * @{
+ * Parsing URLs.
+! * @{
  */
 
 /** A parsed URL */


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


[16/48] 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 ac...@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


[47/48] qpid-proton git commit: PROTON-1356: go: restore compatibility from proton 0.10

Posted by ac...@apache.org.
PROTON-1356: go: restore compatibility from proton 0.10

Remove use of PN_INVALID (not available in proton 0.10)
Link with libqpid-proton not libqpid-proton-core (not available until 0.16)


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

Branch: refs/heads/go1
Commit: a34c93bfbeafb242dee4ecd31ef698aa1e3b2e7b
Parents: 2bcfd36
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Nov 25 15:51:52 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Nov 25 15:51:52 2016 -0500

----------------------------------------------------------------------
 proton-c/bindings/go/src/qpid.apache.org/amqp/doc.go      |  2 +-
 proton-c/bindings/go/src/qpid.apache.org/amqp/types.go    |  4 +---
 .../bindings/go/src/qpid.apache.org/amqp/unmarshal.go     | 10 +++-------
 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 +-
 6 files changed, 8 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a34c93bf/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 d270704..97051a5 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-core
+// #cgo LDFLAGS: -lqpid-proton
 import "C"
 
 // This file is just for the package comment.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a34c93bf/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
index bc0859a..2852c23 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/types.go
@@ -82,10 +82,8 @@ func (t C.pn_type_t) String() string {
 		return "list"
 	case C.PN_MAP:
 		return "map"
-	case C.PN_INVALID:
-		return "no-data"
 	default:
-		return fmt.Sprintf("unknown-type(%d)", t)
+		return "no-data"
 	}
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a34c93bf/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
index 95d4343..8f380a7 100644
--- a/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
+++ b/proton-c/bindings/go/src/qpid.apache.org/amqp/unmarshal.go
@@ -451,8 +451,6 @@ func rewindUnmarshal(v interface{}, data *C.pn_data_t) {
 func getInterface(data *C.pn_data_t, v *interface{}) {
 	pnType := C.pn_data_type(data)
 	switch pnType {
-	case C.PN_NULL, C.PN_INVALID: // No data.
-		*v = nil
 	case C.PN_BOOL:
 		*v = bool(C.pn_data_get_bool(data))
 	case C.PN_UBYTE:
@@ -491,8 +489,8 @@ func getInterface(data *C.pn_data_t, v *interface{}) {
 		l := make(List, 0)
 		unmarshal(&l, data)
 		*v = l
-	default:
-		panic(newUnmarshalError(pnType, v))
+	default: // No data (-1 or NULL)
+		*v = nil
 	}
 }
 
@@ -517,9 +515,7 @@ func getMap(data *C.pn_data_t, v interface{}) {
 				}
 			}
 		}
-	case C.PN_INVALID: // Leave the map empty
-	default:
-		panic(newUnmarshalError(pnType, v))
+	default: // Empty/error/unknown, leave map empty
 	}
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a34c93bf/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 79a566e..bc2c589 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-core
+//#cgo LDFLAGS: -lqpid-proton
 import "C"
 
 // Just for package comment

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a34c93bf/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 27bc5ec..083f701 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-core
+// #cgo LDFLAGS: -lqpid-proton
 import "C"
 
 // This file is just for the package comment.

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


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


[24/48] qpid-proton git commit: PROTON-1352, PROTON-1353: Added message annotations to the String visualization of AMQP message Refactored ReceiverSettleMode and SenderSettleMode for having trivial casting from/to UnsignedByte and added unit tests

Posted by ac...@apache.org.
PROTON-1352,PROTON-1353: Added message annotations to the String visualization of AMQP message
Refactored ReceiverSettleMode and SenderSettleMode for having trivial casting from/to UnsignedByte and added unit tests


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

Branch: refs/heads/go1
Commit: fec0bc8c82ad6eb705757fd2df87cef67c28f930
Parents: eac0bb6
Author: ppatierno <pp...@live.com>
Authored: Wed Nov 16 11:03:35 2016 +0100
Committer: ppatierno <pp...@live.com>
Committed: Wed Nov 16 18:42:35 2016 +0100

----------------------------------------------------------------------
 .../amqp/transport/ReceiverSettleMode.java      | 25 ++++++--
 .../proton/amqp/transport/SenderSettleMode.java | 29 +++++++--
 .../qpid/proton/message/impl/MessageImpl.java   |  4 ++
 .../amqp/transport/ReceiverSettleModeTest.java  | 61 ++++++++++++++++++
 .../amqp/transport/SenderSettleModeTest.java    | 67 ++++++++++++++++++++
 5 files changed, 178 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/fec0bc8c/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleMode.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleMode.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleMode.java
index 1062e39..c2621e6 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleMode.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleMode.java
@@ -27,11 +27,28 @@ import org.apache.qpid.proton.amqp.UnsignedByte;
 
 public enum ReceiverSettleMode
 {
-    FIRST, SECOND;
+    FIRST(0),
+    SECOND(1);
 
-    public UnsignedByte getValue()
-    {
-        return UnsignedByte.valueOf((byte)ordinal());
+    private UnsignedByte value;
+
+    private ReceiverSettleMode(int value) {
+        this.value = UnsignedByte.valueOf((byte)value);
     }
 
+    public static ReceiverSettleMode valueOf(UnsignedByte value) {
+
+        switch (value.intValue()) {
+            case 0:
+                return ReceiverSettleMode.FIRST;
+            case 1:
+                return ReceiverSettleMode.SECOND;
+            default:
+                throw new IllegalArgumentException("The value can be only 0 (for FIRST) and 1 (for SECOND)");
+        }
+    }
+
+    public UnsignedByte getValue() {
+        return this.value;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/fec0bc8c/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/SenderSettleMode.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/SenderSettleMode.java b/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/SenderSettleMode.java
index e3ed0b2..6dae3f4 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/SenderSettleMode.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/amqp/transport/SenderSettleMode.java
@@ -27,11 +27,32 @@ import org.apache.qpid.proton.amqp.UnsignedByte;
 
 public enum SenderSettleMode
 {
-    UNSETTLED, SETTLED, MIXED;
+    UNSETTLED(0),
+    SETTLED(1),
+    MIXED(2);
 
-    public UnsignedByte getValue()
-    {
-        return UnsignedByte.valueOf((byte)ordinal());
+    private UnsignedByte value;
+
+    private SenderSettleMode(int value) {
+        this.value = UnsignedByte.valueOf((byte)value);
+    }
+
+    public static SenderSettleMode valueOf(UnsignedByte value) {
+
+        switch (value.intValue()) {
+
+            case 0:
+                return SenderSettleMode.UNSETTLED;
+            case 1:
+                return SenderSettleMode.SETTLED;
+            case 2:
+                return SenderSettleMode.MIXED;
+            default:
+                throw new IllegalArgumentException("The value can be only 0 (for UNSETTLED), 1 (for SETTLED) and 2 (for MIXED)");
+        }
     }
 
+    public UnsignedByte getValue() {
+        return this.value;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/fec0bc8c/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
index b0204f3..df6373f 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
@@ -769,6 +769,10 @@ public class MessageImpl implements ProtonJMessage
             sb.append("properties=");
             sb.append(_properties);
         }
+        if (_messageAnnotations != null) {
+            sb.append("message_annotations=");
+            sb.append(_messageAnnotations);
+        }
         if (_body != null) {
             sb.append("body=");
             sb.append(_body);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/fec0bc8c/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleModeTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleModeTest.java b/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleModeTest.java
new file mode 100644
index 0000000..eb8472b
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/ReceiverSettleModeTest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.amqp.transport;
+
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class ReceiverSettleModeTest {
+
+    @Test
+    public void testEquality() {
+
+        ReceiverSettleMode first = ReceiverSettleMode.FIRST;
+        ReceiverSettleMode second = ReceiverSettleMode.SECOND;
+
+        assertEquals(first, ReceiverSettleMode.valueOf(UnsignedByte.valueOf((byte)0)));
+        assertEquals(second, ReceiverSettleMode.valueOf(UnsignedByte.valueOf((byte)1)));
+
+        assertEquals(first.getValue(), UnsignedByte.valueOf((byte)0));
+        assertEquals(second.getValue(), UnsignedByte.valueOf((byte)1));
+    }
+
+    @Test
+    public void testNotEquality() {
+
+        ReceiverSettleMode first = ReceiverSettleMode.FIRST;
+        ReceiverSettleMode second = ReceiverSettleMode.SECOND;
+
+        assertNotEquals(first, ReceiverSettleMode.valueOf(UnsignedByte.valueOf((byte)1)));
+        assertNotEquals(second, ReceiverSettleMode.valueOf(UnsignedByte.valueOf((byte)0)));
+
+        assertNotEquals(first.getValue(), UnsignedByte.valueOf((byte)1));
+        assertNotEquals(second.getValue(), UnsignedByte.valueOf((byte)0));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalArgument() {
+
+        ReceiverSettleMode.valueOf(UnsignedByte.valueOf((byte)2));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/fec0bc8c/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/SenderSettleModeTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/SenderSettleModeTest.java b/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/SenderSettleModeTest.java
new file mode 100644
index 0000000..1ef5da1
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/amqp/transport/SenderSettleModeTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.proton.amqp.transport;
+
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class SenderSettleModeTest {
+
+    @Test
+    public void testEquality() {
+
+        SenderSettleMode unsettled = SenderSettleMode.UNSETTLED;
+        SenderSettleMode settled = SenderSettleMode.SETTLED;
+        SenderSettleMode mixed = SenderSettleMode.MIXED;
+
+        assertEquals(unsettled, SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)0)));
+        assertEquals(settled, SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)1)));
+        assertEquals(mixed, SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)2)));
+
+        assertEquals(unsettled.getValue(), UnsignedByte.valueOf((byte)0));
+        assertEquals(settled.getValue(), UnsignedByte.valueOf((byte)1));
+        assertEquals(mixed.getValue(), UnsignedByte.valueOf((byte)2));
+    }
+
+    @Test
+    public void testNotEquality() {
+
+        SenderSettleMode unsettled = SenderSettleMode.UNSETTLED;
+        SenderSettleMode settled = SenderSettleMode.SETTLED;
+        SenderSettleMode mixed = SenderSettleMode.MIXED;
+
+        assertNotEquals(unsettled, SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)2)));
+        assertNotEquals(settled, SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)0)));
+        assertNotEquals(mixed, SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)1)));
+
+        assertNotEquals(unsettled.getValue(), UnsignedByte.valueOf((byte)2));
+        assertNotEquals(settled.getValue(), UnsignedByte.valueOf((byte)0));
+        assertNotEquals(mixed.getValue(), UnsignedByte.valueOf((byte)1));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalArgument() {
+
+        SenderSettleMode.valueOf(UnsignedByte.valueOf((byte)3));
+    }
+}


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


[13/48] 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 ac...@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


[17/48] 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 ac...@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


[31/48] qpid-proton git commit: PROTON-1344: C proactor for multi-threaded proton applications

Posted by ac...@apache.org.
PROTON-1344: C proactor for multi-threaded proton applications

proactor.h is an asynchronous, multi-threaded replacement for reactor.h

It uses the same Proton engine APIs and events, but allows multiple application
threads wait for events to handle, rather than calling back on handler functions
from a single thread.

The proactor ensures that events for the same AMQP connection are handled in
sequence (although possibly by different threads at different times) so event
handling code does not need to lock the use of thread-unsafe proton APIs. It
provides a "wake" feature to signal connections for processing triggered by the
application rather than proton IO.

Examples show C sender, receiver and broker, and a libuv driver implementation.


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

Branch: refs/heads/go1
Commit: ca454180b2846b2538a60ad03a047aa6a738d3ca
Parents: cdc1baa
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 2 15:38:49 2016 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 16 19:52:38 2016 -0500

----------------------------------------------------------------------
 config.sh.in                                    |   2 +-
 examples/CMakeLists.txt                         |  13 +
 examples/c/CMakeLists.txt                       |   5 +
 examples/c/proactor/CMakeLists.txt              |  43 ++
 examples/c/proactor/README.dox                  |  20 +
 examples/c/proactor/broker.c                    | 476 ++++++++++++
 examples/c/proactor/libuv_proactor.c            | 747 +++++++++++++++++++
 examples/c/proactor/receive.c                   | 202 +++++
 examples/c/proactor/send.c                      | 204 +++++
 examples/c/proactor/test.py                     |  52 ++
 examples/engine/c/precv.c                       | 502 -------------
 examples/engine/c/psend.c                       | 373 ---------
 examples/exampletest.py                         | 183 +++++
 .../cpp/include/proton/io/connection_engine.hpp |   7 +-
 .../cpp/include/proton/sender_options.hpp       |   4 +-
 .../bindings/cpp/src/io/connection_engine.cpp   |  78 +-
 proton-c/bindings/cpp/src/sender_options.cpp    |   4 +-
 proton-c/docs/api/index.md                      |  38 +-
 proton-c/include/proton/cid.h                   |   5 +-
 proton-c/include/proton/condition.h             |   4 +
 proton-c/include/proton/connection.h            |  18 +
 proton-c/include/proton/connection_engine.h     | 417 +++++++----
 proton-c/include/proton/event.h                 |  48 +-
 proton-c/include/proton/extra.h                 |  69 ++
 proton-c/include/proton/listener.h              |  76 ++
 proton-c/include/proton/object.h                |  27 +
 proton-c/include/proton/proactor.h              | 174 +++++
 proton-c/include/proton/types.h                 |   2 +
 proton-c/src/core/connection_driver.c           | 163 ++++
 proton-c/src/core/connection_engine.c           | 177 +++--
 proton-c/src/core/engine.c                      |  45 +-
 proton-c/src/core/event.c                       |  13 +-
 proton-c/src/core/object/object.c               |  10 +-
 tools/cmake/Modules/FindLibuv.cmake             |  37 +
 34 files changed, 3092 insertions(+), 1146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/config.sh.in
----------------------------------------------------------------------
diff --git a/config.sh.in b/config.sh.in
index 4902b61..edb77e6 100755
--- a/config.sh.in
+++ b/config.sh.in
@@ -40,7 +40,7 @@ RUBY_BINDINGS=$PROTON_BINDINGS/ruby
 PERL_BINDINGS=$PROTON_BINDINGS/perl
 
 # Python & Jython
-COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/proton-c/bindings/python
+COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/proton-c/bindings/python:$PROTON_HOME/examples
 export PYTHONPATH=$COMMON_PYPATH:$PYTHON_BINDINGS
 export JYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-j/src/main/resources:$PROTON_JARS
 export CLASSPATH=$PROTON_JARS

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 99e8315..4d744d2 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -20,6 +20,19 @@
 set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set (ProtonCpp_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
+# Set result to a native search path
+macro(set_search_path result)  # args after result are directories or search paths.
+  set(${result} ${ARGN})
+  if (UNIX)
+    string(REPLACE ";" ":" ${result} "${${result}}") # native search path separators.
+  endif()
+  file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
+endmacro()
+
+# Some non-python examples use exampletest.py to drive their self-tests.
+set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_CURRENT_SOURCE_DIR}" "$ENV{PYTHON_PATH}")
+set(EXAMPLE_ENV "PYTHONPATH=${EXAMPLE_PYTHONPATH}")
+
 add_subdirectory(c)
 add_subdirectory(go)
 if (BUILD_CPP)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index 1612a86..0d0c7e9 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -17,6 +17,11 @@
 # under the License.
 #
 
+find_package(Proton REQUIRED)
+include(CheckCCompilerFlag)
+
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+add_subdirectory(proactor)
 add_subdirectory(messenger)
 add_subdirectory(reactor)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/c/proactor/CMakeLists.txt b/examples/c/proactor/CMakeLists.txt
new file mode 100644
index 0000000..f701651
--- /dev/null
+++ b/examples/c/proactor/CMakeLists.txt
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+find_package(Proton REQUIRED)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${Proton_INCLUDE_DIRS})
+
+add_definitions(${COMPILE_WARNING_FLAGS} ${WERROR} ${COMPILE_PLATFORM_FLAGS} ${LINK_TIME_OPTIMIZATION})
+
+find_package(Libuv)
+if (Libuv_FOUND)
+  foreach(name broker send receive)
+    add_executable(libuv_${name} ${name}.c libuv_proactor.c)
+    target_link_libraries(libuv_${name} ${Proton_LIBRARIES} ${Libuv_LIBRARIES})
+    set_target_properties(libuv_${name} PROPERTIES
+      COMPILE_DEFINITIONS  "PN_PROACTOR_INCLUDE=\"libuv_proactor.h\"")
+  endforeach()
+
+  # Add a test with the correct environment to find test executables and valgrind.
+  if(WIN32)
+    set(test_path "$<TARGET_FILE_DIR:libuv_broker>;$<TARGET_FILE_DIR:qpid-proton>")
+  else(WIN32)
+    set(test_path "${CMAKE_CURRENT_BINARY_DIR}:$ENV{PATH}")
+  endif(WIN32)
+  set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV})
+  add_test(c-proactor-libuv ${run_env} -- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py)
+endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/README.dox
----------------------------------------------------------------------
diff --git a/examples/c/proactor/README.dox b/examples/c/proactor/README.dox
new file mode 100644
index 0000000..89f7aaa
--- /dev/null
+++ b/examples/c/proactor/README.dox
@@ -0,0 +1,20 @@
+
+/** @example send.c
+
+Send a fixed number of messages to the "example" node.
+
+*/
+
+/** @example simple_recv.cpp
+
+Subscribes to the 'example' node and prints the message bodies received.
+
+*/
+
+/** @example broker.c
+
+A simple multi-threaded broker that works with the send and receive examples.
+
+__Requires C++11__
+
+*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
new file mode 100644
index 0000000..79f34bc
--- /dev/null
+++ b/examples/c/proactor/broker.c
@@ -0,0 +1,476 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/connection_engine.h>
+#include <proton/proactor.h>
+#include <proton/engine.h>
+#include <proton/sasl.h>
+#include <proton/transport.h>
+#include <proton/url.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* TODO aconway 2016-10-14: this example does not require libuv IO,
+   it uses uv.h only for portable mutex and thread functions.
+*/
+#include <uv.h>
+
+bool enable_debug = false;
+
+void debug(const char* fmt, ...) {
+  if (enable_debug) {
+    va_list(ap);
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    fputc('\n', stderr);
+    fflush(stderr);
+  }
+}
+
+void check(int err, const char* s) {
+  if (err != 0) {
+    perror(s);
+    exit(1);
+  }
+}
+
+void pcheck(int err, const char* s) {
+  if (err != 0) {
+    fprintf(stderr, "%s: %s", s, pn_code(err));
+    exit(1);
+  }
+}
+
+/* Simple re-sizable vector that acts as a queue */
+#define VEC(T) struct { T* data; size_t len, cap; }
+
+#define VEC_INIT(V)                             \
+  do {                                          \
+    V.len = 0;                                  \
+    V.cap = 16;                                 \
+    void **vp = (void**)&V.data;                \
+    *vp = malloc(V.cap * sizeof(*V.data));      \
+  } while(0)
+
+#define VEC_FINAL(V) free(V.data)
+
+#define VEC_PUSH(V, X)                                  \
+  do {                                                  \
+    if (V.len == V.cap) {                               \
+      V.cap *= 2;                                       \
+      void **vp = (void**)&V.data;                      \
+      *vp = realloc(V.data, V.cap * sizeof(*V.data));   \
+    }                                                   \
+    V.data[V.len++] = X;                                \
+  } while(0)                                            \
+
+#define VEC_POP(V)                                              \
+  do {                                                          \
+    if (V.len > 0)                                              \
+      memmove(V.data, V.data+1, (--V.len)*sizeof(*V.data));     \
+  } while(0)
+
+/* Simple thread-safe queue implementation */
+typedef struct queue_t {
+  uv_mutex_t lock;
+  char* name;
+  VEC(pn_rwbytes_t) messages;   /* Messages on the queue_t */
+  VEC(pn_connection_t*) waiting; /* Connections waiting to send messages from this queue */
+  struct queue_t *next;            /* Next queue in chain */
+  size_t sent;                     /* Count of messages sent, used as delivery tag */
+} queue_t;
+
+static void queue_init(queue_t *q, const char* name, queue_t *next) {
+  debug("created queue %s", name);
+  uv_mutex_init(&q->lock);
+  q->name = strdup(name);
+  VEC_INIT(q->messages);
+  VEC_INIT(q->waiting);
+  q->next = next;
+  q->sent = 0;
+}
+
+static void queue_destroy(queue_t *q) {
+  uv_mutex_destroy(&q->lock);
+  free(q->name);
+  for (size_t i = 0; i < q->messages.len; ++i)
+    free(q->messages.data[i].start);
+  VEC_FINAL(q->messages);
+  for (size_t i = 0; i < q->waiting.len; ++i)
+    pn_decref(q->waiting.data[i]);
+  VEC_FINAL(q->waiting);
+}
+
+/* Send a message on s, or record s as eating if no messages.
+   Called in s dispatch loop, assumes s has credit.
+*/
+static void queue_send(queue_t *q, pn_link_t *s) {
+  pn_rwbytes_t m = { 0 };
+  size_t tag = 0;
+  uv_mutex_lock(&q->lock);
+  if (q->messages.len == 0) { /* Empty, record connection as waiting */
+    debug("queue is empty %s", q->name);
+    /* Record connection for wake-up if not already on the list. */
+    pn_connection_t *c = pn_session_connection(pn_link_session(s));
+    size_t i = 0;
+    for (; i < q->waiting.len && q->waiting.data[i] != c; ++i)
+      ;
+    if (i == q->waiting.len) {
+      VEC_PUSH(q->waiting, c);
+    }
+  } else {
+    debug("sending from queue %s", q->name);
+    m = q->messages.data[0];
+    VEC_POP(q->messages);
+    tag = ++q->sent;
+  }
+  uv_mutex_unlock(&q->lock);
+  if (m.start) {
+    pn_delivery_t *d = pn_delivery(s, pn_dtag((char*)&tag, sizeof(tag)));
+    pn_link_send(s, m.start, m.size);
+    pn_link_advance(s);
+    pn_delivery_settle(d);  /* Pre-settled: unreliable, there will bea no ack/ */
+    free(m.start);
+  }
+}
+
+/* Data associated with each broker connection */
+typedef struct broker_data_t {
+  bool check_queues;          /* Check senders on the connection for available data in queues. */
+} broker_data_t;
+
+/* Put a message on the queue, called in receiver dispatch loop.
+   If the queue was previously empty, notify waiting senders.
+*/
+static void queue_receive(pn_proactor_t *d, queue_t *q, pn_rwbytes_t m) {
+  debug("received to queue %s", q->name);
+  uv_mutex_lock(&q->lock);
+  VEC_PUSH(q->messages, m);
+  if (q->messages.len == 1) { /* Was empty, notify waiting connections */
+    for (size_t i = 0; i < q->waiting.len; ++i) {
+      pn_connection_t *c = q->waiting.data[i];
+      broker_data_t *bd = (broker_data_t*)pn_connection_get_extra(c).start;
+      bd->check_queues = true;
+      pn_connection_wake(c); /* Wake the connection */
+    }
+    q->waiting.len = 0;
+  }
+  uv_mutex_unlock(&q->lock);
+}
+
+/* Thread safe set of queues */
+typedef struct queues_t {
+  uv_mutex_t lock;
+  queue_t *queues;
+  size_t sent;
+} queues_t;
+
+void queues_init(queues_t *qs) {
+  uv_mutex_init(&qs->lock);
+  qs->queues = NULL;
+}
+
+void queues_destroy(queues_t *qs) {
+  for (queue_t *q = qs->queues; q; q = q->next) {
+    queue_destroy(q);
+    free(q);
+  }
+  uv_mutex_destroy(&qs->lock);
+}
+
+/** Get or create the named queue. */
+queue_t* queues_get(queues_t *qs, const char* name) {
+  uv_mutex_lock(&qs->lock);
+  queue_t *q;
+  for (q = qs->queues; q && strcmp(q->name, name) != 0; q = q->next)
+    ;
+  if (!q) {
+    q = (queue_t*)malloc(sizeof(queue_t));
+    queue_init(q, name, qs->queues);
+    qs->queues = q;
+  }
+  uv_mutex_unlock(&qs->lock);
+  return q;
+}
+
+/* The broker implementation */
+typedef struct broker_t {
+  pn_proactor_t *proactor;
+  pn_listener_t *listener;
+  queues_t queues;
+  const char *container_id;     /* AMQP container-id */
+  size_t threads;
+  pn_millis_t heartbeat;
+} broker_t;
+
+void broker_init(broker_t *b, const char *container_id, size_t threads, pn_millis_t heartbeat) {
+  b->proactor = pn_proactor();
+  b->listener = NULL;
+  queues_init(&b->queues);
+  b->container_id = container_id;
+  b->threads = threads;
+  b->heartbeat = 0;
+}
+
+void broker_stop(broker_t *b) {
+  /* In this broker an interrupt stops a thread, stopping all threads stops the broker */
+  for (size_t i = 0; i < b->threads; ++i)
+    pn_proactor_interrupt(b->proactor);
+}
+
+/* Try to send if link is sender and has credit */
+static void link_send(broker_t *b, pn_link_t *s) {
+  if (pn_link_is_sender(s) && pn_link_credit(s) > 0) {
+    const char *qname = pn_terminus_get_address(pn_link_source(s));
+    queue_t *q = queues_get(&b->queues, qname);
+    queue_send(q, s);
+  }
+}
+
+static void queue_unsub(queue_t *q, pn_connection_t *c) {
+  uv_mutex_lock(&q->lock);
+  for (size_t i = 0; i < q->waiting.len; ++i) {
+    if (q->waiting.data[i] == c){
+      q->waiting.data[i] = q->waiting.data[0]; /* save old [0] */
+      VEC_POP(q->waiting);
+      break;
+    }
+  }
+  uv_mutex_unlock(&q->lock);
+}
+
+/* Unsubscribe from the queue of interest to this link. */
+static void link_unsub(broker_t *b, pn_link_t *s) {
+  if (pn_link_is_sender(s)) {
+    const char *qname = pn_terminus_get_address(pn_link_source(s));
+    if (qname) {
+      queue_t *q = queues_get(&b->queues, qname);
+      queue_unsub(q, pn_session_connection(pn_link_session(s)));
+    }
+  }
+}
+
+/* Called in connection's event loop when a connection is woken for messages.*/
+static void connection_unsub(broker_t *b, pn_connection_t *c) {
+  for (pn_link_t *l = pn_link_head(c, 0); l != NULL; l = pn_link_next(l, 0))
+    link_unsub(b, l);
+}
+
+static void session_unsub(broker_t *b, pn_session_t *ssn) {
+  pn_connection_t *c = pn_session_connection(ssn);
+  for (pn_link_t *l = pn_link_head(c, 0); l != NULL; l = pn_link_next(l, 0)) {
+    if (pn_link_session(l) == ssn)
+      link_unsub(b, l);
+  }
+}
+
+static void check_condition(pn_event_t *e, pn_condition_t *cond) {
+  if (pn_condition_is_set(cond)) {
+    const char *ename = e ? pn_event_type_name(pn_event_type(e)) : "UNKNOWN";
+    fprintf(stderr, "%s: %s: %s\n", ename,
+            pn_condition_get_name(cond), pn_condition_get_description(cond));
+  }
+}
+
+const int WINDOW=10;            /* Incoming credit window */
+
+static bool handle(broker_t* b, pn_event_t* e) {
+  bool more = true;
+  pn_connection_t *c = pn_event_connection(e);
+
+  switch (pn_event_type(e)) {
+
+   case PN_CONNECTION_INIT: {
+     pn_connection_set_container(c, b->container_id);
+     break;
+   }
+   case PN_CONNECTION_BOUND: {
+     /* Turn off security */
+     pn_transport_t *t = pn_connection_transport(c);
+     pn_transport_require_auth(t, false);
+     pn_sasl_allowed_mechs(pn_sasl(t), "ANONYMOUS");
+     pn_transport_set_idle_timeout(t, 2 * b->heartbeat);
+   }
+   case PN_CONNECTION_REMOTE_OPEN: {
+     pn_connection_open(pn_event_connection(e)); /* Complete the open */
+     break;
+   }
+   case PN_CONNECTION_WAKE: {
+     broker_data_t *bd = (broker_data_t*)pn_connection_get_extra(c).start;
+     if (bd->check_queues) {
+       bd->check_queues = false;
+       int flags = PN_LOCAL_ACTIVE&PN_REMOTE_ACTIVE;
+       for (pn_link_t *l = pn_link_head(c, flags); l != NULL; l = pn_link_next(l, flags))
+         link_send(b, l);
+     }
+     break;
+   }
+   case PN_SESSION_REMOTE_OPEN: {
+     pn_session_open(pn_event_session(e));
+     break;
+   }
+   case PN_LINK_REMOTE_OPEN: {
+     pn_link_t *l = pn_event_link(e);
+     if (pn_link_is_sender(l)) {
+       const char *source = pn_terminus_get_address(pn_link_remote_source(l));
+       pn_terminus_set_address(pn_link_source(l), source);
+     } else {
+       const char* target = pn_terminus_get_address(pn_link_remote_target(l));
+       pn_terminus_set_address(pn_link_target(l), target);
+       pn_link_flow(l, WINDOW);
+     }
+     pn_link_open(l);
+     break;
+   }
+   case PN_LINK_FLOW: {
+     link_send(b, pn_event_link(e));
+     break;
+   }
+   case PN_DELIVERY: {
+     pn_delivery_t *d = pn_event_delivery(e);
+     pn_link_t *r = pn_delivery_link(d);
+     if (pn_link_is_receiver(r) &&
+         pn_delivery_readable(d) && !pn_delivery_partial(d))
+     {
+       size_t size = pn_delivery_pending(d);
+       /* The broker does not decode the message, just forwards it. */
+       pn_rwbytes_t m = { size, (char*)malloc(size) };
+       pn_link_recv(r, m.start, m.size);
+       const char *qname = pn_terminus_get_address(pn_link_target(r));
+       queue_receive(b->proactor, queues_get(&b->queues, qname), m);
+       pn_delivery_update(d, PN_ACCEPTED);
+       pn_delivery_settle(d);
+       pn_link_flow(r, WINDOW - pn_link_credit(r));
+     }
+     break;
+   }
+
+   case PN_TRANSPORT_CLOSED:
+    connection_unsub(b, pn_event_connection(e));
+    check_condition(e, pn_transport_condition(pn_event_transport(e)));
+    break;
+
+   case PN_CONNECTION_REMOTE_CLOSE:
+    check_condition(e, pn_connection_remote_condition(pn_event_connection(e)));
+    connection_unsub(b, pn_event_connection(e));
+    pn_connection_close(pn_event_connection(e));
+    break;
+
+   case PN_SESSION_REMOTE_CLOSE:
+    check_condition(e, pn_session_remote_condition(pn_event_session(e)));
+    session_unsub(b, pn_event_session(e));
+    pn_session_close(pn_event_session(e));
+    pn_session_free(pn_event_session(e));
+    break;
+
+   case PN_LINK_REMOTE_CLOSE:
+    check_condition(e, pn_link_remote_condition(pn_event_link(e)));
+    link_unsub(b, pn_event_link(e));
+    pn_link_close(pn_event_link(e));
+    pn_link_free(pn_event_link(e));
+    break;
+
+   case PN_LISTENER_CLOSE:
+    check_condition(e, pn_listener_condition(pn_event_listener(e)));
+    break;
+
+   case PN_PROACTOR_INACTIVE: /* listener and all connections closed */
+    broker_stop(b);
+    break;
+
+   case PN_PROACTOR_INTERRUPT:
+    more = false;
+    break;
+
+   default:
+    break;
+  }
+  pn_event_done(e);
+  return more;
+}
+
+static void broker_thread(void *void_broker) {
+  broker_t *b = (broker_t*)void_broker;
+  while (handle(b, pn_proactor_wait(b->proactor)))
+    ;
+}
+
+static void usage(const char *arg0) {
+  fprintf(stderr, "Usage: %s [-d] [-a url] [-t thread-count]\n", arg0);
+  exit(1);
+}
+
+int main(int argc, char **argv) {
+  /* Command line options */
+  char *urlstr = NULL;
+  char container_id[256];
+  /* Default container-id is program:pid */
+  snprintf(container_id, sizeof(container_id), "%s:%d", argv[0], getpid());
+  size_t nthreads = 4;
+  pn_millis_t heartbeat = 0;
+  int opt;
+  while ((opt = getopt(argc, argv, "a:t:dh:c:")) != -1) {
+    switch (opt) {
+     case 'a': urlstr = optarg; break;
+     case 't': nthreads = atoi(optarg); break;
+     case 'd': enable_debug = true; break;
+     case 'h': heartbeat = atoi(optarg); break;
+     case 'c': strncpy(container_id, optarg, sizeof(container_id)); break;
+     default: usage(argv[0]); break;
+    }
+  }
+  if (optind < argc)
+    usage(argv[0]);
+
+  broker_t b;
+  broker_init(&b, container_id, nthreads, heartbeat);
+
+  /* Parse the URL or use default values */
+  pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
+  const char *host = url ? pn_url_get_host(url) : "localhost";
+  const char *port = url ? pn_url_get_port(url) : NULL;
+  if (!port) port = "amqp";
+
+  /* Initial broker_data value copied to each accepted connection */
+  broker_data_t bd = { false };
+  b.listener = pn_proactor_listen(b.proactor, host, port, 16,
+                                  pn_bytes(sizeof(bd), (char*)&bd));
+  printf("listening on '%s:%s' %zd threads\n", host, port, b.threads);
+
+  if (url) pn_url_free(url);
+  if (b.threads <= 0) {
+    fprintf(stderr, "invalid value -t %zu, threads must be > 0\n", b.threads);
+    exit(1);
+  }
+  /* Start n-1 threads and use main thread */
+  uv_thread_t* threads = (uv_thread_t*)calloc(sizeof(uv_thread_t), b.threads);
+  for (size_t i = 0; i < b.threads-1; ++i) {
+    check(uv_thread_create(&threads[i], broker_thread, &b), "pthread_create");
+  }
+  broker_thread(&b);            /* Use the main thread too. */
+  for (size_t i = 0; i < b.threads-1; ++i) {
+    check(uv_thread_join(&threads[i]), "pthread_join");
+  }
+  pn_proactor_free(b.proactor);
+  free(threads);
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
new file mode 100644
index 0000000..ce5b948
--- /dev/null
+++ b/examples/c/proactor/libuv_proactor.c
@@ -0,0 +1,747 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <uv.h>
+
+#include <proton/condition.h>
+#include <proton/connection_engine.h>
+#include <proton/engine.h>
+#include <proton/extra.h>
+#include <proton/message.h>
+#include <proton/object.h>
+#include <proton/proactor.h>
+#include <proton/transport.h>
+#include <proton/url.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+  libuv loop functions are thread unsafe. The only exception is uv_async_send()
+  which is a thread safe "wakeup" that can wake the uv_loop from another thread.
+
+  To provide concurrency the proactor uses a "leader-worker-follower" model,
+  threads take turns at the roles:
+
+  - a single "leader" calls libuv functions and runs the uv_loop incrementally.
+  When there is work it hands over leadership and becomes a "worker"
+  - "workers" handle events concurrently for distinct connections/listeners
+  When the work is done they become "followers"
+  - "followers" wait for the leader to step aside, one takes over as new leader.
+
+  This model is symmetric: any thread can take on any role based on run-time
+  requirements. It also allows the IO and non-IO work associated with an IO
+  wake-up to be processed in a single thread with no context switches.
+
+  Function naming:
+  - on_ - called in leader thread via uv_run().
+  - leader_ - called in leader thread, while processing the leader_q.
+  - owner_ - called in owning thread, leader or worker but not concurrently.
+
+  Note on_ and leader_ functions can call each other, the prefix indicates the
+  path they are most often called on.
+*/
+
+const char *COND_NAME = "proactor";
+const char *AMQP_PORT = "5672";
+const char *AMQP_PORT_NAME = "amqp";
+const char *AMQPS_PORT = "5671";
+const char *AMQPS_PORT_NAME = "amqps";
+
+PN_HANDLE(PN_PROACTOR)
+
+/* pn_proactor_t and pn_listener_t are plain C structs with normal memory management.
+   Class definitions are for identification as pn_event_t context only.
+*/
+PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
+PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
+
+/* common to connection engine and listeners */
+typedef struct psocket_t {
+  /* Immutable */
+  pn_proactor_t *proactor;
+
+  /* Protected by proactor.lock */
+  struct psocket_t* next;
+  void (*wakeup)(struct psocket_t*); /* interrupting action for leader */
+
+  /* Only used by leader */
+  uv_tcp_t tcp;
+  void (*action)(struct psocket_t*); /* deferred action for leader */
+  bool is_conn:1;
+  char host[NI_MAXHOST];
+  char port[NI_MAXSERV];
+} psocket_t;
+
+/* Special value for psocket.next pointer when socket is not on any any list. */
+psocket_t UNLISTED;
+
+static void psocket_init(psocket_t* ps, pn_proactor_t* p, bool is_conn, const char *host, const char *port) {
+  ps->proactor = p;
+  ps->next = &UNLISTED;
+  ps->is_conn = is_conn;
+  ps->tcp.data = ps;
+
+  /* For platforms that don't know about "amqp" and "amqps" service names. */
+  if (strcmp(port, AMQP_PORT_NAME) == 0)
+    port = AMQP_PORT;
+  else if (strcmp(port, AMQPS_PORT_NAME) == 0)
+    port = AMQPS_PORT;
+  /* Set to "\001" to indicate a NULL as opposed to an empty string "" */
+  strncpy(ps->host, host ? host : "\001", sizeof(ps->host));
+  strncpy(ps->port, port ? port : "\001", sizeof(ps->port));
+}
+
+/* Turn "\001" back to NULL */
+static inline const char* fixstr(const char* str) {
+  return str[0] == '\001' ? NULL : str;
+}
+
+typedef struct pconn {
+  psocket_t psocket;
+
+  /* Only used by owner thread */
+  pn_connection_engine_t ceng;
+
+  /* Only used by leader */
+  uv_connect_t connect;
+  uv_timer_t timer;
+  uv_write_t write;
+  uv_shutdown_t shutdown;
+  size_t writing;
+  bool reading:1;
+  bool server:1;                /* accept, not connect */
+} pconn;
+
+struct pn_listener_t {
+  psocket_t psocket;
+
+  /* Only used by owner thread */
+  pn_condition_t *condition;
+  pn_collector_t *collector;
+  size_t backlog;
+};
+
+PN_EXTRA_DECLARE(pn_listener_t);
+
+typedef struct queue { psocket_t *front, *back; } queue;
+
+struct pn_proactor_t {
+  /* Leader thread  */
+  uv_cond_t cond;
+  uv_loop_t loop;
+  uv_async_t async;
+
+  /* Protected by lock */
+  uv_mutex_t lock;
+  queue start_q;
+  queue worker_q;
+  queue leader_q;
+  size_t interrupt;             /* pending interrupts */
+  size_t count;                 /* psocket count */
+  bool inactive:1;
+  bool has_leader:1;
+
+  /* Immutable collectors to hold fixed events */
+  pn_collector_t *interrupt_event;
+  pn_collector_t *timeout_event;
+  pn_collector_t *inactive_event;
+};
+
+static bool push_lh(queue *q, psocket_t *ps) {
+  if (ps->next != &UNLISTED)  /* Don't move if already listed. */
+    return false;
+  ps->next = NULL;
+  if (!q->front) {
+    q->front = q->back = ps;
+  } else {
+    q->back->next = ps;
+    q->back =  ps;
+  }
+  return true;
+}
+
+static psocket_t* pop_lh(queue *q) {
+  psocket_t *ps = q->front;
+  if (ps) {
+    q->front = ps->next;
+    ps->next = &UNLISTED;
+  }
+  return ps;
+}
+
+static inline pconn *as_pconn(psocket_t* ps) {
+  return ps->is_conn ? (pconn*)ps : NULL;
+}
+
+static inline pn_listener_t *as_listener(psocket_t* ps) {
+  return ps->is_conn ? NULL: (pn_listener_t*)ps;
+}
+
+/* Put ps on the leader queue for processing. Thread safe. */
+static void to_leader_lh(psocket_t *ps) {
+  push_lh(&ps->proactor->leader_q, ps);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+}
+
+static void to_leader(psocket_t *ps) {
+  uv_mutex_lock(&ps->proactor->lock);
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Detach from IO and put ps on the worker queue */
+static void leader_to_worker(psocket_t *ps) {
+  pconn *pc = as_pconn(ps);
+  /* Don't detach if there are no events yet. */
+  if (pc && pn_connection_engine_has_event(&pc->ceng)) {
+    if (pc->writing) {
+      pc->writing  = 0;
+      uv_cancel((uv_req_t*)&pc->write);
+    }
+    if (pc->reading) {
+      pc->reading = false;
+      uv_read_stop((uv_stream_t*)&pc->psocket.tcp);
+    }
+    if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
+      uv_timer_stop(&pc->timer);
+    }
+  }
+
+  /* Nothing to do for a listener, on_accept doesn't touch worker state. */
+
+  uv_mutex_lock(&ps->proactor->lock);
+  push_lh(&ps->proactor->worker_q, ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Re-queue for further work */
+static void worker_requeue(psocket_t* ps) {
+  uv_mutex_lock(&ps->proactor->lock);
+  push_lh(&ps->proactor->worker_q, ps);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+static pconn *new_pconn(pn_proactor_t *p, bool server, const char *host, const char *port, pn_bytes_t extra) {
+  pconn *pc = (pconn*)calloc(1, sizeof(*pc));
+  if (!pc) return NULL;
+  if (pn_connection_engine_init(&pc->ceng, pn_connection_with_extra(extra.size), NULL) != 0) {
+    return NULL;
+  }
+  if (extra.start && extra.size) {
+    memcpy(pn_connection_get_extra(pc->ceng.connection).start, extra.start, extra.size);
+  }
+  psocket_init(&pc->psocket, p,  true, host, port);
+  if (server) {
+    pn_transport_set_server(pc->ceng.transport);
+  }
+  pn_record_t *r = pn_connection_attachments(pc->ceng.connection);
+  pn_record_def(r, PN_PROACTOR, PN_VOID);
+  pn_record_set(r, PN_PROACTOR, pc);
+  return pc;
+}
+
+pn_listener_t *new_listener(pn_proactor_t *p, const char *host, const char *port, int backlog, pn_bytes_t extra) {
+  pn_listener_t *l = (pn_listener_t*)calloc(1, PN_EXTRA_SIZEOF(pn_listener_t, extra.size));
+  if (!l) {
+    return NULL;
+  }
+  l->collector = pn_collector();
+  if (!l->collector) {
+    free(l);
+    return NULL;
+  }
+  if (extra.start && extra.size) {
+    memcpy(pn_listener_get_extra(l).start, extra.start, extra.size);
+  }
+  psocket_init(&l->psocket, p, false, host, port);
+  l->condition = pn_condition();
+  l->backlog = backlog;
+  return l;
+}
+
+static void leader_count(pn_proactor_t *p, int change) {
+  uv_mutex_lock(&p->lock);
+  p->count += change;
+  p->inactive = (p->count == 0);
+  uv_mutex_unlock(&p->lock);
+}
+
+/* Free if there are no uv callbacks pending and no events */
+static void leader_pconn_maybe_free(pconn *pc) {
+    if (pn_connection_engine_has_event(&pc->ceng)) {
+      leader_to_worker(&pc->psocket);         /* Return to worker */
+    } else if (!(pc->psocket.tcp.data || pc->shutdown.data || pc->timer.data)) {
+      pn_connection_engine_destroy(&pc->ceng);
+      leader_count(pc->psocket.proactor, -1);
+      free(pc);
+    }
+}
+
+/* Free if there are no uv callbacks pending and no events */
+static void leader_listener_maybe_free(pn_listener_t *l) {
+    if (pn_collector_peek(l->collector)) {
+      leader_to_worker(&l->psocket);         /* Return to worker */
+    } else if (!l->psocket.tcp.data) {
+      pn_condition_free(l->condition);
+      leader_count(l->psocket.proactor, -1);
+      free(l);
+    }
+}
+
+/* Free if there are no uv callbacks pending and no events */
+static void leader_maybe_free(psocket_t *ps) {
+  if (ps->is_conn) {
+    leader_pconn_maybe_free(as_pconn(ps));
+  } else {
+    leader_listener_maybe_free(as_listener(ps));
+  }
+}
+
+static void on_close(uv_handle_t *h) {
+  psocket_t *ps = (psocket_t*)h->data;
+  h->data = NULL;               /* Mark closed */
+  leader_maybe_free(ps);
+}
+
+static void on_shutdown(uv_shutdown_t *shutdown, int err) {
+  psocket_t *ps = (psocket_t*)shutdown->data;
+  shutdown->data = NULL;        /* Mark closed */
+  leader_maybe_free(ps);
+}
+
+static inline void leader_close(psocket_t *ps) {
+  if (ps->tcp.data && !uv_is_closing((uv_handle_t*)&ps->tcp)) {
+    uv_close((uv_handle_t*)&ps->tcp, on_close);
+  }
+  pconn *pc = as_pconn(ps);
+  if (pc) {
+    pn_connection_engine_close(&pc->ceng);
+    if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
+      uv_timer_stop(&pc->timer);
+      uv_close((uv_handle_t*)&pc->timer, on_close);
+    }
+  }
+  leader_maybe_free(ps);
+}
+
+static pconn *get_pconn(pn_connection_t* c) {
+  if (!c) return NULL;
+  pn_record_t *r = pn_connection_attachments(c);
+  return (pconn*) pn_record_get(r, PN_PROACTOR);
+}
+
+static void leader_error(psocket_t *ps, int err, const char* what) {
+  if (ps->is_conn) {
+    pn_connection_engine_t *ceng = &as_pconn(ps)->ceng;
+    pn_connection_engine_errorf(ceng, COND_NAME, "%s %s:%s: %s",
+                                what, fixstr(ps->host), fixstr(ps->port),
+                                uv_strerror(err));
+    pn_connection_engine_bind(ceng);
+    pn_connection_engine_close(ceng);
+  } else {
+    pn_listener_t *l = as_listener(ps);
+    pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
+                        what, fixstr(ps->host), fixstr(ps->port),
+                        uv_strerror(err));
+    pn_collector_put(l->collector, pn_listener__class(), l, PN_LISTENER_CLOSE);
+  }
+  leader_to_worker(ps);               /* Worker to handle the error */
+}
+
+/* uv-initialization */
+static int leader_init(psocket_t *ps) {
+  leader_count(ps->proactor, +1);
+  int err = uv_tcp_init(&ps->proactor->loop, &ps->tcp);
+  if (!err) {
+    pconn *pc = as_pconn(ps);
+    if (pc) {
+      pc->connect.data = pc->write.data = pc->shutdown.data = ps;
+      int err = uv_timer_init(&ps->proactor->loop, &pc->timer);
+      if (!err) {
+        pc->timer.data = pc;
+      }
+    }
+  }
+  if (err) {
+    leader_error(ps, err, "initialization");
+  }
+  return err;
+}
+
+/* Common logic for on_connect and on_accept */
+static void leader_connect_accept(pconn *pc, int err, const char *what) {
+  if (!err) {
+    leader_to_worker(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, err, what);
+  }
+}
+
+static void on_connect(uv_connect_t *connect, int err) {
+  leader_connect_accept((pconn*)connect->data, err, "on connect");
+}
+
+static void on_accept(uv_stream_t* server, int err) {
+  pn_listener_t* l = (pn_listener_t*)server->data;
+  if (!err) {
+    pn_rwbytes_t v =  pn_listener_get_extra(l);
+    pconn *pc = new_pconn(l->psocket.proactor, true,
+                          fixstr(l->psocket.host),
+                          fixstr(l->psocket.port),
+                          pn_bytes(v.size, v.start));
+    if (pc) {
+      int err2 = leader_init(&pc->psocket);
+      if (!err2) err2 = uv_accept((uv_stream_t*)&l->psocket.tcp, (uv_stream_t*)&pc->psocket.tcp);
+      leader_connect_accept(pc, err2, "on accept");
+    } else {
+      err = UV_ENOMEM;
+    }
+  }
+  if (err) {
+    leader_error(&l->psocket, err, "on accept");
+  }
+}
+
+static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info) {
+  int err = leader_init(ps);
+  if (!err) {
+    err = uv_getaddrinfo(&ps->proactor->loop, info, NULL,
+                         fixstr(ps->host), fixstr(ps->port), NULL);
+  }
+  return err;
+}
+
+static void leader_connect(psocket_t *ps) {
+  pconn *pc = as_pconn(ps);
+  uv_getaddrinfo_t info;
+  int err = leader_resolve(ps, &info);
+  if (!err) {
+    err = uv_tcp_connect(&pc->connect, &pc->psocket.tcp, info.addrinfo->ai_addr, on_connect);
+    uv_freeaddrinfo(info.addrinfo);
+  }
+  if (err) {
+    leader_error(ps, err, "connect to");
+  }
+}
+
+static void leader_listen(psocket_t *ps) {
+  pn_listener_t *l = as_listener(ps);
+  uv_getaddrinfo_t info;
+  int err = leader_resolve(ps, &info);
+  if (!err) {
+    err = uv_tcp_bind(&l->psocket.tcp, info.addrinfo->ai_addr, 0);
+    uv_freeaddrinfo(info.addrinfo);
+  }
+  if (!err) err = uv_listen((uv_stream_t*)&l->psocket.tcp, l->backlog, on_accept);
+  if (err) {
+    leader_error(ps, err, "listen on ");
+  }
+}
+
+static void on_tick(uv_timer_t *timer) {
+  pconn *pc = (pconn*)timer->data;
+  pn_transport_t *t = pc->ceng.transport;
+  if (pn_transport_get_idle_timeout(t) || pn_transport_get_remote_idle_timeout(t)) {
+    uv_timer_stop(&pc->timer);
+    uint64_t now = uv_now(pc->timer.loop);
+    uint64_t next = pn_transport_tick(t, now);
+    if (next) {
+      uv_timer_start(&pc->timer, on_tick, next - now, 0);
+    }
+  }
+}
+
+static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+  pconn *pc = (pconn*)stream->data;
+  if (nread >= 0) {
+    pn_connection_engine_read_done(&pc->ceng, nread);
+    on_tick(&pc->timer);         /* check for tick changes. */
+    leader_to_worker(&pc->psocket);
+    /* Reading continues automatically until stopped. */
+  } else if (nread == UV_EOF) { /* hangup */
+    pn_connection_engine_read_close(&pc->ceng);
+    leader_maybe_free(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, nread, "on read from");
+  }
+}
+
+static void on_write(uv_write_t* request, int err) {
+  pconn *pc = (pconn*)request->data;
+  if (err == 0) {
+    pn_connection_engine_write_done(&pc->ceng, pc->writing);
+    leader_to_worker(&pc->psocket);
+  } else if (err == UV_ECANCELED) {
+    leader_maybe_free(&pc->psocket);
+  } else {
+    leader_error(&pc->psocket, err, "on write to");
+  }
+  pc->writing = 0;              /* Need to send a new write request */
+}
+
+// Read buffer allocation function for uv, just returns the transports read buffer.
+static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
+  pconn *pc = (pconn*)stream->data;
+  pn_rwbytes_t rbuf = pn_connection_engine_read_buffer(&pc->ceng);
+  *buf = uv_buf_init(rbuf.start, rbuf.size);
+}
+
+static void leader_rewatch(psocket_t *ps) {
+  pconn *pc = as_pconn(ps);
+
+  if (pc->timer.data) {         /* uv-initialized */
+    on_tick(&pc->timer);        /* Re-enable ticks if required */
+  }
+  pn_rwbytes_t rbuf = pn_connection_engine_read_buffer(&pc->ceng);
+  pn_bytes_t wbuf = pn_connection_engine_write_buffer(&pc->ceng);
+
+  /* Ticks and checking buffers can generate events, process before proceeding */
+  if (pn_connection_engine_has_event(&pc->ceng)) {
+    leader_to_worker(ps);
+  } else {                      /* Re-watch for IO */
+    if (wbuf.size > 0 && !pc->writing) {
+      pc->writing = wbuf.size;
+      uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
+      uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
+    } else if (wbuf.size == 0 && pn_connection_engine_write_closed(&pc->ceng)) {
+      uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
+    }
+    if (rbuf.size > 0 && !pc->reading) {
+      pc->reading = true;
+      uv_read_start((uv_stream_t*)&pc->psocket.tcp, alloc_read_buffer, on_read);
+    }
+  }
+}
+
+/* Return the next worker event or { 0 } if no events are ready */
+static pn_event_t* get_event_lh(pn_proactor_t *p) {
+  if (p->inactive) {
+    p->inactive = false;
+    return pn_collector_peek(p->inactive_event);
+  }
+  if (p->interrupt > 0) {
+    --p->interrupt;
+    return pn_collector_peek(p->interrupt_event);
+  }
+  for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
+    if (ps->is_conn) {
+      pconn *pc = as_pconn(ps);
+      return pn_connection_engine_event(&pc->ceng);
+    } else {                    /* Listener */
+      pn_listener_t *l = as_listener(ps);
+      return pn_collector_peek(l->collector);
+    }
+    to_leader(ps);      /* No event, back to leader */
+  }
+  return 0;
+}
+
+/* Called in any thread to set a wakeup action. Replaces any previous wakeup action. */
+static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  ps->wakeup = action;
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Defer an action to the leader thread. Only from non-leader threads. */
+static void owner_defer(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  assert(!ps->action);
+  ps->action = action;
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+pn_listener_t *pn_event_listener(pn_event_t *e) {
+  return (pn_event_class(e) == pn_listener__class()) ? (pn_listener_t*)pn_event_context(e) : NULL;
+}
+
+pn_proactor_t *pn_event_proactor(pn_event_t *e) {
+  if (pn_event_class(e) == pn_proactor__class()) return (pn_proactor_t*)pn_event_context(e);
+  pn_listener_t *l = pn_event_listener(e);
+  if (l) return l->psocket.proactor;
+  pn_connection_t *c = pn_event_connection(e);
+  if (c) return pn_connection_proactor(pn_event_connection(e));
+  return NULL;
+}
+
+void pn_event_done(pn_event_t *e) {
+  pn_event_type_t etype = pn_event_type(e);
+  pconn *pc = get_pconn(pn_event_connection(e));
+  if (pc && e == pn_collector_peek(pc->ceng.collector)) {
+    pn_connection_engine_pop_event(&pc->ceng);
+    if (etype == PN_CONNECTION_INIT) {
+      /* Bind after user has handled CONNECTION_INIT */
+      pn_connection_engine_bind(&pc->ceng);
+    }
+    if (pn_connection_engine_has_event(&pc->ceng)) {
+      /* Process all events before going back to IO.
+         Put it back on the worker queue and wake the leader.
+      */
+      worker_requeue(&pc->psocket);
+    } else if (pn_connection_engine_finished(&pc->ceng)) {
+      owner_defer(&pc->psocket, leader_close);
+    } else {
+      owner_defer(&pc->psocket, leader_rewatch);
+    }
+  } else {
+    pn_listener_t *l = pn_event_listener(e);
+    if (l && e == pn_collector_peek(l->collector)) {
+      pn_collector_pop(l->collector);
+      if (etype == PN_LISTENER_CLOSE) {
+        owner_defer(&l->psocket, leader_close);
+      }
+    }
+  }
+}
+
+/* Run follower/leader loop till we can return an event and be a worker */
+pn_event_t *pn_proactor_wait(struct pn_proactor_t* p) {
+  uv_mutex_lock(&p->lock);
+  /* Try to grab work immediately. */
+  pn_event_t *e = get_event_lh(p);
+  if (e == NULL) {
+    /* No work available, follow the leader */
+    while (p->has_leader)
+      uv_cond_wait(&p->cond, &p->lock);
+    /* Lead till there is work to do. */
+    p->has_leader = true;
+    for (e = get_event_lh(p); e == NULL; e = get_event_lh(p)) {
+      /* Run uv_loop outside the lock */
+      uv_mutex_unlock(&p->lock);
+      uv_run(&p->loop, UV_RUN_ONCE);
+      uv_mutex_lock(&p->lock);
+      /* Process leader work queue outside the lock */
+      for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
+        void (*action)(psocket_t*) = ps->action;
+        ps->action = NULL;
+        void (*wakeup)(psocket_t*) = ps->wakeup;
+        ps->wakeup = NULL;
+        if (action || wakeup) {
+          uv_mutex_unlock(&p->lock);
+          if (action) action(ps);
+          if (wakeup) wakeup(ps);
+          uv_mutex_lock(&p->lock);
+        }
+      }
+    }
+    /* Signal the next leader and return to work */
+    p->has_leader = false;
+    uv_cond_signal(&p->cond);
+  }
+  uv_mutex_unlock(&p->lock);
+  return e;
+}
+
+void pn_proactor_interrupt(pn_proactor_t *p) {
+  uv_mutex_lock(&p->lock);
+  ++p->interrupt;
+  uv_async_send(&p->async);   /* Interrupt the UV loop */
+  uv_mutex_unlock(&p->lock);
+}
+
+int pn_proactor_connect(pn_proactor_t *p, const char *host, const char *port, pn_bytes_t extra) {
+  pconn *pc = new_pconn(p, false, host, port, extra);
+  if (!pc) {
+    return PN_OUT_OF_MEMORY;
+  }
+  owner_defer(&pc->psocket, leader_connect); /* Process PN_CONNECTION_INIT before binding */
+  return 0;
+}
+
+pn_rwbytes_t pn_listener_get_extra(pn_listener_t *l) { return PN_EXTRA_GET(pn_listener_t, l); }
+
+pn_listener_t *pn_proactor_listen(pn_proactor_t *p, const char *host, const char *port, int backlog, pn_bytes_t extra) {
+  pn_listener_t *l = new_listener(p, host, port, backlog, extra);
+  if (l)  owner_defer(&l->psocket, leader_listen);
+  return l;
+}
+
+pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
+  pconn *pc = get_pconn(c);
+  return pc ? pc->psocket.proactor : NULL;
+}
+
+pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
+  return l ? l->psocket.proactor : NULL;
+}
+
+void leader_wake_connection(psocket_t *ps) {
+  pconn *pc = as_pconn(ps);
+  pn_collector_put(pc->ceng.collector, PN_OBJECT, pc->ceng.connection, PN_CONNECTION_WAKE);
+  leader_to_worker(ps);
+}
+
+void pn_connection_wake(pn_connection_t* c) {
+  wakeup(&get_pconn(c)->psocket, leader_wake_connection);
+}
+
+void pn_listener_close(pn_listener_t* l) {
+  wakeup(&l->psocket, leader_close);
+}
+
+/* Only called when condition is closed by error. */
+pn_condition_t* pn_listener_condition(pn_listener_t* l) {
+  return l->condition;
+}
+
+/* Collector to hold for a single fixed event that is never popped. */
+static pn_collector_t *event_holder(pn_proactor_t *p, pn_event_type_t t) {
+  pn_collector_t *c = pn_collector();
+  pn_collector_put(c, pn_proactor__class(), p, t);
+  return c;
+}
+
+pn_proactor_t *pn_proactor() {
+  pn_proactor_t *p = (pn_proactor_t*)calloc(1, sizeof(*p));
+  uv_loop_init(&p->loop);
+  uv_mutex_init(&p->lock);
+  uv_cond_init(&p->cond);
+  uv_async_init(&p->loop, &p->async, NULL); /* Just wake the loop */
+  p->interrupt_event = event_holder(p, PN_PROACTOR_INTERRUPT);
+  p->inactive_event = event_holder(p, PN_PROACTOR_INACTIVE);
+  p->timeout_event = event_holder(p, PN_PROACTOR_TIMEOUT);
+  return p;
+}
+
+static void on_stopping(uv_handle_t* h, void* v) {
+  uv_close(h, NULL);           /* Close this handle */
+  if (!uv_loop_alive(h->loop)) /* Everything closed */
+    uv_stop(h->loop);        /* Stop the loop, pn_proactor_destroy() can return */
+}
+
+void pn_proactor_free(pn_proactor_t *p) {
+  uv_walk(&p->loop, on_stopping, NULL); /* Close all handles */
+  uv_run(&p->loop, UV_RUN_DEFAULT);     /* Run till stop, all handles closed */
+  uv_loop_close(&p->loop);
+  uv_mutex_destroy(&p->lock);
+  uv_cond_destroy(&p->cond);
+  pn_collector_free(p->interrupt_event);
+  pn_collector_free(p->inactive_event);
+  pn_collector_free(p->timeout_event);
+  free(p);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
new file mode 100644
index 0000000..303e348
--- /dev/null
+++ b/examples/c/proactor/receive.c
@@ -0,0 +1,202 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/connection.h>
+#include <proton/connection_engine.h>
+#include <proton/delivery.h>
+#include <proton/proactor.h>
+#include <proton/link.h>
+#include <proton/message.h>
+#include <proton/session.h>
+#include <proton/transport.h>
+#include <proton/url.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef char str[1024];
+
+typedef struct app_data_t {
+    str address;
+    str container_id;
+    pn_rwbytes_t message_buffer;
+    int message_count;
+    int received;
+    pn_proactor_t *proactor;
+} app_data_t;
+
+static const int BATCH = 100; /* Batch size for unlimited receive */
+
+static int exit_code = 0;
+
+static void check_condition(pn_event_t *e, pn_condition_t *cond) {
+  if (pn_condition_is_set(cond)) {
+    exit_code = 1;
+    fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)),
+            pn_condition_get_name(cond), pn_condition_get_description(cond));
+  }
+}
+
+#define MAX_SIZE 1024
+
+static void decode_message(pn_delivery_t *dlv) {
+  static char buffer[MAX_SIZE];
+  ssize_t len;
+  // try to decode the message body
+  if (pn_delivery_pending(dlv) < MAX_SIZE) {
+    // read in the raw data
+    len = pn_link_recv(pn_delivery_link(dlv), buffer, MAX_SIZE);
+    if (len > 0) {
+      // decode it into a proton message
+      pn_message_t *m = pn_message();
+      if (PN_OK == pn_message_decode(m, buffer, len)) {
+        pn_string_t *s = pn_string(NULL);
+        pn_inspect(pn_message_body(m), s);
+        printf("%s\n", pn_string_get(s));
+        pn_free(s);
+      }
+      pn_message_free(m);
+    }
+  }
+}
+
+/* Handle event, return true of we should handle more */
+static bool handle(app_data_t* app, pn_event_t* event) {
+  bool more = true;
+  switch (pn_event_type(event)) {
+
+   case PN_CONNECTION_INIT: {
+     pn_connection_t* c = pn_event_connection(event);
+     pn_connection_set_container(c, app->container_id);
+     pn_connection_open(c);
+     pn_session_t* s = pn_session(c);
+     pn_session_open(s);
+     pn_link_t* l = pn_receiver(s, "my_receiver");
+     pn_terminus_set_address(pn_link_source(l), app->address);
+     pn_link_open(l);
+     /* cannot receive without granting credit: */
+     pn_link_flow(l, app->message_count ? app->message_count : BATCH);
+   } break;
+
+   case PN_DELIVERY: {
+     /* A message has been received */
+     pn_link_t *link = NULL;
+     pn_delivery_t *dlv = pn_event_delivery(event);
+     if (pn_delivery_readable(dlv) && !pn_delivery_partial(dlv)) {
+       link = pn_delivery_link(dlv);
+       decode_message(dlv);
+       /* Accept the delivery */
+       pn_delivery_update(dlv, PN_ACCEPTED);
+       /* done with the delivery, move to the next and free it */
+       pn_link_advance(link);
+       pn_delivery_settle(dlv);  /* dlv is now freed */
+
+       if (app->message_count == 0) {
+         /* receive forever - see if more credit is needed */
+         if (pn_link_credit(link) < BATCH/2) {
+           /* Grant enough credit to bring it up to BATCH: */
+           pn_link_flow(link, BATCH - pn_link_credit(link));
+         }
+       } else if (++app->received >= app->message_count) {
+         /* done receiving, close the endpoints */
+         printf("%d messages received\n", app->received);
+         pn_session_t *ssn = pn_link_session(link);
+         pn_link_close(link);
+         pn_session_close(ssn);
+         pn_connection_close(pn_session_connection(ssn));
+       }
+     }
+   } break;
+
+   case PN_TRANSPORT_ERROR:
+    check_condition(event, pn_transport_condition(pn_event_transport(event)));
+    break;
+
+   case PN_CONNECTION_REMOTE_CLOSE:
+    check_condition(event, pn_connection_remote_condition(pn_event_connection(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_SESSION_REMOTE_CLOSE:
+    check_condition(event, pn_session_remote_condition(pn_event_session(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_LINK_REMOTE_CLOSE:
+   case PN_LINK_REMOTE_DETACH:
+    check_condition(event, pn_link_remote_condition(pn_event_link(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_PROACTOR_INACTIVE:
+    more = false;
+    break;
+
+   default: break;
+  }
+  pn_event_done(event);
+  return more;
+}
+
+static void usage(const char *arg0) {
+    fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
+    exit(1);
+}
+
+int main(int argc, char **argv) {
+    /* Default values for application and connection. */
+    app_data_t app = {{0}};
+    app.message_count = 100;
+    const char* urlstr = NULL;
+
+    int opt;
+    while((opt = getopt(argc, argv, "a:m:")) != -1) {
+        switch(opt) {
+          case 'a': urlstr = optarg; break;
+          case 'm': app.message_count = atoi(optarg); break;
+          default: usage(argv[0]); break;
+        }
+    }
+    if (optind < argc)
+        usage(argv[0]);
+
+    snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
+
+    /* Parse the URL or use default values */
+    pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
+    const char *host = url ? pn_url_get_host(url) : NULL;
+    const char *port = url ? pn_url_get_port(url) : NULL;
+    if (!port) port = "amqp";
+    strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
+
+    /* Create the proactor and connect */
+    app.proactor = pn_proactor();
+    pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
+    if (url) pn_url_free(url);
+
+    while (handle(&app, pn_proactor_wait(app.proactor)))
+           ;
+    pn_proactor_free(app.proactor);
+    free(app.message_buffer.start);
+    return exit_code;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
new file mode 100644
index 0000000..68ba0c8
--- /dev/null
+++ b/examples/c/proactor/send.c
@@ -0,0 +1,204 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/connection.h>
+#include <proton/connection_engine.h>
+#include <proton/delivery.h>
+#include <proton/proactor.h>
+#include <proton/link.h>
+#include <proton/message.h>
+#include <proton/session.h>
+#include <proton/transport.h>
+#include <proton/url.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef char str[1024];
+
+typedef struct app_data_t {
+    str address;
+    str container_id;
+    pn_rwbytes_t message_buffer;
+    int message_count;
+    int sent;
+    int acknowledged;
+    pn_proactor_t *proactor;
+} app_data_t;
+
+int exit_code = 0;
+
+static void check_condition(pn_event_t *e, pn_condition_t *cond) {
+  if (pn_condition_is_set(cond)) {
+    exit_code = 1;
+    fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)),
+            pn_condition_get_name(cond), pn_condition_get_description(cond));
+  }
+}
+
+/* Create a message with a map { "sequence" : number } encode it and return the encoded buffer. */
+static pn_bytes_t encode_message(app_data_t* app) {
+    /* Construct a message with the map { "sequence": app.sent } */
+    pn_message_t* message = pn_message();
+    pn_data_put_int(pn_message_id(message), app->sent); /* Set the message_id also */
+    pn_data_t* body = pn_message_body(message);
+    pn_data_put_map(body);
+    pn_data_enter(body);
+    pn_data_put_string(body, pn_bytes(sizeof("sequence")-1, "sequence"));
+    pn_data_put_int(body, app->sent); /* The sequence number */
+    pn_data_exit(body);
+
+    /* encode the message, expanding the encode buffer as needed */
+    if (app->message_buffer.start == NULL) {
+        static const size_t initial_size = 128;
+        app->message_buffer = pn_rwbytes(initial_size, (char*)malloc(initial_size));
+    }
+    /* app->message_buffer is the total buffer space available. */
+    /* mbuf wil point at just the portion used by the encoded message */
+    pn_rwbytes_t mbuf = pn_rwbytes(app->message_buffer.size, app->message_buffer.start);
+    int status = 0;
+    while ((status = pn_message_encode(message, mbuf.start, &mbuf.size)) == PN_OVERFLOW) {
+        app->message_buffer.size *= 2;
+        app->message_buffer.start = (char*)realloc(app->message_buffer.start, app->message_buffer.size);
+        mbuf.size = app->message_buffer.size;
+    }
+    if (status != 0) {
+        fprintf(stderr, "error encoding message: %s\n", pn_error_text(pn_message_error(message)));
+        exit(1);
+    }
+    pn_message_free(message);
+    return pn_bytes(mbuf.size, mbuf.start);
+}
+
+/* Handle event, return true of we should handle more */
+static bool handle(app_data_t* app, pn_event_t* event) {
+  bool more = true;
+  switch (pn_event_type(event)) {
+
+   case PN_CONNECTION_INIT: {
+     pn_connection_t* c = pn_event_connection(event);
+     pn_connection_set_container(c, app->container_id);
+     pn_connection_open(c);
+     pn_session_t* s = pn_session(c);
+     pn_session_open(s);
+     pn_link_t* l = pn_sender(s, "my_sender");
+     pn_terminus_set_address(pn_link_target(l), app->address);
+     pn_link_open(l);
+   } break;
+
+   case PN_LINK_FLOW: {
+     /* The peer has given us some credit, now we can send messages */
+     pn_link_t *sender = pn_event_link(event);
+     while (pn_link_credit(sender) > 0 && app->sent < app->message_count) {
+       ++app->sent;
+       // Use sent counter bytes as unique delivery tag.
+       pn_delivery(sender, pn_dtag((const char *)&app->sent, sizeof(app->sent)));
+       pn_bytes_t msgbuf = encode_message(app);
+       pn_link_send(sender, msgbuf.start, msgbuf.size);
+       pn_link_advance(sender);
+     }
+   } break;
+
+   case PN_DELIVERY: {
+     /* We received acknowledgedment from the peer that a message was delivered. */
+     pn_delivery_t* d = pn_event_delivery(event);
+     if (pn_delivery_remote_state(d) == PN_ACCEPTED) {
+       if (++app->acknowledged == app->message_count) {
+         printf("%d messages sent and acknowledged\n", app->acknowledged);
+         pn_connection_close(pn_event_connection(event));
+       }
+     }
+   } break;
+
+   case PN_TRANSPORT_ERROR:
+    check_condition(event, pn_transport_condition(pn_event_transport(event)));
+    break;
+
+   case PN_CONNECTION_REMOTE_CLOSE:
+    check_condition(event, pn_connection_remote_condition(pn_event_connection(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_SESSION_REMOTE_CLOSE:
+    check_condition(event, pn_session_remote_condition(pn_event_session(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_LINK_REMOTE_CLOSE:
+   case PN_LINK_REMOTE_DETACH:
+    check_condition(event, pn_link_remote_condition(pn_event_link(event)));
+    pn_connection_close(pn_event_connection(event));
+    break;
+
+   case PN_PROACTOR_INACTIVE:
+    more = false;
+    break;
+
+   default: break;
+  }
+  pn_event_done(event);
+  return more;
+}
+
+static void usage(const char *arg0) {
+    fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
+    exit(1);
+}
+
+int main(int argc, char **argv) {
+    /* Default values for application and connection. */
+    app_data_t app = {{0}};
+    app.message_count = 100;
+    const char* urlstr = NULL;
+
+    int opt;
+    while((opt = getopt(argc, argv, "a:m:")) != -1) {
+        switch(opt) {
+          case 'a': urlstr = optarg; break;
+          case 'm': app.message_count = atoi(optarg); break;
+          default: usage(argv[0]); break;
+        }
+    }
+    if (optind < argc)
+        usage(argv[0]);
+
+    snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
+
+    /* Parse the URL or use default values */
+    pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
+    const char *host = url ? pn_url_get_host(url) : NULL;
+    const char *port = url ? pn_url_get_port(url) : NULL;
+    if (!port) port = "amqp";
+    strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
+
+    /* Create the proactor and connect */
+    app.proactor = pn_proactor();
+    pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
+    if (url) pn_url_free(url);
+
+    while (handle(&app, pn_proactor_wait(app.proactor)))
+           ;
+    pn_proactor_free(app.proactor);
+    free(app.message_buffer.start);
+    return exit_code;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/c/proactor/test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/test.py b/examples/c/proactor/test.py
new file mode 100644
index 0000000..5dc3a99
--- /dev/null
+++ b/examples/c/proactor/test.py
@@ -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
+#
+
+# This is a test script to run the examples and verify that they behave as expected.
+
+from exampletest import *
+
+import unittest
+import sys
+
+def python_cmd(name):
+    dir = os.path.dirname(__file__)
+    return [sys.executable, os.path.join(dir, "..", "..", "python", name)]
+
+def receive_expect(n):
+    return ''.join('{"sequence"=%s}\n'%i for i in xrange(1, n+1)) + "%s messages received\n"%n
+
+class CExampleTest(BrokerTestCase):
+    broker_exe = ["libuv_broker"]
+
+    def test_send_receive(self):
+        """Send first then receive"""
+        s = self.proc(["libuv_send", "-a", self.addr])
+        self.assertEqual("100 messages sent and acknowledged\n", s.wait_out())
+        r = self.proc(["libuv_receive", "-a", self.addr])
+        self.assertEqual(receive_expect(100), r.wait_out())
+
+    def test_receive_send(self):
+        """Start receiving  first, then send."""
+        r = self.proc(["libuv_receive", "-a", self.addr]);
+        s = self.proc(["libuv_send", "-a", self.addr]);
+        self.assertEqual("100 messages sent and acknowledged\n", s.wait_out())
+        self.assertEqual(receive_expect(100), r.wait_out())
+
+if __name__ == "__main__":
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/engine/c/precv.c
----------------------------------------------------------------------
diff --git a/examples/engine/c/precv.c b/examples/engine/c/precv.c
deleted file mode 100644
index 3c79a6e..0000000
--- a/examples/engine/c/precv.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-
-/*################################################################
-  This program is half of a pair.  Precv and Psend are meant to 
-  be simple-as-possible examples of how to use the proton-c
-  engine interface to send and receive messages over a single 
-  connection and a single session.
-
-  In addition to being examples, these programs or their 
-  descendants will be used in performance regression testing
-  for both throughput and latency, and long-term soak testing.
-*################################################################*/
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <time.h>
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
-#include <proton/connection.h>
-#include <proton/delivery.h>
-#include <proton/driver.h>
-#include <proton/event.h>
-#include <proton/terminus.h>
-#include <proton/link.h>
-#include <proton/message.h>
-#include <proton/session.h>
-
-
-
-
-
-#define MY_BUF_SIZE  1000
-
-
-
-
-/*---------------------------------------------------------
-  These high-resolution times are used both for
-  interim timing reports -- i.e. every 'report_frequency'
-  messages -- and for the final timestamp, after all 
-  expected messages have been received.
----------------------------------------------------------*/
-static
-double
-get_time ( )
-{
-  struct timeval tv;
-  struct tm      * timeinfo;
-
-  gettimeofday ( & tv, 0 );
-  timeinfo = localtime ( & tv.tv_sec );
-
-  double time_now = 3600 * timeinfo->tm_hour +
-                      60 * timeinfo->tm_min  +
-                           timeinfo->tm_sec;
-
-  time_now += ((double)(tv.tv_usec) / 1000000.0);
-  return time_now;
-}
-
-
-
-
-
-/*----------------------------------------------------
-  These absolute timestamps are useful in soak tests,
-  where I want to align the program's output with 
-  output from top to look at CPU and memory use..
-----------------------------------------------------*/
-void
-print_timestamp_like_a_normal_person ( FILE * fp )
-{
-  char const * month_abbrevs[] = { "jan", 
-                                   "feb", 
-                                   "mar", 
-                                   "apr", 
-                                   "may", 
-                                   "jun", 
-                                   "jul", 
-                                   "aug", 
-                                   "sep", 
-                                   "oct", 
-                                   "nov", 
-                                   "dec" 
-                                 };
-  time_t rawtime;
-  struct tm * timeinfo;
-
-  time ( & rawtime );
-  timeinfo = localtime ( &rawtime );
-
-  char time_string[100];
-  sprintf ( time_string,
-            "%d-%s-%02d %02d:%02d:%02d",
-            1900 + timeinfo->tm_year,
-            month_abbrevs[timeinfo->tm_mon],
-            timeinfo->tm_mday,
-            timeinfo->tm_hour,
-            timeinfo->tm_min,
-            timeinfo->tm_sec
-          );
-
-  fprintf ( fp, "timestamp %s\n", time_string );
-}
-
-
-
-
-
-int 
-main ( int argc, char ** argv  ) 
-{
-  char info[1000];
-
-  uint64_t received = 0;
-
-  char host [1000];
-  char port [1000];
-  char output_file_name[1000];
-
-  int initial_flow   = 400;
-  int flow_increment = 200;
-
-  int       report_frequency  = 200000;
-  int64_t   messages          = 2000000,
-            delivery_count    = 0;
-
-  strcpy ( host, "0.0.0.0" );
-  strcpy ( port, "5672" );
-
-  pn_driver_t     * driver;
-  pn_listener_t   * listener;
-  pn_connector_t  * connector;
-  pn_connection_t * connection;
-  pn_collector_t  * collector;
-  pn_transport_t  * transport;
-  pn_sasl_t       * sasl;
-  pn_session_t    * session;
-  pn_event_t      * event;
-  pn_link_t       * link;
-  pn_delivery_t   * delivery;
-
-
-  double last_time,
-         this_time,
-         time_diff;
-
-  char * message_data          = (char *) malloc ( MY_BUF_SIZE );
-  int    message_data_capacity = MY_BUF_SIZE;
-
-  FILE * output_fp;
-
-
-  /*-----------------------------------------------------------
-    Read the command lines args and override initialization.
-  -----------------------------------------------------------*/
-  for ( int i = 1; i < argc; ++ i )
-  {
-    if ( ! strcmp ( "--host", argv[i] ) )
-    {
-      strcpy ( host, argv[i+1] );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--port", argv[i] ) )
-    {
-      strcpy ( port, argv[i+1] );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--messages", argv[i] ) )
-    {
-      sscanf ( argv [ i+1 ], "%" SCNd64 , & messages );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--output", argv[i] ) )
-    {
-      if ( ! strcmp ( "stderr", argv[i+1] ) )
-      {
-        output_fp = stderr;
-        strcpy ( output_file_name, "stderr");
-      }
-      else
-      if ( ! strcmp ( "stdout", argv[i+1] ) )
-      {
-        output_fp = stdout;
-        strcpy ( output_file_name, "stdout");
-      }
-      else
-      {
-        output_fp = fopen ( argv[i+1], "w" );
-        strcpy ( output_file_name, argv[i+1] );
-        if ( ! output_fp )
-        {
-          fprintf ( stderr, "Can't open |%s| for writing.\n", argv[i+1] );
-          exit ( 1 );
-        }
-      }
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--report_frequency", argv[i] ) )
-    {
-      report_frequency = atoi ( argv[i+1] );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--initial_flow", argv[i] ) )
-    {
-      sscanf ( argv [ i+1 ], "%d", & initial_flow );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--flow_increment", argv[i] ) )
-    {
-      sscanf ( argv [ i+1 ], "%d", & flow_increment );
-      ++ i;
-    }
-    else
-    {
-      fprintf ( output_fp, "unknown arg |%s|\n", argv[i] );
-      exit ( 1 );
-    }
-  }
-
-  /*-----------------------------------------------
-    Show what we ended up with for all the args.
-  -----------------------------------------------*/
-  fprintf ( output_fp, "host                %s\n",          host );
-  fprintf ( output_fp, "port                %s\n",          port );
-  fprintf ( output_fp, "messages            %" PRId64 "\n", messages );
-  fprintf ( output_fp, "report_frequency    %d\n",          report_frequency );
-  fprintf ( output_fp, "initial_flow        %d\n",          initial_flow );
-  fprintf ( output_fp, "flow_increment      %d\n",          flow_increment );
-  fprintf ( output_fp, "output              %s\n",          output_file_name );
-
-
-  /*--------------------------------------------
-    Create a standard driver and listen for the 
-    initial connector.
-  --------------------------------------------*/
-  driver = pn_driver ( );
-
-  if ( ! pn_listener(driver, host, port, 0) ) 
-  {
-    fprintf ( output_fp, "precv listener creation failed.\n" );
-    exit ( 1 );
-  }
-
-  fprintf ( output_fp, "\nprecv ready...\n\n" );
-
-  while ( 1 )
-  {
-    pn_driver_wait ( driver, -1 );
-    if ( listener = pn_driver_listener(driver) )
-    {
-      if ( connector = pn_listener_accept(listener) )
-        break;
-    }
-  }
-
-  /*--------------------------------------------------------
-    Now make all the other structure around the connector,
-    and tell it that skipping sasl is OK.
-  --------------------------------------------------------*/
-  connection = pn_connection ( );
-  collector  = pn_collector  ( );
-  pn_connection_collect ( connection, collector );
-  pn_connector_set_connection ( connector, connection );
-
-  transport = pn_connector_transport ( connector );
-  sasl = pn_sasl ( transport );
-  pn_sasl_mechanisms ( sasl, "ANONYMOUS" );
-  pn_sasl_server ( sasl );
-  pn_sasl_allow_skip ( sasl, true );
-  pn_sasl_done ( sasl, PN_SASL_OK );
-
-  /*----------------------------------------------------------
-    If report_frequency is not set to zero, we will 
-    produce a timing report every report_frequency messages.
-    The timing reported will be the delta from the last_time
-    to the current time.  
-    This is useful in soak testing, where you basically 
-    never stop, but still need to see how the system is doing
-    every so often.
-  ----------------------------------------------------------*/
-  last_time = get_time();
-
-
-  /*------------------------------------------------------------
-    A triply-nested loop.
-    In the outermost one, we just wait for activity to come in 
-    from the driver.
-  ------------------------------------------------------------*/
-  while ( 1 )
-  {
-    pn_driver_wait ( driver, -1 );
-
-    /*---------------------------------------------------------------
-      In the next loop, we keep going as long as we processed
-      some events.  This is because our own processing of events
-      may have caused more to be generated that we need to handle.
-      If we go back to the outermost loop and its pn_driver_wait()
-      without handling these events, we will end up with the sender
-      and receiver programs just staring at each other with blank
-      expressions on their faces.
-    ---------------------------------------------------------------*/
-    int event_count = 1;
-    while ( event_count > 0 )
-    {
-      event_count = 0;
-      pn_connector_process ( connector );
-
-      /*-------------------------------------------------------
-        After we process the connector, it may have generated
-        a batch of events for us to handle.  As we go through 
-        this batch of events, our handling may generate other 
-        events which we must handle before going back to 
-        pn_driver_wait().
-      --------------------------------------------------------*/
-      event = pn_collector_peek(collector);
-      while ( event )
-      {
-        ++ event_count;
-        pn_event_type_t event_type = pn_event_type ( event );
-        //fprintf ( output_fp, "precv event: %s\n", pn_event_type_name(event_type));
-
-
-        switch ( event_type )
-        {
-          case PN_CONNECTION_REMOTE_OPEN:
-          break;
-
-
-          case PN_SESSION_REMOTE_OPEN:
-            session = pn_event_session(event);
-            if ( pn_session_state(session) & PN_LOCAL_UNINIT ) 
-            {
-              // big number because it's in bytes.
-              pn_session_set_incoming_capacity ( session, 1000000 );
-              pn_session_open ( session );
-            }
-          break;
-
-
-          case PN_LINK_REMOTE_OPEN:
-            /*----------------------------------------------------
-              When we first open the link, we give it an initial 
-              amount of credit in units of messages.
-              We will later increment its credit whenever credit
-              falls below some threshold.
-            ----------------------------------------------------*/
-            link = pn_event_link(event);
-            if (pn_link_state(link) & PN_LOCAL_UNINIT )
-            {
-              pn_link_open ( link );
-              pn_link_flow ( link, initial_flow );
-            }
-          break;
-
-
-          case PN_CONNECTION_BOUND:
-            if ( pn_connection_state(connection) & PN_LOCAL_UNINIT )
-            {
-              pn_connection_open ( connection );
-            }
-          break;
-
-
-          // And now the event that you've all been waiting for.....
-
-          case PN_DELIVERY:
-            link = pn_event_link ( event );
-            delivery = pn_event_delivery ( event );
-
-            /*------------------------------------------------
-              Since I want this program to be a receiver,
-              I am not interested in deliver-related events 
-              unless they are incoming, 'readable' events.
-            ------------------------------------------------*/
-            if ( pn_delivery_readable ( delivery ) )
-            {
-              // If the delivery is partial I am just going to ignore
-              // it until it becomes complete.
-              if ( ! pn_delivery_partial ( delivery ) )
-              {
-                ++ delivery_count; 
-                /*
-                if ( ! (delivery_count % report_frequency) )
-                {
-                  pn_link_t * delivery_link = pn_delivery_link ( delivery );
-                  int received_bytes = pn_delivery_pending ( delivery );
-                  pn_link_recv ( delivery_link, incoming, 1000 );
-                  fprintf ( output_fp, "received bytes: %d\n", received_bytes );
-                }
-                */
-
-                // don't bother updating.  they're pre-settled.
-                // pn_delivery_update ( delivery, PN_ACCEPTED );
-                pn_delivery_settle ( delivery );
-
-                int credit = pn_link_credit ( link );
-
-                if ( delivery_count >= messages )
-                {
-                  fprintf ( output_fp, "precv_stop %.3lf\n", get_time() );
-                  goto all_done;
-                }
-
-                // Make a report frequency of zero shut down interim reporting.
-                if ( report_frequency
-                     &&
-                     (! (delivery_count % report_frequency))
-                   )
-                {
-                  this_time = get_time();
-                  time_diff = this_time - last_time;
-
-                  print_timestamp_like_a_normal_person ( output_fp );
-                  fprintf ( output_fp, 
-                            "deliveries: %" PRIu64 "  time: %.3lf\n", 
-                            delivery_count,
-                            time_diff
-                          );
-                  fflush ( output_fp );
-                  last_time = this_time;
-                }
-
-                /*----------------------------------------------------------
-                  I replenish the credit whevere it falls below this limit
-                  because I this psend / precv pair of programs to run as
-                  fast as possible.  A real application might want to do
-                  something fancier here.
-                ----------------------------------------------------------*/
-                if ( credit <= flow_increment )
-                {
-                  pn_link_flow ( link, flow_increment );
-                }
-              }
-            }
-          break;
-
-
-          case PN_TRANSPORT:
-            // not sure why I would care...
-          break;
-
-
-          default:
-            /*
-            fprintf ( output_fp, 
-                      "precv unhandled event: %s\n", 
-                      pn_event_type_name(event_type)
-                    );
-            */
-          break;
-        }
-
-        pn_collector_pop ( collector );
-        event = pn_collector_peek(collector);
-      }
-    }
-  }
-
-
-all_done:
-  pn_session_close ( session );
-  pn_connection_close ( connection );
-  fclose ( output_fp );
-  return 0;
-}
-
-
-
-
-


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


[44/48] qpid-proton git commit: NO-JIRA: cpp: fix clang c++11 compile error in url::impl

Posted by ac...@apache.org.
NO-JIRA: cpp: fix clang c++11 compile error in url::impl

url::impl had explict dtor (delete[] raw C char array) but no explict copy ctor.
Replaced raw char* with vector<char> and removed the explicit dtor.


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

Branch: refs/heads/go1
Commit: 8c306f2964a5f19898b258729393814646d3acb6
Parents: 6af49b8
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 23 11:24:11 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 23 11:24:11 2016 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/src/url.cpp | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8c306f29/proton-c/bindings/cpp/src/url.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/url.cpp b/proton-c/bindings/cpp/src/url.cpp
index 1aa01e1..867f605 100644
--- a/proton-c/bindings/cpp/src/url.cpp
+++ b/proton-c/bindings/cpp/src/url.cpp
@@ -29,6 +29,7 @@
 #include <cstring>
 #include <iomanip>
 #include <sstream>
+#include <vector>
 
 namespace {
 
@@ -156,20 +157,15 @@ struct url::impl {
     const char* host;
     const char* port;
     const char* path;
-    char* cstr;
+    std::vector<char> cstr;
     mutable std::string str;
 
     impl(const std::string& s) :
-      scheme(0), username(0), password(0), host(0), port(0), path(0),
-      cstr(new char[s.size()+1])
+        scheme(0), username(0), password(0), host(0), port(0), path(0),
+        cstr(s.size()+1, '\0')
     {
-        std::strncpy(cstr, s.c_str(), s.size());
-        cstr[s.size()] = 0;
-        parse_url(cstr, &scheme, &username, &password, &host, &port, &path);
-    }
-
-    ~impl() {
-        delete [] cstr;
+        std::copy(s.begin(), s.end(), cstr.begin());
+        parse_url(&cstr[0], &scheme, &username, &password, &host, &port, &path);
     }
 
     void defaults() {


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


[11/48] 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 ac...@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


[34/48] qpid-proton git commit: PROTON-1344: proactor timeout support

Posted by ac...@apache.org.
PROTON-1344: proactor timeout support


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

Branch: refs/heads/go1
Commit: f2c8a3a38439c12d52dd93aed9173280c5754c9e
Parents: 25706a4
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 16 23:59:24 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Nov 17 11:22:50 2016 -0500

----------------------------------------------------------------------
 examples/c/proactor/libuv_proactor.c | 36 +++++++++++++++++++-
 examples/c/proactor/send.c           | 55 +++++++++++++++++++++++--------
 examples/c/proactor/test.py          |  8 +++++
 3 files changed, 84 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2c8a3a3/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
index 35afd5c..a26c311 100644
--- a/examples/c/proactor/libuv_proactor.c
+++ b/examples/c/proactor/libuv_proactor.c
@@ -157,6 +157,7 @@ struct pn_proactor_t {
   uv_cond_t cond;
   uv_loop_t loop;
   uv_async_t async;
+  uv_timer_t timer;
 
   /* Owner thread: proactor collector and batch can belong to leader or a worker */
   pn_collector_t *collector;
@@ -168,8 +169,11 @@ struct pn_proactor_t {
   queue worker_q;
   queue leader_q;
   size_t interrupt;             /* pending interrupts */
+  pn_millis_t timeout;
   size_t count;                 /* psocket count */
   bool inactive:1;
+  bool timeout_request:1;
+  bool timeout_elapsed:1;
   bool has_leader:1;
   bool batch_working:1;          /* batch belongs to a worker.  */
 };
@@ -551,6 +555,13 @@ static void on_write(uv_write_t* write, int err) {
   pc->writing = 0;              /* Need to send a new write request */
 }
 
+static void on_timeout(uv_timer_t *timer) {
+  pn_proactor_t *p = (pn_proactor_t*)timer->data;
+  uv_mutex_lock(&p->lock);
+  p->timeout_elapsed = true;
+  uv_mutex_unlock(&p->lock);
+}
+
 // Read buffer allocation function for uv, just returns the transports read buffer.
 static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
   pconnection_t *pc = (pconnection_t*)stream->data;
@@ -587,6 +598,7 @@ static void leader_rewatch(psocket_t *ps) {
   }
 }
 
+/* Set the event in the proactor's batch  */
 static pn_event_batch_t *proactor_batch_lh(pn_proactor_t *p, pn_event_type_t t) {
   pn_collector_put(p->collector, pn_proactor__class(), p, t);
   p->batch_working = true;
@@ -604,6 +616,10 @@ static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
       --p->interrupt;
       return proactor_batch_lh(p, PN_PROACTOR_INTERRUPT);
     }
+    if (p->timeout_elapsed) {
+      p->timeout_elapsed = false;
+      return proactor_batch_lh(p, PN_PROACTOR_TIMEOUT);
+    }
   }
   for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
     if (ps->is_conn) {
@@ -676,6 +692,14 @@ pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
     /* Lead till there is work to do. */
     p->has_leader = true;
     while (batch == NULL) {
+      if (p->timeout_request) {
+        p->timeout_request = false;
+        if (p->timeout) {
+          uv_timer_start(&p->timer, on_timeout, p->timeout, 0);
+        } else {
+          uv_timer_stop(&p->timer);
+        }
+      }
       for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
         void (*action)(psocket_t*) = ps->action;
         void (*wakeup)(psocket_t*) = ps->wakeup;
@@ -710,6 +734,14 @@ void pn_proactor_interrupt(pn_proactor_t *p) {
   uv_mutex_unlock(&p->lock);
 }
 
+void pn_proactor_set_timeout(pn_proactor_t *p, pn_millis_t t) {
+  uv_mutex_lock(&p->lock);
+  p->timeout = t;
+  p->timeout_request = true;
+  uv_async_send(&p->async);   /* Interrupt the UV loop */
+  uv_mutex_unlock(&p->lock);
+}
+
 int pn_proactor_connect(pn_proactor_t *p, const char *host, const char *port, pn_bytes_t extra) {
   pconnection_t *pc = new_pconnection_t(p, false, host, port, extra);
   if (!pc) {
@@ -765,7 +797,9 @@ pn_proactor_t *pn_proactor() {
   uv_loop_init(&p->loop);
   uv_mutex_init(&p->lock);
   uv_cond_init(&p->cond);
-  uv_async_init(&p->loop, &p->async, NULL); /* Just wake the loop */
+  uv_async_init(&p->loop, &p->async, NULL);
+  uv_timer_init(&p->loop, &p->timer); /* Just wake the loop */
+  p->timer.data = p;
   return p;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2c8a3a3/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index d64ea2d..42facb0 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -44,6 +44,9 @@ typedef struct app_data_t {
   int sent;
   int acknowledged;
   pn_proactor_t *proactor;
+  pn_millis_t delay;
+  bool delaying;
+  pn_link_t *sender;
   bool finished;
 } app_data_t;
 
@@ -91,6 +94,23 @@ static pn_bytes_t encode_message(app_data_t* app) {
   return pn_bytes(mbuf.size, mbuf.start);
 }
 
+static void send(app_data_t* app) {
+  while (pn_link_credit(app->sender) > 0 && app->sent < app->message_count) {
+    ++app->sent;
+    // Use sent counter bytes as unique delivery tag.
+    pn_delivery(app->sender, pn_dtag((const char *)&app->sent, sizeof(app->sent)));
+    pn_bytes_t msgbuf = encode_message(app);
+    pn_link_send(app->sender, msgbuf.start, msgbuf.size);
+    pn_link_advance(app->sender);
+    if (app->delay && app->sent < app->message_count) {
+      /* If delay is set, wait for TIMEOUT event to send more */
+      app->delaying = true;
+      pn_proactor_set_timeout(app->proactor, app->delay);
+      break;
+    }
+  }
+}
+
 static void handle(app_data_t* app, pn_event_t* event) {
   switch (pn_event_type(event)) {
 
@@ -105,18 +125,24 @@ static void handle(app_data_t* app, pn_event_t* event) {
      pn_link_open(l);
    } break;
 
-   case PN_LINK_FLOW: {
-     /* The peer has given us some credit, now we can send messages */
-     pn_link_t *sender = pn_event_link(event);
-     while (pn_link_credit(sender) > 0 && app->sent < app->message_count) {
-       ++app->sent;
-       // Use sent counter bytes as unique delivery tag.
-       pn_delivery(sender, pn_dtag((const char *)&app->sent, sizeof(app->sent)));
-       pn_bytes_t msgbuf = encode_message(app);
-       pn_link_send(sender, msgbuf.start, msgbuf.size);
-       pn_link_advance(sender);
-     }
-   } break;
+   case PN_LINK_FLOW:
+    /* The peer has given us some credit, now we can send messages */
+    if (!app->delaying) {
+      app->sender = pn_event_link(event);
+      send(app);
+    }
+    break;
+
+   case PN_PROACTOR_TIMEOUT:
+    /* Wake the sender's connection */
+    pn_connection_wake(pn_session_connection(pn_link_session(app->sender)));
+    break;
+
+   case PN_CONNECTION_WAKE:
+    /* Timeout, we can send more. */
+    app->delaying = false;
+    send(app);
+    break;
 
    case PN_DELIVERY: {
      /* We received acknowledgedment from the peer that a message was delivered. */
@@ -158,7 +184,7 @@ static void handle(app_data_t* app, pn_event_t* event) {
 }
 
 static void usage(const char *arg0) {
-  fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
+  fprintf(stderr, "Usage: %s [-a url] [-m message-count] [-d delay-ms]\n", arg0);
   exit(1);
 }
 
@@ -169,10 +195,11 @@ int main(int argc, char **argv) {
   const char* urlstr = NULL;
 
   int opt;
-  while((opt = getopt(argc, argv, "a:m:")) != -1) {
+  while((opt = getopt(argc, argv, "a:m:d:")) != -1) {
     switch(opt) {
      case 'a': urlstr = optarg; break;
      case 'm': app.message_count = atoi(optarg); break;
+     case 'd': app.delay = atoi(optarg); break;
      default: usage(argv[0]); break;
     }
   }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2c8a3a3/examples/c/proactor/test.py
----------------------------------------------------------------------
diff --git a/examples/c/proactor/test.py b/examples/c/proactor/test.py
index 5dc3a99..a86425d 100644
--- a/examples/c/proactor/test.py
+++ b/examples/c/proactor/test.py
@@ -48,5 +48,13 @@ class CExampleTest(BrokerTestCase):
         self.assertEqual("100 messages sent and acknowledged\n", s.wait_out())
         self.assertEqual(receive_expect(100), r.wait_out())
 
+    def test_timed_send(self):
+        """Send with timed delay"""
+        s = self.proc(["libuv_send", "-a", self.addr, "-d100", "-m3"])
+        self.assertEqual("3 messages sent and acknowledged\n", s.wait_out())
+        r = self.proc(["libuv_receive", "-a", self.addr, "-m3"])
+        self.assertEqual(receive_expect(3), r.wait_out())
+
+
 if __name__ == "__main__":
     unittest.main()


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


[05/48] 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 ac...@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


[29/48] qpid-proton git commit: PROTON-1344: C proactor for multi-threaded proton applications

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/tools/cmake/Modules/FindLibuv.cmake
----------------------------------------------------------------------
diff --git a/tools/cmake/Modules/FindLibuv.cmake b/tools/cmake/Modules/FindLibuv.cmake
new file mode 100644
index 0000000..ae3ab70
--- /dev/null
+++ b/tools/cmake/Modules/FindLibuv.cmake
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+# Find libuv include dirs and libraries.
+#
+# Sets the following variables:
+#
+#   Libuv_FOUND            - True if headers and requested libraries were found
+#   Libuv_INCLUDE_DIRS     - Libuv include directories
+#   Libuv_LIBRARIES        - Link these to use libuv.
+#
+# This module reads hints about search locations from variables::
+#   LIBUV_ROOT             - Preferred installation prefix
+#   LIBUV_INCLUDEDIR       - Preferred include directory e.g. <prefix>/include
+#   LIBUV_LIBRARYDIR       - Preferred library directory e.g. <prefix>/lib
+
+find_library(Libuv_LIBRARIES Names uv libuv HINTS ${LIBUV_LIBRARYDIR} ${LIBUV_ROOT})
+find_path(Libuv_INCLUDE_DIRS NAMES uv.h HINTS ${LIBUV_INCLUDEDIR} ${LIBUV_ROOT} ${LIBUV_ROOT}/include ${CMAKE_INSTALL_PREFIX}/include PATHS /usr/include)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libuv DEFAULT_MSG Libuv_LIBRARIES Libuv_INCLUDE_DIRS)


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


[32/48] qpid-proton git commit: PROTON-1344: proactor batch events, rename connection_driver

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/src/io/connection_engine.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_engine.cpp b/proton-c/bindings/cpp/src/io/connection_engine.cpp
deleted file mode 100644
index 5e6483f..0000000
--- a/proton-c/bindings/cpp/src/io/connection_engine.cpp
+++ /dev/null
@@ -1,160 +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/connection_engine.hpp"
-
-#include "proton/event_loop.hpp"
-#include "proton/error.hpp"
-#include "proton/messaging_handler.hpp"
-#include "proton/uuid.hpp"
-
-#include "contexts.hpp"
-#include "messaging_adapter.hpp"
-#include "msg.hpp"
-#include "proton_bits.hpp"
-#include "proton_event.hpp"
-
-#include <proton/connection.h>
-#include <proton/transport.h>
-#include <proton/event.h>
-
-#include <algorithm>
-
-
-namespace proton {
-namespace io {
-
-void connection_engine::init() {
-    if (pn_connection_engine_init(&engine_, pn_connection(), pn_transport()) != 0) {
-        this->~connection_engine(); // Dtor won't be called on throw from ctor.
-        throw proton::error(std::string("connection_engine allocation failed"));
-    }
-}
-
-connection_engine::connection_engine() : handler_(0), container_(0) { init(); }
-
-connection_engine::connection_engine(class container& cont, event_loop* loop) : handler_(0), container_(&cont) {
-    init();
-    connection_context& ctx = connection_context::get(connection());
-    ctx.container = container_;
-    ctx.event_loop.reset(loop);
-}
-
-connection_engine::~connection_engine() {
-    pn_connection_engine_destroy(&engine_);
-}
-
-void connection_engine::configure(const connection_options& opts, bool server) {
-    proton::connection c(connection());
-    opts.apply_unbound(c);
-    if (server) pn_transport_set_server(engine_.transport);
-    pn_connection_engine_bind(&engine_);
-    opts.apply_bound(c);
-    handler_ =  opts.handler();
-    connection_context::get(connection()).collector = engine_.collector;
-}
-
-void connection_engine::connect(const connection_options& opts) {
-    connection_options all;
-    if (container_) {
-        all.container_id(container_->id());
-        all.update(container_->client_connection_options());
-    }
-    all.update(opts);
-    configure(all, false);
-    connection().open();
-}
-
-void connection_engine::accept(const connection_options& opts) {
-    connection_options all;
-    if (container_) {
-        all.container_id(container_->id());
-        all.update(container_->server_connection_options());
-    }
-    all.update(opts);
-    configure(all, true);
-}
-
-bool connection_engine::dispatch() {
-    pn_event_t* c_event;
-    while ((c_event = pn_connection_engine_event(&engine_)) != NULL) {
-        proton_event cpp_event(c_event, container_);
-        try {
-            if (handler_ != 0) {
-                messaging_adapter adapter(*handler_);
-                cpp_event.dispatch(adapter);
-            }
-        } catch (const std::exception& e) {
-            pn_condition_t *cond = pn_transport_condition(engine_.transport);
-            if (!pn_condition_is_set(cond)) {
-                pn_condition_format(cond, "exception", "%s", e.what());
-            }
-        }
-        pn_connection_engine_pop_event(&engine_);
-    }
-    return !pn_connection_engine_finished(&engine_);
-}
-
-mutable_buffer connection_engine::read_buffer() {
-    pn_rwbytes_t buffer = pn_connection_engine_read_buffer(&engine_);
-    return mutable_buffer(buffer.start, buffer.size);
-}
-
-void connection_engine::read_done(size_t n) {
-    return pn_connection_engine_read_done(&engine_, n);
-}
-
-void connection_engine::read_close() {
-    pn_connection_engine_read_close(&engine_);
-}
-
-const_buffer connection_engine::write_buffer() {
-    pn_bytes_t buffer = pn_connection_engine_write_buffer(&engine_);
-    return const_buffer(buffer.start, buffer.size);
-}
-
-void connection_engine::write_done(size_t n) {
-    return pn_connection_engine_write_done(&engine_, n);
-}
-
-void connection_engine::write_close() {
-    pn_connection_engine_write_close(&engine_);
-}
-
-void connection_engine::disconnected(const proton::error_condition& err) {
-    pn_condition_t* condition = pn_transport_condition(engine_.transport);
-    if (!pn_condition_is_set(condition))  {
-        set_error_condition(err, condition);
-    }
-    pn_connection_engine_close(&engine_);
-}
-
-proton::connection connection_engine::connection() const {
-    return make_wrapper(engine_.connection);
-}
-
-proton::transport connection_engine::transport() const {
-    return make_wrapper(engine_.transport);
-}
-
-proton::container* connection_engine::container() const {
-    return container_;
-}
-
-}}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/src/receiver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/receiver.cpp b/proton-c/bindings/cpp/src/receiver.cpp
index b84722c..e5ec55a 100644
--- a/proton-c/bindings/cpp/src/receiver.cpp
+++ b/proton-c/bindings/cpp/src/receiver.cpp
@@ -74,7 +74,7 @@ void receiver::drain() {
             // Create dummy flow event where "drain finish" can be detected.
             pn_connection_t *pnc = pn_session_connection(pn_link_session(pn_object()));
             connection_context& cctx = connection_context::get(pnc);
-            // connection_engine collector is per connection.  Reactor collector is global.
+            // connection_driver collector is per connection.  Reactor collector is global.
             pn_collector_t *coll = cctx.collector;
             if (!coll)
                 coll = pn_reactor_collector(pn_object_reactor(pnc));

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/src/thread_safe_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/thread_safe_test.cpp b/proton-c/bindings/cpp/src/thread_safe_test.cpp
index f8dc3d8..5b5d487 100644
--- a/proton-c/bindings/cpp/src/thread_safe_test.cpp
+++ b/proton-c/bindings/cpp/src/thread_safe_test.cpp
@@ -24,7 +24,7 @@
 #include "proton_bits.hpp"
 
 #include "proton/thread_safe.hpp"
-#include "proton/io/connection_engine.hpp"
+#include "proton/io/connection_driver.hpp"
 
 #include <proton/connection.h>
 
@@ -37,7 +37,7 @@ void test_new() {
     pn_connection_t* c = 0;
     thread_safe<connection>* p = 0;
     {
-        io::connection_engine e;
+        io::connection_driver e;
         c = unwrap(e.connection());
         int r = pn_refcount(c);
         ASSERT(r >= 1); // engine may have internal refs (transport, collector).
@@ -54,7 +54,7 @@ void test_new() {
     {
         std::shared_ptr<thread_safe<connection> > sp;
         {
-            io::connection_engine e;
+            io::connection_driver e;
             c = unwrap(e.connection());
             sp = make_shared_thread_safe(e.connection());
         }
@@ -63,7 +63,7 @@ void test_new() {
     {
         std::unique_ptr<thread_safe<connection> > up;
         {
-            io::connection_engine e;
+            io::connection_driver e;
             c = unwrap(e.connection());
             up = make_unique_thread_safe(e.connection());
         }
@@ -78,7 +78,7 @@ void test_convert() {
     connection c;
     pn_connection_t* pc = 0;
     {
-        io::connection_engine eng;
+        io::connection_driver eng;
         c = eng.connection();
         pc = unwrap(c);         // Unwrap in separate scope to avoid confusion from temp values.
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/docs/api/index.md
----------------------------------------------------------------------
diff --git a/proton-c/docs/api/index.md b/proton-c/docs/api/index.md
index ccd679d..9c6009f 100644
--- a/proton-c/docs/api/index.md
+++ b/proton-c/docs/api/index.md
@@ -5,35 +5,31 @@ Proton Documentation            {#index}
 
 The [Engine API](@ref engine) is a "pure AMQP" toolkit, it decodes AMQP bytes
 into proton [events](@ref event) and generates AMQP bytes from application
-calls.
+calls. There is no IO or threading code in this part of the library.
 
-The [connection engine](@ref connection_engine) provides a simple bytes in/bytes
-out, event-driven interface so you can read AMQP data from any source, process
-the resulting [events](@ref event) and write AMQP output to any destination.
+## Proactive event-driven programming
 
-There is no IO or threading code in this part of the library, so it can be
-embedded in many different environments. The proton project provides language
-bindings (Python, Ruby, Go etc.) that embed it into the standard IO and
-threading facilities of the bound language.
+The [Proactor API](@ref proactor) is a pro-active, asynchronous framework to
+build single or multi-threaded Proton C applications. It manages the IO
+transport layer so you can write portable, event-driven AMQP code using the @ref
+engine API.
 
-## Integrating with IO
+## IO Integration
 
-The [Proactor API](@ref proactor) is a pro-active, asynchronous framewokr to
-build single or multi-threaded Proton C applications.
+The [connection driver](@ref connection_driver) provides a simple bytes in/bytes
+out, event-driven interface so you can read AMQP data from any source, process
+the resulting [events](@ref event) and write AMQP output to any destination. It
+lets you use proton in in alternate event loops, or for specialized embedded
+applications.
 
-For advanced use-cases it is possible to write your own implementation of the
-proactor API for an unusual IO or threading framework. Any proton application
+It is also possible to write your own implementation of the @ref proactor if you
+are dealing with an unusual IO or threading framework. Any proton application
 written to the proactor API will be able to use your implementation.
 
-## Messenger and Reactor APIs
-
-The [Messenger](@ref messenger) [Reactor](@ref reactor) APIs were intended
-to be simple APIs that included IO support directly out of the box.
+## Messenger and Reactor APIs (deprecated)
 
-They both had good points but were both based on the assumption of a single-threaded
-environment using a POSIX-like poll() call. This was a problem for performance on some
-platforms and did not support multi-threaded applications.
+The [Messenger](@ref messenger) [Reactor](@ref reactor) APIs are older APIs
+that were limited to single-threaded applications.
 
-Note however that application code which interacts with the AMQP @ref engine and
-processes AMQP @ref "events" event is the same for the proactor and reactor APIs,
-so is quite easy to convert. The main difference is in how connections are set up.
+Existing @ref reactor applications can be converted easily to use the @ref proactor,
+since they share the same @engine API and @ref event set.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/include/proton/connection.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection.h b/proton-c/include/proton/connection.h
index 0ed23b0..70fad73 100644
--- a/proton-c/include/proton/connection.h
+++ b/proton-c/include/proton/connection.h
@@ -38,7 +38,7 @@ extern "C" {
 /**
  * @file
  *
- * Connection API for the proton Engine.
+ * Connection API for the proton @ref engine
  *
  * @defgroup connection Connection
  * @ingroup engine

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/include/proton/connection_driver.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection_driver.h b/proton-c/include/proton/connection_driver.h
new file mode 100644
index 0000000..4fa3fb9
--- /dev/null
+++ b/proton-c/include/proton/connection_driver.h
@@ -0,0 +1,243 @@
+#ifndef PROTON_CONNECTION_DRIVER_H
+#define PROTON_CONNECTION_DRIVER_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @file
+ *
+ * @defgroup connection_driver Connection Driver
+ *
+ * **Experimental**: Toolkit for integrating proton with arbitrary network or IO
+ * transports. Provides a single point of control for an AMQP connection and
+ * a simple bytes-in/bytes-out interface that lets you:
+ *
+ * - process AMQP-encoded bytes from some input byte stream
+ * - generate ::pn_event_t events for your application to handle
+ * - encode resulting AMQP output bytes for some output byte stream
+ *
+ * The pn_connection_driver_() functions provide a simplified API and extra
+ * logic to use ::pn_connection_t and ::pn_transport_t as a unit.  You can also
+ * access them directly for features that are not exposed via the @ref
+ * connection_driver API.
+ *
+ * The engine buffers events and data, you should run it until
+ * pn_connection_driver_finished() is true, to ensure all reading, writing and
+ * event handling (including ERROR and FINAL events) is finished.
+ *
+ * ## Error handling
+ *
+ * The pn_connection_driver_*() functions do not return an error code. IO errors set
+ * the transport condition and are returned as a PN_TRANSPORT_ERROR. The integration
+ * code can set errors using pn_connection_driver_errorf()
+ *
+ * ## IO patterns
+ *
+ * This API supports asynchronous, proactive, non-blocking and reactive IO. An
+ * integration does not have to follow the dispatch-read-write sequence above,
+ * but note that you should handle all available events before calling
+ * pn_connection_driver_read_buffer() and check that `size` is non-zero before
+ * starting a blocking or asynchronous read call. A `read` started while there
+ * are unprocessed CLOSE events in the buffer may never complete.
+ *
+ * AMQP is a full-duplex, asynchronous protocol. The "read" and "write" sides of
+ * an AMQP connection can close separately
+ *
+ * ## Thread safety
+ *
+ * The @ref engine types are not thread safe, but each connection and its
+ * associated types forms an independent unit. Different connections can be
+ * processed concurrently by different threads.
+ *
+ * @{
+ */
+
+#include <proton/import_export.h>
+#include <proton/event.h>
+#include <proton/types.h>
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Struct containing the 3 elements needed to driver AMQP IO and events, aggregated as a unit.
+ */
+typedef struct pn_connection_driver_t {
+  pn_connection_t *connection;
+  pn_transport_t *transport;
+  pn_event_batch_t batch;
+} pn_connection_driver_t;
+
+/**
+ * Set #connection and #transport to the provided values, or create a new
+ * @ref pn_connection_t or @ref pn_transport_t if either is NULL.
+ * The provided values belong to the connection driver and will be freed by
+ * pn_connection_driver_destroy()
+ *
+ * The transport is bound automatically after the PN_CONNECTION_INIT has been is
+ * handled by the application. It can be bound earlier with
+ * pn_connection_driver_bind().
+ *
+ * The following functions must be called before the transport is
+ * bound to have effect: pn_connection_set_username(), pn_connection_set_password(),
+ * pn_transport_set_server()
+ *
+ * @return PN_OUT_OF_MEMORY if any allocation fails.
+ */
+PN_EXTERN int pn_connection_driver_init(pn_connection_driver_t*, pn_connection_t*, pn_transport_t*);
+
+/** Force binding of the transport.
+ * This happens automatically after the PN_CONNECTION_INIT is processed.
+ *
+ * @return PN_STATE_ERR if the transport is already bound.
+ */
+PN_EXTERN int pn_connection_driver_bind(pn_connection_driver_t *d);
+
+/**
+ * Unbind, release and free #connection and #transport. Set all pointers to
+ * NULL.  Does not free the @ref pn_connection_driver_t struct itself.
+ */
+PN_EXTERN void pn_connection_driver_destroy(pn_connection_driver_t *);
+
+/**
+ * Get the read buffer.
+ *
+ * Copy data from your input byte source to buf.start, up to buf.size.
+ * Call pn_connection_driver_read_done() when reading is complete.
+ *
+ * buf.size==0 means reading is not possible: no buffer space or the read side is closed.
+ */
+PN_EXTERN pn_rwbytes_t pn_connection_driver_read_buffer(pn_connection_driver_t *);
+
+/**
+ * Process the first n bytes of data in pn_connection_driver_read_buffer() and
+ * reclaim the buffer space.
+ */
+PN_EXTERN void pn_connection_driver_read_done(pn_connection_driver_t *, size_t n);
+
+/**
+ * Close the read side. Call when the IO can no longer be read.
+ */
+PN_EXTERN void pn_connection_driver_read_close(pn_connection_driver_t *);
+
+/**
+ * True if read side is closed.
+ */
+PN_EXTERN bool pn_connection_driver_read_closed(pn_connection_driver_t *);
+
+/**
+ * Get the write buffer.
+ *
+ * Write data from buf.start to your IO destination, up to a max of buf.size.
+ * Call pn_connection_driver_write_done() when writing is complete.
+ *
+ * buf.size==0 means there is nothing to write.
+ */
+ PN_EXTERN pn_bytes_t pn_connection_driver_write_buffer(pn_connection_driver_t *);
+
+/**
+ * Call when the first n bytes of pn_connection_driver_write_buffer() have been
+ * written to IO. Reclaims the buffer space and reset the write buffer.
+ */
+PN_EXTERN void pn_connection_driver_write_done(pn_connection_driver_t *, size_t n);
+
+/**
+ * Close the write side. Call when IO can no longer be written to.
+ */
+PN_EXTERN void pn_connection_driver_write_close(pn_connection_driver_t *);
+
+/**
+ * True if write side is closed.
+ */
+PN_EXTERN bool pn_connection_driver_write_closed(pn_connection_driver_t *);
+
+/**
+ * Close both sides side.
+ */
+PN_EXTERN void pn_connection_driver_close(pn_connection_driver_t * c);
+
+/**
+ * Get the next event to handle.
+ *
+ * @return pointer is valid till the next call of
+ * pn_connection_driver_next(). NULL if there are no more events available now,
+ * reading/writing may produce more.
+ */
+PN_EXTERN pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *);
+
+/**
+ * True if  pn_connection_driver_next_event() will return a non-NULL event.
+ */
+PN_EXTERN bool pn_connection_driver_has_event(pn_connection_driver_t *);
+
+/**
+ * Return true if the the engine is closed for reading and writing and there are
+ * no more events.
+ *
+ * Call pn_connection_driver_free() to free all related memory.
+ */
+PN_EXTERN bool pn_connection_driver_finished(pn_connection_driver_t *);
+
+/**
+ * Set IO error information.
+ *
+ * The name and formatted description are set on the transport condition, and
+ * returned as a PN_TRANSPORT_ERROR event from pn_connection_driver_next_event().
+ *
+ * You must call this *before* pn_connection_driver_read_close() or
+ * pn_connection_driver_write_close() to ensure the error is processed.
+ */
+PN_EXTERN void pn_connection_driver_errorf(pn_connection_driver_t *d, const char *name, const char *fmt, ...);
+
+/**
+ * Set IO error information via a va_list, see pn_connection_driver_errorf()
+ */
+PN_EXTERN void pn_connection_driver_verrorf(pn_connection_driver_t *d, const char *name, const char *fmt, va_list);
+
+/**
+ * Log a string message using the connection's transport log.
+ */
+PN_EXTERN void pn_connection_driver_log(pn_connection_driver_t *d, const char *msg);
+
+/**
+ * Log a printf formatted message using the connection's transport log.
+ */
+PN_EXTERN void pn_connection_driver_logf(pn_connection_driver_t *d, char *fmt, ...);
+
+/**
+ * Log a printf formatted message using the connection's transport log.
+ */
+PN_EXTERN void pn_connection_driver_vlogf(pn_connection_driver_t *d, const char *fmt, va_list ap);
+
+/**
+ * If batch is part of a connection_driver, return the connection_driver address,
+ * else return NULL
+ */
+PN_EXTERN pn_connection_driver_t* pn_event_batch_connection_driver(pn_event_batch_t *batch);
+///@}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PROTON_CONNECTION_DRIVER_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/include/proton/connection_engine.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection_engine.h b/proton-c/include/proton/connection_engine.h
deleted file mode 100644
index b7022a9..0000000
--- a/proton-c/include/proton/connection_engine.h
+++ /dev/null
@@ -1,313 +0,0 @@
-#ifndef PROTON_CONNECTION_ENGINE_H
-#define PROTON_CONNECTION_ENGINE_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
- *
- * **Experimental** The connection IO API is a set of functions to simplify
- * integrating proton with different IO and concurrency platforms. The portable
- * parts of a Proton application should use the @ref engine types.  We will
- * use "application" to mean the portable part of the application and
- * "integration" to mean code that integrates with a particular IO platform.
- *
- * The connection_engine functions take a @ref pn_connection_t\*, and perform common
- * tasks involving the @ref pn_connection_t and it's @ref pn_transport_t and
- * @ref pn_collector_t so you can treat them as a unit. You can also work with
- * these types directly for features not available via @ref connection_engine API.
- *
- * @defgroup connection_engine Connection Engine
- *
- * **Experimental**: Toolkit for integrating proton with arbitrary network or IO
- * transports. Provides a single point of control for an AMQP connection and
- * a simple bytes-in/bytes-out interface that lets you:
- *
- * - process AMQP-encoded bytes from some input byte stream
- * - generate @ref pn_event_t events for your application to handle
- * - encode resulting AMQP output bytes for some output byte stream
- *
- * The engine contains a @ref pn_connection_t, @ref pn_transport_t and @ref
- * pn_collector_t and provides functions to operate on all three as a unit for
- * IO integration. You can also use them directly for anything not covered by
- * this API
- *
- * For example a simple blocking IO integration with the imaginary "my_io" library:
- *
- *     pn_connection_engine_t ce;
- *     pn_connection_engine_init(&ce);
- *     while (!pn_connection_engine_finished(&ce) {
- *         // Dispatch events to be handled by the application.
- *         pn_event_t *e;
- *         while ((e = pn_connection_engine_event(&ce))!= NULL) {
- *             my_app_handle(e); // Pass to the application handler
- *             switch (pn_event_type(e)) {
- *                 case PN_CONNECTION_INIT: pn_connection_engine_bind(&ce);
- *                 // Only for full-duplex IO where read/write can shutdown separately.
- *                 case PN_TRANSPORT_CLOSE_READ: my_io_shutdown_read(...); break;
- *                 case PN_TRANSPORT_CLOSE_WRITE: my_io_shutdown_write(...); break;
- *                 default: break;
- *             };
- *             e = pn_connection_engine_pop_event(&ce);
- *         }
- *         // Read from my_io into the connection buffer
- *         pn_rwbytes_t readbuf = pn_connection_engine_read_buffer(&ce);
- *         if (readbuf.size) {
- *             size_t n = my_io_read(readbuf.start, readbuf.size, ...);
- *             if (n > 0) {
- *                 pn_connection_engine_read_done(&ce, n);
- *             } else if (n < 0) {
- *                 pn_connection_engine_errorf(&ce, "read-err", "something-bad (%d): %s", n, ...);
- *                 pn_connection_engine_read_close(&ce);
- *             }
- *         }
- *         // Write from connection buffer to my_io
- *         pn_bytes_t writebuf = pn_connection_engine_write_buffer(&ce);
- *         if (writebuf.size) {
- *             size_t n = my_io_write_data(writebuf.start, writebuf.size, ...);
- *             if (n < 0) {
- *                 pn_connection_engine_errorf(&ce, "write-err", "something-bad (%d): %s", d, ...);
- *                 pn_connection_engine_write_close(&ce);
- *             } else {
- *                 pn_connection_engine_write_done(&ce, n);
- *             }
- *         }
- *     }
- *     // If my_io doesn't have separate read/write shutdown, then we should close it now.
- *     my_io_close(...);
- *
- * AMQP is a full-duplex, asynchronous protocol. The "read" and "write" sides of
- * an AMQP connection can close separately, the example shows how to handle this
- * for full-duplex IO or IO with a simple close.
- *
- * The engine buffers events, you must keep processing till
- * pn_connection_engine_finished() is true, to ensure all reading, writing and event
- * handling (including ERROR and FINAL events) is completely finished.
- *
- * ## Error handling
- *
- * The pn_connection_engine_*() functions do not return an error code. IO errors set
- * the transport condition and are returned as a PN_TRANSPORT_ERROR. The integration
- * code can set errors using pn_connection_engine_errorf()
- *
- * ## Other IO patterns
- *
- * This API supports asynchronous, proactive, non-blocking and reactive IO. An
- * integration does not have to follow the dispatch-read-write sequence above,
- * but note that you should handle all available events before calling
- * pn_connection_engine_read_buffer() and check that `size` is non-zero before
- * starting a blocking or asynchronous read call. A `read` started while there
- * are unprocessed CLOSE events in the buffer may never complete.
- *
- * ## Thread safety
- *
- * The @ref engine types are not thread safe, but each connection and its
- * associated types forms an independent unit. Different connections can be
- * processed concurrently by different threads.
- *
- * @defgroup connection_engine Connection IO
- * @{
- */
-
-#include <proton/import_export.h>
-#include <proton/event.h>
-#include <proton/types.h>
-
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Struct containing a connection, transport and collector. See
- * pn_connection_engine_init(), pn_connection_engine_destroy() and pn_connection_engine()
- */
-typedef struct pn_connection_engine_t {
-  pn_connection_t *connection;
-  pn_transport_t *transport;
-  pn_collector_t *collector;
-} pn_connection_engine_t;
-
-/**
- * Set #connection and #transport to the provided values, or create a new
- * @ref pn_connection_t or @ref pn_transport_t if either is NULL.
- * The provided values belong to the connection engine and will be freed by
- * pn_connection_engine_destroy()
- *
- * Create a new @ref pn_collector_t and set as #collector.
- *
- * The transport and connection are *not* bound at this point. You should
- * configure them as needed and let the application handle the
- * PN_CONNECTION_INIT from pn_connection_engine_event() before calling
- * pn_connection_engine_bind().
- *
- * @return if any allocation fails call pn_connection_engine_destroy() and return PN_OUT_OF_MEMORY
- */
-PN_EXTERN int pn_connection_engine_init(pn_connection_engine_t*, pn_connection_t*, pn_transport_t*);
-
-/**
- * Bind the connection to the transport when the external IO is ready.
- *
- * The following functions (if called at all) must be called *before* bind:
- * pn_connection_set_username(), pn_connection_set_password(),  pn_transport_set_server()
- *
- * If there is an external IO error during setup, set a transport error, close
- * the transport and then bind. The error events are reported to the application
- * via pn_connection_engine_event().
- *
- * @return an error code if the bind fails.
- */
-PN_EXTERN int pn_connection_engine_bind(pn_connection_engine_t *);
-
-/**
- * Unbind, release and free #connection, #transpot and #collector. Set all pointers to NULL.
- * Does not free the @ref pn_connection_engine_t struct itself.
- */
-PN_EXTERN void pn_connection_engine_destroy(pn_connection_engine_t *);
-
-/**
- * Get the read buffer.
- *
- * Copy data from your input byte source to buf.start, up to buf.size.
- * Call pn_connection_engine_read_done() when reading is complete.
- *
- * buf.size==0 means reading is not possible: no buffer space or the read side is closed.
- */
-PN_EXTERN pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t *);
-
-/**
- * Process the first n bytes of data in pn_connection_engine_read_buffer() and
- * reclaim the buffer space.
- */
-PN_EXTERN void pn_connection_engine_read_done(pn_connection_engine_t *, size_t n);
-
-/**
- * Close the read side. Call when the IO can no longer be read.
- */
-PN_EXTERN void pn_connection_engine_read_close(pn_connection_engine_t *);
-
-/**
- * True if read side is closed.
- */
-PN_EXTERN bool pn_connection_engine_read_closed(pn_connection_engine_t *);
-
-/**
- * Get the write buffer.
- *
- * Write data from buf.start to your IO destination, up to a max of buf.size.
- * Call pn_connection_engine_write_done() when writing is complete.
- *
- * buf.size==0 means there is nothing to write.
- */
- PN_EXTERN pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t *);
-
-/**
- * Call when the first n bytes of pn_connection_engine_write_buffer() have been
- * written to IO. Reclaims the buffer space and reset the write buffer.
- */
-PN_EXTERN void pn_connection_engine_write_done(pn_connection_engine_t *, size_t n);
-
-/**
- * Close the write side. Call when IO can no longer be written to.
- */
-PN_EXTERN void pn_connection_engine_write_close(pn_connection_engine_t *);
-
-/**
- * True if write side is closed.
- */
-PN_EXTERN bool pn_connection_engine_write_closed(pn_connection_engine_t *);
-
-/**
- * Close both sides side.
- */
-PN_EXTERN void pn_connection_engine_close(pn_connection_engine_t * c);
-
-/**
- * Get the current event. Call pn_connection_engine_done() when done handling it.
- * Note that if PN_TRACE_EVT is enabled this will log the event, so you should
- * avoid calling it more than once per event. Use pn_connection_engine_has_event()
- * to silently test if any events are available.
- *
- * @return NULL if there are no more events ready. Reading/writing data may produce more.
- */
-PN_EXTERN pn_event_t* pn_connection_engine_event(pn_connection_engine_t *);
-
-/**
- * True if  pn_connection_engine_event() will return a non-NULL event.
- */
-PN_EXTERN bool pn_connection_engine_has_event(pn_connection_engine_t *);
-
-/**
- * Drop the current event, advance pn_connection_engine_event() to the next event.
- */
-PN_EXTERN void pn_connection_engine_pop_event(pn_connection_engine_t *);
-
-/**
- * Return true if the the engine is closed for reading and writing and there are
- * no more events.
- *
- * Call pn_connection_engine_free() to free all related memory.
- */
-PN_EXTERN bool pn_connection_engine_finished(pn_connection_engine_t *);
-
-/**
- * Set IO error information.
- *
- * The name and formatted description are set on the transport condition, and
- * returned as a PN_TRANSPORT_ERROR event from pn_connection_engine_event().
- *
- * You must call this *before* pn_connection_engine_read_close() or
- * pn_connection_engine_write_close() to ensure the error is processed.
- *
- * If there is already a transport condition set, this call does nothing.  For
- * more complex cases, you can work with the transport condition directly using:
- *
- *     pn_condition_t *cond = pn_transport_condition(pn_connection_transport(conn));
- */
-PN_EXTERN void pn_connection_engine_errorf(pn_connection_engine_t *ce, const char *name, const char *fmt, ...);
-
-/**
- * Set IO error information via a va_list, see pn_connection_engine_errorf()
- */
-PN_EXTERN void pn_connection_engine_verrorf(pn_connection_engine_t *ce, const char *name, const char *fmt, va_list);
-
-/**
- * Log a string message using the connection's transport log.
- */
-PN_EXTERN void pn_connection_engine_log(pn_connection_engine_t *ce, const char *msg);
-
-/**
- * Log a printf formatted message using the connection's transport log.
- */
-PN_EXTERN void pn_connection_engine_logf(pn_connection_engine_t *ce, char *fmt, ...);
-
-/**
- * Log a printf formatted message using the connection's transport log.
- */
-PN_EXTERN void pn_connection_engine_vlogf(pn_connection_engine_t *ce, const char *fmt, va_list ap);
-
-///@}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // PROTON_CONNECTION_ENGINE_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/include/proton/cproton.i
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cproton.i b/proton-c/include/proton/cproton.i
index ffcf830..931437e 100644
--- a/proton-c/include/proton/cproton.i
+++ b/proton-c/include/proton/cproton.i
@@ -39,6 +39,9 @@ typedef unsigned long int uintptr_t;
 %ignore pn_bytes_t;
 %ignore pn_rwbytes_t;
 
+/* pn_event_batch_t is not used directly by bindings */
+%ignore pn_event_batch_t;
+
 /* There is no need to wrap pn_class_t aa it is an internal implementation detail and cannot be used outside the library */
 %ignore pn_class_t;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index 4dca2d5..31d4bdd 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -428,6 +428,32 @@ PN_EXTERN pn_event_t *pn_collector_peek(pn_collector_t *collector);
 PN_EXTERN bool pn_collector_pop(pn_collector_t *collector);
 
 /**
+ * Return the next event to be handled.
+ *
+ * Returns the head event if it has not previously been returned by
+ * pn_collector_next(), otherwise does pn_collector_pop() and returns
+ * the new head event.
+ *
+ * The returned pointer is valid till the next call of pn_collector_pop(),
+ * pn_collector_next(), pn_collector_release() or pn_collector_free()
+ *
+ * @param[in] collector a collector object
+ * @return the next event.
+ */
+PN_EXTERN pn_event_t *pn_collector_next(pn_collector_t *collector);
+
+/**
+ * Return the same event as the previous call to pn_collector_next()
+ *
+ * The returned pointer is valid till the next call of pn_collector_pop(),
+ * pn_collector_next(), pn_collector_release() or pn_collector_free()
+ *
+ * @param[in] collector a collector object
+ * @return a pointer to the event returned by previous call to pn_collector_next()
+ */
+PN_EXTERN pn_event_t *pn_collector_prev(pn_collector_t *collector);
+
+/**
  * Check if there are more events after the current event. If this
  * returns true, then pn_collector_peek() will return an event even
  * after pn_collector_pop() is called.
@@ -506,6 +532,36 @@ PN_EXTERN pn_transport_t *pn_event_transport(pn_event_t *event);
  */
 PN_EXTERN pn_record_t *pn_event_attachments(pn_event_t *event);
 
+/**
+ * **Experimental**: A batch of events to handle. Call pn_event_batch_next() in
+ * a loop until it returns NULL to handle them.
+ */
+typedef struct pn_event_batch_t pn_event_batch_t;
+
+/* NOTE: there is deliberately no peek(), more() or other look-ahead on an event
+ * batch. We want to know exactly which events have been handled, next() only
+ * allows the user to get each event exactly once, in order.
+ */
+
+/**
+ * **Experimental**: Remove the next event from the batch and return it. NULL
+ *  means the batch is empty. The returned event pointer is valid until
+ *  pn_event_batch_next() is called again on the same batch.
+ */
+PN_EXTERN pn_event_t *pn_event_batch_next(pn_event_batch_t *batch);
+
+/**
+ *@cond INTERNAL
+ * pn_event_batch_next() can be re-implemented for different behaviors in different contextxs.
+ */
+struct pn_event_batch_t {
+  pn_event_t *(*next_event)(pn_event_batch_t *batch);
+};
+
+/**
+ *@endcond
+ */
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index 49d7b6a..e23a24f 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -33,30 +33,27 @@ typedef struct pn_condition_t pn_condition_t;
 /**
  * @file
  *
- * **Experimental**: Proactor API for the the proton @ref engine.
+ * **Experimental**: Proactor API for the the proton @ref engine
  *
  * @defgroup proactor Proactor
  *
  * **Experimental**: Proactor API for portable, multi-threaded, asynchronous applications.
  *
- * The proactor establishes and listens for connections. It creates the @ref
- * "transport" transport that sends and receives data over the network and
- * delivers @ref "events" event to application threads for processing.
+ * The proactor establishes and listens for connections. It creates
+ * the @ref transport that sends and receives data over the network and
+ * delivers @ref event to application threads for handling.
  *
- * ## Multi-threading
- *
- * The @ref proactor is thread-safe, but the @ref "protocol engine" is not.  The
- * proactor ensures that each @ref "connection" connection and its associated
- * values (@ref session, @ref link etc.) is processed sequentially, even if there
- * are multiple application threads. See pn_proactor_wait()
+ * **Multi-threading**:
+ * The @ref proactor is thread-safe, but the @ref engine is not.  The proactor
+ * ensures that each @ref connection and its associated values (@ref session,
+ * @ref link etc.) is handle sequentially, even if there are multiple
+ * application threads. See pn_proactor_wait()
  *
  * @{
  */
 
 /**
- * The proactor creates and manage @ref "transports" transport and delivers @ref
- * "event" events to the application.
- *
+ * The proactor.
  */
 typedef struct pn_proactor_t pn_proactor_t;
 
@@ -70,13 +67,6 @@ pn_proactor_t *pn_proactor(void);
  */
 void pn_proactor_free(pn_proactor_t*);
 
-/* FIXME aconway 2016-11-12: connect and listen need options to enable
-   things like websockets, alternate encryption or other features.
-   The "extra" parameter will be replaced by an "options" parameter
-   that will include providing extra data and other manipulators
-   to affect how the connection is processed.
-*/
-
 /**
  * Asynchronous connect: a connection and transport will be created, the
  * relevant events will be returned by pn_proactor_wait()
@@ -104,13 +94,27 @@ int pn_proactor_connect(pn_proactor_t*, const char *host, const char *port, pn_b
 pn_listener_t *pn_proactor_listen(pn_proactor_t *, const char *host, const char *port, int backlog, pn_bytes_t extra);
 
 /**
- * Wait for an event. Can be called in multiple threads concurrently.
- * You must call pn_event_done() when the event has been handled.
+ * Wait for events to handle. Call pn_proactor_done() after handling events.
+ *
+ * Thread safe: pn_proactor_wait() can be called concurrently, but the events in
+ * the returned ::pn_event_batch_t must be handled sequentially.
+ *
+ * The proactor always returns events that must be handled sequentially in the
+ * same batch or sequentially in a later batch after pn_proactor_done(). Any
+ * events returned concurrently by pn_proactor_wait() are safe to handle
+ * concurrently.
+ */
+pn_event_batch_t *pn_proactor_wait(pn_proactor_t* d);
+
+/**
+ * Call when done handling events.
  *
- * The proactor ensures that events that cannot be handled concurrently
- * (e.g. events for for the same connection) are never returned concurrently.
+ * It is generally most efficient to handle the entire batch in the thread
+ * that calls pn_proactor_wait(), then call pn_proactor_done(). If you call
+ * pn_proactor_done() earlier, the remaining events will be returned again by
+ * pn_proactor_wait(), possibly to another thread.
  */
-pn_event_t *pn_proactor_wait(pn_proactor_t* d);
+void pn_proactor_done(pn_proactor_t* d, pn_event_batch_t *events);
 
 /**
  * Cause PN_PROACTOR_INTERRUPT to be returned to exactly one thread calling wait()
@@ -146,14 +150,6 @@ void pn_connection_wake(pn_connection_t *c);
 pn_proactor_t *pn_connection_proactor(pn_connection_t *c);
 
 /**
- * Call when a proactor event has been handled. Does nothing if not a proactor event.
- *
- * Thread safe: May be called from any thread but must be called exactly once
- * for each event returned by pn_proactor_wait()
- */
-void pn_event_done(pn_event_t *);
-
-/**
  * Get the proactor that created the event or NULL.
  */
 pn_proactor_t *pn_event_proactor(pn_event_t *);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/src/core/connection_driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_driver.c b/proton-c/src/core/connection_driver.c
index f31ddb0..3393e64 100644
--- a/proton-c/src/core/connection_driver.c
+++ b/proton-c/src/core/connection_driver.c
@@ -20,144 +20,149 @@
 #include "engine-internal.h"
 #include <proton/condition.h>
 #include <proton/connection.h>
-#include <proton/connection_engine.h>
+#include <proton/connection_driver.h>
 #include <proton/transport.h>
 #include <string.h>
 
-int pn_connection_engine_init(pn_connection_engine_t* ce, pn_connection_t *c, pn_transport_t *t) {
-  ce->connection = c ? c : pn_connection();
-  ce->transport = t ? t : pn_transport();
-  ce->collector = pn_collector();
-  if (!ce->connection || !ce->transport || !ce->collector) {
-    pn_connection_engine_destroy(ce);
+struct driver_batch {
+  pn_event_batch_t batch;
+};
+
+static pn_event_t *batch_next(pn_event_batch_t *batch) {
+  pn_connection_driver_t *d =
+    (pn_connection_driver_t*)((char*)batch - offsetof(pn_connection_driver_t, batch));
+  pn_collector_t *collector = pn_connection_collector(d->connection);
+  pn_event_t *handled = pn_collector_prev(collector);
+  if (handled && pn_event_type(handled) == PN_CONNECTION_INIT) {
+      pn_transport_bind(d->transport, d->connection); /* Init event handled, auto-bind */
+  }
+  pn_event_t *next = pn_collector_next(collector);
+  if (next && d->transport->trace & PN_TRACE_EVT) {
+    pn_string_clear(d->transport->scratch);
+    pn_inspect(next, d->transport->scratch);
+    pn_transport_log(d->transport, pn_string_get(d->transport->scratch));
+  }
+  return next;
+}
+
+int pn_connection_driver_init(pn_connection_driver_t* d, pn_connection_t *c, pn_transport_t *t) {
+  memset(d, 0, sizeof(*d));
+  d->batch.next_event = &batch_next;
+  d->connection = c ? c : pn_connection();
+  d->transport = t ? t : pn_transport();
+  pn_collector_t *collector = pn_collector();
+  if (!d->connection || !d->transport || !collector) {
+    if (collector) pn_collector_free(collector);
+    pn_connection_driver_destroy(d);
     return PN_OUT_OF_MEMORY;
   }
-  pn_connection_collect(ce->connection, ce->collector);
+  pn_connection_collect(d->connection, collector);
   return 0;
 }
 
-int pn_connection_engine_bind(pn_connection_engine_t *ce) {
-  return pn_transport_bind(ce->transport, ce->connection);
+int pn_connection_driver_bind(pn_connection_driver_t *d) {
+  return pn_transport_bind(d->transport, d->connection);
 }
 
-void pn_connection_engine_destroy(pn_connection_engine_t *ce) {
-  if (ce->transport) {
-    pn_transport_unbind(ce->transport);
-    pn_transport_free(ce->transport);
+void pn_connection_driver_destroy(pn_connection_driver_t *d) {
+  if (d->transport) {
+    pn_transport_unbind(d->transport);
+    pn_transport_free(d->transport);
+  }
+  if (d->connection) {
+    pn_collector_t *collector = pn_connection_collector(d->connection);
+    pn_connection_free(d->connection);
+    pn_collector_free(collector);
   }
-  if (ce->collector) pn_collector_free(ce->collector);
-  if (ce->connection) pn_connection_free(ce->connection);
-  memset(ce, 0, sizeof(*ce));
+  memset(d, 0, sizeof(*d));
 }
 
-pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t *ce) {
-  ssize_t cap = pn_transport_capacity(ce->transport);
-  return (cap > 0) ?  pn_rwbytes(cap, pn_transport_tail(ce->transport)) : pn_rwbytes(0, 0);
+pn_rwbytes_t pn_connection_driver_read_buffer(pn_connection_driver_t *d) {
+  ssize_t cap = pn_transport_capacity(d->transport);
+  return (cap > 0) ?  pn_rwbytes(cap, pn_transport_tail(d->transport)) : pn_rwbytes(0, 0);
 }
 
-void pn_connection_engine_read_done(pn_connection_engine_t *ce, size_t n) {
-  if (n > 0) pn_transport_process(ce->transport, n);
+void pn_connection_driver_read_done(pn_connection_driver_t *d, size_t n) {
+  if (n > 0) pn_transport_process(d->transport, n);
 }
 
-bool pn_connection_engine_read_closed(pn_connection_engine_t *ce) {
-  return pn_transport_capacity(ce->transport) < 0;
+bool pn_connection_driver_read_closed(pn_connection_driver_t *d) {
+  return pn_transport_capacity(d->transport) < 0;
 }
 
-void pn_connection_engine_read_close(pn_connection_engine_t *ce) {
-  if (!pn_connection_engine_read_closed(ce)) {
-    pn_transport_close_tail(ce->transport);
+void pn_connection_driver_read_close(pn_connection_driver_t *d) {
+  if (!pn_connection_driver_read_closed(d)) {
+    pn_transport_close_tail(d->transport);
   }
 }
 
-pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t *ce) {
-  ssize_t pending = pn_transport_pending(ce->transport);
+pn_bytes_t pn_connection_driver_write_buffer(pn_connection_driver_t *d) {
+  ssize_t pending = pn_transport_pending(d->transport);
   return (pending > 0) ?
-    pn_bytes(pending, pn_transport_head(ce->transport)) : pn_bytes_null;
+    pn_bytes(pending, pn_transport_head(d->transport)) : pn_bytes_null;
 }
 
-void pn_connection_engine_write_done(pn_connection_engine_t *ce, size_t n) {
+void pn_connection_driver_write_done(pn_connection_driver_t *d, size_t n) {
   if (n > 0)
-    pn_transport_pop(ce->transport, n);
+    pn_transport_pop(d->transport, n);
 }
 
-bool pn_connection_engine_write_closed(pn_connection_engine_t *ce) {
-  return pn_transport_pending(ce->transport) < 0;
+bool pn_connection_driver_write_closed(pn_connection_driver_t *d) {
+  return pn_transport_pending(d->transport) < 0;
 }
 
-void pn_connection_engine_write_close(pn_connection_engine_t *ce) {
-  if (!pn_connection_engine_write_closed(ce)) {
-    pn_transport_close_head(ce->transport);
+void pn_connection_driver_write_close(pn_connection_driver_t *d) {
+  if (!pn_connection_driver_write_closed(d)) {
+    pn_transport_close_head(d->transport);
   }
 }
 
-void pn_connection_engine_close(pn_connection_engine_t *ce) {
-  pn_connection_engine_read_close(ce);
-  pn_connection_engine_write_close(ce);
-}
-
-pn_event_t* pn_connection_engine_event(pn_connection_engine_t *ce) {
-  pn_event_t *e = ce->collector ? pn_collector_peek(ce->collector) : NULL;
-  if (e) {
-    pn_transport_t *t = ce->transport;
-    if (t && t->trace & PN_TRACE_EVT) {
-      /* This can log the same event twice if pn_connection_engine_event is called
-       * twice but for debugging it is much better to log before handling than after.
-       */
-      pn_string_clear(t->scratch);
-      pn_inspect(e, t->scratch);
-      pn_transport_log(t, pn_string_get(t->scratch));
-    }
-  }
-  return e;
+void pn_connection_driver_close(pn_connection_driver_t *d) {
+  pn_connection_driver_read_close(d);
+  pn_connection_driver_write_close(d);
 }
 
-bool pn_connection_engine_has_event(pn_connection_engine_t *ce) {
-  return ce->collector && pn_collector_peek(ce->collector);
+pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *d) {
+  return pn_event_batch_next(&d->batch);
 }
 
-void pn_connection_engine_pop_event(pn_connection_engine_t *ce) {
-  if (ce->collector) {
-    pn_event_t *e = pn_collector_peek(ce->collector);
-    if (pn_event_type(e) == PN_TRANSPORT_CLOSED) { /* The last event ever */
-      /* Events can accumulate behind the TRANSPORT_CLOSED before the
-       * PN_TRANSPORT_CLOSED event is handled. They can never be processed
-       * so release them.
-       */
-      pn_collector_release(ce->collector);
-    } else {
-      pn_collector_pop(ce->collector);
-    }
-
-  }
+bool pn_connection_driver_has_event(pn_connection_driver_t *d) {
+  return pn_collector_peek(pn_connection_collector(d->connection));
 }
 
-bool pn_connection_engine_finished(pn_connection_engine_t *ce) {
-  return pn_transport_closed(ce->transport) && !pn_connection_engine_has_event(ce);
+bool pn_connection_driver_finished(pn_connection_driver_t *d) {
+  return pn_transport_closed(d->transport) && !pn_connection_driver_has_event(d);
 }
 
-void pn_connection_engine_verrorf(pn_connection_engine_t *ce, const char *name, const char *fmt, va_list ap) {
-  pn_transport_t *t = ce->transport;
+void pn_connection_driver_verrorf(pn_connection_driver_t *d, const char *name, const char *fmt, va_list ap) {
+  pn_transport_t *t = d->transport;
   pn_condition_t *cond = pn_transport_condition(t);
   pn_string_vformat(t->scratch, fmt, ap);
   pn_condition_set_name(cond, name);
   pn_condition_set_description(cond, pn_string_get(t->scratch));
 }
 
-void pn_connection_engine_errorf(pn_connection_engine_t *ce, const char *name, const char *fmt, ...) {
+void pn_connection_driver_errorf(pn_connection_driver_t *d, const char *name, const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
-  pn_connection_engine_verrorf(ce, name, fmt, ap);
+  pn_connection_driver_verrorf(d, name, fmt, ap);
   va_end(ap);
 }
 
-void pn_connection_engine_log(pn_connection_engine_t *ce, const char *msg) {
-  pn_transport_log(ce->transport, msg);
+void pn_connection_driver_log(pn_connection_driver_t *d, const char *msg) {
+  pn_transport_log(d->transport, msg);
+}
+
+void pn_connection_driver_vlogf(pn_connection_driver_t *d, const char *fmt, va_list ap) {
+  pn_transport_vlogf(d->transport, fmt, ap);
 }
 
-void pn_connection_engine_vlogf(pn_connection_engine_t *ce, const char *fmt, va_list ap) {
-  pn_transport_vlogf(ce->transport, fmt, ap);
+void pn_connection_driver_vlog(pn_connection_driver_t *d, const char *msg) {
+  pn_transport_log(d->transport, msg);
 }
 
-void pn_connection_engine_vlog(pn_connection_engine_t *ce, const char *msg) {
-  pn_transport_log(ce->transport, msg);
+pn_connection_driver_t* pn_event_batch_connection_driver(pn_event_batch_t *batch) {
+  return (batch->next_event == batch_next) ?
+    (pn_connection_driver_t*)((char*)batch - offsetof(pn_connection_driver_t, batch)) :
+    NULL;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/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
deleted file mode 100644
index f31ddb0..0000000
--- a/proton-c/src/core/connection_engine.c
+++ /dev/null
@@ -1,163 +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/condition.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* ce, pn_connection_t *c, pn_transport_t *t) {
-  ce->connection = c ? c : pn_connection();
-  ce->transport = t ? t : pn_transport();
-  ce->collector = pn_collector();
-  if (!ce->connection || !ce->transport || !ce->collector) {
-    pn_connection_engine_destroy(ce);
-    return PN_OUT_OF_MEMORY;
-  }
-  pn_connection_collect(ce->connection, ce->collector);
-  return 0;
-}
-
-int pn_connection_engine_bind(pn_connection_engine_t *ce) {
-  return pn_transport_bind(ce->transport, ce->connection);
-}
-
-void pn_connection_engine_destroy(pn_connection_engine_t *ce) {
-  if (ce->transport) {
-    pn_transport_unbind(ce->transport);
-    pn_transport_free(ce->transport);
-  }
-  if (ce->collector) pn_collector_free(ce->collector);
-  if (ce->connection) pn_connection_free(ce->connection);
-  memset(ce, 0, sizeof(*ce));
-}
-
-pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t *ce) {
-  ssize_t cap = pn_transport_capacity(ce->transport);
-  return (cap > 0) ?  pn_rwbytes(cap, pn_transport_tail(ce->transport)) : pn_rwbytes(0, 0);
-}
-
-void pn_connection_engine_read_done(pn_connection_engine_t *ce, size_t n) {
-  if (n > 0) pn_transport_process(ce->transport, n);
-}
-
-bool pn_connection_engine_read_closed(pn_connection_engine_t *ce) {
-  return pn_transport_capacity(ce->transport) < 0;
-}
-
-void pn_connection_engine_read_close(pn_connection_engine_t *ce) {
-  if (!pn_connection_engine_read_closed(ce)) {
-    pn_transport_close_tail(ce->transport);
-  }
-}
-
-pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t *ce) {
-  ssize_t pending = pn_transport_pending(ce->transport);
-  return (pending > 0) ?
-    pn_bytes(pending, pn_transport_head(ce->transport)) : pn_bytes_null;
-}
-
-void pn_connection_engine_write_done(pn_connection_engine_t *ce, size_t n) {
-  if (n > 0)
-    pn_transport_pop(ce->transport, n);
-}
-
-bool pn_connection_engine_write_closed(pn_connection_engine_t *ce) {
-  return pn_transport_pending(ce->transport) < 0;
-}
-
-void pn_connection_engine_write_close(pn_connection_engine_t *ce) {
-  if (!pn_connection_engine_write_closed(ce)) {
-    pn_transport_close_head(ce->transport);
-  }
-}
-
-void pn_connection_engine_close(pn_connection_engine_t *ce) {
-  pn_connection_engine_read_close(ce);
-  pn_connection_engine_write_close(ce);
-}
-
-pn_event_t* pn_connection_engine_event(pn_connection_engine_t *ce) {
-  pn_event_t *e = ce->collector ? pn_collector_peek(ce->collector) : NULL;
-  if (e) {
-    pn_transport_t *t = ce->transport;
-    if (t && t->trace & PN_TRACE_EVT) {
-      /* This can log the same event twice if pn_connection_engine_event is called
-       * twice but for debugging it is much better to log before handling than after.
-       */
-      pn_string_clear(t->scratch);
-      pn_inspect(e, t->scratch);
-      pn_transport_log(t, pn_string_get(t->scratch));
-    }
-  }
-  return e;
-}
-
-bool pn_connection_engine_has_event(pn_connection_engine_t *ce) {
-  return ce->collector && pn_collector_peek(ce->collector);
-}
-
-void pn_connection_engine_pop_event(pn_connection_engine_t *ce) {
-  if (ce->collector) {
-    pn_event_t *e = pn_collector_peek(ce->collector);
-    if (pn_event_type(e) == PN_TRANSPORT_CLOSED) { /* The last event ever */
-      /* Events can accumulate behind the TRANSPORT_CLOSED before the
-       * PN_TRANSPORT_CLOSED event is handled. They can never be processed
-       * so release them.
-       */
-      pn_collector_release(ce->collector);
-    } else {
-      pn_collector_pop(ce->collector);
-    }
-
-  }
-}
-
-bool pn_connection_engine_finished(pn_connection_engine_t *ce) {
-  return pn_transport_closed(ce->transport) && !pn_connection_engine_has_event(ce);
-}
-
-void pn_connection_engine_verrorf(pn_connection_engine_t *ce, const char *name, const char *fmt, va_list ap) {
-  pn_transport_t *t = ce->transport;
-  pn_condition_t *cond = pn_transport_condition(t);
-  pn_string_vformat(t->scratch, fmt, ap);
-  pn_condition_set_name(cond, name);
-  pn_condition_set_description(cond, pn_string_get(t->scratch));
-}
-
-void pn_connection_engine_errorf(pn_connection_engine_t *ce, const char *name, const char *fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  pn_connection_engine_verrorf(ce, name, fmt, ap);
-  va_end(ap);
-}
-
-void pn_connection_engine_log(pn_connection_engine_t *ce, const char *msg) {
-  pn_transport_log(ce->transport, msg);
-}
-
-void pn_connection_engine_vlogf(pn_connection_engine_t *ce, const char *fmt, va_list ap) {
-  pn_transport_vlogf(ce->transport, fmt, ap);
-}
-
-void pn_connection_engine_vlog(pn_connection_engine_t *ce, const char *msg) {
-  pn_transport_log(ce->transport, msg);
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/src/core/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/event.c b/proton-c/src/core/event.c
index 7882327..2a0a5cf 100644
--- a/proton-c/src/core/event.c
+++ b/proton-c/src/core/event.c
@@ -28,7 +28,8 @@ struct pn_collector_t {
   pn_list_t *pool;
   pn_event_t *head;
   pn_event_t *tail;
-  bool freed;
+  bool freed:1;
+  bool head_returned:1;         /* Head has been returned by pn_collector_next() */
 };
 
 struct pn_event_t {
@@ -51,11 +52,8 @@ static void pn_collector_initialize(pn_collector_t *collector)
 static void pn_collector_drain(pn_collector_t *collector)
 {
   assert(collector);
-
-  while (pn_collector_peek(collector)) {
-    pn_collector_pop(collector);
-  }
-
+  while (pn_collector_next(collector))
+    ;
   assert(!collector->head);
   assert(!collector->tail);
 }
@@ -175,6 +173,7 @@ pn_event_t *pn_collector_peek(pn_collector_t *collector)
 
 bool pn_collector_pop(pn_collector_t *collector)
 {
+  collector->head_returned = false;
   pn_event_t *event = collector->head;
   if (event) {
     collector->head = event->next;
@@ -190,6 +189,19 @@ bool pn_collector_pop(pn_collector_t *collector)
   return true;
 }
 
+pn_event_t *pn_collector_next(pn_collector_t *collector)
+{
+  if (collector->head_returned) {
+    pn_collector_pop(collector);
+  }
+  collector->head_returned = collector->head;
+  return collector->head;
+}
+
+pn_event_t *pn_collector_prev(pn_collector_t *collector) {
+  return collector->head_returned ? collector->head : NULL;
+}
+
 bool pn_collector_more(pn_collector_t *collector)
 {
   assert(collector);
@@ -386,3 +398,7 @@ const char *pn_event_type_name(pn_event_type_t type)
   }
   return NULL;
 }
+
+pn_event_t *pn_event_batch_next(pn_event_batch_t *batch) {
+  return batch->next_event(batch);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/src/tests/refcount.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/refcount.c b/proton-c/src/tests/refcount.c
index a36d01c..267c861 100644
--- a/proton-c/src/tests/refcount.c
+++ b/proton-c/src/tests/refcount.c
@@ -313,7 +313,8 @@ static void test_transport_connection(void) {
 }
 
 static void drain(pn_collector_t *collector) {
-  while (pn_collector_peek(collector)) { pn_collector_pop(collector); }
+  while (pn_collector_next(collector))
+    ;
 }
 
 static void test_collector_connection_transport(void) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/qpid-proton-cpp.syms
----------------------------------------------------------------------
diff --git a/qpid-proton-cpp.syms b/qpid-proton-cpp.syms
index 7a25651..c24e898 100644
--- a/qpid-proton-cpp.syms
+++ b/qpid-proton-cpp.syms
@@ -30,24 +30,24 @@ proton::connection::transport() const
 proton::connection::user(std::string const&)
 proton::connection::~connection()
 
-proton::connection_engine::can_read() const
-proton::connection_engine::can_write() const
-proton::connection_engine::closed() const
-proton::connection_engine::connection() const
-proton::connection_engine::connection_engine(proton::handler&, proton::connection_options const&)
-proton::connection_engine::container::container(std::string const&)
-proton::connection_engine::container::id() const
-proton::connection_engine::container::make_options()
-proton::connection_engine::container::options(proton::connection_options const&)
-proton::connection_engine::container::~container()
-proton::connection_engine::dispatch()
-proton::connection_engine::io_error::io_error(std::string const&)
-proton::connection_engine::io_error::~io_error()
-proton::connection_engine::no_opts
-proton::connection_engine::process(int)
-proton::connection_engine::try_read()
-proton::connection_engine::try_write()
-proton::connection_engine::~connection_engine()
+proton::connection_driver::can_read() const
+proton::connection_driver::can_write() const
+proton::connection_driver::closed() const
+proton::connection_driver::connection() const
+proton::connection_driver::connection_driver(proton::handler&, proton::connection_options const&)
+proton::connection_driver::container::container(std::string const&)
+proton::connection_driver::container::id() const
+proton::connection_driver::container::make_options()
+proton::connection_driver::container::options(proton::connection_options const&)
+proton::connection_driver::container::~container()
+proton::connection_driver::dispatch()
+proton::connection_driver::io_error::io_error(std::string const&)
+proton::connection_driver::io_error::~io_error()
+proton::connection_driver::no_opts
+proton::connection_driver::process(int)
+proton::connection_driver::try_read()
+proton::connection_driver::try_write()
+proton::connection_driver::~connection_driver()
 
 proton::connection_options::connection_options()
 proton::connection_options::connection_options(proton::connection_options const&)
@@ -587,8 +587,8 @@ proton::value::value(proton::value const&)
 # Only types with the following info can be thrown across shared abject boundary
 # Or correctly dynamically cast by user
 typeinfo for proton::connection
-typeinfo for proton::connection_engine
-typeinfo for proton::connection_engine::io_error
+typeinfo for proton::connection_driver
+typeinfo for proton::connection_driver::io_error
 typeinfo for proton::conversion_error
 typeinfo for proton::endpoint
 typeinfo for proton::error
@@ -600,8 +600,8 @@ typeinfo for proton::session
 typeinfo for proton::timeout_error
 typeinfo for proton::url_error
 typeinfo name for proton::connection
-typeinfo name for proton::connection_engine
-typeinfo name for proton::connection_engine::io_error
+typeinfo name for proton::connection_driver
+typeinfo name for proton::connection_driver::io_error
 typeinfo name for proton::conversion_error
 typeinfo name for proton::endpoint
 typeinfo name for proton::error
@@ -613,8 +613,8 @@ typeinfo name for proton::session
 typeinfo name for proton::timeout_error
 typeinfo name for proton::url_error
 vtable for proton::connection
-vtable for proton::connection_engine
-vtable for proton::connection_engine::io_error
+vtable for proton::connection_driver
+vtable for proton::connection_driver::io_error
 vtable for proton::conversion_error
 vtable for proton::endpoint
 vtable for proton::error


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


[15/48] 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 ac...@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


[03/48] 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 ac...@apache.org.
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


[39/48] qpid-proton git commit: PROTON-1351: [C++ binding] remove dependency on Proton-c url code - In preparation for moving this to the proton core library - Improved C++ url tests

Posted by ac...@apache.org.
PROTON-1351: [C++ binding] remove dependency on Proton-c url code
- In preparation for moving this to the proton core library
- Improved C++ url tests


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

Branch: refs/heads/go1
Commit: b4cadd1dbd9121f546909502ff35d58500843fcc
Parents: 2eac44b
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Nov 15 10:41:33 2016 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Nov 18 12:51:47 2016 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/include/proton/url.hpp |   6 +-
 proton-c/bindings/cpp/src/url.cpp            | 244 ++++++++++++++++++----
 proton-c/bindings/cpp/src/url_test.cpp       |  40 +++-
 3 files changed, 245 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b4cadd1d/proton-c/bindings/cpp/include/proton/url.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/url.hpp b/proton-c/bindings/cpp/include/proton/url.hpp
index 57ef586..78271b6 100644
--- a/proton-c/bindings/cpp/include/proton/url.hpp
+++ b/proton-c/bindings/cpp/include/proton/url.hpp
@@ -22,14 +22,13 @@
  *
  */
 
+#include "./internal/pn_unique_ptr.hpp"
 #include "./types_fwd.hpp"
 #include "./error.hpp"
 
 #include <iosfwd>
 #include <string>
 
-struct pn_url_t;
-
 namespace proton {
 
 /// An error encountered during URL parsing.
@@ -124,7 +123,8 @@ class url {
     friend PN_CPP_EXTERN std::string to_string(const url&);
 
   private:
-    pn_url_t* url_;
+    struct impl;
+    internal::pn_unique_ptr<impl> impl_;
 
     /// @cond INTERNAL
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b4cadd1d/proton-c/bindings/cpp/src/url.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/url.cpp b/proton-c/bindings/cpp/src/url.cpp
index 923aaf0..1aa01e1 100644
--- a/proton-c/bindings/cpp/src/url.cpp
+++ b/proton-c/bindings/cpp/src/url.cpp
@@ -23,73 +23,239 @@
 
 #include "proton/error.hpp"
 
-#include <proton/url.h>
-
 #include "proton_bits.hpp"
 
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
 #include <sstream>
 
-namespace proton {
+namespace {
 
-url_error::url_error(const std::string& s) : error(s) {}
+/** URL-encode src and append to dst. */
+static std::string pni_urlencode(const std::string &src) {
+    static const char *bad = "@:/";
 
-namespace {
+    std::ostringstream dst;
+    dst << std::hex << std::uppercase << std::setfill('0');
 
-pn_url_t* parse_throw(const char* s) {
-    pn_url_t* u = pn_url_parse(s);
-    if (!u) throw url_error("invalid URL: " + std::string(s));
-    return u;
+    std::size_t i = 0;
+    std::size_t j = src.find_first_of(bad);
+    while (j!=std::string::npos) {
+        dst << src.substr(i, j-i);
+        dst << "%" << std::setw(2) << src[j];
+        i = j + 1;
+        j = src.find_first_of(bad);
+    }
+    dst << src.substr(i);
+    return dst.str();
 }
 
-pn_url_t* parse_allow_empty(const char* s) {
-    return s && *s ? parse_throw(s) : pn_url();
+// 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 = std::strtoul(esc, NULL, 16);
+        *out = (char)d;
+        in += 3;
+        out++;
+      }
+      else
+      {
+        *out = *in;
+        in++;
+        out++;
+      }
+    }
+    else
+    {
+      *out = *in;
+      in++;
+      out++;
+    }
+  }
+  *out = '\0';
 }
 
-void replace(pn_url_t*& var, pn_url_t* val) {
-    if (var) pn_url_free(var);
-    var = val;
-}
+void parse_url(char *url, const char **scheme, const char **user, const char **pass, const char **host, const char **port, const char **path)
+{
+  if (!url) return;
+
+  char *slash = std::strchr(url, '/');
+
+  if (slash && slash>url) {
+    char *scheme_end = std::strstr(slash-1, "://");
+
+    if (scheme_end && scheme_end<slash) {
+      *scheme_end = '\0';
+      *scheme = url;
+      url = scheme_end + 3;
+      slash = std::strchr(url, '/');
+    }
+  }
+
+  if (slash) {
+    *slash = '\0';
+    *path = slash + 1;
+  }
+
+  char *at = std::strchr(url, '@');
+  if (at) {
+    *at = '\0';
+    char *up = url;
+    url = at + 1;
+    char *colon = std::strchr(up, ':');
+    if (colon) {
+      *colon = '\0';
+      char *p = colon + 1;
+      pni_urldecode(p, p);
+      *pass = p;
+    }
+    pni_urldecode(up, up);
+    *user = up;
+  }
+
+  *host = url;
+  char *open = (*url == '[') ? url : 0;
+  if (open) {
+    char *close = std::strchr(open, ']');
+    if (close) {
+        *host = open + 1;
+        *close = '\0';
+        url = close + 1;
+    }
+  }
 
-void defaults(pn_url_t* u) {
-  const char* scheme = pn_url_get_scheme(u);
-  const char* port = pn_url_get_port(u);
-  if (!scheme || *scheme=='\0' ) pn_url_set_scheme(u, url::AMQP.c_str());
-  if (!port || *port=='\0' ) pn_url_set_port(u, pn_url_get_scheme(u));
+  char *colon = std::strchr(url, ':');
+  if (colon) {
+    *colon = '\0';
+    *port = colon + 1;
+  }
 }
 
 } // namespace
 
-url::url(const std::string &s) : url_(parse_throw(s.c_str())) { defaults(url_); }
+namespace proton {
+
+struct url::impl {
+    static const char* const default_host;
+    const char* scheme;
+    const char* username;
+    const char* password;
+    const char* host;
+    const char* port;
+    const char* path;
+    char* cstr;
+    mutable std::string str;
+
+    impl(const std::string& s) :
+      scheme(0), username(0), password(0), host(0), port(0), path(0),
+      cstr(new char[s.size()+1])
+    {
+        std::strncpy(cstr, s.c_str(), s.size());
+        cstr[s.size()] = 0;
+        parse_url(cstr, &scheme, &username, &password, &host, &port, &path);
+    }
+
+    ~impl() {
+        delete [] cstr;
+    }
+
+    void defaults() {
+        if (!scheme || *scheme=='\0' ) scheme = proton::url::AMQP.c_str();
+        if (!host || *host=='\0' ) host = default_host;
+        if (!port || *port=='\0' ) port = scheme;
+    }
 
-url::url(const std::string &s, bool d) : url_(parse_throw(s.c_str())) { if (d) defaults(url_); }
+    operator std::string() const {
+        if ( str.empty() ) {
+            if (scheme) {
+                str += scheme;
+                str += "://";
+            }
+            if (username) {
+                str += pni_urlencode(username);
+            }
+            if (password) {
+                str += ":";
+                str += pni_urlencode(password);
+            }
+            if (username || password) {
+                str += "@";
+            }
+            if (host) {
+                if (std::strchr(host, ':')) {
+                    str += '[';
+                    str += host;
+                    str += ']';
+                } else {
+                    str += host;
+                }
+            }
+            if (port) {
+                str += ':';
+                str += port;
+            }
+            if (path) {
+                str += '/';
+                str += path;
+            }
+        }
+        return str;
+    }
 
-url::url(const url& u) : url_(parse_allow_empty(pn_url_str(u.url_))) {}
+};
 
-url::~url() { pn_url_free(url_); }
+const char* const url::impl::default_host = "localhost";
+
+
+url_error::url_error(const std::string& s) : error(s) {}
+
+url::url(const std::string &s) : impl_(new impl(s)) { impl_->defaults(); }
+
+url::url(const std::string &s, bool d) : impl_(new impl(s)) { if (d) impl_->defaults(); }
+
+url::url(const url& u) : impl_(new impl(u)) {}
+
+url::~url() {}
 
 url& url::operator=(const url& u) {
-    if (this != &u) replace(url_, parse_allow_empty(pn_url_str(u.url_)));
+    if (this != &u) {
+        impl_.reset(new impl(*u.impl_));
+    }
     return *this;
 }
 
-url::operator std::string() const { return str(pn_url_str(url_)); }
+url::operator std::string() const { return *impl_; }
 
-std::string url::scheme() const { return str(pn_url_get_scheme(url_)); }
-std::string url::user() const { return str(pn_url_get_username(url_)); }
-std::string url::password() const { return str(pn_url_get_password(url_)); }
-std::string url::host() const { return str(pn_url_get_host(url_)); }
-std::string url::port() const { return str(pn_url_get_port(url_)); }
-std::string url::path() const { return str(pn_url_get_path(url_)); }
+std::string url::scheme() const { return str(impl_->scheme); }
+std::string url::user() const { return str(impl_->username); }
+std::string url::password() const { return str(impl_->password); }
+std::string url::host() const { return str(impl_->host); }
+std::string url::port() const { return str(impl_->port); }
+std::string url::path() const { return str(impl_->path); }
 
 std::string url::host_port() const { return host() + ":" + port(); }
 
-bool url::empty() const { return *pn_url_str(url_) == '\0'; }
+bool url::empty() const { return impl_->str.empty(); }
 
 const std::string url::AMQP("amqp");
 const std::string url::AMQPS("amqps");
 
 uint16_t url::port_int() const {
     // TODO aconway 2015-10-27: full service name lookup
+    // astitcher 2016-11-17: It is hard to make the full service name lookup platform independent
     if (port() == AMQP) return 5672;
     if (port() == AMQPS) return 5671;
     std::istringstream is(port());
@@ -101,21 +267,21 @@ uint16_t url::port_int() const {
 }
 
 std::ostream& operator<<(std::ostream& o, const url& u) {
-    return o << pn_url_str(u.url_);
+    return o << std::string(u);
 }
 
 std::string to_string(const url& u) {
-    return std::string(pn_url_str(u.url_));
+    return u;
 }
 
 std::istream& operator>>(std::istream& i, url& u) {
     std::string s;
     i >> s;
     if (!i.fail() && !i.bad()) {
-        pn_url_t* p = pn_url_parse(s.c_str());
-        if (p) {
-            replace(u.url_, p);
-            defaults(u.url_);
+        if (!s.empty()) {
+            url::impl* p = new url::impl(s);
+            p->defaults();
+            u.impl_.reset(p);
         } else {
             i.clear(std::ios::failbit);
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b4cadd1d/proton-c/bindings/cpp/src/url_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/url_test.cpp b/proton-c/bindings/cpp/src/url_test.cpp
index ad9eca4..0727e2c 100644
--- a/proton-c/bindings/cpp/src/url_test.cpp
+++ b/proton-c/bindings/cpp/src/url_test.cpp
@@ -22,11 +22,45 @@
 
 namespace {
 
-void parse_to_string_test() {
-    std::string s("amqp://foo:xyz/path");
+void check_url(const std::string& s,
+               const std::string& scheme,
+               const std::string& user,
+               const std::string& pwd,
+               const std::string& host,
+               const std::string& port,
+               const std::string& path
+              )
+{
     proton::url u(s);
-    ASSERT_EQUAL(to_string(u), s);
+    ASSERT_EQUAL(scheme, u.scheme());
+    ASSERT_EQUAL(user, u.user());
+    ASSERT_EQUAL(pwd, u.password());
+    ASSERT_EQUAL(host, u.host());
+    ASSERT_EQUAL(port, u.port());
+    ASSERT_EQUAL(path, u.path());
 }
+
+void parse_to_string_test() {
+    check_url("amqp://foo:xyz/path",
+              "amqp", "", "", "foo", "xyz", "path");
+    check_url("amqp://username:password@host:1234/path",
+              "amqp", "username", "password", "host", "1234", "path");
+    check_url("host:1234",
+              "amqp", "", "", "host", "1234", "");
+    check_url("host",
+              "amqp", "", "", "host", "amqp", "");
+    check_url("host/path",
+              "amqp", "", "", "host", "amqp", "path");
+    check_url("amqps://host",
+              "amqps", "", "", "host", "amqps", "");
+    check_url("/path",
+              "amqp", "", "", "localhost", "amqp", "path");
+    check_url("",
+              "amqp", "", "", "localhost", "amqp", "");
+    check_url(":1234",
+              "amqp", "", "", "localhost", "1234", "");
+}
+
 }
 
 int main(int, char**) {


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


[33/48] qpid-proton git commit: PROTON-1344: proactor batch events, rename connection_driver

Posted by ac...@apache.org.
PROTON-1344: proactor batch events, rename connection_driver

renamed pn_connection_engine as pn_connection_driver.

pn_proactor_wait() returns pn_event_batch_t* rather than individual pn_event_t*
to reduce thread-context switching.

Added pn_collector_next() for simpler event looping.


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

Branch: refs/heads/go1
Commit: 25706a47ea8f29c0a53f5fae44195a916173cfbd
Parents: 94bc296
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 16 22:31:00 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Nov 17 11:22:14 2016 -0500

----------------------------------------------------------------------
 examples/c/proactor/broker.c                    |  21 +-
 examples/c/proactor/libuv_proactor.c            | 323 +++++++++++--------
 examples/c/proactor/receive.c                   | 100 +++---
 examples/c/proactor/send.c                      | 164 +++++-----
 examples/cpp/README.dox                         |   2 +-
 examples/cpp/mt/epoll_container.cpp             |  76 ++---
 proton-c/CMakeLists.txt                         |   4 +-
 proton-c/bindings/cpp/CMakeLists.txt            |   2 +-
 proton-c/bindings/cpp/docs/io.md                |   6 +-
 proton-c/bindings/cpp/docs/main.md              |   2 +-
 .../cpp/include/proton/connection_options.hpp   |   4 +-
 .../cpp/include/proton/io/connection_driver.hpp | 211 ++++++++++++
 .../cpp/include/proton/io/connection_engine.hpp | 215 ------------
 .../cpp/include/proton/messaging_handler.hpp    |   2 +-
 .../bindings/cpp/include/proton/transport.hpp   |   2 +-
 proton-c/bindings/cpp/src/engine_test.cpp       |  12 +-
 proton-c/bindings/cpp/src/include/contexts.hpp  |   2 +-
 .../bindings/cpp/src/io/connection_driver.cpp   | 161 +++++++++
 .../bindings/cpp/src/io/connection_engine.cpp   | 160 ---------
 proton-c/bindings/cpp/src/receiver.cpp          |   2 +-
 proton-c/bindings/cpp/src/thread_safe_test.cpp  |  10 +-
 proton-c/docs/api/index.md                      |  42 ++-
 proton-c/include/proton/connection.h            |   2 +-
 proton-c/include/proton/connection_driver.h     | 243 ++++++++++++++
 proton-c/include/proton/connection_engine.h     | 313 ------------------
 proton-c/include/proton/cproton.i               |   3 +
 proton-c/include/proton/event.h                 |  56 ++++
 proton-c/include/proton/proactor.h              |  62 ++--
 proton-c/src/core/connection_driver.c           | 173 +++++-----
 proton-c/src/core/connection_engine.c           | 163 ----------
 proton-c/src/core/event.c                       |  28 +-
 proton-c/src/tests/refcount.c                   |   3 +-
 qpid-proton-cpp.syms                            |  48 +--
 33 files changed, 1259 insertions(+), 1358 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index e11a8bd..66381fc 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-#include <proton/connection_engine.h>
+#include <proton/connection_driver.h>
 #include <proton/proactor.h>
 #include <proton/engine.h>
 #include <proton/sasl.h>
@@ -220,9 +220,11 @@ typedef struct broker_t {
   const char *container_id;     /* AMQP container-id */
   size_t threads;
   pn_millis_t heartbeat;
+  bool finished;
 } broker_t;
 
 void broker_init(broker_t *b, const char *container_id, size_t threads, pn_millis_t heartbeat) {
+  memset(b, 0, sizeof(*b));
   b->proactor = pn_proactor();
   b->listener = NULL;
   queues_init(&b->queues);
@@ -293,8 +295,7 @@ static void check_condition(pn_event_t *e, pn_condition_t *cond) {
 
 const int WINDOW=10;            /* Incoming credit window */
 
-static bool handle(broker_t* b, pn_event_t* e) {
-  bool more = true;
+static void handle(broker_t* b, pn_event_t* e) {
   pn_connection_t *c = pn_event_connection(e);
 
   switch (pn_event_type(e)) {
@@ -398,20 +399,24 @@ static bool handle(broker_t* b, pn_event_t* e) {
     break;
 
    case PN_PROACTOR_INTERRUPT:
-    more = false;
+    b->finished = true;
     break;
 
    default:
     break;
   }
-  pn_event_done(e);
-  return more;
 }
 
 static void broker_thread(void *void_broker) {
   broker_t *b = (broker_t*)void_broker;
-  while (handle(b, pn_proactor_wait(b->proactor)))
-    ;
+  do {
+    pn_event_batch_t *events = pn_proactor_wait(b->proactor);
+    pn_event_t *e;
+    while ((e = pn_event_batch_next(events))) {
+      handle(b, e);
+    }
+    pn_proactor_done(b->proactor, events);
+  } while(!b->finished);
 }
 
 static void usage(const char *arg0) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
index 8dd2706..35afd5c 100644
--- a/examples/c/proactor/libuv_proactor.c
+++ b/examples/c/proactor/libuv_proactor.c
@@ -22,7 +22,7 @@
 #include <uv.h>
 
 #include <proton/condition.h>
-#include <proton/connection_engine.h>
+#include <proton/connection_driver.h>
 #include <proton/engine.h>
 #include <proton/extra.h>
 #include <proton/message.h>
@@ -44,11 +44,15 @@
   To provide concurrency the proactor uses a "leader-worker-follower" model,
   threads take turns at the roles:
 
-  - a single "leader" calls libuv functions and runs the uv_loop incrementally.
-  When there is work it hands over leadership and becomes a "worker"
+  - a single "leader" calls libuv functions and runs the uv_loop in short bursts
+    to generate work. When there is work available it gives up leadership and
+    becomes a "worker"
+
   - "workers" handle events concurrently for distinct connections/listeners
-  When the work is done they become "followers"
-  - "followers" wait for the leader to step aside, one takes over as new leader.
+    They do as much work as they can get, when none is left they become "followers"
+
+  - "followers" wait for the leader to generate work and become workers.
+    When the leader itself becomes a worker, one of the followers takes over.
 
   This model is symmetric: any thread can take on any role based on run-time
   requirements. It also allows the IO and non-IO work associated with an IO
@@ -77,7 +81,7 @@ PN_HANDLE(PN_PROACTOR)
 PN_STRUCT_CLASSDEF(pn_proactor, CID_pn_proactor)
 PN_STRUCT_CLASSDEF(pn_listener, CID_pn_listener)
 
-/* common to connection engine and listeners */
+/* common to connection and listener */
 typedef struct psocket_t {
   /* Immutable */
   pn_proactor_t *proactor;
@@ -118,11 +122,11 @@ static inline const char* fixstr(const char* str) {
   return str[0] == '\001' ? NULL : str;
 }
 
-typedef struct pconn {
+typedef struct pconnection_t {
   psocket_t psocket;
 
   /* Only used by owner thread */
-  pn_connection_engine_t ceng;
+  pn_connection_driver_t driver;
 
   /* Only used by leader */
   uv_connect_t connect;
@@ -132,7 +136,7 @@ typedef struct pconn {
   size_t writing;
   bool reading:1;
   bool server:1;                /* accept, not connect */
-} pconn;
+} pconnection_t;
 
 struct pn_listener_t {
   psocket_t psocket;
@@ -140,6 +144,7 @@ struct pn_listener_t {
   /* Only used by owner thread */
   pn_condition_t *condition;
   pn_collector_t *collector;
+  pn_event_batch_t batch;
   size_t backlog;
 };
 
@@ -153,6 +158,10 @@ struct pn_proactor_t {
   uv_loop_t loop;
   uv_async_t async;
 
+  /* Owner thread: proactor collector and batch can belong to leader or a worker */
+  pn_collector_t *collector;
+  pn_event_batch_t batch;
+
   /* Protected by lock */
   uv_mutex_t lock;
   queue start_q;
@@ -162,11 +171,7 @@ struct pn_proactor_t {
   size_t count;                 /* psocket count */
   bool inactive:1;
   bool has_leader:1;
-
-  /* Immutable collectors to hold fixed events */
-  pn_collector_t *interrupt_event;
-  pn_collector_t *timeout_event;
-  pn_collector_t *inactive_event;
+  bool batch_working:1;          /* batch belongs to a worker.  */
 };
 
 static bool push_lh(queue *q, psocket_t *ps) {
@@ -191,8 +196,8 @@ static psocket_t* pop_lh(queue *q) {
   return ps;
 }
 
-static inline pconn *as_pconn(psocket_t* ps) {
-  return ps->is_conn ? (pconn*)ps : NULL;
+static inline pconnection_t *as_pconnection_t(psocket_t* ps) {
+  return ps->is_conn ? (pconnection_t*)ps : NULL;
 }
 
 static inline pn_listener_t *as_listener(psocket_t* ps) {
@@ -213,9 +218,9 @@ static void to_leader(psocket_t *ps) {
 
 /* Detach from IO and put ps on the worker queue */
 static void leader_to_worker(psocket_t *ps) {
-  pconn *pc = as_pconn(ps);
+  pconnection_t *pc = as_pconnection_t(ps);
   /* Don't detach if there are no events yet. */
-  if (pc && pn_connection_engine_has_event(&pc->ceng)) {
+  if (pc && pn_connection_driver_has_event(&pc->driver)) {
     if (pc->writing) {
       pc->writing  = 0;
       uv_cancel((uv_req_t*)&pc->write);
@@ -236,6 +241,28 @@ static void leader_to_worker(psocket_t *ps) {
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
+/* Set a deferred action for leader, if not already set. */
+static void owner_to_leader(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  if (!ps->action) {
+    ps->action = action;
+  }
+  to_leader_lh(ps);
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+/* Owner thread send to worker thread. Set deferred action if not already set. */
+static void owner_to_worker(psocket_t *ps, void (*action)(psocket_t*)) {
+  uv_mutex_lock(&ps->proactor->lock);
+  if (!ps->action) {
+    ps->action = action;
+  }
+  push_lh(&ps->proactor->worker_q, ps);
+  uv_async_send(&ps->proactor->async); /* Wake leader */
+  uv_mutex_unlock(&ps->proactor->lock);
+}
+
+
 /* Re-queue for further work */
 static void worker_requeue(psocket_t* ps) {
   uv_mutex_lock(&ps->proactor->lock);
@@ -244,25 +271,43 @@ static void worker_requeue(psocket_t* ps) {
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
-static pconn *new_pconn(pn_proactor_t *p, bool server, const char *host, const char *port, pn_bytes_t extra) {
-  pconn *pc = (pconn*)calloc(1, sizeof(*pc));
+static pconnection_t *new_pconnection_t(pn_proactor_t *p, bool server, const char *host, const char *port, pn_bytes_t extra) {
+  pconnection_t *pc = (pconnection_t*)calloc(1, sizeof(*pc));
   if (!pc) return NULL;
-  if (pn_connection_engine_init(&pc->ceng, pn_connection_with_extra(extra.size), NULL) != 0) {
+  if (pn_connection_driver_init(&pc->driver, pn_connection_with_extra(extra.size), NULL) != 0) {
     return NULL;
   }
   if (extra.start && extra.size) {
-    memcpy(pn_connection_get_extra(pc->ceng.connection).start, extra.start, extra.size);
+    memcpy(pn_connection_get_extra(pc->driver.connection).start, extra.start, extra.size);
   }
   psocket_init(&pc->psocket, p,  true, host, port);
   if (server) {
-    pn_transport_set_server(pc->ceng.transport);
+    pn_transport_set_server(pc->driver.transport);
   }
-  pn_record_t *r = pn_connection_attachments(pc->ceng.connection);
+  pn_record_t *r = pn_connection_attachments(pc->driver.connection);
   pn_record_def(r, PN_PROACTOR, PN_VOID);
   pn_record_set(r, PN_PROACTOR, pc);
   return pc;
 }
 
+static pn_event_t *listener_batch_next(pn_event_batch_t *batch);
+static pn_event_t *proactor_batch_next(pn_event_batch_t *batch);
+
+static inline pn_proactor_t *batch_proactor(pn_event_batch_t *batch) {
+  return (batch->next_event == proactor_batch_next) ?
+    (pn_proactor_t*)((char*)batch - offsetof(pn_proactor_t, batch)) : NULL;
+}
+
+static inline pn_listener_t *batch_listener(pn_event_batch_t *batch) {
+  return (batch->next_event == listener_batch_next) ?
+    (pn_listener_t*)((char*)batch - offsetof(pn_listener_t, batch)) : NULL;
+}
+
+static inline pconnection_t *batch_pconnection(pn_event_batch_t *batch) {
+  pn_connection_driver_t *d = pn_event_batch_connection_driver(batch);
+  return d ? (pconnection_t*)((char*)d - offsetof(pconnection_t, driver)) : NULL;
+}
+
 pn_listener_t *new_listener(pn_proactor_t *p, const char *host, const char *port, int backlog, pn_bytes_t extra) {
   pn_listener_t *l = (pn_listener_t*)calloc(1, PN_EXTRA_SIZEOF(pn_listener_t, extra.size));
   if (!l) {
@@ -278,6 +323,7 @@ pn_listener_t *new_listener(pn_proactor_t *p, const char *host, const char *port
   }
   psocket_init(&l->psocket, p, false, host, port);
   l->condition = pn_condition();
+  l->batch.next_event = listener_batch_next;
   l->backlog = backlog;
   return l;
 }
@@ -290,11 +336,12 @@ static void leader_count(pn_proactor_t *p, int change) {
 }
 
 /* Free if there are no uv callbacks pending and no events */
-static void leader_pconn_maybe_free(pconn *pc) {
-    if (pn_connection_engine_has_event(&pc->ceng)) {
+static void leader_pconnection_t_maybe_free(pconnection_t *pc) {
+    if (pn_connection_driver_has_event(&pc->driver)) {
       leader_to_worker(&pc->psocket);         /* Return to worker */
-    } else if (!(pc->psocket.tcp.data || pc->shutdown.data || pc->timer.data)) {
-      pn_connection_engine_destroy(&pc->ceng);
+    } else if (!(pc->psocket.tcp.data || pc->write.data || pc->shutdown.data || pc->timer.data)) {
+      /* All UV requests are finished */
+      pn_connection_driver_destroy(&pc->driver);
       leader_count(pc->psocket.proactor, -1);
       free(pc);
     }
@@ -314,7 +361,7 @@ static void leader_listener_maybe_free(pn_listener_t *l) {
 /* Free if there are no uv callbacks pending and no events */
 static void leader_maybe_free(psocket_t *ps) {
   if (ps->is_conn) {
-    leader_pconn_maybe_free(as_pconn(ps));
+    leader_pconnection_t_maybe_free(as_pconnection_t(ps));
   } else {
     leader_listener_maybe_free(as_listener(ps));
   }
@@ -336,9 +383,9 @@ static inline void leader_close(psocket_t *ps) {
   if (ps->tcp.data && !uv_is_closing((uv_handle_t*)&ps->tcp)) {
     uv_close((uv_handle_t*)&ps->tcp, on_close);
   }
-  pconn *pc = as_pconn(ps);
+  pconnection_t *pc = as_pconnection_t(ps);
   if (pc) {
-    pn_connection_engine_close(&pc->ceng);
+    pn_connection_driver_close(&pc->driver);
     if (pc->timer.data && !uv_is_closing((uv_handle_t*)&pc->timer)) {
       uv_timer_stop(&pc->timer);
       uv_close((uv_handle_t*)&pc->timer, on_close);
@@ -347,20 +394,20 @@ static inline void leader_close(psocket_t *ps) {
   leader_maybe_free(ps);
 }
 
-static pconn *get_pconn(pn_connection_t* c) {
+static pconnection_t *get_pconnection_t(pn_connection_t* c) {
   if (!c) return NULL;
   pn_record_t *r = pn_connection_attachments(c);
-  return (pconn*) pn_record_get(r, PN_PROACTOR);
+  return (pconnection_t*) pn_record_get(r, PN_PROACTOR);
 }
 
 static void leader_error(psocket_t *ps, int err, const char* what) {
   if (ps->is_conn) {
-    pn_connection_engine_t *ceng = &as_pconn(ps)->ceng;
-    pn_connection_engine_errorf(ceng, COND_NAME, "%s %s:%s: %s",
+    pn_connection_driver_t *driver = &as_pconnection_t(ps)->driver;
+    pn_connection_driver_bind(driver); /* Bind so errors will be reported */
+    pn_connection_driver_errorf(driver, COND_NAME, "%s %s:%s: %s",
                                 what, fixstr(ps->host), fixstr(ps->port),
                                 uv_strerror(err));
-    pn_connection_engine_bind(ceng);
-    pn_connection_engine_close(ceng);
+    pn_connection_driver_close(driver);
   } else {
     pn_listener_t *l = as_listener(ps);
     pn_condition_format(l->condition, COND_NAME, "%s %s:%s: %s",
@@ -376,9 +423,9 @@ static int leader_init(psocket_t *ps) {
   leader_count(ps->proactor, +1);
   int err = uv_tcp_init(&ps->proactor->loop, &ps->tcp);
   if (!err) {
-    pconn *pc = as_pconn(ps);
+    pconnection_t *pc = as_pconnection_t(ps);
     if (pc) {
-      pc->connect.data = pc->write.data = pc->shutdown.data = ps;
+      pc->connect.data = ps;
       int err = uv_timer_init(&ps->proactor->loop, &pc->timer);
       if (!err) {
         pc->timer.data = pc;
@@ -392,7 +439,7 @@ static int leader_init(psocket_t *ps) {
 }
 
 /* Common logic for on_connect and on_accept */
-static void leader_connect_accept(pconn *pc, int err, const char *what) {
+static void leader_connect_accept(pconnection_t *pc, int err, const char *what) {
   if (!err) {
     leader_to_worker(&pc->psocket);
   } else {
@@ -401,14 +448,14 @@ static void leader_connect_accept(pconn *pc, int err, const char *what) {
 }
 
 static void on_connect(uv_connect_t *connect, int err) {
-  leader_connect_accept((pconn*)connect->data, err, "on connect");
+  leader_connect_accept((pconnection_t*)connect->data, err, "on connect");
 }
 
 static void on_accept(uv_stream_t* server, int err) {
   pn_listener_t* l = (pn_listener_t*)server->data;
   if (!err) {
     pn_rwbytes_t v =  pn_listener_get_extra(l);
-    pconn *pc = new_pconn(l->psocket.proactor, true,
+    pconnection_t *pc = new_pconnection_t(l->psocket.proactor, true,
                           fixstr(l->psocket.host),
                           fixstr(l->psocket.port),
                           pn_bytes(v.size, v.start));
@@ -436,7 +483,7 @@ static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
 }
 
 static void leader_connect(psocket_t *ps) {
-  pconn *pc = as_pconn(ps);
+  pconnection_t *pc = as_pconnection_t(ps);
   uv_getaddrinfo_t info;
   int err = leader_resolve(ps, &info, false);
   if (!err) {
@@ -450,7 +497,7 @@ static void leader_connect(psocket_t *ps) {
 
 static void leader_listen(psocket_t *ps) {
   pn_listener_t *l = as_listener(ps);
-  uv_getaddrinfo_t info;
+   uv_getaddrinfo_t info;
   int err = leader_resolve(ps, &info, true);
   if (!err) {
     err = uv_tcp_bind(&l->psocket.tcp, info.addrinfo->ai_addr, 0);
@@ -463,8 +510,8 @@ static void leader_listen(psocket_t *ps) {
 }
 
 static void on_tick(uv_timer_t *timer) {
-  pconn *pc = (pconn*)timer->data;
-  pn_transport_t *t = pc->ceng.transport;
+  pconnection_t *pc = (pconnection_t*)timer->data;
+  pn_transport_t *t = pc->driver.transport;
   if (pn_transport_get_idle_timeout(t) || pn_transport_get_remote_idle_timeout(t)) {
     uv_timer_stop(&pc->timer);
     uint64_t now = uv_now(pc->timer.loop);
@@ -476,24 +523,25 @@ static void on_tick(uv_timer_t *timer) {
 }
 
 static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
-  pconn *pc = (pconn*)stream->data;
+  pconnection_t *pc = (pconnection_t*)stream->data;
   if (nread >= 0) {
-    pn_connection_engine_read_done(&pc->ceng, nread);
+    pn_connection_driver_read_done(&pc->driver, nread);
     on_tick(&pc->timer);         /* check for tick changes. */
     leader_to_worker(&pc->psocket);
     /* Reading continues automatically until stopped. */
   } else if (nread == UV_EOF) { /* hangup */
-    pn_connection_engine_read_close(&pc->ceng);
+    pn_connection_driver_read_close(&pc->driver);
     leader_maybe_free(&pc->psocket);
   } else {
     leader_error(&pc->psocket, nread, "on read from");
   }
 }
 
-static void on_write(uv_write_t* request, int err) {
-  pconn *pc = (pconn*)request->data;
+static void on_write(uv_write_t* write, int err) {
+  pconnection_t *pc = (pconnection_t*)write->data;
+  write->data = NULL;
   if (err == 0) {
-    pn_connection_engine_write_done(&pc->ceng, pc->writing);
+    pn_connection_driver_write_done(&pc->driver, pc->writing);
     leader_to_worker(&pc->psocket);
   } else if (err == UV_ECANCELED) {
     leader_maybe_free(&pc->psocket);
@@ -505,29 +553,31 @@ static void on_write(uv_write_t* request, int err) {
 
 // Read buffer allocation function for uv, just returns the transports read buffer.
 static void alloc_read_buffer(uv_handle_t* stream, size_t size, uv_buf_t* buf) {
-  pconn *pc = (pconn*)stream->data;
-  pn_rwbytes_t rbuf = pn_connection_engine_read_buffer(&pc->ceng);
+  pconnection_t *pc = (pconnection_t*)stream->data;
+  pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
   *buf = uv_buf_init(rbuf.start, rbuf.size);
 }
 
 static void leader_rewatch(psocket_t *ps) {
-  pconn *pc = as_pconn(ps);
+  pconnection_t *pc = as_pconnection_t(ps);
 
   if (pc->timer.data) {         /* uv-initialized */
     on_tick(&pc->timer);        /* Re-enable ticks if required */
   }
-  pn_rwbytes_t rbuf = pn_connection_engine_read_buffer(&pc->ceng);
-  pn_bytes_t wbuf = pn_connection_engine_write_buffer(&pc->ceng);
+  pn_rwbytes_t rbuf = pn_connection_driver_read_buffer(&pc->driver);
+  pn_bytes_t wbuf = pn_connection_driver_write_buffer(&pc->driver);
 
   /* Ticks and checking buffers can generate events, process before proceeding */
-  if (pn_connection_engine_has_event(&pc->ceng)) {
+  if (pn_connection_driver_has_event(&pc->driver)) {
     leader_to_worker(ps);
   } else {                      /* Re-watch for IO */
     if (wbuf.size > 0 && !pc->writing) {
       pc->writing = wbuf.size;
       uv_buf_t buf = uv_buf_init((char*)wbuf.start, wbuf.size);
+      pc->write.data = ps;
       uv_write(&pc->write, (uv_stream_t*)&pc->psocket.tcp, &buf, 1, on_write);
-    } else if (wbuf.size == 0 && pn_connection_engine_write_closed(&pc->ceng)) {
+    } else if (wbuf.size == 0 && pn_connection_driver_write_closed(&pc->driver)) {
+      pc->shutdown.data = ps;
       uv_shutdown(&pc->shutdown, (uv_stream_t*)&pc->psocket.tcp, on_shutdown);
     }
     if (rbuf.size > 0 && !pc->reading) {
@@ -537,23 +587,31 @@ static void leader_rewatch(psocket_t *ps) {
   }
 }
 
-/* Return the next worker event or { 0 } if no events are ready */
-static pn_event_t* get_event_lh(pn_proactor_t *p) {
-  if (p->inactive) {
-    p->inactive = false;
-    return pn_collector_peek(p->inactive_event);
-  }
-  if (p->interrupt > 0) {
-    --p->interrupt;
-    return pn_collector_peek(p->interrupt_event);
+static pn_event_batch_t *proactor_batch_lh(pn_proactor_t *p, pn_event_type_t t) {
+  pn_collector_put(p->collector, pn_proactor__class(), p, t);
+  p->batch_working = true;
+  return &p->batch;
+}
+
+/* Return the next event batch or 0 if no events are ready */
+static pn_event_batch_t* get_batch_lh(pn_proactor_t *p) {
+  if (!p->batch_working) {       /* Can generate proactor events */
+    if (p->inactive) {
+      p->inactive = false;
+      return proactor_batch_lh(p, PN_PROACTOR_INACTIVE);
+    }
+    if (p->interrupt > 0) {
+      --p->interrupt;
+      return proactor_batch_lh(p, PN_PROACTOR_INTERRUPT);
+    }
   }
   for (psocket_t *ps = pop_lh(&p->worker_q); ps; ps = pop_lh(&p->worker_q)) {
     if (ps->is_conn) {
-      pconn *pc = as_pconn(ps);
-      return pn_connection_engine_event(&pc->ceng);
+      pconnection_t *pc = as_pconnection_t(ps);
+      return &pc->driver.batch;
     } else {                    /* Listener */
       pn_listener_t *l = as_listener(ps);
-      return pn_collector_peek(l->collector);
+      return &l->batch;
     }
     to_leader(ps);      /* No event, back to leader */
   }
@@ -568,15 +626,6 @@ static void wakeup(psocket_t *ps, void (*action)(psocket_t*)) {
   uv_mutex_unlock(&ps->proactor->lock);
 }
 
-/* Defer an action to the leader thread. Only from non-leader threads. */
-static void owner_defer(psocket_t *ps, void (*action)(psocket_t*)) {
-  uv_mutex_lock(&ps->proactor->lock);
-  assert(!ps->action);
-  ps->action = action;
-  to_leader_lh(ps);
-  uv_mutex_unlock(&ps->proactor->lock);
-}
-
 pn_listener_t *pn_event_listener(pn_event_t *e) {
   return (pn_event_class(e) == pn_listener__class()) ? (pn_listener_t*)pn_event_context(e) : NULL;
 }
@@ -590,57 +639,47 @@ pn_proactor_t *pn_event_proactor(pn_event_t *e) {
   return NULL;
 }
 
-void pn_event_done(pn_event_t *e) {
-  pn_event_type_t etype = pn_event_type(e);
-  pconn *pc = get_pconn(pn_event_connection(e));
-  if (pc && e == pn_collector_peek(pc->ceng.collector)) {
-    pn_connection_engine_pop_event(&pc->ceng);
-    if (etype == PN_CONNECTION_INIT) {
-      /* Bind after user has handled CONNECTION_INIT */
-      pn_connection_engine_bind(&pc->ceng);
-    }
-    if (pn_connection_engine_has_event(&pc->ceng)) {
-      /* Process all events before going back to IO.
-         Put it back on the worker queue and wake the leader.
-      */
+void pn_proactor_done(pn_proactor_t *p, pn_event_batch_t *batch) {
+  pconnection_t *pc = batch_pconnection(batch);
+  if (pc) {
+    if (pn_connection_driver_has_event(&pc->driver)) {
+      /* Process all events before going back to IO. */
       worker_requeue(&pc->psocket);
-    } else if (pn_connection_engine_finished(&pc->ceng)) {
-      owner_defer(&pc->psocket, leader_close);
+    } else if (pn_connection_driver_finished(&pc->driver)) {
+      owner_to_leader(&pc->psocket, leader_close);
     } else {
-      owner_defer(&pc->psocket, leader_rewatch);
-    }
-  } else {
-    pn_listener_t *l = pn_event_listener(e);
-    if (l && e == pn_collector_peek(l->collector)) {
-      pn_collector_pop(l->collector);
-      if (etype == PN_LISTENER_CLOSE) {
-        owner_defer(&l->psocket, leader_close);
-      }
+      owner_to_leader(&pc->psocket, leader_rewatch);
     }
+    return;
+  }
+  pn_proactor_t *bp = batch_proactor(batch);
+  if (bp == p) {
+    uv_mutex_lock(&p->lock);
+    p->batch_working = false;
+    uv_async_send(&p->async); /* Wake leader */
+    uv_mutex_unlock(&p->lock);
+    return;
   }
+  /* Nothing extra to do for listener, it is always in the UV loop. */
 }
 
 /* Run follower/leader loop till we can return an event and be a worker */
-pn_event_t *pn_proactor_wait(struct pn_proactor_t* p) {
+pn_event_batch_t *pn_proactor_wait(struct pn_proactor_t* p) {
   uv_mutex_lock(&p->lock);
   /* Try to grab work immediately. */
-  pn_event_t *e = get_event_lh(p);
-  if (e == NULL) {
+  pn_event_batch_t *batch = get_batch_lh(p);
+  if (batch == NULL) {
     /* No work available, follow the leader */
-    while (p->has_leader)
+    while (p->has_leader) {
       uv_cond_wait(&p->cond, &p->lock);
+    }
     /* Lead till there is work to do. */
     p->has_leader = true;
-    for (e = get_event_lh(p); e == NULL; e = get_event_lh(p)) {
-      /* Run uv_loop outside the lock */
-      uv_mutex_unlock(&p->lock);
-      uv_run(&p->loop, UV_RUN_ONCE);
-      uv_mutex_lock(&p->lock);
-      /* Process leader work queue outside the lock */
+    while (batch == NULL) {
       for (psocket_t *ps = pop_lh(&p->leader_q); ps; ps = pop_lh(&p->leader_q)) {
         void (*action)(psocket_t*) = ps->action;
-        ps->action = NULL;
         void (*wakeup)(psocket_t*) = ps->wakeup;
+        ps->action = NULL;
         ps->wakeup = NULL;
         if (action || wakeup) {
           uv_mutex_unlock(&p->lock);
@@ -649,13 +688,19 @@ pn_event_t *pn_proactor_wait(struct pn_proactor_t* p) {
           uv_mutex_lock(&p->lock);
         }
       }
+      batch = get_batch_lh(p);
+      if (batch == NULL) {
+        uv_mutex_unlock(&p->lock);
+        uv_run(&p->loop, UV_RUN_ONCE);
+        uv_mutex_lock(&p->lock);
+      }
     }
     /* Signal the next leader and return to work */
     p->has_leader = false;
     uv_cond_signal(&p->cond);
   }
   uv_mutex_unlock(&p->lock);
-  return e;
+  return batch;
 }
 
 void pn_proactor_interrupt(pn_proactor_t *p) {
@@ -666,11 +711,12 @@ void pn_proactor_interrupt(pn_proactor_t *p) {
 }
 
 int pn_proactor_connect(pn_proactor_t *p, const char *host, const char *port, pn_bytes_t extra) {
-  pconn *pc = new_pconn(p, false, host, port, extra);
+  pconnection_t *pc = new_pconnection_t(p, false, host, port, extra);
   if (!pc) {
     return PN_OUT_OF_MEMORY;
   }
-  owner_defer(&pc->psocket, leader_connect); /* Process PN_CONNECTION_INIT before binding */
+  /* Process PN_CONNECTION_INIT before binding */
+  owner_to_worker(&pc->psocket, leader_connect);
   return 0;
 }
 
@@ -678,12 +724,12 @@ pn_rwbytes_t pn_listener_get_extra(pn_listener_t *l) { return PN_EXTRA_GET(pn_li
 
 pn_listener_t *pn_proactor_listen(pn_proactor_t *p, const char *host, const char *port, int backlog, pn_bytes_t extra) {
   pn_listener_t *l = new_listener(p, host, port, backlog, extra);
-  if (l)  owner_defer(&l->psocket, leader_listen);
+  if (l)  owner_to_leader(&l->psocket, leader_listen);
   return l;
 }
 
 pn_proactor_t *pn_connection_proactor(pn_connection_t* c) {
-  pconn *pc = get_pconn(c);
+  pconnection_t *pc = get_pconnection_t(c);
   return pc ? pc->psocket.proactor : NULL;
 }
 
@@ -692,13 +738,14 @@ pn_proactor_t *pn_listener_proactor(pn_listener_t* l) {
 }
 
 void leader_wake_connection(psocket_t *ps) {
-  pconn *pc = as_pconn(ps);
-  pn_collector_put(pc->ceng.collector, PN_OBJECT, pc->ceng.connection, PN_CONNECTION_WAKE);
+  pconnection_t *pc = as_pconnection_t(ps);
+  pn_connection_t *c = pc->driver.connection;
+  pn_collector_put(pn_connection_collector(c), PN_OBJECT, c, PN_CONNECTION_WAKE);
   leader_to_worker(ps);
 }
 
 void pn_connection_wake(pn_connection_t* c) {
-  wakeup(&get_pconn(c)->psocket, leader_wake_connection);
+  wakeup(&get_pconnection_t(c)->psocket, leader_wake_connection);
 }
 
 void pn_listener_close(pn_listener_t* l) {
@@ -710,22 +757,15 @@ pn_condition_t* pn_listener_condition(pn_listener_t* l) {
   return l->condition;
 }
 
-/* Collector to hold for a single fixed event that is never popped. */
-static pn_collector_t *event_holder(pn_proactor_t *p, pn_event_type_t t) {
-  pn_collector_t *c = pn_collector();
-  pn_collector_put(c, pn_proactor__class(), p, t);
-  return c;
-}
-
 pn_proactor_t *pn_proactor() {
   pn_proactor_t *p = (pn_proactor_t*)calloc(1, sizeof(*p));
+  p->collector = pn_collector();
+  p->batch.next_event = &proactor_batch_next;
+  if (!p->collector) return NULL;
   uv_loop_init(&p->loop);
   uv_mutex_init(&p->lock);
   uv_cond_init(&p->cond);
   uv_async_init(&p->loop, &p->async, NULL); /* Just wake the loop */
-  p->interrupt_event = event_holder(p, PN_PROACTOR_INTERRUPT);
-  p->inactive_event = event_holder(p, PN_PROACTOR_INACTIVE);
-  p->timeout_event = event_holder(p, PN_PROACTOR_TIMEOUT);
   return p;
 }
 
@@ -741,8 +781,19 @@ void pn_proactor_free(pn_proactor_t *p) {
   uv_loop_close(&p->loop);
   uv_mutex_destroy(&p->lock);
   uv_cond_destroy(&p->cond);
-  pn_collector_free(p->interrupt_event);
-  pn_collector_free(p->inactive_event);
-  pn_collector_free(p->timeout_event);
+  pn_collector_free(p->collector);
   free(p);
 }
+
+static pn_event_t *listener_batch_next(pn_event_batch_t *batch) {
+  pn_listener_t *l = batch_listener(batch);
+  pn_event_t *handled = pn_collector_prev(l->collector);
+  if (handled && pn_event_type(handled) == PN_LISTENER_CLOSE) {
+    owner_to_leader(&l->psocket, leader_close); /* Close event handled, do close */
+  }
+  return pn_collector_next(l->collector);
+}
+
+static pn_event_t *proactor_batch_next(pn_event_batch_t *batch) {
+  return pn_collector_next(batch_proactor(batch)->collector);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index acdae0c..88e3456 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -20,7 +20,7 @@
  */
 
 #include <proton/connection.h>
-#include <proton/connection_engine.h>
+#include <proton/connection_driver.h>
 #include <proton/delivery.h>
 #include <proton/proactor.h>
 #include <proton/link.h>
@@ -37,12 +37,13 @@
 typedef char str[1024];
 
 typedef struct app_data_t {
-    str address;
-    str container_id;
-    pn_rwbytes_t message_buffer;
-    int message_count;
-    int received;
-    pn_proactor_t *proactor;
+  str address;
+  str container_id;
+  pn_rwbytes_t message_buffer;
+  int message_count;
+  int received;
+  pn_proactor_t *proactor;
+  bool finished;
 } app_data_t;
 
 static const int BATCH = 100; /* Batch size for unlimited receive */
@@ -80,9 +81,7 @@ static void decode_message(pn_delivery_t *dlv) {
   }
 }
 
-/* Handle event, return true of we should handle more */
-static bool handle(app_data_t* app, pn_event_t* event) {
-  bool more = true;
+static void handle(app_data_t* app, pn_event_t* event) {
   switch (pn_event_type(event)) {
 
    case PN_CONNECTION_INIT: {
@@ -149,53 +148,58 @@ static bool handle(app_data_t* app, pn_event_t* event) {
     break;
 
    case PN_PROACTOR_INACTIVE:
-    more = false;
+    app->finished = true;
     break;
 
    default: break;
   }
-  pn_event_done(event);
-  return more;
 }
 
 static void usage(const char *arg0) {
-    fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
-    exit(1);
+  fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
+  exit(1);
 }
 
 int main(int argc, char **argv) {
-    /* Default values for application and connection. */
-    app_data_t app = {{0}};
-    app.message_count = 100;
-    const char* urlstr = NULL;
-
-    int opt;
-    while((opt = getopt(argc, argv, "a:m:")) != -1) {
-        switch(opt) {
-          case 'a': urlstr = optarg; break;
-          case 'm': app.message_count = atoi(optarg); break;
-          default: usage(argv[0]); break;
-        }
+  /* Default values for application and connection. */
+  app_data_t app = {{0}};
+  app.message_count = 100;
+  const char* urlstr = NULL;
+
+  int opt;
+  while((opt = getopt(argc, argv, "a:m:")) != -1) {
+    switch(opt) {
+     case 'a': urlstr = optarg; break;
+     case 'm': app.message_count = atoi(optarg); break;
+     default: usage(argv[0]); break;
     }
-    if (optind < argc)
-        usage(argv[0]);
-
-    snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
-
-    /* Parse the URL or use default values */
-    pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-    const char *host = url ? pn_url_get_host(url) : NULL;
-    const char *port = url ? pn_url_get_port(url) : "amqp";
-    strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
-
-    /* Create the proactor and connect */
-    app.proactor = pn_proactor();
-    pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
-    if (url) pn_url_free(url);
-
-    while (handle(&app, pn_proactor_wait(app.proactor)))
-           ;
-    pn_proactor_free(app.proactor);
-    free(app.message_buffer.start);
-    return exit_code;
+  }
+  if (optind < argc)
+    usage(argv[0]);
+
+  snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
+
+  /* Parse the URL or use default values */
+  pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
+  const char *host = url ? pn_url_get_host(url) : NULL;
+  const char *port = url ? pn_url_get_port(url) : "amqp";
+  strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
+
+  /* Create the proactor and connect */
+  app.proactor = pn_proactor();
+  pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
+  if (url) pn_url_free(url);
+
+  do {
+    pn_event_batch_t *events = pn_proactor_wait(app.proactor);
+    pn_event_t *e;
+    while ((e = pn_event_batch_next(events))) {
+      handle(&app, e);
+    }
+    pn_proactor_done(app.proactor, events);
+  } while(!app.finished);
+
+  pn_proactor_free(app.proactor);
+  free(app.message_buffer.start);
+  return exit_code;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index 5d58895..d64ea2d 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -20,7 +20,7 @@
  */
 
 #include <proton/connection.h>
-#include <proton/connection_engine.h>
+#include <proton/connection_driver.h>
 #include <proton/delivery.h>
 #include <proton/proactor.h>
 #include <proton/link.h>
@@ -37,13 +37,14 @@
 typedef char str[1024];
 
 typedef struct app_data_t {
-    str address;
-    str container_id;
-    pn_rwbytes_t message_buffer;
-    int message_count;
-    int sent;
-    int acknowledged;
-    pn_proactor_t *proactor;
+  str address;
+  str container_id;
+  pn_rwbytes_t message_buffer;
+  int message_count;
+  int sent;
+  int acknowledged;
+  pn_proactor_t *proactor;
+  bool finished;
 } app_data_t;
 
 int exit_code = 0;
@@ -58,41 +59,39 @@ static void check_condition(pn_event_t *e, pn_condition_t *cond) {
 
 /* Create a message with a map { "sequence" : number } encode it and return the encoded buffer. */
 static pn_bytes_t encode_message(app_data_t* app) {
-    /* Construct a message with the map { "sequence": app.sent } */
-    pn_message_t* message = pn_message();
-    pn_data_put_int(pn_message_id(message), app->sent); /* Set the message_id also */
-    pn_data_t* body = pn_message_body(message);
-    pn_data_put_map(body);
-    pn_data_enter(body);
-    pn_data_put_string(body, pn_bytes(sizeof("sequence")-1, "sequence"));
-    pn_data_put_int(body, app->sent); /* The sequence number */
-    pn_data_exit(body);
-
-    /* encode the message, expanding the encode buffer as needed */
-    if (app->message_buffer.start == NULL) {
-        static const size_t initial_size = 128;
-        app->message_buffer = pn_rwbytes(initial_size, (char*)malloc(initial_size));
-    }
-    /* app->message_buffer is the total buffer space available. */
-    /* mbuf wil point at just the portion used by the encoded message */
-    pn_rwbytes_t mbuf = pn_rwbytes(app->message_buffer.size, app->message_buffer.start);
-    int status = 0;
-    while ((status = pn_message_encode(message, mbuf.start, &mbuf.size)) == PN_OVERFLOW) {
-        app->message_buffer.size *= 2;
-        app->message_buffer.start = (char*)realloc(app->message_buffer.start, app->message_buffer.size);
-        mbuf.size = app->message_buffer.size;
-    }
-    if (status != 0) {
-        fprintf(stderr, "error encoding message: %s\n", pn_error_text(pn_message_error(message)));
-        exit(1);
-    }
-    pn_message_free(message);
-    return pn_bytes(mbuf.size, mbuf.start);
+  /* Construct a message with the map { "sequence": app.sent } */
+  pn_message_t* message = pn_message();
+  pn_data_put_int(pn_message_id(message), app->sent); /* Set the message_id also */
+  pn_data_t* body = pn_message_body(message);
+  pn_data_put_map(body);
+  pn_data_enter(body);
+  pn_data_put_string(body, pn_bytes(sizeof("sequence")-1, "sequence"));
+  pn_data_put_int(body, app->sent); /* The sequence number */
+  pn_data_exit(body);
+
+  /* encode the message, expanding the encode buffer as needed */
+  if (app->message_buffer.start == NULL) {
+    static const size_t initial_size = 128;
+    app->message_buffer = pn_rwbytes(initial_size, (char*)malloc(initial_size));
+  }
+  /* app->message_buffer is the total buffer space available. */
+  /* mbuf wil point at just the portion used by the encoded message */
+  pn_rwbytes_t mbuf = pn_rwbytes(app->message_buffer.size, app->message_buffer.start);
+  int status = 0;
+  while ((status = pn_message_encode(message, mbuf.start, &mbuf.size)) == PN_OVERFLOW) {
+    app->message_buffer.size *= 2;
+    app->message_buffer.start = (char*)realloc(app->message_buffer.start, app->message_buffer.size);
+    mbuf.size = app->message_buffer.size;
+  }
+  if (status != 0) {
+    fprintf(stderr, "error encoding message: %s\n", pn_error_text(pn_message_error(message)));
+    exit(1);
+  }
+  pn_message_free(message);
+  return pn_bytes(mbuf.size, mbuf.start);
 }
 
-/* Handle event, return true of we should handle more */
-static bool handle(app_data_t* app, pn_event_t* event) {
-  bool more = true;
+static void handle(app_data_t* app, pn_event_t* event) {
   switch (pn_event_type(event)) {
 
    case PN_CONNECTION_INIT: {
@@ -130,7 +129,7 @@ static bool handle(app_data_t* app, pn_event_t* event) {
      }
    } break;
 
-   case PN_TRANSPORT_ERROR:
+   case PN_TRANSPORT_CLOSED:
     check_condition(event, pn_transport_condition(pn_event_transport(event)));
     break;
 
@@ -151,53 +150,58 @@ static bool handle(app_data_t* app, pn_event_t* event) {
     break;
 
    case PN_PROACTOR_INACTIVE:
-    more = false;
+    app->finished = true;
     break;
 
    default: break;
   }
-  pn_event_done(event);
-  return more;
 }
 
 static void usage(const char *arg0) {
-    fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
-    exit(1);
+  fprintf(stderr, "Usage: %s [-a url] [-m message-count]\n", arg0);
+  exit(1);
 }
 
 int main(int argc, char **argv) {
-    /* Default values for application and connection. */
-    app_data_t app = {{0}};
-    app.message_count = 100;
-    const char* urlstr = NULL;
-
-    int opt;
-    while((opt = getopt(argc, argv, "a:m:")) != -1) {
-        switch(opt) {
-          case 'a': urlstr = optarg; break;
-          case 'm': app.message_count = atoi(optarg); break;
-          default: usage(argv[0]); break;
-        }
+  /* Default values for application and connection. */
+  app_data_t app = {{0}};
+  app.message_count = 100;
+  const char* urlstr = NULL;
+
+  int opt;
+  while((opt = getopt(argc, argv, "a:m:")) != -1) {
+    switch(opt) {
+     case 'a': urlstr = optarg; break;
+     case 'm': app.message_count = atoi(optarg); break;
+     default: usage(argv[0]); break;
     }
-    if (optind < argc)
-        usage(argv[0]);
-
-    snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
-
-    /* Parse the URL or use default values */
-    pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-    const char *host = url ? pn_url_get_host(url) : NULL;
-    const char *port = url ? pn_url_get_port(url) : "amqp";
-    strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
-
-    /* Create the proactor and connect */
-    app.proactor = pn_proactor();
-    pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
-    if (url) pn_url_free(url);
-
-    while (handle(&app, pn_proactor_wait(app.proactor)))
-           ;
-    pn_proactor_free(app.proactor);
-    free(app.message_buffer.start);
-    return exit_code;
+  }
+  if (optind < argc)
+    usage(argv[0]);
+
+  snprintf(app.container_id, sizeof(app.container_id), "%s:%d", argv[0], getpid());
+
+  /* Parse the URL or use default values */
+  pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
+  const char *host = url ? pn_url_get_host(url) : NULL;
+  const char *port = url ? pn_url_get_port(url) : "amqp";
+  strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
+
+  /* Create the proactor and connect */
+  app.proactor = pn_proactor();
+  pn_proactor_connect(app.proactor, host, port, pn_rwbytes_null);
+  if (url) pn_url_free(url);
+
+  do {
+    pn_event_batch_t *events = pn_proactor_wait(app.proactor);
+    pn_event_t *e;
+    while ((e = pn_event_batch_next(events))) {
+      handle(&app, e);
+    }
+    pn_proactor_done(app.proactor, events);
+  } while(!app.finished);
+
+  pn_proactor_free(app.proactor);
+  free(app.message_buffer.start);
+  return exit_code;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/examples/cpp/README.dox
----------------------------------------------------------------------
diff --git a/examples/cpp/README.dox b/examples/cpp/README.dox
index 1d46ec8..447d3ad 100644
--- a/examples/cpp/README.dox
+++ b/examples/cpp/README.dox
@@ -123,7 +123,7 @@ subscribe.
 /** @example mt/epoll_container.cpp
 
 An example implementation of the proton::container API that shows how
-to use the proton::io::connection_engine SPI to adapt the proton API
+to use the proton::io::connection_driver SPI to adapt the proton API
 to native IO, in this case using a multithreaded Linux epoll poller as
 the implementation.
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/examples/cpp/mt/epoll_container.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/mt/epoll_container.cpp b/examples/cpp/mt/epoll_container.cpp
index d9b9f08..7646673 100644
--- a/examples/cpp/mt/epoll_container.cpp
+++ b/examples/cpp/mt/epoll_container.cpp
@@ -25,7 +25,7 @@
 #include <proton/url.hpp>
 
 #include <proton/io/container_impl_base.hpp>
-#include <proton/io/connection_engine.hpp>
+#include <proton/io/connection_driver.hpp>
 #include <proton/io/link_namer.hpp>
 
 #include <atomic>
@@ -97,7 +97,7 @@ class unique_fd {
 };
 
 class pollable;
-class pollable_engine;
+class pollable_driver;
 class pollable_listener;
 
 class epoll_container : public proton::io::container_impl_base {
@@ -124,7 +124,7 @@ class epoll_container : public proton::io::container_impl_base {
     std::string id() const OVERRIDE { return id_; }
 
     // Functions used internally.
-    proton::connection add_engine(proton::connection_options opts, int fd, bool server);
+    proton::connection add_driver(proton::connection_options opts, int fd, bool server);
     void erase(pollable*);
 
     // Link names must be unique per container.
@@ -160,7 +160,7 @@ class epoll_container : public proton::io::container_impl_base {
 
     proton::connection_options options_;
     std::map<std::string, std::unique_ptr<pollable_listener> > listeners_;
-    std::map<pollable*, std::unique_ptr<pollable_engine> > engines_;
+    std::map<pollable*, std::unique_ptr<pollable_driver> > drivers_;
 
     std::condition_variable stopped_;
     bool stopping_;
@@ -274,21 +274,21 @@ class epoll_event_loop : public proton::event_loop {
     bool closed_;
 };
 
-// Handle epoll wakeups for a connection_engine.
-class pollable_engine : public pollable {
+// Handle epoll wakeups for a connection_driver.
+class pollable_driver : public pollable {
   public:
-    pollable_engine(epoll_container& c, int fd, int epoll_fd) :
+    pollable_driver(epoll_container& c, int fd, int epoll_fd) :
         pollable(fd, epoll_fd),
         loop_(new epoll_event_loop(*this)),
-        engine_(c, loop_)
+        driver_(c, loop_)
     {
-        proton::connection conn = engine_.connection();
+        proton::connection conn = driver_.connection();
         proton::io::set_link_namer(conn, c.link_namer);
     }
 
-    ~pollable_engine() {
+    ~pollable_driver() {
         loop_->close();                // No calls to notify() after this.
-        engine_.dispatch();            // Run any final events.
+        driver_.dispatch();            // Run any final events.
         try { write(); } catch(...) {} // Write connection close if we can.
         for (auto f : loop_->pop_all()) {// Run final queued work for side-effects.
             try { f(); } catch(...) {}
@@ -303,17 +303,17 @@ class pollable_engine : public pollable {
                 can_read = can_read && read();
                 for (auto f : loop_->pop_all()) // Run queued work
                     f();
-                engine_.dispatch();
+                driver_.dispatch();
             } while (can_read || can_write);
-            return (engine_.read_buffer().size ? EPOLLIN:0) |
-                (engine_.write_buffer().size ? EPOLLOUT:0);
+            return (driver_.read_buffer().size ? EPOLLIN:0) |
+                (driver_.write_buffer().size ? EPOLLOUT:0);
         } catch (const std::exception& e) {
-            engine_.disconnected(proton::error_condition("exception", e.what()));
+            driver_.disconnected(proton::error_condition("exception", e.what()));
         }
         return 0;               // Ending
     }
 
-    proton::io::connection_engine& engine() { return engine_; }
+    proton::io::connection_driver& driver() { return driver_; }
 
   private:
     static bool try_again(int e) {
@@ -322,11 +322,11 @@ class pollable_engine : public pollable {
     }
 
     bool write() {
-        proton::io::const_buffer wbuf(engine_.write_buffer());
+        proton::io::const_buffer wbuf(driver_.write_buffer());
         if (wbuf.size) {
             ssize_t n = ::write(fd_, wbuf.data, wbuf.size);
             if (n > 0) {
-                engine_.write_done(n);
+                driver_.write_done(n);
                 return true;
             } else if (n < 0 && !try_again(errno)) {
                 check(n, "write");
@@ -336,15 +336,15 @@ class pollable_engine : public pollable {
     }
 
     bool read() {
-        proton::io::mutable_buffer rbuf(engine_.read_buffer());
+        proton::io::mutable_buffer rbuf(driver_.read_buffer());
         if (rbuf.size) {
             ssize_t n = ::read(fd_, rbuf.data, rbuf.size);
             if (n > 0) {
-                engine_.read_done(n);
+                driver_.read_done(n);
                 return true;
             }
             else if (n == 0)
-                engine_.read_close();
+                driver_.read_close();
             else if (!try_again(errno))
                 check(n, "read");
         }
@@ -352,13 +352,13 @@ class pollable_engine : public pollable {
     }
 
     // Lifecycle note: loop_ belongs to the proton::connection, which can live
-    // longer than the engine if the application holds a reference to it, we
-    // disconnect ourselves with loop_->close() in ~connection_engine()
+    // longer than the driver if the application holds a reference to it, we
+    // disconnect ourselves with loop_->close() in ~connection_driver()
     epoll_event_loop* loop_;
-    proton::io::connection_engine engine_;
+    proton::io::connection_driver driver_;
 };
 
-// A pollable listener fd that creates pollable_engine for incoming connections.
+// A pollable listener fd that creates pollable_driver for incoming connections.
 class pollable_listener : public pollable {
   public:
     pollable_listener(
@@ -380,7 +380,7 @@ class pollable_listener : public pollable {
         }
         try {
             int accepted = check(::accept(fd_, NULL, 0), "accept");
-            container_.add_engine(listener_.on_accept(), accepted, true);
+            container_.add_driver(listener_.on_accept(), accepted, true);
             return EPOLLIN;
         } catch (const std::exception& e) {
             listener_.on_error(e.what());
@@ -424,25 +424,25 @@ epoll_container::~epoll_container() {
     } catch (...) {}
 }
 
-proton::connection epoll_container::add_engine(proton::connection_options opts, int fd, bool server)
+proton::connection epoll_container::add_driver(proton::connection_options opts, int fd, bool server)
 {
     lock_guard g(lock_);
     if (stopping_)
         throw proton::error("container is stopping");
-    std::unique_ptr<pollable_engine> eng(new pollable_engine(*this, fd, epoll_fd_));
+    std::unique_ptr<pollable_driver> eng(new pollable_driver(*this, fd, epoll_fd_));
     if (server)
-        eng->engine().accept(opts);
+        eng->driver().accept(opts);
     else
-        eng->engine().connect(opts);
-    proton::connection c = eng->engine().connection();
+        eng->driver().connect(opts);
+    proton::connection c = eng->driver().connection();
     eng->notify();
-    engines_[eng.get()] = std::move(eng);
+    drivers_[eng.get()] = std::move(eng);
     return c;
 }
 
 void epoll_container::erase(pollable* e) {
     lock_guard g(lock_);
-    if (!engines_.erase(e)) {
+    if (!drivers_.erase(e)) {
         pollable_listener* l = dynamic_cast<pollable_listener*>(e);
         if (l)
             listeners_.erase(l->addr());
@@ -451,7 +451,7 @@ void epoll_container::erase(pollable* e) {
 }
 
 void epoll_container::idle_check(const lock_guard&) {
-    if (stopping_  && engines_.empty() && listeners_.empty())
+    if (stopping_  && drivers_.empty() && listeners_.empty())
         interrupt();
 }
 
@@ -462,7 +462,7 @@ proton::returned<proton::connection> epoll_container::connect(
     unique_addrinfo ainfo(addr);
     unique_fd fd(check(::socket(ainfo->ai_family, SOCK_STREAM, 0), msg));
     check(::connect(fd, ainfo->ai_addr, ainfo->ai_addrlen), msg);
-    return make_thread_safe(add_engine(opts, fd.release(), false));
+    return make_thread_safe(add_driver(opts, fd.release(), false));
 }
 
 proton::listener epoll_container::listen(const std::string& addr, proton::listen_handler& lh) {
@@ -520,10 +520,10 @@ void epoll_container::stop(const proton::error_condition& err) {
 void epoll_container::wait() {
     std::unique_lock<std::mutex> l(lock_);
     stopped_.wait(l, [this]() { return this->threads_ == 0; } );
-    for (auto& eng : engines_)
-        eng.second->engine().disconnected(stop_err_);
+    for (auto& eng : drivers_)
+        eng.second->driver().disconnected(stop_err_);
     listeners_.clear();
-    engines_.clear();
+    drivers_.clear();
 }
 
 void epoll_container::interrupt() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index ddab147..ffc6e10 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -369,7 +369,7 @@ set (qpid-proton-core
   src/core/encoder.c
 
   src/core/dispatcher.c
-  src/core/connection_engine.c
+  src/core/connection_driver.c
   src/core/engine.c
   src/core/event.c
   src/core/autodetect.c
@@ -440,7 +440,7 @@ set (qpid-proton-include
   include/proton/codec.h
   include/proton/condition.h
   include/proton/connection.h
-  include/proton/connection_engine.h
+  include/proton/connection_driver.h
   include/proton/delivery.h
   include/proton/disposition.h
   include/proton/engine.h

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index ed969eb..6af4319 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -48,7 +48,7 @@ set(qpid-proton-cpp-source
   src/error_condition.cpp
   src/event_loop.cpp
   src/handler.cpp
-  src/io/connection_engine.cpp
+  src/io/connection_driver.cpp
   src/io/link_namer.cpp
   src/link.cpp
   src/listener.cpp

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/docs/io.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/io.md b/proton-c/bindings/cpp/docs/io.md
index a892e61..230e538 100644
--- a/proton-c/bindings/cpp/docs/io.md
+++ b/proton-c/bindings/cpp/docs/io.md
@@ -7,16 +7,16 @@ The `proton::io` namespace contains a service provider interface (SPI)
 that allows you to implement the Proton API over alternative IO or
 threading libraries.
 
-The `proton::io::connection_engine` class converts an AMQP-encoded
+The `proton::io::connection_driver` class converts an AMQP-encoded
 byte stream, read from any IO source, into `proton::messaging_handler`
 calls. It generates an AMQP-encoded byte stream as output that can be
 written to any IO destination.
 
-The connection engine is deliberately very simple and low level. It
+The connection driver is deliberately very simple and low level. It
 performs no IO of its own, no thread-related locking, and is written
 in simple C++98-compatible code.
 
-The connection engine can be used standalone as an AMQP translator, or
+The connection dirver can be used standalone as an AMQP translator, or
 you can implement the following two interfaces to provide a complete
 implementation of the Proton API that can run any Proton application:
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/docs/main.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/docs/main.md b/proton-c/bindings/cpp/docs/main.md
index 011df29..93ba2c0 100644
--- a/proton-c/bindings/cpp/docs/main.md
+++ b/proton-c/bindings/cpp/docs/main.md
@@ -123,6 +123,6 @@ The default container implementation is created using
 `proton::default_container`.
 
 You can implement your own container to integrate proton with any IO
-provider using the `proton::io::connection_engine`.
+provider using the `proton::io::connection_driver`.
 
 @see @ref io_page

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/include/proton/connection_options.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/connection_options.hpp b/proton-c/bindings/cpp/include/proton/connection_options.hpp
index 9fbdbdc..d2deebf 100644
--- a/proton-c/bindings/cpp/include/proton/connection_options.hpp
+++ b/proton-c/bindings/cpp/include/proton/connection_options.hpp
@@ -40,7 +40,7 @@ class proton_handler;
 class connection;
 
 namespace io {
-class connection_engine;
+class connection_driver;
 }
 
 /// Options for creating a connection.
@@ -163,7 +163,7 @@ class connection_options {
     /// @cond INTERNAL
   friend class container_impl;
   friend class connector;
-  friend class io::connection_engine;
+  friend class io::connection_driver;
   friend class connection;
     /// @endcond
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
new file mode 100644
index 0000000..d5da718
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
@@ -0,0 +1,211 @@
+#ifndef PROTON_IO_CONNECTION_DRIVER_HPP
+#define PROTON_IO_CONNECTION_DRIVER_HPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../internal/config.hpp"
+#include "../connection.hpp"
+#include "../connection_options.hpp"
+#include "../error.hpp"
+#include "../error_condition.hpp"
+#include "../internal/export.hpp"
+#include "../internal/pn_unique_ptr.hpp"
+#include "../transport.hpp"
+#include "../types.hpp"
+
+#include <proton/connection_driver.h>
+
+#include <cstddef>
+#include <utility>
+#include <string>
+
+namespace proton {
+
+class event_loop;
+class proton_handler;
+
+namespace io {
+
+/// **Experimental** - Pointer to a mutable memory region with a size.
+struct mutable_buffer {
+    char* data;                 ///< Beginning of the buffered data.
+    size_t size;                ///< Number of bytes in the buffer.
+
+    /// Construct a buffer starting at data_ with size_ bytes.
+    mutable_buffer(char* data_=0, size_t size_=0) : data(data_), size(size_) {}
+};
+
+/// **Experimental** - Pointer to a const memory region with a size.
+struct const_buffer {
+    const char* data;           ///< Beginning of the buffered data.
+    size_t size;                ///< Number of bytes in the buffer.
+
+    /// Construct a buffer starting at data_ with size_ bytes.
+    const_buffer(const char* data_=0, size_t size_=0) : data(data_), size(size_) {}
+};
+
+/// **Experimental** - An AMQP driver for a single connection.
+///
+/// io::connection_driver manages a single proton::connection and dispatches
+/// events to a proton::messaging_handler. It does no IO of its own, but allows you to
+/// integrate AMQP protocol handling into any IO or concurrency framework.
+///
+/// The application is coded the same way as for the
+/// proton::container. The application implements a
+/// proton::messaging_handler to respond to transport, connection,
+/// session, link, and message events. With a little care, the same
+/// handler classes can be used for both container and
+/// connection_driver. the @ref broker.cpp example illustrates this.
+///
+/// You need to write the IO code to read AMQP data to the
+/// read_buffer(). The engine parses the AMQP frames. dispatch() calls
+/// the appropriate functions on the applications proton::messaging_handler. You
+/// write output data from the engine's write_buffer() to your IO.
+///
+/// The engine is not safe for concurrent use, but you can process
+/// different engines concurrently. A common pattern for
+/// high-performance servers is to serialize read/write activity
+/// per connection and dispatch in a fixed-size thread pool.
+///
+/// The engine is designed to work with a classic reactor (e.g.,
+/// select, poll, epoll) or an async-request driven proactor (e.g.,
+/// windows completion ports, boost.asio, libuv).
+///
+/// The engine never throws exceptions.
+class
+PN_CPP_CLASS_EXTERN connection_driver {
+  public:
+    /// An engine that is not associated with a proton::container or
+    /// proton::event_loop.
+    ///
+    /// Accessing the container or event_loop for this connection in
+    /// a proton::messaging_handler will throw a proton::error exception.
+    ///
+    PN_CPP_EXTERN connection_driver();
+
+    /// Create a connection driver associated with a proton::container and
+    /// optional event_loop. If the event_loop is not provided attempts to use
+    /// it will throw proton::error.
+    ///
+    /// Takes ownership of the event_loop. Note the proton::connection created
+    /// by this connection_driver can outlive the connection_driver itself if
+    /// the user pins it in memory using the proton::thread_safe<> template.
+    /// The event_loop is deleted when, and only when, the proton::connection is.
+    ///
+    PN_CPP_EXTERN connection_driver(proton::container&, event_loop* loop = 0);
+
+    PN_CPP_EXTERN ~connection_driver();
+
+    /// Configure a connection by applying exactly the options in opts (including proton::messaging_handler)
+    /// Does not apply any default options, to apply container defaults use connect() or accept()
+    /// instead. If server==true, configure a server connection.
+    void configure(const connection_options& opts=connection_options(), bool server=false);
+
+    /// Call configure() with client options and call connection::open()
+    /// Options applied: container::id(), container::client_connection_options(), opts.
+    PN_CPP_EXTERN void connect(const connection_options& opts);
+
+    /// Call configure() with server options.
+    /// Options applied: container::id(), container::server_connection_options(), opts.
+    ///
+    /// Note this does not call connection::open(). If there is a messaging_handler in the
+    /// composed options it will receive messaging_handler::on_connection_open() and can
+    /// respond with connection::open() or connection::close()
+    PN_CPP_EXTERN void accept(const connection_options& opts);
+
+    /// The engine's read buffer. Read data into this buffer then call read_done() when complete.
+    /// Returns mutable_buffer(0, 0) if the engine cannot currently read data.
+    /// Calling dispatch() may open up more buffer space.
+    PN_CPP_EXTERN mutable_buffer read_buffer();
+
+    /// Indicate that the first n bytes of read_buffer() have valid data.
+    /// This changes the buffer, call read_buffer() to get the updated buffer.
+    PN_CPP_EXTERN void read_done(size_t n);
+
+    /// Indicate that the read side of the transport is closed and no more data will be read.
+    /// Note that there may still be events to dispatch() or data to write.
+    PN_CPP_EXTERN void read_close();
+
+    /// The engine's write buffer. Write data from this buffer then call write_done()
+    /// Returns const_buffer(0, 0) if the engine has nothing to write.
+    /// Calling dispatch() may generate more data in the write buffer.
+    PN_CPP_EXTERN const_buffer write_buffer();
+
+    /// Indicate that the first n bytes of write_buffer() have been written successfully.
+    /// This changes the buffer, call write_buffer() to get the updated buffer.
+    PN_CPP_EXTERN void write_done(size_t n);
+
+    /// Indicate that the write side of the transport has closed and no more data can be written.
+    /// Note that there may still be events to dispatch() or data to read.
+    PN_CPP_EXTERN void write_close();
+
+    /// Inform the engine that the transport been disconnected unexpectedly,
+    /// without completing the AMQP connection close sequence.
+    ///
+    /// This calls read_close(), write_close(), sets the transport().error() and
+    /// queues an `on_transport_error` event. You must call dispatch() one more
+    /// time to dispatch the messaging_handler::on_transport_error() call and other final
+    /// events.
+    ///
+    /// Note this does not close the connection() so that a proton::messaging_handler can
+    /// distinguish between a connection close error sent by the remote peer and
+    /// a transport failure.
+    ///
+    PN_CPP_EXTERN void disconnected(const error_condition& = error_condition());
+
+    /// Dispatch all available events and call the corresponding \ref messaging_handler methods.
+    ///
+    /// Returns true if the engine is still active, false if it is finished and
+    /// can be destroyed. The engine is finished when all events are dispatched
+    /// and one of the following is true:
+    ///
+    /// - both read_close() and write_close() have been called, no more IO is possible.
+    /// - The AMQP connection() is closed AND the write_buffer() is empty.
+    ///
+    /// May modify the read_buffer() and/or the write_buffer().
+    ///
+    PN_CPP_EXTERN bool dispatch();
+
+    /// Get the AMQP connection associated with this connection_driver.
+    /// The event_loop is availabe via proton::thread_safe<connection>(connection())
+    PN_CPP_EXTERN proton::connection connection() const;
+
+    /// Get the transport associated with this connection_driver.
+    PN_CPP_EXTERN proton::transport transport() const;
+
+    /// Get the container associated with this connection_driver, if there is one.
+    PN_CPP_EXTERN proton::container* container() const;
+
+ private:
+    void init();
+    connection_driver(const connection_driver&);
+    connection_driver& operator=(const connection_driver&);
+
+    messaging_handler* handler_;
+    proton::container* container_;
+    pn_connection_driver_t driver_;
+};
+
+} // io
+} // proton
+
+#endif // PROTON_IO_CONNECTION_DRIVER_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp b/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
deleted file mode 100644
index d9825c2..0000000
--- a/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifndef PROTON_IO_CONNECTION_ENGINE_HPP
-#define PROTON_IO_CONNECTION_ENGINE_HPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "../internal/config.hpp"
-#include "../connection.hpp"
-#include "../connection_options.hpp"
-#include "../error.hpp"
-#include "../error_condition.hpp"
-#include "../internal/export.hpp"
-#include "../internal/pn_unique_ptr.hpp"
-#include "../transport.hpp"
-#include "../types.hpp"
-
-#include <proton/connection_engine.h>
-
-#include <cstddef>
-#include <utility>
-#include <string>
-
-namespace proton {
-
-class event_loop;
-class proton_handler;
-
-namespace io {
-
-/// **Experimental** - Pointer to a mutable memory region with a size.
-struct mutable_buffer {
-    char* data;                 ///< Beginning of the buffered data.
-    size_t size;                ///< Number of bytes in the buffer.
-
-    /// Construct a buffer starting at data_ with size_ bytes.
-    mutable_buffer(char* data_=0, size_t size_=0) : data(data_), size(size_) {}
-};
-
-/// **Experimental** - Pointer to a const memory region with a size.
-struct const_buffer {
-    const char* data;           ///< Beginning of the buffered data.
-    size_t size;                ///< Number of bytes in the buffer.
-
-    /// Construct a buffer starting at data_ with size_ bytes.
-    const_buffer(const char* data_=0, size_t size_=0) : data(data_), size(size_) {}
-};
-
-/// **Experimental** - An AMQP protocol engine for a single
-/// connection.
-///
-/// A connection_engine is a protocol engine that integrates AMQP into
-/// any IO or concurrency framework.
-///
-/// io::connection_engine manages a single proton::connection and dispatches
-/// events to a proton::messaging_handler. It does no IO of its own, but allows you to
-/// integrate AMQP protocol handling into any IO or concurrency framework.
-///
-/// The application is coded the same way as for the
-/// proton::container. The application implements a
-/// proton::messaging_handler to respond to transport, connection,
-/// session, link, and message events. With a little care, the same
-/// handler classes can be used for both container and
-/// connection_engine. the @ref broker.cpp example illustrates this.
-///
-/// You need to write the IO code to read AMQP data to the
-/// read_buffer(). The engine parses the AMQP frames. dispatch() calls
-/// the appropriate functions on the applications proton::messaging_handler. You
-/// write output data from the engine's write_buffer() to your IO.
-///
-/// The engine is not safe for concurrent use, but you can process
-/// different engines concurrently. A common pattern for
-/// high-performance servers is to serialize read/write activity
-/// per connection and dispatch in a fixed-size thread pool.
-///
-/// The engine is designed to work with a classic reactor (e.g.,
-/// select, poll, epoll) or an async-request driven proactor (e.g.,
-/// windows completion ports, boost.asio, libuv).
-///
-/// The engine never throws exceptions.
-class
-PN_CPP_CLASS_EXTERN connection_engine {
-  public:
-    /// An engine that is not associated with a proton::container or
-    /// proton::event_loop.
-    ///
-    /// Accessing the container or event_loop for this connection in
-    /// a proton::messaging_handler will throw a proton::error exception.
-    ///
-    PN_CPP_EXTERN connection_engine();
-
-    /// Create a connection engine associated with a proton::container and
-    /// optional event_loop. If the event_loop is not provided attempts to use
-    /// it will throw proton::error.
-    ///
-    /// Takes ownership of the event_loop. Note the proton::connection created
-    /// by this connection_engine can outlive the connection_engine itself if
-    /// the user pins it in memory using the proton::thread_safe<> template.
-    /// The event_loop is deleted when, and only when, the proton::connection is.
-    ///
-    PN_CPP_EXTERN connection_engine(proton::container&, event_loop* loop = 0);
-
-    PN_CPP_EXTERN ~connection_engine();
-
-    /// Configure a connection by applying exactly the options in opts (including proton::messaging_handler)
-    /// Does not apply any default options, to apply container defaults use connect() or accept()
-    /// instead. If server==true, configure a server connection.
-    void configure(const connection_options& opts=connection_options(), bool server=false);
-
-    /// Call configure() with client options and call connection::open()
-    /// Options applied: container::id(), container::client_connection_options(), opts.
-    PN_CPP_EXTERN void connect(const connection_options& opts);
-
-    /// Call configure() with server options.
-    /// Options applied: container::id(), container::server_connection_options(), opts.
-    ///
-    /// Note this does not call connection::open(). If there is a messaging_handler in the
-    /// composed options it will receive messaging_handler::on_connection_open() and can
-    /// respond with connection::open() or connection::close()
-    PN_CPP_EXTERN void accept(const connection_options& opts);
-
-    /// The engine's read buffer. Read data into this buffer then call read_done() when complete.
-    /// Returns mutable_buffer(0, 0) if the engine cannot currently read data.
-    /// Calling dispatch() may open up more buffer space.
-    PN_CPP_EXTERN mutable_buffer read_buffer();
-
-    /// Indicate that the first n bytes of read_buffer() have valid data.
-    /// This changes the buffer, call read_buffer() to get the updated buffer.
-    PN_CPP_EXTERN void read_done(size_t n);
-
-    /// Indicate that the read side of the transport is closed and no more data will be read.
-    /// Note that there may still be events to dispatch() or data to write.
-    PN_CPP_EXTERN void read_close();
-
-    /// The engine's write buffer. Write data from this buffer then call write_done()
-    /// Returns const_buffer(0, 0) if the engine has nothing to write.
-    /// Calling dispatch() may generate more data in the write buffer.
-    PN_CPP_EXTERN const_buffer write_buffer();
-
-    /// Indicate that the first n bytes of write_buffer() have been written successfully.
-    /// This changes the buffer, call write_buffer() to get the updated buffer.
-    PN_CPP_EXTERN void write_done(size_t n);
-
-    /// Indicate that the write side of the transport has closed and no more data can be written.
-    /// Note that there may still be events to dispatch() or data to read.
-    PN_CPP_EXTERN void write_close();
-
-    /// Inform the engine that the transport been disconnected unexpectedly,
-    /// without completing the AMQP connection close sequence.
-    ///
-    /// This calls read_close(), write_close(), sets the transport().error() and
-    /// queues an `on_transport_error` event. You must call dispatch() one more
-    /// time to dispatch the messaging_handler::on_transport_error() call and other final
-    /// events.
-    ///
-    /// Note this does not close the connection() so that a proton::messaging_handler can
-    /// distinguish between a connection close error sent by the remote peer and
-    /// a transport failure.
-    ///
-    PN_CPP_EXTERN void disconnected(const error_condition& = error_condition());
-
-    /// Dispatch all available events and call the corresponding \ref messaging_handler methods.
-    ///
-    /// Returns true if the engine is still active, false if it is finished and
-    /// can be destroyed. The engine is finished when all events are dispatched
-    /// and one of the following is true:
-    ///
-    /// - both read_close() and write_close() have been called, no more IO is possible.
-    /// - The AMQP connection() is closed AND the write_buffer() is empty.
-    ///
-    /// May modify the read_buffer() and/or the write_buffer().
-    ///
-    PN_CPP_EXTERN bool dispatch();
-
-    /// Get the AMQP connection associated with this connection_engine.
-    /// The event_loop is availabe via proton::thread_safe<connection>(connection())
-    PN_CPP_EXTERN proton::connection connection() const;
-
-    /// Get the transport associated with this connection_engine.
-    PN_CPP_EXTERN proton::transport transport() const;
-
-    /// Get the container associated with this connection_engine, if there is one.
-    PN_CPP_EXTERN proton::container* container() const;
-
- private:
-    void init();
-    connection_engine(const connection_engine&);
-    connection_engine& operator=(const connection_engine&);
-
-    messaging_handler* handler_;
-    proton::container* container_;
-    pn_connection_engine_t engine_;
-};
-
-} // io
-} // proton
-
-#endif // PROTON_IO_CONNECTION_ENGINE_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/include/proton/messaging_handler.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/messaging_handler.hpp b/proton-c/bindings/cpp/include/proton/messaging_handler.hpp
index 2c5423f..acdcd30 100644
--- a/proton-c/bindings/cpp/include/proton/messaging_handler.hpp
+++ b/proton-c/bindings/cpp/include/proton/messaging_handler.hpp
@@ -40,7 +40,7 @@ class message;
 class messaging_adapter;
 
 namespace io {
-class connection_engine;
+class connection_driver;
 }
 
 /// A handler for Proton messaging events.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/include/proton/transport.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/transport.hpp b/proton-c/bindings/cpp/include/proton/transport.hpp
index bcd8a2f..10641e0 100644
--- a/proton-c/bindings/cpp/include/proton/transport.hpp
+++ b/proton-c/bindings/cpp/include/proton/transport.hpp
@@ -35,7 +35,7 @@ class error_condition;
 class sasl;
 
 namespace io {
-class connection_engine;
+class connection_driver;
 }
 
 /// A network channel supporting an AMQP connection.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/src/engine_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/engine_test.cpp b/proton-c/bindings/cpp/src/engine_test.cpp
index 6c3341f..991836d 100644
--- a/proton-c/bindings/cpp/src/engine_test.cpp
+++ b/proton-c/bindings/cpp/src/engine_test.cpp
@@ -24,7 +24,7 @@
 
 #include "proton/container.hpp"
 #include "proton/uuid.hpp"
-#include "proton/io/connection_engine.hpp"
+#include "proton/io/connection_driver.hpp"
 #include "proton/io/link_namer.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/types_fwd.hpp"
@@ -37,7 +37,7 @@ namespace {
 using namespace std;
 using namespace proton;
 
-using proton::io::connection_engine;
+using proton::io::connection_driver;
 using proton::io::const_buffer;
 using proton::io::mutable_buffer;
 
@@ -45,14 +45,14 @@ using test::dummy_container;
 
 typedef std::deque<char> byte_stream;
 
-/// In memory connection_engine that reads and writes from byte_streams
-struct in_memory_engine : public connection_engine {
+/// In memory connection_driver that reads and writes from byte_streams
+struct in_memory_engine : public connection_driver {
 
     byte_stream& reads;
     byte_stream& writes;
 
     in_memory_engine(byte_stream& rd, byte_stream& wr, class container& cont) :
-        connection_engine(cont), reads(rd), writes(wr) {}
+        connection_driver(cont), reads(rd), writes(wr) {}
 
     void do_read() {
         mutable_buffer rbuf = read_buffer();
@@ -247,7 +247,7 @@ void test_engine_disconnected() {
 
 void test_no_container() {
     // An engine with no container should throw, not crash.
-    connection_engine e;
+    connection_driver e;
     try {
         e.connection().container();
         FAIL("expected error");

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/src/include/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp
index 74a763c..1d4194e 100644
--- a/proton-c/bindings/cpp/src/include/contexts.hpp
+++ b/proton-c/bindings/cpp/src/include/contexts.hpp
@@ -24,7 +24,7 @@
 
 #include "proton/connection.hpp"
 #include "proton/container.hpp"
-#include "proton/io/connection_engine.hpp"
+#include "proton/io/connection_driver.hpp"
 #include "proton/event_loop.hpp"
 #include "proton/listen_handler.hpp"
 #include "proton/message.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/25706a47/proton-c/bindings/cpp/src/io/connection_driver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp
new file mode 100644
index 0000000..06b01d8
--- /dev/null
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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/connection_driver.hpp"
+
+#include "proton/event_loop.hpp"
+#include "proton/error.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/uuid.hpp"
+
+#include "contexts.hpp"
+#include "messaging_adapter.hpp"
+#include "msg.hpp"
+#include "proton_bits.hpp"
+#include "proton_event.hpp"
+
+#include <proton/connection.h>
+#include <proton/transport.h>
+#include <proton/event.h>
+
+#include <algorithm>
+
+
+namespace proton {
+namespace io {
+
+void connection_driver::init() {
+    if (pn_connection_driver_init(&driver_, pn_connection(), pn_transport()) != 0) {
+        this->~connection_driver(); // Dtor won't be called on throw from ctor.
+        throw proton::error(std::string("connection_driver allocation failed"));
+    }
+}
+
+connection_driver::connection_driver() : handler_(0), container_(0) { init(); }
+
+connection_driver::connection_driver(class container& cont, event_loop* loop) : handler_(0), container_(&cont) {
+    init();
+    connection_context& ctx = connection_context::get(connection());
+    ctx.container = container_;
+    ctx.event_loop.reset(loop);
+}
+
+connection_driver::~connection_driver() {
+    pn_connection_driver_destroy(&driver_);
+}
+
+// FIXME aconway 2016-11-16: rename _engine > _driver
+void connection_driver::configure(const connection_options& opts, bool server) {
+    proton::connection c(connection());
+    opts.apply_unbound(c);
+    if (server) pn_transport_set_server(driver_.transport);
+    pn_connection_driver_bind(&driver_);
+    opts.apply_bound(c);
+    handler_ =  opts.handler();
+    connection_context::get(connection()).collector =
+      pn_connection_collector(driver_.connection);
+}
+
+void connection_driver::connect(const connection_options& opts) {
+    connection_options all;
+    if (container_) {
+        all.container_id(container_->id());
+        all.update(container_->client_connection_options());
+    }
+    all.update(opts);
+    configure(all, false);
+    connection().open();
+}
+
+void connection_driver::accept(const connection_options& opts) {
+    connection_options all;
+    if (container_) {
+        all.container_id(container_->id());
+        all.update(container_->server_connection_options());
+    }
+    all.update(opts);
+    configure(all, true);
+}
+
+bool connection_driver::dispatch() {
+    pn_event_t* c_event;
+    while ((c_event = pn_connection_driver_next_event(&driver_)) != NULL) {
+        proton_event cpp_event(c_event, container_);
+        try {
+            if (handler_ != 0) {
+                messaging_adapter adapter(*handler_);
+                cpp_event.dispatch(adapter);
+            }
+        } catch (const std::exception& e) {
+            pn_condition_t *cond = pn_transport_condition(driver_.transport);
+            if (!pn_condition_is_set(cond)) {
+                pn_condition_format(cond, "exception", "%s", e.what());
+            }
+        }
+    }
+    return !pn_connection_driver_finished(&driver_);
+}
+
+mutable_buffer connection_driver::read_buffer() {
+    pn_rwbytes_t buffer = pn_connection_driver_read_buffer(&driver_);
+    return mutable_buffer(buffer.start, buffer.size);
+}
+
+void connection_driver::read_done(size_t n) {
+    return pn_connection_driver_read_done(&driver_, n);
+}
+
+void connection_driver::read_close() {
+    pn_connection_driver_read_close(&driver_);
+}
+
+const_buffer connection_driver::write_buffer() {
+    pn_bytes_t buffer = pn_connection_driver_write_buffer(&driver_);
+    return const_buffer(buffer.start, buffer.size);
+}
+
+void connection_driver::write_done(size_t n) {
+    return pn_connection_driver_write_done(&driver_, n);
+}
+
+void connection_driver::write_close() {
+    pn_connection_driver_write_close(&driver_);
+}
+
+void connection_driver::disconnected(const proton::error_condition& err) {
+    pn_condition_t* condition = pn_transport_condition(driver_.transport);
+    if (!pn_condition_is_set(condition))  {
+        set_error_condition(err, condition);
+    }
+    pn_connection_driver_close(&driver_);
+}
+
+proton::connection connection_driver::connection() const {
+    return make_wrapper(driver_.connection);
+}
+
+proton::transport connection_driver::transport() const {
+    return make_wrapper(driver_.transport);
+}
+
+proton::container* connection_driver::container() const {
+    return container_;
+}
+
+}}


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


[21/48] 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 ac...@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/go1
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


[14/48] 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 ac...@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


[28/48] qpid-proton git commit: PROTON-1344: Fix proactor listen and broker examples for interop

Posted by ac...@apache.org.
PROTON-1344: Fix proactor listen and broker examples for interop

Added AI_PASSIVE to listener getaddrinfo() call, more correct and portable.

Example broker default host is "::" which listens for IPv6 and IPv4 on same port
on systems that allow that (IPV6ONLY defaults off)

Note that IPv4-only systems will need to say `libuv_broker -a localhost` but
since most modern systems support IPv6, that seems better than having clients
simply fail to connect depending on whether they use localhost or ::1.


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

Branch: refs/heads/go1
Commit: 94bc2965a8a39b04f3d85b4aa1cfb287b2fc2144
Parents: ca45418
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Nov 14 10:21:07 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 16 19:52:38 2016 -0500

----------------------------------------------------------------------
 examples/c/proactor/broker.c         |  8 +++++---
 examples/c/proactor/libuv_proactor.c | 11 ++++++-----
 examples/c/proactor/receive.c        |  3 +--
 examples/c/proactor/send.c           |  3 +--
 4 files changed, 13 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/94bc2965/examples/c/proactor/broker.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/broker.c b/examples/c/proactor/broker.c
index 79f34bc..e11a8bd 100644
--- a/examples/c/proactor/broker.c
+++ b/examples/c/proactor/broker.c
@@ -446,9 +446,11 @@ int main(int argc, char **argv) {
 
   /* Parse the URL or use default values */
   pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
-  const char *host = url ? pn_url_get_host(url) : "localhost";
-  const char *port = url ? pn_url_get_port(url) : NULL;
-  if (!port) port = "amqp";
+  /* Listen on IPv6 wildcard. On systems that do not set IPV6ONLY by default,
+     this will also listen for mapped IPv4 on the same port.
+  */
+  const char *host = url ? pn_url_get_host(url) : "::";
+  const char *port = url ? pn_url_get_port(url) : "amqp";
 
   /* Initial broker_data value copied to each accepted connection */
   broker_data_t bd = { false };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/94bc2965/examples/c/proactor/libuv_proactor.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/libuv_proactor.c b/examples/c/proactor/libuv_proactor.c
index ce5b948..8dd2706 100644
--- a/examples/c/proactor/libuv_proactor.c
+++ b/examples/c/proactor/libuv_proactor.c
@@ -425,11 +425,12 @@ static void on_accept(uv_stream_t* server, int err) {
   }
 }
 
-static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info) {
+static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info, bool server) {
   int err = leader_init(ps);
+  struct addrinfo hints = { 0 };
+  if (server) hints.ai_flags = AI_PASSIVE;
   if (!err) {
-    err = uv_getaddrinfo(&ps->proactor->loop, info, NULL,
-                         fixstr(ps->host), fixstr(ps->port), NULL);
+    err = uv_getaddrinfo(&ps->proactor->loop, info, NULL, fixstr(ps->host), fixstr(ps->port), &hints);
   }
   return err;
 }
@@ -437,7 +438,7 @@ static int leader_resolve(psocket_t *ps, uv_getaddrinfo_t *info) {
 static void leader_connect(psocket_t *ps) {
   pconn *pc = as_pconn(ps);
   uv_getaddrinfo_t info;
-  int err = leader_resolve(ps, &info);
+  int err = leader_resolve(ps, &info, false);
   if (!err) {
     err = uv_tcp_connect(&pc->connect, &pc->psocket.tcp, info.addrinfo->ai_addr, on_connect);
     uv_freeaddrinfo(info.addrinfo);
@@ -450,7 +451,7 @@ static void leader_connect(psocket_t *ps) {
 static void leader_listen(psocket_t *ps) {
   pn_listener_t *l = as_listener(ps);
   uv_getaddrinfo_t info;
-  int err = leader_resolve(ps, &info);
+  int err = leader_resolve(ps, &info, true);
   if (!err) {
     err = uv_tcp_bind(&l->psocket.tcp, info.addrinfo->ai_addr, 0);
     uv_freeaddrinfo(info.addrinfo);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/94bc2965/examples/c/proactor/receive.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/receive.c b/examples/c/proactor/receive.c
index 303e348..acdae0c 100644
--- a/examples/c/proactor/receive.c
+++ b/examples/c/proactor/receive.c
@@ -185,8 +185,7 @@ int main(int argc, char **argv) {
     /* Parse the URL or use default values */
     pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
     const char *host = url ? pn_url_get_host(url) : NULL;
-    const char *port = url ? pn_url_get_port(url) : NULL;
-    if (!port) port = "amqp";
+    const char *port = url ? pn_url_get_port(url) : "amqp";
     strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
 
     /* Create the proactor and connect */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/94bc2965/examples/c/proactor/send.c
----------------------------------------------------------------------
diff --git a/examples/c/proactor/send.c b/examples/c/proactor/send.c
index 68ba0c8..5d58895 100644
--- a/examples/c/proactor/send.c
+++ b/examples/c/proactor/send.c
@@ -187,8 +187,7 @@ int main(int argc, char **argv) {
     /* Parse the URL or use default values */
     pn_url_t *url = urlstr ? pn_url_parse(urlstr) : NULL;
     const char *host = url ? pn_url_get_host(url) : NULL;
-    const char *port = url ? pn_url_get_port(url) : NULL;
-    if (!port) port = "amqp";
+    const char *port = url ? pn_url_get_port(url) : "amqp";
     strncpy(app.address, (url && pn_url_get_path(url)) ? pn_url_get_path(url) : "example", sizeof(app.address));
 
     /* Create the proactor and connect */


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


[41/48] qpid-proton git commit: PROTON-722: expose session properties and capabilities and wire up handling of them

Posted by ac...@apache.org.
PROTON-722: expose session properties and capabilities and wire up handling of them


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

Branch: refs/heads/go1
Commit: 331e3b9fafaad7e08f76ea7e2b82f6f690562cfc
Parents: 2d5b8d8
Author: Robert Gemmell <ro...@apache.org>
Authored: Mon Nov 21 18:04:54 2016 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Mon Nov 21 18:04:54 2016 +0000

----------------------------------------------------------------------
 .../org/apache/qpid/proton/engine/Session.java  |  87 ++++++++
 .../qpid/proton/engine/impl/SessionImpl.java    |  76 +++++++
 .../qpid/proton/engine/impl/TransportImpl.java  |  19 ++
 .../qpid/proton/systemtests/SessionTest.java    | 198 +++++++++++++++++++
 4 files changed, 380 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/331e3b9f/proton-j/src/main/java/org/apache/qpid/proton/engine/Session.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Session.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Session.java
index 2179dda..1a28c26 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Session.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Session.java
@@ -21,6 +21,9 @@
 package org.apache.qpid.proton.engine;
 
 import java.util.EnumSet;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
 
 
 /**
@@ -60,4 +63,88 @@ public interface Session extends Endpoint
      * @param outgoingWindowSize the outgoing window size
      */
     public void setOutgoingWindow(long outgoingWindowSize);
+
+    /**
+     * Sets the local session properties, to be conveyed to the peer via the Begin frame when
+     * attaching the session to the session.
+     *
+     * Must be called during session setup, i.e. before calling the {@link #open()} method.
+     *
+     * @param properties
+     *          the properties map to send, or null for none.
+     */
+    void setProperties(Map<Symbol, Object> properties);
+
+    /**
+     * Gets the local session properties.
+     *
+     * @return the properties map, or null if none was set.
+     *
+     * @see #setProperties(Map)
+     */
+    Map<Symbol, Object> getProperties();
+
+    /**
+     * Gets the remote session properties, as conveyed from the peer via the Begin frame
+     * when opening the session.
+     *
+     * @return the properties Map conveyed by the peer, or null if there was none.
+     */
+    Map<Symbol, Object> getRemoteProperties();
+
+    /**
+     * Sets the local session offered capabilities, to be conveyed to the peer via the Begin frame
+     * when opening the session.
+     *
+     * Must be called during session setup, i.e. before calling the {@link #open()} method.
+     *
+     * @param offeredCapabilities
+     *          the offered capabilities array to send, or null for none.
+     */
+    public void setOfferedCapabilities(Symbol[] offeredCapabilities);
+
+    /**
+     * Gets the local session offered capabilities.
+     *
+     * @return the offered capabilities array, or null if none was set.
+     *
+     * @see #setOfferedCapabilities(Symbol[])
+     */
+    Symbol[] getOfferedCapabilities();
+
+    /**
+     * Gets the remote session offered capabilities, as conveyed from the peer via the Begin frame
+     * when opening the session.
+     *
+     * @return the offered capabilities array conveyed by the peer, or null if there was none.
+     */
+    Symbol[] getRemoteOfferedCapabilities();
+
+    /**
+     * Sets the local session desired capabilities, to be conveyed to the peer via the Begin frame
+     * when opening the session.
+     *
+     * Must be called during session setup, i.e. before calling the {@link #open()} method.
+     *
+     * @param desiredCapabilities
+     *          the desired capabilities array to send, or null for none.
+     */
+    public void setDesiredCapabilities(Symbol[] desiredCapabilities);
+
+    /**
+     * Gets the local session desired capabilities.
+     *
+     * @return the desired capabilities array, or null if none was set.
+     *
+     * @see #setDesiredCapabilities(Symbol[])
+     */
+    Symbol[] getDesiredCapabilities();
+
+    /**
+     * Gets the remote session desired capabilities, as conveyed from the peer via the Begin frame
+     * when opening the session.
+     *
+     * @return the desired capabilities array conveyed by the peer, or null if there was none.
+     */
+    Symbol[] getRemoteDesiredCapabilities();
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/331e3b9f/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
index e5dd9e8..c7b796d 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
@@ -26,6 +26,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.qpid.proton.amqp.Symbol;
 import org.apache.qpid.proton.engine.EndpointState;
 import org.apache.qpid.proton.engine.Event;
 import org.apache.qpid.proton.engine.ProtonJSession;
@@ -45,6 +46,12 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
     private int _incomingDeliveries = 0;
     private int _outgoingDeliveries = 0;
     private long _outgoingWindow = Integer.MAX_VALUE;
+    private Map<Symbol, Object> _properties;
+    private Map<Symbol, Object> _remoteProperties;
+    private Symbol[] _offeredCapabilities;
+    private Symbol[] _remoteOfferedCapabilities;
+    private Symbol[] _desiredCapabilities;
+    private Symbol[] _remoteDesiredCapabilities;
 
     private LinkNode<SessionImpl> _node;
 
@@ -286,4 +293,73 @@ public class SessionImpl extends EndpointImpl implements ProtonJSession
     {
         return _outgoingWindow;
     }
+
+    @Override
+    public Map<Symbol, Object> getProperties()
+    {
+        return _properties;
+    }
+
+    @Override
+    public void setProperties(Map<Symbol, Object> properties)
+    {
+        _properties = properties;
+    }
+
+    @Override
+    public Map<Symbol, Object> getRemoteProperties()
+    {
+        return _remoteProperties;
+    }
+
+    void setRemoteProperties(Map<Symbol, Object> remoteProperties)
+    {
+        _remoteProperties = remoteProperties;
+    }
+
+    @Override
+    public Symbol[] getDesiredCapabilities()
+    {
+        return _desiredCapabilities;
+    }
+
+    @Override
+    public void setDesiredCapabilities(Symbol[] desiredCapabilities)
+    {
+        _desiredCapabilities = desiredCapabilities;
+    }
+
+    @Override
+    public Symbol[] getRemoteDesiredCapabilities()
+    {
+        return _remoteDesiredCapabilities;
+    }
+
+    void setRemoteDesiredCapabilities(Symbol[] remoteDesiredCapabilities)
+    {
+        _remoteDesiredCapabilities = remoteDesiredCapabilities;
+    }
+
+    @Override
+    public Symbol[] getOfferedCapabilities()
+    {
+        return _offeredCapabilities;
+    }
+
+    @Override
+    public void setOfferedCapabilities(Symbol[] offeredCapabilities)
+    {
+        _offeredCapabilities = offeredCapabilities;
+    }
+
+    @Override
+    public Symbol[] getRemoteOfferedCapabilities()
+    {
+        return _remoteOfferedCapabilities;
+    }
+
+    void setRemoteOfferedCapabilities(Symbol[] remoteOfferedCapabilities)
+    {
+        _remoteOfferedCapabilities = remoteOfferedCapabilities;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/331e3b9f/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
index bb2e43b..42126b0 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
@@ -881,6 +881,21 @@ public class TransportImpl extends EndpointImpl
                         begin.setOutgoingWindow(transportSession.getOutgoingWindowSize());
                         begin.setNextOutgoingId(transportSession.getNextOutgoingId());
 
+                        if(session.getProperties() != null)
+                        {
+                            begin.setProperties(session.getProperties());
+                        }
+
+                        if(session.getOfferedCapabilities() != null)
+                        {
+                            begin.setOfferedCapabilities(session.getOfferedCapabilities());
+                        }
+
+                        if(session.getDesiredCapabilities() != null)
+                        {
+                            begin.setDesiredCapabilities(session.getDesiredCapabilities());
+                        }
+
                         writeFrame(channelId, begin, null, null);
                         transportSession.sentBegin();
                     }
@@ -1118,6 +1133,10 @@ public class TransportImpl extends EndpointImpl
             transportSession.setRemoteChannel(channel);
             session.setRemoteState(EndpointState.ACTIVE);
             transportSession.setNextIncomingId(begin.getNextOutgoingId());
+            session.setRemoteProperties(begin.getProperties());
+            session.setRemoteDesiredCapabilities(begin.getDesiredCapabilities());
+            session.setRemoteOfferedCapabilities(begin.getOfferedCapabilities());
+
             _remoteSessions.put(channel, transportSession);
 
             _connectionEndpoint.put(Event.Type.SESSION_REMOTE_OPEN, session);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/331e3b9f/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SessionTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SessionTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SessionTest.java
new file mode 100644
index 0000000..728c6b9
--- /dev/null
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/SessionTest.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.proton.systemtests;
+
+import static java.util.EnumSet.of;
+import static org.apache.qpid.proton.engine.EndpointState.ACTIVE;
+import static org.apache.qpid.proton.engine.EndpointState.UNINITIALIZED;
+import static org.apache.qpid.proton.systemtests.TestLoggingHelper.bold;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.junit.Test;
+
+public class SessionTest extends EngineTestBase
+{
+    private static final Logger LOGGER = Logger.getLogger(SessionTest.class.getName());
+
+    @Test
+    public void testCapabilities() throws Exception
+    {
+        final Symbol clientOfferedCap = Symbol.valueOf("clientOfferedCapability");
+        final Symbol clientDesiredCap = Symbol.valueOf("clientDesiredCapability");
+        final Symbol serverOfferedCap = Symbol.valueOf("serverOfferedCapability");
+        final Symbol serverDesiredCap = Symbol.valueOf("serverDesiredCapability");
+
+        Symbol[] clientOfferedCapabilities = new Symbol[] { clientOfferedCap };
+        Symbol[] clientDesiredCapabilities = new Symbol[] { clientDesiredCap };
+
+        Symbol[] serverOfferedCapabilities = new Symbol[] { serverOfferedCap };
+        Symbol[] serverDesiredCapabilities = new Symbol[] { serverDesiredCap };
+
+        LOGGER.fine(bold("======== About to create transports"));
+
+        getClient().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getClient().transport, TestLoggingHelper.CLIENT_PREFIX);
+
+        getServer().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getServer().transport, "            " + TestLoggingHelper.SERVER_PREFIX);
+
+        doOutputInputCycle();
+
+        getClient().connection = Proton.connection();
+        getClient().transport.bind(getClient().connection);
+
+        getServer().connection = Proton.connection();
+        getServer().transport.bind(getServer().connection);
+
+        LOGGER.fine(bold("======== About to open connections"));
+        getClient().connection.open();
+        getServer().connection.open();
+
+        doOutputInputCycle();
+
+        LOGGER.fine(bold("======== About to open sessions"));
+        getClient().session = getClient().connection.session();
+
+        // Set the client session capabilities
+        getClient().session.setOfferedCapabilities(clientOfferedCapabilities);
+        getClient().session.setDesiredCapabilities(clientDesiredCapabilities);
+
+        getClient().session.open();
+
+        pumpClientToServer();
+
+        getServer().session = getServer().connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
+        assertEndpointState(getServer().session, UNINITIALIZED, ACTIVE);
+
+        // Set the server session capabilities
+        getServer().session.setOfferedCapabilities(serverOfferedCapabilities);
+        getServer().session.setDesiredCapabilities(serverDesiredCapabilities);
+
+        getServer().session.open();
+        assertEndpointState(getServer().session, ACTIVE, ACTIVE);
+
+        pumpServerToClient();
+
+        // Verify server side got the clients session capabilities as expected
+        Symbol[] serverRemoteOfferedCapabilities = getServer().session.getRemoteOfferedCapabilities();
+        assertNotNull("Server had no remote offered capabilities", serverRemoteOfferedCapabilities);
+        assertEquals("Server remote offered capabilities not expected size", 1, serverRemoteOfferedCapabilities.length);
+        assertTrue("Server remote offered capabilities lack expected value: " + clientOfferedCap, Arrays.asList(serverRemoteOfferedCapabilities).contains(clientOfferedCap));
+
+        Symbol[] serverRemoteDesiredCapabilities = getServer().session.getRemoteDesiredCapabilities();
+        assertNotNull("Server had no remote desired capabilities", serverRemoteDesiredCapabilities);
+        assertEquals("Server remote desired capabilities not expected size", 1, serverRemoteDesiredCapabilities.length);
+        assertTrue("Server remote desired capabilities lack expected value: " + clientDesiredCap, Arrays.asList(serverRemoteDesiredCapabilities).contains(clientDesiredCap));
+
+        // Verify the client side got the servers session capabilities as expected
+        Symbol[]  clientRemoteOfferedCapabilities = getClient().session.getRemoteOfferedCapabilities();
+        assertNotNull("Client had no remote offered capabilities", clientRemoteOfferedCapabilities);
+        assertEquals("Client remote offered capabilities not expected size", 1, clientRemoteOfferedCapabilities.length);
+        assertTrue("Client remote offered capabilities lack expected value: " + serverOfferedCap, Arrays.asList(clientRemoteOfferedCapabilities).contains(serverOfferedCap));
+
+        Symbol[]  clientRemoteDesiredCapabilities = getClient().session.getRemoteDesiredCapabilities();
+        assertNotNull("Client had no remote desired capabilities", clientRemoteDesiredCapabilities);
+        assertEquals("Client remote desired capabilities not expected size", 1, clientRemoteDesiredCapabilities.length);
+        assertTrue("Client remote desired capabilities lack expected value: " + serverDesiredCap, Arrays.asList(clientRemoteDesiredCapabilities).contains(serverDesiredCap));
+    }
+
+    @Test
+    public void testProperties() throws Exception
+    {
+        final Symbol clientPropName = Symbol.valueOf("ClientPropName");
+        final Integer clientPropValue = 1234;
+        final Symbol serverPropName = Symbol.valueOf("ServerPropName");
+        final Integer serverPropValue = 5678;
+
+        Map<Symbol, Object> clientProps = new HashMap<>();
+        clientProps.put(clientPropName, clientPropValue);
+
+        Map<Symbol, Object> serverProps = new HashMap<>();
+        serverProps.put(serverPropName, serverPropValue);
+
+        LOGGER.fine(bold("======== About to create transports"));
+
+        getClient().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getClient().transport, TestLoggingHelper.CLIENT_PREFIX);
+
+        getServer().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getServer().transport, "            " + TestLoggingHelper.SERVER_PREFIX);
+
+        doOutputInputCycle();
+
+        getClient().connection = Proton.connection();
+        getClient().transport.bind(getClient().connection);
+
+        getServer().connection = Proton.connection();
+        getServer().transport.bind(getServer().connection);
+
+        LOGGER.fine(bold("======== About to open connections"));
+        getClient().connection.open();
+        getServer().connection.open();
+
+        doOutputInputCycle();
+
+        LOGGER.fine(bold("======== About to open sessions"));
+        getClient().session = getClient().connection.session();
+
+        // Set the client session properties
+        getClient().session.setProperties(clientProps);
+
+        getClient().session.open();
+
+        pumpClientToServer();
+
+        getServer().session = getServer().connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
+        assertEndpointState(getServer().session, UNINITIALIZED, ACTIVE);
+
+        // Set the server session properties
+        getServer().session.setProperties(serverProps);
+
+        getServer().session.open();
+
+        assertEndpointState(getServer().session, ACTIVE, ACTIVE);
+
+        pumpServerToClient();
+
+        assertEndpointState(getClient().session, ACTIVE, ACTIVE);
+
+        // Verify server side got the clients session properties as expected
+        Map<Symbol, Object> serverRemoteProperties = getServer().session.getRemoteProperties();
+        assertNotNull("Server had no remote properties", serverRemoteProperties);
+        assertEquals("Server remote properties not expected size", 1, serverRemoteProperties.size());
+        assertTrue("Server remote properties lack expected key: " + clientPropName, serverRemoteProperties.containsKey(clientPropName));
+        assertEquals("Server remote properties contain unexpected value for key: " + clientPropName, clientPropValue, serverRemoteProperties.get(clientPropName));
+
+        // Verify the client side got the servers session properties as expected
+        Map<Symbol, Object> clientRemoteProperties = getClient().session.getRemoteProperties();
+        assertNotNull("Client had no remote properties", clientRemoteProperties);
+        assertEquals("Client remote properties not expected size", 1, clientRemoteProperties.size());
+        assertTrue("Client remote properties lack expected key: " + serverPropName, clientRemoteProperties.containsKey(serverPropName));
+        assertEquals("Client remote properties contain unexpected value for key: " + serverPropName, serverPropValue, clientRemoteProperties.get(serverPropName));
+    }
+}
\ No newline at end of file


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


[23/48] qpid-proton git commit: PROTON-1330: [python] bundle the C source in the python source distribution

Posted by ac...@apache.org.
PROTON-1330: [python] bundle the C source in the python source distribution

This closes #88


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

Branch: refs/heads/go1
Commit: 888862f9d149f11516fdec35bdb1e0fa1998c3c1
Parents: eac0bb6
Author: Ken Giusti <kg...@apache.org>
Authored: Tue Nov 1 13:21:15 2016 -0400
Committer: Ken Giusti <kg...@apache.org>
Committed: Wed Nov 16 08:58:22 2016 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt                       |  67 +++-
 proton-c/bindings/python/CMakeLists.txt       |  55 +++
 proton-c/bindings/python/MANIFEST.in          |   3 +
 proton-c/bindings/python/PACKAGING.txt        |  26 ++
 proton-c/bindings/python/README.rst.in        |  11 +
 proton-c/bindings/python/setup.py             | 401 ---------------------
 proton-c/bindings/python/setup.py.in          | 323 +++++++++++++++++
 proton-c/bindings/python/setuputils/bundle.py |  92 -----
 proton-c/bindings/python/setuputils/misc.py   |  38 +-
 proton-c/tox.ini.in                           |   3 +-
 10 files changed, 506 insertions(+), 513 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 3cf01cd..7753f1f 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -91,6 +91,11 @@ add_custom_command (
   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py
   )
 
+add_custom_target(
+  generated_c_files
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
+  )
+
 # Select IO impl
 if(PN_WINAPI)
   set (pn_io_impl src/reactor/io/windows/io.c src/reactor/io/windows/iocp.c src/reactor/io/windows/write_pipeline.c)
@@ -300,16 +305,38 @@ pn_absolute_install_dir(EXEC_PREFIX "." ${CMAKE_INSTALL_PREFIX})
 pn_absolute_install_dir(LIBDIR ${LIB_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
 pn_absolute_install_dir(INCLUDEDIR ${INCLUDE_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX})
 
-add_subdirectory(bindings)
 add_subdirectory(docs/api)
 add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
 
+# for full source distribution:
+set (qpid-proton-platform-all
+  src/platform/platform.c
+  src/reactor/io/windows/io.c
+  src/reactor/io/windows/iocp.c
+  src/reactor/io/windows/write_pipeline.c
+  src/reactor/io/windows/selector.c
+  src/reactor/io/posix/io.c
+  src/reactor/io/posix/selector.c
+  )
+
+# platform specific library build:
 set (qpid-proton-platform-io
   src/platform/platform.c
   ${pn_io_impl}
   ${pn_selector_impl}
   )
 
+# for full source distribution:
+set (qpid-proton-layers-all
+  src/sasl/sasl.c
+  src/sasl/cyrus_sasl.c
+  src/sasl/none_sasl.c
+  src/ssl/openssl.c
+  src/ssl/schannel.c
+  src/ssl/ssl_stub.c
+  )
+
+# for current build system's environment:
 set (qpid-proton-layers
   ${pn_sasl_impl}
   ${pn_ssl_impl}
@@ -347,6 +374,37 @@ set (qpid-proton-core
 set (qpid-proton-include-generated
   ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h
   ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h
+  ${CMAKE_CURRENT_BINARY_DIR}/include/proton/version.h
+  )
+
+set (qpid-proton-private-includes
+  src/extra/scanner.h
+  src/messenger/store.h
+  src/messenger/subscription.h
+  src/messenger/messenger.h
+  src/messenger/transform.h
+  src/ssl/ssl-internal.h
+  src/sasl/sasl-internal.h
+  src/core/autodetect.h
+  src/core/log_private.h
+  src/core/config.h
+  src/core/encoder.h
+  src/core/dispatch_actions.h
+  src/core/engine-internal.h
+  src/core/transport.h
+  src/core/framing.h
+  src/core/buffer.h
+  src/core/util.h
+  src/core/dispatcher.h
+  src/core/data.h
+  src/core/decoder.h
+  src/reactor/io/windows/iocp.h
+  src/reactor/selector.h
+  src/reactor/io.h
+  src/reactor/reactor.h
+  src/reactor/selectable.h
+  src/platform/platform.h
+  src/platform/platform_fmt.h
   )
 
 set (qpid-proton-extra
@@ -376,6 +434,7 @@ set (qpid-proton-include
   include/proton/codec.h
   include/proton/condition.h
   include/proton/connection.h
+  include/proton/connection_engine.h
   include/proton/delivery.h
   include/proton/disposition.h
   include/proton/engine.h
@@ -404,6 +463,10 @@ set (qpid-proton-include-extra
   include/proton/url.h
 )
 
+# note: process bindings after the source lists have been defined so
+# the bindings can reference them
+add_subdirectory(bindings)
+
 source_group("API Header Files" FILES ${qpid-proton-include} ${qpid-proton-include-extra})
 
 set_source_files_properties (
@@ -441,6 +504,7 @@ add_library (
   ${qpid-proton-include}
   ${qpid-proton-include-generated}
   )
+add_dependencies(qpid-proton-core generated_c_files)
 
 target_link_libraries (qpid-proton-core ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
 
@@ -466,6 +530,7 @@ add_library(
   ${qpid-proton-platform-io}
   ${qpid-proton-include-extra}
   )
+add_dependencies(qpid-proton generated_c_files)
 
 target_link_libraries (qpid-proton ${UUID_LIB} ${SSL_LIB} ${SASL_LIB} ${TIME_LIB} ${PLATFORM_LIBS})
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt
index fc28417..fe732d9 100644
--- a/proton-c/bindings/python/CMakeLists.txt
+++ b/proton-c/bindings/python/CMakeLists.txt
@@ -64,6 +64,13 @@ set (pysrc
     proton/wrapper.py
     proton/_compat.py
     )
+# extra files included in the source distribution
+set(py_dist_files
+    cproton.i
+    MANIFEST.in
+    setuputils
+    docs
+    )
 
 macro (py_compile directory files artifacts)
   foreach (src_file ${files})
@@ -122,3 +129,51 @@ install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME}
         COMPONENT Python)
 
 set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "html;tutorial")
+
+#
+# Set up the directory 'dist' for building the python native package
+# source distribution for Pypi/pip
+#
+
+set(py_dist_dir ${CMAKE_CURRENT_BINARY_DIR}/dist)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
+               ${py_dist_dir}/setup.py
+)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/README.rst.in
+               ${py_dist_dir}/README.rst
+)
+
+file(COPY ${py_dist_files} DESTINATION ${py_dist_dir})
+
+file(MAKE_DIRECTORY ${py_dist_dir}/proton)
+file(COPY ${pysrc} DESTINATION ${py_dist_dir}/proton)
+
+add_custom_target(py_src_dist ALL)
+add_dependencies(py_src_dist generated_c_files)
+file(MAKE_DIRECTORY ${py_dist_dir}/proton-c)
+
+# copy generated source files from the binary dir to the dist
+foreach(sfile ${qpid-proton-include-generated})
+  string(REPLACE ${CMAKE_BINARY_DIR} ${py_dist_dir} dfile ${sfile})
+  add_custom_command(TARGET py_src_dist
+                     COMMAND ${CMAKE_COMMAND} -E
+                         copy ${sfile} ${dfile})
+endforeach()
+
+# copy the proton C sources to the dist
+set (all_src
+  ${qpid-proton-core}
+  ${qpid-proton-extra}
+  ${qpid-proton-include}
+  ${qpid-proton-include-extra}
+  ${qpid-proton-layers-all}
+  ${qpid-proton-platform-all}
+  ${qpid-proton-private-includes}
+  include/proton/cproton.i
+)
+foreach(sfile ${all_src})
+  add_custom_command(TARGET py_src_dist
+                     COMMAND ${CMAKE_COMMAND} -E
+                         copy ${CMAKE_SOURCE_DIR}/proton-c/${sfile} ${py_dist_dir}/proton-c/${sfile})
+endforeach()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/MANIFEST.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/MANIFEST.in b/proton-c/bindings/python/MANIFEST.in
index a89a962..a37ad72 100644
--- a/proton-c/bindings/python/MANIFEST.in
+++ b/proton-c/bindings/python/MANIFEST.in
@@ -1,2 +1,5 @@
 graft docs
 graft setuputils
+graft proton-c
+global-exclude proton-c *.pyc *.pyo
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/PACKAGING.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/PACKAGING.txt b/proton-c/bindings/python/PACKAGING.txt
new file mode 100644
index 0000000..fa127f0
--- /dev/null
+++ b/proton-c/bindings/python/PACKAGING.txt
@@ -0,0 +1,26 @@
+This document describes how to build a native Python source package.
+This can be used to install the Python bindings via pip.
+
+First configure the project using 'cmake' then build it. You do not
+need to install the project. See the INSTALL.md file at the project's
+top directory for details on building.
+
+Once you have built the project, there should be a 'dist' directory in
+the Python bindings directory in the build directory.
+
+For example, assuming the build directory is named 'build':
+
+$ cd build/proton-c/bindings/python/dist
+
+You can now run the setup.py script from within the dist directory to
+build your source distribution package.
+
+To build a Python source distribution:
+
+$ python ./setup.py sdist
+
+To build and install:
+
+$ python ./setup.py build install
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/README.rst.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/README.rst.in b/proton-c/bindings/python/README.rst.in
new file mode 100644
index 0000000..8be1dd3
--- /dev/null
+++ b/proton-c/bindings/python/README.rst.in
@@ -0,0 +1,11 @@
+Python bindings for Qpid Proton
+===============================
+
+This module provides version @PN_VERSION_MAJOR@.@PN_VERSION_MINOR@.@PN_VERSION_POINT@ of the Proton AMQP messaging toolkit.
+
+Qpid Proton is a high-performance, lightweight messaging library. It
+can be used in the widest range of messaging applications, including
+brokers, client libraries, routers, bridges, proxies, and more. Proton
+makes it trivial to integrate with the AMQP 1.0 ecosystem from any
+platform, environment, or language.  More about `Proton <http://qpid.apache.org/proton/index.html>`_.
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setup.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py b/proton-c/bindings/python/setup.py
deleted file mode 100755
index 3606bed..0000000
--- a/proton-c/bindings/python/setup.py
+++ /dev/null
@@ -1,401 +0,0 @@
-#!/usr/bin/env 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.
-
-"""
-python-qpid-proton setup script
-
-DISCLAIMER: This script took lots of inspirations from PyZMQ, which is licensed
-under the 'MODIFIED BSD LICENSE'.
-
-Although inspired by the work in PyZMQ, this script and the modules it depends
-on were largely simplified to meet the requirements of the library.
-
-The default behavior of this script is to build the registered `_cproton`
-extension using the system qpid-proton library. However, before doing that, the
-script will try to discover the available qpid-proton's version and whether it's
-suitable for the version of this library. This allows us to have a tight release
-between the versions of the bindings and qpid-proton's version.
-
-The versions used to verify this are in `setuputils.bundle` and they should be
-increased on every release. Note that `bundled_version` matches the current
-released version. The motivation behind this is that we don't know how many
-new releases will be made in the `0.9` series, therefore we need to target the
-latest possible.
-
-If qpid-proton is found in the system and the available versions are match the
-required ones, then the install process will continue normally.
-
-If the available versions are not good for the bindings or the library is
-missing, then the following will happen:
-
-The setup script will attempt to download the C source for qpid-proton - see
-`setuputils.bundle.fetch_libqpid_proton` - and it will include the proton C
-code into the extension itself.
-
-While the above removes the need of *always* having qpid-proton installed, it
-does not solve the need of having `swig` and the libraries qpid-proton requires
-installed to make this setup work.
-
-From the Python side, this scripts overrides 1 command - build_ext - and it adds a
-new one. The later - Configure - is called from the former to setup/discover what's
-in the system. The rest of the comands and steps are done normally without any kind
-of monkey patching.
-"""
-
-import glob
-import os
-import subprocess
-import sys
-
-import distutils.spawn as ds_spawn
-import distutils.sysconfig as ds_sys
-from distutils.ccompiler import new_compiler, get_default_compiler
-from distutils.core import setup, Extension
-from distutils.command.build import build
-from distutils.command.build_ext import build_ext
-from distutils.command.sdist import sdist
-from distutils import errors
-
-from setuputils import bundle
-from setuputils import log
-from setuputils import misc
-
-
-class CheckSDist(sdist):
-
-    def run(self):
-        self.distribution.run_command('configure')
-
-        # Append the source that was removed during
-        # the configuration step.
-        _cproton = self.distribution.ext_modules[-1]
-        _cproton.sources.append('cproton.i')
-
-        try:
-            sdist.run(self)
-        finally:
-            for src in ['cproton.py', 'cproton_wrap.c']:
-                if os.path.exists(src):
-                    os.remove(src)
-
-
-class Configure(build_ext):
-    description = "Discover Qpid Proton version"
-
-    @property
-    def compiler_type(self):
-        compiler = self.compiler
-        if compiler is None:
-            return get_default_compiler()
-        elif isinstance(compiler, str):
-            return compiler
-        else:
-            return compiler.compiler_type
-
-    def prepare_swig_wrap(self):
-        """Run swig against the sources.  This will cause swig to compile the
-        cproton.i file into a .c file called cproton_wrap.c, and create
-        cproton.py.
-        """
-        ext = self.distribution.ext_modules[-1]
-
-        if 'SWIG' in os.environ:
-            self.swig = os.environ['SWIG']
-
-        try:
-            # This will actually call swig to generate the files
-            # and list the sources.
-            self.swig_sources(ext.sources, ext)
-        except (errors.DistutilsExecError, errors.DistutilsPlatformError) as e:
-            if not (os.path.exists('cproton_wrap.c') or
-                    os.path.exists('cproton.py')):
-                raise e
-
-        # now remove the cproton.i file from the source list so we don't run
-        # swig again.
-        ext.sources = ext.sources[1:]
-        ext.swig_opts = []
-
-    def bundle_libqpid_proton_extension(self):
-        """The proper version of libqpid-proton is not present on the system,
-        so attempt to retrieve the proper libqpid-proton sources and
-        include them in the extension.
-        """
-        setup_path = os.path.dirname(os.path.realpath(__file__))
-        base = self.get_finalized_command('build').build_base
-        build_include = os.path.join(base, 'include')
-
-        log.info("Bundling qpid-proton into the extension")
-
-        # QPID_PROTON_SRC - (optional) pathname to the Proton C sources.  Can
-        # be used to override where this setup gets the Proton C sources from
-        # (see bundle.fetch_libqpid_proton())
-        if 'QPID_PROTON_SRC' not in os.environ:
-            if not os.path.exists(os.path.join(setup_path, 'CMakeLists.txt')):
-                bundledir = os.path.join(base, "bundled")
-                if not os.path.exists(bundledir):
-                    os.makedirs(bundledir)
-                bundle.fetch_libqpid_proton(bundledir)
-                libqpid_proton_dir = os.path.abspath(os.path.join(bundledir, 'qpid-proton'))
-            else:
-                # setup.py is being invoked from within the proton source tree
-                # (CMakeLists.txt is not present in the python source dist).
-                # In this case build using the local sources.  This use case is
-                # specifically for developers working on the proton source
-                # code.
-                proton_c = os.path.join(setup_path, '..', '..', '..')
-                libqpid_proton_dir = os.path.abspath(proton_c)
-        else:
-            libqpid_proton_dir = os.path.abspath(os.environ['QPID_PROTON_SRC'])
-
-        log.debug("Using libqpid-proton src: %s" % libqpid_proton_dir)
-
-        proton_base = os.path.join(libqpid_proton_dir, 'proton-c')
-        proton_src = os.path.join(proton_base, 'src')
-        proton_include = os.path.join(proton_base, 'include')
-
-        #
-        # Create any generated header files, and put them in build_include:
-        #
-        if not os.path.exists(build_include):
-            os.makedirs(build_include)
-            os.mkdir(os.path.join(build_include, 'proton'))
-
-        # Create copy of environment variables and modify PYTHONPATH to preserve
-        # all others environment variables defined by user. When `env` is specified
-        # Popen will not inherit environment variables of the current process.
-        proton_envs = os.environ.copy()
-        default_path = proton_envs.get('PYTHONPATH')
-        proton_envs['PYTHONPATH'] = proton_base if not default_path else '{0}{1}{2}'.format(
-            proton_base, os.pathsep, default_path)
-
-        # Generate `protocol.h` by calling the python
-        # script found in the source dir.
-        with open(os.path.join(build_include, 'protocol.h'), 'wb') as header:
-            subprocess.Popen([sys.executable, os.path.join(proton_src, 'protocol.h.py')],
-                              env=proton_envs, stdout=header)
-
-        # 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, 'encodings.h.py')],
-                              env=proton_envs, stdout=header)
-
-        # Create a custom, temporary, version.h file mapping the
-        # major and minor versions from the downloaded tarball. This version should
-        # match the ones in the bundle module
-        with open(os.path.join(build_include, 'proton', 'version.h'), "wb") as ver:
-            version_text = """
-#ifndef _PROTON_VERSION_H
-#define _PROTON_VERSION_H 1
-#define PN_VERSION_MAJOR %i
-#define PN_VERSION_MINOR %i
-#define PN_VERSION_POINT %i
-#endif /* version.h */
-""" % bundle.bundled_version
-            ver.write(version_text.encode('utf-8'))
-
-        # Collect all the Proton C files that need to be built.
-        # we could've used `glob(.., '*', '*.c')` but I preferred going
-        # with an explicit list of subdirs that we can control and expand
-        # depending on the version. Specifically, lets avoid adding things
-        # we don't need.
-
-        sources = []
-        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')))
-
-        sources.extend(filter(lambda x: not x.endswith('dump.c'),
-                       glob.iglob(os.path.join(proton_src, '*.c'))))
-
-        # Look for any optional libraries that proton needs, and adjust the
-        # source list and compile flags as necessary.
-        libraries = []
-
-        # -D flags (None means no value, just define)
-        macros=[('qpid_proton_EXPORTS', None),
-                ('USE_ATOLL', None),
-                ('USE_STRERROR_R', None)]
-
-        # Check whether openssl is installed by poking
-        # pkg-config for a minimum version 0. If it's installed, it should
-        # return True and we'll use it. Otherwise, we'll use the stub.
-        if misc.pkg_config_version(atleast='0', module='openssl'):
-            libraries += ['ssl', 'crypto']
-            sources.append(os.path.join(proton_src, 'ssl', 'openssl.c'))
-        else:
-            sources.append(os.path.join(proton_src, 'ssl', 'ssl_stub.c'))
-
-        # create a temp compiler to check for optional compile-time features
-        cc = new_compiler(compiler=self.compiler_type)
-        cc.output_dir = self.build_temp
-
-        # Some systems need to link to `rt`. Check whether `clock_gettime` is
-        # around and if librt is needed
-        if cc.has_function('clock_gettime'):
-            macros.append(('USE_CLOCK_GETTIME', None))
-        else:
-            if cc.has_function('clock_gettime', libraries=['rt']):
-                libraries.append('rt')
-                macros.append(('USE_CLOCK_GETTIME', None))
-
-        # 0.10 added an implementation for cyrus. Check
-        # if it is available before adding the implementation to the sources
-        # list. Eventually, `sasl.c` will be added and one of the existing
-        # implementations will be used.
-        if cc.has_function('sasl_client_done', includes=['sasl/sasl.h'],
-                           libraries=['sasl2']):
-            libraries.append('sasl2')
-            sources.append(os.path.join(proton_src, 'sasl', 'cyrus_sasl.c'))
-        else:
-            sources.append(os.path.join(proton_src, 'sasl', 'none_sasl.c'))
-
-        sources.append(os.path.join(proton_src, 'sasl', 'sasl.c'))
-
-        # compile all the proton sources.  We'll add the resulting list of
-        # objects to the _cproton extension as 'extra objects'.  We do this
-        # instead of just lumping all the sources into the extension to prevent
-        # any proton-specific compilation flags from affecting the compilation
-        # of the generated swig code
-
-        cc = new_compiler(compiler=self.compiler_type)
-        ds_sys.customize_compiler(cc)
-
-        objects = cc.compile(sources,
-                             macros=macros,
-                             include_dirs=[build_include,
-                                           proton_include,
-                                           proton_src],
-                             # compiler command line options:
-                             extra_postargs=['-std=gnu99'],
-                             output_dir=self.build_temp)
-
-        #
-        # Now update the _cproton extension instance to include the objects and
-        # libraries
-        #
-        _cproton = self.distribution.ext_modules[-1]
-        _cproton.extra_objects = objects
-        _cproton.include_dirs.append(build_include)
-        _cproton.include_dirs.append(proton_include)
-
-        # swig will need to access the proton headers:
-        _cproton.swig_opts.append('-I%s' % build_include)
-        _cproton.swig_opts.append('-I%s' % proton_include)
-
-        # lastly replace the libqpid-proton dependency with libraries required
-        # by the Proton objects:
-        _cproton.libraries=libraries
-
-    def check_qpid_proton_version(self):
-        """check the qpid_proton version"""
-
-        target_version = bundle.bundled_version_str
-        return (misc.pkg_config_version(max_version=target_version) and
-                misc.pkg_config_version(atleast=bundle.min_qpid_proton_str))
-
-    @property
-    def bundle_proton(self):
-        """Need to bundle proton if the conditions below are met."""
-        return ('QPID_PROTON_SRC' in os.environ) or \
-            (not self.check_qpid_proton_version())
-
-    def use_installed_proton(self):
-        """The Proton development headers and library are installed, update the
-        _cproton extension to tell it where to find the library and headers.
-        """
-        _cproton = self.distribution.ext_modules[-1]
-        incs = misc.pkg_config_get_var('includedir')
-        for i in incs.split():
-            _cproton.swig_opts.append('-I%s' % i)
-            _cproton.include_dirs.append(i)
-        ldirs = misc.pkg_config_get_var('libdir')
-        _cproton.library_dirs.extend(ldirs.split())
-
-    def run(self):
-        # check if the Proton library and headers are installed and are
-        # compatible with this version of the binding.
-        if self.bundle_proton:
-            # Proton not installed or compatible
-            self.bundle_libqpid_proton_extension()
-        else:
-            self.use_installed_proton()
-        self.prepare_swig_wrap()
-
-
-class CustomBuildOrder(build):
-    # The sole purpose of this class is to re-order
-    # the commands execution so that `build_ext` is executed *before*
-    # build_py. We need this to make sure `cproton.py` is generated
-    # before the python modules are collected. Otherwise, it won't
-    # be installed.
-    sub_commands = [
-        ('build_ext', build.has_ext_modules),
-        ('build_py', build.has_pure_modules),
-        ('build_clib', build.has_c_libraries),
-        ('build_scripts', build.has_scripts),
-    ]
-
-
-class CheckingBuildExt(build_ext):
-    """Subclass build_ext to build qpid-proton using `cmake`"""
-
-    def run(self):
-        # Discover qpid-proton in the system
-        self.distribution.run_command('configure')
-        build_ext.run(self)
-
-
-# Override `build_ext` and add `configure`
-cmdclass = {'configure': Configure,
-            'build': CustomBuildOrder,
-            'build_ext': CheckingBuildExt,
-            'sdist': CheckSDist}
-
-setup(name='python-qpid-proton',
-      version=bundle.bundled_version_str,
-      description='An AMQP based messaging library.',
-      author='Apache Qpid',
-      author_email='proton@qpid.apache.org',
-      url='http://qpid.apache.org/proton/',
-      packages=['proton'],
-      py_modules=['cproton'],
-      license="Apache Software License",
-      classifiers=["License :: OSI Approved :: Apache Software License",
-                   "Intended Audience :: Developers",
-                   "Programming Language :: Python",
-                   "Programming Language :: Python :: 2",
-                   "Programming Language :: Python :: 2.6",
-                   "Programming Language :: Python :: 2.7",
-                   "Programming Language :: Python :: 3",
-                   "Programming Language :: Python :: 3.3",
-                   "Programming Language :: Python :: 3.4",
-                   "Programming Language :: Python :: 3.5"],
-      cmdclass=cmdclass,
-      # Note well: the following extension instance is modified during the
-      # installation!  If you make changes below, you may need to update the
-      # Configure class above
-      ext_modules=[Extension('_cproton',
-                             sources=['cproton.i', 'cproton_wrap.c'],
-                             swig_opts=['-threads'],
-                             extra_compile_args=['-pthread'],
-                             libraries=['qpid-proton'])])

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setup.py.in
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py.in b/proton-c/bindings/python/setup.py.in
new file mode 100755
index 0000000..57f4368
--- /dev/null
+++ b/proton-c/bindings/python/setup.py.in
@@ -0,0 +1,323 @@
+#!/usr/bin/env 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.
+
+"""
+python-qpid-proton setup script
+
+DISCLAIMER: This script took lots of inspirations from PyZMQ, which is licensed
+under the 'MODIFIED BSD LICENSE'.
+
+Although inspired by the work in PyZMQ, this script and the modules it depends
+on were largely simplified to meet the requirements of the library.
+
+The behavior of this script is to build the registered `_cproton` extension
+using the installed Qpid Proton C library and header files. If the library and
+headers are not installed, or the installed version does not match the version
+of these python bindings, then the script will attempt to build the extension
+using the Proton C sources included in the python source distribution package.
+
+While the above removes the need of *always* having Qpid Proton C development
+files installed, it does not solve the need of having `swig` and the libraries
+qpid-proton requires installed to make this setup work.
+
+From the Python side, this scripts overrides 1 command - build_ext - and it adds a
+new one. The latter - Configure - is called from the former to setup/discover what's
+in the system. The rest of the comands and steps are done normally without any kind
+of monkey patching.
+"""
+
+import glob
+import os
+import subprocess
+import sys
+
+import distutils.spawn as ds_spawn
+import distutils.sysconfig as ds_sys
+from distutils.ccompiler import new_compiler, get_default_compiler
+from distutils.core import setup, Extension
+from distutils.command.build import build
+from distutils.command.build_ext import build_ext
+from distutils.command.sdist import sdist
+from distutils import errors
+
+from setuputils import log
+from setuputils import misc
+
+
+_PROTON_VERSION=(@PN_VERSION_MAJOR@,
+                 @PN_VERSION_MINOR@,
+                 @PN_VERSION_POINT@)
+_PROTON_VERSION_STR = "%d.%d.%d" % _PROTON_VERSION
+
+
+class CheckSDist(sdist):
+
+    def run(self):
+        self.distribution.run_command('configure')
+
+        # Append the source that was removed during
+        # the configuration step.
+        _cproton = self.distribution.ext_modules[-1]
+        _cproton.sources.append('cproton.i')
+
+        try:
+            sdist.run(self)
+        finally:
+            for src in ['cproton.py', 'cproton_wrap.c']:
+                if os.path.exists(src):
+                    os.remove(src)
+
+
+class Configure(build_ext):
+    description = "Discover Qpid Proton version"
+
+    @property
+    def compiler_type(self):
+        compiler = self.compiler
+        if compiler is None:
+            return get_default_compiler()
+        elif isinstance(compiler, str):
+            return compiler
+        else:
+            return compiler.compiler_type
+
+    def prepare_swig_wrap(self):
+        """Run swig against the sources.  This will cause swig to compile the
+        cproton.i file into a .c file called cproton_wrap.c, and create
+        cproton.py.
+        """
+        ext = self.distribution.ext_modules[-1]
+
+        if 'SWIG' in os.environ:
+            self.swig = os.environ['SWIG']
+
+        try:
+            # This will actually call swig to generate the files
+            # and list the sources.
+            self.swig_sources(ext.sources, ext)
+        except (errors.DistutilsExecError, errors.DistutilsPlatformError) as e:
+            if not (os.path.exists('cproton_wrap.c') or
+                    os.path.exists('cproton.py')):
+                raise e
+
+        # now remove the cproton.i file from the source list so we don't run
+        # swig again.
+        ext.sources = ext.sources[1:]
+        ext.swig_opts = []
+
+    def use_bundled_proton(self):
+        """The proper version of libqpid-proton is not installed on the system,
+        so use the included proton-c sources to build the extension
+        """
+        log.info("Building the bundled proton-c sources into the extension")
+
+        setup_path = os.path.dirname(os.path.realpath(__file__))
+        base = self.get_finalized_command('build').build_base
+        build_include = os.path.join(base, 'include')
+        proton_base = os.path.abspath(os.path.join(setup_path, 'proton-c'))
+        proton_src = os.path.join(proton_base, 'src')
+        proton_include = os.path.join(proton_base, 'include')
+
+        log.debug("Using Proton C sources: %s" % proton_base)
+
+        # Collect all the Proton C files that need to be built.
+        # we could've used `glob(.., '*', '*.c')` but I preferred going
+        # with an explicit list of subdirs that we can control and expand
+        # depending on the version. Specifically, lets avoid adding things
+        # we don't need.
+
+        sources = []
+        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')))
+
+        sources.extend(filter(lambda x: not x.endswith('dump.c'),
+                       glob.iglob(os.path.join(proton_src, '*.c'))))
+
+        # Look for any optional libraries that proton needs, and adjust the
+        # source list and compile flags as necessary.
+        libraries = []
+
+        # -D flags (None means no value, just define)
+        macros=[('qpid_proton_EXPORTS', None),
+                ('USE_ATOLL', None),
+                ('USE_STRERROR_R', None)]
+
+        # Check whether openssl is installed by poking
+        # pkg-config for a minimum version 0. If it's installed, it should
+        # return True and we'll use it. Otherwise, we'll use the stub.
+        if misc.pkg_config_version_installed('openssl', atleast='0'):
+            libraries += ['ssl', 'crypto']
+            sources.append(os.path.join(proton_src, 'ssl', 'openssl.c'))
+        else:
+            sources.append(os.path.join(proton_src, 'ssl', 'ssl_stub.c'))
+            log.warn("OpenSSL not installed - disabling SSL support!")
+
+        # create a temp compiler to check for optional compile-time features
+        cc = new_compiler(compiler=self.compiler_type)
+        cc.output_dir = self.build_temp
+
+        # Some systems need to link to `rt`. Check whether `clock_gettime` is
+        # around and if librt is needed
+        if cc.has_function('clock_gettime'):
+            macros.append(('USE_CLOCK_GETTIME', None))
+        else:
+            if cc.has_function('clock_gettime', libraries=['rt']):
+                libraries.append('rt')
+                macros.append(('USE_CLOCK_GETTIME', None))
+
+        # 0.10 added an implementation for cyrus. Check
+        # if it is available before adding the implementation to the sources
+        # list. Eventually, `sasl.c` will be added and one of the existing
+        # implementations will be used.
+        if cc.has_function('sasl_client_done', includes=['sasl/sasl.h'],
+                           libraries=['sasl2']):
+            libraries.append('sasl2')
+            sources.append(os.path.join(proton_src, 'sasl', 'cyrus_sasl.c'))
+        else:
+            sources.append(os.path.join(proton_src, 'sasl', 'none_sasl.c'))
+            log.warn("Cyrus SASL not installed - only the ANONYMOUS and"
+                     " PLAIN mechanisms will be supported!")
+        sources.append(os.path.join(proton_src, 'sasl', 'sasl.c'))
+
+        # compile all the proton sources.  We'll add the resulting list of
+        # objects to the _cproton extension as 'extra objects'.  We do this
+        # instead of just lumping all the sources into the extension to prevent
+        # any proton-specific compilation flags from affecting the compilation
+        # of the generated swig code
+
+        cc = new_compiler(compiler=self.compiler_type)
+        ds_sys.customize_compiler(cc)
+
+        objects = cc.compile(sources,
+                             macros=macros,
+                             include_dirs=[build_include,
+                                           proton_include,
+                                           proton_src],
+                             # compiler command line options:
+                             extra_postargs=['-std=gnu99'],
+                             output_dir=self.build_temp)
+
+        #
+        # Now update the _cproton extension instance passed to setup to include
+        # the objects and libraries
+        #
+        _cproton = self.distribution.ext_modules[-1]
+        _cproton.extra_objects = objects
+        _cproton.include_dirs.append(build_include)
+        _cproton.include_dirs.append(proton_include)
+
+        # swig will need to access the proton headers:
+        _cproton.swig_opts.append('-I%s' % build_include)
+        _cproton.swig_opts.append('-I%s' % proton_include)
+
+        # lastly replace the libqpid-proton dependency with libraries required
+        # by the Proton objects:
+        _cproton.libraries=libraries
+
+    def libqpid_proton_installed(self, version):
+        """Check to see if the proper version of the Proton development library
+        and headers are already installed
+        """
+        return misc.pkg_config_version_installed('libqpid-proton', version)
+
+    def use_installed_proton(self):
+        """The Proton development headers and library are installed, update the
+        _cproton extension to tell it where to find the library and headers.
+        """
+        # update the Extension instance passed to setup() to use the installed
+        # headers and link library
+        _cproton = self.distribution.ext_modules[-1]
+        incs = misc.pkg_config_get_var('libqpid-proton', 'includedir')
+        for i in incs.split():
+            _cproton.swig_opts.append('-I%s' % i)
+            _cproton.include_dirs.append(i)
+        ldirs = misc.pkg_config_get_var('libqpid-proton', 'libdir')
+        _cproton.library_dirs.extend(ldirs.split())
+
+    def run(self):
+        # check if the Proton library and headers are installed and are
+        # compatible with this version of the binding.
+        if self.libqpid_proton_installed(_PROTON_VERSION_STR):
+            self.use_installed_proton()
+        else:
+            # Proton not installed or compatible, use bundled proton-c sources
+            self.use_bundled_proton()
+        self.prepare_swig_wrap()
+
+
+class CustomBuildOrder(build):
+    # The sole purpose of this class is to re-order
+    # the commands execution so that `build_ext` is executed *before*
+    # build_py. We need this to make sure `cproton.py` is generated
+    # before the python modules are collected. Otherwise, it won't
+    # be installed.
+    sub_commands = [
+        ('build_ext', build.has_ext_modules),
+        ('build_py', build.has_pure_modules),
+        ('build_clib', build.has_c_libraries),
+        ('build_scripts', build.has_scripts),
+    ]
+
+
+class CheckingBuildExt(build_ext):
+    """Subclass build_ext to build qpid-proton using `cmake`"""
+
+    def run(self):
+        # Discover qpid-proton in the system
+        self.distribution.run_command('configure')
+        build_ext.run(self)
+
+
+# Override `build_ext` and add `configure`
+cmdclass = {'configure': Configure,
+            'build': CustomBuildOrder,
+            'build_ext': CheckingBuildExt,
+            'sdist': CheckSDist}
+
+setup(name='python-qpid-proton',
+      version=_PROTON_VERSION_STR + os.environ.get('PROTON_VERSION_SUFFIX', ''),
+      description='An AMQP based messaging library.',
+      author='Apache Qpid',
+      author_email='proton@qpid.apache.org',
+      url='http://qpid.apache.org/proton/',
+      packages=['proton'],
+      py_modules=['cproton'],
+      license="Apache Software License",
+      classifiers=["License :: OSI Approved :: Apache Software License",
+                   "Intended Audience :: Developers",
+                   "Programming Language :: Python",
+                   "Programming Language :: Python :: 2",
+                   "Programming Language :: Python :: 2.6",
+                   "Programming Language :: Python :: 2.7",
+                   "Programming Language :: Python :: 3",
+                   "Programming Language :: Python :: 3.3",
+                   "Programming Language :: Python :: 3.4",
+                   "Programming Language :: Python :: 3.5"],
+      cmdclass=cmdclass,
+      # Note well: the following extension instance is modified during the
+      # installation!  If you make changes below, you may need to update the
+      # Configure class above
+      ext_modules=[Extension('_cproton',
+                             sources=['cproton.i', 'cproton_wrap.c'],
+                             swig_opts=['-threads'],
+                             extra_compile_args=['-pthread'],
+                             libraries=['qpid-proton'])])

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setuputils/bundle.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/bundle.py b/proton-c/bindings/python/setuputils/bundle.py
deleted file mode 100644
index 1bf3450..0000000
--- a/proton-c/bindings/python/setuputils/bundle.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#-----------------------------------------------------------------------------
-#  Copyright (C) PyZMQ Developers
-#  Distributed under the terms of the Modified BSD License.
-#
-#  This bundling code is largely adapted from pyzmq-static's get.sh by
-#  Brandon Craig-Rhodes, which is itself BSD licensed.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-#  This bundling code is largely adapted from pyzmq's code
-#  PyZMQ Developers, which is itself Modified BSD licensed.
-#-----------------------------------------------------------------------------
-
-import os
-import shutil
-import stat
-import sys
-import tarfile
-from glob import glob
-from subprocess import Popen, PIPE
-
-try:
-    # py2
-    from urllib2 import urlopen
-except ImportError:
-    # py3
-    from urllib.request import urlopen
-
-from . import log
-
-
-#-----------------------------------------------------------------------------
-# Constants
-#-----------------------------------------------------------------------------
-min_qpid_proton = (0, 16, 0)
-min_qpid_proton_str = "%i.%i.%i" % min_qpid_proton
-
-bundled_version = (0, 16, 0)
-bundled_version_str = "%i.%i.%i" % bundled_version
-libqpid_proton = "qpid-proton-%s.tar.gz" % bundled_version_str
-libqpid_proton_url = ("http://www.apache.org/dist/qpid/proton/%s/%s" %
-                      (bundled_version_str, libqpid_proton))
-
-HERE = os.path.dirname(__file__)
-ROOT = os.path.dirname(HERE)
-
-
-def fetch_archive(savedir, url, fname):
-    """Download an archive to a specific location
-
-    :param savedir: Destination dir
-    :param url: URL where the archive should be downloaded from
-    :param fname: Archive's filename
-    """
-    dest = os.path.join(savedir, fname)
-
-    if os.path.exists(dest):
-        log.info("already have %s" % fname)
-        return dest
-
-    log.info("fetching %s into %s" % (url, savedir))
-    if not os.path.exists(savedir):
-        os.makedirs(savedir)
-    req = urlopen(url)
-    with open(dest, 'wb') as f:
-        f.write(req.read())
-    return dest
-
-
-def fetch_libqpid_proton(savedir):
-    """Download qpid-proton to `savedir`."""
-    def _c_only(members):
-        # just extract the files necessary to build the shared library
-        for tarinfo in members:
-            npath = os.path.normpath(tarinfo.name)
-            if ("proton-c/src" in npath or
-                "proton-c/include" in npath or
-                "proton-c/mllib" in npath):
-                yield tarinfo
-    dest = os.path.join(savedir, 'qpid-proton')
-    if os.path.exists(dest):
-        log.info("already have %s" % dest)
-        return
-    fname = fetch_archive(savedir, libqpid_proton_url, libqpid_proton)
-    tf = tarfile.open(fname)
-    member = tf.firstmember.path
-    if member == '.':
-        member = tf.getmembers()[1].path
-    with_version = os.path.join(savedir, member)
-    tf.extractall(savedir, members=_c_only(tf))
-    tf.close()
-    shutil.move(with_version, dest)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/bindings/python/setuputils/misc.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/misc.py b/proton-c/bindings/python/setuputils/misc.py
index b1864a0..54a8fde 100644
--- a/proton-c/bindings/python/setuputils/misc.py
+++ b/proton-c/bindings/python/setuputils/misc.py
@@ -40,39 +40,43 @@ def _call_pkg_config(args):
 
 
 
-def pkg_config_version(atleast=None, max_version=None, module='libqpid-proton'):
-    """Check the qpid_proton version using pkg-config
+def pkg_config_version_installed(package, version=None, atleast=None):
+    """Check if version of a package is is installed
 
     This function returns True/False depending on whether
-    the library is found and atleast/max_version are met.
+    the package is found and is the correct version.
 
-    :param atleast: The minimum required version
-    :param max_version: The maximum supported version. This
-        basically represents the target version.
+    :param version: The exact version of the package required
+    :param atleast: True if installed package is at least this version
     """
 
-    if atleast and max_version:
-        log.fatal('Specify either atleast or max_version')
+    if version is None and atleast is None:
+        log.fatal('package version string required')
+    elif version and atleast:
+        log.fatal('Specify either version or atleast, not both')
 
-    p = _call_pkg_config(['--%s-version=%s' % (atleast and 'atleast' or 'max',
-                                               atleast or max_version),
-                          module])
+    check = 'exact' if version else 'atleast'
+    p = _call_pkg_config(['--%s-version=%s' % (check,
+                                               version or atleast),
+                          package])
     if p:
         out,err = p.communicate()
         if p.returncode:
-            log.info("Did not find %s via pkg-config: %s" % (module, err))
+            log.info("Did not find %s via pkg-config: %s" % (package, err))
             return False
-        log.info("Using %s (found via pkg-config)." % module)
+        log.info("Using %s version %s (found via pkg-config)" %
+                 (package,
+                  _call_pkg_config(['--modversion', package]).communicate()[0]))
         return True
     return False
 
 
-def pkg_config_get_var(name, module='libqpid-proton'):
-    """Retrieve the value of the named module variable as a string
+def pkg_config_get_var(package, name):
+    """Retrieve the value of the named package variable as a string
     """
-    p = _call_pkg_config(['--variable=%s' % name, module])
+    p = _call_pkg_config(['--variable=%s' % name, package])
     if not p:
-        log.warn("pkg-config: var %s get failed, package %s", name, module)
+        log.warn("pkg-config: var %s get failed, package %s", name, package)
         return ""
     out,err = p.communicate()
     if p.returncode:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/888862f9/proton-c/tox.ini.in
----------------------------------------------------------------------
diff --git a/proton-c/tox.ini.in b/proton-c/tox.ini.in
index 7a9c8eb..2a6b09d 100644
--- a/proton-c/tox.ini.in
+++ b/proton-c/tox.ini.in
@@ -2,14 +2,13 @@
 envlist = py26,py27,py33,py34,py35
 minversion = 1.4
 skipdist = True
-setupdir = @py_src@
+setupdir = @py_bin@/dist
 
 [testenv]
 usedevelop = False
 setenv =
     VIRTUAL_ENV={envdir}
     DEBUG=True
-    QPID_PROTON_SRC=@CMAKE_SOURCE_DIR@
 passenv =
     PKG_CONFIG_PATH
     CFLAGS


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


[04/48] 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 ac...@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


[25/48] qpid-proton git commit: PROTON-1352, PROTON-1353: merge PR for settlement mode valueOf, message annotations in toString

Posted by ac...@apache.org.
PROTON-1352, PROTON-1353: merge PR for settlement mode valueOf, message annotations in toString

This closes #89


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

Branch: refs/heads/go1
Commit: f550d28222304fce9c422e195fb77400ca9622cb
Parents: 888862f fec0bc8
Author: Robert Gemmell <ro...@apache.org>
Authored: Wed Nov 16 17:48:05 2016 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Wed Nov 16 17:48:05 2016 +0000

----------------------------------------------------------------------
 .../amqp/transport/ReceiverSettleMode.java      | 25 ++++++--
 .../proton/amqp/transport/SenderSettleMode.java | 29 +++++++--
 .../qpid/proton/message/impl/MessageImpl.java   |  4 ++
 .../amqp/transport/ReceiverSettleModeTest.java  | 61 ++++++++++++++++++
 .../amqp/transport/SenderSettleModeTest.java    | 67 ++++++++++++++++++++
 5 files changed, 178 insertions(+), 8 deletions(-)
----------------------------------------------------------------------



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


[18/48] 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 ac...@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


[36/48] qpid-proton git commit: PROTON-1344: proactor documentation updates

Posted by ac...@apache.org.
PROTON-1344: proactor documentation updates


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

Branch: refs/heads/go1
Commit: bbeb096036ab67c88e8c33825aeab848605ae5c4
Parents: aadfcbb
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 17 11:17:14 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Nov 17 12:06:04 2016 -0500

----------------------------------------------------------------------
 proton-c/docs/api/index.md                  | 48 ++++++++-------------
 proton-c/include/proton/connection_driver.h | 17 ++++----
 proton-c/include/proton/listener.h          |  2 +-
 proton-c/include/proton/proactor.h          | 55 +++++++++++++-----------
 proton-c/include/proton/selectable.h        |  8 ++--
 5 files changed, 61 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bbeb0960/proton-c/docs/api/index.md
----------------------------------------------------------------------
diff --git a/proton-c/docs/api/index.md b/proton-c/docs/api/index.md
index 9c6009f..6a72d6b 100644
--- a/proton-c/docs/api/index.md
+++ b/proton-c/docs/api/index.md
@@ -1,35 +1,23 @@
 Proton Documentation            {#index}
 ====================
 
-## The Protocol Engine
+The @ref engine is an AMQP "protocol engine".  It provides functions to
+manipulate AMQP endpoints and messages and generates [events](@ref event) for
+the application to handle.  The @ref engine has no dependencies on IO or
+threading libraries.
 
-The [Engine API](@ref engine) is a "pure AMQP" toolkit, it decodes AMQP bytes
-into proton [events](@ref event) and generates AMQP bytes from application
-calls. There is no IO or threading code in this part of the library.
-
-## Proactive event-driven programming
-
-The [Proactor API](@ref proactor) is a pro-active, asynchronous framework to
+The @ref proactor is a proactive, asynchronous framework to
 build single or multi-threaded Proton C applications. It manages the IO
-transport layer so you can write portable, event-driven AMQP code using the @ref
-engine API.
-
-## IO Integration
-
-The [connection driver](@ref connection_driver) provides a simple bytes in/bytes
-out, event-driven interface so you can read AMQP data from any source, process
-the resulting [events](@ref event) and write AMQP output to any destination. It
-lets you use proton in in alternate event loops, or for specialized embedded
-applications.
-
-It is also possible to write your own implementation of the @ref proactor if you
-are dealing with an unusual IO or threading framework. Any proton application
-written to the proactor API will be able to use your implementation.
-
-## Messenger and Reactor APIs (deprecated)
-
-The [Messenger](@ref messenger) [Reactor](@ref reactor) APIs are older APIs
-that were limited to single-threaded applications.
-
-Existing @ref reactor applications can be converted easily to use the @ref proactor,
-since they share the same @engine API and @ref event set.
+transport layer so you can write portable, event-driven AMQP code using the
+@ref engine API.
+
+**Low-level integration**: The @ref connection_driver provides
+a simple bytes in/bytes out interface to the @ref engine for a single
+connection.  You can use this to integrate proton with special IO libraries or
+external event loops. It is also possible to write your own implementation of the
+@ref proactor if you want to transparently replace proton's IO layer.
+
+**Old APIs**: The @ref messenger and @ref reactor APIs are
+older APIs that were limited to single-threaded applications.
+@ref reactor applications can be converted to use the @ref proactor since
+most of the code is written to the common @ref engine API.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bbeb0960/proton-c/include/proton/connection_driver.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection_driver.h b/proton-c/include/proton/connection_driver.h
index 4fa3fb9..8a5132b 100644
--- a/proton-c/include/proton/connection_driver.h
+++ b/proton-c/include/proton/connection_driver.h
@@ -26,8 +26,7 @@
  * @defgroup connection_driver Connection Driver
  *
  * **Experimental**: Toolkit for integrating proton with arbitrary network or IO
- * transports. Provides a single point of control for an AMQP connection and
- * a simple bytes-in/bytes-out interface that lets you:
+ * transports via a bytes-in, bytes-out interface.
  *
  * - process AMQP-encoded bytes from some input byte stream
  * - generate ::pn_event_t events for your application to handle
@@ -35,10 +34,10 @@
  *
  * The pn_connection_driver_() functions provide a simplified API and extra
  * logic to use ::pn_connection_t and ::pn_transport_t as a unit.  You can also
- * access them directly for features that are not exposed via the @ref
- * connection_driver API.
+ * access them directly for features that do not have pn_connection_driver_()
+ * functions
  *
- * The engine buffers events and data, you should run it until
+ * The driver buffers events and data, you should run it until
  * pn_connection_driver_finished() is true, to ensure all reading, writing and
  * event handling (including ERROR and FINAL events) is finished.
  *
@@ -62,7 +61,7 @@
  *
  * ## Thread safety
  *
- * The @ref engine types are not thread safe, but each connection and its
+ * The @ref connection_driver types are not thread safe, but each connection and its
  * associated types forms an independent unit. Different connections can be
  * processed concurrently by different threads.
  *
@@ -89,7 +88,7 @@ typedef struct pn_connection_driver_t {
 } pn_connection_driver_t;
 
 /**
- * Set #connection and #transport to the provided values, or create a new
+ * Set connection and transport to the provided values, or create a new
  * @ref pn_connection_t or @ref pn_transport_t if either is NULL.
  * The provided values belong to the connection driver and will be freed by
  * pn_connection_driver_destroy()
@@ -114,7 +113,7 @@ PN_EXTERN int pn_connection_driver_init(pn_connection_driver_t*, pn_connection_t
 PN_EXTERN int pn_connection_driver_bind(pn_connection_driver_t *d);
 
 /**
- * Unbind, release and free #connection and #transport. Set all pointers to
+ * Unbind, release and free the connection and transport. Set all pointers to
  * NULL.  Does not free the @ref pn_connection_driver_t struct itself.
  */
 PN_EXTERN void pn_connection_driver_destroy(pn_connection_driver_t *);
@@ -191,7 +190,7 @@ PN_EXTERN pn_event_t* pn_connection_driver_next_event(pn_connection_driver_t *);
 PN_EXTERN bool pn_connection_driver_has_event(pn_connection_driver_t *);
 
 /**
- * Return true if the the engine is closed for reading and writing and there are
+ * Return true if the the driver is closed for reading and writing and there are
  * no more events.
  *
  * Call pn_connection_driver_free() to free all related memory.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bbeb0960/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
index 5e60649..4244e69 100644
--- a/proton-c/include/proton/listener.h
+++ b/proton-c/include/proton/listener.h
@@ -29,7 +29,7 @@ extern "C" {
 /**
  * @file
  *
- * Listener API for the proton @proactor
+ * Listener API for the proton @ref proactor
  *
  * @defgroup listener Listener
  * @ingroup proactor

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bbeb0960/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
index 9d39c9c..8a2680b 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -39,9 +39,9 @@ typedef struct pn_condition_t pn_condition_t;
  *
  * **Experimental**: Proactor API for portable, multi-threaded, asynchronous applications.
  *
- * The proactor establishes and listens for connections. It creates
- * the @ref transport that sends and receives data over the network and
- * delivers @ref event to application threads for handling.
+ * The proactor associates a @ref connection with a @ref transport, either
+ * by making an outgoing connection or accepting an incoming one.
+ * It delivers @ref event "events" to application threads for handling.
  *
  * **Multi-threading**:
  * The @ref proactor is thread-safe, but the @ref engine is not.  The proactor
@@ -53,7 +53,7 @@ typedef struct pn_condition_t pn_condition_t;
  */
 
 /**
- * The proactor.
+ * The proactor, see pn_proactor()
  */
 typedef struct pn_proactor_t pn_proactor_t;
 
@@ -71,9 +71,9 @@ void pn_proactor_free(pn_proactor_t*);
  * Connect connection to host/port. Connection and transport events will be
  * returned by pn_proactor_wait()
  *
- * @param[in] connection the proactor takes ownership do not free.
- * @param[in] host the address to listen on
- * @param[in] port the port to connect to
+ * @param[in] connection the proactor takes ownership, do not free
+ * @param[in] host address to connect on
+ * @param[in] port port to connect to
  *
  * @return error on immediate error, e.g. an allocation failure.
  * Other errors are indicated by connection or transport events via pn_proactor_wait()
@@ -84,35 +84,40 @@ int pn_proactor_connect(pn_proactor_t*, pn_connection_t *connection, const char
  * Start listening with listener.
  * pn_proactor_wait() will return a PN_LISTENER_ACCEPT event when a connection can be accepted.
  *
- * @param[in] listener proactor takes ownership of listener, do not free.
- * @param[in] host the address to listen on
- * @param[in] port the port to listen on
+ * @param[in] listener proactor takes ownership of listener, do not free
+ * @param[in] host address to listen on
+ * @param[in] port port to listen on
+ * @param[in] backlog number of connection requests to queue
  *
  * @return error on immediate error, e.g. an allocation failure.
  * Other errors are indicated by pn_listener_condition() on the PN_LISTENER_CLOSE event.
  */
-int pn_proactor_listen(pn_proactor_t *p, pn_listener_t *listener, const char *host, const char *port, int backlog);
+int pn_proactor_listen(pn_proactor_t *, pn_listener_t *listener, const char *host, const char *port, int backlog);
 
 /**
- * Wait for events to handle. Call pn_proactor_done() after handling events.
+ * Wait for events to handle.
  *
- * Thread safe: pn_proactor_wait() can be called concurrently, but the events in
- * the returned ::pn_event_batch_t must be handled sequentially.
+ * Handle events in the returned batch by calling pn_event_batch_next() until it
+ * returns NULL. You must call pn_proactor_done() to when you are finished.
  *
- * The proactor always returns events that must be handled sequentially in the
- * same batch or sequentially in a later batch after pn_proactor_done(). Any
- * events returned concurrently by pn_proactor_wait() are safe to handle
- * concurrently.
+ * If you call pn_proactor_done() before finishing the batch, the remaining
+ * events will be returned again by another call pn_proactor_wait().  This is
+ * less efficient, but allows you to handle part of a batch and then hand off
+ * the rest to another thread.
+ *
+ * Thread safe: can be called concurrently. Events in a single batch must be
+ * handled in sequence, but batches returned by separate calls to
+ * pn_proactor_wait() can be handled concurrently.
  */
 pn_event_batch_t *pn_proactor_wait(pn_proactor_t* d);
 
 /**
  * Call when done handling events.
  *
- * It is generally most efficient to handle the entire batch in the thread
- * that calls pn_proactor_wait(), then call pn_proactor_done(). If you call
- * pn_proactor_done() earlier, the remaining events will be returned again by
- * pn_proactor_wait(), possibly to another thread.
+ * Must be called exactly once to match each call to pn_proactor_wait().
+ *
+ * Thread safe: may be called from any thread provided the exactly once rules is
+ * respected.
  */
 void pn_proactor_done(pn_proactor_t* d, pn_event_batch_t *events);
 
@@ -145,17 +150,17 @@ void pn_proactor_set_timeout(pn_proactor_t* d, pn_millis_t timeout);
 void pn_connection_wake(pn_connection_t *c);
 
 /**
- * The proactor that created the connection.
+ * Return the proactor associated with a connection or null
  */
 pn_proactor_t *pn_connection_proactor(pn_connection_t *c);
 
 /**
- * Get the proactor that created the event or NULL.
+ * Return the proactor associated with an event or NULL.
  */
 pn_proactor_t *pn_event_proactor(pn_event_t *);
 
 /**
- * Get the listener for the event or NULL.
+ * Return the listener associated with an event or NULL.
  */
 pn_listener_t *pn_event_listener(pn_event_t *);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bbeb0960/proton-c/include/proton/selectable.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/selectable.h b/proton-c/include/proton/selectable.h
index fbf3823..5eff58d 100644
--- a/proton-c/include/proton/selectable.h
+++ b/proton-c/include/proton/selectable.h
@@ -51,11 +51,11 @@ typedef pn_iterator_t pn_selectables_t;
  * 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_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.
+ * 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.
  *


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


[12/48] 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 ac...@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


[40/48] qpid-proton git commit: PROTON-721: expose link capabilities and wire up handling of them

Posted by ac...@apache.org.
PROTON-721: expose link capabilities and wire up handling of them


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

Branch: refs/heads/go1
Commit: 2d5b8d8a333d84785fbcfac2f1c22e9c0a754874
Parents: b4cadd1
Author: Robert Gemmell <ro...@apache.org>
Authored: Mon Nov 21 16:45:10 2016 +0000
Committer: Robert Gemmell <ro...@apache.org>
Committed: Mon Nov 21 16:45:10 2016 +0000

----------------------------------------------------------------------
 .../org/apache/qpid/proton/engine/Link.java     |  55 +++++++++
 .../qpid/proton/engine/impl/LinkImpl.java       |  50 ++++++++
 .../qpid/proton/engine/impl/TransportImpl.java  |  13 ++
 .../qpid/proton/systemtests/LinkTest.java       | 123 +++++++++++++++++++
 4 files changed, 241 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2d5b8d8a/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
index 634f3e0..248c687 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Link.java
@@ -243,4 +243,59 @@ public interface Link extends Endpoint
     public void detach();
     public boolean detached();
 
+    /**
+     * Sets the local link offered capabilities, to be conveyed to the peer via the Attach frame
+     * when attaching the link to the session.
+     *
+     * Must be called during link setup, i.e. before calling the {@link #open()} method.
+     *
+     * @param offeredCapabilities
+     *          the offered capabilities array to send, or null for none.
+     */
+    public void setOfferedCapabilities(Symbol[] offeredCapabilities);
+
+    /**
+     * Gets the local link offered capabilities.
+     *
+     * @return the offered capabilities array, or null if none was set.
+     *
+     * @see #setOfferedCapabilities(Symbol[])
+     */
+    Symbol[] getOfferedCapabilities();
+
+    /**
+     * Gets the remote link offered capabilities, as conveyed from the peer via the Attach frame
+     * when attaching the link to the session.
+     *
+     * @return the offered capabilities array conveyed by the peer, or null if there was none.
+     */
+    Symbol[] getRemoteOfferedCapabilities();
+
+    /**
+     * Sets the local link desired capabilities, to be conveyed to the peer via the Attach frame
+     * when attaching the link to the session.
+     *
+     * Must be called during link setup, i.e. before calling the {@link #open()} method.
+     *
+     * @param desiredCapabilities
+     *          the desired capabilities array to send, or null for none.
+     */
+    public void setDesiredCapabilities(Symbol[] desiredCapabilities);
+
+    /**
+     * Gets the local link desired capabilities.
+     *
+     * @return the desired capabilities array, or null if none was set.
+     *
+     * @see #setDesiredCapabilities(Symbol[])
+     */
+    Symbol[] getDesiredCapabilities();
+
+    /**
+     * Gets the remote link desired capabilities, as conveyed from the peer via the Attach frame
+     * when attaching the link to the session.
+     *
+     * @return the desired capabilities array conveyed by the peer, or null if there was none.
+     */
+    Symbol[] getRemoteDesiredCapabilities();
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2d5b8d8a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
index 63e9ddd..a67785e 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
@@ -61,6 +61,10 @@ public abstract class LinkImpl extends EndpointImpl implements Link
     private boolean _detached;
     private Map<Symbol, Object> _properties;
     private Map<Symbol, Object> _remoteProperties;
+    private Symbol[] _offeredCapabilities;
+    private Symbol[] _remoteOfferedCapabilities;
+    private Symbol[] _desiredCapabilities;
+    private Symbol[] _remoteDesiredCapabilities;
 
     LinkImpl(SessionImpl session, String name)
     {
@@ -400,6 +404,52 @@ public abstract class LinkImpl extends EndpointImpl implements Link
     }
 
     @Override
+    public Symbol[] getDesiredCapabilities()
+    {
+        return _desiredCapabilities;
+    }
+
+    @Override
+    public void setDesiredCapabilities(Symbol[] desiredCapabilities)
+    {
+        _desiredCapabilities = desiredCapabilities;
+    }
+
+    @Override
+    public Symbol[] getRemoteDesiredCapabilities()
+    {
+        return _remoteDesiredCapabilities;
+    }
+
+    void setRemoteDesiredCapabilities(Symbol[] remoteDesiredCapabilities)
+    {
+        _remoteDesiredCapabilities = remoteDesiredCapabilities;
+    }
+
+    @Override
+    public Symbol[] getOfferedCapabilities()
+    {
+        return _offeredCapabilities;
+    }
+
+    @Override
+    public void setOfferedCapabilities(Symbol[] offeredCapabilities)
+    {
+        _offeredCapabilities = offeredCapabilities;
+    }
+
+    @Override
+    public Symbol[] getRemoteOfferedCapabilities()
+    {
+        return _remoteOfferedCapabilities;
+    }
+
+    void setRemoteOfferedCapabilities(Symbol[] remoteOfferedCapabilities)
+    {
+        _remoteOfferedCapabilities = remoteOfferedCapabilities;
+    }
+
+    @Override
     public int drained()
     {
         int drained = 0;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2d5b8d8a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
index 9a5fcbd..bb2e43b 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
@@ -781,6 +781,16 @@ public class TransportImpl extends EndpointImpl
                                 attach.setProperties(link.getProperties());
                             }
 
+                            if(link.getOfferedCapabilities() != null)
+                            {
+                                attach.setOfferedCapabilities(link.getOfferedCapabilities());
+                            }
+
+                            if(link.getDesiredCapabilities() != null)
+                            {
+                                attach.setDesiredCapabilities(link.getDesiredCapabilities());
+                            }
+
                             attach.setRole(endpoint instanceof ReceiverImpl ? Role.RECEIVER : Role.SENDER);
 
                             if(link instanceof SenderImpl)
@@ -1182,6 +1192,9 @@ public class TransportImpl extends EndpointImpl
 
                 link.setRemoteProperties(attach.getProperties());
 
+                link.setRemoteDesiredCapabilities(attach.getDesiredCapabilities());
+                link.setRemoteOfferedCapabilities(attach.getOfferedCapabilities());
+
                 transportLink.setName(attach.getName());
                 transportLink.setRemoteHandle(handle);
                 transportSession.addLinkRemoteHandle(transportLink, handle);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2d5b8d8a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/LinkTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/LinkTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/LinkTest.java
index 10b509e..518960c 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/LinkTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/LinkTest.java
@@ -61,6 +61,129 @@ public class LinkTest extends EngineTestBase
     private final String _sourceAddress = getServer().containerId + "-link1-source";
 
     @Test
+    public void testCapabilities() throws Exception
+    {
+        final Symbol recvOfferedCap = Symbol.valueOf("recvOfferedCapability");
+        final Symbol recvDesiredCap = Symbol.valueOf("recvDesiredCapability");
+        final Symbol senderOfferedCap = Symbol.valueOf("senderOfferedCapability");
+        final Symbol senderDesiredCap = Symbol.valueOf("senderDesiredCapability");
+
+        Symbol[] clientOfferedCapabilities = new Symbol[] { recvOfferedCap };
+        Symbol[] clientDesiredCapabilities = new Symbol[] { recvDesiredCap };
+
+        Symbol[] serverOfferedCapabilities = new Symbol[] { senderOfferedCap };
+        Symbol[] serverDesiredCapabilities = new Symbol[] { senderDesiredCap };
+
+        LOGGER.fine(bold("======== About to create transports"));
+
+        getClient().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getClient().transport, TestLoggingHelper.CLIENT_PREFIX);
+
+        getServer().transport = Proton.transport();
+        ProtocolTracerEnabler.setProtocolTracer(getServer().transport, "            " + TestLoggingHelper.SERVER_PREFIX);
+
+        doOutputInputCycle();
+
+        getClient().connection = Proton.connection();
+        getClient().transport.bind(getClient().connection);
+
+        getServer().connection = Proton.connection();
+        getServer().transport.bind(getServer().connection);
+
+        LOGGER.fine(bold("======== About to open connections"));
+        getClient().connection.open();
+        getServer().connection.open();
+
+        doOutputInputCycle();
+
+        LOGGER.fine(bold("======== About to open sessions"));
+        getClient().session = getClient().connection.session();
+        getClient().session.open();
+
+        pumpClientToServer();
+
+        getServer().session = getServer().connection.sessionHead(of(UNINITIALIZED), of(ACTIVE));
+        assertEndpointState(getServer().session, UNINITIALIZED, ACTIVE);
+
+        getServer().session.open();
+        assertEndpointState(getServer().session, ACTIVE, ACTIVE);
+
+        pumpServerToClient();
+        assertEndpointState(getClient().session, ACTIVE, ACTIVE);
+
+        LOGGER.fine(bold("======== About to create reciever"));
+
+        getClient().source = new Source();
+        getClient().source.setAddress(_sourceAddress);
+
+        getClient().target = new Target();
+        getClient().target.setAddress(null);
+
+        getClient().receiver = getClient().session.receiver("link1");
+        getClient().receiver.setTarget(getClient().target);
+        getClient().receiver.setSource(getClient().source);
+
+        getClient().receiver.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+        getClient().receiver.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+
+        // Set the client receivers capabilities
+        getClient().receiver.setOfferedCapabilities(clientOfferedCapabilities);
+        getClient().receiver.setDesiredCapabilities(clientDesiredCapabilities);
+
+        assertEndpointState(getClient().receiver, UNINITIALIZED, UNINITIALIZED);
+
+        getClient().receiver.open();
+        assertEndpointState(getClient().receiver, ACTIVE, UNINITIALIZED);
+
+        pumpClientToServer();
+
+        LOGGER.fine(bold("======== About to set up implicitly created sender"));
+
+        getServer().sender = (Sender) getServer().connection.linkHead(of(UNINITIALIZED), of(ACTIVE));
+
+        getServer().sender.setReceiverSettleMode(getServer().sender.getRemoteReceiverSettleMode());
+        getServer().sender.setSenderSettleMode(getServer().sender.getRemoteSenderSettleMode());
+
+        org.apache.qpid.proton.amqp.transport.Source serverRemoteSource = getServer().sender.getRemoteSource();
+        getServer().sender.setSource(serverRemoteSource);
+
+        // Set the server senders capabilities
+        getServer().sender.setOfferedCapabilities(serverOfferedCapabilities);
+        getServer().sender.setDesiredCapabilities(serverDesiredCapabilities);
+
+        assertEndpointState(getServer().sender, UNINITIALIZED, ACTIVE);
+        getServer().sender.open();
+
+        assertEndpointState(getServer().sender, ACTIVE, ACTIVE);
+
+        pumpServerToClient();
+
+        assertEndpointState(getClient().receiver, ACTIVE, ACTIVE);
+
+        // Verify server side got the clients receiver capabilities as expected
+        Symbol[] serverRemoteOfferedCapabilities = getServer().sender.getRemoteOfferedCapabilities();
+        assertNotNull("Server had no remote offered capabilities", serverRemoteOfferedCapabilities);
+        assertEquals("Server remote offered capabilities not expected size", 1, serverRemoteOfferedCapabilities.length);
+        assertTrue("Server remote offered capabilities lack expected value: " + recvOfferedCap, Arrays.asList(serverRemoteOfferedCapabilities).contains(recvOfferedCap));
+
+        Symbol[] serverRemoteDesiredCapabilities = getServer().sender.getRemoteDesiredCapabilities();
+        assertNotNull("Server had no remote desired capabilities", serverRemoteDesiredCapabilities);
+        assertEquals("Server remote desired capabilities not expected size", 1, serverRemoteDesiredCapabilities.length);
+        assertTrue("Server remote desired capabilities lack expected value: " + recvDesiredCap, Arrays.asList(serverRemoteDesiredCapabilities).contains(recvDesiredCap));
+
+        // Verify the client side got the servers sender capabilities as expected
+        Symbol[]  clientRemoteOfferedCapabilities = getClient().receiver.getRemoteOfferedCapabilities();
+        assertNotNull("Client had no remote offered capabilities", clientRemoteOfferedCapabilities);
+        assertEquals("Client remote offered capabilities not expected size", 1, clientRemoteOfferedCapabilities.length);
+        assertTrue("Client remote offered capabilities lack expected value: " + senderOfferedCap, Arrays.asList(clientRemoteOfferedCapabilities).contains(senderOfferedCap));
+
+        Symbol[]  clientRemoteDesiredCapabilities = getClient().receiver.getRemoteDesiredCapabilities();
+        assertNotNull("Client had no remote desired capabilities", clientRemoteDesiredCapabilities);
+        assertEquals("Client remote desired capabilities not expected size", 1, clientRemoteDesiredCapabilities.length);
+        assertTrue("Client remote desired capabilities lack expected value: " + senderDesiredCap, Arrays.asList(clientRemoteDesiredCapabilities).contains(senderDesiredCap));
+    }
+
+    @Test
     public void testProperties() throws Exception
     {
         Map<Symbol, Object> receiverProps = new HashMap<>();


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


[48/48] qpid-proton git commit: PROTON-1356: go: restore compatibility with proton-c from 0.10

Posted by ac...@apache.org.
PROTON-1356: go: restore compatibility with proton-c from 0.10

Remove use of PN_INVALID (not available in proton 0.10)
Link with libqpid-proton not libqpid-proton-core (not available until 0.16)
Catch up with master branch.


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

Branch: refs/heads/go1
Commit: 0889192a326c6a22973f8eb4fd07353d94bbe97f
Parents: d5c2470 a34c93b
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Nov 25 15:55:52 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Nov 25 15:56:45 2016 -0500

----------------------------------------------------------------------
 amqp/types.go     |  4 +---
 amqp/unmarshal.go | 10 +++-------
 2 files changed, 4 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0889192a/amqp/types.go
----------------------------------------------------------------------
diff --cc amqp/types.go
index bc0859a,0000000..2852c23
mode 100644,000000..100644
--- a/amqp/types.go
+++ b/amqp/types.go
@@@ -1,196 -1,0 +1,194 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +or more contributor license agreements.  See the NOTICE file
 +distributed with this work for additional information
 +regarding copyright ownership.  The ASF licenses this file
 +to you under the Apache License, Version 2.0 (the
 +"License"); you may not use this file except in compliance
 +with the License.  You may obtain a copy of the License at
 +
 +  http://www.apache.org/licenses/LICENSE-2.0
 +
 +Unless required by applicable law or agreed to in writing,
 +software distributed under the License is distributed on an
 +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +KIND, either express or implied.  See the License for the
 +specific language governing permissions and limitations
 +under the License.
 +*/
 +
 +package amqp
 +
 +// #include <proton/codec.h>
 +import "C"
 +
 +import (
 +	"bytes"
 +	"fmt"
 +	"reflect"
 +	"time"
 +	"unsafe"
 +)
 +
 +func (t C.pn_type_t) String() string {
 +	switch C.pn_type_t(t) {
 +	case C.PN_NULL:
 +		return "null"
 +	case C.PN_BOOL:
 +		return "bool"
 +	case C.PN_UBYTE:
 +		return "ubyte"
 +	case C.PN_BYTE:
 +		return "byte"
 +	case C.PN_USHORT:
 +		return "ushort"
 +	case C.PN_SHORT:
 +		return "short"
 +	case C.PN_CHAR:
 +		return "char"
 +	case C.PN_UINT:
 +		return "uint"
 +	case C.PN_INT:
 +		return "int"
 +	case C.PN_ULONG:
 +		return "ulong"
 +	case C.PN_LONG:
 +		return "long"
 +	case C.PN_TIMESTAMP:
 +		return "timestamp"
 +	case C.PN_FLOAT:
 +		return "float"
 +	case C.PN_DOUBLE:
 +		return "double"
 +	case C.PN_DECIMAL32:
 +		return "decimal32"
 +	case C.PN_DECIMAL64:
 +		return "decimal64"
 +	case C.PN_DECIMAL128:
 +		return "decimal128"
 +	case C.PN_UUID:
 +		return "uuid"
 +	case C.PN_BINARY:
 +		return "binary"
 +	case C.PN_STRING:
 +		return "string"
 +	case C.PN_SYMBOL:
 +		return "symbol"
 +	case C.PN_DESCRIBED:
 +		return "described"
 +	case C.PN_ARRAY:
 +		return "array"
 +	case C.PN_LIST:
 +		return "list"
 +	case C.PN_MAP:
 +		return "map"
- 	case C.PN_INVALID:
- 		return "no-data"
 +	default:
- 		return fmt.Sprintf("unknown-type(%d)", t)
++		return "no-data"
 +	}
 +}
 +
 +// Go types
 +var (
 +	bytesType = reflect.TypeOf([]byte{})
 +	valueType = reflect.TypeOf(reflect.Value{})
 +)
 +
 +// TODO aconway 2015-04-08: can't handle AMQP maps with key types that are not valid Go map keys.
 +
 +// Map is a generic map that can have mixed key and value types and so can represent any AMQP map
 +type Map map[interface{}]interface{}
 +
 +// List is a generic list that can hold mixed values and can represent any AMQP list.
 +//
 +type List []interface{}
 +
 +// Symbol is a string that is encoded as an AMQP symbol
 +type Symbol string
 +
 +func (s Symbol) GoString() string { return fmt.Sprintf("s\"%s\"", s) }
 +
 +// Binary is a string that is encoded as an AMQP binary.
 +// It is a string rather than a byte[] because byte[] is not hashable and can't be used as
 +// a map key, AMQP frequently uses binary types as map keys. It can convert to and from []byte
 +type Binary string
 +
 +func (b Binary) GoString() string { return fmt.Sprintf("b\"%s\"", b) }
 +
 +// GoString for Map prints values with their types, useful for debugging.
 +func (m Map) GoString() string {
 +	out := &bytes.Buffer{}
 +	fmt.Fprintf(out, "%T{", m)
 +	i := len(m)
 +	for k, v := range m {
 +		fmt.Fprintf(out, "%T(%#v): %T(%#v)", k, k, v, v)
 +		i--
 +		if i > 0 {
 +			fmt.Fprint(out, ", ")
 +		}
 +	}
 +	fmt.Fprint(out, "}")
 +	return out.String()
 +}
 +
 +// GoString for List prints values with their types, useful for debugging.
 +func (l List) GoString() string {
 +	out := &bytes.Buffer{}
 +	fmt.Fprintf(out, "%T{", l)
 +	for i := 0; i < len(l); i++ {
 +		fmt.Fprintf(out, "%T(%#v)", l[i], l[i])
 +		if i == len(l)-1 {
 +			fmt.Fprint(out, ", ")
 +		}
 +	}
 +	fmt.Fprint(out, "}")
 +	return out.String()
 +}
 +
 +// pnTime converts Go time.Time to Proton millisecond Unix time.
 +func pnTime(t time.Time) C.pn_timestamp_t {
 +	secs := t.Unix()
 +	// Note: sub-second accuracy is not guaraunteed if the Unix time in
 +	// nanoseconds cannot be represented by an int64 (sometime around year 2260)
 +	msecs := (t.UnixNano() % int64(time.Second)) / int64(time.Millisecond)
 +	return C.pn_timestamp_t(secs*1000 + msecs)
 +}
 +
 +// goTime converts a pn_timestamp_t to a Go time.Time.
 +func goTime(t C.pn_timestamp_t) time.Time {
 +	secs := int64(t) / 1000
 +	nsecs := (int64(t) % 1000) * int64(time.Millisecond)
 +	return time.Unix(secs, nsecs)
 +}
 +
 +func goBytes(cBytes C.pn_bytes_t) (bytes []byte) {
 +	if cBytes.start != nil {
 +		bytes = C.GoBytes(unsafe.Pointer(cBytes.start), C.int(cBytes.size))
 +	}
 +	return
 +}
 +
 +func goString(cBytes C.pn_bytes_t) (str string) {
 +	if cBytes.start != nil {
 +		str = C.GoStringN(cBytes.start, C.int(cBytes.size))
 +	}
 +	return
 +}
 +
 +func pnBytes(b []byte) C.pn_bytes_t {
 +	if len(b) == 0 {
 +		return C.pn_bytes_t{0, nil}
 +	} else {
 +		return C.pn_bytes_t{C.size_t(len(b)), (*C.char)(unsafe.Pointer(&b[0]))}
 +	}
 +}
 +
 +func cPtr(b []byte) *C.char {
 +	if len(b) == 0 {
 +		return nil
 +	}
 +	return (*C.char)(unsafe.Pointer(&b[0]))
 +}
 +
 +func cLen(b []byte) C.size_t {
 +	return C.size_t(len(b))
 +}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/0889192a/amqp/unmarshal.go
----------------------------------------------------------------------
diff --cc amqp/unmarshal.go
index 95d4343,0000000..8f380a7
mode 100644,000000..100644
--- a/amqp/unmarshal.go
+++ b/amqp/unmarshal.go
@@@ -1,561 -1,0 +1,557 @@@
 +/*
 +Licensed to the Apache Software Foundation (ASF) under one
 +oor more contributor license agreements.  See the NOTICE file
 +distributed with this work for additional information
 +regarding copyright ownership.  The ASF licenses this file
 +to you under the Apache License, Version 2.0 (the
 +"License"); you may not use this file except in compliance
 +with the License.  You may obtain a copy of the License at
 +
 +  http://www.apache.org/licenses/LICENSE-2.0
 +
 +Unless required by applicable law or agreed to in writing,
 +software distributed under the License is distributed on an
 +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +KIND, either express or implied.  See the License for the
 +specific language governing permissions and limitations
 +under the License.
 +*/
 +
 +package amqp
 +
 +// #include <proton/codec.h>
 +import "C"
 +
 +import (
 +	"bytes"
 +	"fmt"
 +	"io"
 +	"reflect"
 +	"unsafe"
 +)
 +
 +const minDecode = 1024
 +
 +// Error returned if AMQP data cannot be unmarshaled as the desired Go type.
 +type UnmarshalError struct {
 +	// The name of the AMQP type.
 +	AMQPType string
 +	// The Go type.
 +	GoType reflect.Type
 +}
 +
 +func newUnmarshalError(pnType C.pn_type_t, v interface{}) *UnmarshalError {
 +	return &UnmarshalError{C.pn_type_t(pnType).String(), reflect.TypeOf(v)}
 +}
 +
 +func (e UnmarshalError) Error() string {
 +	if e.GoType.Kind() != reflect.Ptr {
 +		return fmt.Sprintf("cannot unmarshal to type %s, not a pointer", e.GoType)
 +	} else {
 +		return fmt.Sprintf("cannot unmarshal AMQP %s to %s", e.AMQPType, e.GoType)
 +	}
 +}
 +
 +func doRecover(err *error) {
 +	r := recover()
 +	switch r := r.(type) {
 +	case nil:
 +	case *UnmarshalError:
 +		*err = r
 +	default:
 +		panic(r)
 +	}
 +}
 +
 +//
 +// Decoding from a pn_data_t
 +//
 +// NOTE: we use panic() to signal a decoding error, simplifies decoding logic.
 +// We recover() at the highest possible level - i.e. in the exported Unmarshal or Decode.
 +//
 +
 +// Decoder decodes AMQP values from an io.Reader.
 +//
 +type Decoder struct {
 +	reader io.Reader
 +	buffer bytes.Buffer
 +}
 +
 +// NewDecoder returns a new decoder that reads from r.
 +//
 +// The decoder has it's own buffer and may read more data than required for the
 +// AMQP values requested.  Use Buffered to see if there is data left in the
 +// buffer.
 +//
 +func NewDecoder(r io.Reader) *Decoder {
 +	return &Decoder{r, bytes.Buffer{}}
 +}
 +
 +// Buffered returns a reader of the data remaining in the Decoder's buffer. The
 +// reader is valid until the next call to Decode.
 +//
 +func (d *Decoder) Buffered() io.Reader {
 +	return bytes.NewReader(d.buffer.Bytes())
 +}
 +
 +// Decode reads the next AMQP value from the Reader and stores it in the value pointed to by v.
 +//
 +// See the documentation for Unmarshal for details about the conversion of AMQP into a Go value.
 +//
 +func (d *Decoder) Decode(v interface{}) (err error) {
 +	defer doRecover(&err)
 +	data := C.pn_data(0)
 +	defer C.pn_data_free(data)
 +	var n int
 +	for n == 0 {
 +		n, err = decode(data, d.buffer.Bytes())
 +		if err != nil {
 +			return err
 +		}
 +		if n == 0 { // n == 0 means not enough data, read more
 +			err = d.more()
 +		} else {
 +			unmarshal(v, data)
 +		}
 +	}
 +	d.buffer.Next(n)
 +	return
 +}
 +
 +/*
 +Unmarshal decodes AMQP-encoded bytes and stores the result in the value pointed to by v.
 +Types are converted as follows:
 +
 + +---------------------------+----------------------------------------------------------------------+
 + |To Go types                |From AMQP types                                                       |
 + +===========================+======================================================================+
 + |bool                       |bool                                                                  |
 + +---------------------------+----------------------------------------------------------------------+
 + |int, int8, int16,          |Equivalent or smaller signed integer type: byte, short, int, long.    |
 + |int32, int64               |                                                                      |
 + +---------------------------+----------------------------------------------------------------------+
 + |uint, uint8, uint16,       |Equivalent or smaller unsigned integer type: ubyte, ushort, uint,     |
 + |uint32, uint64 types       |ulong                                                                 |
 + +---------------------------+----------------------------------------------------------------------+
 + |float32, float64           |Equivalent or smaller float or double.                                |
 + +---------------------------+----------------------------------------------------------------------+
 + |string, []byte             |string, symbol or binary.                                             |
 + +---------------------------+----------------------------------------------------------------------+
 + |Symbol                     |symbol                                                                |
 + +---------------------------+----------------------------------------------------------------------+
 + |map[K]T                    |map, provided all keys and values can unmarshal to types K, T         |
 + +---------------------------+----------------------------------------------------------------------+
 + |Map                        |map, any AMQP map                                                     |
 + +---------------------------+----------------------------------------------------------------------+
 + |interface{}                |Any AMQP value can be unmarshaled to an interface{} as follows:       |
 + |                           +------------------------+---------------------------------------------+
 + |                           |AMQP Type               |Go Type in interface{}                       |
 + |                           +========================+=============================================+
 + |                           |bool                    |bool                                         |
 + |                           +------------------------+---------------------------------------------+
 + |                           |byte,short,int,long     |int8,int16,int32,int64                       |
 + |                           +------------------------+---------------------------------------------+
 + |                           |ubyte,ushort,uint,ulong |uint8,uint16,uint32,uint64                   |
 + |                           +------------------------+---------------------------------------------+
 + |                           |float, double           |float32, float64                             |
 + |                           +------------------------+---------------------------------------------+
 + |                           |string                  |string                                       |
 + |                           +------------------------+---------------------------------------------+
 + |                           |symbol                  |Symbol                                       |
 + |                           +------------------------+---------------------------------------------+
 + |                           |binary                  |Binary                                       |
 + |                           +------------------------+---------------------------------------------+
 + |                           |nulll                   |nil                                          |
 + |                           +------------------------+---------------------------------------------+
 + |                           |map                     |Map                                          |
 + |                           +------------------------+---------------------------------------------+
 + |                           |list                    |List                                         |
 + +---------------------------+------------------------+---------------------------------------------+
 +
 +The following Go types cannot be unmarshaled: uintptr, function, interface, channel.
 +
 +TODO
 +
 +Go types: array, struct.
 +
 +AMQP types: decimal32/64/128, char (round trip), timestamp, uuid, array, multi-section message bodies.
 +
 +AMQP maps with mixed/unhashable key types need an alternate representation.
 +
 +Described types.
 +*/
 +func Unmarshal(bytes []byte, v interface{}) (n int, err error) {
 +	defer doRecover(&err)
 +
 +	data := C.pn_data(0)
 +	defer C.pn_data_free(data)
 +	n, err = decode(data, bytes)
 +	if err != nil {
 +		return 0, err
 +	}
 +	if n == 0 {
 +		return 0, fmt.Errorf("not enough data")
 +	} else {
 +		unmarshal(v, data)
 +	}
 +	return n, nil
 +}
 +
 +// more reads more data when we can't parse a complete AMQP type
 +func (d *Decoder) more() error {
 +	var readSize int64 = minDecode
 +	if int64(d.buffer.Len()) > readSize { // Grow by doubling
 +		readSize = int64(d.buffer.Len())
 +	}
 +	var n int64
 +	n, err := d.buffer.ReadFrom(io.LimitReader(d.reader, readSize))
 +	if n == 0 && err == nil { // ReadFrom won't report io.EOF, just returns 0
 +		err = io.EOF
 +	}
 +	return err
 +}
 +
 +// Unmarshal from data into value pointed at by v.
 +func unmarshal(v interface{}, data *C.pn_data_t) {
 +	pnType := C.pn_data_type(data)
 +	switch v := v.(type) {
 +	case *bool:
 +		switch pnType {
 +		case C.PN_BOOL:
 +			*v = bool(C.pn_data_get_bool(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *int8:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int8(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int8(C.pn_data_get_byte(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *uint8:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint8(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint8(C.pn_data_get_ubyte(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *int16:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int16(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int16(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int16(C.pn_data_get_short(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *uint16:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint16(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint16(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint16(C.pn_data_get_ushort(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *int32:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int32(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int32(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int32(C.pn_data_get_short(data))
 +		case C.PN_INT:
 +			*v = int32(C.pn_data_get_int(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	case *uint32:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint32(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint32(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint32(C.pn_data_get_ushort(data))
 +		case C.PN_UINT:
 +			*v = uint32(C.pn_data_get_uint(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *int64:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int64(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int64(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int64(C.pn_data_get_short(data))
 +		case C.PN_INT:
 +			*v = int64(C.pn_data_get_int(data))
 +		case C.PN_LONG:
 +			*v = int64(C.pn_data_get_long(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *uint64:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint64(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint64(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint64(C.pn_data_get_ushort(data))
 +		case C.PN_ULONG:
 +			*v = uint64(C.pn_data_get_ulong(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *int:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = int(C.pn_data_get_char(data))
 +		case C.PN_BYTE:
 +			*v = int(C.pn_data_get_byte(data))
 +		case C.PN_SHORT:
 +			*v = int(C.pn_data_get_short(data))
 +		case C.PN_INT:
 +			*v = int(C.pn_data_get_int(data))
 +		case C.PN_LONG:
 +			if unsafe.Sizeof(0) == 8 {
 +				*v = int(C.pn_data_get_long(data))
 +			} else {
 +				panic(newUnmarshalError(pnType, v))
 +			}
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *uint:
 +		switch pnType {
 +		case C.PN_CHAR:
 +			*v = uint(C.pn_data_get_char(data))
 +		case C.PN_UBYTE:
 +			*v = uint(C.pn_data_get_ubyte(data))
 +		case C.PN_USHORT:
 +			*v = uint(C.pn_data_get_ushort(data))
 +		case C.PN_UINT:
 +			*v = uint(C.pn_data_get_uint(data))
 +		case C.PN_ULONG:
 +			if unsafe.Sizeof(0) == 8 {
 +				*v = uint(C.pn_data_get_ulong(data))
 +			} else {
 +				panic(newUnmarshalError(pnType, v))
 +			}
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *float32:
 +		switch pnType {
 +		case C.PN_FLOAT:
 +			*v = float32(C.pn_data_get_float(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *float64:
 +		switch pnType {
 +		case C.PN_FLOAT:
 +			*v = float64(C.pn_data_get_float(data))
 +		case C.PN_DOUBLE:
 +			*v = float64(C.pn_data_get_double(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *string:
 +		switch pnType {
 +		case C.PN_STRING:
 +			*v = goString(C.pn_data_get_string(data))
 +		case C.PN_SYMBOL:
 +			*v = goString(C.pn_data_get_symbol(data))
 +		case C.PN_BINARY:
 +			*v = goString(C.pn_data_get_binary(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *[]byte:
 +		switch pnType {
 +		case C.PN_STRING:
 +			*v = goBytes(C.pn_data_get_string(data))
 +		case C.PN_SYMBOL:
 +			*v = goBytes(C.pn_data_get_symbol(data))
 +		case C.PN_BINARY:
 +			*v = goBytes(C.pn_data_get_binary(data))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *Binary:
 +		switch pnType {
 +		case C.PN_BINARY:
 +			*v = Binary(goBytes(C.pn_data_get_binary(data)))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *Symbol:
 +		switch pnType {
 +		case C.PN_SYMBOL:
 +			*v = Symbol(goBytes(C.pn_data_get_symbol(data)))
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +
 +	case *interface{}:
 +		getInterface(data, v)
 +
 +	default:
 +		if reflect.TypeOf(v).Kind() != reflect.Ptr {
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +		switch reflect.TypeOf(v).Elem().Kind() {
 +		case reflect.Map:
 +			getMap(data, v)
 +		case reflect.Slice:
 +			getList(data, v)
 +		default:
 +			panic(newUnmarshalError(pnType, v))
 +		}
 +	}
 +	err := dataError("unmarshaling", data)
 +	if err != nil {
 +		panic(err)
 +	}
 +	return
 +}
 +
 +func rewindUnmarshal(v interface{}, data *C.pn_data_t) {
 +	C.pn_data_rewind(data)
 +	C.pn_data_next(data)
 +	unmarshal(v, data)
 +}
 +
 +// Getting into an interface is driven completely by the AMQP type, since the interface{}
 +// target is type-neutral.
 +func getInterface(data *C.pn_data_t, v *interface{}) {
 +	pnType := C.pn_data_type(data)
 +	switch pnType {
- 	case C.PN_NULL, C.PN_INVALID: // No data.
- 		*v = nil
 +	case C.PN_BOOL:
 +		*v = bool(C.pn_data_get_bool(data))
 +	case C.PN_UBYTE:
 +		*v = uint8(C.pn_data_get_ubyte(data))
 +	case C.PN_BYTE:
 +		*v = int8(C.pn_data_get_byte(data))
 +	case C.PN_USHORT:
 +		*v = uint16(C.pn_data_get_ushort(data))
 +	case C.PN_SHORT:
 +		*v = int16(C.pn_data_get_short(data))
 +	case C.PN_UINT:
 +		*v = uint32(C.pn_data_get_uint(data))
 +	case C.PN_INT:
 +		*v = int32(C.pn_data_get_int(data))
 +	case C.PN_CHAR:
 +		*v = uint8(C.pn_data_get_char(data))
 +	case C.PN_ULONG:
 +		*v = uint64(C.pn_data_get_ulong(data))
 +	case C.PN_LONG:
 +		*v = int64(C.pn_data_get_long(data))
 +	case C.PN_FLOAT:
 +		*v = float32(C.pn_data_get_float(data))
 +	case C.PN_DOUBLE:
 +		*v = float64(C.pn_data_get_double(data))
 +	case C.PN_BINARY:
 +		*v = Binary(goBytes(C.pn_data_get_binary(data)))
 +	case C.PN_STRING:
 +		*v = goString(C.pn_data_get_string(data))
 +	case C.PN_SYMBOL:
 +		*v = Symbol(goString(C.pn_data_get_symbol(data)))
 +	case C.PN_MAP:
 +		m := make(Map)
 +		unmarshal(&m, data)
 +		*v = m
 +	case C.PN_LIST:
 +		l := make(List, 0)
 +		unmarshal(&l, data)
 +		*v = l
- 	default:
- 		panic(newUnmarshalError(pnType, v))
++	default: // No data (-1 or NULL)
++		*v = nil
 +	}
 +}
 +
 +// get into map pointed at by v
 +func getMap(data *C.pn_data_t, v interface{}) {
 +	mapValue := reflect.ValueOf(v).Elem()
 +	mapValue.Set(reflect.MakeMap(mapValue.Type())) // Clear the map
 +	switch pnType := C.pn_data_type(data); pnType {
 +	case C.PN_MAP:
 +		count := int(C.pn_data_get_map(data))
 +		if bool(C.pn_data_enter(data)) {
 +			defer C.pn_data_exit(data)
 +			for i := 0; i < count/2; i++ {
 +				if bool(C.pn_data_next(data)) {
 +					key := reflect.New(mapValue.Type().Key())
 +					unmarshal(key.Interface(), data)
 +					if bool(C.pn_data_next(data)) {
 +						val := reflect.New(mapValue.Type().Elem())
 +						unmarshal(val.Interface(), data)
 +						mapValue.SetMapIndex(key.Elem(), val.Elem())
 +					}
 +				}
 +			}
 +		}
- 	case C.PN_INVALID: // Leave the map empty
- 	default:
- 		panic(newUnmarshalError(pnType, v))
++	default: // Empty/error/unknown, leave map empty
 +	}
 +}
 +
 +func getList(data *C.pn_data_t, v interface{}) {
 +	pnType := C.pn_data_type(data)
 +	if pnType != C.PN_LIST {
 +		panic(newUnmarshalError(pnType, v))
 +	}
 +	count := int(C.pn_data_get_list(data))
 +	listValue := reflect.MakeSlice(reflect.TypeOf(v).Elem(), count, count)
 +	if bool(C.pn_data_enter(data)) {
 +		for i := 0; i < count; i++ {
 +			if bool(C.pn_data_next(data)) {
 +				val := reflect.New(listValue.Type().Elem())
 +				unmarshal(val.Interface(), data)
 +				listValue.Index(i).Set(val.Elem())
 +			}
 +		}
 +		C.pn_data_exit(data)
 +	}
 +	reflect.ValueOf(v).Elem().Set(listValue)
 +}
 +
 +// decode from bytes.
 +// Return bytes decoded or 0 if we could not decode a complete object.
 +//
 +func decode(data *C.pn_data_t, bytes []byte) (int, error) {
 +	if len(bytes) == 0 {
 +		return 0, nil
 +	}
 +	n := int(C.pn_data_decode(data, cPtr(bytes), cLen(bytes)))
 +	if n == int(C.PN_UNDERFLOW) {
 +		C.pn_error_clear(C.pn_data_error(data))
 +		return 0, nil
 +	} else if n <= 0 {
 +		return 0, fmt.Errorf("unmarshal %s", PnErrorCode(n))
 +	}
 +	return n, nil
 +}


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


[26/48] qpid-proton git commit: NO-JIRA: enable warnings-as-errors for clang C compiler

Posted by ac...@apache.org.
NO-JIRA: enable warnings-as-errors for clang C compiler


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

Branch: refs/heads/go1
Commit: b1a292503dc0dacf79fa55c53703f568f4c5b495
Parents: f550d28
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 16 16:33:14 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 16 19:35:26 2016 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt  | 6 ++++++
 proton-c/src/sasl/sasl.c | 6 ------
 2 files changed, 6 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b1a29250/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 7753f1f..ddab147 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -262,6 +262,12 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
   endif (ENABLE_HIDE_UNEXPORTED_SYMBOLS)
 endif (CMAKE_COMPILER_IS_GNUCC)
 
+if (CMAKE_C_COMPILER_ID MATCHES "Clang")
+  if (ENABLE_WARNING_ERROR)
+    set (COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic")
+  endif (ENABLE_WARNING_ERROR)
+endif()
+
 if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
   if (ENABLE_WARNING_ERROR)
     set (WERROR "-Werror")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b1a29250/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index c917d58..69fb6b2 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -32,12 +32,6 @@
 
 #include <assert.h>
 
-static inline pn_transport_t *get_transport_internal(pn_sasl_t *sasl)
-{
-  // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-  return ((pn_transport_t *)sasl);
-}
-
 static inline pni_sasl_t *get_sasl_internal(pn_sasl_t *sasl)
 {
   // The external pn_sasl_t is really a pointer to the internal pni_transport_t


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


[30/48] qpid-proton git commit: PROTON-1344: C proactor for multi-threaded proton applications

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/engine/c/psend.c
----------------------------------------------------------------------
diff --git a/examples/engine/c/psend.c b/examples/engine/c/psend.c
deleted file mode 100644
index 2ad0edb..0000000
--- a/examples/engine/c/psend.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-
-/*################################################################
-  This program is half of a pair.  Precv and Psend are meant to 
-  be simple-as-possible examples of how to use the proton-c
-  engine interface to send and receive messages over a single 
-  connection and a single session.
-
-  In addition to being examples, these programs or their 
-  descendants will be used in performance regression testing
-  for both throughput and latency, and long-term soak testing.
-
-  This program, psend, is highly similar to its peer precv.
-  I put all the good comments in precv.
-*################################################################*/
-
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
-
-#include <proton/connection.h>
-#include <proton/delivery.h>
-#include <proton/driver.h>
-#include <proton/event.h>
-#include <proton/terminus.h>
-#include <proton/link.h>
-#include <proton/message.h>
-#include <proton/session.h>
-
-
-#define MY_BUF_SIZE 1000
-
-
-
-void
-print_timestamp ( FILE * fp, char const * label )
-{
-  struct timeval tv;
-  struct tm      * timeinfo;
-
-  gettimeofday ( & tv, 0 );
-  timeinfo = localtime ( & tv.tv_sec );
-
-  int seconds_today = 3600 * timeinfo->tm_hour +
-                        60 * timeinfo->tm_min  +
-                             timeinfo->tm_sec;
-
-  fprintf ( fp, "time : %d.%.6ld : %s\n", seconds_today, tv.tv_usec, label );
-}
-
-
-
-
-
-static 
-double
-get_time ( )
-{
-  struct timeval tv;
-  struct tm      * timeinfo;
-
-  gettimeofday ( & tv, 0 );
-  timeinfo = localtime ( & tv.tv_sec );
-
-  double time_now = 3600 * timeinfo->tm_hour +
-                      60 * timeinfo->tm_min  +
-                           timeinfo->tm_sec;
-
-  time_now += ((double)(tv.tv_usec) / 1000000.0);
-  return time_now;
-}
-
-
-
-
-
-int 
-main ( int argc, char ** argv )
-{
-  char addr [ 1000 ];
-  char host [ 1000 ];
-  char port [ 1000 ];
-  char output_file_name[1000];
-
-
-  uint64_t messages       = 2000000,
-           delivery_count = 0;
-
-  int message_length = 100;
-
-  bool done           = false;
-  int  sent_count     = 0;
-  int  n_links        = 5;
-  int const max_links = 100;
-
-  strcpy ( addr, "queue" );
-  strcpy ( host, "0.0.0.0" );
-  strcpy ( port, "5672" );
-
-  FILE * output_fp;
-
-
-  for ( int i = 1; i < argc; ++ i )
-  {
-    if ( ! strcmp ( "--host", argv[i] ) )
-    {
-      strcpy ( host, argv[i+1] );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--port", argv[i] ) )
-    {
-      strcpy ( port, argv[i+1] );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--messages", argv[i] ) )
-    {
-      sscanf ( argv [ i+1 ], "%" SCNd64 , & messages );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--message_length", argv[i] ) )
-    {
-      sscanf ( argv [ i+1 ], "%d", & message_length );
-      ++ i;
-    }
-    else
-    if ( ! strcmp ( "--n_links", argv[i] ) )
-    {
-      sscanf ( argv [ i+1 ], "%d", & n_links );
-      ++ i;
-    }
-    if ( ! strcmp ( "--output", argv[i] ) )
-    {
-      if ( ! strcmp ( "stderr", argv[i+1] ) )
-      {
-        output_fp = stderr;
-        strcpy ( output_file_name, "stderr");
-      }
-      else
-      if ( ! strcmp ( "stdout", argv[i+1] ) )
-      {
-        output_fp = stdout;
-        strcpy ( output_file_name, "stdout");
-      }
-      else
-      {
-        output_fp = fopen ( argv[i+1], "w" );
-        strcpy ( output_file_name, argv[i+1] );
-        if ( ! output_fp )
-        {
-          fprintf ( stderr, "Can't open |%s| for writing.\n", argv[i+1] );
-          exit ( 1 );
-        }
-      }
-      ++ i;
-    }
-    else
-    {
-      fprintf ( output_fp, "unknown arg %s", argv[i] );
-    }
-  }
-
-
-  fprintf ( output_fp, "host            %s\n",          host );
-  fprintf ( output_fp, "port            %s\n",          port );
-  fprintf ( output_fp, "messages        %" PRId64 "\n", messages );
-  fprintf ( output_fp, "message_length  %d\n",          message_length );
-  fprintf ( output_fp, "n_links         %d\n",          n_links );
-  fprintf ( output_fp, "output          %s\n",          output_file_name );
-
-
-  if ( n_links > max_links )
-  {
-    fprintf ( output_fp, "You can't have more than %d links.\n", max_links );
-    exit ( 1 );
-  }
-
-  pn_driver_t     * driver;
-  pn_connector_t  * connector;
-  pn_connector_t  * driver_connector;
-  pn_connection_t * connection;
-  pn_collector_t  * collector;
-  pn_link_t       * links [ max_links ];
-  pn_session_t    * session;
-  pn_event_t      * event;
-  pn_delivery_t   * delivery;
-
-
-  char * message = (char *) malloc(message_length);
-  memset ( message, 13, message_length );
-
-  /*----------------------------------------------------
-    Get everything set up.
-    We will have a single connector, a single 
-    connection, a single session, and a single link.
-  ----------------------------------------------------*/
-  driver = pn_driver ( );
-  connector = pn_connector ( driver, host, port, 0 );
-
-  connection = pn_connection();
-  collector  = pn_collector  ( );
-  pn_connection_collect ( connection, collector );
-  pn_connector_set_connection ( connector, connection );
-
-  session = pn_session ( connection );
-  pn_connection_open ( connection );
-  pn_session_open ( session );
-
-  for ( int i = 0; i < n_links; ++ i )
-  {
-    char name[100];
-    sprintf ( name, "tvc_15_%d", i );
-    links[i] = pn_sender ( session, name );
-    pn_terminus_set_address ( pn_link_target(links[i]), addr );
-    pn_link_open ( links[i] );
-  }
-
-  /*-----------------------------------------------------------
-    For my speed tests, I do not want to count setup time.
-    Start timing here.  The receiver will print out a similar
-    timestamp when he receives the final message.
-  -----------------------------------------------------------*/
-  fprintf ( output_fp, "psend: sending %llu messages.\n", messages );
-
-  // Just before we start sending, print the start timestamp.
-  fprintf ( output_fp, "psend_start %.3lf\n", get_time() );
-
-  while ( 1 )
-  {
-    pn_driver_wait ( driver, -1 );
-
-    int event_count = 1;
-    while ( event_count > 0 )
-    {
-      event_count = 0;
-      pn_connector_process ( connector );
-
-      event = pn_collector_peek(collector);
-      while ( event )
-      {
-        ++ event_count;
-        pn_event_type_t event_type = pn_event_type ( event );
-        //fprintf ( output_fp, "event: %s\n", pn_event_type_name ( event_type ) );
-
-        switch ( event_type )
-        {
-          case PN_LINK_FLOW:
-          {
-            if ( delivery_count < messages )
-            {
-              /*---------------------------------------------------
-                We may have opened multiple links.
-                The event will tell us which one this flow-event
-                happened on.  If the flow event gave us some 
-                credit, we will greedily send messages until it
-                is all used up.
-              ---------------------------------------------------*/
-              pn_link_t * link = pn_event_link ( event );
-              int credit = pn_link_credit ( link );
-
-              while ( credit > 0 )
-              {
-                // Every delivery we create needs a unique tag.
-                char str [ 100 ];
-                sprintf ( str, "%x", delivery_count ++ );
-                delivery = pn_delivery ( link, pn_dtag(str, strlen(str)) );
-
-                // If you settle the delivery before sending it,
-                // you will spend some time wondering why your 
-                // messages don't have any content when they arrive 
-                // at the receiver.
-                pn_link_send ( link, message, message_length );
-                pn_delivery_settle ( delivery );
-                pn_link_advance ( link );
-                credit = pn_link_credit ( link );
-              }
-              
-              if ( delivery_count >= messages )
-              {
-                fprintf ( output_fp, 
-                          "I have sent all %d messages.\n" ,
-                          delivery_count
-                        );
-                /*
-                  I'm still kind of hazy on how to shut down the
-                  psend / precv system properly ....
-                  I can't go to all_done here, or precv will never
-                  get all its messages and terminate.
-                  So I let precv terminate properly ... which means
-                  that this program, psend, dies with an error.
-                  Hmm.
-                */
-                // goto all_done;
-              }
-            }
-          }
-          break;
-
-
-          case PN_TRANSPORT:
-            // I don't know what this means here, either.
-          break;
-
-
-          case PN_TRANSPORT_TAIL_CLOSED:
-            goto all_done;
-          break;
-
-
-          default:
-            /*
-            fprintf ( output_fp,
-                      "precv unhandled event: %s\n",
-                      pn_event_type_name(event_type)
-                    );
-            */
-          break;
-
-        }
-
-        pn_collector_pop ( collector );
-        event = pn_collector_peek(collector);
-      }
-    }
-  }
-
-  all_done:
-
-  for ( int i = 0; i < n_links; ++ i )
-  {
-    pn_link_close ( links[i] );
-  }
-
-  pn_session_close ( session );
-  pn_connection_close ( connection );
-
-  return 0;
-}
-
-
-
-
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/examples/exampletest.py
----------------------------------------------------------------------
diff --git a/examples/exampletest.py b/examples/exampletest.py
new file mode 100644
index 0000000..d40b9cb
--- /dev/null
+++ b/examples/exampletest.py
@@ -0,0 +1,183 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+# A test library to make it easy to run unittest tests that start,
+# monitor, and report output from sub-processes. In particular
+# it helps with starting processes that listen on random ports.
+
+import unittest
+import os, sys, socket, time, re, inspect, errno, threading
+from  random import randrange
+from subprocess import Popen, PIPE, STDOUT
+from copy import copy
+import platform
+from os.path import dirname as dirname
+
+def pick_port():
+    """Pick a random port."""
+    p =  randrange(10000, 20000)
+    return p
+
+class ProcError(Exception):
+    """An exception that captures failed process output"""
+    def __init__(self, proc, what="bad exit status"):
+        out = proc.out.strip()
+        if out:
+            out = "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^\n" % out
+        else:
+            out = ", no output)"
+        super(Exception, self, ).__init__(
+            "%s %s, code=%s%s" % (proc.args, what, proc.returncode, out))
+
+class NotFoundError(ProcError):
+    pass
+
+class Proc(Popen):
+    """A example process that stores its output, optionally run with valgrind."""
+
+    if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
+        env_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
+    else:
+        env_args = []
+
+    @property
+    def out(self):
+        self._out.seek(0)
+        return self._out.read()
+
+    def __init__(self, args, **kwargs):
+        """Start an example process"""
+        args = list(args)
+        self.args = args
+        self._out = os.tmpfile()
+        try:
+            Popen.__init__(self, self.env_args + self.args, stdout=self._out, stderr=STDOUT, **kwargs)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                raise NotFoundError(self, str(e))
+            raise ProcError(self, str(e))
+        except Exception, e:
+            raise ProcError(self, str(e))
+
+    def kill(self):
+        try:
+            if self.poll() is None:
+                Popen.kill(self)
+        except:
+            pass                # Already exited.
+        return self.out
+
+    def wait_out(self, timeout=10, expect=0):
+        """Wait for process to exit, return output. Raise ProcError  on failure."""
+        t = threading.Thread(target=self.wait)
+        t.start()
+        t.join(timeout)
+        if self.poll() is None:      # Still running
+            self.kill()
+            raise ProcError(self, "timeout")
+        if expect is not None and self.poll() != expect:
+            raise ProcError(self)
+        return self.out
+
+# Work-around older python unittest that lacks setUpClass.
+if hasattr(unittest.TestCase, 'setUpClass') and  hasattr(unittest.TestCase, 'tearDownClass'):
+    TestCase = unittest.TestCase
+else:
+    class TestCase(unittest.TestCase):
+        """
+        Roughly provides setUpClass and tearDownClass functionality for older python
+        versions in our test scenarios. If subclasses override setUp or tearDown
+        they *must* call the superclass.
+        """
+        def setUp(self):
+            if not hasattr(type(self), '_setup_class_count'):
+                type(self)._setup_class_count = len(
+                    inspect.getmembers(
+                        type(self),
+                        predicate=lambda(m): inspect.ismethod(m) and m.__name__.startswith('test_')))
+                type(self).setUpClass()
+
+        def tearDown(self):
+            self.assertTrue(self._setup_class_count > 0)
+            self._setup_class_count -=  1
+            if self._setup_class_count == 0:
+                type(self).tearDownClass()
+
+class ExampleTestCase(TestCase):
+    """TestCase that manages started processes"""
+    def setUp(self):
+        super(ExampleTestCase, self).setUp()
+        self.procs = []
+
+    def tearDown(self):
+        for p in self.procs:
+            p.kill()
+        super(ExampleTestCase, self).tearDown()
+
+    def proc(self, *args, **kwargs):
+        p = Proc(*args, **kwargs)
+        self.procs.append(p)
+        return p
+
+def wait_port(port, timeout=10):
+    """Wait up to timeout for port to be connectable."""
+    if timeout:
+        deadline = time.time() + timeout
+    while (timeout is None or time.time() < deadline):
+        try:
+            s = socket.create_connection((None, port), timeout) # Works for IPv6 and v4
+            s.close()
+            return
+        except socket.error, e:
+            if e.errno != errno.ECONNREFUSED: # Only retry on connection refused error.
+                raise
+    raise socket.timeout()
+
+
+class BrokerTestCase(ExampleTestCase):
+    """
+    ExampleTest that starts a broker in setUpClass and kills it in tearDownClass.
+    Subclass must set `broker_exe` class variable with the name of the broker executable.
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        cls.port = pick_port()
+        cls.addr = "127.0.0.1:%s/examples" % (cls.port)
+        cls.broker = None       # In case Proc throws, create the attribute.
+        cls.broker = Proc(cls.broker_exe + ["-a", cls.addr])
+        try:
+            wait_port(cls.port)
+        except Exception, e:
+            cls.broker.kill()
+            raise ProcError(cls.broker, "timed out waiting for port")
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.broker: cls.broker.kill()
+
+    def tearDown(self):
+        b = type(self).broker
+        if b and b.poll() !=  None: # Broker crashed
+            type(self).setUpClass() # Start another for the next test.
+            raise ProcError(b, "broker crash")
+        super(BrokerTestCase, self).tearDown()
+
+if __name__ == "__main__":
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp b/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
index 70e6754..d9825c2 100644
--- a/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
+++ b/proton-c/bindings/cpp/include/proton/io/connection_engine.hpp
@@ -121,8 +121,8 @@ PN_CPP_CLASS_EXTERN connection_engine {
 
     /// Configure a connection by applying exactly the options in opts (including proton::messaging_handler)
     /// Does not apply any default options, to apply container defaults use connect() or accept()
-    /// instead.
-    void configure(const connection_options& opts=connection_options());
+    /// instead. If server==true, configure a server connection.
+    void configure(const connection_options& opts=connection_options(), bool server=false);
 
     /// Call configure() with client options and call connection::open()
     /// Options applied: container::id(), container::client_connection_options(), opts.
@@ -200,12 +200,13 @@ PN_CPP_CLASS_EXTERN connection_engine {
     PN_CPP_EXTERN proton::container* container() const;
 
  private:
+    void init();
     connection_engine(const connection_engine&);
     connection_engine& operator=(const connection_engine&);
 
     messaging_handler* handler_;
     proton::container* container_;
-    pn_connection_engine_t c_engine_;
+    pn_connection_engine_t engine_;
 };
 
 } // io

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/bindings/cpp/include/proton/sender_options.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/sender_options.hpp b/proton-c/bindings/cpp/include/proton/sender_options.hpp
index 64fea2f..0a618ff 100644
--- a/proton-c/bindings/cpp/include/proton/sender_options.hpp
+++ b/proton-c/bindings/cpp/include/proton/sender_options.hpp
@@ -90,10 +90,10 @@ class sender_options {
     PN_CPP_EXTERN sender_options& auto_settle(bool);
 
     /// Options for the source node of the sender.
-    PN_CPP_EXTERN sender_options& source(source_options &);
+    PN_CPP_EXTERN sender_options& source(const source_options &);
 
     /// Options for the receiver node of the receiver.
-    PN_CPP_EXTERN sender_options& target(target_options &);
+    PN_CPP_EXTERN sender_options& target(const target_options &);
 
     /// @cond INTERNAL
   private:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/bindings/cpp/src/io/connection_engine.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_engine.cpp b/proton-c/bindings/cpp/src/io/connection_engine.cpp
index 4712b3e..5e6483f 100644
--- a/proton-c/bindings/cpp/src/io/connection_engine.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_engine.cpp
@@ -40,35 +40,34 @@
 namespace proton {
 namespace io {
 
-connection_engine::connection_engine() :
-    container_(0)
-{
-    int err;
-    if ((err = pn_connection_engine_init(&c_engine_)))
-        throw proton::error(std::string("connection_engine init failed: ")+pn_code(err));
-}
-
-connection_engine::connection_engine(class container& cont, event_loop* loop) :
-    container_(&cont)
-{
-    int err;
-    if ((err = pn_connection_engine_init(&c_engine_)))
-        throw proton::error(std::string("connection_engine init failed: ")+pn_code(err));
+void connection_engine::init() {
+    if (pn_connection_engine_init(&engine_, pn_connection(), pn_transport()) != 0) {
+        this->~connection_engine(); // Dtor won't be called on throw from ctor.
+        throw proton::error(std::string("connection_engine allocation failed"));
+    }
+}
+
+connection_engine::connection_engine() : handler_(0), container_(0) { init(); }
+
+connection_engine::connection_engine(class container& cont, event_loop* loop) : handler_(0), container_(&cont) {
+    init();
     connection_context& ctx = connection_context::get(connection());
     ctx.container = container_;
     ctx.event_loop.reset(loop);
 }
 
-void connection_engine::configure(const connection_options& opts) {
-    proton::connection c = connection();
+connection_engine::~connection_engine() {
+    pn_connection_engine_destroy(&engine_);
+}
+
+void connection_engine::configure(const connection_options& opts, bool server) {
+    proton::connection c(connection());
     opts.apply_unbound(c);
+    if (server) pn_transport_set_server(engine_.transport);
+    pn_connection_engine_bind(&engine_);
     opts.apply_bound(c);
     handler_ =  opts.handler();
-    connection_context::get(connection()).collector = c_engine_.collector;
-}
-
-connection_engine::~connection_engine() {
-    pn_connection_engine_final(&c_engine_);
+    connection_context::get(connection()).collector = engine_.collector;
 }
 
 void connection_engine::connect(const connection_options& opts) {
@@ -78,7 +77,7 @@ void connection_engine::connect(const connection_options& opts) {
         all.update(container_->client_connection_options());
     }
     all.update(opts);
-    configure(all);
+    configure(all, false);
     connection().open();
 }
 
@@ -89,12 +88,12 @@ void connection_engine::accept(const connection_options& opts) {
         all.update(container_->server_connection_options());
     }
     all.update(opts);
-    configure(all);
+    configure(all, true);
 }
 
 bool connection_engine::dispatch() {
     pn_event_t* c_event;
-    while ((c_event = pn_connection_engine_dispatch(&c_engine_)) != NULL) {
+    while ((c_event = pn_connection_engine_event(&engine_)) != NULL) {
         proton_event cpp_event(c_event, container_);
         try {
             if (handler_ != 0) {
@@ -102,51 +101,56 @@ bool connection_engine::dispatch() {
                 cpp_event.dispatch(adapter);
             }
         } catch (const std::exception& e) {
-            disconnected(error_condition("exception", e.what()));
+            pn_condition_t *cond = pn_transport_condition(engine_.transport);
+            if (!pn_condition_is_set(cond)) {
+                pn_condition_format(cond, "exception", "%s", e.what());
+            }
         }
+        pn_connection_engine_pop_event(&engine_);
     }
-    return !pn_connection_engine_finished(&c_engine_);
+    return !pn_connection_engine_finished(&engine_);
 }
 
 mutable_buffer connection_engine::read_buffer() {
-    pn_rwbytes_t buffer = pn_connection_engine_read_buffer(&c_engine_);
+    pn_rwbytes_t buffer = pn_connection_engine_read_buffer(&engine_);
     return mutable_buffer(buffer.start, buffer.size);
 }
 
 void connection_engine::read_done(size_t n) {
-    return pn_connection_engine_read_done(&c_engine_, n);
+    return pn_connection_engine_read_done(&engine_, n);
 }
 
 void connection_engine::read_close() {
-    pn_connection_engine_read_close(&c_engine_);
+    pn_connection_engine_read_close(&engine_);
 }
 
 const_buffer connection_engine::write_buffer() {
-    pn_bytes_t buffer = pn_connection_engine_write_buffer(&c_engine_);
+    pn_bytes_t buffer = pn_connection_engine_write_buffer(&engine_);
     return const_buffer(buffer.start, buffer.size);
 }
 
 void connection_engine::write_done(size_t n) {
-    return pn_connection_engine_write_done(&c_engine_, n);
+    return pn_connection_engine_write_done(&engine_, n);
 }
 
 void connection_engine::write_close() {
-    pn_connection_engine_write_close(&c_engine_);
+    pn_connection_engine_write_close(&engine_);
 }
 
 void connection_engine::disconnected(const proton::error_condition& err) {
-    pn_condition_t* condition = pn_connection_engine_condition(&c_engine_);
-    if (!pn_condition_is_set(condition))     // Don't overwrite existing condition
+    pn_condition_t* condition = pn_transport_condition(engine_.transport);
+    if (!pn_condition_is_set(condition))  {
         set_error_condition(err, condition);
-    pn_connection_engine_disconnected(&c_engine_);
+    }
+    pn_connection_engine_close(&engine_);
 }
 
 proton::connection connection_engine::connection() const {
-    return make_wrapper(c_engine_.connection);
+    return make_wrapper(engine_.connection);
 }
 
 proton::transport connection_engine::transport() const {
-    return make_wrapper(c_engine_.transport);
+    return make_wrapper(engine_.transport);
 }
 
 proton::container* connection_engine::container() const {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/bindings/cpp/src/sender_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/sender_options.cpp b/proton-c/bindings/cpp/src/sender_options.cpp
index f5d5525..bed4a69 100644
--- a/proton-c/bindings/cpp/src/sender_options.cpp
+++ b/proton-c/bindings/cpp/src/sender_options.cpp
@@ -108,8 +108,8 @@ void sender_options::update(const sender_options& x) { impl_->update(*x.impl_);
 sender_options& sender_options::handler(class messaging_handler &h) { impl_->handler = &h; return *this; }
 sender_options& sender_options::delivery_mode(proton::delivery_mode m) {impl_->delivery_mode = m; return *this; }
 sender_options& sender_options::auto_settle(bool b) {impl_->auto_settle = b; return *this; }
-sender_options& sender_options::source(source_options &s) {impl_->source = s; return *this; }
-sender_options& sender_options::target(target_options &s) {impl_->target = s; return *this; }
+sender_options& sender_options::source(const source_options &s) {impl_->source = s; return *this; }
+sender_options& sender_options::target(const target_options &s) {impl_->target = s; return *this; }
 
 void sender_options::apply(sender& s) const { impl_->apply(s); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/docs/api/index.md
----------------------------------------------------------------------
diff --git a/proton-c/docs/api/index.md b/proton-c/docs/api/index.md
index 10aea84..ccd679d 100644
--- a/proton-c/docs/api/index.md
+++ b/proton-c/docs/api/index.md
@@ -1,5 +1,39 @@
 Proton Documentation            {#index}
 ====================
 
-The proton library contains two APIs: The [Engine API](@ref engine),
-and the [Messenger API](@ref messenger).
+## The Protocol Engine
+
+The [Engine API](@ref engine) is a "pure AMQP" toolkit, it decodes AMQP bytes
+into proton [events](@ref event) and generates AMQP bytes from application
+calls.
+
+The [connection engine](@ref connection_engine) provides a simple bytes in/bytes
+out, event-driven interface so you can read AMQP data from any source, process
+the resulting [events](@ref event) and write AMQP output to any destination.
+
+There is no IO or threading code in this part of the library, so it can be
+embedded in many different environments. The proton project provides language
+bindings (Python, Ruby, Go etc.) that embed it into the standard IO and
+threading facilities of the bound language.
+
+## Integrating with IO
+
+The [Proactor API](@ref proactor) is a pro-active, asynchronous framewokr to
+build single or multi-threaded Proton C applications.
+
+For advanced use-cases it is possible to write your own implementation of the
+proactor API for an unusual IO or threading framework. Any proton application
+written to the proactor API will be able to use your implementation.
+
+## Messenger and Reactor APIs
+
+The [Messenger](@ref messenger) [Reactor](@ref reactor) APIs were intended
+to be simple APIs that included IO support directly out of the box.
+
+They both had good points but were both based on the assumption of a single-threaded
+environment using a POSIX-like poll() call. This was a problem for performance on some
+platforms and did not support multi-threaded applications.
+
+Note however that application code which interacts with the AMQP @ref engine and
+processes AMQP @ref "events" event is the same for the proactor and reactor APIs,
+so is quite easy to convert. The main difference is in how connections are set up.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/cid.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/cid.h b/proton-c/include/proton/cid.h
index 1e4715f..cd68de4 100644
--- a/proton-c/include/proton/cid.h
+++ b/proton-c/include/proton/cid.h
@@ -56,7 +56,10 @@ typedef enum {
   CID_pn_selector,
   CID_pn_selectable,
 
-  CID_pn_url
+  CID_pn_url,
+
+  CID_pn_listener,
+  CID_pn_proactor
 } pn_cid_t;
 
 #endif /* cid.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/condition.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/condition.h b/proton-c/include/proton/condition.h
index cf2f8aa..ae2beff 100644
--- a/proton-c/include/proton/condition.h
+++ b/proton-c/include/proton/condition.h
@@ -165,6 +165,10 @@ PN_EXTERN const char *pn_condition_redirect_host(pn_condition_t *condition);
  */
 PN_EXTERN int pn_condition_redirect_port(pn_condition_t *condition);
 
+PN_EXTERN int pn_condition_copy(pn_condition_t *dest, pn_condition_t *src);
+PN_EXTERN pn_condition_t *pn_condition(void);
+PN_EXTERN void pn_condition_free(pn_condition_t *);
+
 /** @}
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/connection.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection.h b/proton-c/include/proton/connection.h
index c5b5490..0ed23b0 100644
--- a/proton-c/include/proton/connection.h
+++ b/proton-c/include/proton/connection.h
@@ -82,6 +82,7 @@ extern "C" {
  */
 #define PN_REMOTE_MASK (PN_REMOTE_UNINIT | PN_REMOTE_ACTIVE | PN_REMOTE_CLOSED)
 
+PN_EXTERN pn_connection_t *pn_connection(void);
 /**
  * Factory to construct a new Connection.
  *
@@ -148,6 +149,13 @@ PN_EXTERN pn_error_t *pn_connection_error(pn_connection_t *connection);
 PN_EXTERN void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collector);
 
 /**
+ * Get the collector set with pn_connection_collect()
+ * @return NULL if pn_connection_collect() has not been called.
+*/
+PN_EXTERN pn_collector_t* pn_connection_collector(pn_connection_t *connection);
+
+
+/**
  * @deprecated
  * Get the application context that is associated with a connection
  * object.
@@ -477,6 +485,16 @@ PN_EXTERN pn_data_t *pn_connection_remote_properties(pn_connection_t *connection
  */
 PN_EXTERN pn_transport_t *pn_connection_transport(pn_connection_t *connection);
 
+/**
+ * Create a connection with `size` bytes of extra aligned storage in the same heap block.
+ */
+PN_EXTERN pn_connection_t* pn_connection_with_extra(size_t size);
+
+/**
+ * Get the start and size of extra storage allocated by pn_connection_extra()
+ */
+PN_EXTERN pn_rwbytes_t pn_connection_get_extra(pn_connection_t *connection);
+
 /** @}
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/connection_engine.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/connection_engine.h b/proton-c/include/proton/connection_engine.h
index d9df77b..b7022a9 100644
--- a/proton-c/include/proton/connection_engine.h
+++ b/proton-c/include/proton/connection_engine.h
@@ -20,160 +20,289 @@
  * under the License.
  */
 
-///@file
-///
-/// **Experimental** The Connection Engine API wraps up the proton engine
-/// objects associated with a single connection: pn_connection_t, pn_transport_t
-/// and pn_collector_t. It provides a simple bytes-in/bytes-out interface for IO
-/// and generates pn_event_t events to be handled by the application.
-///
-/// The connection engine can be fed with raw AMQP bytes from any source, and it
-/// generates AMQP byte output to be written to any destination. You can use the
-/// engine to integrate proton AMQP with any IO library, or native IO on any
-/// platform.
-///
-/// The engine is not thread safe but each engine is independent. Separate
-/// engines can be used concurrently. For example a multi-threaded application
-/// can process connections in multiple threads, but serialize work for each
-/// connection to the corresponding engine.
-///
-/// The engine is designed to be thread and IO neutral so it can be integrated with
-/// single or multi-threaded code in reactive or proactive IO frameworks.
-///
-/// Summary of use:
-///
-/// - while !pn_connection_engine_finished()
-///   - Call pn_connection_engine_dispatch() to dispatch events until it returns NULL.
-///   - Read data from your source into pn_connection_engine_read_buffer()
-///   - Call pn_connection_engine_read_done() when complete.
-///   - Write data from pn_connection_engine_write_buffer() to your destination.
-///   - Call pn_connection_engine_write_done() to indicate how much was written.
-///
-/// Note on blocking: the _read/write_buffer and _read/write_done functions can
-/// all generate events that may cause the engine to finish. Before you wait for
-/// IO, always drain pn_connection_engine_dispatch() till it returns NULL and
-/// check pn_connection_engine_finished() in case there is nothing more to do..
-///
-/// Note on error handling: the pn_connection_engine_*() functions do not return
-/// an error code. If an error occurs it will be reported as a
-/// PN_TRANSPORT_ERROR event and pn_connection_engine_finished() will return
-/// true once all final events have been processed.
-///
-/// @defgroup connection_engine The Connection Engine
-/// @{
-///
-
-#include <proton/condition.h>
-#include <proton/event.h>
+/**
+ * @file
+ *
+ * **Experimental** The connection IO API is a set of functions to simplify
+ * integrating proton with different IO and concurrency platforms. The portable
+ * parts of a Proton application should use the @ref engine types.  We will
+ * use "application" to mean the portable part of the application and
+ * "integration" to mean code that integrates with a particular IO platform.
+ *
+ * The connection_engine functions take a @ref pn_connection_t\*, and perform common
+ * tasks involving the @ref pn_connection_t and it's @ref pn_transport_t and
+ * @ref pn_collector_t so you can treat them as a unit. You can also work with
+ * these types directly for features not available via @ref connection_engine API.
+ *
+ * @defgroup connection_engine Connection Engine
+ *
+ * **Experimental**: Toolkit for integrating proton with arbitrary network or IO
+ * transports. Provides a single point of control for an AMQP connection and
+ * a simple bytes-in/bytes-out interface that lets you:
+ *
+ * - process AMQP-encoded bytes from some input byte stream
+ * - generate @ref pn_event_t events for your application to handle
+ * - encode resulting AMQP output bytes for some output byte stream
+ *
+ * The engine contains a @ref pn_connection_t, @ref pn_transport_t and @ref
+ * pn_collector_t and provides functions to operate on all three as a unit for
+ * IO integration. You can also use them directly for anything not covered by
+ * this API
+ *
+ * For example a simple blocking IO integration with the imaginary "my_io" library:
+ *
+ *     pn_connection_engine_t ce;
+ *     pn_connection_engine_init(&ce);
+ *     while (!pn_connection_engine_finished(&ce) {
+ *         // Dispatch events to be handled by the application.
+ *         pn_event_t *e;
+ *         while ((e = pn_connection_engine_event(&ce))!= NULL) {
+ *             my_app_handle(e); // Pass to the application handler
+ *             switch (pn_event_type(e)) {
+ *                 case PN_CONNECTION_INIT: pn_connection_engine_bind(&ce);
+ *                 // Only for full-duplex IO where read/write can shutdown separately.
+ *                 case PN_TRANSPORT_CLOSE_READ: my_io_shutdown_read(...); break;
+ *                 case PN_TRANSPORT_CLOSE_WRITE: my_io_shutdown_write(...); break;
+ *                 default: break;
+ *             };
+ *             e = pn_connection_engine_pop_event(&ce);
+ *         }
+ *         // Read from my_io into the connection buffer
+ *         pn_rwbytes_t readbuf = pn_connection_engine_read_buffer(&ce);
+ *         if (readbuf.size) {
+ *             size_t n = my_io_read(readbuf.start, readbuf.size, ...);
+ *             if (n > 0) {
+ *                 pn_connection_engine_read_done(&ce, n);
+ *             } else if (n < 0) {
+ *                 pn_connection_engine_errorf(&ce, "read-err", "something-bad (%d): %s", n, ...);
+ *                 pn_connection_engine_read_close(&ce);
+ *             }
+ *         }
+ *         // Write from connection buffer to my_io
+ *         pn_bytes_t writebuf = pn_connection_engine_write_buffer(&ce);
+ *         if (writebuf.size) {
+ *             size_t n = my_io_write_data(writebuf.start, writebuf.size, ...);
+ *             if (n < 0) {
+ *                 pn_connection_engine_errorf(&ce, "write-err", "something-bad (%d): %s", d, ...);
+ *                 pn_connection_engine_write_close(&ce);
+ *             } else {
+ *                 pn_connection_engine_write_done(&ce, n);
+ *             }
+ *         }
+ *     }
+ *     // If my_io doesn't have separate read/write shutdown, then we should close it now.
+ *     my_io_close(...);
+ *
+ * AMQP is a full-duplex, asynchronous protocol. The "read" and "write" sides of
+ * an AMQP connection can close separately, the example shows how to handle this
+ * for full-duplex IO or IO with a simple close.
+ *
+ * The engine buffers events, you must keep processing till
+ * pn_connection_engine_finished() is true, to ensure all reading, writing and event
+ * handling (including ERROR and FINAL events) is completely finished.
+ *
+ * ## Error handling
+ *
+ * The pn_connection_engine_*() functions do not return an error code. IO errors set
+ * the transport condition and are returned as a PN_TRANSPORT_ERROR. The integration
+ * code can set errors using pn_connection_engine_errorf()
+ *
+ * ## Other IO patterns
+ *
+ * This API supports asynchronous, proactive, non-blocking and reactive IO. An
+ * integration does not have to follow the dispatch-read-write sequence above,
+ * but note that you should handle all available events before calling
+ * pn_connection_engine_read_buffer() and check that `size` is non-zero before
+ * starting a blocking or asynchronous read call. A `read` started while there
+ * are unprocessed CLOSE events in the buffer may never complete.
+ *
+ * ## Thread safety
+ *
+ * The @ref engine types are not thread safe, but each connection and its
+ * associated types forms an independent unit. Different connections can be
+ * processed concurrently by different threads.
+ *
+ * @defgroup connection_engine Connection IO
+ * @{
+ */
+
 #include <proton/import_export.h>
+#include <proton/event.h>
 #include <proton/types.h>
 
+#include <stdarg.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/// A connection engine is a trio of pn_connection_t, pn_transport_t and pn_collector_t.
-/// Use the pn_connection_engine_*() functions to operate on it.
-/// It is a plain struct, not a proton object. Use pn_connection_engine_init to set up
-/// the initial objects and pn_connection_engine_final to release them.
-///
+/**
+ * Struct containing a connection, transport and collector. See
+ * pn_connection_engine_init(), pn_connection_engine_destroy() and pn_connection_engine()
+ */
 typedef struct pn_connection_engine_t {
-    pn_connection_t* connection;
-    pn_transport_t* transport;
-    pn_collector_t* collector;
-    pn_event_t* event;
+  pn_connection_t *connection;
+  pn_transport_t *transport;
+  pn_collector_t *collector;
 } pn_connection_engine_t;
 
-/// Initialize a pn_connection_engine_t struct with a new connection and
-/// transport.
-///
-/// Call pn_connection_engine_final to free resources when you are done.
-///
-///@return 0 on success, a proton error code on failure (@see error.h)
-///
-PN_EXTERN int pn_connection_engine_init(pn_connection_engine_t* engine);
-
-/// Free resources used by the engine, set the connection and transport pointers
-/// to NULL.
-PN_EXTERN void pn_connection_engine_final(pn_connection_engine_t* engine);
-
-/// Get the engine's read buffer. Read data from your IO source to buf.start, up
-/// to a max of buf.size. Then call pn_connection_engine_read_done().
-///
-/// buf.size==0 means the engine cannot read presently, calling
-/// pn_connection_engine_dispatch() may create more buffer space.
-///
-PN_EXTERN pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t*);
-
-/// Consume the first n bytes of data in pn_connection_engine_read_buffer() and
-/// update the buffer.
-PN_EXTERN void pn_connection_engine_read_done(pn_connection_engine_t*, size_t n);
-
-/// Close the read side of the transport when no more data is available.
-/// Note there may still be events for pn_connection_engine_dispatch() or data
-/// in pn_connection_engine_write_buffer()
-PN_EXTERN void pn_connection_engine_read_close(pn_connection_engine_t*);
-
-/// Get the engine's write buffer. Write data from buf.start to your IO destination,
-/// up to a max of buf.size. Then call pn_connection_engine_write_done().
-///
-/// buf.size==0 means the engine has nothing to write presently.  Calling
-/// pn_connection_engine_dispatch() may generate more data.
-PN_EXTERN pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t*);
-
-/// Call when the first n bytes of pn_connection_engine_write_buffer() have been
-/// written to IO and can be re-used for new data.  Updates the buffer.
-PN_EXTERN void pn_connection_engine_write_done(pn_connection_engine_t*, size_t n);
-
-/// Call when the write side of IO has closed and no more data can be written.
-/// Note that there may still be events for pn_connection_engine_dispatch() or
-/// data to read into pn_connection_engine_read_buffer().
-PN_EXTERN void pn_connection_engine_write_close(pn_connection_engine_t*);
-
-/// Close both sides of the transport, equivalent to
-///     pn_connection_engine_read_close(); pn_connection_engine_write_close()
-///
-/// You must still call pn_connection_engine_dispatch() to process final
-/// events.
-///
-/// To provide transport error information to the handler, set it on
-///     pn_connection_engine_condition()
-/// *before* calling pn_connection_engine_disconnected(). This sets
-/// the error on the pn_transport_t object.
-///
-/// Note this does *not* modify the pn_connection_t, so you can distinguish
-/// between a connection close error sent by the remote peer (which will set the
-/// connection condition) and a transport error (which sets the transport
-/// condition.)
-///
-PN_EXTERN void pn_connection_engine_disconnected(pn_connection_engine_t*);
-
-/// Get the next available event.
-/// Call in a loop until it returns NULL to dispatch all available events.
-/// Note this call may modify the read and write buffers.
-///
-/// @return Pointer to the next event, or NULL if there are none available.
-///
-PN_EXTERN pn_event_t* pn_connection_engine_dispatch(pn_connection_engine_t*);
-
-/// Return true if the engine is finished - all data has been written, all
-/// events have been handled and the transport is closed.
-PN_EXTERN bool pn_connection_engine_finished(pn_connection_engine_t*);
-
-/// Get the AMQP connection, owned by the pn_connection_engine_t.
-PN_EXTERN pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t*);
-
-/// Get the proton transport, owned by the pn_connection_engine_t.
-PN_EXTERN pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t*);
-
-/// Get the condition object for the engine's transport.
-///
-/// Note that IO errors should be set on this, the transport condition, not on
-/// the pn_connection_t condition. The connection's condition is for errors
-/// received via the AMQP protocol, the transport condition is for errors in the
-/// the IO layer such as a socket read or disconnect errors.
-///
-PN_EXTERN pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t*);
+/**
+ * Set #connection and #transport to the provided values, or create a new
+ * @ref pn_connection_t or @ref pn_transport_t if either is NULL.
+ * The provided values belong to the connection engine and will be freed by
+ * pn_connection_engine_destroy()
+ *
+ * Create a new @ref pn_collector_t and set as #collector.
+ *
+ * The transport and connection are *not* bound at this point. You should
+ * configure them as needed and let the application handle the
+ * PN_CONNECTION_INIT from pn_connection_engine_event() before calling
+ * pn_connection_engine_bind().
+ *
+ * @return if any allocation fails call pn_connection_engine_destroy() and return PN_OUT_OF_MEMORY
+ */
+PN_EXTERN int pn_connection_engine_init(pn_connection_engine_t*, pn_connection_t*, pn_transport_t*);
+
+/**
+ * Bind the connection to the transport when the external IO is ready.
+ *
+ * The following functions (if called at all) must be called *before* bind:
+ * pn_connection_set_username(), pn_connection_set_password(),  pn_transport_set_server()
+ *
+ * If there is an external IO error during setup, set a transport error, close
+ * the transport and then bind. The error events are reported to the application
+ * via pn_connection_engine_event().
+ *
+ * @return an error code if the bind fails.
+ */
+PN_EXTERN int pn_connection_engine_bind(pn_connection_engine_t *);
+
+/**
+ * Unbind, release and free #connection, #transpot and #collector. Set all pointers to NULL.
+ * Does not free the @ref pn_connection_engine_t struct itself.
+ */
+PN_EXTERN void pn_connection_engine_destroy(pn_connection_engine_t *);
+
+/**
+ * Get the read buffer.
+ *
+ * Copy data from your input byte source to buf.start, up to buf.size.
+ * Call pn_connection_engine_read_done() when reading is complete.
+ *
+ * buf.size==0 means reading is not possible: no buffer space or the read side is closed.
+ */
+PN_EXTERN pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t *);
+
+/**
+ * Process the first n bytes of data in pn_connection_engine_read_buffer() and
+ * reclaim the buffer space.
+ */
+PN_EXTERN void pn_connection_engine_read_done(pn_connection_engine_t *, size_t n);
+
+/**
+ * Close the read side. Call when the IO can no longer be read.
+ */
+PN_EXTERN void pn_connection_engine_read_close(pn_connection_engine_t *);
+
+/**
+ * True if read side is closed.
+ */
+PN_EXTERN bool pn_connection_engine_read_closed(pn_connection_engine_t *);
+
+/**
+ * Get the write buffer.
+ *
+ * Write data from buf.start to your IO destination, up to a max of buf.size.
+ * Call pn_connection_engine_write_done() when writing is complete.
+ *
+ * buf.size==0 means there is nothing to write.
+ */
+ PN_EXTERN pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t *);
+
+/**
+ * Call when the first n bytes of pn_connection_engine_write_buffer() have been
+ * written to IO. Reclaims the buffer space and reset the write buffer.
+ */
+PN_EXTERN void pn_connection_engine_write_done(pn_connection_engine_t *, size_t n);
+
+/**
+ * Close the write side. Call when IO can no longer be written to.
+ */
+PN_EXTERN void pn_connection_engine_write_close(pn_connection_engine_t *);
+
+/**
+ * True if write side is closed.
+ */
+PN_EXTERN bool pn_connection_engine_write_closed(pn_connection_engine_t *);
+
+/**
+ * Close both sides side.
+ */
+PN_EXTERN void pn_connection_engine_close(pn_connection_engine_t * c);
+
+/**
+ * Get the current event. Call pn_connection_engine_done() when done handling it.
+ * Note that if PN_TRACE_EVT is enabled this will log the event, so you should
+ * avoid calling it more than once per event. Use pn_connection_engine_has_event()
+ * to silently test if any events are available.
+ *
+ * @return NULL if there are no more events ready. Reading/writing data may produce more.
+ */
+PN_EXTERN pn_event_t* pn_connection_engine_event(pn_connection_engine_t *);
+
+/**
+ * True if  pn_connection_engine_event() will return a non-NULL event.
+ */
+PN_EXTERN bool pn_connection_engine_has_event(pn_connection_engine_t *);
+
+/**
+ * Drop the current event, advance pn_connection_engine_event() to the next event.
+ */
+PN_EXTERN void pn_connection_engine_pop_event(pn_connection_engine_t *);
+
+/**
+ * Return true if the the engine is closed for reading and writing and there are
+ * no more events.
+ *
+ * Call pn_connection_engine_free() to free all related memory.
+ */
+PN_EXTERN bool pn_connection_engine_finished(pn_connection_engine_t *);
+
+/**
+ * Set IO error information.
+ *
+ * The name and formatted description are set on the transport condition, and
+ * returned as a PN_TRANSPORT_ERROR event from pn_connection_engine_event().
+ *
+ * You must call this *before* pn_connection_engine_read_close() or
+ * pn_connection_engine_write_close() to ensure the error is processed.
+ *
+ * If there is already a transport condition set, this call does nothing.  For
+ * more complex cases, you can work with the transport condition directly using:
+ *
+ *     pn_condition_t *cond = pn_transport_condition(pn_connection_transport(conn));
+ */
+PN_EXTERN void pn_connection_engine_errorf(pn_connection_engine_t *ce, const char *name, const char *fmt, ...);
+
+/**
+ * Set IO error information via a va_list, see pn_connection_engine_errorf()
+ */
+PN_EXTERN void pn_connection_engine_verrorf(pn_connection_engine_t *ce, const char *name, const char *fmt, va_list);
+
+/**
+ * Log a string message using the connection's transport log.
+ */
+PN_EXTERN void pn_connection_engine_log(pn_connection_engine_t *ce, const char *msg);
+
+/**
+ * Log a printf formatted message using the connection's transport log.
+ */
+PN_EXTERN void pn_connection_engine_logf(pn_connection_engine_t *ce, char *fmt, ...);
+
+/**
+ * Log a printf formatted message using the connection's transport log.
+ */
+PN_EXTERN void pn_connection_engine_vlogf(pn_connection_engine_t *ce, const char *fmt, va_list ap);
 
 ///@}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/event.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/event.h b/proton-c/include/proton/event.h
index d10927b..4dca2d5 100644
--- a/proton-c/include/proton/event.h
+++ b/proton-c/include/proton/event.h
@@ -277,13 +277,19 @@ typedef enum {
   PN_TRANSPORT_ERROR,
 
   /**
-   * Indicates that the head of the transport has been closed. This
+   * Indicates that the "head" or writing end of the transport has been closed. This
    * means the transport will never produce more bytes for output to
    * the network. Events of this type point to the relevant transport.
    */
   PN_TRANSPORT_HEAD_CLOSED,
 
   /**
+   * The write side of the transport is closed, it will no longer produce bytes
+   * to write to external IO. Synonynm for PN_TRANSPORT_HEAD_CLOSED
+   */
+  PN_TRANSPORT_WRITE_CLOSED = PN_TRANSPORT_HEAD_CLOSED,
+
+  /**
    * Indicates that the tail of the transport has been closed. This
    * means the transport will never be able to process more bytes from
    * the network. Events of this type point to the relevant transport.
@@ -291,6 +297,12 @@ typedef enum {
   PN_TRANSPORT_TAIL_CLOSED,
 
   /**
+   * The read side of the transport is closed, it will no longer read bytes
+   * from external IO. Synonynm for PN_TRANSPORT_TAIL_CLOSED
+   */
+  PN_TRANSPORT_READ_CLOSED = PN_TRANSPORT_TAIL_CLOSED,
+
+  /**
    * Indicates that the both the head and tail of the transport are
    * closed. Events of this type point to the relevant transport.
    */
@@ -302,7 +314,39 @@ typedef enum {
   PN_SELECTABLE_WRITABLE,
   PN_SELECTABLE_ERROR,
   PN_SELECTABLE_EXPIRED,
-  PN_SELECTABLE_FINAL
+  PN_SELECTABLE_FINAL,
+
+  /**
+   * pn_connection_wake() was called.
+   * Events of this type point to the @ref pn_connection_t.
+   */
+  PN_CONNECTION_WAKE,
+
+  /**
+   * pn_listener_close() was called or an error occurred, see pn_listener_condition()
+   * Events of this type point to the @ref pn_listener_t.
+   */
+  PN_LISTENER_CLOSE,
+
+  /**
+   * pn_proactor_interrupt() was called to interrupt a proactor thread
+   * Events of this type point to the @ref pn_proactor_t.
+   */
+  PN_PROACTOR_INTERRUPT,
+
+  /**
+   * pn_proactor_set_timeout() time limit expired.
+   * Events of this type point to the @ref pn_proactor_t.
+   */
+  PN_PROACTOR_TIMEOUT,
+
+  /**
+   * The proactor becaome inactive: all listeners and connections are closed and
+   * their events processed, the timeout is expired.
+   *
+   * Events of this type point to the @ref pn_proactor_t.
+   */
+  PN_PROACTOR_INACTIVE
 
 } pn_event_type_t;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/extra.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/extra.h b/proton-c/include/proton/extra.h
new file mode 100644
index 0000000..ea2e1ef
--- /dev/null
+++ b/proton-c/include/proton/extra.h
@@ -0,0 +1,69 @@
+#ifndef EXTRA_H
+#define EXTRA_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/type_compat.h>
+#include <proton/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/**
+ * @cond INTERNAL
+ * Support for allocating extra aligned memory after a type.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * extra_t contains a size and is maximally aligned so the memory immediately
+ * after it can store any type of value.
+ */
+typedef union pn_extra_t {
+  size_t size;
+#if __STDC_VERSION__ >= 201112
+  max_align_t max;
+#else
+/* Not standard but fairly safe */
+  uint64_t i;
+  long double d;
+  void *v;
+  void (*fp)(void);
+#endif
+} pn_extra_t;
+
+static inline pn_rwbytes_t pn_extra_rwbytes(pn_extra_t *x) {
+    return pn_rwbytes(x->size, (char*)(x+1));
+}
+
+/* Declare private helper struct for T */
+#define PN_EXTRA_DECLARE(T) typedef struct T##__extra { T base; pn_extra_t extra; } T##__extra
+#define PN_EXTRA_SIZEOF(T, N) (sizeof(T##__extra)+(N))
+#define PN_EXTRA_GET(T, P) pn_extra_rwbytes(&((T##__extra*)(P))->extra)
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @endcond */
+
+#endif // EXTRA_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/listener.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/listener.h b/proton-c/include/proton/listener.h
new file mode 100644
index 0000000..f55479b
--- /dev/null
+++ b/proton-c/include/proton/listener.h
@@ -0,0 +1,76 @@
+#ifndef PROTON_LISTENER_H
+#define PROTON_LISTENER_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ *
+ * Listener API for the proton @proactor
+ *
+ * @defgroup listener Listener
+ * @ingroup proactor
+ * @{
+ */
+
+typedef struct pn_proactor_t pn_proactor_t;
+typedef struct pn_condition_t pn_condition_t;
+
+/**
+ * Listener accepts connections, see pn_proactor_listen()
+ */
+typedef struct pn_listener_t pn_listener_t;
+
+/**
+ * The proactor that created the listener.
+ */
+pn_proactor_t *pn_listener_proactor(pn_listener_t *c);
+
+/**
+ * Get the error condition for a listener.
+ */
+pn_condition_t *pn_listener_condition(pn_listener_t *l);
+
+/**
+ * Get the user-provided value associated with the listener in pn_proactor_listen()
+ * The start address is aligned so you can cast it to any type.
+ */
+pn_rwbytes_t pn_listener_get_extra(pn_listener_t*);
+
+/**
+ * Close the listener (thread safe).
+ */
+void pn_listener_close(pn_listener_t *l);
+
+/**
+ *@}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PROTON_LISTENER_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/object.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/object.h b/proton-c/include/proton/object.h
index bafdcf4..0433b58 100644
--- a/proton-c/include/proton/object.h
+++ b/proton-c/include/proton/object.h
@@ -159,6 +159,29 @@ PREFIX ## _t *PREFIX ## _new(void) {                                      \
     PREFIX ## _inspect                          \
 }
 
+/* Class to identify a plain C struct in a pn_event_t. No refcounting or memory management. */
+#define PN_STRUCT_CLASSDEF(PREFIX, CID)                                 \
+  const pn_class_t *PREFIX ## __class(void);                            \
+  static const pn_class_t *PREFIX ## _reify(void *p) { return PREFIX ## __class(); } \
+  const pn_class_t *PREFIX  ##  __class(void) {                         \
+  static const pn_class_t clazz = {                                     \
+    #PREFIX,                                                            \
+    CID,                                                                \
+    NULL, /*_new*/                                                      \
+    NULL, /*_initialize*/                                               \
+    pn_void_incref,                                                     \
+    pn_void_decref,                                                     \
+    pn_void_refcount,                                                   \
+    NULL, /* _finalize */                                               \
+    NULL, /* _free */                                                   \
+    PREFIX ## _reify,                                                   \
+    pn_void_hashcode,                                                   \
+    pn_void_compare,                                                    \
+    pn_void_inspect                                                     \
+    };                                                                  \
+  return &clazz;                                                        \
+  }
+
 PN_EXTERN pn_cid_t pn_class_id(const pn_class_t *clazz);
 PN_EXTERN const char *pn_class_name(const pn_class_t *clazz);
 PN_EXTERN void *pn_class_new(const pn_class_t *clazz, size_t size);
@@ -181,6 +204,10 @@ PN_EXTERN intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b);
 PN_EXTERN bool pn_class_equals(const pn_class_t *clazz, void *a, void *b);
 PN_EXTERN int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst);
 
+PN_EXTERN void *pn_void_new(const pn_class_t *clazz, size_t size);
+PN_EXTERN void pn_void_incref(void *object);
+PN_EXTERN void pn_void_decref(void *object);
+PN_EXTERN int pn_void_refcount(void *object);
 PN_EXTERN uintptr_t pn_void_hashcode(void *object);
 PN_EXTERN intptr_t pn_void_compare(void *a, void *b);
 PN_EXTERN int pn_void_inspect(void *object, pn_string_t *dst);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h b/proton-c/include/proton/proactor.h
new file mode 100644
index 0000000..49d7b6a
--- /dev/null
+++ b/proton-c/include/proton/proactor.h
@@ -0,0 +1,174 @@
+#ifndef PROTON_PROACTOR_H
+#define PROTON_PROACTOR_H
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <proton/types.h>
+#include <proton/import_export.h>
+#include <proton/listener.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pn_condition_t pn_condition_t;
+
+/**
+ * @file
+ *
+ * **Experimental**: Proactor API for the the proton @ref engine.
+ *
+ * @defgroup proactor Proactor
+ *
+ * **Experimental**: Proactor API for portable, multi-threaded, asynchronous applications.
+ *
+ * The proactor establishes and listens for connections. It creates the @ref
+ * "transport" transport that sends and receives data over the network and
+ * delivers @ref "events" event to application threads for processing.
+ *
+ * ## Multi-threading
+ *
+ * The @ref proactor is thread-safe, but the @ref "protocol engine" is not.  The
+ * proactor ensures that each @ref "connection" connection and its associated
+ * values (@ref session, @ref link etc.) is processed sequentially, even if there
+ * are multiple application threads. See pn_proactor_wait()
+ *
+ * @{
+ */
+
+/**
+ * The proactor creates and manage @ref "transports" transport and delivers @ref
+ * "event" events to the application.
+ *
+ */
+typedef struct pn_proactor_t pn_proactor_t;
+
+/**
+ * Create a proactor. Must be freed with pn_proactor_free()
+ */
+pn_proactor_t *pn_proactor(void);
+
+/**
+ * Free the proactor.
+ */
+void pn_proactor_free(pn_proactor_t*);
+
+/* FIXME aconway 2016-11-12: connect and listen need options to enable
+   things like websockets, alternate encryption or other features.
+   The "extra" parameter will be replaced by an "options" parameter
+   that will include providing extra data and other manipulators
+   to affect how the connection is processed.
+*/
+
+/**
+ * Asynchronous connect: a connection and transport will be created, the
+ * relevant events will be returned by pn_proactor_wait()
+ *
+ * Errors are indicated by PN_TRANSPORT_ERROR/PN_TRANSPORT_CLOSE events.
+ *
+ * @param extra bytes to copy to pn_connection_get_extra() on the new connection, @ref
+ * pn_rwbytes_null for nothing.
+ *
+ * @return error if the connect cannot be initiated e.g. an allocation failure.
+ * IO errors will be returned as transport events via pn_proactor_wait()
+ */
+int pn_proactor_connect(pn_proactor_t*, const char *host, const char *port, pn_bytes_t extra);
+
+/**
+ * Asynchronous listen: start listening, connections will be returned by pn_proactor_wait()
+ * An error are indicated by PN_LISTENER_ERROR event.
+ *
+ * @param extra bytes to copy to pn_connection_get_extra() on the new connection, @ref
+ * pn_rwbytes_null for nothing.
+ *
+ * @return error if the connect cannot be initiated e.g. an allocation failure.
+ * IO errors will be returned as transport events via pn_proactor_wait()
+ */
+pn_listener_t *pn_proactor_listen(pn_proactor_t *, const char *host, const char *port, int backlog, pn_bytes_t extra);
+
+/**
+ * Wait for an event. Can be called in multiple threads concurrently.
+ * You must call pn_event_done() when the event has been handled.
+ *
+ * The proactor ensures that events that cannot be handled concurrently
+ * (e.g. events for for the same connection) are never returned concurrently.
+ */
+pn_event_t *pn_proactor_wait(pn_proactor_t* d);
+
+/**
+ * Cause PN_PROACTOR_INTERRUPT to be returned to exactly one thread calling wait()
+ * for each call to pn_proactor_interrupt(). Thread safe.
+ */
+void pn_proactor_interrupt(pn_proactor_t* d);
+
+/**
+ * Cause PN_PROACTOR_TIMEOUT to be returned to a thread calling wait() after
+ * timeout milliseconds. Thread safe.
+ *
+ * Note calling pn_proactor_set_timeout() again before the PN_PROACTOR_TIMEOUT is
+ * delivered will cancel the previous timeout and deliver an event only after
+ * the new timeout.
+ */
+void pn_proactor_set_timeout(pn_proactor_t* d, pn_millis_t timeout);
+
+/**
+ * Cause a PN_CONNECTION_WAKE event to be returned by the proactor, even if
+ * there are no IO events pending for the connection.
+ *
+ * Thread safe: this is the only pn_connection_ function that can be
+ * called concurrently.
+ *
+ * Wakes can be "coalesced" - if several pn_connection_wake() calls happen
+ * concurrently, there may be only one PN_CONNECTION_WAKE event.
+ */
+void pn_connection_wake(pn_connection_t *c);
+
+/**
+ * The proactor that created the connection.
+ */
+pn_proactor_t *pn_connection_proactor(pn_connection_t *c);
+
+/**
+ * Call when a proactor event has been handled. Does nothing if not a proactor event.
+ *
+ * Thread safe: May be called from any thread but must be called exactly once
+ * for each event returned by pn_proactor_wait()
+ */
+void pn_event_done(pn_event_t *);
+
+/**
+ * Get the proactor that created the event or NULL.
+ */
+pn_proactor_t *pn_event_proactor(pn_event_t *);
+
+/**
+ * Get the listener for the event or NULL.
+ */
+pn_listener_t *pn_event_listener(pn_event_t *);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PROTON_PROACTOR_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/include/proton/types.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/types.h b/proton-c/include/proton/types.h
index 176af47..378719c 100644
--- a/proton-c/include/proton/types.h
+++ b/proton-c/include/proton/types.h
@@ -67,6 +67,7 @@ typedef struct pn_bytes_t {
 } pn_bytes_t;
 
 PN_EXTERN pn_bytes_t pn_bytes(size_t size, const char *start);
+static const pn_bytes_t pn_bytes_null = { 0, NULL };
 
 /** A non-const byte buffer. */
 typedef struct pn_rwbytes_t {
@@ -75,6 +76,7 @@ typedef struct pn_rwbytes_t {
 } pn_rwbytes_t;
 
 PN_EXTERN pn_rwbytes_t pn_rwbytes(size_t size, char *start);
+static const pn_bytes_t pn_rwbytes_null = { 0, NULL };
 
 /** @}
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/src/core/connection_driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_driver.c b/proton-c/src/core/connection_driver.c
new file mode 100644
index 0000000..f31ddb0
--- /dev/null
+++ b/proton-c/src/core/connection_driver.c
@@ -0,0 +1,163 @@
+/*
+ * 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/condition.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* ce, pn_connection_t *c, pn_transport_t *t) {
+  ce->connection = c ? c : pn_connection();
+  ce->transport = t ? t : pn_transport();
+  ce->collector = pn_collector();
+  if (!ce->connection || !ce->transport || !ce->collector) {
+    pn_connection_engine_destroy(ce);
+    return PN_OUT_OF_MEMORY;
+  }
+  pn_connection_collect(ce->connection, ce->collector);
+  return 0;
+}
+
+int pn_connection_engine_bind(pn_connection_engine_t *ce) {
+  return pn_transport_bind(ce->transport, ce->connection);
+}
+
+void pn_connection_engine_destroy(pn_connection_engine_t *ce) {
+  if (ce->transport) {
+    pn_transport_unbind(ce->transport);
+    pn_transport_free(ce->transport);
+  }
+  if (ce->collector) pn_collector_free(ce->collector);
+  if (ce->connection) pn_connection_free(ce->connection);
+  memset(ce, 0, sizeof(*ce));
+}
+
+pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t *ce) {
+  ssize_t cap = pn_transport_capacity(ce->transport);
+  return (cap > 0) ?  pn_rwbytes(cap, pn_transport_tail(ce->transport)) : pn_rwbytes(0, 0);
+}
+
+void pn_connection_engine_read_done(pn_connection_engine_t *ce, size_t n) {
+  if (n > 0) pn_transport_process(ce->transport, n);
+}
+
+bool pn_connection_engine_read_closed(pn_connection_engine_t *ce) {
+  return pn_transport_capacity(ce->transport) < 0;
+}
+
+void pn_connection_engine_read_close(pn_connection_engine_t *ce) {
+  if (!pn_connection_engine_read_closed(ce)) {
+    pn_transport_close_tail(ce->transport);
+  }
+}
+
+pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t *ce) {
+  ssize_t pending = pn_transport_pending(ce->transport);
+  return (pending > 0) ?
+    pn_bytes(pending, pn_transport_head(ce->transport)) : pn_bytes_null;
+}
+
+void pn_connection_engine_write_done(pn_connection_engine_t *ce, size_t n) {
+  if (n > 0)
+    pn_transport_pop(ce->transport, n);
+}
+
+bool pn_connection_engine_write_closed(pn_connection_engine_t *ce) {
+  return pn_transport_pending(ce->transport) < 0;
+}
+
+void pn_connection_engine_write_close(pn_connection_engine_t *ce) {
+  if (!pn_connection_engine_write_closed(ce)) {
+    pn_transport_close_head(ce->transport);
+  }
+}
+
+void pn_connection_engine_close(pn_connection_engine_t *ce) {
+  pn_connection_engine_read_close(ce);
+  pn_connection_engine_write_close(ce);
+}
+
+pn_event_t* pn_connection_engine_event(pn_connection_engine_t *ce) {
+  pn_event_t *e = ce->collector ? pn_collector_peek(ce->collector) : NULL;
+  if (e) {
+    pn_transport_t *t = ce->transport;
+    if (t && t->trace & PN_TRACE_EVT) {
+      /* This can log the same event twice if pn_connection_engine_event is called
+       * twice but for debugging it is much better to log before handling than after.
+       */
+      pn_string_clear(t->scratch);
+      pn_inspect(e, t->scratch);
+      pn_transport_log(t, pn_string_get(t->scratch));
+    }
+  }
+  return e;
+}
+
+bool pn_connection_engine_has_event(pn_connection_engine_t *ce) {
+  return ce->collector && pn_collector_peek(ce->collector);
+}
+
+void pn_connection_engine_pop_event(pn_connection_engine_t *ce) {
+  if (ce->collector) {
+    pn_event_t *e = pn_collector_peek(ce->collector);
+    if (pn_event_type(e) == PN_TRANSPORT_CLOSED) { /* The last event ever */
+      /* Events can accumulate behind the TRANSPORT_CLOSED before the
+       * PN_TRANSPORT_CLOSED event is handled. They can never be processed
+       * so release them.
+       */
+      pn_collector_release(ce->collector);
+    } else {
+      pn_collector_pop(ce->collector);
+    }
+
+  }
+}
+
+bool pn_connection_engine_finished(pn_connection_engine_t *ce) {
+  return pn_transport_closed(ce->transport) && !pn_connection_engine_has_event(ce);
+}
+
+void pn_connection_engine_verrorf(pn_connection_engine_t *ce, const char *name, const char *fmt, va_list ap) {
+  pn_transport_t *t = ce->transport;
+  pn_condition_t *cond = pn_transport_condition(t);
+  pn_string_vformat(t->scratch, fmt, ap);
+  pn_condition_set_name(cond, name);
+  pn_condition_set_description(cond, pn_string_get(t->scratch));
+}
+
+void pn_connection_engine_errorf(pn_connection_engine_t *ce, const char *name, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  pn_connection_engine_verrorf(ce, name, fmt, ap);
+  va_end(ap);
+}
+
+void pn_connection_engine_log(pn_connection_engine_t *ce, const char *msg) {
+  pn_transport_log(ce->transport, msg);
+}
+
+void pn_connection_engine_vlogf(pn_connection_engine_t *ce, const char *fmt, va_list ap) {
+  pn_transport_vlogf(ce->transport, fmt, ap);
+}
+
+void pn_connection_engine_vlog(pn_connection_engine_t *ce, const char *msg) {
+  pn_transport_log(ce->transport, msg);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/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
index 5d184a1..f31ddb0 100644
--- a/proton-c/src/core/connection_engine.c
+++ b/proton-c/src/core/connection_engine.c
@@ -16,109 +16,148 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-#include "engine-internal.h"
 
+#include "engine-internal.h"
+#include <proton/condition.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;
+int pn_connection_engine_init(pn_connection_engine_t* ce, pn_connection_t *c, pn_transport_t *t) {
+  ce->connection = c ? c : pn_connection();
+  ce->transport = t ? t : pn_transport();
+  ce->collector = pn_collector();
+  if (!ce->connection || !ce->transport || !ce->collector) {
+    pn_connection_engine_destroy(ce);
+    return PN_OUT_OF_MEMORY;
+  }
+  pn_connection_collect(ce->connection, ce->collector);
+  return 0;
 }
 
-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));
+int pn_connection_engine_bind(pn_connection_engine_t *ce) {
+  return pn_transport_bind(ce->transport, ce->connection);
 }
 
-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_destroy(pn_connection_engine_t *ce) {
+  if (ce->transport) {
+    pn_transport_unbind(ce->transport);
+    pn_transport_free(ce->transport);
+  }
+  if (ce->collector) pn_collector_free(ce->collector);
+  if (ce->connection) pn_connection_free(ce->connection);
+  memset(ce, 0, sizeof(*ce));
 }
 
-void pn_connection_engine_read_done(pn_connection_engine_t* e, size_t n) {
-    if (n > 0)
-        pn_transport_process(e->transport, n);
+pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t *ce) {
+  ssize_t cap = pn_transport_capacity(ce->transport);
+  return (cap > 0) ?  pn_rwbytes(cap, pn_transport_tail(ce->transport)) : pn_rwbytes(0, 0);
 }
 
-void pn_connection_engine_read_close(pn_connection_engine_t* e) {
-    pn_transport_close_tail(e->transport);
+void pn_connection_engine_read_done(pn_connection_engine_t *ce, size_t n) {
+  if (n > 0) pn_transport_process(ce->transport, n);
 }
 
-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);
+bool pn_connection_engine_read_closed(pn_connection_engine_t *ce) {
+  return pn_transport_capacity(ce->transport) < 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_read_close(pn_connection_engine_t *ce) {
+  if (!pn_connection_engine_read_closed(ce)) {
+    pn_transport_close_tail(ce->transport);
+  }
 }
 
-void pn_connection_engine_write_close(pn_connection_engine_t* e){
-    pn_transport_close_head(e->transport);
+pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t *ce) {
+  ssize_t pending = pn_transport_pending(ce->transport);
+  return (pending > 0) ?
+    pn_bytes(pending, pn_transport_head(ce->transport)) : pn_bytes_null;
 }
 
-void pn_connection_engine_disconnected(pn_connection_engine_t* e) {
-    pn_connection_engine_read_close(e);
-    pn_connection_engine_write_close(e);
+void pn_connection_engine_write_done(pn_connection_engine_t *ce, size_t n) {
+  if (n > 0)
+    pn_transport_pop(ce->transport, n);
 }
 
-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);
+bool pn_connection_engine_write_closed(pn_connection_engine_t *ce) {
+  return pn_transport_pending(ce->transport) < 0;
+}
+
+void pn_connection_engine_write_close(pn_connection_engine_t *ce) {
+  if (!pn_connection_engine_write_closed(ce)) {
+    pn_transport_close_head(ce->transport);
+  }
+}
+
+void pn_connection_engine_close(pn_connection_engine_t *ce) {
+  pn_connection_engine_read_close(ce);
+  pn_connection_engine_write_close(ce);
+}
+
+pn_event_t* pn_connection_engine_event(pn_connection_engine_t *ce) {
+  pn_event_t *e = ce->collector ? pn_collector_peek(ce->collector) : NULL;
+  if (e) {
+    pn_transport_t *t = ce->transport;
+    if (t && t->trace & PN_TRACE_EVT) {
+      /* This can log the same event twice if pn_connection_engine_event is called
+       * twice but for debugging it is much better to log before handling than after.
+       */
+      pn_string_clear(t->scratch);
+      pn_inspect(e, t->scratch);
+      pn_transport_log(t, pn_string_get(t->scratch));
     }
+  }
+  return e;
+}
+
+bool pn_connection_engine_has_event(pn_connection_engine_t *ce) {
+  return ce->collector && pn_collector_peek(ce->collector);
 }
 
-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);
+void pn_connection_engine_pop_event(pn_connection_engine_t *ce) {
+  if (ce->collector) {
+    pn_event_t *e = pn_collector_peek(ce->collector);
+    if (pn_event_type(e) == PN_TRANSPORT_CLOSED) { /* The last event ever */
+      /* Events can accumulate behind the TRANSPORT_CLOSED before the
+       * PN_TRANSPORT_CLOSED event is handled. They can never be processed
+       * so release them.
+       */
+      pn_collector_release(ce->collector);
+    } else {
+      pn_collector_pop(ce->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 *ce) {
+  return pn_transport_closed(ce->transport) && !pn_connection_engine_has_event(ce);
+}
+
+void pn_connection_engine_verrorf(pn_connection_engine_t *ce, const char *name, const char *fmt, va_list ap) {
+  pn_transport_t *t = ce->transport;
+  pn_condition_t *cond = pn_transport_condition(t);
+  pn_string_vformat(t->scratch, fmt, ap);
+  pn_condition_set_name(cond, name);
+  pn_condition_set_description(cond, pn_string_get(t->scratch));
 }
 
-bool pn_connection_engine_finished(pn_connection_engine_t* e) {
-    return pn_transport_closed(e->transport) && (pn_collector_peek(e->collector) == NULL);
+void pn_connection_engine_errorf(pn_connection_engine_t *ce, const char *name, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  pn_connection_engine_verrorf(ce, name, fmt, ap);
+  va_end(ap);
 }
 
-pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t* e) {
-    return e->connection;
+void pn_connection_engine_log(pn_connection_engine_t *ce, const char *msg) {
+  pn_transport_log(ce->transport, msg);
 }
 
-pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t* e) {
-    return e->transport;
+void pn_connection_engine_vlogf(pn_connection_engine_t *ce, const char *fmt, va_list ap) {
+  pn_transport_vlogf(ce->transport, fmt, ap);
 }
 
-pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t* e) {
-    return pn_transport_condition(e->transport);
+void pn_connection_engine_vlog(pn_connection_engine_t *ce, const char *msg) {
+  pn_transport_log(ce->transport, msg);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/src/core/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine.c b/proton-c/src/core/engine.c
index e238d5c..2836a43 100644
--- a/proton-c/src/core/engine.c
+++ b/proton-c/src/core/engine.c
@@ -32,6 +32,8 @@
 #include "platform/platform_fmt.h"
 #include "transport.h"
 
+#include <proton/extra.h>
+
 
 static void pni_session_bound(pn_session_t *ssn);
 static void pni_link_bound(pn_link_t *link);
@@ -208,6 +210,12 @@ void pn_condition_init(pn_condition_t *condition)
   condition->info = pn_data(0);
 }
 
+pn_condition_t *pn_condition() {
+  pn_condition_t *c = (pn_condition_t*)malloc(sizeof(pn_condition_t));
+  pn_condition_init(c);
+  return c;
+}
+
 void pn_condition_tini(pn_condition_t *condition)
 {
   pn_data_free(condition->info);
@@ -215,6 +223,14 @@ void pn_condition_tini(pn_condition_t *condition)
   pn_free(condition->name);
 }
 
+void pn_condition_free(pn_condition_t *c) {
+  if (c) {
+    pn_condition_clear(c);
+    pn_condition_tini(c);
+    free(c);
+  }
+}
+
 static void pni_add_session(pn_connection_t *conn, pn_session_t *ssn)
 {
   pn_list_add(conn->sessions, ssn);
@@ -495,10 +511,15 @@ static void pn_connection_finalize(void *object)
 #define pn_connection_compare NULL
 #define pn_connection_inspect NULL
 
-pn_connection_t *pn_connection(void)
+PN_EXTRA_DECLARE(pn_connection_t);
+
+pn_rwbytes_t pn_connection_get_extra(pn_connection_t *c) { return PN_EXTRA_GET(pn_connection_t, c); }
+
+pn_connection_t *pn_connection_with_extra(size_t extra)
 {
   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));
+  size_t size = PN_EXTRA_SIZEOF(pn_connection_t, extra);
+  pn_connection_t *conn = (pn_connection_t *) pn_class_new(&clazz, size);
   if (!conn) return NULL;
 
   conn->endpoint_head = NULL;
@@ -527,6 +548,10 @@ pn_connection_t *pn_connection(void)
   return conn;
 }
 
+pn_connection_t *pn_connection(void) {
+  return pn_connection_with_extra(0);
+}
+
 static const pn_event_type_t endpoint_init_event_map[] = {
   PN_CONNECTION_INIT,  /* CONNECTION */
   PN_SESSION_INIT,     /* SESSION */
@@ -545,6 +570,10 @@ void pn_connection_collect(pn_connection_t *connection, pn_collector_t *collecto
   }
 }
 
+pn_collector_t* pn_connection_collector(pn_connection_t *connection) {
+  return connection->collector;
+}
+
 pn_state_t pn_connection_state(pn_connection_t *connection)
 {
   return connection ? connection->endpoint.state : 0;
@@ -2229,3 +2258,15 @@ pn_transport_t *pn_event_transport(pn_event_t *event)
     }
   }
 }
+
+int pn_condition_copy(pn_condition_t *dest, pn_condition_t *src) {
+  assert(dest);
+  assert(src);
+  int err = 0;
+  if (src != dest) {
+    int err = pn_string_copy(dest->name, src->name);
+    if (!err) err = pn_string_copy(dest->description, src->description);
+    if (!err) err = pn_data_copy(dest->info, src->info);
+  }
+  return err;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/proton-c/src/core/event.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/event.c b/proton-c/src/core/event.c
index c13f287..7882327 100644
--- a/proton-c/src/core/event.c
+++ b/proton-c/src/core/event.c
@@ -371,7 +371,18 @@ const char *pn_event_type_name(pn_event_type_t type)
     return "PN_SELECTABLE_EXPIRED";
   case PN_SELECTABLE_FINAL:
     return "PN_SELECTABLE_FINAL";
+   case PN_CONNECTION_WAKE:
+    return "PN_CONNECTION_WAKE";
+   case PN_LISTENER_CLOSE:
+    return "PN_LISTENER_CLOSE";
+   case PN_PROACTOR_INTERRUPT:
+    return "PN_PROACTOR_INTERRUPT";
+   case PN_PROACTOR_TIMEOUT:
+    return "PN_PROACTOR_TIMEOUT";
+   case PN_PROACTOR_INACTIVE:
+    return "PN_PROACTOR_INACTIVE";
+   default:
+    return "PN_UNKNOWN";
   }
-
   return NULL;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca454180/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
index b0c1b33..a6952b6 100644
--- a/proton-c/src/core/object/object.c
+++ b/proton-c/src/core/object/object.c
@@ -32,10 +32,10 @@ intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t)
 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; }
+void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
+void pn_void_incref(void* p) {}
+void pn_void_decref(void* p) {}
+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; }
@@ -199,7 +199,7 @@ typedef struct {
 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);
+  pni_head_t *head = (pni_head_t *) calloc(1, sizeof(pni_head_t) + size);
   if (head != NULL) {
     object = head + 1;
     head->clazz = clazz;


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


[19/48] 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 ac...@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


[27/48] qpid-proton git commit: NO-JIRA: cpp example broker, set source address

Posted by ac...@apache.org.
NO-JIRA: cpp example broker, set source address


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

Branch: refs/heads/go1
Commit: cdc1baa2ecfe5c38ffd6859c97428debc0282002
Parents: b1a2925
Author: Alan Conway <ac...@redhat.com>
Authored: Sat Nov 12 00:51:46 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Nov 16 19:48:31 2016 -0500

----------------------------------------------------------------------
 examples/cpp/mt/broker.cpp | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/cdc1baa2/examples/cpp/mt/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/mt/broker.cpp b/examples/cpp/mt/broker.cpp
index 39d7132..7ef90c3 100644
--- a/examples/cpp/mt/broker.cpp
+++ b/examples/cpp/mt/broker.cpp
@@ -26,6 +26,8 @@
 #include <proton/error_condition.hpp>
 #include <proton/listen_handler.hpp>
 #include <proton/messaging_handler.hpp>
+#include <proton/sender_options.hpp>
+#include <proton/source_options.hpp>
 #include <proton/thread_safe.hpp>
 
 #include <atomic>
@@ -151,6 +153,7 @@ class broker_connection_handler : public proton::messaging_handler {
     void on_sender_open(proton::sender &sender) OVERRIDE {
         queue *q = sender.source().dynamic() ?
             queues_.dynamic() : queues_.get(sender.source().address());
+        sender.open(proton::sender_options().source((proton::source_options().address(q->name()))));
         std::cout << "sending from " << q->name() << std::endl;
     }
 


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


[10/48] 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 ac...@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