You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2017/04/27 17:38:26 UTC

[01/10] qpid-dispatch git commit: DISPATCH-390: Temporarily disable http for first cut proactor work

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master 361a7e9a6 -> b974b884a


DISPATCH-390: Temporarily disable http for first cut proactor work

First cut of proactor integration will not support HTTP.


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

Branch: refs/heads/master
Commit: 0539dc4d5450353222913a81c251feed1258e5fc
Parents: 361a7e9
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jan 19 10:28:12 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:28:24 2017 -0400

----------------------------------------------------------------------
 CMakeLists.txt | 5 ++++-
 src/server.c   | 1 -
 2 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0539dc4d/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46f651e..a06c67f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -103,8 +103,11 @@ find_library(rt_lib rt)
 find_package(Proton 0.15 REQUIRED)
 
 ## Optional dependencies
+
 include(FindLibWebSockets)
-option(USE_LIBWEBSOCKETS "Use libwebsockets for WebSocket support" ${LIBWEBSOCKETS_FOUND})
+# FIXME aconway 2017-01-19: websockets disbled for temporary proactor work.
+# option(USE_LIBWEBSOCKETS "Use libwebsockets for WebSocket support" ${LIBWEBSOCKETS_FOUND})
+set(USE_LIBWEBSOCKETS OFF)
 
 ##
 ## Find Valgrind

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0539dc4d/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index 3875083..848cfcb 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1564,7 +1564,6 @@ void qd_connection_set_context(qd_connection_t *conn, void *context)
 
 void *qd_connection_get_context(qd_connection_t *conn)
 {
-    /* FIXME aconway 2017-04-20: needs to be thread safe with respect to deletion */
     return conn->user_context;
 }
 


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


[06/10] qpid-dispatch git commit: DISPATCH-390: Log process ID with "Operational" notice

Posted by ac...@apache.org.
DISPATCH-390: Log process ID with "Operational" notice

Useful for correlating logs with running processes or core dumps.


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

Branch: refs/heads/master
Commit: 7fe0ac970b195a97c007174359d5d1f615d8d246
Parents: 6f56e28
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Apr 11 17:02:51 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:29:54 2017 -0400

----------------------------------------------------------------------
 src/server.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/7fe0ac97/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index 15a2aef..d121cd4 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1021,8 +1021,9 @@ void qd_server_run(qd_dispatch_t *qd)
     int i;
     assert(qd_server);
     assert(qd_server->container); // Server can't run without a container
-    qd_log(qd_server->log_source, QD_LOG_NOTICE, "Operational, %d Threads Running",
-           qd_server->thread_count);
+    qd_log(qd_server->log_source,
+           QD_LOG_NOTICE, "Operational, %d Threads Running (process ID %ld)",
+           qd_server->thread_count, (long)getpid());
 #ifndef NDEBUG
     qd_log(qd_server->log_source, QD_LOG_INFO, "Running in DEBUG Mode");
 #endif


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


[03/10] qpid-dispatch git commit: DISPATCH-390: Convert dispatch to use pn_proactor_t

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index 848cfcb..15a2aef 100644
--- a/src/server.c
+++ b/src/server.c
@@ -24,6 +24,12 @@
 #include <qpid/dispatch/amqp.h>
 #include <qpid/dispatch/server.h>
 #include <qpid/dispatch/failoverlist.h>
+
+#include <proton/event.h>
+#include <proton/listener.h>
+#include <proton/proactor.h>
+#include <proton/sasl.h>
+
 #include "qpid/dispatch/python_embedded.h"
 #include "entity.h"
 #include "entity_cache.h"
@@ -34,94 +40,33 @@
 #include "alloc.h"
 #include "config.h"
 #include <stdio.h>
-#include <time.h>
 #include <string.h>
 #include <errno.h>
 #include <inttypes.h>
 
-typedef struct qd_thread_t {
-    qd_server_t  *qd_server;
-    int           thread_id;
-    volatile int  running;
-    volatile int  canceled;
-    int           using_thread;
-    sys_thread_t *thread;
-} qd_thread_t;
-
-
-typedef struct qd_work_item_t {
-    DEQ_LINKS(struct qd_work_item_t);
-    qdpn_connector_t *cxtr;
-} qd_work_item_t;
-
-DEQ_DECLARE(qd_work_item_t, qd_work_list_t);
-
-
 struct qd_server_t {
     qd_dispatch_t            *qd;
-    int                       thread_count;
+    const int                thread_count; /* Immutable */
     const char               *container_name;
     const char               *sasl_config_path;
     const char               *sasl_config_name;
-    qdpn_driver_t            *driver;
+    pn_proactor_t            *proactor;
+    qd_container_t           *container;
     qd_log_source_t          *log_source;
-    qd_conn_handler_cb_t      conn_handler;
-    qd_pn_event_handler_cb_t  pn_event_handler;
-    qd_pn_event_complete_cb_t pn_event_complete_handler;
     void                     *start_context;
-    void                     *conn_handler_context;
     sys_cond_t               *cond;
     sys_mutex_t              *lock;
-    qd_thread_t             **threads;
-    qd_work_list_t            work_queue;
-    qd_timer_list_t           pending_timers;
-    bool                      a_thread_is_waiting;
     int                       pause_requests;
     int                       threads_paused;
     int                       pause_next_sequence;
     int                       pause_now_serving;
-    qd_signal_handler_cb_t    signal_handler;
-    bool                      signal_handler_running;
-    void                     *signal_context;
-    int                       pending_signal;
-    qd_timer_t               *heartbeat_timer;
     uint64_t                 next_connection_id;
     void                     *py_displayname_obj;
     qd_http_server_t         *http;
 };
 
-/**
- * Listener objects represent the desire to accept incoming transport connections.
- */
-struct qd_listener_t {
-    qd_server_t              *server;
-    const qd_server_config_t *config;
-    void                     *context;
-    qdpn_listener_t          *pn_listener;
-    qd_http_listener_t       *http;
-};
-
-
-/**
- * Connector objects represent the desire to create and maintain an outgoing transport connection.
- */
-struct qd_connector_t {
-    qd_server_t              *server;
-    cxtr_state_t              state;
-    const qd_server_config_t *config;
-    void                     *context;
-    qd_connection_t          *ctx;
-    qd_timer_t               *timer;
-    long                      delay;
-};
-
-
-
-static __thread qd_server_t *thread_server = 0;
-
 #define HEARTBEAT_INTERVAL 1000
 
-ALLOC_DEFINE(qd_work_item_t);
 ALLOC_DEFINE(qd_listener_t);
 ALLOC_DEFINE(qd_connector_t);
 ALLOC_DEFINE(qd_deferred_call_t);
@@ -142,49 +87,32 @@ const char CERT_FINGERPRINT_SHA256 = '2';
 const char CERT_FINGERPRINT_SHA512 = '5';
 char *COMPONENT_SEPARATOR = ";";
 
-static void setup_ssl_sasl_and_open(qd_connection_t *ctx);
+static const int BACKLOG = 50;  /* Listening backlog */
 
-static qd_thread_t *thread(qd_server_t *qd_server, int id)
-{
-    qd_thread_t *thread = NEW(qd_thread_t);
-    if (!thread)
-        return 0;
-
-    thread->qd_server    = qd_server;
-    thread->thread_id    = id;
-    thread->running      = 0;
-    thread->canceled     = 0;
-    thread->using_thread = 0;
-
-    return thread;
-}
+static void setup_ssl_sasl_and_open(qd_connection_t *ctx);
 
