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