Architecture specific change in rpms/qpid-dispatch.git
by githook-noreply@fedoraproject.org
The package rpms/qpid-dispatch.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/qpid-dispatch.git/commit/?id=835b....
Change:
-ExcludeArch: i686
Thanks.
Full change:
============
commit e252ed890d731b2a726e63c1afe28f2901594e50
Author: Irina Boverman <iboverma(a)redhat.com>
Date: Mon May 17 14:32:26 2021 -0400
0.16.0-1
diff --git a/.gitignore b/.gitignore
index 3214a2a..ad4a548 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,4 +26,8 @@
/qpid-dispatch-console-1.12.0.tar.gz
=======
/qpid-dispatch-1.16.0.tar.gz
+<<<<<<< HEAD
>>>>>>> 4eb6201 (0.16.0-1)
+=======
+/qpid-dispatch-console-1.16.0.tar.gz
+>>>>>>> 8b4411c (0.16.0-1)
diff --git a/sources b/sources
index 06737bb..d053677 100644
--- a/sources
+++ b/sources
@@ -1 +1,2 @@
SHA512 (qpid-dispatch-1.16.0.tar.gz) = 75f8df67d44bc0cececd481b8ccbec9d1d12ba4ed4a637bd71648c807e96b4d28ca87f33fbfa53cd1dd2e42c9a8446fd20d590a451f44f36729c888fb36fd780
+SHA512 (qpid-dispatch-console-1.16.0.tar.gz) = 750184c726c6e57a62d6597e0c41be94ee4ad05c48c7aa74b77fc581ca7aa3981d76c012f24d1460db2a6bee40fc441575e5e136e02bb983c1eb80da5559f693
commit 835b2fc5657c47e193100566013a958a088ad5a4
Author: Irina Boverman <iboverma(a)redhat.com>
Date: Mon May 17 13:56:38 2021 -0400
0.16.0-1
diff --git a/.gitignore b/.gitignore
index 2905740..3214a2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
/qpid-dispatch-0.1.tar.gz
/qpid-dispatch-0.2.tar.gz
/qpid-dispatch-0.3.tar.gz
@@ -23,3 +24,6 @@
/qpid-dispatch-console-1.11.0.tar.gz
/qpid-dispatch-1.12.0.tar.gz
/qpid-dispatch-console-1.12.0.tar.gz
+=======
+/qpid-dispatch-1.16.0.tar.gz
+>>>>>>> 4eb6201 (0.16.0-1)
diff --git a/dispatch.patch b/dispatch.patch
deleted file mode 100644
index c03cc3c..0000000
--- a/dispatch.patch
+++ /dev/null
@@ -1,2998 +0,0 @@
-From b07d0de0f6c8d115047c6ceca453ca495b4f483f Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Tue, 9 Feb 2021 17:07:47 -0500
-Subject: [PATCH 02/16] DISPATCH-1909: Requests are now recorded just before
- freeing streams. Also modified test to account for no stats being present.
- This closes #1024
-
----
- src/adaptors/http2/http2_adaptor.c | 82 ++++++++++++++----------------
- tests/system_tests_http2.py | 33 +++++++-----
- 2 files changed, 57 insertions(+), 58 deletions(-)
-
-diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
-index a08328c7..2330ece8 100644
---- a/src/adaptors/http2/http2_adaptor.c
-+++ b/src/adaptors/http2/http2_adaptor.c
-@@ -68,6 +68,7 @@ typedef struct qdr_http2_adaptor_t {
- static qdr_http2_adaptor_t *http2_adaptor;
-
- static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void *context);
-+static void _http_record_request(qdr_http2_connection_t *conn, qdr_http2_stream_data_t *stream_data);
-
- static void set_stream_data_delivery_flags(qdr_http2_stream_data_t * stream_data, qdr_delivery_t *dlv) {
- if (dlv == stream_data->in_dlv) {
-@@ -284,6 +285,10 @@ static void free_http2_stream_data(qdr_http2_stream_data_t *stream_data, bool on
-
- qdr_http2_session_data_t *session_data = stream_data->session_data;
- qdr_http2_connection_t *conn = session_data->conn;
-+
-+ // Record the request just before freeing the stream.
-+ _http_record_request(conn, stream_data);
-+
- if (!on_shutdown) {
- if (conn->qdr_conn && stream_data->in_link) {
- qdr_link_set_context(stream_data->in_link, 0);
-@@ -339,6 +344,14 @@ static char *get_address_string(pn_raw_connection_t *pn_raw_conn)
-
- void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdown)
- {
-+ // Free all the stream data associated with this connection/session.
-+ qdr_http2_stream_data_t *stream_data = DEQ_HEAD(http_conn->session_data->streams);
-+ while (stream_data) {
-+ qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] Freeing stream in free_qdr_http2_connection", stream_data->session_data->conn->conn_id, stream_data->stream_id);
-+ free_http2_stream_data(stream_data, on_shutdown);
-+ stream_data = DEQ_HEAD(http_conn->session_data->streams);
-+ }
-+
- if(http_conn->remote_address) {
- free(http_conn->remote_address);
- http_conn->remote_address = 0;
-@@ -353,15 +366,6 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
- http_conn->ping_timer = 0;
- }
-
-- // Free all the stream data associated with this connection/session.
-- qdr_http2_stream_data_t *stream_data = DEQ_HEAD(http_conn->session_data->streams);
-- while (stream_data) {
-- DEQ_REMOVE_HEAD(http_conn->session_data->streams);
-- qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] Freeing stream in free_qdr_http2_connection", stream_data->session_data->conn->conn_id, stream_data->stream_id);
-- free_http2_stream_data(stream_data, on_shutdown);
-- stream_data = DEQ_HEAD(http_conn->session_data->streams);
-- }
--
- http_conn->context.context = 0;
-
- nghttp2_session_del(http_conn->session_data->session);
-@@ -378,6 +382,10 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
- buff = DEQ_HEAD(http_conn->granted_read_buffs);
- }
-
-+ if (http_conn->delete_egress_connections) {
-+ http_conn->config = 0;
-+ }
-+
- qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"] Freeing http2 connection in free_qdr_http2_connection", http_conn->conn_id);
-
- free_qdr_http2_connection_t(http_conn);
-@@ -864,9 +872,13 @@ static void _http_record_request(qdr_http2_connection_t *conn, qdr_http2_stream_
- } else {
- remote_addr = conn->config->host;
- }
-- qd_http_record_request(http2_adaptor->core, stream_data->method, stream_data->request_status,
-- conn->config->address, remote_addr, conn->config->site,
-- stream_data->remote_site, conn->ingress, stream_data->bytes_in, stream_data->bytes_out,
-+ qd_http_record_request(http2_adaptor->core,
-+ stream_data->method,
-+ stream_data->request_status,
-+ conn->config->address,
-+ remote_addr, conn->config->site,
-+ stream_data->remote_site,
-+ conn->ingress, stream_data->bytes_in, stream_data->bytes_out,
- stream_data->stop && stream_data->start ? stream_data->stop - stream_data->start : 0);
- if (free_remote_addr) {
- free(remote_addr);
-@@ -912,10 +924,6 @@ static int on_frame_recv_callback(nghttp2_session *session,
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] NGHTTP2_DATA NGHTTP2_FLAG_END_STREAM flag received, setting receive_complete = true", conn->conn_id, stream_id);
- }
- advance_stream_status(stream_data);
--
-- if (!conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- }
-
- if (stream_data->in_dlv && !stream_data->stream_force_closed) {
-@@ -979,9 +987,6 @@ static int on_frame_recv_callback(nghttp2_session *session,
- qd_message_set_receive_complete(stream_data->message);
- advance_stream_status(stream_data);
- receive_complete = true;
-- if (!conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- }
-
- if (stream_data->entire_footer_arrived) {
-@@ -1095,9 +1100,6 @@ ssize_t read_data_callback(nghttp2_session *session,
- stream_data->next_stream_data = 0;
- }
- stream_data->out_dlv_local_disposition = PN_ACCEPTED;
-- if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] read_data_callback, payload_length=0 and next_stream_data=QD_MESSAGE_STREAM_DATA_NO_MORE", conn->conn_id, stream_data->stream_id);
- }
- else if (stream_data->next_stream_data_result == QD_MESSAGE_STREAM_DATA_FOOTER_OK) {
-@@ -1166,10 +1168,6 @@ ssize_t read_data_callback(nghttp2_session *session,
- }
-
- stream_data->bytes_out += bytes_to_send;
--
-- if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] read_data_callback returning bytes_to_send=%zu", conn->conn_id, stream_data->stream_id, bytes_to_send);
- return bytes_to_send;
- }
-@@ -1251,9 +1249,6 @@ ssize_t read_data_callback(nghttp2_session *session,
- return NGHTTP2_ERR_DEFERRED;
- }
-
-- if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_ERROR, "[C%"PRIu64"][S%"PRId32"] read_data_callback Returning zero", conn->conn_id, stream_data->stream_id);
- return 0;
- }
-@@ -2055,8 +2050,6 @@ static void restart_streams(qdr_http2_connection_t *http_conn)
- static void qdr_del_http2_connection_CT(qdr_core_t *core, qdr_action_t *action, bool discard)
- {
- qdr_http2_connection_t *conn = (qdr_http2_connection_t*) action->args.general.context_1;
-- if (conn->config)
-- qd_log(http2_adaptor->log_source, QD_LOG_DEBUG, "Removed http2 connection %s", conn->config->host_port);
- free_qdr_http2_connection(conn, false);
- }
-
-@@ -2097,7 +2090,6 @@ static void handle_disconnected(qdr_http2_connection_t* conn)
- conn->stream_dispatcher_stream_data = 0;
-
- if (conn->delete_egress_connections) {
-- conn->config = 0;
- close_connections(conn);
- }
- }
-@@ -2445,6 +2437,19 @@ static void qdr_http2_adaptor_final(void *adaptor_context)
- qdr_http2_adaptor_t *adaptor = (qdr_http2_adaptor_t*) adaptor_context;
- qdr_protocol_adaptor_free(adaptor->core, adaptor->adaptor);
-
-+ // Free all remaining connections.
-+ qdr_http2_connection_t *http_conn = DEQ_HEAD(adaptor->connections);
-+ while (http_conn) {
-+ if (http_conn->stream_dispatcher_stream_data) {
-+ qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing stream_data (stream_dispatcher, qdr_http2_adaptor_final) (%lx)", http_conn->conn_id, (long) http_conn->stream_dispatcher_stream_data);
-+ free_qdr_http2_stream_data_t(http_conn->stream_dispatcher_stream_data);
-+ http_conn->stream_dispatcher_stream_data = 0;
-+ }
-+ qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing http2 connection (calling free_qdr_http2_connection)", http_conn->conn_id);
-+ free_qdr_http2_connection(http_conn, true);
-+ http_conn = DEQ_HEAD(adaptor->connections);
-+ }
-+
- // Free all http listeners
- qd_http_listener_t *li = DEQ_HEAD(adaptor->listeners);
- while (li) {
-@@ -2459,19 +2464,6 @@ static void qdr_http2_adaptor_final(void *adaptor_context)
- ct = DEQ_HEAD(adaptor->connectors);
- }
-
-- // Free all remaining connections.
-- qdr_http2_connection_t *http_conn = DEQ_HEAD(adaptor->connections);
-- while (http_conn) {
-- if (http_conn->stream_dispatcher_stream_data) {
-- qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing stream_data (stream_dispatcher, qdr_http2_adaptor_final) (%lx)", http_conn->conn_id, (long) http_conn->stream_dispatcher_stream_data);
-- free_qdr_http2_stream_data_t(http_conn->stream_dispatcher_stream_data);
-- http_conn->stream_dispatcher_stream_data = 0;
-- }
-- qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing http2 connection (calling free_qdr_http2_connection)", http_conn->conn_id);
-- free_qdr_http2_connection(http_conn, true);
-- http_conn = DEQ_HEAD(adaptor->connections);
-- }
--
- sys_mutex_free(adaptor->lock);
- nghttp2_session_callbacks_del(adaptor->callbacks);
- http2_adaptor = NULL;
-diff --git a/tests/system_tests_http2.py b/tests/system_tests_http2.py
-index fb9d6716..59a7a23a 100644
---- a/tests/system_tests_http2.py
-+++ b/tests/system_tests_http2.py
-@@ -281,7 +281,7 @@ class Http2TestOneStandaloneRouter(Http2TestBase, CommonHttp2Tests):
- listen_port=int(os.getenv('SERVER_LISTEN_PORT')),
- py_string='python3',
- server_file="http2_server.py")
-- name = "http2-test-router"
-+ name = "http2-test-standalone-router"
- cls.connector_name = 'connectorToBeDeleted'
- cls.connector_props = {
- 'port': os.getenv('SERVER_LISTEN_PORT'),
-@@ -310,20 +310,24 @@ class Http2TestOneStandaloneRouter(Http2TestBase, CommonHttp2Tests):
- def test_000_stats(self):
- # Run curl 127.0.0.1:port --http2-prior-knowledge
- address = self.router_qdra.http_addresses[0]
-- self.run_curl(address=address)
-+ qd_manager = QdManager(self, address=self.router_qdra.addresses[0])
-+
-+ # First request
-+ out = self.run_curl(address=address)
-+
-+ # Second request
- address = self.router_qdra.http_addresses[0] + "/myinfo"
- out = self.run_curl(args=['-d', 'fname=Mickey&lname=Mouse', '-X', 'POST'], address=address)
- self.assertIn('Success! Your first name is Mickey, last name is Mouse', out)
-- qd_manager = QdManager(self, address=self.router_qdra.addresses[0])
-+
- stats = qd_manager.query('org.apache.qpid.dispatch.httpRequestInfo')
- self.assertEqual(len(stats), 2)
-
- # Give time for the core thread to augment the stats.
- i = 0
- while i < 3:
-- s = stats[0]
-- i += 1
-- if s.get('requests') < 2:
-+ if not stats or stats[0].get('requests') < 2:
-+ i += 1
- sleep(1)
- stats = qd_manager.query('org.apache.qpid.dispatch.httpRequestInfo')
- else:
-@@ -475,20 +479,23 @@ class Http2TestTwoRouter(Http2TestBase, CommonHttp2Tests):
- def test_000_stats(self):
- # Run curl 127.0.0.1:port --http2-prior-knowledge
- address = self.router_qdra.http_addresses[0]
-+ qd_manager_a = QdManager(self, address=self.router_qdra.addresses[0])
-+ stats_a = qd_manager_a.query('org.apache.qpid.dispatch.httpRequestInfo')
-+
-+ # First request
- self.run_curl(address=address)
- address = self.router_qdra.http_addresses[0] + "/myinfo"
-+
-+ # Second request
- out = self.run_curl(args=['-d', 'fname=Mickey&lname=Mouse', '-X', 'POST'], address=address)
- self.assertIn('Success! Your first name is Mickey, last name is Mouse', out)
-- qd_manager_a = QdManager(self, address=self.router_qdra.addresses[0])
-- stats_a = qd_manager_a.query('org.apache.qpid.dispatch.httpRequestInfo')
-
- # Give time for the core thread to augment the stats.
- i = 0
- while i < 3:
-- s = stats_a[0]
-- i += 1
-- if s.get('requests') < 2:
-+ if not stats_a or stats_a[0].get('requests') < 2:
- sleep(1)
-+ i += 1
- stats_a = qd_manager_a.query('org.apache.qpid.dispatch.httpRequestInfo')
- else:
- break
-@@ -505,8 +512,8 @@ class Http2TestTwoRouter(Http2TestBase, CommonHttp2Tests):
- i = 0
- while i < 3:
- s = stats_b[0]
-- i += 1
-- if s.get('requests') < 2:
-+ if not stats_b or stats_b[0].get('requests') < 2:
-+ i += 1
- sleep(1)
- stats_b = qd_manager_b.query('org.apache.qpid.dispatch.httpRequestInfo')
- else:
---
-2.20.1
-
-From cb97f9c84ddaadece8ec3495e18c6b3a0c35ec3b Mon Sep 17 00:00:00 2001
-From: Fernando Giorgetti <fgiorgetti(a)users.noreply.github.com>
-Date: Fri, 12 Feb 2021 09:17:06 -0300
-Subject: [PATCH 03/16] DISPATCH-1586 - Add allocator metrics (#696)
-
----
- src/http-libwebsockets.c | 140 +++++++++++++++++++++++++++++++++++++--
- 1 file changed, 136 insertions(+), 4 deletions(-)
-
-diff --git a/src/http-libwebsockets.c b/src/http-libwebsockets.c
-index 9a2e803e..66cf1874 100644
---- a/src/http-libwebsockets.c
-+++ b/src/http-libwebsockets.c
-@@ -460,6 +460,11 @@ typedef struct metric_definition {
- int_metric value;
- } metric_definition;
-
-+typedef struct allocator_metric_definition {
-+ const char* name;
-+ qd_alloc_stats_t *(*fn)(void);
-+} allocator_metric_definition;
-+
- static int stats_get_connections(qdr_global_stats_t *stats) { return stats->connections; }
- static int stats_get_links(qdr_global_stats_t *stats) { return stats->links; }
- static int stats_get_addrs(qdr_global_stats_t *stats) { return stats->addrs; }
-@@ -483,6 +488,43 @@ static int stats_get_deliveries_stuck(qdr_global_stats_t *stats) { return stats-
- static int stats_get_links_blocked(qdr_global_stats_t *stats) { return stats->links_blocked; }
- static int stats_get_deliveries_redirected_to_fallback(qdr_global_stats_t *stats) { return stats->deliveries_redirected_to_fallback; }
-
-+qd_alloc_stats_t *alloc_stats_qd_bitmask_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_buffer_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_composed_field_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_composite_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_connection_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_hash_handle_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_hash_item_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_iterator_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_link_ref_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_link_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_listener_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_log_entry_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_management_context_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_message_content_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_message_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_node_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_parse_node_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_parsed_field_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_timer_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_action_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_address_config_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_address_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_connection_info_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_connection_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_connection_work_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_core_timer_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_delivery_cleanup_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_delivery_ref_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_delivery_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_field_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_general_work_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_link_ref_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_link_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_link_work_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_query_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_terminus_t(void);
-+
- static struct metric_definition metrics[] = {
- {"qdr_connections_total", "gauge", stats_get_connections},
- {"qdr_links_total", "gauge", stats_get_links},
-@@ -509,9 +551,60 @@ static struct metric_definition metrics[] = {
- };
- static size_t metrics_length = sizeof(metrics)/sizeof(metrics[0]);
-
-+static struct allocator_metric_definition allocator_metrics[] = {
-+ {"qdr_allocator_qd_bitmask_t", alloc_stats_qd_bitmask_t},
-+ {"qdr_allocator_qd_buffer_t", alloc_stats_qd_buffer_t},
-+ {"qdr_allocator_qd_composed_field_t", alloc_stats_qd_composed_field_t},
-+ {"qdr_allocator_qd_composite_t", alloc_stats_qd_composite_t},
-+ {"qdr_allocator_qd_connection_t", alloc_stats_qd_connection_t},
-+ {"qdr_allocator_qd_hash_handle_t", alloc_stats_qd_hash_handle_t},
-+ {"qdr_allocator_qd_hash_item_t", alloc_stats_qd_hash_item_t},
-+ {"qdr_allocator_qd_iterator_t", alloc_stats_qd_iterator_t},
-+ {"qdr_allocator_qd_link_ref_t", alloc_stats_qd_link_ref_t},
-+ {"qdr_allocator_qd_link_t", alloc_stats_qd_link_t},
-+ {"qdr_allocator_qd_listener_t", alloc_stats_qd_listener_t},
-+ {"qdr_allocator_qd_log_entry_t", alloc_stats_qd_log_entry_t},
-+ {"qdr_allocator_qd_management_context_t", alloc_stats_qd_management_context_t},
-+ {"qdr_allocator_qd_message_content_t", alloc_stats_qd_message_content_t},
-+ {"qdr_allocator_qd_message_t", alloc_stats_qd_message_t},
-+ {"qdr_allocator_qd_node_t", alloc_stats_qd_node_t},
-+ {"qdr_allocator_qd_parse_node_t", alloc_stats_qd_parse_node_t},
-+ {"qdr_allocator_qd_parsed_field_t", alloc_stats_qd_parsed_field_t},
-+ {"qdr_allocator_qd_timer_t", alloc_stats_qd_timer_t},
-+ {"qdr_allocator_qdr_action_t", alloc_stats_qdr_action_t},
-+ {"qdr_allocator_qdr_address_config_t", alloc_stats_qdr_address_config_t},
-+ {"qdr_allocator_qdr_address_t", alloc_stats_qdr_address_t},
-+ {"qdr_allocator_qdr_connection_info_t", alloc_stats_qdr_connection_info_t},
-+ {"qdr_allocator_qdr_connection_t", alloc_stats_qdr_connection_t},
-+ {"qdr_allocator_qdr_connection_work_t", alloc_stats_qdr_connection_work_t},
-+ {"qdr_allocator_qdr_core_timer_t", alloc_stats_qdr_core_timer_t},
-+ {"qdr_allocator_qdr_delivery_cleanup_t", alloc_stats_qdr_delivery_cleanup_t},
-+ {"qdr_allocator_qdr_delivery_ref_t", alloc_stats_qdr_delivery_ref_t},
-+ {"qdr_allocator_qdr_delivery_t", alloc_stats_qdr_delivery_t},
-+ {"qdr_allocator_qdr_field_t", alloc_stats_qdr_field_t},
-+ {"qdr_allocator_qdr_general_work_t", alloc_stats_qdr_general_work_t},
-+ {"qdr_allocator_qdr_link_ref_t", alloc_stats_qdr_link_ref_t},
-+ {"qdr_allocator_qdr_link_t", alloc_stats_qdr_link_t},
-+ {"qdr_allocator_qdr_link_work_t", alloc_stats_qdr_link_work_t},
-+ {"qdr_allocator_qdr_query_t", alloc_stats_qdr_query_t},
-+ {"qdr_allocator_qdr_terminus_t", alloc_stats_qdr_terminus_t}
-+};
-+static size_t allocator_metrics_length = sizeof(allocator_metrics)/sizeof(allocator_metrics[0]);
-+
-+#define ALLOC_DATA(S, F) ((allocator_field) {#F, (S!=NULL? S->F: 0)})
-+
-+typedef struct allocator_field {
-+ const char* name;
-+ uint64_t value;
-+} allocator_field;
-+
- static bool write_stats(uint8_t **position, const uint8_t * const end, const char* name, const char* type, int value)
- {
- //11 chars + type + 2*name + 20 chars for int
-+ // average metric name size is 30 bytes
-+ // average metric type size is 8 bytes
-+ // current number of metrics is 22
-+ // total metric buffer size = 22 * (11 + 8 + 2*30 + 20) = 2178
- size_t length = 11 + strlen(type) + strlen(name)*2 + 20;
- if (end - *position >= length) {
- *position += lws_snprintf((char*) *position, end - *position, "# TYPE %s %s\n", name, type);
-@@ -522,11 +615,38 @@ static bool write_stats(uint8_t **position, const uint8_t * const end, const cha
- }
- }
-
-+static bool write_allocator_stats(uint8_t **position, const uint8_t * const end, const char* name, allocator_field field)
-+{
-+ // 30 chars (static) + 2*name + 2*field.name + 20 for int
-+ // average allocator metric name size is 54 bytes (name:field.name)
-+ // current number of metrics is 180
-+ // total allocator buffer size = 180 * (30 + 2*54 + 20) = 28440
-+ size_t length = 30 + strlen(name)*2 + strlen(field.name)*2 + 20;
-+ if (end - *position >= length) {
-+ *position += lws_snprintf((char*) *position, end - *position, "# TYPE %s:%s_bytes gauge\n", name, field.name);
-+ *position += lws_snprintf((char*) *position, end - *position, "%s:%s_bytes %"PRIu64"\n", name, field.name, field.value);
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
- static bool write_metric(uint8_t **position, const uint8_t * const end, metric_definition* definition, qdr_global_stats_t* stats)
- {
- return write_stats(position, end, definition->name, definition->type, definition->value(stats));
- }
-
-+static bool write_allocator_metric(uint8_t **position, const uint8_t * const end, allocator_metric_definition* definition)
-+{
-+ qd_alloc_stats_t *allocator_stats = definition->fn();
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, total_alloc_from_heap))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, total_free_to_heap))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, held_by_threads))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, batches_rebalanced_to_threads))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, batches_rebalanced_to_global))) return false;
-+ return true;
-+}
-+
- static int add_header_by_name(struct lws *wsi, const char* name, const char* value, uint8_t** position, uint8_t* end)
- {
- return lws_add_http_header_by_name(wsi, (unsigned char*) name, (unsigned char*) value, strlen(value), position, end);
-@@ -537,7 +657,8 @@ static int callback_metrics(struct lws *wsi, enum lws_callback_reasons reason,
- {
- qd_http_server_t *hs = wsi_server(wsi);
- stats_t *stats = (stats_t*) user;
-- uint8_t buffer[LWS_PRE + 2048];
-+ // rationale for buffer size is explained at write_stats and write_allocator_stats
-+ uint8_t buffer[LWS_PRE + 30618];
- uint8_t *start = &buffer[LWS_PRE], *position = start, *end = &buffer[sizeof(buffer) - LWS_PRE - 1];
-
- switch (reason) {
-@@ -569,15 +690,26 @@ static int callback_metrics(struct lws *wsi, enum lws_callback_reasons reason,
- stats->current++;
- qd_log(hs->log, QD_LOG_DEBUG, "wrote metric %lu of %lu", stats->current, metrics_length);
- } else {
-- qd_log(hs->log, QD_LOG_DEBUG, "insufficient space in buffer");
-+ qd_log(hs->log, QD_LOG_WARNING, "insufficient space in buffer");
- break;
- }
- }
-- int n = stats->current < metrics_length ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL;
-+
-+ int alloc_cur = 0;
-+ while (alloc_cur < allocator_metrics_length) {
-+ if (write_allocator_metric(&position, end, &allocator_metrics[alloc_cur])) {
-+ qd_log(hs->log, QD_LOG_DEBUG, "wrote allocator metric %lu of %lu", alloc_cur, allocator_metrics_length);
-+ alloc_cur++;
-+ } else {
-+ qd_log(hs->log, QD_LOG_WARNING, "insufficient space in buffer");
-+ break;
-+ }
-+ }
-+ int n = (stats->current < metrics_length) || (alloc_cur < allocator_metrics_length) ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL;
-
- //write buffer
- size_t available = position - start;
-- if (lws_write(wsi, (unsigned char*) start, available, n) != available)
-+ if (lws_write(wsi, (unsigned char*) start, available, n) != available)
- return 1;
- if (n == LWS_WRITE_HTTP_FINAL) {
- if (lws_http_transaction_completed(wsi)) return -1;
---
-2.20.1
-
-From 750f86f10fa19b8e0f939d2e188e86218355ece4 Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Tue, 2 Feb 2021 16:52:51 -0500
-Subject: [PATCH 04/16] DISPATCH-1948: fix alignment issues in alloc_pool.c
-
-This closes #1015
----
- src/alloc_pool.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
-diff --git a/src/alloc_pool.c b/src/alloc_pool.c
-index 0feb20e7..284630ec 100644
---- a/src/alloc_pool.c
-+++ b/src/alloc_pool.c
-@@ -348,7 +348,8 @@ void *qd_alloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool)
- DEQ_INSERT_TAIL(qtype->allocated, item);
- sys_mutex_unlock(desc->lock);
- item->header = PATTERN_FRONT;
-- *((uint32_t*) ((char*) &item[1] + desc->total_size))= PATTERN_BACK;
-+ const uint32_t pb = PATTERN_BACK;
-+ memcpy((char*) &item[1] + desc->total_size, &pb, sizeof(pb));
- QD_MEMORY_FILL(&item[1], QD_MEMORY_INIT, desc->total_size);
- #endif
- return &item[1];
-@@ -414,7 +415,8 @@ void *qd_alloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool)
- DEQ_INSERT_TAIL(qtype->allocated, item);
- sys_mutex_unlock(desc->lock);
- item->header = PATTERN_FRONT;
-- *((uint32_t*) ((char*) &item[1] + desc->total_size))= PATTERN_BACK;
-+ const uint32_t pb = PATTERN_BACK;
-+ memcpy((char*) &item[1] + desc->total_size, &pb, sizeof(pb));
- QD_MEMORY_FILL(&item[1], QD_MEMORY_INIT, desc->total_size);
- #endif
- return &item[1];
-@@ -434,7 +436,9 @@ void qd_dealloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool, char *p)
- assert (desc->header == PATTERN_FRONT);
- assert (desc->trailer == PATTERN_BACK);
- assert (item->header == PATTERN_FRONT);
-- assert (*((uint32_t*) (p + desc->total_size)) == PATTERN_BACK);
-+ const uint32_t pb = PATTERN_BACK;
-+ (void)pb; // prevent unused warning
-+ assert (memcmp(p + desc->total_size, &pb, sizeof(pb)) == 0);
- assert (item->desc == desc); // Check for double-free
- qd_alloc_type_t *qtype = (qd_alloc_type_t*) desc->debug;
- sys_mutex_lock(desc->lock);
---
-2.20.1
-
-From b1e309e1c59f50a67fdb6d5c2bd0ff54a64680bb Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Mon, 8 Feb 2021 13:25:35 -0500
-Subject: [PATCH 05/16] DISPATCH-1941: fix http1 parser to detect null
- characters
-
----
- src/adaptors/http1/http1_codec.c | 18 ++++++++++++++----
- src/adaptors/http1/http1_server.c | 4 ++--
- 2 files changed, 16 insertions(+), 6 deletions(-)
-
-diff --git a/src/adaptors/http1/http1_codec.c b/src/adaptors/http1/http1_codec.c
-index 7669d26f..a11f2260 100644
---- a/src/adaptors/http1/http1_codec.c
-+++ b/src/adaptors/http1/http1_codec.c
-@@ -353,6 +353,8 @@ static void ensure_outgoing_capacity(struct encoder_t *encoder, size_t capacity)
- static void write_string(struct encoder_t *encoder, const char *string)
- {
- size_t needed = strlen(string);
-+ if (needed == 0) return;
-+
- ensure_outgoing_capacity(encoder, needed);
-
- encoder->hrs->out_octets += needed;
-@@ -492,6 +494,14 @@ static bool ensure_scratch_size(scratch_memory_t *b, size_t required)
- }
-
-
-+// return true if octet in str
-+static inline bool filter_str(const char *str, uint8_t octet)
-+{
-+ const char *ptr = strchr(str, (int)((unsigned int)octet));
-+ return ptr && *ptr != 0;
-+}
-+
-+
- // trims any optional whitespace characters at the start of 'line'
- // RFC7230 defines OWS as zero or more spaces or horizontal tabs
- //
-@@ -538,7 +548,7 @@ static bool parse_token(qd_iterator_pointer_t *line, qd_iterator_pointer_t *toke
- && (('A' <= octet && octet <= 'Z') ||
- ('a' <= octet && octet <= 'z') ||
- ('0' <= octet && octet <= '9') ||
-- (strchr(TOKEN_EXTRA, octet)))) {
-+ (filter_str(TOKEN_EXTRA, octet)))) {
- len++;
- }
-
-@@ -1733,17 +1743,17 @@ const char *h1_codec_token_list_next(const char *start, size_t *len, const char
-
- if (!start) return 0;
-
-- while (*start && strchr(SKIPME, *start))
-+ while (*start && filter_str(SKIPME, *start))
- ++start;
-
- if (!*start) return 0;
-
- const char *end = start;
-- while (*end && !strchr(SKIPME, *end))
-+ while (*end && !filter_str(SKIPME, *end))
- ++end;
-
- *len = end - start;
-- while (*end && strchr(SKIPME, *end))
-+ while (*end && filter_str(SKIPME, *end))
- ++end;
-
- *next = end;
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index 61a0634d..3f46e448 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -1247,7 +1247,7 @@ static uint64_t _send_request_headers(_server_request_t *hreq, qd_message_t *msg
-
- method_str = (char*) qd_iterator_copy(method_iter);
- qd_iterator_free(method_iter);
-- if (!method_str) {
-+ if (!method_str || *method_str == 0) {
- return PN_REJECTED;
- }
-
-@@ -1267,7 +1267,7 @@ static uint64_t _send_request_headers(_server_request_t *hreq, qd_message_t *msg
-
- qd_parsed_field_t *ref = qd_parse_value_by_key(app_props, TARGET_HEADER_KEY);
- target_str = (char*) qd_iterator_copy(qd_parse_raw(ref));
-- if (!target_str) {
-+ if (!target_str || *target_str == 0) {
- outcome = PN_REJECTED;
- goto exit;
- }
---
-2.20.1
-
-From 479a73afdd55eb0590370c037e4056514a6db4d6 Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Mon, 15 Feb 2021 11:19:45 -0500
-Subject: [PATCH 06/16] DISPATCH-1955: TCP adaptor adds byte totals and other
- stats to logs
-
- 1. Add byte total to logs where incremental values are shown.
- 2. Add management stat summary when connection is closed/deleted.
-
-This closes #1026
----
- src/adaptors/tcp_adaptor.c | 12 ++++++++----
- 1 file changed, 8 insertions(+), 4 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index a38167f4..51d9316d 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -567,7 +567,7 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- int read = handle_incoming(conn);
- conn->last_in_time = tcp_adaptor->core->uptime_ticks;
- conn->bytes_in += read;
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_READ Read %i bytes", conn->conn_id, read);
-+ qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_READ Read %i bytes. Total read %"PRIu64" bytes", conn->conn_id, read, conn->bytes_in);
- while (qdr_connection_process(conn->qdr_conn)) {}
- break;
- }
-@@ -583,9 +583,9 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- }
- }
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_WRITTEN Wrote %zu bytes", conn->conn_id, written);
- conn->last_out_time = tcp_adaptor->core->uptime_ticks;
- conn->bytes_out += written;
-+ qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_WRITTEN Wrote %zu bytes. Total written %"PRIu64" bytes", conn->conn_id, written, conn->bytes_out);
- while (qdr_connection_process(conn->qdr_conn)) {}
- break;
- }
-@@ -1527,8 +1527,12 @@ static void qdr_del_tcp_connection_CT(qdr_core_t *core, qdr_action_t *action, bo
- qdr_tcp_connection_t *conn = (qdr_tcp_connection_t*) action->args.general.context_1;
- if (conn->in_list) {
- DEQ_REMOVE(tcp_adaptor->connections, conn);
-- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] qdr_del_tcp_connection_CT %s (%zu)",
-- conn->conn_id, conn->config.host_port, DEQ_SIZE(tcp_adaptor->connections));
-+ qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG,
-+ "[C%"PRIu64"] qdr_del_tcp_connection_CT %s deleted. bytes_in=%"PRIu64", bytes_out=%"PRId64", "
-+ "opened_time=%"PRId64", last_in_time=%"PRId64", last_out_time=%"PRId64". Connections remaining %zu",
-+ conn->conn_id, conn->config.host_port,
-+ conn->bytes_in, conn->bytes_out, conn->opened_time, conn->last_in_time, conn->last_out_time,
-+ DEQ_SIZE(tcp_adaptor->connections));
- }
- free_qdr_tcp_connection(conn);
- }
---
-2.20.1
-
-From 53a5bbca01678e615b1181c95c293b658a68e9e1 Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Mon, 15 Feb 2021 11:38:37 -0500
-Subject: [PATCH 07/16] DISPATCH-1964: TCP adaptor connection object should be
- a pooled type
-
----
- src/adaptors/tcp_adaptor.c | 9 ++++++---
- 1 file changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index 51d9316d..fce22192 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -22,6 +22,7 @@
- #include <proton/netaddr.h>
- #include <proton/proactor.h>
- #include <proton/raw_connection.h>
-+#include "qpid/dispatch/alloc_pool.h"
- #include "qpid/dispatch/ctools.h"
- #include "qpid/dispatch/protocol_adaptor.h"
- #include "delivery.h"
-@@ -79,6 +80,8 @@ struct qdr_tcp_connection_t {
- };
-
- DEQ_DECLARE(qdr_tcp_connection_t, qdr_tcp_connection_list_t);
-+ALLOC_DECLARE(qdr_tcp_connection_t);
-+ALLOC_DEFINE(qdr_tcp_connection_t);
-
- typedef struct qdr_tcp_adaptor_t {
- qdr_core_t *core;
-@@ -241,7 +244,7 @@ static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- }
- sys_mutex_free(tc->activation_lock);
- //proactor will free the socket
-- free(tc);
-+ free_qdr_tcp_connection_t(tc);
- }
-
- static void handle_disconnected(qdr_tcp_connection_t* conn)
-@@ -597,7 +600,7 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
-
- static qdr_tcp_connection_t *qdr_tcp_connection_ingress(qd_tcp_listener_t* listener)
- {
-- qdr_tcp_connection_t* tc = NEW(qdr_tcp_connection_t);
-+ qdr_tcp_connection_t* tc = new_qdr_tcp_connection_t();
- ZERO(tc);
- tc->activation_lock = sys_mutex();
- tc->ingress = true;
-@@ -682,7 +685,7 @@ static void qdr_tcp_open_server_side_connection(qdr_tcp_connection_t* tc)
-
- static qdr_tcp_connection_t *qdr_tcp_connection_egress(qd_bridge_config_t *config, qd_server_t *server, qdr_delivery_t *initial_delivery)
- {
-- qdr_tcp_connection_t* tc = NEW(qdr_tcp_connection_t);
-+ qdr_tcp_connection_t* tc = new_qdr_tcp_connection_t();
- ZERO(tc);
- tc->activation_lock = sys_mutex();
- if (initial_delivery) {
---
-2.20.1
-
-From 31c23ca83df6aea7feb724811af09aa6a197dd37 Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Wed, 10 Feb 2021 17:23:34 -0500
-Subject: [PATCH 08/16] DISPATCH-1960: Refactor Q2 flow control for protocol
- adaptor use.
-
-This closes #1027
----
- include/qpid/dispatch/alloc_pool.h | 25 +++++++-
- include/qpid/dispatch/container.h | 2 +-
- include/qpid/dispatch/message.h | 27 +++++---
- src/adaptors/http1/http1_client.c | 3 +-
- src/adaptors/http1/http1_server.c | 3 +-
- src/adaptors/http2/http2_adaptor.c | 12 ++--
- src/adaptors/reference_adaptor.c | 6 +-
- src/adaptors/tcp_adaptor.c | 3 +-
- src/alloc_pool.c | 4 ++
- src/message.c | 100 ++++++++++++++++++++++-------
- src/message_private.h | 10 ++-
- src/router_node.c | 24 +++----
- tests/message_test.c | 25 ++++++--
- 13 files changed, 184 insertions(+), 60 deletions(-)
-
-diff --git a/include/qpid/dispatch/alloc_pool.h b/include/qpid/dispatch/alloc_pool.h
-index e8722a52..d872ff49 100644
---- a/include/qpid/dispatch/alloc_pool.h
-+++ b/include/qpid/dispatch/alloc_pool.h
-@@ -80,7 +80,26 @@ void *qd_alloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool);
- /** De-allocate from a thread pool. Use via ALLOC_DECLARE */
- void qd_dealloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool, char *p);
- uint32_t qd_alloc_sequence(void *p);
--static inline void qd_nullify_safe_ptr(qd_alloc_safe_ptr_t *sp) { sp->ptr = 0; }
-+
-+// generic safe pointer api for any alloc pool item
-+
-+#define QD_SAFE_PTR_INIT(p) { .ptr = (void*)(p), .seq = qd_alloc_sequence(p) }
-+
-+static inline void qd_nullify_safe_ptr(qd_alloc_safe_ptr_t *sp)
-+{
-+ sp->ptr = 0;
-+}
-+
-+static inline void qd_alloc_set_safe_ptr(qd_alloc_safe_ptr_t *sp, void *p)
-+{
-+ sp->ptr = p;
-+ sp->seq = qd_alloc_sequence(p);
-+}
-+
-+static inline void *qd_alloc_deref_safe_ptr(const qd_alloc_safe_ptr_t *sp)
-+{
-+ return sp->seq == qd_alloc_sequence(sp->ptr) ? sp->ptr : (void*) 0;
-+}
-
- /**
- * Declare functions new_T and alloc_T
-@@ -102,8 +121,8 @@ static inline void qd_nullify_safe_ptr(qd_alloc_safe_ptr_t *sp) { sp->ptr = 0; }
- __thread qd_alloc_pool_t *__local_pool_##T = 0; \
- T *new_##T(void) { return (T*) qd_alloc(&__desc_##T, &__local_pool_##T); } \
- void free_##T(T *p) { qd_dealloc(&__desc_##T, &__local_pool_##T, (char*) p); } \
-- void set_safe_ptr_##T(T *p, T##_sp *sp) { sp->ptr = (void*) p; sp->seq = qd_alloc_sequence((void*) p); } \
-- T *safe_deref_##T(T##_sp sp) { return sp.seq == qd_alloc_sequence((void*) sp.ptr) ? (T*) sp.ptr : (T*) 0; } \
-+ void set_safe_ptr_##T(T *p, T##_sp *sp) { qd_alloc_set_safe_ptr(sp, (void*)p); } \
-+ T *safe_deref_##T(T##_sp sp) { return (T*) qd_alloc_deref_safe_ptr((qd_alloc_safe_ptr_t*) &(sp)); } \
- qd_alloc_stats_t *alloc_stats_##T(void) { return __desc_##T.stats; } \
- void *unused##T
-
-diff --git a/include/qpid/dispatch/container.h b/include/qpid/dispatch/container.h
-index 08caba13..82d9ad8b 100644
---- a/include/qpid/dispatch/container.h
-+++ b/include/qpid/dispatch/container.h
-@@ -228,7 +228,7 @@ void qd_link_close(qd_link_t *link);
- void qd_link_detach(qd_link_t *link);
- void qd_link_free(qd_link_t *link);
- void *qd_link_get_node_context(const qd_link_t *link);
--void qd_link_restart_rx(qd_link_t *link);
-+void qd_link_q2_restart_receive(const qd_alloc_safe_ptr_t context);
- void qd_link_q3_block(qd_link_t *link);
- void qd_link_q3_unblock(qd_link_t *link);
- uint64_t qd_link_link_id(const qd_link_t *link);
-diff --git a/include/qpid/dispatch/message.h b/include/qpid/dispatch/message.h
-index 657477d0..07e144ad 100644
---- a/include/qpid/dispatch/message.h
-+++ b/include/qpid/dispatch/message.h
-@@ -253,10 +253,9 @@ qd_message_t * qd_get_message_context(pn_delivery_t *delivery);
- * @param msg A pointer to a message to be sent.
- * @param link The outgoing link on which to send the message.
- * @param strip_outbound_annotations [in] annotation control flag
-- * @param restart_rx [out] indication to wake up receive process
- * @param q3_stalled [out] indicates that the link is stalled due to proton-buffer-full
- */
--void qd_message_send(qd_message_t *msg, qd_link_t *link, bool strip_outbound_annotations, bool *restart_rx, bool *q3_stalled);
-+void qd_message_send(qd_message_t *msg, qd_link_t *link, bool strip_outbound_annotations, bool *q3_stalled);
-
- /**
- * Check that the message is well-formed up to a certain depth. Any part of the message that is
-@@ -304,9 +303,10 @@ void qd_message_compose_4(qd_message_t *msg, qd_composed_field_t *content1, qd_c
- *
- * @param msg Pointer to a message
- * @param field A composed field to be appended to the end of the message's stream
-+ * @param q2_blocked Set to true if this call caused Q2 to block
- * @return The number of buffers stored in the message's content
- */
--int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field);
-+int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field, bool *q2_blocked);
-
-
- /**
-@@ -404,9 +404,10 @@ qd_message_stream_data_result_t qd_message_next_stream_data(qd_message_t *msg, q
- *
- * @param msg Pointer to message under construction
- * @param data List of buffers containing body data.
-+ * @param qd_blocked Set to true if this call caused Q2 to block
- * @return The number of buffers stored in the message's content
- */
--int qd_message_stream_data_append(qd_message_t *msg, qd_buffer_list_t *data);
-+int qd_message_stream_data_append(qd_message_t *msg, qd_buffer_list_t *data, bool *q2_blocked);
-
-
- /** Put string representation of a message suitable for logging in buffer.
-@@ -556,12 +557,22 @@ bool qd_message_Q2_holdoff_should_unblock(qd_message_t *msg);
- */
- bool qd_message_is_Q2_blocked(const qd_message_t *msg);
-
-+
- /**
-- * Return qd_link through which the message is being received.
-- * @param msg A pointer to the message
-- * @return the qd_link
-+ * Register a callback that will be invoked when the message has exited the Q2
-+ * blocking state. Note that the callback can be invoked on any I/O thread.
-+ * The callback must be thread safe.
-+ *
-+ * @param msg The message to monitor.
-+ * @param callback The method to invoke
-+ * @param context safe pointer holding the context
- */
--qd_link_t * qd_message_get_receiving_link(const qd_message_t *msg);
-+
-+typedef void (*qd_message_q2_unblocked_handler_t)(qd_alloc_safe_ptr_t context);
-+void qd_message_set_q2_unblocked_handler(qd_message_t *msg,
-+ qd_message_q2_unblocked_handler_t callback,
-+ qd_alloc_safe_ptr_t context);
-+void qd_message_clear_q2_unblocked_handler(qd_message_t *msg);
-
- /**
- * Return message aborted state
-diff --git a/src/adaptors/http1/http1_client.c b/src/adaptors/http1/http1_client.c
-index 1d17724d..27b25cde 100644
---- a/src/adaptors/http1/http1_client.c
-+++ b/src/adaptors/http1/http1_client.c
-@@ -860,7 +860,8 @@ static int _client_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
- "[C%"PRIu64"][L%"PRIu64"] HTTP request body received len=%zu.",
- hconn->conn_id, hconn->in_link_id, len);
-
-- qd_message_stream_data_append(msg, body);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(msg, body, 0);
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index 3f46e448..1ef6b2ab 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -976,7 +976,8 @@ static int _server_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
-
- qd_message_t *msg = rmsg->msg ? rmsg->msg : qdr_delivery_message(rmsg->dlv);
-
-- qd_message_stream_data_append(msg, body);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(msg, body, 0);
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
-index 2330ece8..25347e40 100644
---- a/src/adaptors/http2/http2_adaptor.c
-+++ b/src/adaptors/http2/http2_adaptor.c
-@@ -465,7 +465,8 @@ static int on_data_chunk_recv_callback(nghttp2_session *session,
- qd_buffer_list_t existing_buffers;
- DEQ_INIT(existing_buffers);
- qd_compose_take_buffers(stream_data->body, &existing_buffers);
-- qd_message_stream_data_append(stream_data->message, &existing_buffers);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(stream_data->message, &existing_buffers, 0);
- stream_data->body_data_added = true;
- }
- }
-@@ -475,7 +476,8 @@ static int on_data_chunk_recv_callback(nghttp2_session *session,
- stream_data->body = qd_compose(QD_PERFORMATIVE_BODY_DATA, 0);
- stream_data->body_data_added = true;
- }
-- qd_message_stream_data_append(stream_data->message, &buffers);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(stream_data->message, &buffers, 0);
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] HTTP2 DATA on_data_chunk_recv_callback qd_compose_insert_binary_buffers into stream_data->message", conn->conn_id, stream_id);
- }
- else {
-@@ -930,7 +932,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
- if (!stream_data->body) {
- stream_data->body = qd_compose(QD_PERFORMATIVE_BODY_DATA, 0);
- qd_compose_insert_binary(stream_data->body, 0, 0);
-- qd_message_extend(stream_data->message, stream_data->body);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_extend(stream_data->message, stream_data->body, 0);
- }
- }
-
-@@ -965,7 +968,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
- if (stream_data->use_footer_properties) {
- qd_compose_end_map(stream_data->footer_properties);
- stream_data->entire_footer_arrived = true;
-- qd_message_extend(stream_data->message, stream_data->footer_properties);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_extend(stream_data->message, stream_data->footer_properties, 0);
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] Closing footer map, extending message with footer", conn->conn_id, stream_id);
- }
- else {
-diff --git a/src/adaptors/reference_adaptor.c b/src/adaptors/reference_adaptor.c
-index 2fd3ff2e..9982ad04 100644
---- a/src/adaptors/reference_adaptor.c
-+++ b/src/adaptors/reference_adaptor.c
-@@ -497,7 +497,8 @@ static void on_stream(void *context)
- //
- // Extend the streaming message and free the composed field
- //
-- depth = qd_message_extend(adaptor->streaming_message, field);
-+ // TODO(kgiusti): need to handle Q2 blocking event
-+ depth = qd_message_extend(adaptor->streaming_message, field, 0);
- qd_compose_free(field);
- }
-
-@@ -519,7 +520,8 @@ static void on_stream(void *context)
- qd_compose_insert_symbol(footer, "second");
- qd_compose_insert_string(footer, "value2");
- qd_compose_end_map(footer);
-- depth = qd_message_extend(adaptor->streaming_message, footer);
-+ // @TODO(kgiusti): need to handle Q2 blocking event
-+ depth = qd_message_extend(adaptor->streaming_message, footer, 0);
- qd_compose_free(footer);
-
- qd_message_set_receive_complete(adaptor->streaming_message);
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index fce22192..6cc8855f 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -183,7 +183,8 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- grant_read_buffers(conn);
-
- if (conn->instream) {
-- qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers, 0);
- qdr_delivery_continue(tcp_adaptor->core, conn->instream, false);
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Continuing message with %i bytes", conn->conn_id, conn->incoming_id, count);
- } else {
-diff --git a/src/alloc_pool.c b/src/alloc_pool.c
-index 284630ec..2ab65675 100644
---- a/src/alloc_pool.c
-+++ b/src/alloc_pool.c
-@@ -507,6 +507,10 @@ uint32_t qd_alloc_sequence(void *p)
- return 0;
-
- qd_alloc_item_t *item = ((qd_alloc_item_t*) p) - 1;
-+#ifdef QD_MEMORY_DEBUG
-+ // ensure p actually points to an alloc pool item
-+ assert(item->header == PATTERN_FRONT);
-+#endif
- return item->sequence;
- }
-
-diff --git a/src/message.c b/src/message.c
-index 3e86f544..f81d15e9 100644
---- a/src/message.c
-+++ b/src/message.c
-@@ -1020,7 +1020,8 @@ void qd_message_free(qd_message_t *in_msg)
- {
- if (!in_msg) return;
- uint32_t rc;
-- qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
-+ qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
-+ qd_message_q2_unblocker_t q2_unblock = {0};
-
- qd_buffer_list_free_buffers(&msg->ma_to_override);
- qd_buffer_list_free_buffers(&msg->ma_trace);
-@@ -1055,12 +1056,16 @@ void qd_message_free(qd_message_t *in_msg)
- && was_blocked
- && qd_message_Q2_holdoff_should_unblock(in_msg)) {
- content->q2_input_holdoff = false;
-- qd_link_restart_rx(qd_message_get_receiving_link(in_msg));
-+ q2_unblock = content->q2_unblocker;
- }
-
- UNLOCK(content->lock);
- }
-
-+ // the Q2 handler must be invoked outside the lock
-+ if (q2_unblock.handler)
-+ q2_unblock.handler(q2_unblock.context);
-+
- rc = sys_atomic_dec(&content->ref_count) - 1;
- if (rc == 0) {
- if (content->ma_field_iter_in)
-@@ -1320,7 +1325,14 @@ void qd_message_set_receive_complete(qd_message_t *in_msg)
- {
- if (!!in_msg) {
- qd_message_content_t *content = MSG_CONTENT(in_msg);
-+
-+ LOCK(content->lock);
-+
- content->receive_complete = true;
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
-+
-+ UNLOCK(content->lock);
- }
- }
-
-@@ -1384,7 +1396,6 @@ qd_message_t *discard_receive(pn_delivery_t *delivery,
- } else if (rc == PN_EOS || rc < 0) {
- // End of message or error: finalize message_receive handling
- msg->content->aborted = pn_delivery_aborted(delivery);
-- qd_nullify_safe_ptr(&msg->content->input_link_sp);
- pn_record_t *record = pn_delivery_attachments(delivery);
- pn_record_set(record, PN_DELIVERY_CTX, 0);
- if (msg->content->oversize) {
-@@ -1392,7 +1403,7 @@ qd_message_t *discard_receive(pn_delivery_t *delivery,
- // This has no effect on the received message.
- msg->content->aborted = true;
- }
-- msg->content->receive_complete = true;
-+ qd_message_set_receive_complete((qd_message_t*) msg);
- break;
- } else {
- // rc was > 0. bytes were read and discarded.
-@@ -1429,7 +1440,8 @@ qd_message_t *qd_message_receive(pn_delivery_t *delivery)
- if (!msg) {
- msg = (qd_message_pvt_t*) qd_message();
- qd_connection_t *qdc = qd_link_connection(qdl);
-- set_safe_ptr_qd_link_t(qdl, &msg->content->input_link_sp);
-+ qd_alloc_safe_ptr_t sp = QD_SAFE_PTR_INIT(qdl);
-+ qd_message_set_q2_unblocked_handler((qd_message_t*) msg, qd_link_q2_restart_receive, sp);
- msg->strip_annotations_in = qd_connection_strip_annotations_in(qdc);
- pn_record_def(record, PN_DELIVERY_CTX, PN_WEAKREF);
- pn_record_set(record, PN_DELIVERY_CTX, (void*) msg);
-@@ -1491,8 +1503,9 @@ qd_message_t *qd_message_receive(pn_delivery_t *delivery)
- }
-
- content->receive_complete = true;
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
- content->aborted = pn_delivery_aborted(delivery);
-- qd_nullify_safe_ptr(&content->input_link_sp);
-
- // unlink message and delivery
- pn_record_set(record, PN_DELIVERY_CTX, 0);
-@@ -1726,7 +1739,6 @@ static void compose_message_annotations(qd_message_pvt_t *msg, qd_buffer_list_t
- void qd_message_send(qd_message_t *in_msg,
- qd_link_t *link,
- bool strip_annotations,
-- bool *restart_rx,
- bool *q3_stalled)
- {
- qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
-@@ -1734,7 +1746,6 @@ void qd_message_send(qd_message_t *in_msg,
- qd_buffer_t *buf = 0;
- pn_link_t *pnl = qd_link_pn(link);
-
-- *restart_rx = false;
- *q3_stalled = false;
-
- if (msg->sent_depth < QD_DEPTH_MESSAGE_ANNOTATIONS) {
-@@ -1842,8 +1853,9 @@ void qd_message_send(qd_message_t *in_msg,
-
- buf = msg->cursor.buffer;
-
-- pn_session_t *pns = pn_link_session(pnl);
-- const size_t q3_upper = BUFFER_SIZE * QD_QLIMIT_Q3_UPPER;
-+ qd_message_q2_unblocker_t q2_unblock = {0};
-+ pn_session_t *pns = pn_link_session(pnl);
-+ const size_t q3_upper = BUFFER_SIZE * QD_QLIMIT_Q3_UPPER;
-
- while (!content->aborted
- && buf
-@@ -1913,7 +1925,7 @@ void qd_message_send(qd_message_t *in_msg,
- // set input holdoff before the deferred handler
- // runs.
- content->q2_input_holdoff = false;
-- *restart_rx = true;
-+ q2_unblock = content->q2_unblocker;
- }
- }
- } // end free buffer
-@@ -1940,6 +1952,10 @@ void qd_message_send(qd_message_t *in_msg,
- UNLOCK(content->lock);
- }
-
-+ // the Q2 handler must be invoked outside the lock
-+ if (q2_unblock.handler)
-+ q2_unblock.handler(q2_unblock.context);
-+
- if (content->aborted) {
- if (pn_link_current(pnl)) {
- msg->send_complete = true;
-@@ -2319,13 +2335,16 @@ void qd_message_compose_4(qd_message_t *msg, qd_composed_field_t *field1, qd_com
- }
-
-
--int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field)
-+int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field, bool *q2_blocked)
- {
- qd_message_content_t *content = MSG_CONTENT(msg);
- int count;
- qd_buffer_list_t *buffers = qd_compose_buffers(field);
- qd_buffer_t *buf = DEQ_HEAD(*buffers);
-
-+ if (q2_blocked)
-+ *q2_blocked = false;
-+
- LOCK(content->lock);
- while (buf) {
- qd_buffer_set_fanout(buf, content->fanout);
-@@ -2334,6 +2353,14 @@ int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field)
-
- DEQ_APPEND(content->buffers, (*buffers));
- count = DEQ_SIZE(content->buffers);
-+
-+ // buffers added - much check for Q2:
-+ if (qd_message_Q2_holdoff_should_block(msg)) {
-+ content->q2_input_holdoff = true;
-+ if (q2_blocked)
-+ *q2_blocked = true;
-+ }
-+
- UNLOCK(content->lock);
- return count;
- }
-@@ -2549,7 +2576,8 @@ void qd_message_stream_data_release(qd_message_stream_data_t *stream_data)
-
- LOCK(content->lock);
-
-- bool was_blocked = !qd_message_Q2_holdoff_should_unblock((qd_message_t*) pvt);
-+ bool was_blocked = !qd_message_Q2_holdoff_should_unblock((qd_message_t*) pvt);
-+ qd_message_q2_unblocker_t q2_unblock = {0};
-
- if (pvt->is_fanout) {
- buf = start_buf;
-@@ -2581,13 +2609,16 @@ void qd_message_stream_data_release(qd_message_stream_data_t *stream_data)
- && was_blocked
- && qd_message_Q2_holdoff_should_unblock((qd_message_t*) pvt)) {
- content->q2_input_holdoff = false;
-- qd_link_restart_rx(qd_message_get_receiving_link((qd_message_t*) pvt));
-+ q2_unblock = content->q2_unblocker;
- }
-
- UNLOCK(content->lock);
-
- DEQ_REMOVE(pvt->stream_data_list, stream_data);
- free_qd_message_stream_data_t(stream_data);
-+
-+ if (q2_unblock.handler)
-+ q2_unblock.handler(q2_unblock.context);
- }
-
-
-@@ -2820,12 +2851,6 @@ bool qd_message_is_Q2_blocked(const qd_message_t *msg)
- }
-
-
--qd_link_t * qd_message_get_receiving_link(const qd_message_t *msg)
--{
-- return safe_deref_qd_link_t(((qd_message_pvt_t *)msg)->content->input_link_sp);
--}
--
--
- bool qd_message_aborted(const qd_message_t *msg)
- {
- return ((qd_message_pvt_t *)msg)->content->aborted;
-@@ -2847,12 +2872,15 @@ bool qd_message_oversize(const qd_message_t *msg)
- }
-
-
--int qd_message_stream_data_append(qd_message_t *message, qd_buffer_list_t *data)
-+int qd_message_stream_data_append(qd_message_t *message, qd_buffer_list_t *data, bool *q2_blocked)
- {
- unsigned int length = DEQ_SIZE(*data);
- qd_composed_field_t *field = 0;
- int rc = 0;
-
-+ if (q2_blocked)
-+ *q2_blocked = false;
-+
- if (length == 0)
- return rc;
-
-@@ -2887,7 +2915,35 @@ int qd_message_stream_data_append(qd_message_t *message, qd_buffer_list_t *data)
- field = qd_compose(QD_PERFORMATIVE_BODY_DATA, field);
- qd_compose_insert_binary_buffers(field, data);
-
-- rc = qd_message_extend(message, field);
-+ rc = qd_message_extend(message, field, q2_blocked);
- qd_compose_free(field);
- return rc;
- }
-+
-+
-+void qd_message_set_q2_unblocked_handler(qd_message_t *msg,
-+ qd_message_q2_unblocked_handler_t callback,
-+ qd_alloc_safe_ptr_t context)
-+{
-+ qd_message_content_t *content = MSG_CONTENT(msg);
-+
-+ LOCK(content->lock);
-+
-+ content->q2_unblocker.handler = callback;
-+ content->q2_unblocker.context = context;
-+
-+ UNLOCK(content->lock);
-+}
-+
-+
-+void qd_message_clear_Q2_unblocked_handler(qd_message_t *msg)
-+{
-+ qd_message_content_t *content = MSG_CONTENT(msg);
-+
-+ LOCK(content->lock);
-+
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
-+
-+ UNLOCK(content->lock);
-+}
-diff --git a/src/message_private.h b/src/message_private.h
-index a8067c77..c4262a98 100644
---- a/src/message_private.h
-+++ b/src/message_private.h
-@@ -73,6 +73,13 @@ struct qd_message_stream_data_t {
- ALLOC_DECLARE(qd_message_stream_data_t);
- DEQ_DECLARE(qd_message_stream_data_t, qd_message_stream_data_list_t);
-
-+
-+typedef struct {
-+ qd_message_q2_unblocked_handler_t handler;
-+ qd_alloc_safe_ptr_t context;
-+} qd_message_q2_unblocker_t;
-+
-+
- // TODO - consider using pointers to qd_field_location_t below to save memory
- // TODO - provide a way to allocate a message without a lock for the link-routing case.
- // It's likely that link-routing will cause no contention for the message content.
-@@ -126,7 +133,8 @@ typedef struct {
- uint64_t max_message_size; // configured max; 0 if no max to enforce
- uint64_t bytes_received; // bytes returned by pn_link_recv() when enforcing max_message_size
- uint32_t fanout; // The number of receivers for this message, including in-process subscribers.
-- qd_link_t_sp input_link_sp; // message received on this link
-+
-+ qd_message_q2_unblocker_t q2_unblocker; // callback and context to signal Q2 unblocked to receiver
-
- bool ma_parsed; // have parsed annotations in incoming message
- bool discard; // Should this message be discarded?
-diff --git a/src/router_node.c b/src/router_node.c
-index 7dbdb0d6..70d98f91 100644
---- a/src/router_node.c
-+++ b/src/router_node.c
-@@ -855,6 +855,7 @@ static void deferred_AMQP_rx_handler(void *context, bool discard)
- if (!discard) {
- qd_link_t *qdl = safe_deref_qd_link_t(*safe_qdl);
- if (!!qdl) {
-+ assert(qd_link_direction(qdl) == QD_INCOMING);
- qd_router_t *qdr = (qd_router_t*) qd_link_get_node_context(qdl);
- assert(qdr != 0);
- while (true) {
-@@ -1914,22 +1915,17 @@ static uint64_t CORE_link_deliver(void *context, qdr_link_t *link, qdr_delivery_
- if (!pdlv)
- return 0;
-
-- bool restart_rx = false;
- bool q3_stalled = false;
-
- qd_message_t *msg_out = qdr_delivery_message(dlv);
-
-- qd_message_send(msg_out, qlink, qdr_link_strip_annotations_out(link), &restart_rx, &q3_stalled);
-+ qd_message_send(msg_out, qlink, qdr_link_strip_annotations_out(link), &q3_stalled);
-
- if (q3_stalled) {
- qd_link_q3_block(qlink);
- qdr_link_stalled_outbound(link);
- }
-
-- if (restart_rx) {
-- qd_link_restart_rx(qd_message_get_receiving_link(msg_out));
-- }
--
- bool send_complete = qdr_delivery_send_complete(dlv);
-
- if (send_complete) {
-@@ -2059,7 +2055,10 @@ static void CORE_delivery_update(void *context, qdr_delivery_t *dlv, uint64_t di
- // and if it is blocked by Q2 holdoff, get the link rolling again.
- //
- qd_message_Q2_holdoff_disable(msg);
-- qd_link_restart_rx(link);
-+
-+ qd_link_t_sp *safe_ptr = NEW(qd_link_t_sp);
-+ set_safe_ptr_qd_link_t(link, safe_ptr);
-+ qd_connection_invoke_deferred(qd_conn, deferred_AMQP_rx_handler, safe_ptr);
- }
- }
- }
-@@ -2131,10 +2130,13 @@ qdr_core_t *qd_router_core(qd_dispatch_t *qd)
- }
-
-
--// called when Q2 holdoff is deactivated so we can receive more message buffers
-+// invoked by an I/O thread when enough buffers have been released deactivate
-+// the Q2 block. Note that this method will likely be running on a worker
-+// thread that is not the same thread that "owns" the qd_link_t passed in.
- //
--void qd_link_restart_rx(qd_link_t *in_link)
-+void qd_link_q2_restart_receive(qd_alloc_safe_ptr_t context)
- {
-+ qd_link_t *in_link = (qd_link_t*) qd_alloc_deref_safe_ptr(&context);
- if (!in_link)
- return;
-
-@@ -2142,8 +2144,8 @@ void qd_link_restart_rx(qd_link_t *in_link)
-
- qd_connection_t *in_conn = qd_link_connection(in_link);
- if (in_conn) {
-- qd_link_t_sp *safe_ptr = NEW(qd_link_t_sp);
-- set_safe_ptr_qd_link_t(in_link, safe_ptr);
-+ qd_link_t_sp *safe_ptr = NEW(qd_alloc_safe_ptr_t);
-+ *safe_ptr = context; // use original to keep old sequence counter
- qd_connection_invoke_deferred(in_conn, deferred_AMQP_rx_handler, safe_ptr);
- }
- }
-diff --git a/tests/message_test.c b/tests/message_test.c
-index 7da011c5..18a22b09 100644
---- a/tests/message_test.c
-+++ b/tests/message_test.c
-@@ -738,7 +738,7 @@ static void stream_data_generate_message(qd_message_t *msg, char *s_chunk_size,
- // the buffers in 'field' are inserted into message 'msg'.
- qd_composed_field_t *field = qd_compose(QD_PERFORMATIVE_BODY_DATA, 0);
- qd_compose_insert_binary_buffers(field, &mule_content->buffers);
-- qd_message_extend(msg, field);
-+ qd_message_extend(msg, field, 0);
-
- // Clean up temporary resources
- free(buf2);
-@@ -979,13 +979,20 @@ static char *test_check_stream_data_append(void * context)
- // snapshot the message buffer count to use as a baseline
- const size_t base_bufct = DEQ_SIZE(MSG_CONTENT(msg)->buffers);
-
-- int depth = qd_message_stream_data_append(msg, &bin_data);
-+ bool blocked;
-+ int depth = qd_message_stream_data_append(msg, &bin_data, &blocked);
- if (depth <= body_bufct) {
- // expected to add extra buffer(s) for meta-data
- result = "append length is incorrect";
- goto exit;
- }
-
-+ // expected that the append has triggered Q2 blocking:
-+ if (!blocked) {
-+ result = "expected Q2 block event did not occur!";
-+ goto exit;
-+ }
-+
- // And while we're at it, stuff in a footer
- field = qd_compose(QD_PERFORMATIVE_FOOTER, 0);
- qd_compose_start_map(field);
-@@ -994,7 +1001,7 @@ static char *test_check_stream_data_append(void * context)
- qd_compose_insert_symbol(field, "Key2");
- qd_compose_insert_string(field, "Value2");
- qd_compose_end_map(field);
-- qd_message_extend(msg, field);
-+ qd_message_extend(msg, field, 0);
- qd_compose_free(field);
-
- qd_message_set_receive_complete(msg);
-@@ -1123,7 +1130,7 @@ static char *test_check_stream_data_fanout(void *context)
- memset(buffer, '5', 1001);
- qd_compose_insert_binary(field, buffer, 5);
-
-- qd_message_extend(in_msg, field);
-+ qd_message_extend(in_msg, field, 0);
- qd_compose_free(field);
-
- qd_message_set_receive_complete(in_msg);
-@@ -1232,6 +1239,7 @@ static char *test_check_stream_data_footer(void *context)
- const size_t base_bufct = DEQ_SIZE(MSG_CONTENT(in_msg)->buffers);
-
- // Append a footer
-+ bool q2_blocked;
- field = qd_compose(QD_PERFORMATIVE_FOOTER, 0);
- qd_compose_start_map(field);
- qd_compose_insert_symbol(field, "Key1");
-@@ -1239,9 +1247,16 @@ static char *test_check_stream_data_footer(void *context)
- qd_compose_insert_symbol(field, "Key2");
- qd_compose_insert_string(field, "Value2");
- qd_compose_end_map(field);
-- qd_message_extend(in_msg, field);
-+ qd_message_extend(in_msg, field, &q2_blocked);
- qd_compose_free(field);
-
-+ // this small message should not have triggered Q2
-+ assert(DEQ_SIZE(MSG_CONTENT(in_msg)->buffers) < QD_QLIMIT_Q2_UPPER);
-+ if (q2_blocked) {
-+ result = "Unexpected Q2 block on message extend";
-+ goto exit;
-+ }
-+
- qd_message_set_receive_complete(in_msg);
-
- // "fan out" the message
---
-2.20.1
-
-From 48b0157f3de58eb2d9c69e448e2c4affb0a1c04a Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Thu, 11 Feb 2021 16:24:28 -0500
-Subject: [PATCH 09/16] DISPATCH-1961: Enable Q2 flow control for HTTP/1.x
- adaptor
-
-This closes #1029
----
- src/adaptors/http1/http1_adaptor.c | 21 +++
- src/adaptors/http1/http1_client.c | 86 ++++++++--
- src/adaptors/http1/http1_private.h | 4 +-
- src/adaptors/http1/http1_server.c | 107 +++++++++---
- src/message.c | 14 +-
- tests/system_test.py | 4 +
- tests/system_tests_http1_adaptor.py | 253 +++++++++++++++++++++++++++-
- 7 files changed, 437 insertions(+), 52 deletions(-)
-
-diff --git a/src/adaptors/http1/http1_adaptor.c b/src/adaptors/http1/http1_adaptor.c
-index 6ce1eadf..9e4eeb6f 100644
---- a/src/adaptors/http1/http1_adaptor.c
-+++ b/src/adaptors/http1/http1_adaptor.c
-@@ -119,6 +119,8 @@ void qdr_http1_connection_free(qdr_http1_connection_t *hconn)
- pn_raw_connection_close(rconn);
- }
-
-+ sys_atomic_destroy(&hconn->q2_restart);
-+
- free(hconn->cfg.host);
- free(hconn->cfg.port);
- free(hconn->cfg.address);
-@@ -415,6 +417,25 @@ void qdr_http1_free_written_buffers(qdr_http1_connection_t *hconn)
- }
-
-
-+// Per-message callback to resume receiving after Q2 is unblocked on the
-+// incoming link (to HTTP app). This routine runs on another I/O thread so it
-+// must be thread safe!
-+//
-+void qdr_http1_q2_unblocked_handler(const qd_alloc_safe_ptr_t context)
-+{
-+ // prevent the hconn from being deleted while running:
-+ sys_mutex_lock(qdr_http1_adaptor->lock);
-+
-+ qdr_http1_connection_t *hconn = (qdr_http1_connection_t*)qd_alloc_deref_safe_ptr(&context);
-+ if (hconn && hconn->raw_conn) {
-+ sys_atomic_set(&hconn->q2_restart, 1);
-+ pn_raw_connection_wake(hconn->raw_conn);
-+ }
-+
-+ sys_mutex_unlock(qdr_http1_adaptor->lock);
-+}
-+
-+
- //
- // Protocol Adaptor Callbacks
- //
-diff --git a/src/adaptors/http1/http1_client.c b/src/adaptors/http1/http1_client.c
-index 27b25cde..ff033807 100644
---- a/src/adaptors/http1/http1_client.c
-+++ b/src/adaptors/http1/http1_client.c
-@@ -133,6 +133,7 @@ static qdr_http1_connection_t *_create_client_connection(qd_http_listener_t *li)
- hconn->adaptor = qdr_http1_adaptor;
- hconn->handler_context.handler = &_handle_connection_events;
- hconn->handler_context.context = hconn;
-+ sys_atomic_init(&hconn->q2_restart, 0);
-
- hconn->client.next_msg_id = 1;
-
-@@ -364,6 +365,36 @@ static void _setup_client_connection(qdr_http1_connection_t *hconn)
- }
-
-
-+// handle PN_RAW_CONNECTION_READ
-+static int _handle_conn_read_event(qdr_http1_connection_t *hconn)
-+{
-+ int error = 0;
-+ qd_buffer_list_t blist;
-+ uintmax_t length;
-+ qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
-+ if (length) {
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_DEBUG,
-+ "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from client (%zu buffers)",
-+ hconn->conn_id, hconn->in_link_id, length, DEQ_SIZE(blist));
-+ hconn->in_http1_octets += length;
-+ error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ }
-+ return error;
-+}
-+
-+
-+// handle PN_RAW_CONNECTION_NEED_READ_BUFFERS
-+static void _handle_conn_need_read_buffers(qdr_http1_connection_t *hconn)
-+{
-+ // @TODO(kgiusti): backpressure if no credit
-+ if (hconn->client.reply_to_addr || hconn->cfg.event_channel /* && hconn->in_link_credit > 0 */) {
-+ int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-+ hconn->conn_id, granted);
-+ }
-+}
-+
-+
- // Proton Connection Event Handler
- //
- static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, void *context)
-@@ -424,31 +455,34 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- }
- case PN_RAW_CONNECTION_NEED_READ_BUFFERS: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Need read buffers", hconn->conn_id);
-- // @TODO(kgiusti): backpressure if no credit
-- if (hconn->client.reply_to_addr || hconn->cfg.event_channel /* && hconn->in_link_credit > 0 */) {
-- int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-- hconn->conn_id, granted);
-- }
-+ _handle_conn_need_read_buffers(hconn);
- break;
- }
- case PN_RAW_CONNECTION_WAKE: {
-+ int error = 0;
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Wake-up", hconn->conn_id);
-+
-+ if (sys_atomic_set(&hconn->q2_restart, 0)) {
-+ // note: unit tests grep for this log!
-+ qd_log(log, QD_LOG_TRACE, "[C%"PRIu64"] client link unblocked from Q2 limit", hconn->conn_id);
-+ hconn->q2_blocked = false;
-+ error = _handle_conn_read_event(hconn); // restart receiving
-+ _handle_conn_need_read_buffers(hconn);
-+ }
-+
- while (qdr_connection_process(hconn->qdr_conn)) {}
-+
-+ if (error)
-+ qdr_http1_close_connection(hconn, "Incoming request message failed to parse");
-+
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Processing done", hconn->conn_id);
- break;
- }
- case PN_RAW_CONNECTION_READ: {
-- qd_buffer_list_t blist;
-- uintmax_t length;
-- qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
-- if (length) {
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from client",
-- hconn->conn_id, hconn->in_link_id, length);
-- hconn->in_http1_octets += length;
-- int error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ if (!hconn->q2_blocked) {
-+ int error = _handle_conn_read_event(hconn);
- if (error)
-- qdr_http1_close_connection(hconn, "Incoming request message failed to parse");
-+ qdr_http1_close_connection(hconn, "Incoming response message failed to parse");
- }
- break;
- }
-@@ -581,7 +615,7 @@ static void _client_tx_buffers_cb(h1_codec_request_state_t *hrs, qd_buffer_list_
- }
-
- qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE,
-- "[C%"PRIu64"][L%"PRIu64"] %u request octets encoded",
-+ "[C%"PRIu64"][L%"PRIu64"] %u response octets encoded",
- hconn->conn_id, hconn->out_link_id, len);
-
-
-@@ -825,6 +859,13 @@ static int _client_rx_headers_done_cb(h1_codec_request_state_t *hrs, bool has_bo
- qd_compose_free(hreq->request_props);
- hreq->request_props = 0;
-
-+ // future-proof: ensure the message headers have not caused Q2
-+ // blocking. We only check for Q2 events while adding body data.
-+ assert(!qd_message_is_Q2_blocked(hreq->request_msg));
-+
-+ qd_alloc_safe_ptr_t hconn_sp = QD_SAFE_PTR_INIT(hconn);
-+ qd_message_set_q2_unblocked_handler(hreq->request_msg, qdr_http1_q2_unblocked_handler, hconn_sp);
-+
- // Use up one credit to obtain a delivery and forward to core. If no
- // credit is available the request is stalled until the core grants more
- // flow.
-@@ -848,6 +889,7 @@ static int _client_rx_headers_done_cb(h1_codec_request_state_t *hrs, bool has_bo
- static int _client_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *body, size_t len,
- bool more)
- {
-+ bool q2_blocked = false;
- _client_request_t *hreq = (_client_request_t*) h1_codec_request_state_get_context(hrs);
- qdr_http1_connection_t *hconn = hreq->base.hconn;
- if (hconn->cfg.event_channel && strcasecmp(h1_codec_request_state_method(hrs), POST_METHOD) != 0) {
-@@ -860,8 +902,12 @@ static int _client_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
- "[C%"PRIu64"][L%"PRIu64"] HTTP request body received len=%zu.",
- hconn->conn_id, hconn->in_link_id, len);
-
-- // @TODO(kgiusti): handle Q2 block event:
-- qd_message_stream_data_append(msg, body, 0);
-+ qd_message_stream_data_append(msg, body, &q2_blocked);
-+ hconn->q2_blocked = hconn->q2_blocked || q2_blocked;
-+ if (q2_blocked) {
-+ // note: unit tests grep for this log!
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE, "[C%"PRIu64"] client link blocked on Q2 limit", hconn->conn_id);
-+ }
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-@@ -1635,6 +1681,10 @@ static void _write_pending_response(_client_request_t *hreq)
- static void _client_request_free(_client_request_t *hreq)
- {
- if (hreq) {
-+ // deactivate the Q2 callback
-+ qd_message_t *msg = hreq->request_dlv ? qdr_delivery_message(hreq->request_dlv) : hreq->request_msg;
-+ qd_message_clear_q2_unblocked_handler(msg);
-+
- qdr_http1_request_base_cleanup(&hreq->base);
- qd_message_free(hreq->request_msg);
- if (hreq->request_dlv) {
-diff --git a/src/adaptors/http1/http1_private.h b/src/adaptors/http1/http1_private.h
-index 858efb5d..5ecf4fdf 100644
---- a/src/adaptors/http1/http1_private.h
-+++ b/src/adaptors/http1/http1_private.h
-@@ -172,6 +172,8 @@ struct qdr_http1_connection_t {
- qdr_link_t *in_link;
- uint64_t in_link_id;
- int in_link_credit; // provided by router
-+ sys_atomic_t q2_restart; // signal to resume receive
-+ bool q2_blocked; // stop reading from raw conn
-
- // Oldest at HEAD
- //
-@@ -220,7 +222,7 @@ void qdr_http1_error_response(qdr_http1_request_base_t *hreq,
- const char *reason);
- void qdr_http1_rejected_response(qdr_http1_request_base_t *hreq,
- const qdr_error_t *error);
--
-+void qdr_http1_q2_unblocked_handler(const qd_alloc_safe_ptr_t context);
-
- // http1_client.c protocol adaptor callbacks
- //
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index 1ef6b2ab..c1fb17b0 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -152,6 +152,7 @@ static qdr_http1_connection_t *_create_server_connection(qd_http_connector_t *ct
- hconn->adaptor = qdr_http1_adaptor;
- hconn->handler_context.handler = &_handle_connection_events;
- hconn->handler_context.context = hconn;
-+ sys_atomic_init(&hconn->q2_restart, 0);
- hconn->cfg.host = qd_strdup(bconfig->host);
- hconn->cfg.port = qd_strdup(bconfig->port);
- hconn->cfg.address = qd_strdup(bconfig->address);
-@@ -466,6 +467,48 @@ static void _accept_and_settle_request(_server_request_t *hreq)
- hreq->request_settled = true;
- }
-
-+
-+// handle PN_RAW_CONNECTION_READ
-+static int _handle_conn_read_event(qdr_http1_connection_t *hconn)
-+{
-+ int error = 0;
-+ qd_buffer_list_t blist;
-+ uintmax_t length;
-+
-+ qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
-+
-+ if (HTTP1_DUMP_BUFFERS) {
-+ fprintf(stdout, "\nServer raw buffer READ %"PRIuMAX" total octets\n", length);
-+ qd_buffer_t *bb = DEQ_HEAD(blist);
-+ while (bb) {
-+ fprintf(stdout, " buffer='%.*s'\n", (int)qd_buffer_size(bb), (char*)&bb[1]);
-+ bb = DEQ_NEXT(bb);
-+ }
-+ fflush(stdout);
-+ }
-+
-+ if (length) {
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE,
-+ "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from server (%zu buffers)",
-+ hconn->conn_id, hconn->in_link_id, length, DEQ_SIZE(blist));
-+ hconn->in_http1_octets += length;
-+ error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ }
-+ return error;
-+}
-+
-+
-+// handle PN_RAW_CONNECTION_NEED_READ_BUFFERS
-+static void _handle_conn_need_read_buffers(qdr_http1_connection_t *hconn)
-+{
-+ // @TODO(kgiusti): backpressure if no credit
-+ // if (hconn->in_link_credit > 0 */)
-+ int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-+ hconn->conn_id, granted);
-+}
-+
-+
- // Proton Raw Connection Events
- //
- static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, void *context)
-@@ -490,6 +533,7 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- // message (response body terminated on connection closed)
- h1_codec_connection_rx_closed(hconn->http_conn);
- pn_raw_connection_close(hconn->raw_conn);
-+ hconn->q2_blocked = false;
- break;
- }
-
-@@ -557,39 +601,32 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- break;
- }
- case PN_RAW_CONNECTION_NEED_READ_BUFFERS: {
-- // @TODO(kgiusti): backpressure if no credit
-- // if (hconn->in_link_credit > 0 */)
-- int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-- hconn->conn_id, granted);
-+ _handle_conn_need_read_buffers(hconn);
- break;
- }
- case PN_RAW_CONNECTION_WAKE: {
-+ int error = 0;
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Wake-up", hconn->conn_id);
-+
-+ if (sys_atomic_set(&hconn->q2_restart, 0)) {
-+ // note: unit tests grep for this log!
-+ qd_log(log, QD_LOG_TRACE, "[C%"PRIu64"] server link unblocked from Q2 limit", hconn->conn_id);
-+ hconn->q2_blocked = false;
-+ error = _handle_conn_read_event(hconn); // restart receiving
-+ _handle_conn_need_read_buffers(hconn);
-+ }
-+
- while (qdr_connection_process(hconn->qdr_conn)) {}
-+
-+ if (error)
-+ qdr_http1_close_connection(hconn, "Incoming response message failed to parse");
-+
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Connection processing complete", hconn->conn_id);
- break;
- }
- case PN_RAW_CONNECTION_READ: {
-- qd_buffer_list_t blist;
-- uintmax_t length;
-- qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
--
-- if (HTTP1_DUMP_BUFFERS) {
-- fprintf(stdout, "\nServer raw buffer READ %"PRIuMAX" total octets\n", length);
-- qd_buffer_t *bb = DEQ_HEAD(blist);
-- while (bb) {
-- fprintf(stdout, " buffer='%.*s'\n", (int)qd_buffer_size(bb), (char*)&bb[1]);
-- bb = DEQ_NEXT(bb);
-- }
-- fflush(stdout);
-- }
--
-- if (length) {
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from server",
-- hconn->conn_id, hconn->in_link_id, length);
-- hconn->in_http1_octets += length;
-- int error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ if (!hconn->q2_blocked) {
-+ int error = _handle_conn_read_event(hconn);
- if (error)
- qdr_http1_close_connection(hconn, "Incoming response message failed to parse");
- }
-@@ -934,6 +971,13 @@ static int _server_rx_headers_done_cb(h1_codec_request_state_t *hrs, bool has_bo
- qd_compose_free(rmsg->msg_props);
- rmsg->msg_props = 0;
-
-+ // future-proof: ensure the message headers have not caused Q2
-+ // blocking. We only check for Q2 events while adding body data.
-+ assert(!qd_message_is_Q2_blocked(rmsg->msg));
-+
-+ qd_alloc_safe_ptr_t hconn_sp = QD_SAFE_PTR_INIT(hconn);
-+ qd_message_set_q2_unblocked_handler(rmsg->msg, qdr_http1_q2_unblocked_handler, hconn_sp);
-+
- // start delivery if possible
- if (hconn->in_link_credit > 0 && rmsg == DEQ_HEAD(hreq->responses)) {
- hconn->in_link_credit -= 1;
-@@ -962,6 +1006,7 @@ static int _server_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
- {
- _server_request_t *hreq = (_server_request_t*) h1_codec_request_state_get_context(hrs);
- qdr_http1_connection_t *hconn = hreq->base.hconn;
-+ bool q2_blocked = false;
-
- qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE,
- "[C%"PRIu64"][L%"PRIu64"] HTTP response body received len=%zu.",
-@@ -976,8 +1021,13 @@ static int _server_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
-
- qd_message_t *msg = rmsg->msg ? rmsg->msg : qdr_delivery_message(rmsg->dlv);
-
-- // @TODO(kgiusti): handle Q2 block event:
-- qd_message_stream_data_append(msg, body, 0);
-+
-+ qd_message_stream_data_append(msg, body, &q2_blocked);
-+ hconn->q2_blocked = hconn->q2_blocked || q2_blocked;
-+ if (q2_blocked) {
-+ // note: unit tests grep for this log!
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE, "[C%"PRIu64"] server link blocked on Q2 limit", hconn->conn_id);
-+ }
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-@@ -1518,6 +1568,11 @@ uint64_t qdr_http1_server_core_link_deliver(qdr_http1_adaptor_t *adaptor,
- static void _server_response_msg_free(_server_request_t *hreq, _server_response_msg_t *rmsg)
- {
- DEQ_REMOVE(hreq->responses, rmsg);
-+
-+ // deactivate the Q2 callback
-+ qd_message_t *msg = rmsg->dlv ? qdr_delivery_message(rmsg->dlv) : rmsg->msg;
-+ qd_message_clear_q2_unblocked_handler(msg);
-+
- qd_message_free(rmsg->msg);
- qd_compose_free(rmsg->msg_props);
- if (rmsg->dlv) {
-diff --git a/src/message.c b/src/message.c
-index f81d15e9..16794075 100644
---- a/src/message.c
-+++ b/src/message.c
-@@ -2936,14 +2936,16 @@ void qd_message_set_q2_unblocked_handler(qd_message_t *msg,
- }
-
-
--void qd_message_clear_Q2_unblocked_handler(qd_message_t *msg)
-+void qd_message_clear_q2_unblocked_handler(qd_message_t *msg)
- {
-- qd_message_content_t *content = MSG_CONTENT(msg);
-+ if (msg) {
-+ qd_message_content_t *content = MSG_CONTENT(msg);
-
-- LOCK(content->lock);
-+ LOCK(content->lock);
-
-- content->q2_unblocker.handler = 0;
-- qd_nullify_safe_ptr(&content->q2_unblocker.context);
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
-
-- UNLOCK(content->lock);
-+ UNLOCK(content->lock);
-+ }
- }
-diff --git a/tests/system_test.py b/tests/system_test.py
-index bab62c42..5fec0914 100755
---- a/tests/system_test.py
-+++ b/tests/system_test.py
-@@ -733,6 +733,10 @@ class Qdrouterd(Process):
- def wait_router_connected(self, router_id, **retry_kwargs):
- retry(lambda: self.is_router_connected(router_id), **retry_kwargs)
-
-+ @property
-+ def logfile_path(self):
-+ return os.path.join(self.outdir, self.logfile)
-+
-
- class Tester(object):
- """Tools for use by TestCase
-diff --git a/tests/system_tests_http1_adaptor.py b/tests/system_tests_http1_adaptor.py
-index c182a3dd..9e6776ac 100644
---- a/tests/system_tests_http1_adaptor.py
-+++ b/tests/system_tests_http1_adaptor.py
-@@ -27,10 +27,13 @@ from __future__ import absolute_import
- from __future__ import print_function
-
-
-+import errno
-+import io
-+import select
- import socket
- import sys
- from threading import Thread
--from time import sleep
-+from time import sleep, time
- import uuid
- try:
- from http.server import HTTPServer, BaseHTTPRequestHandler
-@@ -1705,5 +1708,253 @@ class Http1AdaptorBadEndpointsTest(TestCase):
- self.assertEqual(1, count)
-
-
-+
-+class Http1AdaptorQ2Standalone(TestCase):
-+ """
-+ Force Q2 blocking/recovery on both client and server endpoints. This test
-+ uses a single router to ensure both client facing and server facing
-+ Q2 components of the HTTP/1.x adaptor are triggered.
-+ """
-+ @classmethod
-+ def setUpClass(cls):
-+ """
-+ Single router configuration with one HTTPListener and one
-+ HTTPConnector.
-+ """
-+ super(Http1AdaptorQ2Standalone, cls).setUpClass()
-+
-+ cls.http_server_port = cls.tester.get_port()
-+ cls.http_listener_port = cls.tester.get_port()
-+
-+ config = [
-+ ('router', {'mode': 'standalone',
-+ 'id': 'RowdyRoddyRouter',
-+ 'allowUnsettledMulticast': 'yes'}),
-+ ('listener', {'role': 'normal',
-+ 'port': cls.tester.get_port()}),
-+ ('httpListener', {'port': cls.http_listener_port,
-+ 'protocolVersion': 'HTTP1',
-+ 'address': 'testServer'}),
-+ ('httpConnector', {'port': cls.http_server_port,
-+ 'protocolVersion': 'HTTP1',
-+ 'address': 'testServer'}),
-+ ('address', {'prefix': 'closest', 'distribution': 'closest'}),
-+ ('address', {'prefix': 'multicast', 'distribution': 'multicast'}),
-+ ]
-+ config = Qdrouterd.Config(config)
-+ cls.INT_A = cls.tester.qdrouterd("TestBadEndpoints", config, wait=True)
-+ cls.INT_A.listener = cls.INT_A.addresses[0]
-+
-+
-+ def _write_until_full(self, sock, data, timeout):
-+ """
-+ Write data to socket until either all data written or timeout.
-+ Return the number of bytes written, which will == len(data) if timeout
-+ not hit
-+ """
-+ sock.setblocking(0)
-+ sent = 0
-+
-+ while sent < len(data):
-+ try:
-+ _, rw, _ = select.select([], [sock], [], timeout)
-+ except select.error as serror:
-+ if serror[0] == errno.EINTR:
-+ print("ignoring interrupt from select(): %s" % str(serror))
-+ continue
-+ raise # assuming fatal...
-+ if rw:
-+ sent += sock.send(data[sent:])
-+ else:
-+ break # timeout
-+ return sent
-+
-+ def _read_until_empty(self, sock, timeout):
-+ """
-+ Read data from socket until timeout occurs. Return read data.
-+ """
-+ sock.setblocking(0)
-+ data = b''
-+
-+ while True:
-+ try:
-+ rd, _, _ = select.select([sock], [], [], timeout)
-+ except select.error as serror:
-+ if serror[0] == errno.EINTR:
-+ print("ignoring interrupt from select(): %s" % str(serror))
-+ continue
-+ raise # assuming fatal...
-+ if rd:
-+ data += sock.recv(4096)
-+ else:
-+ break # timeout
-+ return data
-+
-+ def test_01_backpressure_client(self):
-+ """
-+ Trigger Q2 backpressure against the HTTP client.
-+ """
-+
-+ # create a listener socket to act as the server service
-+ server_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ server_listener.settimeout(TIMEOUT)
-+ server_listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-+ server_listener.bind(('', self.http_server_port))
-+ server_listener.listen(1)
-+
-+ # block until router connects
-+ server_sock, host_port = server_listener.accept()
-+ server_sock.settimeout(0.5)
-+ server_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+
-+ # create a client connection to the router
-+ client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ client_sock.settimeout(0.5)
-+ client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+ client_sock.connect((host_port[0], self.http_listener_port))
-+
-+ # send a Very Large PUSH request, expecting it to block at some point
-+
-+ push_req_hdr = b'PUSH / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n'
-+ count = self._write_until_full(client_sock, push_req_hdr, 1.0)
-+ self.assertEqual(len(push_req_hdr), count)
-+
-+ chunk = b'8000\r\n' + b'X' * 0x8000 + b'\r\n'
-+ last_chunk = b'0 \r\n\r\n'
-+ count = 0
-+ deadline = time() + TIMEOUT
-+ while deadline >= time():
-+ count = self._write_until_full(client_sock, chunk, 5.0)
-+ if count < len(chunk):
-+ break
-+ self.assertFalse(time() > deadline,
-+ "Client never blocked as expected!")
-+
-+ # client should now be in Q2 block. Drain the server to unblock Q2
-+ _ = self._read_until_empty(server_sock, 2.0)
-+
-+ # finish the PUSH
-+ if count:
-+ remainder = self._write_until_full(client_sock, chunk[count:], 1.0)
-+ self.assertEqual(len(chunk), count + remainder)
-+
-+ count = self._write_until_full(client_sock, last_chunk, 1.0)
-+ self.assertEqual(len(last_chunk), count)
-+
-+ # receive the request and reply
-+ _ = self._read_until_empty(server_sock, 2.0)
-+
-+ response = b'HTTP/1.1 201 Created\r\nContent-Length: 0\r\n\r\n'
-+ count = self._write_until_full(server_sock, response, 1.0)
-+ self.assertEqual(len(response), count)
-+
-+ # complete the response read
-+ _ = self._read_until_empty(client_sock, 2.0)
-+ self.assertEqual(len(response), len(_))
-+
-+ client_sock.shutdown(socket.SHUT_RDWR)
-+ client_sock.close()
-+
-+ server_sock.shutdown(socket.SHUT_RDWR)
-+ server_sock.close()
-+
-+ server_listener.shutdown(socket.SHUT_RDWR)
-+ server_listener.close()
-+
-+ # search the router log file to verify Q2 was hit
-+
-+ block_ct = 0
-+ unblock_ct = 0
-+ with io.open(self.INT_A.logfile_path) as f:
-+ for line in f:
-+ if 'client link blocked on Q2 limit' in line:
-+ block_ct += 1
-+ if 'client link unblocked from Q2 limit' in line:
-+ unblock_ct += 1
-+ self.assertTrue(block_ct > 0)
-+ self.assertEqual(block_ct, unblock_ct)
-+
-+ def test_02_backpressure_server(self):
-+ """
-+ Trigger Q2 backpressure against the HTTP server.
-+ """
-+ small_get_req = b'GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n'
-+
-+ # create a listener socket to act as the server service
-+ server_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ server_listener.settimeout(TIMEOUT)
-+ server_listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-+ server_listener.bind(('', self.http_server_port))
-+ server_listener.listen(1)
-+
-+ # block until router connects
-+ server_sock, host_port = server_listener.accept()
-+ server_sock.settimeout(0.5)
-+ server_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+
-+ # create a client connection to the router
-+ client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ client_sock.settimeout(0.5)
-+ client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+ client_sock.connect((host_port[0], self.http_listener_port))
-+
-+ # send GET request - expect this to be successful
-+ count = self._write_until_full(client_sock, small_get_req, 1.0)
-+ self.assertEqual(len(small_get_req), count)
-+
-+ request = self._read_until_empty(server_sock, 5.0)
-+ self.assertEqual(len(small_get_req), len(request))
-+
-+ # send a Very Long response, expecting it to block at some point
-+ chunk = b'8000\r\n' + b'X' * 0x8000 + b'\r\n'
-+ last_chunk = b'0 \r\n\r\n'
-+ response = b'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n'
-+
-+ count = self._write_until_full(server_sock, response, 1.0)
-+ self.assertEqual(len(response), count)
-+
-+ count = 0
-+ deadline = time() + TIMEOUT
-+ while deadline >= time():
-+ count = self._write_until_full(server_sock, chunk, 5.0)
-+ if count < len(chunk):
-+ break
-+ self.assertFalse(time() > deadline,
-+ "Server never blocked as expected!")
-+
-+ # server should now be in Q2 block. Drain the client to unblock Q2
-+ _ = self._read_until_empty(client_sock, 2.0)
-+
-+ # finish the response
-+ if count:
-+ remainder = self._write_until_full(server_sock, chunk[count:], 1.0)
-+ self.assertEqual(len(chunk), count + remainder)
-+
-+ count = self._write_until_full(server_sock, last_chunk, 1.0)
-+ self.assertEqual(len(last_chunk), count)
-+ server_sock.shutdown(socket.SHUT_RDWR)
-+ server_sock.close()
-+
-+ _ = self._read_until_empty(client_sock, 1.0)
-+ client_sock.shutdown(socket.SHUT_RDWR)
-+ client_sock.close()
-+
-+ server_listener.shutdown(socket.SHUT_RDWR)
-+ server_listener.close()
-+
-+ # search the router log file to verify Q2 was hit
-+
-+ block_ct = 0
-+ unblock_ct = 0
-+ with io.open(self.INT_A.logfile_path) as f:
-+ for line in f:
-+ if 'server link blocked on Q2 limit' in line:
-+ block_ct += 1
-+ if 'server link unblocked from Q2 limit' in line:
-+ unblock_ct += 1
-+ self.assertTrue(block_ct > 0)
-+ self.assertEqual(block_ct, unblock_ct)
-+
-+
- if __name__ == '__main__':
- unittest.main(main_module())
---
-2.20.1
-
-From 4816af35e8ffcfa3621301c97cc602558aa0d5d7 Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Tue, 16 Feb 2021 20:25:21 -0500
-Subject: [PATCH 10/16] DISPATCH-1961: flush any Q2 blocked buffers on conn
- close
-
-This closes #1039
----
- src/adaptors/http1/http1_server.c | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index c1fb17b0..76c35cb7 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -529,11 +529,15 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- break;
- }
- case PN_RAW_CONNECTION_CLOSED_READ: {
-+ if (hconn->q2_blocked) {
-+ hconn->q2_blocked = false;
-+ // drain any pending buffers blocked by Q2
-+ _handle_conn_read_event(hconn);
-+ }
- // notify the codec so it can complete the current response
- // message (response body terminated on connection closed)
- h1_codec_connection_rx_closed(hconn->http_conn);
- pn_raw_connection_close(hconn->raw_conn);
-- hconn->q2_blocked = false;
- break;
- }
-
-@@ -601,7 +605,8 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- break;
- }
- case PN_RAW_CONNECTION_NEED_READ_BUFFERS: {
-- _handle_conn_need_read_buffers(hconn);
-+ if (!hconn->q2_blocked)
-+ _handle_conn_need_read_buffers(hconn);
- break;
- }
- case PN_RAW_CONNECTION_WAKE: {
-@@ -1136,7 +1141,7 @@ void qdr_http1_server_core_link_flow(qdr_http1_adaptor_t *adaptor,
-
- if (hconn->in_link_credit > 0) {
-
-- if (hconn->raw_conn)
-+ if (hconn->raw_conn && !hconn->q2_blocked)
- qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-
- // check for pending responses that are blocked for credit
---
-2.20.1
-
-From 67cf9a8d259052f2aed1c3b8a0fea5d1fde5248c Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Thu, 18 Feb 2021 14:27:27 -0500
-Subject: [PATCH 11/16] DISPATCH-1952: Add back qd_bitmask_t to leak supression
- list
-
----
- src/alloc_pool.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/alloc_pool.c b/src/alloc_pool.c
-index 2ab65675..79c14a27 100644
---- a/src/alloc_pool.c
-+++ b/src/alloc_pool.c
-@@ -102,6 +102,7 @@ static const char *leaking_types[] = {
- "qdr_field_t",
- "qdr_link_work_t",
- "qd_buffer_t",
-+ "qd_bitmask_t",
-
- "qd_parsed_field_t", // DISPATCH-1701
- "qdr_delivery_ref_t", // DISPATCH-1702
---
-2.20.1
-
-From c32f02c27d0471adf20630f830d819348cdc9611 Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Thu, 18 Feb 2021 14:07:52 -0500
-Subject: [PATCH 12/16] DISPATCH-1970: Zero out the conn->config pointer since
- it has already been freed. This closes #1046.
-
----
- src/adaptors/http2/http2_adaptor.c | 12 +++++-------
- 1 file changed, 5 insertions(+), 7 deletions(-)
-
-diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
-index 25347e40..7ffdb0d9 100644
---- a/src/adaptors/http2/http2_adaptor.c
-+++ b/src/adaptors/http2/http2_adaptor.c
-@@ -382,10 +382,6 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
- buff = DEQ_HEAD(http_conn->granted_read_buffs);
- }
-
-- if (http_conn->delete_egress_connections) {
-- http_conn->config = 0;
-- }
--
- qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"] Freeing http2 connection in free_qdr_http2_connection", http_conn->conn_id);
-
- free_qdr_http2_connection_t(http_conn);
-@@ -872,13 +868,13 @@ static void _http_record_request(qdr_http2_connection_t *conn, qdr_http2_stream_
- remote_addr = conn->remote_address;
- }
- } else {
-- remote_addr = conn->config->host;
-+ remote_addr = conn->config?conn->config->host:0;
- }
- qd_http_record_request(http2_adaptor->core,
- stream_data->method,
- stream_data->request_status,
-- conn->config->address,
-- remote_addr, conn->config->site,
-+ conn->config?conn->config->address:0,
-+ remote_addr, conn->config?conn->config->site:0,
- stream_data->remote_site,
- conn->ingress, stream_data->bytes_in, stream_data->bytes_out,
- stream_data->stop && stream_data->start ? stream_data->stop - stream_data->start : 0);
-@@ -2094,6 +2090,8 @@ static void handle_disconnected(qdr_http2_connection_t* conn)
- conn->stream_dispatcher_stream_data = 0;
-
- if (conn->delete_egress_connections) {
-+ // The config has already been freed by the qd_http_connector_decref() function, set it to zero here
-+ conn->config = 0;
- close_connections(conn);
- }
- }
---
-2.20.1
-
-From e4f2a9090d3fee36efeff903dc9a628ea77135ff Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Mon, 22 Feb 2021 11:24:15 -0500
-Subject: [PATCH 13/16] DISPATCH-1968: Avoid proton calls on a closed raw
- connections
-
- * Do not write new buffers if connection is CLOSED_WRITE
- * Do not call connection_wake if CLOSED_READ or CLOSED_WRITE
-
-This closes #1047
----
- src/adaptors/tcp_adaptor.c | 45 ++++++++++++++++++++++++++++++++++----
- 1 file changed, 41 insertions(+), 4 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index 6cc8855f..69bed1ab 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -56,6 +56,8 @@ struct qdr_tcp_connection_t {
- bool egress_dispatcher;
- bool connector_closed;//only used if egress_dispatcher=true
- bool in_list; // This connection is in the adaptor's connections list
-+ bool raw_closed_read;
-+ bool raw_closed_write;
- qdr_delivery_t *initial_delivery;
- qd_timer_t *activate_timer;
- qd_bridge_config_t config;
-@@ -122,6 +124,9 @@ static void on_activate(void *context)
-
- static void grant_read_buffers(qdr_tcp_connection_t *conn)
- {
-+ if (conn->raw_closed_read)
-+ return;
-+
- pn_raw_buffer_t raw_buffers[READ_BUFFERS];
- // Give proactor more read buffers for the socket
- if (!pn_raw_connection_is_read_closed(conn->pn_raw_conn)) {
-@@ -231,6 +236,31 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- return count;
- }
-
-+
-+static void flush_outgoing_buffs(qdr_tcp_connection_t *conn)
-+{
-+ // Flush buffers staged for writing to raw conn
-+ // and free possible references to stream data objects.
-+ if (conn->outgoing_buff_count > 0) {
-+ for (size_t i = conn->outgoing_buff_idx;
-+ i < conn->outgoing_buff_idx + conn->outgoing_buff_count;
-+ ++i) {
-+ if (conn->outgoing_buffs[i].context) {
-+ qd_message_stream_data_release(
-+ (qd_message_stream_data_t*)conn->outgoing_buffs[i].context);
-+ }
-+ }
-+ }
-+ conn->outgoing_buff_count = 0;
-+
-+ // Flush in-progress stream data object
-+ if (conn->outgoing_stream_data) {
-+ free_qd_message_stream_data_t(conn->outgoing_stream_data);
-+ conn->outgoing_stream_data = 0;
-+ }
-+}
-+
-+
- static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- {
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Freeing tcp_connection %p", tc->conn_id, (void*) tc);
-@@ -240,9 +270,7 @@ static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- if (tc->activate_timer) {
- qd_timer_free(tc->activate_timer);
- }
-- if (tc->outgoing_stream_data) {
-- free_qd_message_stream_data_t(tc->outgoing_stream_data);
-- }
-+ flush_outgoing_buffs(tc);
- sys_mutex_free(tc->activation_lock);
- //proactor will free the socket
- free_qdr_tcp_connection_t(tc);
-@@ -348,6 +376,7 @@ static int read_message_body(qdr_tcp_connection_t *conn, qd_message_t *msg, pn_r
- return used;
- }
-
-+
- static bool write_outgoing_buffs(qdr_tcp_connection_t *conn)
- {
- // Send the outgoing buffs to pn_raw_conn.
-@@ -383,6 +412,12 @@ static bool write_outgoing_buffs(qdr_tcp_connection_t *conn)
- static void handle_outgoing(qdr_tcp_connection_t *conn)
- {
- if (conn->outstream) {
-+ if (conn->raw_closed_write) {
-+ // flush outgoing buffers and free attached stream_data objects
-+ flush_outgoing_buffs(conn);
-+ // give no more buffers to raw connection
-+ return;
-+ }
- qd_message_t *msg = qdr_delivery_message(conn->outstream);
- bool read_more_body = true;
-
-@@ -534,11 +569,13 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- case PN_RAW_CONNECTION_CLOSED_READ: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_CLOSED_READ", conn->conn_id);
-+ conn->raw_closed_read = true;
- pn_raw_connection_close(conn->pn_raw_conn);
- break;
- }
- case PN_RAW_CONNECTION_CLOSED_WRITE: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_CLOSED_WRITE", conn->conn_id);
-+ conn->raw_closed_write = true;
- pn_raw_connection_close(conn->pn_raw_conn);
- break;
- }
-@@ -1186,7 +1223,7 @@ static void qdr_tcp_activate(void *notused, qdr_connection_t *c)
- if (context) {
- qdr_tcp_connection_t* conn = (qdr_tcp_connection_t*) context;
- sys_mutex_lock(conn->activation_lock);
-- if (conn->pn_raw_conn) {
-+ if (conn->pn_raw_conn && !(conn->raw_closed_read || conn->raw_closed_write)) {
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] qdr_tcp_activate: waking raw connection", conn->conn_id);
- pn_raw_connection_wake(conn->pn_raw_conn);
- sys_mutex_unlock(conn->activation_lock);
---
-2.20.1
-
-From 29911e6bb37d542ec662ae4af947e98c93619591 Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Tue, 23 Feb 2021 16:48:05 -0500
-Subject: [PATCH 14/16] DISPATCH-1947: TCP Adaptor flow control
-
-This closes #1056
----
- src/adaptors/tcp_adaptor.c | 88 +++++++++++++++++++++++++++++++++-----
- 1 file changed, 78 insertions(+), 10 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index 69bed1ab..0b831231 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -17,6 +17,7 @@
- * under the License.
- */
-
-+#include "tcp_adaptor.h"
- #include <proton/condition.h>
- #include <proton/listener.h>
- #include <proton/netaddr.h>
-@@ -26,7 +27,6 @@
- #include "qpid/dispatch/ctools.h"
- #include "qpid/dispatch/protocol_adaptor.h"
- #include "delivery.h"
--#include "tcp_adaptor.h"
- #include <stdio.h>
- #include <inttypes.h>
-
-@@ -78,6 +78,9 @@ struct qdr_tcp_connection_t {
- int outgoing_buff_count; // number of buffers with data
- int outgoing_buff_idx; // first buffer with data
-
-+ sys_atomic_t q2_restart; // signal to resume receive
-+ bool q2_blocked; // stop reading from raw conn
-+
- DEQ_LINKS(qdr_tcp_connection_t);
- };
-
-@@ -148,7 +151,37 @@ static void grant_read_buffers(qdr_tcp_connection_t *conn)
- }
- }
-
--static int handle_incoming(qdr_tcp_connection_t *conn)
-+
-+// Per-message callback to resume receiving after Q2 is unblocked on the
-+// incoming link.
-+// This routine must be thread safe: the thread on which it is running
-+// is not an IO thread that owns the underlying pn_raw_conn.
-+//
-+void qdr_tcp_q2_unblocked_handler(const qd_alloc_safe_ptr_t context)
-+{
-+ qdr_tcp_connection_t *tc = (qdr_tcp_connection_t*)qd_alloc_deref_safe_ptr(&context);
-+ if (tc == 0) {
-+ // bad news.
-+ assert(false);
-+ return;
-+ }
-+
-+ // prevent the tc from being deleted while running:
-+ sys_mutex_lock(tc->activation_lock);
-+
-+ if (tc && tc->pn_raw_conn) {
-+ sys_atomic_set(&tc->q2_restart, 1);
-+ pn_raw_connection_wake(tc->pn_raw_conn);
-+ }
-+
-+ sys_mutex_unlock(tc->activation_lock);
-+}
-+
-+
-+// Fetch incoming raw incoming buffers from proton and pass them to
-+// existing delivery or create a new delivery.
-+// If close is pending then do not give more buffers to proton.
-+static int handle_incoming_impl(qdr_tcp_connection_t *conn, bool close_pending)
- {
- //
- // Don't initiate an ingress stream message if we don't yet have a reply-to address and credit.
-@@ -163,6 +196,16 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- return 0;
- }
-
-+ //
-+ // Don't read from proton if in Q2 holdoff
-+ //
-+ if (conn->q2_blocked) {
-+ qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] handle_incoming q2_blocked", conn->conn_id);
-+ return 0;
-+ }
-+
-+ // Read all buffers available from proton.
-+ // Collect buffers for ingress; free empty buffers.
- qd_buffer_list_t buffers;
- DEQ_INIT(buffers);
- pn_raw_buffer_t raw_buffers[READ_BUFFERS];
-@@ -182,14 +225,20 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- }
- }
- }
--
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Took %zu read buffers", conn->conn_id, DEQ_SIZE(buffers));
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Freed %i read buffers", conn->conn_id, free_count);
-- grant_read_buffers(conn);
-+
-+ // Only grant more buffers to proton for reading if close is not pending
-+ if (!close_pending) {
-+ grant_read_buffers(conn);
-+ }
-
- if (conn->instream) {
-- // @TODO(kgiusti): handle Q2 block event:
-- qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers, 0);
-+ qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers, &conn->q2_blocked);
-+ if (conn->q2_blocked) {
-+ // note: unit tests grep for this log!
-+ qd_log(tcp_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"] client link blocked on Q2 limit", conn->conn_id);
-+ }
- qdr_delivery_continue(tcp_adaptor->core, conn->instream, false);
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Continuing message with %i bytes", conn->conn_id, conn->incoming_id, count);
- } else {
-@@ -230,6 +279,10 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- qd_message_compose_2(msg, props, false);
- qd_compose_free(props);
-
-+ // set up message q2 unblocked callback handler
-+ qd_alloc_safe_ptr_t conn_sp = QD_SAFE_PTR_INIT(conn);
-+ qd_message_set_q2_unblocked_handler(msg, qdr_tcp_q2_unblocked_handler, conn_sp);
-+
- conn->instream = qdr_link_deliver(conn->incoming, msg, 0, false, 0, 0, 0, 0);
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Initiating message with %i bytes", conn->conn_id, conn->incoming_id, count);
- }
-@@ -237,10 +290,16 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- }
-
-
-+static int handle_incoming(qdr_tcp_connection_t *conn)
-+{
-+ // Normal incoming runs with no close pending
-+ return handle_incoming_impl(conn, false);
-+}
-+
- static void flush_outgoing_buffs(qdr_tcp_connection_t *conn)
- {
- // Flush buffers staged for writing to raw conn
-- // and free possible references to stream data objects.
-+ // and release any references to stream data objects.
- if (conn->outgoing_buff_count > 0) {
- for (size_t i = conn->outgoing_buff_idx;
- i < conn->outgoing_buff_idx + conn->outgoing_buff_count;
-@@ -263,10 +322,10 @@ static void flush_outgoing_buffs(qdr_tcp_connection_t *conn)
-
- static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- {
-- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Freeing tcp_connection %p", tc->conn_id, (void*) tc);
- free(tc->reply_to);
- free(tc->remote_address);
- free(tc->global_id);
-+ sys_atomic_destroy(&tc->q2_restart);
- if (tc->activate_timer) {
- qd_timer_free(tc->activate_timer);
- }
-@@ -278,7 +337,6 @@ static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
-
- static void handle_disconnected(qdr_tcp_connection_t* conn)
- {
-- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] handle_disconnected", conn->conn_id);
- if (conn->instream) {
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] handle_disconnected - close instream", conn->conn_id, conn->incoming_id);
- qd_message_set_receive_complete(qdr_delivery_message(conn->instream));
-@@ -552,8 +610,8 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- switch (pn_event_type(e)) {
- case PN_RAW_CONNECTION_CONNECTED: {
- if (conn->ingress) {
-- qdr_tcp_connection_ingress_accept(conn);
- qd_log(log, QD_LOG_INFO, "[C%"PRIu64"] PN_RAW_CONNECTION_CONNECTED Ingress accepted to %s from %s (global_id=%s)", conn->conn_id, conn->config.host_port, conn->remote_address, conn->global_id);
-+ qdr_tcp_connection_ingress_accept(conn);
- break;
- } else {
- conn->remote_address = get_address_string(conn->pn_raw_conn);
-@@ -569,6 +627,8 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- case PN_RAW_CONNECTION_CLOSED_READ: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_CLOSED_READ", conn->conn_id);
-+ conn->q2_blocked = false;
-+ handle_incoming_impl(conn, true);
- conn->raw_closed_read = true;
- pn_raw_connection_close(conn->pn_raw_conn);
- break;
-@@ -601,6 +661,12 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- case PN_RAW_CONNECTION_WAKE: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_WAKE", conn->conn_id);
-+ if (sys_atomic_set(&conn->q2_restart, 0)) {
-+ // note: unit tests grep for this log!
-+ qd_log(log, QD_LOG_TRACE, "[C%"PRIu64"] client link unblocked from Q2 limit", conn->conn_id);
-+ conn->q2_blocked = false;
-+ handle_incoming(conn);
-+ }
- while (qdr_connection_process(conn->qdr_conn)) {}
- break;
- }
-@@ -646,6 +712,7 @@ static qdr_tcp_connection_t *qdr_tcp_connection_ingress(qd_tcp_listener_t* liste
- tc->context.handler = &handle_connection_event;
- tc->config = listener->config;
- tc->server = listener->server;
-+ sys_atomic_init(&tc->q2_restart, 0);
- tc->pn_raw_conn = pn_raw_connection();
- pn_raw_connection_set_context(tc->pn_raw_conn, tc);
- //the following call will cause a PN_RAW_CONNECTION_CONNECTED
-@@ -739,6 +806,7 @@ static qdr_tcp_connection_t *qdr_tcp_connection_egress(qd_bridge_config_t *confi
- tc->context.handler = &handle_connection_event;
- tc->config = *config;
- tc->server = server;
-+ sys_atomic_init(&tc->q2_restart, 0);
- tc->conn_id = qd_server_allocate_connection_id(tc->server);
-
- //
---
-2.20.1
-
-From 29d04211d03b27049c59418a2d04c76fb60e5fa9 Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Tue, 2 Mar 2021 09:25:11 -0500
-Subject: [PATCH 15/16] DISPATCH-1984: Matched the method signature of
- _client_rx_body_cb with the implementation. Modified uintmax_t len to size_t
- len
-
----
- src/adaptors/http1/http1_client.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/adaptors/http1/http1_client.c b/src/adaptors/http1/http1_client.c
-index ff033807..422dd6ac 100644
---- a/src/adaptors/http1/http1_client.c
-+++ b/src/adaptors/http1/http1_client.c
-@@ -106,7 +106,7 @@ static int _client_rx_response_cb(h1_codec_request_state_t *lib_rs,
- uint32_t version_minor);
- static int _client_rx_header_cb(h1_codec_request_state_t *lib_rs, const char *key, const char *value);
- static int _client_rx_headers_done_cb(h1_codec_request_state_t *lib_rs, bool has_body);
--static int _client_rx_body_cb(h1_codec_request_state_t *lib_rs, qd_buffer_list_t *body, uintmax_t len, bool more);
-+static int _client_rx_body_cb(h1_codec_request_state_t *lib_rs, qd_buffer_list_t *body, size_t len, bool more);
- static void _client_rx_done_cb(h1_codec_request_state_t *lib_rs);
- static void _client_request_complete_cb(h1_codec_request_state_t *lib_rs, bool cancelled);
- static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, void *context);
---
-2.20.1
-
-From 6bb2eb534f9243caeb00891821be8f0d133e4822 Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Thu, 4 Mar 2021 12:42:00 -0500
-Subject: [PATCH 16/16] DISPATCH-1988: Added code to start routing a delivery
- only if there is some data in the content->buffers or in content->pending. If
- we never receive any data and the receive is complete, the delivery is
- rejected. This closes #1062
-
----
- include/qpid/dispatch/message.h | 8 ++
- src/message.c | 20 ++++-
- src/router_node.c | 36 ++++++++
- tests/system_tests_link_routes.py | 145 ++++++++++++++++++++++++++++++
- 4 files changed, 207 insertions(+), 2 deletions(-)
-
-diff --git a/include/qpid/dispatch/message.h b/include/qpid/dispatch/message.h
-index 07e144ad..1558dde3 100644
---- a/include/qpid/dispatch/message.h
-+++ b/include/qpid/dispatch/message.h
-@@ -247,6 +247,14 @@ qd_message_t *qd_message_receive(pn_delivery_t *delivery);
- */
- qd_message_t * qd_get_message_context(pn_delivery_t *delivery);
-
-+/**
-+ * Returns true if there is at least one non-empty buffer at the head of the content->buffers list
-+ * or if the content->pending buffer is non-empty.
-+ *
-+ * @param msg A pointer to a message.
-+ */
-+bool qd_message_has_data_in_content_or_pending_buffers(qd_message_t *msg);
-+
- /**
- * Send the message outbound on an outgoing link.
- *
-diff --git a/src/message.c b/src/message.c
-index 16794075..3508a996 100644
---- a/src/message.c
-+++ b/src/message.c
-@@ -1255,8 +1255,6 @@ void qd_message_add_fanout(qd_message_t *in_msg,
- // DISPATCH-1590: content->buffers may not be set up yet if
- // content->pending is the first buffer and it is not yet full.
- if (!buf) {
-- // assumption: proton will never signal a readable delivery if there is
-- // no data at all.
- assert(content->pending && qd_buffer_size(content->pending) > 0);
- DEQ_INSERT_TAIL(content->buffers, content->pending);
- content->pending = 0;
-@@ -1422,6 +1420,24 @@ qd_message_t * qd_get_message_context(pn_delivery_t *delivery)
- return 0;
- }
-
-+bool qd_message_has_data_in_content_or_pending_buffers(qd_message_t *msg)
-+{
-+ if (!msg)
-+ return false;
-+
-+ if (MSG_CONTENT(msg)) {
-+ if (DEQ_SIZE(MSG_CONTENT(msg)->buffers) > 0) {
-+ qd_buffer_t *buf = DEQ_HEAD(MSG_CONTENT(msg)->buffers);
-+ if (buf && qd_buffer_size(buf) > 0)
-+ return true;
-+ }
-+ if (MSG_CONTENT(msg)->pending && qd_buffer_size(MSG_CONTENT(msg)->pending) > 0)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-
- qd_message_t *qd_message_receive(pn_delivery_t *delivery)
- {
-diff --git a/src/router_node.c b/src/router_node.c
-index 70d98f91..bccf6cfd 100644
---- a/src/router_node.c
-+++ b/src/router_node.c
-@@ -451,6 +451,42 @@ static bool AMQP_rx_handler(void* context, qd_link_t *link)
- qd_message_t *msg = qd_message_receive(pnd);
- bool receive_complete = qd_message_receive_complete(msg);
-
-+ //
-+ // The very first time AMQP_rx_handler is called on a PN_DELIVERY event, it calls qd_message_receive(). When qd_message_receive() returns, we check here if
-+ // there are any data in the content buffers. If there is no content in the buffers, there is no reason to route the delivery. We will wait for some data
-+ // in the buffers before we start to route the delivery.
-+ // Notice that the if statement checks for the existence of a delivery (qdr_delivery_t). Existence of a delivery means that the delivery has been routed when
-+ // there was data in the buffers (When a delivery has been routed successfully, the delivery (qdr_delivery_t) will be non null)
-+ //
-+ // The following if statement will deal with the following cases:-
-+ // 1. We receive one empty transfer frame with more=true followed by another empty transfer frame with (more=false and abort=true) or with just more=false
-+ // In this case, there is no data at all in the message content buffers, we will reject the message when receive_complete=true. We will never route this
-+ // delivery, so core thread will not be involved
-+ // 2. We receive 2 or more empty transfer frames with more=true followed by another empty transfer frame with (more=false and abort=true) or with just more=false
-+ // This case is similar to #1. We have no content in any of the buffers, we will reject this message after receive_complete=true. We will never route this
-+ // delivery, so core thread will not be involved
-+ // 3. Exactly one empty transfer frame with more=false and abort=false
-+ // In this case, again there is still no content in any of the buffers, we will reject this message. Again, we will not route this message, so the core thread is not involved.
-+ //
-+ if (!delivery && !qd_message_has_data_in_content_or_pending_buffers(msg)) {
-+ if (receive_complete) {
-+ // There is no qdr_delivery_t (delivery) yet which means this message has not been routed yet (the first run of this function is not complete yet) and
-+ // the message is fully received (receive_complete=true) but there is no content in the message buffers.
-+ // This is only possible if there were one or more empty transfer frames.
-+ // Since there is nothing in the message, we will reject it (AMQP message must have a non empty message body)
-+ pn_link_flow(pn_link, 1);
-+ if (pn_delivery_aborted(pnd))
-+ qd_message_set_discard(msg, true);
-+ pn_delivery_update(pnd, PN_REJECTED);
-+ pn_delivery_settle(pnd);
-+ // qd_message_free will free all the associated content buffers and also the content->pending buffer
-+ qd_message_free(msg);
-+ qd_log(router->log_source, QD_LOG_TRACE, "Message rejected due to empty message");
-+ }
-+
-+ return false;
-+ }
-+
- if (!qd_message_oversize(msg)) {
- // message not rejected as oversize
- if (receive_complete) {
-diff --git a/tests/system_tests_link_routes.py b/tests/system_tests_link_routes.py
-index 1334618d..80ce0cdd 100644
---- a/tests/system_tests_link_routes.py
-+++ b/tests/system_tests_link_routes.py
-@@ -26,6 +26,7 @@ import os
- from time import sleep, time
- from threading import Event
- from subprocess import PIPE, STDOUT
-+import socket
-
- from system_test import TestCase, Qdrouterd, main_module, TIMEOUT, Process, TestTimeout, \
- AsyncTestSender, AsyncTestReceiver, MgmtMsgProxy, unittest, QdManager
-@@ -1761,6 +1762,150 @@ class LinkRouteDrainTest(TestCase):
- self.assertEquals(drain_receiver.error, None)
-
-
-+class EmptyTransferTest(TestCase):
-+ @classmethod
-+ def setUpClass(cls):
-+ super(EmptyTransferTest, cls).setUpClass()
-+ cls.ROUTER_LISTEN_PORT = cls.tester.get_port()
-+
-+ config = [
-+ ('router', {'mode': 'standalone', 'id': 'QDR.A'}),
-+ # the client will connect to this listener
-+ ('listener', {'role': 'normal',
-+ 'host': '0.0.0.0',
-+ 'port': cls.ROUTER_LISTEN_PORT,
-+ 'saslMechanisms': 'ANONYMOUS'}),
-+ # to connect to the fake broker
-+ ('connector', {'name': 'broker',
-+ 'role': 'route-container',
-+ 'host': '127.0.0.1',
-+ 'port': cls.tester.get_port(),
-+ 'saslMechanisms': 'ANONYMOUS'}),
-+ ('linkRoute',
-+ {'prefix': 'examples', 'containerId': 'FakeBroker',
-+ 'direction': 'in'}),
-+ ('linkRoute',
-+ {'prefix': 'examples', 'containerId': 'FakeBroker',
-+ 'direction': 'out'})
-+ ]
-+ config = Qdrouterd.Config(config)
-+ cls.router = cls.tester.qdrouterd('A', config, wait=False)
-+
-+ def _fake_broker(self, cls):
-+ """
-+ Spawn a fake broker listening on the broker's connector
-+ """
-+ fake_broker = cls(self.router.connector_addresses[0])
-+ # wait until the connection to the fake broker activates
-+ self.router.wait_connectors()
-+ return fake_broker
-+
-+ def test_DISPATCH_1988(self):
-+ fake_broker = self._fake_broker(FakeBroker)
-+ AMQP_OPEN_BEGIN_ATTACH = bytearray(
-+ b'\x41\x4d\x51\x50\x00\x01\x00\x00\x00\x00\x00\x21\x02\x00\x00'
-+ b'\x00\x00\x53\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x04\xa1\x06'
-+ b'\x2e\x2f\x73\x65\x6e\x64\x40\x40\x60\x7f\xff\x00\x00\x00\x21'
-+ b'\x02\x00\x00\x00\x00\x53\x11\xd0\x00\x00\x00\x11\x00\x00\x00'
-+ b'\x04\x40\x52\x00\x70\x7f\xff\xff\xff\x70\x7f\xff\xff\xff\x00'
-+ b'\x00\x00\x5b\x02\x00\x00\x00\x00\x53\x12\xd0\x00\x00\x00\x4b'
-+ b'\x00\x00\x00\x0b\xa1\x09\x6d\x79\x5f\x73\x65\x6e\x64\x65\x72'
-+ b'\x52\x00\x42\x50\x02\x50\x00\x00\x53\x28\xd0\x00\x00\x00\x0b'
-+ b'\x00\x00\x00\x05\x40\x52\x00\x40\x52\x00\x42\x00\x53\x29\xd0'
-+ b'\x00\x00\x00\x14\x00\x00\x00\x05\xa1\x08\x65\x78\x61\x6d\x70'
-+ b'\x6c\x65\x73\x52\x00\x40\x52\x00\x42\x40\x40\x52\x00\x53\x00')
-+
-+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ # Connect to the router listening port and send an amqp, open,
-+ # begin, attach. The attach is sent on the link
-+ # routed address, "examples"
-+ s.connect(("0.0.0.0", EmptyTransferTest.ROUTER_LISTEN_PORT))
-+ s.sendall(AMQP_OPEN_BEGIN_ATTACH)
-+
-+ # Give a second for the attach to propagate to the broker and
-+ # for the broker to send a response attach
-+ sleep(1)
-+ data = s.recv(2048)
-+ self.assertIn("examples", repr(data))
-+
-+ # First send a message on link routed address "examples" with
-+ # message body of "message 0"
-+ # Verify the the sent message has been accepted.
-+ TRANSFER_1 = bytearray(b'\x00\x00\x00\x31\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x01'
-+ + b'\xa0\x01\x01\x43\x42'
-+ + b'\x40\x40\x40\x40\x40\x42\x00\x53'
-+ + b'\x73\xc0\x02\x01\x44\x00\x53\x77'
-+ + b'\xa1\x09\x6d\x65\x73\x73\x61\x67'
-+ + b'\x65\x20\x30')
-+ s.sendall(TRANSFER_1)
-+ sleep(0.5)
-+ data = s.recv(1024)
-+ # The delivery has been accepted.
-+ self.assertIn("x00S$E", repr(data))
-+
-+ # Test case 1
-+ # Send an empty transfer frame to the router and you should
-+ # receive a rejected disposition from the router.
-+ # Without the fix for DISPATCH_1988,
-+ # upon sending this EMPTY_TRANSFER
-+ # the router crashes with the following assert
-+ # qpid-dispatch/src/message.c:1260: qd_message_add_fanout: Assertion `content->pending && qd_buffer_size(content->pending) > 0' failed.
-+ # This is the empty transfer frame that is sent to the router.
-+ # [0x614000030050]: AMQP:FRAME:0 <- @transfer(20) [handle=0, delivery-id=0, delivery-tag=b"\x01", message-format=0, settled=false, batchable=false]
-+ EMPTY_TRANSFER = bytearray(b'\x00\x00\x00\x1c\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52'
-+ + b'\x02\xa0\x01\x02\x43\x42'
-+ + b'\x42\x40\x40\x40\x40\x42')
-+ s.sendall(EMPTY_TRANSFER)
-+ sleep(1)
-+ data = s.recv(1024)
-+ # The delivery has been rejected.
-+ self.assertIn("x00S%E", repr(data))
-+
-+ # Let's send another transfer to make sure that the
-+ # router has not crashed.
-+ TRANSFER_1 = bytearray(b'\x00\x00\x00\x31\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x03'
-+ + b'\xa0\x01\x03\x43\x42'
-+ + b'\x40\x40\x40\x40\x40\x42\x00\x53'
-+ + b'\x73\xc0\x02\x01\x44\x00\x53\x77'
-+ + b'\xa1\x09\x6d\x65\x73\x73\x61\x67'
-+ + b'\x65\x20\x30')
-+ s.sendall(TRANSFER_1)
-+ sleep(0.5)
-+ data = s.recv(1024)
-+ # The delivery has been accepted.
-+ self.assertIn("x00S$E", repr(data))
-+
-+ # Test case 2
-+ # Now, send two empty transfer frames, first transfer has
-+ # more=true and the next transfer has more=false.
-+ # This will again be rejected by the router.
-+ # The following are the two transfer frames that will be
-+ # sent to the router.
-+ #[0x614000020050]: AMQP:FRAME: 0 <- @ transfer(20)[handle = 0, delivery - id = 4, delivery - tag = b"\x04", message - format = 0, settled = false, more = true, batchable = false]
-+ #[0x614000020050]: AMQP:FRAME: 0 <- @ transfer(20)[handle = 0, delivery - id = 4, delivery - tag = b"\x04", message - format = 0, settled = false, more = false, batchable = false]
-+ EMPTY_TRANSFER_MORE_TRUE = bytearray(
-+ b'\x00\x00\x00\x1c\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x04'
-+ + b'\xa0\x01\x04\x43\x42'
-+ + b'\x41\x40\x40\x40\x40\x42')
-+ EMPTY_TRANSFER_MORE_FALSE = bytearray(
-+ b'\x00\x00\x00\x1c\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x04'
-+ + b'\xa0\x01\x04\x43\x42'
-+ + b'\x42\x40\x40\x40\x40\x42')
-+ s.sendall(EMPTY_TRANSFER_MORE_TRUE)
-+ s.sendall(EMPTY_TRANSFER_MORE_FALSE)
-+ sleep(0.5)
-+ data = s.recv(1024)
-+ # The delivery has been rejected.
-+ self.assertIn("x00S%E", repr(data))
-+
-+ s.close()
-+
-+
- class ConnectionLinkRouteTest(TestCase):
- """
- Test connection scoped link route implementation
---
-2.20.1
-
diff --git a/licenses.xml b/licenses.xml
index 7fdff74..34cde69 100644
--- a/licenses.xml
+++ b/licenses.xml
@@ -3,7 +3,7 @@
<dependencies>
<dependency>
<packageName>qpid-dispatch</packageName>
- <version>1.15.0</version>
+ <version>1.16.0</version>
<licenses>
<license>
<name>ASL 2.0</name>
diff --git a/qpid-dispatch.spec b/qpid-dispatch.spec
index 41362ca..810e23f 100644
--- a/qpid-dispatch.spec
+++ b/qpid-dispatch.spec
@@ -6,37 +6,16 @@
# Define pkgdocdir for releases that don't define it already
%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/%{name}-%{version}}
-%if (0%{?fedora} && 0%{?fedora} >= 29)
-%global pythonx python3
-%else
-%global pythonx python2
-%{!?__python2:%global __python2 %{__python}}
-%{!?__python2:%global python2_sitelib %{python_sitelib}}
-%{!?__python2:%global python2_sitearch %{python_sitearch}}
-%{!?__python2:%global pythonx python}
-%endif
-
-# determine whether to install systemd or sysvinit scripts
-%if 0%{?fedora} || 0%{?rhel} >= 7
-
-%global _use_sysvinit 0
%global _use_systemd 1
-%else
-
-%global _use_sysvinit 1
-%global _use_systemd 0
-
-%endif
-
-%global proton_minimum_version 0.33.0
+%global proton_minimum_version 0.34.0
%global libwebsockets_minimum_version 3.2.0
%global libnghttp2_minimum_version 1.33.0
%undefine __brp_mangle_shebangs
Name: qpid-dispatch
-Version: 1.15.0
+Version: 1.16.0
Release: 1%{?dist}
Summary: Dispatch router for Qpid
License: ASL 2.0
@@ -50,24 +29,15 @@ Source3: qpid-dispatch-console-%{version}.tar.gz
%{!?_licensedir:%global license %doc}
%{!?_licensedir:%global _pkglicensedir %{_pkgdocdir}}
-%if 0%{?rhel} && 0%{?rhel} >= 7
-ExcludeArch: i686
-%endif
-
-%if 0%{?rhel} && 0%{?rhel} <= 6
-Source1: docs-%{version}-1.tar.gz
-%endif
-
-Patch1: dispatch.patch
-Patch4: console-listener.patch
+Patch1: console-listener.patch
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: make
BuildRequires: cmake
BuildRequires: qpid-proton-c-devel >= %{proton_minimum_version}
-BuildRequires: %{pythonx}-devel
-BuildRequires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
+BuildRequires: python3-devel
+BuildRequires: python3-qpid-proton >= %{proton_minimum_version}
BuildRequires: openssl-devel
BuildRequires: libwebsockets-devel >= %{libwebsockets_minimum_version}
BuildRequires: libnghttp2-devel >= %{libnghttp2_minimum_version}
@@ -86,13 +56,11 @@ Summary: The Qpid Dispatch Router executable
Obsoletes: libqpid-dispatch
Obsoletes: libqpid-dispatch-devel
Requires: qpid-proton-c%{?_isa} >= %{proton_minimum_version}
-Requires: %{pythonx}
-Requires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
-%if %{_use_systemd}
+Requires: python3
+Requires: python3-qpid-proton >= %{proton_minimum_version}
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
-%endif
Requires: libwebsockets >= %{libwebsockets_minimum_version}
Requires: libnghttp2 >= %{libnghttp2_minimum_version}
@@ -107,27 +75,12 @@ Requires: libnghttp2 >= %{libnghttp2_minimum_version}
%config(noreplace) %{_sysconfdir}/sasl2/qdrouterd.conf
%{_exec_prefix}/lib/qpid-dispatch
-%if (0%{?fedora} && 0%{?fedora} < 29) || (0%{?rhel} && 0%{?rhel} <= 7)
-%{python2_sitelib}/*
-%endif
-%if (0%{?fedora} && 0%{?fedora} >= 29) || (0%{?rhel} && 0%{?rhel} > 7)
%{python3_sitelib}/qpid_dispatch_site.py*
%{python3_sitelib}/qpid_dispatch
%{python3_sitelib}/qpid_dispatch-*.egg-info
%{python3_sitelib}/__pycache__/*
-%endif
-
-%if %{_use_systemd}
%{_unitdir}/qdrouterd.service
-
-%else
-
-%{_initrddir}/qdrouterd
-%attr(755,qdrouterd,qdrouterd) %dir %{_localstatedir}/run/qpid-dispatch
-
-%endif
-
%{_mandir}/man5/qdrouterd.conf.5*
%{_mandir}/man8/qdrouterd.8*
@@ -139,8 +92,6 @@ getent passwd qdrouterd >/dev/null || \
exit 0
-%if %{_use_systemd}
-
%post router
/sbin/ldconfig
%systemd_post qdrouterd.service
@@ -152,28 +103,6 @@ exit 0
/sbin/ldconfig
%systemd_postun_with_restart qdrouterd.service
-%endif
-
-%if %{_use_sysvinit}
-
-%post router
-/sbin/ldconfig
-/sbin/chkconfig --add qdrouterd
-
-%preun router
-if [ $1 -eq 0 ]; then
- /sbin/service qdrouterd stop >/dev/null 2>&1
- /sbin/chkconfig --del qdrouterd
-fi
-
-%postun router
-/sbin/ldconfig
-if [ "$1" -ge "1" ]; then
- /sbin/service qdrouterd condrestart >/dev/null 2>&1
-fi
-
-%endif
-
%package docs
Summary: Documentation for the Qpid Dispatch router
@@ -203,7 +132,7 @@ Requires: qpid-dispatch-router
%package tools
Summary: Tools for the Qpid Dispatch router
BuildArch: noarch
-Requires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
+Requires: python3-qpid-proton >= %{proton_minimum_version}
%description tools
%{summary}.
@@ -219,14 +148,10 @@ Requires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
%prep
%setup -q
%patch1 -p1
-%patch4 -p1
mkdir pre_built
cd pre_built
tar xvzpf %{SOURCE3} -C .
-%if 0%{?rhel} && 0%{?rhel} <= 6
-tar xvzpf %{SOURCE1} -C .
-%endif
%build
%cmake -DDOC_INSTALL_DIR=%{?_pkgdocdir} \
@@ -246,39 +171,14 @@ make doc
%install
%make_install
-%if %{_use_systemd}
-
install -dm 755 %{buildroot}%{_unitdir}
install -pm 644 %{_builddir}/qpid-dispatch-%{version}/etc/fedora/qdrouterd.service \
%{buildroot}%{_unitdir}
-
-%else
-
-install -dm 755 %{buildroot}%{_initrddir}
-install -pm 755 %{_builddir}/qpid-dispatch-%{version}/etc/fedora/qdrouterd \
- %{buildroot}%{_initrddir}
-
-%endif
-
-%if 0%{?rhel} && 0%{?rhel} <= 6
-install -dm 755 %{buildroot}%{_mandir}/man5
-install -dm 755 %{buildroot}%{_mandir}/man8
-install -pm 644 %{_builddir}/qpid-dispatch-%{version}/pre_built/man/man5/* %{buildroot}%{_mandir}/man5/
-install -pm 644 %{_builddir}/qpid-dispatch-%{version}/pre_built/man/man8/* %{buildroot}%{_mandir}/man8/
-cp -a %{_builddir}/qpid-dispatch-%{version}/pre_built/doc/qpid-dispatch-%{version}/* \
- %{buildroot}%{_pkgdocdir}/
-%endif
-
install -dm 755 %{buildroot}/var/run/qpid-dispatch
-
-%if 0%{?rhel} && 0%{?rhel} <= 6
-install -pm 644 %{SOURCE2} %{buildroot}%{_pkgdocdir}
-%else
install -dm 755 %{buildroot}%{_pkglicensedir}
install -pm 644 %{SOURCE2} %{buildroot}%{_pkglicensedir}
install -pm 644 %{buildroot}%{_pkgdocdir}/LICENSE %{buildroot}%{_pkglicensedir}
rm -f %{buildroot}%{_pkgdocdir}/LICENSE
-%endif
install -dm 755 %{buildroot}/%{_datarootdir}/qpid-dispatch/console
cp -a %{_builddir}/qpid-dispatch-%{version}/pre_built/console/* %{buildroot}/%{_datarootdir}/qpid-dispatch/console/
@@ -292,6 +192,9 @@ rm -fr %{buildroot}/%{_includedir}/qpid/dispatch
%changelog
+* Mon May 17 2021 Irina Boverman <iboverma(a)redhat.com> - 1.16.0-1
+- Rebased to 1.16.0
+
* Mon Mar 22 2021 Kim van der Riet <kvanderr(a)redhat.com> - 1.15.0-1
- Rebased to 1.15.0
diff --git a/sources b/sources
index 590ef76..06737bb 100644
--- a/sources
+++ b/sources
@@ -1,2 +1 @@
-SHA512 (qpid-dispatch-1.15.0.tar.gz) = bf5b36bbe67981ac6c5dc43147cf8051c86c46918b6c79d4cb54b6fbd1fa7d140464d9dedd6840a3f0b1bb19e965aca601b57a011d3fe78240a48f7747e440f7
-SHA512 (qpid-dispatch-console-1.15.0.tar.gz) = cedf64f7bc04d7e8ba28937991e6bd795f2f822e6ad9f2021c3d6b0273215b9c1fd65a98dfeee6af6125d26aa6e01ea54cd87df7cd3fea3ca9bf9daf27a3ee58
+SHA512 (qpid-dispatch-1.16.0.tar.gz) = 75f8df67d44bc0cececd481b8ccbec9d1d12ba4ed4a637bd71648c807e96b4d28ca87f33fbfa53cd1dd2e42c9a8446fd20d590a451f44f36729c888fb36fd780
3 years
Architecture specific change in rpms/fwupd-efi.git
by githook-noreply@fedoraproject.org
The package rpms/fwupd-efi.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/fwupd-efi.git/commit/?id=6075b790....
Change:
+%ifarch aarch64
Thanks.
Full change:
============
commit a0d730533ec2b592902a498a3c2e62ceea5bcee7
Author: Richard Hughes <richard(a)hughsie.com>
Date: Mon May 17 19:49:09 2021 +0100
Rebuilt to use the HSM signers
diff --git a/fwupd-efi.spec b/fwupd-efi.spec
index 8304c01..f670631 100644
--- a/fwupd-efi.spec
+++ b/fwupd-efi.spec
@@ -3,7 +3,7 @@
Summary: Firmware update EFI binaries
Name: fwupd-efi
Version: 1.0
-Release: 1%{?dist}
+Release: 2%{?dist}
License: LGPLv2+
URL: https://github.com/fwupd/fwupd-efi
Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz
@@ -60,5 +60,8 @@ rm -vf %{fwup_efi_fn}.tmp
%{_libexecdir}/fwupd/efi/*.efi.signed
%changelog
+* Mon May 17 2021 Richard Hughes <richard(a)hughsie.com> 1.0-2
+- Rebuilt to use the HSM signers.
+
* Mon Apr 26 2021 Richard Hughes <richard(a)hughsie.com> 1.0-1
- Initial package version, split from the main fwupd package
commit 6075b790ba6e924f9e7ac84ceac83d0b561ec9c3
Author: Richard Hughes <richard(a)hughsie.com>
Date: Wed Apr 28 15:40:03 2021 +0100
Initial import (#1953508).
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c4e315d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/fwupd-efi-1.0.tar.xz
diff --git a/fwupd-efi.spec b/fwupd-efi.spec
new file mode 100644
index 0000000..8304c01
--- /dev/null
+++ b/fwupd-efi.spec
@@ -0,0 +1,64 @@
+%global debug_package %{nil}
+
+Summary: Firmware update EFI binaries
+Name: fwupd-efi
+Version: 1.0
+Release: 1%{?dist}
+License: LGPLv2+
+URL: https://github.com/fwupd/fwupd-efi
+Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz
+
+# these are the only architectures supporting UEFI UpdateCapsule
+ExclusiveArch: x86_64 aarch64
+
+BuildRequires: gcc
+BuildRequires: meson
+BuildRequires: gnu-efi-devel
+BuildRequires: pesign
+
+%description
+fwupd is a project to allow updating device firmware, and this package provides
+the EFI binary that is used for updating using UpdateCapsule.
+
+%prep
+%autosetup -p1
+
+%build
+
+%meson \
+ -Defi_sbat_distro_id="fedora" \
+ -Defi_sbat_distro_summary="The Fedora Project" \
+ -Defi_sbat_distro_pkgname="%{name}" \
+ -Defi_sbat_distro_version="%{version}-%{release}" \
+ -Defi_sbat_distro_url="https://src.fedoraproject.org/rpms/%{name}"
+
+%meson_build
+
+%install
+%meson_install
+
+# not required yet
+rm $RPM_BUILD_ROOT%{_libdir}/pkgconfig/fwupd-efi.pc
+
+# sign fwupd.efi loader
+%ifarch x86_64
+%global efiarch x64
+%endif
+%ifarch aarch64
+%global efiarch aa64
+%endif
+%global fwup_efi_fn $RPM_BUILD_ROOT%{_libexecdir}/fwupd/efi/fwupd%{efiarch}.efi
+%pesign -s -i %{fwup_efi_fn} -o %{fwup_efi_fn}.tmp
+%define __pesign_client_cert fwupd-signer
+%pesign -s -i %{fwup_efi_fn}.tmp -o %{fwup_efi_fn}.signed
+rm -vf %{fwup_efi_fn}.tmp
+
+%files
+%doc README.md AUTHORS
+%license COPYING
+%{_libexecdir}/fwupd/efi/*.efi
+%{_libexecdir}/fwupd/efi/*.efi.signed
+
+%changelog
+* Mon Apr 26 2021 Richard Hughes <richard(a)hughsie.com> 1.0-1
+- Initial package version, split from the main fwupd package
diff --git a/sources b/sources
new file mode 100644
index 0000000..69083ab
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (fwupd-efi-1.0.tar.xz) = 601c53c2673c5465faa858520581db34d9b1dc8ae099434ce115aa92c6ad2745f8a0e07677ddc8bed1f5f1ce2a45d099d27a1f41d6a6acdbde499fcf0bb51255
3 years
Architecture specific change in rpms/qpid-dispatch.git
by githook-noreply@fedoraproject.org
The package rpms/qpid-dispatch.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/qpid-dispatch.git/commit/?id=7f6d....
Change:
-ExcludeArch: i686
Thanks.
Full change:
============
commit 02627805ea7c2db91b50b51d08503aeba6723f74
Author: Irina Boverman <iboverma(a)redhat.com>
Date: Mon May 17 14:32:26 2021 -0400
0.16.0-1
diff --git a/.gitignore b/.gitignore
index 3f73c01..5403d7e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,8 @@
/qpid-dispatch-console-1.15.0.tar.gz
=======
/qpid-dispatch-1.16.0.tar.gz
+<<<<<<< HEAD
>>>>>>> 4eb6201 (0.16.0-1)
+=======
+/qpid-dispatch-console-1.16.0.tar.gz
+>>>>>>> 8b4411c (0.16.0-1)
diff --git a/sources b/sources
index 06737bb..d053677 100644
--- a/sources
+++ b/sources
@@ -1 +1,2 @@
SHA512 (qpid-dispatch-1.16.0.tar.gz) = 75f8df67d44bc0cececd481b8ccbec9d1d12ba4ed4a637bd71648c807e96b4d28ca87f33fbfa53cd1dd2e42c9a8446fd20d590a451f44f36729c888fb36fd780
+SHA512 (qpid-dispatch-console-1.16.0.tar.gz) = 750184c726c6e57a62d6597e0c41be94ee4ad05c48c7aa74b77fc581ca7aa3981d76c012f24d1460db2a6bee40fc441575e5e136e02bb983c1eb80da5559f693
commit 7f6d4938226abdfcf0ee9e8ad41aefe894e3d72d
Author: Irina Boverman <iboverma(a)redhat.com>
Date: Mon May 17 13:56:38 2021 -0400
0.16.0-1
diff --git a/.gitignore b/.gitignore
index 47e0616..3f73c01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,6 @@
+<<<<<<< HEAD
/qpid-dispatch-1.15.0.tar.gz
/qpid-dispatch-console-1.15.0.tar.gz
+=======
+/qpid-dispatch-1.16.0.tar.gz
+>>>>>>> 4eb6201 (0.16.0-1)
diff --git a/dispatch.patch b/dispatch.patch
deleted file mode 100644
index c03cc3c..0000000
--- a/dispatch.patch
+++ /dev/null
@@ -1,2998 +0,0 @@
-From b07d0de0f6c8d115047c6ceca453ca495b4f483f Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Tue, 9 Feb 2021 17:07:47 -0500
-Subject: [PATCH 02/16] DISPATCH-1909: Requests are now recorded just before
- freeing streams. Also modified test to account for no stats being present.
- This closes #1024
-
----
- src/adaptors/http2/http2_adaptor.c | 82 ++++++++++++++----------------
- tests/system_tests_http2.py | 33 +++++++-----
- 2 files changed, 57 insertions(+), 58 deletions(-)
-
-diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
-index a08328c7..2330ece8 100644
---- a/src/adaptors/http2/http2_adaptor.c
-+++ b/src/adaptors/http2/http2_adaptor.c
-@@ -68,6 +68,7 @@ typedef struct qdr_http2_adaptor_t {
- static qdr_http2_adaptor_t *http2_adaptor;
-
- static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void *context);
-+static void _http_record_request(qdr_http2_connection_t *conn, qdr_http2_stream_data_t *stream_data);
-
- static void set_stream_data_delivery_flags(qdr_http2_stream_data_t * stream_data, qdr_delivery_t *dlv) {
- if (dlv == stream_data->in_dlv) {
-@@ -284,6 +285,10 @@ static void free_http2_stream_data(qdr_http2_stream_data_t *stream_data, bool on
-
- qdr_http2_session_data_t *session_data = stream_data->session_data;
- qdr_http2_connection_t *conn = session_data->conn;
-+
-+ // Record the request just before freeing the stream.
-+ _http_record_request(conn, stream_data);
-+
- if (!on_shutdown) {
- if (conn->qdr_conn && stream_data->in_link) {
- qdr_link_set_context(stream_data->in_link, 0);
-@@ -339,6 +344,14 @@ static char *get_address_string(pn_raw_connection_t *pn_raw_conn)
-
- void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdown)
- {
-+ // Free all the stream data associated with this connection/session.
-+ qdr_http2_stream_data_t *stream_data = DEQ_HEAD(http_conn->session_data->streams);
-+ while (stream_data) {
-+ qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] Freeing stream in free_qdr_http2_connection", stream_data->session_data->conn->conn_id, stream_data->stream_id);
-+ free_http2_stream_data(stream_data, on_shutdown);
-+ stream_data = DEQ_HEAD(http_conn->session_data->streams);
-+ }
-+
- if(http_conn->remote_address) {
- free(http_conn->remote_address);
- http_conn->remote_address = 0;
-@@ -353,15 +366,6 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
- http_conn->ping_timer = 0;
- }
-
-- // Free all the stream data associated with this connection/session.
-- qdr_http2_stream_data_t *stream_data = DEQ_HEAD(http_conn->session_data->streams);
-- while (stream_data) {
-- DEQ_REMOVE_HEAD(http_conn->session_data->streams);
-- qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] Freeing stream in free_qdr_http2_connection", stream_data->session_data->conn->conn_id, stream_data->stream_id);
-- free_http2_stream_data(stream_data, on_shutdown);
-- stream_data = DEQ_HEAD(http_conn->session_data->streams);
-- }
--
- http_conn->context.context = 0;
-
- nghttp2_session_del(http_conn->session_data->session);
-@@ -378,6 +382,10 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
- buff = DEQ_HEAD(http_conn->granted_read_buffs);
- }
-
-+ if (http_conn->delete_egress_connections) {
-+ http_conn->config = 0;
-+ }
-+
- qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"] Freeing http2 connection in free_qdr_http2_connection", http_conn->conn_id);
-
- free_qdr_http2_connection_t(http_conn);
-@@ -864,9 +872,13 @@ static void _http_record_request(qdr_http2_connection_t *conn, qdr_http2_stream_
- } else {
- remote_addr = conn->config->host;
- }
-- qd_http_record_request(http2_adaptor->core, stream_data->method, stream_data->request_status,
-- conn->config->address, remote_addr, conn->config->site,
-- stream_data->remote_site, conn->ingress, stream_data->bytes_in, stream_data->bytes_out,
-+ qd_http_record_request(http2_adaptor->core,
-+ stream_data->method,
-+ stream_data->request_status,
-+ conn->config->address,
-+ remote_addr, conn->config->site,
-+ stream_data->remote_site,
-+ conn->ingress, stream_data->bytes_in, stream_data->bytes_out,
- stream_data->stop && stream_data->start ? stream_data->stop - stream_data->start : 0);
- if (free_remote_addr) {
- free(remote_addr);
-@@ -912,10 +924,6 @@ static int on_frame_recv_callback(nghttp2_session *session,
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] NGHTTP2_DATA NGHTTP2_FLAG_END_STREAM flag received, setting receive_complete = true", conn->conn_id, stream_id);
- }
- advance_stream_status(stream_data);
--
-- if (!conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- }
-
- if (stream_data->in_dlv && !stream_data->stream_force_closed) {
-@@ -979,9 +987,6 @@ static int on_frame_recv_callback(nghttp2_session *session,
- qd_message_set_receive_complete(stream_data->message);
- advance_stream_status(stream_data);
- receive_complete = true;
-- if (!conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- }
-
- if (stream_data->entire_footer_arrived) {
-@@ -1095,9 +1100,6 @@ ssize_t read_data_callback(nghttp2_session *session,
- stream_data->next_stream_data = 0;
- }
- stream_data->out_dlv_local_disposition = PN_ACCEPTED;
-- if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] read_data_callback, payload_length=0 and next_stream_data=QD_MESSAGE_STREAM_DATA_NO_MORE", conn->conn_id, stream_data->stream_id);
- }
- else if (stream_data->next_stream_data_result == QD_MESSAGE_STREAM_DATA_FOOTER_OK) {
-@@ -1166,10 +1168,6 @@ ssize_t read_data_callback(nghttp2_session *session,
- }
-
- stream_data->bytes_out += bytes_to_send;
--
-- if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] read_data_callback returning bytes_to_send=%zu", conn->conn_id, stream_data->stream_id, bytes_to_send);
- return bytes_to_send;
- }
-@@ -1251,9 +1249,6 @@ ssize_t read_data_callback(nghttp2_session *session,
- return NGHTTP2_ERR_DEFERRED;
- }
-
-- if ((*data_flags & NGHTTP2_DATA_FLAG_EOF) && conn->ingress) {
-- _http_record_request(conn, stream_data);
-- }
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_ERROR, "[C%"PRIu64"][S%"PRId32"] read_data_callback Returning zero", conn->conn_id, stream_data->stream_id);
- return 0;
- }
-@@ -2055,8 +2050,6 @@ static void restart_streams(qdr_http2_connection_t *http_conn)
- static void qdr_del_http2_connection_CT(qdr_core_t *core, qdr_action_t *action, bool discard)
- {
- qdr_http2_connection_t *conn = (qdr_http2_connection_t*) action->args.general.context_1;
-- if (conn->config)
-- qd_log(http2_adaptor->log_source, QD_LOG_DEBUG, "Removed http2 connection %s", conn->config->host_port);
- free_qdr_http2_connection(conn, false);
- }
-
-@@ -2097,7 +2090,6 @@ static void handle_disconnected(qdr_http2_connection_t* conn)
- conn->stream_dispatcher_stream_data = 0;
-
- if (conn->delete_egress_connections) {
-- conn->config = 0;
- close_connections(conn);
- }
- }
-@@ -2445,6 +2437,19 @@ static void qdr_http2_adaptor_final(void *adaptor_context)
- qdr_http2_adaptor_t *adaptor = (qdr_http2_adaptor_t*) adaptor_context;
- qdr_protocol_adaptor_free(adaptor->core, adaptor->adaptor);
-
-+ // Free all remaining connections.
-+ qdr_http2_connection_t *http_conn = DEQ_HEAD(adaptor->connections);
-+ while (http_conn) {
-+ if (http_conn->stream_dispatcher_stream_data) {
-+ qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing stream_data (stream_dispatcher, qdr_http2_adaptor_final) (%lx)", http_conn->conn_id, (long) http_conn->stream_dispatcher_stream_data);
-+ free_qdr_http2_stream_data_t(http_conn->stream_dispatcher_stream_data);
-+ http_conn->stream_dispatcher_stream_data = 0;
-+ }
-+ qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing http2 connection (calling free_qdr_http2_connection)", http_conn->conn_id);
-+ free_qdr_http2_connection(http_conn, true);
-+ http_conn = DEQ_HEAD(adaptor->connections);
-+ }
-+
- // Free all http listeners
- qd_http_listener_t *li = DEQ_HEAD(adaptor->listeners);
- while (li) {
-@@ -2459,19 +2464,6 @@ static void qdr_http2_adaptor_final(void *adaptor_context)
- ct = DEQ_HEAD(adaptor->connectors);
- }
-
-- // Free all remaining connections.
-- qdr_http2_connection_t *http_conn = DEQ_HEAD(adaptor->connections);
-- while (http_conn) {
-- if (http_conn->stream_dispatcher_stream_data) {
-- qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing stream_data (stream_dispatcher, qdr_http2_adaptor_final) (%lx)", http_conn->conn_id, (long) http_conn->stream_dispatcher_stream_data);
-- free_qdr_http2_stream_data_t(http_conn->stream_dispatcher_stream_data);
-- http_conn->stream_dispatcher_stream_data = 0;
-- }
-- qd_log(http2_adaptor->log_source, QD_LOG_INFO, "[C%"PRIu64"] Freeing http2 connection (calling free_qdr_http2_connection)", http_conn->conn_id);
-- free_qdr_http2_connection(http_conn, true);
-- http_conn = DEQ_HEAD(adaptor->connections);
-- }
--
- sys_mutex_free(adaptor->lock);
- nghttp2_session_callbacks_del(adaptor->callbacks);
- http2_adaptor = NULL;
-diff --git a/tests/system_tests_http2.py b/tests/system_tests_http2.py
-index fb9d6716..59a7a23a 100644
---- a/tests/system_tests_http2.py
-+++ b/tests/system_tests_http2.py
-@@ -281,7 +281,7 @@ class Http2TestOneStandaloneRouter(Http2TestBase, CommonHttp2Tests):
- listen_port=int(os.getenv('SERVER_LISTEN_PORT')),
- py_string='python3',
- server_file="http2_server.py")
-- name = "http2-test-router"
-+ name = "http2-test-standalone-router"
- cls.connector_name = 'connectorToBeDeleted'
- cls.connector_props = {
- 'port': os.getenv('SERVER_LISTEN_PORT'),
-@@ -310,20 +310,24 @@ class Http2TestOneStandaloneRouter(Http2TestBase, CommonHttp2Tests):
- def test_000_stats(self):
- # Run curl 127.0.0.1:port --http2-prior-knowledge
- address = self.router_qdra.http_addresses[0]
-- self.run_curl(address=address)
-+ qd_manager = QdManager(self, address=self.router_qdra.addresses[0])
-+
-+ # First request
-+ out = self.run_curl(address=address)
-+
-+ # Second request
- address = self.router_qdra.http_addresses[0] + "/myinfo"
- out = self.run_curl(args=['-d', 'fname=Mickey&lname=Mouse', '-X', 'POST'], address=address)
- self.assertIn('Success! Your first name is Mickey, last name is Mouse', out)
-- qd_manager = QdManager(self, address=self.router_qdra.addresses[0])
-+
- stats = qd_manager.query('org.apache.qpid.dispatch.httpRequestInfo')
- self.assertEqual(len(stats), 2)
-
- # Give time for the core thread to augment the stats.
- i = 0
- while i < 3:
-- s = stats[0]
-- i += 1
-- if s.get('requests') < 2:
-+ if not stats or stats[0].get('requests') < 2:
-+ i += 1
- sleep(1)
- stats = qd_manager.query('org.apache.qpid.dispatch.httpRequestInfo')
- else:
-@@ -475,20 +479,23 @@ class Http2TestTwoRouter(Http2TestBase, CommonHttp2Tests):
- def test_000_stats(self):
- # Run curl 127.0.0.1:port --http2-prior-knowledge
- address = self.router_qdra.http_addresses[0]
-+ qd_manager_a = QdManager(self, address=self.router_qdra.addresses[0])
-+ stats_a = qd_manager_a.query('org.apache.qpid.dispatch.httpRequestInfo')
-+
-+ # First request
- self.run_curl(address=address)
- address = self.router_qdra.http_addresses[0] + "/myinfo"
-+
-+ # Second request
- out = self.run_curl(args=['-d', 'fname=Mickey&lname=Mouse', '-X', 'POST'], address=address)
- self.assertIn('Success! Your first name is Mickey, last name is Mouse', out)
-- qd_manager_a = QdManager(self, address=self.router_qdra.addresses[0])
-- stats_a = qd_manager_a.query('org.apache.qpid.dispatch.httpRequestInfo')
-
- # Give time for the core thread to augment the stats.
- i = 0
- while i < 3:
-- s = stats_a[0]
-- i += 1
-- if s.get('requests') < 2:
-+ if not stats_a or stats_a[0].get('requests') < 2:
- sleep(1)
-+ i += 1
- stats_a = qd_manager_a.query('org.apache.qpid.dispatch.httpRequestInfo')
- else:
- break
-@@ -505,8 +512,8 @@ class Http2TestTwoRouter(Http2TestBase, CommonHttp2Tests):
- i = 0
- while i < 3:
- s = stats_b[0]
-- i += 1
-- if s.get('requests') < 2:
-+ if not stats_b or stats_b[0].get('requests') < 2:
-+ i += 1
- sleep(1)
- stats_b = qd_manager_b.query('org.apache.qpid.dispatch.httpRequestInfo')
- else:
---
-2.20.1
-
-From cb97f9c84ddaadece8ec3495e18c6b3a0c35ec3b Mon Sep 17 00:00:00 2001
-From: Fernando Giorgetti <fgiorgetti(a)users.noreply.github.com>
-Date: Fri, 12 Feb 2021 09:17:06 -0300
-Subject: [PATCH 03/16] DISPATCH-1586 - Add allocator metrics (#696)
-
----
- src/http-libwebsockets.c | 140 +++++++++++++++++++++++++++++++++++++--
- 1 file changed, 136 insertions(+), 4 deletions(-)
-
-diff --git a/src/http-libwebsockets.c b/src/http-libwebsockets.c
-index 9a2e803e..66cf1874 100644
---- a/src/http-libwebsockets.c
-+++ b/src/http-libwebsockets.c
-@@ -460,6 +460,11 @@ typedef struct metric_definition {
- int_metric value;
- } metric_definition;
-
-+typedef struct allocator_metric_definition {
-+ const char* name;
-+ qd_alloc_stats_t *(*fn)(void);
-+} allocator_metric_definition;
-+
- static int stats_get_connections(qdr_global_stats_t *stats) { return stats->connections; }
- static int stats_get_links(qdr_global_stats_t *stats) { return stats->links; }
- static int stats_get_addrs(qdr_global_stats_t *stats) { return stats->addrs; }
-@@ -483,6 +488,43 @@ static int stats_get_deliveries_stuck(qdr_global_stats_t *stats) { return stats-
- static int stats_get_links_blocked(qdr_global_stats_t *stats) { return stats->links_blocked; }
- static int stats_get_deliveries_redirected_to_fallback(qdr_global_stats_t *stats) { return stats->deliveries_redirected_to_fallback; }
-
-+qd_alloc_stats_t *alloc_stats_qd_bitmask_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_buffer_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_composed_field_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_composite_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_connection_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_hash_handle_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_hash_item_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_iterator_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_link_ref_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_link_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_listener_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_log_entry_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_management_context_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_message_content_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_message_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_node_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_parse_node_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_parsed_field_t(void);
-+qd_alloc_stats_t *alloc_stats_qd_timer_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_action_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_address_config_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_address_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_connection_info_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_connection_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_connection_work_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_core_timer_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_delivery_cleanup_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_delivery_ref_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_delivery_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_field_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_general_work_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_link_ref_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_link_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_link_work_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_query_t(void);
-+qd_alloc_stats_t *alloc_stats_qdr_terminus_t(void);
-+
- static struct metric_definition metrics[] = {
- {"qdr_connections_total", "gauge", stats_get_connections},
- {"qdr_links_total", "gauge", stats_get_links},
-@@ -509,9 +551,60 @@ static struct metric_definition metrics[] = {
- };
- static size_t metrics_length = sizeof(metrics)/sizeof(metrics[0]);
-
-+static struct allocator_metric_definition allocator_metrics[] = {
-+ {"qdr_allocator_qd_bitmask_t", alloc_stats_qd_bitmask_t},
-+ {"qdr_allocator_qd_buffer_t", alloc_stats_qd_buffer_t},
-+ {"qdr_allocator_qd_composed_field_t", alloc_stats_qd_composed_field_t},
-+ {"qdr_allocator_qd_composite_t", alloc_stats_qd_composite_t},
-+ {"qdr_allocator_qd_connection_t", alloc_stats_qd_connection_t},
-+ {"qdr_allocator_qd_hash_handle_t", alloc_stats_qd_hash_handle_t},
-+ {"qdr_allocator_qd_hash_item_t", alloc_stats_qd_hash_item_t},
-+ {"qdr_allocator_qd_iterator_t", alloc_stats_qd_iterator_t},
-+ {"qdr_allocator_qd_link_ref_t", alloc_stats_qd_link_ref_t},
-+ {"qdr_allocator_qd_link_t", alloc_stats_qd_link_t},
-+ {"qdr_allocator_qd_listener_t", alloc_stats_qd_listener_t},
-+ {"qdr_allocator_qd_log_entry_t", alloc_stats_qd_log_entry_t},
-+ {"qdr_allocator_qd_management_context_t", alloc_stats_qd_management_context_t},
-+ {"qdr_allocator_qd_message_content_t", alloc_stats_qd_message_content_t},
-+ {"qdr_allocator_qd_message_t", alloc_stats_qd_message_t},
-+ {"qdr_allocator_qd_node_t", alloc_stats_qd_node_t},
-+ {"qdr_allocator_qd_parse_node_t", alloc_stats_qd_parse_node_t},
-+ {"qdr_allocator_qd_parsed_field_t", alloc_stats_qd_parsed_field_t},
-+ {"qdr_allocator_qd_timer_t", alloc_stats_qd_timer_t},
-+ {"qdr_allocator_qdr_action_t", alloc_stats_qdr_action_t},
-+ {"qdr_allocator_qdr_address_config_t", alloc_stats_qdr_address_config_t},
-+ {"qdr_allocator_qdr_address_t", alloc_stats_qdr_address_t},
-+ {"qdr_allocator_qdr_connection_info_t", alloc_stats_qdr_connection_info_t},
-+ {"qdr_allocator_qdr_connection_t", alloc_stats_qdr_connection_t},
-+ {"qdr_allocator_qdr_connection_work_t", alloc_stats_qdr_connection_work_t},
-+ {"qdr_allocator_qdr_core_timer_t", alloc_stats_qdr_core_timer_t},
-+ {"qdr_allocator_qdr_delivery_cleanup_t", alloc_stats_qdr_delivery_cleanup_t},
-+ {"qdr_allocator_qdr_delivery_ref_t", alloc_stats_qdr_delivery_ref_t},
-+ {"qdr_allocator_qdr_delivery_t", alloc_stats_qdr_delivery_t},
-+ {"qdr_allocator_qdr_field_t", alloc_stats_qdr_field_t},
-+ {"qdr_allocator_qdr_general_work_t", alloc_stats_qdr_general_work_t},
-+ {"qdr_allocator_qdr_link_ref_t", alloc_stats_qdr_link_ref_t},
-+ {"qdr_allocator_qdr_link_t", alloc_stats_qdr_link_t},
-+ {"qdr_allocator_qdr_link_work_t", alloc_stats_qdr_link_work_t},
-+ {"qdr_allocator_qdr_query_t", alloc_stats_qdr_query_t},
-+ {"qdr_allocator_qdr_terminus_t", alloc_stats_qdr_terminus_t}
-+};
-+static size_t allocator_metrics_length = sizeof(allocator_metrics)/sizeof(allocator_metrics[0]);
-+
-+#define ALLOC_DATA(S, F) ((allocator_field) {#F, (S!=NULL? S->F: 0)})
-+
-+typedef struct allocator_field {
-+ const char* name;
-+ uint64_t value;
-+} allocator_field;
-+
- static bool write_stats(uint8_t **position, const uint8_t * const end, const char* name, const char* type, int value)
- {
- //11 chars + type + 2*name + 20 chars for int
-+ // average metric name size is 30 bytes
-+ // average metric type size is 8 bytes
-+ // current number of metrics is 22
-+ // total metric buffer size = 22 * (11 + 8 + 2*30 + 20) = 2178
- size_t length = 11 + strlen(type) + strlen(name)*2 + 20;
- if (end - *position >= length) {
- *position += lws_snprintf((char*) *position, end - *position, "# TYPE %s %s\n", name, type);
-@@ -522,11 +615,38 @@ static bool write_stats(uint8_t **position, const uint8_t * const end, const cha
- }
- }
-
-+static bool write_allocator_stats(uint8_t **position, const uint8_t * const end, const char* name, allocator_field field)
-+{
-+ // 30 chars (static) + 2*name + 2*field.name + 20 for int
-+ // average allocator metric name size is 54 bytes (name:field.name)
-+ // current number of metrics is 180
-+ // total allocator buffer size = 180 * (30 + 2*54 + 20) = 28440
-+ size_t length = 30 + strlen(name)*2 + strlen(field.name)*2 + 20;
-+ if (end - *position >= length) {
-+ *position += lws_snprintf((char*) *position, end - *position, "# TYPE %s:%s_bytes gauge\n", name, field.name);
-+ *position += lws_snprintf((char*) *position, end - *position, "%s:%s_bytes %"PRIu64"\n", name, field.name, field.value);
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
- static bool write_metric(uint8_t **position, const uint8_t * const end, metric_definition* definition, qdr_global_stats_t* stats)
- {
- return write_stats(position, end, definition->name, definition->type, definition->value(stats));
- }
-
-+static bool write_allocator_metric(uint8_t **position, const uint8_t * const end, allocator_metric_definition* definition)
-+{
-+ qd_alloc_stats_t *allocator_stats = definition->fn();
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, total_alloc_from_heap))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, total_free_to_heap))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, held_by_threads))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, batches_rebalanced_to_threads))) return false;
-+ if (!write_allocator_stats(position, end, definition->name, ALLOC_DATA(allocator_stats, batches_rebalanced_to_global))) return false;
-+ return true;
-+}
-+
- static int add_header_by_name(struct lws *wsi, const char* name, const char* value, uint8_t** position, uint8_t* end)
- {
- return lws_add_http_header_by_name(wsi, (unsigned char*) name, (unsigned char*) value, strlen(value), position, end);
-@@ -537,7 +657,8 @@ static int callback_metrics(struct lws *wsi, enum lws_callback_reasons reason,
- {
- qd_http_server_t *hs = wsi_server(wsi);
- stats_t *stats = (stats_t*) user;
-- uint8_t buffer[LWS_PRE + 2048];
-+ // rationale for buffer size is explained at write_stats and write_allocator_stats
-+ uint8_t buffer[LWS_PRE + 30618];
- uint8_t *start = &buffer[LWS_PRE], *position = start, *end = &buffer[sizeof(buffer) - LWS_PRE - 1];
-
- switch (reason) {
-@@ -569,15 +690,26 @@ static int callback_metrics(struct lws *wsi, enum lws_callback_reasons reason,
- stats->current++;
- qd_log(hs->log, QD_LOG_DEBUG, "wrote metric %lu of %lu", stats->current, metrics_length);
- } else {
-- qd_log(hs->log, QD_LOG_DEBUG, "insufficient space in buffer");
-+ qd_log(hs->log, QD_LOG_WARNING, "insufficient space in buffer");
- break;
- }
- }
-- int n = stats->current < metrics_length ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL;
-+
-+ int alloc_cur = 0;
-+ while (alloc_cur < allocator_metrics_length) {
-+ if (write_allocator_metric(&position, end, &allocator_metrics[alloc_cur])) {
-+ qd_log(hs->log, QD_LOG_DEBUG, "wrote allocator metric %lu of %lu", alloc_cur, allocator_metrics_length);
-+ alloc_cur++;
-+ } else {
-+ qd_log(hs->log, QD_LOG_WARNING, "insufficient space in buffer");
-+ break;
-+ }
-+ }
-+ int n = (stats->current < metrics_length) || (alloc_cur < allocator_metrics_length) ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL;
-
- //write buffer
- size_t available = position - start;
-- if (lws_write(wsi, (unsigned char*) start, available, n) != available)
-+ if (lws_write(wsi, (unsigned char*) start, available, n) != available)
- return 1;
- if (n == LWS_WRITE_HTTP_FINAL) {
- if (lws_http_transaction_completed(wsi)) return -1;
---
-2.20.1
-
-From 750f86f10fa19b8e0f939d2e188e86218355ece4 Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Tue, 2 Feb 2021 16:52:51 -0500
-Subject: [PATCH 04/16] DISPATCH-1948: fix alignment issues in alloc_pool.c
-
-This closes #1015
----
- src/alloc_pool.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
-diff --git a/src/alloc_pool.c b/src/alloc_pool.c
-index 0feb20e7..284630ec 100644
---- a/src/alloc_pool.c
-+++ b/src/alloc_pool.c
-@@ -348,7 +348,8 @@ void *qd_alloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool)
- DEQ_INSERT_TAIL(qtype->allocated, item);
- sys_mutex_unlock(desc->lock);
- item->header = PATTERN_FRONT;
-- *((uint32_t*) ((char*) &item[1] + desc->total_size))= PATTERN_BACK;
-+ const uint32_t pb = PATTERN_BACK;
-+ memcpy((char*) &item[1] + desc->total_size, &pb, sizeof(pb));
- QD_MEMORY_FILL(&item[1], QD_MEMORY_INIT, desc->total_size);
- #endif
- return &item[1];
-@@ -414,7 +415,8 @@ void *qd_alloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool)
- DEQ_INSERT_TAIL(qtype->allocated, item);
- sys_mutex_unlock(desc->lock);
- item->header = PATTERN_FRONT;
-- *((uint32_t*) ((char*) &item[1] + desc->total_size))= PATTERN_BACK;
-+ const uint32_t pb = PATTERN_BACK;
-+ memcpy((char*) &item[1] + desc->total_size, &pb, sizeof(pb));
- QD_MEMORY_FILL(&item[1], QD_MEMORY_INIT, desc->total_size);
- #endif
- return &item[1];
-@@ -434,7 +436,9 @@ void qd_dealloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool, char *p)
- assert (desc->header == PATTERN_FRONT);
- assert (desc->trailer == PATTERN_BACK);
- assert (item->header == PATTERN_FRONT);
-- assert (*((uint32_t*) (p + desc->total_size)) == PATTERN_BACK);
-+ const uint32_t pb = PATTERN_BACK;
-+ (void)pb; // prevent unused warning
-+ assert (memcmp(p + desc->total_size, &pb, sizeof(pb)) == 0);
- assert (item->desc == desc); // Check for double-free
- qd_alloc_type_t *qtype = (qd_alloc_type_t*) desc->debug;
- sys_mutex_lock(desc->lock);
---
-2.20.1
-
-From b1e309e1c59f50a67fdb6d5c2bd0ff54a64680bb Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Mon, 8 Feb 2021 13:25:35 -0500
-Subject: [PATCH 05/16] DISPATCH-1941: fix http1 parser to detect null
- characters
-
----
- src/adaptors/http1/http1_codec.c | 18 ++++++++++++++----
- src/adaptors/http1/http1_server.c | 4 ++--
- 2 files changed, 16 insertions(+), 6 deletions(-)
-
-diff --git a/src/adaptors/http1/http1_codec.c b/src/adaptors/http1/http1_codec.c
-index 7669d26f..a11f2260 100644
---- a/src/adaptors/http1/http1_codec.c
-+++ b/src/adaptors/http1/http1_codec.c
-@@ -353,6 +353,8 @@ static void ensure_outgoing_capacity(struct encoder_t *encoder, size_t capacity)
- static void write_string(struct encoder_t *encoder, const char *string)
- {
- size_t needed = strlen(string);
-+ if (needed == 0) return;
-+
- ensure_outgoing_capacity(encoder, needed);
-
- encoder->hrs->out_octets += needed;
-@@ -492,6 +494,14 @@ static bool ensure_scratch_size(scratch_memory_t *b, size_t required)
- }
-
-
-+// return true if octet in str
-+static inline bool filter_str(const char *str, uint8_t octet)
-+{
-+ const char *ptr = strchr(str, (int)((unsigned int)octet));
-+ return ptr && *ptr != 0;
-+}
-+
-+
- // trims any optional whitespace characters at the start of 'line'
- // RFC7230 defines OWS as zero or more spaces or horizontal tabs
- //
-@@ -538,7 +548,7 @@ static bool parse_token(qd_iterator_pointer_t *line, qd_iterator_pointer_t *toke
- && (('A' <= octet && octet <= 'Z') ||
- ('a' <= octet && octet <= 'z') ||
- ('0' <= octet && octet <= '9') ||
-- (strchr(TOKEN_EXTRA, octet)))) {
-+ (filter_str(TOKEN_EXTRA, octet)))) {
- len++;
- }
-
-@@ -1733,17 +1743,17 @@ const char *h1_codec_token_list_next(const char *start, size_t *len, const char
-
- if (!start) return 0;
-
-- while (*start && strchr(SKIPME, *start))
-+ while (*start && filter_str(SKIPME, *start))
- ++start;
-
- if (!*start) return 0;
-
- const char *end = start;
-- while (*end && !strchr(SKIPME, *end))
-+ while (*end && !filter_str(SKIPME, *end))
- ++end;
-
- *len = end - start;
-- while (*end && strchr(SKIPME, *end))
-+ while (*end && filter_str(SKIPME, *end))
- ++end;
-
- *next = end;
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index 61a0634d..3f46e448 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -1247,7 +1247,7 @@ static uint64_t _send_request_headers(_server_request_t *hreq, qd_message_t *msg
-
- method_str = (char*) qd_iterator_copy(method_iter);
- qd_iterator_free(method_iter);
-- if (!method_str) {
-+ if (!method_str || *method_str == 0) {
- return PN_REJECTED;
- }
-
-@@ -1267,7 +1267,7 @@ static uint64_t _send_request_headers(_server_request_t *hreq, qd_message_t *msg
-
- qd_parsed_field_t *ref = qd_parse_value_by_key(app_props, TARGET_HEADER_KEY);
- target_str = (char*) qd_iterator_copy(qd_parse_raw(ref));
-- if (!target_str) {
-+ if (!target_str || *target_str == 0) {
- outcome = PN_REJECTED;
- goto exit;
- }
---
-2.20.1
-
-From 479a73afdd55eb0590370c037e4056514a6db4d6 Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Mon, 15 Feb 2021 11:19:45 -0500
-Subject: [PATCH 06/16] DISPATCH-1955: TCP adaptor adds byte totals and other
- stats to logs
-
- 1. Add byte total to logs where incremental values are shown.
- 2. Add management stat summary when connection is closed/deleted.
-
-This closes #1026
----
- src/adaptors/tcp_adaptor.c | 12 ++++++++----
- 1 file changed, 8 insertions(+), 4 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index a38167f4..51d9316d 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -567,7 +567,7 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- int read = handle_incoming(conn);
- conn->last_in_time = tcp_adaptor->core->uptime_ticks;
- conn->bytes_in += read;
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_READ Read %i bytes", conn->conn_id, read);
-+ qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_READ Read %i bytes. Total read %"PRIu64" bytes", conn->conn_id, read, conn->bytes_in);
- while (qdr_connection_process(conn->qdr_conn)) {}
- break;
- }
-@@ -583,9 +583,9 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- }
- }
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_WRITTEN Wrote %zu bytes", conn->conn_id, written);
- conn->last_out_time = tcp_adaptor->core->uptime_ticks;
- conn->bytes_out += written;
-+ qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_WRITTEN Wrote %zu bytes. Total written %"PRIu64" bytes", conn->conn_id, written, conn->bytes_out);
- while (qdr_connection_process(conn->qdr_conn)) {}
- break;
- }
-@@ -1527,8 +1527,12 @@ static void qdr_del_tcp_connection_CT(qdr_core_t *core, qdr_action_t *action, bo
- qdr_tcp_connection_t *conn = (qdr_tcp_connection_t*) action->args.general.context_1;
- if (conn->in_list) {
- DEQ_REMOVE(tcp_adaptor->connections, conn);
-- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] qdr_del_tcp_connection_CT %s (%zu)",
-- conn->conn_id, conn->config.host_port, DEQ_SIZE(tcp_adaptor->connections));
-+ qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG,
-+ "[C%"PRIu64"] qdr_del_tcp_connection_CT %s deleted. bytes_in=%"PRIu64", bytes_out=%"PRId64", "
-+ "opened_time=%"PRId64", last_in_time=%"PRId64", last_out_time=%"PRId64". Connections remaining %zu",
-+ conn->conn_id, conn->config.host_port,
-+ conn->bytes_in, conn->bytes_out, conn->opened_time, conn->last_in_time, conn->last_out_time,
-+ DEQ_SIZE(tcp_adaptor->connections));
- }
- free_qdr_tcp_connection(conn);
- }
---
-2.20.1
-
-From 53a5bbca01678e615b1181c95c293b658a68e9e1 Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Mon, 15 Feb 2021 11:38:37 -0500
-Subject: [PATCH 07/16] DISPATCH-1964: TCP adaptor connection object should be
- a pooled type
-
----
- src/adaptors/tcp_adaptor.c | 9 ++++++---
- 1 file changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index 51d9316d..fce22192 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -22,6 +22,7 @@
- #include <proton/netaddr.h>
- #include <proton/proactor.h>
- #include <proton/raw_connection.h>
-+#include "qpid/dispatch/alloc_pool.h"
- #include "qpid/dispatch/ctools.h"
- #include "qpid/dispatch/protocol_adaptor.h"
- #include "delivery.h"
-@@ -79,6 +80,8 @@ struct qdr_tcp_connection_t {
- };
-
- DEQ_DECLARE(qdr_tcp_connection_t, qdr_tcp_connection_list_t);
-+ALLOC_DECLARE(qdr_tcp_connection_t);
-+ALLOC_DEFINE(qdr_tcp_connection_t);
-
- typedef struct qdr_tcp_adaptor_t {
- qdr_core_t *core;
-@@ -241,7 +244,7 @@ static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- }
- sys_mutex_free(tc->activation_lock);
- //proactor will free the socket
-- free(tc);
-+ free_qdr_tcp_connection_t(tc);
- }
-
- static void handle_disconnected(qdr_tcp_connection_t* conn)
-@@ -597,7 +600,7 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
-
- static qdr_tcp_connection_t *qdr_tcp_connection_ingress(qd_tcp_listener_t* listener)
- {
-- qdr_tcp_connection_t* tc = NEW(qdr_tcp_connection_t);
-+ qdr_tcp_connection_t* tc = new_qdr_tcp_connection_t();
- ZERO(tc);
- tc->activation_lock = sys_mutex();
- tc->ingress = true;
-@@ -682,7 +685,7 @@ static void qdr_tcp_open_server_side_connection(qdr_tcp_connection_t* tc)
-
- static qdr_tcp_connection_t *qdr_tcp_connection_egress(qd_bridge_config_t *config, qd_server_t *server, qdr_delivery_t *initial_delivery)
- {
-- qdr_tcp_connection_t* tc = NEW(qdr_tcp_connection_t);
-+ qdr_tcp_connection_t* tc = new_qdr_tcp_connection_t();
- ZERO(tc);
- tc->activation_lock = sys_mutex();
- if (initial_delivery) {
---
-2.20.1
-
-From 31c23ca83df6aea7feb724811af09aa6a197dd37 Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Wed, 10 Feb 2021 17:23:34 -0500
-Subject: [PATCH 08/16] DISPATCH-1960: Refactor Q2 flow control for protocol
- adaptor use.
-
-This closes #1027
----
- include/qpid/dispatch/alloc_pool.h | 25 +++++++-
- include/qpid/dispatch/container.h | 2 +-
- include/qpid/dispatch/message.h | 27 +++++---
- src/adaptors/http1/http1_client.c | 3 +-
- src/adaptors/http1/http1_server.c | 3 +-
- src/adaptors/http2/http2_adaptor.c | 12 ++--
- src/adaptors/reference_adaptor.c | 6 +-
- src/adaptors/tcp_adaptor.c | 3 +-
- src/alloc_pool.c | 4 ++
- src/message.c | 100 ++++++++++++++++++++++-------
- src/message_private.h | 10 ++-
- src/router_node.c | 24 +++----
- tests/message_test.c | 25 ++++++--
- 13 files changed, 184 insertions(+), 60 deletions(-)
-
-diff --git a/include/qpid/dispatch/alloc_pool.h b/include/qpid/dispatch/alloc_pool.h
-index e8722a52..d872ff49 100644
---- a/include/qpid/dispatch/alloc_pool.h
-+++ b/include/qpid/dispatch/alloc_pool.h
-@@ -80,7 +80,26 @@ void *qd_alloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool);
- /** De-allocate from a thread pool. Use via ALLOC_DECLARE */
- void qd_dealloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool, char *p);
- uint32_t qd_alloc_sequence(void *p);
--static inline void qd_nullify_safe_ptr(qd_alloc_safe_ptr_t *sp) { sp->ptr = 0; }
-+
-+// generic safe pointer api for any alloc pool item
-+
-+#define QD_SAFE_PTR_INIT(p) { .ptr = (void*)(p), .seq = qd_alloc_sequence(p) }
-+
-+static inline void qd_nullify_safe_ptr(qd_alloc_safe_ptr_t *sp)
-+{
-+ sp->ptr = 0;
-+}
-+
-+static inline void qd_alloc_set_safe_ptr(qd_alloc_safe_ptr_t *sp, void *p)
-+{
-+ sp->ptr = p;
-+ sp->seq = qd_alloc_sequence(p);
-+}
-+
-+static inline void *qd_alloc_deref_safe_ptr(const qd_alloc_safe_ptr_t *sp)
-+{
-+ return sp->seq == qd_alloc_sequence(sp->ptr) ? sp->ptr : (void*) 0;
-+}
-
- /**
- * Declare functions new_T and alloc_T
-@@ -102,8 +121,8 @@ static inline void qd_nullify_safe_ptr(qd_alloc_safe_ptr_t *sp) { sp->ptr = 0; }
- __thread qd_alloc_pool_t *__local_pool_##T = 0; \
- T *new_##T(void) { return (T*) qd_alloc(&__desc_##T, &__local_pool_##T); } \
- void free_##T(T *p) { qd_dealloc(&__desc_##T, &__local_pool_##T, (char*) p); } \
-- void set_safe_ptr_##T(T *p, T##_sp *sp) { sp->ptr = (void*) p; sp->seq = qd_alloc_sequence((void*) p); } \
-- T *safe_deref_##T(T##_sp sp) { return sp.seq == qd_alloc_sequence((void*) sp.ptr) ? (T*) sp.ptr : (T*) 0; } \
-+ void set_safe_ptr_##T(T *p, T##_sp *sp) { qd_alloc_set_safe_ptr(sp, (void*)p); } \
-+ T *safe_deref_##T(T##_sp sp) { return (T*) qd_alloc_deref_safe_ptr((qd_alloc_safe_ptr_t*) &(sp)); } \
- qd_alloc_stats_t *alloc_stats_##T(void) { return __desc_##T.stats; } \
- void *unused##T
-
-diff --git a/include/qpid/dispatch/container.h b/include/qpid/dispatch/container.h
-index 08caba13..82d9ad8b 100644
---- a/include/qpid/dispatch/container.h
-+++ b/include/qpid/dispatch/container.h
-@@ -228,7 +228,7 @@ void qd_link_close(qd_link_t *link);
- void qd_link_detach(qd_link_t *link);
- void qd_link_free(qd_link_t *link);
- void *qd_link_get_node_context(const qd_link_t *link);
--void qd_link_restart_rx(qd_link_t *link);
-+void qd_link_q2_restart_receive(const qd_alloc_safe_ptr_t context);
- void qd_link_q3_block(qd_link_t *link);
- void qd_link_q3_unblock(qd_link_t *link);
- uint64_t qd_link_link_id(const qd_link_t *link);
-diff --git a/include/qpid/dispatch/message.h b/include/qpid/dispatch/message.h
-index 657477d0..07e144ad 100644
---- a/include/qpid/dispatch/message.h
-+++ b/include/qpid/dispatch/message.h
-@@ -253,10 +253,9 @@ qd_message_t * qd_get_message_context(pn_delivery_t *delivery);
- * @param msg A pointer to a message to be sent.
- * @param link The outgoing link on which to send the message.
- * @param strip_outbound_annotations [in] annotation control flag
-- * @param restart_rx [out] indication to wake up receive process
- * @param q3_stalled [out] indicates that the link is stalled due to proton-buffer-full
- */
--void qd_message_send(qd_message_t *msg, qd_link_t *link, bool strip_outbound_annotations, bool *restart_rx, bool *q3_stalled);
-+void qd_message_send(qd_message_t *msg, qd_link_t *link, bool strip_outbound_annotations, bool *q3_stalled);
-
- /**
- * Check that the message is well-formed up to a certain depth. Any part of the message that is
-@@ -304,9 +303,10 @@ void qd_message_compose_4(qd_message_t *msg, qd_composed_field_t *content1, qd_c
- *
- * @param msg Pointer to a message
- * @param field A composed field to be appended to the end of the message's stream
-+ * @param q2_blocked Set to true if this call caused Q2 to block
- * @return The number of buffers stored in the message's content
- */
--int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field);
-+int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field, bool *q2_blocked);
-
-
- /**
-@@ -404,9 +404,10 @@ qd_message_stream_data_result_t qd_message_next_stream_data(qd_message_t *msg, q
- *
- * @param msg Pointer to message under construction
- * @param data List of buffers containing body data.
-+ * @param qd_blocked Set to true if this call caused Q2 to block
- * @return The number of buffers stored in the message's content
- */
--int qd_message_stream_data_append(qd_message_t *msg, qd_buffer_list_t *data);
-+int qd_message_stream_data_append(qd_message_t *msg, qd_buffer_list_t *data, bool *q2_blocked);
-
-
- /** Put string representation of a message suitable for logging in buffer.
-@@ -556,12 +557,22 @@ bool qd_message_Q2_holdoff_should_unblock(qd_message_t *msg);
- */
- bool qd_message_is_Q2_blocked(const qd_message_t *msg);
-
-+
- /**
-- * Return qd_link through which the message is being received.
-- * @param msg A pointer to the message
-- * @return the qd_link
-+ * Register a callback that will be invoked when the message has exited the Q2
-+ * blocking state. Note that the callback can be invoked on any I/O thread.
-+ * The callback must be thread safe.
-+ *
-+ * @param msg The message to monitor.
-+ * @param callback The method to invoke
-+ * @param context safe pointer holding the context
- */
--qd_link_t * qd_message_get_receiving_link(const qd_message_t *msg);
-+
-+typedef void (*qd_message_q2_unblocked_handler_t)(qd_alloc_safe_ptr_t context);
-+void qd_message_set_q2_unblocked_handler(qd_message_t *msg,
-+ qd_message_q2_unblocked_handler_t callback,
-+ qd_alloc_safe_ptr_t context);
-+void qd_message_clear_q2_unblocked_handler(qd_message_t *msg);
-
- /**
- * Return message aborted state
-diff --git a/src/adaptors/http1/http1_client.c b/src/adaptors/http1/http1_client.c
-index 1d17724d..27b25cde 100644
---- a/src/adaptors/http1/http1_client.c
-+++ b/src/adaptors/http1/http1_client.c
-@@ -860,7 +860,8 @@ static int _client_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
- "[C%"PRIu64"][L%"PRIu64"] HTTP request body received len=%zu.",
- hconn->conn_id, hconn->in_link_id, len);
-
-- qd_message_stream_data_append(msg, body);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(msg, body, 0);
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index 3f46e448..1ef6b2ab 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -976,7 +976,8 @@ static int _server_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
-
- qd_message_t *msg = rmsg->msg ? rmsg->msg : qdr_delivery_message(rmsg->dlv);
-
-- qd_message_stream_data_append(msg, body);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(msg, body, 0);
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
-index 2330ece8..25347e40 100644
---- a/src/adaptors/http2/http2_adaptor.c
-+++ b/src/adaptors/http2/http2_adaptor.c
-@@ -465,7 +465,8 @@ static int on_data_chunk_recv_callback(nghttp2_session *session,
- qd_buffer_list_t existing_buffers;
- DEQ_INIT(existing_buffers);
- qd_compose_take_buffers(stream_data->body, &existing_buffers);
-- qd_message_stream_data_append(stream_data->message, &existing_buffers);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(stream_data->message, &existing_buffers, 0);
- stream_data->body_data_added = true;
- }
- }
-@@ -475,7 +476,8 @@ static int on_data_chunk_recv_callback(nghttp2_session *session,
- stream_data->body = qd_compose(QD_PERFORMATIVE_BODY_DATA, 0);
- stream_data->body_data_added = true;
- }
-- qd_message_stream_data_append(stream_data->message, &buffers);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(stream_data->message, &buffers, 0);
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] HTTP2 DATA on_data_chunk_recv_callback qd_compose_insert_binary_buffers into stream_data->message", conn->conn_id, stream_id);
- }
- else {
-@@ -930,7 +932,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
- if (!stream_data->body) {
- stream_data->body = qd_compose(QD_PERFORMATIVE_BODY_DATA, 0);
- qd_compose_insert_binary(stream_data->body, 0, 0);
-- qd_message_extend(stream_data->message, stream_data->body);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_extend(stream_data->message, stream_data->body, 0);
- }
- }
-
-@@ -965,7 +968,8 @@ static int on_frame_recv_callback(nghttp2_session *session,
- if (stream_data->use_footer_properties) {
- qd_compose_end_map(stream_data->footer_properties);
- stream_data->entire_footer_arrived = true;
-- qd_message_extend(stream_data->message, stream_data->footer_properties);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_extend(stream_data->message, stream_data->footer_properties, 0);
- qd_log(http2_adaptor->protocol_log_source, QD_LOG_TRACE, "[C%"PRIu64"][S%"PRId32"] Closing footer map, extending message with footer", conn->conn_id, stream_id);
- }
- else {
-diff --git a/src/adaptors/reference_adaptor.c b/src/adaptors/reference_adaptor.c
-index 2fd3ff2e..9982ad04 100644
---- a/src/adaptors/reference_adaptor.c
-+++ b/src/adaptors/reference_adaptor.c
-@@ -497,7 +497,8 @@ static void on_stream(void *context)
- //
- // Extend the streaming message and free the composed field
- //
-- depth = qd_message_extend(adaptor->streaming_message, field);
-+ // TODO(kgiusti): need to handle Q2 blocking event
-+ depth = qd_message_extend(adaptor->streaming_message, field, 0);
- qd_compose_free(field);
- }
-
-@@ -519,7 +520,8 @@ static void on_stream(void *context)
- qd_compose_insert_symbol(footer, "second");
- qd_compose_insert_string(footer, "value2");
- qd_compose_end_map(footer);
-- depth = qd_message_extend(adaptor->streaming_message, footer);
-+ // @TODO(kgiusti): need to handle Q2 blocking event
-+ depth = qd_message_extend(adaptor->streaming_message, footer, 0);
- qd_compose_free(footer);
-
- qd_message_set_receive_complete(adaptor->streaming_message);
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index fce22192..6cc8855f 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -183,7 +183,8 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- grant_read_buffers(conn);
-
- if (conn->instream) {
-- qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers);
-+ // @TODO(kgiusti): handle Q2 block event:
-+ qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers, 0);
- qdr_delivery_continue(tcp_adaptor->core, conn->instream, false);
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Continuing message with %i bytes", conn->conn_id, conn->incoming_id, count);
- } else {
-diff --git a/src/alloc_pool.c b/src/alloc_pool.c
-index 284630ec..2ab65675 100644
---- a/src/alloc_pool.c
-+++ b/src/alloc_pool.c
-@@ -507,6 +507,10 @@ uint32_t qd_alloc_sequence(void *p)
- return 0;
-
- qd_alloc_item_t *item = ((qd_alloc_item_t*) p) - 1;
-+#ifdef QD_MEMORY_DEBUG
-+ // ensure p actually points to an alloc pool item
-+ assert(item->header == PATTERN_FRONT);
-+#endif
- return item->sequence;
- }
-
-diff --git a/src/message.c b/src/message.c
-index 3e86f544..f81d15e9 100644
---- a/src/message.c
-+++ b/src/message.c
-@@ -1020,7 +1020,8 @@ void qd_message_free(qd_message_t *in_msg)
- {
- if (!in_msg) return;
- uint32_t rc;
-- qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
-+ qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
-+ qd_message_q2_unblocker_t q2_unblock = {0};
-
- qd_buffer_list_free_buffers(&msg->ma_to_override);
- qd_buffer_list_free_buffers(&msg->ma_trace);
-@@ -1055,12 +1056,16 @@ void qd_message_free(qd_message_t *in_msg)
- && was_blocked
- && qd_message_Q2_holdoff_should_unblock(in_msg)) {
- content->q2_input_holdoff = false;
-- qd_link_restart_rx(qd_message_get_receiving_link(in_msg));
-+ q2_unblock = content->q2_unblocker;
- }
-
- UNLOCK(content->lock);
- }
-
-+ // the Q2 handler must be invoked outside the lock
-+ if (q2_unblock.handler)
-+ q2_unblock.handler(q2_unblock.context);
-+
- rc = sys_atomic_dec(&content->ref_count) - 1;
- if (rc == 0) {
- if (content->ma_field_iter_in)
-@@ -1320,7 +1325,14 @@ void qd_message_set_receive_complete(qd_message_t *in_msg)
- {
- if (!!in_msg) {
- qd_message_content_t *content = MSG_CONTENT(in_msg);
-+
-+ LOCK(content->lock);
-+
- content->receive_complete = true;
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
-+
-+ UNLOCK(content->lock);
- }
- }
-
-@@ -1384,7 +1396,6 @@ qd_message_t *discard_receive(pn_delivery_t *delivery,
- } else if (rc == PN_EOS || rc < 0) {
- // End of message or error: finalize message_receive handling
- msg->content->aborted = pn_delivery_aborted(delivery);
-- qd_nullify_safe_ptr(&msg->content->input_link_sp);
- pn_record_t *record = pn_delivery_attachments(delivery);
- pn_record_set(record, PN_DELIVERY_CTX, 0);
- if (msg->content->oversize) {
-@@ -1392,7 +1403,7 @@ qd_message_t *discard_receive(pn_delivery_t *delivery,
- // This has no effect on the received message.
- msg->content->aborted = true;
- }
-- msg->content->receive_complete = true;
-+ qd_message_set_receive_complete((qd_message_t*) msg);
- break;
- } else {
- // rc was > 0. bytes were read and discarded.
-@@ -1429,7 +1440,8 @@ qd_message_t *qd_message_receive(pn_delivery_t *delivery)
- if (!msg) {
- msg = (qd_message_pvt_t*) qd_message();
- qd_connection_t *qdc = qd_link_connection(qdl);
-- set_safe_ptr_qd_link_t(qdl, &msg->content->input_link_sp);
-+ qd_alloc_safe_ptr_t sp = QD_SAFE_PTR_INIT(qdl);
-+ qd_message_set_q2_unblocked_handler((qd_message_t*) msg, qd_link_q2_restart_receive, sp);
- msg->strip_annotations_in = qd_connection_strip_annotations_in(qdc);
- pn_record_def(record, PN_DELIVERY_CTX, PN_WEAKREF);
- pn_record_set(record, PN_DELIVERY_CTX, (void*) msg);
-@@ -1491,8 +1503,9 @@ qd_message_t *qd_message_receive(pn_delivery_t *delivery)
- }
-
- content->receive_complete = true;
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
- content->aborted = pn_delivery_aborted(delivery);
-- qd_nullify_safe_ptr(&content->input_link_sp);
-
- // unlink message and delivery
- pn_record_set(record, PN_DELIVERY_CTX, 0);
-@@ -1726,7 +1739,6 @@ static void compose_message_annotations(qd_message_pvt_t *msg, qd_buffer_list_t
- void qd_message_send(qd_message_t *in_msg,
- qd_link_t *link,
- bool strip_annotations,
-- bool *restart_rx,
- bool *q3_stalled)
- {
- qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg;
-@@ -1734,7 +1746,6 @@ void qd_message_send(qd_message_t *in_msg,
- qd_buffer_t *buf = 0;
- pn_link_t *pnl = qd_link_pn(link);
-
-- *restart_rx = false;
- *q3_stalled = false;
-
- if (msg->sent_depth < QD_DEPTH_MESSAGE_ANNOTATIONS) {
-@@ -1842,8 +1853,9 @@ void qd_message_send(qd_message_t *in_msg,
-
- buf = msg->cursor.buffer;
-
-- pn_session_t *pns = pn_link_session(pnl);
-- const size_t q3_upper = BUFFER_SIZE * QD_QLIMIT_Q3_UPPER;
-+ qd_message_q2_unblocker_t q2_unblock = {0};
-+ pn_session_t *pns = pn_link_session(pnl);
-+ const size_t q3_upper = BUFFER_SIZE * QD_QLIMIT_Q3_UPPER;
-
- while (!content->aborted
- && buf
-@@ -1913,7 +1925,7 @@ void qd_message_send(qd_message_t *in_msg,
- // set input holdoff before the deferred handler
- // runs.
- content->q2_input_holdoff = false;
-- *restart_rx = true;
-+ q2_unblock = content->q2_unblocker;
- }
- }
- } // end free buffer
-@@ -1940,6 +1952,10 @@ void qd_message_send(qd_message_t *in_msg,
- UNLOCK(content->lock);
- }
-
-+ // the Q2 handler must be invoked outside the lock
-+ if (q2_unblock.handler)
-+ q2_unblock.handler(q2_unblock.context);
-+
- if (content->aborted) {
- if (pn_link_current(pnl)) {
- msg->send_complete = true;
-@@ -2319,13 +2335,16 @@ void qd_message_compose_4(qd_message_t *msg, qd_composed_field_t *field1, qd_com
- }
-
-
--int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field)
-+int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field, bool *q2_blocked)
- {
- qd_message_content_t *content = MSG_CONTENT(msg);
- int count;
- qd_buffer_list_t *buffers = qd_compose_buffers(field);
- qd_buffer_t *buf = DEQ_HEAD(*buffers);
-
-+ if (q2_blocked)
-+ *q2_blocked = false;
-+
- LOCK(content->lock);
- while (buf) {
- qd_buffer_set_fanout(buf, content->fanout);
-@@ -2334,6 +2353,14 @@ int qd_message_extend(qd_message_t *msg, qd_composed_field_t *field)
-
- DEQ_APPEND(content->buffers, (*buffers));
- count = DEQ_SIZE(content->buffers);
-+
-+ // buffers added - much check for Q2:
-+ if (qd_message_Q2_holdoff_should_block(msg)) {
-+ content->q2_input_holdoff = true;
-+ if (q2_blocked)
-+ *q2_blocked = true;
-+ }
-+
- UNLOCK(content->lock);
- return count;
- }
-@@ -2549,7 +2576,8 @@ void qd_message_stream_data_release(qd_message_stream_data_t *stream_data)
-
- LOCK(content->lock);
-
-- bool was_blocked = !qd_message_Q2_holdoff_should_unblock((qd_message_t*) pvt);
-+ bool was_blocked = !qd_message_Q2_holdoff_should_unblock((qd_message_t*) pvt);
-+ qd_message_q2_unblocker_t q2_unblock = {0};
-
- if (pvt->is_fanout) {
- buf = start_buf;
-@@ -2581,13 +2609,16 @@ void qd_message_stream_data_release(qd_message_stream_data_t *stream_data)
- && was_blocked
- && qd_message_Q2_holdoff_should_unblock((qd_message_t*) pvt)) {
- content->q2_input_holdoff = false;
-- qd_link_restart_rx(qd_message_get_receiving_link((qd_message_t*) pvt));
-+ q2_unblock = content->q2_unblocker;
- }
-
- UNLOCK(content->lock);
-
- DEQ_REMOVE(pvt->stream_data_list, stream_data);
- free_qd_message_stream_data_t(stream_data);
-+
-+ if (q2_unblock.handler)
-+ q2_unblock.handler(q2_unblock.context);
- }
-
-
-@@ -2820,12 +2851,6 @@ bool qd_message_is_Q2_blocked(const qd_message_t *msg)
- }
-
-
--qd_link_t * qd_message_get_receiving_link(const qd_message_t *msg)
--{
-- return safe_deref_qd_link_t(((qd_message_pvt_t *)msg)->content->input_link_sp);
--}
--
--
- bool qd_message_aborted(const qd_message_t *msg)
- {
- return ((qd_message_pvt_t *)msg)->content->aborted;
-@@ -2847,12 +2872,15 @@ bool qd_message_oversize(const qd_message_t *msg)
- }
-
-
--int qd_message_stream_data_append(qd_message_t *message, qd_buffer_list_t *data)
-+int qd_message_stream_data_append(qd_message_t *message, qd_buffer_list_t *data, bool *q2_blocked)
- {
- unsigned int length = DEQ_SIZE(*data);
- qd_composed_field_t *field = 0;
- int rc = 0;
-
-+ if (q2_blocked)
-+ *q2_blocked = false;
-+
- if (length == 0)
- return rc;
-
-@@ -2887,7 +2915,35 @@ int qd_message_stream_data_append(qd_message_t *message, qd_buffer_list_t *data)
- field = qd_compose(QD_PERFORMATIVE_BODY_DATA, field);
- qd_compose_insert_binary_buffers(field, data);
-
-- rc = qd_message_extend(message, field);
-+ rc = qd_message_extend(message, field, q2_blocked);
- qd_compose_free(field);
- return rc;
- }
-+
-+
-+void qd_message_set_q2_unblocked_handler(qd_message_t *msg,
-+ qd_message_q2_unblocked_handler_t callback,
-+ qd_alloc_safe_ptr_t context)
-+{
-+ qd_message_content_t *content = MSG_CONTENT(msg);
-+
-+ LOCK(content->lock);
-+
-+ content->q2_unblocker.handler = callback;
-+ content->q2_unblocker.context = context;
-+
-+ UNLOCK(content->lock);
-+}
-+
-+
-+void qd_message_clear_Q2_unblocked_handler(qd_message_t *msg)
-+{
-+ qd_message_content_t *content = MSG_CONTENT(msg);
-+
-+ LOCK(content->lock);
-+
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
-+
-+ UNLOCK(content->lock);
-+}
-diff --git a/src/message_private.h b/src/message_private.h
-index a8067c77..c4262a98 100644
---- a/src/message_private.h
-+++ b/src/message_private.h
-@@ -73,6 +73,13 @@ struct qd_message_stream_data_t {
- ALLOC_DECLARE(qd_message_stream_data_t);
- DEQ_DECLARE(qd_message_stream_data_t, qd_message_stream_data_list_t);
-
-+
-+typedef struct {
-+ qd_message_q2_unblocked_handler_t handler;
-+ qd_alloc_safe_ptr_t context;
-+} qd_message_q2_unblocker_t;
-+
-+
- // TODO - consider using pointers to qd_field_location_t below to save memory
- // TODO - provide a way to allocate a message without a lock for the link-routing case.
- // It's likely that link-routing will cause no contention for the message content.
-@@ -126,7 +133,8 @@ typedef struct {
- uint64_t max_message_size; // configured max; 0 if no max to enforce
- uint64_t bytes_received; // bytes returned by pn_link_recv() when enforcing max_message_size
- uint32_t fanout; // The number of receivers for this message, including in-process subscribers.
-- qd_link_t_sp input_link_sp; // message received on this link
-+
-+ qd_message_q2_unblocker_t q2_unblocker; // callback and context to signal Q2 unblocked to receiver
-
- bool ma_parsed; // have parsed annotations in incoming message
- bool discard; // Should this message be discarded?
-diff --git a/src/router_node.c b/src/router_node.c
-index 7dbdb0d6..70d98f91 100644
---- a/src/router_node.c
-+++ b/src/router_node.c
-@@ -855,6 +855,7 @@ static void deferred_AMQP_rx_handler(void *context, bool discard)
- if (!discard) {
- qd_link_t *qdl = safe_deref_qd_link_t(*safe_qdl);
- if (!!qdl) {
-+ assert(qd_link_direction(qdl) == QD_INCOMING);
- qd_router_t *qdr = (qd_router_t*) qd_link_get_node_context(qdl);
- assert(qdr != 0);
- while (true) {
-@@ -1914,22 +1915,17 @@ static uint64_t CORE_link_deliver(void *context, qdr_link_t *link, qdr_delivery_
- if (!pdlv)
- return 0;
-
-- bool restart_rx = false;
- bool q3_stalled = false;
-
- qd_message_t *msg_out = qdr_delivery_message(dlv);
-
-- qd_message_send(msg_out, qlink, qdr_link_strip_annotations_out(link), &restart_rx, &q3_stalled);
-+ qd_message_send(msg_out, qlink, qdr_link_strip_annotations_out(link), &q3_stalled);
-
- if (q3_stalled) {
- qd_link_q3_block(qlink);
- qdr_link_stalled_outbound(link);
- }
-
-- if (restart_rx) {
-- qd_link_restart_rx(qd_message_get_receiving_link(msg_out));
-- }
--
- bool send_complete = qdr_delivery_send_complete(dlv);
-
- if (send_complete) {
-@@ -2059,7 +2055,10 @@ static void CORE_delivery_update(void *context, qdr_delivery_t *dlv, uint64_t di
- // and if it is blocked by Q2 holdoff, get the link rolling again.
- //
- qd_message_Q2_holdoff_disable(msg);
-- qd_link_restart_rx(link);
-+
-+ qd_link_t_sp *safe_ptr = NEW(qd_link_t_sp);
-+ set_safe_ptr_qd_link_t(link, safe_ptr);
-+ qd_connection_invoke_deferred(qd_conn, deferred_AMQP_rx_handler, safe_ptr);
- }
- }
- }
-@@ -2131,10 +2130,13 @@ qdr_core_t *qd_router_core(qd_dispatch_t *qd)
- }
-
-
--// called when Q2 holdoff is deactivated so we can receive more message buffers
-+// invoked by an I/O thread when enough buffers have been released deactivate
-+// the Q2 block. Note that this method will likely be running on a worker
-+// thread that is not the same thread that "owns" the qd_link_t passed in.
- //
--void qd_link_restart_rx(qd_link_t *in_link)
-+void qd_link_q2_restart_receive(qd_alloc_safe_ptr_t context)
- {
-+ qd_link_t *in_link = (qd_link_t*) qd_alloc_deref_safe_ptr(&context);
- if (!in_link)
- return;
-
-@@ -2142,8 +2144,8 @@ void qd_link_restart_rx(qd_link_t *in_link)
-
- qd_connection_t *in_conn = qd_link_connection(in_link);
- if (in_conn) {
-- qd_link_t_sp *safe_ptr = NEW(qd_link_t_sp);
-- set_safe_ptr_qd_link_t(in_link, safe_ptr);
-+ qd_link_t_sp *safe_ptr = NEW(qd_alloc_safe_ptr_t);
-+ *safe_ptr = context; // use original to keep old sequence counter
- qd_connection_invoke_deferred(in_conn, deferred_AMQP_rx_handler, safe_ptr);
- }
- }
-diff --git a/tests/message_test.c b/tests/message_test.c
-index 7da011c5..18a22b09 100644
---- a/tests/message_test.c
-+++ b/tests/message_test.c
-@@ -738,7 +738,7 @@ static void stream_data_generate_message(qd_message_t *msg, char *s_chunk_size,
- // the buffers in 'field' are inserted into message 'msg'.
- qd_composed_field_t *field = qd_compose(QD_PERFORMATIVE_BODY_DATA, 0);
- qd_compose_insert_binary_buffers(field, &mule_content->buffers);
-- qd_message_extend(msg, field);
-+ qd_message_extend(msg, field, 0);
-
- // Clean up temporary resources
- free(buf2);
-@@ -979,13 +979,20 @@ static char *test_check_stream_data_append(void * context)
- // snapshot the message buffer count to use as a baseline
- const size_t base_bufct = DEQ_SIZE(MSG_CONTENT(msg)->buffers);
-
-- int depth = qd_message_stream_data_append(msg, &bin_data);
-+ bool blocked;
-+ int depth = qd_message_stream_data_append(msg, &bin_data, &blocked);
- if (depth <= body_bufct) {
- // expected to add extra buffer(s) for meta-data
- result = "append length is incorrect";
- goto exit;
- }
-
-+ // expected that the append has triggered Q2 blocking:
-+ if (!blocked) {
-+ result = "expected Q2 block event did not occur!";
-+ goto exit;
-+ }
-+
- // And while we're at it, stuff in a footer
- field = qd_compose(QD_PERFORMATIVE_FOOTER, 0);
- qd_compose_start_map(field);
-@@ -994,7 +1001,7 @@ static char *test_check_stream_data_append(void * context)
- qd_compose_insert_symbol(field, "Key2");
- qd_compose_insert_string(field, "Value2");
- qd_compose_end_map(field);
-- qd_message_extend(msg, field);
-+ qd_message_extend(msg, field, 0);
- qd_compose_free(field);
-
- qd_message_set_receive_complete(msg);
-@@ -1123,7 +1130,7 @@ static char *test_check_stream_data_fanout(void *context)
- memset(buffer, '5', 1001);
- qd_compose_insert_binary(field, buffer, 5);
-
-- qd_message_extend(in_msg, field);
-+ qd_message_extend(in_msg, field, 0);
- qd_compose_free(field);
-
- qd_message_set_receive_complete(in_msg);
-@@ -1232,6 +1239,7 @@ static char *test_check_stream_data_footer(void *context)
- const size_t base_bufct = DEQ_SIZE(MSG_CONTENT(in_msg)->buffers);
-
- // Append a footer
-+ bool q2_blocked;
- field = qd_compose(QD_PERFORMATIVE_FOOTER, 0);
- qd_compose_start_map(field);
- qd_compose_insert_symbol(field, "Key1");
-@@ -1239,9 +1247,16 @@ static char *test_check_stream_data_footer(void *context)
- qd_compose_insert_symbol(field, "Key2");
- qd_compose_insert_string(field, "Value2");
- qd_compose_end_map(field);
-- qd_message_extend(in_msg, field);
-+ qd_message_extend(in_msg, field, &q2_blocked);
- qd_compose_free(field);
-
-+ // this small message should not have triggered Q2
-+ assert(DEQ_SIZE(MSG_CONTENT(in_msg)->buffers) < QD_QLIMIT_Q2_UPPER);
-+ if (q2_blocked) {
-+ result = "Unexpected Q2 block on message extend";
-+ goto exit;
-+ }
-+
- qd_message_set_receive_complete(in_msg);
-
- // "fan out" the message
---
-2.20.1
-
-From 48b0157f3de58eb2d9c69e448e2c4affb0a1c04a Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Thu, 11 Feb 2021 16:24:28 -0500
-Subject: [PATCH 09/16] DISPATCH-1961: Enable Q2 flow control for HTTP/1.x
- adaptor
-
-This closes #1029
----
- src/adaptors/http1/http1_adaptor.c | 21 +++
- src/adaptors/http1/http1_client.c | 86 ++++++++--
- src/adaptors/http1/http1_private.h | 4 +-
- src/adaptors/http1/http1_server.c | 107 +++++++++---
- src/message.c | 14 +-
- tests/system_test.py | 4 +
- tests/system_tests_http1_adaptor.py | 253 +++++++++++++++++++++++++++-
- 7 files changed, 437 insertions(+), 52 deletions(-)
-
-diff --git a/src/adaptors/http1/http1_adaptor.c b/src/adaptors/http1/http1_adaptor.c
-index 6ce1eadf..9e4eeb6f 100644
---- a/src/adaptors/http1/http1_adaptor.c
-+++ b/src/adaptors/http1/http1_adaptor.c
-@@ -119,6 +119,8 @@ void qdr_http1_connection_free(qdr_http1_connection_t *hconn)
- pn_raw_connection_close(rconn);
- }
-
-+ sys_atomic_destroy(&hconn->q2_restart);
-+
- free(hconn->cfg.host);
- free(hconn->cfg.port);
- free(hconn->cfg.address);
-@@ -415,6 +417,25 @@ void qdr_http1_free_written_buffers(qdr_http1_connection_t *hconn)
- }
-
-
-+// Per-message callback to resume receiving after Q2 is unblocked on the
-+// incoming link (to HTTP app). This routine runs on another I/O thread so it
-+// must be thread safe!
-+//
-+void qdr_http1_q2_unblocked_handler(const qd_alloc_safe_ptr_t context)
-+{
-+ // prevent the hconn from being deleted while running:
-+ sys_mutex_lock(qdr_http1_adaptor->lock);
-+
-+ qdr_http1_connection_t *hconn = (qdr_http1_connection_t*)qd_alloc_deref_safe_ptr(&context);
-+ if (hconn && hconn->raw_conn) {
-+ sys_atomic_set(&hconn->q2_restart, 1);
-+ pn_raw_connection_wake(hconn->raw_conn);
-+ }
-+
-+ sys_mutex_unlock(qdr_http1_adaptor->lock);
-+}
-+
-+
- //
- // Protocol Adaptor Callbacks
- //
-diff --git a/src/adaptors/http1/http1_client.c b/src/adaptors/http1/http1_client.c
-index 27b25cde..ff033807 100644
---- a/src/adaptors/http1/http1_client.c
-+++ b/src/adaptors/http1/http1_client.c
-@@ -133,6 +133,7 @@ static qdr_http1_connection_t *_create_client_connection(qd_http_listener_t *li)
- hconn->adaptor = qdr_http1_adaptor;
- hconn->handler_context.handler = &_handle_connection_events;
- hconn->handler_context.context = hconn;
-+ sys_atomic_init(&hconn->q2_restart, 0);
-
- hconn->client.next_msg_id = 1;
-
-@@ -364,6 +365,36 @@ static void _setup_client_connection(qdr_http1_connection_t *hconn)
- }
-
-
-+// handle PN_RAW_CONNECTION_READ
-+static int _handle_conn_read_event(qdr_http1_connection_t *hconn)
-+{
-+ int error = 0;
-+ qd_buffer_list_t blist;
-+ uintmax_t length;
-+ qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
-+ if (length) {
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_DEBUG,
-+ "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from client (%zu buffers)",
-+ hconn->conn_id, hconn->in_link_id, length, DEQ_SIZE(blist));
-+ hconn->in_http1_octets += length;
-+ error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ }
-+ return error;
-+}
-+
-+
-+// handle PN_RAW_CONNECTION_NEED_READ_BUFFERS
-+static void _handle_conn_need_read_buffers(qdr_http1_connection_t *hconn)
-+{
-+ // @TODO(kgiusti): backpressure if no credit
-+ if (hconn->client.reply_to_addr || hconn->cfg.event_channel /* && hconn->in_link_credit > 0 */) {
-+ int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-+ hconn->conn_id, granted);
-+ }
-+}
-+
-+
- // Proton Connection Event Handler
- //
- static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, void *context)
-@@ -424,31 +455,34 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- }
- case PN_RAW_CONNECTION_NEED_READ_BUFFERS: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Need read buffers", hconn->conn_id);
-- // @TODO(kgiusti): backpressure if no credit
-- if (hconn->client.reply_to_addr || hconn->cfg.event_channel /* && hconn->in_link_credit > 0 */) {
-- int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-- hconn->conn_id, granted);
-- }
-+ _handle_conn_need_read_buffers(hconn);
- break;
- }
- case PN_RAW_CONNECTION_WAKE: {
-+ int error = 0;
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Wake-up", hconn->conn_id);
-+
-+ if (sys_atomic_set(&hconn->q2_restart, 0)) {
-+ // note: unit tests grep for this log!
-+ qd_log(log, QD_LOG_TRACE, "[C%"PRIu64"] client link unblocked from Q2 limit", hconn->conn_id);
-+ hconn->q2_blocked = false;
-+ error = _handle_conn_read_event(hconn); // restart receiving
-+ _handle_conn_need_read_buffers(hconn);
-+ }
-+
- while (qdr_connection_process(hconn->qdr_conn)) {}
-+
-+ if (error)
-+ qdr_http1_close_connection(hconn, "Incoming request message failed to parse");
-+
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Processing done", hconn->conn_id);
- break;
- }
- case PN_RAW_CONNECTION_READ: {
-- qd_buffer_list_t blist;
-- uintmax_t length;
-- qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
-- if (length) {
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from client",
-- hconn->conn_id, hconn->in_link_id, length);
-- hconn->in_http1_octets += length;
-- int error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ if (!hconn->q2_blocked) {
-+ int error = _handle_conn_read_event(hconn);
- if (error)
-- qdr_http1_close_connection(hconn, "Incoming request message failed to parse");
-+ qdr_http1_close_connection(hconn, "Incoming response message failed to parse");
- }
- break;
- }
-@@ -581,7 +615,7 @@ static void _client_tx_buffers_cb(h1_codec_request_state_t *hrs, qd_buffer_list_
- }
-
- qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE,
-- "[C%"PRIu64"][L%"PRIu64"] %u request octets encoded",
-+ "[C%"PRIu64"][L%"PRIu64"] %u response octets encoded",
- hconn->conn_id, hconn->out_link_id, len);
-
-
-@@ -825,6 +859,13 @@ static int _client_rx_headers_done_cb(h1_codec_request_state_t *hrs, bool has_bo
- qd_compose_free(hreq->request_props);
- hreq->request_props = 0;
-
-+ // future-proof: ensure the message headers have not caused Q2
-+ // blocking. We only check for Q2 events while adding body data.
-+ assert(!qd_message_is_Q2_blocked(hreq->request_msg));
-+
-+ qd_alloc_safe_ptr_t hconn_sp = QD_SAFE_PTR_INIT(hconn);
-+ qd_message_set_q2_unblocked_handler(hreq->request_msg, qdr_http1_q2_unblocked_handler, hconn_sp);
-+
- // Use up one credit to obtain a delivery and forward to core. If no
- // credit is available the request is stalled until the core grants more
- // flow.
-@@ -848,6 +889,7 @@ static int _client_rx_headers_done_cb(h1_codec_request_state_t *hrs, bool has_bo
- static int _client_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *body, size_t len,
- bool more)
- {
-+ bool q2_blocked = false;
- _client_request_t *hreq = (_client_request_t*) h1_codec_request_state_get_context(hrs);
- qdr_http1_connection_t *hconn = hreq->base.hconn;
- if (hconn->cfg.event_channel && strcasecmp(h1_codec_request_state_method(hrs), POST_METHOD) != 0) {
-@@ -860,8 +902,12 @@ static int _client_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
- "[C%"PRIu64"][L%"PRIu64"] HTTP request body received len=%zu.",
- hconn->conn_id, hconn->in_link_id, len);
-
-- // @TODO(kgiusti): handle Q2 block event:
-- qd_message_stream_data_append(msg, body, 0);
-+ qd_message_stream_data_append(msg, body, &q2_blocked);
-+ hconn->q2_blocked = hconn->q2_blocked || q2_blocked;
-+ if (q2_blocked) {
-+ // note: unit tests grep for this log!
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE, "[C%"PRIu64"] client link blocked on Q2 limit", hconn->conn_id);
-+ }
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-@@ -1635,6 +1681,10 @@ static void _write_pending_response(_client_request_t *hreq)
- static void _client_request_free(_client_request_t *hreq)
- {
- if (hreq) {
-+ // deactivate the Q2 callback
-+ qd_message_t *msg = hreq->request_dlv ? qdr_delivery_message(hreq->request_dlv) : hreq->request_msg;
-+ qd_message_clear_q2_unblocked_handler(msg);
-+
- qdr_http1_request_base_cleanup(&hreq->base);
- qd_message_free(hreq->request_msg);
- if (hreq->request_dlv) {
-diff --git a/src/adaptors/http1/http1_private.h b/src/adaptors/http1/http1_private.h
-index 858efb5d..5ecf4fdf 100644
---- a/src/adaptors/http1/http1_private.h
-+++ b/src/adaptors/http1/http1_private.h
-@@ -172,6 +172,8 @@ struct qdr_http1_connection_t {
- qdr_link_t *in_link;
- uint64_t in_link_id;
- int in_link_credit; // provided by router
-+ sys_atomic_t q2_restart; // signal to resume receive
-+ bool q2_blocked; // stop reading from raw conn
-
- // Oldest at HEAD
- //
-@@ -220,7 +222,7 @@ void qdr_http1_error_response(qdr_http1_request_base_t *hreq,
- const char *reason);
- void qdr_http1_rejected_response(qdr_http1_request_base_t *hreq,
- const qdr_error_t *error);
--
-+void qdr_http1_q2_unblocked_handler(const qd_alloc_safe_ptr_t context);
-
- // http1_client.c protocol adaptor callbacks
- //
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index 1ef6b2ab..c1fb17b0 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -152,6 +152,7 @@ static qdr_http1_connection_t *_create_server_connection(qd_http_connector_t *ct
- hconn->adaptor = qdr_http1_adaptor;
- hconn->handler_context.handler = &_handle_connection_events;
- hconn->handler_context.context = hconn;
-+ sys_atomic_init(&hconn->q2_restart, 0);
- hconn->cfg.host = qd_strdup(bconfig->host);
- hconn->cfg.port = qd_strdup(bconfig->port);
- hconn->cfg.address = qd_strdup(bconfig->address);
-@@ -466,6 +467,48 @@ static void _accept_and_settle_request(_server_request_t *hreq)
- hreq->request_settled = true;
- }
-
-+
-+// handle PN_RAW_CONNECTION_READ
-+static int _handle_conn_read_event(qdr_http1_connection_t *hconn)
-+{
-+ int error = 0;
-+ qd_buffer_list_t blist;
-+ uintmax_t length;
-+
-+ qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
-+
-+ if (HTTP1_DUMP_BUFFERS) {
-+ fprintf(stdout, "\nServer raw buffer READ %"PRIuMAX" total octets\n", length);
-+ qd_buffer_t *bb = DEQ_HEAD(blist);
-+ while (bb) {
-+ fprintf(stdout, " buffer='%.*s'\n", (int)qd_buffer_size(bb), (char*)&bb[1]);
-+ bb = DEQ_NEXT(bb);
-+ }
-+ fflush(stdout);
-+ }
-+
-+ if (length) {
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE,
-+ "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from server (%zu buffers)",
-+ hconn->conn_id, hconn->in_link_id, length, DEQ_SIZE(blist));
-+ hconn->in_http1_octets += length;
-+ error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ }
-+ return error;
-+}
-+
-+
-+// handle PN_RAW_CONNECTION_NEED_READ_BUFFERS
-+static void _handle_conn_need_read_buffers(qdr_http1_connection_t *hconn)
-+{
-+ // @TODO(kgiusti): backpressure if no credit
-+ // if (hconn->in_link_credit > 0 */)
-+ int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-+ hconn->conn_id, granted);
-+}
-+
-+
- // Proton Raw Connection Events
- //
- static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, void *context)
-@@ -490,6 +533,7 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- // message (response body terminated on connection closed)
- h1_codec_connection_rx_closed(hconn->http_conn);
- pn_raw_connection_close(hconn->raw_conn);
-+ hconn->q2_blocked = false;
- break;
- }
-
-@@ -557,39 +601,32 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- break;
- }
- case PN_RAW_CONNECTION_NEED_READ_BUFFERS: {
-- // @TODO(kgiusti): backpressure if no credit
-- // if (hconn->in_link_credit > 0 */)
-- int granted = qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] %d read buffers granted",
-- hconn->conn_id, granted);
-+ _handle_conn_need_read_buffers(hconn);
- break;
- }
- case PN_RAW_CONNECTION_WAKE: {
-+ int error = 0;
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Wake-up", hconn->conn_id);
-+
-+ if (sys_atomic_set(&hconn->q2_restart, 0)) {
-+ // note: unit tests grep for this log!
-+ qd_log(log, QD_LOG_TRACE, "[C%"PRIu64"] server link unblocked from Q2 limit", hconn->conn_id);
-+ hconn->q2_blocked = false;
-+ error = _handle_conn_read_event(hconn); // restart receiving
-+ _handle_conn_need_read_buffers(hconn);
-+ }
-+
- while (qdr_connection_process(hconn->qdr_conn)) {}
-+
-+ if (error)
-+ qdr_http1_close_connection(hconn, "Incoming response message failed to parse");
-+
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] Connection processing complete", hconn->conn_id);
- break;
- }
- case PN_RAW_CONNECTION_READ: {
-- qd_buffer_list_t blist;
-- uintmax_t length;
-- qda_raw_conn_get_read_buffers(hconn->raw_conn, &blist, &length);
--
-- if (HTTP1_DUMP_BUFFERS) {
-- fprintf(stdout, "\nServer raw buffer READ %"PRIuMAX" total octets\n", length);
-- qd_buffer_t *bb = DEQ_HEAD(blist);
-- while (bb) {
-- fprintf(stdout, " buffer='%.*s'\n", (int)qd_buffer_size(bb), (char*)&bb[1]);
-- bb = DEQ_NEXT(bb);
-- }
-- fflush(stdout);
-- }
--
-- if (length) {
-- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Read %"PRIuMAX" bytes from server",
-- hconn->conn_id, hconn->in_link_id, length);
-- hconn->in_http1_octets += length;
-- int error = h1_codec_connection_rx_data(hconn->http_conn, &blist, length);
-+ if (!hconn->q2_blocked) {
-+ int error = _handle_conn_read_event(hconn);
- if (error)
- qdr_http1_close_connection(hconn, "Incoming response message failed to parse");
- }
-@@ -934,6 +971,13 @@ static int _server_rx_headers_done_cb(h1_codec_request_state_t *hrs, bool has_bo
- qd_compose_free(rmsg->msg_props);
- rmsg->msg_props = 0;
-
-+ // future-proof: ensure the message headers have not caused Q2
-+ // blocking. We only check for Q2 events while adding body data.
-+ assert(!qd_message_is_Q2_blocked(rmsg->msg));
-+
-+ qd_alloc_safe_ptr_t hconn_sp = QD_SAFE_PTR_INIT(hconn);
-+ qd_message_set_q2_unblocked_handler(rmsg->msg, qdr_http1_q2_unblocked_handler, hconn_sp);
-+
- // start delivery if possible
- if (hconn->in_link_credit > 0 && rmsg == DEQ_HEAD(hreq->responses)) {
- hconn->in_link_credit -= 1;
-@@ -962,6 +1006,7 @@ static int _server_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
- {
- _server_request_t *hreq = (_server_request_t*) h1_codec_request_state_get_context(hrs);
- qdr_http1_connection_t *hconn = hreq->base.hconn;
-+ bool q2_blocked = false;
-
- qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE,
- "[C%"PRIu64"][L%"PRIu64"] HTTP response body received len=%zu.",
-@@ -976,8 +1021,13 @@ static int _server_rx_body_cb(h1_codec_request_state_t *hrs, qd_buffer_list_t *b
-
- qd_message_t *msg = rmsg->msg ? rmsg->msg : qdr_delivery_message(rmsg->dlv);
-
-- // @TODO(kgiusti): handle Q2 block event:
-- qd_message_stream_data_append(msg, body, 0);
-+
-+ qd_message_stream_data_append(msg, body, &q2_blocked);
-+ hconn->q2_blocked = hconn->q2_blocked || q2_blocked;
-+ if (q2_blocked) {
-+ // note: unit tests grep for this log!
-+ qd_log(qdr_http1_adaptor->log, QD_LOG_TRACE, "[C%"PRIu64"] server link blocked on Q2 limit", hconn->conn_id);
-+ }
-
- //
- // Notify the router that more data is ready to be pushed out on the delivery
-@@ -1518,6 +1568,11 @@ uint64_t qdr_http1_server_core_link_deliver(qdr_http1_adaptor_t *adaptor,
- static void _server_response_msg_free(_server_request_t *hreq, _server_response_msg_t *rmsg)
- {
- DEQ_REMOVE(hreq->responses, rmsg);
-+
-+ // deactivate the Q2 callback
-+ qd_message_t *msg = rmsg->dlv ? qdr_delivery_message(rmsg->dlv) : rmsg->msg;
-+ qd_message_clear_q2_unblocked_handler(msg);
-+
- qd_message_free(rmsg->msg);
- qd_compose_free(rmsg->msg_props);
- if (rmsg->dlv) {
-diff --git a/src/message.c b/src/message.c
-index f81d15e9..16794075 100644
---- a/src/message.c
-+++ b/src/message.c
-@@ -2936,14 +2936,16 @@ void qd_message_set_q2_unblocked_handler(qd_message_t *msg,
- }
-
-
--void qd_message_clear_Q2_unblocked_handler(qd_message_t *msg)
-+void qd_message_clear_q2_unblocked_handler(qd_message_t *msg)
- {
-- qd_message_content_t *content = MSG_CONTENT(msg);
-+ if (msg) {
-+ qd_message_content_t *content = MSG_CONTENT(msg);
-
-- LOCK(content->lock);
-+ LOCK(content->lock);
-
-- content->q2_unblocker.handler = 0;
-- qd_nullify_safe_ptr(&content->q2_unblocker.context);
-+ content->q2_unblocker.handler = 0;
-+ qd_nullify_safe_ptr(&content->q2_unblocker.context);
-
-- UNLOCK(content->lock);
-+ UNLOCK(content->lock);
-+ }
- }
-diff --git a/tests/system_test.py b/tests/system_test.py
-index bab62c42..5fec0914 100755
---- a/tests/system_test.py
-+++ b/tests/system_test.py
-@@ -733,6 +733,10 @@ class Qdrouterd(Process):
- def wait_router_connected(self, router_id, **retry_kwargs):
- retry(lambda: self.is_router_connected(router_id), **retry_kwargs)
-
-+ @property
-+ def logfile_path(self):
-+ return os.path.join(self.outdir, self.logfile)
-+
-
- class Tester(object):
- """Tools for use by TestCase
-diff --git a/tests/system_tests_http1_adaptor.py b/tests/system_tests_http1_adaptor.py
-index c182a3dd..9e6776ac 100644
---- a/tests/system_tests_http1_adaptor.py
-+++ b/tests/system_tests_http1_adaptor.py
-@@ -27,10 +27,13 @@ from __future__ import absolute_import
- from __future__ import print_function
-
-
-+import errno
-+import io
-+import select
- import socket
- import sys
- from threading import Thread
--from time import sleep
-+from time import sleep, time
- import uuid
- try:
- from http.server import HTTPServer, BaseHTTPRequestHandler
-@@ -1705,5 +1708,253 @@ class Http1AdaptorBadEndpointsTest(TestCase):
- self.assertEqual(1, count)
-
-
-+
-+class Http1AdaptorQ2Standalone(TestCase):
-+ """
-+ Force Q2 blocking/recovery on both client and server endpoints. This test
-+ uses a single router to ensure both client facing and server facing
-+ Q2 components of the HTTP/1.x adaptor are triggered.
-+ """
-+ @classmethod
-+ def setUpClass(cls):
-+ """
-+ Single router configuration with one HTTPListener and one
-+ HTTPConnector.
-+ """
-+ super(Http1AdaptorQ2Standalone, cls).setUpClass()
-+
-+ cls.http_server_port = cls.tester.get_port()
-+ cls.http_listener_port = cls.tester.get_port()
-+
-+ config = [
-+ ('router', {'mode': 'standalone',
-+ 'id': 'RowdyRoddyRouter',
-+ 'allowUnsettledMulticast': 'yes'}),
-+ ('listener', {'role': 'normal',
-+ 'port': cls.tester.get_port()}),
-+ ('httpListener', {'port': cls.http_listener_port,
-+ 'protocolVersion': 'HTTP1',
-+ 'address': 'testServer'}),
-+ ('httpConnector', {'port': cls.http_server_port,
-+ 'protocolVersion': 'HTTP1',
-+ 'address': 'testServer'}),
-+ ('address', {'prefix': 'closest', 'distribution': 'closest'}),
-+ ('address', {'prefix': 'multicast', 'distribution': 'multicast'}),
-+ ]
-+ config = Qdrouterd.Config(config)
-+ cls.INT_A = cls.tester.qdrouterd("TestBadEndpoints", config, wait=True)
-+ cls.INT_A.listener = cls.INT_A.addresses[0]
-+
-+
-+ def _write_until_full(self, sock, data, timeout):
-+ """
-+ Write data to socket until either all data written or timeout.
-+ Return the number of bytes written, which will == len(data) if timeout
-+ not hit
-+ """
-+ sock.setblocking(0)
-+ sent = 0
-+
-+ while sent < len(data):
-+ try:
-+ _, rw, _ = select.select([], [sock], [], timeout)
-+ except select.error as serror:
-+ if serror[0] == errno.EINTR:
-+ print("ignoring interrupt from select(): %s" % str(serror))
-+ continue
-+ raise # assuming fatal...
-+ if rw:
-+ sent += sock.send(data[sent:])
-+ else:
-+ break # timeout
-+ return sent
-+
-+ def _read_until_empty(self, sock, timeout):
-+ """
-+ Read data from socket until timeout occurs. Return read data.
-+ """
-+ sock.setblocking(0)
-+ data = b''
-+
-+ while True:
-+ try:
-+ rd, _, _ = select.select([sock], [], [], timeout)
-+ except select.error as serror:
-+ if serror[0] == errno.EINTR:
-+ print("ignoring interrupt from select(): %s" % str(serror))
-+ continue
-+ raise # assuming fatal...
-+ if rd:
-+ data += sock.recv(4096)
-+ else:
-+ break # timeout
-+ return data
-+
-+ def test_01_backpressure_client(self):
-+ """
-+ Trigger Q2 backpressure against the HTTP client.
-+ """
-+
-+ # create a listener socket to act as the server service
-+ server_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ server_listener.settimeout(TIMEOUT)
-+ server_listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-+ server_listener.bind(('', self.http_server_port))
-+ server_listener.listen(1)
-+
-+ # block until router connects
-+ server_sock, host_port = server_listener.accept()
-+ server_sock.settimeout(0.5)
-+ server_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+
-+ # create a client connection to the router
-+ client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ client_sock.settimeout(0.5)
-+ client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+ client_sock.connect((host_port[0], self.http_listener_port))
-+
-+ # send a Very Large PUSH request, expecting it to block at some point
-+
-+ push_req_hdr = b'PUSH / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n'
-+ count = self._write_until_full(client_sock, push_req_hdr, 1.0)
-+ self.assertEqual(len(push_req_hdr), count)
-+
-+ chunk = b'8000\r\n' + b'X' * 0x8000 + b'\r\n'
-+ last_chunk = b'0 \r\n\r\n'
-+ count = 0
-+ deadline = time() + TIMEOUT
-+ while deadline >= time():
-+ count = self._write_until_full(client_sock, chunk, 5.0)
-+ if count < len(chunk):
-+ break
-+ self.assertFalse(time() > deadline,
-+ "Client never blocked as expected!")
-+
-+ # client should now be in Q2 block. Drain the server to unblock Q2
-+ _ = self._read_until_empty(server_sock, 2.0)
-+
-+ # finish the PUSH
-+ if count:
-+ remainder = self._write_until_full(client_sock, chunk[count:], 1.0)
-+ self.assertEqual(len(chunk), count + remainder)
-+
-+ count = self._write_until_full(client_sock, last_chunk, 1.0)
-+ self.assertEqual(len(last_chunk), count)
-+
-+ # receive the request and reply
-+ _ = self._read_until_empty(server_sock, 2.0)
-+
-+ response = b'HTTP/1.1 201 Created\r\nContent-Length: 0\r\n\r\n'
-+ count = self._write_until_full(server_sock, response, 1.0)
-+ self.assertEqual(len(response), count)
-+
-+ # complete the response read
-+ _ = self._read_until_empty(client_sock, 2.0)
-+ self.assertEqual(len(response), len(_))
-+
-+ client_sock.shutdown(socket.SHUT_RDWR)
-+ client_sock.close()
-+
-+ server_sock.shutdown(socket.SHUT_RDWR)
-+ server_sock.close()
-+
-+ server_listener.shutdown(socket.SHUT_RDWR)
-+ server_listener.close()
-+
-+ # search the router log file to verify Q2 was hit
-+
-+ block_ct = 0
-+ unblock_ct = 0
-+ with io.open(self.INT_A.logfile_path) as f:
-+ for line in f:
-+ if 'client link blocked on Q2 limit' in line:
-+ block_ct += 1
-+ if 'client link unblocked from Q2 limit' in line:
-+ unblock_ct += 1
-+ self.assertTrue(block_ct > 0)
-+ self.assertEqual(block_ct, unblock_ct)
-+
-+ def test_02_backpressure_server(self):
-+ """
-+ Trigger Q2 backpressure against the HTTP server.
-+ """
-+ small_get_req = b'GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n'
-+
-+ # create a listener socket to act as the server service
-+ server_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ server_listener.settimeout(TIMEOUT)
-+ server_listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-+ server_listener.bind(('', self.http_server_port))
-+ server_listener.listen(1)
-+
-+ # block until router connects
-+ server_sock, host_port = server_listener.accept()
-+ server_sock.settimeout(0.5)
-+ server_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+
-+ # create a client connection to the router
-+ client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ client_sock.settimeout(0.5)
-+ client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-+ client_sock.connect((host_port[0], self.http_listener_port))
-+
-+ # send GET request - expect this to be successful
-+ count = self._write_until_full(client_sock, small_get_req, 1.0)
-+ self.assertEqual(len(small_get_req), count)
-+
-+ request = self._read_until_empty(server_sock, 5.0)
-+ self.assertEqual(len(small_get_req), len(request))
-+
-+ # send a Very Long response, expecting it to block at some point
-+ chunk = b'8000\r\n' + b'X' * 0x8000 + b'\r\n'
-+ last_chunk = b'0 \r\n\r\n'
-+ response = b'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n'
-+
-+ count = self._write_until_full(server_sock, response, 1.0)
-+ self.assertEqual(len(response), count)
-+
-+ count = 0
-+ deadline = time() + TIMEOUT
-+ while deadline >= time():
-+ count = self._write_until_full(server_sock, chunk, 5.0)
-+ if count < len(chunk):
-+ break
-+ self.assertFalse(time() > deadline,
-+ "Server never blocked as expected!")
-+
-+ # server should now be in Q2 block. Drain the client to unblock Q2
-+ _ = self._read_until_empty(client_sock, 2.0)
-+
-+ # finish the response
-+ if count:
-+ remainder = self._write_until_full(server_sock, chunk[count:], 1.0)
-+ self.assertEqual(len(chunk), count + remainder)
-+
-+ count = self._write_until_full(server_sock, last_chunk, 1.0)
-+ self.assertEqual(len(last_chunk), count)
-+ server_sock.shutdown(socket.SHUT_RDWR)
-+ server_sock.close()
-+
-+ _ = self._read_until_empty(client_sock, 1.0)
-+ client_sock.shutdown(socket.SHUT_RDWR)
-+ client_sock.close()
-+
-+ server_listener.shutdown(socket.SHUT_RDWR)
-+ server_listener.close()
-+
-+ # search the router log file to verify Q2 was hit
-+
-+ block_ct = 0
-+ unblock_ct = 0
-+ with io.open(self.INT_A.logfile_path) as f:
-+ for line in f:
-+ if 'server link blocked on Q2 limit' in line:
-+ block_ct += 1
-+ if 'server link unblocked from Q2 limit' in line:
-+ unblock_ct += 1
-+ self.assertTrue(block_ct > 0)
-+ self.assertEqual(block_ct, unblock_ct)
-+
-+
- if __name__ == '__main__':
- unittest.main(main_module())
---
-2.20.1
-
-From 4816af35e8ffcfa3621301c97cc602558aa0d5d7 Mon Sep 17 00:00:00 2001
-From: Kenneth Giusti <kgiusti(a)apache.org>
-Date: Tue, 16 Feb 2021 20:25:21 -0500
-Subject: [PATCH 10/16] DISPATCH-1961: flush any Q2 blocked buffers on conn
- close
-
-This closes #1039
----
- src/adaptors/http1/http1_server.c | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
-diff --git a/src/adaptors/http1/http1_server.c b/src/adaptors/http1/http1_server.c
-index c1fb17b0..76c35cb7 100644
---- a/src/adaptors/http1/http1_server.c
-+++ b/src/adaptors/http1/http1_server.c
-@@ -529,11 +529,15 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- break;
- }
- case PN_RAW_CONNECTION_CLOSED_READ: {
-+ if (hconn->q2_blocked) {
-+ hconn->q2_blocked = false;
-+ // drain any pending buffers blocked by Q2
-+ _handle_conn_read_event(hconn);
-+ }
- // notify the codec so it can complete the current response
- // message (response body terminated on connection closed)
- h1_codec_connection_rx_closed(hconn->http_conn);
- pn_raw_connection_close(hconn->raw_conn);
-- hconn->q2_blocked = false;
- break;
- }
-
-@@ -601,7 +605,8 @@ static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, voi
- break;
- }
- case PN_RAW_CONNECTION_NEED_READ_BUFFERS: {
-- _handle_conn_need_read_buffers(hconn);
-+ if (!hconn->q2_blocked)
-+ _handle_conn_need_read_buffers(hconn);
- break;
- }
- case PN_RAW_CONNECTION_WAKE: {
-@@ -1136,7 +1141,7 @@ void qdr_http1_server_core_link_flow(qdr_http1_adaptor_t *adaptor,
-
- if (hconn->in_link_credit > 0) {
-
-- if (hconn->raw_conn)
-+ if (hconn->raw_conn && !hconn->q2_blocked)
- qda_raw_conn_grant_read_buffers(hconn->raw_conn);
-
- // check for pending responses that are blocked for credit
---
-2.20.1
-
-From 67cf9a8d259052f2aed1c3b8a0fea5d1fde5248c Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Thu, 18 Feb 2021 14:27:27 -0500
-Subject: [PATCH 11/16] DISPATCH-1952: Add back qd_bitmask_t to leak supression
- list
-
----
- src/alloc_pool.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/alloc_pool.c b/src/alloc_pool.c
-index 2ab65675..79c14a27 100644
---- a/src/alloc_pool.c
-+++ b/src/alloc_pool.c
-@@ -102,6 +102,7 @@ static const char *leaking_types[] = {
- "qdr_field_t",
- "qdr_link_work_t",
- "qd_buffer_t",
-+ "qd_bitmask_t",
-
- "qd_parsed_field_t", // DISPATCH-1701
- "qdr_delivery_ref_t", // DISPATCH-1702
---
-2.20.1
-
-From c32f02c27d0471adf20630f830d819348cdc9611 Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Thu, 18 Feb 2021 14:07:52 -0500
-Subject: [PATCH 12/16] DISPATCH-1970: Zero out the conn->config pointer since
- it has already been freed. This closes #1046.
-
----
- src/adaptors/http2/http2_adaptor.c | 12 +++++-------
- 1 file changed, 5 insertions(+), 7 deletions(-)
-
-diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
-index 25347e40..7ffdb0d9 100644
---- a/src/adaptors/http2/http2_adaptor.c
-+++ b/src/adaptors/http2/http2_adaptor.c
-@@ -382,10 +382,6 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
- buff = DEQ_HEAD(http_conn->granted_read_buffs);
- }
-
-- if (http_conn->delete_egress_connections) {
-- http_conn->config = 0;
-- }
--
- qd_log(http2_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"] Freeing http2 connection in free_qdr_http2_connection", http_conn->conn_id);
-
- free_qdr_http2_connection_t(http_conn);
-@@ -872,13 +868,13 @@ static void _http_record_request(qdr_http2_connection_t *conn, qdr_http2_stream_
- remote_addr = conn->remote_address;
- }
- } else {
-- remote_addr = conn->config->host;
-+ remote_addr = conn->config?conn->config->host:0;
- }
- qd_http_record_request(http2_adaptor->core,
- stream_data->method,
- stream_data->request_status,
-- conn->config->address,
-- remote_addr, conn->config->site,
-+ conn->config?conn->config->address:0,
-+ remote_addr, conn->config?conn->config->site:0,
- stream_data->remote_site,
- conn->ingress, stream_data->bytes_in, stream_data->bytes_out,
- stream_data->stop && stream_data->start ? stream_data->stop - stream_data->start : 0);
-@@ -2094,6 +2090,8 @@ static void handle_disconnected(qdr_http2_connection_t* conn)
- conn->stream_dispatcher_stream_data = 0;
-
- if (conn->delete_egress_connections) {
-+ // The config has already been freed by the qd_http_connector_decref() function, set it to zero here
-+ conn->config = 0;
- close_connections(conn);
- }
- }
---
-2.20.1
-
-From e4f2a9090d3fee36efeff903dc9a628ea77135ff Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Mon, 22 Feb 2021 11:24:15 -0500
-Subject: [PATCH 13/16] DISPATCH-1968: Avoid proton calls on a closed raw
- connections
-
- * Do not write new buffers if connection is CLOSED_WRITE
- * Do not call connection_wake if CLOSED_READ or CLOSED_WRITE
-
-This closes #1047
----
- src/adaptors/tcp_adaptor.c | 45 ++++++++++++++++++++++++++++++++++----
- 1 file changed, 41 insertions(+), 4 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index 6cc8855f..69bed1ab 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -56,6 +56,8 @@ struct qdr_tcp_connection_t {
- bool egress_dispatcher;
- bool connector_closed;//only used if egress_dispatcher=true
- bool in_list; // This connection is in the adaptor's connections list
-+ bool raw_closed_read;
-+ bool raw_closed_write;
- qdr_delivery_t *initial_delivery;
- qd_timer_t *activate_timer;
- qd_bridge_config_t config;
-@@ -122,6 +124,9 @@ static void on_activate(void *context)
-
- static void grant_read_buffers(qdr_tcp_connection_t *conn)
- {
-+ if (conn->raw_closed_read)
-+ return;
-+
- pn_raw_buffer_t raw_buffers[READ_BUFFERS];
- // Give proactor more read buffers for the socket
- if (!pn_raw_connection_is_read_closed(conn->pn_raw_conn)) {
-@@ -231,6 +236,31 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- return count;
- }
-
-+
-+static void flush_outgoing_buffs(qdr_tcp_connection_t *conn)
-+{
-+ // Flush buffers staged for writing to raw conn
-+ // and free possible references to stream data objects.
-+ if (conn->outgoing_buff_count > 0) {
-+ for (size_t i = conn->outgoing_buff_idx;
-+ i < conn->outgoing_buff_idx + conn->outgoing_buff_count;
-+ ++i) {
-+ if (conn->outgoing_buffs[i].context) {
-+ qd_message_stream_data_release(
-+ (qd_message_stream_data_t*)conn->outgoing_buffs[i].context);
-+ }
-+ }
-+ }
-+ conn->outgoing_buff_count = 0;
-+
-+ // Flush in-progress stream data object
-+ if (conn->outgoing_stream_data) {
-+ free_qd_message_stream_data_t(conn->outgoing_stream_data);
-+ conn->outgoing_stream_data = 0;
-+ }
-+}
-+
-+
- static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- {
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Freeing tcp_connection %p", tc->conn_id, (void*) tc);
-@@ -240,9 +270,7 @@ static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- if (tc->activate_timer) {
- qd_timer_free(tc->activate_timer);
- }
-- if (tc->outgoing_stream_data) {
-- free_qd_message_stream_data_t(tc->outgoing_stream_data);
-- }
-+ flush_outgoing_buffs(tc);
- sys_mutex_free(tc->activation_lock);
- //proactor will free the socket
- free_qdr_tcp_connection_t(tc);
-@@ -348,6 +376,7 @@ static int read_message_body(qdr_tcp_connection_t *conn, qd_message_t *msg, pn_r
- return used;
- }
-
-+
- static bool write_outgoing_buffs(qdr_tcp_connection_t *conn)
- {
- // Send the outgoing buffs to pn_raw_conn.
-@@ -383,6 +412,12 @@ static bool write_outgoing_buffs(qdr_tcp_connection_t *conn)
- static void handle_outgoing(qdr_tcp_connection_t *conn)
- {
- if (conn->outstream) {
-+ if (conn->raw_closed_write) {
-+ // flush outgoing buffers and free attached stream_data objects
-+ flush_outgoing_buffs(conn);
-+ // give no more buffers to raw connection
-+ return;
-+ }
- qd_message_t *msg = qdr_delivery_message(conn->outstream);
- bool read_more_body = true;
-
-@@ -534,11 +569,13 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- case PN_RAW_CONNECTION_CLOSED_READ: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_CLOSED_READ", conn->conn_id);
-+ conn->raw_closed_read = true;
- pn_raw_connection_close(conn->pn_raw_conn);
- break;
- }
- case PN_RAW_CONNECTION_CLOSED_WRITE: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_CLOSED_WRITE", conn->conn_id);
-+ conn->raw_closed_write = true;
- pn_raw_connection_close(conn->pn_raw_conn);
- break;
- }
-@@ -1186,7 +1223,7 @@ static void qdr_tcp_activate(void *notused, qdr_connection_t *c)
- if (context) {
- qdr_tcp_connection_t* conn = (qdr_tcp_connection_t*) context;
- sys_mutex_lock(conn->activation_lock);
-- if (conn->pn_raw_conn) {
-+ if (conn->pn_raw_conn && !(conn->raw_closed_read || conn->raw_closed_write)) {
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] qdr_tcp_activate: waking raw connection", conn->conn_id);
- pn_raw_connection_wake(conn->pn_raw_conn);
- sys_mutex_unlock(conn->activation_lock);
---
-2.20.1
-
-From 29911e6bb37d542ec662ae4af947e98c93619591 Mon Sep 17 00:00:00 2001
-From: Chuck Rolke <chug(a)apache.org>
-Date: Tue, 23 Feb 2021 16:48:05 -0500
-Subject: [PATCH 14/16] DISPATCH-1947: TCP Adaptor flow control
-
-This closes #1056
----
- src/adaptors/tcp_adaptor.c | 88 +++++++++++++++++++++++++++++++++-----
- 1 file changed, 78 insertions(+), 10 deletions(-)
-
-diff --git a/src/adaptors/tcp_adaptor.c b/src/adaptors/tcp_adaptor.c
-index 69bed1ab..0b831231 100644
---- a/src/adaptors/tcp_adaptor.c
-+++ b/src/adaptors/tcp_adaptor.c
-@@ -17,6 +17,7 @@
- * under the License.
- */
-
-+#include "tcp_adaptor.h"
- #include <proton/condition.h>
- #include <proton/listener.h>
- #include <proton/netaddr.h>
-@@ -26,7 +27,6 @@
- #include "qpid/dispatch/ctools.h"
- #include "qpid/dispatch/protocol_adaptor.h"
- #include "delivery.h"
--#include "tcp_adaptor.h"
- #include <stdio.h>
- #include <inttypes.h>
-
-@@ -78,6 +78,9 @@ struct qdr_tcp_connection_t {
- int outgoing_buff_count; // number of buffers with data
- int outgoing_buff_idx; // first buffer with data
-
-+ sys_atomic_t q2_restart; // signal to resume receive
-+ bool q2_blocked; // stop reading from raw conn
-+
- DEQ_LINKS(qdr_tcp_connection_t);
- };
-
-@@ -148,7 +151,37 @@ static void grant_read_buffers(qdr_tcp_connection_t *conn)
- }
- }
-
--static int handle_incoming(qdr_tcp_connection_t *conn)
-+
-+// Per-message callback to resume receiving after Q2 is unblocked on the
-+// incoming link.
-+// This routine must be thread safe: the thread on which it is running
-+// is not an IO thread that owns the underlying pn_raw_conn.
-+//
-+void qdr_tcp_q2_unblocked_handler(const qd_alloc_safe_ptr_t context)
-+{
-+ qdr_tcp_connection_t *tc = (qdr_tcp_connection_t*)qd_alloc_deref_safe_ptr(&context);
-+ if (tc == 0) {
-+ // bad news.
-+ assert(false);
-+ return;
-+ }
-+
-+ // prevent the tc from being deleted while running:
-+ sys_mutex_lock(tc->activation_lock);
-+
-+ if (tc && tc->pn_raw_conn) {
-+ sys_atomic_set(&tc->q2_restart, 1);
-+ pn_raw_connection_wake(tc->pn_raw_conn);
-+ }
-+
-+ sys_mutex_unlock(tc->activation_lock);
-+}
-+
-+
-+// Fetch incoming raw incoming buffers from proton and pass them to
-+// existing delivery or create a new delivery.
-+// If close is pending then do not give more buffers to proton.
-+static int handle_incoming_impl(qdr_tcp_connection_t *conn, bool close_pending)
- {
- //
- // Don't initiate an ingress stream message if we don't yet have a reply-to address and credit.
-@@ -163,6 +196,16 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- return 0;
- }
-
-+ //
-+ // Don't read from proton if in Q2 holdoff
-+ //
-+ if (conn->q2_blocked) {
-+ qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] handle_incoming q2_blocked", conn->conn_id);
-+ return 0;
-+ }
-+
-+ // Read all buffers available from proton.
-+ // Collect buffers for ingress; free empty buffers.
- qd_buffer_list_t buffers;
- DEQ_INIT(buffers);
- pn_raw_buffer_t raw_buffers[READ_BUFFERS];
-@@ -182,14 +225,20 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- }
- }
- }
--
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Took %zu read buffers", conn->conn_id, DEQ_SIZE(buffers));
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Freed %i read buffers", conn->conn_id, free_count);
-- grant_read_buffers(conn);
-+
-+ // Only grant more buffers to proton for reading if close is not pending
-+ if (!close_pending) {
-+ grant_read_buffers(conn);
-+ }
-
- if (conn->instream) {
-- // @TODO(kgiusti): handle Q2 block event:
-- qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers, 0);
-+ qd_message_stream_data_append(qdr_delivery_message(conn->instream), &buffers, &conn->q2_blocked);
-+ if (conn->q2_blocked) {
-+ // note: unit tests grep for this log!
-+ qd_log(tcp_adaptor->log_source, QD_LOG_TRACE, "[C%"PRIu64"] client link blocked on Q2 limit", conn->conn_id);
-+ }
- qdr_delivery_continue(tcp_adaptor->core, conn->instream, false);
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Continuing message with %i bytes", conn->conn_id, conn->incoming_id, count);
- } else {
-@@ -230,6 +279,10 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- qd_message_compose_2(msg, props, false);
- qd_compose_free(props);
-
-+ // set up message q2 unblocked callback handler
-+ qd_alloc_safe_ptr_t conn_sp = QD_SAFE_PTR_INIT(conn);
-+ qd_message_set_q2_unblocked_handler(msg, qdr_tcp_q2_unblocked_handler, conn_sp);
-+
- conn->instream = qdr_link_deliver(conn->incoming, msg, 0, false, 0, 0, 0, 0);
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] Initiating message with %i bytes", conn->conn_id, conn->incoming_id, count);
- }
-@@ -237,10 +290,16 @@ static int handle_incoming(qdr_tcp_connection_t *conn)
- }
-
-
-+static int handle_incoming(qdr_tcp_connection_t *conn)
-+{
-+ // Normal incoming runs with no close pending
-+ return handle_incoming_impl(conn, false);
-+}
-+
- static void flush_outgoing_buffs(qdr_tcp_connection_t *conn)
- {
- // Flush buffers staged for writing to raw conn
-- // and free possible references to stream data objects.
-+ // and release any references to stream data objects.
- if (conn->outgoing_buff_count > 0) {
- for (size_t i = conn->outgoing_buff_idx;
- i < conn->outgoing_buff_idx + conn->outgoing_buff_count;
-@@ -263,10 +322,10 @@ static void flush_outgoing_buffs(qdr_tcp_connection_t *conn)
-
- static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
- {
-- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] Freeing tcp_connection %p", tc->conn_id, (void*) tc);
- free(tc->reply_to);
- free(tc->remote_address);
- free(tc->global_id);
-+ sys_atomic_destroy(&tc->q2_restart);
- if (tc->activate_timer) {
- qd_timer_free(tc->activate_timer);
- }
-@@ -278,7 +337,6 @@ static void free_qdr_tcp_connection(qdr_tcp_connection_t* tc)
-
- static void handle_disconnected(qdr_tcp_connection_t* conn)
- {
-- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"] handle_disconnected", conn->conn_id);
- if (conn->instream) {
- qd_log(tcp_adaptor->log_source, QD_LOG_DEBUG, "[C%"PRIu64"][L%"PRIu64"] handle_disconnected - close instream", conn->conn_id, conn->incoming_id);
- qd_message_set_receive_complete(qdr_delivery_message(conn->instream));
-@@ -552,8 +610,8 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- switch (pn_event_type(e)) {
- case PN_RAW_CONNECTION_CONNECTED: {
- if (conn->ingress) {
-- qdr_tcp_connection_ingress_accept(conn);
- qd_log(log, QD_LOG_INFO, "[C%"PRIu64"] PN_RAW_CONNECTION_CONNECTED Ingress accepted to %s from %s (global_id=%s)", conn->conn_id, conn->config.host_port, conn->remote_address, conn->global_id);
-+ qdr_tcp_connection_ingress_accept(conn);
- break;
- } else {
- conn->remote_address = get_address_string(conn->pn_raw_conn);
-@@ -569,6 +627,8 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- case PN_RAW_CONNECTION_CLOSED_READ: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_CLOSED_READ", conn->conn_id);
-+ conn->q2_blocked = false;
-+ handle_incoming_impl(conn, true);
- conn->raw_closed_read = true;
- pn_raw_connection_close(conn->pn_raw_conn);
- break;
-@@ -601,6 +661,12 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
- }
- case PN_RAW_CONNECTION_WAKE: {
- qd_log(log, QD_LOG_DEBUG, "[C%"PRIu64"] PN_RAW_CONNECTION_WAKE", conn->conn_id);
-+ if (sys_atomic_set(&conn->q2_restart, 0)) {
-+ // note: unit tests grep for this log!
-+ qd_log(log, QD_LOG_TRACE, "[C%"PRIu64"] client link unblocked from Q2 limit", conn->conn_id);
-+ conn->q2_blocked = false;
-+ handle_incoming(conn);
-+ }
- while (qdr_connection_process(conn->qdr_conn)) {}
- break;
- }
-@@ -646,6 +712,7 @@ static qdr_tcp_connection_t *qdr_tcp_connection_ingress(qd_tcp_listener_t* liste
- tc->context.handler = &handle_connection_event;
- tc->config = listener->config;
- tc->server = listener->server;
-+ sys_atomic_init(&tc->q2_restart, 0);
- tc->pn_raw_conn = pn_raw_connection();
- pn_raw_connection_set_context(tc->pn_raw_conn, tc);
- //the following call will cause a PN_RAW_CONNECTION_CONNECTED
-@@ -739,6 +806,7 @@ static qdr_tcp_connection_t *qdr_tcp_connection_egress(qd_bridge_config_t *confi
- tc->context.handler = &handle_connection_event;
- tc->config = *config;
- tc->server = server;
-+ sys_atomic_init(&tc->q2_restart, 0);
- tc->conn_id = qd_server_allocate_connection_id(tc->server);
-
- //
---
-2.20.1
-
-From 29d04211d03b27049c59418a2d04c76fb60e5fa9 Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Tue, 2 Mar 2021 09:25:11 -0500
-Subject: [PATCH 15/16] DISPATCH-1984: Matched the method signature of
- _client_rx_body_cb with the implementation. Modified uintmax_t len to size_t
- len
-
----
- src/adaptors/http1/http1_client.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/adaptors/http1/http1_client.c b/src/adaptors/http1/http1_client.c
-index ff033807..422dd6ac 100644
---- a/src/adaptors/http1/http1_client.c
-+++ b/src/adaptors/http1/http1_client.c
-@@ -106,7 +106,7 @@ static int _client_rx_response_cb(h1_codec_request_state_t *lib_rs,
- uint32_t version_minor);
- static int _client_rx_header_cb(h1_codec_request_state_t *lib_rs, const char *key, const char *value);
- static int _client_rx_headers_done_cb(h1_codec_request_state_t *lib_rs, bool has_body);
--static int _client_rx_body_cb(h1_codec_request_state_t *lib_rs, qd_buffer_list_t *body, uintmax_t len, bool more);
-+static int _client_rx_body_cb(h1_codec_request_state_t *lib_rs, qd_buffer_list_t *body, size_t len, bool more);
- static void _client_rx_done_cb(h1_codec_request_state_t *lib_rs);
- static void _client_request_complete_cb(h1_codec_request_state_t *lib_rs, bool cancelled);
- static void _handle_connection_events(pn_event_t *e, qd_server_t *qd_server, void *context);
---
-2.20.1
-
-From 6bb2eb534f9243caeb00891821be8f0d133e4822 Mon Sep 17 00:00:00 2001
-From: Ganesh Murthy <gmurthy(a)apache.org>
-Date: Thu, 4 Mar 2021 12:42:00 -0500
-Subject: [PATCH 16/16] DISPATCH-1988: Added code to start routing a delivery
- only if there is some data in the content->buffers or in content->pending. If
- we never receive any data and the receive is complete, the delivery is
- rejected. This closes #1062
-
----
- include/qpid/dispatch/message.h | 8 ++
- src/message.c | 20 ++++-
- src/router_node.c | 36 ++++++++
- tests/system_tests_link_routes.py | 145 ++++++++++++++++++++++++++++++
- 4 files changed, 207 insertions(+), 2 deletions(-)
-
-diff --git a/include/qpid/dispatch/message.h b/include/qpid/dispatch/message.h
-index 07e144ad..1558dde3 100644
---- a/include/qpid/dispatch/message.h
-+++ b/include/qpid/dispatch/message.h
-@@ -247,6 +247,14 @@ qd_message_t *qd_message_receive(pn_delivery_t *delivery);
- */
- qd_message_t * qd_get_message_context(pn_delivery_t *delivery);
-
-+/**
-+ * Returns true if there is at least one non-empty buffer at the head of the content->buffers list
-+ * or if the content->pending buffer is non-empty.
-+ *
-+ * @param msg A pointer to a message.
-+ */
-+bool qd_message_has_data_in_content_or_pending_buffers(qd_message_t *msg);
-+
- /**
- * Send the message outbound on an outgoing link.
- *
-diff --git a/src/message.c b/src/message.c
-index 16794075..3508a996 100644
---- a/src/message.c
-+++ b/src/message.c
-@@ -1255,8 +1255,6 @@ void qd_message_add_fanout(qd_message_t *in_msg,
- // DISPATCH-1590: content->buffers may not be set up yet if
- // content->pending is the first buffer and it is not yet full.
- if (!buf) {
-- // assumption: proton will never signal a readable delivery if there is
-- // no data at all.
- assert(content->pending && qd_buffer_size(content->pending) > 0);
- DEQ_INSERT_TAIL(content->buffers, content->pending);
- content->pending = 0;
-@@ -1422,6 +1420,24 @@ qd_message_t * qd_get_message_context(pn_delivery_t *delivery)
- return 0;
- }
-
-+bool qd_message_has_data_in_content_or_pending_buffers(qd_message_t *msg)
-+{
-+ if (!msg)
-+ return false;
-+
-+ if (MSG_CONTENT(msg)) {
-+ if (DEQ_SIZE(MSG_CONTENT(msg)->buffers) > 0) {
-+ qd_buffer_t *buf = DEQ_HEAD(MSG_CONTENT(msg)->buffers);
-+ if (buf && qd_buffer_size(buf) > 0)
-+ return true;
-+ }
-+ if (MSG_CONTENT(msg)->pending && qd_buffer_size(MSG_CONTENT(msg)->pending) > 0)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-
- qd_message_t *qd_message_receive(pn_delivery_t *delivery)
- {
-diff --git a/src/router_node.c b/src/router_node.c
-index 70d98f91..bccf6cfd 100644
---- a/src/router_node.c
-+++ b/src/router_node.c
-@@ -451,6 +451,42 @@ static bool AMQP_rx_handler(void* context, qd_link_t *link)
- qd_message_t *msg = qd_message_receive(pnd);
- bool receive_complete = qd_message_receive_complete(msg);
-
-+ //
-+ // The very first time AMQP_rx_handler is called on a PN_DELIVERY event, it calls qd_message_receive(). When qd_message_receive() returns, we check here if
-+ // there are any data in the content buffers. If there is no content in the buffers, there is no reason to route the delivery. We will wait for some data
-+ // in the buffers before we start to route the delivery.
-+ // Notice that the if statement checks for the existence of a delivery (qdr_delivery_t). Existence of a delivery means that the delivery has been routed when
-+ // there was data in the buffers (When a delivery has been routed successfully, the delivery (qdr_delivery_t) will be non null)
-+ //
-+ // The following if statement will deal with the following cases:-
-+ // 1. We receive one empty transfer frame with more=true followed by another empty transfer frame with (more=false and abort=true) or with just more=false
-+ // In this case, there is no data at all in the message content buffers, we will reject the message when receive_complete=true. We will never route this
-+ // delivery, so core thread will not be involved
-+ // 2. We receive 2 or more empty transfer frames with more=true followed by another empty transfer frame with (more=false and abort=true) or with just more=false
-+ // This case is similar to #1. We have no content in any of the buffers, we will reject this message after receive_complete=true. We will never route this
-+ // delivery, so core thread will not be involved
-+ // 3. Exactly one empty transfer frame with more=false and abort=false
-+ // In this case, again there is still no content in any of the buffers, we will reject this message. Again, we will not route this message, so the core thread is not involved.
-+ //
-+ if (!delivery && !qd_message_has_data_in_content_or_pending_buffers(msg)) {
-+ if (receive_complete) {
-+ // There is no qdr_delivery_t (delivery) yet which means this message has not been routed yet (the first run of this function is not complete yet) and
-+ // the message is fully received (receive_complete=true) but there is no content in the message buffers.
-+ // This is only possible if there were one or more empty transfer frames.
-+ // Since there is nothing in the message, we will reject it (AMQP message must have a non empty message body)
-+ pn_link_flow(pn_link, 1);
-+ if (pn_delivery_aborted(pnd))
-+ qd_message_set_discard(msg, true);
-+ pn_delivery_update(pnd, PN_REJECTED);
-+ pn_delivery_settle(pnd);
-+ // qd_message_free will free all the associated content buffers and also the content->pending buffer
-+ qd_message_free(msg);
-+ qd_log(router->log_source, QD_LOG_TRACE, "Message rejected due to empty message");
-+ }
-+
-+ return false;
-+ }
-+
- if (!qd_message_oversize(msg)) {
- // message not rejected as oversize
- if (receive_complete) {
-diff --git a/tests/system_tests_link_routes.py b/tests/system_tests_link_routes.py
-index 1334618d..80ce0cdd 100644
---- a/tests/system_tests_link_routes.py
-+++ b/tests/system_tests_link_routes.py
-@@ -26,6 +26,7 @@ import os
- from time import sleep, time
- from threading import Event
- from subprocess import PIPE, STDOUT
-+import socket
-
- from system_test import TestCase, Qdrouterd, main_module, TIMEOUT, Process, TestTimeout, \
- AsyncTestSender, AsyncTestReceiver, MgmtMsgProxy, unittest, QdManager
-@@ -1761,6 +1762,150 @@ class LinkRouteDrainTest(TestCase):
- self.assertEquals(drain_receiver.error, None)
-
-
-+class EmptyTransferTest(TestCase):
-+ @classmethod
-+ def setUpClass(cls):
-+ super(EmptyTransferTest, cls).setUpClass()
-+ cls.ROUTER_LISTEN_PORT = cls.tester.get_port()
-+
-+ config = [
-+ ('router', {'mode': 'standalone', 'id': 'QDR.A'}),
-+ # the client will connect to this listener
-+ ('listener', {'role': 'normal',
-+ 'host': '0.0.0.0',
-+ 'port': cls.ROUTER_LISTEN_PORT,
-+ 'saslMechanisms': 'ANONYMOUS'}),
-+ # to connect to the fake broker
-+ ('connector', {'name': 'broker',
-+ 'role': 'route-container',
-+ 'host': '127.0.0.1',
-+ 'port': cls.tester.get_port(),
-+ 'saslMechanisms': 'ANONYMOUS'}),
-+ ('linkRoute',
-+ {'prefix': 'examples', 'containerId': 'FakeBroker',
-+ 'direction': 'in'}),
-+ ('linkRoute',
-+ {'prefix': 'examples', 'containerId': 'FakeBroker',
-+ 'direction': 'out'})
-+ ]
-+ config = Qdrouterd.Config(config)
-+ cls.router = cls.tester.qdrouterd('A', config, wait=False)
-+
-+ def _fake_broker(self, cls):
-+ """
-+ Spawn a fake broker listening on the broker's connector
-+ """
-+ fake_broker = cls(self.router.connector_addresses[0])
-+ # wait until the connection to the fake broker activates
-+ self.router.wait_connectors()
-+ return fake_broker
-+
-+ def test_DISPATCH_1988(self):
-+ fake_broker = self._fake_broker(FakeBroker)
-+ AMQP_OPEN_BEGIN_ATTACH = bytearray(
-+ b'\x41\x4d\x51\x50\x00\x01\x00\x00\x00\x00\x00\x21\x02\x00\x00'
-+ b'\x00\x00\x53\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x04\xa1\x06'
-+ b'\x2e\x2f\x73\x65\x6e\x64\x40\x40\x60\x7f\xff\x00\x00\x00\x21'
-+ b'\x02\x00\x00\x00\x00\x53\x11\xd0\x00\x00\x00\x11\x00\x00\x00'
-+ b'\x04\x40\x52\x00\x70\x7f\xff\xff\xff\x70\x7f\xff\xff\xff\x00'
-+ b'\x00\x00\x5b\x02\x00\x00\x00\x00\x53\x12\xd0\x00\x00\x00\x4b'
-+ b'\x00\x00\x00\x0b\xa1\x09\x6d\x79\x5f\x73\x65\x6e\x64\x65\x72'
-+ b'\x52\x00\x42\x50\x02\x50\x00\x00\x53\x28\xd0\x00\x00\x00\x0b'
-+ b'\x00\x00\x00\x05\x40\x52\x00\x40\x52\x00\x42\x00\x53\x29\xd0'
-+ b'\x00\x00\x00\x14\x00\x00\x00\x05\xa1\x08\x65\x78\x61\x6d\x70'
-+ b'\x6c\x65\x73\x52\x00\x40\x52\x00\x42\x40\x40\x52\x00\x53\x00')
-+
-+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-+ # Connect to the router listening port and send an amqp, open,
-+ # begin, attach. The attach is sent on the link
-+ # routed address, "examples"
-+ s.connect(("0.0.0.0", EmptyTransferTest.ROUTER_LISTEN_PORT))
-+ s.sendall(AMQP_OPEN_BEGIN_ATTACH)
-+
-+ # Give a second for the attach to propagate to the broker and
-+ # for the broker to send a response attach
-+ sleep(1)
-+ data = s.recv(2048)
-+ self.assertIn("examples", repr(data))
-+
-+ # First send a message on link routed address "examples" with
-+ # message body of "message 0"
-+ # Verify the the sent message has been accepted.
-+ TRANSFER_1 = bytearray(b'\x00\x00\x00\x31\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x01'
-+ + b'\xa0\x01\x01\x43\x42'
-+ + b'\x40\x40\x40\x40\x40\x42\x00\x53'
-+ + b'\x73\xc0\x02\x01\x44\x00\x53\x77'
-+ + b'\xa1\x09\x6d\x65\x73\x73\x61\x67'
-+ + b'\x65\x20\x30')
-+ s.sendall(TRANSFER_1)
-+ sleep(0.5)
-+ data = s.recv(1024)
-+ # The delivery has been accepted.
-+ self.assertIn("x00S$E", repr(data))
-+
-+ # Test case 1
-+ # Send an empty transfer frame to the router and you should
-+ # receive a rejected disposition from the router.
-+ # Without the fix for DISPATCH_1988,
-+ # upon sending this EMPTY_TRANSFER
-+ # the router crashes with the following assert
-+ # qpid-dispatch/src/message.c:1260: qd_message_add_fanout: Assertion `content->pending && qd_buffer_size(content->pending) > 0' failed.
-+ # This is the empty transfer frame that is sent to the router.
-+ # [0x614000030050]: AMQP:FRAME:0 <- @transfer(20) [handle=0, delivery-id=0, delivery-tag=b"\x01", message-format=0, settled=false, batchable=false]
-+ EMPTY_TRANSFER = bytearray(b'\x00\x00\x00\x1c\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52'
-+ + b'\x02\xa0\x01\x02\x43\x42'
-+ + b'\x42\x40\x40\x40\x40\x42')
-+ s.sendall(EMPTY_TRANSFER)
-+ sleep(1)
-+ data = s.recv(1024)
-+ # The delivery has been rejected.
-+ self.assertIn("x00S%E", repr(data))
-+
-+ # Let's send another transfer to make sure that the
-+ # router has not crashed.
-+ TRANSFER_1 = bytearray(b'\x00\x00\x00\x31\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x03'
-+ + b'\xa0\x01\x03\x43\x42'
-+ + b'\x40\x40\x40\x40\x40\x42\x00\x53'
-+ + b'\x73\xc0\x02\x01\x44\x00\x53\x77'
-+ + b'\xa1\x09\x6d\x65\x73\x73\x61\x67'
-+ + b'\x65\x20\x30')
-+ s.sendall(TRANSFER_1)
-+ sleep(0.5)
-+ data = s.recv(1024)
-+ # The delivery has been accepted.
-+ self.assertIn("x00S$E", repr(data))
-+
-+ # Test case 2
-+ # Now, send two empty transfer frames, first transfer has
-+ # more=true and the next transfer has more=false.
-+ # This will again be rejected by the router.
-+ # The following are the two transfer frames that will be
-+ # sent to the router.
-+ #[0x614000020050]: AMQP:FRAME: 0 <- @ transfer(20)[handle = 0, delivery - id = 4, delivery - tag = b"\x04", message - format = 0, settled = false, more = true, batchable = false]
-+ #[0x614000020050]: AMQP:FRAME: 0 <- @ transfer(20)[handle = 0, delivery - id = 4, delivery - tag = b"\x04", message - format = 0, settled = false, more = false, batchable = false]
-+ EMPTY_TRANSFER_MORE_TRUE = bytearray(
-+ b'\x00\x00\x00\x1c\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x04'
-+ + b'\xa0\x01\x04\x43\x42'
-+ + b'\x41\x40\x40\x40\x40\x42')
-+ EMPTY_TRANSFER_MORE_FALSE = bytearray(
-+ b'\x00\x00\x00\x1c\x02\x00\x00\x00'
-+ + b'\x00\x53\x14\xc0\x0f\x0b\x43\x52\x04'
-+ + b'\xa0\x01\x04\x43\x42'
-+ + b'\x42\x40\x40\x40\x40\x42')
-+ s.sendall(EMPTY_TRANSFER_MORE_TRUE)
-+ s.sendall(EMPTY_TRANSFER_MORE_FALSE)
-+ sleep(0.5)
-+ data = s.recv(1024)
-+ # The delivery has been rejected.
-+ self.assertIn("x00S%E", repr(data))
-+
-+ s.close()
-+
-+
- class ConnectionLinkRouteTest(TestCase):
- """
- Test connection scoped link route implementation
---
-2.20.1
-
diff --git a/licenses.xml b/licenses.xml
index 7fdff74..34cde69 100644
--- a/licenses.xml
+++ b/licenses.xml
@@ -3,7 +3,7 @@
<dependencies>
<dependency>
<packageName>qpid-dispatch</packageName>
- <version>1.15.0</version>
+ <version>1.16.0</version>
<licenses>
<license>
<name>ASL 2.0</name>
diff --git a/qpid-dispatch.spec b/qpid-dispatch.spec
index 447a700..256c2d6 100644
--- a/qpid-dispatch.spec
+++ b/qpid-dispatch.spec
@@ -6,38 +6,17 @@
# Define pkgdocdir for releases that don't define it already
%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/%{name}-%{version}}
-%if (0%{?fedora} && 0%{?fedora} >= 29)
-%global pythonx python3
-%else
-%global pythonx python2
-%{!?__python2:%global __python2 %{__python}}
-%{!?__python2:%global python2_sitelib %{python_sitelib}}
-%{!?__python2:%global python2_sitearch %{python_sitearch}}
-%{!?__python2:%global pythonx python}
-%endif
-
-# determine whether to install systemd or sysvinit scripts
-%if 0%{?fedora} || 0%{?rhel} >= 7
-
-%global _use_sysvinit 0
%global _use_systemd 1
-%else
-
-%global _use_sysvinit 1
-%global _use_systemd 0
-
-%endif
-
-%global proton_minimum_version 0.33.0
+%global proton_minimum_version 0.34.0
%global libwebsockets_minimum_version 3.2.0
%global libnghttp2_minimum_version 1.33.0
%undefine __brp_mangle_shebangs
Name: qpid-dispatch
-Version: 1.15.0
-Release: 2%{?dist}
+Version: 1.16.0
+Release: 1%{?dist}
Summary: Dispatch router for Qpid
License: ASL 2.0
URL: http://qpid.apache.org/
@@ -50,24 +29,15 @@ Source3: qpid-dispatch-console-%{version}.tar.gz
%{!?_licensedir:%global license %doc}
%{!?_licensedir:%global _pkglicensedir %{_pkgdocdir}}
-%if 0%{?rhel} && 0%{?rhel} >= 7
-ExcludeArch: i686
-%endif
-
-%if 0%{?rhel} && 0%{?rhel} <= 6
-Source1: docs-%{version}-1.tar.gz
-%endif
-
-Patch1: dispatch.patch
-Patch4: console-listener.patch
+Patch1: console-listener.patch
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: make
BuildRequires: cmake
BuildRequires: qpid-proton-c-devel >= %{proton_minimum_version}
-BuildRequires: %{pythonx}-devel
-BuildRequires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
+BuildRequires: python3-devel
+BuildRequires: python3-qpid-proton >= %{proton_minimum_version}
BuildRequires: openssl-devel
BuildRequires: libwebsockets-devel >= %{libwebsockets_minimum_version}
BuildRequires: libnghttp2-devel >= %{libnghttp2_minimum_version}
@@ -86,13 +56,11 @@ Summary: The Qpid Dispatch Router executable
Obsoletes: libqpid-dispatch
Obsoletes: libqpid-dispatch-devel
Requires: qpid-proton-c%{?_isa} >= %{proton_minimum_version}
-Requires: %{pythonx}
-Requires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
-%if %{_use_systemd}
+Requires: python3
+Requires: python3-qpid-proton >= %{proton_minimum_version}
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
-%endif
Requires: libwebsockets >= %{libwebsockets_minimum_version}
Requires: libnghttp2 >= %{libnghttp2_minimum_version}
@@ -107,27 +75,12 @@ Requires: libnghttp2 >= %{libnghttp2_minimum_version}
%config(noreplace) %{_sysconfdir}/sasl2/qdrouterd.conf
%{_exec_prefix}/lib/qpid-dispatch
-%if (0%{?fedora} && 0%{?fedora} < 29) || (0%{?rhel} && 0%{?rhel} <= 7)
-%{python2_sitelib}/*
-%endif
-%if (0%{?fedora} && 0%{?fedora} >= 29) || (0%{?rhel} && 0%{?rhel} > 7)
%{python3_sitelib}/qpid_dispatch_site.py*
%{python3_sitelib}/qpid_dispatch
%{python3_sitelib}/qpid_dispatch-*.egg-info
%{python3_sitelib}/__pycache__/*
-%endif
-
-%if %{_use_systemd}
%{_unitdir}/qdrouterd.service
-
-%else
-
-%{_initrddir}/qdrouterd
-%attr(755,qdrouterd,qdrouterd) %dir %{_localstatedir}/run/qpid-dispatch
-
-%endif
-
%{_mandir}/man5/qdrouterd.conf.5*
%{_mandir}/man8/qdrouterd.8*
@@ -139,8 +92,6 @@ getent passwd qdrouterd >/dev/null || \
exit 0
-%if %{_use_systemd}
-
%post router
/sbin/ldconfig
%systemd_post qdrouterd.service
@@ -152,28 +103,6 @@ exit 0
/sbin/ldconfig
%systemd_postun_with_restart qdrouterd.service
-%endif
-
-%if %{_use_sysvinit}
-
-%post router
-/sbin/ldconfig
-/sbin/chkconfig --add qdrouterd
-
-%preun router
-if [ $1 -eq 0 ]; then
- /sbin/service qdrouterd stop >/dev/null 2>&1
- /sbin/chkconfig --del qdrouterd
-fi
-
-%postun router
-/sbin/ldconfig
-if [ "$1" -ge "1" ]; then
- /sbin/service qdrouterd condrestart >/dev/null 2>&1
-fi
-
-%endif
-
%package docs
Summary: Documentation for the Qpid Dispatch router
@@ -203,7 +132,7 @@ Requires: qpid-dispatch-router
%package tools
Summary: Tools for the Qpid Dispatch router
BuildArch: noarch
-Requires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
+Requires: python3-qpid-proton >= %{proton_minimum_version}
%description tools
%{summary}.
@@ -219,14 +148,10 @@ Requires: %{pythonx}-qpid-proton >= %{proton_minimum_version}
%prep
%setup -q
%patch1 -p1
-%patch4 -p1
mkdir pre_built
cd pre_built
tar xvzpf %{SOURCE3} -C .
-%if 0%{?rhel} && 0%{?rhel} <= 6
-tar xvzpf %{SOURCE1} -C .
-%endif
%build
%cmake -DDOC_INSTALL_DIR=%{?_pkgdocdir} \
@@ -246,39 +171,14 @@ make doc
%install
%make_install
-%if %{_use_systemd}
-
install -dm 755 %{buildroot}%{_unitdir}
install -pm 644 %{_builddir}/qpid-dispatch-%{version}/etc/fedora/qdrouterd.service \
%{buildroot}%{_unitdir}
-
-%else
-
-install -dm 755 %{buildroot}%{_initrddir}
-install -pm 755 %{_builddir}/qpid-dispatch-%{version}/etc/fedora/qdrouterd \
- %{buildroot}%{_initrddir}
-
-%endif
-
-%if 0%{?rhel} && 0%{?rhel} <= 6
-install -dm 755 %{buildroot}%{_mandir}/man5
-install -dm 755 %{buildroot}%{_mandir}/man8
-install -pm 644 %{_builddir}/qpid-dispatch-%{version}/pre_built/man/man5/* %{buildroot}%{_mandir}/man5/
-install -pm 644 %{_builddir}/qpid-dispatch-%{version}/pre_built/man/man8/* %{buildroot}%{_mandir}/man8/
-cp -a %{_builddir}/qpid-dispatch-%{version}/pre_built/doc/qpid-dispatch-%{version}/* \
- %{buildroot}%{_pkgdocdir}/
-%endif
-
install -dm 755 %{buildroot}/var/run/qpid-dispatch
-
-%if 0%{?rhel} && 0%{?rhel} <= 6
-install -pm 644 %{SOURCE2} %{buildroot}%{_pkgdocdir}
-%else
install -dm 755 %{buildroot}%{_pkglicensedir}
install -pm 644 %{SOURCE2} %{buildroot}%{_pkglicensedir}
install -pm 644 %{buildroot}%{_pkgdocdir}/LICENSE %{buildroot}%{_pkglicensedir}
rm -f %{buildroot}%{_pkgdocdir}/LICENSE
-%endif
install -dm 755 %{buildroot}/%{_datarootdir}/qpid-dispatch/console
cp -a %{_builddir}/qpid-dispatch-%{version}/pre_built/console/* %{buildroot}/%{_datarootdir}/qpid-dispatch/console/
@@ -292,6 +192,9 @@ rm -fr %{buildroot}/%{_includedir}/qpid/dispatch
%changelog
+* Mon May 17 2021 Irina Boverman <iboverma(a)redhat.com> - 1.16.0-1
+- Rebased to 1.16.0
+
* Thu Mar 18 2021 Irina Boverman <iboverma(a)redhat.com> - 1.15.0-1
- Rebased to 1.15.0
diff --git a/sources b/sources
index 590ef76..06737bb 100644
--- a/sources
+++ b/sources
@@ -1,2 +1 @@
-SHA512 (qpid-dispatch-1.15.0.tar.gz) = bf5b36bbe67981ac6c5dc43147cf8051c86c46918b6c79d4cb54b6fbd1fa7d140464d9dedd6840a3f0b1bb19e965aca601b57a011d3fe78240a48f7747e440f7
-SHA512 (qpid-dispatch-console-1.15.0.tar.gz) = cedf64f7bc04d7e8ba28937991e6bd795f2f822e6ad9f2021c3d6b0273215b9c1fd65a98dfeee6af6125d26aa6e01ea54cd87df7cd3fea3ca9bf9daf27a3ee58
+SHA512 (qpid-dispatch-1.16.0.tar.gz) = 75f8df67d44bc0cececd481b8ccbec9d1d12ba4ed4a637bd71648c807e96b4d28ca87f33fbfa53cd1dd2e42c9a8446fd20d590a451f44f36729c888fb36fd780
3 years
Architecture specific change in rpms/nodejs.git
by githook-noreply@fedoraproject.org
The package rpms/nodejs.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/nodejs.git/commit/?id=9f1a56347d4...
https://src.fedoraproject.org/cgit/rpms/nodejs.git/commit/?id=a042b795522....
Change:
-%ifarch aarch64
+%ifarch aarch64
Thanks.
Full change:
============
commit 4ff0a33f15f6f65156dbe88f19b64349509a2efc
Merge: 5b26c0e 3d8af66
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon May 17 12:01:20 2021 -0400
Merge branch '14' into f33
commit 3d8af661ad151c39ed6fefb311b3d4723433126c
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon May 17 11:17:58 2021 -0400
Update to 14.17.0
https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.m...
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/0001-Disable-running-gyp-on-shared-deps.patch b/0001-Disable-running-gyp-on-shared-deps.patch
index 1b5cf73..962763f 100644
--- a/0001-Disable-running-gyp-on-shared-deps.patch
+++ b/0001-Disable-running-gyp-on-shared-deps.patch
@@ -1,4 +1,4 @@
-From 0a889af5ee18290d833f7f63742d5b714bdb1a40 Mon Sep 17 00:00:00 2001
+From 867d8911b63b9837d89cd6ba65ea6ebccd7f77e7 Mon Sep 17 00:00:00 2001
From: Zuzana Svetlikova <zsvetlik(a)redhat.com>
Date: Fri, 17 Apr 2020 12:59:44 +0200
Subject: [PATCH 1/3] Disable running gyp on shared deps
@@ -8,7 +8,7 @@ Subject: [PATCH 1/3] Disable running gyp on shared deps
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
-index 93d63110ae2e3928a95d24036b86d11885ab240f..79caaec2112cefa8f6a1c947375b517e9676f176 100644
+index 5bb5d7df5f87e2b1d640e027fd4d0c21975959f7..fc812607ac76fadbbc9f4670a479a040a5024780 100644
--- a/Makefile
+++ b/Makefile
@@ -136,11 +136,11 @@ endif
diff --git a/0002-Install-both-binaries-and-use-libdir.patch b/0002-Install-both-binaries-and-use-libdir.patch
index 9679f8b..94943d1 100644
--- a/0002-Install-both-binaries-and-use-libdir.patch
+++ b/0002-Install-both-binaries-and-use-libdir.patch
@@ -1,4 +1,4 @@
-From 4012d5b9ae521f36c8b0155f591a38383e84407b Mon Sep 17 00:00:00 2001
+From ea59ced68789dc24c95572b84091afcebe9acb98 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade <quantum.analyst(a)gmail.com>
Date: Tue, 19 Mar 2019 23:22:40 -0400
Subject: [PATCH 2/3] Install both binaries and use libdir.
@@ -13,7 +13,7 @@ Signed-off-by: Elliott Sales de Andrade <quantum.analyst(a)gmail.com>
2 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/configure.py b/configure.py
-index e6f7e4db0040dda00e432352afa7576535d9b672..6cf5c45dde79ce355b532c2f11b5b7ed80fde88a 100755
+index a477bd1c9578d03cd81456c513486620435749ee..3067eb9fc3e5c3eb22eb4ff3d20f87415b115bb8 100755
--- a/configure.py
+++ b/configure.py
@@ -624,10 +624,16 @@ parser.add_option('--shared',
@@ -46,7 +46,7 @@ index e6f7e4db0040dda00e432352afa7576535d9b672..6cf5c45dde79ce355b532c2f11b5b7ed
shlib_suffix = 'so'
elif sys.platform == 'darwin':
diff --git a/tools/install.py b/tools/install.py
-index 729b416fc47d3ff3317ae3671dee977c719a8841..9bfc6234edb7732f9b90f063c2ee4a276e840636 100755
+index 693faff4c37ac4d83a47e818f4412900497a2b62..7c0b1ba999cdeacd3431b5334d650677754a9752 100755
--- a/tools/install.py
+++ b/tools/install.py
@@ -119,26 +119,23 @@ def subdir_files(path, dest, action):
diff --git a/0003-src-add-.note.GNU-stack-section.patch b/0003-src-add-.note.GNU-stack-section.patch
index 74fd28f..f943f9c 100644
--- a/0003-src-add-.note.GNU-stack-section.patch
+++ b/0003-src-add-.note.GNU-stack-section.patch
@@ -1,4 +1,4 @@
-From 6aa11a8cf48463432c0b5c6bfca5c2a5b18b1cc7 Mon Sep 17 00:00:00 2001
+From 7388d30b111414507b1353da12529f23daec4ee3 Mon Sep 17 00:00:00 2001
From: James Addison <jay(a)jp-hosting.net>
Date: Tue, 9 Mar 2021 13:08:47 +0000
Subject: [PATCH 3/3] src: add .note.GNU-stack section
@@ -24,22 +24,22 @@ Related: https://github.com/nodejs/node/pull/37688
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
---
- src/large_pages/node_text_start.S | 3 +++
- 1 file changed, 3 insertions(+)
+ src/large_pages/node_text_start.S | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/large_pages/node_text_start.S b/src/large_pages/node_text_start.S
-index 1609b254f0495a32f8896ba96d96bad03f6f2321..d27dd39cc236f0e6be4e68113bfff7b531a37455 100644
+index 3227b62464932ced6d42916a4300ddbd9b4a4fbb..d27dd39cc236f0e6be4e68113bfff7b531a37455 100644
--- a/src/large_pages/node_text_start.S
+++ b/src/large_pages/node_text_start.S
-@@ -1,5 +1,8 @@
-+#if defined(__ELF__)
+@@ -1,7 +1,7 @@
+ #if defined(__ELF__)
+-.section .note.GNU-stack,"",@progbits
+.section .note.GNU-stack,"",%progbits
-+#endif
+ #endif
.text
.align 0x2000
.global __node_text_start
.hidden __node_text_start
- __node_text_start:
--
2.31.1
diff --git a/nodejs.spec b/nodejs.spec
index 4993651..e55b7e4 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -8,7 +8,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 2
+%global baserelease 1
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -19,8 +19,8 @@
# than a Fedora release lifecycle.
%global nodejs_epoch 1
%global nodejs_major 14
-%global nodejs_minor 16
-%global nodejs_patch 1
+%global nodejs_minor 17
+%global nodejs_patch 0
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -36,7 +36,7 @@
%global v8_major 8
%global v8_minor 4
%global v8_build 371
-%global v8_patch 19
+%global v8_patch 23
# V8 presently breaks ABI at least every x.y release while never bumping SONAME
%global v8_abi %{v8_major}.%{v8_minor}
%global v8_version %{v8_major}.%{v8_minor}.%{v8_build}.%{v8_patch}
@@ -45,7 +45,7 @@
# c-ares - from deps/cares/include/ares_version.h
# https://github.com/nodejs/node/pull/9332
%global c_ares_major 1
-%global c_ares_minor 16
+%global c_ares_minor 17
%global c_ares_patch 1
%global c_ares_version %{c_ares_major}.%{c_ares_minor}.%{c_ares_patch}
@@ -57,19 +57,19 @@
# libuv - from deps/uv/include/uv/version.h
%global libuv_major 1
-%global libuv_minor 40
+%global libuv_minor 41
%global libuv_patch 0
%global libuv_version %{libuv_major}.%{libuv_minor}.%{libuv_patch}
# nghttp2 - from deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h
%global nghttp2_major 1
-%global nghttp2_minor 41
+%global nghttp2_minor 42
%global nghttp2_patch 0
%global nghttp2_version %{nghttp2_major}.%{nghttp2_minor}.%{nghttp2_patch}
# ICU - from tools/icu/current_ver.dep
-%global icu_major 67
-%global icu_minor 1
+%global icu_major 68
+%global icu_minor 2
%global icu_version %{icu_major}.%{icu_minor}
%global icudatadir %{nodejs_datadir}/icudata
@@ -92,7 +92,7 @@
%global npm_epoch 1
%global npm_major 6
%global npm_minor 14
-%global npm_patch 12
+%global npm_patch 13
%global npm_version %{npm_major}.%{npm_minor}.%{npm_patch}
# uvwasi - from deps/uvwasi/include/uvwasi.h
@@ -669,6 +669,10 @@ end
%changelog
+* Mon May 17 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.17.0-2
+- Update to 14.17.0
+- https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.m...
+
* Tue Apr 20 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.1-2
- Disable stack execution (bz#1950528)
diff --git a/sources b/sources
index 96692c4..db3ba87 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.16.1-stripped.tar.gz) = 1ec3f503ecd6f8ffa24c3abc04e4e33758e1d577f645dc9c3a22282e3f4755e44169ca54a178fb90e8edb8ef6490d65edc4fd7fcf6ec9b5445d38630b9861a29
-SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
+SHA512 (node-v14.17.0-stripped.tar.gz) = eb1109d13da376df49f3d0b25c21573585c9aec589e9175e182491211bc5b3fd54980f8002ae85544fa9127b95584c030c8f121b6e2520d5f0feb84ef6dab104
+SHA512 (icu4c-68_2-src.tgz) = 24f3b7981667b37df58118f56ae76a09b719358c1efa8d6f044d28ef8df1c722a894957acadfb3c37aee39ac845893924fc3370d6bbe09875aec8d937059f84b
commit b3a32a173864e60e3e3c88c81079b93ec1d44988
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Apr 20 09:43:10 2021 -0400
Truncate %changelog
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index e807c09..4993651 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -686,9 +686,6 @@ end
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.0-1
- Update to 14.16.0
-* Tue Jan 26 2021 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:14.15.4-2
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
-
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.4-1
- Update to 14.15.4
@@ -750,414 +747,3 @@ end
- Update to 14.0.0
- v14.x should be python3 compatible, so commented out py sed scripts
-* Wed Apr 15 2020 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:13.13.0-1
-- Update to 13.13.0
-- Add bundled uvwasi and histogram_c provides
-- Add shared brotli dependency
-- Remove icustrip.py patch, which was merged in upstream
-
-* Tue Mar 17 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:13.11.0-2
-- Fix python3 issue in icustrip.py
-
-* Mon Mar 16 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:13.11.0-1
-- Update to 13.11.0
-
-* Wed Feb 26 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:13.9.0-2
-- Build with python 3 only
-
-* Tue Feb 25 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:13.9.0-1
-- Release Node.js 13.9.0
-
-* Tue Feb 25 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.16.1-1
-- Update to 12.16.1
-- Fixes six regressions introduced in 12.16.0
-
-* Fri Feb 14 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.16.0-1
-- Update to 12.16.0
-- Drop upstreamed patch
-
-* Thu Feb 06 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.15.0-1
-- Update to 12.15.0
-
-* Wed Jan 29 2020 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:12.14.1-4
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
-
-* Mon Jan 13 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.14.1-3
-- Fix issue with header symlinks in v8-devel
-
-* Tue Jan 07 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.14.1-2
-- Drop unneeded dependency on http-parser-devel
-
-* Tue Jan 07 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.14.1-1
-- Update to 12.14.1
-- https://github.com/nodejs/node/blob/v12.14.1/doc/changelogs/CHANGELOG_V12.md
-
-* Mon Jan 06 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.14.0-2
-- Update to 12.14.0
-- https://github.com/nodejs/node/blob/v12.14.0/doc/changelogs/CHANGELOG_V12.md
-- Add new subpackage nodejs-full-i18n to enable optional non-English locale
- support
-- Update documentation packaging for NPM
-
-* Mon Dec 02 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.13.1-1
-- Update to 12.13.1
-- https://github.com/nodejs/node/blob/v12.13.1/doc/changelogs/CHANGELOG_V12.md
-
-* Tue Oct 29 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.13.0-6
-- Add proper i18n support
-
-* Tue Oct 29 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.13.0-5
-- Fix issue with NPM docs being replaced with a symlink
-
-* Mon Oct 28 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.13.0-2
-- Simplify npmrc default configuration
-
-* Mon Oct 28 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.13.0-1
-- Update to 12.13.0 (LTS)
-- https://github.com/nodejs/node/blob/v12.13.0/doc/changelogs/CHANGELOG_V12.md
-- NPM no longer clobbers RPM-installed Node.js modules
-- Drop no-longer needed patch to suppress `npm update -g npm` message
-
-* Wed Sep 04 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.10.0-1
-- Update to 12.10.0
-- https://github.com/nodejs/node/blob/v12.10.0/doc/changelogs/CHANGELOG_V12...
-
-* Wed Aug 21 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.9.0-1
-- Update to 12.9.0
-- https://github.com/nodejs/node/blob/v12.9.0/doc/changelogs/CHANGELOG_V12....
-
-* Thu Aug 15 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.8.2-1
-- Update to 12.8.1
-- Resolves: CVE-2019-9511 "Data Dribble"
-- Resolves: CVE-2019-9512 "Ping Flood"
-- Resolves: CVE-2019-9513 "Resource Loop"
-- Resolves: CVE-2019-9514 "Reset Flood"
-- Resolves: CVE-2019-9515 "Settings Flood"
-- Resolves: CVE-2019-9516 "0-Length Headers Leak"
-- Resolves: CVE-2019-9517 "Internal Data Buffering"
-- Resolves: CVE-2019-9518 "Empty Frames Flood"
-- https://github.com/nodejs/node/blob/v12.8.1/doc/changelogs/CHANGELOG_V12....
-
-* Mon Aug 05 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.7.0-3
-- Fix epoch dependencies
-- Carry data files for ICU
-
-* Fri Aug 02 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.7.0-2
-- Change v8-devel release field to avoid duplicated package names
-
-* Thu Aug 01 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.7.0-1
-- Update to 12.7.0
-- https://nodejs.org/en/blog/release/v12.7.0/
-
-* Tue Jul 30 2019 Tom Hughes <tom(a)compton.nu> - 1:12.6.0-2
-- Bump release to fix dependencies
-
-* Thu Jul 25 2019 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:12.6.0-1.1
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
-
-* Thu Jun 27 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.6.0-1
-- Update to 12.6.0
-- https://nodejs.org/en/blog/release/v12.6.0/
-- https://nodejs.org/en/blog/release/v12.5.0/
-
-* Tue Jun 04 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.4.0-1
-- Update to 12.4.0
-- https://nodejs.org/en/blog/release/v12.4.0/
-
-* Fri May 24 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.3.1-1
-- Update to 12.3.1
-- https://nodejs.org/en/blog/release/v12.3.1/
-- https://nodejs.org/en/blog/release/v12.3.0/
-
-* Wed May 15 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.2.0-1
-- Update to 12.2.0
-- https://nodejs.org/en/blog/release/v12.2.0/
-
-* Tue Apr 30 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.1.0-1
-- Update to 12.1.0
-- https://nodejs.org/en/blog/release/v12.1.0/
-
-* Wed Apr 24 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.0.0-3
-- Fix upgrade bug for v8-devel (BZ #1702609)
-
-* Tue Apr 23 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.0.0-2
-- Node.js 12.x requires OpenSSL 1.1.1+
-
-* Tue Apr 23 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:12.0.0-1
-- Release 12.0.0
-- https://nodejs.org/en/blog/release/v12.0.0/
-
-* Thu Apr 11 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:11.13.0-1
-- Update to 11.13.0
-- https://nodejs.org/en/blog/release/v11.13.0/
-- https://nodejs.org/en/blog/release/v11.12.0/
-- https://nodejs.org/en/blog/release/v11.11.0/
-
-* Fri Mar 01 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:11.10.1-1
-- Update to 11.10.1
-- https://nodejs.org/en/blog/release/v11.10.1/
-- https://nodejs.org/en/blog/release/v11.10.0/
-- https://nodejs.org/en/blog/release/v11.9.0/
-- https://nodejs.org/en/blog/release/v11.8.0/
-
-* Fri Jan 18 2019 Stephen Gallagher <sgallagh(a)redhat.com> - 1:11.7.0-1
-- Update to 11.7.0
-- https://nodejs.org/en/blog/release/v11.7.0/
-- https://nodejs.org/en/blog/release/v11.6.0/
-- https://nodejs.org/en/blog/release/v11.5.0/
-- https://nodejs.org/en/blog/release/v11.4.0/
-
-* Thu Nov 29 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:11.3.0-1
-- Update to 11.3.0
-- https://nodejs.org/en/blog/release/v11.2.0/
-- https://nodejs.org/en/blog/release/v11.3.0/
-
-* Fri Nov 02 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:11.1.0-1
-- Update to 11.1.0
-- https://nodejs.org/en/blog/release/v11.1.0/
-
-* Thu Nov 01 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:11.0.0-1
-- Update to 11.0.0
-- https://nodejs.org/en/blog/release/v11.0.0/
-
-* Thu Nov 01 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.13.0-1
-- Update to 10.13.0
-- https://nodejs.org/en/blog/release/v10.13.0/
-
-* Thu Oct 11 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.12.0-1
-- Update to 10.12.0
-- https://nodejs.org/en/blog/release/v10.12.0/
-
-* Wed Oct 10 2018 Jan Staněk <jstanek(a)redhat.com> - 1:10.11.0-2
-- Add non-bootstrap BR for nodejs-packaging
-
-* Thu Sep 20 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.11.0-1
-- Update to 10.11.0
-- https://nodejs.org/en/blog/release/v10.11.0/
-
-* Wed Sep 19 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.10.0-2
-- Really, finally fix npm dep executable permissions
-
-* Tue Sep 11 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.10.0-1
-- Update to 10.10.0
-- https://nodejs.org/en/blog/release/v10.10.0/
-- Fix issue with npm permissions
-
-* Tue Aug 21 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.9.0-2
-- Clean up automatic dependencies for npm
-
-* Thu Aug 16 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.9.0-1
-- Update to 10.9.0
-- https://nodejs.org/en/blog/release/v10.9.0/
-
-* Tue Aug 07 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.8.0-1
-- Update to 10.8.0
-- https://nodejs.org/en/blog/release/v10.8.0/
-
-* Fri Jul 20 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.7.0-4
-- Fix npm upgrade scriptlet
-- Fix unexpected trailing .1 in npm release field
-
-* Fri Jul 20 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.7.0-3
-- Restore annotations to binaries
-- Fix unexpected trailing .1 in release field
-
-* Thu Jul 19 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.7.0-2
-- Update to 10.7.0
-- https://nodejs.org/en/blog/release/v10.7.0/
-- https://nodejs.org/en/blog/release/v10.6.0/
-
-* Fri Jul 13 2018 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:10.5.0-1.1
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
-
-* Thu Jun 21 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.5.0-1
-- Update to 10.5.0
-- https://nodejs.org/en/blog/release/v10.5.0/
-
-* Thu Jun 14 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.4.1-1
-- Update to 10.4.1 to address security issues
-- https://nodejs.org/en/blog/release/v10.4.1/
-- Resolves: rhbz#1590801
-- Resolves: rhbz#1591014
-- Resolves: rhbz#1591019
-
-* Thu Jun 07 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.4.0-1
-- Update to 10.4.0
-- https://nodejs.org/en/blog/release/v10.4.0/
-
-* Wed May 30 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.3.0-1
-- Update to 10.3.0
-- Update npm to 6.1.0
-- https://nodejs.org/en/blog/release/v10.3.0/
-
-* Tue May 29 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.2.1-2
-- Fix up bare 'python' to be python2
-- Drop redundant entry in docs section
-
-* Fri May 25 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.2.1-1
-- Update to 10.2.1
-- https://nodejs.org/en/blog/release/v10.2.1/
-
-* Wed May 23 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.2.0-1
-- Update to 10.2.0
-- https://nodejs.org/en/blog/release/v10.2.0/
-
-* Thu May 10 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.1.0-3
-- Fix incorrect rpm macro
-
-* Thu May 10 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.1.0-2
-- Include upstream v8 fix for ppc64[le]
-- Disable debug build on ppc64[le] and s390x
-
-* Wed May 09 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.1.0-1
-- Update to 10.1.0
-- https://nodejs.org/en/blog/release/v10.1.0/
-- Reenable node_g binary
-
-* Thu Apr 26 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:10.0.0-1
-- Update to 10.0.0
-- https://nodejs.org/en/blog/release/v10.0.0/
-- Drop workaround patch
-- Temporarily drop node_g binary due to
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85587
-
-* Fri Apr 13 2018 Rafael dos Santos <rdossant(a)redhat.com> - 1:9.11.1-2
-- Use standard Fedora linker flags (bug #1543859)
-
-* Thu Apr 05 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.11.1-1
-- Update to 9.11.1
-- https://nodejs.org/en/blog/release/v9.11.0/
-- https://nodejs.org/en/blog/release/v9.11.1/
-
-* Wed Mar 28 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.10.0-1
-- Update to 9.10.0
-- https://nodejs.org/en/blog/release/v9.10.0/
-
-* Wed Mar 21 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.9.0-1
-- Update to 9.9.0
-- https://nodejs.org/en/blog/release/v9.9.0/
-
-* Thu Mar 08 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.8.0-1
-- Update to 9.8.0
-- https://nodejs.org/en/blog/release/v9.8.0/
-
-* Thu Mar 01 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.7.0-1
-- Update to 9.7.0
-- https://nodejs.org/en/blog/release/v9.7.0/
-- Work around F28 build issue
-
-* Sun Feb 25 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.6.1-1
-- Update to 9.6.1
-- https://nodejs.org/en/blog/release/v9.6.1/
-- https://nodejs.org/en/blog/release/v9.6.0/
-
-* Mon Feb 05 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:9.5.0-1
-- Package Node.js 9.5.0
-
-* Thu Jan 11 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.9.4-2
-- Fix incorrect Requires:
-
-* Thu Jan 11 2018 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.9.4-1
-- Update to 8.9.4
-- https://nodejs.org/en/blog/release/v8.9.4/
-- Switch to system copy of nghttp2
-
-* Fri Dec 08 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.9.3-2
-- Update to 8.9.3
-- https://nodejs.org/en/blog/release/v8.9.3/
-- https://nodejs.org/en/blog/release/v8.9.2/
-
-* Thu Nov 30 2017 Pete Walter <pwalter(a)fedoraproject.org> - 1:8.9.1-2
-- Rebuild for ICU 60.1
-
-* Thu Nov 09 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.9.1-1
-- Update to 8.9.1
-
-* Tue Oct 31 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.9.0-1
-- Update to 8.9.0
-- Drop upstreamed patch
-
-* Thu Oct 26 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.8.1-1
-- Update to 8.8.1 to fix a regression
-
-* Wed Oct 25 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.8.0-1
-- Security update to 8.8.0
-- https://nodejs.org/en/blog/release/v8.8.0/
-
-* Sun Oct 15 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.7.0-1
-- Update to 8.7.0
-- https://nodejs.org/en/blog/release/v8.7.0/
-
-* Fri Oct 06 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.6.0-2
-- Use bcond macro instead of bootstrap conditional
-
-* Wed Sep 27 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.6.0-1
-- Fix nghttp2 version
-- Update to 8.6.0
-- https://nodejs.org/en/blog/release/v8.6.0/
-
-* Wed Sep 20 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.5.0-3
-- Build with bootstrap + bundle libuv for modularity
-- backport patch for aarch64 debug build
-
-* Wed Sep 13 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.5.0-2
-- Disable debug builds on aarch64 due to https://github.com/nodejs/node/issues/15395
-
-* Tue Sep 12 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.5.0-1
-- Update to v8.5.0
-- https://nodejs.org/en/blog/release/v8.5.0/
-
-* Thu Sep 07 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.4.0-2
-- Refactor openssl BR
-
-* Wed Aug 16 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.4.0-1
-- Update to v8.4.0
-- https://nodejs.org/en/blog/release/v8.4.0/
-- http2 is now supported, add bundled nghttp2
-- remove openssl 1.0.1 patches, we won't be using them in fedora
-
-* Thu Aug 10 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.3.0-1
-- Update to v8.3.0
-- https://nodejs.org/en/blog/release/v8.3.0/
-- update V8 to 6.0
-- update minimal gcc and g++ requirements to 4.9.4
-
-* Wed Aug 09 2017 Tom Hughes <tom(a)compton.nu> - 1:8.2.1-2
-- Bump release to fix broken dependencies
-
-* Thu Aug 03 2017 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:8.2.1-1.2
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
-
-* Wed Jul 26 2017 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:8.2.1-1.1
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
-
-* Fri Jul 21 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.2.1-1
-- Update to v8.2.1
-- https://nodejs.org/en/blog/release/v8.2.1/
-
-* Thu Jul 20 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.2.0-1
-- Update to v8.2.0
-- https://nodejs.org/en/blog/release/v8.2.0/
-- Update npm to 5.3.0
-- Adds npx command
-
-* Tue Jul 18 2017 Igor Gnatenko <ignatenko(a)redhat.com> - 1:8.1.4-3
-- s/BuildRequires/Requires/ for http-parser-devel%%{?_isa}
-
-* Mon Jul 17 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.1.4-2
-- Rename python-devel to python2-devel
-- own %%{_pkgdocdir}/npm
-
-* Tue Jul 11 2017 Stephen Gallagher <sgallagh(a)redhat.com> - 1:8.1.4-1
-- Update to v8.1.4
-- https://nodejs.org/en/blog/release/v8.1.4/
-- Drop upstreamed c-ares patch
-
-* Thu Jun 29 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.1.3-1
-- Update to v8.1.3
-- https://nodejs.org/en/blog/release/v8.1.3/
-
-* Wed Jun 28 2017 Zuzana Svetlikova <zsvetlik(a)redhat.com> - 1:8.1.2-1
-- Update to v8.1.2
-- remove GCC 7 patch, as it is now fixed in node >= 6.12
-
commit 32edd143c20830bf393c7563daa1a2ca024b0eb2
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Apr 20 09:35:18 2021 -0400
Disable stack execution
Resolves: rhbz#1950528
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/0001-Disable-running-gyp-on-shared-deps.patch b/0001-Disable-running-gyp-on-shared-deps.patch
index 361ea08..1b5cf73 100644
--- a/0001-Disable-running-gyp-on-shared-deps.patch
+++ b/0001-Disable-running-gyp-on-shared-deps.patch
@@ -1,7 +1,7 @@
-From b0b4d1ddbc720db73fb8ab13cdbbf1ce6524eebd Mon Sep 17 00:00:00 2001
+From 0a889af5ee18290d833f7f63742d5b714bdb1a40 Mon Sep 17 00:00:00 2001
From: Zuzana Svetlikova <zsvetlik(a)redhat.com>
Date: Fri, 17 Apr 2020 12:59:44 +0200
-Subject: [PATCH 1/2] Disable running gyp on shared deps
+Subject: [PATCH 1/3] Disable running gyp on shared deps
---
Makefile | 2 +-
@@ -25,5 +25,5 @@ index 93d63110ae2e3928a95d24036b86d11885ab240f..79caaec2112cefa8f6a1c947375b517e
# node_version.h is listed because the N-API version is taken from there
--
-2.29.2
+2.31.1
diff --git a/0002-Install-both-binaries-and-use-libdir.patch b/0002-Install-both-binaries-and-use-libdir.patch
index 1dc8b12..9679f8b 100644
--- a/0002-Install-both-binaries-and-use-libdir.patch
+++ b/0002-Install-both-binaries-and-use-libdir.patch
@@ -1,7 +1,7 @@
-From 45a9bca165f6ed76c4e43cc2cc3fdf596814bc77 Mon Sep 17 00:00:00 2001
+From 4012d5b9ae521f36c8b0155f591a38383e84407b Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade <quantum.analyst(a)gmail.com>
Date: Tue, 19 Mar 2019 23:22:40 -0400
-Subject: [PATCH 2/2] Install both binaries and use libdir.
+Subject: [PATCH 2/3] Install both binaries and use libdir.
This allows us to build with a shared library for other users while
still providing the normal executable.
@@ -86,5 +86,5 @@ index 729b416fc47d3ff3317ae3671dee977c719a8841..9bfc6234edb7732f9b90f063c2ee4a27
# behave similarly for systemtap
--
-2.29.2
+2.31.1
diff --git a/0003-src-add-.note.GNU-stack-section.patch b/0003-src-add-.note.GNU-stack-section.patch
new file mode 100644
index 0000000..74fd28f
--- /dev/null
+++ b/0003-src-add-.note.GNU-stack-section.patch
@@ -0,0 +1,45 @@
+From 6aa11a8cf48463432c0b5c6bfca5c2a5b18b1cc7 Mon Sep 17 00:00:00 2001
+From: James Addison <jay(a)jp-hosting.net>
+Date: Tue, 9 Mar 2021 13:08:47 +0000
+Subject: [PATCH 3/3] src: add .note.GNU-stack section
+
+This indicates to GNU binutils that it can unset the executable stack
+flag on the binary that it is building.
+
+PR-URL: https://github.com/nodejs/node/pull/37688
+Refs: https://github.com/nodejs/node/issues/17933
+Reviewed-By: Daniel Bevenius <daniel.bevenius(a)gmail.com>
+
+src: Use %progbits instead of @progbits
+
+While @progbits is preferred for most architectures, there are some
+(notably 32-bit ARM) for which it does not. %progbits is effective
+everywhere.
+
+See https://bugzilla.redhat.com/show_bug.cgi?id=1950528 for more
+details.
+
+Related: https://github.com/nodejs/node/issues/17933
+Related: https://github.com/nodejs/node/pull/37688
+
+Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
+---
+ src/large_pages/node_text_start.S | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/large_pages/node_text_start.S b/src/large_pages/node_text_start.S
+index 1609b254f0495a32f8896ba96d96bad03f6f2321..d27dd39cc236f0e6be4e68113bfff7b531a37455 100644
+--- a/src/large_pages/node_text_start.S
++++ b/src/large_pages/node_text_start.S
+@@ -1,5 +1,8 @@
++#if defined(__ELF__)
++.section .note.GNU-stack,"",%progbits
++#endif
+ .text
+ .align 0x2000
+ .global __node_text_start
+ .hidden __node_text_start
+ __node_text_start:
+--
+2.31.1
+
diff --git a/nodejs.spec b/nodejs.spec
index a4eb5e2..e807c09 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -8,7 +8,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 1
+%global baserelease 2
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -145,6 +145,10 @@ Patch1: 0001-Disable-running-gyp-on-shared-deps.patch
# Patch to install both node and libnode.so, using the correct libdir
Patch2: 0002-Install-both-binaries-and-use-libdir.patch
+# Patch to disable stack execution. Merged from one upstream patch and
+# one upstream proposed patch
+Patch3: 0003-src-add-.note.GNU-stack-section.patch
+
BuildRequires: make
BuildRequires: python3-devel
BuildRequires: python3-setuptools
@@ -665,6 +669,9 @@ end
%changelog
+* Tue Apr 20 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.1-2
+- Disable stack execution (bz#1950528)
+
* Thu Apr 08 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.1-1
- Update to 14.16.1
commit 4fb06444126942877fd999911ffdc1edde41a5e2
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon Jan 18 12:47:39 2021 -0500
Simplify handling of unversioned python
Now that /usr/bin/python == python3, we can just BR: the
python-unversioned-command package instead of doing a complicated
search and replace through the codebase.
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 10fdeaa..a4eb5e2 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -1,6 +1,5 @@
# bundle dependencies that are not available as Fedora modules
%bcond_with bootstrap
-%bcond_without python3_fixup
# LTO is currently broken on Node.js builds
%define _lto_cflags %{nil}
@@ -149,6 +148,7 @@ Patch2: 0002-Install-both-binaries-and-use-libdir.patch
BuildRequires: make
BuildRequires: python3-devel
BuildRequires: python3-setuptools
+BuildRequires: python-unversioned-command
BuildRequires: zlib-devel
BuildRequires: brotli-devel
BuildRequires: gcc >= 6.3.0
@@ -358,16 +358,6 @@ The API documentation for the Node.js JavaScript runtime.
rm -rf deps/zlib
rm -rf deps/brotli
-# Replace any instances of unversioned python' with python3
-%if %{with python3_fixup}
-pathfix.py -i %{__python3} -pn $(find -type f ! -name "*.js")
-find . -type f -exec sed -i "s~/usr\/bin\/env python~/usr/bin/python3~" {} \;
-find . -type f -exec sed -i "s~/usr\/bin\/python\W~/usr/bin/python3~" {} \;
-sed -i "s~python~python3~" $(find . -type f | grep "gyp$")
-sed -i "s~usr\/bin\/python2~usr\/bin\/python3~" ./deps/v8/tools/gen-inlining-tests.py
-sed -i "s~usr\/bin\/python.*$~usr\/bin\/python3~" ./deps/v8/tools/mb/mb_unittest.py
-find . -type f -exec sed -i "s~python -c~python3 -c~" {} \;
-%endif
%build
# When compiled on armv7hl this package generates an out of range
commit 3ce811c32fe85e6689e386345f72b30127321727
Merge: d51feae 0e63a14
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Thu Apr 8 12:26:38 2021 -0400
Merge branch '14' into rawhide
diff --cc nodejs.spec
index 80b9828,c2d4caf..10fdeaa
--- a/nodejs.spec
+++ b/nodejs.spec
@@@ -675,9 -675,9 +675,12 @@@ en
%changelog
+ * Thu Apr 08 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.1-1
+ - Update to 14.16.1
+
+* Wed Mar 31 2021 Jonathan Wakely <jwakely(a)redhat.com> - 1:14.16.0-4
+- Rebuilt for removed libstdc++ symbols (#1937698)
+
* Tue Mar 09 2021 Zuzana Svetlikova <zsvetlik(a)redhat.com - 1:14.16.0-3
- Only require nodejs-packaging on Fedora
- remove --debug-nghttp2 (#1930775)
commit 0e63a1498397f5001f7298bc5f7c5ba39563d17c
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Thu Apr 8 12:25:10 2021 -0400
Fix package.cfg
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/package.cfg b/package.cfg
index ceab82f..5e7e859 100644
--- a/package.cfg
+++ b/package.cfg
@@ -1,2 +1,2 @@
[koji]
-targets = master f34 f33
+targets = rawhide f34 f33
commit 37e035e7684ee405ab3b90e4f6cc2ffe0940faa5
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Thu Apr 8 12:23:11 2021 -0400
Update to 14.16.1
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 730889d..c2d4caf 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -9,7 +9,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 3
+%global baserelease 1
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -21,7 +21,7 @@
%global nodejs_epoch 1
%global nodejs_major 14
%global nodejs_minor 16
-%global nodejs_patch 0
+%global nodejs_patch 1
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -93,7 +93,7 @@
%global npm_epoch 1
%global npm_major 6
%global npm_minor 14
-%global npm_patch 11
+%global npm_patch 12
%global npm_version %{npm_major}.%{npm_minor}.%{npm_patch}
# uvwasi - from deps/uvwasi/include/uvwasi.h
@@ -675,6 +675,9 @@ end
%changelog
+* Thu Apr 08 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.1-1
+- Update to 14.16.1
+
* Tue Mar 09 2021 Zuzana Svetlikova <zsvetlik(a)redhat.com - 1:14.16.0-3
- Only require nodejs-packaging on Fedora
- remove --debug-nghttp2 (#1930775)
diff --git a/sources b/sources
index b355517..96692c4 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.16.0-stripped.tar.gz) = 817683b85eb47aa976f90b26e6e4a582ad67e7a2f48841be7ca378af46e87434d55fbc894e262889d07283775946348cb3fad152c488ce0c2199eba742018094
+SHA512 (node-v14.16.1-stripped.tar.gz) = 1ec3f503ecd6f8ffa24c3abc04e4e33758e1d577f645dc9c3a22282e3f4755e44169ca54a178fb90e8edb8ef6490d65edc4fd7fcf6ec9b5445d38630b9861a29
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit d51feaec0d8b415a6392576bc5790ede5a994a98
Author: Jonathan Wakely <jwakely(a)redhat.com>
Date: Wed Mar 31 17:35:43 2021 +0100
Rebuilt for removed libstdc++ symbols (#1937698)
diff --git a/nodejs.spec b/nodejs.spec
index 730889d..80b9828 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -9,7 +9,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 3
+%global baserelease 4
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -675,6 +675,9 @@ end
%changelog
+* Wed Mar 31 2021 Jonathan Wakely <jwakely(a)redhat.com> - 1:14.16.0-4
+- Rebuilt for removed libstdc++ symbols (#1937698)
+
* Tue Mar 09 2021 Zuzana Svetlikova <zsvetlik(a)redhat.com - 1:14.16.0-3
- Only require nodejs-packaging on Fedora
- remove --debug-nghttp2 (#1930775)
commit 562828877ed4f5cfa589da19a7001785f8b22008
Author: Zuzana Svetlikova <zsvetlik(a)redhat.com>
Date: Tue Mar 9 18:26:30 2021 +0100
Only require nodejs-packaging on Fedora
remove --debug-nghttp2 (#1930775)
always build with systemtap
diff --git a/nodejs.spec b/nodejs.spec
index dabb932..730889d 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -9,7 +9,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 2
+%global baserelease 3
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -159,12 +159,12 @@ BuildRequires: gcc-c++ >= 6.3.0
BuildRequires: nodejs-packaging
BuildRequires: chrpath
BuildRequires: libatomic
+BuildRequires: systemtap-sdt-devel
%if %{with bootstrap}
Provides: bundled(libuv) = %{libuv_version}
Provides: bundled(nghttp2) = %{nghttp2_version}
%else
-BuildRequires: systemtap-sdt-devel
BuildRequires: libuv-devel >= 1:%{libuv_version}
Requires: libuv >= 1:%{libuv_version}
BuildRequires: libnghttp2-devel >= %{nghttp2_version}
@@ -235,8 +235,10 @@ Provides: bundled(icu) = %{icu_version}
Provides: bundled(uvwasi) = %{uvwasi_version}
Provides: bundled(histogram) = %{histogram_version}
+%if 0%{?fedora}
# Make sure to pull in the appropriate packaging macros when building RPMs
Requires: (nodejs-packaging if rpm-build)
+%endif
# Make sure we keep NPM up to date when we update Node.js
Recommends: npm >= %{npm_epoch}:%{npm_version}-%{npm_release}%{?dist}
@@ -412,7 +414,6 @@ export LDFLAGS="%{build_ldflags}"
--shared-brotli \
--without-dtrace \
--with-intl=small-icu \
- --debug-nghttp2 \
--openssl-use-def-ca-store
%else
%{__python3} configure.py --prefix=%{_prefix} \
@@ -426,7 +427,6 @@ export LDFLAGS="%{build_ldflags}"
--with-dtrace \
--with-intl=small-icu \
--with-icu-default-data-dir=%{icudatadir} \
- --debug-nghttp2 \
--openssl-use-def-ca-store
%endif
@@ -675,6 +675,11 @@ end
%changelog
+* Tue Mar 09 2021 Zuzana Svetlikova <zsvetlik(a)redhat.com - 1:14.16.0-3
+- Only require nodejs-packaging on Fedora
+- remove --debug-nghttp2 (#1930775)
+- always build with systemtap
+
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.0-1
- Update to 14.16.0
commit 095039c5a9ea57e731cd96b54d204dec1ca29333
Author: Zuzana Svetlikova <zsvetlik(a)redhat.com>
Date: Tue Mar 9 18:26:30 2021 +0100
Only require nodejs-packaging on Fedora
remove --debug-nghttp2 (#1930775)
always build with systemtap
diff --git a/nodejs.spec b/nodejs.spec
index dabb932..730889d 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -9,7 +9,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 2
+%global baserelease 3
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -159,12 +159,12 @@ BuildRequires: gcc-c++ >= 6.3.0
BuildRequires: nodejs-packaging
BuildRequires: chrpath
BuildRequires: libatomic
+BuildRequires: systemtap-sdt-devel
%if %{with bootstrap}
Provides: bundled(libuv) = %{libuv_version}
Provides: bundled(nghttp2) = %{nghttp2_version}
%else
-BuildRequires: systemtap-sdt-devel
BuildRequires: libuv-devel >= 1:%{libuv_version}
Requires: libuv >= 1:%{libuv_version}
BuildRequires: libnghttp2-devel >= %{nghttp2_version}
@@ -235,8 +235,10 @@ Provides: bundled(icu) = %{icu_version}
Provides: bundled(uvwasi) = %{uvwasi_version}
Provides: bundled(histogram) = %{histogram_version}
+%if 0%{?fedora}
# Make sure to pull in the appropriate packaging macros when building RPMs
Requires: (nodejs-packaging if rpm-build)
+%endif
# Make sure we keep NPM up to date when we update Node.js
Recommends: npm >= %{npm_epoch}:%{npm_version}-%{npm_release}%{?dist}
@@ -412,7 +414,6 @@ export LDFLAGS="%{build_ldflags}"
--shared-brotli \
--without-dtrace \
--with-intl=small-icu \
- --debug-nghttp2 \
--openssl-use-def-ca-store
%else
%{__python3} configure.py --prefix=%{_prefix} \
@@ -426,7 +427,6 @@ export LDFLAGS="%{build_ldflags}"
--with-dtrace \
--with-intl=small-icu \
--with-icu-default-data-dir=%{icudatadir} \
- --debug-nghttp2 \
--openssl-use-def-ca-store
%endif
@@ -675,6 +675,11 @@ end
%changelog
+* Tue Mar 09 2021 Zuzana Svetlikova <zsvetlik(a)redhat.com - 1:14.16.0-3
+- Only require nodejs-packaging on Fedora
+- remove --debug-nghttp2 (#1930775)
+- always build with systemtap
+
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.0-1
- Update to 14.16.0
commit 867d4da14b272bfdc3514a5decad078503d06328
Merge: 44f3bfe a630cd6
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Feb 23 13:57:03 2021 -0500
Merge branch '14' into rawhide
diff --cc nodejs.spec
index 210889e,8c8be0a..dabb932
--- a/nodejs.spec
+++ b/nodejs.spec
@@@ -675,9 -674,9 +675,12 @@@ en
%changelog
+ * Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.0-1
+ - Update to 14.16.0
+
+* Tue Jan 26 2021 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:14.15.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
+
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.4-1
- Update to 14.15.4
commit a630cd6af9c313edbebc198215cc87e4e96f9c24
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Feb 23 13:53:36 2021 -0500
Update to 14.16.0
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 6717f99..8c8be0a 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -20,8 +20,8 @@
# than a Fedora release lifecycle.
%global nodejs_epoch 1
%global nodejs_major 14
-%global nodejs_minor 15
-%global nodejs_patch 4
+%global nodejs_minor 16
+%global nodejs_patch 0
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -93,7 +93,7 @@
%global npm_epoch 1
%global npm_major 6
%global npm_minor 14
-%global npm_patch 10
+%global npm_patch 11
%global npm_version %{npm_major}.%{npm_minor}.%{npm_patch}
# uvwasi - from deps/uvwasi/include/uvwasi.h
@@ -674,6 +674,9 @@ end
%changelog
+* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.16.0-1
+- Update to 14.16.0
+
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.4-1
- Update to 14.15.4
diff --git a/package.cfg b/package.cfg
index dfe80fb..ceab82f 100644
--- a/package.cfg
+++ b/package.cfg
@@ -1,2 +1,2 @@
[koji]
-targets = master f33
+targets = master f34 f33
diff --git a/sources b/sources
index 3547e12..b355517 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.15.4-stripped.tar.gz) = 2c1d9b67e6b9bbdd960eeb82edfb02c237a7c7190407cf60bf14b02eb2b6143159b6f45e7bddb7c97120eab4faa37455534ab8b90bd4161b6d66dab0a72b122e
+SHA512 (node-v14.16.0-stripped.tar.gz) = 817683b85eb47aa976f90b26e6e4a582ad67e7a2f48841be7ca378af46e87434d55fbc894e262889d07283775946348cb3fad152c488ce0c2199eba742018094
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit 44f3bfe9c7a4919bd088aa95b52546960aa030fb
Author: Fedora Release Engineering <releng(a)fedoraproject.org>
Date: Tue Jan 26 21:35:49 2021 +0000
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng(a)fedoraproject.org>
diff --git a/nodejs.spec b/nodejs.spec
index 00a12d8..210889e 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -9,7 +9,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 1
+%global baserelease 2
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -675,6 +675,9 @@ end
%changelog
+* Tue Jan 26 2021 Fedora Release Engineering <releng(a)fedoraproject.org> - 1:14.15.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
+
* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.4-1
- Update to 14.15.4
commit c2e87c433405746eed5667023febc41fd04dc08a
Author: Tom Stellard <tstellar(a)redhat.com>
Date: Thu Jan 7 05:55:20 2021 +0000
Add BuildRequires: make
https://fedoraproject.org/wiki/Changes/Remove_make_from_BuildRoot
diff --git a/nodejs.spec b/nodejs.spec
index 6717f99..00a12d8 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -146,6 +146,7 @@ Patch1: 0001-Disable-running-gyp-on-shared-deps.patch
# Patch to install both node and libnode.so, using the correct libdir
Patch2: 0002-Install-both-binaries-and-use-libdir.patch
+BuildRequires: make
BuildRequires: python3-devel
BuildRequires: python3-setuptools
BuildRequires: zlib-devel
commit 9f1a56347d44c7841a0d9615b0cdcbd7c17d66c1
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon Jan 4 15:58:35 2021 -0500
Disable LTO
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index dcc511d..6717f99 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -2,11 +2,8 @@
%bcond_with bootstrap
%bcond_without python3_fixup
-# LTO is currently broken on aarch64 builds
-%ifarch aarch64
+# LTO is currently broken on Node.js builds
%define _lto_cflags %{nil}
-%endif
-
# == Master Relase ==
# This is used by both the nodejs package and the npm subpackage thar
commit 74b49c257f94c38b880f43e7e44d4439da4a65fe
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon Jan 4 15:18:59 2021 -0500
Update to 14.15.4
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/0001-Disable-running-gyp-on-shared-deps.patch b/0001-Disable-running-gyp-on-shared-deps.patch
index ef45163..361ea08 100644
--- a/0001-Disable-running-gyp-on-shared-deps.patch
+++ b/0001-Disable-running-gyp-on-shared-deps.patch
@@ -1,18 +1,20 @@
-From 65f5eb67f4691ab535cc00240a00bd33efe29969 Mon Sep 17 00:00:00 2001
+From b0b4d1ddbc720db73fb8ab13cdbbf1ce6524eebd Mon Sep 17 00:00:00 2001
From: Zuzana Svetlikova <zsvetlik(a)redhat.com>
Date: Fri, 17 Apr 2020 12:59:44 +0200
-Subject: [PATCH] 0001
+Subject: [PATCH 1/2] Disable running gyp on shared deps
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
-index 34cdec7f7767b5152678adaeea10a8cf711fb9a8..3b548907033108831e99e054bc84d3ce91daa25c 100644
+index 93d63110ae2e3928a95d24036b86d11885ab240f..79caaec2112cefa8f6a1c947375b517e9676f176 100644
--- a/Makefile
+++ b/Makefile
-@@ -141,7 +141,7 @@ test-code-cache: with-code-cache
- echo "'test-code-cache' target is a noop"
+@@ -136,11 +136,11 @@ endif
+ .PHONY: test-code-cache
+ with-code-cache test-code-cache:
+ $(warning '$@' target is a noop)
out/Makefile: config.gypi common.gypi node.gyp \
- deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \
@@ -20,6 +22,8 @@ index 34cdec7f7767b5152678adaeea10a8cf711fb9a8..3b548907033108831e99e054bc84d3ce
tools/v8_gypfiles/toolchain.gypi tools/v8_gypfiles/features.gypi \
tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp
$(PYTHON) tools/gyp_node.py -f make
+
+ # node_version.h is listed because the N-API version is taken from there
--
-2.25.2
+2.29.2
diff --git a/0002-Install-both-binaries-and-use-libdir.patch b/0002-Install-both-binaries-and-use-libdir.patch
index b3441a7..1dc8b12 100644
--- a/0002-Install-both-binaries-and-use-libdir.patch
+++ b/0002-Install-both-binaries-and-use-libdir.patch
@@ -1,4 +1,4 @@
-From 0b315d55b13d098ce8f3e96d501aeb33152a9e00 Mon Sep 17 00:00:00 2001
+From 45a9bca165f6ed76c4e43cc2cc3fdf596814bc77 Mon Sep 17 00:00:00 2001
From: Elliott Sales de Andrade <quantum.analyst(a)gmail.com>
Date: Tue, 19 Mar 2019 23:22:40 -0400
Subject: [PATCH 2/2] Install both binaries and use libdir.
@@ -9,14 +9,16 @@ still providing the normal executable.
Signed-off-by: Elliott Sales de Andrade <quantum.analyst(a)gmail.com>
---
configure.py | 7 +++++++
- tools/install.py | 29 +++++++++++++----------------
- 2 files changed, 20 insertions(+), 16 deletions(-)
+ tools/install.py | 21 +++++++++------------
+ 2 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/configure.py b/configure.py
-index beb08df0884f7693b6c07d7fb5e85ae7bdcd1d7d..9e364586d4f79322fe53f41915ed7aad0e23a30d 100755
+index e6f7e4db0040dda00e432352afa7576535d9b672..6cf5c45dde79ce355b532c2f11b5b7ed80fde88a 100755
--- a/configure.py
+++ b/configure.py
-@@ -582,6 +582,12 @@ parser.add_option('--shared',
+@@ -624,10 +624,16 @@ parser.add_option('--shared',
+ action='store_true',
+ dest='shared',
help='compile shared library for embedding node in another project. ' +
'(This mode is not officially supported for regular applications)')
@@ -29,7 +31,11 @@ index beb08df0884f7693b6c07d7fb5e85ae7bdcd1d7d..9e364586d4f79322fe53f41915ed7aad
parser.add_option('--without-v8-platform',
action='store_true',
dest='without_v8_platform',
-@@ -1124,6 +1130,7 @@ def configure_node(o):
+ default=False,
+ help='do not initialize v8 platform during node.js startup. ' +
+@@ -1200,10 +1206,11 @@ def configure_node(o):
+ o['variables']['debug_nghttp2'] = 'false'
+
o['variables']['node_no_browser_globals'] = b(options.no_browser_globals)
o['variables']['node_shared'] = b(options.shared)
@@ -37,11 +43,15 @@ index beb08df0884f7693b6c07d7fb5e85ae7bdcd1d7d..9e364586d4f79322fe53f41915ed7aad
node_module_version = getmoduleversion.get_version()
if options.dest_os == 'android':
+ shlib_suffix = 'so'
+ elif sys.platform == 'darwin':
diff --git a/tools/install.py b/tools/install.py
-index 655802980a6ea94d1d4ca1dc63c8c8e905fbb83a..fe4723bf15012c8aacacb0393dc8294c049b0503 100755
+index 729b416fc47d3ff3317ae3671dee977c719a8841..9bfc6234edb7732f9b90f063c2ee4a276e840636 100755
--- a/tools/install.py
+++ b/tools/install.py
-@@ -121,26 +121,23 @@ def subdir_files(path, dest, action):
+@@ -119,26 +119,23 @@ def subdir_files(path, dest, action):
+ for subdir, files_in_path in ret.items():
+ action(files_in_path, subdir + '/')
def files(action):
is_windows = sys.platform == 'win32'
@@ -60,16 +70,8 @@ index 655802980a6ea94d1d4ca1dc63c8c8e905fbb83a..fe4723bf15012c8aacacb0393dc8294c
- output_file += '.dll'
- else:
- output_file = 'lib' + output_file + '.' + variables.get('shlib_suffix')
-- # GYP will output to lib.target except on OS X, this is hardcoded
-- # in its source - see the _InstallableTargetInstallPath function.
-- if sys.platform != 'darwin':
-- output_prefix += 'lib.target/'
+ output_bin = 'node'
+ output_lib = 'libnode.' + variables.get('shlib_suffix')
-+ # GYP will output to lib.target except on OS X, this is hardcoded
-+ # in its source - see the _InstallableTargetInstallPath function.
-+ if sys.platform != 'darwin':
-+ output_libprefix += 'lib.target/'
- if 'false' == variables.get('node_shared'):
- action([output_prefix + output_file], 'bin/' + output_file)
@@ -81,6 +83,8 @@ index 655802980a6ea94d1d4ca1dc63c8c8e905fbb83a..fe4723bf15012c8aacacb0393dc8294c
if 'true' == variables.get('node_use_dtrace'):
action(['out/Release/node.d'], 'lib/dtrace/node.d')
+
+ # behave similarly for systemtap
--
-2.24.1
+2.29.2
diff --git a/nodejs.spec b/nodejs.spec
index 9ba5ae5..dcc511d 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -24,7 +24,7 @@
%global nodejs_epoch 1
%global nodejs_major 14
%global nodejs_minor 15
-%global nodejs_patch 1
+%global nodejs_patch 4
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -96,7 +96,7 @@
%global npm_epoch 1
%global npm_major 6
%global npm_minor 14
-%global npm_patch 8
+%global npm_patch 10
%global npm_version %{npm_major}.%{npm_minor}.%{npm_patch}
# uvwasi - from deps/uvwasi/include/uvwasi.h
@@ -677,6 +677,9 @@ end
%changelog
+* Mon Jan 04 2021 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.4-1
+- Update to 14.15.4
+
* Wed Dec 02 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.1-1
- Update to 14.15.1
diff --git a/sources b/sources
index 7478cbc..3547e12 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.15.1-stripped.tar.gz) = aa07a49485a0fecc282173b8b6d915b912a19191446ed6f4684d979e4baebadb7708a338410c2c42ee81d8395db6cfaf9b0879baea9e652dd97f7811a077975d
+SHA512 (node-v14.15.4-stripped.tar.gz) = 2c1d9b67e6b9bbdd960eeb82edfb02c237a7c7190407cf60bf14b02eb2b6143159b6f45e7bddb7c97120eab4faa37455534ab8b90bd4161b6d66dab0a72b122e
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit d4fae2de5af42fef0048e8ff5290f76df0e9e4ba
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Wed Dec 2 20:53:53 2020 -0500
Update to 14.15.1
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 0aa6bfb..9ba5ae5 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -12,7 +12,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 2
+%global baserelease 1
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -23,8 +23,8 @@
# than a Fedora release lifecycle.
%global nodejs_epoch 1
%global nodejs_major 14
-%global nodejs_minor 14
-%global nodejs_patch 0
+%global nodejs_minor 15
+%global nodejs_patch 1
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -677,6 +677,9 @@ end
%changelog
+* Wed Dec 02 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.15.1-1
+- Update to 14.15.1
+
* Tue Oct 20 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.14.0-2
- Don't build with LTO on aarch64
diff --git a/sources b/sources
index 74190a6..7478cbc 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.14.0-stripped.tar.gz) = 208bcc585e6e8a25a656d942424afa26aa7442a6252c428c01081e3f052998363d3126e290576493bb8fcc3e2944026013cf7a5757113a8717574cefdaa72c31
+SHA512 (node-v14.15.1-stripped.tar.gz) = aa07a49485a0fecc282173b8b6d915b912a19191446ed6f4684d979e4baebadb7708a338410c2c42ee81d8395db6cfaf9b0879baea9e652dd97f7811a077975d
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit a042b795522128838140f15a3019f0cc42a63781
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Oct 20 08:52:25 2020 -0400
Don't build with LTO on aarch64
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 96bfaff..0aa6bfb 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -2,12 +2,17 @@
%bcond_with bootstrap
%bcond_without python3_fixup
+# LTO is currently broken on aarch64 builds
+%ifarch aarch64
+%define _lto_cflags %{nil}
+%endif
+
# == Master Relase ==
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 1
+%global baserelease 2
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -672,6 +677,9 @@ end
%changelog
+* Tue Oct 20 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.14.0-2
+- Don't build with LTO on aarch64
+
* Mon Oct 19 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.14.0-1
- Update to 14.14.0
commit ab1676bdb39acbfb7184338364769f22e5277599
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon Oct 19 09:37:56 2020 -0400
Update to 14.14.0
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 600e725..96bfaff 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -18,8 +18,8 @@
# than a Fedora release lifecycle.
%global nodejs_epoch 1
%global nodejs_major 14
-%global nodejs_minor 13
-%global nodejs_patch 1
+%global nodejs_minor 14
+%global nodejs_patch 0
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -672,6 +672,9 @@ end
%changelog
+* Mon Oct 19 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.14.0-1
+- Update to 14.14.0
+
* Fri Oct 09 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.13.1-1
- Update to 14.13.1
diff --git a/sources b/sources
index 703a43d..74190a6 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.13.1-stripped.tar.gz) = eae37da105b0a176353c53d96ce081f6d018f9abe90476fa7396be7d3cf9b6d863d6edac4f67f09d384a717c6491f0c250b25e588dd449750bd70da6180ca35f
+SHA512 (node-v14.14.0-stripped.tar.gz) = 208bcc585e6e8a25a656d942424afa26aa7442a6252c428c01081e3f052998363d3126e290576493bb8fcc3e2944026013cf7a5757113a8717574cefdaa72c31
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit 52d3230036dd6bdc1c3b16ab7df8007696af8eef
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Fri Oct 9 09:44:18 2020 -0400
Update to 14.13.1
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index ebdbac5..600e725 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -19,7 +19,7 @@
%global nodejs_epoch 1
%global nodejs_major 14
%global nodejs_minor 13
-%global nodejs_patch 0
+%global nodejs_patch 1
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
%global nodejs_soversion 83
@@ -51,7 +51,7 @@
# llhttp - from deps/llhttp/include/llhttp.h
%global llhttp_major 2
%global llhttp_minor 1
-%global llhttp_patch 2
+%global llhttp_patch 3
%global llhttp_version %{llhttp_major}.%{llhttp_minor}.%{llhttp_patch}
# libuv - from deps/uv/include/uv/version.h
@@ -672,6 +672,9 @@ end
%changelog
+* Fri Oct 09 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.13.1-1
+- Update to 14.13.1
+
* Thu Oct 01 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.13.0-1
- Update to 14.13.0
diff --git a/sources b/sources
index ae6c258..703a43d 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.13.0-stripped.tar.gz) = be305a7e636a1f04e34b675d905be526f6370a94642bffa19c899e0885d58ddca3eb171765307238a6572cda7efceec2a6aaebf7af2e7a5ad617dee6124500ca
+SHA512 (node-v14.13.1-stripped.tar.gz) = eae37da105b0a176353c53d96ce081f6d018f9abe90476fa7396be7d3cf9b6d863d6edac4f67f09d384a717c6491f0c250b25e588dd449750bd70da6180ca35f
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit 3781c81a5cccd262ea984b11219c5419b9c6fc4d
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Mon Oct 5 09:40:46 2020 -0400
Add explicit setuptools dep
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index b66b6f2..ebdbac5 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -145,6 +145,7 @@ Patch1: 0001-Disable-running-gyp-on-shared-deps.patch
Patch2: 0002-Install-both-binaries-and-use-libdir.patch
BuildRequires: python3-devel
+BuildRequires: python3-setuptools
BuildRequires: zlib-devel
BuildRequires: brotli-devel
BuildRequires: gcc >= 6.3.0
commit 2cd44ffc6bf6d8b291a848189b31cc8f16771ca7
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Thu Oct 1 13:36:19 2020 -0400
Update to 14.13.0
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/.gitignore b/.gitignore
index c7ca6db..fdd7ef0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+*~
+*.swp
/*.tar.gz
/*.src.rpm
/*.tgz
diff --git a/nodejs.spec b/nodejs.spec
index 2918a64..b66b6f2 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -18,7 +18,7 @@
# than a Fedora release lifecycle.
%global nodejs_epoch 1
%global nodejs_major 14
-%global nodejs_minor 11
+%global nodejs_minor 13
%global nodejs_patch 0
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
@@ -45,7 +45,7 @@
# https://github.com/nodejs/node/pull/9332
%global c_ares_major 1
%global c_ares_minor 16
-%global c_ares_patch 0
+%global c_ares_patch 1
%global c_ares_version %{c_ares_major}.%{c_ares_minor}.%{c_ares_patch}
# llhttp - from deps/llhttp/include/llhttp.h
@@ -56,7 +56,7 @@
# libuv - from deps/uv/include/uv/version.h
%global libuv_major 1
-%global libuv_minor 39
+%global libuv_minor 40
%global libuv_patch 0
%global libuv_version %{libuv_major}.%{libuv_minor}.%{libuv_patch}
@@ -97,7 +97,7 @@
# uvwasi - from deps/uvwasi/include/uvwasi.h
%global uvwasi_major 0
%global uvwasi_minor 0
-%global uvwasi_patch 10
+%global uvwasi_patch 11
%global uvwasi_version %{uvwasi_major}.%{uvwasi_minor}.%{uvwasi_patch}
# histogram_c - assumed from timestamps
@@ -671,6 +671,9 @@ end
%changelog
+* Thu Oct 01 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.13.0-1
+- Update to 14.13.0
+
* Wed Sep 16 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.11.0-1
- Update to 14.11.0
diff --git a/sources b/sources
index 5aae63e..ae6c258 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.11.0-stripped.tar.gz) = 0ac5496eed70d6d00b0d71fed6f07395d96a4fd1d7efdf2598ba66964f04bbabadbf465e26d07e80856ae825794ed740e607d63bdf8f2b2e64f80171d71851f0
+SHA512 (node-v14.13.0-stripped.tar.gz) = be305a7e636a1f04e34b675d905be526f6370a94642bffa19c899e0885d58ddca3eb171765307238a6572cda7efceec2a6aaebf7af2e7a5ad617dee6124500ca
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit 78306ffa5a3b1bf9853313bea9b8973043733d78
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Thu Sep 17 11:55:27 2020 -0400
Drop old pretrans scriptlet
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index e3750ba..2918a64 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -585,24 +585,6 @@ if st and st.type == "directory" then
end
-%pretrans -n v8-devel -p <lua>
--- Replace the v8 libplatform include directory with a symlink
--- Drop this scriptlet when F30 is EOL
-path = "%{_includedir}/libplatform"
-st = posix.stat(path)
-if st and st.type == "directory" then
- status = os.rename(path, path .. ".rpmmoved")
- if not status then
- suffix = 0
- while not status do
- suffix = suffix + 1
- status = os.rename(path .. ".rpmmoved", path .. ".rpmmoved." .. suffix)
- end
- os.rename(path, path .. ".rpmmoved")
- end
-end
-
-
%files
%{_bindir}/node
%dir %{_prefix}/lib/node_modules
@@ -652,7 +634,6 @@ end
%{_libdir}/libv8.so
%{_libdir}/libv8_libbase.so
%{_libdir}/libv8_libplatform.so
-%ghost %{_includedir}/libplatform.rpmmoved
%files -n npm
commit af60d955d99018b81098bf0f8bf08e8a8e99de75
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Wed Sep 16 08:55:53 2020 -0400
Add package.cfg
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/package.cfg b/package.cfg
new file mode 100644
index 0000000..dfe80fb
--- /dev/null
+++ b/package.cfg
@@ -0,0 +1,2 @@
+[koji]
+targets = master f33
3 years
Architecture specific change in rpms/cbmc.git
by githook-noreply@fedoraproject.org
The package rpms/cbmc.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/cbmc.git/commit/?id=bba9eeaa9cb83....
Change:
+%ifarch i686
Thanks.
Full change:
============
commit bba9eeaa9cb8386d9e8c19515be513bae6c74690
Author: Vincent Mihalkovic <vmihalko(a)redhat.com>
Date: Wed May 12 22:35:10 2021 +0200
New upstream release
diff --git a/cbmc-32bit-arch-fix.patch b/cbmc-32bit-arch-fix.patch
deleted file mode 100644
index 491859c..0000000
--- a/cbmc-32bit-arch-fix.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff --git src/ansi-c/library/gcc.c src/ansi-c/library/gcc.c
-index e38167e81..96a2739bc 100644
---- src/ansi-c/library/gcc.c
-+++ src/ansi-c/library/gcc.c
-@@ -1,3 +1,4 @@
-+#define _XOPEN_SOURCE
- /* FUNCTION: __builtin_ia32_sfence */
-
- inline void __builtin_ia32_sfence(void)
-@@ -65,8 +66,10 @@ inline int __builtin_clzl(unsigned long int x)
- x = x | (x >> 8);
- if(sizeof(x) >= 4)
- x = x | (x >> 16);
-+ #if LONG_BIT > 32
- if(sizeof(x) >= 8)
- x = x | (x >> 32);
-+ #endif
-
- return __builtin_popcountl(~x);
- }
diff --git a/cbmc-errno-realpath.patch b/cbmc-errno-realpath.patch
deleted file mode 100644
index e4e5e88..0000000
--- a/cbmc-errno-realpath.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git src/util/tempdir.cpp src/util/tempdir.cpp
-index d61636b..c1fb7a9 100644
---- src/util/tempdir.cpp
-+++ src/util/tempdir.cpp
-@@ -93,7 +93,8 @@ std::string get_temporary_directory(const std::string &name_template)
- errno = 0;
- char *wd = realpath(td, nullptr);
-
-- if(wd == nullptr || errno != 0)
-+ // Comment out due to the https://bugzilla.redhat.com/show_bug.cgi?id=1916968
-+ if(wd == nullptr /* || errno != 0 */)
- throw system_exceptiont(
- std::string("realpath failed: ") + std::strerror(errno));
-
diff --git a/cbmc-f35-deprecated-python.patch b/cbmc-f35-deprecated-python.patch
new file mode 100644
index 0000000..e753f55
--- /dev/null
+++ b/cbmc-f35-deprecated-python.patch
@@ -0,0 +1,24 @@
+diff --git regression/CMakeLists.txt regression/CMakeLists.txt
+index 42c772a..e9b8807 100644
+--- regression/CMakeLists.txt
++++ regression/CMakeLists.txt
+@@ -73,7 +73,6 @@ add_subdirectory(validate-trace-xml-schema)
+ add_subdirectory(cbmc-primitives)
+ add_subdirectory(goto-interpreter)
+ add_subdirectory(cbmc-sequentialization)
+-add_subdirectory(cpp-linter)
+
+ if(WITH_MEMORY_ANALYZER)
+ add_subdirectory(snapshot-harness)
+diff --git regression/Makefile regression/Makefile
+index b344727..a53ef45 100644
+--- regression/Makefile
++++ regression/Makefile
+@@ -46,7 +46,6 @@ DIRS = cbmc \
+ cbmc-primitives \
+ goto-interpreter \
+ cbmc-sequentialization \
+- cpp-linter \
+ # Empty last line
+
+ ifeq ($(OS),Windows_NT)
diff --git a/cbmc-f35-enable_sse2.patch b/cbmc-f35-enable_sse2.patch
new file mode 100644
index 0000000..6c995ec
--- /dev/null
+++ b/cbmc-f35-enable_sse2.patch
@@ -0,0 +1,15 @@
+diff --git src/ansi-c/library_check.sh src/ansi-c/library_check.sh
+index bb362dc..3c64fba 100755
+--- src/ansi-c/library_check.sh
++++ src/ansi-c/library_check.sh
+@@ -10,8 +10,8 @@ for f in "$@"; do
+ perl -p -i -e 's/(_mm_.fence)/s$1/' __libcheck.c
+ perl -p -i -e 's/(__sync_)/s$1/' __libcheck.c
+ perl -p -i -e 's/(__atomic_)/s$1/' __libcheck.c
+- "$CC" -std=gnu99 -E -include library/cprover.h -D__CPROVER_bool=_Bool -D__CPROVER_thread_local=__thread -DLIBRARY_CHECK -o __libcheck.i __libcheck.c
+- "$CC" -S -Wall -Werror -pedantic -Wextra -std=gnu99 __libcheck.i \
++ "$CC" -std=gnu99 -msse2 -E -include library/cprover.h -D__CPROVER_bool=_Bool -D__CPROVER_thread_local=__thread -DLIBRARY_CHECK -o __libcheck.i __libcheck.c
++ "$CC" -S -Wall -Werror -pedantic -Wextra -std=gnu99 -msse2 __libcheck.i \
+ -o __libcheck.s -Wno-unused-label -Wno-unknown-pragmas
+ ec="${?}"
+ rm __libcheck.s __libcheck.i __libcheck.c
diff --git a/cbmc-goto-cc-type-change.patch b/cbmc-goto-cc-type-change.patch
deleted file mode 100644
index abd3bb8..0000000
--- a/cbmc-goto-cc-type-change.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git src/goto-cc/ms_link_cmdline.cpp src/goto-cc/ms_link_cmdline.cpp
-index 771b45c..e0a8a06 100644
---- src/goto-cc/ms_link_cmdline.cpp
-+++ src/goto-cc/ms_link_cmdline.cpp
-@@ -333,7 +333,7 @@ void ms_link_cmdlinet::process_link_option(const std::string &s)
- return;
- }
-
-- for(const std::string &ms_link_option : ms_link_options)
-+ for(const std::string ms_link_option : ms_link_options)
- {
- // These are case insensitive.
- if(
diff --git a/cbmc-signed-char.patch b/cbmc-signed-char.patch
deleted file mode 100644
index a871f96..0000000
--- a/cbmc-signed-char.patch
+++ /dev/null
@@ -1,529 +0,0 @@
-diff --git unit/util/string_utils/escape_non_alnum.cpp unit/util/string_utils/escape_non_alnum.cpp
-index 147ef17..ebc1f8f 100644
---- unit/util/string_utils/escape_non_alnum.cpp
-+++ unit/util/string_utils/escape_non_alnum.cpp
-@@ -20,267 +20,267 @@ TEST_CASE(
- "escape_non_alnum should work with any single byte signed character (part 1)",
- "[core][utils][string_utils][escape_non_alnum]")
- {
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x00)}) == "_00");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x01)}) == "_01");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x02)}) == "_02");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x03)}) == "_03");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x04)}) == "_04");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x05)}) == "_05");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x06)}) == "_06");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x07)}) == "_07");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x08)}) == "_08");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x09)}) == "_09");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x0A)}) == "_0a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x0B)}) == "_0b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x0C)}) == "_0c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x0D)}) == "_0d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x0E)}) == "_0e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x0F)}) == "_0f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x10)}) == "_10");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x11)}) == "_11");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x12)}) == "_12");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x13)}) == "_13");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x14)}) == "_14");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x15)}) == "_15");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x16)}) == "_16");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x17)}) == "_17");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x18)}) == "_18");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x19)}) == "_19");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x1A)}) == "_1a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x1B)}) == "_1b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x1C)}) == "_1c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x1D)}) == "_1d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x1E)}) == "_1e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x1F)}) == "_1f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x20)}) == "_20");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x21)}) == "_21");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x22)}) == "_22");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x23)}) == "_23");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x24)}) == "_24");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x25)}) == "_25");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x26)}) == "_26");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x27)}) == "_27");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x28)}) == "_28");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x29)}) == "_29");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2A)}) == "_2a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2B)}) == "_2b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2B)}) == "_2b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2C)}) == "_2c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2D)}) == "_2d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2E)}) == "_2e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x2F)}) == "_2f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x30)}) == "0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x31)}) == "1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x32)}) == "2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x33)}) == "3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x34)}) == "4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x35)}) == "5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x36)}) == "6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x37)}) == "7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x38)}) == "8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x39)}) == "9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x3A)}) == "_3a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x3B)}) == "_3b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x3C)}) == "_3c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x3D)}) == "_3d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x3E)}) == "_3e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x3F)}) == "_3f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x40)}) == "_40");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x41)}) == "A");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x42)}) == "B");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x43)}) == "C");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x44)}) == "D");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x45)}) == "E");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x46)}) == "F");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x47)}) == "G");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x48)}) == "H");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x49)}) == "I");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x4A)}) == "J");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x4B)}) == "K");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x4C)}) == "L");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x4D)}) == "M");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x4E)}) == "N");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x4F)}) == "O");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x50)}) == "P");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x51)}) == "Q");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x52)}) == "R");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x53)}) == "S");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x54)}) == "T");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x55)}) == "U");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x56)}) == "V");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x57)}) == "W");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x58)}) == "X");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x59)}) == "Y");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x5A)}) == "Z");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x5B)}) == "_5b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x5C)}) == "_5c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x5D)}) == "_5d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x5E)}) == "_5e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x5F)}) == "__");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x60)}) == "_60");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x61)}) == "a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x62)}) == "b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x63)}) == "c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x64)}) == "d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x65)}) == "e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x66)}) == "f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x67)}) == "g");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x68)}) == "h");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x69)}) == "i");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x6A)}) == "j");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x6B)}) == "k");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x6C)}) == "l");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x6D)}) == "m");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x6E)}) == "n");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x6F)}) == "o");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x70)}) == "p");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x71)}) == "q");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x72)}) == "r");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x73)}) == "s");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x74)}) == "t");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x75)}) == "u");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x76)}) == "v");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x77)}) == "w");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x78)}) == "x");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x79)}) == "y");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x7A)}) == "z");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x7B)}) == "_7b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x7C)}) == "_7c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x7D)}) == "_7d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x7E)}) == "_7e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x7F)}) == "_7f");
-+ CHECK(escape_non_alnum({'\x00'}) == "_00");
-+ CHECK(escape_non_alnum({'\x01'}) == "_01");
-+ CHECK(escape_non_alnum({'\x02'}) == "_02");
-+ CHECK(escape_non_alnum({'\x03'}) == "_03");
-+ CHECK(escape_non_alnum({'\x04'}) == "_04");
-+ CHECK(escape_non_alnum({'\x05'}) == "_05");
-+ CHECK(escape_non_alnum({'\x06'}) == "_06");
-+ CHECK(escape_non_alnum({'\x07'}) == "_07");
-+ CHECK(escape_non_alnum({'\x08'}) == "_08");
-+ CHECK(escape_non_alnum({'\x09'}) == "_09");
-+ CHECK(escape_non_alnum({'\x0A'}) == "_0a");
-+ CHECK(escape_non_alnum({'\x0B'}) == "_0b");
-+ CHECK(escape_non_alnum({'\x0C'}) == "_0c");
-+ CHECK(escape_non_alnum({'\x0D'}) == "_0d");
-+ CHECK(escape_non_alnum({'\x0E'}) == "_0e");
-+ CHECK(escape_non_alnum({'\x0F'}) == "_0f");
-+ CHECK(escape_non_alnum({'\x10'}) == "_10");
-+ CHECK(escape_non_alnum({'\x11'}) == "_11");
-+ CHECK(escape_non_alnum({'\x12'}) == "_12");
-+ CHECK(escape_non_alnum({'\x13'}) == "_13");
-+ CHECK(escape_non_alnum({'\x14'}) == "_14");
-+ CHECK(escape_non_alnum({'\x15'}) == "_15");
-+ CHECK(escape_non_alnum({'\x16'}) == "_16");
-+ CHECK(escape_non_alnum({'\x17'}) == "_17");
-+ CHECK(escape_non_alnum({'\x18'}) == "_18");
-+ CHECK(escape_non_alnum({'\x19'}) == "_19");
-+ CHECK(escape_non_alnum({'\x1A'}) == "_1a");
-+ CHECK(escape_non_alnum({'\x1B'}) == "_1b");
-+ CHECK(escape_non_alnum({'\x1C'}) == "_1c");
-+ CHECK(escape_non_alnum({'\x1D'}) == "_1d");
-+ CHECK(escape_non_alnum({'\x1E'}) == "_1e");
-+ CHECK(escape_non_alnum({'\x1F'}) == "_1f");
-+ CHECK(escape_non_alnum({'\x20'}) == "_20");
-+ CHECK(escape_non_alnum({'\x21'}) == "_21");
-+ CHECK(escape_non_alnum({'\x22'}) == "_22");
-+ CHECK(escape_non_alnum({'\x23'}) == "_23");
-+ CHECK(escape_non_alnum({'\x24'}) == "_24");
-+ CHECK(escape_non_alnum({'\x25'}) == "_25");
-+ CHECK(escape_non_alnum({'\x26'}) == "_26");
-+ CHECK(escape_non_alnum({'\x27'}) == "_27");
-+ CHECK(escape_non_alnum({'\x28'}) == "_28");
-+ CHECK(escape_non_alnum({'\x29'}) == "_29");
-+ CHECK(escape_non_alnum({'\x2A'}) == "_2a");
-+ CHECK(escape_non_alnum({'\x2B'}) == "_2b");
-+ CHECK(escape_non_alnum({'\x2B'}) == "_2b");
-+ CHECK(escape_non_alnum({'\x2C'}) == "_2c");
-+ CHECK(escape_non_alnum({'\x2D'}) == "_2d");
-+ CHECK(escape_non_alnum({'\x2E'}) == "_2e");
-+ CHECK(escape_non_alnum({'\x2F'}) == "_2f");
-+ CHECK(escape_non_alnum({'\x30'}) == "0");
-+ CHECK(escape_non_alnum({'\x31'}) == "1");
-+ CHECK(escape_non_alnum({'\x32'}) == "2");
-+ CHECK(escape_non_alnum({'\x33'}) == "3");
-+ CHECK(escape_non_alnum({'\x34'}) == "4");
-+ CHECK(escape_non_alnum({'\x35'}) == "5");
-+ CHECK(escape_non_alnum({'\x36'}) == "6");
-+ CHECK(escape_non_alnum({'\x37'}) == "7");
-+ CHECK(escape_non_alnum({'\x38'}) == "8");
-+ CHECK(escape_non_alnum({'\x39'}) == "9");
-+ CHECK(escape_non_alnum({'\x3A'}) == "_3a");
-+ CHECK(escape_non_alnum({'\x3B'}) == "_3b");
-+ CHECK(escape_non_alnum({'\x3C'}) == "_3c");
-+ CHECK(escape_non_alnum({'\x3D'}) == "_3d");
-+ CHECK(escape_non_alnum({'\x3E'}) == "_3e");
-+ CHECK(escape_non_alnum({'\x3F'}) == "_3f");
-+ CHECK(escape_non_alnum({'\x40'}) == "_40");
-+ CHECK(escape_non_alnum({'\x41'}) == "A");
-+ CHECK(escape_non_alnum({'\x42'}) == "B");
-+ CHECK(escape_non_alnum({'\x43'}) == "C");
-+ CHECK(escape_non_alnum({'\x44'}) == "D");
-+ CHECK(escape_non_alnum({'\x45'}) == "E");
-+ CHECK(escape_non_alnum({'\x46'}) == "F");
-+ CHECK(escape_non_alnum({'\x47'}) == "G");
-+ CHECK(escape_non_alnum({'\x48'}) == "H");
-+ CHECK(escape_non_alnum({'\x49'}) == "I");
-+ CHECK(escape_non_alnum({'\x4A'}) == "J");
-+ CHECK(escape_non_alnum({'\x4B'}) == "K");
-+ CHECK(escape_non_alnum({'\x4C'}) == "L");
-+ CHECK(escape_non_alnum({'\x4D'}) == "M");
-+ CHECK(escape_non_alnum({'\x4E'}) == "N");
-+ CHECK(escape_non_alnum({'\x4F'}) == "O");
-+ CHECK(escape_non_alnum({'\x50'}) == "P");
-+ CHECK(escape_non_alnum({'\x51'}) == "Q");
-+ CHECK(escape_non_alnum({'\x52'}) == "R");
-+ CHECK(escape_non_alnum({'\x53'}) == "S");
-+ CHECK(escape_non_alnum({'\x54'}) == "T");
-+ CHECK(escape_non_alnum({'\x55'}) == "U");
-+ CHECK(escape_non_alnum({'\x56'}) == "V");
-+ CHECK(escape_non_alnum({'\x57'}) == "W");
-+ CHECK(escape_non_alnum({'\x58'}) == "X");
-+ CHECK(escape_non_alnum({'\x59'}) == "Y");
-+ CHECK(escape_non_alnum({'\x5A'}) == "Z");
-+ CHECK(escape_non_alnum({'\x5B'}) == "_5b");
-+ CHECK(escape_non_alnum({'\x5C'}) == "_5c");
-+ CHECK(escape_non_alnum({'\x5D'}) == "_5d");
-+ CHECK(escape_non_alnum({'\x5E'}) == "_5e");
-+ CHECK(escape_non_alnum({'\x5F'}) == "__");
-+ CHECK(escape_non_alnum({'\x60'}) == "_60");
-+ CHECK(escape_non_alnum({'\x61'}) == "a");
-+ CHECK(escape_non_alnum({'\x62'}) == "b");
-+ CHECK(escape_non_alnum({'\x63'}) == "c");
-+ CHECK(escape_non_alnum({'\x64'}) == "d");
-+ CHECK(escape_non_alnum({'\x65'}) == "e");
-+ CHECK(escape_non_alnum({'\x66'}) == "f");
-+ CHECK(escape_non_alnum({'\x67'}) == "g");
-+ CHECK(escape_non_alnum({'\x68'}) == "h");
-+ CHECK(escape_non_alnum({'\x69'}) == "i");
-+ CHECK(escape_non_alnum({'\x6A'}) == "j");
-+ CHECK(escape_non_alnum({'\x6B'}) == "k");
-+ CHECK(escape_non_alnum({'\x6C'}) == "l");
-+ CHECK(escape_non_alnum({'\x6D'}) == "m");
-+ CHECK(escape_non_alnum({'\x6E'}) == "n");
-+ CHECK(escape_non_alnum({'\x6F'}) == "o");
-+ CHECK(escape_non_alnum({'\x70'}) == "p");
-+ CHECK(escape_non_alnum({'\x71'}) == "q");
-+ CHECK(escape_non_alnum({'\x72'}) == "r");
-+ CHECK(escape_non_alnum({'\x73'}) == "s");
-+ CHECK(escape_non_alnum({'\x74'}) == "t");
-+ CHECK(escape_non_alnum({'\x75'}) == "u");
-+ CHECK(escape_non_alnum({'\x76'}) == "v");
-+ CHECK(escape_non_alnum({'\x77'}) == "w");
-+ CHECK(escape_non_alnum({'\x78'}) == "x");
-+ CHECK(escape_non_alnum({'\x79'}) == "y");
-+ CHECK(escape_non_alnum({'\x7A'}) == "z");
-+ CHECK(escape_non_alnum({'\x7B'}) == "_7b");
-+ CHECK(escape_non_alnum({'\x7C'}) == "_7c");
-+ CHECK(escape_non_alnum({'\x7D'}) == "_7d");
-+ CHECK(escape_non_alnum({'\x7E'}) == "_7e");
-+ CHECK(escape_non_alnum({'\x7F'}) == "_7f");
- }
-
- TEST_CASE(
- "escape_non_alnum should work with any single byte signed character (part 2)",
- "[core][utils][string_utils][escape_non_alnum]")
- {
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x80)}) == "_80");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x81)}) == "_81");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x82)}) == "_82");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x83)}) == "_83");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x84)}) == "_84");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x85)}) == "_85");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x86)}) == "_86");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x87)}) == "_87");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x88)}) == "_88");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x89)}) == "_89");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x8A)}) == "_8a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x8B)}) == "_8b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x8C)}) == "_8c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x8D)}) == "_8d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x8E)}) == "_8e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x8F)}) == "_8f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x90)}) == "_90");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x91)}) == "_91");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x92)}) == "_92");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x93)}) == "_93");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x94)}) == "_94");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x95)}) == "_95");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x96)}) == "_96");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x97)}) == "_97");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x98)}) == "_98");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x99)}) == "_99");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x9A)}) == "_9a");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x9B)}) == "_9b");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x9C)}) == "_9c");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x9D)}) == "_9d");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x9E)}) == "_9e");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0x9F)}) == "_9f");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA0)}) == "_a0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA1)}) == "_a1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA2)}) == "_a2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA3)}) == "_a3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA4)}) == "_a4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA5)}) == "_a5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA6)}) == "_a6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA7)}) == "_a7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA8)}) == "_a8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xA9)}) == "_a9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xAA)}) == "_aa");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xAB)}) == "_ab");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xAC)}) == "_ac");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xAD)}) == "_ad");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xAE)}) == "_ae");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xAF)}) == "_af");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB0)}) == "_b0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB1)}) == "_b1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB2)}) == "_b2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB3)}) == "_b3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB4)}) == "_b4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB5)}) == "_b5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB6)}) == "_b6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB7)}) == "_b7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB8)}) == "_b8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xB9)}) == "_b9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xBA)}) == "_ba");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xBB)}) == "_bb");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xBC)}) == "_bc");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xBD)}) == "_bd");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xBE)}) == "_be");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xBF)}) == "_bf");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC0)}) == "_c0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC1)}) == "_c1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC2)}) == "_c2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC3)}) == "_c3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC4)}) == "_c4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC5)}) == "_c5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC6)}) == "_c6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC7)}) == "_c7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC8)}) == "_c8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xC9)}) == "_c9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xCA)}) == "_ca");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xCB)}) == "_cb");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xCC)}) == "_cc");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xCD)}) == "_cd");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xCE)}) == "_ce");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xCF)}) == "_cf");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD0)}) == "_d0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD1)}) == "_d1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD2)}) == "_d2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD3)}) == "_d3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD4)}) == "_d4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD5)}) == "_d5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD6)}) == "_d6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD7)}) == "_d7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD8)}) == "_d8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xD9)}) == "_d9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xDA)}) == "_da");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xDB)}) == "_db");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xDC)}) == "_dc");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xDD)}) == "_dd");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xDE)}) == "_de");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xDF)}) == "_df");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE0)}) == "_e0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE1)}) == "_e1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE2)}) == "_e2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE3)}) == "_e3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE4)}) == "_e4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE5)}) == "_e5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE6)}) == "_e6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE7)}) == "_e7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE8)}) == "_e8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xE9)}) == "_e9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xEA)}) == "_ea");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xEB)}) == "_eb");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xEC)}) == "_ec");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xED)}) == "_ed");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xEE)}) == "_ee");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xEF)}) == "_ef");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF0)}) == "_f0");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF1)}) == "_f1");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF2)}) == "_f2");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF3)}) == "_f3");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF4)}) == "_f4");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF5)}) == "_f5");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF6)}) == "_f6");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF7)}) == "_f7");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF8)}) == "_f8");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xF9)}) == "_f9");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xFA)}) == "_fa");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xFB)}) == "_fb");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xFC)}) == "_fc");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xFD)}) == "_fd");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xFE)}) == "_fe");
-- CHECK(escape_non_alnum(std::string{static_cast<signed char>(0xFF)}) == "_ff");
-+ CHECK(escape_non_alnum({'\x80'}) == "_80");
-+ CHECK(escape_non_alnum({'\x81'}) == "_81");
-+ CHECK(escape_non_alnum({'\x82'}) == "_82");
-+ CHECK(escape_non_alnum({'\x83'}) == "_83");
-+ CHECK(escape_non_alnum({'\x84'}) == "_84");
-+ CHECK(escape_non_alnum({'\x85'}) == "_85");
-+ CHECK(escape_non_alnum({'\x86'}) == "_86");
-+ CHECK(escape_non_alnum({'\x87'}) == "_87");
-+ CHECK(escape_non_alnum({'\x88'}) == "_88");
-+ CHECK(escape_non_alnum({'\x89'}) == "_89");
-+ CHECK(escape_non_alnum({'\x8A'}) == "_8a");
-+ CHECK(escape_non_alnum({'\x8B'}) == "_8b");
-+ CHECK(escape_non_alnum({'\x8C'}) == "_8c");
-+ CHECK(escape_non_alnum({'\x8D'}) == "_8d");
-+ CHECK(escape_non_alnum({'\x8E'}) == "_8e");
-+ CHECK(escape_non_alnum({'\x8F'}) == "_8f");
-+ CHECK(escape_non_alnum({'\x90'}) == "_90");
-+ CHECK(escape_non_alnum({'\x91'}) == "_91");
-+ CHECK(escape_non_alnum({'\x92'}) == "_92");
-+ CHECK(escape_non_alnum({'\x93'}) == "_93");
-+ CHECK(escape_non_alnum({'\x94'}) == "_94");
-+ CHECK(escape_non_alnum({'\x95'}) == "_95");
-+ CHECK(escape_non_alnum({'\x96'}) == "_96");
-+ CHECK(escape_non_alnum({'\x97'}) == "_97");
-+ CHECK(escape_non_alnum({'\x98'}) == "_98");
-+ CHECK(escape_non_alnum({'\x99'}) == "_99");
-+ CHECK(escape_non_alnum({'\x9A'}) == "_9a");
-+ CHECK(escape_non_alnum({'\x9B'}) == "_9b");
-+ CHECK(escape_non_alnum({'\x9C'}) == "_9c");
-+ CHECK(escape_non_alnum({'\x9D'}) == "_9d");
-+ CHECK(escape_non_alnum({'\x9E'}) == "_9e");
-+ CHECK(escape_non_alnum({'\x9F'}) == "_9f");
-+ CHECK(escape_non_alnum({'\xA0'}) == "_a0");
-+ CHECK(escape_non_alnum({'\xA1'}) == "_a1");
-+ CHECK(escape_non_alnum({'\xA2'}) == "_a2");
-+ CHECK(escape_non_alnum({'\xA3'}) == "_a3");
-+ CHECK(escape_non_alnum({'\xA4'}) == "_a4");
-+ CHECK(escape_non_alnum({'\xA5'}) == "_a5");
-+ CHECK(escape_non_alnum({'\xA6'}) == "_a6");
-+ CHECK(escape_non_alnum({'\xA7'}) == "_a7");
-+ CHECK(escape_non_alnum({'\xA8'}) == "_a8");
-+ CHECK(escape_non_alnum({'\xA9'}) == "_a9");
-+ CHECK(escape_non_alnum({'\xAA'}) == "_aa");
-+ CHECK(escape_non_alnum({'\xAB'}) == "_ab");
-+ CHECK(escape_non_alnum({'\xAC'}) == "_ac");
-+ CHECK(escape_non_alnum({'\xAD'}) == "_ad");
-+ CHECK(escape_non_alnum({'\xAE'}) == "_ae");
-+ CHECK(escape_non_alnum({'\xAF'}) == "_af");
-+ CHECK(escape_non_alnum({'\xB0'}) == "_b0");
-+ CHECK(escape_non_alnum({'\xB1'}) == "_b1");
-+ CHECK(escape_non_alnum({'\xB2'}) == "_b2");
-+ CHECK(escape_non_alnum({'\xB3'}) == "_b3");
-+ CHECK(escape_non_alnum({'\xB4'}) == "_b4");
-+ CHECK(escape_non_alnum({'\xB5'}) == "_b5");
-+ CHECK(escape_non_alnum({'\xB6'}) == "_b6");
-+ CHECK(escape_non_alnum({'\xB7'}) == "_b7");
-+ CHECK(escape_non_alnum({'\xB8'}) == "_b8");
-+ CHECK(escape_non_alnum({'\xB9'}) == "_b9");
-+ CHECK(escape_non_alnum({'\xBA'}) == "_ba");
-+ CHECK(escape_non_alnum({'\xBB'}) == "_bb");
-+ CHECK(escape_non_alnum({'\xBC'}) == "_bc");
-+ CHECK(escape_non_alnum({'\xBD'}) == "_bd");
-+ CHECK(escape_non_alnum({'\xBE'}) == "_be");
-+ CHECK(escape_non_alnum({'\xBF'}) == "_bf");
-+ CHECK(escape_non_alnum({'\xC0'}) == "_c0");
-+ CHECK(escape_non_alnum({'\xC1'}) == "_c1");
-+ CHECK(escape_non_alnum({'\xC2'}) == "_c2");
-+ CHECK(escape_non_alnum({'\xC3'}) == "_c3");
-+ CHECK(escape_non_alnum({'\xC4'}) == "_c4");
-+ CHECK(escape_non_alnum({'\xC5'}) == "_c5");
-+ CHECK(escape_non_alnum({'\xC6'}) == "_c6");
-+ CHECK(escape_non_alnum({'\xC7'}) == "_c7");
-+ CHECK(escape_non_alnum({'\xC8'}) == "_c8");
-+ CHECK(escape_non_alnum({'\xC9'}) == "_c9");
-+ CHECK(escape_non_alnum({'\xCA'}) == "_ca");
-+ CHECK(escape_non_alnum({'\xCB'}) == "_cb");
-+ CHECK(escape_non_alnum({'\xCC'}) == "_cc");
-+ CHECK(escape_non_alnum({'\xCD'}) == "_cd");
-+ CHECK(escape_non_alnum({'\xCE'}) == "_ce");
-+ CHECK(escape_non_alnum({'\xCF'}) == "_cf");
-+ CHECK(escape_non_alnum({'\xD0'}) == "_d0");
-+ CHECK(escape_non_alnum({'\xD1'}) == "_d1");
-+ CHECK(escape_non_alnum({'\xD2'}) == "_d2");
-+ CHECK(escape_non_alnum({'\xD3'}) == "_d3");
-+ CHECK(escape_non_alnum({'\xD4'}) == "_d4");
-+ CHECK(escape_non_alnum({'\xD5'}) == "_d5");
-+ CHECK(escape_non_alnum({'\xD6'}) == "_d6");
-+ CHECK(escape_non_alnum({'\xD7'}) == "_d7");
-+ CHECK(escape_non_alnum({'\xD8'}) == "_d8");
-+ CHECK(escape_non_alnum({'\xD9'}) == "_d9");
-+ CHECK(escape_non_alnum({'\xDA'}) == "_da");
-+ CHECK(escape_non_alnum({'\xDB'}) == "_db");
-+ CHECK(escape_non_alnum({'\xDC'}) == "_dc");
-+ CHECK(escape_non_alnum({'\xDD'}) == "_dd");
-+ CHECK(escape_non_alnum({'\xDE'}) == "_de");
-+ CHECK(escape_non_alnum({'\xDF'}) == "_df");
-+ CHECK(escape_non_alnum({'\xE0'}) == "_e0");
-+ CHECK(escape_non_alnum({'\xE1'}) == "_e1");
-+ CHECK(escape_non_alnum({'\xE2'}) == "_e2");
-+ CHECK(escape_non_alnum({'\xE3'}) == "_e3");
-+ CHECK(escape_non_alnum({'\xE4'}) == "_e4");
-+ CHECK(escape_non_alnum({'\xE5'}) == "_e5");
-+ CHECK(escape_non_alnum({'\xE6'}) == "_e6");
-+ CHECK(escape_non_alnum({'\xE7'}) == "_e7");
-+ CHECK(escape_non_alnum({'\xE8'}) == "_e8");
-+ CHECK(escape_non_alnum({'\xE9'}) == "_e9");
-+ CHECK(escape_non_alnum({'\xEA'}) == "_ea");
-+ CHECK(escape_non_alnum({'\xEB'}) == "_eb");
-+ CHECK(escape_non_alnum({'\xEC'}) == "_ec");
-+ CHECK(escape_non_alnum({'\xED'}) == "_ed");
-+ CHECK(escape_non_alnum({'\xEE'}) == "_ee");
-+ CHECK(escape_non_alnum({'\xEF'}) == "_ef");
-+ CHECK(escape_non_alnum({'\xF0'}) == "_f0");
-+ CHECK(escape_non_alnum({'\xF1'}) == "_f1");
-+ CHECK(escape_non_alnum({'\xF2'}) == "_f2");
-+ CHECK(escape_non_alnum({'\xF3'}) == "_f3");
-+ CHECK(escape_non_alnum({'\xF4'}) == "_f4");
-+ CHECK(escape_non_alnum({'\xF5'}) == "_f5");
-+ CHECK(escape_non_alnum({'\xF6'}) == "_f6");
-+ CHECK(escape_non_alnum({'\xF7'}) == "_f7");
-+ CHECK(escape_non_alnum({'\xF8'}) == "_f8");
-+ CHECK(escape_non_alnum({'\xF9'}) == "_f9");
-+ CHECK(escape_non_alnum({'\xFA'}) == "_fa");
-+ CHECK(escape_non_alnum({'\xFB'}) == "_fb");
-+ CHECK(escape_non_alnum({'\xFC'}) == "_fc");
-+ CHECK(escape_non_alnum({'\xFD'}) == "_fd");
-+ CHECK(escape_non_alnum({'\xFE'}) == "_fe");
-+ CHECK(escape_non_alnum({'\xFF'}) == "_ff");
- }
diff --git a/cbmc.spec b/cbmc.spec
index f3cbe33..25ea933 100644
--- a/cbmc.spec
+++ b/cbmc.spec
@@ -5,7 +5,7 @@
%define _lto_cflags %{nil}
Name: cbmc
-Version: 5.25.0
+Version: 5.29.0
Release: 1%{?dist}
Summary: Bounded Model Checker for ANSI-C and C++ programs
@@ -21,34 +21,33 @@ Patch0: %{name}-5.9-glpk.patch
Patch1: %{name}-5.12-fix-f33.patch
# Use minisat from Fedora repos
Patch2: %{name}-minisat.patch
-# Fix compilation on 32 bit architectures
-Patch3: %{name}-32bit-arch-fix.patch
-# Fix compilation of tests
-Patch4: %{name}-signed-char.patch
-# /src/goto-cc/ms_link_cmdline.cpp, use non-reference type 'const string'
-Patch5: %{name}-goto-cc-type-change.patch
-# Fix imcompatibility with glibc 2.33+
-Patch6: %{name}-errno-realpath.patch
# Skip some c++ tests as cbmc cannot parse some GCC 11 headers
-Patch7: %{name}-f34-fix-build.patch
-# from https://src.fedoraproject.org/rpms/catch/c/771d2
-Patch8: %{name}-catch2.patch
+Patch3: %{name}-f34-fix-build.patch
+# From https://src.fedoraproject.org/rpms/catch/c/771d2
+Patch4: %{name}-catch2.patch
+# Revert https://github.com/diffblue/cbmc/commit/a5b3008411f89a7800fde9003017242a8...
+# due deprecated python2 in fedora
+Patch5: %{name}-f35-deprecated-python.patch
+# Enable SSE2 (https://fedoraproject.org/wiki/Changes/Update_i686_architectural_baseline...)
+Patch6: %{name}-f35-enable_sse2.patch
-BuildRequires: bash
BuildRequires: bison
BuildRequires: cmake
BuildRequires: doxygen-latex
BuildRequires: flex
BuildRequires: gcc-c++
-BuildRequires: gdb
BuildRequires: glpk-devel
-BuildRequires: graphviz
BuildRequires: make
BuildRequires: minisat2-devel
BuildRequires: ninja-build
BuildRequires: zlib-devel
+# for the test
+BuildRequires: jq
+BuildRequires: gdb
+BuildRequires: perl
+BuildRequires: python3
+BuildRequires: z3
-Requires: clang
Requires: gcc-c++
Requires: sed
@@ -79,16 +78,14 @@ Output conversion utilities for CBMC (GCC like format)
%patch1 -p0
%endif
%patch2 -p0
-%ifarch armv7hl i686
+%if 0%{?fedora} > 33
%patch3 -p0
%endif
%patch4 -p0
%patch5 -p0
+%ifarch i686
%patch6 -p0
-%if 0%{?fedora} > 33
-%patch7 -p0
%endif
-%patch8 -p0
%build
%cmake -GNinja -DWITH_JBMC:BOOL=OFF -DWITH_SYSTEM_SAT_SOLVER:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=OFF
@@ -121,7 +118,7 @@ ln -s xml_y.tab.h src/xmllang/xml_y.tab.hpp
%endif
%files
-%doc CHANGELOG README.md
+%doc README.md
%license LICENSE
%{_bindir}/*
%{_mandir}/man1/*
@@ -137,6 +134,9 @@ ln -s xml_y.tab.h src/xmllang/xml_y.tab.hpp
%changelog
+* Wed May 12 2021 Vincent Mihalkovic <vmihalko(a)redhat.com> - 5.29.0-1
+- New upstream release
+
* Wed Mar 10 2021 Vincent Mihalkovic <vmihalko(a)redhat.com> - 5.25.0-1
- Add csexec-cbmc.sh script
- New upstream release
diff --git a/sources b/sources
index 860bf0d..86311bc 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (cbmc-5.25.0.tar.gz) = 90fbaaaf9189be67a52b3e88f6165d3b9dc791c2d86b50ea2b4405f1f69071dadec404d0004a2e537cffbdf1a782e2b1a8240f21b259b114c8799fd2fe3a1a95
+SHA512 (cbmc-5.29.0.tar.gz) = 23402f72f13a04096d7a3cea8e570620558288118231833bf8cd4f3f47c85f11ed2719f5330f570b9263a5732999800017ec910dfe84b96dbd0326ad77ecf2c3
SHA512 (cbmc-utils-1.1.tar.gz) = d6170e08cc8b8c6a116cc5db883f8d13dfa976087434468eae1e213c8aada3ebf1bf913e565ff971defbe06106ad4180a5cff1a32bbbb2ee3b035a7600b0183c
3 years
Architecture specific change in rpms/rust-wat.git
by githook-noreply@fedoraproject.org
The package rpms/rust-wat.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/rust-wat.git/commit/?id=031abe473....
Change:
+ExclusiveArch: %{rust_arches}
Thanks.
Full change:
============
commit 031abe473980d15bff403e423aa92aeb8d39ceac
Author: Olivier Lemasle <o.lemasle(a)gmail.com>
Date: Sat May 15 20:18:21 2021 +0200
Initial import (#1901097)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ec46005
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/wat-1.0.37.crate
diff --git a/rust-wat.spec b/rust-wat.spec
new file mode 100644
index 0000000..a79beca
--- /dev/null
+++ b/rust-wat.spec
@@ -0,0 +1,77 @@
+# Generated by rust2rpm 16
+%bcond_without check
+%global debug_package %{nil}
+
+%global crate wat
+
+Name: rust-%{crate}
+Version: 1.0.37
+Release: 1%{?dist}
+Summary: Rust parser for the WebAssembly Text format
+
+# Upstream license specification: Apache-2.0 WITH LLVM-exception
+License: ASL 2.0 with exceptions
+URL: https://crates.io/crates/wat
+Source: %{crates_source}
+
+ExclusiveArch: %{rust_arches}
+%if %{__cargo_skip_build}
+BuildArch: noarch
+%endif
+
+BuildRequires: rust-packaging
+
+%global _description %{expand:
+Rust parser for the WebAssembly Text format, WAT.}
+
+%description %{_description}
+
+%package devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description devel %{_description}
+
+This package contains library source intended for building other packages
+which use "%{crate}" crate.
+
+%files devel
+%doc README.md
+%{cargo_registry}/%{crate}-%{version_no_tilde}/
+
+%package -n %{name}+default-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+default-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "default" feature of "%{crate}" crate.
+
+%files -n %{name}+default-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%prep
+%autosetup -n %{crate}-%{version_no_tilde} -p1
+%cargo_prep
+
+%generate_buildrequires
+%cargo_generate_buildrequires
+
+%build
+%cargo_build
+
+%install
+%cargo_install
+
+%if %{with check}
+%check
+%cargo_test
+%endif
+
+%changelog
+* Wed May 12 11:11:03 CEST 2021 Olivier Lemasle <o.lemasle(a)gmail.com> - 1.0.37-1
+- Update to 1.0.37
+
+* Sat Nov 21 19:34:48 CET 2020 Olivier Lemasle <o.lemasle(a)gmail.com> - 1.0.28-1
+- Initial package
diff --git a/sources b/sources
new file mode 100644
index 0000000..1035dea
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (wat-1.0.37.crate) = 894da784ee64ef9c3bd45821433c74ee745d8e67c55d385f908ac24161d97dddb915f6b78a839295e8479664e76611e30405ded7027f301a75aeff614594715e
3 years
Architecture specific change in rpms/rust-wast.git
by githook-noreply@fedoraproject.org
The package rpms/rust-wast.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/rust-wast.git/commit/?id=87b0b53b....
Change:
+ExclusiveArch: %{rust_arches}
Thanks.
Full change:
============
commit 87b0b53b7266c907d4cf89b968ae44f95ce7766e
Author: Olivier Lemasle <o.lemasle(a)gmail.com>
Date: Tue May 11 21:42:47 2021 +0200
Initial import (#1901090)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..db9778f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/wast-35.0.2.crate
diff --git a/dev-dependencies.diff b/dev-dependencies.diff
new file mode 100644
index 0000000..7ec560f
--- /dev/null
+++ b/dev-dependencies.diff
@@ -0,0 +1,16 @@
+diff --color -u wast-27.0.0/Cargo.toml wast-27.0.1/Cargo.toml
+--- wast-27.0.0/Cargo.toml 2020-11-09 15:58:35.000000000 +0100
++++ wast-27.0.1/Cargo.toml 2020-11-22 11:57:48.145927257 +0100
+@@ -33,6 +33,12 @@
+ [dev-dependencies.rayon]
+ version = "1.0"
+
++[dev-dependencies.wasmparser]
++version = "0.78.0"
++
++[dev-dependencies.wat]
++version = "1.0.28"
++
+ [features]
+ default = ["wasm-module"]
+ wasm-module = []
diff --git a/rust-wast.spec b/rust-wast.spec
new file mode 100644
index 0000000..cb97ac5
--- /dev/null
+++ b/rust-wast.spec
@@ -0,0 +1,93 @@
+# Generated by rust2rpm 16
+# Disable checks to bootstrap this package, to fix the dependency loop
+%bcond_without bootstrap
+%bcond_with check
+%global debug_package %{nil}
+
+%global crate wast
+
+Name: rust-%{crate}
+Version: 35.0.2
+Release: 1%{?dist}
+Summary: Customizable Rust parsers for the WebAssembly Text formats WAT and WAST
+
+# Upstream license specification: Apache-2.0 WITH LLVM-exception
+License: ASL 2.0 with exceptions
+URL: https://crates.io/crates/wast
+Source: %{crates_source}
+# Add dev-dependencies specified in Cargo.toml.orig with paths only
+Patch0: dev-dependencies.diff
+
+ExclusiveArch: %{rust_arches}
+%if %{__cargo_skip_build}
+BuildArch: noarch
+%endif
+
+BuildRequires: rust-packaging
+
+%global _description %{expand:
+Customizable Rust parsers for the WebAssembly Text formats WAT and WAST.}
+
+%description %{_description}
+
+%package devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description devel %{_description}
+
+This package contains library source intended for building other packages
+which use "%{crate}" crate.
+
+%files devel
+%doc README.md
+%{cargo_registry}/%{crate}-%{version_no_tilde}/
+
+%package -n %{name}+default-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+default-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "default" feature of "%{crate}" crate.
+
+%files -n %{name}+default-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%package -n %{name}+wasm-module-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+wasm-module-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "wasm-module" feature of "%{crate}" crate.
+
+%files -n %{name}+wasm-module-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%prep
+%autosetup -n %{crate}-%{version_no_tilde} -p1
+%cargo_prep
+
+%generate_buildrequires
+%cargo_generate_buildrequires
+
+%build
+%cargo_build
+
+%install
+%cargo_install
+
+%if %{with check}
+%check
+%cargo_test
+%endif
+
+%changelog
+* Mon May 10 2021 Olivier Lemasle <o.lemasle(a)gmail.com> - 35.0.2-1
+- Bump to version 35.0.2
+
+* Sat Nov 21 19:34:45 CET 2020 Olivier Lemasle <o.lemasle(a)gmail.com> - 27.0.0-1
+- Initial package
diff --git a/sources b/sources
new file mode 100644
index 0000000..4d2d034
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (wast-35.0.2.crate) = 0076bc3d5950d9026915b4271fc2e1b4d117913e0ebd459cec2acc78ab11a8e98b7bc98bd333c3924f8130ab0dffcb9b640475f38a53721ccc73ea54b73f0855
3 years
Architecture specific change in rpms/rust-cranelift-entity.git
by githook-noreply@fedoraproject.org
The package rpms/rust-cranelift-entity.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/rust-cranelift-entity.git/commit/....
Change:
+ExclusiveArch: %{rust_arches}
Thanks.
Full change:
============
commit 5b4d5559d3f2628fde53d6535faadc137c97d6d1
Author: Olivier Lemasle <o.lemasle(a)gmail.com>
Date: Mon May 17 10:27:51 2021 +0200
Initial import (#1959754)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40a2c60
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/cranelift-entity-0.73.0.crate
diff --git a/rust-cranelift-entity.spec b/rust-cranelift-entity.spec
new file mode 100644
index 0000000..eee5a10
--- /dev/null
+++ b/rust-cranelift-entity.spec
@@ -0,0 +1,99 @@
+# Generated by rust2rpm 17
+%bcond_without check
+%global debug_package %{nil}
+
+%global crate cranelift-entity
+
+Name: rust-%{crate}
+Version: 0.73.0
+Release: 1%{?dist}
+Summary: Data structures using entity references as mapping keys
+
+# Upstream license specification: Apache-2.0 WITH LLVM-exception
+License: ASL 2.0 with exceptions
+URL: https://crates.io/crates/cranelift-entity
+Source: %{crates_source}
+
+ExclusiveArch: %{rust_arches}
+%if %{__cargo_skip_build}
+BuildArch: noarch
+%endif
+
+BuildRequires: rust-packaging
+
+%global _description %{expand:
+Data structures using entity references as mapping keys.}
+
+%description %{_description}
+
+%package devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description devel %{_description}
+
+This package contains library source intended for building other packages
+which use "%{crate}" crate.
+
+%files devel
+%doc README.md
+%license LICENSE
+%{cargo_registry}/%{crate}-%{version_no_tilde}/
+
+%package -n %{name}+default-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+default-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "default" feature of "%{crate}" crate.
+
+%files -n %{name}+default-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%package -n %{name}+enable-serde-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+enable-serde-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "enable-serde" feature of "%{crate}" crate.
+
+%files -n %{name}+enable-serde-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%package -n %{name}+serde-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+serde-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "serde" feature of "%{crate}" crate.
+
+%files -n %{name}+serde-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%prep
+%autosetup -n %{crate}-%{version_no_tilde} -p1
+%cargo_prep
+
+%generate_buildrequires
+%cargo_generate_buildrequires
+
+%build
+%cargo_build
+
+%install
+%cargo_install
+
+%if %{with check}
+%check
+%cargo_test
+%endif
+
+%changelog
+* Wed May 12 11:24:53 CEST 2021 Olivier Lemasle <o.lemasle(a)gmail.com> - 0.73.0-1
+- Initial package
diff --git a/sources b/sources
new file mode 100644
index 0000000..339e904
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (cranelift-entity-0.73.0.crate) = 7bb5f4e1a0af9c2173bead4143fb72eba5166cda02beb0015e2c07f049f0a1ea9826deec5dc6b911a6a6f54383c81c46c3fda8ffe267fb031cb80175f04351f0
3 years
Architecture specific change in rpms/rust-cranelift-codegen-shared.git
by githook-noreply@fedoraproject.org
The package rpms/rust-cranelift-codegen-shared.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/rust-cranelift-codegen-shared.git....
Change:
+ExclusiveArch: %{rust_arches}
Thanks.
Full change:
============
commit f4c6e51c4c9f0f85532437011514676ad5372aa9
Author: Olivier Lemasle <o.lemasle(a)gmail.com>
Date: Mon May 17 10:25:00 2021 +0200
Initial import (#1959780)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cdb205c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/cranelift-codegen-shared-0.73.0.crate
diff --git a/rust-cranelift-codegen-shared.spec b/rust-cranelift-codegen-shared.spec
new file mode 100644
index 0000000..0973e94
--- /dev/null
+++ b/rust-cranelift-codegen-shared.spec
@@ -0,0 +1,99 @@
+# Generated by rust2rpm 17
+%bcond_without check
+%global debug_package %{nil}
+
+%global crate cranelift-codegen-shared
+
+Name: rust-%{crate}
+Version: 0.73.0
+Release: 1%{?dist}
+Summary: For code shared between cranelift-codegen-meta and cranelift-codegen
+
+# Upstream license specification: Apache-2.0 WITH LLVM-exception
+License: ASL 2.0 with exceptions
+URL: https://crates.io/crates/cranelift-codegen-shared
+Source: %{crates_source}
+
+ExclusiveArch: %{rust_arches}
+%if %{__cargo_skip_build}
+BuildArch: noarch
+%endif
+
+BuildRequires: rust-packaging
+
+%global _description %{expand:
+For code shared between cranelift-codegen-meta and cranelift-codegen.}
+
+%description %{_description}
+
+%package devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description devel %{_description}
+
+This package contains library source intended for building other packages
+which use "%{crate}" crate.
+
+%files devel
+%doc README.md
+%license LICENSE
+%{cargo_registry}/%{crate}-%{version_no_tilde}/
+
+%package -n %{name}+default-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+default-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "default" feature of "%{crate}" crate.
+
+%files -n %{name}+default-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%package -n %{name}+enable-serde-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+enable-serde-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "enable-serde" feature of "%{crate}" crate.
+
+%files -n %{name}+enable-serde-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%package -n %{name}+serde-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+serde-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "serde" feature of "%{crate}" crate.
+
+%files -n %{name}+serde-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%prep
+%autosetup -n %{crate}-%{version_no_tilde} -p1
+%cargo_prep
+
+%generate_buildrequires
+%cargo_generate_buildrequires
+
+%build
+%cargo_build
+
+%install
+%cargo_install
+
+%if %{with check}
+%check
+%cargo_test
+%endif
+
+%changelog
+* Wed May 12 12:47:22 CEST 2021 Olivier Lemasle <o.lemasle(a)gmail.com> - 0.73.0-1
+- Initial package
diff --git a/sources b/sources
new file mode 100644
index 0000000..1d48b0a
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (cranelift-codegen-shared-0.73.0.crate) = bd42ebe882ee102d4190a67243e4662b5e1a3bd1c055650bb0e0e2917309a7d9541340527c926597638d4c4ec6b5c216426a65377bf6f6c799ba6b272df532dc
3 years
Architecture specific change in rpms/rust-typetag.git
by githook-noreply@fedoraproject.org
The package rpms/rust-typetag.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/rust-typetag.git/commit/?id=9928d....
Change:
+ExclusiveArch: %{rust_arches}
Thanks.
Full change:
============
commit 9928d5b8a711c0e574710d23b356478b91147cd2
Author: Olivier Lemasle <o.lemasle(a)gmail.com>
Date: Sat May 15 20:15:02 2021 +0200
Initial import (#1900411)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cdbb32d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/typetag-0.1.7.crate
diff --git a/rust-typetag.spec b/rust-typetag.spec
new file mode 100644
index 0000000..773dd6c
--- /dev/null
+++ b/rust-typetag.spec
@@ -0,0 +1,78 @@
+# Generated by rust2rpm 16
+%bcond_without check
+%global debug_package %{nil}
+
+%global crate typetag
+
+Name: rust-%{crate}
+Version: 0.1.7
+Release: 1%{?dist}
+Summary: Serde serializable and deserializable trait objects
+
+# Upstream license specification: MIT OR Apache-2.0
+License: MIT or ASL 2.0
+URL: https://crates.io/crates/typetag
+Source: %{crates_source}
+
+ExclusiveArch: %{rust_arches}
+%if %{__cargo_skip_build}
+BuildArch: noarch
+%endif
+
+BuildRequires: rust-packaging
+
+%global _description %{expand:
+Serde serializable and deserializable trait objects.}
+
+%description %{_description}
+
+%package devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description devel %{_description}
+
+This package contains library source intended for building other packages
+which use "%{crate}" crate.
+
+%files devel
+%doc README.md
+%license LICENSE-APACHE LICENSE-MIT
+%{cargo_registry}/%{crate}-%{version_no_tilde}/
+
+%package -n %{name}+default-devel
+Summary: %{summary}
+BuildArch: noarch
+
+%description -n %{name}+default-devel %{_description}
+
+This package contains library source intended for building other packages
+which use "default" feature of "%{crate}" crate.
+
+%files -n %{name}+default-devel
+%ghost %{cargo_registry}/%{crate}-%{version_no_tilde}/Cargo.toml
+
+%prep
+%autosetup -n %{crate}-%{version_no_tilde} -p1
+%cargo_prep
+
+%generate_buildrequires
+%cargo_generate_buildrequires
+
+%build
+%cargo_build
+
+%install
+%cargo_install
+
+%if %{with check}
+%check
+%cargo_test
+%endif
+
+%changelog
+* Thu May 13 12:30:19 CEST 2021 Olivier Lemasle <o.lemasle(a)gmail.com> - 0.1.7-1
+- Update to 0.1.7
+
+* Sun Nov 22 17:58:44 CET 2020 Olivier Lemasle <o.lemasle(a)gmail.com> - 0.1.6-1
+- Initial package
diff --git a/sources b/sources
new file mode 100644
index 0000000..9987ce5
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (typetag-0.1.7.crate) = 5909e28a94ec53bf31ae65f34908b4d45b9174a2a45a349a11e6033669222c0c41bf4391e2feb4c63196894a2e802d6bb8f1f9f4daba1da102c9ce89175ad1b9
3 years