-static void free_qd_connection(qd_connection_t *ctx)
-{
-    if (ctx->policy_settings) {
-        if (ctx->policy_settings->sources)
-            free(ctx->policy_settings->sources);
-        if (ctx->policy_settings->targets)
-            free(ctx->policy_settings->targets);
-        free (ctx->policy_settings);
-        ctx->policy_settings = 0;
-    }
-    if (ctx->pn_conn) {
-        pn_connection_set_context(ctx->pn_conn, 0);
-        pn_decref(ctx->pn_conn);
-        ctx->pn_conn = NULL;
-    }
-    if (ctx->collector) {
-        pn_collector_free(ctx->collector);
-        ctx->collector = NULL;
+/* Construct a new qd_connectoin. */
+static qd_connection_t *qd_connection(qd_server_t *server, const char *role) {
+    qd_connection_t *ctx = new_qd_connection_t();
+    if (!ctx) return NULL;
+    ZERO(ctx);
+    ctx->pn_conn       = pn_connection();
+    ctx->deferred_call_lock = sys_mutex();
+    ctx->role = strdup(role);
+    if (!ctx->pn_conn || !ctx->deferred_call_lock || !role) {
+        if (ctx->pn_conn) pn_connection_free(ctx->pn_conn);
+        if (ctx->deferred_call_lock) sys_mutex_free(ctx->deferred_call_lock);
+        free(ctx->role);
+        return NULL;
     }
-
-    if (ctx->free_user_id)
-        free((char*)ctx->user_id);
-
-    free(ctx->role);
-
-    free_qd_connection_t(ctx);
+    ctx->server        = server;
+    DEQ_ITEM_INIT(ctx);
+    DEQ_INIT(ctx->deferred_calls);
+    DEQ_INIT(ctx->free_link_session_list);
+    sys_mutex_lock(server->lock);
+    ctx->connection_id = server->next_connection_id++;
+    sys_mutex_unlock(server->lock);
+    return ctx;
 }
 
 /**
@@ -222,7 +150,7 @@ qd_error_t qd_register_display_name_service(qd_dispatch_t *qd, void *displayname
 static const char *transport_get_user(qd_connection_t *conn, pn_transport_t *tport)
 {
     const qd_server_config_t *config =
-            conn->connector ? conn->connector->config : conn->listener->config;
+            conn->connector ? &conn->connector->config : &conn->listener->config;
 
     if (config->ssl_uid_format) {
         // The ssl_uid_format length cannot be greater that 7
@@ -418,22 +346,6 @@ static const char *transport_get_user(qd_connection_t *conn, pn_transport_t *tpo
 }
 
 
-/**
- * Allocate a new qd_connection
- *  with DEQ items initialized, call lock allocated, and all other fields cleared.
- */
-static qd_connection_t *connection_allocate()
-{
-    qd_connection_t *ctx = new_qd_connection_t();
-    ZERO(ctx);
-    DEQ_ITEM_INIT(ctx);
-    DEQ_INIT(ctx->deferred_calls);
-    ctx->deferred_call_lock = sys_mutex();
-    DEQ_INIT(ctx->free_link_session_list);
-    return ctx;
-}
-
-
 void qd_connection_set_user(qd_connection_t *conn)
 {
     pn_transport_t *tport = pn_connection_transport(conn->pn_conn);
@@ -507,20 +419,6 @@ static qd_error_t listener_setup_ssl(qd_connection_t *ctx, const qd_server_confi
     return QD_ERROR_NONE;
 }
 
-// Format the identity of an incoming connection to buf for logging
-static const char *log_incoming(char *buf, size_t size, qdpn_connector_t *cxtr)
-{
-    qd_listener_t *qd_listener = qdpn_listener_context(qdpn_connector_listener(cxtr));
-    assert(qd_listener);
-    const char *cname = qdpn_connector_name(cxtr);
-    const char *host = qd_listener->config->host;
-    const char *port = qd_listener->config->port;
-    const char *protocol = qd_listener->config->http ? "HTTP" : "AMQP";
-    snprintf(buf, size, "incoming %s connection from %s to %s:%s",
-             protocol, cname, host, port);
-    return buf;
-}
-
 
 static void decorate_connection(qd_server_t *qd_server, pn_connection_t *conn, const qd_server_config_t *config)
 {
@@ -602,637 +500,383 @@ static void decorate_connection(qd_server_t *qd_server, pn_connection_t *conn, c
 }
 
 
-static void thread_process_listeners_LH(qd_server_t *qd_server)
+static void on_accept(pn_event_t *e)
 {
-    qdpn_driver_t    *driver = qd_server->driver;
-    qdpn_listener_t  *listener;
-    qdpn_connector_t *cxtr;
-    qd_connection_t  *ctx;
-
-    for (listener = qdpn_driver_listener(driver); listener; listener = qdpn_driver_listener(driver)) {
-        qd_listener_t *li = qdpn_listener_context(listener);
-        bool policy_counted = false;
-        cxtr = qdpn_listener_accept(listener, qd_server->qd->policy, &qd_policy_socket_accept, &policy_counted);
-        if (!cxtr)
-            continue;
-
-        char logbuf[qd_log_max_len()];
-
-        ctx = connection_allocate();
-        ctx->server        = qd_server;
-        ctx->owner_thread  = CONTEXT_UNSPECIFIED_OWNER;
-        ctx->pn_cxtr       = cxtr;
-        ctx->listener      = qdpn_listener_context(listener);
-        ctx->context       = ctx->listener->context;
-        ctx->connection_id = qd_server->next_connection_id++; // Increment the connection id so the next connection can use it
-        ctx->policy_counted = policy_counted;
-
-        // Copy the role from the listener config
-        int role_length    = strlen(ctx->listener->config->role) + 1;
-        ctx->role          = (char*) malloc(role_length);
-        strcpy(ctx->role, ctx->listener->config->role);
-
-        pn_connection_t *conn = pn_connection();
-        ctx->collector = pn_collector();
-        pn_connection_collect(conn, ctx->collector);
-        decorate_connection(qd_server, conn, ctx->listener->config);
-        qdpn_connector_set_connection(cxtr, conn);
-        pn_connection_set_context(conn, ctx);
-        ctx->pn_conn = conn;
-        ctx->owner_thread = CONTEXT_NO_OWNER;
-        qdpn_connector_set_context(cxtr, ctx);
-
-        qd_log(qd_server->log_source, QD_LOG_INFO, "Accepting %s with connection id [%"PRIu64"]",
-           log_incoming(logbuf, sizeof(logbuf), cxtr), ctx->connection_id);
+    assert(pn_event_type(e) == PN_LISTENER_ACCEPT);
+    pn_listener_t *pn_listener = pn_event_listener(e);
+    qd_listener_t *listener = pn_listener_get_context(pn_listener);
+    qd_connection_t *ctx = qd_connection(listener->server, listener->config.role);
+    if (!ctx) {
+        qd_log(listener->server->log_source, QD_LOG_CRITICAL,
+               "Allocation failure during accept to %s", listener->config.host_port);
+        return;
+    }
+    pn_connection_set_context(ctx->pn_conn, ctx);
+    ctx->listener = listener;
+    decorate_connection(listener->server, ctx->pn_conn, &ctx->listener->config);
+    qd_log(listener->server->log_source, QD_LOG_TRACE,
+           "[%"PRIu64"] Accepting incoming connection from %s to %s",
+           ctx->connection_id, qd_connection_name(ctx), ctx->listener->config.host_port);
+    /* Asynchronous accept, configure the transport on PN_CONNECTION_BOUND */
+    pn_listener_accept(pn_listener, ctx->pn_conn);
+ }
+
+
+/* Log the description, set the transport condition (name, description) close the transport tail. */
+void connect_fail(qd_connection_t *ctx, const char *name, const char *description, ...)
+{
+    va_list ap;
+    va_start(ap, description);
+    qd_verror(QD_ERROR_RUNTIME, description, ap);
+    va_end(ap);
+    if (ctx->pn_conn) {
+        pn_transport_t *t = pn_connection_transport(ctx->pn_conn);
+        /* Normally this is closing the transport but if not bound close the connection. */
+        pn_condition_t *cond = t ? pn_transport_condition(t) : pn_connection_condition(ctx->pn_conn);
+        if (cond && !pn_condition_is_set(cond)) {
+            va_start(ap, description);
+            pn_condition_vformat(cond, name, description, ap);
+            va_end(ap);
+        }
+        if (t) {
+            pn_transport_close_tail(t);
+        } else {
+            pn_connection_close(ctx->pn_conn);
+        }
+    }
+}
 
-        //
-        // Get a pointer to the transport so we can insert security components into it
-        //
-        pn_transport_t           *tport  = qdpn_connector_transport(cxtr);
-        const qd_server_config_t *config = ctx->listener->config;
 
-        //
-        // Configure the transport.
-        //
+/* Get the host IP address for the remote end */
+static int set_remote_host_port(qd_connection_t *ctx) {
+    pn_transport_t *tport  = pn_connection_transport(ctx->pn_conn);
+    const struct sockaddr_storage* addr = pn_proactor_addr_sockaddr(pn_proactor_addr_remote(tport));
+    int err = 0;
+    if (!addr) {
+        err = -1;
+        qd_log(ctx->server->log_source, QD_LOG_ERROR, "No remote address for connection to %s");
+    } else {
+        char rport[NI_MAXSERV] = "";
+        int err = getnameinfo((struct sockaddr*)addr, sizeof(*addr),
+                              ctx->rhost, sizeof(ctx->rhost), rport, sizeof(rport),
+                              NI_NUMERICHOST | NI_NUMERICSERV);
+        if (!err) {
+            snprintf(ctx->rhost_port, sizeof(ctx->rhost_port), "%s:%s", ctx->rhost, rport);
+        } else {
+            qd_log(ctx->server->log_source, QD_LOG_ERROR, "No remote address for connection to %s");
+        }
+    }
+    return err;
+}
+
+
+/* Configure the transport once it is bound to the connection */
+static void on_connection_bound(qd_server_t *server, pn_event_t *e) {
+    pn_connection_t *pn_conn = pn_event_connection(e);
+    qd_connection_t *ctx = pn_connection_get_context(pn_conn);
+    pn_transport_t *tport  = pn_connection_transport(pn_conn);
+    pn_transport_set_context(tport, ctx); /* for transport_tracer */
+
+    //
+    // Proton pushes out its trace to transport_tracer() which in turn writes a trace
+    // message to the qdrouter log If trace level logging is enabled on the router set
+    // PN_TRACE_DRV | PN_TRACE_FRM | PN_TRACE_RAW on the proton transport
+    //
+    if (qd_log_enabled(ctx->server->log_source, QD_LOG_TRACE)) {
+        pn_transport_trace(tport, PN_TRACE_FRM);
+        pn_transport_set_tracer(tport, transport_tracer);
+    }
+
+    const qd_server_config_t *config = NULL;
+    if (ctx->listener) {        /* Accepting an incoming connection */
+        config = &ctx->listener->config;
+        const char *name = config->host_port;
         pn_transport_set_server(tport);
-        pn_transport_set_max_frame(tport, config->max_frame_size);
-        pn_transport_set_channel_max(tport, config->max_sessions - 1);
-        pn_transport_set_idle_timeout(tport, config->idle_timeout_seconds * 1000);
 
-        //
-        // Proton pushes out its trace to transport_tracer() which in turn writes a trace message to the qdrouter log
-        // If trace level logging is enabled on the router set PN_TRACE_DRV | PN_TRACE_FRM | PN_TRACE_RAW on the proton transport
-        //
-        pn_transport_set_context(tport, ctx);
-        if (qd_log_enabled(qd_server->log_source, QD_LOG_TRACE)) {
-            pn_transport_trace(tport, PN_TRACE_FRM);
-            pn_transport_set_tracer(tport, transport_tracer);
+        if (set_remote_host_port(ctx) == 0 &&
+            qd_policy_socket_accept(server->qd->policy, ctx->rhost))
+        {
+            ctx->policy_counted = true;
+        } else {
+            pn_transport_close_tail(tport);
+            pn_transport_close_head(tport);
+            return;
         }
 
-        if (li->http) {
-            // Set up HTTP if configured, HTTP provides its own SSL.
-            qd_log(qd_server->log_source, QD_LOG_TRACE, "Configuring HTTP%s on %s",
-                   config->ssl_profile ? "S" : "",
-                   log_incoming(logbuf, sizeof(logbuf), cxtr));
-            qd_http_listener_accept(li->http, cxtr);
-        } else if (config->ssl_profile)  {
-            // Set up SSL if configured and HTTP is not providing SSL.
-            qd_log(qd_server->log_source, QD_LOG_TRACE, "Configuring SSL on %s",
-                   log_incoming(logbuf, sizeof(logbuf), cxtr));
+        // Set up SSL
+        if (config->ssl_profile)  {
+            qd_log(ctx->server->log_source, QD_LOG_TRACE, "Configuring SSL on %s", name);
             if (listener_setup_ssl(ctx, config, tport) != QD_ERROR_NONE) {
-                qd_log(qd_server->log_source, QD_LOG_ERROR, "%s on %s",
-                       qd_error_message(), log_incoming(logbuf, sizeof(logbuf), cxtr));
-                qdpn_connector_close(cxtr);
-                continue;
+                connect_fail(ctx, QD_AMQP_COND_INTERNAL_ERROR, "%s on %s", qd_error_message(), name);
+                return;
             }
         }
-
         //
         // Set up SASL
         //
+        sys_mutex_lock(ctx->server->lock);
         pn_sasl_t *sasl = pn_sasl(tport);
-        if (qd_server->sasl_config_path)
-            pn_sasl_config_path(sasl, qd_server->sasl_config_path);
-        pn_sasl_config_name(sasl, qd_server->sasl_config_name);
+        if (ctx->server->sasl_config_path)
+            pn_sasl_config_path(sasl, ctx->server->sasl_config_path);
+        pn_sasl_config_name(sasl, ctx->server->sasl_config_name);
         if (config->sasl_mechanisms)
             pn_sasl_allowed_mechs(sasl, config->sasl_mechanisms);
         pn_transport_require_auth(tport, config->requireAuthentication);
         pn_transport_require_encryption(tport, config->requireEncryption);
         pn_sasl_set_allow_insecure_mechs(sasl, config->allowInsecureAuthentication);
+        sys_mutex_unlock(ctx->server->lock);
+
+        qd_log(ctx->server->log_source, QD_LOG_INFO, "Accepted connection to %s from %s",
+               name, ctx->rhost_port);
+    } else if (ctx->connector) { /* Establishing an outgoing connection */
+        config = &ctx->connector->config;
+        setup_ssl_sasl_and_open(ctx);
+    } else {                    /* No connector and no listener */
+        connect_fail(ctx, QD_AMQP_COND_INTERNAL_ERROR, "unknown Connection");
+        return;
     }
-}
-
-
-static void handle_signals_LH(qd_server_t *qd_server)
-{
-    int signum = qd_server->pending_signal;
-
-    if (signum && !qd_server->signal_handler_running) {
-        qd_server->signal_handler_running = true;
-        qd_server->pending_signal = 0;
-        if (qd_server->signal_handler) {
-            sys_mutex_unlock(qd_server->lock);
-            qd_server->signal_handler(qd_server->signal_context, signum);
-            sys_mutex_lock(qd_server->lock);
-        }
-        qd_server->signal_handler_running = false;
-    }
-}
-
 
-static void block_if_paused_LH(qd_server_t *qd_server)
-{
-    if (qd_server->pause_requests > 0) {
-        qd_server->threads_paused++;
-        sys_cond_signal_all(qd_server->cond);
-        while (qd_server->pause_requests > 0)
-            sys_cond_wait(qd_server->cond, qd_server->lock);
-        qd_server->threads_paused--;
-    }
+    //
+    // Common transport configuration.
+    //
+    pn_transport_set_max_frame(tport, config->max_frame_size);
+    pn_transport_set_channel_max(tport, config->max_sessions - 1);
+    pn_transport_set_idle_timeout(tport, config->idle_timeout_seconds * 1000);
 }
 
 
 static void invoke_deferred_calls(qd_connection_t *conn, bool discard)
 {
-    qd_deferred_call_list_t  calls;
-    qd_deferred_call_t      *dc;
-
-    //
-    // Copy the deferred calls out of the connection under lock.
+    // Lock access to deferred_calls, other threads may concurrently add to it.  Invoke
+    // the calls outside of the critical section.
     //
-    DEQ_INIT(calls);
     sys_mutex_lock(conn->deferred_call_lock);
-    dc = DEQ_HEAD(conn->deferred_calls);
-    while (dc) {
+    qd_deferred_call_t *dc;
+    while ((dc = DEQ_HEAD(conn->deferred_calls))) {
         DEQ_REMOVE_HEAD(conn->deferred_calls);
-        DEQ_INSERT_TAIL(calls, dc);
-        dc = DEQ_HEAD(conn->deferred_calls);
-    }
-    sys_mutex_unlock(conn->deferred_call_lock);
-
-    //
-    // Invoke the calls outside of the critical section.
-    //
-    dc = DEQ_HEAD(calls);
-    while (dc) {
-        DEQ_REMOVE_HEAD(calls);
+        sys_mutex_unlock(conn->deferred_call_lock);
         dc->call(dc->context, discard);
         free_qd_deferred_call_t(dc);
-        dc = DEQ_HEAD(calls);
+        sys_mutex_lock(conn->deferred_call_lock);
     }
+    sys_mutex_unlock(conn->deferred_call_lock);
 }
 
-
-static int process_connector(qd_server_t *qd_server, qdpn_connector_t *cxtr)
-{
-    qd_connection_t *ctx = qdpn_connector_context(cxtr);
-    int events = 0;
-    int passes = 0;
-
-    if (ctx->closed)
-        return 0;
-
-    do {
-        passes++;
-
-        //
-        // If this connection is outbound and is just now opening, do the initial SSL/SASL setup
-        //
-        if (!ctx->opened && !!ctx->connector && !qdpn_connector_closed(cxtr))
-            setup_ssl_sasl_and_open(ctx);
-
-        //
-        // Step the engine for pre-handler processing
-        //
-        qdpn_connector_process(cxtr);
-
-        //
-        // If the connector has closed, notify the client via callback.
-        //
-        if (qdpn_connector_closed(cxtr)) {
-            if (ctx->opened)
-                qd_server->conn_handler(qd_server->conn_handler_context, ctx->context,
-                                        QD_CONN_EVENT_CLOSE,
-                                        (qd_connection_t*) qdpn_connector_context(cxtr));
-            ctx->closed = true;
-            events = 0;
-            break;
-        }
-
-        invoke_deferred_calls(ctx, false);
-
-        qd_connection_t *qd_conn   = (qd_connection_t*) qdpn_connector_context(cxtr);
-        pn_collector_t  *collector = qd_connection_collector(qd_conn);
-        pn_event_t      *event;
-
-        events = 0;
-        if (!ctx->event_stall) {
-            event = pn_collector_peek(collector);
-            while (event) {
-                //
-                // If we are transitioning to the open state, notify the client via callback.
-                //
-                if (!ctx->opened && pn_event_type(event) == PN_CONNECTION_REMOTE_OPEN) {
-                    ctx->opened = true;
-                    if (ctx->connector) {
-                        ctx->connector->delay = 2000;  // Delay on re-connect in case there is a recurring error
-                    } else
-                        assert(ctx->listener);
-                    events = 1;
-                } else if (pn_event_type(event) == PN_TRANSPORT_ERROR) {
-                    if (ctx->connector) {
-                        const qd_server_config_t *config = ctx->connector->config;
-                        qd_log(qd_server->log_source, QD_LOG_TRACE, "Connection to %s:%s failed", config->host, config->port);
-                    }
-                }
-
-                events += qd_server->pn_event_handler(qd_server->conn_handler_context, ctx->context, event, qd_conn);
-                pn_collector_pop(collector);
-
-                event = ctx->event_stall ? 0 : pn_collector_peek(collector);
+void qd_container_handle_event(qd_container_t *container, pn_event_t *event);
+
+static void handle_listener(pn_event_t *e, qd_server_t *qd_server) {
+    qd_log_source_t *log = qd_server->log_source;
+
+    /* FIXME aconway 2017-02-20: HTTP support */
+    qd_listener_t *li = (qd_listener_t*) pn_listener_get_context(pn_event_listener(e));
+    const char *host_port = li->config.host_port;
+    switch (pn_event_type(e)) {
+
+    case PN_LISTENER_OPEN:
+        qd_log(log, QD_LOG_NOTICE, "Listening on %s", host_port);
+        break;
+
+    case PN_LISTENER_ACCEPT:
+        qd_log(log, QD_LOG_INFO, "Accepting connection on %s", host_port);
+        on_accept(e);
+        break;
+
+    case PN_LISTENER_CLOSE: {
+        pn_condition_t *cond = pn_listener_condition(li->pn_listener);
+        if (pn_condition_is_set(cond)) {
+            qd_log(log, QD_LOG_ERROR, "Listener error on %s: %s (%s)", host_port,
+                   pn_condition_get_description(cond),
+                   pn_condition_get_name(cond));
+            if (li->exit_on_error) {
+                qd_log(log, QD_LOG_CRITICAL, "Shutting down, required listener failed %s",
+                       host_port);
+                exit(1);
             }
-
-            //
-            // Free up any links and sessions that need to be freed since all the events have been popped from the collector.
-            //
-            qd_server->pn_event_complete_handler(qd_server->conn_handler_context, qd_conn);
-            events += qd_server->conn_handler(qd_server->conn_handler_context, ctx->context, QD_CONN_EVENT_WRITABLE, qd_conn);
+        } else {
+            qd_log(log, QD_LOG_TRACE, "Listener closed on %s", host_port);
         }
-    } while (events > 0);
-
-    return passes > 1;
+        qd_listener_decref(li);
+        break;
+    }
+    default:
+        break;
+    }
 }
 
 
-//
-// TEMPORARY FUNCTION PROTOTYPES
-//
-void qdpn_driver_wait_1(qdpn_driver_t *d);
-int  qdpn_driver_wait_2(qdpn_driver_t *d, int timeout);
-void qdpn_driver_wait_3(qdpn_driver_t *d);
-//
-// END TEMPORARY
-//
-
-static void *thread_run(void *arg)
+static void qd_connection_free(qd_connection_t *ctx)
 {
-    qd_thread_t      *thread    = (qd_thread_t*) arg;
-    qd_work_item_t   *work;
-    qdpn_connector_t *cxtr;
-    qd_connection_t  *ctx;
-    int               error;
-    int               poll_result;
-
-    if (!thread)
-        return 0;
+    qd_server_t *qd_server = ctx->server;
 
-    qd_server_t      *qd_server = thread->qd_server;
-    thread_server   = qd_server;
-    thread->running = 1;
+    qd_entity_cache_remove(QD_CONNECTION_TYPE, ctx); /* Removed management entity */
 
-    if (thread->canceled)
-        return 0;
-
-    //
-    // Main Loop
-    //
-    while (thread->running) {
-        sys_mutex_lock(qd_server->lock);
-
-        //
-        // Check for pending signals to process
-        //
-        handle_signals_LH(qd_server);
-        if (!thread->running) {
-            sys_mutex_unlock(qd_server->lock);
-            break;
-        }
-
-        //
-        // Check to see if the server is pausing.  If so, block here.
-        //
-        block_if_paused_LH(qd_server);
-        if (!thread->running) {
-            sys_mutex_unlock(qd_server->lock);
-            break;
-        }
-
-        //
-        // Service pending timers.
-        //
-        qd_timer_t *timer = DEQ_HEAD(qd_server->pending_timers);
-        if (timer) {
-            DEQ_REMOVE_HEAD(qd_server->pending_timers);
-
-            //
-            // Mark the timer as idle in case it reschedules itself.
-            //
-            qd_timer_idle_LH(timer);
+    // If this is a dispatch connector, schedule the re-connect timer
+    if (ctx->connector) {
+        sys_mutex_lock(ctx->connector->lock);
+        ctx->connector->ctx = 0;
+        ctx->connector->state = CXTR_STATE_CONNECTING;
+        sys_mutex_unlock(ctx->connector->lock);
+        qd_timer_schedule(ctx->connector->timer, ctx->connector->delay);
+    }
 
-            //
-            // Release the lock and invoke the connection handler.
-            //
-            sys_mutex_unlock(qd_server->lock);
-            timer->handler(timer->context);
-            qdpn_driver_wakeup(qd_server->driver);
-            continue;
-        }
+    // If counted for policy enforcement, notify it has closed
+    sys_mutex_lock(qd_server->lock);
+    if (ctx->policy_counted) {
+        qd_policy_socket_close(qd_server->qd->policy, ctx);
+    }
+    sys_mutex_unlock(qd_server->lock);
 
-        //
-        // Check the work queue for connectors scheduled for processing.
-        //
-        work = DEQ_HEAD(qd_server->work_queue);
-        if (!work) {
-            //
-            // There is no pending work to do
-            //
-            if (qd_server->a_thread_is_waiting) {
-                //
-                // Another thread is waiting on the proton driver, this thread must
-                // wait on the condition variable until signaled.
-                //
-                sys_cond_wait(qd_server->cond, qd_server->lock);
-            } else {
-                //
-                // This thread elects itself to wait on the proton driver.  Set the
-                // thread-is-waiting flag so other idle threads will not interfere.
-                //
-                qd_server->a_thread_is_waiting = true;
-
-                //
-                // Ask the timer module when its next timer is scheduled to fire.  We'll
-                // use this value in driver_wait as the timeout.  If there are no scheduled
-                // timers, the returned value will be -1.
-                //
-                qd_timestamp_t duration = qd_timer_next_duration_LH();
-
-                //
-                // Invoke the proton driver's wait sequence.  This is a bit of a hack for now
-                // and will be improved in the future.  The wait process is divided into three parts,
-                // the first and third of which need to be non-reentrant, and the second of which
-                // must be reentrant (and blocks).
-                //
-                qdpn_driver_wait_1(qd_server->driver);
-                sys_mutex_unlock(qd_server->lock);
-
-                do {
-                    error = 0;
-                    poll_result = qdpn_driver_wait_2(qd_server->driver, duration);
-                    if (poll_result == -1)
-                        error = errno;
-                } while (error == EINTR);
-                if (error) {
-                    exit(-1);
-                }
+    invoke_deferred_calls(ctx, true);  // Discard any pending deferred calls
+    if (ctx->deferred_call_lock)
+        sys_mutex_free(ctx->deferred_call_lock);
 
-                sys_mutex_lock(qd_server->lock);
-                qdpn_driver_wait_3(qd_server->driver);
+    if (ctx->policy_settings) {
+        if (ctx->policy_settings->sources)
+            free(ctx->policy_settings->sources);
+        if (ctx->policy_settings->targets)
+            free(ctx->policy_settings->targets);
+        free (ctx->policy_settings);
+        ctx->policy_settings = 0;
+    }
 
-                if (!thread->running) {
-                    sys_mutex_unlock(qd_server->lock);
-                    break;
-                }
+    if (ctx->free_user_id) free((char*)ctx->user_id);
+    free(ctx->role);
+    free_qd_connection_t(ctx);
 
-                //
-                // Visit the timer module.
-                //
-                struct timespec tv;
-                clock_gettime(CLOCK_REALTIME, &tv);
-                qd_timestamp_t milliseconds = ((qd_timestamp_t)tv.tv_sec) * 1000 + tv.tv_nsec / 1000000;
-                qd_timer_visit_LH(milliseconds);
-
-                //
-                // Process listeners (incoming connections).
-                //
-                thread_process_listeners_LH(qd_server);
-
-                //
-                // Traverse the list of connectors-needing-service from the proton driver.
-                // If the connector is not already in the work queue and it is not currently
-                // being processed by another thread, put it in the work queue and signal the
-                // condition variable.
-                //
-                cxtr = qdpn_driver_connector(qd_server->driver);
-                while (cxtr) {
-                    ctx = qdpn_connector_context(cxtr);
-                    if (!ctx->enqueued && ctx->owner_thread == CONTEXT_NO_OWNER) {
-                        ctx->enqueued = 1;
-                        qd_work_item_t *workitem = new_qd_work_item_t();
-                        DEQ_ITEM_INIT(workitem);
-                        workitem->cxtr = cxtr;
-                        DEQ_INSERT_TAIL(qd_server->work_queue, workitem);
-                        sys_cond_signal(qd_server->cond);
-                    }
-                    cxtr = qdpn_driver_connector(qd_server->driver);
-                }
+    /* Note: pn_conn is freed by the proactor */
+}
 
-                //
-                // Release our exclusive claim on qdpn_driver_wait.
-                //
-                qd_server->a_thread_is_waiting = false;
-            }
-        }
 
-        //
-        // If we were given a connector to work on from the work queue, mark it as
-        // owned by this thread and as no longer enqueued.
-        //
-        cxtr = 0;
-        if (work) {
-            DEQ_REMOVE_HEAD(qd_server->work_queue);
-            ctx = qdpn_connector_context(work->cxtr);
-            if (ctx->owner_thread == CONTEXT_NO_OWNER) {
-                ctx->owner_thread = thread->thread_id;
-                ctx->enqueued = 0;
-                cxtr = work->cxtr;
-                free_qd_work_item_t(work);
-            } else {
-                //
-                // This connector is being processed by another thread, re-queue it.
-                //
-                DEQ_INSERT_TAIL(qd_server->work_queue, work);
+/* Events involving a connection or listener are serialized by the proactor so
+ * only one event per connection / listener will be processed at a time.
+ */
+static bool handle(pn_event_t *e, qd_server_t *qd_server) {
+    pn_connection_t *pn_conn = pn_event_connection(e);
+    qd_connection_t *ctx  = pn_conn ? (qd_connection_t*) pn_connection_get_context(pn_conn) : NULL;
+
+    switch (pn_event_type(e)) {
+
+    case PN_PROACTOR_INTERRUPT:
+        /* Stop the current thread */
+        return false;
+
+    case PN_PROACTOR_TIMEOUT:
+        qd_timer_visit();
+        break;
+
+    case PN_LISTENER_OPEN:
+    case PN_LISTENER_ACCEPT:
+    case PN_LISTENER_CLOSE:
+        handle_listener(e, qd_server);
+        break;
+
+    case PN_CONNECTION_BOUND:
+        on_connection_bound(qd_server, e);
+        break;
+
+    case PN_CONNECTION_REMOTE_OPEN:
+        // If we are transitioning to the open state, notify the client via callback.
+        if (!ctx->opened) {
+            ctx->opened = true;
+            if (ctx->connector) {
+                ctx->connector->delay = 2000;  // Delay re-connect in case there is a recurring error
             }
         }
-        sys_mutex_unlock(qd_server->lock);
-
-        //
-        // Process the connector that we now have exclusive access to.
-        //
-        if (cxtr) {
-            int work_done = 1;
-
-            if (qdpn_connector_failed(cxtr))
-                qdpn_connector_close(cxtr);
-
-            //
-            // Even if the connector has failed there are still events that 
-            // must be processed so that associated links will be cleaned up.
-            //
-            work_done = process_connector(qd_server, cxtr);
+        break;
 
-            //
-            // Check to see if the connector was closed during processing
-            //
-            if (qdpn_connector_closed(cxtr)) {
-                qd_entity_cache_remove(QD_CONNECTION_TYPE, ctx);
-                //
-                // Connector is closed.  Free the context and the connector.
-                // If this is a dispatch connector, schedule the re-connect timer
-                //
-                if (ctx->connector) {
-                    ctx->connector->ctx = 0;
-                    ctx->connector->state = CXTR_STATE_CONNECTING;
-                    qd_timer_schedule(ctx->connector->timer, ctx->connector->delay);
-                }
-
-                sys_mutex_lock(qd_server->lock);
-
-                if (ctx->policy_counted) {
-                    qd_policy_socket_close(qd_server->qd->policy, ctx);
-                }
-
-                invoke_deferred_calls(ctx, true);  // Discard any pending deferred calls
-                sys_mutex_free(ctx->deferred_call_lock);
-                qdpn_connector_free(cxtr);
-                free_qd_connection(ctx);
-                sys_mutex_unlock(qd_server->lock);
-            } else {
-                //
-                // The connector lives on.  Mark it as no longer owned by this thread.
-                //
-                sys_mutex_lock(qd_server->lock);
-                ctx->owner_thread = CONTEXT_NO_OWNER;
-                sys_mutex_unlock(qd_server->lock);
-            }
+    case PN_CONNECTION_WAKE:
+        invoke_deferred_calls(ctx, false);
+        break;
 
-            //
-            // Wake up the proton driver to force it to reconsider its set of FDs
-            // in light of the processing that just occurred.
-            //
-            if (work_done)
-                qdpn_driver_wakeup(qd_server->driver);
+    case PN_TRANSPORT_ERROR:
+        if (ctx && ctx->connector) { /* Outgoing connection */
+            const qd_server_config_t *config = &ctx->connector->config;
+            qd_log(qd_server->log_source, QD_LOG_TRACE, "Connection to %s failed", config->host_port);
         }
-    }
-
-    return 0;
-}
-
-
-static void thread_start(qd_thread_t *thread)
-{
-    if (!thread)
-        return;
-
-    thread->using_thread = 1;
-    thread->thread = sys_thread(thread_run, (void*) thread);
-}
-
-
-static void thread_cancel(qd_thread_t *thread)
-{
-    if (!thread)
-        return;
-
-    thread->running  = 0;
-    thread->canceled = 1;
-}
+        break;
 
+    default:
+        break;
+    } // Switch event type
 
-static void thread_join(qd_thread_t *thread)
-{
-    if (!thread)
-        return;
+    /* TODO aconway 2017-04-18: fold the container handler into the server */
+    qd_container_handle_event(qd_server->container, e);
 
-    if (thread->using_thread) {
-        sys_thread_join(thread->thread);
-        sys_thread_free(thread->thread);
+    /* Free the connection after all other processing */
+    if (ctx && pn_event_type(e) == PN_TRANSPORT_CLOSED) {
+        pn_connection_set_context(pn_conn, NULL);
+        qd_connection_free(ctx);
     }
+    return true;
 }
 
-
-static void thread_free(qd_thread_t *thread)
+static void *thread_run(void *arg)
 {
-    if (!thread)
-        return;
-
-    free(thread);
+    qd_server_t      *qd_server = (qd_server_t*)arg;
+    bool running = true;
+    while (running) {
+        pn_event_batch_t *events = pn_proactor_wait(qd_server->proactor);
+        pn_event_t * e;
+        while (running && (e = pn_event_batch_next(events))) {
+            running = handle(e, qd_server);
+        }
+        pn_proactor_done(qd_server->proactor, events);
+    }
+    return NULL;
 }
 
 
-static void cxtr_try_open(void *context)
+/* Timer callback to try/retry connection open */
+static void try_open_lh(qd_connector_t *ct)
 {
-    qd_connector_t *ct = (qd_connector_t*) context;
-    if (ct->state != CXTR_STATE_CONNECTING)
+    if (ct->state != CXTR_STATE_CONNECTING) {
+        /* No longer referenced by pn_connection or timer */
+        qd_connector_decref(ct);
         return;
+    }
 
-    qd_connection_t *ctx = connection_allocate();
-    ctx->server       = ct->server;
-    ctx->owner_thread = CONTEXT_UNSPECIFIED_OWNER;
-    ctx->pn_conn      = pn_connection();
-    ctx->collector    = pn_collector();
-    ctx->connector    = ct;
-    ctx->context      = ct->context;
-
-    // Copy the role from the connector config
-    int role_length    = strlen(ctx->connector->config->role) + 1;
-    ctx->role          = (char*) malloc(role_length);
-    strcpy(ctx->role, ctx->connector->config->role);
-
-    qd_log(ct->server->log_source, QD_LOG_INFO, "Connecting to %s:%s", ct->config->host, ct->config->port);
-
-    pn_connection_collect(ctx->pn_conn, ctx->collector);
-    decorate_connection(ctx->server, ctx->pn_conn, ct->config);
-
-    //
-    // qdpn_connector is not thread safe
-    //
-    sys_mutex_lock(ct->server->lock);
-    // Increment the connection id so the next connection can use it
-    ctx->connection_id = ct->server->next_connection_id++;
-    ctx->pn_cxtr = qdpn_connector(ct->server->driver, ct->config->host, ct->config->port, ct->config->protocol_family, (void*) ctx);
-    sys_mutex_unlock(ct->server->lock);
-
-    const qd_server_config_t *config = ct->config;
-
-    if (ctx->pn_cxtr == 0) {
-        sys_mutex_free(ctx->deferred_call_lock);
-        free_qd_connection(ctx);
+    qd_connection_t *ctx = qd_connection(ct->server, ct->config.role);
+    if (!ctx) {                 /* Try again later */
+        qd_log(ct->server->log_source, QD_LOG_CRITICAL, "Allocation failure connecting to %s",
+               ct->config.host_port);
         ct->delay = 10000;
         qd_timer_schedule(ct->timer, ct->delay);
         return;
     }
+    ctx->connector    = ct;
+    decorate_connection(ctx->server, ctx->pn_conn, &ct->config);
+    const qd_server_config_t *config = &ct->config;
 
     //
-    // Set the hostname on the pn_connection. This hostname will be used by proton as the hostname in the open frame.
+    // Set the hostname on the pn_connection. This hostname will be used by proton as the
+    // hostname in the open frame.
     //
     pn_connection_set_hostname(ctx->pn_conn, config->host);
 
-    // Set the sasl user name and password on the proton connection object. This has to be done before the call to qdpn_connector_transport() which
-    // binds the transport to the connection
+    // Set the sasl user name and password on the proton connection object. This has to be
+    // done before pn_proactor_connect which will bind a transport to the connection
     if(config->sasl_username)
         pn_connection_set_user(ctx->pn_conn, config->sasl_username);
     if (config->sasl_password)
         pn_connection_set_password(ctx->pn_conn, config->sasl_password);
 
-    qdpn_connector_set_connection(ctx->pn_cxtr, ctx->pn_conn);
     pn_connection_set_context(ctx->pn_conn, ctx);
 
     ctx->connector->state = CXTR_STATE_OPEN;
-
     ct->ctx   = ctx;
     ct->delay = 5000;
 
-    //
-    // Set up the transport, SASL, and SSL for the connection.
-    //
-    pn_transport_t *tport  = qdpn_connector_transport(ctx->pn_cxtr);
-
-    //
-    // Configure the transport
-    //
-    pn_transport_set_max_frame(tport, config->max_frame_size);
-    pn_transport_set_channel_max(tport, config->max_sessions - 1);
-    pn_transport_set_idle_timeout(tport, config->idle_timeout_seconds * 1000);
-
-    //
-    // Proton pushes out its trace to transport_tracer() which in turn writes a trace message to the qdrouter log
-    //
-    // If trace level logging is enabled on the router set PN_TRACE_DRV | PN_TRACE_FRM | PN_TRACE_RAW on the proton transport
-    pn_transport_set_context(tport, ctx);
-    if (qd_log_enabled(ct->server->log_source, QD_LOG_TRACE)) {
-        pn_transport_trace(tport, PN_TRACE_FRM);
-        pn_transport_set_tracer(tport, transport_tracer);
-    }
-
-    ctx->owner_thread = CONTEXT_NO_OWNER;
+    qd_log(ct->server->log_source, QD_LOG_TRACE,
+           "[%"PRIu64"] Connecting to %s", ctx->connection_id, config->host_port);
+    /* Note: the transport is configured in the PN_CONNECTION_BOUND event */
+    pn_proactor_connect(ct->server->proactor, ctx->pn_conn, config->host_port);
 }
 
-
 static void setup_ssl_sasl_and_open(qd_connection_t *ctx)
 {
     qd_connector_t *ct = ctx->connector;
-    const qd_server_config_t *config = ct->config;
-    pn_transport_t *tport  = qdpn_connector_transport(ctx->pn_cxtr);
+    const qd_server_config_t *config = &ct->config;
+    pn_transport_t *tport  = pn_connection_transport(ctx->pn_conn);
 
     //
     // Set up SSL if appropriate
@@ -1242,19 +886,16 @@ static void setup_ssl_sasl_and_open(qd_connection_t *ctx)
 
         if (!domain) {
             qd_error(QD_ERROR_RUNTIME, "SSL domain failed for connection to %s:%s",
-                     ct->config->host, ct->config->port);
-            /* TODO aconway 2014-07-15: Close the connection, clean up. */
+                     ct->config.host, ct->config.port);
             return;
         }
 
-        /* TODO aconway 2014-07-15: error handling on all SSL calls. */
-
         // set our trusted database for checking the peer's cert:
         if (config->ssl_trusted_certificate_db) {
             if (pn_ssl_domain_set_trusted_ca_db(domain, config->ssl_trusted_certificate_db)) {
                 qd_log(ct->server->log_source, QD_LOG_ERROR,
                        "SSL CA configuration failed for %s:%s",
-                       ct->config->host, ct->config->port);
+                       ct->config.host, ct->config.port);
             }
         }
         // should we force the peer to provide a cert?
@@ -1267,7 +908,7 @@ static void setup_ssl_sasl_and_open(qd_connection_t *ctx)
                                                       trusted)) {
                 qd_log(ct->server->log_source, QD_LOG_ERROR,
                        "SSL peer auth configuration failed for %s:%s",
-                       ct->config->host, ct->config->port);
+                       config->host, config->port);
             }
         }
 
@@ -1279,7 +920,7 @@ static void setup_ssl_sasl_and_open(qd_connection_t *ctx)
                                               config->ssl_password)) {
                 qd_log(ct->server->log_source, QD_LOG_ERROR,
                        "SSL local configuration failed for %s:%s",
-                       ct->config->host, ct->config->port);
+                       config->host, config->port);
             }
         }
 
@@ -1288,7 +929,7 @@ static void setup_ssl_sasl_and_open(qd_connection_t *ctx)
             if (pn_ssl_domain_set_peer_authentication(domain, PN_SSL_VERIFY_PEER_NAME, NULL)) {
                     qd_log(ct->server->log_source, QD_LOG_ERROR,
                            "SSL peer host name verification failed for %s:%s",
-                           ct->config->host, ct->config->port);
+                           config->host, config->port);
             }
         }
 
@@ -1310,58 +951,46 @@ static void setup_ssl_sasl_and_open(qd_connection_t *ctx)
     pn_connection_open(ctx->pn_conn);
 }
 
-
-static void heartbeat_cb(void *context)
-{
-    qd_server_t *qd_server = (qd_server_t*) context;
-    qdpn_activate_all(qd_server->driver);
-    qd_timer_schedule(qd_server->heartbeat_timer, HEARTBEAT_INTERVAL);
+static void try_open_cb(void *context) {
+    qd_connector_t *ct = (qd_connector_t*) context;
+    sys_mutex_lock(ct->lock);
+    try_open_lh(ct);
+    sys_mutex_unlock(ct->lock);
 }
 
 
 qd_server_t *qd_server(qd_dispatch_t *qd, int thread_count, const char *container_name,
                        const char *sasl_config_path, const char *sasl_config_name)
 {
-    int i;
-
+    /* Initialize const members, 0 initialize all others. */
+    qd_server_t tmp = { .thread_count = thread_count };
     qd_server_t *qd_server = NEW(qd_server_t);
     if (qd_server == 0)
         return 0;
+    memcpy(qd_server, &tmp, sizeof(tmp));
 
     qd_server->qd               = qd;
     qd_server->log_source       = qd_log_source("SERVER");
-    qd_server->thread_count     = thread_count;
     qd_server->container_name   = container_name;
     qd_server->sasl_config_path = sasl_config_path;
     qd_server->sasl_config_name = sasl_config_name;
-    qd_server->driver           = qdpn_driver(qd_server->log_source);
-    qd_server->conn_handler     = 0;
-    qd_server->pn_event_handler = 0;
-    qd_server->signal_handler   = 0;
+    qd_server->proactor         = pn_proactor();
+    qd_server->container        = 0;
     qd_server->start_context    = 0;
-    qd_server->signal_context   = 0;
     qd_server->lock             = sys_mutex();
     qd_server->cond             = sys_cond();
 
     qd_timer_initialize(qd_server->lock);
 
-    qd_server->threads = NEW_PTR_ARRAY(qd_thread_t, thread_count);
-    for (i = 0; i < thread_count; i++)
-        qd_server->threads[i] = thread(qd_server, i);
-
-    DEQ_INIT(qd_server->work_queue);
-    DEQ_INIT(qd_server->pending_timers);
-    qd_server->a_thread_is_waiting    = false;
     qd_server->pause_requests         = 0;
     qd_server->threads_paused         = 0;
     qd_server->pause_next_sequence    = 0;
     qd_server->pause_now_serving      = 0;
-    qd_server->pending_signal         = 0;
-    qd_server->signal_handler_running = false;
-    qd_server->heartbeat_timer        = 0;
     qd_server->next_connection_id     = 1;
     qd_server->py_displayname_obj     = 0;
-    qd_server->http                   = qd_http_server(qd, qd_server->log_source);
+
+    /* FIXME aconway 2017-01-20: restore HTTP support */
+
     qd_log(qd_server->log_source, QD_LOG_INFO, "Container Name: %s", qd_server->container_name);
 
     return qd_server;
@@ -1371,191 +1000,64 @@ qd_server_t *qd_server(qd_dispatch_t *qd, int thread_count, const char *containe
 void qd_server_free(qd_server_t *qd_server)
 {
     if (!qd_server) return;
-    for (int i = 0; i < qd_server->thread_count; i++)
-        thread_free(qd_server->threads[i]);
     qd_http_server_free(qd_server->http);
     qd_timer_finalize();
-    qdpn_driver_free(qd_server->driver);
+    pn_proactor_free(qd_server->proactor);
     sys_mutex_free(qd_server->lock);
     sys_cond_free(qd_server->cond);
-    free(qd_server->threads);
     Py_XDECREF((PyObject *)qd_server->py_displayname_obj);
     free(qd_server);
 }
 
-
-void qd_server_set_conn_handler(qd_dispatch_t            *qd,
-                                qd_conn_handler_cb_t      handler,
-                                qd_pn_event_handler_cb_t  pn_event_handler,
-                                qd_pn_event_complete_cb_t pn_event_complete_handler,
-                                void                     *handler_context)
-{
-    qd->server->conn_handler              = handler;
-    qd->server->pn_event_handler          = pn_event_handler;
-    qd->server->pn_event_complete_handler = pn_event_complete_handler;
-    qd->server->conn_handler_context      = handler_context;
-}
-
-
-void qd_server_set_signal_handler(qd_dispatch_t *qd, qd_signal_handler_cb_t handler, void *context)
+void qd_server_set_container(qd_dispatch_t *qd, qd_container_t *container)
 {
-    qd->server->signal_handler = handler;
-    qd->server->signal_context = context;
-}
-
-
-static void qd_server_announce(qd_server_t* qd_server)
-{
-    qd_log(qd_server->log_source, QD_LOG_INFO, "Operational, %d Threads Running", qd_server->thread_count);
-#ifndef NDEBUG
-    qd_log(qd_server->log_source, QD_LOG_INFO, "Running in DEBUG Mode");
-#endif
+    qd->server->container              = container;
 }
 
 
 void qd_server_run(qd_dispatch_t *qd)
 {
     qd_server_t *qd_server = qd->server;
-
-    int i;
-    if (!qd_server)
-        return;
-
-    assert(qd_server->conn_handler); // Server can't run without a connection handler.
-
-    for (i = 1; i < qd_server->thread_count; i++)
-        thread_start(qd_server->threads[i]);
-
-    qd_server->heartbeat_timer = qd_timer(qd, heartbeat_cb, qd_server);
-    qd_timer_schedule(qd_server->heartbeat_timer, HEARTBEAT_INTERVAL);
-
-    qd_server_announce(qd_server);
-
-    thread_run((void*) qd_server->threads[0]);
-
-    for (i = 1; i < qd_server->thread_count; i++)
-        thread_join(qd_server->threads[i]);
-
-    for (i = 0; i < qd_server->thread_count; i++)
-        qd_server->threads[i]->canceled = 0;
-
-    qd_log(qd_server->log_source, QD_LOG_INFO, "Shut Down");
-}
-
-
-void qd_server_start(qd_dispatch_t *qd)
-{
-    qd_server_t *qd_server = qd->server;
     int i;
+    assert(qd_server);
+    assert(qd_server->container); // Server can't run without a container
+    qd_log(qd_server->log_source, QD_LOG_NOTICE, "Operational, %d Threads Running",
+           qd_server->thread_count);
+#ifndef NDEBUG
+    qd_log(qd_server->log_source, QD_LOG_INFO, "Running in DEBUG Mode");
+#endif
+    int n = qd_server->thread_count - 1; /* Start count-1 threads + use current thread */
+    sys_thread_t **threads = (sys_thread_t **)calloc(n, sizeof(sys_thread_t*));
+    for (i = 0; i < n; i++) {
+        threads[i] = sys_thread(thread_run, qd_server);
+    }
+    thread_run(qd_server);      /* Use the current thread */
+    for (i = 0; i < n; i++) {
+        sys_thread_join(threads[i]);
+        sys_thread_free(threads[i]);
+    }
+    free(threads);
 
-    if (!qd_server)
-        return;
-
-    assert(qd_server->conn_handler); // Server can't run without a connection handler.
-
-    for (i = 0; i < qd_server->thread_count; i++)
-        thread_start(qd_server->threads[i]);
-
-    qd_server->heartbeat_timer = qd_timer(qd, heartbeat_cb, qd_server);
-    qd_timer_schedule(qd_server->heartbeat_timer, HEARTBEAT_INTERVAL);
-
-    qd_server_announce(qd_server);
+    qd_log(qd_server->log_source, QD_LOG_NOTICE, "Shut Down");
 }
 
 
 void qd_server_stop(qd_dispatch_t *qd)
 {
-    qd_server_t *qd_server = qd->server;
-    int idx;
-
-    sys_mutex_lock(qd_server->lock);
-    for (idx = 0; idx < qd_server->thread_count; idx++)
-        thread_cancel(qd_server->threads[idx]);
-    sys_cond_signal_all(qd_server->cond);
-    qdpn_driver_wakeup(qd_server->driver);
-    sys_mutex_unlock(qd_server->lock);
-
-    if (thread_server != qd_server) {
-        for (idx = 0; idx < qd_server->thread_count; idx++)
-            thread_join(qd_server->threads[idx]);
-        qd_log(qd_server->log_source, QD_LOG_INFO, "Shut Down");
+    /* Disconnect everything, interrupt threads */
+    pn_proactor_disconnect(qd->server->proactor, NULL);
+    for (int i = 0; i < qd->server->thread_count; i++) {
+        pn_proactor_interrupt(qd->server->proactor);
     }
 }
 
-
-void qd_server_signal(qd_dispatch_t *qd, int signum)
+void qd_server_activate(qd_connection_t *ctx)
 {
-    if (!qd)
+    if (!ctx || !ctx->pn_conn)
         return;
-
-    qd_server_t *qd_server = qd->server;
-
-    qd_server->pending_signal = signum;
-    sys_cond_signal_all(qd_server->cond);
-    qdpn_driver_wakeup(qd_server->driver);
-}
-
-
-void qd_server_pause(qd_dispatch_t *qd)
-{
-    qd_server_t *qd_server = qd->server;
-
-    sys_mutex_lock(qd_server->lock);
-
-    //
-    // Bump the request count to stop all the threads.
-    //
-    qd_server->pause_requests++;
-    int my_sequence = qd_server->pause_next_sequence++;
-
-    //
-    // Awaken all threads that are currently blocking.
-    //
-    sys_cond_signal_all(qd_server->cond);
-    qdpn_driver_wakeup(qd_server->driver);
-
-    //
-    // Wait for the paused thread count plus the number of threads requesting a pause to equal
-    // the total thread count.  Also, don't exit the blocking loop until now_serving equals our
-    // sequence number.  This ensures that concurrent pausers don't run at the same time.
-    //
-    while ((qd_server->threads_paused + qd_server->pause_requests < qd_server->thread_count) ||
-           (my_sequence != qd_server->pause_now_serving))
-        sys_cond_wait(qd_server->cond, qd_server->lock);
-
-    sys_mutex_unlock(qd_server->lock);
-}
-
-
-void qd_server_resume(qd_dispatch_t *qd)
-{
-    qd_server_t *qd_server = qd->server;
-
-    sys_mutex_lock(qd_server->lock);
-    qd_server->pause_requests--;
-    qd_server->pause_now_serving++;
-    sys_cond_signal_all(qd_server->cond);
-    sys_mutex_unlock(qd_server->lock);
+    pn_connection_wake(ctx->pn_conn);
 }
 
-
-void qd_server_activate(qd_connection_t *ctx, bool awaken)
-{
-    if (!ctx)
-        return;
-
-    qdpn_connector_t *ctor = ctx->pn_cxtr;
-    if (!ctor)
-        return;
-
-    if (!qdpn_connector_closed(ctor)) {
-        qdpn_connector_activate(ctor, QDPN_CONNECTOR_WRITABLE);
-        if (awaken)
-            qdpn_driver_wakeup(ctx->server->driver);
-    }
-}
-
-
 void qd_connection_set_context(qd_connection_t *conn, void *context)
 {
     conn->user_context = context;
@@ -1598,11 +1100,6 @@ bool qd_connection_inbound(qd_connection_t *conn)
 }
 
 
-pn_collector_t *qd_connection_collector(qd_connection_t *conn)
-{
-    return conn->collector;
-}
-
 uint64_t qd_connection_connection_id(qd_connection_t *conn)
 {
     return conn->connection_id;
@@ -1612,8 +1109,8 @@ uint64_t qd_connection_connection_id(qd_connection_t *conn)
 const qd_server_config_t *qd_connection_config(const qd_connection_t *conn)
 {
     if (conn->listener)
-        return conn->listener->config;
-    return conn->connector->config;
+        return &conn->listener->config;
+    return &conn->connector->config;
 }
 
 
@@ -1628,131 +1125,106 @@ void qd_connection_invoke_deferred(qd_connection_t *conn, qd_deferred_t call, vo
     DEQ_INSERT_TAIL(conn->deferred_calls, dc);
     sys_mutex_unlock(conn->deferred_call_lock);
 
-    qd_server_activate(conn, true);
+    qd_server_activate(conn);
 }
 
 
-void qd_connection_set_event_stall(qd_connection_t *conn, bool stall)
+qd_listener_t *qd_server_listener(qd_server_t *server)
 {
-    conn->event_stall = stall;
-     if (!stall)
-         qd_server_activate(conn, true);
-}
+    qd_listener_t *li = new_qd_listener_t();
+    if (!li) return 0;
+    ZERO(li);
 
-qd_listener_t *qd_server_listen(qd_dispatch_t *qd, const qd_server_config_t *config, void *context)
-{
-    qd_server_t   *qd_server = qd->server;
-    qd_listener_t *li        = new_qd_listener_t();
-
-    if (!li)
-        return 0;
-
-    li->server      = qd_server;
-    li->config      = config;
-    li->context     = context;
+    sys_atomic_init(&li->ref_count, 1);
+    li->server      = server;
     li->http = NULL;
-
-    if (config->http) {
-        li->http = qd_http_listener(qd_server->http, config);
-        if (!li->http) {
-            free_qd_listener_t(li);
-            qd_log(qd_server->log_source, QD_LOG_ERROR, "Cannot start HTTP listener on %s:%s",
-                   config->host, config->port);
-            return NULL;
-        }
-    }
-
-    li->pn_listener = qdpn_listener(
-        qd_server->driver, config->host, config->port, config->protocol_family, li);
-
-    if (!li->pn_listener) {
-        free_qd_listener_t(li);
-        qd_log(qd_server->log_source, QD_LOG_ERROR, "Cannot start listener on %s:%s",
-               config->host, config->port);
-        return NULL;
-    }
-    qd_log(qd_server->log_source, QD_LOG_TRACE, "Listening on %s:%s%s", config->host, config->port,
-           config->http ? (config->ssl_profile ? "(HTTPS)":"(HTTP)") : "");
-
     return li;
 }
 
 
-void qd_server_listener_free(qd_listener_t* li)
-{
-    if (!li)
-        return;
-    if (li->http) qd_http_listener_free(li->http);
-    qdpn_listener_free(li->pn_listener);
-    free_qd_listener_t(li);
+bool qd_listener_listen(qd_listener_t *li) {
+    if (!li->pn_listener) {      /* Not already listening */
+        li->pn_listener = pn_listener();
+        if (!li->pn_listener) {
+            qd_log(li->server->log_source, QD_LOG_ERROR, "No memory listening on %s",
+                   li->config.host_port);
+            return false;
+        }
+        pn_listener_set_context(li->pn_listener, li);
+        /* Listen is asynchronous, log listening on PN_LISTENER_OPEN */
+        sys_atomic_inc(&li->ref_count);
+        pn_proactor_listen(li->server->proactor, li->pn_listener, li->config.host_port, BACKLOG);
+    }
+    return true;
 }
 
 
-void qd_server_listener_close(qd_listener_t* li)
+void qd_listener_decref(qd_listener_t* li)
 {
-    if (li)
-        qdpn_listener_close(li->pn_listener);
+    if (li && sys_atomic_dec(&li->ref_count) == 1) {
+        qd_server_config_free(&li->config);
+        if (li->http) qd_http_listener_free(li->http);
+        free_qd_listener_t(li);
+    }
 }
 
 
-qd_connector_t *qd_server_connect(qd_dispatch_t *qd, const qd_server_config_t *config, void *context)
+qd_connector_t *qd_server_connector(qd_server_t *server)
 {
-    qd_server_t    *qd_server = qd->server;
     qd_connector_t *ct        = new_qd_connector_t();
-
-    if (!ct)
+    if (!ct) return 0;
+    sys_atomic_init(&ct->ref_count, 1);
+    ct->server  = server;
+    ct->lock = sys_mutex();
+    ct->timer = qd_timer(ct->server->qd, try_open_cb, ct);
+    if (!ct->lock || !ct->timer) {
+        qd_connector_decref(ct);
         return 0;
+    }
+    return ct;
+}
 
-    ct->server  = qd_server;
+
+bool qd_connector_connect(qd_connector_t *ct)
+{
+    sys_mutex_lock(ct->lock);
     ct->state   = CXTR_STATE_CONNECTING;
-    ct->config  = config;
-    ct->context = context;
     ct->ctx     = 0;
-    ct->timer   = qd_timer(qd, cxtr_try_open, (void*) ct);
     ct->delay   = 0;
-
+    /* Referenced by timer */
+    sys_atomic_inc(&ct->ref_count);
     qd_timer_schedule(ct->timer, ct->delay);
-    return ct;
+    sys_mutex_unlock(ct->lock);
+    return true;
 }
 
 
-void qd_server_connector_free(qd_connector_t* ct)
+void qd_connector_decref(qd_connector_t* ct)
 {
-    // Don't free the proton connector.  This will be done by the connector
-    // processing/cleanup.
-
-    if (!ct)
-        return;
-
-    if (ct->ctx) {
-        qdpn_connector_close(ct->ctx->pn_cxtr);
-        ct->ctx->connector = 0;
+    if (ct && sys_atomic_dec(&ct->ref_count) == 1) {
+        sys_mutex_lock(ct->lock);
+        if (ct->ctx) {
+            ct->ctx->connector = 0;
+        }
+        sys_mutex_unlock(ct->lock);
+        qd_server_config_free(&ct->config);
+        qd_timer_free(ct->timer);
+        free_qd_connector_t(ct);
     }
-
-    qd_timer_free(ct->timer);
-    free_qd_connector_t(ct);
 }
 
-void qd_server_timer_pending_LH(qd_timer_t *timer)
-{
-    DEQ_INSERT_TAIL(timer->server->pending_timers, timer);
-    qdpn_driver_wakeup(timer->server->driver);
-}
-
-
-void qd_server_timer_cancel_LH(qd_timer_t *timer)
-{
-    DEQ_REMOVE(timer->server->pending_timers, timer);
+void qd_server_timeout(qd_server_t *server, qd_duration_t duration) {
+    pn_proactor_set_timeout(server->proactor, duration);
 }
 
 qd_dispatch_t* qd_server_dispatch(qd_server_t *server) { return server->qd; }
 
 const char* qd_connection_name(const qd_connection_t *c) {
-    return qdpn_connector_name(c->pn_cxtr);
-}
-
-const char* qd_connection_hostip(const qd_connection_t *c) {
-    return qdpn_connector_hostip(c->pn_cxtr);
+    if (c->connector) {
+        return c->connector->config.host_port;
+    } else {
+        return c->rhost_port;
+    }
 }
 
 qd_connector_t* qd_connection_connector(const qd_connection_t *c) {
@@ -1760,9 +1232,13 @@ qd_connector_t* qd_connection_connector(const qd_connection_t *c) {
 }
 
 const qd_server_config_t *qd_connector_config(const qd_connector_t *c) {
-    return c->config;
+    return &c->config;
 }
 
-qd_http_listener_t *qd_listener_http(qd_listener_t *l) {
-    return l->http;
+qd_http_listener_t *qd_listener_http(qd_listener_t *li) {
+    return li->http;
+}
+
+const char* qd_connection_hostip(const qd_connection_t *c) {
+    return c->rhost;
 }

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/server_private.h
----------------------------------------------------------------------
diff --git a/src/server_private.h b/src/server_private.h
index 9581196..a6543fa 100644
--- a/src/server_private.h
+++ b/src/server_private.h
@@ -19,34 +19,39 @@
  * under the License.
  */
 
+#include <qpid/dispatch/atomic.h>
 #include <qpid/dispatch/enum.h>
 #include <qpid/dispatch/server.h>
+#include <qpid/dispatch/threading.h>
 #include "alloc.h"
 #include <qpid/dispatch/ctools.h>
 #include <qpid/dispatch/log.h>
-#include <qpid/dispatch/driver.h>
 #include <proton/engine.h>
 #include <proton/event.h>
+#include <proton/ssl.h>
 
 #include "dispatch_private.h"
 #include "timer_private.h"
 #include "http.h"
 
-void qd_server_timer_pending_LH(qd_timer_t *timer);
-void qd_server_timer_cancel_LH(qd_timer_t *timer);
+#include <netdb.h>              /* For NI_MAXHOST/NI_MAXSERV */
 
-struct qd_dispatch_t* qd_server_dispatch(qd_server_t *server);
+qd_dispatch_t* qd_server_dispatch(qd_server_t *server);
+void qd_server_timeout(qd_server_t *server, qd_duration_t delay);
 
 const char* qd_connection_name(const qd_connection_t *c);
-const char* qd_connection_hostip(const qd_connection_t *c);
 qd_connector_t* qd_connection_connector(const qd_connection_t *c);
+const char* qd_connection_hostip(const qd_connection_t *c);
 
 const qd_server_config_t *qd_connector_config(const qd_connector_t *c);
 
 qd_http_listener_t *qd_listener_http(qd_listener_t *l);
 
-#define CONTEXT_NO_OWNER -1
-#define CONTEXT_UNSPECIFIED_OWNER -2
+qd_listener_t *qd_server_listener(qd_server_t *server);
+qd_connector_t *qd_server_connector(qd_server_t *server);
+void qd_connector_decref(qd_connector_t* ct);
+void qd_listener_decref(qd_listener_t* ct);
+void qd_server_config_free(qd_server_config_t *cf);
 
 typedef enum {
     CXTR_STATE_CONNECTING = 0,
@@ -55,8 +60,6 @@ typedef enum {
 } cxtr_state_t;
 
 
-
-
 typedef struct qd_deferred_call_t {
     DEQ_LINKS(struct qd_deferred_call_t);
     qd_deferred_t  call;
@@ -73,19 +76,63 @@ typedef struct qd_pn_free_link_session_t {
 
 DEQ_DECLARE(qd_pn_free_link_session_t, qd_pn_free_link_session_list_t);
 
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+/**
+ * Listener objects represent the desire to accept incoming transport connections.
+ */
+struct qd_listener_t {
+    /* May be referenced by connection_manager and pn_listener_t */
+    sys_atomic_t              ref_count;
+    qd_server_t              *server;
+    qd_server_config_t        config;
+    pn_listener_t            *pn_listener;
+    qd_http_listener_t       *http;
+    DEQ_LINKS(qd_listener_t);
+    bool                      exit_on_error;
+};
+
+DEQ_DECLARE(qd_listener_t, qd_listener_list_t);
+
+
+/**
+ * Connector objects represent the desire to create and maintain an outgoing transport connection.
+ */
+struct qd_connector_t {
+    /* May be referenced by connection_manager, timer and pn_connection_t */
+    sys_atomic_t              ref_count;
+    qd_server_t              *server;
+    qd_server_config_t        config;
+    qd_timer_t               *timer;
+    long                      delay;
+
+    /* Connector state and ctx can be modified in proactor or management threads. */
+    sys_mutex_t              *lock;
+    cxtr_state_t              state;
+    qd_connection_t          *ctx;
+    DEQ_LINKS(qd_connector_t);
+};
+
+DEQ_DECLARE(qd_connector_t, qd_connector_list_t);
+
+
 /**
  * Connection objects wrap Proton connection objects.
  */
 struct qd_connection_t {
     DEQ_LINKS(qd_connection_t);
+    char                     *name;
     qd_server_t              *server;
     bool                      opened; // An open callback was invoked for this connection
     bool                      closed;
-    int                       owner_thread;
     int                       enqueued;
-    qdpn_connector_t         *pn_cxtr;
     pn_connection_t          *pn_conn;
-    pn_collector_t           *collector;
     pn_ssl_t                 *ssl;
     qd_listener_t            *listener;
     qd_connector_t           *connector;
@@ -102,10 +149,11 @@ struct qd_connection_t {
     void                     *open_container;
     qd_deferred_call_list_t   deferred_calls;
     sys_mutex_t              *deferred_call_lock;
-    bool                      event_stall;
     bool                      policy_counted;
     char                     *role;  //The specified role of the connection, e.g. "normal", "inter-router", "route-container" etc.
     qd_pn_free_link_session_list_t  free_link_session_list;
+    char rhost[NI_MAXHOST];     /* Remote host numeric IP for incoming connections */
+    char rhost_port[NI_MAXHOST+NI_MAXSERV]; /* Remote host:port for incoming connections */
 };
 
 DEQ_DECLARE(qd_connection_t, qd_connection_list_t);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/timer.c
----------------------------------------------------------------------
diff --git a/src/timer.c b/src/timer.c
index b2121ae..988c086 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -25,11 +25,15 @@
 #include "alloc.h"
 #include <assert.h>
 #include <stdio.h>
+#include <time.h>
 
-static sys_mutex_t     *lock;
-static qd_timer_list_t  idle_timers;
-static qd_timer_list_t  scheduled_timers;
-static qd_timestamp_t   time_base;
+static sys_mutex_t     *lock = NULL;
+static qd_timer_list_t  idle_timers = {0};
+static qd_timer_list_t  scheduled_timers = {0};
+/* Timers have relative delta_time measured from the previous timer.
+ * The delta_time of the first timer on the queue is measured from timer_base.
+ */
+static qd_timestamp_t   time_base = 0;
 
 ALLOC_DECLARE(qd_timer_t);
 ALLOC_DEFINE(qd_timer_t);
@@ -41,30 +45,35 @@ sys_mutex_t* qd_timer_lock() { return lock; }
 // Private static functions
 //=========================================================================
 
-static void qd_timer_cancel_LH(qd_timer_t *timer)
+static void timer_cancel_LH(qd_timer_t *timer)
 {
-    switch (timer->state) {
-    case TIMER_FREE:
-        assert(0);
-        break;
-
-    case TIMER_IDLE:
-        break;
-
-    case TIMER_SCHEDULED:
+    if (timer->scheduled) {
         if (timer->next)
             timer->next->delta_time += timer->delta_time;
         DEQ_REMOVE(scheduled_timers, timer);
         DEQ_INSERT_TAIL(idle_timers, timer);
-        break;
-
-    case TIMER_PENDING:
-        qd_server_timer_cancel_LH(timer);
-        DEQ_INSERT_TAIL(idle_timers, timer);
-        break;
+        timer->scheduled = false;
     }
+}
 
-    timer->state = TIMER_IDLE;
+/* Adjust timer's time_base and delays for the current time. */
+static void timer_adjust_now_LH()
+{
+    qd_timestamp_t now = qd_timer_now();
+    if (time_base != 0 && now > time_base) {
+        qd_duration_t delta = now - time_base;
+        /* Adjust timer delays by removing duration delta, starting from timer. */
+        for (qd_timer_t *timer = DEQ_HEAD(scheduled_timers); delta > 0 && timer; timer = DEQ_NEXT(timer)) {
+            if (timer->delta_time >= delta) {
+                timer->delta_time -= delta;
+                delta = 0;
+            } else {
+                delta -= timer->delta_time;
+                timer->delta_time = 0; /* Ready to fire */
+            }
+        }
+    }
+    time_base = now;
 }
 
 
@@ -72,6 +81,7 @@ static void qd_timer_cancel_LH(qd_timer_t *timer)
 // Public Functions from timer.h
 //=========================================================================
 
+
 qd_timer_t *qd_timer(qd_dispatch_t *qd, qd_timer_cb_t cb, void* context)
 {
     qd_timer_t *timer = new_qd_timer_t();
@@ -84,8 +94,7 @@ qd_timer_t *qd_timer(qd_dispatch_t *qd, qd_timer_cb_t cb, void* context)
     timer->handler    = cb;
     timer->context    = context;
     timer->delta_time = 0;
-    timer->state      = TIMER_IDLE;
-
+    timer->scheduled  = false;
     sys_mutex_lock(lock);
     DEQ_INSERT_TAIL(idle_timers, timer);
     sys_mutex_unlock(lock);
@@ -98,73 +107,55 @@ void qd_timer_free(qd_timer_t *timer)
 {
     if (!timer) return;
     sys_mutex_lock(lock);
-    qd_timer_cancel_LH(timer);
+    timer_cancel_LH(timer);
     DEQ_REMOVE(idle_timers, timer);
     sys_mutex_unlock(lock);
-
-    timer->state = TIMER_FREE;
     free_qd_timer_t(timer);
 }
 
 
-void qd_timer_schedule(qd_timer_t *timer, qd_timestamp_t duration)
-{
-    qd_timer_t     *ptr;
-    qd_timer_t     *last;
-    qd_timestamp_t  total_time;
+qd_timestamp_t qd_timer_now() {
+    struct timespec tv;
+    clock_gettime(CLOCK_REALTIME, &tv);
+    return ((qd_timestamp_t)tv.tv_sec) * 1000 + tv.tv_nsec / 1000000;
+}
+
 
+void qd_timer_schedule(qd_timer_t *timer, qd_duration_t duration)
+{
     sys_mutex_lock(lock);
-    qd_timer_cancel_LH(timer);  // Timer is now on the idle list
-    assert(timer->state == TIMER_IDLE);
+    timer_cancel_LH(timer);  // Timer is now on the idle list
     DEQ_REMOVE(idle_timers, timer);
 
     //
-    // Handle the special case of a zero-time scheduling.  In this case,
-    // the timer doesn't go on the scheduled list.  It goes straight to the
-    // pending list in the server.
-    //
-    if (duration == 0) {
-        timer->state = TIMER_PENDING;
-        qd_server_timer_pending_LH(timer);
-        sys_mutex_unlock(lock);
-        return;
-    }
-
-    //
     // Find the insert point in the schedule.
     //
-    total_time = 0;
-    ptr        = DEQ_HEAD(scheduled_timers);
-    assert(!ptr || ptr->prev == 0);
-    while (ptr) {
-        total_time += ptr->delta_time;
-        if (total_time > duration)
-            break;
+    timer_adjust_now_LH();   /* Adjust the timers for current time */
+
+    /* Invariant: time_before == total time up to but not including ptr */
+    qd_timer_t *ptr = DEQ_HEAD(scheduled_timers);
+    qd_duration_t time_before = 0;
+    while (ptr && time_before + ptr->delta_time < duration) {
+        time_before += ptr->delta_time;
         ptr = ptr->next;
     }
-
-    //
-    // Insert the timer into the schedule and adjust the delta time
-    // of the following timer if present.
-    //
-    if (total_time <= duration) {
-        assert(ptr == 0);
-        timer->delta_time = duration - total_time;
+    /* ptr is the first timer to exceed duration or NULL if we ran out */
+    if (!ptr) {
+        timer->delta_time = duration - time_before;
         DEQ_INSERT_TAIL(scheduled_timers, timer);
     } else {
-        total_time -= ptr->delta_time;
-        timer->delta_time = duration - total_time;
-        assert(ptr->delta_time > timer->delta_time);
+        timer->delta_time = duration - time_before;
         ptr->delta_time -= timer->delta_time;
-        last = ptr->prev;
-        if (last)
-            DEQ_INSERT_AFTER(scheduled_timers, timer, last);
+        ptr = ptr->prev;
+        if (ptr)
+            DEQ_INSERT_AFTER(scheduled_timers, timer, ptr);
         else
             DEQ_INSERT_HEAD(scheduled_timers, timer);
     }
+    timer->scheduled = true;
 
-    timer->state = TIMER_SCHEDULED;
-
+    qd_timer_t *first = DEQ_HEAD(scheduled_timers);
+    qd_server_timeout(first->server, first->delta_time);
     sys_mutex_unlock(lock);
 }
 
@@ -172,7 +163,7 @@ void qd_timer_schedule(qd_timer_t *timer, qd_timestamp_t duration)
 void qd_timer_cancel(qd_timer_t *timer)
 {
     sys_mutex_lock(lock);
-    qd_timer_cancel_LH(timer);
+    timer_cancel_LH(timer);
     sys_mutex_unlock(lock);
 }
 
@@ -181,6 +172,7 @@ void qd_timer_cancel(qd_timer_t *timer)
 // Private Functions from timer_private.h
 //=========================================================================
 
+
 void qd_timer_initialize(sys_mutex_t *server_lock)
 {
     lock = server_lock;
@@ -196,47 +188,22 @@ void qd_timer_finalize(void)
 }
 
 
-qd_timestamp_t qd_timer_next_duration_LH(void)
+/* Execute all timers that are ready and set up next timeout. */
+void qd_timer_visit()
 {
+    sys_mutex_lock(lock);
+    timer_adjust_now_LH();
     qd_timer_t *timer = DEQ_HEAD(scheduled_timers);
-    if (timer)
-        return timer->delta_time;
-    return -1;
-}
-
-
-void qd_timer_visit_LH(qd_timestamp_t current_time)
-{
-    qd_timestamp_t  delta;
-    qd_timer_t     *timer = DEQ_HEAD(scheduled_timers);
-
-    if (time_base == 0) {
-        time_base = current_time;
-        return;
-    }
-
-    delta     = current_time - time_base;
-    time_base = current_time;
-
-    while (timer) {
-        assert(delta >= 0);
-        if (timer->delta_time > delta) {
-            timer->delta_time -= delta;
-            break;
-        } else {
-            DEQ_REMOVE_HEAD(scheduled_timers);
-            delta -= timer->delta_time;
-            timer->state = TIMER_PENDING;
-            qd_server_timer_pending_LH(timer);
-
-        }
+    while (timer && timer->delta_time == 0) {
+        timer_cancel_LH(timer); /* Removes timer from scheduled_timers */
+        sys_mutex_unlock(lock);
+        timer->handler(timer->context); /* Call the handler outside the lock, may re-schedule */
+        sys_mutex_lock(lock);
         timer = DEQ_HEAD(scheduled_timers);
     }
-}
-
-
-void qd_timer_idle_LH(qd_timer_t *timer)
-{
-    timer->state = TIMER_IDLE;
-    DEQ_INSERT_TAIL(idle_timers, timer);
+    qd_timer_t *first = DEQ_HEAD(scheduled_timers);
+    if (first) {
+        qd_server_timeout(first->server, first->delta_time);
+    }
+    sys_mutex_unlock(lock);
 }

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/timer_private.h
----------------------------------------------------------------------
diff --git a/src/timer_private.h b/src/timer_private.h
index 4acd988..537eb4b 100644
--- a/src/timer_private.h
+++ b/src/timer_private.h
@@ -23,30 +23,20 @@
 #include <qpid/dispatch/timer.h>
 #include <qpid/dispatch/threading.h>
 
-typedef enum {
-    TIMER_FREE,
-    TIMER_IDLE,
-    TIMER_SCHEDULED,
-    TIMER_PENDING
-} qd_timer_state_t;
-
-
 struct qd_timer_t {
     DEQ_LINKS(qd_timer_t);
     qd_server_t      *server;
     qd_timer_cb_t     handler;
     void             *context;
     qd_timestamp_t    delta_time;
-    qd_timer_state_t  state;
+    bool              scheduled; /* true means on scheduled list, false on idle list */
 };
 
 DEQ_DECLARE(qd_timer_t, qd_timer_list_t);
 
 void qd_timer_initialize(sys_mutex_t *server_lock);
 void qd_timer_finalize(void);
-qd_timestamp_t qd_timer_next_duration_LH(void);
-void qd_timer_visit_LH(qd_timestamp_t current_time);
-void qd_timer_idle_LH(qd_timer_t *timer);
+void qd_timer_visit();
 
 /// For tests only
 sys_mutex_t* qd_timer_lock();

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 314ad50..bc62232 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -29,9 +29,9 @@ set(unit_test_SOURCES
     compose_test.c
     policy_test.c
     run_unit_tests.c
-    timer_test.c
     tool_test.c
     failoverlist_test.c
+    timer_test.c
     )
 if (USE_MEMORY_POOL)
   list(APPEND unit_test_SOURCES alloc_test.c)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/tests/run_unit_tests.c
----------------------------------------------------------------------
diff --git a/tests/run_unit_tests.c b/tests/run_unit_tests.c
index e481f13..c8c4ef3 100644
--- a/tests/run_unit_tests.c
+++ b/tests/run_unit_tests.c
@@ -24,7 +24,7 @@
 #include <stdio.h>
 
 int tool_tests(void);
-int timer_tests(void);
+int timer_tests(qd_dispatch_t*);
 int alloc_tests(void);
 int compose_tests(void);
 int policy_tests(void);
@@ -52,7 +52,7 @@ int main(int argc, char** argv)
         printf("Config failed: %s\n", qd_error_message());
         return 1;
     }
-    result += timer_tests();
+    result += timer_tests(qd);
     result += tool_tests();
     result += compose_tests();
 #if USE_MEMORY_POOL

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/tests/system_tests_management.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_management.py b/tests/system_tests_management.py
index b9535a8..c26741f 100644
--- a/tests/system_tests_management.py
+++ b/tests/system_tests_management.py
@@ -169,7 +169,7 @@ class ManagementTest(system_test.TestCase):
         attributes = {'name':'foo', 'port':str(port), 'role':'normal', 'saslMechanisms': 'ANONYMOUS', 'authenticatePeer': False}
         entity = self.assert_create_ok(LISTENER, 'foo', attributes)
         self.assertEqual(entity['name'], 'foo')
-        self.assertEqual(entity['host'], '127.0.0.1')
+        self.assertEqual(entity['host'], '')
 
         # Connect via the new listener
         node3 = self.cleanup(Node.connect(Url(port=port)))

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/tests/system_tests_policy.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_policy.py b/tests/system_tests_policy.py
index 2ce3778..120137d 100644
--- a/tests/system_tests_policy.py
+++ b/tests/system_tests_policy.py
@@ -275,66 +275,29 @@ class SenderReceiverLimits(TestCase):
     def test_verify_n_receivers(self):
         n = 4
         addr = self.address()
-
-        # connection should be ok
-        denied = False
-        try:
-            br1 = BlockingConnection(addr)
-        except ConnectionException:
-            denied = True
-
-        self.assertFalse(denied) # assert if connections that should open did not open
+        br1 = BlockingConnection(addr)
 
         # n receivers OK
-        try:
-            r1 = br1.create_receiver(address="****YES_1of4***")
-            r2 = br1.create_receiver(address="****YES_20f4****")
-            r3 = br1.create_receiver(address="****YES_3of4****")
-            r4 = br1.create_receiver(address="****YES_4of4****")
-        except Exception:
-            denied = True
-
-        self.assertFalse(denied) # n receivers should have worked
+        br1.create_receiver(address="****YES_1of4***")
+        br1.create_receiver(address="****YES_20f4****")
+        br1.create_receiver(address="****YES_3of4****")
+        br1.create_receiver(address="****YES_4of4****")
 
         # receiver n+1 should be denied
-        try:
-            r5 = br1.create_receiver("****NO****")
-        except Exception:
-            denied = True
-
-        self.assertTrue(denied) # receiver n+1 should have failed
+        self.assertRaises(LinkDetached, br1.create_receiver, "****NO****")
 
         br1.close()
 
     def test_verify_n_senders(self):
         n = 2
         addr = self.address()
-
-        # connection should be ok
-        denied = False
-        try:
-            bs1 = BlockingConnection(addr)
-        except ConnectionException:
-            denied = True
-
-        self.assertFalse(denied) # assert if connections that should open did not open
+        bs1 = BlockingConnection(addr)
 
         # n senders OK
-        try:
-            s1 = bs1.create_sender(address="****YES_1of2****")
-            s2 = bs1.create_sender(address="****YES_2of2****")
-        except Exception:
-            denied = True
-
-        self.assertFalse(denied) # n senders should have worked
-
-        # receiver n+1 should be denied
-        try:
-            s3 = bs1.create_sender("****NO****")
-        except Exception:
-            denied = True
-
-        self.assertTrue(denied) # sender n+1 should have failed
+        bs1.create_sender(address="****YES_1of2****")
+        bs1.create_sender(address="****YES_2of2****")
+        # sender n+1 should be denied
+        self.assertRaises(LinkDetached, bs1.create_sender, "****NO****")
 
         bs1.close()
 


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


[05/10] qpid-dispatch git commit: DISPATCH-390: Convert dispatch to use pn_proactor_t

Posted by ac...@apache.org.
DISPATCH-390: Convert dispatch to use pn_proactor_t

- remove driver.h/c, server.c uses proactor API directly
- update stop/start, signal handling
- refactor server connector queue processing as PN event handlers
- qd_timer using pn_proactor_timeout()
- deferred calls use pn_proactor_wake()
- drop qd_thread_t struct, use sys_thread_t directly
- document new listen "host" semantics in schema
- updated logging, NOTICE for key life-cycle events
- merge qd_listener_t+qd_config_listener, qd_connector_t+qd_config_connector_t
- remove dead code: work_ queue, a_thread_is_waiting, owner_thread


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

Branch: refs/heads/master
Commit: 6f56e289bec0db4a1de257883dc456a502c42fe7
Parents: 0539dc4
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jan 20 14:20:31 2017 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:29:40 2017 -0400

----------------------------------------------------------------------
 config.sh                                       |   41 +-
 include/qpid/dispatch/amqp.h                    |    2 -
 include/qpid/dispatch/connection_manager.h      |   21 -
 include/qpid/dispatch/driver.h                  |  441 ------
 include/qpid/dispatch/error.h                   |    7 +
 include/qpid/dispatch/router_core.h             |   11 +-
 include/qpid/dispatch/server.h                  |  240 +--
 include/qpid/dispatch/timer.h                   |   10 +-
 python/qpid_dispatch/management/qdrouter.json   |    4 +-
 python/qpid_dispatch_internal/router/address.py |    5 -
 router/CMakeLists.txt                           |    2 +-
 router/src/main.c                               |   29 +-
 src/CMakeLists.txt                              |    3 +-
 src/amqp.c                                      |    2 -
 src/connection_manager.c                        |  192 ++-
 src/container.c                                 |  110 +-
 src/error.c                                     |   15 +-
 src/http-none.c                                 |    1 -
 src/policy.c                                    |   97 +-
 src/policy.h                                    |    9 +-
 src/posix/driver.c                              | 1093 --------------
 src/router_core/connections.c                   |   14 +-
 src/router_core/router_core_private.h           |    3 -
 src/router_core/router_core_thread.c            |   18 -
 src/router_node.c                               |   16 +-
 src/server.c                                    | 1398 ++++++------------
 src/server_private.h                            |   74 +-
 src/timer.c                                     |  183 +--
 src/timer_private.h                             |   14 +-
 tests/CMakeLists.txt                            |    2 +-
 tests/run_unit_tests.c                          |    4 +-
 tests/system_tests_management.py                |    2 +-
 tests/system_tests_policy.py                    |   59 +-
 tests/timer_test.c                              |  305 ++--
 34 files changed, 961 insertions(+), 3466 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/config.sh
----------------------------------------------------------------------
diff --git a/config.sh b/config.sh
index 7e5e97f..beb7ed2 100644
--- a/config.sh
+++ b/config.sh
@@ -1,33 +1,8 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-if [[ ! -f config.sh ]]; then
-    echo "You must source config.sh from within its own directory"
-    return
-fi
-
-export SOURCE_DIR=$(pwd)
-export BUILD_DIR=$SOURCE_DIR/${1:-build}
-export INSTALL_DIR=$SOURCE_DIR/${2:-install}
-
-PYTHON_LIB=$(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(prefix='$INSTALL_DIR')")
-
-export LD_LIBRARY_PATH=$INSTALL_DIR/lib64:$INSTALL_DIR/lib:$LD_LIBRARY_PATH
-export PYTHONPATH=$PYTHON_LIB:$PYTHONPATH
-export PATH=$INSTALL_DIR/sbin:$INSTALL_DIR/bin:$SOURCE_DIR/bin:$PATH
+PYTHONPATH=/home/aconway/dispatch/python:/home/aconway/dispatch/tests:/home/aconway/dispatch:/usr/local/lib/proton/bindings/python:/usr/local/lib64/proton/bindings/python:/usr/local/lib/python2.7/site-packages:/usr/local/lib64/python2.7/site-packages:/usr/lib/python27.zip:/usr/lib64/python2.7:/usr/lib64/python2.7/plat-linux2:/usr/lib64/python2.7/lib-tk:/usr/lib64/python2.7/lib-old:/usr/lib64/python2.7/lib-dynload:/usr/lib64/python2.7/site-packages:/usr/lib/python2.7/site-packages
+BUILD_DIR=/home/aconway/dispatch
+QPID_DISPATCH_HOME=/home/aconway/dispatch
+QPID_DISPATCH_LIB=/home/aconway/dispatch/src/
+MANPATH=/home/aconway/dispatch/doc/man:/usr/local/share/man:/usr/share/man
+PATH=/home/aconway/dispatch:/home/aconway/dispatch/tests:/home/aconway/dispatch/router:/home/aconway/dispatch/tools:/home/aconway/dispatch/bin:/home/aconway/bin:/home/aconway/ha/bin:/usr/local/bin:/usr/local/sbin:/usr/lib64/qt-3.3/bin:/usr/lib64/ccache:/usr/bin:/usr/sbin:/home/aconway/go/bin:/home/aconway/proton/proton-c/bindings/go/bin
+SOURCE_DIR=/home/aconway/dispatch
+export PYTHONPATH BUILD_DIR QPID_DISPATCH_HOME QPID_DISPATCH_LIB MANPATH PATH SOURCE_DIR

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/amqp.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/amqp.h b/include/qpid/dispatch/amqp.h
index 60ad973..e5c45c6 100644
--- a/include/qpid/dispatch/amqp.h
+++ b/include/qpid/dispatch/amqp.h
@@ -165,6 +165,4 @@ extern const char * const QD_AMQP_COND_ILLEGAL_STATE;
 extern const char * const QD_AMQP_COND_FRAME_SIZE_TOO_SMALL;
 /// @};
 
-/// Name for AMQP conditions from the router that don't have a more specific name.
-extern const char * const QD_COND;
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/connection_manager.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/connection_manager.h b/include/qpid/dispatch/connection_manager.h
index 12ac35e..4392966 100644
--- a/include/qpid/dispatch/connection_manager.h
+++ b/include/qpid/dispatch/connection_manager.h
@@ -27,8 +27,6 @@
 #include <qpid/dispatch/server.h>
 
 typedef struct qd_connection_manager_t qd_connection_manager_t;
-typedef struct qd_config_connector_t qd_config_connector_t;
-typedef struct qd_config_listener_t qd_config_listener_t;
 typedef struct qd_config_ssl_profile_t qd_config_ssl_profile_t;
 
 typedef void (*qd_connection_manager_handler_t) (void *context, qd_connection_t *conn);
@@ -49,16 +47,6 @@ qd_connection_manager_t *qd_connection_manager(qd_dispatch_t *qd);
 void qd_connection_manager_free(qd_connection_manager_t *cm);
 
 /**
- * Free all the resources associated with a config listener
- */
-void qd_config_listener_free(qd_connection_manager_t *cm, qd_config_listener_t *cl);
-
-/**
- * Free all the resources associated with a config connector
- */
-void qd_config_connector_free(qd_connection_manager_t *cm, qd_config_connector_t *cl);
-
-/**
  * Start the configured Listeners and Connectors
  *
  * Note that on-demand connectors are not started by this function.
@@ -67,13 +55,4 @@ void qd_config_connector_free(qd_connection_manager_t *cm, qd_config_connector_t
  */
 void qd_connection_manager_start(qd_dispatch_t *qd);
 
-
-/**
- * Get the connector's name.
- *
- * @param cc Connector handle
- * @return The name of the connector
- */
-const char *qd_config_connector_name(qd_config_connector_t *cc);
-
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/driver.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/driver.h b/include/qpid/dispatch/driver.h
deleted file mode 100644
index 6c24a23..0000000
--- a/include/qpid/dispatch/driver.h
+++ /dev/null
@@ -1,441 +0,0 @@
-#ifndef __dispatch_posix_driver_h__
-#define __dispatch_posix_driver_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 <qpid/dispatch/log.h>
-
-#include <proton/error.h>
-#include <proton/sasl.h>
-#include <proton/selectable.h>
-#include <proton/ssl.h>
-#include <proton/transport.h>
-#include <proton/types.h>
-
-/** @file
- * API for the Driver Layer.
- *
- * The driver library provides a simple implementation of a driver for
- * the proton engine. A driver is responsible for providing input,
- * output, and tick events to the bottom half of the engine API. See
- * pn_transport_input, pn_transport_output, and
- * pn_transport_tick. The driver also provides an interface for the
- * application to access the top half of the API when the state of the
- * engine may have changed due to I/O or timing events. Additionally
- * the driver incorporates the SASL engine as well in order to provide
- * a complete network stack: AMQP over SASL over TCP.
- *
- */
-
-typedef struct qdpn_driver_t qdpn_driver_t;
-typedef struct qdpn_listener_t qdpn_listener_t;
-typedef struct qdpn_connector_t qdpn_connector_t;
-
-typedef enum {
-    QDPN_CONNECTOR_WRITABLE,
-    QDPN_CONNECTOR_READABLE
-} qdpn_activate_criteria_t;
-
-/** Construct a driver
- *
- *  Call qdpn_driver_free() to release the driver object.
- *  @param log source to use for log messages, the driver does not have it's own.
- *  @return new driver object, NULL if error
- */
-qdpn_driver_t *qdpn_driver(qd_log_source_t* log);
-
-/** Return the most recent error code.
- *
- * @param[in] d the driver
- *
- * @return the most recent error text for d
- */
-int qdpn_driver_errno(qdpn_driver_t *d);
-
-/** Get additional error information associated with the driver.
- *
- * Whenever a driver operation fails, additional error information can
- * be obtained using this function. The error object that is returned
- * may also be used to clear the error condition.
- *
- * The pointer returned by this operation is valid until the
- * driver object is freed.
- *
- * @param[in] d the driver
- *
- * @return the driver's error object
- */
-pn_error_t *qdpn_driver_error(qdpn_driver_t *d);
-
-/** Force qdpn_driver_wait() to return
- *
- * @param[in] driver the driver to wake up
- *
- * @return zero on success, an error code on failure
- */
-int qdpn_driver_wakeup(qdpn_driver_t *driver);
-
-/** Wait for an active connector or listener
- *
- * @param[in] driver the driver to wait on
- * @param[in] timeout maximum time in milliseconds to wait, -1 means
- *                    infinite wait
- *
- * @return zero on success, an error code on failure
- */
-int qdpn_driver_wait(qdpn_driver_t *driver, int timeout);
-
-/** Get the next listener with pending data in the driver.
- *
- * @param[in] driver the driver
- * @return NULL if no active listener available
- */
-qdpn_listener_t *qdpn_driver_listener(qdpn_driver_t *driver);
-
-/** Get the next active connector in the driver.
- *
- * Returns the next connector with pending inbound data, available
- * capacity for outbound data, or pending tick.
- *
- * @param[in] driver the driver
- * @return NULL if no active connector available
- */
-qdpn_connector_t *qdpn_driver_connector(qdpn_driver_t *driver);
-
-/** Free the driver allocated via qdpn_driver, and all associated
- *  listeners and connectors.
- *
- * @param[in] driver the driver to free, no longer valid on
- *                   return
- */
-void qdpn_driver_free(qdpn_driver_t *driver);
-
-
-/** qdpn_listener - the server API **/
-
-/** Construct a listener for the given address.
- *
- * @param[in] driver driver that will 'own' this listener
- * @param[in] host local host address to listen on
- * @param[in] port local port to listen on
- * @param[in] protocol family to use (IPv4 or IPv6 or 0). If 0 (zero) is passed in the protocol family will be automatically determined from the address
- * @param[in] context application-supplied, can be accessed via
- *                    qdpn_listener_context()
- * @param[in] methods to apply to new connectors.
- * @return a new listener on the given host:port, NULL if error
- */
-qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver,
-                               const char *host,
-                               const char *port,
-                               const char *protocol_family,
-                               void* context
-                              );
-
-/** Access the head listener for a driver.
- *
- * @param[in] driver the driver whose head listener will be returned
- *
- * @return the head listener for driver or NULL if there is none
- */
-qdpn_listener_t *qdpn_listener_head(qdpn_driver_t *driver);
-
-/** Access the next listener.
- *
- * @param[in] listener the listener whose next listener will be
- *            returned
- *
- * @return the next listener
- */
-qdpn_listener_t *qdpn_listener_next(qdpn_listener_t *listener);
-
-/** Accept a connection that is pending on the listener.
- *
- * @param[in] listener the listener to accept the connection on
- * @param[in] policy policy that holds absolute connection limits
- * @param[in] policy_fn function that accepts remote host name and returns
- *            decision to allow or deny this connection
- * @param[out] counted pointer to a bool set to true when the connection was
- *             counted against absolute connection limits
- * @return a new connector for the remote, or NULL on error
- */
-qdpn_connector_t *qdpn_listener_accept(qdpn_listener_t *listener,
-                                       void *policy,
-                                       bool (*policy_fn)(void *, const char *),
-                                       bool *counted);
-
-/** Access the application context that is associated with the listener.
- *
- * @param[in] listener the listener whose context is to be returned
- * @return the application context that was passed to qdpn_listener() or
- *         qdpn_listener_fd()
- */
-void *qdpn_listener_context(qdpn_listener_t *listener);
-
-void qdpn_listener_set_context(qdpn_listener_t *listener, void *context);
-
-/** Close the socket used by the listener.
- *
- * @param[in] listener the listener whose socket will be closed.
- */
-void qdpn_listener_close(qdpn_listener_t *listener);
-
-/** Frees the given listener.
- *
- * Assumes the listener's socket has been closed prior to call.
- *
- * @param[in] listener the listener object to free, no longer valid
- *            on return
- */
-void qdpn_listener_free(qdpn_listener_t *listener);
-
-
-
-
-/** qdpn_connector - the client API **/
-
-/** Construct a connector to the given remote address.
- *
- * @param[in] driver owner of this connection.
- * @param[in] host remote host to connect to.
- * @param[in] port remote port to connect to.
- * @param[in] protocol family to use (IPv4 or IPv6 or 0). If 0 (zero) is passed in the protocol family will be automatically determined from the address
- * @param[in] context application supplied, can be accessed via
- *                    qdpn_connector_context() @return a new connector
- *                    to the given remote, or NULL on error.
- */
-qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver,
-                                 const char *host,
-                                 const char *port,
-                                 const char *protocol_family,
-                                 void* context);
-
-/** Access the head connector for a driver.
- *
- * @param[in] driver the driver whose head connector will be returned
- *
- * @return the head connector for driver or NULL if there is none
- */
-qdpn_connector_t *qdpn_connector_head(qdpn_driver_t *driver);
-
-/** Access the next connector.
- *
- * @param[in] connector the connector whose next connector will be
- *            returned
- *
- * @return the next connector
- */
-qdpn_connector_t *qdpn_connector_next(qdpn_connector_t *connector);
-
-/** Service the given connector.
- *
- * Handle any inbound data, outbound data, or timing events pending on
- * the connector.
- *
- * @param[in] connector the connector to process.
- */
-void qdpn_connector_process(qdpn_connector_t *connector);
-
-/** Access the listener which opened this connector.
- *
- * @param[in] connector connector whose listener will be returned.
- * @return the listener which created this connector, or NULL if the
- *         connector has no listener (e.g. an outbound client
- *         connection)
- */
-qdpn_listener_t *qdpn_connector_listener(qdpn_connector_t *connector);
-
-/** Access the Authentication and Security context of the connector.
- *
- * @param[in] connector connector whose security context will be
- *                      returned
- * @return the Authentication and Security context for the connector,
- *         or NULL if none
- */
-pn_sasl_t *qdpn_connector_sasl(qdpn_connector_t *connector);
-
-/** Access the AMQP Connection associated with the connector.
- *
- * @param[in] connector the connector whose connection will be
- *                      returned
- * @return the connection context for the connector, or NULL if none
- */
-pn_connection_t *qdpn_connector_connection(qdpn_connector_t *connector);
-
-/** Assign the AMQP Connection associated with the connector.
- *
- * @param[in] connector the connector whose connection will be set.
- * @param[in] connection the connection to associate with the
- *                       connector
- */
-void qdpn_connector_set_connection(qdpn_connector_t *connector, pn_connection_t *connection);
-
-/** Access the application context that is associated with the
- *  connector.
- *
- * @param[in] connector the connector whose context is to be returned.
- * @return the application context that was passed to qdpn_connector()
- *         or qdpn_connector_fd()
- */
-void *qdpn_connector_context(qdpn_connector_t *connector);
-
-/** Assign a new application context to the connector.
- *
- * @param[in] connector the connector which will hold the context.
- * @param[in] context new application context to associate with the
- *                    connector
- */
-void qdpn_connector_set_context(qdpn_connector_t *connector, void *context);
-
-/** Access the name of the connector
- *
- * @param[in] connector the connector of interest
- * @return the name of the connector in the form of a null-terminated character string.
- */
-const char *qdpn_connector_name(const qdpn_connector_t *connector);
-
-/** Access the numeric host ip of the connector
- *
- * @param[in] connector the connector of interest
- * @return the numeric host ip address of the connector in the form of a null-terminated character string.
- */
-const char *qdpn_connector_hostip(const qdpn_connector_t *connector);
-
-/** Access the transport used by this connector.
- *
- * @param[in] connector connector whose transport will be returned
- * @return the transport, or NULL if none
- */
-pn_transport_t *qdpn_connector_transport(qdpn_connector_t *connector);
-
-/** Close the socket used by the connector.
- *
- * @param[in] connector the connector whose socket will be closed
- */
-void qdpn_connector_close(qdpn_connector_t *connector);
-
-/** Call when the socket is already closed, an the connector needs updating.
- *
- * @param[in] connector the connector whose socket has been closed
- */
-void qdpn_connector_after_close(qdpn_connector_t *connector);
-
-
-/** Socket has been closed externally, mark it closed.
- *
- * @param[in] connector the connector whose socket will be closed
- */
-void qdpn_connector_mark_closed(qdpn_connector_t *connector);
-
-/** Determine if the connector is closed.
- *
- * @return True if closed, otherwise false
- */
-bool qdpn_connector_closed(qdpn_connector_t *connector);
-
-bool qdpn_connector_failed(qdpn_connector_t *connector);
-
-
-/** Destructor for the given connector.
- *
- * Assumes the connector's socket has been closed prior to call.
- *
- * @param[in] connector the connector object to free. No longer
- *                      valid on return
- */
-void qdpn_connector_free(qdpn_connector_t *connector);
-
-/** Activate a connector when a criteria is met
- *
- * Set a criteria for a connector (i.e. it's transport is writable) that, once met,
- * the connector shall be placed in the driver's work queue.
- *
- * @param[in] connector The connector object to activate
- * @param[in] criteria  The criteria that must be met prior to activating the connector
- */
-void qdpn_connector_activate(qdpn_connector_t *connector, qdpn_activate_criteria_t criteria);
-
-/** Activate all of the open file descriptors
- */
-void qdpn_activate_all(qdpn_driver_t *driver);
-
-/** Return the activation status of the connector for a criteria
- *
- * Return the activation status (i.e. readable, writable) for the connector.  This function
- * has the side-effect of canceling the activation of the criteria.
- *
- * Please note that this function must not be used for normal AMQP connectors.  It is only
- * used for connectors created so the driver can track non-AMQP file descriptors.  Such
- * connectors are never passed into qdpn_connector_process.
- *
- * @param[in] connector The connector object to activate
- * @param[in] criteria  The criteria to test.  "Is this the reason the connector appeared
- *                      in the work list?"
- * @return true iff the criteria is activated on the connector.
- */
-bool qdpn_connector_activated(qdpn_connector_t *connector, qdpn_activate_criteria_t criteria);
-
-/** True if the connector has received a hangup */
-bool qdpn_connector_hangup(qdpn_connector_t *connector);
-
-/** Create a listener using the existing file descriptor.
- *
- * @param[in] driver driver that will 'own' this listener
- * @param[in] fd existing socket for listener to listen on
- * @param[in] context application-supplied, can be accessed via
- *                    qdpn_listener_context()
- * @return a new listener on the given host:port, NULL if error
- */
-qdpn_listener_t *qdpn_listener_fd(qdpn_driver_t *driver, pn_socket_t fd, void *context);
-
-pn_socket_t qdpn_listener_get_fd(qdpn_listener_t *listener);
-
-/** Create a connector using the existing file descriptor.
- *
- * @param[in] driver driver that will 'own' this connector.
- * @param[in] fd existing socket to use for this connector.
- * @param[in] context application-supplied, can be accessed via
- *                    qdpn_connector_context()
- * @return a new connector to the given host:port, NULL if error.
- */
-qdpn_connector_t *qdpn_connector_fd(qdpn_driver_t *driver, pn_socket_t fd, void *context);
-
-/** Get the file descriptor for this connector */
-int qdpn_connector_get_fd(qdpn_connector_t *connector);
-
-/** Set the wakeup time on the connector */
-void qdpn_connector_wakeup(qdpn_connector_t* c, pn_timestamp_t t);
-
-/** Current time according */
-pn_timestamp_t qdpn_now();
-
-/** Implementation of connector methods (e.g. these are different for HTTP connectors */
-typedef struct qdpn_connector_methods_t {
-    void (*process)(qdpn_connector_t *c);
-    void (*close)(qdpn_connector_t *c);
-} qdpn_connector_methods_t;
-
-/** Set new methods for a connector (e.g. because it is a HTTP connector) */
-void qdpn_connector_set_methods(qdpn_connector_t *c, qdpn_connector_methods_t *methods);
-
-/**@}*/
-
-#endif /* driver.h */

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/error.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/error.h b/include/qpid/dispatch/error.h
index 6bf7e82..f464e58 100644
--- a/include/qpid/dispatch/error.h
+++ b/include/qpid/dispatch/error.h
@@ -20,6 +20,7 @@
  */
 
 #include <qpid/dispatch/enum.h>
+#include <stdarg.h>
 
 /** @file
  * Thread-safe error handling mechansim for dispatch.
@@ -59,7 +60,13 @@ ENUM_DECLARE(qd_error);
  */
 #define qd_error(code, ...) qd_error_impl(code, __FILE__, __LINE__, __VA_ARGS__)
 
+/**
+ * Like qd_error but takes a va_list of format arguments
+ */
+#define qd_verror(code, fmt, ap) qd_error_vimpl(code, __FILE__, __LINE__, fmt, ap)
+
 qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char *fmt, ...);
+qd_error_t qd_error_vimpl(qd_error_t code, const char *file, int line, const char *fmt, va_list ap);
 
 /**
  * Clear thread-local error code and message.

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/router_core.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/router_core.h b/include/qpid/dispatch/router_core.h
index 2f749b7..0031ed7 100644
--- a/include/qpid/dispatch/router_core.h
+++ b/include/qpid/dispatch/router_core.h
@@ -220,18 +220,17 @@ int qdr_connection_process(qdr_connection_t *conn);
 /**
  * qdr_connection_activate_t callback
  *
- * Activate a connection for transmission (socket write).  This is called whenever
- * the core has deliveries on links, disposition updates on deliveries, or flow updates
- * to be sent across the connection.
+ * Activate a connection with pending work from the core to ensure it will be processed by
+ * the proactor: the core has deliveries on links, disposition updates on deliveries, or
+ * flow updates to be sent across the connection.
  *
  * IMPORTANT: This function will be invoked on the core thread.  It must never block,
  * delay, or do any lenghty computation.
  *
  * @param context The context supplied when the callback was registered
  * @param conn The connection object to be activated
- * @param awaken Iff true, awaken the driver poll loop after the activation
  */
-typedef void (*qdr_connection_activate_t) (void *context, qdr_connection_t *conn, bool awaken);
+typedef void (*qdr_connection_activate_t) (void *context, qdr_connection_t *conn);
 
 /**
  ******************************************************************************
@@ -560,7 +559,7 @@ typedef int  (*qdr_link_push_t)          (void *context, qdr_link_t *link, int l
 typedef void (*qdr_link_deliver_t)       (void *context, qdr_link_t *link, qdr_delivery_t *delivery, bool settled);
 typedef void (*qdr_delivery_update_t)    (void *context, qdr_delivery_t *dlv, uint64_t disp, bool settled);
 
-void qdr_connection_handlers(qdr_core_t                *core,
+void qdr_connection_handlers(qdr_core_t             *core,
                              void                      *context,
                              qdr_connection_activate_t  activate,
                              qdr_link_first_attach_t    first_attach,

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/server.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h
index a466ec0..ec885ae 100644
--- a/include/qpid/dispatch/server.h
+++ b/include/qpid/dispatch/server.h
@@ -24,8 +24,10 @@
 #include <proton/engine.h>
 #include <proton/event.h>
 
+struct qd_container_t;
+
 /**@file
- * Control server threads, signals and connections.
+ * Control server threads and connections.
  */
 
 /**
@@ -52,9 +54,8 @@ typedef void (*qd_deferred_t)(void *context, bool discard);
  * Run the server threads until completion - The blocking version.
  *
  * Start the operation of the server, including launching all of the worker
- * threads.  This function does not return until after the server has been
- * stopped.  The thread that calls qd_server_run is used as one of the worker
- * threads.
+ * threads.  Returns when all server threads have exited. The thread that calls
+ * qd_server_run is used as one of the worker threads.
  *
  * @param qd The dispatch handle returned by qd_dispatch.
  */
@@ -62,103 +63,16 @@ void qd_server_run(qd_dispatch_t *qd);
 
 
 /**
- * Start the server threads and return immediately - The non-blocking version.
+ * Tells the server to stop but doesn't wait for server to exit.
+ * The call to qd_server_run() will exit when all server threads have exited.
  *
- * Start the operation of the server, including launching all of the worker
- * threads.
+ * May be called from any thread or from a signal handler.
  *
  * @param qd The dispatch handle returned by qd_dispatch.
  */
-void qd_server_start(qd_dispatch_t *qd);
 
-
-/**
- * Stop the server
- *
- * Stop the server and join all of its worker threads.  This function may be
- * called from any thread.  When this function returns, all of the other
- * server threads have been closed and joined.  The calling thread will be the
- * only running thread in the process.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- */
 void qd_server_stop(qd_dispatch_t *qd);
 
-
-/**
- * Pause (quiesce) the server.
- *
- * This call blocks until all of the worker threads (except the one calling
- * this function) are finished processing and have been blocked.  When this
- * call returns, the calling thread is the only thread running in the process.
- *
- * If the calling process is *not* one of the server's worker threads, then
- * this function will block all of the worker threads before returning.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- */
-void qd_server_pause(qd_dispatch_t *qd);
-
-
-/**
- * Resume normal operation of a paused server.
- *
- * This call unblocks all of the worker threads so they can resume normal
- * connection processing.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- */
-void qd_server_resume(qd_dispatch_t *qd);
-
-
-/**
- * @}
- * @defgroup server_signal server_signal
- *
- * Server Signal Handling
- * 
- * @{
- */
-
-
-/**
- * Signal Handler
- *
- * Callback for signal handling.  This handler will be invoked on one of the
- * worker threads in an orderly fashion.  This callback is triggered by a call
- * to qd_server_signal.
- *
- * @param context The handler context supplied in qd_server_initialize.
- * @param signum The signal number that was passed into qd_server_signal.
- */
-typedef void (*qd_signal_handler_cb_t)(void* context, int signum);
-
-
-/**
- * Set the signal handler for the server.  The signal handler is invoked
- * cleanly on a worker thread after a call is made to qd_server_signal.  The
- * signal handler is optional and need not be set.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- * @param signal_handler The signal handler called when a registered signal is caught.
- * @param context Opaque context to be passed back in the callback function.
- */
-void qd_server_set_signal_handler(qd_dispatch_t *qd, qd_signal_handler_cb_t signal_handler, void *context);
-
-
-/**
- * Schedule the invocation of the Server's signal handler.
- *
- * This function is safe to call from any context, including an OS signal
- * handler or an Interrupt Service Routine.  It schedules the orderly
- * invocation of the Server's signal handler on one of the worker threads.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- * @param signum The signal number... TODO
- */
-void qd_server_signal(qd_dispatch_t *qd, int signum);
-
-
 /**
  * @}
  * @defgroup connection connection
@@ -459,76 +373,15 @@ typedef struct qd_server_config_t {
     char *host_port;
 
     /**
-     * Set for listeners that are part of the initial router configuration.
-     * An error in setting up initial listeners must shut down the router.
-     */
-    bool exit_on_error;
-
-    /**
      * @}
      */
 } qd_server_config_t;
 
 
 /**
- * Connection Event Handler
- *
- * Callback invoked when processing is needed on a proton connection.  This
- * callback shall be invoked on one of the server's worker threads.  The
- * server guarantees that no two threads shall be allowed to process a single
- * connection concurrently.  The implementation of this handler may assume
- * that it has exclusive access to the connection and its subservient
- * components (sessions, links, deliveries, etc.).
- *
- * @param handler_context The handler context supplied in qd_server_set_conn_handler.
- * @param conn_context The handler context supplied in qd_server_{connect,listen}.
- * @param event The event/reason for the invocation of the handler.
- * @param conn The connection that requires processing by the handler.
- * @return A value greater than zero if the handler did any proton processing for
- *         the connection.  If no work was done, zero is returned.
- */
-typedef int (*qd_conn_handler_cb_t)(void *handler_context, void* conn_context, qd_conn_event_t event, qd_connection_t *conn);
-
-/**
- * Proton Event Handler
- *
- * This callback is invoked when proton events for a connection require
- * processing.
- *
- * @param handler_context The handler context supplied in qd_server_set_conn_handler.
- * @param conn_context The handler context supplied in qd_server_{connect,listen}.
- * @param event The proton event being raised.
- * @param conn The connection associated with this proton event.
+ * Set the container, must be set prior to the invocation of qd_server_run.
  */
-typedef int (*qd_pn_event_handler_cb_t)(void *handler_context, void* conn_context, pn_event_t *event, qd_connection_t *conn);
-
-
-/**
- * Post event process handler
- * Invoke only after all proton events have been popped from the collector.
- *
- * @param conn The connection for which all proton events have been popped.
- */
-typedef void (*qd_pn_event_complete_cb_t)(void *handler_context, qd_connection_t *conn);
-
-
-/**
- * Set the connection event handler callback.
- *
- * Set the connection handler callback for the server.  This callback is
- * mandatory and must be set prior to the invocation of qd_server_run.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- * @param conn_handler The handler for processing connection-related events.
- * @param pn_event_handler The handler for proton events.
- * @param handler_context Context data to associate with the handler.
- */
-void qd_server_set_conn_handler(qd_dispatch_t *qd,
-                                qd_conn_handler_cb_t conn_handler,
-                                qd_pn_event_handler_cb_t pn_event_handler,
-                                qd_pn_event_complete_cb_t pn_event_complete_handler,
-                                void *handler_context);
-
+void qd_server_set_container(qd_dispatch_t *qd, struct qd_container_t *container);
 
 /**
  * Set the user context for a connection.
@@ -596,9 +449,8 @@ void qd_connection_set_user(qd_connection_t *conn);
  * internal work list and be invoked for processing by a worker thread.
  *
  * @param conn The connection over which the application wishes to send data
- * @param awaken Iff true, wakeup the driver poll after the activation
  */
-void qd_server_activate(qd_connection_t *conn, bool awaken);
+void qd_server_activate(qd_connection_t *conn);
 
 
 /**
@@ -620,15 +472,6 @@ bool qd_connection_inbound(qd_connection_t *conn);
 
 
 /**
- * Get the event collector for a connection.
- *
- * @param conn Connection object supplied in QD_CONN_EVENT_{LISTENER,CONNETOR}_OPEN
- * @return The pn_collector associated with the connection.
- */
-pn_collector_t *qd_connection_collector(qd_connection_t *conn);
-
-
-/**
  * Get the connection id of a connection.
  *
  * @param conn Connection object supplied in QD_CONN_EVENT_{LISTENER,CONNETOR}_OPEN
@@ -658,67 +501,14 @@ void qd_connection_invoke_deferred(qd_connection_t *conn, qd_deferred_t call, vo
 
 
 /**
- * Write accessor to the connection's proton-event stall flag.
- * When set no further events are processed on this connection.
- * Used during processing of policy decisions to hold off incoming
- * pipeline of amqp events.
- *
- * @param conn Connection object
- * @param stall Value of stall flag
- */
-void qd_connection_set_event_stall(qd_connection_t *conn, bool stall);
-
-
-/**
- * Create a listener for incoming connections.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- * @param config Pointer to a configuration block for this listener.  This block will be
- *               referenced by the server, not copied.  The referenced record must remain
- *               in-scope for the life of the listener.
- * @param context User context passed back in the connection handler.
- * @return A pointer to the new listener, or NULL in case of failure.
- */
-qd_listener_t *qd_server_listen(qd_dispatch_t *qd, const qd_server_config_t *config, void *context);
-
-
-/**
- * Free the resources associated with a listener.
- *
- * @param li A listener pointer returned by qd_listen.
+ * Listen for incoming connections, return true if listening succeeded.
  */
-void qd_server_listener_free(qd_listener_t* li);
-
+bool qd_listener_listen(qd_listener_t *l);
 
 /**
- * Close a listener so it will accept no more connections.
- *
- * @param li A listener pointer returned by qd_listen.
+ * Initiate an outgoing connection. Returns true if successful.
  */
-void qd_server_listener_close(qd_listener_t* li);
-
-
-/**
- * Create a connector for an outgoing connection.
- *
- * @param qd The dispatch handle returned by qd_dispatch.
- * @param config Pointer to a configuration block for this connector.  This block will be
- *               referenced by the server, not copied.  The referenced record must remain
- *               in-scope for the life of the connector..
- * @param context User context passed back in the connection handler.
- * @return A pointer to the new connector, or NULL in case of failure.
- */
-qd_connector_t *qd_server_connect(qd_dispatch_t *qd, const qd_server_config_t *config, void *context);
-
-
-/**
- * Free the resources associated with a connector.
- *
- * @param ct A connector pointer returned by qd_connect.
- */
-void qd_server_connector_free(qd_connector_t* ct);
-
-
+bool qd_connector_connect(qd_connector_t *ct);
 
 /**
  * Store address of display name service py object for C code use

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/include/qpid/dispatch/timer.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/timer.h b/include/qpid/dispatch/timer.h
index e5ba6ab..d0592d3 100644
--- a/include/qpid/dispatch/timer.h
+++ b/include/qpid/dispatch/timer.h
@@ -33,7 +33,10 @@
  */
 
 typedef struct qd_timer_t qd_timer_t;
+/** Absolute time stamp, milliseconds since epoch */
 typedef int64_t qd_timestamp_t;
+/** Relative duration in milliseconds */
+typedef int64_t qd_duration_t;
 
 /**
  * Timer Callback
@@ -77,7 +80,7 @@ void qd_timer_free(qd_timer_t *timer);
  * @param msec The minimum number of milliseconds of delay until the timer fires.
  *             If 0 is supplied, the timer will be scheduled to fire immediately.
  */
-void qd_timer_schedule(qd_timer_t *timer, qd_timestamp_t msec);
+void qd_timer_schedule(qd_timer_t *timer, qd_duration_t msec);
 
 
 /**
@@ -90,6 +93,11 @@ void qd_timer_schedule(qd_timer_t *timer, qd_timestamp_t msec);
 void qd_timer_cancel(qd_timer_t *timer);
 
 /**
+ * The current time.
+ */
+qd_timestamp_t qd_timer_now() ;
+
+/**
  * @}
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/python/qpid_dispatch/management/qdrouter.json
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index 667c0ec..3f66abb 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -562,9 +562,9 @@
             "operations": ["CREATE", "DELETE"],
             "attributes": {
                 "host": {
-                    "description":"IP address: ipv4 or ipv6 literal or a host name",
+                    "description":"A host name, IPV4 or IPV6 literal, or the empty string. The empty string listens on all local addresses. A host name listens on all addresses associated with the name. An IPV6 literal address (or wildcard '[::]') listens only for IPV6. An IPV4 literal address (or wildcard '0.0.0.0') listens only for IPV4.",
                     "type": "string",
-                    "default": "127.0.0.1",
+                    "default": "",
                     "create": true
                 },
                 "port": {

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/python/qpid_dispatch_internal/router/address.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/router/address.py b/python/qpid_dispatch_internal/router/address.py
index 4092ac7..0cff578 100644
--- a/python/qpid_dispatch_internal/router/address.py
+++ b/python/qpid_dispatch_internal/router/address.py
@@ -27,11 +27,6 @@ class Address(str):
     Provides a central place for logic to construct addresses of various types.
     """
 
-    # FIXME aconway 2015-02-06: not finished:
-    # - Move to C, make accessible in C code also - provide python wrapper.
-    # - Provide access to parts of address using C field iterator, avoid duplicating that logic
-    # - (Maybe) separate address logic out of general field iterator logic for clarity.
-
     AMQP="amqp:"
     TOPO="_topo"
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/router/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/router/CMakeLists.txt b/router/CMakeLists.txt
index 5681e00..52e9ccc 100644
--- a/router/CMakeLists.txt
+++ b/router/CMakeLists.txt
@@ -35,6 +35,6 @@ set(router_SOURCES
 SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${QPID_DISPATCH_HOME}")
 
 add_executable(qdrouterd ${router_SOURCES})
-target_link_libraries(qdrouterd qpid-dispatch ${proton_lib})
+target_link_libraries(qdrouterd qpid-dispatch)
 
 install(TARGETS qdrouterd RUNTIME DESTINATION sbin)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/router/src/main.c
----------------------------------------------------------------------
diff --git a/router/src/main.c b/router/src/main.c
index c09b0a8..ee084df 100644
--- a/router/src/main.c
+++ b/router/src/main.c
@@ -38,42 +38,21 @@ static const char* argv0 = 0;
 
 /**
  * This is the OS signal handler, invoked on an undetermined thread at a completely
- * arbitrary point of time.  It is not safe to do anything here but signal the dispatch
- * server with the signal number.
+ * arbitrary point of time.
  */
 static void signal_handler(int signum)
 {
-    qd_server_signal(dispatch, signum);
-}
-
-
-/**
- * This signal handler is called cleanly by one of the server's worker threads in
- * response to an earlier call to qd_server_signal.
- */
-static void server_signal_handler(void* context, int signum)
-{
-    qd_server_pause(dispatch);
-
     switch (signum) {
     case SIGINT:
         exit_with_sigint = 1;
         // fallthrough
-
     case SIGQUIT:
     case SIGTERM:
-        fflush(stdout);
-        qd_server_stop(dispatch);
-        break;
-
-    case SIGHUP:
+        qd_server_stop(dispatch); /* qpid_server_stop is signal-safe */
         break;
-
     default:
         break;
     }
-
-    qd_server_resume(dispatch);
 }
 
 static void check(int fd) {
@@ -109,9 +88,6 @@ static void main_process(const char *config_path, const char *python_pkgdir, int
     qd_dispatch_load_config(dispatch, config_path);
     check(fd);
 
-    (void)server_signal_handler; (void)signal_handler;
-    qd_server_set_signal_handler(dispatch, server_signal_handler, 0);
-
     signal(SIGHUP,  signal_handler);
     signal(SIGQUIT, signal_handler);
     signal(SIGTERM, signal_handler);
@@ -133,6 +109,7 @@ static void main_process(const char *config_path, const char *python_pkgdir, int
     dispatch = NULL;
     qd_dispatch_free(d);
 
+    fflush(stdout);
     if (exit_with_sigint) {
         signal(SIGINT, SIG_DFL);
         kill(getpid(), SIGINT);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4c00206..17674d4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -62,7 +62,6 @@ set(qpid_dispatch_SOURCES
   message.c
   parse.c
   policy.c
-  posix/driver.c
   posix/threading.c
   python_embedded.c
   router_agent.c
@@ -112,7 +111,7 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
 endif (CMAKE_C_COMPILER_ID STREQUAL "GNU")
 
 add_library(qpid-dispatch SHARED ${qpid_dispatch_SOURCES})
-target_link_libraries(qpid-dispatch ${Proton_LIBRARIES} ${pthread_lib} ${rt_lib} ${dl_lib} ${PYTHON_LIBRARIES} ${LIBWEBSOCKETS_LIBRARIES})
+target_link_libraries(qpid-dispatch ${ProtonCore_LIBRARIES} ${ProtonProactor_LIBRARIES} ${pthread_lib} ${rt_lib} ${dl_lib} ${PYTHON_LIBRARIES} ${LIBWEBSOCKETS_LIBRARIES})
 set_target_properties(qpid-dispatch PROPERTIES
   LINK_FLAGS "${CATCH_UNDEFINED}"
   )

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/amqp.c
----------------------------------------------------------------------
diff --git a/src/amqp.c b/src/amqp.c
index 0c49a16..cf9f775 100644
--- a/src/amqp.c
+++ b/src/amqp.c
@@ -63,5 +63,3 @@ const char * const QD_AMQP_COND_PRECONDITION_FAILED = "amqp:precondition-failed"
 const char * const QD_AMQP_COND_RESOURCE_DELETED = "amqp:resource-deleted";
 const char * const QD_AMQP_COND_ILLEGAL_STATE = "amqp:illegal-state";
 const char * const QD_AMQP_COND_FRAME_SIZE_TOO_SMALL = "amqp:frame-size-too-small";
-
-const char * const QD_COND_NAME = "router:error";

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/connection_manager.c
----------------------------------------------------------------------
diff --git a/src/connection_manager.c b/src/connection_manager.c
index 8957185..4bc18ce 100644
--- a/src/connection_manager.c
+++ b/src/connection_manager.c
@@ -22,6 +22,7 @@
 #include <qpid/dispatch/threading.h>
 #include <qpid/dispatch/atomic.h>
 #include <qpid/dispatch/failoverlist.h>
+#include <proton/listener.h>
 #include "dispatch_private.h"
 #include "connection_manager_private.h"
 #include "server_private.h"
@@ -47,29 +48,13 @@ struct qd_config_ssl_profile_t {
     char        *ssl_private_key_file;
 };
 
-struct qd_config_listener_t {
-    qd_listener_t           *listener;
-    qd_server_config_t       configuration;
-    DEQ_LINKS(qd_config_listener_t);
-};
-
-DEQ_DECLARE(qd_config_listener_t, qd_config_listener_list_t);
 DEQ_DECLARE(qd_config_ssl_profile_t, qd_config_ssl_profile_list_t);
 
-
-struct qd_config_connector_t {
-    DEQ_LINKS(qd_config_connector_t);
-    qd_connector_t          *connector;
-    qd_server_config_t       configuration;
-};
-
-DEQ_DECLARE(qd_config_connector_t, qd_config_connector_list_t);
-
 struct qd_connection_manager_t {
     qd_log_source_t              *log_source;
     qd_server_t                  *server;
-    qd_config_listener_list_t     config_listeners;
-    qd_config_connector_list_t    config_connectors;
+    qd_listener_list_t            listeners;
+    qd_connector_list_t           connectors;
     qd_config_ssl_profile_list_t  config_ssl_profiles;
 };
 
@@ -108,11 +93,12 @@ static qd_config_ssl_profile_t *qd_find_ssl_profile(qd_connection_manager_t *cm,
     return 0;
 }
 
-static void qd_server_config_free(qd_server_config_t *cf)
+void qd_server_config_free(qd_server_config_t *cf)
 {
     if (!cf) return;
     free(cf->host);
     free(cf->port);
+    free(cf->host_port);
     free(cf->role);
     if (cf->http_root)       free(cf->http_root);
     if (cf->name)            free(cf->name);
@@ -199,6 +185,10 @@ static void set_config_host(qd_server_config_t *config, qd_entity_t* entity)
     }
 
     assert(config->host);
+
+    int hplen = strlen(config->host) + strlen(config->port) + 2;
+    config->host_port = malloc(hplen);
+    snprintf(config->host_port, hplen, "%s:%s", config->host, config->port);
 }
 
 
@@ -402,6 +392,7 @@ static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *conf
     return qd_error_code();
 }
 
+
 bool is_log_component_enabled(qd_log_bits log_message, char *component_name) {
 
     for(int i=0;;i++) {
@@ -507,45 +498,32 @@ static void log_config(qd_log_source_t *log, qd_server_config_t *c, const char *
 }
 
 
-static void config_listener_free(qd_connection_manager_t *cm, qd_config_listener_t *cl)
-{
-    if (cl->listener) {
-        qd_server_listener_close(cl->listener);
-        qd_server_listener_free(cl->listener);
-        cl->listener = 0;
-    }
-    qd_server_config_free(&cl->configuration);
-    free(cl);
-}
-
-
-qd_config_listener_t *qd_dispatch_configure_listener(qd_dispatch_t *qd, qd_entity_t *entity)
+qd_listener_t *qd_dispatch_configure_listener(qd_dispatch_t *qd, qd_entity_t *entity)
 {
     qd_connection_manager_t *cm = qd->connection_manager;
-    qd_config_listener_t *cl = NEW(qd_config_listener_t);
-    cl->listener = 0;
-
-    if (load_server_config(qd, &cl->configuration, entity) != QD_ERROR_NONE) {
-        qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create config listener: %s", qd_error_message());
-        config_listener_free(qd->connection_manager, cl);
+    qd_listener_t *li = qd_server_listener(qd->server);
+    if (!li || load_server_config(qd, &li->config, entity) != QD_ERROR_NONE) {
+        qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create listener: %s", qd_error_message());
+        qd_listener_decref(li);
         return 0;
     }
     char *fol = qd_entity_opt_string(entity, "failoverList", 0);
     if (fol) {
-        cl->configuration.failover_list = qd_failover_list(fol);
+        li->config.failover_list = qd_failover_list(fol);
         free(fol);
-        if (cl->configuration.failover_list == 0) {
-            qd_log(cm->log_source, QD_LOG_ERROR, "Error parsing failover list: %s", qd_error_message());
-            config_listener_free(qd->connection_manager, cl);
+        if (li->config.failover_list == 0) {
+            qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create listener, bad failover list: %s",
+                   qd_error_message());
+            qd_listener_decref(li);
             return 0;
         }
     } else {
-        cl->configuration.failover_list = 0;
+        li->config.failover_list = 0;
     }
-    DEQ_ITEM_INIT(cl);
-    DEQ_INSERT_TAIL(cm->config_listeners, cl);
-    log_config(cm->log_source, &cl->configuration, "Listener");
-    return cl;
+    DEQ_ITEM_INIT(li);
+    DEQ_INSERT_TAIL(cm->listeners, li);
+    log_config(cm->log_source, &li->config, "Listener");
+    return li;
 }
 
 
@@ -561,32 +539,19 @@ qd_error_t qd_entity_refresh_connector(qd_entity_t* entity, void *impl)
 }
 
 
-static void config_connector_free(qd_connection_manager_t *cm, qd_config_connector_t *cc)
+qd_connector_t *qd_dispatch_configure_connector(qd_dispatch_t *qd, qd_entity_t *entity)
 {
-    if (cc->connector) {
-        qd_server_connector_free(cc->connector);
-        qd_server_config_free(&cc->configuration);
-    }
-    free(cc);
-}
-
-
-qd_config_connector_t *qd_dispatch_configure_connector(qd_dispatch_t *qd, qd_entity_t *entity)
-{
-    qd_error_clear();
     qd_connection_manager_t *cm = qd->connection_manager;
-    qd_config_connector_t *cc = NEW(qd_config_connector_t);
-    ZERO(cc);
-
-    if (load_server_config(qd, &cc->configuration, entity) != QD_ERROR_NONE) {
-        qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create config connector: %s", qd_error_message());
-        config_connector_free(qd->connection_manager, cc);
-        return 0;
+    qd_connector_t *ct = qd_server_connector(qd->server);
+    if (ct && load_server_config(qd, &ct->config, entity) == QD_ERROR_NONE) {
+        DEQ_ITEM_INIT(ct);
+        DEQ_INSERT_TAIL(cm->connectors, ct);
+        log_config(cm->log_source, &ct->config, "Connector");
+        return ct;
     }
-    DEQ_ITEM_INIT(cc);
-    DEQ_INSERT_TAIL(cm->config_connectors, cc);
-    log_config(cm->log_source, &cc->configuration, "Connector");
-    return cc;
+    qd_log(cm->log_source, QD_LOG_ERROR, "Unable to create connector: %s", qd_error_message());
+    qd_connector_decref(ct);
+    return 0;
 }
 
 
@@ -598,8 +563,8 @@ qd_connection_manager_t *qd_connection_manager(qd_dispatch_t *qd)
 
     cm->log_source = qd_log_source("CONN_MGR");
     cm->server     = qd->server;
-    DEQ_INIT(cm->config_listeners);
-    DEQ_INIT(cm->config_connectors);
+    DEQ_INIT(cm->listeners);
+    DEQ_INIT(cm->connectors);
     DEQ_INIT(cm->config_ssl_profiles);
 
     return cm;
@@ -609,18 +574,18 @@ qd_connection_manager_t *qd_connection_manager(qd_dispatch_t *qd)
 void qd_connection_manager_free(qd_connection_manager_t *cm)
 {
     if (!cm) return;
-    qd_config_listener_t *cl = DEQ_HEAD(cm->config_listeners);
-    while (cl) {
-        DEQ_REMOVE_HEAD(cm->config_listeners);
-        config_listener_free(cm, cl);
-        cl = DEQ_HEAD(cm->config_listeners);
+    qd_listener_t *li = DEQ_HEAD(cm->listeners);
+    while (li) {
+        DEQ_REMOVE_HEAD(cm->listeners);
+        qd_listener_decref(li);
+        li = DEQ_HEAD(cm->listeners);
     }
 
-    qd_config_connector_t *cc = DEQ_HEAD(cm->config_connectors);
-    while (cc) {
-        DEQ_REMOVE_HEAD(cm->config_connectors);
-        config_connector_free(cm, cc);
-        cc = DEQ_HEAD(cm->config_connectors);
+    qd_connector_t *c = DEQ_HEAD(cm->connectors);
+    while (c) {
+        DEQ_REMOVE_HEAD(cm->connectors);
+        qd_connector_decref(c);
+        c = DEQ_HEAD(cm->connectors);
     }
 
     qd_config_ssl_profile_t *sslp = DEQ_HEAD(cm->config_ssl_profiles);
@@ -637,25 +602,26 @@ void qd_connection_manager_free(qd_connection_manager_t *cm)
 void qd_connection_manager_start(qd_dispatch_t *qd)
 {
     static bool first_start = true;
-    qd_config_listener_t  *cl = DEQ_HEAD(qd->connection_manager->config_listeners);
-    qd_config_connector_t *cc = DEQ_HEAD(qd->connection_manager->config_connectors);
+    qd_listener_t  *li = DEQ_HEAD(qd->connection_manager->listeners);
+    qd_connector_t *ct = DEQ_HEAD(qd->connection_manager->connectors);
 
-    while (cl) {
-        if (cl->listener == 0 ) {
-            cl->listener = qd_server_listen(qd, &cl->configuration, cl);
-            if (!cl->listener &&  first_start) {
+    while (li) {
+        if (!li->pn_listener) {
+            qd_listener_listen(li);
+            if (!li->pn_listener && first_start) {
                 qd_log(qd->connection_manager->log_source, QD_LOG_CRITICAL,
-                       "Socket bind failed during initial configuration");
+                       "Listen on %s failed during initial config", li->config.host_port);
                 exit(1);
+            } else {
+                li->exit_on_error = first_start;
             }
         }
-        cl = DEQ_NEXT(cl);
+        li = DEQ_NEXT(li);
     }
 
-    while (cc) {
-        if (cc->connector == 0)
-            cc->connector = qd_server_connect(qd, &cc->configuration, cc);
-        cc = DEQ_NEXT(cc);
+    while (ct) {
+        qd_connector_connect(ct);
+        ct = DEQ_NEXT(ct);
     }
 
     first_start = false;
@@ -664,12 +630,13 @@ void qd_connection_manager_start(qd_dispatch_t *qd)
 
 void qd_connection_manager_delete_listener(qd_dispatch_t *qd, void *impl)
 {
-    qd_config_listener_t *cl = (qd_config_listener_t*) impl;
-
-    if (cl) {
-        qd_server_listener_close(cl->listener);
-        DEQ_REMOVE(qd->connection_manager->config_listeners, cl);
-        config_listener_free(qd->connection_manager, cl);
+    qd_listener_t *li = (qd_listener_t*) impl;
+    if (li) {
+        if (li->pn_listener) {
+            pn_listener_close(li->pn_listener);
+        }
+        DEQ_REMOVE(qd->connection_manager->listeners, li);
+        qd_listener_decref(li);
     }
 }
 
@@ -681,19 +648,30 @@ void qd_connection_manager_delete_ssl_profile(qd_dispatch_t *qd, void *impl)
 }
 
 
+static void deferred_close(void *context, bool discard) {
+    if (!discard) {
+        pn_connection_close((pn_connection_t*)context);
+    }
+}
+
+
 void qd_connection_manager_delete_connector(qd_dispatch_t *qd, void *impl)
 {
-    qd_config_connector_t *cc = (qd_config_connector_t*) impl;
-
-    if (cc) {
-        DEQ_REMOVE(qd->connection_manager->config_connectors, cc);
-        config_connector_free(qd->connection_manager, cc);
+    qd_connector_t *ct = (qd_connector_t*) impl;
+    if (ct) {
+        sys_mutex_lock(ct->lock);
+        if (ct->ctx && ct->ctx->pn_conn) {
+            qd_connection_invoke_deferred(ct->ctx, deferred_close, ct->ctx->pn_conn);
+        }
+        sys_mutex_unlock(ct->lock);
+        DEQ_REMOVE(qd->connection_manager->connectors, ct);
+        qd_connector_decref(ct);
     }
 }
 
 
-const char *qd_config_connector_name(qd_config_connector_t *cc)
+const char *qd_connector_name(qd_connector_t *ct)
 {
-    return cc ? cc->configuration.name : 0;
+    return ct ? ct->config.name : 0;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/container.c
----------------------------------------------------------------------
diff --git a/src/container.c b/src/container.c
index 1fb83a6..ddc0418 100644
--- a/src/container.c
+++ b/src/container.c
@@ -106,7 +106,6 @@ static void setup_outgoing_link(qd_container_t *container, pn_link_t *pn_link)
         pn_link_close(pn_link);
         return;
     }
-
     link->pn_sess    = pn_link_session(pn_link);
     link->pn_link    = pn_link;
     link->direction  = QD_OUTGOING;
@@ -234,7 +233,7 @@ static void notify_opened(qd_container_t *container, qd_connection_t *conn, void
 
 void policy_notify_opened(void *container, qd_connection_t *conn, void *context)
 {
-	notify_opened((qd_container_t *)container, (qd_connection_t *)conn, context);
+    notify_opened((qd_container_t *)container, (qd_connection_t *)conn, context);
 }
 
 static void notify_closed(qd_container_t *container, qd_connection_t *conn, void *context)
@@ -287,27 +286,21 @@ static void close_links(qd_container_t *container, pn_connection_t *conn, bool p
 }
 
 
-static int close_handler(qd_container_t *container, void* conn_context, pn_connection_t *conn, qd_connection_t* qd_conn)
+static int close_handler(qd_container_t *container, pn_connection_t *conn, qd_connection_t* qd_conn)
 {
     //
     // Close all links, passing QD_LOST as the reason.  These links are not
     // being properly 'detached'.  They are being orphaned.
     //
     close_links(container, conn, true);
-
-    // close the connection
-    pn_connection_close(conn);
-
-    notify_closed(container, qd_conn, conn_context);
+    notify_closed(container, qd_conn, qd_connection_get_context(qd_conn));
     return 0;
 }
 
 
-static int writable_handler(qd_container_t *container, pn_connection_t *conn, qd_connection_t* qd_conn)
+static void writable_handler(qd_container_t *container, pn_connection_t *conn, qd_connection_t* qd_conn)
 {
     const qd_node_type_t *nt;
-    int                   event_count = 0;
-
     //
     // Note the locking structure in this function.  Generally this would be unsafe, but since
     // this particular list is only ever appended to and never has items inserted or deleted,
@@ -320,14 +313,12 @@ static int writable_handler(qd_container_t *container, pn_connection_t *conn, qd
     while (nt_item) {
         nt = nt_item->ntype;
         if (nt->writable_handler)
-            event_count += nt->writable_handler(nt->type_context, qd_conn, 0);
+            nt->writable_handler(nt->type_context, qd_conn, 0);
 
         sys_mutex_lock(container->lock);
         nt_item = DEQ_NEXT(nt_item);
         sys_mutex_unlock(container->lock);
     }
-
-    return event_count;
 }
 
 /**
@@ -382,7 +373,18 @@ static void add_link_to_free_list(qd_pn_free_link_session_list_t  *free_link_ses
 
 }
 
-void pn_event_complete_handler(void *handler_context, qd_connection_t *qd_conn)
+
+/*
+ * FIXME aconway 2017-04-12: IMO this should not be necessary, we should
+ * be able to pn_*_free links and sessions directly the handler function.
+ * They will not actually be freed from memory till the event, connection,
+ * proactor etc. have all released their references.
+ *
+ * The need for these lists may indicate a router bug, where the router is
+ * using links/sessions after they are freed. Investigate and simplify if
+ * possible.
+ */
+static void conn_event_complete(qd_connection_t *qd_conn)
 {
     qd_pn_free_link_session_t *to_free_link = DEQ_HEAD(qd_conn->free_link_session_list);
     qd_pn_free_link_session_t *to_free_session = DEQ_HEAD(qd_conn->free_link_session_list);
@@ -405,27 +407,38 @@ void pn_event_complete_handler(void *handler_context, qd_connection_t *qd_conn)
     }
 }
 
-int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *event, qd_connection_t *qd_conn)
+
+void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
 {
-    qd_container_t  *container = (qd_container_t*) handler_context;
-    pn_connection_t *conn      = qd_connection_pn(qd_conn);
-    pn_session_t    *ssn;
-    pn_link_t       *pn_link;
-    qd_link_t       *qd_link;
-    pn_delivery_t   *delivery;
+    pn_connection_t *conn = pn_event_connection(event);
+    qd_connection_t *qd_conn = conn ? pn_connection_get_context(conn) : NULL;
+    pn_session_t    *ssn = NULL;
+    pn_link_t       *pn_link = NULL;
+    qd_link_t       *qd_link = NULL;
+    pn_delivery_t   *delivery = NULL;
 
     switch (pn_event_type(event)) {
+
     case PN_CONNECTION_REMOTE_OPEN :
         qd_connection_set_user(qd_conn);
         if (pn_connection_state(conn) & PN_LOCAL_UNINIT) {
             // This Open is an externally initiated connection
             // Let policy engine decide
-            qd_connection_set_event_stall(qd_conn, true);
+            /* TODO aconway 2017-04-11: presently the policy test is run
+             * in the current thread.
+             *
+             * If/when the policy test can run in another thread, the connection
+             * can be stalled by saving the current pn_event_batch and passing it
+             * to pn_proactor_done() when the policy check is complete. Note we
+             * can't run the policy check as a deferred function on the current
+             * connection since by stalling the current connection it will never be
+             * run, so we need some other thread context to run it in.
+             */
             qd_conn->open_container = (void *)container;
-            qd_connection_invoke_deferred(qd_conn, qd_policy_amqp_open, qd_conn);
+            qd_policy_amqp_open(qd_conn);
         } else {
             // This Open is in response to an internally initiated connection
-            notify_opened(container, qd_conn, conn_context);
+            notify_opened(container, qd_conn, qd_connection_get_context(qd_conn));
         }
         break;
 
@@ -451,20 +464,21 @@ int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *even
             }
         }
         break;
+
     case PN_SESSION_LOCAL_CLOSE :
         ssn = pn_event_session(event);
-
         pn_link = pn_link_head(conn, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED);
         while (pn_link) {
-                qd_link_t *qd_link = (qd_link_t*) pn_link_get_context(pn_link);
-                qd_link->pn_link = 0;
-                pn_link = pn_link_next(pn_link, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED);
+            qd_link_t *qd_link = (qd_link_t*) pn_link_get_context(pn_link);
+            qd_link->pn_link = 0;
+            pn_link = pn_link_next(pn_link, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED);
         }
 
         if (pn_session_state(ssn) == (PN_LOCAL_CLOSED | PN_REMOTE_CLOSED)) {
             add_session_to_free_list(&qd_conn->free_link_session_list,ssn);
         }
         break;
+
     case PN_SESSION_REMOTE_CLOSE :
         if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) {
             ssn = pn_event_session(event);
@@ -600,28 +614,20 @@ int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *even
         }
         break;
 
-     default:
-      break;
-    }
-    return 1;
-}
-
-
-static int handler(void *handler_context, void *conn_context, qd_conn_event_t event, qd_connection_t *qd_conn)
-{
-    qd_container_t  *container = (qd_container_t*) handler_context;
-    pn_connection_t *conn      = qd_connection_pn(qd_conn);
-
-    switch (event) {
+    case PN_CONNECTION_WAKE:
+        writable_handler(container, conn, qd_conn);
+        break;
 
-    case QD_CONN_EVENT_CLOSE:
-        return close_handler(container, conn_context, conn, qd_conn);
+    case PN_TRANSPORT_CLOSED:
+        close_handler(container, conn, qd_conn);
+        break;
 
-    case QD_CONN_EVENT_WRITABLE:
-        return writable_handler(container, conn, qd_conn);
+    default:
+        break;
+    }
+    if (qd_conn) {
+        conn_event_complete(qd_conn);
     }
-
-    return 0;
 }
 
 
@@ -639,8 +645,7 @@ qd_container_t *qd_container(qd_dispatch_t *qd)
     DEQ_INIT(container->nodes);
     DEQ_INIT(container->node_type_list);
 
-    qd_server_set_conn_handler(qd, handler, pn_event_handler, pn_event_complete_handler, container);
-
+    qd_server_set_container(qd, container);
     qd_log(container->log_source, QD_LOG_TRACE, "Container Initialized");
     return container;
 }
@@ -801,6 +806,9 @@ qd_lifetime_policy_t qd_container_node_get_life_policy(const qd_node_t *node)
 qd_link_t *qd_link(qd_node_t *node, qd_connection_t *conn, qd_direction_t dir, const char* name)
 {
     qd_link_t *link = new_qd_link_t();
+    if (!link) {
+        return NULL;
+    }
     const qd_server_config_t * cf = qd_connection_config(conn);
 
     link->pn_sess = pn_session(qd_connection_pn(conn));
@@ -932,7 +940,7 @@ void qd_link_activate(qd_link_t *link)
     if (!ctx)
         return;
 
-    qd_server_activate(ctx, true);
+    qd_server_activate(ctx);
 }
 
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/error.c
----------------------------------------------------------------------
diff --git a/src/error.c b/src/error.c
index 6b7239a..b837a65 100644
--- a/src/error.c
+++ b/src/error.c
@@ -64,7 +64,7 @@ void qd_error_initialize() {
     log_source = qd_log_source("ERROR");
 }
 
-qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char *fmt, ...) {
+qd_error_t qd_error_vimpl(qd_error_t code, const char *file, int line, const char *fmt, va_list ap) {
     ts.error_code = code;
     if (code) {
         char *begin = ts.error_message;
@@ -75,10 +75,7 @@ qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char
             aprintf(&begin, end, "%s: ", name);
         else
             aprintf(&begin, end, "%d: ", code);
-        va_list arglist;
-        va_start(arglist, fmt);
-        vaprintf(&begin, end, fmt, arglist);
-        va_end(arglist);
+        vaprintf(&begin, end, fmt, ap);
         // NOTE: Use the file/line from the qd_error macro, not this line in error.c
         qd_log_impl(log_source, QD_LOG_ERROR, file, line, "%s", qd_error_message());
         return code;
@@ -88,6 +85,14 @@ qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char
     return 0;
 }
 
+qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char *fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    qd_error_t err = qd_error_vimpl(code, file, line, fmt, ap);
+    va_end(ap);
+    return err;
+}
+
 qd_error_t qd_error_clear() {
     ts.error_code = 0;
     snprintf(ts.error_message, ERROR_MAX, "No Error");

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/http-none.c
----------------------------------------------------------------------
diff --git a/src/http-none.c b/src/http-none.c
index b9af9e1..a8953e5 100644
--- a/src/http-none.c
+++ b/src/http-none.c
@@ -18,7 +18,6 @@
  */
 
 #include <qpid/dispatch/log.h>
-#include <qpid/dispatch/driver.h>
 #include "http.h"
 
 /* No HTTP implementation available. */

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/policy.c
----------------------------------------------------------------------
diff --git a/src/policy.c b/src/policy.c
index 39ead3c..a55f245 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -184,9 +184,8 @@ qd_error_t qd_entity_refresh_policy(qd_entity_t* entity, void *unused) {
 // error conditions.
 //
 
-bool qd_policy_socket_accept(void *context, const char *hostname)
+bool qd_policy_socket_accept(qd_policy_t *policy, const char *hostname)
 {
-    qd_policy_t *policy = (qd_policy_t *)context;
     bool result = true;
     if (n_connections < policy->max_connection_limit) {
         // connection counted and allowed
@@ -205,10 +204,8 @@ bool qd_policy_socket_accept(void *context, const char *hostname)
 
 //
 //
-void qd_policy_socket_close(void *context, const qd_connection_t *conn)
+void qd_policy_socket_close(qd_policy_t *policy, const qd_connection_t *conn)
 {
-    qd_policy_t *policy = (qd_policy_t *)context;
-
     n_connections -= 1;
     assert (n_connections >= 0);
     if (policy->enableVhostPolicy) {
@@ -567,8 +564,7 @@ bool _qd_policy_approve_link_name(const char *username, const char *allowed, con
     return result;
 }
 
-//
-//
+
 bool qd_policy_approve_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_conn)
 {
     const char *hostip = qd_connection_hostip(qd_conn);
@@ -678,55 +674,48 @@ bool qd_policy_approve_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *q
 }
 
 
-//
-//
-void qd_policy_amqp_open(void *context, bool discard)
-{
-    qd_connection_t *qd_conn = (qd_connection_t *)context;
-    if (!discard) {
-        pn_connection_t *conn = qd_connection_pn(qd_conn);
-        qd_dispatch_t *qd = qd_server_dispatch(qd_conn->server);
-        qd_policy_t *policy = qd->policy;
-        bool connection_allowed = true;
-
-        if (policy->enableVhostPolicy) {
-            // Open connection or not based on policy.
-            pn_transport_t *pn_trans = pn_connection_transport(conn);
-            const char *hostip = qd_connection_hostip(qd_conn);
-            const char *pcrh = pn_connection_remote_hostname(conn);
-            const char *vhost = (pcrh ? pcrh : "");
-            const char *conn_name = qd_connection_name(qd_conn);
+void qd_policy_amqp_open(qd_connection_t *qd_conn) {
+    pn_connection_t *conn = qd_connection_pn(qd_conn);
+    qd_dispatch_t *qd = qd_server_dispatch(qd_conn->server);
+    qd_policy_t *policy = qd->policy;
+    bool connection_allowed = true;
+
+    if (policy->enableVhostPolicy) {
+        // Open connection or not based on policy.
+        pn_transport_t *pn_trans = pn_connection_transport(conn);
+        const char *hostip = qd_connection_hostip(qd_conn);
+        const char *pcrh = pn_connection_remote_hostname(conn);
+        const char *vhost = (pcrh ? pcrh : "");
+        const char *conn_name = qd_connection_name(qd_conn);
 #define SETTINGS_NAME_SIZE 256
-            char settings_name[SETTINGS_NAME_SIZE];
-            uint32_t conn_id = qd_conn->connection_id;
-            qd_conn->policy_settings = NEW(qd_policy_settings_t); // TODO: memory pool for settings
-            memset(qd_conn->policy_settings, 0, sizeof(qd_policy_settings_t));
-
-            if (qd_policy_open_lookup_user(policy, qd_conn->user_id, hostip, vhost, conn_name,
-                                           settings_name, SETTINGS_NAME_SIZE, conn_id,
-                                           qd_conn->policy_settings) &&
-                settings_name[0]) {
-                // This connection is allowed by policy.
-                // Apply transport policy settings
-                if (qd_conn->policy_settings->maxFrameSize > 0)
-                    pn_transport_set_max_frame(pn_trans, qd_conn->policy_settings->maxFrameSize);
-                if (qd_conn->policy_settings->maxSessions > 0)
-                    pn_transport_set_channel_max(pn_trans, qd_conn->policy_settings->maxSessions - 1);
-            } else {
-                // This connection is denied by policy.
-                connection_allowed = false;
-            }
+        char settings_name[SETTINGS_NAME_SIZE];
+        uint32_t conn_id = qd_conn->connection_id;
+        qd_conn->policy_settings = NEW(qd_policy_settings_t); // TODO: memory pool for settings
+        memset(qd_conn->policy_settings, 0, sizeof(qd_policy_settings_t));
+
+        if (qd_policy_open_lookup_user(policy, qd_conn->user_id, hostip, vhost, conn_name,
+                                       settings_name, SETTINGS_NAME_SIZE, conn_id,
+                                       qd_conn->policy_settings) &&
+            settings_name[0]) {
+            // This connection is allowed by policy.
+            // Apply transport policy settings
+            if (qd_conn->policy_settings->maxFrameSize > 0)
+                pn_transport_set_max_frame(pn_trans, qd_conn->policy_settings->maxFrameSize);
+            if (qd_conn->policy_settings->maxSessions > 0)
+                pn_transport_set_channel_max(pn_trans, qd_conn->policy_settings->maxSessions - 1);
         } else {
-            // No policy implies automatic policy allow
-            // Note that connections not governed by policy have no policy_settings.
-        }
-        if (connection_allowed) {
-            if (pn_connection_state(conn) & PN_LOCAL_UNINIT)
-                pn_connection_open(conn);
-            policy_notify_opened(qd_conn->open_container, qd_conn, qd_conn->context);
-        } else {
-            qd_policy_private_deny_amqp_connection(conn, QD_AMQP_COND_RESOURCE_LIMIT_EXCEEDED, CONNECTION_DISALLOWED);
+            // This connection is denied by policy.
+            connection_allowed = false;
         }
+    } else {
+        // No policy implies automatic policy allow
+        // Note that connections not governed by policy have no policy_settings.
+    }
+    if (connection_allowed) {
+        if (pn_connection_state(conn) & PN_LOCAL_UNINIT)
+            pn_connection_open(conn);
+        policy_notify_opened(qd_conn->open_container, qd_conn, qd_conn->context);
+    } else {
+        qd_policy_private_deny_amqp_connection(conn, QD_AMQP_COND_RESOURCE_LIMIT_EXCEEDED, CONNECTION_DISALLOWED);
     }
-    qd_connection_set_event_stall(qd_conn, false);
 }

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/policy.h
----------------------------------------------------------------------
diff --git a/src/policy.h b/src/policy.h
index c89ca2b..23f3610 100644
--- a/src/policy.h
+++ b/src/policy.h
@@ -99,7 +99,7 @@ qd_error_t qd_policy_c_counts_refresh(long ccounts, qd_entity_t*entity);
  * @param[in] name the connector name
  * @return the connection is allowed or not
  **/
-bool qd_policy_socket_accept(void *context, const char *hostname);
+bool qd_policy_socket_accept(qd_policy_t *context, const char *hostname);
 
 
 /** Record a closing connection.
@@ -109,7 +109,7 @@ bool qd_policy_socket_accept(void *context, const char *hostname);
  * @param[in] context the current policy
  * @param[in] conn qd_connection
  **/
-void qd_policy_socket_close(void *context, const qd_connection_t *conn);
+void qd_policy_socket_close(qd_policy_t *context, const qd_connection_t *conn);
 
 
 /** Approve a new session based on connection's policy.
@@ -153,10 +153,7 @@ bool qd_policy_approve_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *q
  *  allowed to make this connection.
  * Denied pn_connections are closed with a condition.
  * Allowed connections are signaled through qd_connection_manager.
- * This function is called from the deferred queue.
- * @param[in] context a qd_connection_t object
- * @param[in] discard callback switch
  **/
-void qd_policy_amqp_open(void *context, bool discard);
+void qd_policy_amqp_open(qd_connection_t *conn);
 
 #endif


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


[08/10] qpid-dispatch git commit: DISPATCH-390: common AMQP port name string to integer function

Posted by ac...@apache.org.
DISPATCH-390: common AMQP port name string to integer function


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

Branch: refs/heads/master
Commit: 20b06ac3452ae4ecdc21b577c164538d454de3a1
Parents: 6d34045
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Apr 12 21:27:06 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:30:17 2017 -0400

----------------------------------------------------------------------
 include/qpid/dispatch/amqp.h | 11 ++++++++++-
 src/amqp.c                   | 15 +++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/20b06ac3/include/qpid/dispatch/amqp.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/amqp.h b/include/qpid/dispatch/amqp.h
index e5c45c6..beb083a 100644
--- a/include/qpid/dispatch/amqp.h
+++ b/include/qpid/dispatch/amqp.h
@@ -33,9 +33,17 @@
  * AMQP Constants
  */
 typedef enum {
-    QD_AMQP_MIN_MAX_FRAME_SIZE = 512
+    QD_AMQP_MIN_MAX_FRAME_SIZE = 512,
+    QD_AMQP_PORT_INT = 5672,
+    QD_AMQPS_PORT_INT = 5671
 } qd_amqp_constants_t;
 
+extern const char * const QD_AMQP_PORT_STR;
+extern const char * const QD_AMQPS_PORT_STR;
+
+/* Returns -1 if string is not a number or recognized symbolic port name */
+int qd_port_int(const char* port_str);
+
 /**
  * AMQP Performative Tags
  */
@@ -165,4 +173,5 @@ extern const char * const QD_AMQP_COND_ILLEGAL_STATE;
 extern const char * const QD_AMQP_COND_FRAME_SIZE_TOO_SMALL;
 /// @};
 
+
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/20b06ac3/src/amqp.c
----------------------------------------------------------------------
diff --git a/src/amqp.c b/src/amqp.c
index cf9f775..d2f2cfe 100644
--- a/src/amqp.c
+++ b/src/amqp.c
@@ -18,6 +18,9 @@
  */
 
 #include <qpid/dispatch/amqp.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
 
 const char * const QD_MA_PREFIX  = "x-opt-qd.";
 const char * const QD_MA_INGRESS = "x-opt-qd.ingress";
@@ -63,3 +66,15 @@ const char * const QD_AMQP_COND_PRECONDITION_FAILED = "amqp:precondition-failed"
 const char * const QD_AMQP_COND_RESOURCE_DELETED = "amqp:resource-deleted";
 const char * const QD_AMQP_COND_ILLEGAL_STATE = "amqp:illegal-state";
 const char * const QD_AMQP_COND_FRAME_SIZE_TOO_SMALL = "amqp:frame-size-too-small";
+
+const char * const QD_AMQP_PORT_STR = "5672";
+const char * const QD_AMQPS_PORT_STR = "5671";
+
+int qd_port_int(const char* port_str) {
+    if (!strcmp(port_str, QD_AMQP_PORT_STR)) return QD_AMQP_PORT_INT;
+    if (!strcmp(port_str, QD_AMQPS_PORT_STR)) return QD_AMQPS_PORT_INT;
+    errno = 0;
+    unsigned long n = strtoul(port_str, NULL, 10);
+    if (errno || n > 0xFFFF) return -1;
+    return n;
+}


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


[04/10] qpid-dispatch git commit: DISPATCH-390: Convert dispatch to use pn_proactor_t

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/posix/driver.c
----------------------------------------------------------------------
diff --git a/src/posix/driver.c b/src/posix/driver.c
deleted file mode 100644
index aa80fd9..0000000
--- a/src/posix/driver.c
+++ /dev/null
@@ -1,1093 +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 <assert.h>
-#include <poll.h>
-#include <stdio.h>
-#include <string.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 <time.h>
-
-#ifndef __sun
-#include <sys/eventfd.h>
-#endif
-
-#ifdef __sun
-#include <signal.h>
-#endif
-
-#include <qpid/dispatch/driver.h>
-#include <qpid/dispatch/error.h>
-#include <qpid/dispatch/threading.h>
-#include <proton/error.h>
-#include <proton/ssl.h>
-#include <proton/object.h>
-#include <qpid/dispatch/ctools.h>
-#include "alloc.h"
-#include "aprintf.h"
-#include "log_private.h"
-
-/* Decls */
-
-#define MAX_HOST  1024
-#define MAX_SERV  256
-#define ERROR_MAX 128
-
-#define PN_SEL_RD (0x0001)
-#define PN_SEL_WR (0x0002)
-
-DEQ_DECLARE(qdpn_listener_t, qdpn_listener_list_t);
-DEQ_DECLARE(qdpn_connector_t, qdpn_connector_list_t);
-
-const char *protocol_family_ipv4 = "IPv4";
-const char *protocol_family_ipv6 = "IPv6";
-
-const char *AF_INET6_STR = "AF_INET6";
-const char *AF_INET_STR = "AF_INET";
-
-static inline void ignore_result(int unused_result) {
-    (void) unused_result;
-}
-
-struct qdpn_driver_t {
-    qd_log_source_t *log;
-    sys_mutex_t     *lock;
-
-    //
-    // The following values need to be protected by lock from multi-threaded access.
-    //
-    qdpn_listener_list_t   listeners;
-    qdpn_connector_list_t  connectors;
-    qdpn_listener_t       *listener_next;
-    qdpn_connector_t      *connector_next;
-    size_t                 closed_count;
-
-    //
-    // The following values will only be accessed by one thread at a time.
-    //
-    size_t          capacity;
-    struct pollfd  *fds;
-    size_t          nfds;
-#ifdef __sun
-    int             ctrl[2];
-#else
-    int             efd;    // Event-FD for signaling the poll (driver-wakeup)
-#endif
-    pn_timestamp_t  wakeup;
-};
-
-struct qdpn_listener_t {
-    DEQ_LINKS(qdpn_listener_t);
-    qdpn_driver_t *driver;
-    void *context;
-    int idx;
-    int fd;
-    bool pending:1;
-    bool closed:1;
-};
-
-#define PN_NAME_MAX (256)
-
-struct qdpn_connector_t {
-    DEQ_LINKS(qdpn_connector_t);
-    qdpn_driver_t *driver;
-    char name[PN_NAME_MAX];
-    char hostip[PN_NAME_MAX];
-    pn_timestamp_t wakeup;
-    pn_connection_t *connection;
-    pn_transport_t *transport;
-    qdpn_listener_t *listener;
-    void *context;
-    qdpn_connector_methods_t *methods;
-    int idx;
-    int fd;
-    int status;
-    bool pending_tick:1;
-    bool pending_read:1;
-    bool pending_write:1;
-    bool socket_error:1;
-    bool hangup:1;
-    bool closed:1;
-};
-
-ALLOC_DECLARE(qdpn_listener_t);
-ALLOC_DEFINE(qdpn_listener_t);
-
-ALLOC_DECLARE(qdpn_connector_t);
-ALLOC_DEFINE(qdpn_connector_t);
-
-/* Impls */
-
-static void qdpn_log_errno(qdpn_driver_t *d, const char *fmt, ...)
-{
-    char msg[QD_LOG_TEXT_MAX];
-    char *begin = msg, *end = msg+sizeof(msg);
-    va_list ap;
-    va_start(ap, fmt);
-    vaprintf(&begin, end, fmt, ap);
-    va_end(ap);
-    aprintf(&begin, end, ": ");
-    strerror_r(errno, begin, end - begin);
-    qd_log(d->log, QD_LOG_ERROR, "%s", msg);
-}
-
-
-pn_timestamp_t pn_i_now(void)
-{
-    struct timespec now;
-#ifdef CLOCK_MONOTONIC_COARSE
-    int cid = CLOCK_MONOTONIC_COARSE;
-#else
-    int cid = CLOCK_MONOTONIC;
-#endif
-    if (clock_gettime(cid, &now)) {
-        qd_error_errno(errno, "clock_gettime");
-        exit(1);
-    }
-    return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_nsec / 1000000);
-}
-
-pn_timestamp_t qdpn_now() { return pn_i_now(); }
-
-#define pn_min(X,Y) ((X) > (Y) ? (Y) : (X))
-#define pn_max(X,Y) ((X) < (Y) ? (Y) : (X))
-
-static 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;
-}
-
-// listener
-
-static void qdpn_driver_add_listener(qdpn_driver_t *d, qdpn_listener_t *l)
-{
-    if (!l->driver) return;
-    sys_mutex_lock(d->lock);
-    DEQ_INSERT_TAIL(d->listeners, l);
-    sys_mutex_unlock(d->lock);
-    l->driver = d;
-}
-
-static void qdpn_driver_remove_listener(qdpn_driver_t *d, qdpn_listener_t *l)
-{
-    if (!l->driver) return;
-
-    sys_mutex_lock(d->lock);
-    if (l == d->listener_next)
-        d->listener_next = DEQ_NEXT(l);
-    DEQ_REMOVE(d->listeners, l);
-    sys_mutex_unlock(d->lock);
-
-    l->driver = NULL;
-}
-
-
-static int qdpn_create_socket(int af)
-{
-    struct protoent *pe_tcp = getprotobyname("tcp");
-    if (pe_tcp == NULL)
-        return -1;
-    return socket(af, SOCK_STREAM, pe_tcp->p_proto);
-}
-
-
-static void qdpn_configure_sock(qdpn_driver_t *driver, int sock, bool tcp)
-{
-    //
-    // Set the socket to be non-blocking for asynchronous operation.
-    //
-    int flags = fcntl(sock, F_GETFL);
-    flags |= O_NONBLOCK;
-    if (fcntl(sock, F_SETFL, flags) < 0)
-        qdpn_log_errno(driver, "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.
-    //
-    if (tcp) {
-        int tcp_nodelay = 1;
-        if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*) &tcp_nodelay, sizeof(tcp_nodelay)) < 0)
-            qdpn_log_errno(driver, "setsockopt");
-    }
-}
-
-
-/**
- * Sets the ai_family field on the addrinfo struct based on the passed in NON-NULL protocol_family.
- * If the passed in protocol family does not match IPv6, IPv4, the function does not set the ai_family field
- */
-static void qd_set_addr_ai_family(qdpn_driver_t *driver, struct addrinfo *addr, const char* protocol_family)
-{
-    if (protocol_family) {
-        if(strcmp(protocol_family, protocol_family_ipv6) == 0)
-            addr->ai_family = AF_INET6;
-        else if(strcmp(protocol_family, protocol_family_ipv4) == 0)
-            addr->ai_family = AF_INET;
-    }
-}
-
-
-qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver,
-                               const char *host,
-                               const char *port,
-                               const char *protocol_family,
-                               void* context)
-{
-    if (!driver) return NULL;
-
-    struct addrinfo hints = {0}, *addr;
-    hints.ai_socktype = SOCK_STREAM;
-    int code = getaddrinfo(host, port, &hints, &addr);
-    if (code) {
-        qd_log(driver->log, QD_LOG_ERROR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
-        return 0;
-    }
-
-    // Set the protocol family before creating the socket.
-    qd_set_addr_ai_family(driver, addr, protocol_family);
-
-    int sock = qdpn_create_socket(addr->ai_family);
-    if (sock < 0) {
-        qdpn_log_errno(driver, "pn_create_socket");
-        freeaddrinfo(addr);
-        return 0;
-    }
-
-    int optval = 1;
-    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
-        qdpn_log_errno(driver, "setsockopt");
-        close(sock);
-        freeaddrinfo(addr);
-        return 0;
-    }
-
-    if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
-        qdpn_log_errno(driver, "bind");
-        freeaddrinfo(addr);
-        close(sock);
-        return 0;
-    }
-
-    freeaddrinfo(addr);
-
-    if (listen(sock, 50) == -1) {
-        qdpn_log_errno(driver, "listen");
-        close(sock);
-        return 0;
-    }
-
-    qdpn_listener_t *l = qdpn_listener_fd(driver, sock, context);
-    return l;
-}
-
-qdpn_listener_t *qdpn_listener_fd(qdpn_driver_t *driver, int fd, void *context)
-{
-    if (!driver) return NULL;
-
-    qdpn_listener_t *l = new_qdpn_listener_t();
-    if (!l) return NULL;
-    DEQ_ITEM_INIT(l);
-    l->driver = driver;
-    l->idx = 0;
-    l->pending = false;
-    l->fd = fd;
-    l->closed = false;
-    l->context = context;
-
-    qdpn_driver_add_listener(driver, l);
-    return l;
-}
-
-int qdpn_listener_get_fd(qdpn_listener_t *listener)
-{
-    assert(listener);
-    return listener->fd;
-}
-
-qdpn_listener_t *qdpn_listener_head(qdpn_driver_t *driver)
-{
-    if (!driver)
-        return 0;
-
-    qdpn_listener_t *head;
-    sys_mutex_lock(driver->lock);
-    head = DEQ_HEAD(driver->listeners);
-    sys_mutex_unlock(driver->lock);
-    return head;
-}
-
-qdpn_listener_t *qdpn_listener_next(qdpn_listener_t *listener)
-{
-    if (!listener || !listener->driver)
-        return 0;
-
-    qdpn_listener_t *next;
-    sys_mutex_lock(listener->driver->lock);
-    next = DEQ_NEXT(listener);
-    sys_mutex_unlock(listener->driver->lock);
-    return next;
-}
-
-void *qdpn_listener_context(qdpn_listener_t *l)
-{
-    return l ? l->context : NULL;
-}
-
-void qdpn_listener_set_context(qdpn_listener_t *listener, void *context)
-{
-    assert(listener);
-    listener->context = context;
-}
-
-qdpn_connector_t *qdpn_listener_accept(qdpn_listener_t *l,
-                                       void *policy,
-                                       bool (*policy_fn)(void *, const char *name),
-                                       bool *counted)
-{
-    if (!l || !l->pending) return NULL;
-    char name[PN_NAME_MAX];
-    char serv[MAX_SERV];
-    char hostip[MAX_HOST];
-
-    struct sockaddr_in addr = {0};
-    addr.sin_family = AF_UNSPEC;
-    socklen_t addrlen = sizeof(addr);
-
-    int sock = accept(l->fd, (struct sockaddr *) &addr, &addrlen);
-    if (sock < 0) {
-        qdpn_log_errno(l->driver, "accept");
-        return 0;
-    } else {
-        int code = getnameinfo((struct sockaddr *) &addr, addrlen, hostip, MAX_HOST, serv, MAX_SERV, NI_NUMERICHOST | NI_NUMERICSERV);
-        if (code != 0) {
-            qd_log(l->driver->log, QD_LOG_ERROR, "getnameinfo: %s", gai_strerror(code));
-            close(sock);
-            return 0;
-        } else {
-            qdpn_configure_sock(l->driver, sock, true);
-            snprintf(name, PN_NAME_MAX-1, "%s:%s", hostip, serv);
-        }
-    }
-
-    if (policy_fn) {
-        if (!(*policy_fn)(policy, name)) {
-            close(sock);
-            return 0;
-        } else {
-            *counted = true;
-        }
-    }
-    qdpn_connector_t *c = qdpn_connector_fd(l->driver, sock, NULL);
-    snprintf(c->name, PN_NAME_MAX, "%s", name);
-    snprintf(c->hostip, PN_NAME_MAX, "%s", hostip);
-    c->listener = l;
-    return c;
-}
-
-void qdpn_listener_close(qdpn_listener_t *l)
-{
-    if (!l) return;
-    if (l->closed) return;
-
-    if (close(l->fd) == -1)
-        qdpn_log_errno(l->driver, "close");
-    l->closed = true;
-}
-
-void qdpn_listener_free(qdpn_listener_t *l)
-{
-    if (!l) return;
-    if (l->driver) qdpn_driver_remove_listener(l->driver, l);
-    free_qdpn_listener_t(l);
-}
-
-// connector
-
-static void qdpn_driver_add_connector(qdpn_driver_t *d, qdpn_connector_t *c)
-{
-    if (!c->driver) return;
-    sys_mutex_lock(d->lock);
-    DEQ_INSERT_TAIL(d->connectors, c);
-    sys_mutex_unlock(d->lock);
-    c->driver = d;
-}
-
-static void qdpn_driver_remove_connector(qdpn_driver_t *d, qdpn_connector_t *c)
-{
-    if (!c->driver) return;
-
-    sys_mutex_lock(d->lock);
-    if (c == d->connector_next) {
-        d->connector_next = DEQ_NEXT(c);
-    }
-
-    DEQ_REMOVE(d->connectors, c);
-    c->driver = NULL;
-    if (c->closed) {
-        d->closed_count--;
-    }
-    sys_mutex_unlock(d->lock);
-}
-
-qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver,
-                                 const char *host,
-                                 const char *port,
-                                 const char *protocol_family,
-                                 void *context)
-{
-    if (!driver) return NULL;
-
-    struct addrinfo hints = {0}, *addr;
-    hints.ai_socktype = SOCK_STREAM;
-    int code = getaddrinfo(host, port, &hints, &addr);
-    if (code) {
-        qd_log(driver->log, QD_LOG_ERROR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code));
-        return 0;
-    }
-
-    // Set the protocol family before creating the socket.
-    qd_set_addr_ai_family(driver, addr, protocol_family);
-
-    int sock = qdpn_create_socket(addr->ai_family);
-    if (sock == PN_INVALID_SOCKET) {
-        freeaddrinfo(addr);
-        qdpn_log_errno(driver, "pn_create_socket");
-        return 0;
-    }
-
-    qdpn_configure_sock(driver, sock, true);
-
-    if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
-        if (errno != EINPROGRESS) {
-            qdpn_log_errno(driver, "connect");
-            freeaddrinfo(addr);
-            close(sock);
-            return 0;
-        }
-    }
-
-    freeaddrinfo(addr);
-
-    qdpn_connector_t *c = qdpn_connector_fd(driver, sock, context);
-    snprintf(c->name, PN_NAME_MAX, "%s:%s", host, port);
-    return c;
-}
-
-
-static void connector_process(qdpn_connector_t *c);
-static void connector_close(qdpn_connector_t *c);
-
-static qdpn_connector_methods_t connector_methods = {
-    connector_process,
-    connector_close
-};
-
-qdpn_connector_t *qdpn_connector_fd(qdpn_driver_t *driver, int fd, void *context)
-{
-    if (!driver) return NULL;
-
-    qdpn_connector_t *c = new_qdpn_connector_t();
-    if (!c) return NULL;
-    DEQ_ITEM_INIT(c);
-    c->driver = driver;
-    c->pending_tick = false;
-    c->pending_read = false;
-    c->pending_write = false;
-    c->socket_error = false;
-    c->hangup = false;
-    c->name[0] = '\0';
-    c->idx = 0;
-    c->fd = fd;
-    c->status = PN_SEL_RD | PN_SEL_WR;
-    c->closed = false;
-    c->wakeup = 0;
-    c->connection = NULL;
-    c->transport = pn_transport();
-    c->context = context;
-    c->listener = NULL;
-    c->methods = &connector_methods;
-    qdpn_driver_add_connector(driver, c);
-    return c;
-}
-
-int qdpn_connector_get_fd(qdpn_connector_t *connector)
-{
-    assert(connector);
-    return connector->fd;
-}
-
-qdpn_connector_t *qdpn_connector_head(qdpn_driver_t *driver)
-{
-    if (!driver)
-        return 0;
-
-    sys_mutex_lock(driver->lock);
-    qdpn_connector_t *head = DEQ_HEAD(driver->connectors);
-    sys_mutex_unlock(driver->lock);
-    return head;
-}
-
-qdpn_connector_t *qdpn_connector_next(qdpn_connector_t *connector)
-{
-    if (!connector || !connector->driver)
-        return 0;
-    sys_mutex_lock(connector->driver->lock);
-    qdpn_connector_t *next = DEQ_NEXT(connector);
-    sys_mutex_unlock(connector->driver->lock);
-    return next;
-}
-
-pn_transport_t *qdpn_connector_transport(qdpn_connector_t *ctor)
-{
-    return ctor ? ctor->transport : NULL;
-}
-
-void qdpn_connector_set_connection(qdpn_connector_t *ctor, pn_connection_t *connection)
-{
-    if (!ctor) return;
-    if (ctor->connection) {
-        pn_class_decref(PN_OBJECT, ctor->connection);
-        pn_transport_unbind(ctor->transport);
-    }
-    ctor->connection = connection;
-    if (ctor->connection) {
-        pn_class_incref(PN_OBJECT, ctor->connection);
-        pn_transport_bind(ctor->transport, connection);
-    }
-}
-
-pn_connection_t *qdpn_connector_connection(qdpn_connector_t *ctor)
-{
-    return ctor ? ctor->connection : NULL;
-}
-
-void *qdpn_connector_context(qdpn_connector_t *ctor)
-{
-    return ctor ? ctor->context : NULL;
-}
-
-void qdpn_connector_set_context(qdpn_connector_t *ctor, void *context)
-{
-    if (!ctor) return;
-    ctor->context = context;
-}
-
-const char *qdpn_connector_name(const qdpn_connector_t *ctor)
-{
-    if (!ctor) return 0;
-    return ctor->name;
-}
-
-const char *qdpn_connector_hostip(const qdpn_connector_t *ctor)
-{
-    if (!ctor) return 0;
-    return ctor->hostip;
-}
-
-qdpn_listener_t *qdpn_connector_listener(qdpn_connector_t *ctor)
-{
-    return ctor ? ctor->listener : NULL;
-}
-
-/* Mark the connector as closed, but don't close the FD (already closed or
- * will be closed elsewhere)
- */
-void qdpn_connector_mark_closed(qdpn_connector_t *ctor)
-{
-    if (!ctor || !ctor->driver) return;
-    sys_mutex_lock(ctor->driver->lock);
-    ctor->status = 0;
-    if (!ctor->closed) {
-        qd_log(ctor->driver->log, QD_LOG_TRACE, "closed %s", ctor->name);
-        ctor->closed = true;
-        ctor->driver->closed_count++;
-    }
-    sys_mutex_unlock(ctor->driver->lock);
-}
-
-static void connector_close(qdpn_connector_t *ctor)
-{
-    if (ctor && !ctor->closed) {
-        qdpn_connector_mark_closed(ctor);
-        if (close(ctor->fd) == -1)
-            qdpn_log_errno(ctor->driver, "close %s", ctor->name);
-    }
-}
-
-void qdpn_connector_close(qdpn_connector_t *c)
-{
-    if (c && !c->closed) c->methods->close(c);
-}
-
-bool qdpn_connector_closed(qdpn_connector_t *ctor)
-{
-    return ctor ? ctor->closed : true;
-}
-
-bool qdpn_connector_failed(qdpn_connector_t *ctor)
-{
-    return ctor ? ctor->socket_error : true;
-}
-
-void qdpn_connector_free(qdpn_connector_t *ctor)
-{
-    if (!ctor) return;
-
-    if (ctor->driver) qdpn_driver_remove_connector(ctor->driver, ctor);
-    pn_transport_unbind(ctor->transport);
-    pn_transport_free(ctor->transport);
-    ctor->transport = NULL;
-    if (ctor->connection) pn_class_decref(PN_OBJECT, ctor->connection);
-    ctor->connection = NULL;
-    free_qdpn_connector_t(ctor);
-}
-
-void qdpn_connector_activate(qdpn_connector_t *ctor, qdpn_activate_criteria_t crit)
-{
-    switch (crit) {
-    case QDPN_CONNECTOR_WRITABLE :
-        ctor->status |= PN_SEL_WR;
-        break;
-
-    case QDPN_CONNECTOR_READABLE :
-        ctor->status |= PN_SEL_RD;
-        break;
-    }
-}
-
-
-void qdpn_activate_all(qdpn_driver_t *d)
-{
-    sys_mutex_lock(d->lock);
-    qdpn_connector_t *c = DEQ_HEAD(d->connectors);
-    while (c) {
-        c->status |= PN_SEL_WR;
-        c = DEQ_NEXT(c);
-    }
-    sys_mutex_unlock(d->lock);
-}
-
-bool qdpn_connector_hangup(qdpn_connector_t *ctor) {
-    return ctor->hangup;
-}
-
-bool qdpn_connector_activated(qdpn_connector_t *ctor, qdpn_activate_criteria_t crit)
-{
-    bool result = false;
-
-    switch (crit) {
-    case QDPN_CONNECTOR_WRITABLE :
-        result = ctor->pending_write;
-        ctor->pending_write = false;
-        ctor->status &= ~PN_SEL_WR;
-        break;
-
-    case QDPN_CONNECTOR_READABLE :
-        result = ctor->pending_read;
-        ctor->pending_read = false;
-        ctor->status &= ~PN_SEL_RD;
-        break;
-    }
-
-    return result;
-}
-
-static pn_timestamp_t qdpn_connector_tick(qdpn_connector_t *ctor, pn_timestamp_t now)
-{
-    if (!ctor->transport) return 0;
-    return pn_transport_tick(ctor->transport, now);
-}
-
-void qdpn_connector_process(qdpn_connector_t *c)
-{
-    if (c && !c->closed) c->methods->process(c);
-}
-
-static void connector_process(qdpn_connector_t *c)
-{
-    if(c->closed) return;
-
-    pn_transport_t *transport = c->transport;
-    c->status = 0;
-
-    ///
-    /// Socket read
-    ///
-    ssize_t capacity = pn_transport_capacity(transport);
-    if (capacity > 0) {
-        c->status |= PN_SEL_RD;
-        if (c->pending_read) {
-            c->pending_read = false;
-            ssize_t n =  recv(c->fd, pn_transport_tail(transport), capacity, 0);
-            if (n < 0) {
-                if (errno != EAGAIN) {
-                    qdpn_log_errno(c->driver, "recv %s", c->name);
-                    pn_transport_close_tail( transport );
-                }
-            } else if (n == 0) { /* HUP */
-                pn_transport_close_tail( transport );
-            } else {
-                pn_transport_process(transport, (size_t) n);
-            }
-        }
-    }
-
-    ///
-    /// Event wakeup
-    ///
-    c->wakeup = qdpn_connector_tick(c, pn_i_now());
-
-    ///
-    /// Socket write
-    ///
-    ssize_t pending = pn_transport_pending(transport);
-    if (pending > 0) {
-        c->status |= PN_SEL_WR;
-        if (c->pending_write) {
-            c->pending_write = false;
-#ifdef MSG_NOSIGNAL
-            ssize_t n = send(c->fd, pn_transport_head(transport), pending, MSG_NOSIGNAL);
-#else
-            ssize_t n = send(c->fd, pn_transport_head(transport), pending, 0);
-#endif
-            if (n < 0) {
-                if (errno != EAGAIN) {
-                    qdpn_log_errno(c->driver, "send %s", c->name);
-                    pn_transport_close_head( transport );
-                }
-            } else if (n) {
-                pn_transport_pop(transport, (size_t) n);
-            }
-        }
-    }
-
-    if (pn_transport_closed(c->transport)) {
-        qdpn_connector_close(c);
-    }
-}
-
-// driver
-
-qdpn_driver_t *qdpn_driver(qd_log_source_t *log)
-{
-    qdpn_driver_t *d = (qdpn_driver_t *) malloc(sizeof(qdpn_driver_t));
-    if (!d) return NULL;
-    ZERO(d);
-    DEQ_INIT(d->listeners);
-    DEQ_INIT(d->connectors);
-    d->log = log;
-    d->lock = sys_mutex();
-
-#ifdef __sun
-    if (pipe(d->ctrl))
-        perror("Can't create control pipe");
-
-    qdpn_configure_sock(d, d->ctrl[0], false);
-    qdpn_configure_sock(d, d->ctrl[1], false);
-
-    struct sigaction act;
-    act.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &act, NULL);
-#else
-    d->efd = eventfd(0, EFD_NONBLOCK);
-    if (d->efd < 0) {
-        qdpn_log_errno(d, "Can't create eventfd");
-        exit(1);
-    }
-#endif
-
-    return d;
-}
-
-void qdpn_driver_free(qdpn_driver_t *d)
-{
-    if (!d) return;
-
-#ifdef __sun
-    close(d->ctrl[0]);
-    close(d->ctrl[1]);
-#else
-    close(d->efd);
-#endif
-
-    qdpn_connector_t *conn = DEQ_HEAD(d->connectors);
-
-    while (conn) {
-        qdpn_connector_free(conn);
-        conn = DEQ_HEAD(d->connectors);
-    }
-
-    qdpn_listener_t *listener = DEQ_HEAD(d->listeners);
-
-    while (listener) {
-        qdpn_listener_free(listener);
-        listener = DEQ_HEAD(d->listeners);
-    }
-
-    free(d->fds);
-    sys_mutex_free(d->lock);
-    free(d);
-}
-
-int qdpn_driver_wakeup(qdpn_driver_t *d)
-{
-#ifdef __sun
-    if (d) {
-        ssize_t count = write(d->ctrl[1], "x", 1);
-        if (count <= 0) {
-            return count;
-        } else {
-            return 0;
-        }
-    } else {
-        return PN_ARG_ERR;
-    }
-#else
-    static uint64_t efd_delta = 1;
-
-    if (d)
-        ignore_result(write(d->efd, &efd_delta, sizeof(uint64_t)));
-    return 0;
-#endif
-}
-
-static void qdpn_driver_rebuild(qdpn_driver_t *d)
-{
-    sys_mutex_lock(d->lock);
-    size_t size = DEQ_SIZE(d->listeners) + DEQ_SIZE(d->connectors);
-    if (d->capacity < size + 1) {
-        d->capacity = d->capacity > 16 ? d->capacity : 16;
-        while (d->capacity < size + 1) {
-            d->capacity *= 2;
-        }
-        d->fds = (struct pollfd *) realloc(d->fds, d->capacity*sizeof(struct pollfd));
-    }
-
-
-    d->wakeup = 0;
-    d->nfds = 0;
-
-#ifdef __sun
-    d->fds[d->nfds].fd = d->ctrl[0];
-#else
-    d->fds[d->nfds].fd = d->efd;
-#endif
-    d->fds[d->nfds].events = POLLIN;
-    d->fds[d->nfds].revents = 0;
-    d->nfds++;
-
-    qdpn_listener_t *l = DEQ_HEAD(d->listeners);
-    while (l) {
-        d->fds[d->nfds].fd = l->fd;
-        d->fds[d->nfds].events = POLLIN;
-        d->fds[d->nfds].revents = 0;
-        l->idx = d->nfds;
-        d->nfds++;
-        l = DEQ_NEXT(l);
-    }
-
-    qdpn_connector_t *c = DEQ_HEAD(d->connectors);
-    while (c) {
-        if (!c->closed && !c->socket_error && !c->hangup) {
-            d->wakeup = pn_timestamp_min(d->wakeup, c->wakeup);
-            d->fds[d->nfds].fd = c->fd;
-            d->fds[d->nfds].events = (c->status & PN_SEL_RD ? POLLIN : 0) | (c->status & PN_SEL_WR ? POLLOUT : 0);
-            d->fds[d->nfds].revents = 0;
-            c->idx = d->nfds;
-            d->nfds++;
-        }
-        c = DEQ_NEXT(c);
-    }
-
-    sys_mutex_unlock(d->lock);
-}
-
-void qdpn_driver_wait_1(qdpn_driver_t *d)
-{
-    qdpn_driver_rebuild(d);
-}
-
-int qdpn_driver_wait_2(qdpn_driver_t *d, int timeout)
-{
-    if (d->wakeup) {
-        pn_timestamp_t now = pn_i_now();
-        if (now >= d->wakeup)
-            timeout = 0;
-        else
-            timeout = (timeout < 0) ? d->wakeup-now : pn_min(timeout, d->wakeup - now);
-    }
-    int result = poll(d->fds, d->nfds, d->closed_count > 0 ? 0 : timeout);
-    if (result == -1 && errno != EINTR)
-        qdpn_log_errno(d, "poll");
-    return result;
-}
-
-int qdpn_driver_wait_3(qdpn_driver_t *d)
-{
-    bool woken = false;
-    if (d->fds[0].revents & POLLIN) {
-        woken = true;
-#ifdef __sun
-        //clear the pipe
-        char buffer[512];
-        while (read(d->ctrl[0], buffer, 512) == 512);
-#else
-        char buffer[sizeof(uint64_t)];
-        ignore_result(read(d->efd, buffer, sizeof(uint64_t)));
-#endif
-    }
-
-    sys_mutex_lock(d->lock);
-    qdpn_listener_t *l = DEQ_HEAD(d->listeners);
-    while (l) {
-        l->pending = (l->idx && d->fds[l->idx].revents & POLLIN);
-        l = DEQ_NEXT(l);
-    }
-
-    pn_timestamp_t now = pn_i_now();
-    qdpn_connector_t *c = DEQ_HEAD(d->connectors);
-    while (c) {
-        if (c->closed) {
-            c->pending_read = false;
-            c->pending_write = false;
-            c->pending_tick = false;
-        } else if (c->idx) {
-            short revents = d->fds[c->idx].revents;
-            c->pending_read = (revents & POLLIN);
-            c->pending_write = (revents & POLLOUT);
-            c->socket_error = (revents & POLLERR);
-            c->pending_tick = (c->wakeup &&  c->wakeup <= now);
-            if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP)) {
-                qd_log(c->driver->log, QD_LOG_ERROR, "unexpected poll events %04x on %s",
-                       revents, c->name);
-                c->socket_error = true;
-            }
-            if (revents & POLLHUP) {
-                c->hangup = true;
-                /* poll() is signalling POLLHUP. To see what happened we need
-                 * to do an actual recv() to get the error code. But we might
-                 * be in a state where we're not interested in input, in that
-                 * case try to get the error code via send() */
-                short events = d->fds[c->idx].events;
-                if (events & POLLIN) c->pending_read = true;
-                else if (events & POLLOUT) c->pending_write = true;
-            }
-        }
-        c = DEQ_NEXT(c);
-    }
-
-    //
-    // Rotate the head connector to the tail.  This improves the fairness of polling on
-    // open FDs.
-    //
-    c = DEQ_HEAD(d->connectors);
-    if (c) {
-        DEQ_REMOVE_HEAD(d->connectors);
-        DEQ_INSERT_TAIL(d->connectors, c);
-    }
-
-    d->listener_next = DEQ_HEAD(d->listeners);
-    d->connector_next = DEQ_HEAD(d->connectors);
-    sys_mutex_unlock(d->lock);
-
-    return woken ? PN_INTR : 0;
-}
-
-//
-// XXX - pn_driver_wait has been divided into three internal functions as a
-//       temporary workaround for a multi-threading problem.  A multi-threaded
-//       application must hold a lock on parts 1 and 3, but not on part 2.
-//       This temporary change, which is not reflected in the driver's API, allows
-//       a multi-threaded application to use the three parts separately.
-//
-//       This workaround will eventually be replaced by a more elegant solution
-//       to the problem.
-//
-int qdpn_driver_wait(qdpn_driver_t *d, int timeout)
-{
-    qdpn_driver_wait_1(d);
-    int result = qdpn_driver_wait_2(d, timeout);
-    if (result == -1)
-        return errno;
-    return qdpn_driver_wait_3(d);
-}
-
-qdpn_listener_t *qdpn_driver_listener(qdpn_driver_t *d)
-{
-    if (!d) return NULL;
-
-    sys_mutex_lock(d->lock);
-    while (d->listener_next) {
-        qdpn_listener_t *l = d->listener_next;
-        d->listener_next = DEQ_NEXT(l);
-
-        if (l->pending) {
-            sys_mutex_unlock(d->lock);
-            return l;
-        }
-    }
-
-    sys_mutex_unlock(d->lock);
-    return NULL;
-}
-
-qdpn_connector_t *qdpn_driver_connector(qdpn_driver_t *d)
-{
-    if (!d) return NULL;
-
-    sys_mutex_lock(d->lock);
-    while (d->connector_next) {
-        qdpn_connector_t *c = d->connector_next;
-        d->connector_next = DEQ_NEXT(c);
-
-        if (c->closed || c->pending_read || c->pending_write || c->pending_tick || c->socket_error) {
-            sys_mutex_unlock(d->lock);
-            return c;
-        }
-    }
-
-    sys_mutex_unlock(d->lock);
-    return NULL;
-}
-
-void qdpn_connector_wakeup(qdpn_connector_t *c, pn_timestamp_t t) {
-    c->wakeup = t;
-}
-
-void qdpn_connector_set_methods(qdpn_connector_t *c, qdpn_connector_methods_t *m) {
-    c->methods = m;
-}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/router_core/connections.c
----------------------------------------------------------------------
diff --git a/src/router_core/connections.c b/src/router_core/connections.c
index 20bcf56..277fd37 100644
--- a/src/router_core/connections.c
+++ b/src/router_core/connections.c
@@ -472,7 +472,6 @@ void qdr_connection_handlers(qdr_core_t                *core,
                              qdr_delivery_update_t      delivery_update)
 {
     core->user_context            = context;
-    core->activate_handler        = activate;
     core->first_attach_handler    = first_attach;
     core->second_attach_handler   = second_attach;
     core->detach_handler          = detach;
@@ -492,10 +491,7 @@ void qdr_connection_handlers(qdr_core_t                *core,
 
 void qdr_connection_activate_CT(qdr_core_t *core, qdr_connection_t *conn)
 {
-    if (!conn->in_activate_list) {
-        DEQ_INSERT_TAIL_N(ACTIVATE, core->connections_to_activate, conn);
-        conn->in_activate_list = true;
-    }
+    qd_server_activate((qd_connection_t*) qdr_connection_get_context(conn));
 }
 
 
@@ -1236,14 +1232,6 @@ static void qdr_connection_closed_CT(qdr_core_t *core, qdr_action_t *action, boo
         work = DEQ_HEAD(conn->work_list);
     }
 
-    //
-    // If this connection is on the activation list, remove it from the list
-    //
-    if (conn->in_activate_list) {
-        conn->in_activate_list = false;
-        DEQ_REMOVE_N(ACTIVATE, core->connections_to_activate, conn);
-    }
-
     DEQ_REMOVE(core->open_connections, conn);
     sys_mutex_free(conn->work_lock);
     qdr_connection_free(conn);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/router_core/router_core_private.h
----------------------------------------------------------------------
diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h
index 5e92326..ecd4807 100644
--- a/src/router_core/router_core_private.h
+++ b/src/router_core/router_core_private.h
@@ -518,7 +518,6 @@ struct qdr_connection_t {
     uint64_t                    identity;
     qdr_core_t                 *core;
     bool                        incoming;
-    bool                        in_activate_list;
     qdr_connection_role_t       role;
     int                         inter_router_cost;
     qdr_conn_identifier_t      *conn_id;
@@ -611,7 +610,6 @@ struct qdr_core_t {
     qd_timer_t              *work_timer;
 
     qdr_connection_list_t open_connections;
-    qdr_connection_list_t connections_to_activate;
     qdr_link_list_t       open_links;
 
     //
@@ -636,7 +634,6 @@ struct qdr_core_t {
     // Connection section
     //
     void                      *user_context;
-    qdr_connection_activate_t  activate_handler;
     qdr_link_first_attach_t    first_attach_handler;
     qdr_link_second_attach_t   second_attach_handler;
     qdr_link_detach_t          detach_handler;

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/router_core/router_core_thread.c
----------------------------------------------------------------------
diff --git a/src/router_core/router_core_thread.c b/src/router_core/router_core_thread.c
index 5cffeb9..926063c 100644
--- a/src/router_core/router_core_thread.c
+++ b/src/router_core/router_core_thread.c
@@ -29,19 +29,6 @@
 
 ALLOC_DEFINE(qdr_action_t);
 
-
-static void qdr_activate_connections_CT(qdr_core_t *core)
-{
-    qdr_connection_t *conn = DEQ_HEAD(core->connections_to_activate);
-    while (conn) {
-        DEQ_REMOVE_HEAD_N(ACTIVATE, core->connections_to_activate);
-        conn->in_activate_list = false;
-        core->activate_handler(core->user_context, conn, DEQ_IS_EMPTY(core->connections_to_activate));
-        conn = DEQ_HEAD(core->connections_to_activate);
-    }
-}
-
-
 void *router_core_thread(void *arg)
 {
     qdr_core_t        *core = (qdr_core_t*) arg;
@@ -84,11 +71,6 @@ void *router_core_thread(void *arg)
             free_qdr_action_t(action);
             action = DEQ_HEAD(action_list);
         }
-
-        //
-        // Activate all connections that were flagged for activation during the above processing
-        //
-        qdr_activate_connections_CT(core);
     }
 
     qd_log(core->log, QD_LOG_INFO, "Router Core thread exited");

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/src/router_node.c
----------------------------------------------------------------------
diff --git a/src/router_node.c b/src/router_node.c
index 12b6887..ca7d746 100644
--- a/src/router_node.c
+++ b/src/router_node.c
@@ -27,6 +27,7 @@
 #include "entity_cache.h"
 #include "router_private.h"
 #include <qpid/dispatch/router_core.h>
+#include <proton/sasl.h>
 
 const char *QD_ROUTER_NODE_TYPE = "router.node";
 const char *QD_ROUTER_ADDRESS_TYPE = "router.address";
@@ -58,7 +59,7 @@ static void qd_router_connection_get_config(const qd_connection_t  *conn,
         *strip_annotations_out = cf ? cf->strip_outbound_annotations : false;
         *link_capacity         = cf ? cf->link_capacity : 1;
 
-        if        (cf && strcmp(cf->role, router_role) == 0) {
+        if (cf && strcmp(cf->role, router_role) == 0) {
             *strip_annotations_in  = false;
             *strip_annotations_out = false;
             *role = QDR_ROLE_INTER_ROUTER;
@@ -296,7 +297,7 @@ static void AMQP_rx_handler(void* context, qd_link_t *link, pn_delivery_t *pnd)
     qdr_connection_t *qdr_conn     = (qdr_connection_t*) qd_connection_get_context(conn);
     int               tenant_space_len;
     const char       *tenant_space = qdr_connection_get_tenant_space(qdr_conn, &tenant_space_len);
-    if (conn->policy_settings) 
+    if (conn->policy_settings)
         check_user = !conn->policy_settings->allowUserIdProxy;
 
     //
@@ -650,7 +651,7 @@ static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool
     const qd_server_config_t *config;
     if (qd_connection_connector(conn)) {
         config = qd_connector_config(qd_connection_connector(conn));
-        snprintf(host_local, 254, "%s:%s", config->host, config->port);
+        snprintf(host_local, 254, "%s", config->host_port);
         host = &host_local[0];
     }
     else
@@ -851,14 +852,13 @@ qd_router_t *qd_router(qd_dispatch_t *qd, qd_router_mode_t mode, const char *are
 }
 
 
-static void CORE_connection_activate(void *context, qdr_connection_t *conn, bool awaken)
+static void CORE_connection_activate(void *context, qdr_connection_t *conn)
 {
     //
     // IMPORTANT:  This is the only core callback that is invoked on the core
-    //             thread itself.  It is imperative that this function do nothing
-    //             apart from setting the activation in the server for the connection.
+    //             thread itself. It must not take locks that could deadlock the core.
     //
-    qd_server_activate((qd_connection_t*) qdr_connection_get_context(conn), awaken);
+    qd_server_activate((qd_connection_t*) qdr_connection_get_context(conn));
 }
 
 
@@ -952,7 +952,7 @@ static void CORE_link_flow(void *context, qdr_link_t *link, int credit)
     qd_link_t *qlink = (qd_link_t*) qdr_link_get_context(link);
     if (!qlink)
         return;
-    
+
     pn_link_t *plink = qd_link_pn(qlink);
 
     if (plink)


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


[10/10] qpid-dispatch git commit: DISPATCH-739: Fix double free bug, remove _to_free_ lists

Posted by ac...@apache.org.
DISPATCH-739: Fix double free bug, remove _to_free_ lists

Don't defer freeing sessions/links, just ensure they are freed exactly once.


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

Branch: refs/heads/master
Commit: b974b884a7f9ac7ba2d13508af21d779d4f84beb
Parents: 16980f6
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Apr 25 09:42:17 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:32:36 2017 -0400

----------------------------------------------------------------------
 src/container.c      | 103 ++++------------------------------------------
 src/server.c         |   1 -
 src/server_private.h |   3 --
 3 files changed, 7 insertions(+), 100 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/b974b884/src/container.c
----------------------------------------------------------------------
diff --git a/src/container.c b/src/container.c
index 639ffa2..3add3ac 100644
--- a/src/container.c
+++ b/src/container.c
@@ -84,8 +84,6 @@ struct qd_container_t {
     qdc_node_type_list_t  node_type_list;
 };
 
-ALLOC_DEFINE(qd_pn_free_link_session_t);
-
 static void setup_outgoing_link(qd_container_t *container, pn_link_t *pn_link)
 {
     qd_node_t *node = container->default_node;
@@ -321,92 +319,6 @@ static void writable_handler(qd_container_t *container, pn_connection_t *conn, q
     }
 }
 
-/**
- * Returns true if the free_link already exists in free_link_list, false otherwise
- */
-static bool link_exists(qd_pn_free_link_session_list_t  **free_list, pn_link_t *free_link)
-{
-    qd_pn_free_link_session_t *free_item = DEQ_HEAD(**free_list);
-    while(free_item) {
-        if (free_item->pn_link == free_link)
-            return true;
-        free_item = DEQ_NEXT(free_item);
-    }
-    return false;
-}
-
-/**
- * Returns true if the free_session already exists in free_session_list, false otherwise
- */
-static bool session_exists(qd_pn_free_link_session_list_t  **free_list, pn_session_t *free_session)
-{
-    qd_pn_free_link_session_t *free_item = DEQ_HEAD(**free_list);
-    while(free_item) {
-        if (free_item->pn_session == free_session)
-            return true;
-        free_item = DEQ_NEXT(free_item);
-    }
-    return false;
-}
-
-static void add_session_to_free_list(qd_pn_free_link_session_list_t  *free_link_session_list, pn_session_t *ssn)
-{
-    if (!session_exists(&free_link_session_list, ssn)) {
-        qd_pn_free_link_session_t *to_free = new_qd_pn_free_link_session_t();
-        DEQ_ITEM_INIT(to_free);
-        to_free->pn_session = ssn;
-        to_free->pn_link = 0;
-        DEQ_INSERT_TAIL(*free_link_session_list, to_free);
-    }
-}
-
-
-static void add_link_to_free_list(qd_pn_free_link_session_list_t  *free_link_session_list, pn_link_t *pn_link)
-{
-    if (!link_exists(&free_link_session_list, pn_link)) {
-        qd_pn_free_link_session_t *to_free = new_qd_pn_free_link_session_t();
-        DEQ_ITEM_INIT(to_free);
-        to_free->pn_link = pn_link;
-        to_free->pn_session = 0;
-        DEQ_INSERT_TAIL(*free_link_session_list, to_free);
-    }
-
-}
-
-
-/*
- * TODO aconway 2017-04-12: IMO this should not be necessary, we should
- * be able to pn_*_free links and sessions directly the handler function.
- * They will not actually be freed from memory till the event, connection,
- * proactor etc. have all released their references.
- *
- * The need for these lists may indicate a router bug, where the router is
- * using links/sessions after they are freed. Investigate and simplify if
- * possible.
- */
-static void conn_event_complete(qd_connection_t *qd_conn)
-{
-    qd_pn_free_link_session_t *to_free_link = DEQ_HEAD(qd_conn->free_link_session_list);
-    qd_pn_free_link_session_t *to_free_session = DEQ_HEAD(qd_conn->free_link_session_list);
-    while(to_free_link) {
-        if (to_free_link->pn_link) {
-            pn_link_free(to_free_link->pn_link);
-            to_free_link->pn_link = 0;
-        }
-        to_free_link = DEQ_NEXT(to_free_link);
-    }
-
-    while(to_free_session) {
-        if (to_free_session->pn_session) {
-            pn_session_free(to_free_session->pn_session);
-            to_free_session->pn_session = 0;
-        }
-        DEQ_REMOVE_HEAD(qd_conn->free_link_session_list);
-        free_qd_pn_free_link_session_t(to_free_session);
-        to_free_session = DEQ_HEAD(qd_conn->free_link_session_list);
-    }
-}
-
 
 void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
 {
@@ -475,7 +387,7 @@ void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
         }
 
         if (pn_session_state(ssn) == (PN_LOCAL_CLOSED | PN_REMOTE_CLOSED)) {
-            add_session_to_free_list(&qd_conn->free_link_session_list,ssn);
+            pn_session_free(ssn);
         }
         break;
 
@@ -516,7 +428,7 @@ void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
                 pn_session_close(ssn);
             }
             else if (pn_session_state(ssn) == (PN_LOCAL_CLOSED | PN_REMOTE_CLOSED)) {
-                add_session_to_free_list(&qd_conn->free_link_session_list,ssn);
+                pn_session_free(ssn);
             }
         }
         break;
@@ -578,7 +490,8 @@ void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
                 if (pn_link_state(pn_link) & PN_LOCAL_CLOSED) {
                     if (qd_link->close_sess_with_link && sess)
                         pn_session_close(sess);
-                    add_link_to_free_list(&qd_conn->free_link_session_list, pn_link);
+                    pn_link_set_context(pn_link, NULL);
+                    pn_link_free(pn_link);
                 }
                 if (node) {
                     node->ntype->link_detach_handler(node->context, qd_link, dt);
@@ -590,8 +503,9 @@ void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
     case PN_LINK_LOCAL_DETACH:
     case PN_LINK_LOCAL_CLOSE:
         pn_link = pn_event_link(event);
-        if (pn_link_state(pn_link) == (PN_LOCAL_CLOSED | PN_REMOTE_CLOSED)) {
-            add_link_to_free_list(&qd_conn->free_link_session_list, pn_link);
+        if (pn_link_state(pn_link) == (PN_LOCAL_CLOSED | PN_REMOTE_CLOSED) && pn_link_get_context(pn_link)) {
+            pn_link_set_context(pn_link, NULL);
+            pn_link_free(pn_link);
         }
         break;
 
@@ -625,9 +539,6 @@ void qd_container_handle_event(qd_container_t *container, pn_event_t *event)
     default:
         break;
     }
-    if (qd_conn) {
-        conn_event_complete(qd_conn);
-    }
 }
 
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/b974b884/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index 066c862..52651d1 100644
--- a/src/server.c
+++ b/src/server.c
@@ -500,7 +500,6 @@ qd_connection_t *qd_server_connection(qd_server_t *server, qd_server_config_t *c
     pn_connection_set_context(ctx->pn_conn, ctx);
     DEQ_ITEM_INIT(ctx);
     DEQ_INIT(ctx->deferred_calls);
-    DEQ_INIT(ctx->free_link_session_list);
     sys_mutex_lock(server->lock);
     ctx->connection_id = server->next_connection_id++;
     sys_mutex_unlock(server->lock);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/b974b884/src/server_private.h
----------------------------------------------------------------------
diff --git a/src/server_private.h b/src/server_private.h
index 6e6f1c3..77adf32 100644
--- a/src/server_private.h
+++ b/src/server_private.h
@@ -154,7 +154,6 @@ struct qd_connection_t {
     sys_mutex_t              *deferred_call_lock;
     bool                      policy_counted;
     char                     *role;  //The specified role of the connection, e.g. "normal", "inter-router", "route-container" etc.
-    qd_pn_free_link_session_list_t  free_link_session_list;
     void (*wake)(qd_connection_t*); /* Wake method, different for HTTP vs. proactor */
     char rhost[NI_MAXHOST];     /* Remote host numeric IP for incoming connections */
     char rhost_port[NI_MAXHOST+NI_MAXSERV]; /* Remote host:port for incoming connections */
@@ -166,7 +165,5 @@ ALLOC_DECLARE(qd_listener_t);
 ALLOC_DECLARE(qd_deferred_call_t);
 ALLOC_DECLARE(qd_connector_t);
 ALLOC_DECLARE(qd_connection_t);
-ALLOC_DECLARE(qd_pn_free_link_session_t);
-
 
 #endif


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


[09/10] qpid-dispatch git commit: DISPATCH-390: Restore HTTP using libwebsockets

Posted by ac...@apache.org.
DISPATCH-390: Restore HTTP using libwebsockets

- single HTTP thread uses libwebsockets standard polling features
- works with released libwebsockets, no patches required


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

Branch: refs/heads/master
Commit: 16980f6703f0b2b03a320c89cad60cdf669770d7
Parents: 20b06ac
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Apr 12 19:29:14 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:31:36 2017 -0400

----------------------------------------------------------------------
 CMakeLists.txt                   |   5 +-
 cmake/FindLibWebSockets.cmake    |  20 +-
 include/qpid/dispatch/server.h   |  11 +
 src/connection_manager.c         |   3 +-
 src/container.c                  |   2 +-
 src/http-libwebsockets.c         | 796 ++++++++++++++++++++--------------
 src/http-none.c                  |  22 +-
 src/http.h                       |  19 +-
 src/policy.c                     |   8 +-
 src/server.c                     | 103 +++--
 src/server_private.h             |  14 +-
 tests/system_tests_http.py       |   8 +
 tests/system_tests_one_router.py |   8 +
 13 files changed, 584 insertions(+), 435 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a06c67f..46f651e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -103,11 +103,8 @@ find_library(rt_lib rt)
 find_package(Proton 0.15 REQUIRED)
 
 ## Optional dependencies
-
 include(FindLibWebSockets)
-# FIXME aconway 2017-01-19: websockets disbled for temporary proactor work.
-# option(USE_LIBWEBSOCKETS "Use libwebsockets for WebSocket support" ${LIBWEBSOCKETS_FOUND})
-set(USE_LIBWEBSOCKETS OFF)
+option(USE_LIBWEBSOCKETS "Use libwebsockets for WebSocket support" ${LIBWEBSOCKETS_FOUND})
 
 ##
 ## Find Valgrind

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/cmake/FindLibWebSockets.cmake
----------------------------------------------------------------------
diff --git a/cmake/FindLibWebSockets.cmake b/cmake/FindLibWebSockets.cmake
index 18ef18a..a15d0d2 100644
--- a/cmake/FindLibWebSockets.cmake
+++ b/cmake/FindLibWebSockets.cmake
@@ -44,22 +44,10 @@ find_path(LIBWEBSOCKETS_INCLUDE_DIRS
 
 include(FindPackageHandleStandardArgs)
 
-find_package_handle_standard_args(LIBWEBSOCKETS DEFAULT_MSG LIBWEBSOCKETS_LIBRARIES LIBWEBSOCKETS_INCLUDE_DIRS)
-
-if(LIBWEBSOCKETS_FOUND)
-  # For the moment we need a patched version of LibWebSockets:
-  # https://github.com/alanconway/libwebsockets/tree/v2.1-stable-aconway-adopt-ssl
-  # This function check verifies we have it.
-  set(CMAKE_REQUIRED_INCLUDES ${LIBWEBSOCKETS_INCLUDE_DIRS})
-  set(CMAKE_REQUIRED_LIBRARIES ${LIBWEBSOCKETS_LIBRARIES})
-  check_function_exists(lws_adopt_socket_vhost LWS_ADOPT_SOCKET_VHOST_FOUND)
-  if (NOT LWS_ADOPT_SOCKET_VHOST_FOUND)
-    message("Cannot use LibWebSockets, no function lws_adopt_socket_vhost")
-    unset(LIBWEBSOCKETS_FOUND)
-  endif()
-endif()
+find_package_handle_standard_args(
+  LIBWEBSOCKETS DEFAULT_MSG LIBWEBSOCKETS_LIBRARIES LIBWEBSOCKETS_INCLUDE_DIRS)
 
 if(NOT LIBWEBSOCKETS_FOUND)
-  set(LIBWEBSOCKETS_LIBRARIES "")
-  set(LIBWEBSOCKETS_INCLUDE_DIRS "")
+  unset(LIBWEBSOCKETS_LIBRARIES)
+  unset(LIBWEBSOCKETS_INCLUDE_DIRS)
 endif()

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/include/qpid/dispatch/server.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h
index ec885ae..eb5214b 100644
--- a/include/qpid/dispatch/server.h
+++ b/include/qpid/dispatch/server.h
@@ -519,6 +519,17 @@ bool qd_connector_connect(qd_connector_t *ct);
 qd_error_t qd_register_display_name_service(qd_dispatch_t *qd, void *display_name_service);
 
 /**
+ * Get the name of the connection, based on its IP address.
+ */
+const char* qd_connection_name(const qd_connection_t *c);
+
+
+/**
+ * Get the remote host IP address of the connection.
+ */
+const char* qd_connection_remote_ip(const qd_connection_t *c);
+
+/**
  * @}
  */
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/connection_manager.c
----------------------------------------------------------------------
diff --git a/src/connection_manager.c b/src/connection_manager.c
index 4bc18ce..fefc961 100644
--- a/src/connection_manager.c
+++ b/src/connection_manager.c
@@ -607,8 +607,7 @@ void qd_connection_manager_start(qd_dispatch_t *qd)
 
     while (li) {
         if (!li->pn_listener) {
-            qd_listener_listen(li);
-            if (!li->pn_listener && first_start) {
+            if (!qd_listener_listen(li) && first_start) {
                 qd_log(qd->connection_manager->log_source, QD_LOG_CRITICAL,
                        "Listen on %s failed during initial config", li->config.host_port);
                 exit(1);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/container.c
----------------------------------------------------------------------
diff --git a/src/container.c b/src/container.c
index ddc0418..639ffa2 100644
--- a/src/container.c
+++ b/src/container.c
@@ -375,7 +375,7 @@ static void add_link_to_free_list(qd_pn_free_link_session_list_t  *free_link_ses
 
 
 /*
- * FIXME aconway 2017-04-12: IMO this should not be necessary, we should
+ * TODO aconway 2017-04-12: IMO this should not be necessary, we should
  * be able to pn_*_free links and sessions directly the handler function.
  * They will not actually be freed from memory till the event, connection,
  * proactor etc. have all released their references.

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/http-libwebsockets.c
----------------------------------------------------------------------
diff --git a/src/http-libwebsockets.c b/src/http-libwebsockets.c
index 745b090..9f6fbe8 100644
--- a/src/http-libwebsockets.c
+++ b/src/http-libwebsockets.c
@@ -19,10 +19,11 @@
 
 #include <qpid/dispatch/atomic.h>
 #include <qpid/dispatch/amqp.h>
-#include <qpid/dispatch/driver.h>
 #include <qpid/dispatch/threading.h>
 #include <qpid/dispatch/timer.h>
 
+#include <proton/connection_driver.h>
+
 #include <libwebsockets.h>
 
 #include <assert.h>
@@ -33,432 +34,555 @@
 #include "server_private.h"
 #include "config.h"
 
+static const char *CIPHER_LIST = "ALL:aNULL:!eNULL:@STRENGTH"; /* Default */
+
+/* Log for LWS messages. For dispatch server messages use qd_http_server_t::log */
 static qd_log_source_t* http_log;
 
-static const char *CIPHER_LIST = "ALL:aNULL:!eNULL:@STRENGTH";
+static qd_log_level_t qd_level(int lll) {
+    switch (lll) {
+    case LLL_ERR: return QD_LOG_ERROR;
+    case LLL_WARN: return QD_LOG_WARNING;
+    /* LWS is noisy compared to dispatch on the informative levels, downgrade */
+    case LLL_NOTICE: return QD_LOG_DEBUG;
+    default: return QD_LOG_TRACE; /* Everything else to trace  */
+    }
+}
+
+static void logger(int lll, const char *line)  {
+    size_t  len = strlen(line);
+    while (len > 1 && isspace(line[len-1])) { /* Strip trailing newline */
+        --len;
+    }
+    qd_log(http_log, qd_level(lll), "%.*s", len, line);
+}
+
+static void log_init() {
+    http_log = qd_log_source("HTTP");
+    int levels = 0;
+    for (int i = 0; i < LLL_COUNT; ++i) {
+        int lll = 1<<i;
+        levels |= qd_log_enabled(http_log, qd_level(lll)) ? lll : 0;
+    }
+    lws_set_log_level(levels, logger);
+}
+
+/* Intermediate write buffer: LWS needs extra header space on write.  */
+typedef struct buffer_t {
+    char *start;
+    size_t size, cap;
+} buffer_t;
+
+/* Ensure size bytes in buffer, make buf empty if alloc fails */
+static void buffer_set_size(buffer_t *buf, size_t size) {
+    if (size > buf->cap) {
+        buf->cap = (size > buf->cap * 2) ? size : buf->cap * 2;
+        buf->start = realloc(buf->start, buf->cap);
+    }
+    if (buf->start) {
+        buf->size = size;
+    } else {
+        buf->size = buf->cap = 0;
+    }
+}
 
-/* Associate file-descriptors, LWS instances and qdpn_connectors */
-typedef struct fd_data_t {
-    qdpn_connector_t *connector;
+/* AMQPWS connection: set as lws user data and qd_conn->context */
+typedef struct connection_t {
+    pn_connection_driver_t driver;
+    qd_connection_t* qd_conn;
+    buffer_t wbuf;   /* LWS requires allocated header space at start of buffer */
     struct lws *wsi;
-} fd_data_t;
+} connection_t;
 
-/* HTTP server state shared by all listeners  */
+/* Navigating from WSI pointer to qd objects */
+static qd_http_server_t *wsi_server(struct lws *wsi);
+static qd_http_listener_t *wsi_listener(struct lws *wsi);
+static qd_log_source_t *wsi_log(struct lws *wsi);
+
+
+/* Declare LWS callbacks and protocol list */
+static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+                         void *user, void *in, size_t len);
+static int callback_amqpws(struct lws *wsi, enum lws_callback_reasons reason,
+                           void *user, void *in, size_t len);
+
+static struct lws_protocols protocols[] = {
+    /* HTTP only protocol comes first */
+    {
+        "http-only",
+        callback_http,
+        0,
+    },
+    /* "amqp" is the official oasis AMQP over WebSocket protocol name */
+    {
+        "amqp",
+        callback_amqpws,
+        sizeof(connection_t),
+    },
+    /* "binary" is an alias for "amqp", for compatibility with clients designed
+     * to work with a WebSocket proxy
+     */
+    {
+        "binary",
+        callback_amqpws,
+        sizeof(connection_t),
+    },
+    { NULL, NULL, 0, 0 } /* terminator */
+};
+
+
+static inline int unexpected_close(struct lws *wsi, const char *msg) {
+    lws_close_reason(wsi, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION,
+                     (unsigned char*)msg, strlen(msg));
+    char peer[64];
+    lws_get_peer_simple(wsi, peer, sizeof(peer));
+    qd_log(wsi_log(wsi), QD_LOG_ERROR, "Error on HTTP connection from %s: %s", peer, msg);
+    return -1;
+}
+
+static int handle_events(connection_t* c) {
+    if (!c->qd_conn) {
+        return unexpected_close(c->wsi, "not-established");
+    }
+    pn_event_t *e;
+    while ((e = pn_connection_driver_next_event(&c->driver))) {
+        qd_connection_handle(c->qd_conn, e);
+    }
+    if (pn_connection_driver_write_buffer(&c->driver).size) {
+        lws_callback_on_writable(c->wsi);
+    }
+    if (pn_connection_driver_finished(&c->driver)) {
+        lws_close_reason(c->wsi, LWS_CLOSE_STATUS_NORMAL, NULL, 0);
+        return -1;
+    }
+    return 0;
+}
+
+/* The server has a bounded, thread-safe queue for external work */
+typedef struct work_t {
+    enum { W_NONE, W_LISTEN, W_CLOSE, W_WAKE, W_STOP } type;
+    void *value;
+} work_t;
+
+#define WORK_MAX 8              /* Just decouple threads, not a big buffer */
+
+typedef struct work_queue_t {
+    sys_mutex_t *lock;
+    sys_cond_t *cond;
+    work_t work[WORK_MAX];
+    size_t head, len;          /* Ring buffer */
+} work_queue_t;
+
+/* HTTP Server runs in a single thread, communication from other threads via work_queue */
 struct qd_http_server_t {
-    qd_dispatch_t *dispatch;
+    qd_server_t *server;
+    sys_thread_t *thread;
+    work_queue_t work;
     qd_log_source_t *log;
-    sys_mutex_t *lock;         /* For now use LWS as a thread-unsafe library. */
     struct lws_context *context;
-    qd_timer_t *timer;
-    int vhost_id;               /* unique identifier for vhost name */
-    fd_data_t *fd;              /* indexed by file descriptor */
-    size_t fd_len;
+    pn_timestamp_t now;         /* Cache current time in thread_run */
+    pn_timestamp_t next_tick;   /* Next requested tick service */
 };
 
-/* Per-HTTP-listener */
+static void work_queue_destroy(work_queue_t *wq) {
+    if (wq->lock) sys_mutex_free(wq->lock);
+    if (wq->cond) sys_cond_free(wq->cond);
+}
+
+static void work_queue_init(work_queue_t *wq) {
+    wq->lock = sys_mutex();
+    wq->cond = sys_cond();
+}
+
+ /* Block till there is space */
+static void work_push(qd_http_server_t *hs, work_t w) {
+    work_queue_t *wq = &hs->work;
+    sys_mutex_lock(wq->lock);
+    while (wq->len == WORK_MAX) {
+        lws_cancel_service(hs->context); /* Wake up the run thread to clear space */
+        sys_cond_wait(wq->cond, wq->lock);
+    }
+    wq->work[(wq->head + wq->len) % WORK_MAX] = w;
+    ++wq->len;
+    sys_mutex_unlock(wq->lock);
+    lws_cancel_service(hs->context); /* Wake up the run thread to handle my work */
+}
+
+/* Non-blocking, return { W_NONE, NULL } if empty */
+static work_t work_pop(qd_http_server_t *hs) {
+    work_t w = { W_NONE, NULL };
+    work_queue_t *wq = &hs->work;
+    sys_mutex_lock(wq->lock);
+    if (wq->len > 0) {
+        w = wq->work[wq->head];
+        wq->head = (wq->head + 1) % WORK_MAX;
+        --wq->len;
+        sys_cond_signal(wq->cond);
+    }
+    sys_mutex_unlock(wq->lock);
+    return w;
+}
+
+/* Each qd_http_listener_t is associated with an lws_vhost */
 struct qd_http_listener_t {
+    qd_listener_t *listener;
     qd_http_server_t *server;
     struct lws_vhost *vhost;
     struct lws_http_mount mount;
-    char name[256];             /* vhost name */
 };
 
-/* Get wsi/connector associated with fd or NULL if nothing on record. */
-static inline fd_data_t *fd_data(qd_http_server_t *s, int fd) {
-    fd_data_t *d = (fd < s->fd_len) ? &s->fd[fd] : NULL;
-    return (d && (d->connector || d->wsi)) ? d : NULL;
+void qd_http_listener_free(qd_http_listener_t *hl) {
+    if (!hl) return;
+    if (hl->listener) {
+        hl->listener->http = NULL;
+        qd_listener_decref(hl->listener);
+    }
+    free(hl);
 }
 
-static inline qd_http_server_t *wsi_http_server(struct lws *wsi) {
-    return (qd_http_server_t*)lws_context_user(lws_get_context(wsi));
+static qd_http_listener_t *qd_http_listener(qd_http_server_t *hs, qd_listener_t *li) {
+    qd_http_listener_t *hl = calloc(1, sizeof(*hl));
+    if (hl) {
+        hl->server = hs;
+        hl->listener = li;
+        li->http = hl;
+        sys_atomic_inc(&li->ref_count); /* Keep it around till qd_http_server_free() */
+    } else {
+        qd_log(hs->log, QD_LOG_CRITICAL, "No memory for HTTP listen on %s",
+               li->config.host_port);
+    }
+    return hl;
 }
 
-static inline qdpn_connector_t *wsi_connector(struct lws *wsi) {
-    fd_data_t *d = fd_data(wsi_http_server(wsi), lws_get_socket_fd(wsi));
-    return d ? d->connector : NULL;
-}
+static void listener_start(qd_http_listener_t *hl, qd_http_server_t *hs) {
+    log_init();                 /* Update log flags at each listener */
 
-static inline fd_data_t *set_fd(qd_http_server_t *s, int fd, qdpn_connector_t *c, struct lws *wsi) {
-    if (!s->fd || fd >= s->fd_len) {
-        size_t oldlen = s->fd_len;
-        s->fd_len = fd + 16;    /* Don't double, low-range FDs will be re-used first. */
-        void *newfds = realloc(s->fd, s->fd_len*sizeof(*s->fd));
-        if (!newfds) return NULL;
-        s->fd = newfds;
-        memset(s->fd + oldlen, 0, sizeof(*s->fd)*(s->fd_len - oldlen));
-    }
-    fd_data_t *d = &s->fd[fd];
-    d->connector = c;
-    d->wsi = wsi;
-    return d;
-}
+    qd_server_config_t *config = &hl->listener->config;
 
-/* Push read data into the transport.
- * Return 0 on success, number of bytes un-pushed on failure.
- */
-static int transport_push(pn_transport_t *t, pn_bytes_t buf) {
-    ssize_t cap;
-    while (buf.size > 0 && (cap = pn_transport_capacity(t)) > 0) {
-        if (buf.size > cap) {
-            pn_transport_push(t, buf.start, cap);
-            buf.start += cap;
-            buf.size -= cap;
-        } else {
-            pn_transport_push(t, buf.start, buf.size);
-            buf.size = 0;
-        }
+    int port = qd_port_int(config->port);
+    if (port < 0) {
+        qd_log(hs->log, QD_LOG_ERROR, "HTTP listener %s has invalid port %s",
+               config->host_port, config->port);
+        goto error;
     }
-    return buf.size;
-}
+    struct lws_http_mount *m = &hl->mount;
+    m->mountpoint = "/";    /* URL mount point */
+    m->mountpoint_len = strlen(m->mountpoint); /* length of the mountpoint */
+    m->origin = (config->http_root && *config->http_root) ? /* File system root */
+        config->http_root : QPID_CONSOLE_STAND_ALONE_INSTALL_DIR;
+    m->def = "index.html";  /* Default file name */
+    m->origin_protocol = LWSMPRO_FILE; /* mount type is a directory in a filesystem */
 
-static inline int normal_close(struct lws *wsi, const char *msg) {
-    lws_close_reason(wsi, LWS_CLOSE_STATUS_NORMAL, (unsigned char*)msg, strlen(msg));
-    return -1;
+    struct lws_context_creation_info info = {0};
+    info.mounts = m;
+    info.port = port;
+    info.protocols = protocols;
+    info.keepalive_timeout = 1;
+    info.ssl_cipher_list = CIPHER_LIST;
+    info.options |= LWS_SERVER_OPTION_VALIDATE_UTF8;
+    if (config->ssl_profile) {
+        info.ssl_cert_filepath = config->ssl_certificate_file;
+        info.ssl_private_key_filepath = config->ssl_private_key_file;
+        info.ssl_private_key_password = config->ssl_password;
+        info.ssl_ca_filepath = config->ssl_trusted_certificates;
+        info.options |=
+            LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+            (config->ssl_required ? 0 : LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT) |
+            (config->requireAuthentication ? LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT : 0);
+    }
+    info.vhost_name = hl->listener->config.host_port;
+    hl->vhost = lws_create_vhost(hs->context, &info);
+    if (hl->vhost) {
+        /* Store hl pointer in vhost */
+        void *vp = lws_protocol_vh_priv_zalloc(hl->vhost, &protocols[0], sizeof(hl));
+        memcpy(vp, &hl, sizeof(hl));
+        qd_log(hs->log, QD_LOG_NOTICE, "Listening for HTTP on %s", config->host_port);
+        return;
+    } else {
+        qd_log(hs->log, QD_LOG_NOTICE, "Error listening for HTTP on %s", config->host_port);
+        goto error;
+    }
+    return;
+
+  error:
+    if (hl->listener->exit_on_error) {
+        qd_log(hs->log, QD_LOG_CRITICAL, "Shutting down, required listener failed %s",
+               config->host_port);
+        exit(1);
+    }
+    qd_http_listener_free(hl);
 }
 
-static inline int unexpected_close(struct lws *wsi, const char *msg) {
-    lws_close_reason(wsi, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION, (unsigned char*)msg, strlen(msg));
-    return -1;
+static void listener_close(qd_http_listener_t *hl, qd_http_server_t *hs) {
+    /* TODO aconway 2017-04-13: can't easily stop listeners under libwebsockets */
+    qd_log(hs->log, QD_LOG_ERROR, "Cannot close HTTP listener %s",
+           hl->listener->config.host_port);
 }
 
 /*
- * Callback for un-promoted HTTP connections, and low-level external poll operations.
+ * LWS callback for un-promoted HTTP connections.
  * Note main HTTP file serving is handled by the "mount" struct below.
- * Called with http lock held.
  */
 static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                          void *user, void *in, size_t len)
 {
     switch (reason) {
 
-    case LWS_CALLBACK_HTTP:     /* Called if file mount can't find the file */
-        lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, (char*)in);
+    case LWS_CALLBACK_PROTOCOL_DESTROY:
+        qd_http_listener_free(wsi_listener(wsi));
         return -1;
 
-    case LWS_CALLBACK_ADD_POLL_FD: {
-        /* Record WSI against FD here, the connector will be recorded when lws_service returns. */
-        set_fd(wsi_http_server(wsi), lws_get_socket_fd(wsi), 0, wsi);
-        break;
-    }
-    case LWS_CALLBACK_DEL_POLL_FD: {
-        fd_data_t *d = fd_data(wsi_http_server(wsi), lws_get_socket_fd(wsi));
-        if (d) {
-            /* Tell dispatch to forget this FD, but let LWS do the actual close() */
-            if (d->connector) qdpn_connector_mark_closed(d->connector);
-            memset(d, 0, sizeof(*d));
-        }
-        break;
-    }
-    case LWS_CALLBACK_CHANGE_MODE_POLL_FD: {
-        struct lws_pollargs *p = (struct lws_pollargs*)in;
-        qdpn_connector_t *c = wsi_connector(wsi);
-        if (c) {
-            if (p->events & POLLIN) qdpn_connector_activate(c, QDPN_CONNECTOR_READABLE);
-            if (p->events & POLLOUT) qdpn_connector_activate(c, QDPN_CONNECTOR_WRITABLE);
-        }
-        break;
+    case LWS_CALLBACK_HTTP: {
+        /* Called if file mount can't find the file */
+        lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, (char*)in);
+        return -1;
     }
 
-    /* NOTE: Not using LWS_CALLBACK_LOCK/UNLOCK_POLL as we are serializing all HTTP work for now. */
-
     default:
-        break;
+        return 0;
     }
-
-    return 0;
 }
 
-/* Buffer to allocate extra header space required by LWS.  */
-typedef struct buffer_t { char *start; size_t size; size_t cap; } buffer_t;
+/* Wake up a connection managed by the http server thread */
+static void connection_wake(qd_connection_t *qd_conn)
+{
+    connection_t *c = qd_conn->context;
+    if (c && qd_conn->listener->http) {
+        qd_http_server_t *hs = qd_conn->listener->http->server;
+        work_t w = { W_WAKE, c };
+        work_push(hs, w);
+    }
+}
 
-/* Callbacks for promoted AMQP over WS connections.
- * Called with http lock held.
- */
+/* Callbacks for promoted AMQP over WS connections. */
 static int callback_amqpws(struct lws *wsi, enum lws_callback_reasons reason,
                            void *user, void *in, size_t len)
 {
-    qdpn_connector_t *c = wsi_connector(wsi);
-    pn_transport_t *t = c ? qdpn_connector_transport(c) : NULL;
+    qd_http_server_t *hs = wsi_server(wsi);
+    connection_t *c = (connection_t*)user;
 
     switch (reason) {
 
     case LWS_CALLBACK_ESTABLISHED: {
-        qd_log(wsi_http_server(wsi)->log, QD_LOG_DEBUG,
-               "Upgraded incoming HTTP connection from  %s[%"PRIu64"] to AMQP over WebSocket",
-               qdpn_connector_name(c),
-               qd_connection_connection_id((qd_connection_t*)qdpn_connector_context(c)));
-        memset(user, 0, sizeof(buffer_t));
-        break;
+        /* Upgrade accepted HTTP connection to AMQPWS */
+        memset(c, 0, sizeof(*c));
+        c->wsi = wsi;
+        qd_http_listener_t *hl = wsi_listener(wsi);
+        if (hl == NULL) {
+            return unexpected_close(c->wsi, "cannot-upgrade");
+        }
+        c->qd_conn = qd_server_connection(hs->server, &hl->listener->config);
+        if (c->qd_conn == NULL) {
+            return unexpected_close(c->wsi, "out-of-memory");
+        }
+        c->qd_conn->context = c;
+        c->qd_conn->wake = connection_wake;
+        c->qd_conn->listener = hl->listener;
+        lws_get_peer_simple(wsi, c->qd_conn->rhost, sizeof(c->qd_conn->rhost));
+        int err = pn_connection_driver_init(&c->driver, c->qd_conn->pn_conn, NULL);
+        if (err) {
+            return unexpected_close(c->wsi, pn_code(err));
+        }
+        strncpy(c->qd_conn->rhost_port, c->qd_conn->rhost, sizeof(c->qd_conn->rhost_port));
+        qd_log(hs->log, QD_LOG_DEBUG,
+               "[%"PRIu64"] upgraded HTTP connection from %s to AMQPWS",
+               qd_connection_connection_id(c->qd_conn), qd_connection_name(c->qd_conn));
+        return handle_events(c);
     }
 
     case LWS_CALLBACK_SERVER_WRITEABLE: {
-        ssize_t size;
-        if (!t || (size = pn_transport_pending(t)) < 0) {
-            return normal_close(wsi, "write-closed");
-        }
-        if (size > 0) {
-            const void *start = pn_transport_head(t);
-            /* lws_write() demands LWS_PRE bytes of free space before the data */
-            size_t tmpsize = size + LWS_PRE;
-            buffer_t *wtmp = (buffer_t*)user;
-            if (wtmp->start == NULL || wtmp->cap < tmpsize) {
-                wtmp->start = realloc(wtmp->start, tmpsize);
-                wtmp->size = wtmp->cap = tmpsize;
-            }
-            if (wtmp->start == NULL) {
-                return unexpected_close(wsi, "out-of-memory");
+        if (handle_events(c)) return -1;
+        pn_bytes_t dbuf = pn_connection_driver_write_buffer(&c->driver);
+        if (dbuf.size) {
+            /* lws_write() demands LWS_PRE bytes of free space before the data,
+             * so we must copy from the driver's buffer to larger temporary wbuf
+             */
+            buffer_set_size(&c->wbuf, LWS_PRE + dbuf.size);
+            if (c->wbuf.start == NULL) {
+                return unexpected_close(c->wsi, "out-of-memory");
             }
-            void *tmpstart = wtmp->start + LWS_PRE;
-            memcpy(tmpstart, start, size);
-            ssize_t wrote = lws_write(wsi, tmpstart, size, LWS_WRITE_BINARY);
+            unsigned char* buf = (unsigned char*)c->wbuf.start + LWS_PRE;
+            memcpy(buf, dbuf.start, dbuf.size);
+            ssize_t wrote = lws_write(wsi, buf, dbuf.size, LWS_WRITE_BINARY);
             if (wrote < 0) {
-                pn_transport_close_head(t);
-                return normal_close(wsi, "write-error");
+                pn_connection_driver_write_close(&c->driver);
+                return unexpected_close(c->wsi, "write-error");
             } else {
-                pn_transport_pop(t, (size_t)wrote);
+                pn_connection_driver_write_done(&c->driver, wrote);
             }
         }
-        break;
+        return handle_events(c);
     }
 
     case LWS_CALLBACK_RECEIVE: {
-        if (!t || pn_transport_capacity(t) < 0) {
-            return normal_close(wsi, "read-closed");
-        }
-        if (transport_push(t, pn_bytes(len, in))) {
-            return unexpected_close(wsi, "read-overflow");
+        while (len > 0) {
+            if (handle_events(c)) return -1;
+            pn_rwbytes_t dbuf = pn_connection_driver_read_buffer(&c->driver);
+            if (dbuf.size == 0) {
+                return unexpected_close(c->wsi, "unexpected-data");
+            }
+            size_t copy = (len < dbuf.size) ? len : dbuf.size;
+            memcpy(dbuf.start, in, copy);
+            pn_connection_driver_read_done(&c->driver, copy);
+            len -= copy;
+            in = (char*)in + copy;
         }
-        break;
+        return handle_events(c);
     }
 
-    case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
-        if (t) {
-            pn_transport_close_tail(t);
+    case LWS_CALLBACK_USER: {
+        pn_timestamp_t next_tick = pn_transport_tick(c->driver.transport, hs->now);
+        if (next_tick && next_tick > hs->now && next_tick < hs->next_tick) {
+            hs->next_tick = next_tick;
         }
+        return handle_events(c);
+    }
 
-    case LWS_CALLBACK_CLOSED:
-        break;
-
-    default:
-        break;
+    case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: {
+        pn_connection_driver_read_close(&c->driver);
+        return handle_events(c);
     }
-    return 0;
-}
 
-static void check_timer(void *void_http_server) {
-    qd_http_server_t *s = (qd_http_server_t*)void_http_server;
-    /* Run LWS global timer and forced-service checks. */
-    sys_mutex_lock(s->lock);
-    lws_service_fd(s->context, NULL);
-    while (!lws_service_adjust_timeout(s->context, 1, 0)) {
-        /* -1 timeout means just do forced service */
-        lws_plat_service_tsi(s->context, -1, 0);
-    }
-    if (!s->timer) {
-        s->timer = qd_timer(s->dispatch, check_timer, s);
-    }
-    sys_mutex_unlock(s->lock);
-    /* Timer is locked using server lock. */
-    qd_timer_cancel(s->timer);
-    qd_timer_schedule(s->timer, 1000); /* LWS wants per-second wakeups */
-}
+    case LWS_CALLBACK_CLOSED: {
+        if (c->driver.transport) {
+            pn_connection_driver_close(&c->driver);
+            handle_events(c);
+        }
+        pn_connection_driver_destroy(&c->driver);
+        free(c->wbuf.start);
+        return -1;
+    }
 
-static qd_http_listener_t * qdpn_connector_http_listener(qdpn_connector_t* c) {
-    qd_listener_t* ql = (qd_listener_t*)qdpn_listener_context(qdpn_connector_listener(c));
-    return qd_listener_http(ql);
+    default:
+        return 0;
+    }
 }
 
-static void http_connector_process(qdpn_connector_t *c) {
-    qd_http_listener_t *hl = qdpn_connector_http_listener(c);
-    qd_http_server_t *s = hl->server;
-    sys_mutex_lock(s->lock);
-    int fd = qdpn_connector_get_fd(c);
-    fd_data_t *d = fd_data(s, fd);
-    /* Make sure we are still tracking this fd, could have been closed by timer */
-    if (d) {
-        pn_transport_t *t = qdpn_connector_transport(c);
-        int flags =
-            (qdpn_connector_hangup(c) ? POLLHUP : 0) |
-            (qdpn_connector_activated(c, QDPN_CONNECTOR_READABLE) ? POLLIN : 0) |
-            (qdpn_connector_activated(c, QDPN_CONNECTOR_WRITABLE) ? POLLOUT : 0);
-        struct lws_pollfd pfd = { fd, flags, flags };
-        if (pn_transport_pending(t) > 0) {
-            lws_callback_on_writable(d->wsi);
+#define DEFAULT_TICK 1000
+
+static void* http_thread_run(void* v) {
+    qd_http_server_t *hs = v;
+    qd_log(hs->log, QD_LOG_INFO, "HTTP server thread running");
+    int result = 0;
+    while(result >= 0) {
+        /* Send a USER event to run transport ticks, may decrease hs->next_tick. */
+        hs->now = qd_timer_now();
+        hs->next_tick = hs->now + DEFAULT_TICK;
+        lws_callback_all_protocol(hs->context, &protocols[1], LWS_CALLBACK_USER);
+        lws_callback_all_protocol(hs->context, &protocols[2], LWS_CALLBACK_USER);
+        pn_millis_t timeout = (hs->next_tick > hs->now) ? hs->next_tick - hs->now : 1;
+        result = lws_service(hs->context, timeout);
+
+        /* Process any work items on the queue */
+        for (work_t w = work_pop(hs); w.type != W_NONE; w = work_pop(hs)) {
+            switch (w.type) {
+            case W_NONE:
+                break;
+            case W_STOP:
+                result = -1;
+                break;
+            case W_LISTEN:
+                listener_start((qd_http_listener_t*)w.value, hs);
+                break;
+            case W_CLOSE:
+                listener_close((qd_http_listener_t*)w.value, hs);
+                break;
+            case W_WAKE: {
+                connection_t *c = w.value;
+                pn_collector_put(c->driver.collector, PN_OBJECT, c->driver.connection,
+                                 PN_CONNECTION_WAKE);
+                handle_events(c);
+                break;
+            }
+            }
         }
-        lws_service_fd(s->context, &pfd);
-        d = fd_data(s, fd);    /* We may have stopped tracking during service */
-        if (pn_transport_capacity(t) > 0)
-            qdpn_connector_activate(c, QDPN_CONNECTOR_READABLE);
-        if (pn_transport_pending(t) > 0 || (d && lws_partial_buffered(d->wsi)))
-            qdpn_connector_activate(c, QDPN_CONNECTOR_WRITABLE);
-        pn_timestamp_t wake = pn_transport_tick(t, qdpn_now(NULL));
-        if (wake) qdpn_connector_wakeup(c, wake);
-    }
-    sys_mutex_unlock(s->lock);
-    check_timer(s);             /* Make sure the timer is running */
+    }
+    qd_log(hs->log, QD_LOG_INFO, "HTTP server thread exit");
+    return NULL;
 }
 
-/* Dispatch closes a connector because it is HUP, socket_error or transport_closed()  */
-static void http_connector_close(qdpn_connector_t *c) {
-    int fd = qdpn_connector_get_fd(c);
-    qd_http_server_t *s = qdpn_connector_http_listener(c)->server;
-    sys_mutex_lock(s->lock);
-    fd_data_t *d = fd_data(s, fd);
-    if (d) {                    /* Only if we are still tracking fd */
-        /* Shutdown but let LWS do the close(),  possibly in later timer */
-        shutdown(qdpn_connector_get_fd(c), SHUT_RDWR);
-        short flags = POLLIN|POLLOUT|POLLHUP;
-        struct lws_pollfd pfd = { qdpn_connector_get_fd(c), flags, flags };
-        lws_service_fd(s->context, &pfd);
-        qdpn_connector_mark_closed(c);
-        memset(d, 0 , sizeof(*d));
-    }
-    sys_mutex_unlock(s->lock);
+void qd_http_server_free(qd_http_server_t *hs) {
+    if (!hs) return;
+    if (hs->thread) {
+        /* Thread safe, stop via work queue then clean up */
+        work_t work = { W_STOP, NULL };
+        work_push(hs, work);
+        sys_thread_join(hs->thread);
+        sys_thread_free(hs->thread);
+        hs->thread = NULL;
+    }
+    work_queue_destroy(&hs->work);
+    if (hs->context) lws_context_destroy(hs->context);
+    free(hs);
 }
 
-static struct qdpn_connector_methods_t http_methods = {
-    http_connector_process,
-    http_connector_close
-};
-
-void qd_http_listener_accept(qd_http_listener_t *hl, qdpn_connector_t *c) {
-    qd_http_server_t *s = hl->server;
-    sys_mutex_lock(s->lock);
-    int fd = qdpn_connector_get_fd(c);
-    struct lws *wsi = lws_adopt_socket_vhost(hl->vhost, fd);
-    fd_data_t *d = fd_data(s, fd);
-    if (d) {          /* FD was adopted by LWS, so dispatch must not close it */
-        qdpn_connector_set_methods(c, &http_methods);
-        if (wsi) d->connector = c;
-    }
-    sys_mutex_unlock(s->lock);
-    if (!wsi) {       /* accept failed, dispatch should forget the FD. */
-        qdpn_connector_mark_closed(c);
+qd_http_server_t *qd_http_server(qd_server_t *s, qd_log_source_t *log) {
+    log_init();
+    qd_http_server_t *hs = calloc(1, sizeof(*hs));
+    if (hs) {
+        work_queue_init(&hs->work);
+        struct lws_context_creation_info info = {0};
+        info.gid = info.uid = -1;
+        info.user = hs;
+        info.server_string = QD_CONNECTION_PROPERTY_PRODUCT_VALUE;
+        info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+            LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME |
+            LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+        info.max_http_header_pool = 32;
+        info.timeout_secs = 1;
+
+        hs->context = lws_create_context(&info);
+        hs->server = s;
+        hs->log = log;              /* For messages from this file */
+        if (!hs->context) {
+            qd_log(hs->log, QD_LOG_CRITICAL, "No memory starting HTTP server");
+            qd_http_server_free(hs);
+            hs = NULL;
+        }
     }
+    return hs;
 }
 
-static struct lws_protocols protocols[] = {
-    /* HTTP only protocol comes first */
-    {
-        "http-only",
-        callback_http,
-        0,
-    },
-    /* "amqp" is the official oasis AMQP over WebSocket protocol name */
-    {
-        "amqp",
-        callback_amqpws,
-        sizeof(buffer_t),
-    },
-    /* "binary" is an alias for "amqp", for compatibility with clients designed
-     * to work with a WebSocket proxy
-     */
-    {
-        "binary",
-        callback_amqpws,
-        sizeof(buffer_t),
-    },
-    { NULL, NULL, 0, 0 } /* terminator */
-};
+/* Thread safe calls that put items on work queue */
 
-static qd_log_level_t qd_level(int lll) {
-    switch (lll) {
-    case LLL_ERR: return QD_LOG_ERROR;
-    case LLL_WARN: return QD_LOG_WARNING;
-    case LLL_NOTICE: return QD_LOG_INFO;
-    case LLL_INFO:return QD_LOG_DEBUG;
-    case LLL_DEBUG: return QD_LOG_TRACE;
-    default: return QD_LOG_NONE;
+qd_http_listener_t *qd_http_server_listen(qd_http_server_t *hs, qd_listener_t *li)
+{
+    sys_mutex_lock(hs->work.lock);
+    if (!hs->thread) {
+        hs->thread = sys_thread(http_thread_run, hs);
     }
+    bool ok = hs->thread;
+    sys_mutex_unlock(hs->work.lock);
+    if (!ok) return NULL;
+
+    qd_http_listener_t *hl = qd_http_listener(hs, li);
+    if (hl) {
+        work_t w = { W_LISTEN, hl };
+        work_push(hs, w);
+    }
+    return hl;
 }
 
-static void emit_lws_log(int lll, const char *line)  {
-    size_t  len = strlen(line);
-    while (len > 1 && isspace(line[len-1]))
-        --len;
-    qd_log(http_log, qd_level(lll), "%.*s", len, line);
-}
-
-qd_http_server_t *qd_http_server(qd_dispatch_t *d, qd_log_source_t *log) {
-    if (!http_log) http_log = qd_log_source("HTTP");
-    qd_http_server_t *s = calloc(1, sizeof(*s));
-    if (!s) return NULL;
-    s->log = log;
-    s->lock = sys_mutex();
-    s->dispatch = d;
-    int levels =
-        (qd_log_enabled(log, QD_LOG_ERROR) ? LLL_ERR : 0) |
-        (qd_log_enabled(log, QD_LOG_WARNING) ? LLL_WARN : 0) |
-        (qd_log_enabled(log, QD_LOG_INFO) ? LLL_NOTICE : 0) |
-        (qd_log_enabled(log, QD_LOG_DEBUG) ? LLL_INFO : 0) |
-        (qd_log_enabled(log, QD_LOG_TRACE) ? LLL_DEBUG : 0);
-    lws_set_log_level(levels, emit_lws_log);
-
-    struct lws_context_creation_info info = {0};
-    info.gid = info.uid = -1;
-    info.user = s;
-    info.server_string = QD_CONNECTION_PROPERTY_PRODUCT_VALUE;
-    info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
-        LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME |
-        LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-    info.max_http_header_pool = 32;
-    info.timeout_secs = 1;
-    s->context = lws_create_context(&info);
-    if (!s->context) {
-        free(s);
-        return NULL;
-    }
-    return s;
+void qd_http_listener_close(qd_http_listener_t *hl)
+{
+    work_t w = { W_CLOSE, hl };
+    work_push(hl->server, w);
 }
 
-void qd_http_server_free(qd_http_server_t *s) {
-    sys_mutex_free(s->lock);
-    lws_context_destroy(s->context);
-    if (s->timer) qd_timer_free(s->timer);
-    if (s->fd) free(s->fd);
-    free(s);
+static qd_http_server_t *wsi_server(struct lws *wsi) {
+    return (qd_http_server_t*)lws_context_user(lws_get_context(wsi));
 }
 
-qd_http_listener_t *qd_http_listener(qd_http_server_t *s, const qd_server_config_t *config) {
-    qd_http_listener_t *hl = calloc(1, sizeof(*hl));
-    if (!hl) return NULL;
-    hl->server = s;
-
-    struct lws_context_creation_info info = {0};
-
-    struct lws_http_mount *m = &hl->mount;
-    m->mountpoint = "/";    /* URL mount point */
-    m->mountpoint_len = strlen(m->mountpoint); /* length of the mountpoint */
-    m->origin = (config->http_root && *config->http_root) ? /* File system root */
-        config->http_root : QPID_CONSOLE_STAND_ALONE_INSTALL_DIR;
-    m->def = "index.html";  /* Default file name */
-    m->origin_protocol = LWSMPRO_FILE; /* mount type is a directory in a filesystem */
-    info.mounts = m;
-    info.port = CONTEXT_PORT_NO_LISTEN_SERVER; /* Don't use LWS listener */
-    info.protocols = protocols;
-    info.keepalive_timeout = 1;
-    info.ssl_cipher_list = CIPHER_LIST;
-    info.options |= LWS_SERVER_OPTION_VALIDATE_UTF8;
-    if (config->ssl_profile) {
-        info.ssl_cert_filepath = config->ssl_certificate_file;
-        info.ssl_private_key_filepath = config->ssl_private_key_file;
-        info.ssl_private_key_password = config->ssl_password;
-        info.ssl_ca_filepath = config->ssl_trusted_certificates;
-        info.options |=
-            LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
-            (config->ssl_required ? 0 : LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT) |
-            (config->requireAuthentication ? LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT : 0);
-    }
-    snprintf(hl->name, sizeof(hl->name), "vhost%x", s->vhost_id++);
-    info.vhost_name = hl->name;
-    hl->vhost = lws_create_vhost(s->context, &info);
-    if (!hl->vhost) {
-        free(hl);
-        return NULL;
+static qd_http_listener_t *wsi_listener(struct lws *wsi) {
+    qd_http_listener_t *hl = NULL;
+    struct lws_vhost *vhost = lws_get_vhost(wsi);
+    if (vhost) {                /* Get qd_http_listener from vhost data */
+        void *vp = lws_protocol_vh_priv_get(vhost, &protocols[0]);
+        memcpy(&hl, vp, sizeof(hl));
     }
     return hl;
 }
 
-void qd_http_listener_free(qd_http_listener_t *hl) {
-    free(hl);
+static qd_log_source_t *wsi_log(struct lws *wsi) {
+    return wsi_server(wsi)->log;
 }

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/http-none.c
----------------------------------------------------------------------
diff --git a/src/http-none.c b/src/http-none.c
index a8953e5..57869d5 100644
--- a/src/http-none.c
+++ b/src/http-none.c
@@ -20,29 +20,21 @@
 #include <qpid/dispatch/log.h>
 #include "http.h"
 
+struct qd_dispatch_t;
+
 /* No HTTP implementation available. */
 
-qd_http_server_t *qd_http_server(struct qd_dispatch_t *d, qd_log_source_t *log)
+qd_http_server_t *qd_http_server(struct qd_server_t *s, qd_log_source_t *log)
 {
     qd_log(log, QD_LOG_WARNING, "HTTP support is not available");
     return 0;
 }
 
-void qd_http_server_free(qd_http_server_t *h)
-{
-}
+void qd_http_server_free(qd_http_server_t *h) {}
 
-qd_http_listener_t *qd_http_listener(struct qd_http_server_t *s,
-                                     const struct qd_server_config_t *config)
-{
-    return 0;
-}
+void* qd_http_server_run(void* qd_http_server) { return 0; }
+
+qd_http_listener_t *qd_http_server_listen(qd_http_server_t *s, struct qd_listener_t *li) { return 0; }
 
-void qd_http_listener_free(qd_http_listener_t *hl)
-{
-}
 
-void qd_http_listener_accept(qd_http_listener_t *hl, struct qdpn_connector_t *c)
-{
-}
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/http.h
----------------------------------------------------------------------
diff --git a/src/http.h b/src/http.h
index fae3f1d..a169998 100644
--- a/src/http.h
+++ b/src/http.h
@@ -23,17 +23,18 @@
 typedef struct qd_http_listener_t qd_http_listener_t;
 typedef struct qd_http_server_t qd_http_server_t;
 
-struct qd_dispatch_t;
-struct qd_log_source_t;
+struct qd_server_t;
 struct qd_server_config_t;
-struct qdpn_connector_t;
+struct qd_listener_t;
+struct qd_log_source_t;
 
-qd_http_server_t *qd_http_server(struct qd_dispatch_t *dispatch, struct qd_log_source_t *log);
+/* Create a HTTP server */
+qd_http_server_t *qd_http_server(struct qd_server_t *server, struct qd_log_source_t *log);
+
+/* Free the HTTP server */
 void qd_http_server_free(qd_http_server_t*);
-qd_http_listener_t *qd_http_listener(struct qd_http_server_t *s,
-                                     const struct qd_server_config_t *config);
-void qd_http_listener_free(qd_http_listener_t *hl);
-/* On error, qdpn_connector_closed(c) is true. */
-void qd_http_listener_accept(qd_http_listener_t *hl, struct qdpn_connector_t *c);
+
+/* Listening for HTTP, thread safe. */
+qd_http_listener_t *qd_http_server_listen(qd_http_server_t *s, struct qd_listener_t *li);
 
 #endif // QD_HTTP_H

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/policy.c
----------------------------------------------------------------------
diff --git a/src/policy.c b/src/policy.c
index a55f245..2ddbf94 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -396,7 +396,7 @@ bool qd_policy_approve_amqp_session(pn_session_t *ssn, qd_connection_t *qd_conn)
     pn_connection_t *conn = qd_connection_pn(qd_conn);
     qd_dispatch_t *qd = qd_server_dispatch(qd_conn->server);
     qd_policy_t *policy = qd->policy;
-    const char *hostip = qd_connection_hostip(qd_conn);
+    const char *hostip = qd_connection_remote_ip(qd_conn);
     const char *vhost = pn_connection_remote_hostname(conn);
     if (result) {
         qd_log(policy->log_source,
@@ -567,7 +567,7 @@ bool _qd_policy_approve_link_name(const char *username, const char *allowed, con
 
 bool qd_policy_approve_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_conn)
 {
-    const char *hostip = qd_connection_hostip(qd_conn);
+    const char *hostip = qd_connection_remote_ip(qd_conn);
     const char *vhost = pn_connection_remote_hostname(qd_connection_pn(qd_conn));
 
     if (qd_conn->policy_settings->maxSenders) {
@@ -618,7 +618,7 @@ bool qd_policy_approve_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_
 
 bool qd_policy_approve_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *qd_conn)
 {
-    const char *hostip = qd_connection_hostip(qd_conn);
+    const char *hostip = qd_connection_remote_ip(qd_conn);
     const char *vhost = pn_connection_remote_hostname(qd_connection_pn(qd_conn));
 
     if (qd_conn->policy_settings->maxReceivers) {
@@ -683,7 +683,7 @@ void qd_policy_amqp_open(qd_connection_t *qd_conn) {
     if (policy->enableVhostPolicy) {
         // Open connection or not based on policy.
         pn_transport_t *pn_trans = pn_connection_transport(conn);
-        const char *hostip = qd_connection_hostip(qd_conn);
+        const char *hostip = qd_connection_remote_ip(qd_conn);
         const char *pcrh = pn_connection_remote_hostname(conn);
         const char *vhost = (pcrh ? pcrh : "");
         const char *conn_name = qd_connection_name(qd_conn);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index e7fa34d..066c862 100644
--- a/src/server.c
+++ b/src/server.c
@@ -475,9 +475,14 @@ static void decorate_connection(qd_server_t *qd_server, pn_connection_t *conn, c
     pn_data_exit(pn_connection_properties(conn));
 }
 
+/* Wake function for proactor-manaed connections */
+static void connection_wake(qd_connection_t *ctx) {
+    if (ctx->pn_conn) pn_connection_wake(ctx->pn_conn);
+}
 
-/* Construct a new qd_connection. */
-static qd_connection_t *qd_connection(qd_server_t *server, qd_server_config_t *config) {
+/* Construct a new qd_connection. Thread safe. */
+qd_connection_t *qd_server_connection(qd_server_t *server, qd_server_config_t *config)
+{
     qd_connection_t *ctx = new_qd_connection_t();
     if (!ctx) return NULL;
     ZERO(ctx);
@@ -491,6 +496,7 @@ static qd_connection_t *qd_connection(qd_server_t *server, qd_server_config_t *c
         return NULL;
     }
     ctx->server = server;
+    ctx->wake = connection_wake; /* Default, over-ridden for HTTP connections */
     pn_connection_set_context(ctx->pn_conn, ctx);
     DEQ_ITEM_INIT(ctx);
     DEQ_INIT(ctx->deferred_calls);
@@ -508,7 +514,7 @@ static void on_accept(pn_event_t *e)
     assert(pn_event_type(e) == PN_LISTENER_ACCEPT);
     pn_listener_t *pn_listener = pn_event_listener(e);
     qd_listener_t *listener = pn_listener_get_context(pn_listener);
-    qd_connection_t *ctx = qd_connection(listener->server, &listener->config);
+    qd_connection_t *ctx = qd_server_connection(listener->server, &listener->config);
     if (!ctx) {
         qd_log(listener->server->log_source, QD_LOG_CRITICAL,
                "Allocation failure during accept to %s", listener->config.host_port);
@@ -549,25 +555,19 @@ void connect_fail(qd_connection_t *ctx, const char *name, const char *descriptio
 
 
 /* Get the host IP address for the remote end */
-static int set_remote_host_port(qd_connection_t *ctx) {
+static void set_rhost_port(qd_connection_t *ctx) {
     pn_transport_t *tport  = pn_connection_transport(ctx->pn_conn);
-    const struct sockaddr_storage* addr = pn_proactor_addr_sockaddr(pn_proactor_addr_remote(tport));
-    int err = 0;
-    if (!addr) {
-        err = -1;
-        qd_log(ctx->server->log_source, QD_LOG_ERROR, "No remote address for connection to %s");
-    } else {
+    const struct sockaddr_storage* addr =
+        pn_proactor_addr_sockaddr(pn_proactor_addr_remote(tport));
+    if (addr) {
         char rport[NI_MAXSERV] = "";
         int err = getnameinfo((struct sockaddr*)addr, sizeof(*addr),
                               ctx->rhost, sizeof(ctx->rhost), rport, sizeof(rport),
                               NI_NUMERICHOST | NI_NUMERICSERV);
         if (!err) {
             snprintf(ctx->rhost_port, sizeof(ctx->rhost_port), "%s:%s", ctx->rhost, rport);
-        } else {
-            qd_log(ctx->server->log_source, QD_LOG_ERROR, "No remote address for connection to %s");
         }
     }
-    return err;
 }
 
 
@@ -581,7 +581,6 @@ static void on_connection_bound(qd_server_t *server, pn_event_t *e) {
     //
     // Proton pushes out its trace to transport_tracer() which in turn writes a trace
     // message to the qdrouter log If trace level logging is enabled on the router set
-    // PN_TRACE_DRV | PN_TRACE_FRM | PN_TRACE_RAW on the proton transport
     //
     if (qd_log_enabled(ctx->server->log_source, QD_LOG_TRACE)) {
         pn_transport_trace(tport, PN_TRACE_FRM);
@@ -593,9 +592,9 @@ static void on_connection_bound(qd_server_t *server, pn_event_t *e) {
         config = &ctx->listener->config;
         const char *name = config->host_port;
         pn_transport_set_server(tport);
+        set_rhost_port(ctx);
 
-        if (set_remote_host_port(ctx) == 0 &&
-            qd_policy_socket_accept(server->qd->policy, ctx->rhost))
+        if (qd_policy_socket_accept(server->qd->policy, ctx->rhost))
         {
             ctx->policy_counted = true;
         } else {
@@ -667,10 +666,9 @@ void qd_container_handle_event(qd_container_t *container, pn_event_t *event);
 
 static void handle_listener(pn_event_t *e, qd_server_t *qd_server) {
     qd_log_source_t *log = qd_server->log_source;
-
-    /* FIXME aconway 2017-02-20: HTTP support */
     qd_listener_t *li = (qd_listener_t*) pn_listener_get_context(pn_event_listener(e));
     const char *host_port = li->config.host_port;
+
     switch (pn_event_type(e)) {
 
     case PN_LISTENER_OPEN:
@@ -705,7 +703,7 @@ static void handle_listener(pn_event_t *e, qd_server_t *qd_server) {
 }
 
 
-static void qd_connection_free(qd_connection_t *ctx)
+void qd_connection_free(qd_connection_t *ctx)
 {
     qd_server_t *qd_server = ctx->server;
 
@@ -751,7 +749,7 @@ static void qd_connection_free(qd_connection_t *ctx)
 /* Events involving a connection or listener are serialized by the proactor so
  * only one event per connection / listener will be processed at a time.
  */
-static bool handle(pn_event_t *e, qd_server_t *qd_server) {
+static bool handle(qd_server_t *qd_server, pn_event_t *e) {
     pn_connection_t *pn_conn = pn_event_connection(e);
     qd_connection_t *ctx  = pn_conn ? (qd_connection_t*) pn_connection_get_context(pn_conn) : NULL;
 
@@ -803,7 +801,7 @@ static bool handle(pn_event_t *e, qd_server_t *qd_server) {
     /* TODO aconway 2017-04-18: fold the container handler into the server */
     qd_container_handle_event(qd_server->container, e);
 
-    /* Free the connection after all other processing */
+    /* Free the connection after all other processing is complete */
     if (ctx && pn_event_type(e) == PN_TRANSPORT_CLOSED) {
         pn_connection_set_context(pn_conn, NULL);
         qd_connection_free(ctx);
@@ -819,7 +817,7 @@ static void *thread_run(void *arg)
         pn_event_batch_t *events = pn_proactor_wait(qd_server->proactor);
         pn_event_t * e;
         while (running && (e = pn_event_batch_next(events))) {
-            running = handle(e, qd_server);
+            running = handle(qd_server, e);
         }
         pn_proactor_done(qd_server->proactor, events);
     }
@@ -836,7 +834,7 @@ static void try_open_lh(qd_connector_t *ct)
         return;
     }
 
-    qd_connection_t *ctx = qd_connection(ct->server, &ct->config);
+    qd_connection_t *ctx = qd_server_connection(ct->server, &ct->config);
     if (!ctx) {                 /* Try again later */
         qd_log(ct->server->log_source, QD_LOG_CRITICAL, "Allocation failure connecting to %s",
                ct->config.host_port);
@@ -987,7 +985,7 @@ qd_server_t *qd_server(qd_dispatch_t *qd, int thread_count, const char *containe
     qd_server->next_connection_id     = 1;
     qd_server->py_displayname_obj     = 0;
 
-    /* FIXME aconway 2017-01-20: restore HTTP support */
+    qd_server->http = qd_http_server(qd_server, qd_server->log_source);
 
     qd_log(qd_server->log_source, QD_LOG_INFO, "Container Name: %s", qd_server->container_name);
 
@@ -1052,11 +1050,10 @@ void qd_server_stop(qd_dispatch_t *qd)
 
 void qd_server_activate(qd_connection_t *ctx)
 {
-    if (!ctx || !ctx->pn_conn)
-        return;
-    pn_connection_wake(ctx->pn_conn);
+    if (ctx) ctx->wake(ctx);
 }
 
+
 void qd_connection_set_context(qd_connection_t *conn, void *context)
 {
     conn->user_context = context;
@@ -1133,28 +1130,44 @@ qd_listener_t *qd_server_listener(qd_server_t *server)
     qd_listener_t *li = new_qd_listener_t();
     if (!li) return 0;
     ZERO(li);
-
     sys_atomic_init(&li->ref_count, 1);
     li->server      = server;
     li->http = NULL;
     return li;
 }
 
-
-bool qd_listener_listen(qd_listener_t *li) {
-    if (!li->pn_listener) {      /* Not already listening */
-        li->pn_listener = pn_listener();
-        if (!li->pn_listener) {
-            qd_log(li->server->log_source, QD_LOG_ERROR, "No memory listening on %s",
-                   li->config.host_port);
-            return false;
-        }
+static bool qd_listener_listen_pn(qd_listener_t *li) {
+   li->pn_listener = pn_listener();
+    if (li->pn_listener) {
         pn_listener_set_context(li->pn_listener, li);
-        /* Listen is asynchronous, log listening on PN_LISTENER_OPEN */
-        sys_atomic_inc(&li->ref_count);
-        pn_proactor_listen(li->server->proactor, li->pn_listener, li->config.host_port, BACKLOG);
+        pn_proactor_listen(li->server->proactor, li->pn_listener, li->config.host_port,
+                           BACKLOG);
+        sys_atomic_inc(&li->ref_count); /* In use by proactor, PN_LISTENER_CLOSE will dec */
+        /* Listen is asynchronous, log "listening" message on PN_LISTENER_OPEN event */
+    } else {
+        qd_log(li->server->log_source, QD_LOG_CRITICAL, "No memory listening on %s",
+               li->config.host_port);
+     }
+    return li->pn_listener;
+}
+
+static bool qd_listener_listen_http(qd_listener_t *li) {
+    if (li->server->http) {
+        /* qd_http_listener holds a reference to li, will decref when closed */
+        qd_http_server_listen(li->server->http, li);
+        return li->http;
+    } else {
+        qd_log(li->server->log_source, QD_LOG_ERROR, "No HTTP support to listen on %s",
+               li->config.host_port);
+        return false;
     }
-    return true;
+}
+
+
+bool qd_listener_listen(qd_listener_t *li) {
+    if (li->pn_listener || li->http) /* Already listening */
+        return true;
+    return li->config.http ? qd_listener_listen_http(li) : qd_listener_listen_pn(li);
 }
 
 
@@ -1162,7 +1175,6 @@ void qd_listener_decref(qd_listener_t* li)
 {
     if (li && sys_atomic_dec(&li->ref_count) == 1) {
         qd_server_config_free(&li->config);
-        if (li->http) qd_http_listener_free(li->http);
         free_qd_listener_t(li);
     }
 }
@@ -1238,6 +1250,11 @@ qd_http_listener_t *qd_listener_http(qd_listener_t *li) {
     return li->http;
 }
 
-const char* qd_connection_hostip(const qd_connection_t *c) {
+const char* qd_connection_remote_ip(const qd_connection_t *c) {
     return c->rhost;
 }
+
+/* Expose event handling for HTTP connections */
+void qd_connection_handle(qd_connection_t *c, pn_event_t *e) {
+    handle(c->server, e);
+}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/src/server_private.h
----------------------------------------------------------------------
diff --git a/src/server_private.h b/src/server_private.h
index a6543fa..6e6f1c3 100644
--- a/src/server_private.h
+++ b/src/server_private.h
@@ -39,16 +39,19 @@
 qd_dispatch_t* qd_server_dispatch(qd_server_t *server);
 void qd_server_timeout(qd_server_t *server, qd_duration_t delay);
 
-const char* qd_connection_name(const qd_connection_t *c);
+qd_connection_t *qd_server_connection(qd_server_t *server, qd_server_config_t* config);
+void qd_connection_free(qd_connection_t* conn);
+
 qd_connector_t* qd_connection_connector(const qd_connection_t *c);
-const char* qd_connection_hostip(const qd_connection_t *c);
 
-const qd_server_config_t *qd_connector_config(const qd_connector_t *c);
+void qd_connection_handle(qd_connection_t *c, pn_event_t *e);
 
-qd_http_listener_t *qd_listener_http(qd_listener_t *l);
+
+const qd_server_config_t *qd_connector_config(const qd_connector_t *c);
 
 qd_listener_t *qd_server_listener(qd_server_t *server);
 qd_connector_t *qd_server_connector(qd_server_t *server);
+
 void qd_connector_decref(qd_connector_t* ct);
 void qd_listener_decref(qd_listener_t* ct);
 void qd_server_config_free(qd_server_config_t *cf);
@@ -136,7 +139,7 @@ struct qd_connection_t {
     pn_ssl_t                 *ssl;
     qd_listener_t            *listener;
     qd_connector_t           *connector;
-    void                     *context; // Copy of context from listener or connector
+    void                     *context; // context from listener or connector
     void                     *user_context;
     void                     *link_context; // Context shared by this connection's links
     uint64_t                  connection_id; // A unique identifier for the qd_connection_t. The underlying pn_connection already has one but it is long and clunky.
@@ -152,6 +155,7 @@ struct qd_connection_t {
     bool                      policy_counted;
     char                     *role;  //The specified role of the connection, e.g. "normal", "inter-router", "route-container" etc.
     qd_pn_free_link_session_list_t  free_link_session_list;
+    void (*wake)(qd_connection_t*); /* Wake method, different for HTTP vs. proactor */
     char rhost[NI_MAXHOST];     /* Remote host numeric IP for incoming connections */
     char rhost_port[NI_MAXHOST+NI_MAXSERV]; /* Remote host:port for incoming connections */
 };

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/tests/system_tests_http.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_http.py b/tests/system_tests_http.py
index 5627277..3d13c32 100644
--- a/tests/system_tests_http.py
+++ b/tests/system_tests_http.py
@@ -50,6 +50,14 @@ class RouterTestHttp(TestCase):
     def assert_get_cert(self, url):
         self.assertEqual("HTTP test\n", self.get_cert("%s/system_tests_http.txt" % url))
 
+    def test_listen_error(self):
+        """Make sure a router exits if an initial HTTP listener fails, doesn't hang"""
+        config = Qdrouterd.Config([
+            ('router', {'mode': 'standalone', 'id': 'bad'}),
+            ('listener', {'port': 80, 'http':True})])
+        r = Qdrouterd(name="expect_fail", config=config, wait=False);
+        self.assertEqual(1, r.wait())
+
     def test_http_get(self):
         config = Qdrouterd.Config([
             ('router', {'id': 'QDR.HTTP'}),

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/16980f67/tests/system_tests_one_router.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_one_router.py b/tests/system_tests_one_router.py
index 0a982c7..483d5e2 100644
--- a/tests/system_tests_one_router.py
+++ b/tests/system_tests_one_router.py
@@ -57,6 +57,14 @@ class RouterTest(TestCase):
         cls.router.wait_ready()
         cls.address = cls.router.addresses[0]
 
+    def test_listen_error(self):
+        """Make sure a router exits if a initial listener fails, doesn't hang"""
+        config = Qdrouterd.Config([
+            ('router', {'mode': 'standalone', 'id': 'bad'}),
+            ('listener', {'port': 80})])
+        r = Qdrouterd(name="expect_fail", config=config, wait=False);
+        self.assertEqual(1, r.wait())
+
     def test_01_pre_settled(self):
         addr = self.address+"/pre_settled/1"
         M1 = self.messenger()


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


[07/10] qpid-dispatch git commit: DISPATCH-390: centralize qd_connection setup logic

Posted by ac...@apache.org.
DISPATCH-390: centralize qd_connection setup logic


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

Branch: refs/heads/master
Commit: 6d34045e9c715b1dc949b786e097aaf6bf22c4df
Parents: 7fe0ac9
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Apr 12 21:17:14 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Apr 27 13:30:05 2017 -0400

----------------------------------------------------------------------
 src/server.c | 60 +++++++++++++++++++++++++++----------------------------
 1 file changed, 29 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6d34045e/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index d121cd4..e7fa34d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -91,30 +91,6 @@ static const int BACKLOG = 50;  /* Listening backlog */
 
 static void setup_ssl_sasl_and_open(qd_connection_t *ctx);
 
-/* Construct a new qd_connectoin. */
-static qd_connection_t *qd_connection(qd_server_t *server, const char *role) {
-    qd_connection_t *ctx = new_qd_connection_t();
-    if (!ctx) return NULL;
-    ZERO(ctx);
-    ctx->pn_conn       = pn_connection();
-    ctx->deferred_call_lock = sys_mutex();
-    ctx->role = strdup(role);
-    if (!ctx->pn_conn || !ctx->deferred_call_lock || !role) {
-        if (ctx->pn_conn) pn_connection_free(ctx->pn_conn);
-        if (ctx->deferred_call_lock) sys_mutex_free(ctx->deferred_call_lock);
-        free(ctx->role);
-        return NULL;
-    }
-    ctx->server        = server;
-    DEQ_ITEM_INIT(ctx);
-    DEQ_INIT(ctx->deferred_calls);
-    DEQ_INIT(ctx->free_link_session_list);
-    sys_mutex_lock(server->lock);
-    ctx->connection_id = server->next_connection_id++;
-    sys_mutex_unlock(server->lock);
-    return ctx;
-}
-
 /**
  * This function is set as the pn_transport->tracer and is invoked when proton tries to write the log message to pn_transport->tracer
  */
@@ -500,20 +476,45 @@ static void decorate_connection(qd_server_t *qd_server, pn_connection_t *conn, c
 }
 
 
+/* Construct a new qd_connection. */
+static qd_connection_t *qd_connection(qd_server_t *server, qd_server_config_t *config) {
+    qd_connection_t *ctx = new_qd_connection_t();
+    if (!ctx) return NULL;
+    ZERO(ctx);
+    ctx->pn_conn       = pn_connection();
+    ctx->deferred_call_lock = sys_mutex();
+    ctx->role = strdup(config->role);
+    if (!ctx->pn_conn || !ctx->deferred_call_lock || !ctx->role) {
+        if (ctx->pn_conn) pn_connection_free(ctx->pn_conn);
+        if (ctx->deferred_call_lock) sys_mutex_free(ctx->deferred_call_lock);
+        free(ctx->role);
+        return NULL;
+    }
+    ctx->server = server;
+    pn_connection_set_context(ctx->pn_conn, ctx);
+    DEQ_ITEM_INIT(ctx);
+    DEQ_INIT(ctx->deferred_calls);
+    DEQ_INIT(ctx->free_link_session_list);
+    sys_mutex_lock(server->lock);
+    ctx->connection_id = server->next_connection_id++;
+    sys_mutex_unlock(server->lock);
+    decorate_connection(ctx->server, ctx->pn_conn, config);
+    return ctx;
+}
+
+
 static void on_accept(pn_event_t *e)
 {
     assert(pn_event_type(e) == PN_LISTENER_ACCEPT);
     pn_listener_t *pn_listener = pn_event_listener(e);
     qd_listener_t *listener = pn_listener_get_context(pn_listener);
-    qd_connection_t *ctx = qd_connection(listener->server, listener->config.role);
+    qd_connection_t *ctx = qd_connection(listener->server, &listener->config);
     if (!ctx) {
         qd_log(listener->server->log_source, QD_LOG_CRITICAL,
                "Allocation failure during accept to %s", listener->config.host_port);
         return;
     }
-    pn_connection_set_context(ctx->pn_conn, ctx);
     ctx->listener = listener;
-    decorate_connection(listener->server, ctx->pn_conn, &ctx->listener->config);
     qd_log(listener->server->log_source, QD_LOG_TRACE,
            "[%"PRIu64"] Accepting incoming connection from %s to %s",
            ctx->connection_id, qd_connection_name(ctx), ctx->listener->config.host_port);
@@ -835,7 +836,7 @@ static void try_open_lh(qd_connector_t *ct)
         return;
     }
 
-    qd_connection_t *ctx = qd_connection(ct->server, ct->config.role);
+    qd_connection_t *ctx = qd_connection(ct->server, &ct->config);
     if (!ctx) {                 /* Try again later */
         qd_log(ct->server->log_source, QD_LOG_CRITICAL, "Allocation failure connecting to %s",
                ct->config.host_port);
@@ -844,7 +845,6 @@ static void try_open_lh(qd_connector_t *ct)
         return;
     }
     ctx->connector    = ct;
-    decorate_connection(ctx->server, ctx->pn_conn, &ct->config);
     const qd_server_config_t *config = &ct->config;
 
     //
@@ -860,8 +860,6 @@ static void try_open_lh(qd_connector_t *ct)
     if (config->sasl_password)
         pn_connection_set_password(ctx->pn_conn, config->sasl_password);
 
-    pn_connection_set_context(ctx->pn_conn, ctx);
-
     ctx->connector->state = CXTR_STATE_OPEN;
     ct->ctx   = ctx;
     ct->delay = 5000;


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


[02/10] qpid-dispatch git commit: DISPATCH-390: Convert dispatch to use pn_proactor_t

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6f56e289/tests/timer_test.c
----------------------------------------------------------------------
diff --git a/tests/timer_test.c b/tests/timer_test.c
index 510ac95..355d8fc 100644
--- a/tests/timer_test.c
+++ b/tests/timer_test.c
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *   http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,6 +18,7 @@
  */
 
 #include <stdio.h>
+#include <limits.h>
 #include <qpid/dispatch/timer.h>
 #include "dispatch_private.h"
 #include "alloc.h"
@@ -27,68 +28,45 @@
 
 
 static unsigned long    fire_mask;
-static qd_timer_list_t  pending_timers;
-static sys_mutex_t     *lock;
+static unsigned long    fired;
+static qd_duration_t    timeout;
 static long             time_value;
 static qd_timer_t      *timers[16];
 
 
-void qd_server_timer_pending_LH(qd_timer_t *timer)
-{
-    DEQ_INSERT_TAIL(pending_timers, timer);
+/* Dummy out the now and timeout functions */
+qd_timestamp_t qd_timer_now() {
+    return time_value;
 }
 
-
-void qd_server_timer_cancel_LH(qd_timer_t *timer)
-{
-    if (timer->state == TIMER_PENDING)
-        DEQ_REMOVE(pending_timers, timer);
+void qd_server_timeout(qd_server_t *server, qd_duration_t duration) {
+    timeout = duration;
 }
 
-
-static int fire_head()
+static void on_timer(void *context)
 {
-    sys_mutex_lock(lock);
-    int         result = DEQ_SIZE(pending_timers);
-    qd_timer_t *timer  = DEQ_HEAD(pending_timers);
-    if (timer) {
-        DEQ_REMOVE_HEAD(pending_timers);
-        qd_timer_idle_LH(timer);
-        fire_mask |= (unsigned long) timer->context;
-    }
-    sys_mutex_unlock(lock);
-    return result;
+    fire_mask |= (unsigned long) context;
+    ++fired;
 }
 
 
 static char* test_quiet(void *context)
 {
-    fire_mask = 0;
-
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-
-    while(fire_head());
-
-    if (fire_mask != 0)
+    fire_mask = fired = 0;
+    qd_timer_visit();
+    qd_timer_visit();
+    if (fired != 0 && fire_mask != 0)
         return "Expected zero timers fired";
     return 0;
 }
 
 static char* test_immediate(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
-
+    fire_mask = fired = 0;
     qd_timer_schedule(timers[0], 0);
-
-    if (fire_mask != 0)  return "Premature firing";
-    if (fire_head() > 1) return "Too many firings";
+    if (fired != 0)  return "Premature firing";
+    qd_timer_visit();
+    if (fired != 1)  return "Expected 1 firing";
     if (fire_mask != 1)  return "Incorrect fire mask";
 
     return 0;
@@ -97,22 +75,20 @@ static char* test_immediate(void *context)
 
 static char* test_immediate_reschedule(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
-
+    fire_mask = fired = 0;
     qd_timer_schedule(timers[0], 0);
     qd_timer_schedule(timers[0], 0);
+    qd_timer_visit();
 
-    if (fire_mask != 0)  return "pass 1 - Premature firing";
-    if (fire_head() > 1) return "pass 1 - Too many firings";
-    if (fire_mask != 1)  return "pass 1 - Incorrect fire mask";
+    if (fired > 1) return "pass 1 - Too many firings";
+    if (fire_mask != 1) return "pass 1 - Incorrect fire mask";
 
-    fire_mask = 0;
+    fire_mask = fired = 0;
     qd_timer_schedule(timers[0], 0);
     qd_timer_schedule(timers[0], 0);
+    qd_timer_visit();
 
-    if (fire_mask != 0)  return "pass 2 - Premature firing";
-    if (fire_head() > 1) return "pass 2 - Too many firings";
+    if (fired > 1) return "pass 2 - Too many firings";
     if (fire_mask != 1)  return "pass 2 - Incorrect fire mask";
 
     return 0;
@@ -121,23 +97,18 @@ static char* test_immediate_reschedule(void *context)
 
 static char* test_immediate_plus_delayed(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
-
+    fire_mask = fired = 0;
     qd_timer_schedule(timers[0], 0);
     qd_timer_schedule(timers[1], 5);
+    qd_timer_visit();
 
-    if (fire_mask != 0)  return "Premature firing";
-    if (fire_head() > 1) return "Too many firings";
+    if (fired > 1) return "Too many firings";
     if (fire_mask != 1)  return "Incorrect fire mask 1";
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
     time_value += 8;
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
+    qd_timer_visit();
 
-    if (fire_head() < 1) return "Delayed Failed to fire";
+    if (fired < 1) return "Delayed Failed to fire";
     if (fire_mask != 3)  return "Incorrect fire mask 3";
 
     return 0;
@@ -146,31 +117,25 @@ static char* test_immediate_plus_delayed(void *context)
 
 static char* test_single(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
+    fire_mask = fired = 0;
 
     qd_timer_schedule(timers[0], 2);
-    if (fire_head() > 0) return "Premature firing 1";
-
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    if (fire_head() > 0) return "Premature firing 2";
-
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    if (fire_head() < 1) return "Failed to fire";
-
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    if (fire_head() != 0) return "Spurious fires";
-
+    if (timeout != 2) return "Incorrect timeout";
+    qd_timer_visit();
+    if (fired > 0) return "Premature firing";
+    time_value++;
+    qd_timer_visit();
+    if (fired > 0) return "Premature firing 2";
+    time_value++;
+    qd_timer_visit();
     if (fire_mask != 1)  return "Incorrect fire mask";
-    if (timers[0]->state != TIMER_IDLE) return "Expected idle timer state";
+
+    fire_mask = fired = 0;
+    time_value++;
+    qd_timer_visit();
+    time_value++;
+    qd_timer_visit();
+    if (fired != 0) return "Spurious fires";
 
     return 0;
 }
@@ -178,26 +143,21 @@ static char* test_single(void *context)
 
 static char* test_two_inorder(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
+    fire_mask = fired = 0;
 
     qd_timer_schedule(timers[0], 2);
+    if (timeout != 2) return "bad timeout 2";
     qd_timer_schedule(timers[1], 4);
+    if (timeout != 2) return "bad timeout still 2";
+    time_value += 2;
+    qd_timer_visit();
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    int count = fire_head();
-    if (count < 1) return "First failed to fire";
-    if (count > 1) return "Second fired prematurely";
+    if (fire_mask & 2) return "Second fired prematurely";
     if (fire_mask != 1) return "Incorrect fire mask 1";
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    if (fire_head() < 1) return "Second failed to fire";
+    time_value += 2;
+    qd_timer_visit();
+
     if (fire_mask != 3)  return "Incorrect fire mask 3";
 
     return 0;
@@ -206,26 +166,21 @@ static char* test_two_inorder(void *context)
 
 static char* test_two_reverse(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
+    fire_mask = fired = 0;
 
     qd_timer_schedule(timers[0], 4);
     qd_timer_schedule(timers[1], 2);
+    time_value += 2;
+    qd_timer_visit();
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    int count = fire_head();
-    if (count < 1) return "First failed to fire";
-    if (count > 1) return "Second fired prematurely";
+    if (fired < 1) return "First failed to fire";
+    if (fired > 1) return "Second fired prematurely";
     if (fire_mask != 2) return "Incorrect fire mask 2";
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    if (fire_head() < 1) return "Second failed to fire";
+    time_value += 2;
+    qd_timer_visit();
+
+    if (fired < 1) return "Second failed to fire";
     if (fire_mask != 3)  return "Incorrect fire mask 3";
 
     return 0;
@@ -234,26 +189,19 @@ static char* test_two_reverse(void *context)
 
 static char* test_two_duplicate(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
+    fire_mask = fired = 0;
 
     qd_timer_schedule(timers[0], 2);
     qd_timer_schedule(timers[1], 2);
-
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    int count = fire_head();
-    if (count != 2) return "Expected two firings";
-    fire_head();
+    time_value += 2;
+    qd_timer_visit();
+    if (fired != 2) return "Expected two firings";
     if (fire_mask != 3) return "Incorrect fire mask 3";
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    if (fire_head() > 0) return "Spurious timer fires";
+    fire_mask = fired = 0;
+    time_value += 2;
+    qd_timer_visit();
+    if (fired > 0) return "Spurious timer fires";
 
     return 0;
 }
@@ -261,64 +209,39 @@ static char* test_two_duplicate(void *context)
 
 static char* test_separated(void *context)
 {
-    int count;
-
-    while(fire_head());
-    fire_mask = 0;
-
+    fire_mask = fired = 0;
     qd_timer_schedule(timers[0], 2);
     qd_timer_schedule(timers[1], 4);
+    time_value +=  2;
+    qd_timer_visit();
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    count = fire_head();
-    if (count < 1) return "First failed to fire";
-    if (count > 1) return "Second fired prematurely";
+    if (fired < 1) return "First failed to fire";
+    if (fired > 1) return "Second fired prematurely";
     if (fire_mask != 1) return "Incorrect fire mask 1";
 
+    fired = 0;
     qd_timer_schedule(timers[2], 2);
     qd_timer_schedule(timers[3], 4);
+    time_value +=  2;
+    qd_timer_visit();
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    count = fire_head();
-    fire_head();
-    if (count < 1) return "Second failed to fire";
-    if (count < 2) return "Third failed to fire";
+    if (fired < 1) return "Second failed to fire";
+    if (fired < 2) return "Third failed to fire";
     if (fire_mask != 7)  return "Incorrect fire mask 7";
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    count = fire_head();
-    if (count < 1) return "Fourth failed to fire";
+    fired = 0;
+    time_value +=  2;
+    qd_timer_visit();
+    if (fired < 1) return "Fourth failed to fire";
     if (fire_mask != 15) return "Incorrect fire mask 15";
 
-    sys_mutex_lock(lock);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    qd_timer_visit_LH(time_value++);
-    sys_mutex_unlock(lock);
-    count = fire_head();
-    if (count > 0) return "Spurious fire";
-
     return 0;
 }
 
 
 static char* test_big(void *context)
 {
-    while(fire_head());
-    fire_mask = 0;
-
+    fire_mask = fired = 0;
     long durations[16] =
         { 5,  8,  7,  6,
          14, 10, 16, 15,
@@ -349,10 +272,8 @@ static char* test_big(void *context)
     for (i = 0; i < 16; i++)
         qd_timer_schedule(timers[i], durations[i]);
     for (i = 0; i < 18; i++) {
-        sys_mutex_lock(lock);
-        qd_timer_visit_LH(time_value++);
-        sys_mutex_unlock(lock);
-        while(fire_head());
+        ++time_value;
+        qd_timer_visit();
         if (fire_mask != masks[i]) {
             static char error[100];
             sprintf(error, "Iteration %d: expected mask %04lx, got %04lx", i, masks[i], fire_mask);
@@ -364,32 +285,29 @@ static char* test_big(void *context)
 }
 
 
-int timer_tests(void)
+int timer_tests()
 {
-    int result = 0;
     char *test_group = "timer_tests";
-
-    fire_mask = 0;
-    DEQ_INIT(pending_timers);
-    lock = qd_timer_lock();
+    int result = 0;
+    fire_mask = fired = 0;
     time_value = 1;
 
-    timers[0]  = qd_timer(0, 0, (void*) 0x00000001);
-    timers[1]  = qd_timer(0, 0, (void*) 0x00000002);
-    timers[2]  = qd_timer(0, 0, (void*) 0x00000004);
-    timers[3]  = qd_timer(0, 0, (void*) 0x00000008);
-    timers[4]  = qd_timer(0, 0, (void*) 0x00000010);
-    timers[5]  = qd_timer(0, 0, (void*) 0x00000020);
-    timers[6]  = qd_timer(0, 0, (void*) 0x00000040);
-    timers[7]  = qd_timer(0, 0, (void*) 0x00000080);
-    timers[8]  = qd_timer(0, 0, (void*) 0x00000100);
-    timers[9]  = qd_timer(0, 0, (void*) 0x00000200);
-    timers[10] = qd_timer(0, 0, (void*) 0x00000400);
-    timers[11] = qd_timer(0, 0, (void*) 0x00000800);
-    timers[12] = qd_timer(0, 0, (void*) 0x00001000);
-    timers[13] = qd_timer(0, 0, (void*) 0x00002000);
-    timers[14] = qd_timer(0, 0, (void*) 0x00004000);
-    timers[15] = qd_timer(0, 0, (void*) 0x00008000);
+    timers[0]  = qd_timer(0, on_timer, (void*) 0x00000001);
+    timers[1]  = qd_timer(0, on_timer, (void*) 0x00000002);
+    timers[2]  = qd_timer(0, on_timer, (void*) 0x00000004);
+    timers[3]  = qd_timer(0, on_timer, (void*) 0x00000008);
+    timers[4]  = qd_timer(0, on_timer, (void*) 0x00000010);
+    timers[5]  = qd_timer(0, on_timer, (void*) 0x00000020);
+    timers[6]  = qd_timer(0, on_timer, (void*) 0x00000040);
+    timers[7]  = qd_timer(0, on_timer, (void*) 0x00000080);
+    timers[8]  = qd_timer(0, on_timer, (void*) 0x00000100);
+    timers[9]  = qd_timer(0, on_timer, (void*) 0x00000200);
+    timers[10] = qd_timer(0, on_timer, (void*) 0x00000400);
+    timers[11] = qd_timer(0, on_timer, (void*) 0x00000800);
+    timers[12] = qd_timer(0, on_timer, (void*) 0x00001000);
+    timers[13] = qd_timer(0, on_timer, (void*) 0x00002000);
+    timers[14] = qd_timer(0, on_timer, (void*) 0x00004000);
+    timers[15] = qd_timer(0, on_timer, (void*) 0x00008000);
 
     TEST_CASE(test_quiet, 0);
     TEST_CASE(test_immediate, 0);
@@ -408,4 +326,3 @@ int timer_tests(void)
 
     return result;
 }
-


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