You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by gm...@apache.org on 2021/10/27 19:13:37 UTC

[qpid-dispatch] branch main updated: DISPATCH-2264: Fix for router crash when deleting listener

This is an automated email from the ASF dual-hosted git repository.

gmurthy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/main by this push:
     new cf1d3d9  DISPATCH-2264: Fix for router crash when deleting listener
cf1d3d9 is described below

commit cf1d3d9456ac400c4ee2508de39361b78f2dc30e
Author: Ganesh Murthy <gm...@apache.org>
AuthorDate: Wed Oct 27 12:07:11 2021 -0400

    DISPATCH-2264: Fix for router crash when deleting listener
---
 src/adaptors/http2/http2_adaptor.c | 37 +++++++++++++++++---------
 tests/system_tests_http2.py        | 54 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 77 insertions(+), 14 deletions(-)

diff --git a/src/adaptors/http2/http2_adaptor.c b/src/adaptors/http2/http2_adaptor.c
index e70c331..a3864a6 100644
--- a/src/adaptors/http2/http2_adaptor.c
+++ b/src/adaptors/http2/http2_adaptor.c
@@ -2603,9 +2603,25 @@ static void handle_listener_event(pn_event_t *e, qd_server_t *qd_server, void *c
         }
         break;
 
-        case PN_LISTENER_CLOSE:
-            qd_log(log, QD_LOG_INFO, "Closing HTTP connection on %s", host_port);
-            break;
+        case PN_LISTENER_CLOSE: {
+            if (li->pn_listener) {
+                pn_condition_t *cond = pn_listener_condition(li->pn_listener);
+                if (pn_condition_is_set(cond)) {
+                    qd_log(log, QD_LOG_ERROR, "Listener error on %s: %s (%s)", host_port, pn_condition_get_description(cond), pn_condition_get_name(cond));
+                }
+                else {
+                    qd_log(log, QD_LOG_TRACE, "Listener closed on %s", host_port);
+                }
+            }
+
+            sys_mutex_lock(http2_adaptor->lock);
+            pn_listener_set_context(li->pn_listener, 0);
+            li->pn_listener = 0;
+            DEQ_REMOVE(http2_adaptor->listeners, li);
+            sys_mutex_unlock(http2_adaptor->lock);
+            qd_http_listener_decref(li);
+        }
+        break;
 
         default:
             break;
