Repository: qpid-dispatch Updated Branches: refs/heads/master 3d73a89c1 -> cc2d0cb9b
DISPATCH-190 - Exposed the protocol family for the configuration of listeners and connectors. Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/de3bba38 Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/de3bba38 Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/de3bba38 Branch: refs/heads/master Commit: de3bba38d7e372bc5bb4d86241a8f9795ab67c29 Parents: 3d73a89 Author: ganeshmurthy <[email protected]> Authored: Wed Dec 2 13:29:49 2015 -0500 Committer: ganeshmurthy <[email protected]> Committed: Fri Dec 4 09:55:48 2015 -0500 ---------------------------------------------------------------------- include/qpid/dispatch/driver.h | 16 ++- include/qpid/dispatch/server.h | 6 + python/qpid_dispatch/management/qdrouter.json | 8 +- src/connection_manager.c | 19 ++-- src/posix/driver.c | 43 ++++++- src/server.c | 4 +- tests/CMakeLists.txt | 23 ++-- tests/system_test.py | 87 ++++++++++++--- tests/system_tests_protocol_family.py | 124 +++++++++++++++++++++ 9 files changed, 286 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/include/qpid/dispatch/driver.h ---------------------------------------------------------------------- diff --git a/include/qpid/dispatch/driver.h b/include/qpid/dispatch/driver.h index c286c44..05e8b18 100644 --- a/include/qpid/dispatch/driver.h +++ b/include/qpid/dispatch/driver.h @@ -142,12 +142,16 @@ void qdpn_driver_free(qdpn_driver_t *driver); * @param[in] driver driver that will 'own' this listener * @param[in] host local host address to listen on * @param[in] port local port to listen on + * @param[in] protocol family to use (IPv4 or IPv6 or 0). If 0 (zero) is passed in the protocol family will be automatically determined from the address * @param[in] context application-supplied, can be accessed via * qdpn_listener_context() * @return a new listener on the given host:port, NULL if error */ -qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver, const char *host, - const char *port, void* context); +qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver, + const char *host, + const char *port, + const char *protocol_family, + void* context); /** Access the head listener for a driver. * @@ -213,12 +217,16 @@ void qdpn_listener_free(qdpn_listener_t *listener); * @param[in] driver owner of this connection. * @param[in] host remote host to connect to. * @param[in] port remote port to connect to. + * @param[in] protocol family to use (IPv4 or IPv6 or 0). If 0 (zero) is passed in the protocol family will be automatically determined from the address * @param[in] context application supplied, can be accessed via * qdpn_connector_context() @return a new connector * to the given remote, or NULL on error. */ -qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver, const char *host, - const char *port, void* context); +qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver, + const char *host, + const char *port, + const char *protocol_family, + void* context); /** Access the head connector for a driver. * http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/include/qpid/dispatch/server.h ---------------------------------------------------------------------- diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h index 2fb237d..4f39fc5 100644 --- a/include/qpid/dispatch/server.h +++ b/include/qpid/dispatch/server.h @@ -248,6 +248,12 @@ typedef struct qd_server_config_t { char *port; /** + * Protocol family that the socket will use when binding listener or connector. + * Possible values are IPv4 or IPv6. If not specified, the protocol family will be automatically determined from the address + */ + char *protocol_family; + + /** * Space-separated list of SASL mechanisms to be accepted for the connection. */ char *sasl_mechanisms; http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/python/qpid_dispatch/management/qdrouter.json ---------------------------------------------------------------------- diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json index a3ee6d0..50b6640 100644 --- a/python/qpid_dispatch/management/qdrouter.json +++ b/python/qpid_dispatch/management/qdrouter.json @@ -20,6 +20,12 @@ "default": "amqp", "create": true + }, + "protocolFamily": { + "type": ["IPv4", "IPv6"], + "required": false, + "description": "['IPv4', 'IPv6'] IPv4: Internet Protocol version 4; IPv6: Internet Protocol version 6. If not specified, the protocol family will be automatically determined from the address.", + "create": true } } }, @@ -633,7 +639,7 @@ "default": "both", "description": "['in', 'out', 'both', 'no'] in: Strip the dispatch router specific annotations only on ingress; out: Strip the dispatch router specific annotations only on egress; both: Strip the dispatch router specific annotations on both ingress and egress; no - do not strip dispatch router specific annotations", "create": true - } + } } }, http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/src/connection_manager.c ---------------------------------------------------------------------- diff --git a/src/connection_manager.c b/src/connection_manager.c index c90db75..3b597da 100644 --- a/src/connection_manager.c +++ b/src/connection_manager.c @@ -62,7 +62,6 @@ struct qd_connection_manager_t { qd_config_connector_list_t on_demand_connectors; }; - // True if entity has any of attributes. static bool has_attrs(qd_entity_t *entity, const char **attributes, int n) { for (int i = 0; i < n; ++i) @@ -73,6 +72,7 @@ static bool has_attrs(qd_entity_t *entity, const char **attributes, int n) { static const char *ssl_attributes[] = { "certDb", "certFile", "keyFile", "passwordFile", "password" }; + static const int ssl_attributes_count = sizeof(ssl_attributes)/sizeof(ssl_attributes[0]); static void qd_server_config_free(qd_server_config_t *cf) @@ -139,15 +139,16 @@ static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *conf bool depAllowUnsecured = qd_entity_opt_bool(entity, "allowUnsecured", !requireSsl); CHECK(); memset(config, 0, sizeof(*config)); - config->host = qd_entity_get_string(entity, "addr"); CHECK(); - config->port = qd_entity_get_string(entity, "port"); CHECK(); - config->role = qd_entity_get_string(entity, "role"); CHECK(); - config->max_frame_size = qd_entity_get_long(entity, "maxFrameSize"); CHECK(); + config->host = qd_entity_get_string(entity, "addr"); CHECK(); + config->port = qd_entity_get_string(entity, "port"); CHECK(); + config->role = qd_entity_get_string(entity, "role"); CHECK(); + config->protocol_family = qd_entity_opt_string(entity, "protocolFamily", 0); CHECK(); + config->max_frame_size = qd_entity_get_long(entity, "maxFrameSize"); CHECK(); config->idle_timeout_seconds = qd_entity_get_long(entity, "idleTimeoutSeconds"); CHECK(); - config->sasl_username = qd_entity_opt_string(entity, "saslUsername", 0); CHECK(); - config->sasl_password = qd_entity_opt_string(entity, "saslPassword", 0); CHECK(); - config->sasl_mechanisms = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK(); - config->ssl_enabled = has_attrs(entity, ssl_attributes, ssl_attributes_count); + config->sasl_username = qd_entity_opt_string(entity, "saslUsername", 0); CHECK(); + config->sasl_password = qd_entity_opt_string(entity, "saslPassword", 0); CHECK(); + config->sasl_mechanisms = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK(); + config->ssl_enabled = has_attrs(entity, ssl_attributes, ssl_attributes_count); // // For now we are hardwiring this attribute to true. If there's an outcry from the http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/src/posix/driver.c ---------------------------------------------------------------------- diff --git a/src/posix/driver.c b/src/posix/driver.c index 5eb7c55..2fa4e45 100644 --- a/src/posix/driver.c +++ b/src/posix/driver.c @@ -58,6 +58,12 @@ DEQ_DECLARE(qdpn_listener_t, qdpn_listener_list_t); DEQ_DECLARE(qdpn_connector_t, qdpn_connector_list_t); +const char *protocol_family_ipv4 = "IPv4"; +const char *protocol_family_ipv6 = "IPv6"; + +const char *AF_INET6_STR = "AF_INET6"; +const char *AF_INET_STR = "AF_INET"; + struct qdpn_driver_t { qd_log_source_t *log; pn_trace_t trace; @@ -232,8 +238,26 @@ static void qdpn_configure_sock(qdpn_driver_t *driver, int sock) } -qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver, const char *host, - const char *port, void* context) +/** + * Sets the ai_family field on the addrinfo struct based on the passed in NON-NULL protocol_family. + * If the passed in protocol family does not match IPv6, IPv4, the function does not set the ai_family field + */ +static void qd_set_addr_ai_family(qdpn_driver_t *driver, struct addrinfo *addr, const char* protocol_family) +{ + if (protocol_family) { + if(strcmp(protocol_family, protocol_family_ipv6) == 0) + addr->ai_family = AF_INET6; + else if(strcmp(protocol_family, protocol_family_ipv4) == 0) + addr->ai_family = AF_INET; + } +} + + +qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver, + const char *host, + const char *port, + const char *protocol_family, + void* context) { if (!driver) return NULL; @@ -244,6 +268,10 @@ qdpn_listener_t *qdpn_listener(qdpn_driver_t *driver, const char *host, return 0; } + // Set the protocol family before creating the socket. + qd_set_addr_ai_family(driver, addr, protocol_family); + qd_log(driver->log, QD_LOG_TRACE, "Set protocol family of port %s to: %s", port, protocol_family); + int sock = qdpn_create_socket(addr->ai_family); if (sock < 0) { qdpn_log_errno(driver, "pn_create_socket"); @@ -428,8 +456,11 @@ static void qdpn_driver_remove_connector(qdpn_driver_t *d, qdpn_connector_t *c) sys_mutex_unlock(d->lock); } -qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver, const char *host, - const char *port, void *context) +qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver, + const char *host, + const char *port, + const char *protocol_family, + void *context) { if (!driver) return NULL; @@ -440,6 +471,10 @@ qdpn_connector_t *qdpn_connector(qdpn_driver_t *driver, const char *host, return 0; } + // Set the protocol family before creating the socket. + qd_set_addr_ai_family(driver, addr, protocol_family); + qd_log(driver->log, QD_LOG_TRACE, "Set protocol family of port %s to: %s", port, protocol_family); + int sock = qdpn_create_socket(addr->ai_family); if (sock == PN_INVALID_SOCKET) { freeaddrinfo(addr); http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/src/server.c ---------------------------------------------------------------------- diff --git a/src/server.c b/src/server.c index c15e871..8ff30b1 100644 --- a/src/server.c +++ b/src/server.c @@ -826,7 +826,7 @@ static void cxtr_try_open(void *context) sys_mutex_lock(ct->server->lock); // Increment the connection id so the next connection can use it ctx->connection_id = ct->server->next_connection_id++; - ctx->pn_cxtr = qdpn_connector(ct->server->driver, ct->config->host, ct->config->port, (void*) ctx); + ctx->pn_cxtr = qdpn_connector(ct->server->driver, ct->config->host, ct->config->port, ct->config->protocol_family, (void*) ctx); if (ctx->pn_cxtr) { DEQ_INSERT_TAIL(ct->server->connections, ctx); qd_entity_cache_add(QD_CONNECTION_TYPE, ctx); @@ -1282,7 +1282,7 @@ qd_listener_t *qd_server_listen(qd_dispatch_t *qd, const qd_server_config_t *con li->server = qd_server; li->config = config; li->context = context; - li->pn_listener = qdpn_listener(qd_server->driver, config->host, config->port, (void*) li); + li->pn_listener = qdpn_listener(qd_server->driver, config->host, config->port, config->protocol_family, (void*) li); if (!li->pn_listener) { free_qd_listener_t(li); http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/tests/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c02c4fa..825f84e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -60,6 +60,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_one_router.py DESTINATION ${C file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_qdmanage.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_qdstat.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_two_routers.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_protocol_family.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_link_routes.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/run_system_tests.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_test.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) @@ -78,16 +79,17 @@ add_test(unit_tests_size_1 ${TEST_WRAP} --vg unit_tests_size 1) add_test(unit_tests ${TEST_WRAP} --vg unit_tests ${CMAKE_CURRENT_SOURCE_DIR}/threads4.conf) # Add all sytem_tests* using add_test -add_test(router_tests ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/router_engine_test.py -v) -add_test(system_tests_broker ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_broker.py -v) -add_test(system_tests_management ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_management.py -v) -add_test(system_tests_one_router ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_one_router.py -v) -add_test(system_tests_qdmanage ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdmanage.py -v) -add_test(system_tests_qdstat ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdstat.py -v) -add_test(system_tests_two_routers ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_two_routers.py -v) -add_test(system_tests_link_routes ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_link_routes.py -v) -add_test(system_tests_sasl_plain ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_sasl_plain.py -v) -add_test(management_tests ${TEST_WRAP} -m unittest -v management) +add_test(router_tests ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/router_engine_test.py -v) +add_test(system_tests_broker ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_broker.py -v) +add_test(system_tests_management ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_management.py -v) +add_test(system_tests_one_router ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_one_router.py -v) +add_test(system_tests_qdmanage ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdmanage.py -v) +add_test(system_tests_qdstat ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdstat.py -v) +add_test(system_tests_two_routers ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_two_routers.py -v) +add_test(system_tests_protocol_family ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_protocol_family.py -v) +add_test(system_tests_link_routes ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_link_routes.py -v) +add_test(system_tests_sasl_plain ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_sasl_plain.py -v) +add_test(management_tests ${TEST_WRAP} -m unittest -v management) #macro(add_system_test test) # add_test(${test} ${TEST_WRAP} -m ${test} -v) @@ -102,6 +104,7 @@ set(SYSTEM_TEST_FILES ${CMAKE_CURRENT_BINARY_DIR}/system_test.py ${CMAKE_CURRENT_BINARY_DIR}/system_tests_one_router.py ${CMAKE_CURRENT_BINARY_DIR}/system_tests_two_routers.py + ${CMAKE_CURRENT_BINARY_DIR}/system_tests_protocol_family.py ${CMAKE_CURRENT_BINARY_DIR}/system_tests_broker.py ${CMAKE_CURRENT_BINARY_DIR}/system_tests_management.py ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdstat.py http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/tests/system_test.py ---------------------------------------------------------------------- diff --git a/tests/system_test.py b/tests/system_test.py index 60f54c6..964bf88 100644 --- a/tests/system_test.py +++ b/tests/system_test.py @@ -57,6 +57,7 @@ from copy import copy import proton from proton import Message from qpid_dispatch.management.client import Node + try: # NOTE: the tests can be run outside a build to test an installed dispatch. # In this case we won't have access to the run.py module so no valgrind. @@ -159,9 +160,20 @@ def retry_exception(function, timeout=TIMEOUT, delay=.001, max_delay=1, exceptio if delay is None: raise -def port_available(port, host='127.0.0.1'): +def get_local_host_socket(protocol_family='IPv4'): + if protocol_family == 'IPv4': + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + host = '127.0.0.1' + elif protocol_family == 'IPv6': + s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + host = '::1' + + return s, host + +def port_available(port, protocol_family='IPv4'): """Return true if connecting to host:port gives 'connection refused'.""" - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s, host = get_local_host_socket(protocol_family) + try: s.connect((host, port)) s.close() @@ -171,14 +183,14 @@ def port_available(port, host='127.0.0.1'): pass return False -def wait_port(port, host='127.0.0.1', **retry_kwargs): +def wait_port(port, protocol_family='IPv4', **retry_kwargs): """Wait up to timeout for port (on host) to be connectable. Takes same keyword arguments as retry to control the timeout""" def check(e): """Only retry on connection refused""" if not isinstance(e, socket.error) or not e.errno == 111: raise - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s, host = get_local_host_socket(protocol_family) try: retry_exception(lambda: s.connect((host, port)), exception_test=check, **retry_kwargs) @@ -187,11 +199,11 @@ def wait_port(port, host='127.0.0.1', **retry_kwargs): finally: s.close() -def wait_ports(ports, host="127.0.0.1", **retry_kwargs): +def wait_ports(ports, **retry_kwargs): """Wait up to timeout for all ports (on host) to be connectable. Takes same keyword arguments as retry to control the timeout""" - for p in ports: - wait_port(p, host=host, **retry_kwargs) + for port, protocol_family in ports.iteritems(): + wait_port(port=port, protocol_family=protocol_family, **retry_kwargs) def message(**properties): """Convenience to create a proton.Message with properties set""" @@ -372,6 +384,22 @@ class Qdrouterd(Process): super(Qdrouterd, self).teardown() @property + def ports_family(self): + """ + Return a dict of listener ports and the respective port family + Example - + { 23456: 'IPv4', 243455: 'IPv6' } + """ + ports_fam = {} + for l in self.config.sections('listener'): + if l.get('protocolFamily'): + ports_fam[l['port']] = l['protocolFamily'] + else: + ports_fam[l['port']] = 'IPv4' + + return ports_fam + + @property def ports(self): """Return list of configured ports for all listeners""" return [l['port'] for l in self.config.sections('listener')] @@ -379,12 +407,34 @@ class Qdrouterd(Process): @property def addresses(self): """Return amqp://host:port addresses for all listeners""" - return ["amqp://%s:%s"%(l['addr'], l['port']) for l in self.config.sections('listener')] + address_list = [] + for l in self.config.sections('listener'): + protocol_family = l.get('protocolFamily') + if protocol_family == 'IPv6': + address_list.append("amqp://[%s]:%s"%(l['addr'], l['port'])) + elif protocol_family == 'IPv4': + address_list.append("amqp://%s:%s"%(l['addr'], l['port'])) + else: + # Default to IPv4 + address_list.append("amqp://%s:%s"%(l['addr'], l['port'])) + + return address_list @property def hostports(self): """Return host:port for all listeners""" - return ["%s:%s"%(l['addr'], l['port']) for l in self.config.sections('listener')] + address_list = [] + for l in self.config.sections('listener'): + protocol_family = l.get('protocolFamily') + if protocol_family == 'IPv6': + address_list.append("[%s]:%s"%(l['addr'], l['port'])) + elif protocol_family == 'IPv4': + address_list.append("%s:%s"%(l['addr'], l['port'])) + else: + # Default to IPv4 + address_list.append("%s:%s"%(l['addr'], l['port'])) + + return address_list def is_connected(self, port, host='127.0.0.1'): """If router has a connection to host:port return the management info. @@ -412,19 +462,27 @@ class Qdrouterd(Process): return addrs and addrs[0]['subscriberCount'] >= subscribers and addrs[0]['remoteCount'] >= remotes assert retry(check, **retry_kwargs) + def get_host(self, protocol_family): + if protocol_family == 'IPv4': + return '127.0.0.1' + elif protocol_family == 'IPv6': + return '::1' + else: + return '127.0.0.1' + def wait_connectors(self, **retry_kwargs): """ Wait for all connectors to be connected @param retry_kwargs: keyword args for L{retry} """ for c in self.config.sections('connector'): - assert retry(lambda: self.is_connected(c['port']), **retry_kwargs), "Port not connected %s" % c['port'] + assert retry(lambda: self.is_connected(port=c['port'], host=self.get_host(c.get('protocolFamily'))), **retry_kwargs), "Port not connected %s" % c['port'] def wait_ready(self, **retry_kwargs): """Wait for ports and connectors to be ready""" if not self._wait_ready: self._wait_ready = True - wait_ports(self.ports, **retry_kwargs) + wait_ports(self.ports_family, **retry_kwargs) self.wait_connectors(**retry_kwargs) return self @@ -466,6 +524,7 @@ class Qpidd(Process): name=name, expect=Process.RUNNING) self.port = self.config['port'] or 5672 self.address = "127.0.0.1:%s"%self.port + self._management = None if wait: self.wait_ready() @@ -587,7 +646,7 @@ class Tester(object): next_port = random.randint(port_range[0], port_range[1]) @classmethod - def get_port(cls): + def get_port(cls, protocol_family='IPv4'): """Get an unused port""" def advance(): """Advance with wrap-around""" @@ -595,10 +654,10 @@ class Tester(object): if cls.next_port >= cls.port_range[1]: cls.next_port = cls.port_range[0] start = cls.next_port - while not port_available(cls.next_port): + while not port_available(cls.next_port, protocol_family): advance() if cls.next_port == start: - raise Exception("No avaliable ports in range %s", cls.port_range) + raise Exception("No available ports in range %s", cls.port_range) p = cls.next_port advance() return p http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/de3bba38/tests/system_tests_protocol_family.py ---------------------------------------------------------------------- diff --git a/tests/system_tests_protocol_family.py b/tests/system_tests_protocol_family.py new file mode 100644 index 0000000..0a3182b --- /dev/null +++ b/tests/system_tests_protocol_family.py @@ -0,0 +1,124 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import unittest +from time import sleep +from proton import Message +from system_test import TestCase, Qdrouterd, main_module + +try: + from proton import MODIFIED +except ImportError: + from proton import PN_STATUS_MODIFIED as MODIFIED + + +class ProtocolFamilyTest(TestCase): + @classmethod + def setUpClass(cls): + """ + Starts three routers with various listeners and connectors. + There is a call to wait_router_connected to make sure that the routers are able to communicate with each + other on ports using the assigned protocol family. + """ + super(ProtocolFamilyTest, cls).setUpClass() + + def router(name, connection): + + config = [ + ('container', {'workerThreads': 4, 'containerName': 'Qpid.Dispatch.Router.%s'%name}), + ('router', {'mode': 'interior', 'routerId': 'QDR.%s'%name}), + + # No protocolFamily is specified for this listener. + # This will test if the router defaults addr to 127.0.0.1 and if the router auto-detects protocol family + + ('listener', {'port': cls.tester.get_port()}), + + # Specify addr as 127.0.0.1 and protocol family as IPv4 + ('listener', {'addr': '127.0.0.1', 'protocolFamily': 'IPv4','port': cls.tester.get_port()}), + + # Specify protocol family as IPv4 but don't specify any addr + # This will test if the router defaults the addr field to 127.0.0.1 + ('listener', {'protocolFamily': 'IPv4', 'port': cls.tester.get_port()}), + + # Specify the addr as 127.0.0.1 + # This will test router's auto-detection of protocol family + ('listener', {'addr': '127.0.0.1', 'port': cls.tester.get_port()}), + + + # Specify addr as ::1 and protocol family as IPv6 + ('listener', {'addr': '::1', 'protocolFamily': 'IPv6', 'port': cls.tester.get_port(protocol_family='IPv6')}), + + ('fixedAddress', {'prefix': '/closest/', 'fanout': 'single', 'bias': 'closest'}), + ('fixedAddress', {'prefix': '/spread/', 'fanout': 'single', 'bias': 'spread'}), + ('fixedAddress', {'prefix': '/multicast/', 'fanout': 'multiple'}), + ('fixedAddress', {'prefix': '/', 'fanout': 'multiple'}), + + ] + connection + + config = Qdrouterd.Config(config) + + # The wait=True attempts to connect to each listening port with the appropriate protocol family + # and tests each connector + cls.routers.append(cls.tester.qdrouterd(name, config, wait=True)) + + cls.routers = [] + + inter_router_port = cls.tester.get_port(protocol_family='IPv6') + inter_router_ipv4_port = cls.tester.get_port(protocol_family='IPv4') + + router('A', + [ + ('listener', {'addr': '::1', 'role': 'inter-router', 'protocolFamily': 'IPv6', 'port': inter_router_port}) + ] + ) + + router('B', + [ + # Tests an IPv6 connector + ('connector', {'addr': '::1', 'role': 'inter-router', 'protocolFamily': 'IPv6', 'port': inter_router_port}), + ('listener', {'addr': '127.0.0.1', 'role': 'inter-router', 'port': inter_router_ipv4_port}) + ] + + ) + + router('C', + [ + # Tests an IPv4 connector + ('connector', {'addr': '127.0.0.1', 'role': 'inter-router', 'port': inter_router_ipv4_port}) + ] + ) + + cls.routers[0].wait_router_connected('QDR.B') + cls.routers[1].wait_router_connected('QDR.A') + cls.routers[2].wait_router_connected('QDR.B') + + # Without at least one test the setUpClass does not execute + def test_00_discard(self): + addr = self.routers[0].addresses[4]+"/test/1" + print 'addr', addr + M1 = self.messenger() + tm = Message() + tm.address = addr + for i in range(100): + tm.body = {'number': i} + M1.put(tm) + M1.send() + +if __name__ == '__main__': + unittest.main(main_module()) \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
