http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/reactor/selectable.c
----------------------------------------------------------------------
diff --git a/c/src/reactor/selectable.c b/c/src/reactor/selectable.c
new file mode 100644
index 0000000..b42ad1f
--- /dev/null
+++ b/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);
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/reactor/selectable.h
----------------------------------------------------------------------
diff --git a/c/src/reactor/selectable.h b/c/src/reactor/selectable.h
new file mode 100644
index 0000000..7a5b80b
--- /dev/null
+++ b/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/37136940/c/src/reactor/selector.h
----------------------------------------------------------------------
diff --git a/c/src/reactor/selector.h b/c/src/reactor/selector.h
new file mode 100644
index 0000000..2a1e31f
--- /dev/null
+++ b/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/37136940/c/src/reactor/timer.c
----------------------------------------------------------------------
diff --git a/c/src/reactor/timer.c b/c/src/reactor/timer.c
new file mode 100644
index 0000000..bfd768e
--- /dev/null
+++ b/c/src/reactor/timer.c
@@ -0,0 +1,168 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/reactor.h>
+#include <assert.h>
+
+struct pn_task_t {
+  pn_list_t *pool;
+  pn_record_t *attachments;
+  pn_timestamp_t deadline;
+  bool cancelled;
+};
+
+void pn_task_initialize(pn_task_t *task) {
+  task->pool = NULL;
+  task->attachments = pn_record();
+  task->deadline = 0;
+  task->cancelled = false;
+}
+
+void pn_task_finalize(pn_task_t *task) {
+  // if we are the last reference to the pool then don't put ourselves
+  // into it
+  if (task->pool && pn_refcount(task->pool) > 1) {
+    pn_record_clear(task->attachments);
+    pn_list_add(task->pool, task);
+    pn_decref(task->pool);
+    task->pool = NULL;
+  } else {
+    pn_decref(task->pool);
+    pn_decref(task->attachments);
+  }
+}
+
+intptr_t pn_task_compare(pn_task_t *a, pn_task_t *b) {
+  return a->deadline - b->deadline;
+}
+
+#define pn_task_inspect NULL
+#define pn_task_hashcode NULL
+
+PN_CLASSDEF(pn_task)
+
+pn_task_t *pn_task(void) {
+  pn_task_t *task = pn_task_new();
+  return task;
+}
+
+pn_record_t *pn_task_attachments(pn_task_t *task) {
+  assert(task);
+  return task->attachments;
+}
+
+void pn_task_cancel(pn_task_t *task) {
+    assert(task);
+    task->cancelled = true;
+}
+
+//
+// timer
+//
+
+struct pn_timer_t {
+  pn_list_t *pool;
+  pn_list_t *tasks;
+  pn_collector_t *collector;
+};
+
+static void pn_timer_initialize(pn_timer_t *timer) {
+  timer->pool = pn_list(PN_OBJECT, 0);
+  timer->tasks = pn_list(PN_OBJECT, 0);
+}
+
+static void pn_timer_finalize(pn_timer_t *timer) {
+  pn_decref(timer->pool);
+  pn_free(timer->tasks);
+}
+
+#define pn_timer_inspect NULL
+#define pn_timer_compare NULL
+#define pn_timer_hashcode NULL
+
+PN_CLASSDEF(pn_timer)
+
+pn_timer_t *pn_timer(pn_collector_t *collector) {
+  pn_timer_t *timer = pn_timer_new();
+  timer->collector = collector;
+  return timer;
+}
+
+pn_task_t *pn_timer_schedule(pn_timer_t *timer,  pn_timestamp_t deadline) {
+  pn_task_t *task = (pn_task_t *) pn_list_pop(timer->pool);
+  if (!task) {
+    task = pn_task();
+  }
+  task->pool = timer->pool;
+  pn_incref(task->pool);
+  task->deadline = deadline;
+  task->cancelled = false;
+  pn_list_minpush(timer->tasks, task);
+  pn_decref(task);
+  return task;
+}
+
+void pni_timer_flush_cancelled(pn_timer_t *timer) {
+    while (pn_list_size(timer->tasks)) {
+        pn_task_t *task = (pn_task_t *) pn_list_get(timer->tasks, 0);
+        if (task->cancelled) {
+            pn_task_t *min = (pn_task_t *) pn_list_minpop(timer->tasks);
+            assert(min == task);
+            pn_decref(min);
+        } else {
+            break;
+        }
+    }
+}
+
+pn_timestamp_t pn_timer_deadline(pn_timer_t *timer) {
+  assert(timer);
+  pni_timer_flush_cancelled(timer);
+  if (pn_list_size(timer->tasks)) {
+    pn_task_t *task = (pn_task_t *) pn_list_get(timer->tasks, 0);
+    return task->deadline;
+  } else {
+    return 0;
+  }
+}
+
+void pn_timer_tick(pn_timer_t *timer, pn_timestamp_t now) {
+  assert(timer);
+  while (pn_list_size(timer->tasks)) {
+    pn_task_t *task = (pn_task_t *) pn_list_get(timer->tasks, 0);
+    if (now >= task->deadline) {
+      pn_task_t *min = (pn_task_t *) pn_list_minpop(timer->tasks);
+      assert(min == task);
+      if (!min->cancelled)
+          pn_collector_put(timer->collector, PN_OBJECT, min, PN_TIMER_TASK);
+      pn_decref(min);
+    } else {
+      break;
+    }
+  }
+}
+
+int pn_timer_tasks(pn_timer_t *timer) {
+  assert(timer);
+  pni_timer_flush_cancelled(timer);
+  return pn_list_size(timer->tasks);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/sasl/cyrus_sasl.c
----------------------------------------------------------------------
diff --git a/c/src/sasl/cyrus_sasl.c b/c/src/sasl/cyrus_sasl.c
new file mode 100644
index 0000000..c589fab
--- /dev/null
+++ b/c/src/sasl/cyrus_sasl.c
@@ -0,0 +1,605 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "proton/sasl.h"
+#include "proton/sasl-plugin.h"
+#include "proton/transport.h"
+
+#include <sasl/sasl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#ifndef CYRUS_SASL_MAX_BUFFSIZE
+# define CYRUS_SASL_MAX_BUFFSIZE (32768) /* bytes */
+#endif
+
+// SASL implementation entry points
+static void cyrus_sasl_prepare(pn_transport_t *transport);
+static void cyrus_sasl_free(pn_transport_t *transport);
+static const char *cyrus_sasl_list_mechs(pn_transport_t *transport);
+
+static bool cyrus_sasl_init_server(pn_transport_t *transport);
+static void cyrus_sasl_process_init(pn_transport_t *transport, const char 
*mechanism, const pn_bytes_t *recv);
+static void cyrus_sasl_process_response(pn_transport_t *transport, const 
pn_bytes_t *recv);
+
+static bool cyrus_sasl_init_client(pn_transport_t *transport);
+static bool cyrus_sasl_process_mechanisms(pn_transport_t *transport, const 
char *mechs);
+static void cyrus_sasl_process_challenge(pn_transport_t *transport, const 
pn_bytes_t *recv);
+static void cyrus_sasl_process_outcome(pn_transport_t *transport);
+
+static bool cyrus_sasl_can_encrypt(pn_transport_t *transport);
+static ssize_t cyrus_sasl_max_encrypt_size(pn_transport_t *transport);
+static ssize_t cyrus_sasl_encode(pn_transport_t *transport, pn_bytes_t in, 
pn_bytes_t *out);
+static ssize_t cyrus_sasl_decode(pn_transport_t *transport, pn_bytes_t in, 
pn_bytes_t *out);
+
+static const pnx_sasl_implementation sasl_impl = {
+    cyrus_sasl_free,
+
+    cyrus_sasl_list_mechs,
+
+    cyrus_sasl_init_server,
+    cyrus_sasl_init_client,
+
+    cyrus_sasl_prepare,
+
+    cyrus_sasl_process_init,
+    cyrus_sasl_process_response,
+
+    cyrus_sasl_process_mechanisms,
+    cyrus_sasl_process_challenge,
+    cyrus_sasl_process_outcome,
+
+    cyrus_sasl_can_encrypt,
+    cyrus_sasl_max_encrypt_size,
+    cyrus_sasl_encode,
+    cyrus_sasl_decode
+};
+
+extern const pnx_sasl_implementation * const cyrus_sasl_impl;
+const pnx_sasl_implementation * const cyrus_sasl_impl = &sasl_impl;
+
+// If the version of Cyrus SASL is too early for 
sasl_client_done()/sasl_server_done()
+// don't do any global clean up as it's not safe to use just sasl_done() for an
+// executable that uses both client and server parts of Cyrus SASL, because it 
can't
+// be called twice.
+#if SASL_VERSION_FULL<0x020118
+# define sasl_client_done()
+# define sasl_server_done()
+#endif
+
+static const char *amqp_service = "amqp";
+
+static inline bool pni_check_result(sasl_conn_t *conn, int r, pn_transport_t 
*logger, const char* condition_name)
+{
+    if (r==SASL_OK) return true;
+
+    const char* err = conn ? sasl_errdetail(conn) : sasl_errstring(r, NULL, 
NULL);
+    pnx_sasl_logf(logger, "sasl error: %s", err);
+    pn_condition_t* c = pn_transport_condition(logger);
+    pn_condition_set_name(c, condition_name);
+    pn_condition_set_description(c, err);
+    return false;
+}
+
+static bool pni_check_io_result(sasl_conn_t *conn, int r, pn_transport_t 
*logger)
+{
+    return pni_check_result(conn, r, logger, "proton:io:sasl_error");
+}
+
+static bool pni_check_sasl_result(sasl_conn_t *conn, int r, pn_transport_t 
*logger)
+{
+    return pni_check_result(conn, r, logger, "amqp:unauthorized-access");
+}
+
+// Cyrus wrappers
+static void pni_cyrus_interact(pn_transport_t *transport, sasl_interact_t 
*interact)
+{
+  for (sasl_interact_t *i = interact; i->id!=SASL_CB_LIST_END; i++) {
+    switch (i->id) {
+    case SASL_CB_USER:
+      i->result = 0;
+      i->len = 0;
+      break;
+    case SASL_CB_AUTHNAME: {
+      const char *username = pnx_sasl_get_username(transport);
+      i->result = username;
+      i->len = strlen(username);
+      break;
+    }
+    case SASL_CB_PASS: {
+      const char *password = pnx_sasl_get_password(transport);
+      i->result = password;
+      i->len = strlen(password);
+      break;
+    }
+    default:
+      fprintf(stderr, "(%s): %s - %s\n", i->challenge, i->prompt, 
i->defresult);
+    }
+  }
+}
+
+const char *cyrus_sasl_list_mechs(pn_transport_t *transport)
+{
+  sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+  if (!cyrus_conn) return NULL;
+
+  int count = 0;
+  const char *result = NULL;
+  int r = sasl_listmech(cyrus_conn, NULL, "", " ", "", &result, NULL, &count);
+  pni_check_sasl_result(cyrus_conn, r, transport);
+  return result;
+}
+
+// Set up callbacks to use interact
+static const sasl_callback_t pni_user_password_callbacks[] = {
+    {SASL_CB_USER, NULL, NULL},
+    {SASL_CB_AUTHNAME, NULL, NULL},
+    {SASL_CB_PASS, NULL, NULL},
+    {SASL_CB_LIST_END, NULL, NULL},
+};
+
+static const sasl_callback_t pni_user_callbacks[] = {
+    {SASL_CB_USER, NULL, NULL},
+    {SASL_CB_AUTHNAME, NULL, NULL},
+    {SASL_CB_LIST_END, NULL, NULL},
+};
+
+// Machinery to initialise the cyrus library only once even in a multithreaded 
environment
+// Relies on pthreads.
+static const char * const default_config_name = "proton-server";
+static char *pni_cyrus_config_dir = NULL;
+static char *pni_cyrus_config_name = NULL;
+static pthread_mutex_t pni_cyrus_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool pni_cyrus_client_started = false;
+static bool pni_cyrus_server_started = false;
+
+bool pn_sasl_extended(void)
+{
+  return true;
+}
+
+void pn_sasl_config_name(pn_sasl_t *sasl0, const char *name)
+{
+    if (!pni_cyrus_config_name) {
+      pni_cyrus_config_name = strdup(name);
+    }
+}
+
+void pn_sasl_config_path(pn_sasl_t *sasl0, const char *dir)
+{
+  if (!pni_cyrus_config_dir) {
+    pni_cyrus_config_dir = strdup(dir);
+  }
+}
+
+__attribute__((destructor))
+static void pni_cyrus_finish(void) {
+  pthread_mutex_lock(&pni_cyrus_mutex);
+  if (pni_cyrus_client_started) sasl_client_done();
+  if (pni_cyrus_server_started) sasl_server_done();
+  free(pni_cyrus_config_dir);
+  free(pni_cyrus_config_name);
+  pthread_mutex_unlock(&pni_cyrus_mutex);
+}
+
+static int pni_cyrus_client_init_rc = SASL_OK;
+static void pni_cyrus_client_once(void) {
+  pthread_mutex_lock(&pni_cyrus_mutex);
+  int result = SASL_OK;
+  if (pni_cyrus_config_dir) {
+    result = sasl_set_path(SASL_PATH_TYPE_CONFIG, pni_cyrus_config_dir);
+  } else {
+    char *config_dir = getenv("PN_SASL_CONFIG_PATH");
+    if (config_dir) {
+      result = sasl_set_path(SASL_PATH_TYPE_CONFIG, config_dir);
+    }
+  }
+  if (result==SASL_OK) {
+    result = sasl_client_init(NULL);
+  }
+  pni_cyrus_client_started = true;
+  pni_cyrus_client_init_rc = result;
+  pthread_mutex_unlock(&pni_cyrus_mutex);
+}
+
+static int pni_cyrus_server_init_rc = SASL_OK;
+static void pni_cyrus_server_once(void) {
+  pthread_mutex_lock(&pni_cyrus_mutex);
+  int result = SASL_OK;
+  if (pni_cyrus_config_dir) {
+    result = sasl_set_path(SASL_PATH_TYPE_CONFIG, pni_cyrus_config_dir);
+  } else {
+    char *config_dir = getenv("PN_SASL_CONFIG_PATH");
+    if (config_dir) {
+      result = sasl_set_path(SASL_PATH_TYPE_CONFIG, config_dir);
+    }
+  }
+  if (result==SASL_OK) {
+    result = sasl_server_init(NULL, pni_cyrus_config_name ? 
pni_cyrus_config_name : default_config_name);
+  }
+  pni_cyrus_server_started = true;
+  pni_cyrus_server_init_rc = result;
+  pthread_mutex_unlock(&pni_cyrus_mutex);
+}
+
+static pthread_once_t pni_cyrus_client_init = PTHREAD_ONCE_INIT;
+static void pni_cyrus_client_start(void) {
+  pthread_once(&pni_cyrus_client_init, pni_cyrus_client_once);
+}
+static pthread_once_t pni_cyrus_server_init = PTHREAD_ONCE_INIT;
+static void pni_cyrus_server_start(void) {
+  pthread_once(&pni_cyrus_server_init, pni_cyrus_server_once);
+}
+
+void cyrus_sasl_prepare(pn_transport_t* transport)
+{
+}
+
+bool cyrus_sasl_init_client(pn_transport_t* transport) {
+  int result;
+  sasl_conn_t *cyrus_conn = NULL;
+  do {
+    pni_cyrus_client_start();
+    result = pni_cyrus_client_init_rc;
+    if (result!=SASL_OK) break;
+
+    const sasl_callback_t *callbacks =
+      pnx_sasl_get_username(transport) ? pnx_sasl_get_password(transport) ? 
pni_user_password_callbacks : pni_user_callbacks : NULL;
+    result = sasl_client_new(amqp_service,
+                             pnx_sasl_get_remote_fqdn(transport),
+                             NULL, NULL,
+                             callbacks, 0,
+                             &cyrus_conn);
+    if (result!=SASL_OK) break;
+    pnx_sasl_set_context(transport, cyrus_conn);
+
+    sasl_security_properties_t secprops = {0};
+    secprops.security_flags =
+      ( pnx_sasl_get_allow_insecure_mechs(transport) ? 0 : 
SASL_SEC_NOPLAINTEXT ) |
+      ( pnx_sasl_get_auth_required(transport) ? SASL_SEC_NOANONYMOUS : 0 ) ;
+    secprops.min_ssf = 0;
+    secprops.max_ssf = 2048;
+    secprops.maxbufsize = CYRUS_SASL_MAX_BUFFSIZE;
+
+    result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops);
+    if (result!=SASL_OK) break;
+
+    sasl_ssf_t ssf = pnx_sasl_get_external_ssf(transport);
+    result = sasl_setprop(cyrus_conn, SASL_SSF_EXTERNAL, &ssf);
+    if (result!=SASL_OK) break;
+
+    const char *extid = pnx_sasl_get_external_username(transport);
+    if (extid) {
+      result = sasl_setprop(cyrus_conn, SASL_AUTH_EXTERNAL, extid);
+    }
+  } while (false);
+  cyrus_conn = (sasl_conn_t*) pnx_sasl_get_context(transport);
+  return pni_check_sasl_result(cyrus_conn, result, transport);
+}
+
+static int pni_wrap_client_start(pn_transport_t *transport, const char *mechs, 
const char **mechusing)
+{
+    int result;
+    sasl_interact_t *client_interact=NULL;
+    const char *out;
+    unsigned outlen;
+
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    do {
+
+        result = sasl_client_start(cyrus_conn,
+                                   mechs,
+                                   &client_interact,
+                                   &out, &outlen,
+                                   mechusing);
+        if (result==SASL_INTERACT) {
+            pni_cyrus_interact(transport, client_interact);
+        }
+    } while (result==SASL_INTERACT);
+
+    pnx_sasl_set_bytes_out(transport, pn_bytes(outlen, out));
+    return result;
+}
+
+bool cyrus_sasl_process_mechanisms(pn_transport_t *transport, const char 
*mechs)
+{
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    const char *mech_selected;
+    int result = pni_wrap_client_start(transport, mechs, &mech_selected);
+    switch (result) {
+        case SASL_OK:
+        case SASL_CONTINUE:
+          pnx_sasl_set_selected_mechanism(transport, mech_selected);
+          pnx_sasl_set_desired_state(transport, SASL_POSTED_INIT);
+          return true;
+        case SASL_NOMECH:
+        default:
+          pni_check_sasl_result(cyrus_conn, result, transport);
+          return false;
+    }
+}
+
+
+static int pni_wrap_client_step(pn_transport_t *transport, const pn_bytes_t 
*in)
+{
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    sasl_interact_t *client_interact=NULL;
+    const char *out;
+    unsigned outlen;
+
+    int result;
+    do {
+
+        result = sasl_client_step(cyrus_conn,
+                                  in->start, in->size,
+                                  &client_interact,
+                                  &out, &outlen);
+        if (result==SASL_INTERACT) {
+            pni_cyrus_interact(transport, client_interact);
+        }
+    } while (result==SASL_INTERACT);
+
+    pnx_sasl_set_bytes_out(transport, pn_bytes(outlen, out));
+    return result;
+}
+
+void cyrus_sasl_process_challenge(pn_transport_t *transport, const pn_bytes_t 
*recv)
+{
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    int result = pni_wrap_client_step(transport, recv);
+    switch (result) {
+        case SASL_OK:
+            // Authenticated
+            // TODO: Documented that we need to call sasl_client_step() again 
to be sure!;
+        case SASL_CONTINUE:
+            // Need to send a response
+            pnx_sasl_set_desired_state(transport, SASL_POSTED_RESPONSE);
+            break;
+        default:
+            pni_check_sasl_result(cyrus_conn, result, transport);
+
+            // Failed somehow - equivalent to failing authentication
+            pnx_sasl_fail_authentication(transport);
+            pnx_sasl_set_desired_state(transport, SASL_RECVED_OUTCOME_FAIL);
+            break;
+    }
+}
+
+void cyrus_sasl_process_outcome(pn_transport_t* transport)
+{
+}
+
+bool cyrus_sasl_init_server(pn_transport_t* transport)
+{
+  int result;
+  sasl_conn_t *cyrus_conn = NULL;
+  do {
+    pni_cyrus_server_start();
+    result = pni_cyrus_server_init_rc;
+    if (result!=SASL_OK) break;
+
+    result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, 
&cyrus_conn);
+    if (result!=SASL_OK) break;
+    pnx_sasl_set_context(transport, cyrus_conn);
+
+    sasl_security_properties_t secprops = {0};
+    secprops.security_flags =
+      ( pnx_sasl_get_allow_insecure_mechs(transport) ? 0 : 
SASL_SEC_NOPLAINTEXT ) |
+      ( pnx_sasl_get_auth_required(transport) ? SASL_SEC_NOANONYMOUS : 0 ) ;
+    secprops.min_ssf = 0;
+    secprops.max_ssf = 2048;
+    secprops.maxbufsize = CYRUS_SASL_MAX_BUFFSIZE;
+
+    result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops);
+    if (result!=SASL_OK) break;
+
+    sasl_ssf_t ssf = pnx_sasl_get_external_ssf(transport);
+    result = sasl_setprop(cyrus_conn, SASL_SSF_EXTERNAL, &ssf);
+    if (result!=SASL_OK) break;
+
+    const char *extid = pnx_sasl_get_external_username(transport);
+    if (extid) {
+    result = sasl_setprop(cyrus_conn, SASL_AUTH_EXTERNAL, extid);
+    }
+  } while (false);
+  cyrus_conn = (sasl_conn_t*) pnx_sasl_get_context(transport);
+  if (pni_check_sasl_result(cyrus_conn, result, transport)) {
+      // Setup to send SASL mechanisms frame
+      pnx_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
+      return true;
+  } else {
+      return false;
+  }
+}
+
+static int pni_wrap_server_start(pn_transport_t *transport, const char 
*mech_selected, const pn_bytes_t *in)
+{
+    int result;
+    const char *out;
+    unsigned outlen;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    const char *in_bytes = in->start;
+    size_t in_size = in->size;
+    // Interop hack for ANONYMOUS - some of the earlier versions of proton 
will send and no data
+    // with an anonymous init because it is optional. It seems that Cyrus 
wants an empty string here
+    // or it will challenge, which the earlier implementation is not prepared 
for.
+    // However we can't just always use an empty string as the CRAM-MD5 mech 
won't allow any data in the server start
+    if (!in_bytes && strcmp(mech_selected, "ANONYMOUS")==0) {
+        in_bytes = "";
+        in_size = 0;
+    } else if (in_bytes && strcmp(mech_selected, "CRAM-MD5")==0) {
+        in_bytes = 0;
+        in_size = 0;
+    }
+    result = sasl_server_start(cyrus_conn,
+                               mech_selected,
+                               in_bytes, in_size,
+                               &out, &outlen);
+
+    pnx_sasl_set_bytes_out(transport, pn_bytes(outlen, out));
+    return result;
+}
+
+static void pni_process_server_result(pn_transport_t *transport, int result)
+{
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    switch (result) {
+        case SASL_OK: {
+            // Authenticated
+            // Get username from SASL
+            const void* value;
+            sasl_getprop(cyrus_conn, SASL_USERNAME, &value);
+            pnx_sasl_succeed_authentication(transport, (const char*) value);
+            pnx_sasl_logf(transport, "Authenticated user: %s with mechanism 
%s",
+                          pnx_sasl_get_username(transport), 
pnx_sasl_get_selected_mechanism(transport));
+            pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+            break;
+        }
+        case SASL_CONTINUE:
+            // Need to send a challenge
+            pnx_sasl_set_desired_state(transport, SASL_POSTED_CHALLENGE);
+            break;
+        default:
+            pni_check_sasl_result(cyrus_conn, result, transport);
+
+            // Failed to authenticate
+            pnx_sasl_fail_authentication(transport);
+            pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+            break;
+    }
+}
+
+void cyrus_sasl_process_init(pn_transport_t *transport, const char *mechanism, 
const pn_bytes_t *recv)
+{
+    int result = pni_wrap_server_start(transport, mechanism, recv);
+    if (result==SASL_OK) {
+        // We need to filter out a supplied mech in in the inclusion list
+        // as the client could have used a mech that we support, but that
+        // wasn't on the list we sent.
+        if (!pnx_sasl_is_included_mech(transport, pn_bytes(strlen(mechanism), 
mechanism))) {
+            sasl_conn_t *cyrus_conn = 
(sasl_conn_t*)pnx_sasl_get_context(transport);
+            sasl_seterror(cyrus_conn, 0, "Client mechanism not in mechanism 
inclusion list.");
+            result = SASL_FAIL;
+        }
+    }
+    pni_process_server_result(transport, result);
+}
+
+static int pni_wrap_server_step(pn_transport_t *transport, const pn_bytes_t 
*in)
+{
+    int result;
+    const char *out;
+    unsigned outlen;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    result = sasl_server_step(cyrus_conn,
+                              in->start, in->size,
+                              &out, &outlen);
+
+    pnx_sasl_set_bytes_out(transport, pn_bytes(outlen, out));
+    return result;
+}
+
+void cyrus_sasl_process_response(pn_transport_t *transport, const pn_bytes_t 
*recv)
+{
+    int result = pni_wrap_server_step(transport, recv);
+    pni_process_server_result(transport, result);
+}
+
+bool cyrus_sasl_can_encrypt(pn_transport_t *transport)
+{
+  sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+  if (!cyrus_conn) return false;
+
+  // Get SSF to find out if we need to encrypt or not
+  const void* value;
+  int r = sasl_getprop(cyrus_conn, SASL_SSF, &value);
+  if (r != SASL_OK) {
+    // TODO: Should log an error here too, maybe assert here
+    return false;
+  }
+  int ssf = *(int *) value;
+  if (ssf > 0) {
+    return true;
+  }
+  return false;
+}
+
+ssize_t cyrus_sasl_max_encrypt_size(pn_transport_t *transport)
+{
+  sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+  if (!cyrus_conn) return PN_ERR;
+
+  const void* value;
+  int r = sasl_getprop(cyrus_conn, SASL_MAXOUTBUF, &value);
+  if (r != SASL_OK) {
+    // TODO: Should log an error here too, maybe assert here
+    return PN_ERR;
+  }
+  int outbuf_size = *(int *) value;
+  return outbuf_size -
+    // XXX: this  is a clientside workaround/hack to make GSSAPI work as the 
Cyrus SASL
+    // GSSAPI plugin seems to return an incorrect value for the buffer size on 
the client
+    // side, which is greater than the value returned on the server side. 
Actually using
+    // the entire client side buffer will cause a server side error due to a 
buffer overrun.
+    (pnx_sasl_is_client(transport)? 60 : 0);
+}
+
+ssize_t cyrus_sasl_encode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t 
*out)
+{
+  if ( in.size==0 ) return 0;
+  sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+  const char *output;
+  unsigned int outlen;
+  int r = sasl_encode(cyrus_conn, in.start, in.size, &output, &outlen);
+  if (outlen==0) return 0;
+  if ( pni_check_io_result(cyrus_conn, r, transport) ) {
+    *out = pn_bytes(outlen, output);
+    return outlen;
+  }
+  return PN_ERR;
+}
+
+ssize_t cyrus_sasl_decode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t 
*out)
+{
+  if ( in.size==0 ) return 0;
+  sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+  const char *output;
+  unsigned int outlen;
+  int r = sasl_decode(cyrus_conn, in.start, in.size, &output, &outlen);
+  if (outlen==0) return 0;
+  if ( pni_check_io_result(cyrus_conn, r, transport) ) {
+    *out = pn_bytes(outlen, output);
+    return outlen;
+  }
+  return PN_ERR;
+}
+
+void cyrus_sasl_free(pn_transport_t *transport)
+{
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)pnx_sasl_get_context(transport);
+    sasl_dispose(&cyrus_conn);
+    pnx_sasl_set_context(transport, cyrus_conn);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/sasl/cyrus_stub.c
----------------------------------------------------------------------
diff --git a/c/src/sasl/cyrus_stub.c b/c/src/sasl/cyrus_stub.c
new file mode 100644
index 0000000..983ace8
--- /dev/null
+++ b/c/src/sasl/cyrus_stub.c
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/sasl.h"
+#include "proton/sasl-plugin.h"
+
+extern const pnx_sasl_implementation * const cyrus_sasl_impl;
+const pnx_sasl_implementation * const cyrus_sasl_impl = NULL;
+
+bool pn_sasl_extended(void)
+{
+  return false;
+}
+
+void pn_sasl_config_name(pn_sasl_t *sasl0, const char *name)
+{
+}
+
+void pn_sasl_config_path(pn_sasl_t *sasl0, const char *dir)
+{
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/sasl/default_sasl.c
----------------------------------------------------------------------
diff --git a/c/src/sasl/default_sasl.c b/c/src/sasl/default_sasl.c
new file mode 100644
index 0000000..66dd318
--- /dev/null
+++ b/c/src/sasl/default_sasl.c
@@ -0,0 +1,248 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/sasl.h"
+#include "proton/sasl-plugin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+// SASL implementation interface
+static void default_sasl_prepare(pn_transport_t *transport);
+static void default_sasl_impl_free(pn_transport_t *transport);
+static const char *default_sasl_impl_list_mechs(pn_transport_t *transport);
+
+static bool default_sasl_init_server(pn_transport_t *transport);
+static void default_sasl_process_init(pn_transport_t *transport, const char 
*mechanism, const pn_bytes_t *recv);
+static void default_sasl_process_response(pn_transport_t *transport, const 
pn_bytes_t *recv);
+
+static bool default_sasl_init_client(pn_transport_t *transport);
+static bool default_sasl_process_mechanisms(pn_transport_t *transport, const 
char *mechs);
+static void default_sasl_process_challenge(pn_transport_t *transport, const 
pn_bytes_t *recv);
+static void default_sasl_process_outcome(pn_transport_t *transport);
+
+static bool default_sasl_impl_can_encrypt(pn_transport_t *transport);
+static ssize_t default_sasl_impl_max_encrypt_size(pn_transport_t *transport);
+static ssize_t default_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t 
in, pn_bytes_t *out);
+static ssize_t default_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t 
in, pn_bytes_t *out);
+
+extern const pnx_sasl_implementation default_sasl_impl;
+const pnx_sasl_implementation default_sasl_impl = {
+    default_sasl_impl_free,
+    default_sasl_impl_list_mechs,
+
+    default_sasl_init_server,
+    default_sasl_init_client,
+
+    default_sasl_prepare,
+
+    default_sasl_process_init,
+    default_sasl_process_response,
+
+    default_sasl_process_mechanisms,
+    default_sasl_process_challenge,
+    default_sasl_process_outcome,
+
+    default_sasl_impl_can_encrypt,
+    default_sasl_impl_max_encrypt_size,
+    default_sasl_impl_encode,
+    default_sasl_impl_decode
+};
+
+static const char ANONYMOUS[] = "ANONYMOUS";
+static const char EXTERNAL[] = "EXTERNAL";
+static const char PLAIN[] = "PLAIN";
+
+void default_sasl_prepare(pn_transport_t* transport)
+{
+}
+
+bool default_sasl_init_server(pn_transport_t* transport)
+{
+  // Setup to send SASL mechanisms frame
+  pnx_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
+  return true;
+}
+
+bool default_sasl_init_client(pn_transport_t* transport)
+{
+  return true;
+}
+
+void default_sasl_impl_free(pn_transport_t *transport)
+{
+  free(pnx_sasl_get_context(transport));
+}
+
+// Client handles ANONYMOUS or PLAIN mechanisms if offered
+bool default_sasl_process_mechanisms(pn_transport_t *transport, const char 
*mechs)
+{
+  const char *username = pnx_sasl_get_username(transport);
+  const char *password = pnx_sasl_get_password(transport);
+
+  // Check whether offered EXTERNAL, PLAIN or ANONYMOUS
+  // Look for "EXTERNAL" in mechs
+  const char *found = strstr(mechs, EXTERNAL);
+  // Make sure that string is separated and terminated and allowed
+  if (found && (found==mechs || found[-1]==' ') && (found[8]==0 || found[8]==' 
') &&
+      pnx_sasl_is_included_mech(transport, pn_bytes(8, found))) {
+    pnx_sasl_set_selected_mechanism(transport, EXTERNAL);
+    if (username) {
+      size_t size = strlen(username);
+      char *iresp = (char *) malloc(size);
+      if (!iresp) return false;
+
+      pnx_sasl_set_context(transport, iresp);
+
+      memmove(iresp, username, size);
+      pnx_sasl_set_bytes_out(transport, pn_bytes(size, iresp));
+    } else {
+      static const char empty[] = "";
+      pnx_sasl_set_bytes_out(transport, pn_bytes(0, empty));
+    }
+    pnx_sasl_set_desired_state(transport, SASL_POSTED_INIT);
+    return true;
+  }
+
+  // Look for "PLAIN" in mechs
+  found = strstr(mechs, PLAIN);
+  // Make sure that string is separated and terminated, allowed
+  // and we have a username and password and connection is encrypted or we 
allow insecure
+  if (found && (found==mechs || found[-1]==' ') && (found[5]==0 || found[5]==' 
') &&
+      pnx_sasl_is_included_mech(transport, pn_bytes(5, found)) &&
+      (pnx_sasl_is_transport_encrypted(transport) || 
pnx_sasl_get_allow_insecure_mechs(transport)) &&
+      username && password) {
+    pnx_sasl_set_selected_mechanism(transport, PLAIN);
+    size_t usize = strlen(username);
+    size_t psize = strlen(password);
+    size_t size = usize + psize + 2;
+    char *iresp = (char *) malloc(size);
+    if (!iresp) return false;
+
+    pnx_sasl_set_context(transport, iresp);
+
+    iresp[0] = 0;
+    memmove(&iresp[1], username, usize);
+    iresp[usize + 1] = 0;
+    memmove(&iresp[usize + 2], password, psize);
+    pnx_sasl_set_bytes_out(transport, pn_bytes(size, iresp));
+
+    // Zero out password and dealloc
+    pnx_sasl_clear_password(transport);
+
+    pnx_sasl_set_desired_state(transport, SASL_POSTED_INIT);
+    return true;
+  }
+
+  // Look for "ANONYMOUS" in mechs
+  found = strstr(mechs, ANONYMOUS);
+  // Make sure that string is separated and terminated and allowed
+  if (found && (found==mechs || found[-1]==' ') && (found[9]==0 || found[9]==' 
') &&
+      pnx_sasl_is_included_mech(transport, pn_bytes(9, found))) {
+    pnx_sasl_set_selected_mechanism(transport, ANONYMOUS);
+    if (username) {
+      size_t size = strlen(username);
+      char *iresp = (char *) malloc(size);
+      if (!iresp) return false;
+
+      pnx_sasl_set_context(transport, iresp);
+
+      memmove(iresp, username, size);
+      pnx_sasl_set_bytes_out(transport, pn_bytes(size, iresp));
+    } else {
+      static const char anon[] = "anonymous";
+      pnx_sasl_set_bytes_out(transport, pn_bytes(sizeof anon-1, anon));
+    }
+    pnx_sasl_set_desired_state(transport, SASL_POSTED_INIT);
+    return true;
+  }
+  return false;
+}
+
+// Server will offer only ANONYMOUS and EXTERNAL if appropriate
+const char *default_sasl_impl_list_mechs(pn_transport_t *transport)
+{
+  // If we have an external authid then we can offer EXTERNAL
+  if (pnx_sasl_get_external_username(transport)) {
+    return "EXTERNAL ANONYMOUS";
+  } else {
+    return "ANONYMOUS";
+  }
+}
+
+void default_sasl_process_init(pn_transport_t *transport, const char 
*mechanism, const pn_bytes_t *recv)
+{
+  // Check that mechanism is ANONYMOUS and it is allowed
+  if (strcmp(mechanism, ANONYMOUS)==0 &&
+      pnx_sasl_is_included_mech(transport, pn_bytes(sizeof(ANONYMOUS)-1, 
ANONYMOUS))) {
+    pnx_sasl_succeed_authentication(transport, "anonymous");
+    pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+    return;
+  }
+
+  // Or maybe EXTERNAL
+  const char *ext_username = pnx_sasl_get_external_username(transport);
+  if (strcmp(mechanism, EXTERNAL)==0 &&
+      pnx_sasl_is_included_mech(transport, pn_bytes(sizeof(EXTERNAL)-1, 
EXTERNAL)) &&
+      ext_username) {
+    pnx_sasl_succeed_authentication(transport, ext_username);
+    pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+    return;
+  }
+
+  // Otherwise authentication failed
+  pnx_sasl_fail_authentication(transport);
+  pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+
+}
+
+/* The default implementation neither sends nor receives challenges or 
responses */
+void default_sasl_process_challenge(pn_transport_t *transport, const 
pn_bytes_t *recv)
+{
+}
+
+void default_sasl_process_response(pn_transport_t *transport, const pn_bytes_t 
*recv)
+{
+}
+
+void default_sasl_process_outcome(pn_transport_t* transport)
+{
+}
+
+bool default_sasl_impl_can_encrypt(pn_transport_t *transport)
+{
+  return false;
+}
+
+ssize_t default_sasl_impl_max_encrypt_size(pn_transport_t *transport)
+{
+  return 0;
+}
+
+ssize_t default_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, 
pn_bytes_t *out)
+{
+  return 0;
+}
+
+ssize_t default_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, 
pn_bytes_t *out)
+{
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/c/src/sasl/sasl-internal.h b/c/src/sasl/sasl-internal.h
new file mode 100644
index 0000000..aade2e0
--- /dev/null
+++ b/c/src/sasl/sasl-internal.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef PROTON_SASL_INTERNAL_H
+#define PROTON_SASL_INTERNAL_H 1
+
+#include "core/buffer.h"
+#include "core/engine-internal.h"
+
+#include "proton/types.h"
+#include "proton/sasl.h"
+#include "proton/sasl-plugin.h"
+
+extern const pnx_sasl_implementation default_sasl_impl;
+extern const pnx_sasl_implementation * const cyrus_sasl_impl;
+
+// SASL APIs used by transport code
+void pn_sasl_free(pn_transport_t *transport);
+void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, 
const char *password);
+void pni_sasl_set_remote_hostname(pn_transport_t *transport, const char* fqdn);
+void pni_sasl_set_external_security(pn_transport_t *transport, int ssf, const 
char *authid);
+
+struct pni_sasl_t {
+  void *impl_context;
+  const pnx_sasl_implementation* impl;
+  char *selected_mechanism;
+  char *included_mechanisms;
+  const char *username;
+  char *password;
+  const char *remote_fqdn;
+  char *local_fqdn;
+  char *external_auth;
+  int external_ssf;
+  size_t max_encrypt_size;
+  pn_buffer_t* decoded_buffer;
+  pn_buffer_t* encoded_buffer;
+  pn_bytes_t bytes_out;
+  pn_sasl_outcome_t outcome;
+  enum pnx_sasl_state desired_state;
+  enum pnx_sasl_state last_state;
+  bool allow_insecure_mechs;
+  bool client;
+};
+
+#endif /* sasl-internal.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/c/src/sasl/sasl.c b/c/src/sasl/sasl.c
new file mode 100644
index 0000000..f015514
--- /dev/null
+++ b/c/src/sasl/sasl.c
@@ -0,0 +1,918 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 "sasl-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 <assert.h>
+
+// Machinery to allow plugin SASL implementations
+// Change this to &default_sasl_impl when we change cyrus to opt in
+static const pnx_sasl_implementation *global_sasl_impl = NULL;
+
+//-----------------------------------------------------------------------------
+// pnx_sasl: API for SASL implementations to use
+
+void pnx_sasl_logf(pn_transport_t *logger, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    if (logger->trace & PN_TRACE_DRV)
+        pn_transport_vlogf(logger, fmt, ap);
+    va_end(ap);
+}
+
+void *pnx_sasl_get_context(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->impl_context : NULL;
+}
+
+void  pnx_sasl_set_context(pn_transport_t *transport, void *context)
+{
+  if (transport->sasl) transport->sasl->impl_context = context;
+}
+
+bool  pnx_sasl_is_client(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->client : false;
+}
+
+bool  pnx_sasl_is_transport_encrypted(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->external_ssf>0 : false;
+}
+
+bool  pnx_sasl_get_allow_insecure_mechs(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->allow_insecure_mechs : false;
+}
+
+bool  pnx_sasl_get_auth_required(pn_transport_t *transport)
+{
+  return transport->auth_required;
+}
+
+const char *pnx_sasl_get_username(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->username : NULL;
+}
+
+const char *pnx_sasl_get_external_username(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->external_auth : NULL;
+}
+
+int   pnx_sasl_get_external_ssf(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->external_ssf : 0;
+}
+
+const char *pnx_sasl_get_password(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->password : NULL;
+}
+
+void  pnx_sasl_clear_password(pn_transport_t *transport)
+{
+  if (transport->sasl) {
+    char *password = transport->sasl->password;
+    free(memset(password, 0, strlen(password)));
+    transport->sasl->password = NULL;
+  }
+}
+
+const char *pnx_sasl_get_remote_fqdn(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->remote_fqdn : NULL;
+}
+
+const char *pnx_sasl_get_selected_mechanism(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->selected_mechanism : NULL;
+}
+
+void  pnx_sasl_set_bytes_out(pn_transport_t *transport, pn_bytes_t bytes)
+{
+  if (transport->sasl) {
+    transport->sasl->bytes_out = bytes;
+  }
+}
+
+void  pnx_sasl_set_selected_mechanism(pn_transport_t *transport, const char 
*mechanism)
+{
+  if (transport->sasl) {
+    transport->sasl->selected_mechanism = pn_strdup(mechanism);
+  }
+}
+
+void  pnx_sasl_succeed_authentication(pn_transport_t *transport, const char 
*username)
+{
+  if (transport->sasl) {
+    transport->sasl->username = username;
+    transport->sasl->outcome = PN_SASL_OK;
+    transport->authenticated = true;
+  }
+}
+
+void  pnx_sasl_fail_authentication(pn_transport_t *transport)
+{
+  if (transport->sasl) {
+    transport->sasl->outcome = PN_SASL_AUTH;
+  }
+}
+
+void pnx_sasl_set_implementation(pn_transport_t *transport, const 
pnx_sasl_implementation *i, void* context)
+{
+  transport->sasl->impl = i;
+  transport->sasl->impl_context = context;
+}
+
+void pnx_sasl_set_default_implementation(const pnx_sasl_implementation* impl)
+{
+  global_sasl_impl = impl;
+}
+
+
+//-----------------------------------------------------------------------------
+// pni_sasl_impl: Abstract the entry points to the SASL implementation 
(virtual function calls)
+
+static inline void pni_sasl_impl_free(pn_transport_t *transport)
+{
+  transport->sasl->impl->free(transport);
+}
+
+static inline const char *pni_sasl_impl_list_mechs(pn_transport_t *transport)
+{
+  return transport->sasl->impl->list_mechs(transport);
+}
+
+static inline bool pni_sasl_impl_init_server(pn_transport_t *transport)
+{
+  return transport->sasl->impl->init_server(transport);
+}
+
+static inline void pni_sasl_impl_prepare_write(pn_transport_t *transport)
+{
+  transport->sasl->impl->prepare_write(transport);
+}
+
+static inline void pni_sasl_impl_process_init(pn_transport_t *transport, const 
char *mechanism, const pn_bytes_t *recv)
+{
+  transport->sasl->impl->process_init(transport, mechanism, recv);
+}
+
+static inline void pni_sasl_impl_process_response(pn_transport_t *transport, 
const pn_bytes_t *recv)
+{
+  transport->sasl->impl->process_response(transport, recv);
+}
+
+static inline bool pni_sasl_impl_init_client(pn_transport_t *transport)
+{
+  return transport->sasl->impl->init_client(transport);
+}
+
+static inline bool pni_sasl_impl_process_mechanisms(pn_transport_t *transport, 
const char *mechs)
+{
+  return transport->sasl->impl->process_mechanisms(transport, mechs);
+}
+
+static inline void pni_sasl_impl_process_challenge(pn_transport_t *transport, 
const pn_bytes_t *recv)
+{
+  transport->sasl->impl->process_challenge(transport, recv);
+}
+
+static inline void pni_sasl_impl_process_outcome(pn_transport_t *transport)
+{
+  transport->sasl->impl->process_outcome(transport);
+}
+
+static inline bool pni_sasl_impl_can_encrypt(pn_transport_t *transport)
+{
+    return transport->sasl->impl->can_encrypt(transport);
+}
+
+static inline ssize_t pni_sasl_impl_max_encrypt_size(pn_transport_t *transport)
+{
+    return transport->sasl->impl->max_encrypt_size(transport);
+}
+
+static inline ssize_t pni_sasl_impl_encode(pn_transport_t *transport, 
pn_bytes_t in, pn_bytes_t *out)
+{
+    return transport->sasl->impl->encode(transport, in, out);
+}
+
+static inline ssize_t pni_sasl_impl_decode(pn_transport_t *transport, 
pn_bytes_t in, pn_bytes_t *out)
+{
+    return transport->sasl->impl->decode(transport, in, out);
+}
+
+//-----------------------------------------------------------------------------
+// General SASL implementation
+
+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
+  return sasl ? ((pn_transport_t *)sasl)->sasl : NULL;
+}
+
+static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned 
int layer, const char* bytes, size_t available);
+static ssize_t pn_input_read_sasl(pn_transport_t *transport, unsigned int 
layer, const char *bytes, size_t available);
+static ssize_t pn_input_read_sasl_encrypt(pn_transport_t *transport, unsigned 
int layer, const char *bytes, size_t available);
+static ssize_t pn_output_write_sasl_header(pn_transport_t* transport, unsigned 
int layer, char* bytes, size_t size);
+static ssize_t pn_output_write_sasl(pn_transport_t *transport, unsigned int 
layer, char *bytes, size_t available);
+static ssize_t pn_output_write_sasl_encrypt(pn_transport_t *transport, 
unsigned int layer, char *bytes, size_t available);
+static void pn_error_sasl(pn_transport_t* transport, unsigned int layer);
+
+const pn_io_layer_t sasl_header_layer = {
+    pn_input_read_sasl_header,
+    pn_output_write_sasl_header,
+    pn_error_sasl,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t sasl_write_header_layer = {
+    pn_input_read_sasl,
+    pn_output_write_sasl_header,
+    pn_error_sasl,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t sasl_read_header_layer = {
+    pn_input_read_sasl_header,
+    pn_output_write_sasl,
+    pn_error_sasl,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t sasl_layer = {
+    pn_input_read_sasl,
+    pn_output_write_sasl,
+    pn_error_sasl,
+    NULL,
+    NULL
+};
+
+const pn_io_layer_t sasl_encrypt_layer = {
+    pn_input_read_sasl_encrypt,
+    pn_output_write_sasl_encrypt,
+    NULL,
+    NULL,
+    NULL
+};
+
+#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
+#define SASL_HEADER_LEN 8
+
+static bool pni_sasl_is_server_state(enum pnx_sasl_state state)
+{
+  return state==SASL_NONE
+      || state==SASL_POSTED_MECHANISMS
+      || state==SASL_POSTED_CHALLENGE
+      || state==SASL_POSTED_OUTCOME
+      || state==SASL_ERROR;
+}
+
+static bool pni_sasl_is_client_state(enum pnx_sasl_state state)
+{
+  return state==SASL_NONE
+      || state==SASL_POSTED_INIT
+      || state==SASL_POSTED_RESPONSE
+      || state==SASL_RECVED_OUTCOME_SUCCEED
+      || state==SASL_RECVED_OUTCOME_FAIL
+      || state==SASL_ERROR;
+}
+
+static bool pni_sasl_is_final_input_state(pni_sasl_t *sasl)
+{
+  enum pnx_sasl_state desired_state = sasl->desired_state;
+  return desired_state==SASL_RECVED_OUTCOME_SUCCEED
+      || desired_state==SASL_RECVED_OUTCOME_FAIL
+      || desired_state==SASL_ERROR
+      || desired_state==SASL_POSTED_OUTCOME;
+}
+
+static bool pni_sasl_is_final_output_state(pni_sasl_t *sasl)
+{
+  enum pnx_sasl_state last_state = sasl->last_state;
+  enum pnx_sasl_state desired_state = sasl->desired_state;
+  return (desired_state==SASL_RECVED_OUTCOME_SUCCEED && 
last_state>=SASL_POSTED_INIT)
+      || last_state==SASL_RECVED_OUTCOME_SUCCEED
+      || last_state==SASL_RECVED_OUTCOME_FAIL
+      || last_state==SASL_ERROR
+      || last_state==SASL_POSTED_OUTCOME;
+}
+
+static void pni_emit(pn_transport_t *transport)
+{
+  if (transport->connection && transport->connection->collector) {
+    pn_collector_t *collector = transport->connection->collector;
+    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT);
+  }
+}
+
+void pnx_sasl_set_desired_state(pn_transport_t *transport, enum pnx_sasl_state 
desired_state)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  if (sasl->last_state > desired_state) {
+    if (transport->trace & PN_TRACE_DRV)
+      pn_transport_logf(transport, "Trying to send SASL frame (%d), but 
illegal: already in later state (%d)", desired_state, sasl->last_state);
+  } else if (sasl->client && !pni_sasl_is_client_state(desired_state)) {
+    if (transport->trace & PN_TRACE_DRV)
+      pn_transport_logf(transport, "Trying to send server SASL frame (%d) on a 
client", desired_state);
+  } else if (!sasl->client && !pni_sasl_is_server_state(desired_state)) {
+    if (transport->trace & PN_TRACE_DRV)
+      pn_transport_logf(transport, "Trying to send client SASL frame (%d) on a 
server", desired_state);
+  } else {
+    // If we need to repeat CHALLENGE or RESPONSE frames adjust current state 
to seem
+    // like they haven't been sent yet
+    if (sasl->last_state==desired_state && 
desired_state==SASL_POSTED_RESPONSE) {
+      sasl->last_state = SASL_POSTED_INIT;
+    }
+    if (sasl->last_state==desired_state && 
desired_state==SASL_POSTED_CHALLENGE) {
+      sasl->last_state = SASL_POSTED_MECHANISMS;
+    }
+    bool changed = sasl->desired_state != desired_state;
+    sasl->desired_state = desired_state;
+    // Don't emit transport event on error as there will be a TRANSPORT_ERROR 
event
+    if (desired_state != SASL_ERROR && changed) pni_emit(transport);
+  }
+}
+
+// Look for symbol in the mech include list - not particularly efficient,
+// but probably not used enough to matter.
+//
+// Note that if there is no inclusion list then every mech is implicitly 
included.
+static bool pni_sasl_included_mech(const char *included_mech_list, pn_bytes_t 
s)
+{
+  if (!included_mech_list) return true;
+
+  const char * end_list = included_mech_list+strlen(included_mech_list);
+  size_t len = s.size;
+  const char *c = included_mech_list;
+  while (c!=NULL) {
+    // If there are not enough chars left in the list no matches
+    if ((ptrdiff_t)len > end_list-c) return false;
+
+    // Is word equal with a space or end of string afterwards?
+    if (pn_strncasecmp(c, s.start, len)==0 && (c[len]==' ' || c[len]==0) ) 
return true;
+
+    c = strchr(c, ' ');
+    c = c ? c+1 : NULL;
+  }
+  return false;
+}
+
+// Look for symbol in the mech include list - plugin API version
+//
+// Note that if there is no inclusion list then every mech is implicitly 
included.
+bool pnx_sasl_is_included_mech(pn_transport_t* transport, pn_bytes_t s)
+{
+  return pni_sasl_included_mech(transport->sasl->included_mechanisms, s);
+}
+
+// This takes a space separated list and zero terminates it in place
+// whilst adding pointers to the existing strings in a string array.
+// This means that you can't free the original storage until you have
+// finished with the resulting list.
+static void pni_split_mechs(char *mechlist, const char* included_mechs, char 
*mechs[], int *count)
+{
+  char *start = mechlist;
+  char *end = start;
+
+  while (*end) {
+    if (*end == ' ') {
+      if (start != end) {
+        *end = '\0';
+        if (pni_sasl_included_mech(included_mechs, pn_bytes(end-start, 
start))) {
+          mechs[(*count)++] = start;
+        }
+      }
+      end++;
+      start = end;
+    } else {
+      end++;
+    }
+  }
+
+  if (start != end) {
+    if (pni_sasl_included_mech(included_mechs, pn_bytes(end-start, start))) {
+      mechs[(*count)++] = start;
+    }
+  }
+}
+
+// Post SASL frame
+static void pni_post_sasl_frame(pn_transport_t *transport)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  pn_bytes_t out = sasl->bytes_out;
+  enum pnx_sasl_state desired_state = sasl->desired_state;
+  while (sasl->desired_state > sasl->last_state) {
+    switch (desired_state) {
+    case SASL_POSTED_INIT:
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[szS]", SASL_INIT, 
sasl->selected_mechanism,
+                    out.size, out.start, sasl->local_fqdn);
+      pni_emit(transport);
+      break;
+    case SASL_POSTED_MECHANISMS: {
+      // TODO: Hardcoded limit of 16 mechanisms
+      char *mechs[16];
+      char *mechlist = pn_strdup(pni_sasl_impl_list_mechs(transport));
+
+      int count = 0;
+      if (mechlist) {
+        pni_split_mechs(mechlist, sasl->included_mechanisms, mechs, &count);
+      }
+
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[@T[*s]]", 
SASL_MECHANISMS, PN_SYMBOL, count, mechs);
+      free(mechlist);
+      pni_emit(transport);
+      break;
+    }
+    case SASL_POSTED_RESPONSE:
+      if (sasl->last_state != SASL_POSTED_RESPONSE) {
+        pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[Z]", SASL_RESPONSE, 
out.size, out.start);
+        pni_emit(transport);
+      }
+      break;
+    case SASL_POSTED_CHALLENGE:
+      if (sasl->last_state < SASL_POSTED_MECHANISMS) {
+        desired_state = SASL_POSTED_MECHANISMS;
+        continue;
+      } else if (sasl->last_state != SASL_POSTED_CHALLENGE) {
+        pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[Z]", SASL_CHALLENGE, 
out.size, out.start);
+        pni_emit(transport);
+      }
+      break;
+    case SASL_POSTED_OUTCOME:
+      if (sasl->last_state < SASL_POSTED_MECHANISMS) {
+        desired_state = SASL_POSTED_MECHANISMS;
+        continue;
+      }
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[B]", SASL_OUTCOME, 
sasl->outcome);
+      pni_emit(transport);
+      if (sasl->outcome!=PN_SASL_OK) {
+        pn_do_error(transport, "amqp:unauthorized-access", "Failed to 
authenticate client [mech=%s]",
+                    transport->sasl->selected_mechanism ? 
transport->sasl->selected_mechanism : "none");
+        desired_state = SASL_ERROR;
+      }
+      break;
+    case SASL_RECVED_OUTCOME_SUCCEED:
+      if (sasl->last_state < SASL_POSTED_INIT) {
+        desired_state = SASL_POSTED_INIT;
+        continue;
+      }
+      break;
+    case SASL_RECVED_OUTCOME_FAIL:
+      pn_do_error(transport, "amqp:unauthorized-access", "Authentication 
failed [mech=%s]",
+                  transport->sasl->selected_mechanism ? 
transport->sasl->selected_mechanism : "none");
+      desired_state = SASL_ERROR;
+      break;
+    case SASL_ERROR:
+      break;
+    case SASL_NONE:
+      return;
+    }
+    sasl->last_state = desired_state;
+    desired_state = sasl->desired_state;
+  }
+}
+
+static void pn_error_sasl(pn_transport_t* transport, unsigned int layer)
+{
+  transport->close_sent = true;
+  pnx_sasl_set_desired_state(transport, SASL_ERROR);
+}
+
+static ssize_t pn_input_read_sasl_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_AMQP_SASL:
+    if (transport->io_layers[layer] == &sasl_read_header_layer) {
+        transport->io_layers[layer] = &sasl_layer;
+    } else {
+        transport->io_layers[layer] = &sasl_write_header_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 SASL_HEADER_LEN;
+  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", "SASL", 
pni_protocol_name(protocol), quoted,
+              !eos ? "" : " (connection aborted)");
+  pn_set_error_layer(transport);
+  return PN_EOS;
+}
+
+static void pni_sasl_start_server_if_needed(pn_transport_t *transport)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  if (!sasl->client && sasl->desired_state<SASL_POSTED_MECHANISMS) {
+    pni_sasl_impl_init_server(transport);
+  }
+}
+
+static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int 
layer, const char* bytes, size_t available)
+{
+  pni_sasl_t *sasl = transport->sasl;
+
+  bool eos = pn_transport_capacity(transport)==PN_EOS;
+  if (eos) {
+    pn_do_error(transport, "amqp:connection:framing-error", "connection 
aborted");
+    pn_set_error_layer(transport);
+    return PN_EOS;
+  }
+
+  pni_sasl_start_server_if_needed(transport);
+
+  if (!pni_sasl_is_final_input_state(sasl)) {
+    return pn_dispatcher_input(transport, bytes, available, false, 
&transport->halt);
+  }
+
+  if (!pni_sasl_is_final_output_state(sasl)) {
+    return pni_passthru_layer.process_input(transport, layer, bytes, 
available);
+  }
+
+  if (pni_sasl_impl_can_encrypt(transport)) {
+    sasl->max_encrypt_size = pni_sasl_impl_max_encrypt_size(transport);
+    if (transport->trace & PN_TRACE_DRV)
+      pn_transport_logf(transport, "SASL Encryption enabled: buffer=%d", 
sasl->max_encrypt_size);
+    transport->io_layers[layer] = &sasl_encrypt_layer;
+  } else {
+    transport->io_layers[layer] = &pni_passthru_layer;
+  }
+  return transport->io_layers[layer]->process_input(transport, layer, bytes, 
available);
+}
+
+static ssize_t pn_input_read_sasl_encrypt(pn_transport_t* transport, unsigned 
int layer, const char* bytes, size_t available)
+{
+  pn_buffer_t *in = transport->sasl->decoded_buffer;
+  const size_t max_buffer = transport->sasl->max_encrypt_size;
+  for (size_t processed = 0; processed<available;) {
+    pn_bytes_t decoded = pn_bytes(0, NULL);
+    size_t decode_size = 
(available-processed)<=max_buffer?(available-processed):max_buffer;
+    ssize_t size = pni_sasl_impl_decode(transport, pn_bytes(decode_size, 
bytes+processed), &decoded);
+    if (size<0) return size;
+    if (size>0) {
+      size = pn_buffer_append(in, decoded.start, decoded.size);
+      if (size) return size;
+    }
+    processed += decode_size;
+  }
+  pn_bytes_t decoded = pn_buffer_bytes(in);
+  size_t processed_size = 0;
+  while (processed_size < decoded.size) {
+    ssize_t size = pni_passthru_layer.process_input(transport, layer, 
decoded.start+processed_size, decoded.size-processed_size);
+    if (size==0) break;
+    if (size<0) return size;
+    pn_buffer_trim(in, size, 0);
+    processed_size += size;
+  }
+  return available;
+}
+
+static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned 
int layer, char *bytes, size_t size)
+{
+  if (transport->trace & PN_TRACE_FRM)
+    pn_transport_logf(transport, "  -> %s", "SASL");
+  assert(size >= SASL_HEADER_LEN);
+  memmove(bytes, SASL_HEADER, SASL_HEADER_LEN);
+  if (transport->io_layers[layer]==&sasl_write_header_layer) {
+      transport->io_layers[layer] = &sasl_layer;
+  } else {
+      transport->io_layers[layer] = &sasl_read_header_layer;
+  }
+  return SASL_HEADER_LEN;
+}
+
+static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int 
layer, char* bytes, size_t available)
+{
+  pni_sasl_t *sasl = transport->sasl;
+
+  // this accounts for when pn_do_error is invoked, e.g. by idle timeout
+  if (transport->close_sent) return PN_EOS;
+
+  pni_sasl_start_server_if_needed(transport);
+
+  pni_sasl_impl_prepare_write(transport);
+
+  pni_post_sasl_frame(transport);
+
+  if (pn_buffer_size(transport->output_buffer) != 0 || 
!pni_sasl_is_final_output_state(sasl)) {
+    return pn_dispatcher_output(transport, bytes, available);
+  }
+
+  if (!pni_sasl_is_final_input_state(sasl)) {
+    return pni_passthru_layer.process_output(transport, layer, bytes, 
available );
+  }
+
+  // We only get here if there is nothing to output and we're in a final state
+  if (sasl->outcome != PN_SASL_OK) {
+    return PN_EOS;
+  }
+
+  // We know that auth succeeded or we're not in final input state
+  if (pni_sasl_impl_can_encrypt(transport)) {
+    sasl->max_encrypt_size = pni_sasl_impl_max_encrypt_size(transport);
+    if (transport->trace & PN_TRACE_DRV)
+      pn_transport_logf(transport, "SASL Encryption enabled: buffer=%d", 
sasl->max_encrypt_size);
+    transport->io_layers[layer] = &sasl_encrypt_layer;
+  } else {
+    transport->io_layers[layer] = &pni_passthru_layer;
+  }
+  return transport->io_layers[layer]->process_output(transport, layer, bytes, 
available);
+}
+
+static ssize_t pn_output_write_sasl_encrypt(pn_transport_t* transport, 
unsigned int layer, char* bytes, size_t available)
+{
+  ssize_t clear_size = pni_passthru_layer.process_output(transport, layer, 
bytes, available );
+  if (clear_size<0) return clear_size;
+
+  const ssize_t max_buffer = transport->sasl->max_encrypt_size;
+  pn_buffer_t *out = transport->sasl->encoded_buffer;
+  for (ssize_t processed = 0; processed<clear_size;) {
+    pn_bytes_t encoded = pn_bytes(0, NULL);
+    ssize_t encode_size = 
(clear_size-processed)<=max_buffer?(clear_size-processed):max_buffer;
+    ssize_t size = pni_sasl_impl_encode(transport, pn_bytes(encode_size, 
bytes+processed), &encoded);
+    if (size<0) return size;
+    if (size>0) {
+      size = pn_buffer_append(out, encoded.start, encoded.size);
+      if (size) return size;
+    }
+    processed += encode_size;
+  }
+  ssize_t size = pn_buffer_get(out, 0, available, bytes);
+  pn_buffer_trim(out, size, 0);
+  return size;
+}
+
+pn_sasl_t *pn_sasl(pn_transport_t *transport)
+{
+  if (!transport->sasl) {
+    pni_sasl_t *sasl = (pni_sasl_t *) malloc(sizeof(pni_sasl_t));
+
+    sasl->impl_context = NULL;
+    // Change this to just global_sasl_impl when we make cyrus opt in
+    sasl->impl = global_sasl_impl ? global_sasl_impl : cyrus_sasl_impl ? 
cyrus_sasl_impl : &default_sasl_impl;
+    sasl->client = !transport->server;
+    sasl->selected_mechanism = NULL;
+    sasl->included_mechanisms = NULL;
+    sasl->username = NULL;
+    sasl->password = NULL;
+    sasl->remote_fqdn = NULL;
+    sasl->local_fqdn = NULL;
+    sasl->external_auth = NULL;
+    sasl->external_ssf = 0;
+    sasl->outcome = PN_SASL_NONE;
+    sasl->decoded_buffer = pn_buffer(0);
+    sasl->encoded_buffer = pn_buffer(0);
+    sasl->bytes_out.size = 0;
+    sasl->bytes_out.start = NULL;
+    sasl->desired_state = SASL_NONE;
+    sasl->last_state = SASL_NONE;
+    sasl->allow_insecure_mechs = false;
+
+    transport->sasl = sasl;
+  }
+
+  // The actual external pn_sasl_t pointer is a pointer to its enclosing 
pn_transport_t
+  return (pn_sasl_t *)transport;
+}
+
+void pn_sasl_free(pn_transport_t *transport)
+{
+  if (transport) {
+    pni_sasl_t *sasl = transport->sasl;
+    if (sasl) {
+      free(sasl->selected_mechanism);
+      free(sasl->included_mechanisms);
+      free(sasl->password);
+      free(sasl->external_auth);
+      free(sasl->local_fqdn);
+
+      if (sasl->impl_context) {
+        pni_sasl_impl_free(transport);
+      }
+      pn_buffer_free(sasl->decoded_buffer);
+      pn_buffer_free(sasl->encoded_buffer);
+      free(sasl);
+    }
+  }
+}
+
+void pni_sasl_set_remote_hostname(pn_transport_t * transport, const char * 
fqdn)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->remote_fqdn = fqdn;
+}
+
+void pnx_sasl_set_local_hostname(pn_transport_t * transport, const char * fqdn)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->local_fqdn = pn_strdup(fqdn);
+}
+
+void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, 
const char *password)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->username = user;
+  free(sasl->password);
+  sasl->password = password ? pn_strdup(password) : NULL;
+}
+
+void pni_sasl_set_external_security(pn_transport_t *transport, int ssf, const 
char *authid)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->external_ssf = ssf;
+  free(sasl->external_auth);
+  sasl->external_auth = authid ? pn_strdup(authid) : NULL;
+}
+
+const char *pn_sasl_get_user(pn_sasl_t *sasl0)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    return sasl->username;
+}
+
+const char *pn_sasl_get_mech(pn_sasl_t *sasl0)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    return sasl->selected_mechanism;
+}
+
+void pn_sasl_allowed_mechs(pn_sasl_t *sasl0, const char *mechs)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    free(sasl->included_mechanisms);
+    sasl->included_mechanisms = mechs ? pn_strdup(mechs) : NULL;
+}
+
+void pn_sasl_set_allow_insecure_mechs(pn_sasl_t *sasl0, bool insecure)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    sasl->allow_insecure_mechs = insecure;
+}
+
+bool pn_sasl_get_allow_insecure_mechs(pn_sasl_t *sasl0)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    return sasl->allow_insecure_mechs;
+}
+
+void pn_sasl_done(pn_sasl_t *sasl0, pn_sasl_outcome_t outcome)
+{
+  pni_sasl_t *sasl = get_sasl_internal(sasl0);
+  if (sasl) {
+    sasl->outcome = outcome;
+  }
+}
+
+pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl0)
+{
+  pni_sasl_t *sasl = get_sasl_internal(sasl0);
+  return sasl ? sasl->outcome : PN_SASL_NONE;
+}
+
+// Received Server side
+int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t 
channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  pn_bytes_t mech;
+  pn_bytes_t recv;
+  int err = pn_data_scan(args, "D.[sz]", &mech, &recv);
+  if (err) return err;
+  sasl->selected_mechanism = pn_strndup(mech.start, mech.size);
+
+  pni_sasl_impl_process_init(transport, sasl->selected_mechanism, &recv);
+
+  return 0;
+}
+
+// Received client side
+int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t 
channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pni_sasl_t *sasl = transport->sasl;
+
+  // This scanning relies on pn_data_scan leaving the pn_data_t cursors
+  // where they are after finishing the scan
+  pn_string_t *mechs = pn_string("");
+
+  // Try array of symbols for mechanism list
+  bool array = false;
+  int err = pn_data_scan(args, "D.[?@[", &array);
+  if (err) return err;
+
+  if (array) {
+    // Now keep checking for end of array and pull a symbol
+    while(pn_data_next(args)) {
+      pn_bytes_t s = pn_data_get_symbol(args);
+      if (pnx_sasl_is_included_mech(transport, s)) {
+        pn_string_addf(mechs, "%*s ", (int)s.size, s.start);
+      }
+    }
+
+    if (pn_string_size(mechs)) {
+        pn_string_buffer(mechs)[pn_string_size(mechs)-1] = 0;
+    }
+  } else {
+    // No array of symbols; try single symbol
+    pn_data_rewind(args);
+    pn_bytes_t symbol;
+    int err = pn_data_scan(args, "D.[s]", &symbol);
+    if (err) return err;
+
+    pn_string_setn(mechs, symbol.start, symbol.size);
+  }
+
+  if (!(pni_sasl_impl_init_client(transport) &&
+        pn_string_size(mechs) &&
+        pni_sasl_impl_process_mechanisms(transport, pn_string_get(mechs)))) {
+    sasl->outcome = PN_SASL_PERM;
+    pnx_sasl_set_desired_state(transport, SASL_RECVED_OUTCOME_FAIL);
+  }
+
+  pn_free(mechs);
+  return 0;
+}
+
+// Received client side
+int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t 
channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_bytes_t recv;
+  int err = pn_data_scan(args, "D.[z]", &recv);
+  if (err) return err;
+
+  pni_sasl_impl_process_challenge(transport, &recv);
+
+  return 0;
+}
+
+// Received server side
+int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t 
channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_bytes_t recv;
+  int err = pn_data_scan(args, "D.[z]", &recv);
+  if (err) return err;
+
+  pni_sasl_impl_process_response(transport, &recv);
+
+  return 0;
+}
+
+// Received client side
+int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t 
channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  uint8_t outcome;
+  int err = pn_data_scan(args, "D.[B]", &outcome);
+  if (err) return err;
+
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->outcome = (pn_sasl_outcome_t) outcome;
+  bool authenticated = sasl->outcome==PN_SASL_OK;
+  transport->authenticated = authenticated;
+  pnx_sasl_set_desired_state(transport, authenticated ? 
SASL_RECVED_OUTCOME_SUCCEED : SASL_RECVED_OUTCOME_FAIL);
+
+  pni_sasl_impl_process_outcome(transport);
+
+  return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/security.xml
----------------------------------------------------------------------
diff --git a/c/src/security.xml b/c/src/security.xml
new file mode 100644
index 0000000..c6ac018
--- /dev/null
+++ b/c/src/security.xml
@@ -0,0 +1,76 @@
+<?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="security" xmlns="http://www.amqp.org/schema/amqp.xsd";>
+  <section name="tls">
+    <definition name="TLS-MAJOR" value="1"/>
+    <definition name="TLS-MINOR" value="0"/>
+    <definition name="TLS-REVISION" value="0"/>
+  </section>
+  <section name="sasl">
+    <type name="sasl-mechanisms" class="composite" source="list" 
provides="sasl-frame">
+      <descriptor name="amqp:sasl-mechanisms:list" 
code="0x00000000:0x00000040"/>
+      <field name="sasl-server-mechanisms" type="symbol" mandatory="true" 
multiple="true"/>
+    </type>
+    <type name="sasl-init" class="composite" source="list" 
provides="sasl-frame">
+      <descriptor name="amqp:sasl-init:list" code="0x00000000:0x00000041"/>
+      <field name="mechanism" type="symbol" mandatory="true"/>
+      <field name="initial-response" type="binary"/>
+      <field name="hostname" type="string"/>
+    </type>
+    <type name="sasl-challenge" class="composite" source="list" 
provides="sasl-frame">
+      <descriptor name="amqp:sasl-challenge:list" 
code="0x00000000:0x00000042"/>
+      <field name="challenge" type="binary" mandatory="true"/>
+    </type>
+    <type name="sasl-response" class="composite" source="list" 
provides="sasl-frame">
+      <descriptor name="amqp:sasl-response:list" code="0x00000000:0x00000043"/>
+      <field name="response" type="binary" mandatory="true"/>
+    </type>
+    <type name="sasl-outcome" class="composite" source="list" 
provides="sasl-frame">
+      <descriptor name="amqp:sasl-outcome:list" code="0x00000000:0x00000044"/>
+      <field name="code" type="sasl-code" mandatory="true"/>
+      <field name="additional-data" type="binary"/>
+    </type>
+    <type name="sasl-code" class="restricted" source="ubyte">
+      <choice name="ok" value="0"/>
+      <choice name="auth" value="1"/>
+      <choice name="sys" value="2"/>
+      <choice name="sys-perm" value="3"/>
+      <choice name="sys-temp" value="4"/>
+    </type>
+    <definition name="SASL-MAJOR" value="1"/>
+    <definition name="SASL-MINOR" value="0"/>
+    <definition name="SASL-REVISION" value="0"/>
+  </section>
+</amqp>


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

Reply via email to