@@ -2637,18 +2653,13 @@ void qd_http2_delete_connector(qd_dispatch_t *qd, qd_http_connector_t *connector
  */
 void qd_http2_delete_listener(qd_dispatch_t *qd, qd_http_listener_t *li)
 {
+    sys_mutex_lock(http2_adaptor->lock);
     if (li) {
         if (li->pn_listener) {
             pn_listener_close(li->pn_listener);
-            li->pn_listener = 0;
         }
-        sys_mutex_lock(http2_adaptor->lock);
-        DEQ_REMOVE(http2_adaptor->listeners, li);
-        sys_mutex_unlock(http2_adaptor->lock);
-
-        qd_log(http2_adaptor->log_source, QD_LOG_INFO, "Deleted HttpListener for %s, %s:%s", li->config.address, li->config.host, li->config.port);
-        qd_http_listener_decref(li);
     }
+    sys_mutex_unlock(http2_adaptor->lock);
 }
 
 
@@ -2708,14 +2719,16 @@ static void qdr_http2_adaptor_final(void *adaptor_context)
     // Free all http listeners
     qd_http_listener_t *li = DEQ_HEAD(adaptor->listeners);
     while (li) {
-        qd_http2_delete_listener(0, li);
+        DEQ_REMOVE_HEAD(adaptor->listeners);
+        qd_http_listener_decref(li);
         li = DEQ_HEAD(adaptor->listeners);
     }
 
     // Free all http connectors
     qd_http_connector_t *ct = DEQ_HEAD(adaptor->connectors);
     while (ct) {
-        qd_http2_delete_connector(0, ct);
+        DEQ_REMOVE_HEAD(adaptor->connectors);
+        qd_http_connector_decref(ct);
         ct = DEQ_HEAD(adaptor->connectors);
     }
 
diff --git a/tests/system_tests_http2.py b/tests/system_tests_http2.py
index 74746c3..e373a17 100644
--- a/tests/system_tests_http2.py
+++ b/tests/system_tests_http2.py
@@ -221,6 +221,43 @@ class CommonHttp2Tests:
         digest_of_response_file = get_digest(self.router_qdra.outdir + image_file_name)
         self.assertEqual(digest_of_server_file, digest_of_response_file)
 
+    def check_listener_delete(self, client_addr, server_addr):
+        # Run curl 127.0.0.1:port --http2-prior-knowledge
+        # We are first making sure that the http request goes thru successfully.
+        out = self.run_curl(client_addr)
+        ret_string = ""
+        i = 0
+        while (i < 1000):
+            ret_string += str(i) + ","
+            i += 1
+        self.assertIn(ret_string, out)
+
+        qd_manager = QdManager(self, address=server_addr)
+        http_listeners = qd_manager.query('org.apache.qpid.dispatch.httpListener')
+        self.assertEqual(len(http_listeners), 1)
+
+        # Run a qdmanage DELETE on the httpListener
+        qd_manager.delete("org.apache.qpid.dispatch.httpListener", name=self.listener_name)
+
+        # Make sure the listener is gone
+        http_listeners  = qd_manager.query('org.apache.qpid.dispatch.httpListener')
+        self.assertEqual(len(http_listeners), 0)
+
+        # Try running a curl command against the listener to make sure it times out
+        request_timed_out = False
+        try:
+            out = self.run_curl(client_addr, timeout=3)
+        except Exception as e:
+            request_timed_out = True
+        self.assertTrue(request_timed_out)
+
+        # Add back the listener and run a curl command to make sure that the newly added listener is
+        # back up and running.
+        create_result = qd_manager.create("org.apache.qpid.dispatch.httpListener", self.http_listener_props)
+        sleep(2)
+        out = self.run_curl(client_addr)
+        self.assertIn(ret_string, out)
+
     def check_connector_delete(self, client_addr, server_addr):
         # Run curl 127.0.0.1:port --http2-prior-knowledge
         # We are first making sure that the http request goes thru successfully.
@@ -469,12 +506,20 @@ class Http2TestTwoRouter(Http2TestBase, CommonHttp2Tests):
                                                   server_file="http2_server.py")
         name = "http2-test-router"
         inter_router_port = cls.tester.get_port()
+        cls.http_listener_port = cls.tester.get_port()
+        cls.listener_name = 'listenerToBeDeleted'
+        cls.http_listener_props = {
+            'port': cls.http_listener_port,
+            'address': 'examples',
+            'host': '127.0.0.1',
+            'protocolVersion': 'HTTP2',
+            'name': cls.listener_name
+        }
 
         config_qdra = Qdrouterd.Config([
             ('router', {'mode': 'interior', 'id': 'QDR.A'}),
             ('listener', {'port': cls.tester.get_port(), 'role': 'normal', 'host': '0.0.0.0'}),
-            ('httpListener', {'port': cls.tester.get_port(), 'address': 'examples',
-                              'host': '127.0.0.1', 'protocolVersion': 'HTTP2'}),
+            ('httpListener', cls.http_listener_props),
             ('listener', {'role': 'inter-router', 'port': inter_router_port})
         ])
 
@@ -554,6 +599,11 @@ class Http2TestTwoRouter(Http2TestBase, CommonHttp2Tests):
         self.assertEqual(stats_b[0].get('bytesIn'), 3944)
 
     @unittest.skipIf(skip_test(), "Python 3.7 or greater, Quart 0.13.0 or greater and curl needed to run http2 tests")
+    def test_yyy_http_listener_delete(self):
+        self.check_listener_delete(client_addr=self.router_qdra.http_addresses[0],
+                                   server_addr=self.router_qdra.addresses[0])
+
+    @unittest.skipIf(skip_test(), "Python 3.7 or greater, Quart 0.13.0 or greater and curl needed to run http2 tests")
     def test_zzz_http_connector_delete(self):
         self.check_connector_delete(client_addr=self.router_qdra.http_addresses[0],
                                     server_addr=self.router_qdrb.addresses[0])

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